@sayknow-cli/coding-agent 0.4.7 → 0.5.1

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 (428) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/dist/types/capability/index.d.ts +10 -20
  3. package/dist/types/capability/types.d.ts +3 -0
  4. package/dist/types/cli/args.d.ts +0 -2
  5. package/dist/types/cli/read-cli.d.ts +1 -0
  6. package/dist/types/cli.d.ts +9 -1
  7. package/dist/types/commands/daemon.d.ts +2 -2
  8. package/dist/types/commands/deep-interview.d.ts +9 -0
  9. package/dist/types/commands/harness.d.ts +22 -0
  10. package/dist/types/commands/read.d.ts +6 -0
  11. package/dist/types/commands/sdk.d.ts +20 -2
  12. package/dist/types/config/keybindings.d.ts +34 -4
  13. package/dist/types/config/model-profile-contract.d.ts +40 -0
  14. package/dist/types/config/model-profiles.d.ts +2 -3
  15. package/dist/types/config/model-registry.d.ts +5 -0
  16. package/dist/types/config/provider-auth-health.d.ts +14 -0
  17. package/dist/types/config/provider-ranking.d.ts +59 -0
  18. package/dist/types/config/settings-schema.d.ts +156 -10
  19. package/dist/types/config/settings.d.ts +3 -0
  20. package/dist/types/edit/modes/patch.d.ts +13 -0
  21. package/dist/types/edit/path-mutation-lock.d.ts +15 -0
  22. package/dist/types/eval/py/executor.d.ts +1 -1
  23. package/dist/types/eval/py/runner-artifact.d.ts +8 -0
  24. package/dist/types/eval/py/tool-bridge.d.ts +1 -2
  25. package/dist/types/extensibility/extensions/types.d.ts +43 -2
  26. package/dist/types/extensibility/shared-events.d.ts +6 -0
  27. package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
  28. package/dist/types/main.d.ts +33 -2
  29. package/dist/types/memories/index.d.ts +2 -0
  30. package/dist/types/modes/acp/acp-agent.d.ts +22 -9
  31. package/dist/types/modes/components/assistant-message.d.ts +3 -1
  32. package/dist/types/modes/components/btw-panel.d.ts +1 -0
  33. package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
  34. package/dist/types/modes/components/queue-pane.d.ts +8 -0
  35. package/dist/types/modes/components/queued-message-selector.d.ts +6 -0
  36. package/dist/types/modes/components/read-tool-group.d.ts +4 -4
  37. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
  38. package/dist/types/modes/components/session-observer-overlay.d.ts +4 -0
  39. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  40. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  41. package/dist/types/modes/components/tool-status-header.d.ts +4 -2
  42. package/dist/types/modes/components/welcome.d.ts +5 -0
  43. package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
  44. package/dist/types/modes/controllers/command-controller.d.ts +2 -0
  45. package/dist/types/modes/controllers/event-controller.d.ts +3 -0
  46. package/dist/types/modes/interactive-mode.d.ts +13 -2
  47. package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
  48. package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
  49. package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
  50. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
  51. package/dist/types/modes/types.d.ts +6 -0
  52. package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
  53. package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
  54. package/dist/types/runtime/memory-domain.d.ts +9 -0
  55. package/dist/types/runtime/memory-guard-contract.d.ts +71 -0
  56. package/dist/types/runtime/memory-guard.d.ts +39 -0
  57. package/dist/types/runtime/memory-limit.d.ts +11 -0
  58. package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
  59. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +1 -1
  60. package/dist/types/runtime-mcp/manager.d.ts +9 -1
  61. package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
  62. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
  63. package/dist/types/runtime-mcp/redaction.d.ts +2 -0
  64. package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
  65. package/dist/types/sdk/acp/final-text.d.ts +19 -0
  66. package/dist/types/sdk/acp/mcp.d.ts +23 -0
  67. package/dist/types/sdk/broker/broker.d.ts +2 -0
  68. package/dist/types/sdk/broker/lifecycle.d.ts +13 -0
  69. package/dist/types/sdk/bus/chat-daemon-control.d.ts +9 -1
  70. package/dist/types/sdk/bus/config-commands.d.ts +2 -2
  71. package/dist/types/sdk/bus/config.d.ts +2 -0
  72. package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
  73. package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
  74. package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
  75. package/dist/types/sdk/bus/index.d.ts +52 -4
  76. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +37 -0
  77. package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
  78. package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
  79. package/dist/types/sdk/bus/notification-service.d.ts +34 -0
  80. package/dist/types/sdk/bus/operator-runtime.d.ts +1 -0
  81. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +106 -0
  82. package/dist/types/sdk/bus/rate-limit-pool.d.ts +2 -0
  83. package/dist/types/sdk/bus/reconciliation-store.d.ts +65 -0
  84. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +33 -9
  85. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
  86. package/dist/types/sdk/bus/telegram-daemon.d.ts +286 -12
  87. package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
  88. package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
  89. package/dist/types/sdk/client/discovery.d.ts +2 -0
  90. package/dist/types/sdk/client/liveness.d.ts +7 -0
  91. package/dist/types/sdk/host/control/operations.d.ts +3 -2
  92. package/dist/types/sdk/host/host.d.ts +3 -1
  93. package/dist/types/sdk/host/query/handlers.d.ts +14 -0
  94. package/dist/types/sdk/index.d.ts +2 -0
  95. package/dist/types/sdk/lifecycle-session.d.ts +10 -1
  96. package/dist/types/sdk/prompt-status.d.ts +88 -0
  97. package/dist/types/sdk/session-directory.d.ts +1 -1
  98. package/dist/types/sdk/session.d.ts +7 -0
  99. package/dist/types/sdk/startup-capability.d.ts +9 -0
  100. package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
  101. package/dist/types/sdk/transport/index.d.ts +12 -0
  102. package/dist/types/sdk/transport/relay.d.ts +43 -0
  103. package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
  104. package/dist/types/sdk/transport/socket.d.ts +7 -0
  105. package/dist/types/sdk/transport/stdio.d.ts +3 -0
  106. package/dist/types/session/agent-session.d.ts +83 -24
  107. package/dist/types/session/btw-contract.d.ts +16 -0
  108. package/dist/types/session/fallback-chain-controller.d.ts +18 -2
  109. package/dist/types/session/internal/managed-session-scope.d.ts +70 -10
  110. package/dist/types/session/internal/managed-session-storage.d.ts +34 -12
  111. package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
  112. package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
  113. package/dist/types/session/session-manager.d.ts +89 -18
  114. package/dist/types/session/session-storage.d.ts +31 -0
  115. package/dist/types/session/streaming-output.d.ts +60 -5
  116. package/dist/types/setup/credential-import.d.ts +5 -1
  117. package/dist/types/setup/provider-onboarding.d.ts +2 -0
  118. package/dist/types/skc-runtime/deep-interview-runtime.d.ts +1 -1
  119. package/dist/types/skc-runtime/deep-interview-stage.d.ts +37 -0
  120. package/dist/types/skc-runtime/gc-runtime.d.ts +1 -1
  121. package/dist/types/skc-runtime/linux-proc.d.ts +22 -14
  122. package/dist/types/skc-runtime/memory-guard-owner-claims.d.ts +47 -0
  123. package/dist/types/skc-runtime/ralplan-runtime.d.ts +112 -1
  124. package/dist/types/skc-runtime/repository-binding.d.ts +63 -0
  125. package/dist/types/skc-runtime/state-runtime.d.ts +3 -1
  126. package/dist/types/skc-runtime/state-writer.d.ts +5 -1
  127. package/dist/types/skc-runtime/team-launch.d.ts +1 -1
  128. package/dist/types/skc-runtime/team-runtime.d.ts +9 -2
  129. package/dist/types/skc-runtime/team-store.d.ts +12 -0
  130. package/dist/types/skc-runtime/team-worker-memory-guard.d.ts +92 -0
  131. package/dist/types/skc-runtime/tmux-owner-isolation.d.ts +7 -0
  132. package/dist/types/skc-runtime/ultragoal-guard.d.ts +6 -5
  133. package/dist/types/skc-runtime/ultragoal-receipt-freshness.d.ts +28 -0
  134. package/dist/types/skc-runtime/ultragoal-runtime.d.ts +43 -5
  135. package/dist/types/skill-state/workflow-hud.d.ts +3 -0
  136. package/dist/types/ssh/utils.d.ts +1 -0
  137. package/dist/types/task/discovery.d.ts +3 -1
  138. package/dist/types/task/executor.d.ts +6 -0
  139. package/dist/types/task/index.d.ts +3 -1
  140. package/dist/types/task/provider-retry-status.d.ts +13 -0
  141. package/dist/types/task/receipt.d.ts +2 -0
  142. package/dist/types/task/types.d.ts +133 -0
  143. package/dist/types/task/ultragoal-redteam-activation.d.ts +33 -0
  144. package/dist/types/tools/browser/launch.d.ts +7 -0
  145. package/dist/types/tools/fetch.d.ts +22 -9
  146. package/dist/types/tools/image-gen.d.ts +63 -1
  147. package/dist/types/tools/index.d.ts +7 -1
  148. package/dist/types/tools/output-meta.d.ts +21 -1
  149. package/dist/types/tools/read-internals.d.ts +12 -0
  150. package/dist/types/tools/read.d.ts +45 -1
  151. package/dist/types/tools/resource-gc.d.ts +23 -0
  152. package/dist/types/tools/skill-discovery.d.ts +7 -0
  153. package/dist/types/tools/sqlite-reader.d.ts +7 -0
  154. package/dist/types/tools/tool-result.d.ts +7 -1
  155. package/dist/types/utils/prompt-suggestion.d.ts +33 -0
  156. package/dist/types/utils/shell-snapshot.d.ts +12 -0
  157. package/dist/types/web/insane/bridge.d.ts +1 -0
  158. package/dist/types/web/insane/url-guard.d.ts +17 -0
  159. package/package.json +8 -12
  160. package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
  161. package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
  162. package/scripts/capture-sticky-viewport-showcase.ts +292 -0
  163. package/scripts/compile-args.ts +0 -1
  164. package/scripts/dogfood-repository-binding.ts +209 -0
  165. package/scripts/generate-docs-index.ts +4 -1
  166. package/scripts/generate-sdk-operation-inventory.ts +9 -0
  167. package/scripts/run-test-manifest.ts +6 -4
  168. package/scripts/verify-skc-sdk-canonicalization.ts +122 -18
  169. package/scripts/verify-sticky-viewport-showcase.ts +611 -0
  170. package/src/capability/index.ts +58 -42
  171. package/src/capability/types.ts +3 -0
  172. package/src/cli/args.ts +16 -100
  173. package/src/cli/fast-help.ts +1 -1
  174. package/src/cli/mcp-cli.ts +4 -21
  175. package/src/cli/notify-cli.ts +6 -38
  176. package/src/cli/read-cli.ts +2 -1
  177. package/src/cli/setup-cli.ts +10 -4
  178. package/src/cli.ts +133 -11
  179. package/src/commands/daemon.ts +22 -5
  180. package/src/commands/deep-interview.ts +26 -1
  181. package/src/commands/harness.ts +35 -12
  182. package/src/commands/read.ts +11 -2
  183. package/src/commands/sdk.ts +134 -17
  184. package/src/commands/team.ts +1 -1
  185. package/src/commit/agentic/index.ts +3 -3
  186. package/src/commit/map-reduce/index.ts +2 -2
  187. package/src/config/keybindings.ts +158 -25
  188. package/src/config/model-profile-contract.ts +174 -0
  189. package/src/config/model-profiles.ts +51 -10
  190. package/src/config/model-registry.ts +24 -4
  191. package/src/config/model-resolver.ts +2 -2
  192. package/src/config/provider-auth-health.ts +42 -0
  193. package/src/config/provider-ranking.ts +119 -0
  194. package/src/config/settings-schema.ts +157 -10
  195. package/src/config/settings.ts +254 -108
  196. package/src/coordinator-mcp/model-preset.ts +21 -74
  197. package/src/defaults/skc/skills/deep-interview/SKILL.md +147 -24
  198. package/src/defaults/skc/skills/ralplan/SKILL.md +91 -34
  199. package/src/defaults/skc/skills/team/SKILL.md +1 -1
  200. package/src/defaults/skc/skills/ultragoal/SKILL.md +68 -17
  201. package/src/discovery/ssh.ts +12 -1
  202. package/src/edit/index.ts +3 -6
  203. package/src/edit/modes/patch.ts +38 -1
  204. package/src/edit/modes/replace.ts +42 -0
  205. package/src/edit/path-mutation-lock.ts +112 -0
  206. package/src/eval/js/tool-bridge.ts +1 -1
  207. package/src/eval/py/executor.ts +37 -13
  208. package/src/eval/py/kernel.ts +1 -21
  209. package/src/eval/py/prelude.py +2 -2
  210. package/src/eval/py/runner-artifact.ts +84 -0
  211. package/src/eval/py/tool-bridge.ts +34 -18
  212. package/src/extensibility/extensions/runner.ts +4 -0
  213. package/src/extensibility/extensions/types.ts +42 -4
  214. package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
  215. package/src/extensibility/shared-events.ts +5 -0
  216. package/src/extensibility/skc-plugins/runtime-adapters.ts +2 -1
  217. package/src/hooks/native-skill-hook.ts +17 -4
  218. package/src/internal-urls/docs-index.generated.ts +17 -16
  219. package/src/internal-urls/local-protocol.ts +87 -25
  220. package/src/internal-urls/local-root-gc.ts +127 -0
  221. package/src/internal-urls/mcp-protocol.ts +73 -11
  222. package/src/main.ts +120 -42
  223. package/src/memories/index.ts +10 -0
  224. package/src/modes/DESIGN.md +52 -0
  225. package/src/modes/acp/acp-agent.ts +647 -83
  226. package/src/modes/acp/acp-event-mapper.ts +106 -12
  227. package/src/modes/acp/acp-mode.ts +39 -3
  228. package/src/modes/action-registry.ts +1 -1
  229. package/src/modes/components/assistant-message.ts +123 -22
  230. package/src/modes/components/btw-panel.ts +82 -16
  231. package/src/modes/components/irc-sidebar.ts +176 -62
  232. package/src/modes/components/model-selector.ts +61 -4
  233. package/src/modes/components/notifications-settings-editor.ts +1 -1
  234. package/src/modes/components/oauth-selector.ts +42 -12
  235. package/src/modes/components/plan-preview-overlay.ts +1 -1
  236. package/src/modes/components/queue-pane.ts +55 -9
  237. package/src/modes/components/queued-message-selector.ts +53 -10
  238. package/src/modes/components/read-tool-group.ts +82 -14
  239. package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
  240. package/src/modes/components/sayknow-pet-widget.ts +20 -8
  241. package/src/modes/components/session-observer-overlay.ts +187 -32
  242. package/src/modes/components/settings-selector.ts +60 -18
  243. package/src/modes/components/tool-execution.ts +138 -27
  244. package/src/modes/components/tool-status-header.ts +26 -8
  245. package/src/modes/components/welcome.ts +50 -23
  246. package/src/modes/controllers/btw-controller.ts +119 -36
  247. package/src/modes/controllers/command-controller.ts +101 -54
  248. package/src/modes/controllers/event-controller.ts +119 -27
  249. package/src/modes/controllers/extension-ui-controller.ts +23 -12
  250. package/src/modes/controllers/input-controller.ts +100 -8
  251. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
  252. package/src/modes/controllers/selector-controller.ts +4 -1
  253. package/src/modes/interactive-mode.ts +201 -60
  254. package/src/modes/irc-observation-ledger.ts +71 -15
  255. package/src/modes/prompt-action-autocomplete.ts +32 -13
  256. package/src/modes/prompt-suggestion-controller.ts +96 -0
  257. package/src/modes/runtime-init.ts +20 -2
  258. package/src/modes/shared/agent-wire/command-dispatch.ts +3 -3
  259. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
  260. package/src/modes/types.ts +6 -0
  261. package/src/modes/utils/hotkeys-markdown.ts +64 -36
  262. package/src/modes/utils/ui-helpers.ts +99 -4
  263. package/src/prompts/agent-fragments/restricted-bash.md +1 -1
  264. package/src/prompts/agents/architect.md +17 -3
  265. package/src/prompts/agents/critic.md +17 -2
  266. package/src/prompts/agents/executor.md +1 -1
  267. package/src/prompts/agents/planner.md +8 -1
  268. package/src/prompts/system/btw-user.md +3 -8
  269. package/src/prompts/system/prompt-suggestion-system.md +32 -0
  270. package/src/prompts/system/system-prompt.md +6 -3
  271. package/src/prompts/tools/cron.md +3 -1
  272. package/src/prompts/tools/read.md +4 -2
  273. package/src/prompts/tools/skill-discovery.md +1 -0
  274. package/src/runtime/memory-domain.ts +66 -0
  275. package/src/runtime/memory-guard-contract.ts +73 -0
  276. package/src/runtime/memory-guard.ts +292 -0
  277. package/src/runtime/memory-limit.ts +50 -0
  278. package/src/runtime-mcp/client.ts +41 -55
  279. package/src/runtime-mcp/content-limits.ts +71 -0
  280. package/src/runtime-mcp/discoverable-tool-metadata.ts +1 -1
  281. package/src/runtime-mcp/json-rpc.ts +28 -11
  282. package/src/runtime-mcp/manager.ts +77 -59
  283. package/src/runtime-mcp/oauth-flow.ts +0 -72
  284. package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
  285. package/src/runtime-mcp/redaction.ts +30 -0
  286. package/src/runtime-mcp/smithery-auth.ts +17 -2
  287. package/src/runtime-mcp/smithery-connect.ts +11 -1
  288. package/src/runtime-mcp/transports/http.ts +63 -22
  289. package/src/sdk/acp/adapter.ts +8 -1
  290. package/src/sdk/acp/final-text.ts +40 -0
  291. package/src/sdk/acp/mcp.ts +26 -0
  292. package/src/sdk/broker/broker.ts +34 -20
  293. package/src/sdk/broker/identity.ts +22 -12
  294. package/src/sdk/broker/lifecycle.ts +293 -43
  295. package/src/sdk/broker/session-index.ts +11 -1
  296. package/src/sdk/bus/chat-daemon-cli.ts +2 -2
  297. package/src/sdk/bus/chat-daemon-control.ts +22 -5
  298. package/src/sdk/bus/config-commands.ts +2 -2
  299. package/src/sdk/bus/config.ts +10 -2
  300. package/src/sdk/bus/control-drain-lease.ts +104 -0
  301. package/src/sdk/bus/conversation-store.ts +40 -6
  302. package/src/sdk/bus/daemon-paths.ts +2 -0
  303. package/src/sdk/bus/index.ts +793 -121
  304. package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
  305. package/src/sdk/bus/lifecycle-commands.ts +63 -10
  306. package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
  307. package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
  308. package/src/sdk/bus/notification-orchestration.ts +12 -0
  309. package/src/sdk/bus/notification-service.ts +87 -25
  310. package/src/sdk/bus/operator-runtime.ts +31 -5
  311. package/src/sdk/bus/prompt-reconciliation.ts +240 -0
  312. package/src/sdk/bus/rate-limit-pool.ts +8 -0
  313. package/src/sdk/bus/recent-activity.ts +90 -26
  314. package/src/sdk/bus/reconciliation-store.ts +224 -0
  315. package/src/sdk/bus/telegram-cli.ts +6 -13
  316. package/src/sdk/bus/telegram-daemon-cli.ts +8 -3
  317. package/src/sdk/bus/telegram-daemon-contract.ts +34 -9
  318. package/src/sdk/bus/telegram-daemon-control.ts +161 -40
  319. package/src/sdk/bus/telegram-daemon.ts +3649 -593
  320. package/src/sdk/bus/telegram-reference.ts +20 -2
  321. package/src/sdk/bus/topic-registry.ts +451 -12
  322. package/src/sdk/cli/session-cli.ts +15 -2
  323. package/src/sdk/client/discovery.ts +19 -3
  324. package/src/sdk/client/liveness.ts +49 -0
  325. package/src/sdk/host/control/dispatch.ts +8 -2
  326. package/src/sdk/host/control/operations.ts +3 -2
  327. package/src/sdk/host/host.ts +27 -9
  328. package/src/sdk/host/query/handlers.ts +125 -5
  329. package/src/sdk/index.ts +12 -0
  330. package/src/sdk/lifecycle-session.ts +19 -3
  331. package/src/sdk/mcp/server.ts +46 -18
  332. package/src/sdk/prompt-status.ts +97 -0
  333. package/src/sdk/protocol/operation-inventory.generated.json +145 -0
  334. package/src/sdk/protocol/operation-registry.ts +24 -4
  335. package/src/sdk/session-directory.ts +5 -1
  336. package/src/sdk/session.ts +69 -8
  337. package/src/sdk/startup-capability.ts +15 -1
  338. package/src/sdk/transport/auth-preface.ts +82 -0
  339. package/src/sdk/transport/index.ts +18 -0
  340. package/src/sdk/transport/relay.ts +252 -0
  341. package/src/sdk/transport/serve-cli.ts +105 -0
  342. package/src/sdk/transport/socket.ts +197 -0
  343. package/src/sdk/transport/stdio.ts +17 -0
  344. package/src/session/agent-session.ts +1112 -314
  345. package/src/session/blob-store.ts +25 -7
  346. package/src/session/btw-contract.ts +59 -0
  347. package/src/session/fallback-chain-controller.ts +47 -8
  348. package/src/session/internal/managed-session-scope.ts +1426 -259
  349. package/src/session/internal/managed-session-storage.ts +414 -238
  350. package/src/session/internal/native-publish-outcome.ts +271 -0
  351. package/src/session/memory-guard-checkpoint-participant.ts +131 -0
  352. package/src/session/session-manager.ts +2079 -469
  353. package/src/session/session-storage.ts +151 -11
  354. package/src/session/streaming-output.ts +262 -43
  355. package/src/setup/credential-import.ts +28 -3
  356. package/src/setup/provider-onboarding.ts +49 -5
  357. package/src/setup/provider-presets.json +2 -1
  358. package/src/skc-runtime/deep-interview-runtime.ts +303 -36
  359. package/src/skc-runtime/deep-interview-stage.ts +1016 -0
  360. package/src/skc-runtime/deep-interview-state.ts +8 -5
  361. package/src/skc-runtime/gc-render.ts +1 -0
  362. package/src/skc-runtime/gc-runtime.ts +11 -1
  363. package/src/skc-runtime/linux-proc.ts +70 -36
  364. package/src/skc-runtime/managed-owner-supervisor.ts +83 -4
  365. package/src/skc-runtime/memory-guard-owner-claims.ts +389 -0
  366. package/src/skc-runtime/ralplan-runtime.ts +1057 -75
  367. package/src/skc-runtime/repository-binding.ts +267 -0
  368. package/src/skc-runtime/session-state-sidecar.ts +25 -9
  369. package/src/skc-runtime/state-runtime.ts +50 -12
  370. package/src/skc-runtime/state-writer.ts +68 -56
  371. package/src/skc-runtime/team-launch.ts +34 -5
  372. package/src/skc-runtime/team-runtime.ts +41 -1
  373. package/src/skc-runtime/team-store.ts +32 -0
  374. package/src/skc-runtime/team-worker-memory-guard.ts +363 -0
  375. package/src/skc-runtime/team-workers.ts +1 -0
  376. package/src/skc-runtime/tmux-common.ts +13 -2
  377. package/src/skc-runtime/tmux-owner-isolation.ts +20 -1
  378. package/src/skc-runtime/tmux-sessions.ts +45 -6
  379. package/src/skc-runtime/ultragoal-guard.ts +93 -15
  380. package/src/skc-runtime/ultragoal-receipt-freshness.ts +123 -0
  381. package/src/skc-runtime/ultragoal-runtime.ts +469 -38
  382. package/src/skc-runtime/workflow-manifest.generated.json +195 -5
  383. package/src/skc-runtime/workflow-manifest.ts +67 -3
  384. package/src/skill-state/workflow-hud.ts +25 -2
  385. package/src/skill-state/workflow-mutation-guard.ts +104 -12
  386. package/src/slash-commands/builtin-registry.ts +1 -1
  387. package/src/ssh/utils.ts +14 -0
  388. package/src/task/discovery.ts +8 -2
  389. package/src/task/executor.ts +165 -47
  390. package/src/task/index.ts +123 -15
  391. package/src/task/provider-retry-status.ts +88 -0
  392. package/src/task/receipt.ts +3 -0
  393. package/src/task/render.ts +45 -26
  394. package/src/task/skc-command.ts +2 -2
  395. package/src/task/types.ts +55 -10
  396. package/src/task/ultragoal-redteam-activation.ts +75 -0
  397. package/src/tools/ask.ts +1 -1
  398. package/src/tools/ast-edit.ts +2 -2
  399. package/src/tools/bash-allowed-prefixes.ts +45 -1
  400. package/src/tools/bash-pty-selection.ts +2 -2
  401. package/src/tools/browser/launch.ts +41 -6
  402. package/src/tools/browser/screenshot-format.ts +6 -1
  403. package/src/tools/cron.ts +1 -1
  404. package/src/tools/fetch.ts +127 -154
  405. package/src/tools/image-gen.ts +476 -23
  406. package/src/tools/index.ts +7 -1
  407. package/src/tools/output-meta.ts +176 -9
  408. package/src/tools/path-utils.ts +5 -1
  409. package/src/tools/read-internals.ts +44 -0
  410. package/src/tools/read.ts +1544 -310
  411. package/src/tools/resource-gc.ts +665 -125
  412. package/src/tools/skill-discovery.ts +39 -3
  413. package/src/tools/sqlite-reader.ts +63 -5
  414. package/src/tools/subagent-render.ts +74 -16
  415. package/src/tools/subagent.ts +2 -0
  416. package/src/tools/tool-result.ts +14 -1
  417. package/src/utils/edit-mode.ts +2 -2
  418. package/src/utils/pasted-image-path.ts +15 -6
  419. package/src/utils/prompt-suggestion.ts +265 -0
  420. package/src/utils/shell-snapshot.ts +173 -63
  421. package/src/utils/sixel.ts +3 -3
  422. package/src/web/insane/bridge.ts +5 -1
  423. package/src/web/insane/url-guard.ts +140 -27
  424. package/src/web/scrapers/docs-rs.ts +30 -5
  425. package/src/web/scrapers/types.ts +19 -49
  426. package/src/web/scrapers/utils.ts +12 -26
  427. package/src/web/search/providers/codex.ts +1 -1
  428. package/src/workflow/workflow-intent-diff.ts +4 -1
