@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
@@ -0,0 +1,363 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import { appendJsonl, type StateWriterOptions } from "./state-writer";
4
+
5
+ export type SkcTeamWorkerMemoryGuardState = "idle" | "advisory" | "retrying" | "checkpointed" | "replaced" | "blocked";
6
+
7
+ export type SkcTeamWorkerMemoryGuardCheckpointKind =
8
+ | "clean"
9
+ | "eligible"
10
+ | "protected_only"
11
+ | "conflicted"
12
+ | "git_error";
13
+
14
+ export type SkcTeamWorkerMemoryGuardPidProbe =
15
+ | { kind: "live"; start_time: string }
16
+ | { kind: "absent" }
17
+ | { kind: "unverifiable"; reason: string };
18
+
19
+ export interface SkcTeamWorkerMemoryGuardCheckpoint {
20
+ kind: SkcTeamWorkerMemoryGuardCheckpointKind;
21
+ files: string[];
22
+ head?: string | null;
23
+ commit?: string | null;
24
+ recorded_at: string;
25
+ }
26
+
27
+ export interface SkcTeamWorkerMemoryGuardReplacement {
28
+ old_pane_id?: string;
29
+ new_pane_id?: string;
30
+ recorded_at: string;
31
+ }
32
+
33
+ export interface SkcTeamWorkerMemoryGuardLedger {
34
+ schema_version: 1;
35
+ worker_id: string;
36
+ platform: string;
37
+ state: SkcTeamWorkerMemoryGuardState;
38
+ automatic_action_allowed: boolean;
39
+ retry_count: number;
40
+ retry_limit: number;
41
+ current_task_id?: string;
42
+ last_incident_id?: string;
43
+ last_reason?: string;
44
+ last_pid_probe?: SkcTeamWorkerMemoryGuardPidProbe;
45
+ last_checkpoint?: SkcTeamWorkerMemoryGuardCheckpoint;
46
+ last_replacement?: SkcTeamWorkerMemoryGuardReplacement;
47
+ updated_at: string;
48
+ }
49
+
50
+ export interface SkcTeamWorkerMemoryGuardSelectionCandidate {
51
+ worker_id: string;
52
+ platform: string;
53
+ excess_bytes: number;
54
+ retry_count: number;
55
+ retry_limit: number;
56
+ blocked?: boolean;
57
+ current_task_id?: string;
58
+ }
59
+
60
+ export interface SkcTeamWorkerMemoryGuardSelection {
61
+ worker_id: string;
62
+ excess_bytes: number;
63
+ retry_count: number;
64
+ current_task_id?: string;
65
+ }
66
+
67
+ const ledgerKeys = new Set([
68
+ "schema_version",
69
+ "worker_id",
70
+ "platform",
71
+ "state",
72
+ "automatic_action_allowed",
73
+ "retry_count",
74
+ "retry_limit",
75
+ "current_task_id",
76
+ "last_incident_id",
77
+ "last_reason",
78
+ "last_pid_probe",
79
+ "last_checkpoint",
80
+ "last_replacement",
81
+ "updated_at",
82
+ ]);
83
+ const checkpointKeys = new Set(["kind", "files", "head", "commit", "recorded_at"]);
84
+ const replacementKeys = new Set(["old_pane_id", "new_pane_id", "recorded_at"]);
85
+ const absentPidProbeKeys = new Set(["kind"]);
86
+ const livePidProbeKeys = new Set(["kind", "start_time"]);
87
+ const unverifiablePidProbeKeys = new Set(["kind", "reason"]);
88
+
89
+ function isRecord(value: unknown): value is Record<string, unknown> {
90
+ return typeof value === "object" && value !== null && !Array.isArray(value);
91
+ }
92
+
93
+ function hasExactKeys(value: Record<string, unknown>, keys: Set<string>): boolean {
94
+ return Object.keys(value).every(key => keys.has(key));
95
+ }
96
+
97
+ function isNonEmptyString(value: unknown): value is string {
98
+ return typeof value === "string" && value.trim().length > 0;
99
+ }
100
+
101
+ function isTimestamp(value: unknown): value is string {
102
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
103
+ }
104
+
105
+ function isRetryCount(value: unknown): value is number {
106
+ return Number.isInteger(value) && (value as number) >= 0;
107
+ }
108
+
109
+ function isWorkerMemoryGuardState(value: unknown): value is SkcTeamWorkerMemoryGuardState {
110
+ return ["idle", "advisory", "retrying", "checkpointed", "replaced", "blocked"].includes(String(value));
111
+ }
112
+
113
+ function isCheckpointKind(value: unknown): value is SkcTeamWorkerMemoryGuardCheckpointKind {
114
+ return ["clean", "eligible", "protected_only", "conflicted", "git_error"].includes(String(value));
115
+ }
116
+
117
+ export function workerMemoryGuardLedgerPath(dir: string, workerId: string): string {
118
+ return path.join(dir, "workers", workerId, "memory-guard.json");
119
+ }
120
+
121
+ export function normalizeSkcTeamWorkerMemoryGuardPidProbe(
122
+ value: unknown,
123
+ ): SkcTeamWorkerMemoryGuardPidProbe | undefined {
124
+ if (value === undefined) return undefined;
125
+ if (!isRecord(value)) throw new Error("invalid_worker_memory_guard_pid_probe");
126
+ const kind = typeof value.kind === "string" ? value.kind : "";
127
+ if (kind === "absent") {
128
+ if (!hasExactKeys(value, absentPidProbeKeys)) throw new Error("invalid_worker_memory_guard_pid_probe:absent");
129
+ return { kind: "absent" };
130
+ }
131
+ if (kind === "live") {
132
+ if (!hasExactKeys(value, livePidProbeKeys) || !isNonEmptyString(value.start_time))
133
+ throw new Error("invalid_worker_memory_guard_pid_probe:live");
134
+ return { kind: "live", start_time: value.start_time.trim() };
135
+ }
136
+ if (kind === "unverifiable") {
137
+ if (!hasExactKeys(value, unverifiablePidProbeKeys) || !isNonEmptyString(value.reason))
138
+ throw new Error("invalid_worker_memory_guard_pid_probe:unverifiable");
139
+ return { kind: "unverifiable", reason: value.reason.trim() };
140
+ }
141
+ throw new Error("invalid_worker_memory_guard_pid_probe");
142
+ }
143
+
144
+ export function isCanonicalSkcTeamWorkerMemoryGuardCheckpoint(
145
+ value: unknown,
146
+ ): value is SkcTeamWorkerMemoryGuardCheckpoint {
147
+ return (
148
+ isRecord(value) &&
149
+ hasExactKeys(value, checkpointKeys) &&
150
+ isCheckpointKind(value.kind) &&
151
+ Array.isArray(value.files) &&
152
+ value.files.every(file => isNonEmptyString(file)) &&
153
+ (value.head === undefined || value.head === null || isNonEmptyString(value.head)) &&
154
+ (value.commit === undefined || value.commit === null || isNonEmptyString(value.commit)) &&
155
+ isTimestamp(value.recorded_at)
156
+ );
157
+ }
158
+
159
+ export function isCanonicalSkcTeamWorkerMemoryGuardReplacement(
160
+ value: unknown,
161
+ ): value is SkcTeamWorkerMemoryGuardReplacement {
162
+ return (
163
+ isRecord(value) &&
164
+ hasExactKeys(value, replacementKeys) &&
165
+ (value.old_pane_id === undefined || isNonEmptyString(value.old_pane_id)) &&
166
+ (value.new_pane_id === undefined || isNonEmptyString(value.new_pane_id)) &&
167
+ isTimestamp(value.recorded_at)
168
+ );
169
+ }
170
+
171
+ export function isCanonicalSkcTeamWorkerMemoryGuardPidProbe(value: unknown): value is SkcTeamWorkerMemoryGuardPidProbe {
172
+ try {
173
+ return normalizeSkcTeamWorkerMemoryGuardPidProbe(value) !== undefined;
174
+ } catch {
175
+ return false;
176
+ }
177
+ }
178
+
179
+ export function isCanonicalSkcTeamWorkerMemoryGuardLedger(value: unknown): value is SkcTeamWorkerMemoryGuardLedger {
180
+ return (
181
+ isRecord(value) &&
182
+ hasExactKeys(value, ledgerKeys) &&
183
+ value.schema_version === 1 &&
184
+ isNonEmptyString(value.worker_id) &&
185
+ isNonEmptyString(value.platform) &&
186
+ isWorkerMemoryGuardState(value.state) &&
187
+ typeof value.automatic_action_allowed === "boolean" &&
188
+ isRetryCount(value.retry_count) &&
189
+ isRetryCount(value.retry_limit) &&
190
+ (value.current_task_id === undefined || isNonEmptyString(value.current_task_id)) &&
191
+ (value.last_incident_id === undefined || isNonEmptyString(value.last_incident_id)) &&
192
+ (value.last_reason === undefined || isNonEmptyString(value.last_reason)) &&
193
+ (value.last_pid_probe === undefined || isCanonicalSkcTeamWorkerMemoryGuardPidProbe(value.last_pid_probe)) &&
194
+ (value.last_checkpoint === undefined || isCanonicalSkcTeamWorkerMemoryGuardCheckpoint(value.last_checkpoint)) &&
195
+ (value.last_replacement === undefined ||
196
+ isCanonicalSkcTeamWorkerMemoryGuardReplacement(value.last_replacement)) &&
197
+ isTimestamp(value.updated_at)
198
+ );
199
+ }
200
+
201
+ export function createInitialSkcTeamWorkerMemoryGuardLedger(input: {
202
+ workerId: string;
203
+ platform: string;
204
+ now: string;
205
+ retryLimit?: number;
206
+ }): SkcTeamWorkerMemoryGuardLedger {
207
+ const retryLimit = Number.isInteger(input.retryLimit) && (input.retryLimit ?? 0) > 0 ? input.retryLimit! : 2;
208
+ return {
209
+ schema_version: 1,
210
+ worker_id: input.workerId,
211
+ platform: input.platform.trim() || "unknown",
212
+ state: "idle",
213
+ automatic_action_allowed: false,
214
+ retry_count: 0,
215
+ retry_limit: retryLimit,
216
+ updated_at: input.now,
217
+ };
218
+ }
219
+
220
+ function workerIndex(workerId: string): number {
221
+ const match = /(?:^|[^0-9])(\d+)$/.exec(workerId);
222
+ return match ? Number.parseInt(match[1]!, 10) : Number.MAX_SAFE_INTEGER;
223
+ }
224
+
225
+ export function selectSkcTeamWorkerMemoryGuardCandidate(
226
+ candidates: readonly SkcTeamWorkerMemoryGuardSelectionCandidate[],
227
+ ): SkcTeamWorkerMemoryGuardSelection | undefined {
228
+ const eligible = candidates
229
+ .filter(candidate => candidate.platform === "linux")
230
+ .filter(candidate => Number.isFinite(candidate.excess_bytes) && candidate.excess_bytes > 0)
231
+ .filter(candidate => !candidate.blocked)
232
+ .filter(candidate => candidate.retry_count < candidate.retry_limit)
233
+ .sort((left, right) => {
234
+ if (right.excess_bytes !== left.excess_bytes) return right.excess_bytes - left.excess_bytes;
235
+ if (left.retry_count !== right.retry_count) return left.retry_count - right.retry_count;
236
+ const leftIndex = workerIndex(left.worker_id);
237
+ const rightIndex = workerIndex(right.worker_id);
238
+ if (leftIndex !== rightIndex) return leftIndex - rightIndex;
239
+ return left.worker_id.localeCompare(right.worker_id);
240
+ });
241
+ const first = eligible[0];
242
+ return first
243
+ ? {
244
+ worker_id: first.worker_id,
245
+ excess_bytes: first.excess_bytes,
246
+ retry_count: first.retry_count,
247
+ current_task_id: first.current_task_id,
248
+ }
249
+ : undefined;
250
+ }
251
+
252
+ export type TeamWorkerMemoryGuardAction = "advisory" | "replace" | "blocked";
253
+ export type TeamWorkerMemoryGuardResult = "noop" | "scheduled" | "succeeded" | "failed" | "blocked";
254
+
255
+ export interface TeamWorkerMemoryGuardLedgerEntry {
256
+ schema_version: 1;
257
+ recorded_at: string;
258
+ incident_id: string;
259
+ team_name: string;
260
+ worker_id: string;
261
+ task_id: string;
262
+ claim_token: string;
263
+ attempt: number;
264
+ platform: NodeJS.Platform;
265
+ action: TeamWorkerMemoryGuardAction;
266
+ result: TeamWorkerMemoryGuardResult;
267
+ reason: string;
268
+ }
269
+
270
+ const teamWorkerMemoryGuardActions = new Set<TeamWorkerMemoryGuardAction>(["advisory", "replace", "blocked"]);
271
+ const teamWorkerMemoryGuardResults = new Set<TeamWorkerMemoryGuardResult>([
272
+ "noop",
273
+ "scheduled",
274
+ "succeeded",
275
+ "failed",
276
+ "blocked",
277
+ ]);
278
+
279
+ export function isCanonicalTeamWorkerMemoryGuardLedgerEntry(value: unknown): value is TeamWorkerMemoryGuardLedgerEntry {
280
+ if (!isRecord(value)) return false;
281
+ const requiredKeys = [
282
+ "schema_version",
283
+ "recorded_at",
284
+ "incident_id",
285
+ "team_name",
286
+ "worker_id",
287
+ "task_id",
288
+ "claim_token",
289
+ "attempt",
290
+ "platform",
291
+ "action",
292
+ "result",
293
+ "reason",
294
+ ];
295
+ return (
296
+ Object.keys(value).length === requiredKeys.length &&
297
+ requiredKeys.every(key => Object.hasOwn(value, key)) &&
298
+ value.schema_version === 1 &&
299
+ isTimestamp(value.recorded_at) &&
300
+ isNonEmptyString(value.incident_id) &&
301
+ isNonEmptyString(value.team_name) &&
302
+ isNonEmptyString(value.worker_id) &&
303
+ isNonEmptyString(value.task_id) &&
304
+ isNonEmptyString(value.claim_token) &&
305
+ Number.isInteger(value.attempt) &&
306
+ (value.attempt as number) > 0 &&
307
+ isNonEmptyString(value.platform) &&
308
+ teamWorkerMemoryGuardActions.has(value.action as TeamWorkerMemoryGuardAction) &&
309
+ teamWorkerMemoryGuardResults.has(value.result as TeamWorkerMemoryGuardResult) &&
310
+ isNonEmptyString(value.reason)
311
+ );
312
+ }
313
+
314
+ export function teamWorkerMemoryGuardDir(workerDirPath: string): string {
315
+ return path.join(workerDirPath, "memory-guard");
316
+ }
317
+
318
+ export function teamWorkerMemoryGuardLedgerPath(workerDirPath: string): string {
319
+ return path.join(teamWorkerMemoryGuardDir(workerDirPath), "ledger.jsonl");
320
+ }
321
+
322
+ export function canMutateTeamWorkerMemoryGuard(platform: NodeJS.Platform): boolean {
323
+ return platform === "linux";
324
+ }
325
+
326
+ export function advisoryReasonForTeamWorkerMemoryGuard(platform: NodeJS.Platform): string | undefined {
327
+ return canMutateTeamWorkerMemoryGuard(platform) ? undefined : `unsupported_platform:${platform}`;
328
+ }
329
+
330
+ export async function appendTeamWorkerMemoryGuardLedgerEntry(
331
+ workerDirPath: string,
332
+ entry: TeamWorkerMemoryGuardLedgerEntry,
333
+ options?: StateWriterOptions,
334
+ ): Promise<string> {
335
+ await fs.mkdir(teamWorkerMemoryGuardDir(workerDirPath), { recursive: true });
336
+ return appendJsonl(teamWorkerMemoryGuardLedgerPath(workerDirPath), entry, options);
337
+ }
338
+
339
+ export async function readTeamWorkerMemoryGuardLedger(
340
+ workerDirPath: string,
341
+ ): Promise<TeamWorkerMemoryGuardLedgerEntry[]> {
342
+ const ledgerPath = teamWorkerMemoryGuardLedgerPath(workerDirPath);
343
+ if (!(await Bun.file(ledgerPath).exists())) return [];
344
+ const entries: TeamWorkerMemoryGuardLedgerEntry[] = [];
345
+ for (const [index, line] of (await Bun.file(ledgerPath).text()).split(/\r?\n/).filter(Boolean).entries()) {
346
+ const parsed = JSON.parse(line) as unknown;
347
+ if (!isCanonicalTeamWorkerMemoryGuardLedgerEntry(parsed))
348
+ throw new Error(`invalid_team_worker_memory_guard_ledger:${ledgerPath}:${index + 1}`);
349
+ entries.push(parsed);
350
+ }
351
+ return entries;
352
+ }
353
+
354
+ export function nextTeamWorkerMemoryGuardAttempt(
355
+ entries: readonly TeamWorkerMemoryGuardLedgerEntry[],
356
+ incidentId: string,
357
+ ): number {
358
+ let attempt = 0;
359
+ for (const entry of entries) {
360
+ if (entry.incident_id === incidentId && entry.attempt > attempt) attempt = entry.attempt;
361
+ }
362
+ return attempt + 1;
363
+ }
@@ -352,6 +352,7 @@ export async function writeSkcWorkerStartupAck(
352
352
  pid: typeof input.pid === "number" ? input.pid : undefined,
353
353
  session: typeof input.session === "string" ? input.session : undefined,
354
354
  protocol_version: String(input.protocol_version ?? "1"),
355
+ replacement_token: typeof input.replacement_token === "string" ? input.replacement_token : undefined,
355
356
  ack_at: runtime.now(),
356
357
  };
