mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-19 23:42:03 +08:00
Fix semantic review issues and release action runtime
This commit is contained in:
@@ -76,7 +76,7 @@ jobs:
|
||||
test -n "$(find release/local-server -maxdepth 1 -name 'cloudcli-local-server-*.tar.gz.sha256' -print -quit)"
|
||||
|
||||
- name: Publish branch server bundle
|
||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
tag_name: ${{ steps.artifact.outputs.server_bundle_tag }}
|
||||
name: CloudCLI Internal Local Runtime (${{ github.ref_name }})
|
||||
|
||||
4
.github/workflows/desktop-macos-release.yml
vendored
4
.github/workflows/desktop-macos-release.yml
vendored
@@ -99,7 +99,7 @@ jobs:
|
||||
test -n "$(find release/local-server -maxdepth 1 -name 'cloudcli-local-server-*.tar.gz.sha256' -print -quit)"
|
||||
|
||||
- name: Publish local server runtime assets
|
||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
tag_name: ${{ steps.release.outputs.server_bundle_tag }}
|
||||
target_commitish: ${{ github.sha }}
|
||||
@@ -122,7 +122,7 @@ jobs:
|
||||
cat release/SHASUMS256.txt
|
||||
|
||||
- name: Publish GitHub release assets
|
||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
tag_name: ${{ steps.release.outputs.tag }}
|
||||
target_commitish: ${{ github.sha }}
|
||||
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
test -n "$(find release/local-server -maxdepth 1 -name 'cloudcli-local-server-*.tar.gz.sha256' -print -quit)"
|
||||
|
||||
- name: Publish branch server bundle
|
||||
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
tag_name: ${{ steps.artifact.outputs.server_bundle_tag }}
|
||||
name: CloudCLI Internal Local Runtime (${{ github.ref_name }})
|
||||
|
||||
@@ -345,7 +345,8 @@ export const computerSemanticsService = {
|
||||
}
|
||||
case 'get_app_state':
|
||||
return getAppState(sessionId, readString(input.app));
|
||||
case 'click': {
|
||||
case 'click':
|
||||
case 'click_element': {
|
||||
const app = readString(input.app);
|
||||
const helperState = await withHelperState(sessionId, (adapter) => adapter.clickElement({ ...input, sessionId, app }));
|
||||
if (helperState) {
|
||||
@@ -381,7 +382,8 @@ export const computerSemanticsService = {
|
||||
await executor.drag(await targetFor(sessionId, app, stateId), { x: fromX, y: fromY }, { x: toX, y: toY }, readButton(input.mouse_button ?? input.mouseButton));
|
||||
return getAppState(sessionId, app);
|
||||
}
|
||||
case 'scroll': {
|
||||
case 'scroll':
|
||||
case 'scroll_element': {
|
||||
const app = readString(input.app);
|
||||
const helperState = await withHelperState(sessionId, (adapter) => adapter.scrollElement({ ...input, sessionId, app }));
|
||||
if (helperState) {
|
||||
|
||||
@@ -8,8 +8,10 @@ using System.Windows.Automation;
|
||||
|
||||
static class Program
|
||||
{
|
||||
private const int MaxStoredStates = 100;
|
||||
private static readonly Dictionary<string, List<ElementRecord>> StateElements = new();
|
||||
private static readonly Dictionary<string, Dictionary<string, AutomationElement>> StateAutomationElements = new();
|
||||
private static readonly Queue<string> StateOrder = new();
|
||||
|
||||
public static void Main()
|
||||
{
|
||||
@@ -121,6 +123,8 @@ static class Program
|
||||
var stateId = $"state_{Guid.NewGuid()}";
|
||||
StateElements[stateId] = records;
|
||||
StateAutomationElements[stateId] = automationElements;
|
||||
StateOrder.Enqueue(stateId);
|
||||
PruneStoredStates();
|
||||
|
||||
var elements = records.Select(record => record.ToDictionary()).ToList();
|
||||
var bounds = root.Current.BoundingRectangle;
|
||||
@@ -258,11 +262,21 @@ static class Program
|
||||
}
|
||||
SetCursorPos(point.Value.X, point.Value.Y);
|
||||
var wheel = (int)Math.Round(Math.Max(1, pages) * 120);
|
||||
if (direction == "up") wheel = -wheel;
|
||||
if (direction == "down") wheel = -wheel;
|
||||
mouse_event(0x0800, 0, 0, unchecked((uint)wheel), UIntPtr.Zero);
|
||||
return GetAppState(parameters);
|
||||
}
|
||||
|
||||
private static void PruneStoredStates()
|
||||
{
|
||||
while (StateOrder.Count > MaxStoredStates)
|
||||
{
|
||||
var evicted = StateOrder.Dequeue();
|
||||
StateElements.Remove(evicted);
|
||||
StateAutomationElements.Remove(evicted);
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, object?> Drag(JsonElement parameters)
|
||||
{
|
||||
var fromX = ReadDouble(parameters, "from_x", double.NaN);
|
||||
|
||||
@@ -43,7 +43,8 @@ export class SemanticSessionStore {
|
||||
this.expire();
|
||||
if (stateId) {
|
||||
const entry = this.states.get(stateId);
|
||||
return entry && entry.sessionId === sessionId ? entry.state : null;
|
||||
const appKey = normalizeAppKey(app);
|
||||
return entry && entry.sessionId === sessionId && entry.appKey === appKey ? entry.state : null;
|
||||
}
|
||||
const latestStateId = this.latestBySessionApp.get(this.latestKey(sessionId, normalizeAppKey(app)));
|
||||
return latestStateId ? this.states.get(latestStateId)?.state || null : null;
|
||||
@@ -70,7 +71,10 @@ export class SemanticSessionStore {
|
||||
for (const [stateId, entry] of this.states.entries()) {
|
||||
if (now - entry.updatedAt > ttl) {
|
||||
this.states.delete(stateId);
|
||||
this.latestBySessionApp.delete(this.latestKey(entry.sessionId, entry.appKey));
|
||||
const key = this.latestKey(entry.sessionId, entry.appKey);
|
||||
if (this.latestBySessionApp.get(key) === stateId) {
|
||||
this.latestBySessionApp.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export const semanticMcpToolMap: Record<string, string> = {
|
||||
computer_app_drag: 'drag',
|
||||
computer_click_element: 'click',
|
||||
computer_click_element: 'click_element',
|
||||
computer_get_app_state: 'get_app_state',
|
||||
computer_list_apps: 'list_apps',
|
||||
computer_perform_secondary_action: 'perform_secondary_action',
|
||||
computer_press_key: 'press_key',
|
||||
computer_scroll_element: 'scroll',
|
||||
computer_scroll_element: 'scroll_element',
|
||||
computer_set_value: 'set_value',
|
||||
computer_type_text: 'type_text',
|
||||
};
|
||||
|
||||
@@ -121,27 +121,43 @@ function MainContent({
|
||||
|
||||
const loadComputerUseSettings = useCallback(async () => {
|
||||
try {
|
||||
const [settingsResponse, statusResponse] = await Promise.all([
|
||||
const [settingsResponse, statusResponse] = await Promise.allSettled([
|
||||
authenticatedFetch('/api/computer-use/settings'),
|
||||
authenticatedFetch('/api/computer-use/status'),
|
||||
]);
|
||||
const settingsData = await settingsResponse.json();
|
||||
const statusData = await statusResponse.json();
|
||||
const settingsRes = settingsResponse.status === 'fulfilled' ? settingsResponse.value : null;
|
||||
const statusRes = statusResponse.status === 'fulfilled' ? statusResponse.value : null;
|
||||
const readJson = async (response: Response | null) => {
|
||||
if (!response) return null;
|
||||
try {
|
||||
return await response.json();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
const settingsData = await readJson(settingsRes);
|
||||
const statusData = await readJson(statusRes);
|
||||
const runtime = statusData?.data?.runtime;
|
||||
const settingsUsable = Boolean(settingsRes?.ok && settingsData?.success !== false);
|
||||
const statusUsable = Boolean(statusRes?.ok && statusData?.success !== false);
|
||||
const settingsEnabled = Boolean(
|
||||
settingsResponse.ok &&
|
||||
settingsData?.success !== false &&
|
||||
settingsUsable &&
|
||||
settingsData?.data?.settings?.enabled
|
||||
);
|
||||
const cloudEnabled = Boolean(
|
||||
statusResponse.ok &&
|
||||
statusData?.success !== false &&
|
||||
statusUsable &&
|
||||
runtime === 'cloud' &&
|
||||
statusData?.data?.enabled
|
||||
);
|
||||
setComputerUseEnabled(runtime === 'cloud' ? cloudEnabled : settingsEnabled);
|
||||
if (runtime === 'cloud') {
|
||||
setComputerUseEnabled(cloudEnabled);
|
||||
} else if (settingsUsable) {
|
||||
setComputerUseEnabled(settingsEnabled);
|
||||
} else if (statusUsable) {
|
||||
setComputerUseEnabled(Boolean(statusData?.data?.enabled));
|
||||
}
|
||||
} catch {
|
||||
setComputerUseEnabled(false);
|
||||
// Keep the current tab availability on transient status/settings failures.
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user