@@ -110,7 +110,13 @@
110
110
  "doctor",
111
111
  "kickoff",
112
112
  "write-spec",
113
- "write-artifact"
113
+ "write-artifact",
114
+ "stage",
115
+ "check",
116
+ "apply",
117
+ "discard",
118
+ "read",
119
+ "write"
114
120
  ],
115
121
  "name": "session-id",
116
122
  "type": "string"
@@ -256,11 +262,49 @@
256
262
  },
257
263
  {
258
264
  "appliesToVerbs": [
259
- "write-spec"
265
+ "write-spec",
266
+ "stage",
267
+ "check",
268
+ "apply",
269
+ "discard",
270
+ "read",
271
+ "write",
272
+ "clear",
273
+ "handoff"
260
274
  ],
261
275
  "name": "json",
262
276
  "type": "boolean"
263
277
  },
278
+ {
279
+ "appliesToVerbs": [
280
+ "stage",
281
+ "write"
282
+ ],
283
+ "name": "input",
284
+ "required": true,
285
+ "type": "string"
286
+ },
287
+ {
288
+ "appliesToVerbs": [
289
+ "write"
290
+ ],
291
+ "name": "reset",
292
+ "type": "boolean"
293
+ },
294
+ {
295
+ "appliesToVerbs": [
296
+ "stage"
297
+ ],
298
+ "enumValues": [
299
+ "initialize-context",
300
+ "record-round",
301
+ "update-facts",
302
+ "merge-state"
303
+ ],
304
+ "name": "for",
305
+ "required": true,
306
+ "type": "enum"
307
+ },
264
308
  {
265
309
  "name": "args",
266
310
  "planned": true,
@@ -305,6 +349,38 @@
305
349
  "name": "write-spec",
306
350
  "surface": "command-flag"
307
351
  },