357
358
  await runtime.writeJson(path.join(runtime.workerDir(dir, worker), "startup-ack.json"), ack);
@@ -246,8 +246,19 @@ export function buildSkcTmuxProfileCommands(
246
246
  commands.push(
247
247
  { description: "enable tmux clipboard integration", args: ["set-option", "-t", target, "set-clipboard", "on"] },
248
248
  {
249
- // Forward DCS passthrough (sixel graphics / Sayknow Pet) to the outer
250
- // terminal. `-pq` scopes it to this session's pane (never the global
249
+ // Hand tmux ownership of sixel. tmux 3.4+ parses sixel into its own screen
250
+ // model and re-renders it, so scroll / clear / resize / copy-mode all work on
251
+ // the pet. Without this tmux never records the image, and an erase can only
252
+ // reach its cell buffer while the pixels sit in the outer terminal's image
253
+ // plane — which is what leaves residue behind the pet.
254
+ // `-a` appends so a user's own terminal-features survive; unknown on tmux <
255
+ // 3.2, hence `-q`.
256
+ description: "let tmux own sixel graphics",
257
+ args: ["set-option", "-aq", "-t", target, "terminal-features", ",*:sixel"],
258
+ },
259
+ {
260
+ // Passthrough remains the fallback for terminals/tmux builds that do not
261
+ // claim sixel. `-pq` scopes it to this session's pane (never the global
251
262
  // server state) and stays quiet on tmux < 3.3 where the option is unknown.
252
263
  description: "allow DCS passthrough for sixel graphics",
253
264
  args: ["set-option", "-pq", "-t", target, "allow-passthrough", "on"],
@@ -960,6 +960,24 @@ export function lifecyclePaths(stateDir: string, sessionId: string, generation:
960
960
  };
961
961
  }
962
962
 
963
+ export interface MemoryGuardClaimPaths {
964
+ root: string;
965
+ databaseFile: string;
966
+ walFile: string;
967
+ shmFile: string;
968
+ }
969
+
970
+ export function memoryGuardClaimPaths(stateDir: string, sessionId: string): MemoryGuardClaimPaths {
971
+ const root = path.join(stateDir, "memory-guard-claims", sessionId);
972
+ const databaseFile = path.join(root, "claims.sqlite");
973
+ return {
974
+ root,
975
+ databaseFile,
976
+ walFile: `${databaseFile}-wal`,
977
+ shmFile: `${databaseFile}-shm`,
978
+ };
979
+ }
980
+
963
981
  export async function replaceOwnerGeneration(
964
982
  stateDir: string,
965
983
  sessionId: string,
@@ -1646,7 +1664,8 @@ export function isValidOwnerIntent(intent: unknown, request?: ObserveTerminalReq
1646
1664
  intent.generation === request.owner_generation &&
1647
1665
  intent.session_id === request.session_id &&
1648
1666
  intent.server_key === request.socket_key &&
1649
- (request.operator_dispatch_id === undefined || intent.dispatch_id === request.operator_dispatch_id) &&
1667
+ request.operator_dispatch_id !== undefined &&
1668
+ intent.dispatch_id === request.operator_dispatch_id &&
1650
1669
  request.signal === "SIGTERM"
1651
1670
  );
1652
1671
  }
@@ -3,6 +3,7 @@ import * as crypto from "node:crypto";
3
3
  import * as fsSync from "node:fs";
4
4
  import * as fs from "node:fs/promises";
5
5
  import * as path from "node:path";
6
+ import { Process } from "@sayknow-cli/natives";
6
7
  import { readLinuxProcStartTime, readLinuxProcStartTimeSync } from "./linux-proc";
7
8
  import { resolveSkcTmuxBinary } from "./psmux-detect";
8
9
  import { tmuxRuntimeSessionPath } from "./session-layout";
@@ -43,6 +44,7 @@ import {
43
44
  lifecyclePaths,
44
45
  type OwnerIsolationProbeSync,
45
46
  type OwnerVerdict,
47
+ observeOwnerTerminal,
46
48
  type PlanResponse,
47
49
  planTmuxOwnerIsolationSync,
48
50
  replaceOwnerGenerationSync,
@@ -963,6 +965,14 @@ async function readProcessStartTime(pid: number): Promise<string | null> {
963
965
  return readLinuxProcStartTime(pid);
964
966
  }
965
967
 
968
+ function exactManagedOwnerSupervisor(supervisorPid: number, supervisorStartTime: string): Process {
969
+ const supervisor = Process.fromPid(supervisorPid);
970
+ if (!supervisor) throw new Error("managed_owner_supervisor_unverifiable");
971
+ if (process.platform === "linux" && supervisor.incarnation !== `linux:${supervisorStartTime}`)
972
+ throw new Error("managed_owner_supervisor_incarnation_mismatch");
973
+ return supervisor;
974
+ }
975
+
966
976
  async function readCurrentGeneration(stateDir: string, sessionId: string): Promise<string | null> {
967
977
  try {
968
978
  const value: unknown = JSON.parse(
@@ -1016,12 +1026,12 @@ async function requireUnchangedOwnerForCompatibilityCleanup(
1016
1026
  initialServer: { pid: number; startTime: string },
1017
1027
  listPanePids: (sessionName: string, env: NodeJS.ProcessEnv) => number[],
1018
1028
  readStartTime: (pid: number) => Promise<string | null>,
1019
- ): Promise<void> {
1029
+ ): Promise<boolean> {
1020
1030
  try {
1021
1031
  const currentNativeSessionId = readNativeTmuxSessionId(nativeSessionId, env);
1022
1032
  if (!currentNativeSessionId) {
1023
1033
  if (readNativeTmuxSessionId(sessionName, env)) throw new Error(`skc_tmux_owner_changed:${sessionName}`);
1024
- return;
1034
+ return false;
1025
1035
  }
1026
1036
  const currentServer = requireSafeTmuxServerForMutation(resolveSkcTmuxCommand(env), env);
1027
1037
  const panePids = listPanePids(nativeSessionId, env);
@@ -1054,10 +1064,11 @@ async function requireUnchangedOwnerForCompatibilityCleanup(
1054
1064
  : null,
1055
1065
  ].filter((value): value is string => value !== null);
1056
1066
  if (mismatches.length > 0) throw new Error(`skc_tmux_owner_changed:${sessionName}:${mismatches.join(",")}`);
1067
+ return true;
1057
1068
  } catch (error) {
1058
1069
  if (!readNativeTmuxSessionId(nativeSessionId, env)) {
1059
1070
  if (readNativeTmuxSessionId(sessionName, env)) throw new Error(`skc_tmux_owner_changed:${sessionName}`);
1060
- return;
1071
+ return false;
1061
1072
  }
1062
1073
  if (error instanceof Error && error.message.startsWith(`skc_tmux_owner_changed:${sessionName}`))
1063
1074
  throw new Error(`skc_tmux_owner_changed:${sessionName}`);
@@ -1152,6 +1163,7 @@ export async function forceCloseSkcTmuxSession(
1152
1163
  const now = deps.now ?? (() => new Date());
1153
1164
  const sleep = deps.sleep ?? (ms => Bun.sleep(ms));
1154
1165
  const dispatchId = crypto.randomUUID();
1166
+ let operatorVerdict: Promise<OwnerVerdict> | null = null;
1155
1167
  await closeExactTmuxOwner(
1156
1168
  {
1157
1169
  stateDir: identity.stateDir,
@@ -1169,12 +1181,37 @@ export async function forceCloseSkcTmuxSession(
1169
1181
  sendSigterm: async pid => {
1170
1182
  if ((await (deps.readProcessStartTime ?? readProcessStartTime)(pid)) !== identity.startTime)
1171
1183
  throw new Error("owner_pid_identity_mismatch");
1172
- (deps.signalTerm ?? (target => process.kill(target, "SIGTERM")))(pid);
1184
+ if (deps.signalTerm) {
1185
+ deps.signalTerm(pid);
1186
+ } else {
1187
+ const supervisor = exactManagedOwnerSupervisor(pid, identity.startTime);
1188
+ if (!supervisor.signalRoot(15)) throw new Error("managed_owner_supervisor_signal_failed");
1189
+ operatorVerdict = supervisor
1190
+ .waitForExit({ timeoutMs: FORCE_CLOSE_VERDICT_TIMEOUT_MS - 500 })
1191
+ .then(async exited => {
1192
+ if (!exited) throw new Error("managed_owner_supervisor_exit_timeout");
1193
+ return await observeOwnerTerminal({
1194
+ schema_version: 1,
1195
+ op: "observe_terminal",
1196
+ session_id: identity.sessionId,
1197
+ owner_generation: identity.generation,
1198
+ state_dir: identity.stateDir,
1199
+ socket_key: identity.socketKey,
1200
+ observer: "raw_monitor",
1201
+ observed_at: now().toISOString(),
1202
+ signal: "SIGTERM",
1203
+ exit_code: null,
1204
+ exit_kind: "exact_owner_exit_observed",
1205
+ reason: "operator_observed_owner_exit",
1206
+ operator_dispatch_id: dispatchId,
1207
+ });
1208
+ });
1209
+ }
1173
1210
  },
1174
1211
 
1175
- waitForVerdict: () => waitForExpectedVerdict(identity, sleep, now),
1212
+ waitForVerdict: () => operatorVerdict ?? waitForExpectedVerdict(identity, sleep, now),
1176
1213
  cleanupSession: async () => {
1177
- await requireUnchangedOwnerForCompatibilityCleanup(
1214
+ const cleanupRequired = await requireUnchangedOwnerForCompatibilityCleanup(
1178
1215
  session.name,
1179
1216
  nativeSessionId,
1180
1217
  env,
@@ -1184,6 +1221,7 @@ export async function forceCloseSkcTmuxSession(
1184
1221
  deps.listPanePids ?? readExactSessionPanePids,
1185
1222
  deps.readProcessStartTime ?? readProcessStartTime,
1186
1223
  );
1224
+ if (!cleanupRequired) return;
1187
1225
  if (deps.cleanupSession) deps.cleanupSession(nativeSessionId, env);
1188
1226
  else
1189
1227
  runGuardedTmuxSessionCommand(
@@ -1192,6 +1230,7 @@ export async function forceCloseSkcTmuxSession(
1192
1230
  initialServer.pid,
1193
1231
  env,
1194
1232
  `kill-session -t '${nativeSessionId}'`,
1233
+ identity.generation,
1195
1234
  );
1196
1235
  },
1197
1236
  },