@sayknow-cli/coding-agent 0.4.6 → 0.5.0

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 +112 -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 +27 -8
  241. package/src/modes/components/session-observer-overlay.ts +187 -32
  242. package/src/modes/components/settings-selector.ts +60 -18
  243. package/src/modes/components/tool-execution.ts +138 -27
  244. package/src/modes/components/tool-status-header.ts +26 -8
  245. package/src/modes/components/welcome.ts +50 -23
  246. package/src/modes/controllers/btw-controller.ts +119 -36
  247. package/src/modes/controllers/command-controller.ts +101 -54
  248. package/src/modes/controllers/event-controller.ts +119 -27
  249. package/src/modes/controllers/extension-ui-controller.ts +23 -12
  250. package/src/modes/controllers/input-controller.ts +100 -8
  251. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
  252. package/src/modes/controllers/selector-controller.ts +4 -1
  253. package/src/modes/interactive-mode.ts +201 -60
  254. package/src/modes/irc-observation-ledger.ts +71 -15
  255. package/src/modes/prompt-action-autocomplete.ts +32 -13
  256. package/src/modes/prompt-suggestion-controller.ts +96 -0
  257. package/src/modes/runtime-init.ts +20 -2
  258. package/src/modes/shared/agent-wire/command-dispatch.ts +3 -3
  259. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
  260. package/src/modes/types.ts +6 -0
  261. package/src/modes/utils/hotkeys-markdown.ts +64 -36
  262. package/src/modes/utils/ui-helpers.ts +99 -4
  263. package/src/prompts/agent-fragments/restricted-bash.md +1 -1
  264. package/src/prompts/agents/architect.md +17 -3
  265. package/src/prompts/agents/critic.md +17 -2
  266. package/src/prompts/agents/executor.md +1 -1
  267. package/src/prompts/agents/planner.md +8 -1
  268. package/src/prompts/system/btw-user.md +3 -8
  269. package/src/prompts/system/prompt-suggestion-system.md +32 -0
  270. package/src/prompts/system/system-prompt.md +6 -3
  271. package/src/prompts/tools/cron.md +3 -1
  272. package/src/prompts/tools/read.md +4 -2
  273. package/src/prompts/tools/skill-discovery.md +1 -0
  274. package/src/runtime/memory-domain.ts +66 -0
  275. package/src/runtime/memory-guard-contract.ts +73 -0
  276. package/src/runtime/memory-guard.ts +292 -0
  277. package/src/runtime/memory-limit.ts +50 -0
  278. package/src/runtime-mcp/client.ts +41 -55
  279. package/src/runtime-mcp/content-limits.ts +71 -0
  280. package/src/runtime-mcp/discoverable-tool-metadata.ts +1 -1
  281. package/src/runtime-mcp/json-rpc.ts +28 -11
  282. package/src/runtime-mcp/manager.ts +77 -59
  283. package/src/runtime-mcp/oauth-flow.ts +0 -72
  284. package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
  285. package/src/runtime-mcp/redaction.ts +30 -0
  286. package/src/runtime-mcp/smithery-auth.ts +17 -2
  287. package/src/runtime-mcp/smithery-connect.ts +11 -1
  288. package/src/runtime-mcp/transports/http.ts +63 -22
  289. package/src/sdk/acp/adapter.ts +8 -1
  290. package/src/sdk/acp/final-text.ts +40 -0
  291. package/src/sdk/acp/mcp.ts +26 -0
  292. package/src/sdk/broker/broker.ts +34 -20
  293. package/src/sdk/broker/identity.ts +22 -12
  294. package/src/sdk/broker/lifecycle.ts +293 -43
  295. package/src/sdk/broker/session-index.ts +11 -1
  296. package/src/sdk/bus/chat-daemon-cli.ts +2 -2
  297. package/src/sdk/bus/chat-daemon-control.ts +22 -5
  298. package/src/sdk/bus/config-commands.ts +2 -2
  299. package/src/sdk/bus/config.ts +10 -2
  300. package/src/sdk/bus/control-drain-lease.ts +104 -0
  301. package/src/sdk/bus/conversation-store.ts +40 -6
  302. package/src/sdk/bus/daemon-paths.ts +2 -0
  303. package/src/sdk/bus/index.ts +793 -121
  304. package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
  305. package/src/sdk/bus/lifecycle-commands.ts +63 -10
  306. package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
  307. package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
  308. package/src/sdk/bus/notification-orchestration.ts +12 -0
  309. package/src/sdk/bus/notification-service.ts +87 -25
  310. package/src/sdk/bus/operator-runtime.ts +31 -5
  311. package/src/sdk/bus/prompt-reconciliation.ts +240 -0
  312. package/src/sdk/bus/rate-limit-pool.ts +8 -0
  313. package/src/sdk/bus/recent-activity.ts +90 -26
  314. package/src/sdk/bus/reconciliation-store.ts +224 -0
  315. package/src/sdk/bus/telegram-cli.ts +6 -13
  316. package/src/sdk/bus/telegram-daemon-cli.ts +8 -3
  317. package/src/sdk/bus/telegram-daemon-contract.ts +34 -9
  318. package/src/sdk/bus/telegram-daemon-control.ts +161 -40
  319. package/src/sdk/bus/telegram-daemon.ts +3649 -593
  320. package/src/sdk/bus/telegram-reference.ts +20 -2
  321. package/src/sdk/bus/topic-registry.ts +451 -12
  322. package/src/sdk/cli/session-cli.ts +15 -2
  323. package/src/sdk/client/discovery.ts +19 -3
  324. package/src/sdk/client/liveness.ts +49 -0
  325. package/src/sdk/host/control/dispatch.ts +8 -2
  326. package/src/sdk/host/control/operations.ts +3 -2
  327. package/src/sdk/host/host.ts +27 -9
  328. package/src/sdk/host/query/handlers.ts +125 -5
  329. package/src/sdk/index.ts +12 -0
  330. package/src/sdk/lifecycle-session.ts +19 -3
  331. package/src/sdk/mcp/server.ts +46 -18
  332. package/src/sdk/prompt-status.ts +97 -0
  333. package/src/sdk/protocol/operation-inventory.generated.json +145 -0
  334. package/src/sdk/protocol/operation-registry.ts +24 -4
  335. package/src/sdk/session-directory.ts +5 -1
  336. package/src/sdk/session.ts +69 -8
  337. package/src/sdk/startup-capability.ts +15 -1
  338. package/src/sdk/transport/auth-preface.ts +82 -0
  339. package/src/sdk/transport/index.ts +18 -0
  340. package/src/sdk/transport/relay.ts +252 -0
  341. package/src/sdk/transport/serve-cli.ts +105 -0
  342. package/src/sdk/transport/socket.ts +197 -0
  343. package/src/sdk/transport/stdio.ts +17 -0
  344. package/src/session/agent-session.ts +1112 -314
  345. package/src/session/blob-store.ts +25 -7
  346. package/src/session/btw-contract.ts +59 -0
  347. package/src/session/fallback-chain-controller.ts +47 -8
  348. package/src/session/internal/managed-session-scope.ts +1426 -259
  349. package/src/session/internal/managed-session-storage.ts +414 -238
  350. package/src/session/internal/native-publish-outcome.ts +271 -0
  351. package/src/session/memory-guard-checkpoint-participant.ts +131 -0
  352. package/src/session/session-manager.ts +2079 -469
  353. package/src/session/session-storage.ts +151 -11
  354. package/src/session/streaming-output.ts +262 -43
  355. package/src/setup/credential-import.ts +28 -3
  356. package/src/setup/provider-onboarding.ts +49 -5
  357. package/src/setup/provider-presets.json +2 -1
  358. package/src/skc-runtime/deep-interview-runtime.ts +303 -36
  359. package/src/skc-runtime/deep-interview-stage.ts +1016 -0
  360. package/src/skc-runtime/deep-interview-state.ts +8 -5
  361. package/src/skc-runtime/gc-render.ts +1 -0
  362. package/src/skc-runtime/gc-runtime.ts +11 -1
  363. package/src/skc-runtime/linux-proc.ts +70 -36
  364. package/src/skc-runtime/managed-owner-supervisor.ts +83 -4
  365. package/src/skc-runtime/memory-guard-owner-claims.ts +389 -0
  366. package/src/skc-runtime/ralplan-runtime.ts +1057 -75
  367. package/src/skc-runtime/repository-binding.ts +267 -0
  368. package/src/skc-runtime/session-state-sidecar.ts +25 -9
  369. package/src/skc-runtime/state-runtime.ts +50 -12
  370. package/src/skc-runtime/state-writer.ts +68 -56
  371. package/src/skc-runtime/team-launch.ts +34 -5
  372. package/src/skc-runtime/team-runtime.ts +41 -1
  373. package/src/skc-runtime/team-store.ts +32 -0
  374. package/src/skc-runtime/team-worker-memory-guard.ts +363 -0
  375. package/src/skc-runtime/team-workers.ts +1 -0
  376. package/src/skc-runtime/tmux-common.ts +13 -2
  377. package/src/skc-runtime/tmux-owner-isolation.ts +20 -1
  378. package/src/skc-runtime/tmux-sessions.ts +45 -6
  379. package/src/skc-runtime/ultragoal-guard.ts +93 -15
  380. package/src/skc-runtime/ultragoal-receipt-freshness.ts +123 -0
  381. package/src/skc-runtime/ultragoal-runtime.ts +469 -38
  382. package/src/skc-runtime/workflow-manifest.generated.json +195 -5
  383. package/src/skc-runtime/workflow-manifest.ts +67 -3
  384. package/src/skill-state/workflow-hud.ts +25 -2
  385. package/src/skill-state/workflow-mutation-guard.ts +104 -12
  386. package/src/slash-commands/builtin-registry.ts +1 -1
  387. package/src/ssh/utils.ts +14 -0
  388. package/src/task/discovery.ts +8 -2
  389. package/src/task/executor.ts +165 -47
  390. package/src/task/index.ts +123 -15
  391. package/src/task/provider-retry-status.ts +88 -0
  392. package/src/task/receipt.ts +3 -0
  393. package/src/task/render.ts +45 -26
  394. package/src/task/skc-command.ts +2 -2
  395. package/src/task/types.ts +55 -10
  396. package/src/task/ultragoal-redteam-activation.ts +75 -0
  397. package/src/tools/ask.ts +1 -1
  398. package/src/tools/ast-edit.ts +2 -2
  399. package/src/tools/bash-allowed-prefixes.ts +45 -1
  400. package/src/tools/bash-pty-selection.ts +2 -2
  401. package/src/tools/browser/launch.ts +41 -6
  402. package/src/tools/browser/screenshot-format.ts +6 -1
  403. package/src/tools/cron.ts +1 -1
  404. package/src/tools/fetch.ts +127 -154
  405. package/src/tools/image-gen.ts +476 -23
  406. package/src/tools/index.ts +7 -1
  407. package/src/tools/output-meta.ts +176 -9
  408. package/src/tools/path-utils.ts +5 -1
  409. package/src/tools/read-internals.ts +44 -0
  410. package/src/tools/read.ts +1544 -310
  411. package/src/tools/resource-gc.ts +665 -125
  412. package/src/tools/skill-discovery.ts +39 -3
  413. package/src/tools/sqlite-reader.ts +63 -5
  414. package/src/tools/subagent-render.ts +74 -16
  415. package/src/tools/subagent.ts +2 -0
  416. package/src/tools/tool-result.ts +14 -1
  417. package/src/utils/edit-mode.ts +2 -2
  418. package/src/utils/pasted-image-path.ts +15 -6
  419. package/src/utils/prompt-suggestion.ts +265 -0
  420. package/src/utils/shell-snapshot.ts +173 -63
  421. package/src/utils/sixel.ts +3 -3
  422. package/src/web/insane/bridge.ts +5 -1
  423. package/src/web/insane/url-guard.ts +140 -27
  424. package/src/web/scrapers/docs-rs.ts +30 -5
  425. package/src/web/scrapers/types.ts +19 -49
  426. package/src/web/scrapers/utils.ts +12 -26
  427. package/src/web/search/providers/codex.ts +1 -1
  428. package/src/workflow/workflow-intent-diff.ts +4 -1