352
+ {
353
+ "name": "stage",
354
+ "surface": "command-positional"
355
+ },
356
+ {
357
+ "name": "check",
358
+ "surface": "command-positional"
359
+ },
360
+ {
361
+ "name": "apply",
362
+ "surface": "command-positional"
363
+ },
364
+ {
365
+ "name": "discard",
366
+ "surface": "command-positional"
367
+ },
368
+ {
369
+ "name": "read",
370
+ "surface": "command-positional"
371
+ },
372
+ {
373
+ "name": "write",
374
+ "surface": "command-positional"
375
+ },
376
+ {
377
+ "name": "clear",
378
+ "surface": "command-positional"
379
+ },
380
+ {
381
+ "name": "handoff",
382
+ "surface": "command-positional"
383
+ },
308
384
  {
309
385
  "name": "graph",
310
386
  "planned": true,
@@ -534,7 +610,13 @@
534
610
  "doctor",
535
611
  "kickoff",
536
612
  "write-spec",
537
- "write-artifact"
613
+ "write-artifact",
614
+ "stage",
615
+ "check",
616
+ "apply",
617
+ "discard",
618
+ "read",
619
+ "write"
538
620
  ],
539
621
  "name": "session-id",
540
622
  "type": "string"
@@ -922,7 +1004,13 @@
922
1004
  "doctor",
