@duckmind/dm-windows-x64 0.61.4 → 0.61.9

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 (279) hide show
  1. package/dm.exe +0 -0
  2. package/extensions/.dm-extensions.json +211 -67
  3. package/extensions/dm-subagents/agents/claude-code-writer.md +15 -0
  4. package/extensions/dm-subagents/agents/claude-code.md +15 -0
  5. package/extensions/dm-subagents/agents/codex-exec-writer.md +15 -0
  6. package/extensions/dm-subagents/agents/codex-exec.md +15 -0
  7. package/extensions/dm-subagents/agents/cursor-agent-writer.md +14 -0
  8. package/extensions/dm-subagents/agents/cursor-agent.md +14 -0
  9. package/extensions/dm-subagents/agents/delegate.md +3 -2
  10. package/extensions/dm-subagents/agents/oracle.md +10 -5
  11. package/extensions/dm-subagents/agents/researcher.md +2 -2
  12. package/extensions/dm-subagents/agents/reviewer.md +17 -7
  13. package/extensions/dm-subagents/agents/scout.md +5 -5
  14. package/extensions/dm-subagents/agents/worker.md +6 -2
  15. package/extensions/dm-subagents/async-retention-discovery-worker.mjs +167 -0
  16. package/extensions/dm-subagents/index.js +4 -0
  17. package/extensions/dm-subagents/inspector-runner.mjs +10 -0
  18. package/extensions/dm-subagents/install.mjs +3 -2
  19. package/extensions/dm-subagents/package.json +2 -2
  20. package/extensions/dm-subagents/prompts/council.md +60 -0
  21. package/extensions/dm-subagents/prompts/parallel-review.md +5 -1
  22. package/extensions/dm-subagents/prompts/review-loop.md +13 -7
  23. package/extensions/dm-subagents/skills/council-mode/SKILL.md +59 -0
  24. package/extensions/dm-subagents/skills/council-mode/references/pass-contracts.md +150 -0
  25. package/extensions/dm-subagents/skills/dm-subagents/SKILL.md +96 -911
  26. package/extensions/dm-subagents/skills/dm-subagents/references/constraints-and-recipes.md +70 -0
  27. package/extensions/dm-subagents/skills/dm-subagents/references/execution-controls.md +539 -0
  28. package/extensions/dm-subagents/skills/dm-subagents/references/management-authoring-rpc.md +161 -0
  29. package/extensions/dm-subagents/skills/dm-subagents/references/multi-lane-orchestration.md +51 -0
  30. package/extensions/dm-subagents/skills/dm-subagents/references/prompting-and-roles.md +295 -0
  31. package/extensions/dm-subagents/skills/dm-subagents/references/review-and-validation.md +73 -0
  32. package/extensions/dm-subagents/src/agents/agent-management.js +716 -484
  33. package/extensions/dm-subagents/src/agents/agent-refinements.js +563 -0
  34. package/extensions/dm-subagents/src/agents/agent-serializer.js +70 -5
  35. package/extensions/dm-subagents/src/agents/agents.js +1447 -299
  36. package/extensions/dm-subagents/src/agents/builtin-names.js +15 -0
  37. package/extensions/dm-subagents/src/agents/chain-serializer.js +12 -7
  38. package/extensions/dm-subagents/src/agents/frontmatter.js +64 -14
  39. package/extensions/dm-subagents/src/agents/identity.js +1 -1
  40. package/extensions/dm-subagents/src/agents/proactive-skills.js +14 -11
  41. package/extensions/dm-subagents/src/agents/runtime-agent-events.js +49 -0
  42. package/extensions/dm-subagents/src/agents/runtime-agent-registry.js +412 -0
  43. package/extensions/dm-subagents/src/agents/skills.js +52 -35
  44. package/extensions/dm-subagents/src/api/agents.js +6 -0
  45. package/extensions/dm-subagents/src/api/background-work.js +151 -0
  46. package/extensions/dm-subagents/src/api/capability-ceiling.js +12 -0
  47. package/extensions/dm-subagents/src/api/control-channel.js +3 -0
  48. package/extensions/dm-subagents/src/api/delegation.js +5 -0
  49. package/extensions/dm-subagents/src/api/dm-args.js +3 -0
  50. package/extensions/dm-subagents/src/api/external-job-provider.js +137 -0
  51. package/extensions/dm-subagents/src/api/external-runs.js +233 -0
  52. package/extensions/dm-subagents/src/api/intercom-bridge.js +3 -0
  53. package/extensions/dm-subagents/src/api/preflight.js +322 -0
  54. package/extensions/dm-subagents/src/api/project-panes.js +11 -0
  55. package/extensions/dm-subagents/src/api/shared-types.js +4 -0
  56. package/extensions/dm-subagents/src/extension/config.js +175 -0
  57. package/extensions/dm-subagents/src/extension/control-notices.js +4 -43
  58. package/extensions/dm-subagents/src/extension/doctor.js +71 -17
  59. package/extensions/dm-subagents/src/extension/fanout-child.js +49 -32
  60. package/extensions/dm-subagents/src/extension/index.js +711 -265
  61. package/extensions/dm-subagents/src/extension/public-execution.js +114 -0
  62. package/extensions/dm-subagents/src/extension/rpc.js +427 -22
  63. package/extensions/dm-subagents/src/extension/schemas.js +158 -65
  64. package/extensions/dm-subagents/src/extension/steering-notices.js +23 -0
  65. package/extensions/dm-subagents/src/extension/subagent-guide.js +31 -0
  66. package/extensions/dm-subagents/src/extension/tool-description.js +92 -74
  67. package/extensions/dm-subagents/src/extension/tool-result.js +7 -0
  68. package/extensions/dm-subagents/src/inspectors/herdr/actions.js +218 -0
  69. package/extensions/dm-subagents/src/inspectors/herdr/client.js +123 -0
  70. package/extensions/dm-subagents/src/inspectors/herdr/focus.js +47 -0
  71. package/extensions/dm-subagents/src/inspectors/herdr/inspector-runner.js +160 -0
  72. package/extensions/dm-subagents/src/inspectors/herdr/project-panes.js +618 -0
  73. package/extensions/dm-subagents/src/inspectors/herdr/session-roots-codec.js +21 -0
  74. package/extensions/dm-subagents/src/inspectors/herdr/shell-command.js +15 -0
  75. package/extensions/dm-subagents/src/integrations/herdr-status.js +377 -0
  76. package/extensions/dm-subagents/src/intercom/intercom-bridge.js +17 -13
  77. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +371 -79
  78. package/extensions/dm-subagents/src/intercom/result-intercom.js +47 -7
  79. package/extensions/dm-subagents/src/missions/actions.js +394 -0
  80. package/extensions/dm-subagents/src/missions/goal-driver.js +149 -0
  81. package/extensions/dm-subagents/src/missions/lifecycle.js +331 -0
  82. package/extensions/dm-subagents/src/missions/store.js +548 -0
  83. package/extensions/dm-subagents/src/missions/types.js +9 -0
  84. package/extensions/dm-subagents/src/missions/workflow-state.js +245 -0
  85. package/extensions/dm-subagents/src/policy/authority.js +37 -0
  86. package/extensions/dm-subagents/src/profiles/profiles.js +36 -18
  87. package/extensions/dm-subagents/src/runs/background/active-async-capacity.js +427 -0
  88. package/extensions/dm-subagents/src/runs/background/active-run-index.js +122 -0
  89. package/extensions/dm-subagents/src/runs/background/async-execution.js +925 -137
  90. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +515 -148
  91. package/extensions/dm-subagents/src/runs/background/async-resume.js +378 -51
  92. package/extensions/dm-subagents/src/runs/background/async-retention.js +828 -0
  93. package/extensions/dm-subagents/src/runs/background/async-status-snapshot.js +31 -0
  94. package/extensions/dm-subagents/src/runs/background/async-status.js +259 -22
  95. package/extensions/dm-subagents/src/runs/background/auto-drain.js +46 -0
  96. package/extensions/dm-subagents/src/runs/background/chain-append.js +50 -15
  97. package/extensions/dm-subagents/src/runs/background/chain-root-attachment.js +67 -12
  98. package/extensions/dm-subagents/src/runs/background/completion-batcher.js +5 -1
  99. package/extensions/dm-subagents/src/runs/background/completion-dedupe.js +3 -11
  100. package/extensions/dm-subagents/src/runs/background/completion-replay.js +245 -0
  101. package/extensions/dm-subagents/src/runs/background/control-channel.js +423 -36
  102. package/extensions/dm-subagents/src/runs/background/fleet-view.js +132 -59
  103. package/extensions/dm-subagents/src/runs/background/index-segment.js +38 -0
  104. package/extensions/dm-subagents/src/runs/background/inspect-rpc.js +373 -0
  105. package/extensions/dm-subagents/src/runs/background/notify.js +357 -57
  106. package/extensions/dm-subagents/src/runs/background/owned-process-tree.js +86 -0
  107. package/extensions/dm-subagents/src/runs/background/process-terminal.js +269 -0
  108. package/extensions/dm-subagents/src/runs/background/result-delivery-ownership.js +34 -0
  109. package/extensions/dm-subagents/src/runs/background/result-files.js +469 -0
  110. package/extensions/dm-subagents/src/runs/background/result-watcher.js +540 -75
  111. package/extensions/dm-subagents/src/runs/background/resume-guidance.js +44 -0
  112. package/extensions/dm-subagents/src/runs/background/retained-children.js +119 -0
  113. package/extensions/dm-subagents/src/runs/background/run-id-query.js +5 -0
  114. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +93 -9
  115. package/extensions/dm-subagents/src/runs/background/run-status.js +303 -32
  116. package/extensions/dm-subagents/src/runs/background/scheduled-runs.js +784 -376
  117. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +75 -34
  118. package/extensions/dm-subagents/src/runs/background/steering.js +221 -0
  119. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +3106 -844
  120. package/extensions/dm-subagents/src/runs/background/subagent-wait.js +529 -0
  121. package/extensions/dm-subagents/src/runs/background/terminal-run-index.js +106 -0
  122. package/extensions/dm-subagents/src/runs/background/top-level-async.js +1 -1
  123. package/extensions/dm-subagents/src/runs/background/wait-completions.js +155 -0
  124. package/extensions/dm-subagents/src/runs/background/wait-config.js +46 -0
  125. package/extensions/dm-subagents/src/runs/background/wait-subscriptions.js +278 -0
  126. package/extensions/dm-subagents/src/runs/background/wait-tool.js +47 -0
  127. package/extensions/dm-subagents/src/runs/foreground/async-dismiss-action.js +81 -0
  128. package/extensions/dm-subagents/src/runs/foreground/async-steering-action.js +245 -0
  129. package/extensions/dm-subagents/src/runs/foreground/async-stop-action.js +74 -0
  130. package/extensions/dm-subagents/src/runs/foreground/execution.js +1401 -342
  131. package/extensions/dm-subagents/src/runs/foreground/foreground-control.js +133 -0
  132. package/extensions/dm-subagents/src/runs/foreground/foreground-history.js +148 -0
  133. package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +139 -0
  134. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +4278 -1441
  135. package/extensions/dm-subagents/src/runs/foreground/workflow-detach-reconcile.js +278 -0
  136. package/extensions/dm-subagents/src/runs/foreground/workflow-foreground-steering.js +155 -0
  137. package/extensions/dm-subagents/src/runs/shared/abort-recovery.js +97 -0
  138. package/extensions/dm-subagents/src/runs/shared/acceptance.js +597 -148
  139. package/extensions/dm-subagents/src/runs/shared/agent-contract.js +35 -0
  140. package/extensions/dm-subagents/src/runs/shared/async-status-projection.js +472 -0
  141. package/extensions/dm-subagents/src/runs/shared/background-process-options.js +6 -0
  142. package/extensions/dm-subagents/src/runs/shared/capability-ceiling.js +175 -0
  143. package/extensions/dm-subagents/src/runs/shared/child-identity.js +32 -0
  144. package/extensions/dm-subagents/src/runs/shared/child-launch-plan.js +65 -0
  145. package/extensions/dm-subagents/src/runs/shared/child-protocol.js +447 -0
  146. package/extensions/dm-subagents/src/runs/shared/claude-code-adapter.js +120 -0
  147. package/extensions/dm-subagents/src/runs/shared/codex-exec-adapter.js +129 -0
  148. package/extensions/dm-subagents/src/runs/shared/completion-evidence.js +40 -0
  149. package/extensions/dm-subagents/src/runs/shared/completion-guard.js +140 -83
  150. package/extensions/dm-subagents/src/runs/shared/context-mode.js +38 -0
  151. package/extensions/dm-subagents/src/runs/shared/cursor-agent-adapter.js +101 -0
  152. package/extensions/dm-subagents/src/runs/shared/dm-args.js +445 -72
  153. package/extensions/dm-subagents/src/runs/shared/dm-spawn.js +27 -16
  154. package/extensions/dm-subagents/src/runs/shared/dynamic-fanout.js +19 -6
  155. package/extensions/dm-subagents/src/runs/shared/extension-bindings.js +81 -0
  156. package/extensions/dm-subagents/src/runs/shared/external-cli-contract.js +134 -0
  157. package/extensions/dm-subagents/src/runs/shared/external-cli-preflight.js +98 -0
  158. package/extensions/dm-subagents/src/runs/shared/external-cli-runner.js +419 -0
  159. package/extensions/dm-subagents/src/runs/shared/external-job-bridge.js +404 -0
  160. package/extensions/dm-subagents/src/runs/shared/external-job-runner.js +334 -0
  161. package/extensions/dm-subagents/src/runs/shared/fast-mode-extension.js +8 -0
  162. package/extensions/dm-subagents/src/runs/shared/host-step-status.js +228 -0
  163. package/extensions/dm-subagents/src/runs/shared/lane-metadata.js +104 -0
  164. package/extensions/dm-subagents/src/runs/shared/launch-cwd.js +17 -0
  165. package/extensions/dm-subagents/src/runs/shared/llm-intent-arbiter.js +190 -0
  166. package/extensions/dm-subagents/src/runs/shared/long-running-guard.js +48 -3
  167. package/extensions/dm-subagents/src/runs/shared/mcp-config-sources.js +387 -0
  168. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-allowlist.js +212 -137
  169. package/extensions/dm-subagents/src/runs/shared/mcp-direct-tool-grant.js +131 -0
  170. package/extensions/dm-subagents/src/runs/shared/model-exclusions.js +207 -0
  171. package/extensions/dm-subagents/src/runs/shared/model-fallback.js +225 -55
  172. package/extensions/dm-subagents/src/runs/shared/model-scope.js +85 -28
  173. package/extensions/dm-subagents/src/runs/shared/mutation-evidence.js +182 -0
  174. package/extensions/dm-subagents/src/runs/shared/nested-events.js +264 -102
  175. package/extensions/dm-subagents/src/runs/shared/nested-render.js +15 -5
  176. package/extensions/dm-subagents/src/runs/shared/orca-progress-tabs.js +505 -0
  177. package/extensions/dm-subagents/src/runs/shared/parallel-handoff.js +653 -0
  178. package/extensions/dm-subagents/src/runs/shared/parallel-utils.js +29 -12
  179. package/extensions/dm-subagents/src/runs/shared/permissions.js +108 -0
  180. package/extensions/dm-subagents/src/runs/shared/process-signal.js +13 -0
  181. package/extensions/dm-subagents/src/runs/shared/run-fanout-budget.js +257 -0
  182. package/extensions/dm-subagents/src/runs/shared/run-history.js +133 -13
  183. package/extensions/dm-subagents/src/runs/shared/runtime-acknowledged-extensions.js +62 -0
  184. package/extensions/dm-subagents/src/runs/shared/session-lease.js +225 -0
  185. package/extensions/dm-subagents/src/runs/shared/single-output.js +129 -27
  186. package/extensions/dm-subagents/src/runs/shared/spawn-budget.js +95 -0
  187. package/extensions/dm-subagents/src/runs/shared/structured-output.js +129 -10
  188. package/extensions/dm-subagents/src/runs/shared/subagent-control.js +66 -11
  189. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +548 -70
  190. package/extensions/dm-subagents/src/runs/shared/subagent-startup-retry.js +50 -0
  191. package/extensions/dm-subagents/src/runs/shared/task-intent.js +130 -0
  192. package/extensions/dm-subagents/src/runs/shared/tool-availability.js +59 -0
  193. package/extensions/dm-subagents/src/runs/shared/tool-budget.js +7 -5
  194. package/extensions/dm-subagents/src/runs/shared/tool-timeout.js +64 -0
  195. package/extensions/dm-subagents/src/runs/shared/usage-budget.js +74 -0
  196. package/extensions/dm-subagents/src/runs/shared/workflow-graph.js +22 -0
  197. package/extensions/dm-subagents/src/runs/shared/worktree-cleanup-plan.js +721 -0
  198. package/extensions/dm-subagents/src/runs/shared/worktree.js +168 -19
  199. package/extensions/dm-subagents/src/shared/accessible-dir.js +35 -0
  200. package/extensions/dm-subagents/src/shared/agent-stream-options.js +3 -0
  201. package/extensions/dm-subagents/src/shared/artifacts.js +170 -11
  202. package/extensions/dm-subagents/src/shared/atomic-json.js +36 -38
  203. package/extensions/dm-subagents/src/shared/capacity-resilient-json.js +77 -0
  204. package/extensions/dm-subagents/src/shared/child-session-name.js +15 -0
  205. package/extensions/dm-subagents/src/shared/child-transcript.js +57 -2
  206. package/extensions/dm-subagents/src/shared/completion-owner.js +7 -0
  207. package/extensions/dm-subagents/src/shared/display-text.js +142 -0
  208. package/extensions/dm-subagents/src/shared/extension-context.js +17 -0
  209. package/extensions/dm-subagents/src/shared/file-coalescer.js +9 -0
  210. package/extensions/dm-subagents/src/shared/file-system-retry.js +56 -0
  211. package/extensions/dm-subagents/src/shared/fork-context.js +96 -33
  212. package/extensions/dm-subagents/src/shared/formatters.js +21 -7
  213. package/extensions/dm-subagents/src/shared/launch-contract.js +94 -0
  214. package/extensions/dm-subagents/src/shared/model-info.js +10 -5
  215. package/extensions/dm-subagents/src/shared/node-executable.js +19 -0
  216. package/extensions/dm-subagents/src/shared/prompt-resources.js +10 -0
  217. package/extensions/dm-subagents/src/shared/pruned-fork.js +427 -0
  218. package/extensions/dm-subagents/src/shared/session-file-trust.js +19 -0
  219. package/extensions/dm-subagents/src/shared/session-tokens.js +14 -3
  220. package/extensions/dm-subagents/src/shared/settings.js +39 -47
  221. package/extensions/dm-subagents/src/shared/shortcuts.js +16 -0
  222. package/extensions/dm-subagents/src/shared/status-format.js +9 -2
  223. package/extensions/dm-subagents/src/shared/thinking-ceiling.js +41 -0
  224. package/extensions/dm-subagents/src/shared/types.js +47 -7
  225. package/extensions/dm-subagents/src/shared/utf8.js +12 -0
  226. package/extensions/dm-subagents/src/shared/utils.js +151 -131
  227. package/extensions/dm-subagents/src/shared/watch-strategy.js +3 -0
  228. package/extensions/dm-subagents/src/shared/workflow-child-permit.js +84 -0
  229. package/extensions/dm-subagents/src/slash/delegation-adapters.js +274 -0
  230. package/extensions/dm-subagents/src/slash/delegation-json.js +113 -0
  231. package/extensions/dm-subagents/src/slash/delegation-request.js +152 -0
  232. package/extensions/dm-subagents/src/slash/prompt-template-bridge.js +294 -243
  233. package/extensions/dm-subagents/src/slash/prompt-workflows.js +35 -73
  234. package/extensions/dm-subagents/src/slash/selector.js +101 -0
  235. package/extensions/dm-subagents/src/slash/slash-bridge.js +17 -1
  236. package/extensions/dm-subagents/src/slash/slash-commands.js +722 -732
  237. package/extensions/dm-subagents/src/slash/slash-live-state.js +37 -19
  238. package/extensions/dm-subagents/src/slash/subagents-admin.js +410 -0
  239. package/extensions/dm-subagents/src/tui/fleet-status.js +824 -0
  240. package/extensions/dm-subagents/src/tui/fleet-transcript.js +479 -0
  241. package/extensions/dm-subagents/src/tui/fleet.js +1326 -0
  242. package/extensions/dm-subagents/src/tui/render-helpers.js +22 -0
  243. package/extensions/dm-subagents/src/tui/render.js +1511 -261
  244. package/extensions/dm-subagents/src/watchdog/change-signature.js +220 -0
  245. package/extensions/dm-subagents/src/watchdog/child-status.js +151 -0
  246. package/extensions/dm-subagents/src/watchdog/emission-guard.js +90 -0
  247. package/extensions/dm-subagents/src/watchdog/lsp-diagnostics.js +484 -0
  248. package/extensions/dm-subagents/src/watchdog/model-selection.js +154 -0
  249. package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +138 -0
  250. package/extensions/dm-subagents/src/watchdog/register-child.js +112 -0
  251. package/extensions/dm-subagents/src/watchdog/register-main.js +419 -0
  252. package/extensions/dm-subagents/src/watchdog/render.js +54 -0
  253. package/extensions/dm-subagents/src/watchdog/review.js +251 -0
  254. package/extensions/dm-subagents/src/watchdog/runtime.js +803 -0
  255. package/extensions/dm-subagents/src/watchdog/scope.js +56 -0
  256. package/extensions/dm-subagents/src/watchdog/settings.js +515 -0
  257. package/extensions/dm-subagents/src/watchdog/tool-actions.js +151 -0
  258. package/extensions/dm-subagents/src/watchdog/turn-delta.js +169 -0
  259. package/extensions/dm-subagents/src/watchdog/types.js +29 -0
  260. package/extensions/dm-subagents/src/watchdog/warning-format.js +58 -0
  261. package/extensions/dm-subagents/src/workflows/chat-progress.js +116 -0
  262. package/extensions/dm-subagents/src/workflows/host-command.js +227 -0
  263. package/extensions/dm-subagents/src/workflows/scripted-workflow.js +2011 -0
  264. package/extensions/dm-subagents/src/workflows/workflow-child-summary.js +116 -0
  265. package/extensions/dm-subagents/src/workflows/workflow-preflight.js +243 -0
  266. package/extensions/dm-subagents/src/workflows/workflow-receipt.js +387 -0
  267. package/extensions/dm-subagents/src/workflows/workflow-settlement.js +189 -0
  268. package/package.json +4 -3
  269. package/extensions/dm-fff/package.json +0 -21
  270. package/extensions/dm-fff/src/index.js +0 -691
  271. package/extensions/dm-fff/src/query.js +0 -60
  272. package/extensions/dm-subagents/agents/context-builder.md +0 -46
  273. package/extensions/dm-subagents/agents/planner.md +0 -55
  274. package/extensions/dm-subagents/prompts/parallel-context-build.md +0 -55
  275. package/extensions/dm-subagents/prompts/parallel-handoff-plan.md +0 -61
  276. package/extensions/dm-subagents/src/runs/background/wait.js +0 -206
  277. package/extensions/dm-subagents/src/runs/foreground/chain-clarify.js +0 -1013
  278. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +0 -981
  279. package/extensions/dm-subagents/src/runs/shared/turn-budget.js +0 -50
