@songsid/agend 2.3.4-beta.7 → 2.3.5-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/README.zh-TW.md +2 -0
- package/THIRD_PARTY_NOTICES.md +53 -0
- package/dist/agent-endpoint.d.ts +5 -1
- package/dist/agent-endpoint.js +12 -2
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/auth-api.d.ts +21 -0
- package/dist/auth-api.js +89 -2
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/web-authority.d.ts +12 -2
- package/dist/authority/web-authority.js +25 -4
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/claude-code.d.ts +15 -12
- package/dist/backend/claude-code.js +152 -133
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-package.d.ts +5 -2
- package/dist/backend/codex-package.js +1 -5
- package/dist/backend/codex-package.js.map +1 -1
- package/dist/backend/codex.d.ts +136 -113
- package/dist/backend/codex.js +1281 -1219
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok-model-cache.d.ts +7 -0
- package/dist/backend/grok-model-cache.js +65 -0
- package/dist/backend/grok-model-cache.js.map +1 -0
- package/dist/backend/grok.d.ts +2 -0
- package/dist/backend/grok.js +22 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/native-pane.d.ts +9 -0
- package/dist/backend/native-pane.js +59 -0
- package/dist/backend/native-pane.js.map +1 -0
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/ipc-bridge.d.ts +2 -0
- package/dist/channel/mcp-tools.js +1 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/cli.js +3 -0
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +71 -1
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +16 -0
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +67 -5
- package/dist/daemon.js +823 -266
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-consumed-watch.d.ts +15 -3
- package/dist/delivery-consumed-watch.js +23 -1
- package/dist/delivery-consumed-watch.js.map +1 -1
- package/dist/delivery-outbox.d.ts +5 -0
- package/dist/delivery-outbox.js +32 -4
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +2 -35
- package/dist/delivery-reconciliation.js +2 -156
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/fleet-context.d.ts +2 -2
- package/dist/fleet-level-config.d.ts +1 -1
- package/dist/fleet-level-config.js +2 -0
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +238 -3
- package/dist/fleet-manager.js +1826 -104
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-windows-runtime.d.ts +92 -0
- package/dist/fleet-windows-runtime.js +380 -0
- package/dist/fleet-windows-runtime.js.map +1 -0
- package/dist/general-binding.d.ts +85 -0
- package/dist/general-binding.js +298 -0
- package/dist/general-binding.js.map +1 -0
- package/dist/general-host-owner.d.ts +8 -0
- package/dist/general-host-owner.js +26 -0
- package/dist/general-host-owner.js.map +1 -0
- package/dist/general-instance.d.ts +7 -0
- package/dist/general-instance.js +20 -3
- package/dist/general-instance.js.map +1 -1
- package/dist/general-role.d.ts +5 -0
- package/dist/general-role.js +26 -0
- package/dist/general-role.js.map +1 -0
- package/dist/instance-config-impact.js +4 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +21 -3
- package/dist/instance-lifecycle.js +378 -162
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +2 -0
- package/dist/instructions.js +6 -0
- package/dist/instructions.js.map +1 -1
- package/dist/local-pane-endpoint.d.ts +46 -0
- package/dist/local-pane-endpoint.js +189 -0
- package/dist/local-pane-endpoint.js.map +1 -0
- package/dist/local-pane-launcher.d.ts +2 -0
- package/dist/local-pane-launcher.js +38 -0
- package/dist/local-pane-launcher.js.map +1 -0
- package/dist/local-pane-stage.ps1 +101 -0
- package/dist/locale.js +85 -0
- package/dist/locale.js.map +1 -1
- package/dist/model-catalog-defaults.d.ts +14 -0
- package/dist/model-catalog-defaults.js +20 -0
- package/dist/model-catalog-defaults.js.map +1 -0
- package/dist/native-agent-admission.d.ts +7 -0
- package/dist/native-agent-admission.js +26 -0
- package/dist/native-agent-admission.js.map +1 -0
- package/dist/native-daemon-client.d.ts +13 -0
- package/dist/native-daemon-client.js +28 -0
- package/dist/native-daemon-client.js.map +1 -0
- package/dist/native-instance-api.d.ts +14 -0
- package/dist/native-instance-api.js +205 -0
- package/dist/native-instance-api.js.map +1 -0
- package/dist/native-instance-input.d.ts +84 -0
- package/dist/native-instance-input.js +54 -0
- package/dist/native-instance-input.js.map +1 -0
- package/dist/native-instance-registry.d.ts +32 -0
- package/dist/native-instance-registry.js +105 -0
- package/dist/native-instance-registry.js.map +1 -0
- package/dist/native-mcp.d.ts +40 -0
- package/dist/native-mcp.js +278 -0
- package/dist/native-mcp.js.map +1 -0
- package/dist/native-model-catalog.d.ts +5 -0
- package/dist/native-model-catalog.js +76 -0
- package/dist/native-model-catalog.js.map +1 -0
- package/dist/native-pane-crash-budget.d.ts +20 -0
- package/dist/native-pane-crash-budget.js +60 -0
- package/dist/native-pane-crash-budget.js.map +1 -0
- package/dist/native-pane-create.d.ts +26 -0
- package/dist/native-pane-create.js +53 -0
- package/dist/native-pane-create.js.map +1 -0
- package/dist/native-pane-lifecycle.d.ts +65 -0
- package/dist/native-pane-lifecycle.js +230 -0
- package/dist/native-pane-lifecycle.js.map +1 -0
- package/dist/native-pane-manager.d.ts +59 -0
- package/dist/native-pane-manager.js +584 -0
- package/dist/native-pane-manager.js.map +1 -0
- package/dist/native-pane-output-log.d.ts +15 -0
- package/dist/native-pane-output-log.js +108 -0
- package/dist/native-pane-output-log.js.map +1 -0
- package/dist/native-pane-reconciliation.d.ts +4 -0
- package/dist/native-pane-reconciliation.js +40 -0
- package/dist/native-pane-reconciliation.js.map +1 -0
- package/dist/native-pane-recovery.d.ts +12 -0
- package/dist/native-pane-recovery.js +10 -0
- package/dist/native-pane-recovery.js.map +1 -0
- package/dist/native-pane-tools.d.ts +2 -0
- package/dist/native-pane-tools.js +14 -0
- package/dist/native-pane-tools.js.map +1 -0
- package/dist/needs-you-hub.d.ts +2 -0
- package/dist/needs-you-hub.js +2 -1
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +19 -1
- package/dist/needs-you.js +12 -2
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +16 -2
- package/dist/outbound-handlers.js +67 -3
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +38 -0
- package/dist/outbound-schemas.js +12 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/pane-port.d.ts +118 -0
- package/dist/pane-port.js +2 -0
- package/dist/pane-port.js.map +1 -0
- package/dist/public-web-gateway.js +9 -0
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +5 -0
- package/dist/public-web-link.js +4 -0
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart-api.js +9 -5
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +1 -0
- package/dist/quickstart.js +4 -1
- package/dist/quickstart.js.map +1 -1
- package/dist/runtime-api.d.ts +8 -0
- package/dist/runtime-api.js +96 -0
- package/dist/runtime-api.js.map +1 -0
- package/dist/runtime-assets/@xterm/addon-serialize/LICENSE +21 -0
- package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.js +2 -0
- package/dist/runtime-assets/@xterm/addon-serialize/lib/addon-serialize.mjs +19 -0
- package/dist/runtime-assets/@xterm/addon-serialize/package.json +29 -0
- package/dist/runtime-assets/@xterm/headless/LICENSE +21 -0
- package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.js +2 -0
- package/dist/runtime-assets/@xterm/headless/lib-headless/xterm-headless.mjs +46 -0
- package/dist/runtime-assets/@xterm/headless/package.json +29 -0
- package/dist/runtime-assets/node-pty/CONPTY-LICENSE +21 -0
- package/dist/runtime-assets/node-pty/CONPTY-NOTICE.md +503 -0
- package/dist/runtime-assets/node-pty/LICENSE +69 -0
- package/dist/runtime-assets/node-pty/lib/conpty_console_list_agent.js +16 -0
- package/dist/runtime-assets/node-pty/lib/eventEmitter2.js +47 -0
- package/dist/runtime-assets/node-pty/lib/index.js +52 -0
- package/dist/runtime-assets/node-pty/lib/interfaces.js +7 -0
- package/dist/runtime-assets/node-pty/lib/shared/conout.js +11 -0
- package/dist/runtime-assets/node-pty/lib/terminal.js +190 -0
- package/dist/runtime-assets/node-pty/lib/types.js +7 -0
- package/dist/runtime-assets/node-pty/lib/unixTerminal.js +346 -0
- package/dist/runtime-assets/node-pty/lib/utils.js +39 -0
- package/dist/runtime-assets/node-pty/lib/windowsConoutConnection.js +125 -0
- package/dist/runtime-assets/node-pty/lib/windowsPtyAgent.js +320 -0
- package/dist/runtime-assets/node-pty/lib/windowsTerminal.js +199 -0
- package/dist/runtime-assets/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/dist/runtime-assets/node-pty/package.json +64 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/dist/runtime-assets/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/dist/runtime-bundle.d.ts +17 -0
- package/dist/runtime-bundle.js +150 -0
- package/dist/runtime-bundle.js.map +1 -0
- package/dist/runtime-cli.d.ts +2 -0
- package/dist/runtime-cli.js +117 -0
- package/dist/runtime-cli.js.map +1 -0
- package/dist/runtime-client-store.d.ts +49 -0
- package/dist/runtime-client-store.js +292 -0
- package/dist/runtime-client-store.js.map +1 -0
- package/dist/runtime-client.d.ts +100 -0
- package/dist/runtime-client.js +700 -0
- package/dist/runtime-client.js.map +1 -0
- package/dist/runtime-coordinator.d.ts +82 -0
- package/dist/runtime-coordinator.js +864 -0
- package/dist/runtime-coordinator.js.map +1 -0
- package/dist/runtime-general-protocol.d.ts +22 -0
- package/dist/runtime-general-protocol.js +57 -0
- package/dist/runtime-general-protocol.js.map +1 -0
- package/dist/runtime-general-workspace.d.ts +17 -0
- package/dist/runtime-general-workspace.js +213 -0
- package/dist/runtime-general-workspace.js.map +1 -0
- package/dist/runtime-pane-assets.d.ts +17 -0
- package/dist/runtime-pane-assets.js +23 -0
- package/dist/runtime-pane-assets.js.map +1 -0
- package/dist/runtime-pane-boot.d.ts +2 -0
- package/dist/runtime-pane-boot.js +24 -0
- package/dist/runtime-pane-boot.js.map +1 -0
- package/dist/runtime-pane-codex-index.d.ts +1 -0
- package/dist/runtime-pane-codex-index.js +47 -0
- package/dist/runtime-pane-codex-index.js.map +1 -0
- package/dist/runtime-pane-config.d.ts +16 -0
- package/dist/runtime-pane-config.js +54 -0
- package/dist/runtime-pane-config.js.map +1 -0
- package/dist/runtime-pane-host.d.ts +44 -0
- package/dist/runtime-pane-host.js +424 -0
- package/dist/runtime-pane-host.js.map +1 -0
- package/dist/runtime-pane-job-owner.d.ts +1 -0
- package/dist/runtime-pane-job-owner.js +29 -0
- package/dist/runtime-pane-job-owner.js.map +1 -0
- package/dist/runtime-pane-job.ps1 +116 -0
- package/dist/runtime-pane-link.d.ts +40 -0
- package/dist/runtime-pane-link.js +246 -0
- package/dist/runtime-pane-link.js.map +1 -0
- package/dist/runtime-pane-mcp-protocol.d.ts +32 -0
- package/dist/runtime-pane-mcp-protocol.js +39 -0
- package/dist/runtime-pane-mcp-protocol.js.map +1 -0
- package/dist/runtime-pane-mcp-relay.d.ts +17 -0
- package/dist/runtime-pane-mcp-relay.js +70 -0
- package/dist/runtime-pane-mcp-relay.js.map +1 -0
- package/dist/runtime-pane-mcp.d.ts +51 -0
- package/dist/runtime-pane-mcp.js +150 -0
- package/dist/runtime-pane-mcp.js.map +1 -0
- package/dist/runtime-pane-native.d.ts +45 -0
- package/dist/runtime-pane-native.js +65 -0
- package/dist/runtime-pane-native.js.map +1 -0
- package/dist/runtime-pane-output.d.ts +19 -0
- package/dist/runtime-pane-output.js +53 -0
- package/dist/runtime-pane-output.js.map +1 -0
- package/dist/runtime-pane-port.d.ts +139 -0
- package/dist/runtime-pane-port.js +558 -0
- package/dist/runtime-pane-port.js.map +1 -0
- package/dist/runtime-pane-private.d.ts +14 -0
- package/dist/runtime-pane-private.js +51 -0
- package/dist/runtime-pane-private.js.map +1 -0
- package/dist/runtime-pane-private.ps1 +14 -0
- package/dist/runtime-pane-process.d.ts +4 -0
- package/dist/runtime-pane-process.js +108 -0
- package/dist/runtime-pane-process.js.map +1 -0
- package/dist/runtime-pane-protocol.d.ts +172 -0
- package/dist/runtime-pane-protocol.js +195 -0
- package/dist/runtime-pane-protocol.js.map +1 -0
- package/dist/runtime-pane-screen.d.ts +19 -0
- package/dist/runtime-pane-screen.js +76 -0
- package/dist/runtime-pane-screen.js.map +1 -0
- package/dist/runtime-pane-service.d.ts +11 -0
- package/dist/runtime-pane-service.js +221 -0
- package/dist/runtime-pane-service.js.map +1 -0
- package/dist/runtime-pane-stdio-protocol.d.ts +54 -0
- package/dist/runtime-pane-stdio-protocol.js +94 -0
- package/dist/runtime-pane-stdio-protocol.js.map +1 -0
- package/dist/runtime-pane-stdio.d.ts +3 -0
- package/dist/runtime-pane-stdio.js +123 -0
- package/dist/runtime-pane-stdio.js.map +1 -0
- package/dist/runtime-pane-store.d.ts +33 -0
- package/dist/runtime-pane-store.js +164 -0
- package/dist/runtime-pane-store.js.map +1 -0
- package/dist/runtime-pane-transcript-protocol.d.ts +43 -0
- package/dist/runtime-pane-transcript-protocol.js +58 -0
- package/dist/runtime-pane-transcript-protocol.js.map +1 -0
- package/dist/runtime-pane-transcript.d.ts +45 -0
- package/dist/runtime-pane-transcript.js +605 -0
- package/dist/runtime-pane-transcript.js.map +1 -0
- package/dist/runtime-pane-worker.d.ts +1 -0
- package/dist/runtime-pane-worker.js +154 -0
- package/dist/runtime-pane-worker.js.map +1 -0
- package/dist/runtime-protocol.d.ts +149 -0
- package/dist/runtime-protocol.js +19 -0
- package/dist/runtime-protocol.js.map +1 -0
- package/dist/runtime-switches.d.ts +79 -0
- package/dist/runtime-switches.js +90 -0
- package/dist/runtime-switches.js.map +1 -0
- package/dist/runtime-transcript-delta-reader.d.ts +23 -0
- package/dist/runtime-transcript-delta-reader.js +74 -0
- package/dist/runtime-transcript-delta-reader.js.map +1 -0
- package/dist/runtime-transcript-source.d.ts +36 -0
- package/dist/runtime-transcript-source.js +189 -0
- package/dist/runtime-transcript-source.js.map +1 -0
- package/dist/runtime-windows-bridge.d.ts +41 -0
- package/dist/runtime-windows-bridge.js +157 -0
- package/dist/runtime-windows-bridge.js.map +1 -0
- package/dist/settings-api.d.ts +5 -0
- package/dist/settings-api.js +95 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-baseline.d.ts +1 -0
- package/dist/settings-baseline.js +1 -1
- package/dist/settings-baseline.js.map +1 -1
- package/dist/settings-change.js +28 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +16 -1
- package/dist/settings-confirmation.js +47 -9
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-effect.d.ts +4 -0
- package/dist/settings-effect.js +58 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +1 -0
- package/dist/settings-http-confirmation.js +15 -2
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/settings-request-capability.d.ts +2 -0
- package/dist/settings-request-capability.js +4 -0
- package/dist/settings-request-capability.js.map +1 -1
- package/dist/settings-route-lifetime.d.ts +14 -0
- package/dist/settings-route-lifetime.js +48 -0
- package/dist/settings-route-lifetime.js.map +1 -0
- package/dist/settings-transaction.d.ts +4 -0
- package/dist/settings-transaction.js +9 -0
- package/dist/settings-transaction.js.map +1 -1
- package/dist/setup-form.js +6 -3
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-i18n.js +3 -0
- package/dist/setup-i18n.js.map +1 -1
- package/dist/tmux-control.d.ts +2 -1
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-manager.d.ts +2 -1
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-pane-host.d.ts +26 -0
- package/dist/tmux-pane-host.js +25 -0
- package/dist/tmux-pane-host.js.map +1 -0
- package/dist/tool-permissions.js +2 -1
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.js +3 -0
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-delta-reader.d.ts +1 -1
- package/dist/transcript-delta-reader.js +1 -1
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/transcript-monitor.d.ts +3 -0
- package/dist/transcript-monitor.js +22 -46
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-needles.d.ts +35 -0
- package/dist/transcript-needles.js +158 -0
- package/dist/transcript-needles.js.map +1 -0
- package/dist/transcript-records.d.ts +21 -0
- package/dist/transcript-records.js +140 -0
- package/dist/transcript-records.js.map +1 -0
- package/dist/transcript-sources.d.ts +5 -0
- package/dist/transcript-sources.js +8 -79
- package/dist/transcript-sources.js.map +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/ui/agent-proposals.js +90 -0
- package/dist/ui/agent-runtime.js +106 -0
- package/dist/ui/chat-store.js +13 -2
- package/dist/ui/chat-strings.js +48 -0
- package/dist/ui/cli-picker.js +42 -0
- package/dist/ui/general-location.js +71 -0
- package/dist/ui/native-instance-settings.js +47 -0
- package/dist/ui/native-pane-recovery.js +45 -0
- package/dist/ui/panel-chat.js +63 -32
- package/dist/ui/panel-details.js +2 -1
- package/dist/ui/panel-fleet.js +99 -18
- package/dist/ui/panel-needs.js +154 -3
- package/dist/ui/panel-runtimes.js +231 -0
- package/dist/ui/panel-settings.js +19 -9
- package/dist/ui/panel-windows-agent.js +86 -0
- package/dist/ui/panel-windows-cli.js +143 -0
- package/dist/ui/provider-marks.js +83 -0
- package/dist/ui/runtime-catalog.js +55 -0
- package/dist/ui/settings-catalog.js +37 -10
- package/dist/ui/settings-confirm.js +3 -1
- package/dist/ui/settings-dialogs.js +22 -7
- package/dist/ui/settings-model.js +2 -1
- package/dist/ui/settings-outside.js +176 -0
- package/dist/ui/settings-registry.js +6 -0
- package/dist/ui/settings-strings.js +16 -0
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-route.js +6 -2
- package/dist/ui/shared/app-shell.js +3 -2
- package/dist/ui/shared/app-store.js +1 -0
- package/dist/ui/shared/app-stream.js +3 -1
- package/dist/ui/shared/app.css +301 -0
- package/dist/ui/shared/app.js +4 -0
- package/dist/ui/shared/header-tools.js +6 -4
- package/dist/ui/shared/instance-nav.js +33 -7
- package/dist/ui/shared/instance-switch.js +4 -3
- package/dist/ui/shared/qrcode.module.js +2237 -0
- package/dist/ui/shared/signin.js +39 -5
- package/dist/ui/shared/ui-menu.js +28 -8
- package/dist/ui/shared/vendor/qrcode-generator.LICENSE +27 -0
- package/dist/ui/shared/vendor/vendor.json +19 -2
- package/dist/ui/shared/view-strings.js +8 -0
- package/dist/ui/windows-agents-nav.js +2 -0
- package/dist/ui/windows-cli-catalog.js +79 -0
- package/dist/web-api.d.ts +37 -0
- package/dist/web-api.js +248 -6
- package/dist/web-api.js.map +1 -1
- package/dist/web-chat-history.d.ts +19 -2
- package/dist/web-chat-history.js +72 -3
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-only-fleet.d.ts +20 -0
- package/dist/web-only-fleet.js +21 -0
- package/dist/web-only-fleet.js.map +1 -1
- package/dist/web-remote-access.d.ts +152 -0
- package/dist/web-remote-access.js +368 -0
- package/dist/web-remote-access.js.map +1 -0
- package/dist/web-session.d.ts +7 -0
- package/dist/web-session.js +2 -0
- package/dist/web-session.js.map +1 -1
- package/dist/web-shell-routes.d.ts +4 -1
- package/dist/web-shell-routes.js +7 -2
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/windows-agents.d.ts +124 -0
- package/dist/windows-agents.js +487 -0
- package/dist/windows-agents.js.map +1 -0
- package/dist/windows-cli-api.d.ts +23 -0
- package/dist/windows-cli-api.js +158 -0
- package/dist/windows-cli-api.js.map +1 -0
- package/dist/windows-cli-providers.d.ts +115 -0
- package/dist/windows-cli-providers.js +429 -0
- package/dist/windows-cli-providers.js.map +1 -0
- package/dist/windows-cli-worker.d.ts +58 -0
- package/dist/windows-cli-worker.js +479 -0
- package/dist/windows-cli-worker.js.map +1 -0
- package/dist/windows-cli.d.ts +115 -0
- package/dist/windows-cli.js +402 -0
- package/dist/windows-cli.js.map +1 -0
- package/dist/windows-native-mcp.d.ts +19 -0
- package/dist/windows-native-mcp.js +143 -0
- package/dist/windows-native-mcp.js.map +1 -0
- package/dist/windows-pane-mcp.d.ts +26 -0
- package/dist/windows-pane-mcp.js +187 -0
- package/dist/windows-pane-mcp.js.map +1 -0
- package/package.json +9 -3
- package/templates/runtime-assets/conpty-LICENSE +21 -0
- package/templates/runtime-assets/conpty-NOTICE.md +503 -0
- package/templates/runtime-assets/local-pane-stage.ps1 +101 -0
- package/templates/runtime-assets/runtime-pane-job.ps1 +116 -0
- package/templates/runtime-assets/runtime-pane-private.ps1 +14 -0
- package/templates/runtime-assets/xterm-LICENSE +21 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { html, useEffect, useRef, useState } from "/assets/app-html.js";
|
|
2
|
+
import { register, t } from "/assets/app-i18n.js";
|
|
3
|
+
import { useLease } from "/assets/app-ctx.js";
|
|
4
|
+
import { Icon } from "/assets/ui-icons.js";
|
|
5
|
+
import { appStore, useStore } from "/assets/app-store.js";
|
|
6
|
+
import { confirmDialog } from "/assets/ui-confirm.js";
|
|
7
|
+
import { confirmedWrite } from "./settings-confirm.js";
|
|
8
|
+
import { CliProductMark, cliLabel } from "./cli-picker.js";
|
|
9
|
+
import { WindowsCliPanel } from "./panel-windows-cli.js";
|
|
10
|
+
import { useRuntimeCatalog } from "./runtime-catalog.js";
|
|
11
|
+
|
|
12
|
+
register("machines", {
|
|
13
|
+
en: {
|
|
14
|
+
title:"Runtime", lead:"Connect computers to run agents with each computer's own CLIs, sign-ins and files.",
|
|
15
|
+
connect:"Connect a computer", download:"Download Windows Runtime (ZIP)", downloadHint:"Download here, then transfer the ZIP to the Windows computer and extract it. Windows Node.js is required.", refresh:"Refresh machines", loading:"Loading machines…", empty:"No remote computers connected yet.",
|
|
16
|
+
disabled:"Other Windows PCs can connect once “Allow other Windows PCs to pair” is on.", local:"This computer", localHint:"WSL / Linux agents run on the AgEnD host. Native Windows diagnostics are below when enabled.",
|
|
17
|
+
localWindows:"Local Windows CLI diagnostics", online:"Online", offline:"Offline", pending:"Awaiting approval", revoked:"Revoked", unknown:"Not reported",
|
|
18
|
+
lastSeen:"Last seen: {0}", inventoryAt:"CLI inventory: {0}", noInventory:"CLI inventory has not been reported yet.", noClis:"No installed CLIs reported.",
|
|
19
|
+
approve:"Approve computer", revoke:"Revoke connection", rename:"Rename", save:"Save name", cancel:"Cancel", name:"Computer name", probe:"Refresh CLI inventory",
|
|
20
|
+
fingerprint:"Pairing fingerprint", fingerprintLabel:"Pairing fingerprint: ", approvalHint:"Compare this fingerprint with the one shown in the requesting Runtime before approving.", identity:"Computer identity", signedIn:"Signed in", signedOut:"Not signed in", authUnknown:"Sign-in unknown", detectionOnly:"Detection only", ready:"Tasks supported",
|
|
21
|
+
pairing:"Connect a computer", pairingHint:"On the other computer, extract this version's portable Runtime bundle and run the command below from its folder. Paste the one-time code when asked, then approve the computer here. Keep that runtime window open.",
|
|
22
|
+
pairingCode:"One-time pairing code", expires:"Expires: {0}", command:"Run on the other computer", pairingWait:"Waiting for the computer to request approval. This page updates automatically.",
|
|
23
|
+
server:"AgEnD address", serverHint:"Use an address reachable from the other computer. A localhost address works only with a connection forwarded on that computer.", serverInvalid:"Enter an HTTPS origin, or a localhost HTTP origin with a forwarded connection. Leave out paths, credentials and query strings.", closeCode:"Hide pairing code", revokeAsk:"Revoke this computer's connection? New work will be refused. A task already running may need to be stopped on that computer.",
|
|
24
|
+
failed:"Could not update Runtime", cliFailed:"CLI refresh failed; the last reported inventory is still shown.", retry:"Retry", seenCached:"Showing the last successfully loaded machine list.",
|
|
25
|
+
machines:"Connected computers", cli:"CLI", version:"Runtime version", platform:"Platform",
|
|
26
|
+
switches:"What this fleet may use", switchesNote:"Turning one on asks a fleet admin to confirm, like other access settings. Turning one off needs no fleet admin; it applies as soon as you confirm here.",
|
|
27
|
+
windowsCli:"Use this PC's Windows CLIs", windowsCliHelp:"Agents can run the CLIs installed on Windows on this PC, such as Codex or Claude Code, with your Windows sign-ins. Windows Node.js is required.",
|
|
28
|
+
remoteRuntime:"Allow other Windows PCs to pair", remoteRuntimeHelp:"This computer stays your fleet. Another Windows PC runs only a small runner, not a fleet; once you approve it here, agents can use that PC's CLIs and files. That PC must reach this fleet at an HTTPS address, as the guide below explains.",
|
|
29
|
+
remoteRuntimeDocs:"Full guide", setByEnv:"Set by the environment ({0}={1}). To change it, remove it from AgEnD's environment and restart AgEnD.",
|
|
30
|
+
switchPending:"Waiting for a fleet admin to confirm. It turns on once they do.", switchFailed:"Could not change this setting: {0}", switchesUnavailable:"These switches can be changed only on this fleet's own dashboard.",
|
|
31
|
+
windowsCliOffAsk:"Turn off this PC's Windows CLIs? A Windows agent turn in progress on this PC stops, and these agents stay stopped until you turn it on again.",
|
|
32
|
+
remoteRuntimeOffAsk:"Stop accepting other Windows PCs? Paired PCs disconnect now and their agents stay stopped until you turn it on again. Approved PCs are kept.",
|
|
33
|
+
limit:"Agents at once on each Windows PC", limitHelp:"Each Windows PC, this one or a paired one, runs at most this many agents at the same time ({0}–{1}, default {2}). This limit applies to persistent terminal agents. Per-message execution keeps its existing admission limit.", limitSave:"Save", limitSaved:"Saved.",
|
|
34
|
+
guide:"How another PC connects", guideAddress:"1. Give this fleet an HTTPS address the other PC can reach. Recommended: Tailscale Serve, run on this computer (on Windows, if AgEnD runs in WSL). Then use the https://….ts.net address it prints:",
|
|
35
|
+
guideSsh:"Or: an SSH tunnel, opened on the other PC (replace user@this-computer with your SSH sign-in for this computer). Then use http://localhost:{0}:", guideFunnel:"Never use Tailscale Funnel: it puts this fleet on the internet.",
|
|
36
|
+
guideLan:"A plain http:// address on your network (such as http://192.168.1.20) is refused: it would send the pairing code unencrypted.",
|
|
37
|
+
guidePair:"2. Click Connect a computer, download the Runtime ZIP, and run the command it shows on the other PC.", guideApprove:"3. When that PC asks to join, approve it here.",
|
|
38
|
+
turnOff:"Turn off",
|
|
39
|
+
},
|
|
40
|
+
"zh-TW": {
|
|
41
|
+
title:"Runtime", lead:"連接電腦,讓 Agent 使用各台電腦上的 CLI、登入與檔案。",
|
|
42
|
+
connect:"連接電腦", download:"下載 Windows Runtime(ZIP)", downloadHint:"下載後,將 ZIP 傳到要執行 CLI 的 Windows 電腦並解壓縮。需要 Windows Node.js。", refresh:"更新機器清單", loading:"正在載入機器…", empty:"尚未連接其他電腦。",
|
|
43
|
+
disabled:"開啟「允許其他 Windows 電腦配對」後,其他 Windows 電腦才能連接。", local:"這台電腦", localHint:"WSL / Linux Agent 在 AgEnD 主機上執行。啟用後可在下方查看本機 Windows 診斷。",
|
|
44
|
+
localWindows:"本機 Windows CLI 診斷", online:"在線", offline:"離線", pending:"等待核准", revoked:"已撤銷", unknown:"尚未回報",
|
|
45
|
+
lastSeen:"最近連線:{0}", inventoryAt:"CLI 清單更新:{0}", noInventory:"尚未回報 CLI 清單。", noClis:"尚未回報已安裝的 CLI。",
|
|
46
|
+
approve:"核准電腦", revoke:"撤銷連線", rename:"重新命名", save:"儲存名稱", cancel:"取消", name:"電腦名稱", probe:"更新 CLI 清單",
|
|
47
|
+
fingerprint:"配對指紋", fingerprintLabel:"配對指紋:", approvalHint:"核准前,請比對提出要求的 Runtime 視窗所顯示的配對指紋。", identity:"電腦識別碼", signedIn:"已登入", signedOut:"尚未登入", authUnknown:"登入狀態未知", detectionOnly:"僅偵測", ready:"支援派工",
|
|
48
|
+
pairing:"連接電腦", pairingHint:"在另一台電腦解壓縮此版本的可攜式 Runtime 套件,從其資料夾執行下方指令,在提示時貼上一次性配對碼,再回到這裡核准電腦。請保持 Runtime 視窗開啟。",
|
|
49
|
+
pairingCode:"一次性配對碼", expires:"到期時間:{0}", command:"在另一台電腦執行", pairingWait:"正在等待電腦提出核准要求。此頁會自動更新。",
|
|
50
|
+
server:"AgEnD 位址", serverHint:"請使用另一台電腦連得到的位址。localhost 只有在另一台電腦已建立連線轉發時才適用。", serverInvalid:"請填入 HTTPS 來源位址,或已轉發連線的 localhost HTTP 位址,不包含路徑、帳密或查詢參數。", closeCode:"隱藏配對碼", revokeAsk:"要撤銷這台電腦的連線嗎?新的派工會被拒絕;已在執行的任務可能需要在該電腦上停止。",
|
|
51
|
+
failed:"無法更新 Runtime", cliFailed:"CLI 更新失敗,目前仍顯示上次回報的清單。", retry:"重試", seenCached:"目前顯示上次成功載入的機器清單。",
|
|
52
|
+
machines:"已連接的電腦", cli:"CLI", version:"Runtime 版本", platform:"平台",
|
|
53
|
+
switches:"這個 Fleet 可以使用", switchesNote:"開啟時,和其他存取設定一樣需要 Fleet 管理員確認;關閉不需 Fleet 管理員確認,你在這裡確認後就會立即生效。",
|
|
54
|
+
windowsCli:"使用這台電腦 Windows 上的 CLI", windowsCliHelp:"Agent 可以使用這台電腦 Windows 上安裝的 CLI(例如 Codex 或 Claude Code),沿用你在 Windows 的登入。需要 Windows Node.js。",
|
|
55
|
+
remoteRuntime:"允許其他 Windows 電腦配對", remoteRuntimeHelp:"這台電腦仍是你的 Fleet。另一台 Windows 電腦只執行一個小 runner,不是 Fleet;你在這裡核准後,Agent 就能使用那台電腦的 CLI 與檔案。那台電腦必須能用 HTTPS 位址連到這個 Fleet,做法見下方說明。",
|
|
56
|
+
remoteRuntimeDocs:"完整說明", setByEnv:"由環境變數設定({0}={1})。若要變更,請從 AgEnD 的環境移除它並重新啟動 AgEnD。",
|
|
57
|
+
switchPending:"等待 Fleet 管理員確認,確認後就會開啟。", switchFailed:"無法變更此設定:{0}", switchesUnavailable:"這些開關只能在這個 Fleet 自己的儀表板上變更。",
|
|
58
|
+
windowsCliOffAsk:"要關閉這台電腦的 Windows CLI 嗎?這台電腦上進行中的 Windows Agent 回合會停止,這些 Agent 會保持停止,直到你再次開啟。",
|
|
59
|
+
remoteRuntimeOffAsk:"要停止接受其他 Windows 電腦嗎?已配對的電腦會立即中斷連線,它們的 Agent 會保持停止,直到你再次開啟。已核准的電腦會保留。",
|
|
60
|
+
limit:"每台 Windows 電腦同時執行的 Agent 數", limitHelp:"每台 Windows 電腦(這台或已配對的電腦)最多同時執行這麼多個 Agent({0}–{1},預設 {2})。此限制適用於持續執行的終端 Agent。每則訊息各自執行的模式維持原本的執行數限制。", limitSave:"儲存", limitSaved:"已儲存。",
|
|
61
|
+
guide:"另一台電腦如何連線", guideAddress:"1. 讓另一台電腦能用 HTTPS 位址連到這個 Fleet。建議在這台電腦上執行 Tailscale Serve(若 AgEnD 在 WSL 中執行,請在 Windows 上執行),再使用它顯示的 https://….ts.net 位址:",
|
|
62
|
+
guideSsh:"或:在另一台電腦上開啟 SSH 通道(把 user@this-computer 換成你登入這台電腦的 SSH 帳號),再使用 http://localhost:{0}:", guideFunnel:"請勿使用 Tailscale Funnel:它會把這個 Fleet 公開到網際網路。",
|
|
63
|
+
guideLan:"網路上的一般 http:// 位址(例如 http://192.168.1.20)會被拒絕:配對碼會以未加密的方式傳送。",
|
|
64
|
+
guidePair:"2. 按「連接電腦」,下載 Runtime ZIP,在另一台電腦執行頁面顯示的指令。", guideApprove:"3. 那台電腦要求加入時,在這裡核准它。",
|
|
65
|
+
turnOff:"關閉此功能",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
export const machineText = (key,...values) => t(`machines.${key}`,...values);
|
|
69
|
+
/** Only an origin composed of inert hostname/port characters is placed in a copyable shell command. */
|
|
70
|
+
export function runtimeConnectCommand(server) {
|
|
71
|
+
try {
|
|
72
|
+
const url = new URL(server);
|
|
73
|
+
const local = ["localhost","127.0.0.1","[::1]"].includes(url.hostname);
|
|
74
|
+
if (!/^([a-z0-9.-]+|\[[a-f0-9:]+\])$/i.test(url.hostname) || url.username || url.password || url.search || url.hash || url.pathname !== "/"
|
|
75
|
+
|| !(url.protocol === "https:" || url.protocol === "http:" && local)) return "";
|
|
76
|
+
return `.\\agend-runtime.cmd connect --server "${url.origin}"`;
|
|
77
|
+
} catch { return ""; }
|
|
78
|
+
}
|
|
79
|
+
export function machineTime(value) { const date=new Date(value); return value && Number.isFinite(date.getTime()) ? date.toLocaleString() : machineText("unknown"); }
|
|
80
|
+
function MachineCard({ machine, busy, action }) {
|
|
81
|
+
const [editing,setEditing] = useState(false), [name,setName] = useState(machine.name);
|
|
82
|
+
const clis = (machine.inventory?.clis || []).filter(cli => cli.path);
|
|
83
|
+
return html`<article class="runtime-machine" data-machine-id=${machine.id}>
|
|
84
|
+
<header><span class="runtime-machine-icon"><${Icon} name="view" size=${22} /></span><div><h3>${machine.name}</h3><p>${[machine.platform || machineText("unknown"), machine.hostname, machine.version].filter(Boolean).join(" · ")}</p></div><span class=${`runtime-status is-${machine.status}`}>${machineText(["online","offline","pending","revoked"].includes(machine.status) ? machine.status : "unknown")}</span></header>
|
|
85
|
+
<p class="note">${machineText("lastSeen",machineTime(machine.lastSeenAt))}</p><p class="note">${machine.inventoryUpdatedAt ? machineText("inventoryAt",machineTime(machine.inventoryUpdatedAt)) : machineText("noInventory")}</p>
|
|
86
|
+
<details><summary>${machineText("identity")}</summary><code class="runtime-machine-id">${machine.id}</code></details>
|
|
87
|
+
${machine.status === "pending" ? html`<div><p>${machineText("fingerprintLabel")}<code class="runtime-pairing-fingerprint">${machine.pairingFingerprint || machineText("unknown")}</code></p><p class="note">${machineText("approvalHint")}</p></div>` : null}
|
|
88
|
+
<ul class="runtime-cli-list" aria-label=${machineText("cli")}>${clis.map(cli => html`<li key=${cli.id}><${CliProductMark} id=${cli.id} size=${22} /><span><strong>${cliLabel(cli.id)}</strong><small>${cli.version || "—"}</small></span><span class="note">${machineText(cli.authenticated === true ? "signedIn" : cli.authenticated === false ? "signedOut" : "authUnknown")} · ${machineText(cli.supports?.execution === false ? "detectionOnly" : "ready")}</span></li>`)}</ul>
|
|
89
|
+
${!clis.length ? html`<p class="note">${machineText("noClis")}</p>` : null}
|
|
90
|
+
${editing ? html`<form class="runtime-rename" onSubmit=${event => {event.preventDefault();if(name.trim())void action(machine,"rename",{name:name.trim()}).then(ok => {if(ok)setEditing(false);});}}><label><span>${machineText("name")}</span><input value=${name} maxLength=${100} onInput=${event => setName(event.target.value)} /></label><button class="btn btn-sm" type="submit" disabled=${busy || !name.trim()}>${machineText("save")}</button><button class="btn btn-ghost btn-sm" type="button" onClick=${() => setEditing(false)}>${machineText("cancel")}</button></form>` : null}
|
|
91
|
+
<div class="runtime-machine-actions">${machine.status === "pending" ? html`<button type="button" class="btn btn-primary btn-sm" disabled=${busy || !machine.pairingFingerprint} onClick=${() => action(machine,"approve",{fingerprint:machine.pairingFingerprint})}>${machineText("approve")}</button>` : null}${machine.status === "online" ? html`<button type="button" class="btn btn-sm" disabled=${busy} onClick=${() => action(machine,"refresh")}><${Icon} name="restart" size=${14} />${machineText("probe")}</button>` : null}${machine.status !== "revoked" ? html`<button type="button" class="btn btn-ghost btn-sm" disabled=${busy} onClick=${() => setEditing(true)}>${machineText("rename")}</button><button type="button" class="btn btn-ghost btn-sm danger" disabled=${busy} onClick=${() => action(machine,"revoke")}>${machineText("revoke")}</button>` : null}</div>
|
|
92
|
+
</article>`;
|
|
93
|
+
}
|
|
94
|
+
/** M-2255: the switches (fleet.yaml `runtimes`); `env` names the variable that overrides each. */
|
|
95
|
+
const SWITCHES = [
|
|
96
|
+
{ name: "windows_cli", id: "runtimeWindowsCli", env: "AGEND_WINDOWS_CLI", label: "windowsCli" },
|
|
97
|
+
{ name: "remote_runtime", id: "runtimeRemoteRuntime", env: "AGEND_REMOTE_RUNTIME", label: "remoteRuntime" },
|
|
98
|
+
];
|
|
99
|
+
export const RUNTIME_DOCS = "https://github.com/songsid/AgEnD/blob/main/docs/remote-runtime.md#connecting-over-a-private-network";
|
|
100
|
+
/**
|
|
101
|
+
* M-2255 (the user, hmsg-71c25c9b): "Use this PC's Windows CLIs" and "Allow other Windows computers to pair", saved in
|
|
102
|
+
* fleet.yaml like any setting: on is confirmed by a fleet admin, off applies at once (after asking here). A switch the
|
|
103
|
+
* environment sets is shown as such and cannot be changed here.
|
|
104
|
+
*/
|
|
105
|
+
function RuntimeSwitches({ lease, onChanged }) {
|
|
106
|
+
const [view,setView]=useState(null), [busy,setBusy]=useState(""), [pending,setPending]=useState(""), [error,setError]=useState(""), [unavailable,setUnavailable]=useState(false);
|
|
107
|
+
const [limit,setLimit]=useState(""), [limitNote,setLimitNote]=useState("");
|
|
108
|
+
// A number being typed is the person's: a reload (a switch's answer) never replaces it; a save of it does.
|
|
109
|
+
const limitEdited=useRef(false);
|
|
110
|
+
const switches=view?.switches;
|
|
111
|
+
const load=async() => {
|
|
112
|
+
const response=await lease.fetch("/api/settings/runtimes",{credentials:"same-origin"});
|
|
113
|
+
if (!lease.current()) return;
|
|
114
|
+
if (response.status === 403) { setUnavailable(true); return; }
|
|
115
|
+
const value=await response.json().catch(() => ({}));
|
|
116
|
+
if (!response.ok || !value.switches) throw new Error(value.error || `HTTP ${response.status}`);
|
|
117
|
+
if (!lease.current()) return;
|
|
118
|
+
setView(value);
|
|
119
|
+
if (!limitEdited.current) setLimit(String(value.max_agents_per_machine?.value ?? ""));
|
|
120
|
+
};
|
|
121
|
+
useEffect(() => { load().catch(e => { if (lease.current()) setError(machineText("switchFailed", e.message)); }); }, [lease]);
|
|
122
|
+
const change=async(item,on) => {
|
|
123
|
+
if (busy) return;
|
|
124
|
+
if (!on && !await confirmDialog({message:machineText(`${item.label}OffAsk`),confirmLabel:machineText("turnOff"),danger:true})) return;
|
|
125
|
+
if (!lease.current()) return;
|
|
126
|
+
setBusy(item.name);setError("");
|
|
127
|
+
try {
|
|
128
|
+
const res=await confirmedWrite("/api/settings/fleet/runtimes",{method:"PUT",body:{[item.name]:on},label:machineText(item.label),onPending:() => { if (lease.current()) setPending(item.name); }});
|
|
129
|
+
if (!lease.current()) return;
|
|
130
|
+
if (!res.ok) setError(machineText("switchFailed",(res.body && res.body.error) || String(res.status)));
|
|
131
|
+
await load();
|
|
132
|
+
if (lease.current()) onChanged?.();
|
|
133
|
+
} catch (e) { if (lease.current()) setError(machineText("switchFailed",e.message)); }
|
|
134
|
+
finally { if (lease.current()) { setBusy("");setPending(""); } }
|
|
135
|
+
};
|
|
136
|
+
const bounds=view?.max_agents_per_machine;
|
|
137
|
+
const limitValue=Number(limit), limitValid=!!bounds && Number.isInteger(limitValue) && limitValue >= bounds.min && limitValue <= bounds.max;
|
|
138
|
+
const saveLimit=async(event) => {
|
|
139
|
+
event.preventDefault();
|
|
140
|
+
if (busy || !limitValid || limitValue === bounds.value) return;
|
|
141
|
+
setBusy("limit");setError("");setLimitNote("");
|
|
142
|
+
try {
|
|
143
|
+
const res=await confirmedWrite("/api/settings/fleet/runtimes",{method:"PUT",body:{max_agents_per_machine:limitValue},label:machineText("limit")});
|
|
144
|
+
if (!lease.current()) return;
|
|
145
|
+
if (res.ok) { limitEdited.current=false; setLimitNote(machineText("limitSaved")); } else setError(machineText("switchFailed",(res.body && res.body.error) || String(res.status)));
|
|
146
|
+
await load();
|
|
147
|
+
} catch (e) { if (lease.current()) setError(machineText("switchFailed",e.message)); }
|
|
148
|
+
finally { if (lease.current()) setBusy(""); }
|
|
149
|
+
};
|
|
150
|
+
const origin=view?.local_origin || "http://127.0.0.1:19280", port=(() => { try { return new URL(origin).port || "80"; } catch { return "19280"; } })();
|
|
151
|
+
// Commands, not words: the same in every language (built here, never translated).
|
|
152
|
+
const serveCommand=`tailscale serve --https=443 ${origin}`, sshCommand=`ssh -N -L 127.0.0.1:${port}:127.0.0.1:${port} user@this-computer`;
|
|
153
|
+
const guide=html`<details class="runtime-guide" open=${switches?.remote_runtime?.on === true}>
|
|
154
|
+
<summary>${machineText("guide")}</summary>
|
|
155
|
+
<p>${machineText("guideAddress")}</p><pre><code>${serveCommand}</code></pre>
|
|
156
|
+
<p>${machineText("guideSsh",port)}</p><pre><code>${sshCommand}</code></pre>
|
|
157
|
+
<p class="runtime-guide-warn">${machineText("guideFunnel")}</p><p class="runtime-guide-warn">${machineText("guideLan")}</p>
|
|
158
|
+
<p>${machineText("guidePair")}</p><p>${machineText("guideApprove")}</p>
|
|
159
|
+
<a class="runtime-guide-link" href=${RUNTIME_DOCS} target="_blank" rel="noopener noreferrer">${machineText("remoteRuntimeDocs")}<${Icon} name="external" size=${14} /></a>
|
|
160
|
+
</details>`;
|
|
161
|
+
if (unavailable) return html`<section class="runtime-switches" aria-label=${machineText("switches")}><h3>${machineText("switches")}</h3><p class="note">${machineText("switchesUnavailable")}</p></section>`;
|
|
162
|
+
return html`<section class="runtime-switches" aria-label=${machineText("switches")}>
|
|
163
|
+
<h3>${machineText("switches")}</h3>
|
|
164
|
+
${SWITCHES.map(item => {
|
|
165
|
+
const state=switches?.[item.name];
|
|
166
|
+
return html`<div key=${item.name} class="runtime-switch" data-switch=${item.name}>
|
|
167
|
+
<label class="runtime-switch-row" for=${item.id}>
|
|
168
|
+
<input id=${item.id} type="checkbox" role="switch" checked=${state?.on === true} aria-describedby=${`${item.id}Help`}
|
|
169
|
+
disabled=${!state || !!state.environment || !!busy} onChange=${e => { const want=e.target.checked; e.target.checked=!want; void change(item,want); }} />
|
|
170
|
+
<span><strong>${machineText(item.label)}</strong><small id=${`${item.id}Help`}>${machineText(`${item.label}Help`)}</small></span>
|
|
171
|
+
</label>
|
|
172
|
+
${pending === item.name ? html`<p class="note runtime-switch-pending" role="status">${machineText("switchPending")}</p>` : null}
|
|
173
|
+
${state?.environment ? html`<p class="note runtime-switch-env">${machineText("setByEnv",item.env,state.environment === "on" ? "1" : "0")}</p>` : null}
|
|
174
|
+
${item.name === "remote_runtime" ? guide : null}
|
|
175
|
+
</div>`;
|
|
176
|
+
})}
|
|
177
|
+
<form class="runtime-limit" onSubmit=${saveLimit}>
|
|
178
|
+
<label for="runtimeMaxAgents"><strong>${machineText("limit")}</strong><small id="runtimeMaxAgentsHelp">${bounds ? machineText("limitHelp",bounds.min,bounds.max,bounds.default) : ""}</small></label>
|
|
179
|
+
<div><input id="runtimeMaxAgents" type="number" inputMode="numeric" min=${bounds?.min ?? 1} max=${bounds?.max ?? 16} step="1" value=${limit} aria-describedby="runtimeMaxAgentsHelp"
|
|
180
|
+
disabled=${!bounds || !!busy} onInput=${e => { limitEdited.current=true; setLimit(e.target.value); setLimitNote(""); }} />
|
|
181
|
+
<button type="submit" class="btn btn-sm" disabled=${!limitValid || limitValue === bounds?.value || !!busy}>${machineText("limitSave")}</button>
|
|
182
|
+
${limitNote ? html`<span class="note" role="status">${limitNote}</span>` : null}</div>
|
|
183
|
+
</form>
|
|
184
|
+
<p class="note">${machineText("switchesNote")}</p>
|
|
185
|
+
${error ? html`<p class="runtime-error" role="alert">${error}</p>` : null}
|
|
186
|
+
</section>`;
|
|
187
|
+
}
|
|
188
|
+
export function RuntimesPanel({navKey}) {
|
|
189
|
+
const lease=useLease(`runtimes:${navKey}`), state=useRuntimeCatalog(), {windowsCli}=useStore(appStore);
|
|
190
|
+
const [pairing,setPairing]=useState(null), [busy,setBusy]=useState(""), [error,setError]=useState("");
|
|
191
|
+
const [server,setServer]=useState(() => typeof location === "undefined" ? "" : location.origin);
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
if (!pairing) return;
|
|
194
|
+
const remaining = new Date(pairing.expiresAt).getTime()-Date.now();
|
|
195
|
+
if (!Number.isFinite(remaining) || remaining <= 0) {setPairing(null);return;}
|
|
196
|
+
const timer=lease.timeout(() => setPairing(null),remaining);
|
|
197
|
+
return () => lease.clear(timer);
|
|
198
|
+
},[lease,pairing]);
|
|
199
|
+
const post=async(path,body={}) => {
|
|
200
|
+
const response=await lease.fetch(path,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)});
|
|
201
|
+
const value=await response.json();
|
|
202
|
+
if (!response.ok) throw new Error(value.error || `HTTP ${response.status}`);
|
|
203
|
+
return value;
|
|
204
|
+
};
|
|
205
|
+
const connect=async() => {
|
|
206
|
+
setBusy("pairing");setError("");
|
|
207
|
+
try {const value=await post("/ui/runtimes/pairing");if(lease.current())setPairing(value);}catch(e){if(lease.current())setError(e.message);}finally{if(lease.current())setBusy("");}
|
|
208
|
+
};
|
|
209
|
+
const action=async(machine,operation,body={}) => {
|
|
210
|
+
if(operation === "revoke" && !await confirmDialog({message:machineText("revokeAsk"),confirmLabel:machineText("revoke"),danger:true}))return false;
|
|
211
|
+
if(!lease.current())return false;
|
|
212
|
+
setBusy(machine.id);setError("");
|
|
213
|
+
try {await post(`/ui/runtimes/machines/${encodeURIComponent(machine.id)}/${operation}`,body);if(!lease.current())return false;await state.refresh();return lease.current();}
|
|
214
|
+
catch(e){if(lease.current())setError(operation === "refresh" ? `${machineText("cliFailed")} ${e.message}` : e.message);return false;}
|
|
215
|
+
finally{if(lease.current())setBusy("");}
|
|
216
|
+
};
|
|
217
|
+
const machines=state.data?.machines || [];
|
|
218
|
+
const command=runtimeConnectCommand(server);
|
|
219
|
+
const download=()=>html`<a class="btn btn-sm runtime-bundle-download" href="/ui/runtimes/download/windows" download><${Icon} name="download" size=${15} />${machineText("download")}</a>`;
|
|
220
|
+
return html`<section class="runtime-settings">
|
|
221
|
+
<header class="runtime-heading"><div><h2>${machineText("title")}</h2><p class="note">${machineText("lead")}</p></div><div>${state.data?.enabled === true && !pairing ? download() : null}<button type="button" class="btn btn-sm" disabled=${state.loading} onClick=${state.refresh}><${Icon} name="restart" size=${15} />${machineText("refresh")}</button><button type="button" class="btn btn-primary btn-sm" disabled=${!!busy || state.data?.enabled !== true} onClick=${connect}><${Icon} name="plus" size=${15} />${machineText("connect")}</button></div></header>
|
|
222
|
+
<${RuntimeSwitches} lease=${lease} onChanged=${state.refresh} />
|
|
223
|
+
${state.data?.enabled === false ? html`<p class="note">${machineText("disabled")}</p>` : null}
|
|
224
|
+
${state.loading && !state.data ? html`<p role="status" aria-busy="true"><span class="out-spin" aria-hidden="true"></span> ${machineText("loading")}</p>` : null}
|
|
225
|
+
${error || state.error ? html`<div class="runtime-error" role="alert"><p>${error || state.error}</p>${state.data && state.error ? html`<p>${machineText("seenCached")}</p>` : null}<button type="button" class="btn btn-sm" onClick=${state.refresh}>${machineText("retry")}</button></div>` : null}
|
|
226
|
+
${pairing ? html`<section class="runtime-pairing" aria-label=${machineText("pairing")}><h3>${machineText("pairing")}</h3><p>${machineText("pairingHint")}</p><div class="runtime-bundle-step">${download()}<p class="note">${machineText("downloadHint")}</p></div><label><span>${machineText("server")}</span><input type="url" value=${server} spellcheck=${false} onInput=${event => setServer(event.target.value)} /></label><p class="note">${machineText("serverHint")}</p>${command ? html`<label><span>${machineText("command")}</span><input class="runtime-command" value=${command} readOnly=${true} spellcheck=${false} /></label>` : html`<p role="alert">${machineText("serverInvalid")}</p>`}<label><span>${machineText("pairingCode")}</span><input class="runtime-pair-code" value=${pairing.code} readOnly=${true} spellcheck=${false} autocomplete="off" /></label><p class="note">${machineText("expires",machineTime(pairing.expiresAt))}</p><p role="status">${machineText("pairingWait")}</p><button type="button" class="btn btn-ghost btn-sm" onClick=${() => setPairing(null)}>${machineText("closeCode")}</button></section>` : null}
|
|
227
|
+
<article class="runtime-local"><h3><${Icon} name="code" size=${18} />${machineText("local")}</h3><p class="note">${machineText("localHint")}</p></article>
|
|
228
|
+
<section aria-label=${machineText("machines")}>${machines.map(machine => html`<${MachineCard} key=${machine.id} machine=${machine} busy=${!!busy} action=${action} />`)}${state.data && !machines.length ? html`<p class="note">${machineText("empty")}</p>` : null}</section>
|
|
229
|
+
${windowsCli ? html`<details class="runtime-local-diagnostics"><summary>${machineText("localWindows")}</summary><${WindowsCliPanel} navKey=${`${navKey}:local`} embedded=${true} /></details>` : null}
|
|
230
|
+
</section>`;
|
|
231
|
+
}
|
|
@@ -39,6 +39,8 @@ import {
|
|
|
39
39
|
} from "./settings-dialogs.js";
|
|
40
40
|
import { SetupWizard } from "./settings-wizard.js";
|
|
41
41
|
import { CreateInstanceDialog } from "./panel-fleet.js";
|
|
42
|
+
import { RuntimesPanel } from "./panel-runtimes.js";
|
|
43
|
+
import { NativeInstanceSettings } from "./native-instance-settings.js";
|
|
42
44
|
import { FirstRunCard, takeWizardRequest } from "./first-run.js";
|
|
43
45
|
import { takeAgentRequest } from "./settings-request.js";
|
|
44
46
|
// #1604: This device — the preview opt-in (one path: the app's confirm, then preview.js) and the tour, from the chat.
|
|
@@ -51,8 +53,10 @@ import { OfficeSharesCard } from "./office-share-dialog.js";
|
|
|
51
53
|
import { PageSharesCard } from "./page-share-dialog.js";
|
|
52
54
|
import { syncStage, useDraft } from "./settings-draft.js";
|
|
53
55
|
import { WebAuthorityCard } from "./settings-web-authority.js";
|
|
56
|
+
import { OutsideCard } from "./settings-outside.js";
|
|
54
57
|
import { NamedLinkTest, setTypedTunnelToken } from "./settings-named-test.js";
|
|
55
58
|
import { SignInList } from "./backend-signin.js";
|
|
59
|
+
import { GeneralLocation } from "./general-location.js";
|
|
56
60
|
|
|
57
61
|
const tn = (k, ...v) => t(`settings.${k}`, ...v);
|
|
58
62
|
/** What a refused change says to a person: the server's code in words (the code itself only for one not listed). */
|
|
@@ -60,7 +64,7 @@ const APPLY_ERRORS = new Set(["unsupported_sensitive_effect", "confirmation_diff
|
|
|
60
64
|
"request_no_longer_current", "too_many_pending_changes", "fleet_unavailable", "invalid_settings_effect", "settings_confirmation_unavailable", "failed"]);
|
|
61
65
|
// #2726: a code or words of the setup host (the wizard's commit) in the page's language; anything else as it came.
|
|
62
66
|
export const applyErrorText = (code) => (APPLY_ERRORS.has(code) ? tn(`applyError_${code}`) : tn("applyErrorOther", hostText(String(code), lang())));
|
|
63
|
-
const ICONS = { preferences: "user", look: "palette", agents: "bot", "agent-defaults": "sliders", chat: "chat", "web-dashboard": "globe", access: "key", advanced: "code" };
|
|
67
|
+
const ICONS = { preferences: "user", look: "palette", agents: "bot", runtimes: "view", "agent-defaults": "sliders", chat: "chat", "web-dashboard": "globe", access: "key", advanced: "code" };
|
|
64
68
|
const RELEASES = "https://github.com/songsid/AgEnD/releases";
|
|
65
69
|
|
|
66
70
|
/** GET under the panel's lease → { ok, status, body }. */
|
|
@@ -103,7 +107,7 @@ async function loadLive(lease) {
|
|
|
103
107
|
if (!lease.current()) return null;
|
|
104
108
|
const live = {}, classicLive = {};
|
|
105
109
|
if (f.ok && f.body && Array.isArray(f.body.instances)) for (const i of f.body.instances) {
|
|
106
|
-
live[i.name] = { status: i.status, state: i.state, backend: i.backend, model: i.model, model_display: modelText(i, i.model_display), effort: i.effort, effort_supported: i.effort_supported };
|
|
110
|
+
live[i.name] = { status: i.status, state: i.state, backend: i.backend, model: i.model, model_display: modelText(i, i.model_display), effort: i.effort, effort_supported: i.effort_supported, runtime:i.runtime, capabilities:i.capabilities };
|
|
107
111
|
if (i.classic) classicLive[i.name] = { status: i.status, state: i.state };
|
|
108
112
|
}
|
|
109
113
|
// /api/fleet carries live state for ClassicBot rooms; the profiles are the fallback for one not listed there yet.
|
|
@@ -379,10 +383,11 @@ export function SettingsPanel({ route, navKey }) {
|
|
|
379
383
|
// defaults, Web) is one form with one draft, shown a part at a time.
|
|
380
384
|
const sectionBody = section === "preferences" ? html`<${DeviceSection} key=${you.key} /><${AppearanceSection} ...${you} part="device" />`
|
|
381
385
|
: section === "look" ? html`<${AppearanceSection} ...${you} part="look" />`
|
|
386
|
+
: section === "runtimes" ? html`<${RuntimesPanel} navKey=${navKey} />`
|
|
382
387
|
: !data ? html`<${Skeleton} lines=${6} />`
|
|
383
388
|
: data.error ? html`<${ErrorState} message=${tn("configLoadFailed")} onRetry=${reload} />`
|
|
384
389
|
: section === "agents" ? html`<${YamlLock} staged=${staged}><${Agents} ctx=${ctx} search=${search} openDialog=${toDialog} /></${YamlLock}>${ctx.providerOk ? html`<${ProviderKeys} ctx=${ctx} />` : null}`
|
|
385
|
-
: section === "agent-defaults" ? html`<${YamlLock} staged=${staged}><${General} key=${formKey} ctx=${ctx} part="fleet" /></${YamlLock}>`
|
|
390
|
+
: section === "agent-defaults" ? html`<${GeneralLocation} /><${YamlLock} staged=${staged}><${General} key=${formKey} ctx=${ctx} part="fleet" /></${YamlLock}>`
|
|
386
391
|
: section === "chat" ? html`<${YamlLock} staged=${staged}><${Bots} ctx=${ctx} search=${search} openDialog=${toDialog} /></${YamlLock}>
|
|
387
392
|
<${WebSection} key=${formKey} ctx=${ctx} staged=${staged} part="chat" />
|
|
388
393
|
<div id="classicbot" class="s-anchor"><h2 class="s-ap-group">ClassicBot</h2><${Classic} ctx=${ctx} search=${search} openDialog=${toDialog} />
|
|
@@ -667,7 +672,7 @@ const opBusy = (op) => !!op && (["writing", "posting", "watching"].includes(op.p
|
|
|
667
672
|
function dropSecrets(staged) { for (const c of staged.values()) if (c.connectionSecret) c.connectionSecret.secret = ""; }
|
|
668
673
|
|
|
669
674
|
function renderDialog(d, ctx, close) {
|
|
670
|
-
if (d.kind === "agent") return html`<${AgentDialog} name=${d.name} inst=${d.inst} ctx=${ctx} onClose=${close} />`;
|
|
675
|
+
if (d.kind === "agent") return d.inst.runtime === "windows" ? html`<${NativeInstanceSettings} name=${d.name} inst=${d.inst} ctx=${ctx} onClose=${close} />` : html`<${AgentDialog} name=${d.name} inst=${d.inst} ctx=${ctx} onClose=${close} />`;
|
|
671
676
|
if (d.kind === "bot") return html`<${BotDialog} key=${d.id} id=${d.id} ctx=${ctx} onClose=${close} />`;
|
|
672
677
|
if (d.kind === "newBot") return html`<${NewBotDialog} ctx=${ctx} onClose=${close} />`;
|
|
673
678
|
if (d.kind === "classic") return html`<${ClassicDialog} room=${d.room} ctx=${ctx} onClose=${close} />`;
|
|
@@ -701,16 +706,17 @@ function makeCtx(data, setData, stage, unstage, reload, reloadLive, alive, extra
|
|
|
701
706
|
});
|
|
702
707
|
stage(`agent:${name}`, {
|
|
703
708
|
label: tn("updateAgent", shortName(name, { ...inst, ...patch })),
|
|
704
|
-
impact: batchImpact(schema, Object.keys(patch), (k) => impactOf(schema, `instance.${k}`)),
|
|
705
|
-
request: { method: "PATCH", url: `/api/settings/fleet/instances/${encodeURIComponent(name)}`, body: patch },
|
|
709
|
+
impact: inst.runtime === "windows" ? "now" : batchImpact(schema, Object.keys(patch), (k) => impactOf(schema, `instance.${k}`)),
|
|
710
|
+
request: { method: "PATCH", url: inst.runtime === "windows" ? `/ui/instances/${encodeURIComponent(name)}` : `/api/settings/fleet/instances/${encodeURIComponent(name)}`, body: patch },
|
|
706
711
|
});
|
|
707
712
|
},
|
|
708
713
|
async deleteAgent(name) {
|
|
709
714
|
if (!(await ask(tn("deleteAgent", name), { confirmLabel: tn("deleteAgentMenu"), danger: true }))) return;
|
|
710
715
|
if (!alive()) return; // the panel went while it asked: nothing staged, nothing said
|
|
716
|
+
const native = fleet.instances?.[name]?.runtime === "windows";
|
|
711
717
|
edit((d) => { delete d.fleet.instances[name]; });
|
|
712
|
-
stage(`agent:${name}`, { label: tn("deleteAgentLabel", name), impact: impactOf(schema, "instance.delete"),
|
|
713
|
-
request: { method: "DELETE", url: `/api/settings/fleet/instances/${encodeURIComponent(name)}` } });
|
|
718
|
+
stage(`agent:${name}`, { label: tn("deleteAgentLabel", name), impact: native ? "now" : impactOf(schema, "instance.delete"),
|
|
719
|
+
request: { method: "DELETE", url: native ? `/ui/instances/${encodeURIComponent(name)}` : `/api/settings/fleet/instances/${encodeURIComponent(name)}` } });
|
|
714
720
|
},
|
|
715
721
|
stageChannels(key, nextChannels, meta) {
|
|
716
722
|
edit((d) => { d.fleet.channels = nextChannels; delete d.fleet.channel; });
|
|
@@ -791,12 +797,14 @@ function Agents({ ctx, search, openDialog }) {
|
|
|
791
797
|
return html`<div key=${name} class="s-row">
|
|
792
798
|
<span class=${dotClass(st)} title=${tn(STATUS_KEY[st] || "stStopped")} aria-hidden="true"></span>
|
|
793
799
|
<span class="s-name" title=${name}>${shortName(name, inst)}</span>
|
|
800
|
+
${inst.runtime === "windows" ? html`<span class="tag">Windows</span>` : null}
|
|
794
801
|
<span class="s-meta" title=${sum.backend}>${sum.model}</span>
|
|
795
802
|
<span class="s-br" aria-hidden="true"></span>
|
|
796
|
-
|
|
803
|
+
${inst.runtime !== "windows" || ctx.live[name]?.capabilities?.effort === true ? html`<span class="tag">${tn("effortTag", sum.effort)}</span>` : null}
|
|
797
804
|
${ch ? html`<span class=${`tag${ch.includes("persona") ? " persona" : ""}`}>${ch}</span>` : null}
|
|
798
805
|
<span class="sr-only">${tn(STATUS_KEY[st] || "stStopped")}</span>
|
|
799
806
|
<span class="s-actions">
|
|
807
|
+
${inst.runtime === "windows" ? html`<a class="btn btn-sm" href=${chatPath(name)}>${t("app.chat")}</a>` : null}
|
|
800
808
|
<button type="button" class="btn btn-sm" disabled=${working} onClick=${() => openDialog({ kind: "agent", name, inst })}>${tn("settingsButton")}</button>
|
|
801
809
|
${st === "running" ? html`<button type="button" class="btn btn-sm" disabled=${working} onClick=${() => run(name, "pause", () => ctx.pauseWake(name, "pause"))}>${label("pause", tn("pause"))}</button>` : null}
|
|
802
810
|
${st === "paused" ? html`<button type="button" class="btn btn-sm" disabled=${working} onClick=${() => run(name, "wake", () => ctx.pauseWake(name, "wake"))}>${label("wake", tn("wake"))}</button>` : null}
|
|
@@ -1371,6 +1379,8 @@ function WebSection({ ctx, staged, part = "all" }) {
|
|
|
1371
1379
|
${has("access") ? html`<${OfficeSharesCard} />` : null}
|
|
1372
1380
|
${has("access") ? html`<${PageSharesCard} />` : null}
|
|
1373
1381
|
${has("access") && !overPublicLink ? html`<${GuestsCard} ctx=${ctx} staged=${staged} /><${WebAuthorityCard} ctx=${ctx} staged=${staged} />` : null}
|
|
1382
|
+
${/* #3008: a web-only fleet's connections from outside — changed on this computer only, shown (read-only) elsewhere. */ ""}
|
|
1383
|
+
${has("access") ? html`<${OutsideCard} />` : null}
|
|
1374
1384
|
${has("chat") ? lock(html`<section class="card"><h3>${tn("webChat")}</h3>
|
|
1375
1385
|
<label class=${fc("check", "echo")}><input id="webEchoToChannel" type="checkbox" checked=${f.echo} onChange=${(e) => set("echo")(e.target.checked)} /><span>${tn("webEcho")}</span><${Impact} schema=${schema} field="web.echo_to_channel" /></label>
|
|
1376
1386
|
<p class="note">${tn("webEchoHint")}</p>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { html, useEffect, useRef, useState } from "/assets/app-html.js";
|
|
2
|
+
import { register, t } from "/assets/app-i18n.js";
|
|
3
|
+
import { useLease } from "/assets/app-ctx.js";
|
|
4
|
+
import { PanelHeader, setTitle } from "/assets/app-shell.js";
|
|
5
|
+
import { Icon } from "/assets/ui-icons.js";
|
|
6
|
+
import { CliProductMark, cliLabel } from "./cli-picker.js";
|
|
7
|
+
import { appStore, useStore } from "/assets/app-store.js";
|
|
8
|
+
import { navigate } from "/assets/app-nav.js";
|
|
9
|
+
import { chatPath } from "/assets/app-route.js";
|
|
10
|
+
|
|
11
|
+
register("winagent", {
|
|
12
|
+
"zh-TW": { loading:"正在載入 Windows Agent…", send:"傳送", message:"傳送任務給 Windows Agent", empty:"開始與 Windows Agent 對話", emptyHint:"對話使用 Windows 本機 Codex,後續訊息會接續同一個對話。", settings:"Windows CLI 設定", waiting:"Windows Codex 正在處理…", cancel:"取消任務", you:"你", refresh:"更新", read:"唯讀", write:"工作目錄可寫入", limit:"每次執行最多五分鐘後請求取消,同時一個 Windows 任務。", uncertain:"提交結果不明,請先更新確認,避免重複派工。", blocked:"上次執行的結束狀態不明。請先檢查 Windows 程序是否已停止。", recover:"已確認程序停止,解除鎖定" },
|
|
13
|
+
en: { loading:"Loading Windows agent…", send:"Send", message:"Send a task to the Windows agent", empty:"Start a Windows conversation", emptyHint:"Runs native Windows Codex. Follow-up messages continue the same conversation.", settings:"Windows CLI settings", waiting:"Windows Codex is working…", cancel:"Cancel task", you:"You", refresh:"Refresh", read:"Read only", write:"Workspace write", limit:"Cancellation after five minutes per turn; one Windows task at a time.", uncertain:"Submission outcome is unknown. Refresh before sending again.", blocked:"The last execution outcome is unknown. Check that its Windows processes have stopped.", recover:"Processes stopped — unlock agent" },
|
|
14
|
+
});
|
|
15
|
+
const tn = key => t(`winagent.${key}`);
|
|
16
|
+
register("winagent", {
|
|
17
|
+
"zh-TW": { emptyHint:"使用所選 Windows 本機 CLI,後續訊息會接續同一個對話。", waiting:"Windows CLI 正在處理…", write:"使用本機 CLI 權限" },
|
|
18
|
+
en: { emptyHint:"Runs the selected native Windows CLI. Follow-up messages continue the same conversation.", waiting:"Windows CLI is working…", write:"Native CLI permissions" },
|
|
19
|
+
});
|
|
20
|
+
register("winagent", {
|
|
21
|
+
"zh-TW": { starting:"準備啟動", running:"執行中", cancelling:"正在取消", completed:"已完成", failed:"失敗", cancelled:"已取消", interrupted:"已中斷", noOutput:"這次執行沒有文字輸出。" },
|
|
22
|
+
en: { starting:"Starting", running:"Running", cancelling:"Cancelling", completed:"Completed", failed:"Failed", cancelled:"Cancelled", interrupted:"Interrupted", noOutput:"This turn returned no text." },
|
|
23
|
+
});
|
|
24
|
+
export function WindowsAgentPanel({ route, navKey }) {
|
|
25
|
+
const lease = useLease(navKey);
|
|
26
|
+
const { instances = [] } = useStore(appStore);
|
|
27
|
+
const canonical = route.panel === "windows-agent" ? instances.find(instance => instance.runtime === "windows" && instance.native_agent_id === route.instance)?.name : route.instance;
|
|
28
|
+
useEffect(() => { if (route.panel === "windows-agent" && canonical) navigate(chatPath(canonical),{replace:true}); },[canonical,route.panel]);
|
|
29
|
+
const [data,setData] = useState(null), [prompt,setPrompt] = useState(""), [error,setError] = useState("");
|
|
30
|
+
const [submitting,setSubmitting] = useState(false);
|
|
31
|
+
const request = useRef(null), polling = useRef(false), generation = useRef(0);
|
|
32
|
+
const api = async (path, body) => {
|
|
33
|
+
const r = await lease.fetch(path,{credentials:"same-origin",...(body === undefined ? {} : {method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)})});
|
|
34
|
+
const value = await r.json();
|
|
35
|
+
if (!r.ok) { const e = new Error(value.error || `HTTP ${r.status}`); e.rejected = true; throw e; }
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
38
|
+
const common = route.panel === "chat";
|
|
39
|
+
const root = common ? `/ui/instances/${encodeURIComponent(route.instance)}` : `/ui/windows-cli/agents/${route.instance}`;
|
|
40
|
+
const refresh = async () => {
|
|
41
|
+
const mine = ++generation.current;
|
|
42
|
+
try {
|
|
43
|
+
const value = await api(root);
|
|
44
|
+
if (!lease.current() || mine !== generation.current) return;
|
|
45
|
+
setData({...value.agent,_route:route.instance}); setTitle(`${value.agent.name} · Windows`);
|
|
46
|
+
if (request.current && value.agent.turns.some(turn => turn.id === request.current.id)) { request.current = null; setSubmitting(false); setPrompt(""); }
|
|
47
|
+
} catch(e) { if (lease.current()) setError(e.message); }
|
|
48
|
+
};
|
|
49
|
+
useEffect(() => { request.current = null; setSubmitting(false); setPrompt(""); setError(""); void refresh(); },[lease]);
|
|
50
|
+
const agent = data?._route === route.instance ? data : null;
|
|
51
|
+
const { sandbox: fileAccess } = agent || {};
|
|
52
|
+
const busy = !!agent?.activeId;
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!busy || agent?.blocked) return;
|
|
55
|
+
const timer = lease.interval(async () => { if (polling.current) return; polling.current = true; try { await refresh(); } finally { polling.current = false; } },1000);
|
|
56
|
+
return () => lease.clear(timer);
|
|
57
|
+
},[lease,busy,agent?.blocked]);
|
|
58
|
+
const send = async e => {
|
|
59
|
+
e.preventDefault();
|
|
60
|
+
if (!agent || busy || submitting || request.current || !prompt.trim()) return;
|
|
61
|
+
const message = request.current = { id:crypto.randomUUID(), prompt };
|
|
62
|
+
setSubmitting(true); setError("");
|
|
63
|
+
try { await api(`${root}/messages`,{requestId:message.id,prompt:message.prompt}); }
|
|
64
|
+
catch(e) {
|
|
65
|
+
if (!lease.current()) return;
|
|
66
|
+
setError(e.rejected ? e.message : tn("uncertain"));
|
|
67
|
+
if (e.rejected) { request.current = null; setSubmitting(false); }
|
|
68
|
+
}
|
|
69
|
+
if (lease.current()) await refresh();
|
|
70
|
+
};
|
|
71
|
+
const cancel = async () => { try { await api(common ? `${root}/cancel` : `/ui/windows-cli/tasks/${agent.activeId}/cancel`,{}); if (lease.current()) await refresh(); } catch(e) { if (lease.current()) setError(e.message); } };
|
|
72
|
+
const recover = async () => { try { await api(`${root}/recover`,{confirmedStopped:true}); if (lease.current()) await refresh(); } catch(e) { if (lease.current()) setError(e.message); } };
|
|
73
|
+
return html`<div class="panel p-windows-agent"><${PanelHeader} title=${agent?.name || "Windows Agent"}>
|
|
74
|
+
<a class="btn btn-ghost btn-sm" href="/settings/agents"><${Icon} name="settings" size=${16} />${t("app.settings")}</a>
|
|
75
|
+
</${PanelHeader}>
|
|
76
|
+
<div class="panel-body"><div class="col windows-agent-conversation">
|
|
77
|
+
${agent ? html`<div class="windows-agent-identity"><span class="windows-cli-brand"><${CliProductMark} id=${agent.cli || "codex"} size=${24} /></span><div><strong>Windows · ${cliLabel(agent.cli || "codex")}${agent.model ? ` · ${agent.model}` : ""}</strong><code>${agent.cwd}</code></div><span class="pill">${tn(fileAccess === "read-only" ? "read" : "write")}</span></div>
|
|
78
|
+
${agent.description ? html`<p class="note">${agent.description}</p>` : null}
|
|
79
|
+
${!agent.turns.length ? html`<div class="windows-agent-empty"><${Icon} name="chat" size=${32} /><h2>${tn("empty")}</h2><p>${tn("emptyHint")}</p></div>` : agent.turns.map(turn => html`<article key=${turn.id} class="windows-agent-turn"><div class="windows-agent-human"><strong>${tn("you")}</strong><p>${turn.prompt}</p></div><div class="windows-agent-reply"><strong><${CliProductMark} id=${agent.cli || "codex"} size=${18} />${cliLabel(agent.cli || "codex")}</strong><pre tabIndex="0">${turn.output || tn(["starting","running","cancelling"].includes(turn.status) ? "waiting" : "noOutput")}</pre>${turn.error ? html`<p class="error">${turn.error}</p>` : null}<small>${tn(turn.status)}</small></div></article>`)}
|
|
80
|
+
` : html`<p class="note">${tn("loading")}</p>`}
|
|
81
|
+
${error ? html`<p class="error" role="alert">${error}</p>` : null}
|
|
82
|
+
${agent?.blocked ? html`<div class="windows-agent-blocked"><p>${tn("blocked")}</p><button type="button" class="btn" onClick=${recover}>${tn("recover")}</button></div>` : null}
|
|
83
|
+
</div></div>
|
|
84
|
+
<form class="windows-agent-composer" onSubmit=${send}><div class="windows-agent-input"><textarea aria-label=${tn("message")} placeholder=${tn("message")} rows="3" maxLength=${8000} value=${prompt} disabled=${!agent || busy || submitting} onInput=${e => setPrompt(e.target.value)} /><div><button type="button" class="icon-btn" aria-label=${tn("refresh")} onClick=${refresh}><${Icon} name="restart" size=${17} /></button>${busy && !agent?.blocked ? html`<button type="button" class="btn" onClick=${cancel}><${Icon} name="stop" size=${15} />${tn("cancel")}</button>` : html`<button type="submit" class="btn btn-primary" disabled=${!agent || busy || submitting || !prompt.trim()}><${Icon} name="send" size=${16} />${tn("send")}</button>`}</div></div><p class="note">${tn("limit")}</p></form>
|
|
85
|
+
</div>`;
|
|
86
|
+
}
|