@toddzheng024/dscode-desktop 0.0.0-stage → 0.7.33

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 (484) 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 +641 -0
  7. package/docs/account-login.md +44 -0
  8. package/docs/auto-review.md +128 -0
  9. package/docs/browser-use.md +783 -0
  10. package/docs/computer-use.md +81 -0
  11. package/docs/custom-providers.md +88 -0
  12. package/docs/demo.md +76 -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 +190 -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 +30 -0
  54. package/docs/releases/0.7.4.md +16 -0
  55. package/docs/releases/0.7.5.md +18 -0
  56. package/docs/releases/0.7.6.md +29 -0
  57. package/docs/releases/0.7.7.md +36 -0
  58. package/docs/releases/0.7.8.md +14 -0
  59. package/docs/releases/0.7.9.md +15 -0
  60. package/docs/session-bridge.md +80 -0
  61. package/docs/session-cards.md +53 -0
  62. package/docs/session-communication.md +186 -0
  63. package/docs/session-metrics.md +41 -0
  64. package/docs/skills.md +81 -0
  65. package/docs/triggers.md +338 -0
  66. package/docs/tui-commands.md +204 -0
  67. package/extensions/browser/manifest.json +22 -0
  68. package/extensions/browser/popup.css +6 -0
  69. package/extensions/browser/popup.html +11 -0
  70. package/extensions/browser/popup.mjs +47 -0
  71. package/extensions/browser/protocol.mjs +168 -0
  72. package/extensions/browser/worker.mjs +94 -0
  73. package/icon.svg +7 -0
  74. package/locale/en.json +6 -0
  75. package/locale/zh-cn.json +6 -0
  76. package/node_modules/@deepseek-ai/node-addon-system/LICENSE +21 -0
  77. package/node_modules/@deepseek-ai/node-addon-system/README.i18n.yaml +6 -0
  78. package/node_modules/@deepseek-ai/node-addon-system/README.md +15 -0
  79. package/node_modules/@deepseek-ai/node-addon-system/README.zh.md +15 -0
  80. package/node_modules/@deepseek-ai/node-addon-system/lib/flock.d.ts +13 -0
  81. package/node_modules/@deepseek-ai/node-addon-system/lib/flock.js +51 -0
  82. package/node_modules/@deepseek-ai/node-addon-system/lib/index.d.ts +73 -0
  83. package/node_modules/@deepseek-ai/node-addon-system/lib/index.js +98 -0
  84. package/node_modules/@deepseek-ai/node-addon-system/package.json +45 -0
  85. package/node_modules/@deepseek-ai/node-addon-system/src/flock.c +164 -0
  86. package/node_modules/@deepseek-ai/node-addon-system/src/main.c +298 -0
  87. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/LICENSE +28 -0
  88. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/README.i18n.yaml +6 -0
  89. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/README.md +9 -0
  90. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/README.zh.md +9 -0
  91. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/bin/system.node +0 -0
  92. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/package.json +31 -0
  93. package/node_modules/@deepseek-ai/node-addon-system-darwin-arm64/prebuilds.json +6 -0
  94. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/LICENSE +28 -0
  95. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/README.i18n.yaml +6 -0
  96. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/README.md +9 -0
  97. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/README.zh.md +9 -0
  98. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/bin/system.node +0 -0
  99. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/package.json +31 -0
  100. package/node_modules/@deepseek-ai/node-addon-system-darwin-x64/prebuilds.json +6 -0
  101. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/LICENSE +28 -0
  102. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/README.i18n.yaml +6 -0
  103. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/README.md +11 -0
  104. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/README.zh.md +11 -0
  105. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/bin/glibc/system.node +0 -0
  106. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/bin/landlock-run +0 -0
  107. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/bin/musl/system.node +0 -0
  108. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/package.json +31 -0
  109. package/node_modules/@deepseek-ai/node-addon-system-linux-arm64/prebuilds.json +24 -0
  110. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/LICENSE +28 -0
  111. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/README.i18n.yaml +6 -0
  112. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/README.md +11 -0
  113. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/README.zh.md +11 -0
  114. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/glibc/system.node +0 -0
  115. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/landlock-run +0 -0
  116. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/bin/musl/system.node +0 -0
  117. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/package.json +31 -0
  118. package/node_modules/@deepseek-ai/node-addon-system-linux-x64/prebuilds.json +24 -0
  119. package/package.json +156 -4
  120. package/plugins/account/index.mjs +178 -0
  121. package/plugins/account/state.mjs +123 -0
  122. package/plugins/auto-review/audit.mjs +24 -0
  123. package/plugins/auto-review/index.mjs +267 -0
  124. package/plugins/auto-review/policy.mjs +92 -0
  125. package/plugins/browser/SKILL.md +158 -0
  126. package/plugins/browser/access.mjs +143 -0
  127. package/plugins/browser/config.mjs +60 -0
  128. package/plugins/browser/connection.mjs +385 -0
  129. package/plugins/browser/desktop-client.mjs +282 -0
  130. package/plugins/browser/desktop-host.mjs +74 -0
  131. package/plugins/browser/document-identity.mjs +57 -0
  132. package/plugins/browser/extension-relay.mjs +66 -0
  133. package/plugins/browser/files.mjs +32 -0
  134. package/plugins/browser/index.mjs +235 -0
  135. package/plugins/browser/mcp-entry.mjs +18 -0
  136. package/plugins/browser/mcp-tools.mjs +21 -0
  137. package/plugins/browser/presentation.mjs +45 -0
  138. package/plugins/browser/preview.mjs +77 -0
  139. package/plugins/browser/review.mjs +20 -0
  140. package/plugins/browser/screenshots.mjs +35 -0
  141. package/plugins/clipboard-image/clipboard-image.swift +56 -0
  142. package/plugins/clipboard-image/index.mjs +70 -0
  143. package/plugins/code-review/baseline.mjs +143 -0
  144. package/plugins/code-review/git.mjs +163 -0
  145. package/plugins/code-review/index.mjs +236 -0
  146. package/plugins/compaction/engine.mjs +304 -0
  147. package/plugins/compaction/tetris.mjs +65 -0
  148. package/plugins/compaction/threshold.mjs +98 -0
  149. package/plugins/computer-use/DESKTOP-SKILL.md +64 -0
  150. package/plugins/computer-use/desktop-host.mjs +75 -0
  151. package/plugins/computer-use/desktop-skill.mjs +28 -0
  152. package/plugins/computer-use/desktop-upstream.mjs +3 -0
  153. package/plugins/computer-use/index.mjs +37 -0
  154. package/plugins/cordis-config/plain.mjs +31 -0
  155. package/plugins/credentials/index.mjs +73 -0
  156. package/plugins/custom/adapter.mjs +110 -0
  157. package/plugins/custom/config.mjs +85 -0
  158. package/plugins/custom/desktop-client.mjs +150 -0
  159. package/plugins/custom/desktop-host.mjs +78 -0
  160. package/plugins/custom/images.mjs +32 -0
  161. package/plugins/custom/index.mjs +145 -0
  162. package/plugins/custom/wire.mjs +179 -0
  163. package/plugins/desktop/client.mjs +1041 -0
  164. package/plugins/desktop/index.mjs +10 -0
  165. package/plugins/desktop/shell-environment.mjs +9 -0
  166. package/plugins/desktop-workspace/hooks.mjs +29 -0
  167. package/plugins/desktop-workspace/index.mjs +37 -0
  168. package/plugins/dscode/board.mjs +260 -0
  169. package/plugins/dscode/child-target.mjs +11 -0
  170. package/plugins/dscode/control.mjs +17 -0
  171. package/plugins/dscode/desktop-client.mjs +55 -0
  172. package/plugins/dscode/desktop-host.mjs +37 -0
  173. package/plugins/dscode/index.mjs +270 -0
  174. package/plugins/email/cli.mjs +32 -0
  175. package/plugins/email/contacts.mjs +36 -0
  176. package/plugins/email/desktop-client.mjs +117 -0
  177. package/plugins/email/desktop-host.mjs +54 -0
  178. package/plugins/email/desktop-service.mjs +106 -0
  179. package/plugins/email/gmail-oauth.mjs +69 -0
  180. package/plugins/email/gmail-store.mjs +2 -0
  181. package/plugins/email/gmail.mjs +194 -0
  182. package/plugins/email/imap.mjs +136 -0
  183. package/plugins/email/inbox.d.mts +25 -0
  184. package/plugins/email/inbox.mjs +76 -0
  185. package/plugins/email/smtp.mjs +70 -0
  186. package/plugins/email/store.mjs +32 -0
  187. package/plugins/email-tools/index.mjs +46 -0
  188. package/plugins/exec/cli.mjs +64 -0
  189. package/plugins/exec/index.mjs +112 -0
  190. package/plugins/grok/adapter.mjs +114 -0
  191. package/plugins/grok/auth.mjs +76 -0
  192. package/plugins/grok/billing.mjs +146 -0
  193. package/plugins/grok/index.mjs +122 -0
  194. package/plugins/grok/models.mjs +129 -0
  195. package/plugins/grok/status.mjs +28 -0
  196. package/plugins/grok/wire.mjs +268 -0
  197. package/plugins/hub/catalog.mjs +82 -0
  198. package/plugins/hub/desktop-client.mjs +114 -0
  199. package/plugins/hub/desktop-host.mjs +129 -0
  200. package/plugins/i18n/messages.d.mts +21 -0
  201. package/plugins/i18n/messages.mjs +537 -0
  202. package/plugins/jev/approval.mjs +131 -0
  203. package/plugins/jev/client.mjs +74 -0
  204. package/plugins/jev/index.mjs +99 -0
  205. package/plugins/memory/content.mjs +57 -0
  206. package/plugins/memory/desktop-host.mjs +3 -0
  207. package/plugins/memory/index.mjs +168 -0
  208. package/plugins/memory/pipeline.mjs +79 -0
  209. package/plugins/memory/store.mjs +93 -0
  210. package/plugins/message-source/kind.mjs +20 -0
  211. package/plugins/opencode-go/adapter.mjs +96 -0
  212. package/plugins/opencode-go/command.mjs +128 -0
  213. package/plugins/opencode-go/index.mjs +120 -0
  214. package/plugins/opencode-go/models.mjs +58 -0
  215. package/plugins/opencode-go/oauth.mjs +194 -0
  216. package/plugins/opencode-go/search.mjs +86 -0
  217. package/plugins/opencode-go/usage.mjs +119 -0
  218. package/plugins/opencode-go/version.mjs +10 -0
  219. package/plugins/opencode-go/wire.mjs +73 -0
  220. package/plugins/openrouter/adapter.mjs +232 -0
  221. package/plugins/openrouter/index.mjs +123 -0
  222. package/plugins/openrouter/models.mjs +157 -0
  223. package/plugins/openrouter/search.mjs +113 -0
  224. package/plugins/openrouter/wire.mjs +101 -0
  225. package/plugins/providers/catalog.mjs +160 -0
  226. package/plugins/providers/chat-messages.mjs +120 -0
  227. package/plugins/providers/chat-stream.mjs +174 -0
  228. package/plugins/providers/desktop-client.mjs +84 -0
  229. package/plugins/providers/desktop-host.mjs +63 -0
  230. package/plugins/providers/effort.mjs +35 -0
  231. package/plugins/providers/http-errors.mjs +50 -0
  232. package/plugins/providers/openrouter-account.mjs +171 -0
  233. package/plugins/session-bridge/client.mjs +106 -0
  234. package/plugins/session-bridge/communication.mjs +260 -0
  235. package/plugins/session-bridge/index.mjs +68 -0
  236. package/plugins/session-bridge/mailbox.mjs +267 -0
  237. package/plugins/session-bridge/paths.mjs +21 -0
  238. package/plugins/session-bridge/server.mjs +172 -0
  239. package/plugins/session-bridge/tasks.mjs +229 -0
  240. package/plugins/session-cards/content.mjs +64 -0
  241. package/plugins/session-cards/index.mjs +38 -0
  242. package/plugins/session-cards/manager.mjs +140 -0
  243. package/plugins/session-metrics/attribution.mjs +30 -0
  244. package/plugins/session-metrics/balance.mjs +81 -0
  245. package/plugins/session-metrics/desktop-client.mjs +62 -0
  246. package/plugins/session-metrics/desktop-host.mjs +46 -0
  247. package/plugins/session-metrics/index.mjs +96 -0
  248. package/plugins/session-metrics/pricing.mjs +84 -0
  249. package/plugins/session-metrics/rate.mjs +59 -0
  250. package/plugins/session-metrics/store.mjs +75 -0
  251. package/plugins/session-metrics/turns.mjs +134 -0
  252. package/plugins/session-metrics/view.mjs +271 -0
  253. package/plugins/time-marks/desktop-host.mjs +2 -0
  254. package/plugins/time-marks/index.mjs +116 -0
  255. package/plugins/time-marks/marks.mjs +152 -0
  256. package/plugins/triggers/cli.mjs +558 -0
  257. package/plugins/triggers/commands.mjs +143 -0
  258. package/plugins/triggers/config.mjs +264 -0
  259. package/plugins/triggers/desktop-client.mjs +155 -0
  260. package/plugins/triggers/desktop-host.mjs +88 -0
  261. package/plugins/triggers/desktop-management.mjs +97 -0
  262. package/plugins/triggers/desktop-scheduler.mjs +125 -0
  263. package/plugins/triggers/host.mjs +24 -0
  264. package/plugins/triggers/index.mjs +27 -0
  265. package/plugins/triggers/job-cli.mjs +110 -0
  266. package/plugins/triggers/jobs.mjs +156 -0
  267. package/plugins/triggers/launchd.mjs +101 -0
  268. package/plugins/triggers/lease.mjs +24 -0
  269. package/plugins/triggers/log.mjs +104 -0
  270. package/plugins/triggers/management.mjs +181 -0
  271. package/plugins/triggers/options.mjs +117 -0
  272. package/plugins/triggers/overlay.mjs +7 -0
  273. package/plugins/triggers/poll.mjs +65 -0
  274. package/plugins/triggers/run.mjs +157 -0
  275. package/plugins/triggers/schedule.mjs +40 -0
  276. package/plugins/triggers/scheduler-service.mjs +46 -0
  277. package/plugins/triggers/scheduler.mjs +92 -0
  278. package/plugins/triggers/session-run.mjs +125 -0
  279. package/plugins/triggers/session.mjs +48 -0
  280. package/plugins/triggers/source-emit.mjs +19 -0
  281. package/plugins/triggers/source-host.mjs +78 -0
  282. package/plugins/triggers/source-ingress.mjs +70 -0
  283. package/plugins/triggers/source-sandbox.mjs +35 -0
  284. package/plugins/triggers/sources.mjs +45 -0
  285. package/plugins/triggers/spool.mjs +145 -0
  286. package/plugins/triggers/tools.mjs +67 -0
  287. package/plugins/triggers/unattended.mjs +18 -0
  288. package/plugins/tui-tools/composition.mjs +28 -0
  289. package/plugins/tui-tools/desktop-host.mjs +2 -0
  290. package/plugins/tui-tools/doctor-cli.mjs +22 -0
  291. package/plugins/tui-tools/doctor.mjs +148 -0
  292. package/plugins/tui-tools/hook-sources.mjs +113 -0
  293. package/plugins/tui-tools/hooks.mjs +23 -0
  294. package/plugins/tui-tools/index.mjs +268 -0
  295. package/plugins/tui-tools/sandbox-runner.mjs +123 -0
  296. package/plugins/tui-tools/shell.mjs +27 -0
  297. package/plugins/tui-tools/update.mjs +111 -0
  298. package/plugins/tui-tools/workspace-discovery.mjs +129 -0
  299. package/plugins/ultra/policy.mjs +42 -0
  300. package/plugins/worktree-subagent/worktree.mjs +56 -0
  301. package/runtime-sources.json +94 -0
  302. package/vendor/bash/LICENSE +21 -0
  303. package/vendor/bash/index.js +717 -0
  304. package/vendor/bash/types/background.d.ts +50 -0
  305. package/vendor/bash/types/index.d.ts +38 -0
  306. package/vendor/bash/types/render.d.ts +57 -0
  307. package/vendor/command-goal/LICENSE +21 -0
  308. package/vendor/command-goal/index.js +210 -0
  309. package/vendor/command-goal/types/index.d.ts +10 -0
  310. package/vendor/computer-use/LICENSE +21 -0
  311. package/vendor/computer-use/lib/approval-policy.js +12 -0
  312. package/vendor/computer-use/lib/approval-policy.js.map +1 -0
  313. package/vendor/computer-use/lib/artifacts.js +79 -0
  314. package/vendor/computer-use/lib/artifacts.js.map +1 -0
  315. package/vendor/computer-use/lib/backend.js +3 -0
  316. package/vendor/computer-use/lib/backend.js.map +1 -0
  317. package/vendor/computer-use/lib/client.js +369 -0
  318. package/vendor/computer-use/lib/client.js.map +1 -0
  319. package/vendor/computer-use/lib/config.js +159 -0
  320. package/vendor/computer-use/lib/config.js.map +1 -0
  321. package/vendor/computer-use/lib/confirmations.js +99 -0
  322. package/vendor/computer-use/lib/confirmations.js.map +1 -0
  323. package/vendor/computer-use/lib/diff.js +58 -0
  324. package/vendor/computer-use/lib/diff.js.map +1 -0
  325. package/vendor/computer-use/lib/errors.js +22 -0
  326. package/vendor/computer-use/lib/errors.js.map +1 -0
  327. package/vendor/computer-use/lib/exposure.js +244 -0
  328. package/vendor/computer-use/lib/exposure.js.map +1 -0
  329. package/vendor/computer-use/lib/index.js +66 -0
  330. package/vendor/computer-use/lib/index.js.map +1 -0
  331. package/vendor/computer-use/lib/leases.js +262 -0
  332. package/vendor/computer-use/lib/leases.js.map +1 -0
  333. package/vendor/computer-use/lib/providers/macos.js +243 -0
  334. package/vendor/computer-use/lib/providers/macos.js.map +1 -0
  335. package/vendor/computer-use/lib/providers/native-helper.js +726 -0
  336. package/vendor/computer-use/lib/providers/native-helper.js.map +1 -0
  337. package/vendor/computer-use/lib/providers/unsupported.js +51 -0
  338. package/vendor/computer-use/lib/providers/unsupported.js.map +1 -0
  339. package/vendor/computer-use/lib/service.js +608 -0
  340. package/vendor/computer-use/lib/service.js.map +1 -0
  341. package/vendor/computer-use/lib/skill.js +136 -0
  342. package/vendor/computer-use/lib/skill.js.map +1 -0
  343. package/vendor/computer-use/lib/target-resolver.js +180 -0
  344. package/vendor/computer-use/lib/target-resolver.js.map +1 -0
  345. package/vendor/computer-use/lib/tools.js +511 -0
  346. package/vendor/computer-use/lib/tools.js.map +1 -0
  347. package/vendor/computer-use/lib/types/approval-policy.d.ts +13 -0
  348. package/vendor/computer-use/lib/types/approval-policy.d.ts.map +1 -0
  349. package/vendor/computer-use/lib/types/artifacts.d.ts +10 -0
  350. package/vendor/computer-use/lib/types/artifacts.d.ts.map +1 -0
  351. package/vendor/computer-use/lib/types/backend.d.ts +124 -0
  352. package/vendor/computer-use/lib/types/backend.d.ts.map +1 -0
  353. package/vendor/computer-use/lib/types/client/index.d.ts +83 -0
  354. package/vendor/computer-use/lib/types/client/index.d.ts.map +1 -0
  355. package/vendor/computer-use/lib/types/config.d.ts +94 -0
  356. package/vendor/computer-use/lib/types/config.d.ts.map +1 -0
  357. package/vendor/computer-use/lib/types/confirmations.d.ts +23 -0
  358. package/vendor/computer-use/lib/types/confirmations.d.ts.map +1 -0
  359. package/vendor/computer-use/lib/types/diff.d.ts +5 -0
  360. package/vendor/computer-use/lib/types/diff.d.ts.map +1 -0
  361. package/vendor/computer-use/lib/types/errors.d.ts +15 -0
  362. package/vendor/computer-use/lib/types/errors.d.ts.map +1 -0
  363. package/vendor/computer-use/lib/types/exposure.d.ts +30 -0
  364. package/vendor/computer-use/lib/types/exposure.d.ts.map +1 -0
  365. package/vendor/computer-use/lib/types/index.d.ts +21 -0
  366. package/vendor/computer-use/lib/types/index.d.ts.map +1 -0
  367. package/vendor/computer-use/lib/types/leases.d.ts +81 -0
  368. package/vendor/computer-use/lib/types/leases.d.ts.map +1 -0
  369. package/vendor/computer-use/lib/types/providers/macos.d.ts +39 -0
  370. package/vendor/computer-use/lib/types/providers/macos.d.ts.map +1 -0
  371. package/vendor/computer-use/lib/types/providers/native-helper.d.ts +48 -0
  372. package/vendor/computer-use/lib/types/providers/native-helper.d.ts.map +1 -0
  373. package/vendor/computer-use/lib/types/providers/unsupported.d.ts +23 -0
  374. package/vendor/computer-use/lib/types/providers/unsupported.d.ts.map +1 -0
  375. package/vendor/computer-use/lib/types/service.d.ts +58 -0
  376. package/vendor/computer-use/lib/types/service.d.ts.map +1 -0
  377. package/vendor/computer-use/lib/types/skill.d.ts +14 -0
  378. package/vendor/computer-use/lib/types/skill.d.ts.map +1 -0
  379. package/vendor/computer-use/lib/types/target-resolver.d.ts +38 -0
  380. package/vendor/computer-use/lib/types/target-resolver.d.ts.map +1 -0
  381. package/vendor/computer-use/lib/types/tools.d.ts +6 -0
  382. package/vendor/computer-use/lib/types/tools.d.ts.map +1 -0
  383. package/vendor/computer-use/lib/types/types.d.ts +270 -0
  384. package/vendor/computer-use/lib/types/types.d.ts.map +1 -0
  385. package/vendor/computer-use/lib/types/web.d.ts +33 -0
  386. package/vendor/computer-use/lib/types/web.d.ts.map +1 -0
  387. package/vendor/computer-use/lib/types.js +9 -0
  388. package/vendor/computer-use/lib/types.js.map +1 -0
  389. package/vendor/computer-use/lib/web.js +188 -0
  390. package/vendor/computer-use/lib/web.js.map +1 -0
  391. package/vendor/computer-use/native/macos/Sources/Fixture/main.swift +412 -0
  392. package/vendor/computer-use/native/macos/Sources/Helper/CursorImage.swift +11 -0
  393. package/vendor/computer-use/native/macos/Sources/Helper/CursorMotion.swift +67 -0
  394. package/vendor/computer-use/native/macos/Sources/Helper/CursorOverlay.swift +840 -0
  395. package/vendor/computer-use/native/macos/Sources/Helper/TargetedPointer.swift +327 -0
  396. package/vendor/computer-use/native/macos/Sources/Helper/WindowNumberMatcher.swift +29 -0
  397. package/vendor/computer-use/native/macos/Sources/Helper/main.swift +1244 -0
  398. package/vendor/computer-use/native/macos/Sources/Monitor/main.swift +153 -0
  399. package/vendor/computer-use/native/macos/bin/dsh-computer-use-helper +0 -0
  400. package/vendor/computer-use/native/macos/manifest.json +14 -0
  401. package/vendor/persistent/LICENSE +21 -0
  402. package/vendor/persistent/index.js +411 -0
  403. package/vendor/persistent/types/index.d.ts +24 -0
  404. package/vendor/subagent/LICENSE +21 -0
  405. package/vendor/subagent/index.js +694 -0
  406. package/vendor/subagent/invariant.js +52 -0
  407. package/vendor/subagent/model-selection-settings.js +68 -0
  408. package/vendor/subagent/types/index.d.ts +82 -0
  409. package/vendor/subagent/types/invariant.d.ts +16 -0
  410. package/vendor/subagent/types/list-models.d.ts +10 -0
  411. package/vendor/subagent/types/model-selection-settings.d.ts +45 -0
  412. package/vendor/subagent/types/model-selection-state.d.ts +48 -0
  413. package/vendor/subagent/types/model-selection.d.ts +81 -0
  414. package/vendor/subagent-core/LICENSE +21 -0
  415. package/vendor/subagent-core/index.js +3202 -0
  416. package/vendor/subagent-core/invariant.js +76 -0
  417. package/vendor/subagent-core/typert.host.d.ts +3 -0
  418. package/vendor/subagent-core/typert.host.js +978 -0
  419. package/vendor/subagent-core/typert.remote-client.d.ts +25 -0
  420. package/vendor/subagent-core/typert.remote-client.js +114 -0
  421. package/vendor/subagent-core/types/archive-admission.d.ts +16 -0
  422. package/vendor/subagent-core/types/archive-admission.js +151 -0
  423. package/vendor/subagent-core/types/assistant-output.d.ts +48 -0
  424. package/vendor/subagent-core/types/assistant-output.js +73 -0
  425. package/vendor/subagent-core/types/catalog.d.ts +84 -0
  426. package/vendor/subagent-core/types/catalog.js +109 -0
  427. package/vendor/subagent-core/types/child-agent.d.ts +156 -0
  428. package/vendor/subagent-core/types/child-agent.js +213 -0
  429. package/vendor/subagent-core/types/client.d.ts +8 -0
  430. package/vendor/subagent-core/types/client.js +7 -0
  431. package/vendor/subagent-core/types/continuation-activation.d.ts +267 -0
  432. package/vendor/subagent-core/types/continuation-activation.js +700 -0
  433. package/vendor/subagent-core/types/continuation-messages.d.ts +62 -0
  434. package/vendor/subagent-core/types/continuation-messages.js +106 -0
  435. package/vendor/subagent-core/types/continuation.d.ts +124 -0
  436. package/vendor/subagent-core/types/continuation.js +455 -0
  437. package/vendor/subagent-core/types/control-types.d.ts +135 -0
  438. package/vendor/subagent-core/types/control-types.js +8 -0
  439. package/vendor/subagent-core/types/control.d.ts +45 -0
  440. package/vendor/subagent-core/types/control.js +79 -0
  441. package/vendor/subagent-core/types/depth.d.ts +31 -0
  442. package/vendor/subagent-core/types/depth.js +39 -0
  443. package/vendor/subagent-core/types/descriptor.d.ts +144 -0
  444. package/vendor/subagent-core/types/descriptor.js +193 -0
  445. package/vendor/subagent-core/types/error.d.ts +11 -0
  446. package/vendor/subagent-core/types/error.js +14 -0
  447. package/vendor/subagent-core/types/inbox.d.ts +43 -0
  448. package/vendor/subagent-core/types/inbox.js +61 -0
  449. package/vendor/subagent-core/types/index.d.ts +320 -0
  450. package/vendor/subagent-core/types/index.js +475 -0
  451. package/vendor/subagent-core/types/internal.d.ts +58 -0
  452. package/vendor/subagent-core/types/internal.js +58 -0
  453. package/vendor/subagent-core/types/invariant.d.ts +13 -0
  454. package/vendor/subagent-core/types/invariant.js +91 -0
  455. package/vendor/subagent-core/types/lifecycle.d.ts +113 -0
  456. package/vendor/subagent-core/types/lifecycle.js +180 -0
  457. package/vendor/subagent-core/types/list-children.d.ts +36 -0
  458. package/vendor/subagent-core/types/list-children.js +166 -0
  459. package/vendor/subagent-core/types/out-of-process.d.ts +118 -0
  460. package/vendor/subagent-core/types/out-of-process.js +219 -0
  461. package/vendor/subagent-core/types/projection-types.d.ts +82 -0
  462. package/vendor/subagent-core/types/projection-types.js +7 -0
  463. package/vendor/subagent-core/types/projection.d.ts +100 -0
  464. package/vendor/subagent-core/types/projection.js +157 -0
  465. package/vendor/subagent-core/types/run-settlement.d.ts +17 -0
  466. package/vendor/subagent-core/types/run-settlement.js +70 -0
  467. package/vendor/subagent-core/types/types.d.ts +377 -0
  468. package/vendor/subagent-core/types/types.js +19 -0
  469. package/vendor/subagent-driver/LICENSE +21 -0
  470. package/vendor/subagent-driver/index.js +255 -0
  471. package/vendor/subagent-driver/types/index.d.ts +33 -0
  472. package/vendor/subagent-driver/types/structured.d.ts +42 -0
  473. package/vendor/subagent-fork/LICENSE +21 -0
  474. package/vendor/subagent-fork/index.js +61 -0
  475. package/vendor/subagent-fork/types/index.d.ts +20 -0
  476. package/vendor/subagent-spawn/LICENSE +21 -0
  477. package/vendor/subagent-spawn/index.js +45 -0
  478. package/vendor/subagent-spawn/types/index.d.ts +19 -0
  479. package/vendor/terminal/LICENSE +21 -0
  480. package/vendor/terminal/index.js +1093 -0
  481. package/vendor/terminal/types/config.d.ts +82 -0
  482. package/vendor/terminal/types/index.d.ts +36 -0
  483. package/vendor/terminal/types/sanitize.d.ts +47 -0
  484. package/vendor/terminal/types/session.d.ts +87 -0
