@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
@@ -74,7 +74,7 @@ export class NotificationOperatorRuntime {
74
74
  #stopRequested = false;
75
75
  #activeAbort: AbortController | undefined;
76
76
  #intervals = new Map<string, OperatorIntervalHandle>();
77
- #exclusive = new Set<string>();
77
+ #exclusive = new Map<string, Promise<void>>();
78
78
 
79
79
  #deps: NotificationOperatorTimerDeps;
80
80
 
@@ -130,7 +130,7 @@ export class NotificationOperatorRuntime {
130
130
 
131
131
  stopInterval(name: string): void {
132
132
  const timer = this.#intervals.get(name);
133
- if (!timer) return;
133
+ if (timer === undefined) return;
134
134
  const clearIntervalImpl = this.#deps.clearIntervalImpl ?? clearInterval;
135
135
  clearIntervalImpl(timer);
136
136
  this.#intervals.delete(name);
@@ -142,14 +142,40 @@ export class NotificationOperatorRuntime {
142
142
 
143
143
  async runExclusive(name: string, fn: () => Promise<void>): Promise<void> {
144
144
  if (this.#exclusive.has(name)) return;
145
- this.#exclusive.add(name);
145
+ const completion = Promise.withResolvers<void>();
146
+ this.#exclusive.set(name, completion.promise);
146
147
  try {
147
- await fn();
148
+ try {
149
+ void fn().then(completion.resolve, completion.reject);
150
+ } catch (error) {
151
+ completion.reject(error);
152
+ }
153
+ await completion.promise;
148
154
  } finally {
149
- this.#exclusive.delete(name);
155
+ if (this.#exclusive.get(name) === completion.promise) this.#exclusive.delete(name);
150
156
  }
151
157
  }
152
158
 
159
+ async joinExclusive(name: string, timeoutMs: number): Promise<boolean> {
160
+ const completion = this.#exclusive.get(name);
161
+ if (!completion) return true;
162
+ const setTimeoutImpl = this.#deps.setTimeoutImpl ?? setTimeout;
163
+ const clearTimeoutImpl = this.#deps.clearTimeoutImpl ?? clearTimeout;
164
+ const { promise, resolve } = Promise.withResolvers<boolean>();
165
+ const timer = setTimeoutImpl(() => resolve(false), timeoutMs);
166
+ void completion.then(
167
+ () => {
168
+ clearTimeoutImpl(timer);
169
+ resolve(true);
170
+ },
171
+ () => {
172
+ clearTimeoutImpl(timer);
173
+ resolve(true);
174
+ },
175
+ );
176
+ return await promise;
177
+ }
178
+
153
179
  sleep(ms: number, signal?: AbortSignal): Promise<void> {
154
180
  return new Promise<void>(resolve => {
155
181
  if (signal?.aborted) return resolve();
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Bounded authoritative reconciliation state for Q26 `turn.prompt_status`.
3
+ *
4
+ * Separate from the lifecycle delivery buffers (promptSubmissions /
5
+ * promptTerminalTombstones), which exist to deliver frames and intentionally
6
+ * forget outcomes. This record preserves accepted/in_flight/terminal_ok/failed
7
+ * plus bounded sanitized failure metadata so a caller can reconcile a prior
8
+ * `turn.prompt` after disconnect/reconnect.
9
+ *
10
+ * Semantics (public contract, mirrored in sdk/prompt-status.ts):
11
+ * - Active records are NEVER converted to terminal by age or capacity.
12
+ * - Terminal records are retained for TERMINAL_TTL_MS and bounded to
13
+ * TERMINAL_CAPACITY, evicted oldest-terminal-first by terminalAt; only then
14
+ * does a lookup honestly report `unknown`.
15
+ * - Process-local durability floor is the live session process: restart means `unknown`.
16
+ * Session-scoped durable retention (kind-aware store) is provided by reconciliation-store.ts (#3032).
17
+ * - The clientRef index is session-runtime scoped; a ref conflicts only while
18
+ * retained and must never be reused as a retry mechanism.
19
+ * - Terminal transitions settle once: the first terminal outcome wins.
20
+ */
21
+
22
+ export const PROMPT_RECONCILIATION_ACTIVE_CAPACITY = 128;
23
+ export const PROMPT_RECONCILIATION_TERMINAL_CAPACITY = 256;
24
+ export const PROMPT_RECONCILIATION_TERMINAL_TTL_MS = 15 * 60_000;
25
+ export const PROMPT_FAILURE_CODE_MAX = 64;
26
+
27
+ export type PromptReconciliationStatus = "accepted" | "in_flight" | "terminal_ok" | "failed";
28
+
29
+ export interface PromptCorrelation {
30
+ commandId: string;
31
+ turnId: string;
32
+ }
33
+
34
+ export interface PromptReconciliationRecord extends PromptCorrelation {
35
+ clientRef?: string;
36
+ status: PromptReconciliationStatus;
37
+ error?: { code: string; message: string };
38
+ acceptedAt: number;
39
+ startedAt?: number;
40
+ terminalAt?: number;
41
+ }
42
+
43
+ export type TurnPromptReconciliation =
44
+ | {
45
+ status: "accepted";
46
+ commandId: string;
47
+ turnId: string;
48
+ clientRef?: string;
49
+ acceptedAt: number;
50
+ }
51
+ | {
52
+ status: "in_flight";
53
+ commandId: string;
54
+ turnId: string;
55
+ clientRef?: string;
56
+ acceptedAt: number;
57
+ startedAt: number;
58
+ }
59
+ | {
60
+ status: "terminal_ok";
61
+ commandId: string;
62
+ turnId: string;
63
+ clientRef?: string;
64
+ acceptedAt: number;
65
+ startedAt?: number;
66
+ terminalAt: number;
67
+ }
68
+ | {
69
+ status: "failed";
70
+ commandId: string;
71
+ turnId: string;
72
+ clientRef?: string;
73
+ acceptedAt: number;
74
+ startedAt?: number;
75
+ terminalAt: number;
76
+ error: { code: string; message: string };
77
+ }
78
+ | { status: "unknown" };
79
+
80
+ export interface PromptReconciliation {
81
+ /** Fail-closed admission BEFORE any execution; holds an identity-bound reservation. */
82
+ admit(clientRef?: string): void;
83
+ /** Discard one admission reservation without creating a record (rejection/cancellation). */
84
+ releaseAdmission(clientRef?: string): void;
85
+ /** Transition a reservation into the accepted record at preflight acceptance. */
86
+ noteAccepted(correlation: PromptCorrelation, clientRef?: string): void;
87
+ /** Lifecycle transition; terminal outcomes settle exactly once. */
88
+ noteTransition(
89
+ correlation: PromptCorrelation | undefined,
90
+ frame: { type: "agent_start" | "agent_end" } | { type: "agent_failed"; error: unknown },
91
+ ): void;
92
+ lookup(selector: { commandId?: string; turnId?: string; clientRef?: string }): TurnPromptReconciliation;
93
+ cleanup(): void;
94
+ activeCount(): number;
95
+ }
96
+
97
+ /** Safe-token code capped at 64; arbitrary failure text is never retained. */
98
+ export function sanitizePromptFailure(error: unknown): { code: string; message: string } {
99
+ const candidate = error as { code?: unknown } | undefined;
100
+ const rawCode = typeof candidate?.code === "string" ? candidate.code : "";
101
+ const code = rawCode.length <= PROMPT_FAILURE_CODE_MAX && /^[A-Za-z0-9._-]+$/.test(rawCode) ? rawCode : "internal";
102
+ return { code, message: "Prompt submission failed." };
103
+ }
104
+
105
+ export function createPromptReconciliation(options: { now?: () => number } = {}): PromptReconciliation {
106
+ const now = options.now ?? Date.now;
107
+ const records = new Map<string, PromptReconciliationRecord>();
108
+ const clientRefIndex = new Map<string, string>();
109
+ const reservedClientRefs = new Set<string>();
110
+ // One identity-bound entry per admission. Transitions consume exactly one
111
+ // matching entry and stale/duplicate transitions are no-ops, so reservation
112
+ // accounting is exactly-once even under repeated calls.
113
+ const reservations: Array<string | undefined> = [];
114
+ const keyOf = (correlation: PromptCorrelation) => `${correlation.commandId}:${correlation.turnId}`;
115
+
116
+ const remove = (key: string) => {
117
+ const record = records.get(key);
118
+ if (!record) return;
119
+ records.delete(key);
120
+ if (record.clientRef !== undefined && clientRefIndex.get(record.clientRef) === key)
121
+ clientRefIndex.delete(record.clientRef);
122
+ };
123
+
124
+ const cleanup = () => {
125
+ const at = now();
126
+ for (const [key, record] of records)
127
+ if (record.terminalAt !== undefined && record.terminalAt + PROMPT_RECONCILIATION_TERMINAL_TTL_MS <= at)
128
+ remove(key);
129
+ const terminalEntries = [...records.entries()].filter(([, record]) => record.terminalAt !== undefined);
130
+ if (terminalEntries.length <= PROMPT_RECONCILIATION_TERMINAL_CAPACITY) return;
131
+ // Evict oldest-terminal-first by terminalAt, not acceptance/insertion
132
+ // order; the stable sort keeps acceptance order for exact ties.
133
+ terminalEntries.sort((a, b) => (a[1].terminalAt as number) - (b[1].terminalAt as number));
134
+ for (const [key] of terminalEntries.slice(0, terminalEntries.length - PROMPT_RECONCILIATION_TERMINAL_CAPACITY))
135
+ remove(key);
136
+ };
137
+
138
+ const activeCount = () => {
139
+ let count = 0;
140
+ for (const record of records.values()) if (record.terminalAt === undefined) count++;
141
+ return count;
142
+ };
143
+
144
+ /** Consume one reservation matching clientRef; no-op when none is outstanding. */
145
+ const consumeReservation = (clientRef?: string) => {
146
+ const index = reservations.indexOf(clientRef);
147
+ if (index === -1) return;
148
+ reservations.splice(index, 1);
149
+ if (clientRef !== undefined && !reservations.includes(clientRef)) reservedClientRefs.delete(clientRef);
150
+ };
151
+
152
+ const admit = (clientRef?: string) => {
153
+ cleanup();
154
+ if (clientRef !== undefined && (clientRefIndex.has(clientRef) || reservedClientRefs.has(clientRef)))
155
+ throw Object.assign(
156
+ new Error("A prompt with this clientRef is already retained; never reuse a clientRef for retry."),
157
+ { code: "client_ref_conflict" },
158
+ );
159
+ if (activeCount() + reservations.length >= PROMPT_RECONCILIATION_ACTIVE_CAPACITY)
160
+ throw Object.assign(new Error("Too many active prompt submissions; reconcile or await terminal state."), {
161
+ code: "reconciliation_capacity",
162
+ });
163
+ reservations.push(clientRef);
164
+ if (clientRef !== undefined) reservedClientRefs.add(clientRef);
165
+ };
166
+
167
+ const releaseAdmission = (clientRef?: string) => {
168
+ consumeReservation(clientRef);
169
+ };
170
+
171
+ const noteAccepted = (correlation: PromptCorrelation, clientRef?: string) => {
172
+ cleanup();
173
+ consumeReservation(clientRef);
174
+ const at = now();
175
+ const key = keyOf(correlation);
176
+ records.set(key, {
177
+ commandId: correlation.commandId,
178
+ turnId: correlation.turnId,
179
+ ...(clientRef !== undefined ? { clientRef } : {}),
180
+ status: "accepted",
181
+ acceptedAt: at,
182
+ });
183
+ if (clientRef !== undefined) clientRefIndex.set(clientRef, key);
184
+ };
185
+
186
+ const noteTransition = (
187
+ correlation: PromptCorrelation | undefined,
188
+ frame: { type: "agent_start" | "agent_end" } | { type: "agent_failed"; error: unknown },
189
+ ) => {
190
+ if (!correlation) return;
191
+ const record = records.get(keyOf(correlation));
192
+ if (!record || record.terminalAt !== undefined) return;
193
+ if (frame.type === "agent_start") {
194
+ if (record.status === "accepted") {
195
+ record.status = "in_flight";
196
+ record.startedAt = now();
197
+ }
198
+ return;
199
+ }
200
+ record.terminalAt = now();
201
+ if (frame.type === "agent_failed") {
202
+ record.status = "failed";
203
+ record.error = sanitizePromptFailure(frame.error);
204
+ } else {
205
+ record.status = "terminal_ok";
206
+ }
207
+ // Enforce terminal retention immediately at settlement, not lazily.
208
+ cleanup();
209
+ };
210
+
211
+ const lookup = (selector: { commandId?: string; turnId?: string; clientRef?: string }): TurnPromptReconciliation => {
212
+ cleanup();
213
+ const key =
214
+ selector.clientRef !== undefined
215
+ ? clientRefIndex.get(selector.clientRef)
216
+ : selector.commandId !== undefined && selector.turnId !== undefined
217
+ ? keyOf({ commandId: selector.commandId, turnId: selector.turnId })
218
+ : undefined;
219
+ const record = key === undefined ? undefined : records.get(key);
220
+ if (!record) return { status: "unknown" };
221
+ const identity = {
222
+ commandId: record.commandId,
223
+ turnId: record.turnId,
224
+ ...(record.clientRef !== undefined ? { clientRef: record.clientRef } : {}),
225
+ acceptedAt: record.acceptedAt,
226
+ };
227
+ if (record.status === "accepted") return { status: "accepted", ...identity };
228
+ if (record.status === "in_flight")
229
+ return { status: "in_flight", ...identity, startedAt: record.startedAt as number };
230
+ const terminal = {
231
+ ...identity,
232
+ ...(record.startedAt !== undefined ? { startedAt: record.startedAt } : {}),
233
+ terminalAt: record.terminalAt as number,
234
+ };
235
+ if (record.status === "terminal_ok") return { status: "terminal_ok", ...terminal };
236
+ return { status: "failed", ...terminal, error: record.error ?? sanitizePromptFailure(undefined) };
237
+ };
238
+
239
+ return { admit, releaseAdmission, noteAccepted, noteTransition, lookup, cleanup, activeCount };
240
+ }
@@ -116,6 +116,14 @@ export class RateLimitPool<T = unknown> {
116
116
  return total;
117
117
  }
118
118
 
119
+ /** Whether any queued item currently matches the predicate. */
120
+ someQueued(predicate: (item: RateLimitItem<T>) => boolean): boolean {
121
+ for (const queue of this.lanes.values()) {
122
+ if (queue.some(entry => predicate(entry.item))) return true;
123
+ }
124
+ return false;
125
+ }
126
+
119
127
  /** Current available token count (after refill at `now`). */
120
128
  availableTokens(nowMs: number = this.now()): number {
121
129
  this.refill(nowMs);
@@ -11,7 +11,7 @@ import * as fs from "node:fs/promises";
11
11
  import * as path from "node:path";
12
12
  import { verifyOwnerOnlyPathSecurity } from "@sayknow-cli/natives";
13
13
  import { getAgentDir, getSessionsDir } from "@sayknow-cli/utils";
14
- import { FileSessionStorage } from "../../session/session-storage";
14
+ import { FileSessionStorage, type SessionStorageSnapshot } from "../../session/session-storage";
15
15
  import {
16
16
  type LogicalSessionCandidate,
17
17
  listManagedSessionCandidates,
@@ -58,25 +58,52 @@ export interface RecentActivityDeps {
58
58
  readInitialLines?: (file: string, maxLines: number) => string[];
59
59
  }
60
60
 
61
+ class ManagedCandidateChangedError extends Error {}
62
+ class ManagedCandidateUnavailableError extends Error {}
63
+
64
+ const CHANGED_CANDIDATE_WARNING = "Ignored managed session candidate that changed during inspection.";
65
+
66
+ function isAppendExtension(bytes: Uint8Array, candidate: LogicalSessionCandidate): boolean {
67
+ return (
68
+ bytes.byteLength >= candidate.identity.size &&
69
+ createHash("sha256").update(bytes.subarray(0, candidate.identity.size)).digest("hex") ===
70
+ candidate.identity.sha256
71
+ );
72
+ }
73
+
61
74
  function readCandidateInitialLines(
62
75
  candidate: LogicalSessionCandidate,
63
76
  readInitialLines: ((file: string, maxLines: number) => string[]) | undefined,
77
+ appendBase?: LogicalSessionCandidate,
64
78
  ): string[] {
65
79
  if (readInitialLines) return readInitialLines(candidate.path, 8);
66
80
  if (candidate.provenance !== "legacy") {
67
81
  const security = verifyOwnerOnlyPathSecurity(candidate.path, "file");
68
- if (!security.ok) throw new Error(`Managed session metadata path is unsafe: ${security.code}`);
82
+ if (!security.ok) throw new ManagedCandidateUnavailableError("Managed session metadata path is unsafe.");
69
83
  }
70
- const snapshot = new FileSessionStorage().readSnapshotSync(candidate.path);
84
+ let snapshot: SessionStorageSnapshot;
85
+ try {
86
+ snapshot = new FileSessionStorage().readSnapshotSync(candidate.path);
87
+ } catch (error) {
88
+ const code = (error as NodeJS.ErrnoException).code;
89
+ if (code === "ENOENT" || code === "ELOOP" || code === "ENOTDIR")
90
+ throw new ManagedCandidateUnavailableError("Managed session metadata is unavailable.");
91
+ throw error;
92
+ }
93
+ const sameFile = snapshot.stat.dev === candidate.identity.dev && snapshot.stat.ino === candidate.identity.ino;
71
94
  const digest = createHash("sha256").update(snapshot.bytes).digest("hex");
72
- if (
73
- snapshot.stat.dev !== candidate.identity.dev ||
74
- snapshot.stat.ino !== candidate.identity.ino ||
75
- snapshot.stat.size !== candidate.identity.size ||
76
- snapshot.stat.mtimeNs !== candidate.identity.mtimeNs ||
77
- digest !== candidate.identity.sha256
78
- )
79
- throw new Error("Managed session changed after ownership was verified.");
95
+ const exactIdentity =
96
+ sameFile &&
97
+ snapshot.stat.size === candidate.identity.size &&
98
+ snapshot.stat.mtimeNs === candidate.identity.mtimeNs &&
99
+ digest === candidate.identity.sha256;
100
+ if (appendBase && (!sameFile || !isAppendExtension(snapshot.bytes, appendBase)))
101
+ throw new ManagedCandidateUnavailableError("Managed session no longer extends the verified transcript.");
102
+ if (!exactIdentity) {
103
+ if (sameFile && isAppendExtension(snapshot.bytes, candidate))
104
+ throw new ManagedCandidateChangedError("Managed session was appended after ownership was verified.");
105
+ throw new ManagedCandidateUnavailableError("Managed session changed without an append-only extension.");
106
+ }
80
107
  return Buffer.from(snapshot.bytes).toString("utf8").split("\n").slice(0, 8);
81
108
  }
82
109
 
@@ -227,13 +254,13 @@ export async function listRecentSessions(deps: RecentActivityDeps): Promise<List
227
254
  const resolved = await resolveRecentScopes(deps);
228
255
  if (resolved.kind === "error") return resolved;
229
256
  const warnings = [...resolved.warnings];
230
- const candidates: LogicalSessionCandidate[] = [];
257
+ const candidates: Array<{ scope: ManagedSessionScope; candidate: LogicalSessionCandidate }> = [];
231
258
  for (const scope of resolved.scopes) {
232
259
  const listed = await listManagedSessionCandidates({ scope });
233
260
  if (listed.kind !== "complete") {
234
261
  return { kind: "error", code: "managed_scan_failed", message: listed.message };
235
262
  }
236
- candidates.push(...listed.owned);
263
+ candidates.push(...listed.owned.map(candidate => ({ scope, candidate })));
237
264
  warnings.push(
238
265
  ...listed.invalid
239
266
  .filter(
@@ -245,28 +272,65 @@ export async function listRecentSessions(deps: RecentActivityDeps): Promise<List
245
272
  }
246
273
 
247
274
  const entries: RecentSessionEntry[] = [];
248
- for (const candidate of candidates) {
249
- let initialLines: string[];
275
+ for (const { scope, candidate } of candidates) {
276
+ let selected = candidate;
277
+ let initialLines: string[] | undefined;
250
278
  try {
251
- initialLines = readCandidateInitialLines(candidate, readInitialLines);
279
+ initialLines = readCandidateInitialLines(selected, readInitialLines);
252
280
  } catch (error) {
253
- return {
254
- kind: "error",
255
- code: "managed_scan_failed",
256
- message: `Could not read managed session metadata: ${error instanceof Error ? error.message : String(error)}`,
257
- };
281
+ if (error instanceof ManagedCandidateChangedError) {
282
+ const refreshed = await listManagedSessionCandidates({ scope });
283
+ if (refreshed.kind !== "complete")
284
+ return { kind: "error", code: "managed_scan_failed", message: refreshed.message };
285
+ const sameFile = refreshed.owned.find(
286
+ current =>
287
+ path.resolve(current.path) === path.resolve(candidate.path) &&
288
+ current.identity.dev === candidate.identity.dev &&
289
+ current.identity.ino === candidate.identity.ino,
290
+ );
291
+ if (sameFile) {
292
+ try {
293
+ initialLines = readCandidateInitialLines(sameFile, readInitialLines, candidate);
294
+ selected = sameFile;
295
+ } catch (retryError) {
296
+ if (
297
+ !(retryError instanceof ManagedCandidateChangedError) &&
298
+ !(retryError instanceof ManagedCandidateUnavailableError)
299
+ )
300
+ return {
301
+ kind: "error",
302
+ code: "managed_scan_failed",
303
+ message: `Could not read managed session metadata: ${
304
+ retryError instanceof Error ? retryError.message : String(retryError)
305
+ }`,
306
+ };
307
+ }
308
+ }
309
+ } else if (!(error instanceof ManagedCandidateUnavailableError)) {
310
+ return {
311
+ kind: "error",
312
+ code: "managed_scan_failed",
313
+ message: `Could not read managed session metadata: ${
314
+ error instanceof Error ? error.message : String(error)
315
+ }`,
316
+ };
317
+ }
318
+ if (!initialLines) {
319
+ warnings.push(CHANGED_CANDIDATE_WARNING);
320
+ continue;
321
+ }
258
322
  }
259
323
  const meta = headerMeta(initialLines[0]);
260
324
  const internal = isInternalSession(initialLines);
261
325
  if (internal && !includeInternal) continue;
262
326
  entries.push({
263
- sessionId: candidate.sessionId,
264
- path: candidate.cwd,
327
+ sessionId: selected.sessionId,
328
+ path: selected.cwd,
265
329
  branch: meta.branch,
266
330
  title: meta.title,
267
- sessionStateFile: candidate.path,
268
- mtimeMs: candidate.identity.mtimeMs,
269
- currentTerminal: breadcrumbs.has(path.resolve(candidate.path)) || undefined,
331
+ sessionStateFile: selected.path,
332
+ mtimeMs: selected.identity.mtimeMs,
333
+ currentTerminal: breadcrumbs.has(path.resolve(selected.path)) || undefined,
270
334
  internal: internal || undefined,
271
335
  });
272
336
  }