923
1005
  "kickoff",
924
1006
  "write-spec",
925
- "write-artifact"
1007
+ "write-artifact",
1008
+ "stage",
1009
+ "check",
1010
+ "apply",
1011
+ "discard",
1012
+ "read",
1013
+ "write"
926
1014
  ],
927
1015
  "name": "session-id",
928
1016
  "type": "string"
@@ -1046,6 +1134,9 @@
1046
1134
  "read-worker-status",
1047
1135
  "read-worker-heartbeat",
1048
1136
  "update-worker-heartbeat",
1137
+ "read-worker-memory-guard",
1138
+ "update-worker-memory-guard",
1139
+ "apply-worker-memory-guard",
1049
1140
  "write-worker-inbox",
1050
1141
  "write-worker-identity",
1051
1142
  "append-event",
@@ -1111,6 +1202,41 @@
1111
1202
  "name": "completionEvidence",
1112
1203
  "type": "object"
1113
1204
  },
1205
+ {
1206
+ "appliesToVerbs": [
1207
+ "api"
1208
+ ],
1209
+ "name": "platform",
1210
+ "type": "string"
1211
+ },
1212
+ {
1213
+ "appliesToVerbs": [
1214
+ "api"
1215
+ ],
1216
+ "name": "automatic-action-allowed",
1217
+ "type": "boolean"
1218
+ },
1219
+ {
1220
+ "appliesToVerbs": [
1221
+ "api"
1222
+ ],
1223
+ "name": "incident-id",
1224
+ "type": "string"
1225
+ },
1226
+ {
1227
+ "appliesToVerbs": [
1228
+ "api"
1229
+ ],
1230
+ "name": "pid-probe",
1231
+ "type": "object"
1232
+ },
1233
+ {
1234
+ "appliesToVerbs": [
1235
+ "api"
1236
+ ],
1237
+ "name": "candidates",
1238
+ "type": "object"
1239
+ },
1114
1240
  {
1115
1241
  "name": "args",
1116
1242
  "planned": true,
@@ -1370,7 +1496,13 @@
1370
1496
  "doctor",
1371
1497
  "kickoff",
1372
1498
  "write-spec",
1373
- "write-artifact"
1499
+ "write-artifact",
1500
+ "stage",
1501
+ "check",
1502
+ "apply",
1503
+ "discard",
1504
+ "read",
1505
+ "write"
1374
1506
  ],
