@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.
Files changed (485) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -2
  3. package/THIRD_PARTY_NOTICES.md +30 -0
  4. package/bin/apply_patch +9 -0
  5. package/cordis.patch.yml +433 -0
  6. package/docs/CHANGELOG.md +649 -0
  7. package/docs/account-login.md +44 -0
  8. package/docs/auto-review.md +128 -0
  9. package/docs/browser-use.md +784 -0
  10. package/docs/computer-use.md +81 -0
  11. package/docs/custom-providers.md +88 -0
  12. package/docs/demo.md +158 -0
  13. package/docs/distribution.md +58 -0
  14. package/docs/dscode-ultra.md +75 -0
  15. package/docs/email.md +296 -0
  16. package/docs/exec.md +40 -0
  17. package/docs/hub-distribution.md +212 -0
  18. package/docs/memory.md +121 -0
  19. package/docs/opencode-go.md +61 -0
  20. package/docs/plugin-hub.md +68 -0
  21. package/docs/releases/0.2.0.md +28 -0
  22. package/docs/releases/0.3.0.md +21 -0
  23. package/docs/releases/0.4.0.md +20 -0
  24. package/docs/releases/0.5.0.md +19 -0
  25. package/docs/releases/0.6.0.md +20 -0
  26. package/docs/releases/0.7.0.md +22 -0
  27. package/docs/releases/0.7.1.md +20 -0
  28. package/docs/releases/0.7.10.md +10 -0
  29. package/docs/releases/0.7.11.md +17 -0
  30. package/docs/releases/0.7.12.md +11 -0
  31. package/docs/releases/0.7.13.md +12 -0
  32. package/docs/releases/0.7.14.md +11 -0
  33. package/docs/releases/0.7.15.md +11 -0
  34. package/docs/releases/0.7.16.md +10 -0
  35. package/docs/releases/0.7.17.md +12 -0
  36. package/docs/releases/0.7.18.md +13 -0
  37. package/docs/releases/0.7.19.md +8 -0
  38. package/docs/releases/0.7.2.md +19 -0
  39. package/docs/releases/0.7.20.md +10 -0
  40. package/docs/releases/0.7.21.md +9 -0
  41. package/docs/releases/0.7.22.md +11 -0
  42. package/docs/releases/0.7.23.md +14 -0
  43. package/docs/releases/0.7.24.md +11 -0
  44. package/docs/releases/0.7.25.md +8 -0
  45. package/docs/releases/0.7.26.md +18 -0
  46. package/docs/releases/0.7.27.md +8 -0
  47. package/docs/releases/0.7.28.md +22 -0
  48. package/docs/releases/0.7.29.md +12 -0
  49. package/docs/releases/0.7.3.md +23 -0
  50. package/docs/releases/0.7.30.md +19 -0
  51. package/docs/releases/0.7.31.md +14 -0
  52. package/docs/releases/0.7.32.md +14 -0
  53. package/docs/releases/0.7.33.md +37 -0
  54. package/docs/releases/0.7.34.md +24 -0
  55. package/docs/releases/0.7.4.md +16 -0
  56. package/docs/releases/0.7.5.md +18 -0
  57. package/docs/releases/0.7.6.md +29 -0
  58. package/docs/releases/0.7.7.md +36 -0
  59. package/docs/releases/0.7.8.md +14 -0
  60. package/docs/releases/0.7.9.md +15 -0
  61. package/docs/session-bridge.md +80 -0
  62. package/docs/session-cards.md +53 -0
  63. package/docs/session-communication.md +186 -0
  64. package/docs/session-metrics.md +41 -0
  65. package/docs/skills.md +81 -0
  66. package/docs/triggers.md +338 -0
  67. package/docs/tui-commands.md +204 -0
  68. package/extensions/browser/manifest.json +22 -0
  69. package/extensions/browser/popup.css +6 -0
  70. package/extensions/browser/popup.html +11 -0
  71. package/extensions/browser/popup.mjs +47 -0
  72. package/extensions/browser/protocol.mjs +168 -0
  73. package/extensions/browser/worker.mjs +94 -0
  74. package/icon.svg +7 -0
  75. package/locale/en.json +6 -0
  76. package/locale/zh-cn.json +6 -0
  77. package/node_modules/@deepseek-ai/node-addon-system/LICENSE +21 -0
  78. package/node_modules/@deepseek-ai/node-addon-system/README.i18n.yaml +6 -0
  79. package/node_modules/@deepseek-ai/node-addon-system/README.md +15 -0
  80. package/node_modules/@deepseek-ai/node-addon-system/README.zh.md +15 -0
  81. package/node_modules/@deepseek-ai/node-addon-system/lib/flock.d.ts +13 -0
  82. package/node_modules/@deepseek-ai/node-addon-system/lib/flock.js +51 -0
  83. package/node_modules/@deepseek-ai/node-addon-system/lib/index.d.ts +73 -0
  84. package/node_modules/@deepseek-ai/node-addon-system/lib/index.js +98 -0
  85. package/node_modules/@deepseek-ai/node-addon-system/package.json +45 -0
  86. package/node_modules/@deepseek-ai/node-addon-system/src/flock.c +164 -0
  87. package/node_modules/@deepseek-ai/node-addon-system/src/main.c +298 -0
  88. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/LICENSE +28 -0
  89. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/README.i18n.yaml +6 -0
  90. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/README.md +9 -0
  91. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/README.zh.md +9 -0
  92. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/bin/system.node +0 -0
  93. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/package.json +31 -0
  94. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/prebuilds.json +6 -0
  95. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/LICENSE +28 -0
  96. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/README.i18n.yaml +6 -0
  97. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/README.md +9 -0
  98. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/README.zh.md +9 -0
  99. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/bin/system.node +0 -0
  100. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/package.json +31 -0
  101. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/prebuilds.json +6 -0
  102. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/LICENSE +28 -0
  103. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/README.i18n.yaml +6 -0
  104. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/README.md +11 -0
  105. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/README.zh.md +11 -0
  106. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/bin/glibc/system.node +0 -0
  107. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/bin/landlock-run +0 -0
  108. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/bin/musl/system.node +0 -0
  109. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/package.json +31 -0
  110. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/prebuilds.json +24 -0
  111. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/LICENSE +28 -0
  112. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/README.i18n.yaml +6 -0
  113. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/README.md +11 -0
  114. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/README.zh.md +11 -0
  115. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/glibc/system.node +0 -0
  116. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/landlock-run +0 -0
  117. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/musl/system.node +0 -0
  118. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/package.json +31 -0
  119. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/prebuilds.json +24 -0
  120. package/package.json +156 -4
  121. package/plugins/account/index.mjs +178 -0
  122. package/plugins/account/state.mjs +123 -0
  123. package/plugins/auto-review/audit.mjs +24 -0
  124. package/plugins/auto-review/index.mjs +267 -0
  125. package/plugins/auto-review/policy.mjs +92 -0
  126. package/plugins/browser/SKILL.md +158 -0
  127. package/plugins/browser/access.mjs +143 -0
  128. package/plugins/browser/config.mjs +60 -0
  129. package/plugins/browser/connection.mjs +385 -0
  130. package/plugins/browser/desktop-client.mjs +282 -0
  131. package/plugins/browser/desktop-host.mjs +74 -0
  132. package/plugins/browser/document-identity.mjs +57 -0
  133. package/plugins/browser/extension-relay.mjs +66 -0
  134. package/plugins/browser/files.mjs +32 -0
  135. package/plugins/browser/index.mjs +235 -0
  136. package/plugins/browser/mcp-entry.mjs +18 -0
  137. package/plugins/browser/mcp-tools.mjs +21 -0
  138. package/plugins/browser/presentation.mjs +45 -0
  139. package/plugins/browser/preview.mjs +77 -0
  140. package/plugins/browser/review.mjs +20 -0
  141. package/plugins/browser/screenshots.mjs +35 -0
  142. package/plugins/clipboard-image/clipboard-image.swift +56 -0
  143. package/plugins/clipboard-image/index.mjs +70 -0
  144. package/plugins/code-review/baseline.mjs +143 -0
  145. package/plugins/code-review/git.mjs +163 -0
  146. package/plugins/code-review/index.mjs +236 -0
  147. package/plugins/compaction/engine.mjs +304 -0
  148. package/plugins/compaction/tetris.mjs +65 -0
  149. package/plugins/compaction/threshold.mjs +99 -0
  150. package/plugins/computer-use/DESKTOP-SKILL.md +64 -0
  151. package/plugins/computer-use/desktop-host.mjs +75 -0
  152. package/plugins/computer-use/desktop-skill.mjs +28 -0
  153. package/plugins/computer-use/desktop-upstream.mjs +3 -0
  154. package/plugins/computer-use/index.mjs +37 -0
  155. package/plugins/cordis-config/plain.mjs +31 -0
  156. package/plugins/credentials/index.mjs +73 -0
  157. package/plugins/custom/adapter.mjs +110 -0
  158. package/plugins/custom/config.mjs +85 -0
  159. package/plugins/custom/desktop-client.mjs +150 -0
  160. package/plugins/custom/desktop-host.mjs +78 -0
  161. package/plugins/custom/images.mjs +32 -0
  162. package/plugins/custom/index.mjs +145 -0
  163. package/plugins/custom/wire.mjs +179 -0
  164. package/plugins/desktop/client.mjs +1041 -0
  165. package/plugins/desktop/index.mjs +10 -0
  166. package/plugins/desktop/shell-environment.mjs +9 -0
  167. package/plugins/desktop-workspace/hooks.mjs +29 -0
  168. package/plugins/desktop-workspace/index.mjs +37 -0
  169. package/plugins/dscode/board.mjs +260 -0
  170. package/plugins/dscode/child-target.mjs +11 -0
  171. package/plugins/dscode/control.mjs +17 -0
  172. package/plugins/dscode/desktop-client.mjs +55 -0
  173. package/plugins/dscode/desktop-host.mjs +37 -0
  174. package/plugins/dscode/index.mjs +270 -0
  175. package/plugins/email/cli.mjs +32 -0
  176. package/plugins/email/contacts.mjs +36 -0
  177. package/plugins/email/desktop-client.mjs +117 -0
  178. package/plugins/email/desktop-host.mjs +54 -0
  179. package/plugins/email/desktop-service.mjs +106 -0
  180. package/plugins/email/gmail-oauth.mjs +69 -0
  181. package/plugins/email/gmail-store.mjs +2 -0
  182. package/plugins/email/gmail.mjs +194 -0
  183. package/plugins/email/imap.mjs +136 -0
  184. package/plugins/email/inbox.d.mts +25 -0
  185. package/plugins/email/inbox.mjs +76 -0
  186. package/plugins/email/smtp.mjs +70 -0
  187. package/plugins/email/store.mjs +32 -0
  188. package/plugins/email-tools/index.mjs +46 -0
  189. package/plugins/exec/cli.mjs +64 -0
  190. package/plugins/exec/index.mjs +112 -0
  191. package/plugins/grok/adapter.mjs +114 -0
  192. package/plugins/grok/auth.mjs +76 -0
  193. package/plugins/grok/billing.mjs +147 -0
  194. package/plugins/grok/index.mjs +123 -0
  195. package/plugins/grok/models.mjs +129 -0
  196. package/plugins/grok/status.mjs +29 -0
  197. package/plugins/grok/wire.mjs +268 -0
  198. package/plugins/hub/catalog.mjs +82 -0
  199. package/plugins/hub/desktop-client.mjs +114 -0
  200. package/plugins/hub/desktop-host.mjs +129 -0
  201. package/plugins/i18n/messages.d.mts +21 -0
  202. package/plugins/i18n/messages.mjs +537 -0
  203. package/plugins/jev/approval.mjs +131 -0
  204. package/plugins/jev/client.mjs +74 -0
  205. package/plugins/jev/index.mjs +100 -0
  206. package/plugins/memory/content.mjs +57 -0
  207. package/plugins/memory/desktop-host.mjs +3 -0
  208. package/plugins/memory/index.mjs +168 -0
  209. package/plugins/memory/pipeline.mjs +79 -0
  210. package/plugins/memory/store.mjs +93 -0
  211. package/plugins/message-source/kind.mjs +20 -0
  212. package/plugins/opencode-go/adapter.mjs +96 -0
  213. package/plugins/opencode-go/command.mjs +128 -0
  214. package/plugins/opencode-go/index.mjs +121 -0
  215. package/plugins/opencode-go/models.mjs +58 -0
  216. package/plugins/opencode-go/oauth.mjs +194 -0
  217. package/plugins/opencode-go/search.mjs +86 -0
  218. package/plugins/opencode-go/usage.mjs +120 -0
  219. package/plugins/opencode-go/version.mjs +10 -0
  220. package/plugins/opencode-go/wire.mjs +73 -0
  221. package/plugins/openrouter/adapter.mjs +232 -0
  222. package/plugins/openrouter/index.mjs +124 -0
  223. package/plugins/openrouter/models.mjs +157 -0
  224. package/plugins/openrouter/search.mjs +113 -0
  225. package/plugins/openrouter/wire.mjs +101 -0
  226. package/plugins/providers/catalog.mjs +160 -0
  227. package/plugins/providers/chat-messages.mjs +120 -0
  228. package/plugins/providers/chat-stream.mjs +174 -0
  229. package/plugins/providers/desktop-client.mjs +84 -0
  230. package/plugins/providers/desktop-host.mjs +63 -0
  231. package/plugins/providers/effort.mjs +35 -0
  232. package/plugins/providers/http-errors.mjs +50 -0
  233. package/plugins/providers/openrouter-account.mjs +171 -0
  234. package/plugins/session-bridge/client.mjs +106 -0
  235. package/plugins/session-bridge/communication.mjs +260 -0
  236. package/plugins/session-bridge/index.mjs +67 -0
  237. package/plugins/session-bridge/mailbox.mjs +267 -0
  238. package/plugins/session-bridge/paths.mjs +21 -0
  239. package/plugins/session-bridge/server.mjs +172 -0
  240. package/plugins/session-bridge/tasks.mjs +229 -0
  241. package/plugins/session-cards/content.mjs +64 -0
  242. package/plugins/session-cards/index.mjs +38 -0
  243. package/plugins/session-cards/manager.mjs +140 -0
  244. package/plugins/session-metrics/attribution.mjs +30 -0
  245. package/plugins/session-metrics/balance.mjs +81 -0
  246. package/plugins/session-metrics/desktop-client.mjs +62 -0
  247. package/plugins/session-metrics/desktop-host.mjs +46 -0
  248. package/plugins/session-metrics/index.mjs +97 -0
  249. package/plugins/session-metrics/pricing.mjs +84 -0
  250. package/plugins/session-metrics/rate.mjs +59 -0
  251. package/plugins/session-metrics/store.mjs +75 -0
  252. package/plugins/session-metrics/turns.mjs +134 -0
  253. package/plugins/session-metrics/view.mjs +272 -0
  254. package/plugins/time-marks/desktop-host.mjs +2 -0
  255. package/plugins/time-marks/index.mjs +116 -0
  256. package/plugins/time-marks/marks.mjs +152 -0
  257. package/plugins/triggers/cli.mjs +558 -0
  258. package/plugins/triggers/commands.mjs +143 -0
  259. package/plugins/triggers/config.mjs +264 -0
  260. package/plugins/triggers/desktop-client.mjs +155 -0
  261. package/plugins/triggers/desktop-host.mjs +88 -0
  262. package/plugins/triggers/desktop-management.mjs +97 -0
  263. package/plugins/triggers/desktop-scheduler.mjs +125 -0
  264. package/plugins/triggers/host.mjs +24 -0
  265. package/plugins/triggers/index.mjs +27 -0
  266. package/plugins/triggers/job-cli.mjs +110 -0
  267. package/plugins/triggers/jobs.mjs +156 -0
  268. package/plugins/triggers/launchd.mjs +101 -0
  269. package/plugins/triggers/lease.mjs +24 -0
  270. package/plugins/triggers/log.mjs +104 -0
  271. package/plugins/triggers/management.mjs +181 -0
  272. package/plugins/triggers/options.mjs +117 -0
  273. package/plugins/triggers/overlay.mjs +7 -0
  274. package/plugins/triggers/poll.mjs +65 -0
  275. package/plugins/triggers/run.mjs +157 -0
  276. package/plugins/triggers/schedule.mjs +40 -0
  277. package/plugins/triggers/scheduler-service.mjs +46 -0
  278. package/plugins/triggers/scheduler.mjs +92 -0
  279. package/plugins/triggers/session-run.mjs +125 -0
  280. package/plugins/triggers/session.mjs +48 -0
  281. package/plugins/triggers/source-emit.mjs +19 -0
  282. package/plugins/triggers/source-host.mjs +78 -0
  283. package/plugins/triggers/source-ingress.mjs +70 -0
  284. package/plugins/triggers/source-sandbox.mjs +35 -0
  285. package/plugins/triggers/sources.mjs +45 -0
  286. package/plugins/triggers/spool.mjs +145 -0
  287. package/plugins/triggers/tools.mjs +67 -0
  288. package/plugins/triggers/unattended.mjs +18 -0
  289. package/plugins/tui-tools/composition.mjs +28 -0
  290. package/plugins/tui-tools/desktop-host.mjs +2 -0
  291. package/plugins/tui-tools/doctor-cli.mjs +22 -0
  292. package/plugins/tui-tools/doctor.mjs +149 -0
  293. package/plugins/tui-tools/hook-sources.mjs +113 -0
  294. package/plugins/tui-tools/hooks.mjs +23 -0
  295. package/plugins/tui-tools/index.mjs +269 -0
  296. package/plugins/tui-tools/sandbox-runner.mjs +123 -0
  297. package/plugins/tui-tools/shell.mjs +27 -0
  298. package/plugins/tui-tools/update.mjs +111 -0
  299. package/plugins/tui-tools/workspace-discovery.mjs +129 -0
  300. package/plugins/ultra/policy.mjs +42 -0
  301. package/plugins/worktree-subagent/worktree.mjs +56 -0
  302. package/runtime-sources.json +94 -0
  303. package/vendor/bash/LICENSE +21 -0
  304. package/vendor/bash/index.js +717 -0
  305. package/vendor/bash/types/background.d.ts +50 -0
  306. package/vendor/bash/types/index.d.ts +38 -0
  307. package/vendor/bash/types/render.d.ts +57 -0
  308. package/vendor/command-goal/LICENSE +21 -0
  309. package/vendor/command-goal/index.js +210 -0
  310. package/vendor/command-goal/types/index.d.ts +10 -0
  311. package/vendor/computer-use/LICENSE +21 -0
  312. package/vendor/computer-use/lib/approval-policy.js +12 -0
  313. package/vendor/computer-use/lib/approval-policy.js.map +1 -0
  314. package/vendor/computer-use/lib/artifacts.js +79 -0
  315. package/vendor/computer-use/lib/artifacts.js.map +1 -0
  316. package/vendor/computer-use/lib/backend.js +3 -0
  317. package/vendor/computer-use/lib/backend.js.map +1 -0
  318. package/vendor/computer-use/lib/client.js +369 -0
  319. package/vendor/computer-use/lib/client.js.map +1 -0
  320. package/vendor/computer-use/lib/config.js +159 -0
  321. package/vendor/computer-use/lib/config.js.map +1 -0
  322. package/vendor/computer-use/lib/confirmations.js +99 -0
  323. package/vendor/computer-use/lib/confirmations.js.map +1 -0
  324. package/vendor/computer-use/lib/diff.js +58 -0
  325. package/vendor/computer-use/lib/diff.js.map +1 -0
  326. package/vendor/computer-use/lib/errors.js +22 -0
  327. package/vendor/computer-use/lib/errors.js.map +1 -0
  328. package/vendor/computer-use/lib/exposure.js +244 -0
  329. package/vendor/computer-use/lib/exposure.js.map +1 -0
  330. package/vendor/computer-use/lib/index.js +66 -0
  331. package/vendor/computer-use/lib/index.js.map +1 -0
  332. package/vendor/computer-use/lib/leases.js +262 -0
  333. package/vendor/computer-use/lib/leases.js.map +1 -0
  334. package/vendor/computer-use/lib/providers/macos.js +243 -0
  335. package/vendor/computer-use/lib/providers/macos.js.map +1 -0
  336. package/vendor/computer-use/lib/providers/native-helper.js +726 -0
  337. package/vendor/computer-use/lib/providers/native-helper.js.map +1 -0
  338. package/vendor/computer-use/lib/providers/unsupported.js +51 -0
  339. package/vendor/computer-use/lib/providers/unsupported.js.map +1 -0
  340. package/vendor/computer-use/lib/service.js +608 -0
  341. package/vendor/computer-use/lib/service.js.map +1 -0
  342. package/vendor/computer-use/lib/skill.js +136 -0
  343. package/vendor/computer-use/lib/skill.js.map +1 -0
  344. package/vendor/computer-use/lib/target-resolver.js +180 -0
  345. package/vendor/computer-use/lib/target-resolver.js.map +1 -0
  346. package/vendor/computer-use/lib/tools.js +511 -0
  347. package/vendor/computer-use/lib/tools.js.map +1 -0
  348. package/vendor/computer-use/lib/types/approval-policy.d.ts +13 -0
  349. package/vendor/computer-use/lib/types/approval-policy.d.ts.map +1 -0
  350. package/vendor/computer-use/lib/types/artifacts.d.ts +10 -0
  351. package/vendor/computer-use/lib/types/artifacts.d.ts.map +1 -0
  352. package/vendor/computer-use/lib/types/backend.d.ts +124 -0
  353. package/vendor/computer-use/lib/types/backend.d.ts.map +1 -0
  354. package/vendor/computer-use/lib/types/client/index.d.ts +83 -0
  355. package/vendor/computer-use/lib/types/client/index.d.ts.map +1 -0
  356. package/vendor/computer-use/lib/types/config.d.ts +94 -0
  357. package/vendor/computer-use/lib/types/config.d.ts.map +1 -0
  358. package/vendor/computer-use/lib/types/confirmations.d.ts +23 -0
  359. package/vendor/computer-use/lib/types/confirmations.d.ts.map +1 -0
  360. package/vendor/computer-use/lib/types/diff.d.ts +5 -0
  361. package/vendor/computer-use/lib/types/diff.d.ts.map +1 -0
  362. package/vendor/computer-use/lib/types/errors.d.ts +15 -0
  363. package/vendor/computer-use/lib/types/errors.d.ts.map +1 -0
  364. package/vendor/computer-use/lib/types/exposure.d.ts +30 -0
  365. package/vendor/computer-use/lib/types/exposure.d.ts.map +1 -0
  366. package/vendor/computer-use/lib/types/index.d.ts +21 -0
  367. package/vendor/computer-use/lib/types/index.d.ts.map +1 -0
  368. package/vendor/computer-use/lib/types/leases.d.ts +81 -0
  369. package/vendor/computer-use/lib/types/leases.d.ts.map +1 -0
  370. package/vendor/computer-use/lib/types/providers/macos.d.ts +39 -0
  371. package/vendor/computer-use/lib/types/providers/macos.d.ts.map +1 -0
  372. package/vendor/computer-use/lib/types/providers/native-helper.d.ts +48 -0
  373. package/vendor/computer-use/lib/types/providers/native-helper.d.ts.map +1 -0
  374. package/vendor/computer-use/lib/types/providers/unsupported.d.ts +23 -0
  375. package/vendor/computer-use/lib/types/providers/unsupported.d.ts.map +1 -0
  376. package/vendor/computer-use/lib/types/service.d.ts +58 -0
  377. package/vendor/computer-use/lib/types/service.d.ts.map +1 -0
  378. package/vendor/computer-use/lib/types/skill.d.ts +14 -0
  379. package/vendor/computer-use/lib/types/skill.d.ts.map +1 -0
  380. package/vendor/computer-use/lib/types/target-resolver.d.ts +38 -0
  381. package/vendor/computer-use/lib/types/target-resolver.d.ts.map +1 -0
  382. package/vendor/computer-use/lib/types/tools.d.ts +6 -0
  383. package/vendor/computer-use/lib/types/tools.d.ts.map +1 -0
  384. package/vendor/computer-use/lib/types/types.d.ts +270 -0
  385. package/vendor/computer-use/lib/types/types.d.ts.map +1 -0
  386. package/vendor/computer-use/lib/types/web.d.ts +33 -0
  387. package/vendor/computer-use/lib/types/web.d.ts.map +1 -0
  388. package/vendor/computer-use/lib/types.js +9 -0
  389. package/vendor/computer-use/lib/types.js.map +1 -0
  390. package/vendor/computer-use/lib/web.js +188 -0
  391. package/vendor/computer-use/lib/web.js.map +1 -0
  392. package/vendor/computer-use/native/macos/Sources/Fixture/main.swift +412 -0
  393. package/vendor/computer-use/native/macos/Sources/Helper/CursorImage.swift +11 -0
  394. package/vendor/computer-use/native/macos/Sources/Helper/CursorMotion.swift +67 -0
  395. package/vendor/computer-use/native/macos/Sources/Helper/CursorOverlay.swift +840 -0
  396. package/vendor/computer-use/native/macos/Sources/Helper/TargetedPointer.swift +327 -0
  397. package/vendor/computer-use/native/macos/Sources/Helper/WindowNumberMatcher.swift +29 -0
  398. package/vendor/computer-use/native/macos/Sources/Helper/main.swift +1244 -0
  399. package/vendor/computer-use/native/macos/Sources/Monitor/main.swift +153 -0
  400. package/vendor/computer-use/native/macos/bin/dsh-computer-use-helper +0 -0
  401. package/vendor/computer-use/native/macos/manifest.json +14 -0
  402. package/vendor/persistent/LICENSE +21 -0
  403. package/vendor/persistent/index.js +411 -0
  404. package/vendor/persistent/types/index.d.ts +24 -0
  405. package/vendor/subagent/LICENSE +21 -0
  406. package/vendor/subagent/index.js +694 -0
  407. package/vendor/subagent/invariant.js +52 -0
  408. package/vendor/subagent/model-selection-settings.js +68 -0
  409. package/vendor/subagent/types/index.d.ts +82 -0
  410. package/vendor/subagent/types/invariant.d.ts +16 -0
  411. package/vendor/subagent/types/list-models.d.ts +10 -0
  412. package/vendor/subagent/types/model-selection-settings.d.ts +45 -0
  413. package/vendor/subagent/types/model-selection-state.d.ts +48 -0
  414. package/vendor/subagent/types/model-selection.d.ts +81 -0
  415. package/vendor/subagent-core/LICENSE +21 -0
  416. package/vendor/subagent-core/index.js +3202 -0
  417. package/vendor/subagent-core/invariant.js +76 -0
  418. package/vendor/subagent-core/typert.host.d.ts +3 -0
  419. package/vendor/subagent-core/typert.host.js +978 -0
  420. package/vendor/subagent-core/typert.remote-client.d.ts +25 -0
  421. package/vendor/subagent-core/typert.remote-client.js +114 -0
  422. package/vendor/subagent-core/types/archive-admission.d.ts +16 -0
  423. package/vendor/subagent-core/types/archive-admission.js +151 -0
  424. package/vendor/subagent-core/types/assistant-output.d.ts +48 -0
  425. package/vendor/subagent-core/types/assistant-output.js +73 -0
  426. package/vendor/subagent-core/types/catalog.d.ts +84 -0
  427. package/vendor/subagent-core/types/catalog.js +109 -0
  428. package/vendor/subagent-core/types/child-agent.d.ts +156 -0
  429. package/vendor/subagent-core/types/child-agent.js +213 -0
  430. package/vendor/subagent-core/types/client.d.ts +8 -0
  431. package/vendor/subagent-core/types/client.js +7 -0
  432. package/vendor/subagent-core/types/continuation-activation.d.ts +267 -0
  433. package/vendor/subagent-core/types/continuation-activation.js +700 -0
  434. package/vendor/subagent-core/types/continuation-messages.d.ts +62 -0
  435. package/vendor/subagent-core/types/continuation-messages.js +106 -0
  436. package/vendor/subagent-core/types/continuation.d.ts +124 -0
  437. package/vendor/subagent-core/types/continuation.js +455 -0
  438. package/vendor/subagent-core/types/control-types.d.ts +135 -0
  439. package/vendor/subagent-core/types/control-types.js +8 -0
  440. package/vendor/subagent-core/types/control.d.ts +45 -0
  441. package/vendor/subagent-core/types/control.js +79 -0
  442. package/vendor/subagent-core/types/depth.d.ts +31 -0
  443. package/vendor/subagent-core/types/depth.js +39 -0
  444. package/vendor/subagent-core/types/descriptor.d.ts +144 -0
  445. package/vendor/subagent-core/types/descriptor.js +193 -0
  446. package/vendor/subagent-core/types/error.d.ts +11 -0
  447. package/vendor/subagent-core/types/error.js +14 -0
  448. package/vendor/subagent-core/types/inbox.d.ts +43 -0
  449. package/vendor/subagent-core/types/inbox.js +61 -0
  450. package/vendor/subagent-core/types/index.d.ts +320 -0
  451. package/vendor/subagent-core/types/index.js +475 -0
  452. package/vendor/subagent-core/types/internal.d.ts +58 -0
  453. package/vendor/subagent-core/types/internal.js +58 -0
  454. package/vendor/subagent-core/types/invariant.d.ts +13 -0
  455. package/vendor/subagent-core/types/invariant.js +91 -0
  456. package/vendor/subagent-core/types/lifecycle.d.ts +113 -0
  457. package/vendor/subagent-core/types/lifecycle.js +180 -0
  458. package/vendor/subagent-core/types/list-children.d.ts +36 -0
  459. package/vendor/subagent-core/types/list-children.js +166 -0
  460. package/vendor/subagent-core/types/out-of-process.d.ts +118 -0
  461. package/vendor/subagent-core/types/out-of-process.js +219 -0
  462. package/vendor/subagent-core/types/projection-types.d.ts +82 -0
  463. package/vendor/subagent-core/types/projection-types.js +7 -0
  464. package/vendor/subagent-core/types/projection.d.ts +100 -0
  465. package/vendor/subagent-core/types/projection.js +157 -0
  466. package/vendor/subagent-core/types/run-settlement.d.ts +17 -0
  467. package/vendor/subagent-core/types/run-settlement.js +70 -0
  468. package/vendor/subagent-core/types/types.d.ts +377 -0
  469. package/vendor/subagent-core/types/types.js +19 -0
  470. package/vendor/subagent-driver/LICENSE +21 -0
  471. package/vendor/subagent-driver/index.js +255 -0
  472. package/vendor/subagent-driver/types/index.d.ts +33 -0
  473. package/vendor/subagent-driver/types/structured.d.ts +42 -0
  474. package/vendor/subagent-fork/LICENSE +21 -0
  475. package/vendor/subagent-fork/index.js +61 -0
  476. package/vendor/subagent-fork/types/index.d.ts +20 -0
  477. package/vendor/subagent-spawn/LICENSE +21 -0
  478. package/vendor/subagent-spawn/index.js +45 -0
  479. package/vendor/subagent-spawn/types/index.d.ts +19 -0
  480. package/vendor/terminal/LICENSE +21 -0
  481. package/vendor/terminal/index.js +1093 -0
  482. package/vendor/terminal/types/config.d.ts +82 -0
  483. package/vendor/terminal/types/index.d.ts +36 -0
  484. package/vendor/terminal/types/sanitize.d.ts +47 -0
  485. package/vendor/terminal/types/session.d.ts +87 -0
