@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
package/src/cli.ts CHANGED
@@ -5,9 +5,17 @@
5
5
  * lightweight CLI runner from pi-utils.
6
6
  */
7
7
  import "@sayknow-cli/utils/postmortem";
8
+ import { THINKING_EFFORTS } from "@sayknow-cli/ai";
8
9
  import { Args, type CliConfig, Command, type CommandEntry, Flags, run } from "@sayknow-cli/utils/cli";
9
10
  import { APP_NAME, formatBunRuntimeError, MIN_BUN_VERSION, VERSION } from "@sayknow-cli/utils/dirs";
11
+ import { loadNative as loadNativeBindings } from "../../natives/native/loader-state.js";
10
12
  import { runFixtureReport } from "./cli/fixture-report";
13
+ import { admitManagedOwnerBeforeCli, completeManagedOwnerRecovery } from "./skc-runtime/managed-owner-admission";
14
+ import {
15
+ isManagedOwnerSupervisorArgv,
16
+ MANAGED_OWNER_CHILD_TOKEN_ENV,
17
+ runManagedOwnerSupervisor,
18
+ } from "./skc-runtime/managed-owner-supervisor";
11
19
  import { isTmuxOwnerIsolationCliArgv, runTmuxOwnerIsolationCliFromStdin } from "./skc-runtime/tmux-owner-isolation-cli";
12
20
  import { smokeTestTabWorker } from "./tools/browser/tab-worker-smoke";
13
21
 