package/src/main.ts CHANGED
@@ -11,7 +11,8 @@ import * as path from "node:path";
11
11
  import { createInterface } from "node:readline/promises";
12
12
  import type { ImageContent } from "@sayknow-cli/ai";
13
13
  import {
14
- $env,
14
+ $pickenv,
15
+ getAgentDir,
15
16
  getProjectDir,
16
17
  logger,
17
18
  normalizePathForComparison,
@@ -534,7 +535,16 @@ interface InteractiveModeFactoryOptions {
534
535
  type CreateInteractiveMode = (options: InteractiveModeFactoryOptions) => InteractiveMode;
535
536
 
536
537
  type ResumePickerTerminalCheck = () => boolean;
537
- type ListForResumePickerReadOnly = (cwd: string, sessionDir?: string) => Promise<SessionInfo[]>;
538
+ type ListForResumePickerReadOnly = (cwd: string, sessionDir?: string, storage?: undefined) => Promise<SessionInfo[]>;
539
+
540
+ type ListManagedForResumePickerReadOnly = (
541
+ cwd: string,
542
+ managedAgentDir?: string,
543
+ storage?: undefined,
544
+ ) => Promise<SessionInfo[]>;
545
+
546
+ type ResolveManagedAgentDirForScope = (cwd: string) => string;
547
+
538
548
  type SelectResumeSession = (sessions: SessionInfo[]) => Promise<SessionSelectionResult>;
539
549
  type OpenExistingSessionStrict = (
540
550
  identity: ResumeSessionIdentity,
@@ -546,6 +556,11 @@ type OpenExistingSessionStrict = (
546
556
  export const BARE_RESUME_CONFLICT_ERROR =
547
557
  "--resume without a session cannot be combined with --continue, --fork, or --no-session.";
548
558
  export const BARE_RESUME_INTERACTIVE_ERROR = "--resume requires an interactive terminal; use --resume <id>.";
559
+
560
+ /** Resolves only the managed agent root needed for pre-consent picker inventory. */
561
+ export function resolveManagedAgentDirForScope(_cwd: string): string {
562
+ return getAgentDir();
563
+ }
549
564
  export const BARE_RESUME_OPEN_ERROR = "Could not open the selected session. Use --resume <id>.";
550
565
 
551
566
  function isBareResume(parsed: Args): boolean {
@@ -683,7 +698,7 @@ async function promptForkSession(session: SessionInfo): Promise<boolean> {
683
698
  }
684
699
  }
685
700
 
686
- async function getChangelogForDisplay(parsed: Args): Promise<string | undefined> {
701
+ export async function getChangelogForDisplay(parsed: Args): Promise<string | undefined> {
687
702
  if (parsed.continue || parsed.resume) {
688
703
  return undefined;
689
704
  }
@@ -695,15 +710,19 @@ async function getChangelogForDisplay(parsed: Args): Promise<string | undefined>
695
710
 
696
711
  const lastVersion = settings.get("lastChangelogVersion");
697
712
  if (!lastVersion) {
698
- settings.set("lastChangelogVersion", VERSION);
699
- await flushChangelogVersion();
713
+ if (settings.canWriteDurableConfig()) {
714
+ settings.set("lastChangelogVersion", VERSION);
715
+ await flushChangelogVersion();
716
+ }
700
717
  return getInstalledVersionChangelogEntry(entries, VERSION)?.content;
701
718
  }
702
719
 
703
720
  if (lastVersion !== VERSION) {
704
721
  const newEntries = getNewEntries(entries, lastVersion);
705
- settings.set("lastChangelogVersion", VERSION);
706
- await flushChangelogVersion();
722
+ if (settings.canWriteDurableConfig()) {
723
+ settings.set("lastChangelogVersion", VERSION);
724
+ await flushChangelogVersion();
725
+ }
707
726
  if (newEntries.length > 0) {
708
727
  return newEntries.map(e => e.content).join("\n\n");
709
728
  }
@@ -741,7 +760,13 @@ export async function createSessionManager(
741
760
  if (forkSource.includes("/") || forkSource.includes("\\") || forkSource.endsWith(".jsonl")) {
742
761
  return await SessionManager.forkFrom(forkSource, cwd, sessionDestination(), undefined, migrationPolicy);
743
762
  }
744
- const match = await resolveResumableSession(forkSource, cwd, parsed.sessionDir);
763
+ const match = await resolveResumableSession(
764
+ forkSource,
765
+ cwd,
766
+ parsed.sessionDir,
767
+ undefined,
768
+ parsed.sessionDir ? undefined : activeSettings.getAgentDir(),
769
+ );
745
770
  if (!match) {
746
771
  throw new Error(`Session "${forkSource}" not found.`);
747
772
  }
@@ -754,14 +779,18 @@ export async function createSessionManager(
754
779
  if (typeof parsed.resume === "string") {
755
780
  const sessionArg = parsed.resume;
756
781
  if (sessionArg.includes("/") || sessionArg.includes("\\") || sessionArg.endsWith(".jsonl")) {
757
- return await SessionManager.open(
758
- sessionArg,
759
- SessionManager.explicitDestination(path.dirname(sessionArg)),
760
- undefined,
761
- migrationPolicy,
762
- );
782
+ const destination = parsed.sessionDir
783
+ ? SessionManager.explicitDestination(parsed.sessionDir)
784
+ : SessionManager.explicitDestination(path.dirname(sessionArg));
785
+ return await SessionManager.open(sessionArg, destination, undefined, migrationPolicy);
763
786
  }
764
- const match = await resolveResumableSession(sessionArg, cwd, parsed.sessionDir);
787
+ const match = await resolveResumableSession(
788
+ sessionArg,
789
+ cwd,
790
+ parsed.sessionDir,
791
+ undefined,
792
+ parsed.sessionDir ? undefined : activeSettings.getAgentDir(),
793
+ );
765
794
  if (!match) {
766
795
  throw new Error(`Session "${sessionArg}" not found.`);
767
796
  }
@@ -1058,12 +1087,62 @@ export interface RunRootCommandDependencies {
1058
1087
  runPrintMode?: RunPrintMode;
1059
1088
  isResumePickerTerminal?: ResumePickerTerminalCheck;
1060
1089
  listForResumePickerReadOnly?: ListForResumePickerReadOnly;
1090
+ listManagedForResumePickerReadOnly?: ListManagedForResumePickerReadOnly;
1091
+ resolveManagedAgentDirForScope?: ResolveManagedAgentDirForScope;
1061
1092
  selectResumeSession?: SelectResumeSession;
1062
1093
  openExistingSessionStrict?: OpenExistingSessionStrict;
1063
1094
  initializeSettings?: typeof Settings.init;
1064
1095
  loadSettingsForScope?: typeof Settings.loadForScope;
1065
1096
  }
1066
1097
 
1098
+ export interface ModelRoleOverrides {
1099
+ smol?: string;
1100
+ slow?: string;
1101
+ plan?: string;
1102
+ }
1103
+
1104
+ /**
1105
+ * Resolve the ephemeral `smol`/`slow`/`plan` model-role overrides.
1106
+ *
1107
+ * Precedence per role is CLI flag > documented `SKC_*_MODEL` > legacy
1108
+ * `PI_*_MODEL`, matching the repo-wide SKC-first/PI-fallback convention.
1109
+ * Resolution reads the process environment via `$pickenv`, which trims values
1110
+ * and treats empty/whitespace as unset; it is deliberately kept separate from
1111
+ * credential env resolution (`$credentialEnv`/`$pickCredentialEnv`). The
1112
+ * function is pure and stateless, so it reads fresh each call and a later
1113
+ * invocation never inherits an earlier one's values.
1114
+ */
1115
+ export function resolveModelRoleOverrides(parsed: Pick<Args, "smol" | "slow" | "plan">): ModelRoleOverrides {
1116
+ const overrides: ModelRoleOverrides = {};
1117
+ const smol = parsed.smol ?? $pickenv("SKC_SMOL_MODEL", "PI_SMOL_MODEL");
1118
+ const slow = parsed.slow ?? $pickenv("SKC_SLOW_MODEL", "PI_SLOW_MODEL");
1119
+ const plan = parsed.plan ?? $pickenv("SKC_PLAN_MODEL", "PI_PLAN_MODEL");
1120
+ if (smol) overrides.smol = smol;
1121
+ if (slow) overrides.slow = slow;
1122
+ if (plan) overrides.plan = plan;
1123
+ return overrides;
1124
+ }
1125
+
1126
+ /**
1127
+ * Apply the `--no-pty` / `--no-title` terminal-control flags to the environment.
1128
+ *
1129
+ * Sets the canonical `SKC_*` name (so an explicit flag wins over a user-set
1130
+ * `SKC_*` value under the SKC-first resolver — CLI authority) and the legacy
1131
+ * `PI_*` name for backward compatibility. `--acp` mode implies `--no-title`.
1132
+ */
1133
+ export function applyTerminalControlFlagsToEnv(
1134
+ parsed: Pick<Args, "noPty" | "noTitle" | "mode">,
1135
+ env: NodeJS.ProcessEnv = Bun.env,
1136
+ ): void {
1137
+ if (parsed.noPty) {
1138
+ env.SKC_NO_PTY = "1";
1139
+ env.PI_NO_PTY = "1";
1140
+ }
1141
+ if (parsed.noTitle || parsed.mode === "acp") {
1142
+ env.SKC_NO_TITLE = "1";
1143
+ env.PI_NO_TITLE = "1";
1144
+ }
1145
+ }
1067
1146
  export async function runRootCommand(
1068
1147
  parsed: Args,
1069
1148
  rawArgs: string[],
@@ -1094,10 +1173,18 @@ export async function runRootCommand(
1094
1173
  await logger.time("maybeAutoChdir", maybeAutoChdir, parsedArgs);
1095
1174
  autoChdirApplied = true;
1096
1175
  const resumeCwd = getProjectDir();
1097
- const sessions = await (deps.listForResumePickerReadOnly ?? SessionManager.listForResumePickerReadOnly)(
1098
- resumeCwd,
1099
- parsedArgs.sessionDir,
1100
- );
1176
+ const managedAgentDir = parsedArgs.sessionDir
1177
+ ? undefined
1178
+ : (deps.resolveManagedAgentDirForScope ?? resolveManagedAgentDirForScope)(resumeCwd);
1179
+ const sessions = parsedArgs.sessionDir
1180
+ ? await (deps.listForResumePickerReadOnly ?? SessionManager.listForResumePickerReadOnly)(
1181
+ resumeCwd,
1182
+ parsedArgs.sessionDir,
1183
+ )
1184
+ : await (deps.listManagedForResumePickerReadOnly ?? SessionManager.listManagedForResumePickerReadOnly)(
1185
+ resumeCwd,
1186
+ managedAgentDir,
1187
+ );
1101
1188
  if (sessions.length === 0) {
1102
1189
  process.stdout.write(`${chalk.dim("No sessions found")}\n`);
1103
1190
  return;
@@ -1108,19 +1195,16 @@ export async function runRootCommand(
1108
1195
  if (selection.kind === "cancelled") {
1109
1196
  return;
1110
1197
  }
1198
+ const scopedSettings = await (deps.loadSettingsForScope ?? Settings.loadForScope)({ cwd: resumeCwd });
1111
1199
  const resumeMigrationPolicy =
1112
- (await (deps.loadSettingsForScope ?? Settings.loadForScope)({ cwd: resumeCwd })).get(
1113
- "session.directoryMigration",
1114
- ) === "disabled"
1115
- ? "disabled"
1116
- : "copy-retain";
1200
+ scopedSettings.get("session.directoryMigration") === "disabled" ? "disabled" : "copy-retain";
1117
1201
  let opened: StrictSessionOpenResult;
1118
1202
  try {
1119
1203
  opened = await (deps.openExistingSessionStrict ?? SessionManager.openExistingStrict)(
1120
1204
  selection.identity,
1121
1205
  parsedArgs.sessionDir
1122
1206
  ? SessionManager.explicitDestination(parsedArgs.sessionDir)
1123
- : SessionManager.managedDestination(resumeCwd, settings.getAgentDir()),
1207
+ : SessionManager.managedDestination(resumeCwd, scopedSettings.getAgentDir()),
1124
1208
  undefined,
1125
1209
  resumeMigrationPolicy,
1126
1210
  );
@@ -1198,12 +1282,7 @@ export async function runRootCommand(
1198
1282
  applyAcpDefaultSettingOverrides(settingsInstance);
1199
1283
  }
1200
1284
  modelRegistry.applyConfiguredModelBindings(settingsInstance);
1201
- if (parsedArgs.noPty) {
1202
- Bun.env.PI_NO_PTY = "1";
1203
- }
1204
- if (parsedArgs.noTitle || parsedArgs.mode === "acp") {
1205
- Bun.env.PI_NO_TITLE = "1";
1206
- }
1285
+ applyTerminalControlFlagsToEnv(parsedArgs);
1207
1286
  const hasPreparedInput = parsedArgs.messages.length > 0 || parsedArgs.fileArgs.length > 0;
1208
1287
  const { pipedInput, fileText, fileImages } = await logger.time("prepareInitialMessage", async () => {
1209
1288
  const pipedInput =
@@ -1254,15 +1333,14 @@ export async function runRootCommand(
1254
1333
  // Auto-start Telegram Remote gateway if enabled in settings
1255
1334
  if (!parsedArgs.print && !autoPrint) await maybeAutostartTelegramRemote();
1256
1335
 
1257
- // Apply model role overrides from CLI args or env vars (ephemeral, not persisted)
1258
- const smolModel = parsedArgs.smol ?? $env.PI_SMOL_MODEL;
1259
- const slowModel = parsedArgs.slow ?? $env.PI_SLOW_MODEL;
1260
- const planModel = parsedArgs.plan ?? $env.PI_PLAN_MODEL;
1261
- if (smolModel || slowModel || planModel) {
1336
+ // Apply model role overrides from CLI args or env vars (ephemeral, not persisted).
1337
+ // Precedence per role: CLI flag > documented SKC_*_MODEL > legacy PI_*_MODEL.
1338
+ const roleOverrides = resolveModelRoleOverrides(parsedArgs);
1339
+ if (roleOverrides.smol || roleOverrides.slow || roleOverrides.plan) {
1262
1340
  settingsInstance.overrideModelRoles({
1263
- smol: smolModel,
1264
- slow: slowModel,
1265
- plan: planModel,
1341
+ ...(roleOverrides.smol ? { smol: roleOverrides.smol } : {}),
1342
+ ...(roleOverrides.slow ? { slow: roleOverrides.slow } : {}),
1343
+ ...(roleOverrides.plan ? { plan: roleOverrides.plan } : {}),
1266
1344
  });
1267
1345
  }
1268
1346
 
@@ -1556,9 +1634,9 @@ export async function runRootCommand(
1556
1634
  process.stdout.write(`${chalk.dim(`Model scope: ${modelList} ${chalk.gray("(Alt+N to cycle)")}`)}\n`);
1557
1635
  }
1558
1636
 
1559
- if ($env.PI_TIMING) {
1637
+ if ($pickenv("SKC_TIMING", "PI_TIMING")) {
1560
1638
  logger.printTimings();
1561
- exitForTiming = $env.PI_TIMING === "x";
1639
+ exitForTiming = $pickenv("SKC_TIMING", "PI_TIMING") === "x";
1562
1640
  }
1563
1641
 
1564
1642
  if (!exitForTiming) {
@@ -1603,7 +1681,7 @@ export async function runRootCommand(
1603
1681
  initialImages,
1604
1682
  suppressProcessExit: deps.suppressProcessExit,
1605
1683
  });
1606
- if ($env.PI_TIMING) {
1684
+ if ($pickenv("SKC_TIMING", "PI_TIMING")) {
1607
1685
  logger.printTimings();
1608
1686
  }
1609
1687
  } finally {
@@ -976,6 +976,11 @@ function redactSecrets(input: string): string {
976
976
  /(?:sk|pk|rk|tok|key|secret|token|password)[-_A-Za-z0-9]{12,}/g,
977
977
  /[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}/g,
978
978
  /(?:AKIA|ASIA)[A-Z0-9]{16}/g,
979
+ // GitHub tokens carry no keyword the first pattern recognizes, so without
980
+ // this they reached MEMORY.md and memory_summary.md verbatim — and the
981
+ // summary is injected into every later session. Same shapes the
982
+ // contribution-prep scrubber already covers.
983
+ /\b(?:gh[opsur]_[A-Za-z0-9_]{12,}|github_pat_[A-Za-z0-9_]{12,})\b/g,
979
984
  ];
980
985
  for (const pattern of patterns) {
981
986
  out = out.replace(pattern, "[REDACTED]");
@@ -983,6 +988,11 @@ function redactSecrets(input: string): string {
983
988
  return out;
984
989
  }
985
990
 
991
+ /** Secret scrubbing applied to every phase-2 consolidation output. Test seam. */
992
+ export function redactMemorySecretsForTesting(input: string): string {
993
+ return redactSecrets(input);
994
+ }
995
+
986
996
  function sanitizeSkillName(name: string): string {
987
997
  return name
988
998
  .toLowerCase()
@@ -94,6 +94,11 @@ empty space and list density for an operational setup flow.
94
94
  removing line breaks. Notification secrets will use the dedicated masked
95
95
  input from Work item 6; they must never appear in list values, descriptions,
96
96
  previews, artifacts, or logs.
97
+ ### Shortcut labels and binding authority
98
+
99
+ Keybinding configuration is a portable canonical grammar: textual key IDs use `ctrl`, `alt`, `shift`, and `super` plus a key name (for example, `ctrl+p` or `alt+enter`). Do not serialize or require display-only labels. Runtime UI renders those IDs through the shared formatter for its explicit platform context; macOS uses MacBook-style glyphs (`⌃`, `⌥`, `⇧`, `⌘`, `↩`, `⎋`, `⇥`, `⌫`, `⌦`, and arrow glyphs) while other platforms use textual labels. A glyph is never configuration syntax.
100
+
101
+ Static onboarding and generated documentation have authority only over shipped defaults. Keep generated tables host-independent by showing canonical textual IDs, not the capture host's labels. The runtime `KeybindingsManager` owns the effective binding set after user remaps and extensions load; `/hotkeys` and runtime hints must render that effective set with the platform context injected by their host. Do not let a static onboarding hint imply that it reflects remaps.
97
102
 
98
103
  ### Status, errors, confirmation, and disabled work
99
104
 
@@ -256,3 +261,50 @@ record both manifest counts as 108 plus CJK review results.
256
261
 
257
262
  No raw third-party design corpus, screenshot, or reference asset is stored by
258
263
  this workflow.
264
+
265
+ ## Sticky transcript viewport contract
266
+
267
+ Live mode remains in natural terminal flow. Entering manual history makes the
268
+ application-owned transcript lane scrollable while the status line and every
269
+ later direct composer child are a fixed suffix at the bottom. PageUp/PageDown
270
+ move by the transcript capacity; the wheel remains three rows. A focused editor
271
+ keeps focus, and ordinary editor input or paste follows live before processing
272
+ that input.
273
+
274
+ Manual output has one bounded boolean indication, exactly **`New output — type
275
+ to follow`**. It is not a count. New visible agent/tool/extension output may set
276
+ it while manual; reflow, transient chrome, reconciliation, and user input may
277
+ not. Following clears it only after a successful live repaint. Manual-era output
278
+ is authoritative in the application transcript but is never retroactively
279
+ replayed into native host scrollback; subsequent ordinary live output follows
280
+ normal host behavior.
281
+
282
+ The transcript is the only selectable coordinate space. Pinned status/composer
283
+ chrome, notices, blank rows, and overlays never enter selection or copied text;
284
+ CJK selection clamping remains directional and grapheme/cell aware. Under
285
+ constrained height the notice drops first, then decorative pet and low-priority
286
+ hooks. Focused editor/cursor, status, and normal hooks outrank those rows; zero
287
+ transcript capacity is valid and must not corrupt cursor geometry.
288
+
289
+ At narrow widths use ANSI-aware terminal-cell measurement. ASCII/no-color keeps
290
+ textual state without SGR. Korean, Japanese, Chinese, and mixed CJK/Latin prose
291
+ must wrap at semantic phrase boundaries, never through an action/status label or
292
+ short identifier; a semantic CJK break is a visual-QA failure.
293
+
294
+ ### Sticky viewport deterministic visual QA
295
+
296
+ `test/fixtures/tui/sticky-viewport-showcase.ts` is a fixed-clock, no-network,
297
+ first-party harness that starts the production `TUI` over a `VirtualTerminal`.
298
+ It constructs transcript, status, hooks, and the real composer as children,
299
+ then drives the live/manual viewport path before capturing the terminal frame.
300
+ Capture with `bun packages/coding-agent/scripts/capture-sticky-viewport-showcase.ts
301
+ --out .skc/qa/sticky-viewport-<run>` and verify with the paired `--root` script.
302
+ The immutable matrix has exactly 20 keys: `live-overflow`, `manual-history`,
303
+ `manual-new-output`, `multiline-editor-hooks-pet`, `capacity-many`,
304
+ `capacity-one`, `capacity-zero`, and `selection-boundary` at both 80x24 and
305
+ 120x36 Unicode/color; plus `manual-new-output/80x24/ascii-no-color`,
306
+ `capacity-zero/48x10/ascii-no-color`,
307
+ `multiline-editor-hooks-pet/48x10/unicode-color`, and
308
+ `narrow-cjk/48x10/unicode-color`. Do not add or replace a manual-follow case.
309
+
310
+ Each key has only `terminal.txt`, ANSI-preserving `terminal-ansi.txt`, `terminal.html`, and `metadata.json`; the manifest records SHA-256 and byte length. Per-key metadata binds immutable font/render assumptions and the ANSI-aware wrapping/truncation policy. `VirtualTerminal` reconstructs ANSI from visible xterm cells, including cell padding, palette/RGB colors, attributes, and inverse video; plain text is always the stripped reconstruction. The verifier owns an independent literal 20-key oracle and fails closed unless stripped ANSI equals text, `terminal.html` equals the exported canonical `ansiToHtml(terminal-ansi.txt)` byte-for-byte (including its complete document envelope and global CSS), HTML independently preserves the ANSI style-run text, every retained row has the exact `Bun.stringWidth` cell width (including trailing spaces), and `ansi_mode` agrees with required Unicode color SGR or ASCII/no-color output. Every metadata entry has exact CJK phrase-boundary metadata: the narrow-CJK key has only the three canonical boundaries in order and every other key has `[]`. Manual captures prove successful production wheel and PageUp paths and retain observable historical transcript-row evidence. It validates exact payload paths (no duplicates or traversal), immutable source/output revisions, state/status/suffix order, notice cardinality, capacity, actual mouse-copied transcript-only selection, composer, CJK, and provenance invariants. `review-input.json` binds the exact manifest digest, capture author/executor identity, acceptance/design versions, required artifacts, narrow-CJK boundaries, and deterministic host matrix. `--require-independent-review` requires an attestation with an exact root key set; exact per-key result and artifact-check key sets; exact defect `{ description, accepted }` keys with a trimmed, nonblank description; canonical trimmed reviewer identity distinct from both bound identities; the independent-terminal-reviewer role; fixture revision; expected and observed counts of 20; exact checked keys; accepted per-key artifact-check/notes results; accepted artifact/CJK/host decisions; bound digest; and final `accept`. Any malformed, incomplete, or extra attestation content fails closed.