1375
1507
  "name": "session-id",
1376
1508
  "type": "string"
@@ -1515,12 +1647,60 @@
1515
1647
  "record-review-blockers",
1516
1648
  "steer",
1517
1649
  "classify-blocker",
1650
+ "record-critic-verdict",
1651
+ "record-critic-gate-override",
1518
1652
  "rebaseline-pipeline-overlap"
1519
1653
  ],
1520
1654
  "name": "evidence",
1521
1655
  "required": true,
1522
1656
  "type": "string"
1523
1657
  },
1658
+ {
1659
+ "appliesToVerbs": [
1660
+ "record-critic-verdict"
1661
+ ],
1662
+ "enumValues": [
1663
+ "completion",
1664
+ "pause"
1665
+ ],
1666
+ "name": "terminus",
1667
+ "required": true,
1668
+ "type": "enum"
1669
+ },
1670
+ {
1671
+ "appliesToVerbs": [
1672
+ "record-critic-verdict"
1673
+ ],
1674
+ "enumValues": [
1675
+ "OKAY",
1676
+ "ITERATE",
1677
+ "REJECT"
1678
+ ],
1679
+ "name": "verdict",
1680
+ "required": true,
1681
+ "type": "enum"
1682
+ },
1683
+ {
1684
+ "appliesToVerbs": [
1685
+ "record-critic-verdict"
1686
+ ],
1687
+ "name": "blockers-json",
1688
+ "type": "string"
1689
+ },
1690
+ {
1691
+ "appliesToVerbs": [
1692
+ "record-critic-verdict"
1693
+ ],
1694
+ "name": "goal-id",
1695
+ "type": "string"
1696
+ },
1697
+ {
1698
+ "appliesToVerbs": [
1699
+ "record-critic-verdict"
1700
+ ],
1701
+ "name": "classification-event-id",
1702
+ "type": "string"
1703
+ },
1524
1704
  {
1525
1705
  "appliesToVerbs": [
1526
1706
  "create-goals"
@@ -1743,6 +1923,8 @@
1743
1923
  "record-review-blockers",
1744
1924
  "steer",
1745
1925
  "classify-blocker",
1926
+ "record-critic-verdict",
1927
+ "record-critic-gate-override",
1746
1928
  "start-pipeline-overlap",
1747
1929
  "join-pipeline-overlap",
1748
1930
  "rebaseline-pipeline-overlap"
@@ -1830,6 +2012,14 @@
1830
2012
  "name": "classify-blocker",
1831
2013
  "surface": "command-positional"
1832
2014
  },
2015
+ {
2016
+ "name": "record-critic-verdict",
2017
+ "surface": "command-positional"
2018
+ },
2019
+ {
2020
+ "name": "record-critic-gate-override",
2021
+ "surface": "command-positional"
2022
+ },
1833
2023
  {
1834
2024
  "name": "start-pipeline-overlap",
1835
2025
  "surface": "command-positional"
@@ -72,7 +72,22 @@ const PLANNED_ADMIN_VERBS = ["graph", "prune", "migrate", "force-overwrite"] as
72
72
  const COMMON_TYPED_ARGS: TypedArgSpec[] = [
73
73
  { name: "input", type: "string", appliesToVerbs: ["write", "api"] },
74
74
  { name: "mode", type: "enum", enumValues: [...CANONICAL_SKC_WORKFLOW_SKILLS], appliesToVerbs: [...STATE_VERBS] },
75
- { name: "session-id", type: "string", appliesToVerbs: [...STATE_VERBS, "kickoff", "write-spec", "write-artifact"] },
75
+ {
76
+ name: "session-id",
77
+ type: "string",
78
+ appliesToVerbs: [
79
+ ...STATE_VERBS,
80
+ "kickoff",
81
+ "write-spec",
82
+ "write-artifact",
83
+ "stage",
84
+ "check",
85
+ "apply",
86
+ "discard",
87
+ "read",
88
+ "write",
89
+ ],
90
+ },
76
91
  { name: "thread-id", type: "string", appliesToVerbs: ["write", "clear", "handoff"] },
77
92
  { name: "turn-id", type: "string", appliesToVerbs: ["write", "clear", "handoff"] },
78
93
  { name: "to", type: "string", required: true, appliesToVerbs: ["handoff"] },
@@ -160,7 +175,12 @@ export const WORKFLOW_MANIFEST: Record<CanonicalSkcWorkflowSkill, SkillManifest>
160
175
  { from: "handoff", to: "complete", verb: "clear" },
161
176
  { from: "interviewing", to: "complete", verb: "clear" },
162
177
  ],
163
- verbs: [...stateVerbs(), ...flagVerbs(["kickoff", "write-spec"]), ...plannedVerbs(PLANNED_ADMIN_VERBS)],
178
+ verbs: [
179
+ ...stateVerbs(),
180
+ ...flagVerbs(["kickoff", "write-spec"]),
181
+ ...positionalVerbs(["stage", "check", "apply", "discard", "read", "write", "clear", "handoff"]),
182
+ ...plannedVerbs(PLANNED_ADMIN_VERBS),
183
+ ],
164
184
  typedArgs: [
165
185
  { name: "quick", type: "boolean", appliesToVerbs: ["kickoff"] },
166
186
  { name: "standard", type: "boolean", appliesToVerbs: ["kickoff"] },
@@ -172,7 +192,20 @@ export const WORKFLOW_MANIFEST: Record<CanonicalSkcWorkflowSkill, SkillManifest>
172
192
  { name: "spec", type: "string", required: true, appliesToVerbs: ["write-spec"] },
173
193
  { name: "handoff", type: "enum", enumValues: ["ralplan"], appliesToVerbs: ["write-spec"] },
174
194
  { name: "deliberate", type: "boolean", appliesToVerbs: ["write-spec"] },
175
- { name: "json", type: "boolean", appliesToVerbs: ["write-spec"] },
195
+ {
196
+ name: "json",
197
+ type: "boolean",
198
+ appliesToVerbs: ["write-spec", "stage", "check", "apply", "discard", "read", "write", "clear", "handoff"],
199
+ },
200
+ { name: "input", type: "string", required: true, appliesToVerbs: ["stage", "write"] },
201
+ { name: "reset", type: "boolean", appliesToVerbs: ["write"] },
202
+ {
203
+ name: "for",
204
+ type: "enum",
205
+ enumValues: ["initialize-context", "record-round", "update-facts", "merge-state"],
206
+ required: true,
207
+ appliesToVerbs: ["stage"],
208
+ },
176
209
  { name: "args", type: "string", planned: true },
177
210
  { name: "metadata-json", type: "string", planned: true },
178
211
  ],
@@ -255,6 +288,8 @@ export const WORKFLOW_MANIFEST: Record<CanonicalSkcWorkflowSkill, SkillManifest>
255
288
  "record-review-blockers",
256
289
  "steer",
257
290
  "classify-blocker",
291
+ "record-critic-verdict",
292
+ "record-critic-gate-override",
258
293
  "start-pipeline-overlap",
259
294
  "join-pipeline-overlap",
260
295
  "rebaseline-pipeline-overlap",
@@ -290,9 +325,28 @@ export const WORKFLOW_MANIFEST: Record<CanonicalSkcWorkflowSkill, SkillManifest>
290
325
  "record-review-blockers",
291
326
  "steer",
292
327
  "classify-blocker",
328
+ "record-critic-verdict",
329
+ "record-critic-gate-override",
293
330
  "rebaseline-pipeline-overlap",
294
331
  ],
295
332
  },