@@ -0,0 +1,282 @@
1
+ // Official Harness client-module format; React is supplied by the shared UI.
2
+ globalThis.__ModuleLoader__.load({
3
+ id: '@toddzheng024/dscode-browser-desktop',
4
+ factory: require => {
5
+ const { createElement: h, useState, useEffect, useRef } = require('react');
6
+ const id = '@toddzheng024/dscode-browser-desktop';
7
+ const button = { padding: '7px 11px', border: '1px solid #8886', borderRadius: 6, background: 'transparent', color: 'inherit', cursor: 'pointer' };
8
+ function previewButton(props, label) {
9
+ return h('button', { ...props, style: { ...button, ...props.style, ...(props.disabled ? { opacity: 0.5, cursor: 'not-allowed' } : {}) } }, label);
10
+ }
11
+ const sitePermissions = (permissions, origin) => origin && JSON.stringify([
12
+ permissions?.developerMode, permissions?.sites?.[origin], permissions?.sessionSites?.includes(origin),
13
+ ]);
14
+ function SessionPreview({ execute, draft }) {
15
+ const { pageId, setPageId, text, setText, draftRevision } = draft;
16
+ const [pages, setPages] = useState([]);
17
+ const [permissions, setPermissions] = useState(null);
18
+ const [handoff, setHandoff] = useState(null);
19
+ const [frame, setFrame] = useState(null), [point, setPoint] = useState(null);
20
+ const [expanded, setExpanded] = useState(false);
21
+ const [expired, setExpired] = useState(false);
22
+ const mounted = useRef(true);
23
+ useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []);
24
+ const [error, setError] = useState(''), [notice, setNotice] = useState(''), [busy, setBusy] = useState(false), [live, setLive] = useState(false);
25
+ const pending = useRef(false), controlPending = useRef(false), controlEpoch = useRef(0);
26
+ const activityEpoch = useRef(0);
27
+ const browserAvailable = useRef(!!pageId);
28
+ const [controlBusy, setControlBusy] = useState(false);
29
+ const disconnected = () => {
30
+ browserAvailable.current = false;
31
+ setHandoff(null); setPages([]); setPageId(''); setPermissions(null);
32
+ setFrame(null); setPoint(null); setLive(false);
33
+ setNotice('Browser disconnected. Your draft is kept. Start or reconnect the browser and capture a new preview.');
34
+ };
35
+ const run = async action => {
36
+ if (pending.current || controlPending.current) return;
37
+ activityEpoch.current++;
38
+ const epoch = controlEpoch.current;
39
+ const current = () => epoch === controlEpoch.current && !controlPending.current;
40
+ const operation = {};
41
+ pending.current = operation; setBusy(true); setError('');
42
+ try { await action(current); } catch (error) {
43
+ if (!current()) return;
44
+ setError(error.message); setLive(false); setFrame(null); setPoint(null); setPermissions(null);
45
+ }
46
+ finally { if (pending.current === operation) { pending.current = false; setBusy(false); } }
47
+ };
48
+ const list = async (current, { preserveDraft = false } = {}) => {
49
+ const revision = draftRevision.current;
50
+ const result = await execute('tabs');
51
+ if (!current() || !mounted.current) return;
52
+ if (result.connected === false) { disconnected(); return; }
53
+ browserAvailable.current = true;
54
+ setPages(result.pages);
55
+ setPermissions(result.permissions ?? null);
56
+ setHandoff(result.handoff ?? null);
57
+ if (result.handoff) { setFrame(null); setPoint(null); setLive(false); }
58
+ const selected = result.pages.find(page => String(page.id) === pageId) ?? result.pages.find(page => page.selected) ?? result.pages[0];
59
+ if (String(selected?.id ?? '') !== pageId) {
60
+ setPageId(selected ? String(selected.id) : ''); setFrame(null); setPoint(null); setLive(false);
61
+ // A first selection can follow browser startup or an empty tab list.
62
+ // Keep text written before any page was assigned to the draft.
63
+ if (pageId && !preserveDraft && !result.handoff && draftRevision.current === revision) setText('');
64
+ } else if (frame && (selected?.url !== frame.url || selected?.documentId !== frame.documentId)) {
65
+ setFrame(null); setPoint(null); setLive(false);
66
+ setNotice('The page changed or could not be verified. Refresh the preview; your draft is kept.');
67
+ }
68
+ };
69
+ const refresh = async current => {
70
+ if (!pageId || handoff) return;
71
+ setPoint(null);
72
+ const result = await execute('capture', { pageId: Number(pageId) });
73
+ if (current()) {
74
+ browserAvailable.current = true;
75
+ setPages(previous => previous.map(page => page.id === result.pageId ? { ...page, url: result.url, documentId: result.documentId } : page));
76
+ setPermissions(result.permissions ?? null);
77
+ setFrame(result); setNotice('');
78
+ }
79
+ };
80
+ let origin;
81
+ try {
82
+ const url = new URL(pages.find(page => String(page.id) === pageId)?.url);
83
+ if (['http:', 'https:'].includes(url.protocol) && !url.username && !url.password) origin = url.origin;
84
+ } catch { /* Blank and unavailable tabs have no site grant. */ }
85
+ useEffect(() => { void run(list); }, []);
86
+ useEffect(() => {
87
+ let active = true, reading = false;
88
+ const timer = setInterval(async () => {
89
+ if (reading || pending.current || controlPending.current) return;
90
+ const epoch = activityEpoch.current;
91
+ reading = true;
92
+ try {
93
+ // Read Host state and grants: no Chrome request or image capture.
94
+ const result = await execute('handoff');
95
+ if (!active || !mounted.current || epoch !== activityEpoch.current) return;
96
+ if (result.connected === false) {
97
+ if (!browserAvailable.current && !handoff) return;
98
+ disconnected();
99
+ return;
100
+ }
101
+ if (result.connected === true) browserAvailable.current = true;
102
+ if (result.permissions && JSON.stringify(result.permissions) !== JSON.stringify(permissions)) {
103
+ if (sitePermissions(result.permissions, origin) !== sitePermissions(permissions, origin)) {
104
+ setFrame(null); setPoint(null); setLive(false);
105
+ setNotice('Site permissions changed. Your draft is kept. Capture a new preview after access is granted.');
106
+ }
107
+ setPermissions(result.permissions);
108
+ }
109
+ const next = result.handoff ?? null;
110
+ if (JSON.stringify(next) === JSON.stringify(handoff)) return;
111
+ setHandoff(next); setFrame(null); setPoint(null); setLive(false);
112
+ } catch { /* The next visible tick retries; browser actions still enforce handoff. */ }
113
+ finally { reading = false; }
114
+ }, 2500);
115
+ return () => { active = false; clearInterval(timer); };
116
+ }, [execute, handoff, permissions, origin]);
117
+ const expire = () => { setExpired(true); setPoint(null); setLive(false); };
118
+ useEffect(() => {
119
+ setExpired(false);
120
+ if (!frame) return;
121
+ const remaining = frame.capturedAt + 60000 - Date.now();
122
+ if (remaining <= 0) { expire(); return; }
123
+ let active = true;
124
+ const timer = setTimeout(() => { if (active) expire(); }, remaining);
125
+ return () => { active = false; clearTimeout(timer); };
126
+ }, [frame]);
127
+ useEffect(() => {
128
+ if (!live || point || !pageId || handoff) return;
129
+ const timer = setInterval(() => { void run(refresh); }, 2500);
130
+ return () => clearInterval(timer);
131
+ }, [live, point, pageId, handoff, execute]);
132
+ const canSelect = () => {
133
+ if (!frame || handoff || pending.current || controlPending.current || expired) return false;
134
+ if (Date.now() - frame.capturedAt >= 60000) { expire(); return false; }
135
+ return true;
136
+ };
137
+ const selectPoint = event => {
138
+ if (!canSelect()) return;
139
+ setLive(false);
140
+ const rect = event.currentTarget.getBoundingClientRect();
141
+ setPoint({ x: Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width)), y: Math.min(1, Math.max(0, (event.clientY - rect.top) / rect.height)) });
142
+ };
143
+ const selectPointKey = event => {
144
+ if (event.altKey || event.ctrlKey || event.metaKey || !['Enter', ' ', 'Escape', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.key)) return;
145
+ event.preventDefault();
146
+ if (!canSelect()) return;
147
+ if (event.key === 'Escape') { setPoint(null); return; }
148
+ setLive(false);
149
+ setPoint(previous => {
150
+ const xMax = frame.width - 1, yMax = frame.height - 1;
151
+ const base = ['Enter', ' '].includes(event.key) ? null : previous;
152
+ let x = Math.round((base?.x ?? 0.5) * xMax), y = Math.round((base?.y ?? 0.5) * yMax);
153
+ const step = event.shiftKey ? 10 : 1;
154
+ if (event.key === 'ArrowLeft') x -= step;
155
+ if (event.key === 'ArrowRight') x += step;
156
+ if (event.key === 'ArrowUp') y -= step;
157
+ if (event.key === 'ArrowDown') y += step;
158
+ return { x: xMax ? Math.min(xMax, Math.max(0, x)) / xMax : 0, y: yMax ? Math.min(yMax, Math.max(0, y)) / yMax : 0 };
159
+ });
160
+ };
161
+ const rule = permissions?.sites?.[origin];
162
+ const access = rule?.access === 'block' ? 'Blocked' : rule?.access === 'allow' ? 'Always allowed' :
163
+ permissions?.sessionSites?.includes(origin) ? 'Allowed until browser stops' : permissions ? 'Permission required' : 'Refresh tabs to load permissions';
164
+ const changeControl = async action => {
165
+ if (controlPending.current) return;
166
+ // Stop and revocation must not wait for a slow ordinary request. The epoch
167
+ // prevents earlier responses from restoring pixels or stale grants.
168
+ controlPending.current = true; controlEpoch.current++;
169
+ activityEpoch.current++;
170
+ // Superseded requests may remain in transport indefinitely. Release their
171
+ // UI lock; only the currently owned operation may clear a later lock.
172
+ pending.current = false; setBusy(false);
173
+ setControlBusy(true); setError(''); setNotice('');
174
+ setFrame(null); setPoint(null); setLive(false);
175
+ try {
176
+ await action();
177
+ } catch (error) {
178
+ setError(error.message); setPermissions(null);
179
+ } finally { controlPending.current = false; setControlBusy(false); }
180
+ };
181
+ const changePermission = (change, value = origin) => changeControl(async () => {
182
+ const result = await execute('permission', { change, value });
183
+ setPermissions(result.permissions);
184
+ setNotice(change === 'developer-mode' ? `Developer mode ${value}. Each site also needs its own grant.` : `Permissions updated for ${value}.`);
185
+ });
186
+ const stop = () => changeControl(async () => {
187
+ browserAvailable.current = false;
188
+ setPages([]); setPageId(''); setPermissions(null); setHandoff(null);
189
+ await execute('stop');
190
+ setNotice('Browser stopped. Your draft is kept. Start the browser and capture a new preview to continue.');
191
+ });
192
+ const resume = () => run(async current => {
193
+ setNotice(''); setFrame(null); setPoint(null); setLive(false);
194
+ await execute('resume');
195
+ if (!current() || !mounted.current) return;
196
+ setHandoff(null);
197
+ setNotice('Browser control resumed. Your draft is kept. Capture a new preview before sending.');
198
+ await list(current, { preserveDraft: true });
199
+ });
200
+ return h('section', { 'aria-label': 'DSCODE browser preview', style: { padding: 12, boxSizing: 'border-box', overflow: 'auto', height: '100%', display: 'flex', flexDirection: 'column', gap: 8, color: 'inherit' } },
201
+ h('strong', null, 'Browser preview'),
202
+ handoff && h('div', { 'aria-label': 'Browser handoff', role: 'status', style: { border: '1px solid #8886', borderRadius: 8, padding: 10, overflowWrap: 'anywhere' } },
203
+ h('strong', null, 'Waiting for you'),
204
+ h('p', null, handoff.reason),
205
+ handoff.invalidated && h('p', null, 'Chrome restarted. The original tab is unavailable; choose a live tab after resuming.'),
206
+ handoff.focusError && h('p', null, handoff.focusError),
207
+ h('p', null, 'Complete the manual step in Chrome, then resume browser control.'),
208
+ previewButton({ style: button, disabled: busy || controlBusy, onClick: resume }, 'Resume browser control')),
209
+ h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 8 } },
210
+ previewButton({ style: button, disabled: busy || controlBusy || !!handoff, onClick: () => run(async current => { setNotice(''); await execute('start'); if (current()) await list(current); }) }, 'Start browser'),
211
+ previewButton({ style: button, disabled: controlBusy, onClick: stop }, 'Stop browser'),
212
+ previewButton({ style: button, disabled: busy || controlBusy, onClick: () => run(list) }, 'Refresh tabs'),
213
+ previewButton({ style: button, disabled: busy || controlBusy || !pageId || !!handoff, onClick: () => run(refresh) }, 'Refresh preview'),
214
+ frame && previewButton({ style: button, onClick: () => setExpanded(!expanded) }, expanded ? 'Fit image' : 'Expand image')),
215
+ h('select', { 'aria-label': 'Browser tab', value: pageId, disabled: busy || controlBusy, onChange: e => { setPageId(e.target.value); setFrame(null); setPoint(null); setText(''); setLive(false); }, style: { ...button, width: '100%' } }, h('option', { value: '' }, 'Choose a tab'), ...pages.map(page => h('option', { key: page.id, value: String(page.id) }, `${page.id} · ${page.url}`))),
216
+ origin && h('details', { 'aria-label': 'Browser site permissions', style: { border: '1px solid #8886', borderRadius: 8, padding: '8px 10px', margin: 0, minWidth: 0 } },
217
+ h('summary', { 'aria-label': `Site permissions · ${access}`, style: { cursor: 'pointer' } }, 'Site permissions · ', h('span', { 'aria-label': 'Site access status' }, access)),
218
+ h('div', { style: { fontSize: 12, overflowWrap: 'anywhere', margin: '8px 0' } }, origin),
219
+ h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 6 } },
220
+ ...[['Allow this session', 'once'], ['Always allow', 'allow'], ['Block site', 'block'], ['Forget decision', 'forget']].map(([label, change]) =>
221
+ previewButton({ key: change, style: button, disabled: controlBusy || change === 'once' && ['block', 'allow'].includes(rule?.access), onClick: () => changePermission(change) }, label))),
222
+ h('details', { style: { marginTop: 10 } },
223
+ h('summary', { style: { cursor: 'pointer' } }, 'Developer access'),
224
+ h('p', { 'aria-label': 'Developer access status', style: { fontSize: 12 } }, permissions ?
225
+ `Developer mode: ${permissions.developerMode ? 'on globally' : 'off globally'}. This site: ${rule?.developer ? 'granted' : 'not granted'}. Scripts, CSS, console and network inspection require both.` : 'Refresh tabs to load Developer permissions.'),
226
+ h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: 6 } },
227
+ previewButton({ style: button, disabled: controlBusy || !permissions, onClick: () => changePermission('developer-mode', permissions.developerMode ? 'off' : 'on') }, permissions?.developerMode ? 'Disable Developer mode' : 'Enable Developer mode'),
228
+ previewButton({ style: button, disabled: controlBusy || !permissions || rule?.access === 'block', onClick: () => changePermission(rule?.developer ? 'developer-block' : 'developer-allow') }, rule?.developer ? 'Revoke site Developer access' : 'Grant site Developer access'))),
229
+ h('p', { style: { fontSize: 12, opacity: 0.75, marginBottom: 0 } }, 'Changes apply to this exact origin. Action approvals still apply. Permissions sync while this pane is visible and idle; Refresh tabs updates them immediately.')),
230
+ h('label', null, h('input', { type: 'checkbox', checked: live, disabled: controlBusy || !pageId || !!point || !!handoff, onChange: e => setLive(e.target.checked) }), ' Refresh while visible'),
231
+ error && h('div', { role: 'alert', style: { whiteSpace: 'pre-wrap', color: '#db6868' } }, error),
232
+ frame && h('div', null,
233
+ h('div', { style: { fontSize: 12, overflowWrap: 'anywhere', marginBottom: 8 } }, `${frame.url} · ${new Date(frame.capturedAt).toLocaleTimeString()}`),
234
+ h('div', { style: { position: 'relative', lineHeight: 0, display: 'inline-block', maxWidth: '100%', ...(expanded ? { width: '100%' } : {}) } },
235
+ h('img', { src: `data:${frame.image.mimeType};base64,${frame.image.data}`, alt: expired ? 'Expired browser preview; refresh before annotating' : 'Captured browser page; click a point to annotate', role: 'button', tabIndex: 0, 'aria-disabled': busy || controlBusy || expired, 'aria-description': 'Enter or Space selects the center. Arrow keys move one pixel; Shift moves ten. Escape clears the point.', onClick: selectPoint, onKeyDown: selectPointKey, style: { maxWidth: '100%', maxHeight: expanded ? 'none' : '30vh', width: expanded ? '100%' : 'auto', height: 'auto', display: 'block', cursor: expired ? 'default' : 'crosshair', borderRadius: 6 } }),
236
+ point && h('span', { 'aria-label': 'Selected annotation point', style: { position: 'absolute', left: `${point.x * 100}%`, top: `${point.y * 100}%`, width: 20, height: 20, border: '3px solid #f97316', borderRadius: '50%', transform: 'translate(-50%, -50%)', pointerEvents: 'none', boxShadow: '0 0 0 2px white' } }))),
237
+ h('p', { style: { fontSize: 12, margin: 0, opacity: 0.75 } }, 'Preview shows the controlled Chrome tab. Click a point, or focus the image and press Enter or Space to select the center. Arrow keys move one pixel; Shift moves ten. Escape clears the point. Refresh after navigation or after one minute.'),
238
+ frame && point && h('p', { 'aria-label': 'Annotation coordinates', 'aria-live': 'polite', style: { fontSize: 12, margin: 0 } }, `Selected pixel: (${Math.round(point.x * (frame.width - 1))}, ${Math.round(point.y * (frame.height - 1))}) in ${frame.width}×${frame.height}.`),
239
+ frame && expired && h('p', { 'aria-label': 'Preview freshness', role: 'status', style: { fontSize: 12, margin: 0 } }, 'This preview has expired. Choose Refresh preview, then select the point again. Your draft is kept.'),
240
+ h('textarea', { 'aria-label': 'Browser annotation', placeholder: 'Describe what should change here…', value: text, maxLength: 4000, onChange: e => { draftRevision.current++; setText(e.target.value); }, style: { ...button, minHeight: 76, width: '100%', boxSizing: 'border-box', cursor: 'text' } }),
241
+ previewButton({ style: button, disabled: busy || controlBusy || expired || !!handoff || !frame || !point || !text.trim(), onClick: () => run(async current => {
242
+ if (!frame || handoff || expired || !point || !text.trim()) return;
243
+ // Background windows may throttle timers; check again at submission.
244
+ if (Date.now() - frame.capturedAt >= 60000) { expire(); return; }
245
+ const revision = draftRevision.current;
246
+ const result = await execute('annotate', { annotation: { token: frame.token, ...point, text } });
247
+ if (!current()) return;
248
+ setNotice(result.message); setPoint(null); setFrame(null);
249
+ // The editable field may already contain the user's next annotation.
250
+ if (draftRevision.current === revision) setText('');
251
+ }) }, 'Send annotation'),
252
+ notice && h('div', { role: 'status' }, notice));
253
+ }
254
+ function SessionPane({ execute, visible }) {
255
+ // Keep only the draft and selected tab while this session's pane is hidden.
256
+ // Sharing the revision also lets an in-flight send settle without clearing
257
+ // text edited after reopening. Pixels and refresh timers remain disposable.
258
+ const [pageId, setPageId] = useState(''), [text, setText] = useState('');
259
+ const draftRevision = useRef(0);
260
+ return visible ? h(SessionPreview, { execute, draft: { pageId, setPageId, text, setText, draftRevision } }) : null;
261
+ }
262
+ function Preview({ sessionId, execute, useTabInfo }) {
263
+ const { tab } = useTabInfo();
264
+ // Session changes discard the draft. Hidden panes discard their request
265
+ // lock and preview, while late responses stay bound to the original session.
266
+ return h(SessionPane, { key: sessionId, execute, visible: tab.visible });
267
+ }
268
+ return {
269
+ inject: ['slots', 'sidebarRightTabs', 'connection'],
270
+ apply(ctx) {
271
+ ctx.effect(() => ctx.sidebarRightTabs.register({ id, kind: 'dscode-browser', multiple: false, keepMounted: true, title: () => 'Browser preview', guide: [{ id: 'open', order: 31, title: () => 'Browser preview', description: () => 'Inspect the controlled Chrome tab and send a visual annotation.' }] }), 'dscode-browser-preview.type');
272
+ ctx.effect(() => ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register({ name: 'sidebar.right.pane.tab', key: id,
273
+ inject: sessionId => ({ sessionId, execute: async (action, args = {}) => {
274
+ const response = await ctx.connection.rpc.call('/api', 'dscode-browser', { sessionId, action, ...args });
275
+ if (!response.ok) throw Error(response.error.message);
276
+ return response.value;
277
+ } }),
278
+ }, Preview)), 'dscode-browser-preview.body');
279
+ },
280
+ };
281
+ },
282
+ });
@@ -0,0 +1,74 @@
1
+ import { browserForAgent } from './review.mjs';
2
+ import { BrowserPreview } from './preview.mjs';
3
+ import { clientRequestSchema } from '@deepseek-ai/dsh-client-connection';
4
+
5
+ // Reuse the Host's authenticated, origin-checked Connection carrier, including
6
+ // Electron's transport. Preview bytes never enter command lifecycle history.
7
+ export const inject = ['agents', 'commands'];
8
+ export function apply(ctx) {
9
+ const previews = new WeakMap();
10
+ ctx.inject(['connection'], scope => {
11
+ const dispatch = async (action, payload, signal) => {
12
+ try {
13
+ if (!payload || typeof payload !== 'object' || typeof payload.sessionId !== 'string') throw Error('Choose a live session.');
14
+ const agent = ctx.agents.get(payload.sessionId);
15
+ if (!agent) throw Error('The session is no longer active. Open it before using Browser preview.');
16
+ if (action === 'start' || action === 'stop' || action === 'resume') {
17
+ if (action === 'resume') {
18
+ const browser = browserForAgent(agent);
19
+ if (browser && previews.has(browser)) previews.get(browser).frame = undefined;
20
+ }
21
+ // Commands persist their result in conversation history before returning.
22
+ // Sidebar controls should leave the same readable status as typed commands.
23
+ const result = (await ctx.commands.execute(agent, `/browser ${action}`, [], signal))?.result;
24
+ if (result?.kind !== 'success') throw Error(result?.text ?? `Browser ${action} is unavailable.`);
25
+ return { ok: true, value: { message: result.text } };
26
+ }
27
+ const browser = browserForAgent(agent);
28
+ if (action === 'handoff') {
29
+ const permissions = browser?.status().connected ? await browser.access.status() : undefined;
30
+ // Reading grants can yield while the transport closes or enters handoff.
31
+ const state = browser?.status();
32
+ return { ok: true, value: { connected: state?.connected ?? false, handoff: state?.connected ? state.handoff ?? null : null,
33
+ ...(state?.connected ? { permissions } : {}) } };
34
+ }
35
+ if (!browser) throw Error('Start this session’s browser first.');
36
+ if (action === 'permission') {
37
+ if (!['once', 'allow', 'block', 'forget', 'developer-mode', 'developer-allow', 'developer-block'].includes(payload.change)) throw Error('Unknown browser permission change.');
38
+ const permissions = await browser.access.update(payload.change, payload.value);
39
+ if (previews.has(browser)) previews.get(browser).frame = undefined;
40
+ return { ok: true, value: { permissions } };
41
+ }
42
+ if (action === 'tabs') {
43
+ const result = await browser.call('list_pages', {}, signal);
44
+ if (result.isError) throw Error('Could not refresh browser tabs.');
45
+ return { ok: true, value: { ...browser.status(), permissions: await browser.access.status() } };
46
+ }
47
+ if (!previews.has(browser)) previews.set(browser, new BrowserPreview(browser));
48
+ const preview = previews.get(browser);
49
+ if (action === 'capture') {
50
+ const frame = await preview.capture(payload.pageId, signal);
51
+ const permissions = await browser.access.status();
52
+ browser.assertAgentControl();
53
+ await browser.access.checkUrl(frame.url);
54
+ browser.assertAgentControl();
55
+ if (preview.frame !== frame || !preview.isCurrent(frame)) throw Error('The browser page changed. Refresh the preview.');
56
+ return { ok: true, value: { ...frame, permissions } };
57
+ }
58
+ if (action === 'annotate') return { ok: true, value: await preview.annotate(payload.annotation, ctx, agent, signal) };
59
+ throw Error('Unknown browser preview action.');
60
+ } catch (error) { return { ok: false, error: { code: 'browser-preview', message: error.message, details: {} } }; }
61
+ };
62
+ scope.effect(() => scope.connection.fetch.register({ path: '/api/dscode-browser', methods: ['POST'], requestBody: 'buffered',
63
+ fetch: async request => {
64
+ let body;
65
+ try { body = await request.json(); } catch { return new Response('Invalid JSON', { status: 400 }); }
66
+ const parsed = clientRequestSchema.safeParse(body);
67
+ if (!parsed.success || parsed.data.method !== 'dscode-browser') return new Response('Invalid preview request', { status: 400 });
68
+ const { rpcId, payload } = parsed.data;
69
+ const result = await dispatch(payload?.action, payload, request.signal);
70
+ return Response.json({ type: 'server-response', rpcId, result }, { headers: { 'Cache-Control': 'no-store' } });
71
+ },
72
+ }), 'dscode-browser-preview.rpc');
73
+ }).then(undefined, error => { ctx.logger.error(`Browser preview transport failed: ${error.message}`); });
74
+ }
@@ -0,0 +1,57 @@
1
+ import { createHash } from 'node:crypto';
2
+
3
+ // Page.getFrameTree only covers frames served by its CDP target. Cross-process
4
+ // iframes have separate sessions already owned by the pinned MCP/Puppeteer graph.
5
+ // Borrow those sessions for read-only metadata; never attach to unrelated targets
6
+ // or detach the browser's live sessions.
7
+ async function documentIdentity(page, url) {
8
+ const describe = frame => ({ frame, id: frame._id, loader: frame._loaderId, url: frame.url(),
9
+ parent: frame.parentFrame()?._id ?? '', session: frame._client() });
10
+ const before = page.frames().map(describe);
11
+ const expected = new Map(before.map(frame => [frame.id, frame]));
12
+ const main = before.filter(frame => !frame.parent);
13
+ if (expected.size !== before.length || main.length !== 1 || main[0].url !== url) return null;
14
+ const sessions = [...new Set(before.map(frame => frame.session))];
15
+ const trees = await Promise.all(sessions.map(async session => ({ session,
16
+ tree: (await session.send('Page.getFrameTree', {}, { timeout: 5000 })).frameTree })));
17
+ const documents = new Map();
18
+ for (const { session, tree } of trees) {
19
+ const pending = [tree];
20
+ for (const node of pending) {
21
+ const frame = node.frame, observed = expected.get(frame.id);
22
+ const frameUrl = frame.url + (frame.urlFragment ?? '');
23
+ // A connection to an already loaded document can have no cached lifecycle
24
+ // loader yet. CDP supplies the identity; populated caches add a race check.
25
+ if (!observed || documents.has(frame.id) || observed.session !== session || !frame.loaderId ||
26
+ (observed.loader && observed.loader !== frame.loaderId) || observed.url !== frameUrl || observed.parent !== (frame.parentId ?? '')) return null;
27
+ documents.set(frame.id, [frame.id, frame.parentId ?? '', frame.loaderId, frameUrl]);
28
+ pending.push(...(node.childFrames ?? []));
29
+ }
30
+ }
31
+ if (documents.size !== before.length) return null;
32
+ const after = page.frames().map(describe);
33
+ if (after.length !== before.length || after.some(frame => {
34
+ const old = expected.get(frame.id);
35
+ return !old || ['frame', 'loader', 'url', 'parent', 'session'].some(key => frame[key] !== old[key]);
36
+ })) return null;
37
+ // Bound page-list metadata without exposing every embedded frame's URL.
38
+ const ordered = [...documents.values()].sort((a, b) => a[0].localeCompare(b[0]));
39
+ return 'frames-v1:' + createHash('sha256').update(JSON.stringify(ordered)).digest('hex');
40
+ }
41
+
42
+ /** Add browser-issued document identities without evaluating page JavaScript. */
43
+ export function installDocumentIdentity(McpResponse) {
44
+ const handle = McpResponse.prototype.handle;
45
+ if (typeof handle !== 'function') throw Error('Unsupported Chrome MCP response adapter.');
46
+ McpResponse.prototype.handle = async function (context, ...args) {
47
+ const result = await handle.call(this, context, ...args);
48
+ await Promise.all((result.structuredContent?.pages ?? []).map(async entry => {
49
+ // An unavailable identity must never compare equal to a captured one.
50
+ entry.documentId = null;
51
+ try {
52
+ entry.documentId = await documentIdentity(context.getPageById(entry.id).pptrPage, entry.url);
53
+ } catch { /* Tab closure or unavailable metadata leaves preview unavailable. */ }
54
+ }));
55
+ return result;
56
+ };
57
+ }
@@ -0,0 +1,66 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { createServer } from 'node:http';
3
+ import { WebSocketServer, WebSocket } from 'ws';
4
+
5
+ export const extensionId = 'ehdpecpkmekimhklnpeagobiimnbadfh';
6
+
7
+ /** Single-use, loopback-only bridge. Losing either peer revokes the pairing. */
8
+ export async function createExtensionRelay() {
9
+ const extensionToken = randomBytes(32).toString('hex');
10
+ const clientToken = randomBytes(32).toString('hex');
11
+ const server = createServer((_req, res) => { res.writeHead(404); res.end(); });
12
+ const sockets = new WebSocketServer({ noServer: true, maxPayload: 32 * 1024 * 1024 });
13
+ let extension;
14
+ let client;
15
+ let closed = false;
16
+ let ready = false;
17
+ let timer;
18
+ const listeners = new Set();
19
+ const close = () => {
20
+ if (closed) return;
21
+ closed = true;
22
+ clearTimeout(timer);
23
+ for (const socket of [client, extension]) socket?.terminate();
24
+ sockets.close();
25
+ server.close();
26
+ for (const listener of listeners) listener();
27
+ };
28
+ server.on('upgrade', (req, socket, head) => {
29
+ const origin = `127.0.0.1:${server.address()?.port}`;
30
+ const isExtension = req.url === `/extension?token=${extensionToken}`;
31
+ const isClient = req.url === `/cdp?token=${clientToken}`;
32
+ if (closed || req.headers.host !== origin ||
33
+ (isExtension ? !!extension || req.headers.origin !== `chrome-extension://${extensionId}` :
34
+ isClient ? !!client || !ready || req.headers.origin !== undefined : true)) {
35
+ socket.end('HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n');
36
+ return;
37
+ }
38
+ sockets.handleUpgrade(req, socket, head, ws => {
39
+ if (isExtension) extension = ws;
40
+ else { client = ws; clearTimeout(timer); }
41
+ ws.on('error', close);
42
+ ws.on('close', close);
43
+ ws.on('message', (data, binary) => {
44
+ if (binary) return close();
45
+ let value;
46
+ try { value = JSON.parse(data.toString()); } catch { return close(); }
47
+ if (isExtension && value?.type === 'ready') { ready = true; return; }
48
+ if (isExtension && value?.type === 'keepalive') return;
49
+ const peer = isExtension ? client : extension;
50
+ if (peer?.readyState === WebSocket.OPEN) peer.send(data.toString());
51
+ });
52
+ });
53
+ });
54
+ await new Promise((resolve, reject) => { server.once('error', reject); server.listen(0, '127.0.0.1', resolve); });
55
+ timer = setTimeout(close, 5 * 60 * 1000);
56
+ timer.unref();
57
+ const base = `ws://127.0.0.1:${server.address().port}`;
58
+ return {
59
+ pairingUrl: `${base}/extension?token=${extensionToken}`,
60
+ endpoint: `${base}/cdp?token=${clientToken}`,
61
+ get ready() { return ready && !closed; },
62
+ get closed() { return closed; },
63
+ onClose(listener) { listeners.add(listener); return () => listeners.delete(listener); },
64
+ close,
65
+ };
66
+ }
@@ -0,0 +1,32 @@
1
+ import { realpath, lstat, readlink } from 'node:fs/promises';
2
+ import path, { dirname, isAbsolute, relative, resolve } from 'node:path';
3
+
4
+ async function canonical(path) {
5
+ try { return await realpath(path); }
6
+ catch (error) {
7
+ if (error.code !== 'ENOENT') throw error;
8
+ const entry = await lstat(path).catch(error => { if (error.code === 'ENOENT') return undefined; throw error; });
9
+ if (entry?.isSymbolicLink()) return canonical(resolve(dirname(path), await readlink(path)));
10
+ const parent = dirname(path);
11
+ if (parent === path) throw error;
12
+ return resolve(await canonical(parent), relative(parent, path));
13
+ }
14
+ }
15
+
16
+ /** Both inputs must already be canonical absolute paths. */
17
+ export function withinFileRoot(root, target, paths = path) {
18
+ const rel = paths.relative(root, target);
19
+ return rel === '' || (!paths.isAbsolute(rel) && rel !== '..' && !rel.startsWith('..' + paths.sep));
20
+ }
21
+
22
+ /** Enforce file roots even for attached Chrome, where upstream skips some checks. */
23
+ export async function checkFileArguments(args, roots) {
24
+ const paths = Object.entries(args).filter(([key]) => /filepaths?$/i.test(key)).flatMap(([, value]) => Array.isArray(value) ? value : [value]);
25
+ if (!paths.length) return;
26
+ const allowed = await Promise.all(roots.map(root => canonical(resolve(root))));
27
+ for (const path of paths) {
28
+ if (typeof path !== 'string' || !isAbsolute(path)) throw Error('Browser file paths must be absolute and inside the workspace or browser artifact directory.');
29
+ const target = await canonical(path);
30
+ if (!allowed.some(root => withinFileRoot(root, target))) throw Error('Browser file path is outside the workspace and browser artifact directory.');
31
+ }
32
+ }