@@ -0,0 +1,138 @@
1
+ import { Agent } from "@duckmind/dm-agent-core";
2
+ import { convertToLlm } from "@duckmind/dm-coding-agent";
3
+ import { streamSimple } from "@duckmind/dm-ai/compat";
4
+ import { Type } from "typebox";
5
+ import { appendPermissionAudit, permissionArgsPreview } from "../runs/shared/permissions.js";
6
+ import { agentStreamOptions } from "../shared/agent-stream-options.js";
7
+ import { decodeChildWatchdogConfig } from "./child-status.js";
8
+ import { childResolvedConfig } from "./register-child.js";
9
+ import { resolveWatchdogReviewModel } from "./review.js";
10
+ const PermissionDecisionParams = Type.Object({
11
+ decision: Type.String({ enum: ["approve", "deny"] }),
12
+ reason: Type.String({ description: "One concise reason for this exact decision." })
13
+ }, { additionalProperties: false });
14
+ function conciseReason(value) {
15
+ const trimmed = value.trim();
16
+ return trimmed ? trimmed.slice(0, 500) : "Watchdog returned an empty reason.";
17
+ }
18
+ export function createWatchdogPermissionArbiter(options = {}) {
19
+ return async (request) => {
20
+ const preview = permissionArgsPreview(request.args);
21
+ const createdAt = Date.now();
22
+ const auditBase = { type: "permission.request", createdAt, toolName: request.toolName, preview, matchedRule: "ask", decisionSource: "watchdog" };
23
+ appendPermissionAudit(request.auditPath, auditBase);
24
+ let completed = false;
25
+ const finish = (approved, reason, decision) => {
26
+ const concise = conciseReason(reason);
27
+ if (completed)
28
+ return { approved, reason: concise, source: "watchdog" };
29
+ completed = true;
30
+ appendPermissionAudit(request.auditPath, {
31
+ type: "permission.decision",
32
+ createdAt: Date.now(),
33
+ requestCreatedAt: createdAt,
34
+ toolName: request.toolName,
35
+ decision,
36
+ approved,
37
+ decisionSource: "watchdog",
38
+ reason: concise
39
+ });
40
+ return { approved, reason: concise, source: "watchdog" };
41
+ };
42
+ let childConfig;
43
+ try {
44
+ childConfig = decodeChildWatchdogConfig(request.rawWatchdogConfig);
45
+ } catch (error) {
46
+ const reason = error instanceof Error ? error.message : String(error);
47
+ return finish(false, `Watchdog permission arbiter configuration is invalid: ${reason}`, "unavailable");
48
+ }
49
+ if (!childConfig)
50
+ return finish(false, "Watchdog permission arbiter is unavailable because the child watchdog is disabled.", "unavailable");
51
+ if (request.signal?.aborted || request.ctx.signal?.aborted)
52
+ return finish(false, "Watchdog permission decision was cancelled.", "cancelled");
53
+ let decision;
54
+ const tool = {
55
+ name: "watchdog_permission_decision",
56
+ label: "Watchdog permission decision",
57
+ description: "Approve or deny this exact child tool call. Call exactly once.",
58
+ parameters: PermissionDecisionParams,
59
+ executionMode: "sequential",
60
+ async execute(_toolCallId, params) {
61
+ if (!decision)
62
+ decision = params;
63
+ return { content: [{ type: "text", text: "Permission decision recorded." }], details: { recorded: true } };
64
+ }
65
+ };
66
+ let timeout;
67
+ let agent;
68
+ let abort;
69
+ try {
70
+ const run = async () => {
71
+ const config = childResolvedConfig(childConfig);
72
+ const selection = await resolveWatchdogReviewModel(request.ctx, config);
73
+ const auth = selection.auth;
74
+ const registeredProvider = request.ctx.modelRegistry.getRegisteredProviderConfig?.(selection.model.provider);
75
+ const baseStreamFn = options.streamFn ?? (registeredProvider?.streamSimple && registeredProvider.api === selection.model.api ? registeredProvider.streamSimple : streamSimple);
76
+ const streamFn = (model, context, streamOptions) => baseStreamFn(model, context, {
77
+ ...streamOptions,
78
+ ...auth.apiKey ? { apiKey: auth.apiKey } : {},
79
+ env: auth.env || streamOptions?.env ? { ...auth.env ?? {}, ...streamOptions?.env ?? {} } : undefined,
80
+ headers: { ...streamOptions?.headers ?? {}, ...auth.headers ?? {} }
81
+ });
82
+ agent = new Agent({
83
+ initialState: {
84
+ systemPrompt: [
85
+ "You are the dm-subagents watchdog permission arbiter.",
86
+ "Decide only whether this exact non-bash child tool call should proceed.",
87
+ "Call watchdog_permission_decision exactly once with approve or deny and a concise reason.",
88
+ "Deny when uncertain. Do not produce freeform advice or ask the parent orchestrator."
89
+ ].join(`
90
+ `),
91
+ model: selection.model,
92
+ thinkingLevel: selection.thinkingLevel,
93
+ tools: [tool]
94
+ },
95
+ convertToLlm,
96
+ ...agentStreamOptions(streamFn),
97
+ getApiKey: (providerName) => providerName === selection.model.provider ? auth.apiKey : undefined,
98
+ beforeToolCall: async ({ toolCall }) => toolCall.name === tool.name ? undefined : { block: true, reason: `Permission arbiter tool '${toolCall.name}' is not allowed.` },
99
+ toolExecution: "sequential"
100
+ });
101
+ await agent.prompt(`Tool: ${request.toolName}
102
+ Redacted arguments: ${preview}`);
103
+ if (!decision)
104
+ return finish(false, "Watchdog permission arbiter returned no decision.", "malformed");
105
+ const approved = decision.decision === "approve";
106
+ return finish(approved, decision.reason, decision.decision);
107
+ };
108
+ return await Promise.race([
109
+ run(),
110
+ new Promise((resolve) => {
111
+ timeout = setTimeout(() => {
112
+ agent?.abort();
113
+ resolve(finish(false, "Watchdog permission decision timed out.", "timeout"));
114
+ }, childConfig.agentEndTimeoutMs);
115
+ }),
116
+ new Promise((resolve) => {
117
+ abort = () => {
118
+ agent?.abort();
119
+ resolve(finish(false, "Watchdog permission decision was cancelled.", "cancelled"));
120
+ };
121
+ request.signal?.addEventListener("abort", abort, { once: true });
122
+ request.ctx.signal?.addEventListener("abort", abort, { once: true });
123
+ })
124
+ ]);
125
+ } catch (error) {
126
+ const reason = error instanceof Error ? error.message : String(error);
127
+ return finish(false, `Watchdog permission arbiter failed closed: ${reason}`, reason.includes("timed out") ? "timeout" : "error");
128
+ } finally {
129
+ if (timeout)
130
+ clearTimeout(timeout);
131
+ if (abort) {
132
+ request.signal?.removeEventListener("abort", abort);
133
+ request.ctx.signal?.removeEventListener("abort", abort);
134
+ }
135
+ }
136
+ };
137
+ }
138
+ export const requestWatchdogPermission = createWatchdogPermissionArbiter();
@@ -0,0 +1,112 @@
1
+ import { MainWatchdogRuntime } from "./runtime.js";
2
+ import { createMainWatchdogReview } from "./review.js";
3
+ import { DEFAULT_WATCHDOG_CONFIG } from "./settings.js";
4
+ import { createWatchdogWarningMessage } from "./warning-format.js";
5
+ import {
6
+ CHILD_WATCHDOG_CONFIG_ENV,
7
+ CHILD_WATCHDOG_STATUS_EVENT,
8
+ decodeChildWatchdogConfig
9
+ } from "./child-status.js";
10
+ export function childResolvedConfig(config) {
11
+ return {
12
+ ...DEFAULT_WATCHDOG_CONFIG,
13
+ enabled: true,
14
+ agentEndTimeoutMs: config.agentEndTimeoutMs,
15
+ maxWarnings: config.maxWarnings,
16
+ main: {
17
+ enabled: true,
18
+ ...config.model ? { model: config.model } : {},
19
+ ...config.thinking !== undefined ? { thinking: config.thinking } : {}
20
+ },
21
+ autoFollow: {
22
+ blockers: config.autoFollowBlockers,
23
+ maxAttempts: config.autoFollowMaxAttempts,
24
+ stalemateRepeats: config.stalemateRepeats
25
+ },
26
+ children: {
27
+ ...DEFAULT_WATCHDOG_CONFIG.children,
28
+ watchdogTailTimeoutMs: config.watchdogTailTimeoutMs
29
+ },
30
+ lsp: { ...config.lsp }
31
+ };
32
+ }
33
+ function childWarningDetails(details, config) {
34
+ return {
35
+ ...details,
36
+ source: details.source === "lsp" ? "lsp" : "child",
37
+ ...config.agent ? { agent: config.agent } : {},
38
+ ...config.runId ? { runId: config.runId } : {}
39
+ };
40
+ }
41
+ function writeStatus(event) {
42
+ try {
43
+ process.stdout.write(`${JSON.stringify(event)}
44
+ `);
45
+ } catch {}
46
+ }
47
+ export function registerChildWatchdog(dm, rawConfig = process.env[CHILD_WATCHDOG_CONFIG_ENV]) {
48
+ const childConfig = decodeChildWatchdogConfig(rawConfig);
49
+ if (!childConfig?.enabled)
50
+ return;
51
+ let currentContext;
52
+ let seq = 0;
53
+ const emitStatus = (phase, followUpPending = false, reason) => {
54
+ writeStatus({
55
+ type: CHILD_WATCHDOG_STATUS_EVENT,
56
+ ...childConfig.runId ? { runId: childConfig.runId } : {},
57
+ ...childConfig.agent ? { agent: childConfig.agent } : {},
58
+ ...childConfig.childIndex !== undefined ? { childIndex: childConfig.childIndex, stepIndex: childConfig.childIndex } : {},
59
+ seq: ++seq,
60
+ phase,
61
+ ts: Date.now(),
62
+ followUpPending,
63
+ ...reason ? { reason } : {}
64
+ });
65
+ };
66
+ const resolved = childResolvedConfig(childConfig);
67
+ const runtime = new MainWatchdogRuntime({
68
+ resolveConfig: () => ({ ok: true, config: resolved, errors: [], sources: [{ scope: "session", exists: true }] }),
69
+ review: createMainWatchdogReview(() => currentContext, { getThinkingLevel: () => dm.getThinkingLevel() }),
70
+ reviewDescription: "child model review",
71
+ reviewChangesOnly: true,
72
+ displayWarning: (details) => {
73
+ const childDetails = childWarningDetails(details, childConfig);
74
+ dm.sendMessage(createWatchdogWarningMessage(childDetails, { display: true, details: childDetails }));
75
+ }
76
+ });
77
+ const rememberContext = (ctx) => {
78
+ currentContext = ctx;
79
+ };
80
+ const onRuntimeEvent = dm.on;
81
+ onRuntimeEvent("session_start", (_event, ctx) => {
82
+ rememberContext(ctx);
83
+ runtime.bindSession(ctx);
84
+ emitStatus("idle");
85
+ });
86
+ onRuntimeEvent("before_agent_start", (event, ctx) => {
87
+ rememberContext(ctx);
88
+ runtime.handleBeforeAgentStart(event, ctx);
89
+ });
90
+ onRuntimeEvent("turn_end", (event, ctx) => {
91
+ rememberContext(ctx);
92
+ runtime.handleTurnEnd(event, ctx);
93
+ });
94
+ onRuntimeEvent("agent_end", async (event, ctx) => {
95
+ rememberContext(ctx);
96
+ emitStatus("reviewing");
97
+ await runtime.handleAgentEnd(event, ctx);
98
+ const snapshot = runtime.getSnapshot(ctx.cwd);
99
+ if (snapshot.status === "failed")
100
+ emitStatus("failed", false, snapshot.lastError);
101
+ else if (snapshot.status === "stale")
102
+ emitStatus("stale", false, "review stale");
103
+ else
104
+ emitStatus("idle");
105
+ });
106
+ onRuntimeEvent("session_shutdown", () => {
107
+ currentContext = undefined;
108
+ runtime.dispose();
109
+ emitStatus("idle");
110
+ });
111
+ return runtime;
112
+ }
@@ -0,0 +1,419 @@
1
+ import { Text } from "@duckmind/dm-tui";
2
+ import { resolveEffectiveThinking, splitKnownThinkingSuffix, THINKING_LEVELS } from "../shared/model-info.js";
3
+ import { SLASH_TEXT_RESULT_TYPE } from "../shared/types.js";
4
+ import { recommendStrongWatchdogModel, resolveWatchdogModelInput, parseWatchdogThinkingInput } from "./model-selection.js";
5
+ import { renderWatchdogWarning } from "./render.js";
6
+ import { createMainWatchdogReview } from "./review.js";
7
+ import { MainWatchdogRuntime } from "./runtime.js";
8
+ import { getWatchdogUserSettingsPath, writeUserWatchdogEnabled, writeWatchdogModelSettings } from "./settings.js";
9
+ import {
10
+ SUBAGENT_WATCHDOG_WARNING_TYPE
11
+ } from "./types.js";
12
+ import { createWatchdogWarningMessage } from "./warning-format.js";
13
+ function sendSlashText(dm, text) {
14
+ dm.sendMessage({ customType: SLASH_TEXT_RESULT_TYPE, content: text, display: true });
15
+ }
16
+ function messageFromError(error) {
17
+ return error instanceof Error ? error.message : String(error);
18
+ }
19
+ function boolLabel(value) {
20
+ return value ? "on" : "off";
21
+ }
22
+ function statusLabel(status) {
23
+ return status.replaceAll("-", " ");
24
+ }
25
+ function sourceLine(source) {
26
+ const location = source.path ? ` ${source.path}` : "";
27
+ return `- ${source.scope}${location}: ${source.exists ? "found" : "not found"}`;
28
+ }
29
+ function currentSessionModelLine(ctx) {
30
+ const model = ctx.model;
31
+ if (model && typeof model.provider === "string" && typeof model.id === "string")
32
+ return `current session (${model.provider}/${model.id})`;
33
+ return "current session (not configured)";
34
+ }
35
+ function mainThinkingLine(snapshot, ctx) {
36
+ const configuredModel = snapshot.config.main.model;
37
+ const configuredThinking = snapshot.config.main.thinking;
38
+ if (configuredModel) {
39
+ const effective = resolveEffectiveThinking(configuredModel, configuredThinking);
40
+ if (effective)
41
+ return effective;
42
+ return "off (default for explicit watchdog model)";
43
+ }
44
+ if (configuredThinking === false)
45
+ return "off";
46
+ if (configuredThinking !== undefined)
47
+ return configuredThinking;
48
+ const currentThinking = ctx.thinkingLevel;
49
+ return typeof currentThinking === "string" ? `current session (${currentThinking})` : "current session";
50
+ }
51
+ function mainModelLine(snapshot, ctx) {
52
+ if (snapshot.config.main.model) {
53
+ const source = snapshot.sessionModelOverride?.model ? "session override" : "configured";
54
+ return `Main model: ${splitKnownThinkingSuffix(snapshot.config.main.model).baseModel} (${source})`;
55
+ }
56
+ return `Main model: ${currentSessionModelLine(ctx)}`;
57
+ }
58
+ function childrenLine(snapshot) {
59
+ const children = snapshot.config.children;
60
+ const model = children.model ? splitKnownThinkingSuffix(children.model).baseModel : "current child session";
61
+ const thinking = children.thinking === undefined ? "current child session" : children.thinking === false ? "off" : children.thinking;
62
+ const overrides = Object.entries(children.overrides);
63
+ const overrideText = overrides.length ? ` · overrides ${overrides.map(([agent, override]) => {
64
+ const bits = [agent];
65
+ if (override.enabled !== undefined)
66
+ bits.push(boolLabel(override.enabled));
67
+ if (override.model)
68
+ bits.push(splitKnownThinkingSuffix(override.model).baseModel);
69
+ if (override.thinking !== undefined)
70
+ bits.push(`thinking ${override.thinking === false ? "off" : override.thinking}`);
71
+ return bits.join(" ");
72
+ }).join("; ")}` : "";
73
+ return `Children: ${boolLabel(snapshot.config.enabled && children.enabled)} · model ${model} · thinking ${thinking}${overrideText}`;
74
+ }
75
+ function recommendationLine(ctx) {
76
+ try {
77
+ const recommendation = recommendStrongWatchdogModel(ctx);
78
+ return `Recommended strong watchdog: ${recommendation.model}:${recommendation.thinking} (${recommendation.label}, complementary reviewer)`;
79
+ } catch (error) {
80
+ return `Recommended strong watchdog: unavailable (${messageFromError(error)})`;
81
+ }
82
+ }
83
+ function lspLine(snapshot) {
84
+ const lsp = snapshot.lsp;
85
+ const provider = lsp.provider ? ` · ${lsp.provider}` : "";
86
+ const counts = lsp.diagnosticCount > 0 || lsp.freshDiagnosticCount > 0 ? ` · ${lsp.freshDiagnosticCount} new/${lsp.diagnosticCount} total` : "";
87
+ const message = lsp.message ? ` · ${lsp.message}` : "";
88
+ return `LSP diagnostics: ${lsp.enabled ? "on" : "off"} · ${lsp.status}${provider}${counts}${message}`;
89
+ }
90
+ export function buildWatchdogStatus(snapshot, ctx) {
91
+ const lines = [
92
+ "Subagent watchdog",
93
+ `Main: ${boolLabel(snapshot.enabled)}${!snapshot.config.enabled && snapshot.sessionOverride === undefined ? " (default off)" : ""}`,
94
+ `Runtime: ${statusLabel(snapshot.status)}${snapshot.bufferedDeltas > 0 ? ` · buffered deltas ${snapshot.bufferedDeltas}` : ""}`,
95
+ `Review trigger: ${snapshot.reviewTrigger === "repo-edits" ? "repo edits only" : "every non-empty turn delta"}`,
96
+ `Scope context: ${snapshot.config.scope.enabled ? "on" : "off"}`,
97
+ `Cadence: ${snapshot.config.cadence.everyNTools === null ? "boundary only" : `every ${snapshot.config.cadence.everyNTools} tools + boundary`}`,
98
+ lspLine(snapshot),
99
+ `Session override: ${snapshot.sessionOverride === undefined ? "none" : boolLabel(snapshot.sessionOverride)}`,
100
+ mainModelLine(snapshot, ctx),
101
+ `Main thinking: ${mainThinkingLine(snapshot, ctx)}`,
102
+ childrenLine(snapshot),
103
+ recommendationLine(ctx),
104
+ `Agent-end timeout: ${snapshot.config.agentEndTimeoutMs}ms`,
105
+ `Auto-follow: ${snapshot.enabled && snapshot.config.autoFollow.blockers ? "on for blockers" : "off"} · attempts ${snapshot.autoFollowAttempts}${snapshot.config.autoFollow.maxAttempts === null ? "" : `/${snapshot.config.autoFollow.maxAttempts}`}${snapshot.autoFollowQueued ? " · queued" : ""}${snapshot.autoFollowStalemate ? " · stalemate" : ""}`,
106
+ `Review model call: ${snapshot.reviewDescription}`
107
+ ];
108
+ if (snapshot.failedReviews > 0)
109
+ lines.push(`Failed reviews: ${snapshot.failedReviews}`);
110
+ if (snapshot.staleReviews > 0)
111
+ lines.push(`Stale reviews: ${snapshot.staleReviews}`);
112
+ if (snapshot.changedPaths?.length) {
113
+ lines.push(`Changed paths: ${snapshot.changedPaths.slice(0, 8).join(", ")}${snapshot.changedPaths.length > 8 ? `, +${snapshot.changedPaths.length - 8} more` : ""}`);
114
+ }
115
+ if (snapshot.lastWarning) {
116
+ lines.push(`Last warning: ${snapshot.lastWarning.severity} · ${snapshot.lastWarning.state ?? "candidate"} · ${snapshot.lastWarning.summary}`);
117
+ }
118
+ if (snapshot.lastError)
119
+ lines.push(`Last error: ${snapshot.lastError}`);
120
+ if (!snapshot.configOk) {
121
+ lines.push("", "Config errors:", ...snapshot.errors.map((error) => `- ${error.message}`), "Watchdog is disabled until the config is fixed.");
122
+ } else {
123
+ lines.push("", "Config: ok");
124
+ }
125
+ lines.push("Sources:", ...snapshot.sources.map(sourceLine), "", "Model commands:", "- /subagents-watchdog recommend-model", "- /subagents-watchdog model recommended", "- /subagents-watchdog model <provider/model[:thinking]>", "- /subagents-watchdog model inherit", "- /subagents-watchdog session model recommended", 'Agent action: subagent({ action: "watchdog.configure", model: "recommended", scope: "session" })');
126
+ return lines.join(`
127
+ `);
128
+ }
129
+ function parseTestCommand(input) {
130
+ const match = input.match(/^test\s+(concern|blocker)\s+([\s\S]+)$/);
131
+ if (!match)
132
+ return;
133
+ return { severity: match[1], text: match[2].trim() };
134
+ }
135
+ function formatThinking(value) {
136
+ if (value === undefined)
137
+ return "inherit";
138
+ return value === false ? "off" : value;
139
+ }
140
+ function parseThinkingCommand(raw) {
141
+ const value = raw.trim();
142
+ if (value === "inherit")
143
+ return null;
144
+ return parseWatchdogThinkingInput(value, "/subagents-watchdog thinking") ?? null;
145
+ }
146
+ function resolveModelCommandValue(ctx, raw) {
147
+ const value = raw.trim();
148
+ if (!value)
149
+ throw new Error("Expected a model, 'recommended', or 'inherit'.");
150
+ if (value === "inherit")
151
+ return { model: null, thinking: null, description: "current session model and thinking" };
152
+ if (value === "recommended") {
153
+ const recommendation = recommendStrongWatchdogModel(ctx);
154
+ return {
155
+ model: recommendation.model,
156
+ thinking: recommendation.thinking,
157
+ description: `${recommendation.model}:${recommendation.thinking} (${recommendation.label})`
158
+ };
159
+ }
160
+ const resolved = resolveWatchdogModelInput(ctx, value);
161
+ return {
162
+ model: resolved.model,
163
+ thinking: resolved.thinking ?? null,
164
+ description: `${resolved.model}${resolved.thinking ? `:${resolved.thinking}` : ""}`
165
+ };
166
+ }
167
+ function buildRecommendationText(ctx) {
168
+ const recommendation = recommendStrongWatchdogModel(ctx);
169
+ return [
170
+ "Subagent watchdog recommended model",
171
+ `Current session: ${currentSessionModelLine(ctx)}`,
172
+ `Recommended: ${recommendation.model}:${recommendation.thinking}`,
173
+ `Reason: ${recommendation.reason}`,
174
+ "",
175
+ "Apply for this session:",
176
+ "/subagents-watchdog session model recommended",
177
+ "",
178
+ "Save as your user default:",
179
+ "/subagents-watchdog model recommended"
180
+ ].join(`
181
+ `);
182
+ }
183
+ function buildCheckText(runtime, ctx) {
184
+ const snapshot = runtime.getSnapshot(ctx.cwd);
185
+ if (!snapshot.configOk) {
186
+ return ["Subagent watchdog config check", "", "Config errors:", ...snapshot.errors.map((error) => `- ${error.message}`)].join(`
187
+ `);
188
+ }
189
+ const lines = ["Subagent watchdog config check", "", "Config: ok"];
190
+ if (snapshot.config.main.model) {
191
+ const resolved = resolveWatchdogModelInput(ctx, snapshot.config.main.model);
192
+ lines.push(`Main model: ${resolved.model} auth ok`);
193
+ } else {
194
+ lines.push(`Main model: ${currentSessionModelLine(ctx)}`);
195
+ }
196
+ lines.push(`Main thinking: ${mainThinkingLine(snapshot, ctx)}`);
197
+ lines.push(lspLine(snapshot));
198
+ try {
199
+ const recommendation = recommendStrongWatchdogModel(ctx);
200
+ lines.push(`Recommended strong watchdog: ${recommendation.model}:${recommendation.thinking}`);
201
+ } catch (error) {
202
+ lines.push(`Recommended strong watchdog: unavailable (${messageFromError(error)})`);
203
+ }
204
+ return lines.join(`
205
+ `);
206
+ }
207
+ function createTestWarning(severity, text) {
208
+ return {
209
+ severity,
210
+ category: "other",
211
+ confidence: "high",
212
+ source: "main",
213
+ state: "displayed",
214
+ summary: text,
215
+ evidence: `Manual /subagents-watchdog test ${severity} message from the main session.`,
216
+ recommendedAction: severity === "blocker" ? "Verify the renderer, transcript delivery, and auto-follow policy." : "Verify the renderer and transcript delivery; decide manually whether any action is needed."
217
+ };
218
+ }
219
+ async function handleWatchdogCommand(dm, runtime, args, ctx) {
220
+ const input = args.trim();
221
+ if (!input || input === "status") {
222
+ sendSlashText(dm, buildWatchdogStatus(runtime.getSnapshot(ctx.cwd), ctx));
223
+ return;
224
+ }
225
+ if (input === "recommend-model") {
226
+ try {
227
+ sendSlashText(dm, buildRecommendationText(ctx));
228
+ } catch (error) {
229
+ sendSlashText(dm, `Subagent watchdog recommended model
230
+
231
+ ${messageFromError(error)}`);
232
+ }
233
+ return;
234
+ }
235
+ if (input === "check") {
236
+ try {
237
+ sendSlashText(dm, buildCheckText(runtime, ctx));
238
+ } catch (error) {
239
+ sendSlashText(dm, `Subagent watchdog config check
240
+
241
+ ${messageFromError(error)}`);
242
+ }
243
+ return;
244
+ }
245
+ if (input === "on" || input === "off") {
246
+ const enabled = input === "on";
247
+ try {
248
+ const settingsPath = writeUserWatchdogEnabled(enabled);
249
+ const snapshot = runtime.getSnapshot(ctx.cwd);
250
+ sendSlashText(dm, [
251
+ `Subagent watchdog ${boolLabel(enabled)} saved to user settings.`,
252
+ `Updated: ${settingsPath}`,
253
+ `Main now: ${boolLabel(snapshot.enabled)}${snapshot.sessionOverride !== undefined ? ` (session override ${boolLabel(snapshot.sessionOverride)})` : ""}`
254
+ ].join(`
255
+ `));
256
+ } catch (error) {
257
+ sendSlashText(dm, `Subagent watchdog
258
+
259
+ Could not update ${getWatchdogUserSettingsPath()}: ${messageFromError(error)}`);
260
+ }
261
+ return;
262
+ }
263
+ if (input === "session on" || input === "session off") {
264
+ const enabled = input.endsWith("on");
265
+ const snapshot = runtime.setSessionEnabled(enabled, ctx.cwd);
266
+ sendSlashText(dm, [
267
+ `Subagent watchdog session override: ${boolLabel(enabled)}.`,
268
+ "No settings files were changed.",
269
+ "",
270
+ buildWatchdogStatus(snapshot, ctx)
271
+ ].join(`
272
+ `));
273
+ return;
274
+ }
275
+ if (input.startsWith("session model ")) {
276
+ const rawModel = input.slice("session model ".length);
277
+ try {
278
+ const value = resolveModelCommandValue(ctx, rawModel);
279
+ const snapshot = value.model === null ? runtime.clearSessionModel(ctx.cwd) : runtime.setSessionModel({ model: value.model, thinking: value.thinking ?? null }, ctx.cwd);
280
+ sendSlashText(dm, [
281
+ `Subagent watchdog session model: ${value.description}.`,
282
+ "No settings files were changed.",
283
+ "",
284
+ buildWatchdogStatus(snapshot, ctx)
285
+ ].join(`
286
+ `));
287
+ } catch (error) {
288
+ sendSlashText(dm, `Subagent watchdog session model
289
+
290
+ ${messageFromError(error)}`);
291
+ }
292
+ return;
293
+ }
294
+ if (input.startsWith("model ")) {
295
+ const rawModel = input.slice("model ".length);
296
+ try {
297
+ const value = resolveModelCommandValue(ctx, rawModel);
298
+ const settingsPath = writeWatchdogModelSettings({
299
+ scope: "user",
300
+ target: { kind: "main" },
301
+ model: value.model,
302
+ thinking: value.thinking
303
+ });
304
+ runtime.refreshConfig(ctx.cwd);
305
+ const snapshot = runtime.getSnapshot(ctx.cwd);
306
+ sendSlashText(dm, [
307
+ `Subagent watchdog model saved: ${value.description}.`,
308
+ `Updated: ${settingsPath}`,
309
+ `Main now: ${boolLabel(snapshot.enabled)}`,
310
+ value.model === null ? "The watchdog now inherits the current session model and thinking." : "Run /subagents-watchdog on if the watchdog is still off.",
311
+ "",
312
+ buildWatchdogStatus(snapshot, ctx)
313
+ ].join(`
314
+ `));
315
+ } catch (error) {
316
+ sendSlashText(dm, `Subagent watchdog model
317
+
318
+ ${messageFromError(error)}
319
+ No settings files were changed.`);
320
+ }
321
+ return;
322
+ }
323
+ if (input.startsWith("thinking ")) {
324
+ const rawThinking = input.slice("thinking ".length);
325
+ try {
326
+ const thinking = parseThinkingCommand(rawThinking);
327
+ const settingsPath = writeWatchdogModelSettings({
328
+ scope: "user",
329
+ target: { kind: "main" },
330
+ thinking
331
+ });
332
+ runtime.refreshConfig(ctx.cwd);
333
+ sendSlashText(dm, [
334
+ `Subagent watchdog thinking saved: ${formatThinking(thinking ?? undefined)}.`,
335
+ `Updated: ${settingsPath}`,
336
+ "",
337
+ buildWatchdogStatus(runtime.getSnapshot(ctx.cwd), ctx)
338
+ ].join(`
339
+ `));
340
+ } catch (error) {
341
+ sendSlashText(dm, `Subagent watchdog thinking
342
+
343
+ ${messageFromError(error)}
344
+ No settings files were changed.`);
345
+ }
346
+ return;
347
+ }
348
+ const test = parseTestCommand(input);
349
+ if (test) {
350
+ if (!test.text) {
351
+ ctx.ui.notify("Usage: /subagents-watchdog test concern|blocker <text>", "error");
352
+ return;
353
+ }
354
+ const warning = createTestWarning(test.severity, test.text);
355
+ const details = runtime.recordDisplayedWarning(warning);
356
+ dm.sendMessage(createWatchdogWarningMessage(details, { display: true, details }));
357
+ return;
358
+ }
359
+ ctx.ui.notify(`Usage: /subagents-watchdog [status|on|off|session on|session off|recommend-model|model recommended|model <provider/model[:thinking]>|model inherit|thinking ${THINKING_LEVELS.join("|")}|thinking inherit|session model recommended|check|test concern <text>|test blocker <text>]`, "error");
360
+ }
361
+ export function registerMainWatchdog(dm, options = {}) {
362
+ let currentContext;
363
+ const rememberContext = (ctx) => {
364
+ currentContext = ctx;
365
+ };
366
+ const runtime = options.runtime ?? new MainWatchdogRuntime({
367
+ review: options.review ?? createMainWatchdogReview(() => currentContext, { getThinkingLevel: () => dm.getThinkingLevel() }),
368
+ reviewDescription: options.review ? "injected seam" : "real model review",
369
+ reviewChangesOnly: true,
370
+ displayWarning: (details, delivery) => {
371
+ dm.sendMessage(createWatchdogWarningMessage(details, { display: true, details }), delivery?.deliverAs === "steer" ? { deliverAs: "steer" } : undefined);
372
+ },
373
+ sendUserMessage: (message) => dm.sendUserMessage(message)
374
+ });
375
+ dm.registerMessageRenderer(SUBAGENT_WATCHDOG_WARNING_TYPE, (message, renderOptions, theme) => {
376
+ const details = message.details;
377
+ if (!details?.summary || !details.evidence || !details.recommendedAction) {
378
+ const content = typeof message.content === "string" ? message.content : message.content.filter((entry) => entry.type === "text").map((entry) => entry.text).join(`
379
+ `);
380
+ return new Text(content, 0, 0);
381
+ }
382
+ return renderWatchdogWarning(details, renderOptions, theme);
383
+ });
384
+ dm.registerCommand("subagents-watchdog", {
385
+ description: "Show or toggle the default-off subagent watchdog",
386
+ handler: (args, ctx) => {
387
+ rememberContext(ctx);
388
+ return handleWatchdogCommand(dm, runtime, args, ctx);
389
+ }
390
+ });
391
+ dm.on("session_start", (_event, ctx) => {
392
+ rememberContext(ctx);
393
+ runtime.bindSession(ctx);
394
+ });
395
+ dm.on("before_agent_start", (event, ctx) => {
396
+ rememberContext(ctx);
397
+ runtime.handleBeforeAgentStart(event, ctx);
398
+ });
399
+ dm.on("turn_end", (event, ctx) => {
400
+ rememberContext(ctx);
401
+ runtime.handleTurnEnd(event, ctx);
402
+ });
403
+ dm.on("tool_result", (_event, ctx) => {
404
+ rememberContext(ctx);
405
+ runtime.handleToolResult(ctx);
406
+ });
407
+ dm.on("agent_end", (event, ctx) => {
408
+ rememberContext(ctx);
409
+ return runtime.handleAgentEnd(event, ctx);
410
+ });
411
+ dm.on("session_before_switch", () => runtime.reset("session switch", { clearReviewInputSignature: true, clearLspLedger: true, clearScope: true, resetAutoFollow: true }));
412
+ dm.on("session_before_fork", () => runtime.reset("session fork", { clearReviewInputSignature: true, clearLspLedger: true, clearScope: true, resetAutoFollow: true }));
413
+ dm.on("session_compact", () => runtime.reset("session compact", { clearScope: true }));
414
+ dm.on("session_shutdown", () => {
415
+ currentContext = undefined;
416
+ runtime.dispose();
417
+ });
418
+ return runtime;
419
+ }