333
+ {
334
+ name: "terminus",
335
+ type: "enum",
336
+ enumValues: ["completion", "pause"],
337
+ required: true,
338
+ appliesToVerbs: ["record-critic-verdict"],
339
+ },
340
+ {
341
+ name: "verdict",
342
+ type: "enum",
343
+ enumValues: ["OKAY", "ITERATE", "REJECT"],
344
+ required: true,
345
+ appliesToVerbs: ["record-critic-verdict"],
346
+ },
347
+ { name: "blockers-json", type: "string", appliesToVerbs: ["record-critic-verdict"] },
348
+ { name: "goal-id", type: "string", appliesToVerbs: ["record-critic-verdict"] },
349
+ { name: "classification-event-id", type: "string", appliesToVerbs: ["record-critic-verdict"] },
296
350
  {
297
351
  name: "goal-metadata-json",
298
352
  type: "string",
@@ -403,6 +457,8 @@ export const WORKFLOW_MANIFEST: Record<CanonicalSkcWorkflowSkill, SkillManifest>
403
457
  "record-review-blockers",
404
458
  "steer",
405
459
  "classify-blocker",
460
+ "record-critic-verdict",
461
+ "record-critic-gate-override",
406
462
  "start-pipeline-overlap",
407
463
  "join-pipeline-overlap",
408
464
  "rebaseline-pipeline-overlap",
@@ -470,6 +526,9 @@ export const WORKFLOW_MANIFEST: Record<CanonicalSkcWorkflowSkill, SkillManifest>
470
526
  "read-worker-status",
471
527
  "read-worker-heartbeat",
472
528
  "update-worker-heartbeat",
529
+ "read-worker-memory-guard",
530
+ "update-worker-memory-guard",
531
+ "apply-worker-memory-guard",
473
532
  "write-worker-inbox",
474
533
  "write-worker-identity",
475
534
  "append-event",
@@ -496,6 +555,11 @@ export const WORKFLOW_MANIFEST: Record<CanonicalSkcWorkflowSkill, SkillManifest>
496
555
  },
497
556
  { name: "completion_evidence", type: "object", appliesToVerbs: ["api"] },
498
557
  { name: "completionEvidence", type: "object", appliesToVerbs: ["api"] },
558
+ { name: "platform", type: "string", appliesToVerbs: ["api"] },
559
+ { name: "automatic-action-allowed", type: "boolean", appliesToVerbs: ["api"] },
560
+ { name: "incident-id", type: "string", appliesToVerbs: ["api"] },
561
+ { name: "pid-probe", type: "object", appliesToVerbs: ["api"] },
562
+ { name: "candidates", type: "object", appliesToVerbs: ["api"] },
499
563
  { name: "args", type: "string", planned: true },
500
564
  { name: "metadata-json", type: "string", planned: true },
501
565
  ],