@@ -0,0 +1,101 @@
1
+ // Installing a trigger into the system scheduler. launchd owns the clock
2
+ // (docs/triggers-design.md), so this module turns one definition into a
3
+ // LaunchAgent plist and, for anything launchd cannot express, into the crontab
4
+ // line a person can paste. Nothing here runs a session or decides anything about
5
+ // a run: it is text generation plus two launchctl calls.
6
+ //
7
+ // Only shapes launchd can express are accepted on purpose. A cron expression it
8
+ // cannot map (ranges, steps, lists) fails the install with a message rather than
9
+ // silently scheduling something else.
10
+
11
+ import { join } from 'node:path';
12
+
13
+ /** Label prefix for a DSCODE trigger agent; one label per trigger id. */
14
+ export const AGENT_LABEL_PREFIX = 'ai.dscode.trigger.';
15
+
16
+ /** Where an installed agent's plist and its launchd output live. */
17
+ export const agentPath = (home, id) => join(home, 'triggers', 'agents', `${id}.plist`);
18
+ export const agentStdoutPath = (home, id) => join(home, 'triggers', 'agents', `${id}.log`);
19
+ export const agentLabel = id => `${AGENT_LABEL_PREFIX}${id}`;
20
+
21
+ const CRON_FIELDS = ['Minute', 'Hour', 'Day', 'Month', 'Weekday'];
22
+
23
+ /**
24
+ * Map a five-field cron expression onto launchd's StartCalendarInterval keys.
25
+ * Only `*` and plain numbers are accepted: launchd has no syntax for ranges,
26
+ * steps or lists, so those are refused instead of approximated.
27
+ * @param cron - `minute hour day month weekday`.
28
+ * @returns the keys an integer-valued StartCalendarInterval may carry.
29
+ * @throws {Error} with a user-facing message for anything launchd cannot express.
30
+ */
31
+ export function cronToCalendarInterval(cron) {
32
+ const fields = String(cron).trim().split(/\s+/u);
33
+ if (fields.length !== 5) throw new Error('the cron expression needs five fields (minute hour day month weekday)');
34
+ const interval = {};
35
+ fields.forEach((field, index) => {
36
+ if (field === '*') return;
37
+ if (!/^\d{1,2}$/u.test(field)) {
38
+ throw new Error(`launchd cannot schedule "${field}" in the ${CRON_FIELDS[index]} field: use intervals for a cadence, or plain numbers here`);
39
+ }
40
+ interval[CRON_FIELDS[index]] = Number(field);
41
+ });
42
+ if (Object.keys(interval).length === 0) throw new Error('a cron expression of five "*" fields would fire every minute; use an interval instead');
43
+ return interval;
44
+ }
45
+
46
+ /** Escape the five XML characters a plist value may contain. */
47
+ const xml = value => String(value).replace(/[<>&"']/gu, char => ({ '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;', "'": '&apos;' }[char]));
48
+
49
+ /**
50
+ * Build the LaunchAgent plist for one definition.
51
+ * @param definition - a normalized definition.
52
+ * @param options - `{ home, dscodePath, project }`; `dscodePath` must be absolute.
53
+ * @returns the plist XML.
54
+ * @throws {Error} when the source has no schedule to install.
55
+ */
56
+ export function launchAgent(definition, { home, dscodePath, project }) {
57
+ const args = [dscodePath, 'trigger', 'run', definition.id, '--project', project];
58
+ const lines = [
59
+ '<?xml version="1.0" encoding="UTF-8"?>',
60
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
61
+ '<plist version="1.0">',
62
+ '<dict>',
63
+ ` <key>Label</key><string>${xml(agentLabel(definition.id))}</string>`,
64
+ ' <key>ProgramArguments</key>',
65
+ ' <array>',
66
+ ...args.map(argument => ` <string>${xml(argument)}</string>`),
67
+ ' </array>',
68
+ ` <key>WorkingDirectory</key><string>${xml(definition.workspace)}</string>`,
69
+ ' <key>ProcessType</key><string>Background</string>',
70
+ ` <key>StandardOutPath</key><string>${xml(agentStdoutPath(home, definition.id))}</string>`,
71
+ ` <key>StandardErrorPath</key><string>${xml(agentStdoutPath(home, definition.id))}</string>`,
72
+ ];
73
+ const { kind } = definition.source;
74
+ if (kind === 'interval') lines.push(` <key>StartInterval</key><integer>${definition.source.seconds}</integer>`);
75
+ else if (kind === 'poll') lines.push(` <key>StartInterval</key><integer>${definition.source.everySeconds}</integer>`);
76
+ else if (kind === 'calendar') {
77
+ const interval = cronToCalendarInterval(definition.source.cron);
78
+ lines.push(' <key>StartCalendarInterval</key>', ' <dict>', ...Object.entries(interval).map(([key, value]) => ` <key>${key}</key><integer>${value}</integer>`), ' </dict>');
79
+ } else if (kind === 'watch') {
80
+ lines.push(' <key>WatchPaths</key>', ' <array>', ...definition.source.paths.map(path => ` <string>${xml(path)}</string>`), ' </array>');
81
+ } else {
82
+ throw new Error(`a "${kind}" source has nothing to schedule: producers post into its spool with "dscode trigger emit ${definition.id}"`);
83
+ }
84
+ lines.push('</dict>', '</plist>', '');
85
+ return lines.join('\n');
86
+ }
87
+
88
+ /**
89
+ * The crontab line for the same schedule, for a machine without launchd.
90
+ * @returns the line, or a comment explaining why there is none.
91
+ */
92
+ export function crontabLine(definition, { dscodePath, project }) {
93
+ const command = `${dscodePath} trigger run ${definition.id} --project ${project}`;
94
+ if (definition.source.kind === 'calendar') return `${definition.source.cron} ${command}`;
95
+ const seconds = definition.source.kind === 'interval' ? definition.source.seconds
96
+ : definition.source.kind === 'poll' ? definition.source.everySeconds : undefined;
97
+ if (seconds === undefined) return `# ${definition.id}: a "${definition.source.kind}" source has no crontab form; producers post events instead`;
98
+ if (seconds % 60 !== 0) return `# ${definition.id}: ${seconds}s is not a whole number of minutes; cron runs at minute resolution`;
99
+ const minutes = seconds / 60;
100
+ return minutes < 60 ? `*/${minutes} * * * * ${command}` : `0 */${Math.round(minutes / 60)} * * * ${command}`;
101
+ }
@@ -0,0 +1,24 @@
1
+ // A permanent inode and a kernel lock serialize CLI processes. The Host inherits
2
+ // the descriptor so a killed parent cannot leave a still-running session unowned.
3
+ import { closeSync, mkdirSync, openSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { tryLockExclusive } from '@deepseek-ai/node-addon-system/flock';
6
+ import { setTimeout as sleep } from 'node:timers/promises';
7
+
8
+ export async function acquireTriggerLease(home, id, { wait = false, delay = sleep } = {}) {
9
+ const directory = join(home, 'triggers', 'locks');
10
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
11
+ const fd = openSync(join(directory, `${id}.guard`), 'a', 0o600);
12
+ try {
13
+ for (;;) {
14
+ try { await tryLockExclusive(fd); break; }
15
+ catch (error) {
16
+ if (!['EAGAIN', 'EWOULDBLOCK'].includes(error.code)) throw error;
17
+ if (!wait) { closeSync(fd); return undefined; }
18
+ await delay(100);
19
+ }
20
+ }
21
+ let released = false;
22
+ return { fd, release() { if (!released) { released = true; closeSync(fd); } } };
23
+ } catch (error) { closeSync(fd); throw error; }
24
+ }
@@ -0,0 +1,104 @@
1
+ // The run log: the durable record every trigger run appends, and the pipe a
2
+ // failure notifier will read later (docs/triggers-design.md). One JSONL file for
3
+ // outcomes plus a per-run text tail for the transcript end. A record must carry
4
+ // enough to explain a run without the terminal: what fired, which session, how
5
+ // it ended, and why.
6
+
7
+ import { appendFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
8
+ import { dirname, join } from 'node:path';
9
+
10
+ /** Outcomes a run record may carry. */
11
+ export const OUTCOMES = Object.freeze(['completed', 'skipped', 'failed', 'timedout', 'blocked', 'overrun']);
12
+
13
+ /** Stable skip/failure reasons; `null` on a clean completion. */
14
+ export const REASONS = Object.freeze([
15
+ 'model_error', 'approval_required', 'goal_blocked', 'goal_paused', 'round_cap', 'cost_cap', 'timeout', 'interrupted',
16
+ 'already_running', 'no_match', 'duplicate', 'disabled', 'over_daily_limit', 'too_soon', 'workspace_missing',
17
+ ]);
18
+
19
+ const isPlainObject = value => typeof value === 'object' && value !== null && !Array.isArray(value);
20
+
21
+ class RunLogError extends Error {}
22
+
23
+ const fail = message => { throw new RunLogError(message); };
24
+
25
+ /** The append-only outcome log for one state directory. */
26
+ export const runsPath = home => join(home, 'triggers', 'runs.jsonl');
27
+
28
+ /** The text tail of one run (the agent's own last words), beside the outcome log. */
29
+ export const runTailPath = (home, triggerId, runId) => join(home, 'triggers', 'logs', triggerId, `${runId}.log`);
30
+
31
+ /**
32
+ * Append one run record.
33
+ * @param home - the state directory.
34
+ * @param record - the record; see the design record for the field set.
35
+ * @returns the record that was written.
36
+ * @throws {RunLogError} when a required field is missing or a value is outside the vocabulary.
37
+ */
38
+ export function appendRun(home, record) {
39
+ if (!isPlainObject(record)) fail('a run record must be an object');
40
+ for (const field of ['triggerId', 'runId', 'startedAt', 'outcome', 'exitCode']) {
41
+ if (record[field] === undefined) fail(`a run record needs ${field}`);
42
+ }
43
+ if (typeof record.triggerId !== 'string' || record.triggerId === '') fail('triggerId must be a non-empty string');
44
+ if (typeof record.runId !== 'string' || record.runId === '') fail('runId must be a non-empty string');
45
+ if (!Number.isFinite(record.startedAt)) fail('startedAt must be a number (epoch milliseconds)');
46
+ if (!Number.isSafeInteger(record.exitCode)) fail('exitCode must be a whole number');
47
+ if (!OUTCOMES.includes(record.outcome)) fail(`outcome must be one of: ${OUTCOMES.join(', ')}`);
48
+ if (record.reason !== null && record.reason !== undefined && !REASONS.includes(record.reason)) {
49
+ fail(`reason must be null or one of: ${REASONS.join(', ')}`);
50
+ }
51
+ const path = runsPath(home);
52
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
53
+ appendFileSync(path, JSON.stringify({ endedAt: null, sessionId: null, cost: null, rounds: null, ...record, reason: record.reason ?? null }) + '\n', { mode: 0o600 });
54
+ return record;
55
+ }
56
+
57
+ /**
58
+ * Read recent run records, newest first. A torn or unreadable line is skipped
59
+ * rather than failing the listing: the log is append-only and a half-written
60
+ * line is what a crash mid-append leaves behind.
61
+ * @param home - the state directory.
62
+ * @param options - `{ triggerId, limit }`.
63
+ * @returns run records, newest first.
64
+ */
65
+ export function readRuns(home, { triggerId, limit = 20 } = {}) {
66
+ let raw;
67
+ try {
68
+ raw = readFileSync(runsPath(home), 'utf8');
69
+ } catch {
70
+ return [];
71
+ }
72
+ const records = [];
73
+ for (const line of raw.split('\n')) {
74
+ if (line.trim() === '') continue;
75
+ let record;
76
+ try {
77
+ record = JSON.parse(line);
78
+ } catch {
79
+ continue;
80
+ }
81
+ if (triggerId !== undefined && record.triggerId !== triggerId) continue;
82
+ records.push(record);
83
+ }
84
+ records.reverse();
85
+ return limit === 0 ? records : records.slice(0, limit);
86
+ }
87
+
88
+ /** Write (replacing) one run's text tail. */
89
+ export function writeRunTail(home, triggerId, runId, text) {
90
+ const path = runTailPath(home, triggerId, runId);
91
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
92
+ writeFileSync(path, text, { mode: 0o600 });
93
+ return path;
94
+ }
95
+
96
+ /** One record as the single listing line `/triggers` shows. */
97
+ export function formatRun(record) {
98
+ if (record === undefined) return 'never ran';
99
+ const when = new Date(record.startedAt).toISOString().replace('T', ' ').slice(0, 19);
100
+ const reason = record.reason === null || record.reason === undefined ? '' : ` (${record.reason})`;
101
+ const cost = Number.isFinite(record.cost) ? ` $${record.cost.toFixed(2)}` : '';
102
+ const rounds = Number.isFinite(record.rounds) ? ` ${record.rounds}r` : '';
103
+ return `${when} ${record.outcome}${reason} exit ${record.exitCode}${cost}${rounds}`;
104
+ }
@@ -0,0 +1,181 @@
1
+ // Agent-facing management uses the same definitions, jobs and scheduler as the CLI.
2
+ import { existsSync, lstatSync, mkdirSync, renameSync, rmSync, writeFileSync, linkSync } from 'node:fs';
3
+ import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
4
+ import { randomUUID } from 'node:crypto';
5
+ import { spawn } from 'node:child_process';
6
+ import { stringify } from 'yaml';
7
+ import { loadTriggerDefinitions, normalizeTrigger } from './config.mjs';
8
+ import { JobStore } from './jobs.mjs';
9
+ import { normalizeEvent } from './spool.mjs';
10
+ import { dueTime } from './schedule.mjs';
11
+ import { acquireTriggerLease } from './lease.mjs';
12
+ import { schedulerService } from './scheduler-service.mjs';
13
+
14
+ const stable = value => JSON.stringify(value, (_key, item) => item && typeof item === 'object' && !Array.isArray(item)
15
+ ? Object.fromEntries(Object.entries(item).sort(([a], [b]) => a.localeCompare(b))) : item);
16
+ const required = (value, label) => { if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} is required`); return value; };
17
+ const clean = definition => Object.fromEntries(Object.entries(definition).filter(([key]) => !['origin', 'path', 'overrides'].includes(key)));
18
+
19
+ /** No shell, inherited input or unbounded launchctl wait. */
20
+ function launchctl(args, { ignoreFailure = false } = {}) {
21
+ return new Promise((resolveRun, reject) => {
22
+ const child = spawn('/bin/launchctl', args, { stdio: 'ignore' });
23
+ const timer = setTimeout(() => child.kill('SIGKILL'), 10000);
24
+ child.once('error', error => { clearTimeout(timer); if (ignoreFailure) resolveRun(1); else reject(error); });
25
+ child.once('exit', code => { clearTimeout(timer); if (code === 0 || ignoreFailure) resolveRun(code ?? 1); else reject(new Error(`launchctl failed (${code})`)); });
26
+ });
27
+ }
28
+
29
+ export class TriggerManagement {
30
+ constructor({ home, dscodePath, platform = process.platform, now = Date.now, service = schedulerService, runLaunchctl = launchctl }) {
31
+ Object.assign(this, { home, dscodePath, platform, now, service, runLaunchctl });
32
+ }
33
+ workspace(agent) {
34
+ const cwd = agent?.session?.header?.cwd;
35
+ if (!cwd || !isAbsolute(cwd)) throw new Error('A session bound to a workspace is required');
36
+ return resolve(cwd);
37
+ }
38
+ definitions(project) { return loadTriggerDefinitions({ home: this.home, workspace: project }); }
39
+ definition(project, id) {
40
+ required(id, 'trigger_id');
41
+ const definition = this.definitions(project).definitions.find(item => item.id === id);
42
+ if (!definition) throw new Error(`No trigger "${id}"`);
43
+ if (resolve(definition.workspace) !== project) throw new Error('The trigger belongs to another workspace');
44
+ return definition;
45
+ }
46
+ runnable(definition) {
47
+ if (!['read-only', 'workspace-write'].includes(definition.permission) || definition.preset !== 'dscode') {
48
+ throw new Error('Agent-managed scheduling requires the dscode preset and read-only or workspace-write permission');
49
+ }
50
+ }
51
+ withStore(fn) {
52
+ const store = new JobStore(this.home);
53
+ try { return fn(store); } finally { store.close(); }
54
+ }
55
+ async status() {
56
+ const lease = await acquireTriggerLease(this.home, '_scheduler');
57
+ const running = !lease;
58
+ lease?.release();
59
+ return { running, ...(!running ? { next_step: 'Use trigger_scheduler(action="install") on macOS, or run dscode trigger scheduler start under a service manager.' } : {}) };
60
+ }
61
+ write(project, definition, existing) {
62
+ const directory = join(project, '.dsh', 'triggers');
63
+ // Do not turn a project-local tool into an arbitrary-file writer via symlinks.
64
+ for (const path of [join(project, '.dsh'), directory]) {
65
+ if (existsSync(path) && lstatSync(path).isSymbolicLink()) throw new Error('Trigger configuration directories must not be symlinks');
66
+ }
67
+ mkdirSync(directory, { recursive: true });
68
+ const path = existing?.path ?? join(directory, `${definition.id}.yml`);
69
+ if (relative(directory, dirname(path)) !== '' || (existsSync(path) && lstatSync(path).isSymbolicLink())) throw new Error('Only regular project-local definitions can be changed');
70
+ const body = path.endsWith('.json') ? JSON.stringify(clean(definition), null, 2) + '\n' : stringify(clean(definition));
71
+ const temp = join(directory, `.${randomUUID()}.tmp`);
72
+ try {
73
+ writeFileSync(temp, body, { flag: 'wx', mode: 0o600 });
74
+ if (existing) renameSync(temp, path);
75
+ else linkSync(temp, path); // Never overwrite a concurrently created definition.
76
+ } finally { rmSync(temp, { force: true }); }
77
+ return path;
78
+ }
79
+ async manage(args, agent) {
80
+ const project = this.workspace(agent);
81
+ const { action, trigger_id: id } = args;
82
+ if (action === 'list') {
83
+ const found = this.definitions(project);
84
+ return { definitions: found.definitions.filter(d => resolve(d.workspace) === project), problems: found.problems, schedules: this.withStore(s => s.schedules().filter(row => row.project === project)), sources: this.withStore(s => s.sources().filter(row => row.project === project)), scheduler: await this.status() };
85
+ }
86
+ if (action === 'get') return { definition: this.definition(project, id) };
87
+ if (!['create', 'update', 'enable', 'disable', 'register', 'unregister'].includes(action)) throw new Error('Unknown trigger action');
88
+ let definition;
89
+ if (action === 'create' || action === 'update') {
90
+ required(id, 'trigger_id');
91
+ const found = this.definitions(project);
92
+ const existing = found.definitions.find(d => d.id === id);
93
+ if (action === 'create' && existing) throw new Error('Trigger already exists; use update');
94
+ if (action === 'update' && (!existing || existing.origin !== 'project')) throw new Error('Only existing project-local definitions can be updated');
95
+ if (existing && resolve(existing.workspace) !== project) throw new Error('The trigger belongs to another workspace');
96
+ // A broken JSON/YAML file must be repaired explicitly, never shadowed by a new extension.
97
+ if (found.problems.some(p => ['yml', 'yaml', 'json'].some(ext => p.path === join(project, '.dsh', 'triggers', `${id}.${ext}`)))) throw new Error('Repair the unreadable definition before editing it');
98
+ const patch = args.definition;
99
+ if (!patch || typeof patch !== 'object' || Array.isArray(patch)) throw new Error('definition is required for create/update');
100
+ const allowed = ['prompt', 'source', 'goal', 'limits', 'session', 'enabled', 'permission', 'model', 'effort'];
101
+ if (Object.keys(patch).some(key => !allowed.includes(key))) throw new Error(`definition accepts only ${allowed.join(', ')}`);
102
+ const base = existing ? clean(existing) : {};
103
+ if (patch.session) delete base.overlap;
104
+ definition = normalizeTrigger({ ...base, ...patch, id, workspace: project, preset: 'dscode' }, { origin: 'project' });
105
+ if (!['external', 'calendar', 'interval', 'script'].includes(definition.source.kind)) throw new Error('Agent-managed sources must be external, calendar, interval or script');
106
+ this.runnable(definition);
107
+ definition.path = this.write(project, definition, existing);
108
+ // Creating/editing a recurring source also registers it; external has no cadence.
109
+ this.withStore(s => definition.source.kind === 'external' ? s.unregister(id, project, this.now()) : s.register(definition, project, this.now()));
110
+ } else {
111
+ definition = this.definition(project, id);
112
+ if (action === 'register') {
113
+ this.runnable(definition);
114
+ this.withStore(s => s.register(definition, project, this.now()));
115
+ } else if (action === 'unregister') this.withStore(s => s.unregister(id, project, this.now()));
116
+ else {
117
+ if (definition.origin !== 'project') throw new Error('Only project-local definitions can be enabled or disabled');
118
+ definition.enabled = action === 'enable';
119
+ if (definition.enabled) this.runnable(definition);
120
+ this.write(project, definition, definition);
121
+ }
122
+ }
123
+ return { definition, action, scheduler: await this.status() };
124
+ }
125
+ async source(args, agent) {
126
+ const project = this.workspace(agent);
127
+ const definition = this.definition(project, args.trigger_id);
128
+ if (definition.source.kind !== 'script') throw new Error('source management requires a script source');
129
+ const source = this.withStore(s => {
130
+ if (['status', 'logs'].includes(args.action)) return s.source(definition.id, project);
131
+ this.runnable(definition);
132
+ return s.controlSource(definition, project, args.action);
133
+ });
134
+ if (args.action === 'logs') return { log: source?.log ?? '' };
135
+ return { source: source ?? { status: 'unregistered' }, scheduler: await this.status() };
136
+ }
137
+ async emit(args, agent) {
138
+ const project = this.workspace(agent);
139
+ const definition = this.definition(project, args.trigger_id);
140
+ this.runnable(definition);
141
+ const job = this.withStore(s => s.acceptEvent({ definition, project, payload: args.event ?? {}, eventId: args.eventId, now: this.now() }));
142
+ return { job, scheduler: await this.status() };
143
+ }
144
+ async jobs(args, agent) {
145
+ const project = this.workspace(agent);
146
+ const now = this.now();
147
+ if (args.action === 'list') {
148
+ const limit = args.limit ?? 50;
149
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100) throw new Error('limit must be 1..100');
150
+ return { jobs: this.withStore(s => s.list(args.trigger_id).filter(j => j.project === project && j.workspace === project).slice(0, limit)), scheduler: await this.status() };
151
+ }
152
+ if (args.action === 'cancel') {
153
+ required(args.job_id, 'job_id');
154
+ return this.withStore(s => {
155
+ const job = s.get(args.job_id);
156
+ if (!job || job.project !== project || job.workspace !== project) throw new Error('No job in this workspace');
157
+ if (job.state !== 'cancelled') s.cancel(job.id, now);
158
+ return { job: s.get(job.id) };
159
+ });
160
+ }
161
+ if (args.action !== 'schedule') throw new Error('Unknown job action');
162
+ const definition = this.definition(project, args.trigger_id);
163
+ this.runnable(definition);
164
+ const requestKey = required(args.idempotency_key, 'idempotency_key');
165
+ if (requestKey.length > 200) throw new Error('idempotency_key must be at most 200 characters');
166
+ const payload = args.event ?? {};
167
+ normalizeEvent(definition.id, payload, { eventId: 'validation', now });
168
+ // Lookup a retry before future-time validation: its original due time may have passed.
169
+ const request = stable({ triggerId: definition.id, after: args.after, at: args.at, payload });
170
+ const job = this.withStore(s => s.createOnce({ requestKey, request, triggerId: definition.id, project, workspace: project, payload, dueAt: () => dueTime(args, now), now }));
171
+ return { job, scheduler: await this.status() };
172
+ }
173
+ async scheduler(args) {
174
+ if (args.action === 'status') return this.status();
175
+ if (args.action !== 'install') throw new Error('Scheduler action must be status or install');
176
+ if (!this.dscodePath || !isAbsolute(this.dscodePath) || !existsSync(this.dscodePath)) throw new Error('Restart DSCODE to provide its launcher path, or install the scheduler through the CLI');
177
+ const messages = [];
178
+ await this.service('install', { home: this.home, dscodePath: this.dscodePath, platform: this.platform, launchctl: this.runLaunchctl, out: text => messages.push(text) });
179
+ return { messages, scheduler: await this.status() };
180
+ }
181
+ }
@@ -0,0 +1,117 @@
1
+ // The run spec and run result: the two files that cross the process boundary
2
+ // between `dscode trigger run` (which owns the lock, the limits and the record)
3
+ // and the Host it spawns (which owns the agent, the goal and the transcript).
4
+ // Keeping them small and validated is what lets either half be tested alone.
5
+
6
+ import { readFileSync, writeFileSync } from 'node:fs';
7
+
8
+ const isPlainObject = value => typeof value === 'object' && value !== null && !Array.isArray(value);
9
+
10
+ class TriggerIoError extends Error {}
11
+
12
+ const fail = message => { throw new TriggerIoError(message); };
13
+
14
+ /** Write one JSON file atomically enough for a spawned child to read it once. */
15
+ function writeJson(path, value) {
16
+ writeFileSync(path, JSON.stringify(value, null, 2) + '\n', { mode: 0o600 });
17
+ return path;
18
+ }
19
+
20
+ /** Read a JSON file that must exist and must be an object. */
21
+ function readJson(path, label) {
22
+ let raw;
23
+ try {
24
+ raw = readFileSync(path, 'utf8');
25
+ } catch (error) {
26
+ fail(`${label} is unreadable: ${error?.code ?? error?.message ?? error}`);
27
+ }
28
+ try {
29
+ const value = JSON.parse(raw);
30
+ if (!isPlainObject(value)) fail(`${label} must be an object`);
31
+ return value;
32
+ } catch (error) {
33
+ fail(`${label} is not valid JSON: ${error?.message ?? error}`);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Render the prompt one run sends: the definition's template with the event's
39
+ * values substituted. A template that never mentions the event text gets it
40
+ * appended, so an event can never be silently dropped by a forgetting template.
41
+ * @param template - the definition's prompt.
42
+ * @param event - the event that fired the run, when there is one.
43
+ * @returns the prompt text.
44
+ */
45
+ export function renderPrompt(template, event) {
46
+ const text = typeof template === 'string' ? template : '';
47
+ if (event === undefined || event === null) return text;
48
+ let rendered = text
49
+ .replace(/\{\{event\.text\}\}/gu, event.text ?? '')
50
+ .replace(/\{\{event\.title\}\}/gu, event.title ?? '')
51
+ .replace(/\{\{event\.source\}\}/gu, event.source ?? '')
52
+ .replace(/\{\{event\.eventId\}\}/gu, event.eventId ?? '')
53
+ .replace(/\{\{event\.fields\.([A-Za-z0-9_.-]+)\}\}/gu, (_whole, key) => {
54
+ const value = isPlainObject(event.fields) ? event.fields[key] : undefined;
55
+ return value === undefined ? '' : String(value);
56
+ });
57
+ if (!/\{\{event\./u.test(text) && String(event.text ?? '').trim() !== '') {
58
+ const title = event.title === undefined ? '' : `${event.title}: `;
59
+ const block = `Event (${event.source ?? 'unspecified'}): ${title}${event.text}`;
60
+ rendered = [rendered.trimEnd(), block].filter(part => part !== '').join('\n\n');
61
+ }
62
+ return rendered;
63
+ }
64
+
65
+ /**
66
+ * Write the spec the spawned Host reads.
67
+ * @param path - where to write it.
68
+ * @param spec - `{ triggerId, runId, workspace, prompt, preset, permission, model?, effort?, goal, limits }`.
69
+ * @returns the path.
70
+ */
71
+ export function writeRunSpec(path, spec) {
72
+ if (!isPlainObject(spec)) fail('a run spec must be an object');
73
+ for (const field of ['triggerId', 'runId', 'workspace', 'prompt', 'goal']) {
74
+ if (spec[field] === undefined) fail(`a run spec needs ${field}`);
75
+ }
76
+ if (!isPlainObject(spec.goal) || typeof spec.goal.objective !== 'string' || spec.goal.objective.trim() === '') fail('a run spec needs goal.objective');
77
+ if (!Number.isSafeInteger(spec.goal.maxRounds) || spec.goal.maxRounds <= 0) fail('a run spec needs a positive goal.maxRounds');
78
+ validateSessionMode(spec);
79
+ return writeJson(path, spec);
80
+ }
81
+
82
+ /** Read a run spec written by {@link writeRunSpec}. */
83
+ export function readRunSpec(path) {
84
+ const spec = readJson(path, 'the run spec');
85
+ for (const field of ['triggerId', 'runId', 'workspace', 'prompt', 'goal']) {
86
+ if (spec[field] === undefined) fail(`the run spec is missing ${field}`);
87
+ }
88
+ validateSessionMode(spec);
89
+ return spec;
90
+ }
91
+
92
+ /** Write the result the Host reports back, which the parent turns into a record. */
93
+ export function writeRunResult(path, result) {
94
+ if (!isPlainObject(result)) fail('a run result must be an object');
95
+ if (typeof result.outcome !== 'string') fail('a run result needs an outcome');
96
+ if (!Number.isSafeInteger(result.exitCode)) fail('a run result needs an exitCode');
97
+ return writeJson(path, result);
98
+ }
99
+
100
+ /**
101
+ * Read the Host's result.
102
+ * @param path - the result file.
103
+ * @returns the result, or undefined when the child died before writing one.
104
+ */
105
+ export function readRunResult(path) {
106
+ try {
107
+ return readJson(path, 'the run result');
108
+ } catch {
109
+ return undefined;
110
+ }
111
+ }
112
+
113
+ function validateSessionMode(spec) {
114
+ if (spec.session !== undefined && (!isPlainObject(spec.session) || !['new', 'persistent'].includes(spec.session.mode) || Object.keys(spec.session).some(key => key !== 'mode'))) {
115
+ fail('a run spec session must contain only mode: new or persistent');
116
+ }
117
+ }
@@ -0,0 +1,7 @@
1
+ // The composition overlay that turns a terminal profile into one triggered run:
2
+ // the terminal rows are disabled and the trigger host is inserted instead. It is
3
+ // a pure string builder on purpose — the published launcher ships this file to
4
+ // compose the same overlay, and it must not pull the host's dependencies in.
5
+ export function triggerOverlay(pluginPath) {
6
+ return `- id: tui-startup\n disabled: true\n- id: tui-runner\n disabled: true\n- id: dscode-session-cards\n config:\n enabled: false\n- insert:\n - id: dscode-trigger-host\n name: ${JSON.stringify(pluginPath)}\n`;
7
+ }
@@ -0,0 +1,65 @@
1
+ // The poll predicate: with no resident listener, "watch an external thing" is a
2
+ // scheduled cheap check that only starts a session when something changed. The
3
+ // check is a shell command run in the definition's workspace; exit 0 means
4
+ // "there is work", anything else means "nothing to do".
5
+ //
6
+ // A predicate that cannot run must not fire a run: a spawn failure or a timeout
7
+ // is reported as not matched, never as a match.
8
+
9
+ import { mkdtempSync, rmSync } from 'node:fs';
10
+ import { sandboxCommand, signalGroup } from './source-sandbox.mjs';
11
+ import { spawn as nodeSpawn } from 'node:child_process';
12
+
13
+ /** Output cap for the check's own text, so a chatty check cannot flood a record. */
14
+ export const MAX_CHECK_OUTPUT_CHARS = 2000;
15
+
16
+ /**
17
+ * Run one poll predicate.
18
+ * @param check - the shell command from `source.check`.
19
+ * @param options - `{ cwd, timeoutMs, spawn }`; `spawn` is injectable for tests.
20
+ * @returns `{ matched, code, output }`: `matched` is true only on exit 0.
21
+ */
22
+ export function evaluateCheck(check, { cwd, timeoutMs = 60000, spawn = nodeSpawn, home, permission = 'read-only' } = {}) {
23
+ return new Promise(resolveCheck => {
24
+ let child, scratch;
25
+ const cleanup = () => { if (child) signalGroup(child, 'SIGKILL'); if (scratch) rmSync(scratch, { recursive: true, force: true }); };
26
+ try {
27
+ scratch = mkdtempSync('/tmp/dscode-poll-');
28
+ const launch = sandboxCommand(['/bin/sh', '-c', check], { workspace: cwd, writable: [scratch], home, permission });
29
+ child = spawn(launch.command, launch.args, { cwd, detached: true, env: { ...process.env, TMPDIR: scratch, TMP: scratch, TEMP: scratch }, stdio: ['ignore', 'pipe', 'pipe'] });
30
+ } catch (error) {
31
+ cleanup();
32
+ resolveCheck({ matched: false, code: null, output: `could not start the check: ${error?.message ?? error}` });
33
+ return;
34
+ }
35
+ let output = '';
36
+ let settled = false;
37
+ const collect = chunk => {
38
+ if (output.length < MAX_CHECK_OUTPUT_CHARS) output += String(chunk);
39
+ };
40
+ child.stdout?.on('data', collect);
41
+ child.stderr?.on('data', collect);
42
+ const timer = setTimeout(() => {
43
+ if (settled) return;
44
+ settled = true;
45
+ cleanup();
46
+ resolveCheck({ matched: false, code: null, output: `${output}\n(the check exceeded ${timeoutMs}ms and was stopped)`.trim().slice(0, MAX_CHECK_OUTPUT_CHARS) });
47
+ }, timeoutMs);
48
+ timer.unref?.();
49
+ const finish = code => {
50
+ if (settled) return;
51
+ settled = true;
52
+ clearTimeout(timer);
53
+ cleanup();
54
+ resolveCheck({ matched: code === 0, code, output: output.replace(/\s+/gu, ' ').trim().slice(0, MAX_CHECK_OUTPUT_CHARS) });
55
+ };
56
+ child.once('error', error => {
57
+ if (settled) return;
58
+ settled = true;
59
+ clearTimeout(timer);
60
+ cleanup();
61
+ resolveCheck({ matched: false, code: null, output: `the check failed to start: ${error?.message ?? error}` });
62
+ });
63
+ child.once('exit', code => finish(code));
64
+ });
65
+ }