@toddzheng024/dscode-desktop 0.0.0-stage → 0.7.34
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/LICENSE +21 -0
- package/README.md +120 -2
- package/THIRD_PARTY_NOTICES.md +30 -0
- package/bin/apply_patch +9 -0
- package/cordis.patch.yml +433 -0
- package/docs/CHANGELOG.md +649 -0
- package/docs/account-login.md +44 -0
- package/docs/auto-review.md +128 -0
- package/docs/browser-use.md +784 -0
- package/docs/computer-use.md +81 -0
- package/docs/custom-providers.md +88 -0
- package/docs/demo.md +158 -0
- package/docs/distribution.md +58 -0
- package/docs/dscode-ultra.md +75 -0
- package/docs/email.md +296 -0
- package/docs/exec.md +40 -0
- package/docs/hub-distribution.md +212 -0
- package/docs/memory.md +121 -0
- package/docs/opencode-go.md +61 -0
- package/docs/plugin-hub.md +68 -0
- package/docs/releases/0.2.0.md +28 -0
- package/docs/releases/0.3.0.md +21 -0
- package/docs/releases/0.4.0.md +20 -0
- package/docs/releases/0.5.0.md +19 -0
- package/docs/releases/0.6.0.md +20 -0
- package/docs/releases/0.7.0.md +22 -0
- package/docs/releases/0.7.1.md +20 -0
- package/docs/releases/0.7.10.md +10 -0
- package/docs/releases/0.7.11.md +17 -0
- package/docs/releases/0.7.12.md +11 -0
- package/docs/releases/0.7.13.md +12 -0
- package/docs/releases/0.7.14.md +11 -0
- package/docs/releases/0.7.15.md +11 -0
- package/docs/releases/0.7.16.md +10 -0
- package/docs/releases/0.7.17.md +12 -0
- package/docs/releases/0.7.18.md +13 -0
- package/docs/releases/0.7.19.md +8 -0
- package/docs/releases/0.7.2.md +19 -0
- package/docs/releases/0.7.20.md +10 -0
- package/docs/releases/0.7.21.md +9 -0
- package/docs/releases/0.7.22.md +11 -0
- package/docs/releases/0.7.23.md +14 -0
- package/docs/releases/0.7.24.md +11 -0
- package/docs/releases/0.7.25.md +8 -0
- package/docs/releases/0.7.26.md +18 -0
- package/docs/releases/0.7.27.md +8 -0
- package/docs/releases/0.7.28.md +22 -0
- package/docs/releases/0.7.29.md +12 -0
- package/docs/releases/0.7.3.md +23 -0
- package/docs/releases/0.7.30.md +19 -0
- package/docs/releases/0.7.31.md +14 -0
- package/docs/releases/0.7.32.md +14 -0
- package/docs/releases/0.7.33.md +37 -0
- package/docs/releases/0.7.34.md +24 -0
- package/docs/releases/0.7.4.md +16 -0
- package/docs/releases/0.7.5.md +18 -0
- package/docs/releases/0.7.6.md +29 -0
- package/docs/releases/0.7.7.md +36 -0
- package/docs/releases/0.7.8.md +14 -0
- package/docs/releases/0.7.9.md +15 -0
- package/docs/session-bridge.md +80 -0
- package/docs/session-cards.md +53 -0
- package/docs/session-communication.md +186 -0
- package/docs/session-metrics.md +41 -0
- package/docs/skills.md +81 -0
- package/docs/triggers.md +338 -0
- package/docs/tui-commands.md +204 -0
- package/extensions/browser/manifest.json +22 -0
- package/extensions/browser/popup.css +6 -0
- package/extensions/browser/popup.html +11 -0
- package/extensions/browser/popup.mjs +47 -0
- package/extensions/browser/protocol.mjs +168 -0
- package/extensions/browser/worker.mjs +94 -0
- package/icon.svg +7 -0
- package/locale/en.json +6 -0
- package/locale/zh-cn.json +6 -0
- package/node_modules/@deepseek-ai/node-addon-system/LICENSE +21 -0
- package/node_modules/@deepseek-ai/node-addon-system/README.i18n.yaml +6 -0
- package/node_modules/@deepseek-ai/node-addon-system/README.md +15 -0
- package/node_modules/@deepseek-ai/node-addon-system/README.zh.md +15 -0
- package/node_modules/@deepseek-ai/node-addon-system/lib/flock.d.ts +13 -0
- package/node_modules/@deepseek-ai/node-addon-system/lib/flock.js +51 -0
- package/node_modules/@deepseek-ai/node-addon-system/lib/index.d.ts +73 -0
- package/node_modules/@deepseek-ai/node-addon-system/lib/index.js +98 -0
- package/node_modules/@deepseek-ai/node-addon-system/package.json +45 -0
- package/node_modules/@deepseek-ai/node-addon-system/src/flock.c +164 -0
- package/node_modules/@deepseek-ai/node-addon-system/src/main.c +298 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/LICENSE +28 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/README.i18n.yaml +6 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/README.md +9 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/README.zh.md +9 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/bin/system.node +0 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/package.json +31 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/prebuilds.json +6 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/LICENSE +28 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/README.i18n.yaml +6 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/README.md +9 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/README.zh.md +9 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/bin/system.node +0 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/package.json +31 -0
- package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/prebuilds.json +6 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/LICENSE +28 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/README.i18n.yaml +6 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/README.md +11 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/README.zh.md +11 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/bin/glibc/system.node +0 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/bin/landlock-run +0 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/bin/musl/system.node +0 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/package.json +31 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/prebuilds.json +24 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-x64/LICENSE +28 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-x64/README.i18n.yaml +6 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-x64/README.md +11 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-x64/README.zh.md +11 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/glibc/system.node +0 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/landlock-run +0 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/musl/system.node +0 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-x64/package.json +31 -0
- package/node_modules/@deepseek-ai/node-addon-system-linux-x64/prebuilds.json +24 -0
- package/package.json +156 -4
- package/plugins/account/index.mjs +178 -0
- package/plugins/account/state.mjs +123 -0
- package/plugins/auto-review/audit.mjs +24 -0
- package/plugins/auto-review/index.mjs +267 -0
- package/plugins/auto-review/policy.mjs +92 -0
- package/plugins/browser/SKILL.md +158 -0
- package/plugins/browser/access.mjs +143 -0
- package/plugins/browser/config.mjs +60 -0
- package/plugins/browser/connection.mjs +385 -0
- package/plugins/browser/desktop-client.mjs +282 -0
- package/plugins/browser/desktop-host.mjs +74 -0
- package/plugins/browser/document-identity.mjs +57 -0
- package/plugins/browser/extension-relay.mjs +66 -0
- package/plugins/browser/files.mjs +32 -0
- package/plugins/browser/index.mjs +235 -0
- package/plugins/browser/mcp-entry.mjs +18 -0
- package/plugins/browser/mcp-tools.mjs +21 -0
- package/plugins/browser/presentation.mjs +45 -0
- package/plugins/browser/preview.mjs +77 -0
- package/plugins/browser/review.mjs +20 -0
- package/plugins/browser/screenshots.mjs +35 -0
- package/plugins/clipboard-image/clipboard-image.swift +56 -0
- package/plugins/clipboard-image/index.mjs +70 -0
- package/plugins/code-review/baseline.mjs +143 -0
- package/plugins/code-review/git.mjs +163 -0
- package/plugins/code-review/index.mjs +236 -0
- package/plugins/compaction/engine.mjs +304 -0
- package/plugins/compaction/tetris.mjs +65 -0
- package/plugins/compaction/threshold.mjs +99 -0
- package/plugins/computer-use/DESKTOP-SKILL.md +64 -0
- package/plugins/computer-use/desktop-host.mjs +75 -0
- package/plugins/computer-use/desktop-skill.mjs +28 -0
- package/plugins/computer-use/desktop-upstream.mjs +3 -0
- package/plugins/computer-use/index.mjs +37 -0
- package/plugins/cordis-config/plain.mjs +31 -0
- package/plugins/credentials/index.mjs +73 -0
- package/plugins/custom/adapter.mjs +110 -0
- package/plugins/custom/config.mjs +85 -0
- package/plugins/custom/desktop-client.mjs +150 -0
- package/plugins/custom/desktop-host.mjs +78 -0
- package/plugins/custom/images.mjs +32 -0
- package/plugins/custom/index.mjs +145 -0
- package/plugins/custom/wire.mjs +179 -0
- package/plugins/desktop/client.mjs +1041 -0
- package/plugins/desktop/index.mjs +10 -0
- package/plugins/desktop/shell-environment.mjs +9 -0
- package/plugins/desktop-workspace/hooks.mjs +29 -0
- package/plugins/desktop-workspace/index.mjs +37 -0
- package/plugins/dscode/board.mjs +260 -0
- package/plugins/dscode/child-target.mjs +11 -0
- package/plugins/dscode/control.mjs +17 -0
- package/plugins/dscode/desktop-client.mjs +55 -0
- package/plugins/dscode/desktop-host.mjs +37 -0
- package/plugins/dscode/index.mjs +270 -0
- package/plugins/email/cli.mjs +32 -0
- package/plugins/email/contacts.mjs +36 -0
- package/plugins/email/desktop-client.mjs +117 -0
- package/plugins/email/desktop-host.mjs +54 -0
- package/plugins/email/desktop-service.mjs +106 -0
- package/plugins/email/gmail-oauth.mjs +69 -0
- package/plugins/email/gmail-store.mjs +2 -0
- package/plugins/email/gmail.mjs +194 -0
- package/plugins/email/imap.mjs +136 -0
- package/plugins/email/inbox.d.mts +25 -0
- package/plugins/email/inbox.mjs +76 -0
- package/plugins/email/smtp.mjs +70 -0
- package/plugins/email/store.mjs +32 -0
- package/plugins/email-tools/index.mjs +46 -0
- package/plugins/exec/cli.mjs +64 -0
- package/plugins/exec/index.mjs +112 -0
- package/plugins/grok/adapter.mjs +114 -0
- package/plugins/grok/auth.mjs +76 -0
- package/plugins/grok/billing.mjs +147 -0
- package/plugins/grok/index.mjs +123 -0
- package/plugins/grok/models.mjs +129 -0
- package/plugins/grok/status.mjs +29 -0
- package/plugins/grok/wire.mjs +268 -0
- package/plugins/hub/catalog.mjs +82 -0
- package/plugins/hub/desktop-client.mjs +114 -0
- package/plugins/hub/desktop-host.mjs +129 -0
- package/plugins/i18n/messages.d.mts +21 -0
- package/plugins/i18n/messages.mjs +537 -0
- package/plugins/jev/approval.mjs +131 -0
- package/plugins/jev/client.mjs +74 -0
- package/plugins/jev/index.mjs +100 -0
- package/plugins/memory/content.mjs +57 -0
- package/plugins/memory/desktop-host.mjs +3 -0
- package/plugins/memory/index.mjs +168 -0
- package/plugins/memory/pipeline.mjs +79 -0
- package/plugins/memory/store.mjs +93 -0
- package/plugins/message-source/kind.mjs +20 -0
- package/plugins/opencode-go/adapter.mjs +96 -0
- package/plugins/opencode-go/command.mjs +128 -0
- package/plugins/opencode-go/index.mjs +121 -0
- package/plugins/opencode-go/models.mjs +58 -0
- package/plugins/opencode-go/oauth.mjs +194 -0
- package/plugins/opencode-go/search.mjs +86 -0
- package/plugins/opencode-go/usage.mjs +120 -0
- package/plugins/opencode-go/version.mjs +10 -0
- package/plugins/opencode-go/wire.mjs +73 -0
- package/plugins/openrouter/adapter.mjs +232 -0
- package/plugins/openrouter/index.mjs +124 -0
- package/plugins/openrouter/models.mjs +157 -0
- package/plugins/openrouter/search.mjs +113 -0
- package/plugins/openrouter/wire.mjs +101 -0
- package/plugins/providers/catalog.mjs +160 -0
- package/plugins/providers/chat-messages.mjs +120 -0
- package/plugins/providers/chat-stream.mjs +174 -0
- package/plugins/providers/desktop-client.mjs +84 -0
- package/plugins/providers/desktop-host.mjs +63 -0
- package/plugins/providers/effort.mjs +35 -0
- package/plugins/providers/http-errors.mjs +50 -0
- package/plugins/providers/openrouter-account.mjs +171 -0
- package/plugins/session-bridge/client.mjs +106 -0
- package/plugins/session-bridge/communication.mjs +260 -0
- package/plugins/session-bridge/index.mjs +67 -0
- package/plugins/session-bridge/mailbox.mjs +267 -0
- package/plugins/session-bridge/paths.mjs +21 -0
- package/plugins/session-bridge/server.mjs +172 -0
- package/plugins/session-bridge/tasks.mjs +229 -0
- package/plugins/session-cards/content.mjs +64 -0
- package/plugins/session-cards/index.mjs +38 -0
- package/plugins/session-cards/manager.mjs +140 -0
- package/plugins/session-metrics/attribution.mjs +30 -0
- package/plugins/session-metrics/balance.mjs +81 -0
- package/plugins/session-metrics/desktop-client.mjs +62 -0
- package/plugins/session-metrics/desktop-host.mjs +46 -0
- package/plugins/session-metrics/index.mjs +97 -0
- package/plugins/session-metrics/pricing.mjs +84 -0
- package/plugins/session-metrics/rate.mjs +59 -0
- package/plugins/session-metrics/store.mjs +75 -0
- package/plugins/session-metrics/turns.mjs +134 -0
- package/plugins/session-metrics/view.mjs +272 -0
- package/plugins/time-marks/desktop-host.mjs +2 -0
- package/plugins/time-marks/index.mjs +116 -0
- package/plugins/time-marks/marks.mjs +152 -0
- package/plugins/triggers/cli.mjs +558 -0
- package/plugins/triggers/commands.mjs +143 -0
- package/plugins/triggers/config.mjs +264 -0
- package/plugins/triggers/desktop-client.mjs +155 -0
- package/plugins/triggers/desktop-host.mjs +88 -0
- package/plugins/triggers/desktop-management.mjs +97 -0
- package/plugins/triggers/desktop-scheduler.mjs +125 -0
- package/plugins/triggers/host.mjs +24 -0
- package/plugins/triggers/index.mjs +27 -0
- package/plugins/triggers/job-cli.mjs +110 -0
- package/plugins/triggers/jobs.mjs +156 -0
- package/plugins/triggers/launchd.mjs +101 -0
- package/plugins/triggers/lease.mjs +24 -0
- package/plugins/triggers/log.mjs +104 -0
- package/plugins/triggers/management.mjs +181 -0
- package/plugins/triggers/options.mjs +117 -0
- package/plugins/triggers/overlay.mjs +7 -0
- package/plugins/triggers/poll.mjs +65 -0
- package/plugins/triggers/run.mjs +157 -0
- package/plugins/triggers/schedule.mjs +40 -0
- package/plugins/triggers/scheduler-service.mjs +46 -0
- package/plugins/triggers/scheduler.mjs +92 -0
- package/plugins/triggers/session-run.mjs +125 -0
- package/plugins/triggers/session.mjs +48 -0
- package/plugins/triggers/source-emit.mjs +19 -0
- package/plugins/triggers/source-host.mjs +78 -0
- package/plugins/triggers/source-ingress.mjs +70 -0
- package/plugins/triggers/source-sandbox.mjs +35 -0
- package/plugins/triggers/sources.mjs +45 -0
- package/plugins/triggers/spool.mjs +145 -0
- package/plugins/triggers/tools.mjs +67 -0
- package/plugins/triggers/unattended.mjs +18 -0
- package/plugins/tui-tools/composition.mjs +28 -0
- package/plugins/tui-tools/desktop-host.mjs +2 -0
- package/plugins/tui-tools/doctor-cli.mjs +22 -0
- package/plugins/tui-tools/doctor.mjs +149 -0
- package/plugins/tui-tools/hook-sources.mjs +113 -0
- package/plugins/tui-tools/hooks.mjs +23 -0
- package/plugins/tui-tools/index.mjs +269 -0
- package/plugins/tui-tools/sandbox-runner.mjs +123 -0
- package/plugins/tui-tools/shell.mjs +27 -0
- package/plugins/tui-tools/update.mjs +111 -0
- package/plugins/tui-tools/workspace-discovery.mjs +129 -0
- package/plugins/ultra/policy.mjs +42 -0
- package/plugins/worktree-subagent/worktree.mjs +56 -0
- package/runtime-sources.json +94 -0
- package/vendor/bash/LICENSE +21 -0
- package/vendor/bash/index.js +717 -0
- package/vendor/bash/types/background.d.ts +50 -0
- package/vendor/bash/types/index.d.ts +38 -0
- package/vendor/bash/types/render.d.ts +57 -0
- package/vendor/command-goal/LICENSE +21 -0
- package/vendor/command-goal/index.js +210 -0
- package/vendor/command-goal/types/index.d.ts +10 -0
- package/vendor/computer-use/LICENSE +21 -0
- package/vendor/computer-use/lib/approval-policy.js +12 -0
- package/vendor/computer-use/lib/approval-policy.js.map +1 -0
- package/vendor/computer-use/lib/artifacts.js +79 -0
- package/vendor/computer-use/lib/artifacts.js.map +1 -0
- package/vendor/computer-use/lib/backend.js +3 -0
- package/vendor/computer-use/lib/backend.js.map +1 -0
- package/vendor/computer-use/lib/client.js +369 -0
- package/vendor/computer-use/lib/client.js.map +1 -0
- package/vendor/computer-use/lib/config.js +159 -0
- package/vendor/computer-use/lib/config.js.map +1 -0
- package/vendor/computer-use/lib/confirmations.js +99 -0
- package/vendor/computer-use/lib/confirmations.js.map +1 -0
- package/vendor/computer-use/lib/diff.js +58 -0
- package/vendor/computer-use/lib/diff.js.map +1 -0
- package/vendor/computer-use/lib/errors.js +22 -0
- package/vendor/computer-use/lib/errors.js.map +1 -0
- package/vendor/computer-use/lib/exposure.js +244 -0
- package/vendor/computer-use/lib/exposure.js.map +1 -0
- package/vendor/computer-use/lib/index.js +66 -0
- package/vendor/computer-use/lib/index.js.map +1 -0
- package/vendor/computer-use/lib/leases.js +262 -0
- package/vendor/computer-use/lib/leases.js.map +1 -0
- package/vendor/computer-use/lib/providers/macos.js +243 -0
- package/vendor/computer-use/lib/providers/macos.js.map +1 -0
- package/vendor/computer-use/lib/providers/native-helper.js +726 -0
- package/vendor/computer-use/lib/providers/native-helper.js.map +1 -0
- package/vendor/computer-use/lib/providers/unsupported.js +51 -0
- package/vendor/computer-use/lib/providers/unsupported.js.map +1 -0
- package/vendor/computer-use/lib/service.js +608 -0
- package/vendor/computer-use/lib/service.js.map +1 -0
- package/vendor/computer-use/lib/skill.js +136 -0
- package/vendor/computer-use/lib/skill.js.map +1 -0
- package/vendor/computer-use/lib/target-resolver.js +180 -0
- package/vendor/computer-use/lib/target-resolver.js.map +1 -0
- package/vendor/computer-use/lib/tools.js +511 -0
- package/vendor/computer-use/lib/tools.js.map +1 -0
- package/vendor/computer-use/lib/types/approval-policy.d.ts +13 -0
- package/vendor/computer-use/lib/types/approval-policy.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/artifacts.d.ts +10 -0
- package/vendor/computer-use/lib/types/artifacts.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/backend.d.ts +124 -0
- package/vendor/computer-use/lib/types/backend.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/client/index.d.ts +83 -0
- package/vendor/computer-use/lib/types/client/index.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/config.d.ts +94 -0
- package/vendor/computer-use/lib/types/config.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/confirmations.d.ts +23 -0
- package/vendor/computer-use/lib/types/confirmations.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/diff.d.ts +5 -0
- package/vendor/computer-use/lib/types/diff.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/errors.d.ts +15 -0
- package/vendor/computer-use/lib/types/errors.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/exposure.d.ts +30 -0
- package/vendor/computer-use/lib/types/exposure.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/index.d.ts +21 -0
- package/vendor/computer-use/lib/types/index.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/leases.d.ts +81 -0
- package/vendor/computer-use/lib/types/leases.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/providers/macos.d.ts +39 -0
- package/vendor/computer-use/lib/types/providers/macos.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/providers/native-helper.d.ts +48 -0
- package/vendor/computer-use/lib/types/providers/native-helper.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/providers/unsupported.d.ts +23 -0
- package/vendor/computer-use/lib/types/providers/unsupported.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/service.d.ts +58 -0
- package/vendor/computer-use/lib/types/service.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/skill.d.ts +14 -0
- package/vendor/computer-use/lib/types/skill.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/target-resolver.d.ts +38 -0
- package/vendor/computer-use/lib/types/target-resolver.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/tools.d.ts +6 -0
- package/vendor/computer-use/lib/types/tools.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/types.d.ts +270 -0
- package/vendor/computer-use/lib/types/types.d.ts.map +1 -0
- package/vendor/computer-use/lib/types/web.d.ts +33 -0
- package/vendor/computer-use/lib/types/web.d.ts.map +1 -0
- package/vendor/computer-use/lib/types.js +9 -0
- package/vendor/computer-use/lib/types.js.map +1 -0
- package/vendor/computer-use/lib/web.js +188 -0
- package/vendor/computer-use/lib/web.js.map +1 -0
- package/vendor/computer-use/native/macos/Sources/Fixture/main.swift +412 -0
- package/vendor/computer-use/native/macos/Sources/Helper/CursorImage.swift +11 -0
- package/vendor/computer-use/native/macos/Sources/Helper/CursorMotion.swift +67 -0
- package/vendor/computer-use/native/macos/Sources/Helper/CursorOverlay.swift +840 -0
- package/vendor/computer-use/native/macos/Sources/Helper/TargetedPointer.swift +327 -0
- package/vendor/computer-use/native/macos/Sources/Helper/WindowNumberMatcher.swift +29 -0
- package/vendor/computer-use/native/macos/Sources/Helper/main.swift +1244 -0
- package/vendor/computer-use/native/macos/Sources/Monitor/main.swift +153 -0
- package/vendor/computer-use/native/macos/bin/dsh-computer-use-helper +0 -0
- package/vendor/computer-use/native/macos/manifest.json +14 -0
- package/vendor/persistent/LICENSE +21 -0
- package/vendor/persistent/index.js +411 -0
- package/vendor/persistent/types/index.d.ts +24 -0
- package/vendor/subagent/LICENSE +21 -0
- package/vendor/subagent/index.js +694 -0
- package/vendor/subagent/invariant.js +52 -0
- package/vendor/subagent/model-selection-settings.js +68 -0
- package/vendor/subagent/types/index.d.ts +82 -0
- package/vendor/subagent/types/invariant.d.ts +16 -0
- package/vendor/subagent/types/list-models.d.ts +10 -0
- package/vendor/subagent/types/model-selection-settings.d.ts +45 -0
- package/vendor/subagent/types/model-selection-state.d.ts +48 -0
- package/vendor/subagent/types/model-selection.d.ts +81 -0
- package/vendor/subagent-core/LICENSE +21 -0
- package/vendor/subagent-core/index.js +3202 -0
- package/vendor/subagent-core/invariant.js +76 -0
- package/vendor/subagent-core/typert.host.d.ts +3 -0
- package/vendor/subagent-core/typert.host.js +978 -0
- package/vendor/subagent-core/typert.remote-client.d.ts +25 -0
- package/vendor/subagent-core/typert.remote-client.js +114 -0
- package/vendor/subagent-core/types/archive-admission.d.ts +16 -0
- package/vendor/subagent-core/types/archive-admission.js +151 -0
- package/vendor/subagent-core/types/assistant-output.d.ts +48 -0
- package/vendor/subagent-core/types/assistant-output.js +73 -0
- package/vendor/subagent-core/types/catalog.d.ts +84 -0
- package/vendor/subagent-core/types/catalog.js +109 -0
- package/vendor/subagent-core/types/child-agent.d.ts +156 -0
- package/vendor/subagent-core/types/child-agent.js +213 -0
- package/vendor/subagent-core/types/client.d.ts +8 -0
- package/vendor/subagent-core/types/client.js +7 -0
- package/vendor/subagent-core/types/continuation-activation.d.ts +267 -0
- package/vendor/subagent-core/types/continuation-activation.js +700 -0
- package/vendor/subagent-core/types/continuation-messages.d.ts +62 -0
- package/vendor/subagent-core/types/continuation-messages.js +106 -0
- package/vendor/subagent-core/types/continuation.d.ts +124 -0
- package/vendor/subagent-core/types/continuation.js +455 -0
- package/vendor/subagent-core/types/control-types.d.ts +135 -0
- package/vendor/subagent-core/types/control-types.js +8 -0
- package/vendor/subagent-core/types/control.d.ts +45 -0
- package/vendor/subagent-core/types/control.js +79 -0
- package/vendor/subagent-core/types/depth.d.ts +31 -0
- package/vendor/subagent-core/types/depth.js +39 -0
- package/vendor/subagent-core/types/descriptor.d.ts +144 -0
- package/vendor/subagent-core/types/descriptor.js +193 -0
- package/vendor/subagent-core/types/error.d.ts +11 -0
- package/vendor/subagent-core/types/error.js +14 -0
- package/vendor/subagent-core/types/inbox.d.ts +43 -0
- package/vendor/subagent-core/types/inbox.js +61 -0
- package/vendor/subagent-core/types/index.d.ts +320 -0
- package/vendor/subagent-core/types/index.js +475 -0
- package/vendor/subagent-core/types/internal.d.ts +58 -0
- package/vendor/subagent-core/types/internal.js +58 -0
- package/vendor/subagent-core/types/invariant.d.ts +13 -0
- package/vendor/subagent-core/types/invariant.js +91 -0
- package/vendor/subagent-core/types/lifecycle.d.ts +113 -0
- package/vendor/subagent-core/types/lifecycle.js +180 -0
- package/vendor/subagent-core/types/list-children.d.ts +36 -0
- package/vendor/subagent-core/types/list-children.js +166 -0
- package/vendor/subagent-core/types/out-of-process.d.ts +118 -0
- package/vendor/subagent-core/types/out-of-process.js +219 -0
- package/vendor/subagent-core/types/projection-types.d.ts +82 -0
- package/vendor/subagent-core/types/projection-types.js +7 -0
- package/vendor/subagent-core/types/projection.d.ts +100 -0
- package/vendor/subagent-core/types/projection.js +157 -0
- package/vendor/subagent-core/types/run-settlement.d.ts +17 -0
- package/vendor/subagent-core/types/run-settlement.js +70 -0
- package/vendor/subagent-core/types/types.d.ts +377 -0
- package/vendor/subagent-core/types/types.js +19 -0
- package/vendor/subagent-driver/LICENSE +21 -0
- package/vendor/subagent-driver/index.js +255 -0
- package/vendor/subagent-driver/types/index.d.ts +33 -0
- package/vendor/subagent-driver/types/structured.d.ts +42 -0
- package/vendor/subagent-fork/LICENSE +21 -0
- package/vendor/subagent-fork/index.js +61 -0
- package/vendor/subagent-fork/types/index.d.ts +20 -0
- package/vendor/subagent-spawn/LICENSE +21 -0
- package/vendor/subagent-spawn/index.js +45 -0
- package/vendor/subagent-spawn/types/index.d.ts +19 -0
- package/vendor/terminal/LICENSE +21 -0
- package/vendor/terminal/index.js +1093 -0
- package/vendor/terminal/types/config.d.ts +82 -0
- package/vendor/terminal/types/index.d.ts +36 -0
- package/vendor/terminal/types/sanitize.d.ts +47 -0
- package/vendor/terminal/types/session.d.ts +87 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/** Optional Web Settings and provider-health route. */
|
|
2
|
+
import { SettingsConflictError } from '@deepseek-ai/dsh-settings';
|
|
3
|
+
import { COMPUTER_USE_SETTINGS_NAMESPACE, resolveConfig, } from "./config.js";
|
|
4
|
+
/** Exact same-origin Settings endpoint. */
|
|
5
|
+
export const COMPUTER_USE_SETTINGS_ROUTE = '/_dsh/computer-use/settings';
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function descriptorOf(ctx) {
|
|
10
|
+
const descriptor = ctx.settings.describe().find(row => row.ns === COMPUTER_USE_SETTINGS_NAMESPACE);
|
|
11
|
+
if (descriptor === undefined)
|
|
12
|
+
throw new Error('computer-use Settings namespace is not registered');
|
|
13
|
+
return descriptor;
|
|
14
|
+
}
|
|
15
|
+
function responseJson(res, status, body) {
|
|
16
|
+
const bytes = Buffer.from(JSON.stringify(body));
|
|
17
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
18
|
+
res.setHeader('Content-Length', String(bytes.length));
|
|
19
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
20
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
21
|
+
res.setHeader('Content-Security-Policy', "default-src 'none'; frame-ancestors 'none'");
|
|
22
|
+
res.writeHead(status);
|
|
23
|
+
res.end(bytes);
|
|
24
|
+
}
|
|
25
|
+
function requestError(res, status, code, message) {
|
|
26
|
+
responseJson(res, status, { ok: false, error: { code, message } });
|
|
27
|
+
}
|
|
28
|
+
function sameOriginPost(req, authorizeUnmarkedPost) {
|
|
29
|
+
const fetchSite = req.headers['sec-fetch-site'];
|
|
30
|
+
if (fetchSite === 'cross-site')
|
|
31
|
+
return false;
|
|
32
|
+
const origin = req.headers.origin;
|
|
33
|
+
if (origin === undefined) {
|
|
34
|
+
if (fetchSite === 'same-origin' || fetchSite === 'same-site' || fetchSite === 'none')
|
|
35
|
+
return true;
|
|
36
|
+
// Desktop strips browser origin metadata before forwarding, but injects a
|
|
37
|
+
// Host-issued signed cookie. Verify it through Connection's own fence;
|
|
38
|
+
// mere Cookie header presence is not authentication.
|
|
39
|
+
return fetchSite === undefined && authorizeUnmarkedPost?.(req) === true;
|
|
40
|
+
}
|
|
41
|
+
const host = req.headers.host;
|
|
42
|
+
if (host === undefined)
|
|
43
|
+
return false;
|
|
44
|
+
try {
|
|
45
|
+
const parsed = new URL(origin);
|
|
46
|
+
return (parsed.protocol === 'http:' || parsed.protocol === 'https:') && parsed.host === host;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function readJson(req, maxBytes = 128 * 1024) {
|
|
53
|
+
const contentType = req.headers['content-type']?.split(';', 1)[0]?.trim().toLowerCase();
|
|
54
|
+
if (contentType !== 'application/json')
|
|
55
|
+
throw new TypeError('Content-Type must be application/json');
|
|
56
|
+
const chunks = [];
|
|
57
|
+
let bytes = 0;
|
|
58
|
+
for await (const chunk of req) {
|
|
59
|
+
const part = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
60
|
+
bytes += part.length;
|
|
61
|
+
if (bytes > maxBytes)
|
|
62
|
+
throw new RangeError(`request body exceeds ${maxBytes} bytes`);
|
|
63
|
+
chunks.push(part);
|
|
64
|
+
}
|
|
65
|
+
return JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
66
|
+
}
|
|
67
|
+
function parseRequest(value) {
|
|
68
|
+
if (!isRecord(value) || typeof value.action !== 'string')
|
|
69
|
+
throw new TypeError('request needs an action');
|
|
70
|
+
if (value.action === 'health')
|
|
71
|
+
return { action: 'health' };
|
|
72
|
+
if (value.action === 'open-settings') {
|
|
73
|
+
if (value.kind !== 'accessibility' && value.kind !== 'screen-recording')
|
|
74
|
+
throw new TypeError('open-settings needs a valid kind');
|
|
75
|
+
return { action: 'open-settings', kind: value.kind };
|
|
76
|
+
}
|
|
77
|
+
if (value.action === 'save') {
|
|
78
|
+
if (!Number.isInteger(value.expectedRevision) || !isRecord(value.value))
|
|
79
|
+
throw new TypeError('save needs expectedRevision and value');
|
|
80
|
+
return { action: 'save', expectedRevision: value.expectedRevision, value: value.value };
|
|
81
|
+
}
|
|
82
|
+
throw new TypeError(`unknown action: ${value.action}`);
|
|
83
|
+
}
|
|
84
|
+
function publicMessage(error) {
|
|
85
|
+
return error instanceof Error ? error.message.slice(0, 1000) : String(error).slice(0, 1000);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Whether one thrown value is the Settings provider's optimistic-concurrency
|
|
89
|
+
* conflict. The provider — not this module — throws it, so a second copy of
|
|
90
|
+
* `SettingsConflictError` (plugin-local versus host-local install) makes
|
|
91
|
+
* `instanceof` alone unreliable. Both the 0.1.5 and the older class carry the
|
|
92
|
+
* stable machine code `"SETTINGS_CONFLICT"`, which is checked first-class;
|
|
93
|
+
* `instanceof` stays as an equivalent additional branch.
|
|
94
|
+
*/
|
|
95
|
+
function isSettingsConflict(error) {
|
|
96
|
+
if (error instanceof SettingsConflictError)
|
|
97
|
+
return true;
|
|
98
|
+
return typeof error === 'object'
|
|
99
|
+
&& error !== null
|
|
100
|
+
&& error.code === 'SETTINGS_CONFLICT';
|
|
101
|
+
}
|
|
102
|
+
/** Same-origin backend used by the optional client Settings section. */
|
|
103
|
+
export class ComputerUseWebBackend {
|
|
104
|
+
ctx;
|
|
105
|
+
authorizeUnmarkedPost;
|
|
106
|
+
constructor(ctx, authorizeUnmarkedPost) {
|
|
107
|
+
this.ctx = ctx;
|
|
108
|
+
this.authorizeUnmarkedPost = authorizeUnmarkedPost;
|
|
109
|
+
}
|
|
110
|
+
/** Current browser-safe Settings and health state. */
|
|
111
|
+
snapshot() {
|
|
112
|
+
const descriptor = descriptorOf(this.ctx);
|
|
113
|
+
return {
|
|
114
|
+
schemaVersion: 1,
|
|
115
|
+
writable: this.ctx.settings.writable,
|
|
116
|
+
settings: {
|
|
117
|
+
value: descriptor.value,
|
|
118
|
+
...(descriptor.user === undefined ? {} : { user: descriptor.user }),
|
|
119
|
+
...(descriptor.base === undefined ? {} : { base: descriptor.base }),
|
|
120
|
+
revision: descriptor.revision,
|
|
121
|
+
applies: 'live',
|
|
122
|
+
},
|
|
123
|
+
provider: this.ctx.computerUse.status(),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/** Handle one Settings request. */
|
|
127
|
+
async handle(req, res) {
|
|
128
|
+
if (req.method === 'GET') {
|
|
129
|
+
try {
|
|
130
|
+
responseJson(res, 200, { ok: true, value: this.snapshot() });
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
requestError(res, 503, 'settings-unavailable', publicMessage(error));
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (req.method !== 'POST') {
|
|
138
|
+
res.setHeader('Allow', 'GET, POST');
|
|
139
|
+
requestError(res, 405, 'method-not-allowed', 'Use GET or POST');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (!sameOriginPost(req, this.authorizeUnmarkedPost)) {
|
|
143
|
+
requestError(res, 403, 'origin-rejected', 'The request must originate from this DSH Web application');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
let parsed;
|
|
147
|
+
try {
|
|
148
|
+
parsed = parseRequest(await readJson(req));
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
requestError(res, error instanceof RangeError ? 413 : 400, 'invalid-request', publicMessage(error));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
if (parsed.action === 'save') {
|
|
156
|
+
if (!this.ctx.settings.writable)
|
|
157
|
+
throw new Error('settings provider is read-only');
|
|
158
|
+
resolveConfig(parsed.value);
|
|
159
|
+
await this.ctx.settings.replace(COMPUTER_USE_SETTINGS_NAMESPACE, parsed.value, parsed.expectedRevision);
|
|
160
|
+
}
|
|
161
|
+
else if (parsed.action === 'health') {
|
|
162
|
+
await this.ctx.computerUse.health(AbortSignal.timeout(30000));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
await this.ctx.computerUse.openPermissionSettings(parsed.kind, AbortSignal.timeout(10000));
|
|
166
|
+
}
|
|
167
|
+
responseJson(res, 200, { ok: true, value: this.snapshot() });
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
const conflict = isSettingsConflict(error);
|
|
171
|
+
this.ctx.logger.warn('dsh-computer-use Web action=%s failed: %s', parsed.action, publicMessage(error));
|
|
172
|
+
requestError(res, conflict ? 409 : 400, conflict ? 'settings-conflict' : 'action-failed', publicMessage(error));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/** Attach the optional route when a Web host is present. */
|
|
177
|
+
export function installComputerUseWeb(ctx) {
|
|
178
|
+
ctx.inject(['webServer', 'connection'], (webCtx) => {
|
|
179
|
+
const connection = webCtx.connection;
|
|
180
|
+
const backend = new ComputerUseWebBackend(webCtx, (req) => typeof connection?.requestRejection === 'function' && connection.requestRejection(req) === undefined);
|
|
181
|
+
webCtx.effect(() => webCtx.webServer.register({
|
|
182
|
+
kind: 'exact',
|
|
183
|
+
path: COMPUTER_USE_SETTINGS_ROUTE,
|
|
184
|
+
handler: (req, res) => backend.handle(req, res),
|
|
185
|
+
}), 'dsh-computer-use: Web Settings route');
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import AppKit
|
|
2
|
+
import Foundation
|
|
3
|
+
|
|
4
|
+
private final class InputProbeView: NSView {
|
|
5
|
+
var onEvent: ((String) -> Void)?
|
|
6
|
+
private var dragging = false
|
|
7
|
+
|
|
8
|
+
override var isFlipped: Bool { true }
|
|
9
|
+
|
|
10
|
+
override init(frame frameRect: NSRect) {
|
|
11
|
+
super.init(frame: frameRect)
|
|
12
|
+
wantsLayer = true
|
|
13
|
+
layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor
|
|
14
|
+
layer?.borderColor = NSColor.separatorColor.cgColor
|
|
15
|
+
layer?.borderWidth = 1
|
|
16
|
+
layer?.cornerRadius = 8
|
|
17
|
+
setAccessibilityElement(true)
|
|
18
|
+
setAccessibilityRole(.group)
|
|
19
|
+
setAccessibilityLabel("Targeted pointer probe")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
required init?(coder: NSCoder) {
|
|
23
|
+
fatalError("init(coder:) has not been implemented")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override func acceptsFirstMouse(for event: NSEvent?) -> Bool { true }
|
|
27
|
+
|
|
28
|
+
override func mouseDown(with event: NSEvent) {
|
|
29
|
+
dragging = true
|
|
30
|
+
onEvent?("pointer down")
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override func mouseDragged(with event: NSEvent) {
|
|
34
|
+
guard dragging else { return }
|
|
35
|
+
onEvent?("pointer drag")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
override func mouseUp(with event: NSEvent) {
|
|
39
|
+
let wasDragging = dragging
|
|
40
|
+
dragging = false
|
|
41
|
+
onEvent?(wasDragging ? "pointer up" : "pointer up without down")
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
override func scrollWheel(with event: NSEvent) {
|
|
45
|
+
onEvent?("pointer scroll")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override func draw(_ dirtyRect: NSRect) {
|
|
49
|
+
super.draw(dirtyRect)
|
|
50
|
+
let text = "Targeted pointer probe"
|
|
51
|
+
let attributes: [NSAttributedString.Key: Any] = [
|
|
52
|
+
.font: NSFont.systemFont(ofSize: 13, weight: .medium),
|
|
53
|
+
.foregroundColor: NSColor.secondaryLabelColor,
|
|
54
|
+
]
|
|
55
|
+
let size = text.size(withAttributes: attributes)
|
|
56
|
+
text.draw(at: NSPoint(x: (bounds.width - size.width) / 2, y: (bounds.height - size.height) / 2), withAttributes: attributes)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private final class FixtureDelegate: NSObject, NSApplicationDelegate {
|
|
61
|
+
private var window: NSWindow!
|
|
62
|
+
private var textField: NSTextField!
|
|
63
|
+
private var secureField: NSSecureTextField!
|
|
64
|
+
private var checkbox: NSButton!
|
|
65
|
+
private var popup: NSPopUpButton!
|
|
66
|
+
private var slider: NSSlider!
|
|
67
|
+
private var statusLabel: NSTextField!
|
|
68
|
+
private var inputProbe: InputProbeView!
|
|
69
|
+
private var stack: NSStackView!
|
|
70
|
+
private var insertedHarmlessSibling = false
|
|
71
|
+
private var keyMonitor: Any?
|
|
72
|
+
private var reorderTimer: Timer?
|
|
73
|
+
private var activationTimer: Timer?
|
|
74
|
+
private var activationReleaseTimer: Timer?
|
|
75
|
+
private var activationHoldUntil: Date?
|
|
76
|
+
private var pointerClickCount = 0
|
|
77
|
+
private var pointerScrollCount = 0
|
|
78
|
+
private var pointerDragCount = 0
|
|
79
|
+
private var pointerMouseDownCount = 0
|
|
80
|
+
private var pointerMouseUpCount = 0
|
|
81
|
+
private var pointerDragGestureCount = 0
|
|
82
|
+
private var activeDragGesture = false
|
|
83
|
+
private var activationCount = 0
|
|
84
|
+
private let transcriptPath: String?
|
|
85
|
+
private let reorderTriggerPath: String?
|
|
86
|
+
private let activationTriggerPath: String?
|
|
87
|
+
private let activationReleaseTriggerPath: String?
|
|
88
|
+
private let activationOnly: Bool
|
|
89
|
+
private let launchInBackground: Bool
|
|
90
|
+
|
|
91
|
+
override init() {
|
|
92
|
+
let arguments = ProcessInfo.processInfo.arguments
|
|
93
|
+
if let index = arguments.firstIndex(of: "--transcript"), arguments.indices.contains(index + 1) {
|
|
94
|
+
transcriptPath = arguments[index + 1]
|
|
95
|
+
} else {
|
|
96
|
+
transcriptPath = nil
|
|
97
|
+
}
|
|
98
|
+
if let index = arguments.firstIndex(of: "--reorder-trigger"), arguments.indices.contains(index + 1) {
|
|
99
|
+
reorderTriggerPath = arguments[index + 1]
|
|
100
|
+
} else {
|
|
101
|
+
reorderTriggerPath = nil
|
|
102
|
+
}
|
|
103
|
+
if let index = arguments.firstIndex(of: "--activation-trigger"), arguments.indices.contains(index + 1) {
|
|
104
|
+
activationTriggerPath = arguments[index + 1]
|
|
105
|
+
} else {
|
|
106
|
+
activationTriggerPath = nil
|
|
107
|
+
}
|
|
108
|
+
if let index = arguments.firstIndex(of: "--activation-release-trigger"), arguments.indices.contains(index + 1) {
|
|
109
|
+
activationReleaseTriggerPath = arguments[index + 1]
|
|
110
|
+
} else {
|
|
111
|
+
activationReleaseTriggerPath = nil
|
|
112
|
+
}
|
|
113
|
+
activationOnly = arguments.contains("--activation-only")
|
|
114
|
+
launchInBackground = arguments.contains("--background")
|
|
115
|
+
super.init()
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
func applicationDidFinishLaunching(_ notification: Notification) {
|
|
119
|
+
buildWindow()
|
|
120
|
+
keyMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
|
|
121
|
+
guard event.keyCode == 36 else { return event }
|
|
122
|
+
self?.applyValues()
|
|
123
|
+
return nil
|
|
124
|
+
}
|
|
125
|
+
if launchInBackground {
|
|
126
|
+
window.orderFrontRegardless()
|
|
127
|
+
window.orderBack(nil)
|
|
128
|
+
} else {
|
|
129
|
+
NSApplication.shared.activate(ignoringOtherApps: true)
|
|
130
|
+
window.makeKeyAndOrderFront(nil)
|
|
131
|
+
}
|
|
132
|
+
writeTranscript(event: "ready")
|
|
133
|
+
if activationOnly {
|
|
134
|
+
activationHoldUntil = Date().addingTimeInterval(5)
|
|
135
|
+
}
|
|
136
|
+
if let reorderTriggerPath {
|
|
137
|
+
reorderTimer = Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { [weak self] timer in
|
|
138
|
+
guard FileManager.default.fileExists(atPath: reorderTriggerPath) else { return }
|
|
139
|
+
timer.invalidate()
|
|
140
|
+
self?.insertHarmlessSibling()
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if activationTriggerPath != nil || activationOnly {
|
|
144
|
+
activationTimer = Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { [weak self] _ in
|
|
145
|
+
guard let self else { return }
|
|
146
|
+
if let activationTriggerPath,
|
|
147
|
+
FileManager.default.fileExists(atPath: activationTriggerPath) {
|
|
148
|
+
try? FileManager.default.removeItem(atPath: activationTriggerPath)
|
|
149
|
+
self.activationHoldUntil = Date().addingTimeInterval(5)
|
|
150
|
+
}
|
|
151
|
+
guard let holdUntil = self.activationHoldUntil else { return }
|
|
152
|
+
guard Date() < holdUntil else {
|
|
153
|
+
self.activationHoldUntil = nil
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
NSApplication.shared.activate(ignoringOtherApps: true)
|
|
157
|
+
self.window.makeKeyAndOrderFront(nil)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if let activationReleaseTriggerPath {
|
|
161
|
+
activationReleaseTimer = Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { [weak self] _ in
|
|
162
|
+
guard FileManager.default.fileExists(atPath: activationReleaseTriggerPath) else { return }
|
|
163
|
+
try? FileManager.default.removeItem(atPath: activationReleaseTriggerPath)
|
|
164
|
+
self?.activationHoldUntil = nil
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
func applicationDidBecomeActive(_ notification: Notification) {
|
|
170
|
+
activationCount += 1
|
|
171
|
+
writeTranscript(event: "activated")
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
func applicationWillTerminate(_ notification: Notification) {
|
|
175
|
+
if let keyMonitor { NSEvent.removeMonitor(keyMonitor) }
|
|
176
|
+
reorderTimer?.invalidate()
|
|
177
|
+
activationTimer?.invalidate()
|
|
178
|
+
activationReleaseTimer?.invalidate()
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
|
182
|
+
true
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private func buildWindow() {
|
|
186
|
+
window = NSWindow(
|
|
187
|
+
contentRect: NSRect(x: 0, y: 0, width: 760, height: 560),
|
|
188
|
+
styleMask: [.titled, .closable, .miniaturizable, .resizable],
|
|
189
|
+
backing: .buffered,
|
|
190
|
+
defer: false
|
|
191
|
+
)
|
|
192
|
+
window.title = "DSH Computer Use Fixture"
|
|
193
|
+
window.center()
|
|
194
|
+
window.setFrameAutosaveName("dsh-computer-use-fixture")
|
|
195
|
+
|
|
196
|
+
let content = NSView()
|
|
197
|
+
content.translatesAutoresizingMaskIntoConstraints = false
|
|
198
|
+
window.contentView = content
|
|
199
|
+
|
|
200
|
+
let title = NSTextField(labelWithString: "Computer Use deterministic fixture")
|
|
201
|
+
title.font = .systemFont(ofSize: 22, weight: .semibold)
|
|
202
|
+
title.setAccessibilityLabel("Fixture title")
|
|
203
|
+
|
|
204
|
+
textField = NSTextField(string: "initial text")
|
|
205
|
+
textField.placeholderString = "Editable text"
|
|
206
|
+
textField.setAccessibilityLabel("Editable text")
|
|
207
|
+
textField.identifier = NSUserInterfaceItemIdentifier("fixture.text")
|
|
208
|
+
textField.target = self
|
|
209
|
+
textField.action = #selector(applyValues)
|
|
210
|
+
|
|
211
|
+
secureField = NSSecureTextField(string: "fixture-secret")
|
|
212
|
+
secureField.placeholderString = "Secure text"
|
|
213
|
+
secureField.setAccessibilityLabel("Secure text")
|
|
214
|
+
secureField.identifier = NSUserInterfaceItemIdentifier("fixture.secure")
|
|
215
|
+
|
|
216
|
+
checkbox = makeCheckbox(state: .off)
|
|
217
|
+
|
|
218
|
+
popup = NSPopUpButton(frame: .zero, pullsDown: false)
|
|
219
|
+
popup.addItems(withTitles: ["Alpha", "Beta", "Gamma"])
|
|
220
|
+
popup.selectItem(at: 0)
|
|
221
|
+
popup.target = self
|
|
222
|
+
popup.action = #selector(selectPopup)
|
|
223
|
+
popup.setAccessibilityLabel("Fixture selection")
|
|
224
|
+
|
|
225
|
+
slider = NSSlider(value: 25, minValue: 0, maxValue: 100, target: self, action: #selector(changeSlider))
|
|
226
|
+
slider.setAccessibilityLabel("Fixture slider")
|
|
227
|
+
|
|
228
|
+
let apply = NSButton(title: "Apply", target: self, action: #selector(applyValues))
|
|
229
|
+
apply.bezelStyle = .rounded
|
|
230
|
+
apply.keyEquivalent = "\r"
|
|
231
|
+
apply.setAccessibilityLabel("Apply fixture values")
|
|
232
|
+
|
|
233
|
+
let delayed = NSButton(title: "Delayed update", target: self, action: #selector(delayedUpdate))
|
|
234
|
+
delayed.bezelStyle = .rounded
|
|
235
|
+
delayed.setAccessibilityLabel("Start delayed update")
|
|
236
|
+
|
|
237
|
+
let modal = NSButton(title: "Show modal", target: self, action: #selector(showModal))
|
|
238
|
+
modal.bezelStyle = .rounded
|
|
239
|
+
modal.setAccessibilityLabel("Show fixture modal")
|
|
240
|
+
|
|
241
|
+
statusLabel = NSTextField(labelWithString: "Status: ready")
|
|
242
|
+
statusLabel.font = .monospacedSystemFont(ofSize: 13, weight: .regular)
|
|
243
|
+
statusLabel.setAccessibilityLabel("Fixture status")
|
|
244
|
+
statusLabel.identifier = NSUserInterfaceItemIdentifier("fixture.status")
|
|
245
|
+
|
|
246
|
+
inputProbe = InputProbeView(frame: .zero)
|
|
247
|
+
inputProbe.translatesAutoresizingMaskIntoConstraints = false
|
|
248
|
+
inputProbe.heightAnchor.constraint(equalToConstant: 54).isActive = true
|
|
249
|
+
inputProbe.onEvent = { [weak self] event in
|
|
250
|
+
guard let self else { return }
|
|
251
|
+
switch event {
|
|
252
|
+
case "pointer down":
|
|
253
|
+
self.pointerMouseDownCount += 1
|
|
254
|
+
self.activeDragGesture = false
|
|
255
|
+
return
|
|
256
|
+
case "pointer drag":
|
|
257
|
+
self.pointerDragCount += 1
|
|
258
|
+
self.activeDragGesture = true
|
|
259
|
+
self.statusLabel.stringValue = "Status: pointer drag"
|
|
260
|
+
case "pointer up":
|
|
261
|
+
self.pointerMouseUpCount += 1
|
|
262
|
+
if self.activeDragGesture {
|
|
263
|
+
self.pointerDragGestureCount += 1
|
|
264
|
+
self.statusLabel.stringValue = "Status: pointer drag"
|
|
265
|
+
} else {
|
|
266
|
+
self.pointerClickCount += 1
|
|
267
|
+
self.statusLabel.stringValue = "Status: pointer click"
|
|
268
|
+
}
|
|
269
|
+
self.activeDragGesture = false
|
|
270
|
+
case "pointer scroll":
|
|
271
|
+
self.pointerScrollCount += 1
|
|
272
|
+
self.statusLabel.stringValue = "Status: pointer scroll"
|
|
273
|
+
default: break
|
|
274
|
+
}
|
|
275
|
+
self.writeTranscript(event: event)
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
let longText = (1...80).map { "Scrollable row \($0)" }.joined(separator: "\n")
|
|
279
|
+
let textView = NSTextView()
|
|
280
|
+
textView.string = longText
|
|
281
|
+
textView.isEditable = false
|
|
282
|
+
textView.isSelectable = true
|
|
283
|
+
textView.setAccessibilityLabel("Scrollable fixture rows")
|
|
284
|
+
let scroll = NSScrollView()
|
|
285
|
+
scroll.hasVerticalScroller = true
|
|
286
|
+
scroll.documentView = textView
|
|
287
|
+
scroll.heightAnchor.constraint(equalToConstant: 180).isActive = true
|
|
288
|
+
|
|
289
|
+
let fields = NSGridView(views: [
|
|
290
|
+
[NSTextField(labelWithString: "Text"), textField],
|
|
291
|
+
[NSTextField(labelWithString: "Secret"), secureField],
|
|
292
|
+
[NSTextField(labelWithString: "Selection"), popup],
|
|
293
|
+
[NSTextField(labelWithString: "Level"), slider],
|
|
294
|
+
])
|
|
295
|
+
fields.rowSpacing = 10
|
|
296
|
+
fields.columnSpacing = 14
|
|
297
|
+
fields.column(at: 0).xPlacement = .trailing
|
|
298
|
+
fields.column(at: 1).width = 460
|
|
299
|
+
|
|
300
|
+
let buttons = NSStackView(views: [apply, delayed, modal])
|
|
301
|
+
buttons.orientation = .horizontal
|
|
302
|
+
buttons.spacing = 10
|
|
303
|
+
|
|
304
|
+
stack = NSStackView(views: [title, fields, checkbox, buttons, statusLabel, inputProbe, scroll])
|
|
305
|
+
stack.translatesAutoresizingMaskIntoConstraints = false
|
|
306
|
+
stack.orientation = .vertical
|
|
307
|
+
stack.alignment = .leading
|
|
308
|
+
stack.spacing = 16
|
|
309
|
+
content.addSubview(stack)
|
|
310
|
+
NSLayoutConstraint.activate([
|
|
311
|
+
stack.leadingAnchor.constraint(equalTo: content.leadingAnchor, constant: 28),
|
|
312
|
+
stack.trailingAnchor.constraint(equalTo: content.trailingAnchor, constant: -28),
|
|
313
|
+
stack.topAnchor.constraint(equalTo: content.topAnchor, constant: 24),
|
|
314
|
+
stack.bottomAnchor.constraint(lessThanOrEqualTo: content.bottomAnchor, constant: -24),
|
|
315
|
+
scroll.widthAnchor.constraint(equalTo: stack.widthAnchor),
|
|
316
|
+
inputProbe.widthAnchor.constraint(equalTo: stack.widthAnchor),
|
|
317
|
+
])
|
|
318
|
+
window.makeFirstResponder(textField)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
@objc private func applyValues() {
|
|
322
|
+
statusLabel.stringValue = "Status: applied \(textField.stringValue)"
|
|
323
|
+
writeTranscript(event: "apply")
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
@objc private func toggleCheckbox() {
|
|
327
|
+
statusLabel.stringValue = checkbox.state == .on ? "Status: option enabled" : "Status: option disabled"
|
|
328
|
+
writeTranscript(event: "checkbox")
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
@objc private func selectPopup() {
|
|
332
|
+
statusLabel.stringValue = "Status: selected \(popup.titleOfSelectedItem ?? "")"
|
|
333
|
+
writeTranscript(event: "selection")
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
@objc private func changeSlider() {
|
|
337
|
+
statusLabel.stringValue = "Status: slider \(Int(slider.doubleValue))"
|
|
338
|
+
writeTranscript(event: "slider")
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
@objc private func delayedUpdate() {
|
|
342
|
+
statusLabel.stringValue = "Status: waiting"
|
|
343
|
+
writeTranscript(event: "delay-start")
|
|
344
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
|
|
345
|
+
self?.statusLabel.stringValue = "Status: delayed complete"
|
|
346
|
+
self?.writeTranscript(event: "delay-complete")
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private func insertHarmlessSibling() {
|
|
351
|
+
guard !insertedHarmlessSibling else { return }
|
|
352
|
+
insertedHarmlessSibling = true
|
|
353
|
+
let checkboxState = checkbox.state
|
|
354
|
+
stack.removeArrangedSubview(checkbox)
|
|
355
|
+
checkbox.removeFromSuperview()
|
|
356
|
+
let label = NSTextField(labelWithString: "Harmless dynamic sibling")
|
|
357
|
+
label.setAccessibilityLabel("Harmless dynamic sibling")
|
|
358
|
+
label.identifier = NSUserInterfaceItemIdentifier("fixture.harmless-sibling")
|
|
359
|
+
stack.insertArrangedSubview(label, at: 2)
|
|
360
|
+
checkbox = makeCheckbox(state: checkboxState)
|
|
361
|
+
stack.insertArrangedSubview(checkbox, at: 3)
|
|
362
|
+
statusLabel.stringValue = "Status: harmless sibling inserted"
|
|
363
|
+
writeTranscript(event: "reorder")
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private func makeCheckbox(state: NSControl.StateValue) -> NSButton {
|
|
367
|
+
let value = NSButton(checkboxWithTitle: "Enable deterministic option", target: self, action: #selector(toggleCheckbox))
|
|
368
|
+
value.state = state
|
|
369
|
+
value.setAccessibilityLabel("Enable deterministic option")
|
|
370
|
+
value.identifier = NSUserInterfaceItemIdentifier("fixture.checkbox")
|
|
371
|
+
return value
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
@objc private func showModal() {
|
|
375
|
+
let alert = NSAlert()
|
|
376
|
+
alert.messageText = "Fixture modal"
|
|
377
|
+
alert.informativeText = "This modal exists for deterministic Accessibility observation."
|
|
378
|
+
alert.addButton(withTitle: "Confirm")
|
|
379
|
+
alert.beginSheetModal(for: window) { [weak self] _ in
|
|
380
|
+
self?.statusLabel.stringValue = "Status: modal confirmed"
|
|
381
|
+
self?.writeTranscript(event: "modal")
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private func writeTranscript(event: String) {
|
|
386
|
+
guard let transcriptPath else { return }
|
|
387
|
+
let payload: [String: Any] = [
|
|
388
|
+
"event": event,
|
|
389
|
+
"text": textField?.stringValue ?? "",
|
|
390
|
+
"secureLength": secureField?.stringValue.count ?? 0,
|
|
391
|
+
"checked": checkbox?.state == .on,
|
|
392
|
+
"selection": popup?.titleOfSelectedItem ?? "",
|
|
393
|
+
"slider": Int(slider?.doubleValue ?? 0),
|
|
394
|
+
"status": statusLabel?.stringValue ?? "",
|
|
395
|
+
"pointerClickCount": pointerClickCount,
|
|
396
|
+
"pointerScrollCount": pointerScrollCount,
|
|
397
|
+
"pointerDragCount": pointerDragCount,
|
|
398
|
+
"pointerMouseDownCount": pointerMouseDownCount,
|
|
399
|
+
"pointerMouseUpCount": pointerMouseUpCount,
|
|
400
|
+
"pointerDragGestureCount": pointerDragGestureCount,
|
|
401
|
+
"activationCount": activationCount,
|
|
402
|
+
]
|
|
403
|
+
guard let data = try? JSONSerialization.data(withJSONObject: payload, options: [.sortedKeys]) else { return }
|
|
404
|
+
try? data.write(to: URL(fileURLWithPath: transcriptPath), options: .atomic)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
let app = NSApplication.shared
|
|
409
|
+
private let delegate = FixtureDelegate()
|
|
410
|
+
app.delegate = delegate
|
|
411
|
+
app.setActivationPolicy(.regular)
|
|
412
|
+
app.run()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import AppKit
|
|
2
|
+
|
|
3
|
+
/// Source asset: assets/cursor.png (whole image, 64x64, hotspot at top-left).
|
|
4
|
+
/// The overlay draws it at 28x28 points with the top-left corner at the target.
|
|
5
|
+
/// Embedded transparent cursor image for the Agent cursor overlay.
|
|
6
|
+
enum EmbeddedCursorImage {
|
|
7
|
+
static let image: NSImage? = {
|
|
8
|
+
guard let data = Data(base64Encoded: "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") else { return nil }
|
|
9
|
+
return NSImage(data: data)
|
|
10
|
+
}()
|
|
11
|
+
}
|