@@ -23,6 +23,9 @@ interface RalplanHudState extends WorkflowGateHudState {
23
23
  iteration?: number;
24
24
  iterationFromIndex?: number;
25
25
  stages?: string;
26
+ architectPasses?: number;
27
+ criticPasses?: number;
28
+ reviewPassBudget?: number;
26
29
  verdict?: string;
27
30
  latestSummary?: string;
28
31
  pendingApproval?: boolean;
@@ -194,13 +197,31 @@ export function deriveDeepInterviewHud(
194
197
  export function buildRalplanHudSummary(state: RalplanHudState): WorkflowHudSummary {
195
198
  const verdict = state.verdict?.toUpperCase();
196
199
  const verdictSeverity =
197
- verdict === "BLOCK"
200
+ verdict === "BLOCK" || verdict === "REJECT"
198
201
  ? "blocked"
199
202
  : verdict === "ITERATE" || verdict === "WATCH"
200
203
  ? "warning"
201
- : verdict === "APPROVE" || verdict === "CLEAR"
204
+ : verdict === "APPROVE" || verdict === "CLEAR" || verdict === "OKAY"
202
205
  ? "success"
203
206
  : undefined;
207
+ const reviewPassChip = (
208
+ label: "arch" | "crit",
209
+ passes: number | undefined,
210
+ priority: number,
211
+ ): WorkflowHudChip | null => {
212
+ if (
213
+ state.pendingApproval ||
214
+ typeof passes !== "number" ||
215
+ !Number.isFinite(passes) ||
216
+ passes <= 0 ||
217
+ typeof state.reviewPassBudget !== "number" ||
218
+ !Number.isFinite(state.reviewPassBudget) ||
219
+ state.reviewPassBudget <= 0
220
+ ) {
221
+ return null;
222
+ }
223
+ return chip(label, `${passes}/${state.reviewPassBudget}`, priority);
224
+ };
204
225
  return {
205
226
  version: 1,
206
227
  summary: state.latestSummary,
@@ -217,6 +238,8 @@ export function buildRalplanHudSummary(state: RalplanHudState): WorkflowHudSumma
217
238
  30,
218
239
  ),
219
240
  chip("stages", state.stages, 35),
241
+ reviewPassChip("arch", state.architectPasses, 36),
242
+ reviewPassChip("crit", state.criticPasses, 38),
220
243
  chip("verdict", verdict, 40, verdictSeverity),
221
244
  ]),
222
245
  ...(state.updatedAt ? { updated_at: state.updatedAt } : {}),
@@ -35,17 +35,31 @@ function planningPhaseBlockMessage(skill: CanonicalSkcWorkflowSkill): string {
35
35
  }
36
36
 
37
37
  const BLOCKED_TOOL_NAMES = new Set(["edit", "write", "ast_edit", "bash"]);
38
+ /**
39
+ * Only `/dev/null` is exempt. `/dev/stdout`, `/dev/stderr`, and `/dev/fd/<n>` are descriptor
40
+ * aliases: `exec 1<>src/product.ts; printf x >/dev/stdout` reaches a real repository file
41
+ * through a rebound descriptor, so they must stay blocked.
42
+ */
43
+ const DEVICE_SINK_PATHS = new Set(["/dev/null"]);
44
+ /** Bash write forms the plain `>`/`>>` scanner misses: clobber, dup-to-path, and read-write open. */
45
+ const BASH_EXTENDED_WRITE_RE = /(?:>\||<>|>&(?![\s;&|]*(?:\d+|-)(?:[\s;&|]|$)))\s*([^\s;&|]+)/g;
46
+ /** Descriptor rebinding is not statically resolvable; any `exec` redirection forces a fail-closed verdict. */
47
+ const BASH_EXEC_REDIRECT_RE = /(?:^|[;&|\n])\s*(?:sudo\s+)?exec\b[^;&|\n]*[<>]/i;
48
+
38
49
  const ARCHIVE_OR_SQLITE_BASE_RE = /^(.+?\.(?:tar\.gz|sqlite3|sqlite|db3|zip|tgz|tar|db))(?:$|:)/i;
39
50
  const INTERNAL_SCHEME_RE = /^[a-z][a-z0-9+.-]*:\/\//i;
40
51
  const VIM_FILE_SWITCH_RE = /^\s*:(?:e|e!|edit|edit!)(?:\s+([^<\r\n]+))?(?:<CR>|\r|\n|$)/i;
41
52
  const BASH_MUTATION_COMMAND_RE =
42
- /(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?(?:tee|touch|rm|mkdir|cp|mv|install|truncate)\b([^;&|\n]*)|(?:^|[^<>])(?:>>?|\d>>?)\s*([^\s;&|]+)/gi;
53
+ /(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?(?:[^\s;&|]*\/)?(?:tee|touch|rm|mkdir|cp|mv|install|truncate)\b([^;&|\n]*)|(?:^|[^<>])(?:>>?|\d>>?)\s*([^\s;&|]+)/gi;
43
54
  const BASH_IN_PLACE_MUTATION_COMMAND_RE = /(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?(?:sed|perl)\b([^;&|\n]*)/gi;
44
55
  const BASH_OPAQUE_INTERPRETER_WRITE_RE =
45
56
  /(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?(?:python3?|node|ruby)\b[^;&|\n]*(?:-c|-e)\b[^;&|\n]*(?:open\s*\(|writeFile(?:Sync)?\s*\(|\.write\s*\()/i;
46
57
  const BASH_HEREDOC_OPAQUE_INTERPRETER_WRITE_RE =
47
58
  /(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?(?:python3?|node|ruby)\b[^;&|\n]*(?:<<[-]?\s*['"]?\w+['"]?)[\s\S]*(?:open\s*\(|writeFile(?:Sync)?\s*\(|\.write\s*\()/i;
48
- const BASH_DD_OUTPUT_RE = /(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?dd\b([^;&|\n]*)/gi;
59
+ const BASH_DD_OUTPUT_RE = /(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?(?:[^\s;&|]*\/)?dd\b([^;&|\n]*)/gi;
60
+ /** Literal `sh|bash|zsh -c '<script>'` payloads whose nested script must also be scanned. */
61
+ const BASH_NESTED_SHELL_RE =
62
+ /(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?(?:[^\s;&|]*\/)?(?:ba|z|da)?sh\s+(?:-[A-Za-z]+\s+)*-[A-Za-z]*c\s+(?:(')([^']*)'|(")([^"]*)")/g;
49
63
 
50
64
  type ToolWithEditMode = AgentTool & {
51
65
  mode?: unknown;
@@ -66,6 +80,12 @@ export interface WorkflowMutationGuardInput {
66
80
  interface ExtractedTargets {
67
81
  paths: string[];
68
82
  unknown: boolean;
83
+ /**
84
+ * Set when a bash command was recognized as performing a filesystem write.
85
+ * During a planning phase an unrecognized bash command is allowed (reading
86
+ * and inspection must not be blocked); only a recognized mutation blocks.
87
+ */
88
+ explicitMutation?: boolean;
69
89
  }
70
90
 
71
91
  export interface WorkflowMutationDecision {
@@ -371,7 +391,34 @@ function cleanShellWord(value: string): string {
371
391
  return value.replace(/^['"]|['"]$/g, "");
372
392
  }
373
393
 
374
- function extractBashTargets(args: unknown): ExtractedTargets {
394
+ /**
395
+ * Blank out single-quoted spans so shell metacharacters inside a literal
396
+ * argument value (e.g. `--value 'uses `x`; a > b'`) are not misread as
397
+ * redirections or separators. Single quotes suppress every expansion in POSIX
398
+ * shells, so their contents are always inert data. Double-quoted spans are left
399
+ * intact because they still expand `$(...)` and backticks.
400
+ */
401
+ function maskSingleQuotedSpans(command: string): string {
402
+ let masked = "";
403
+ let inSingle = false;
404
+ for (const character of command) {
405
+ if (character === "'") {
406
+ inSingle = !inSingle;
407
+ masked += character;
408
+ continue;
409
+ }
410
+ masked += inSingle && character !== "\n" ? " " : character;
411
+ }
412
+ // An unbalanced quote means the parse is unreliable; keep the original text
413
+ // so the scanner stays fail-closed rather than blind.
414
+ return inSingle ? command : masked;
415
+ }
416
+
417
+ function isDeviceSinkPath(value: string): boolean {
418
+ return DEVICE_SINK_PATHS.has(cleanShellWord(value));
419
+ }
420
+
421
+ function extractBashTargets(args: unknown, depth = 0): ExtractedTargets {
375
422
  const record = getRecord(args);
376
423
  const command = safeString(record?.command);
377
424
  const targets: ExtractedTargets = { paths: [], unknown: false };
@@ -379,32 +426,74 @@ function extractBashTargets(args: unknown): ExtractedTargets {
379
426
  targets.unknown = true;
380
427
  return targets;
381
428
  }
429
+ // A literal `sh|bash|zsh -c '<script>'` payload is a real command list. Its
430
+ // mutations never match the top-level patterns, so recurse into it; anything
431
+ // deeper than a bounded depth is not statically analyzable and fails closed.
432
+ for (const match of command.matchAll(BASH_NESTED_SHELL_RE)) {
433
+ if (depth >= 2) {
434
+ targets.explicitMutation = true;
435
+ targets.unknown = true;
436
+ break;
437
+ }
438
+ const nested = extractBashTargets({ command: match[2] ?? match[4] ?? "" }, depth + 1);
439
+ for (const nestedPath of nested.paths) addPath(targets, nestedPath);
440
+ if (nested.unknown) targets.unknown = true;
441
+ if (nested.explicitMutation) targets.explicitMutation = true;
442
+ }
443
+ // Nested scripts were read from the raw text above; every scanner below works
444
+ // on the masked view so quoted argument data cannot look like a redirection.
445
+ const scanned = maskSingleQuotedSpans(command);
382
446
  if (BASH_OPAQUE_INTERPRETER_WRITE_RE.test(command) || BASH_HEREDOC_OPAQUE_INTERPRETER_WRITE_RE.test(command)) {
447
+ targets.explicitMutation = true;
383
448
  targets.unknown = true;
384
449
  }
385
- for (const match of command.matchAll(BASH_DD_OUTPUT_RE)) {
450
+ // `exec 1<>file` rebinds a descriptor, so a later `>/dev/null` may not reach the device at all.
451
+ if (BASH_EXEC_REDIRECT_RE.test(scanned)) {
452
+ targets.explicitMutation = true;
453
+ targets.unknown = true;
454
+ }
455
+ for (const match of scanned.matchAll(BASH_EXTENDED_WRITE_RE)) {
456
+ targets.explicitMutation = true;
457
+ const cleaned = cleanShellWord(match[1] ?? "");
458
+ if (!cleaned) targets.unknown = true;
459
+ else if (!isDeviceSinkPath(cleaned)) addPath(targets, cleaned);
460
+ }
461
+ for (const match of scanned.matchAll(BASH_DD_OUTPUT_RE)) {
462
+ targets.explicitMutation = true;
386
463
  const parts = shellWords(match[1] ?? "").map(cleanShellWord);
387
- const output = parts.find(part => part.startsWith("of="));
388
- if (output) addPath(targets, output.slice(3));
389
- else targets.unknown = true;
464
+ // Every `of=` counts: GNU dd honors the last one, so `of=/dev/null of=real.ts` writes real.ts.
465
+ const outputs = parts.filter(part => part.startsWith("of="));
466
+ if (outputs.length === 0) targets.unknown = true;
467
+ for (const output of outputs) {
468
+ const outputPath = cleanShellWord(output.slice(3));
469
+ if (!outputPath) targets.unknown = true;
470
+ else if (!isDeviceSinkPath(outputPath)) addPath(targets, outputPath);
471
+ }
390
472
  }
391
- for (const match of command.matchAll(BASH_IN_PLACE_MUTATION_COMMAND_RE)) {
473
+ for (const match of scanned.matchAll(BASH_IN_PLACE_MUTATION_COMMAND_RE)) {
392
474
  const parts = shellWords(match[1] ?? "").map(cleanShellWord);
393
475
  const hasInPlaceFlag = parts.some(part => /^-.*i/.test(part));
394
476
  if (!hasInPlaceFlag) continue;
477
+ targets.explicitMutation = true;
395
478
  const target = [...parts].reverse().find(part => part && !part.startsWith("-"));
396
479
  if (target) addPath(targets, target);
397
480
  else targets.unknown = true;
398
481
  }
399
- for (const match of command.matchAll(BASH_MUTATION_COMMAND_RE)) {
482
+ for (const match of scanned.matchAll(BASH_MUTATION_COMMAND_RE)) {
483
+ targets.explicitMutation = true;
400
484
  const redirected = match[2]?.trim();
401
485
  if (redirected) {
402
- addPath(targets, cleanShellWord(redirected));
486
+ const cleaned = cleanShellWord(redirected);
487
+ // A capture that dequotes to nothing (e.g. `>" src.ts"`) is a truncated parse, not a safe no-op.
488
+ if (!cleaned) targets.unknown = true;
489
+ else if (!isDeviceSinkPath(cleaned)) addPath(targets, cleaned);
403
490
  continue;
404
491
  }
405
492
  const parts = shellWords(match[1] ?? "");
406
493
  const commandName = match[0]
407
- ?.match(/(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?(tee|touch|rm|mkdir|cp|mv|install|truncate)\b/i)?.[1]
494
+ ?.match(
495
+ /(?:^|[;&|\n])\s*(?:\w+=[^\s]+\s+)*(?:sudo\s+)?(?:[^\s;&|]*\/)?(tee|touch|rm|mkdir|cp|mv|install|truncate)\b/i,
496
+ )?.[1]
408
497
  ?.toLowerCase();
409
498
  const targetParts =
410
499
  commandName === "cp" || commandName === "mv" || commandName === "install" || commandName === "truncate"
@@ -632,7 +721,10 @@ export async function getWorkflowMutationDecision(
632
721
  }
633
722
  if (input.forceOverride) return { blocked: false, targets: [] };
634
723
  const message = planningPhaseBlockMessage(planning.skill);
635
- if (targets.unknown) {
724
+ // Bash during a planning phase blocks only when a filesystem mutation was
725
+ // actually recognized. Inspection, reads, and CLI invocations the scanner does
726
+ // not model stay usable; other tools keep failing closed on unknown targets.
727
+ if (targets.unknown && (input.tool.name !== "bash" || targets.explicitMutation)) {
636
728
  return {
637
729
  blocked: true,
638
730
  message,
@@ -1516,7 +1516,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1516
1516
  },
1517
1517
  {
1518
1518
  name: "btw",
1519
- description: "Ask an ephemeral side question using the current session context",
1519
+ description: "Start an ephemeral multi-turn side chat using the current session context",
1520
1520
  inlineHint: "<question>",
1521
1521
  allowArgs: true,
1522
1522
  handleTui: async (command, runtime) => {
package/src/ssh/utils.ts CHANGED
@@ -3,6 +3,20 @@ export function sanitizeHostName(name: string): string {
3
3
  return sanitized.length > 0 ? sanitized : "remote";
4
4
  }
5
5
 
6
+ export function validateSshDestination(username: string | undefined, host: string): string | undefined {
7
+ if (host.startsWith("-") || username?.startsWith("-")) {
8
+ return "username and host must not begin with '-'";
9
+ }
10
+ if (/\0|\r|\n/.test(host) || (username !== undefined && /\0|\r|\n/.test(username))) {
11
+ return "username and host must not contain NUL or line breaks";
12
+ }
13
+ return undefined;
14
+ }
15
+
6
16
  export function buildSshTarget(username: string | undefined, host: string): string {
17
+ const validationError = validateSshDestination(username, host);
18
+ if (validationError) {
19
+ throw new Error(`Invalid SSH destination: ${validationError}`);
20
+ }
7
21
  return username ? `${username}@${host}` : host;
8
22
  }