@@ -56,6 +64,7 @@ export const commands: CommandEntry[] = [
56
64
  { name: "migrate", load: () => import("./commands/migrate").then(m => m.default) },
57
65
  { name: "rlm", load: () => import("./commands/rlm").then(m => m.default) },
58
66
  { name: "update", load: () => import("./commands/update").then(m => m.default) },
67
+ { name: "read", load: () => import("./commands/read").then(m => m.default) },
59
68
  { name: "plugin", load: () => import("./commands/plugin").then(m => m.default) },
60
69
  { name: "completion", load: () => import("./commands/completion").then(m => m.default) },
61
70
  { name: "launch", load: () => import("./commands/launch").then(m => m.default) },
@@ -112,6 +121,36 @@ Options:
112
121
  `);
113
122
  }
114
123
 
124
+ export function interactiveBootstrapText(
125
+ argv: readonly string[],
126
+ stdinIsTTY = process.stdin.isTTY,
127
+ stdoutIsTTY = process.stdout.isTTY,
128
+ ): string | undefined {
129
+ if (!stdinIsTTY || !stdoutIsTTY || argv[0] !== "launch") return undefined;
130
+ for (let index = 1; index < argv.length; index++) {
131
+ const arg = argv[index];
132
+ if (
133
+ arg === "--print" ||
134
+ arg?.startsWith("--print=") ||
135
+ arg === "-p" ||
136
+ arg === "--export" ||
137
+ arg?.startsWith("--export=") ||
138
+ arg === "--list-models" ||
139
+ arg?.startsWith("--list-models=") ||
140
+ arg === "--mode" ||
141
+ arg?.startsWith("--mode=") ||
142
+ arg === "--help" ||
143
+ arg?.startsWith("--help=") ||
144
+ arg === "-h" ||
145
+ arg === "--version" ||
146
+ arg?.startsWith("--version=") ||
147
+ arg === "-v"
148
+ )
149
+ return undefined;
150
+ }
151
+ return "\u001b[?25h\u001b[38;5;45mSKC\u001b[0m warming workspace\r\n\r\n> ";
152
+ }
153
+
115
154
  function isNotifyDaemonInternalFastPath(argv: string[]): boolean {
116
155
  return argv[0] === "notify" && argv[1] === "daemon-internal";
117
156
  }
@@ -138,6 +177,46 @@ async function runChatDaemonInternalFastPath(argv: string[]): Promise<void> {
138
177
  await runChatDaemonInternal(action === "discord-internal" ? "discord" : "slack", argv.slice(2));
139
178
  }
140
179
 
180
+ type MemoryGuardNativeSmokeLoad = () => Record<string, unknown>;
181
+ type WindowsJobMemoryProbeResult = Record<string, unknown> & { kind: string };
182
+ type MemoryGuardNativeSmokeReceipt = {
183
+ api: "memory_guard_windows_job_probe_v1";
184
+ source: "pi_natives";
185
+ result: WindowsJobMemoryProbeResult;
186
+ };
187
+
188
+ export function isMemoryGuardNativeSmokeFastPath(argv: readonly string[]): boolean {
189
+ return (
190
+ argv.length === 3 && argv[0] === "internal" && argv[1] === "memory-guard-native-smoke" && argv[2] === "--json"
191
+ );
192
+ }
193
+
194
+ function parseWindowsJobMemoryProbeResult(value: unknown): WindowsJobMemoryProbeResult {
195
+ if (!value || typeof value !== "object") {
196
+ throw new Error("memory-guard-native-smoke: native probe returned a non-object result");
197
+ }
198
+ const result = value as Record<string, unknown>;
199
+ if (typeof result.kind !== "string") {
200
+ throw new Error("memory-guard-native-smoke: native probe result is missing a string kind tag");
201
+ }
202
+ return result as WindowsJobMemoryProbeResult;
203
+ }
204
+
205
+ export function runMemoryGuardNativeSmokeFastPath(
206
+ options: { loadNative?: MemoryGuardNativeSmokeLoad; writeStdout?: (text: string) => void } = {},
207
+ ): void {
208
+ const probe = (options.loadNative ?? loadNativeBindings)().probeWindowsJobMemory;
209
+ if (typeof probe !== "function") {
210
+ throw new Error("memory-guard-native-smoke: probeWindowsJobMemory export missing from native addon");
211
+ }
212
+ const receipt: MemoryGuardNativeSmokeReceipt = {
213
+ api: "memory_guard_windows_job_probe_v1",
214
+ source: "pi_natives",
215
+ result: parseWindowsJobMemoryProbeResult((probe as () => unknown)()),
216
+ };
217
+ (options.writeStdout ?? (text => process.stdout.write(text)))(`${JSON.stringify(receipt)}\n`);
218
+ }
219
+
141
220
  function rootFixtureArg(argv: string[]): { present: boolean; id: string | undefined } {
142
221
  for (let i = 0; i < argv.length; i++) {
143
222
  const arg = argv[i];
@@ -208,8 +287,8 @@ export class RootHelpCommand extends Command {
208
287
  tmux: Flags.boolean({ description: "Launch interactive startup inside tmux" }),
209
288
  tools: Flags.string({ description: "Comma-separated list of tools to enable (default: all)" }),
210
289
  thinking: Flags.string({
211
- description: "Set thinking level: ultra, high, medium, low",
212
- options: ["ultra", "high", "medium", "low"],
290
+ description: `Set thinking level: ${THINKING_EFFORTS.join(", ")}`,
291
+ options: [...THINKING_EFFORTS],
213
292
  }),
214
293
  hook: Flags.string({ description: "Load a hook/extension file (can be used multiple times)", multiple: true }),
215
294
  extension: Flags.string({
@@ -287,9 +366,34 @@ export function normalizeResumeAlias(argv: readonly string[]): string[] {
287
366
  return argv.length === 1 && argv[0] === "resume" ? ["--resume"] : [...argv];
288
367
  }
289
368
 
369
+ function routeLegacyRootArgv(argv: readonly string[]): string[] | undefined {
370
+ if (argv[0] === "coordinator-mcp") return ["mcp-serve", "coordinator", ...argv.slice(1)];
371
+ if (argv[0] !== "--team") return undefined;
372
+ const sizeValues: string[] = [];
373
+ const remaining: string[] = [];
374
+ for (let index = 1; index < argv.length; index++) {
375
+ const arg = argv[index] ?? "";
376
+ if (arg === "--team-size") {
377
+ sizeValues.push(argv[index + 1] ?? "");
378
+ index++;
379
+ } else if (arg.startsWith("--team-size=")) {
380
+ sizeValues.push(arg.slice("--team-size=".length));
381
+ } else {
382
+ remaining.push(arg);
383
+ }
384
+ }
385
+ const size = sizeValues[0];
386
+ if (sizeValues.length !== 1 || !size || !/^[1-9]\d*$/.test(size)) {
387
+ return ["team", "0", "invalid legacy --team-size"];
388
+ }
389
+ return ["team", size, ...remaining];
390
+ }
391
+
290
392
  /** Apply the same default-launch routing used by runCli after root fast paths. */
291
393
  export function routeRootArgv(argv: readonly string[]): string[] {
292
394
  const normalizedArgv = normalizeResumeAlias(argv);
395
+ const legacyArgv = routeLegacyRootArgv(normalizedArgv);
396
+ if (legacyArgv) return legacyArgv;
293
397
  const first = normalizedArgv[0];
294
398
  return first === "--help" || first === "-h" || first === "--version" || first === "-v" || first === "help"
295
399
  ? normalizedArgv
@@ -321,10 +425,26 @@ export async function runCli(argv: string[]): Promise<void> {
321
425
  }
322
426
  // Re-exec could not be spawned; fall through and run in this process.
323
427
  }
428
+ if (isMemoryGuardNativeSmokeFastPath(argv)) {
429
+ runMemoryGuardNativeSmokeFastPath();
430
+ return;
431
+ }
324
432
  if (isTmuxOwnerIsolationCliArgv(argv)) {
325
433
  await runTmuxOwnerIsolationCliFromStdin();
326
434
  return;
327
435
  }
436
+ if (isManagedOwnerSupervisorArgv(argv)) {
437
+ await runManagedOwnerSupervisor();
438
+ return;
439
+ }
440
+ if (process.env[MANAGED_OWNER_CHILD_TOKEN_ENV] !== undefined) {
441
+ const admission = await admitManagedOwnerBeforeCli();
442
+ if (admission.kind === "blocked") return;
443
+ if (admission.kind === "recovery") {
444
+ await completeManagedOwnerRecovery(admission.context);
445
+ return;
446
+ }
447
+ }
328
448
  if (isNotifyDaemonInternalFastPath(argv)) {
329
449
  await runNotifyDaemonInternalFastPath(argv);
330
450
  return;
@@ -348,11 +468,9 @@ export async function runCli(argv: string[]): Promise<void> {
348
468
  process.exitCode = await runFixtureReport(id);
349
469
  return;
350
470
  }
351
- if (isStatsHelpFastPath(argv)) {
352
- showStatsFastHelp();
353
- return;
354
- }
355
- if (hasRootHelpFlag(argv)) {
471
+ const normalizedArgv = normalizeResumeAlias(argv);
472
+ const legacyArgv = routeLegacyRootArgv(normalizedArgv);
473
+ if (!legacyArgv && hasRootHelpFlag(normalizedArgv)) {
356
474
  const { renderRootHelp } = await import("@sayknow-cli/utils/cli");
357
475
  const { getExtraHelpText } = await import("./cli/fast-help");
358
476
  renderRootHelp({ bin: APP_NAME, version: VERSION, commands: new Map([["launch", RootHelpCommand]]) });
@@ -362,14 +480,18 @@ export async function runCli(argv: string[]): Promise<void> {
362
480
  }
363
481
  return;
364
482
  }
365
- if (hasRootVersionFlag(argv)) {
483
+ if (!legacyArgv && hasRootVersionFlag(normalizedArgv)) {
366
484
  process.stdout.write(`${APP_NAME}/${VERSION}\n`);
367
485
  return;
368
486
  }
487
+ const runArgv = legacyArgv ?? routeRootArgv(normalizedArgv);
488
+ if (isStatsHelpFastPath(runArgv)) {
489
+ showStatsFastHelp();
490
+ return;
491
+ }
492
+ const bootstrap = interactiveBootstrapText(runArgv);
493
+ if (bootstrap) process.stdout.write(bootstrap);
369
494
  await installRuntimeGlobals();
370
- // --help and --version are handled by run() directly, don't rewrite those.
371
- // Everything else that isn't a known subcommand routes to "launch".
372
- const runArgv = routeRootArgv(argv);
373
495
  return run({ bin: APP_NAME, version: VERSION, argv: runArgv, commands, help: showHelp });
374
496
  }
375
497
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Manage SKC background daemons (status/list/stop/reload).
3
3
  */
4
- import { Args, Command, Flags } from "@sayknow-cli/utils/cli";
4
+ import { Args, CliParseError, Command, Flags } from "@sayknow-cli/utils/cli";
5
5
  import {
6
6
  type DaemonCommandAction,
7
7
  type DaemonCommandArgs,
@@ -15,6 +15,18 @@ import { runSdkSessionCli } from "../sdk/cli";
15
15
 
16
16
  const ACTIONS = [...DAEMON_ACTION_TOKENS, "discord-internal", "slack-internal", "session"] as const;
17
17
 
18
+ function parsePositiveTimeout(raw: string | undefined, flagName: string): number | undefined {
19
+ if (raw === undefined) return undefined;
20
+ if (!/^[0-9]+$/.test(raw)) {
21
+ throw new CliParseError(`Expected ${flagName} to be a positive safe integer, got "${raw}"`);
22
+ }
23
+ const value = Number(raw);
24
+ if (!Number.isSafeInteger(value) || value <= 0) {
25
+ throw new CliParseError(`Expected ${flagName} to be a positive safe integer, got "${raw}"`);
26
+ }
27
+ return value;
28
+ }
29
+
18
30
  export default class Daemon extends Command {
19
31
  static description =
20
32
  "Manage SKC background daemons and SDK sessions. Routine use: `skc daemon status` to check, `skc daemon restart` to reload (spawns one if none is running). `stop`/`list` and the escalation flags below are advanced primitives.";
@@ -41,8 +53,8 @@ export default class Daemon extends Command {
41
53
  all: Flags.boolean({ description: "Target all registered daemon kinds" }),
42
54
  json: Flags.boolean({ description: "Emit JSON output" }),
43
55
  force: Flags.boolean({ description: "Allow hard-kill escalation when graceful stop times out" }),
44
- "graceful-timeout-ms": Flags.integer({ description: "Cooperative stop timeout before escalation" }),
45
- "kill-timeout-ms": Flags.integer({ description: "Wait for old pid death after SIGKILL" }),
56
+ "graceful-timeout-ms": Flags.string({ description: "Cooperative stop timeout before escalation" }),
57
+ "kill-timeout-ms": Flags.string({ description: "Wait for old pid death after SIGKILL" }),
46
58
  "spawn-if-stopped": Flags.boolean({ description: "On reload, spawn even when no daemon is running" }),
47
59
  smoke: Flags.boolean({ description: "Internal: run worker smoke without configuration or network" }),
48
60
  "owner-id": Flags.string({ description: "Internal: daemon owner id" }),
@@ -64,6 +76,11 @@ export default class Daemon extends Command {
64
76
  const rawAction = args.action ?? "status";
65
77
  const positional = Array.isArray(args.kind) ? args.kind : args.kind ? [args.kind] : [];
66
78
  const flagRec = flags as Record<string, unknown>;
79
+ const gracefulTimeoutMs = parsePositiveTimeout(
80
+ flagRec["graceful-timeout-ms"] as string | undefined,
81
+ "--graceful-timeout-ms",
82
+ );
83
+ const killTimeoutMs = parsePositiveTimeout(flagRec["kill-timeout-ms"] as string | undefined, "--kill-timeout-ms");
67
84
  if (rawAction === "session") {
68
85
  await runSdkSessionCli({
69
86
  action: positional[0],
@@ -91,8 +108,8 @@ export default class Daemon extends Command {
91
108
  json: Boolean(flags.json),
92
109
  force: Boolean(flags.force),
93
110
  verbose: Boolean(flags.verbose),
94
- gracefulTimeoutMs: flagRec["graceful-timeout-ms"] as number | undefined,
95
- killTimeoutMs: flagRec["kill-timeout-ms"] as number | undefined,
111
+ gracefulTimeoutMs,
112
+ killTimeoutMs,
96
113
  spawnIfStopped: flagRec["spawn-if-stopped"] as boolean | undefined,
97
114
  smoke: Boolean(flags.smoke),
98
115
  ownerId: flagRec["owner-id"] as string | undefined,
@@ -2,7 +2,22 @@ import { Command, Flags } from "@sayknow-cli/utils/cli";
2
2
  import { runNativeDeepInterviewCommand } from "../skc-runtime/deep-interview-runtime";
3
3
 
4
4
  export default class DeepInterview extends Command {
5
- static description = "Run native SKC deep-interview workflow";
5
+ static description = `Run native SKC deep-interview workflow.
6
+
7
+ All deep-interview state operations go through this command — no skc state needed:
8
+ read Print the persisted envelope, revision, content sha, and any pending draft
9
+ write One-shot incremental JSON merge into state (--reset replaces; the locked
10
+ intent contract survives a reset)
11
+ stage Stage one JSON transition draft (--for <transition> --input '<json>'|@file)
12
+ check Dry-run the staged draft against current state (same merge apply performs)
13
+ apply Commit the staged draft with runtime-owned revision+sha CAS
14
+ discard Remove the pending draft
15
+ clear Clear deep-interview state for the session (lifecycle passthrough)
16
+ handoff Hand off to the next workflow skill (lifecycle passthrough)
17
+
18
+ Ambiguity is runtime-owned: apply/write derive current_ambiguity from the latest valid scored
19
+ round and clamp it to the deterministic floor. Sessions resolve from --session-id, payload
20
+ session_id, or SKC_SESSION_ID.`;
6
21
  static strict = false;
7
22
  static flags = {
8
23
  quick: Flags.boolean({ description: "Seed a quick deep-interview run" }),
@@ -14,6 +29,11 @@ export default class DeepInterview extends Command {
14
29
  "session-id": Flags.string({
15
30
  description: "Route state/spec handoff through a session-scoped .skc/_session-{sessionid} directory",
16
31
  }),
32
+ input: Flags.string({ description: "JSON payload (or @file) for the write/stage verbs" }),
33
+ for: Flags.string({
34
+ description: "Transition for stage: initialize-context | record-round | update-facts | merge-state",
35
+ }),
36
+ reset: Flags.boolean({ description: "With write: replace state instead of incremental merge" }),
17
37
  write: Flags.boolean({ description: "Persist a final deep-interview spec through the sanctioned SKC CLI/API" }),
18
38
  stage: Flags.string({ description: 'Spec stage for --write (currently "final")' }),
19
39
  slug: Flags.string({ description: "Safe slug for .skc/_session-{sessionid}/specs/deep-interview-<slug>.md" }),
@@ -27,6 +47,11 @@ export default class DeepInterview extends Command {
27
47
  };
28
48
  static examples = [
29
49
  '$ skc deep-interview --trace --standard "<idea>"',
50
+ "$ skc deep-interview read --json",
51
+ '$ skc deep-interview write --input \'{"state":{"threshold":0.05}}\' --json',
52
+ '$ skc deep-interview stage --for record-round --input \'{"state":{"rounds":[{"round":1,"round_key":"r1"}]}}\' --json',
53
+ "$ skc deep-interview check --json",
54
+ "$ skc deep-interview apply --json",
30
55
  "$ skc deep-interview --write --stage final --slug my-feature --spec ./final-spec.md",
31
56
  "$ skc deep-interview --write --stage final --slug my-feature --spec ./final-spec.md --deliberate",
32
57
  ];
@@ -14,6 +14,7 @@ import { existsSync, readFileSync } from "node:fs";
14
14
  import * as fs from "node:fs/promises";
15
15
  import * as path from "node:path";
16
16
  import { Args, Command, Flags } from "@sayknow-cli/utils/cli";
17
+ import { $credentialEnv } from "@sayknow-cli/utils/env";
17
18
  import { classifyRecovery } from "../harness-control-plane/classifier";
18
19
  import { callEndpoint, EndpointUnreachableError } from "../harness-control-plane/control-endpoint";
19
20
  import {
@@ -565,20 +566,42 @@ function ownerIsolationPlatform(): NodeJS.Platform {
565
566
  : "linux";
566
567
  }
567
568
 
569
+ /**
570
+ * Operator override for the process-start probe command, resolved from trusted
571
+ * environment sources only.
572
+ *
573
+ * The result is spawned, so whatever can set it chooses which binary runs.
574
+ * `$env` merges the caller's `cwd/.env` into `process.env`, so reading it there
575
+ * would let repository content pick the command; resolve it the same way
576
+ * provider credentials are (launching shell plus SKC/user-owned `.env` files,
577
+ * never the project `.env`). A malformed override stays fatal rather than
578
+ * silently falling back to `ps`, matching the previous behavior.
579
+ */
580
+ type ProcessStartCommandOverride = { kind: "none" } | { kind: "invalid" } | { kind: "command"; command: string[] };
581
+
582
+ function processStartCommandOverride(): ProcessStartCommandOverride {
583
+ const configured = $credentialEnv("SKC_HARNESS_PROCESS_START_COMMAND");
584
+ if (!configured) return { kind: "none" };
585
+ try {
586
+ const parsed = JSON.parse(configured) as unknown;
587
+ if (!Array.isArray(parsed) || parsed.length === 0 || parsed.some(value => typeof value !== "string" || !value))
588
+ return { kind: "invalid" };
589
+ return { kind: "command", command: parsed as string[] };
590
+ } catch {
591
+ return { kind: "invalid" };
592
+ }
593
+ }
594
+
595
+ /** Test seam: the process-start command override as resolved from trusted env. */
596
+ export function processStartCommandOverrideForTest(): ProcessStartCommandOverride {
597
+ return processStartCommandOverride();
598
+ }
599
+
568
600
  function portableProcessStartTime(pid: number): string | null {
569
601
  if (process.platform === "linux") return null;
570
- const configured = process.env.SKC_HARNESS_PROCESS_START_COMMAND;
571
- let command: string[] = ["ps", "-o", "lstart=", "-p"];
572
- if (configured) {
573
- try {
574
- const parsed = JSON.parse(configured) as unknown;
575
- if (!Array.isArray(parsed) || parsed.length === 0 || parsed.some(value => typeof value !== "string" || !value))
576
- return null;
577
- command = parsed;
578
- } catch {
579
- return null;
580
- }
581
- }
602
+ const override = processStartCommandOverride();
603
+ if (override.kind === "invalid") return null;
604
+ const command: string[] = override.kind === "command" ? override.command : ["ps", "-o", "lstart=", "-p"];
582
605
  const result = Bun.spawnSync([...command, String(pid)], {
583
606
  stdout: "pipe",
584
607
  stderr: "ignore",
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Show what the read tool will return for a given path.
3
3
  */
4
- import { Args, Command } from "@sayknow-cli/utils/cli";
4
+ import { Args, Command, Flags } from "@sayknow-cli/utils/cli";
5
5
  import { type ReadCommandArgs, runReadCommand } from "../cli/read-cli";
6
6
  import { initTheme } from "../modes/theme/theme";
7
7
 
@@ -15,8 +15,16 @@ export default class Read extends Command {
15
15
  }),
16
16
  };
17
17
 
18
+ static flags = {
19
+ truncation: Flags.string({
20
+ options: ["head", "last", "both"],
21
+ description: "Which end of an over-budget result to keep",
22
+ }),
23
+ };
24
+
18
25
  static examples = [
19
26
  "skc read src/foo.ts",
27
+ "skc read src/foo.ts --truncation head",
20
28
  "skc read src/foo.ts:50-100",
21
29
  "skc read src/foo.ts:raw",
22
30
  "skc read https://example.com",
@@ -25,9 +33,10 @@ export default class Read extends Command {
25
33
  ];
26
34
 
27
35
  async run(): Promise<void> {
28
- const { args } = await this.parse(Read);
36
+ const { args, flags } = await this.parse(Read);
29
37
  const cmd: ReadCommandArgs = {
30
38
  path: args.path ?? "",
39
+ truncation: flags.truncation as ReadCommandArgs["truncation"],
31
40
  };
32
41
  await initTheme();
33
42
  await runReadCommand(cmd);
@@ -1,11 +1,13 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import * as fs from "node:fs/promises";
3
+ import * as os from "node:os";
3
4
  import * as path from "node:path";
4
- import { Args, Command, Flags } from "@sayknow-cli/utils/cli";
5
+ import { Args, CliParseError, Command, Flags, renderCommandHelp } from "@sayknow-cli/utils/cli";
5
6
  import type { Args as ParsedArgs } from "../cli/args";
6
7
  import { Settings } from "../config/settings";
7
8
  import { applyStartupModelProfiles, createSessionManager } from "../main";
8
9
  import { initializeExtensions } from "../modes/runtime-init";
10
+ import { ACP_MCP_REQUEST_TIMEOUT_MS, ACP_MCP_STARTUP_HEADROOM_MS } from "../sdk/acp/mcp";
9
11
  import { Broker } from "../sdk/broker/broker";
10
12
  import { completeBrokerProcess } from "../sdk/broker/internal";
11
13
  import {
@@ -25,6 +27,7 @@ import {
25
27
  type SdkStartupRollbackResult,
26
28
  SdkStartupRollbackTracker,
27
29
  } from "../sdk/startup-capability";
30
+ import { runSdkServe } from "../sdk/transport/serve-cli";
28
31
  import {
29
32
  type CapturedSessionTranscriptSnapshot,
30
33
  type ResumeSessionIdentity,
@@ -284,24 +287,106 @@ export async function runSessionHost(
284
287
  throw new Error("SDK startup did not complete before readiness cutoff.");
285
288
  }
286
289
 
287
- let opened: { parsed: ParsedArgs; sessionManager: SessionManager | undefined };
288
- let created: CreateLifecycleAgentSessionResult;
289
- try {
290
- opened = await openLifecycleSessionManager(request, cwd, agentDir);
291
- created = await createLifecycleAgentSession({ cwd, agentDir, sessionManager: opened.sessionManager });
292
- } catch (error) {
290
+ // Inlined rather than extracted to a helper: TypeScript's definite-assignment
291
+ // analysis does not see a `Promise<never>` helper as terminating, so hoisting
292
+ // this would make `opened`/`created` "used before assigned" below.
293
+ const registrationFailure = async (error: unknown): Promise<SdkStartupFailure> => {
293
294
  const rollback = new SdkStartupRollbackTracker();
294
295
  rollback.recordAbsent();
295
296
  const failure = normalizeSdkStartupFailure("registration", "failed", error);
296
297
  await writeFailure(failure, rollback.result);
297
- throw new Error(failure.message);
298
+ return failure;
299
+ };
300
+
301
+ let opened: { parsed: ParsedArgs; sessionManager: SessionManager | undefined };
302
+ let created: CreateLifecycleAgentSessionResult;
303
+ let mcpConfigDirectory: string | undefined;
304
+ try {
305
+ let mcpConfigPath: string | undefined;
306
+ try {
307
+ opened = await openLifecycleSessionManager(request, cwd, agentDir);
308
+ if (request.mcpServers && request.mcpServers.length > 0) {
309
+ mcpConfigDirectory = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), "skc-acp-mcp-")));
310
+ mcpConfigPath = path.join(mcpConfigDirectory, "mcp.json");
311
+ await Bun.write(
312
+ mcpConfigPath,
313
+ JSON.stringify({
314
+ mcpServers: Object.fromEntries(
315
+ request.mcpServers.map(server => [
316
+ server.name,
317
+ "url" in server
318
+ ? {
319
+ type: server.type,
320
+ url: server.url,
321
+ ...(server.headers ? { headers: server.headers } : {}),
322
+ timeout: ACP_MCP_REQUEST_TIMEOUT_MS,
323
+ }
324
+ : {
325
+ type: "stdio",
326
+ command: server.command,
327
+ args: server.args,
328
+ ...(server.env ? { env: server.env } : {}),
329
+ noInheritEnv: true,
330
+ timeout: ACP_MCP_REQUEST_TIMEOUT_MS,
331
+ },
332
+ ]),
333
+ ),
334
+ }),
335
+ );
336
+ }
337
+ } catch (error) {
338
+ throw await registrationFailure(error);
339
+ }
340
+
341
+ // The longer MCP startup ceiling is scoped to ACP lifecycle launches only:
342
+ // it applies when this request actually carried `mcpServers`. Ordinary
343
+ // CLI/SDK `mcpConfigPath` consumers keep the manager's short default.
344
+ //
345
+ // This recheck deliberately sits OUTSIDE the registration catch above.
346
+ // Inside it, the throw would be caught, reclassified as
347
+ // `registration`/`failed`, and written a second time, losing the
348
+ // `startup`/`pending` outcome the readiness cutoff is supposed to report.
349
+ // Session-manager open and MCP config write already consumed part of the
350
+ // budget, so re-read the clock here rather than reusing the earlier check.
351
+ let mcpStartupTimeoutMs: number | undefined;
352
+ if (mcpConfigPath !== undefined) {
353
+ const remaining = request.semanticReadyDeadlineAt - now() - ACP_MCP_STARTUP_HEADROOM_MS;
354
+ if (remaining <= 0) {
355
+ const absent = new SdkStartupRollbackTracker();
356
+ absent.recordAbsent();
357
+ await writeFailure(
358
+ {
359
+ phase: "startup",
360
+ reason: "pending",
361
+ message: "SDK startup did not complete before readiness cutoff.",
362
+ },
363
+ absent.result,
364
+ );
365
+ throw new Error("SDK startup did not complete before readiness cutoff.");
366
+ }
367
+ mcpStartupTimeoutMs = remaining;
368
+ }
369
+
370
+ try {
371
+ created = await createLifecycleAgentSession({
372
+ cwd,
373
+ agentDir,
374
+ sessionManager: opened.sessionManager,
375
+ ...(mcpConfigPath ? { mcpConfigPath } : {}),
376
+ ...(mcpStartupTimeoutMs !== undefined ? { mcpStartupTimeoutMs } : {}),
377
+ });
378
+ } catch (error) {
379
+ throw await registrationFailure(error);
380
+ }
381
+ } finally {
382
+ if (mcpConfigDirectory) await fs.rm(mcpConfigDirectory, { recursive: true, force: true });
298
383
  }
299
384
  const { parsed } = opened;
300
385
  if ("failure" in created) {
301
386
  created.rollback.recordAbsent();
302
387
  await writeFailure(created.failure, created.rollback.result);
303
388
 
304
- throw new Error(created.failure.message);
389
+ throw created.failure;
305
390
  }
306
391
  const { session, capability, rollback } = created;
307
392
  let sessionDisposal: Promise<void> | undefined;
@@ -423,19 +508,51 @@ export async function runSessionHost(
423
508
  await new Promise<void>(() => {});
424
509
  }
425
510
 
511
+ export type SdkInternalArgv = { action: "broker-internal"; agentDir: string } | { action: "session-host-internal" };
512
+
513
+ /** Parses the exact private argv contracts used by SDK child-process spawns. */
514
+ export function parseSdkInternalArgv(argv: readonly string[]): SdkInternalArgv {
515
+ if (argv[0] === "session-host-internal" && argv.length === 1) return { action: "session-host-internal" };
516
+ if (argv[0] === "broker-internal" && argv.length === 3 && argv[1] === "--agent-dir" && argv[2])
517
+ return { action: "broker-internal", agentDir: argv[2] };
518
+ throw new CliParseError("Invalid internal SDK invocation.");
519
+ }
520
+
521
+ class SdkServeHelp extends Command {
522
+ static description = "skc sdk serve --stdio | --socket <path> [--session <id>] [--pending-ceiling <bytes>]";
523
+ static flags = {
524
+ stdio: Flags.boolean({ description: "Serve SDK frames over standard input and output" }),
525
+ socket: Flags.string({ description: "Serve SDK frames over a Unix socket path" }),
526
+ session: Flags.string({ description: "Attach to a specific SDK session" }),
527
+ "pending-ceiling": Flags.string({ description: "Maximum queued relay bytes per direction" }),
528
+ };
529
+ async run(): Promise<void> {}
530
+ }
531
+
426
532
  export default class Sdk extends Command {
427
- static description = "SDK internal services";
428
- static hidden = true;
429
- static args = { action: Args.string({ required: true, options: ["broker-internal", "session-host-internal"] }) };
430
- static flags = { "agent-dir": Flags.string({ description: "Internal broker agent directory" }) };
533
+ static description = "skc sdk serve --stdio | --socket <path> [--session <id>] [--pending-ceiling <bytes>]";
534
+ static hidden = false;
535
+ static delegateHelp = true;
536
+ static args = { action: Args.string({ required: false, options: ["serve"] }) };
537
+ static flags = SdkServeHelp.flags;
431
538
  async run(): Promise<void> {
432
- const { args, flags } = await this.parse(Sdk);
433
- if (args.action === "session-host-internal") {
539
+ const action = this.argv[0];
540
+ if (this.argv.includes("--help") || this.argv.includes("-h")) {
541
+ renderCommandHelp("skc", action === "serve" ? "sdk serve" : "sdk", action === "serve" ? SdkServeHelp : Sdk);
542
+ return;
543
+ }
544
+ if (action === "serve") {
545
+ await runSdkServe(this.argv.slice(1));
546
+ return;
547
+ }
548
+ if (action !== "broker-internal" && action !== "session-host-internal")
549
+ throw new CliParseError("Expected action to be serve.");
550
+ const internal = parseSdkInternalArgv(this.argv);
551
+ if (internal.action === "session-host-internal") {
434
552
  await runSessionHost();
435
553
  return;
436
554
  }
437
- const agentDir = flags["agent-dir"] as string | undefined;
438
- if (!agentDir) throw new Error("--agent-dir is required for sdk broker-internal.");
555
+ const agentDir = internal.agentDir;
439
556
  const broker = new Broker({
440
557
  agentDir,
441
558
  resolveDirectoryMigration: async cwd => {
@@ -173,7 +173,7 @@ export default class Team extends Command {
173
173
  "Supported operations:",
174
174
  "send-message broadcast mailbox-list mailbox-mark-delivered mailbox-mark-notified notification-list notification-read notification-replay notification-mark-pane-attempt worker-startup-ack",
175
175
  "create-task read-task list-tasks update-task claim-task transition-task-status release-task-claim",
176
- "read-config read-manifest read-worker-status update-worker-status read-worker-heartbeat recover-stale-claims update-worker-heartbeat write-worker-inbox write-worker-identity",
176
+ "read-config read-manifest read-worker-status update-worker-status read-worker-heartbeat recover-stale-claims update-worker-heartbeat read-worker-memory-guard update-worker-memory-guard apply-worker-memory-guard write-worker-inbox write-worker-identity",
177
177
  "append-event read-events read-traces await-event write-shutdown-request read-shutdown-ack read-monitor-snapshot write-monitor-snapshot read-task-approval write-task-approval",
178
178
  "Completion example:",
179
179
  'transition-task-status --input \'{"team_name":"demo","task_id":"task-1","to":"completed","claim_token":"...","completion_evidence":{"summary":"done","items":[{"kind":"command","status":"passed","summary":"focused tests passed","command":"bun test packages/coding-agent/test/skc-runtime/team-runtime.test.ts"}]}}\' --json',
@@ -1,6 +1,6 @@
1
1
  import * as path from "node:path";
2
2
  import { createInterface } from "node:readline/promises";
3
- import { $env, getProjectDir, isEnoent, prompt } from "@sayknow-cli/utils";
3
+ import { $env, $pickenv, getProjectDir, isEnoent, prompt } from "@sayknow-cli/utils";
4
4
  import { applyChangelogProposals } from "../../commit/changelog";
5
5
  import { detectChangelogBoundaries } from "../../commit/changelog/detect";
6
6
  import { parseUnreleasedSection } from "../../commit/changelog/parse";
@@ -88,7 +88,7 @@ export async function runAgenticCommit(args: CommitCommandArgs): Promise<void> {
88
88
  } else {
89
89
  process.stdout.write(" └─ (none found)\n");
90
90
  }
91
- const forceFallback = $env.PI_COMMIT_TEST_FALLBACK?.toLowerCase() === "true";
91
+ const forceFallback = $pickenv("SKC_COMMIT_TEST_FALLBACK", "PI_COMMIT_TEST_FALLBACK")?.toLowerCase() === "true";
92
92
  if (forceFallback) {
93
93
  process.stdout.write("● Forcing fallback commit generation...\n");
94
94
  const fallbackProposal = generateFallbackProposal(numstat);
@@ -152,7 +152,7 @@ export async function runAgenticCommit(args: CommitCommandArgs): Promise<void> {
152
152
  }
153
153
 
154
154
  if (!usedFallback && !commitState.proposal && !commitState.splitProposal) {
155
- if ($env.PI_COMMIT_NO_FALLBACK?.toLowerCase() !== "true") {
155
+ if ($pickenv("SKC_COMMIT_NO_FALLBACK", "PI_COMMIT_NO_FALLBACK")?.toLowerCase() !== "true") {
156
156
  process.stdout.write("● Agent did not provide proposal, using fallback...\n");
157
157
  commitState.proposal = generateFallbackProposal(numstat);
158
158
  usedFallback = true;