@sayknow-cli/coding-agent 0.4.7 → 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 +97 -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,611 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import { ansiToHtml, xterm256Color } from "./capture-sticky-viewport-showcase";
4
+
5
+ const KEYS = [
6
+ "live-overflow/80x24/unicode-color",
7
+ "live-overflow/120x36/unicode-color",
8
+ "manual-history/80x24/unicode-color",
9
+ "manual-history/120x36/unicode-color",
10
+ "manual-new-output/80x24/unicode-color",
11
+ "manual-new-output/120x36/unicode-color",
12
+ "multiline-editor-hooks-pet/80x24/unicode-color",
13
+ "multiline-editor-hooks-pet/120x36/unicode-color",
14
+ "capacity-many/80x24/unicode-color",
15
+ "capacity-many/120x36/unicode-color",
16
+ "capacity-one/80x24/unicode-color",
17
+ "capacity-one/120x36/unicode-color",
18
+ "capacity-zero/80x24/unicode-color",
19
+ "capacity-zero/120x36/unicode-color",
20
+ "selection-boundary/80x24/unicode-color",
21
+ "selection-boundary/120x36/unicode-color",
22
+ "manual-new-output/80x24/ascii-no-color",
23
+ "capacity-zero/48x10/ascii-no-color",
24
+ "multiline-editor-hooks-pet/48x10/unicode-color",
25
+ "narrow-cjk/48x10/unicode-color",
26
+ ] as const;
27
+ const PAYLOADS = ["terminal.txt", "terminal-ansi.txt", "terminal.html", "metadata.json"] as const;
28
+ const COMMAND =
29
+ "bun packages/coding-agent/scripts/capture-sticky-viewport-showcase.ts --out .skc/qa/sticky-viewport-<run>";
30
+ const TIMESTAMP = "1970-01-01T00:00:00.000Z";
31
+ const FIXTURE = "packages/coding-agent/test/fixtures/tui/sticky-viewport-showcase.ts";
32
+ const DEFAULT_FOREGROUND = "#ffe7dc";
33
+ const DEFAULT_BACKGROUND = "#110b0b";
34
+ const CJK = ["의미 있는 문장 경계", "意味のある文の境界", "保留语义短语边界"] as const;
35
+ const FONT_RENDERING_ASSUMPTIONS =
36
+ "Embedded red-octopus theme at deterministic truecolor; HTML uses a monospace terminal fallback stack.";
37
+ const WRAPPING_TRUNCATION_POLICY =
38
+ "ANSI-aware terminal-cell wrapping preserves semantic CJK phrase boundaries; constrained height drops the notice, decorative pet, then low-priority hooks without truncating pinned status or the focused composer.";
39
+ const ACCEPTANCE_VERSION = "sticky-viewport-stage-03";
40
+ const DESIGN_VERSION = "modes-design-sticky-viewport-v3";
41
+ const HOST_MATRIX = { capture_host: "VirtualTerminal", live_pty: false, network: false } as const;
42
+ const ARTIFACT_CHECKS = {
43
+ terminal_txt: true,
44
+ terminal_ansi_txt: true,
45
+ terminal_html: true,
46
+ metadata_json: true,
47
+ } as const;
48
+ const INDEPENDENT_REVIEW_KEYS = [
49
+ "schema_version",
50
+ "manifest_sha256",
51
+ "reviewer_identity",
52
+ "reviewer_role",
53
+ "fixture_revision",
54
+ "expected_entry_count",
55
+ "observed_entry_count",
56
+ "final",
57
+ "checked_keys",
58
+ "defects",
59
+ "artifact_decision",
60
+ "cjk_semantic_line_breaks",
61
+ "host_matrix",
62
+ "per_key_results",
63
+ ] as const;
64
+ const INDEPENDENT_REVIEW_RESULT_KEYS = ["key", "result", "notes", "artifact_checks"] as const;
65
+ const INDEPENDENT_REVIEW_DEFECT_KEYS = ["description", "accepted"] as const;
66
+ const ARTIFACT_CHECK_KEYS = ["terminal_txt", "terminal_ansi_txt", "terminal_html", "metadata_json"] as const;
67
+ type Style = {
68
+ foreground: string;
69
+ background: string;
70
+ bold: boolean;
71
+ dim: boolean;
72
+ italic: boolean;
73
+ underline: boolean;
74
+ blink: boolean;
75
+ inverse: boolean;
76
+ invisible: boolean;
77
+ strikethrough: boolean;
78
+ overline: boolean;
79
+ };
80
+ type Run = { text: string; style: Style };
81
+ const hash = (value: string) => new Bun.CryptoHasher("sha256").update(value).digest("hex");
82
+ const fail = (message: string): never => {
83
+ throw new Error(`Sticky viewport evidence invalid: ${message}`);
84
+ };
85
+ const exactKeys = (value: Record<string, unknown>, expected: readonly string[], label: string) => {
86
+ const actual = Object.keys(value).sort();
87
+ const sortedExpected = [...expected].sort();
88
+ if (JSON.stringify(actual) !== JSON.stringify(sortedExpected)) fail(`${label} keys must be exact`);
89
+ };
90
+ const object = (value: unknown, label: string): Record<string, unknown> => {
91
+ if (!value || typeof value !== "object" || Array.isArray(value)) fail(`${label} must be an object`);
92
+ return value as Record<string, unknown>;
93
+ };
94
+ const array = (value: unknown, label: string): unknown[] =>
95
+ Array.isArray(value) ? value : fail(`${label} must be an array`);
96
+ const strings = (value: unknown, expected: readonly string[], label: string) => {
97
+ if (
98
+ !Array.isArray(value) ||
99
+ value.length !== expected.length ||
100
+ value.some((item, index) => item !== expected[index])
101
+ )
102
+ fail(`${label} differs from immutable matrix`);
103
+ };
104
+ async function readJson(file: string, label: string): Promise<Record<string, unknown>> {
105
+ try {
106
+ return object(JSON.parse(await fs.readFile(file, "utf8")), label);
107
+ } catch (error) {
108
+ return fail(`${label} is unreadable: ${error instanceof Error ? error.message : String(error)}`);
109
+ }
110
+ }
111
+ async function allFiles(root: string): Promise<string[]> {
112
+ const result: string[] = [];
113
+ const walk = async (directory: string): Promise<void> => {
114
+ for (const item of await fs.readdir(directory, { withFileTypes: true })) {
115
+ const target = path.join(directory, item.name);
116
+ if (item.isDirectory()) await walk(target);
117
+ else if (item.isFile()) result.push(path.relative(root, target).split(path.sep).join("/"));
118
+ else fail(`unsupported filesystem entry ${target}`);
119
+ }
120
+ };
121
+ await walk(root);
122
+ return result.sort();
123
+ }
124
+ const baseStyle = (): Style => ({
125
+ foreground: DEFAULT_FOREGROUND,
126
+ background: DEFAULT_BACKGROUND,
127
+ bold: false,
128
+ dim: false,
129
+ italic: false,
130
+ underline: false,
131
+ blink: false,
132
+ inverse: false,
133
+ invisible: false,
134
+ strikethrough: false,
135
+ overline: false,
136
+ });
137
+ const color = (code: number): string | undefined => {
138
+ const colors: Record<number, string> = {
139
+ 30: "#000000",
140
+ 31: "#cc0000",
141
+ 32: "#4e9a06",
142
+ 33: "#c4a000",
143
+ 34: "#3465a4",
144
+ 35: "#75507b",
145
+ 36: "#06989a",
146
+ 37: "#d3d7cf",
147
+ 90: "#555753",
148
+ 91: "#ef2929",
149
+ 92: "#8ae234",
150
+ 93: "#fce94f",
151
+ 94: "#729fcf",
152
+ 95: "#ad7fa8",
153
+ 96: "#34e2e2",
154
+ 97: "#eeeeec",
155
+ };
156
+ return colors[code];
157
+ };
158
+ const pushRun = (runs: Run[], text: string, style: Style) => {
159
+ if (!text) return;
160
+ const effective = style.inverse
161
+ ? {
162
+ ...style,
163
+ foreground: style.background,
164
+ background: style.foreground,
165
+ inverse: false,
166
+ }
167
+ : { ...style };
168
+ runs.push({ text, style: effective });
169
+ };
170
+ function ansiRuns(ansi: string): Run[] {
171
+ const runs: Run[] = [];
172
+ let style = baseStyle(),
173
+ offset = 0;
174
+ for (const match of ansi.matchAll(/\x1b\[([0-9;]*)m/g)) {
175
+ pushRun(runs, ansi.slice(offset, match.index), style);
176
+ offset = (match.index ?? 0) + match[0].length;
177
+ const codes = (match[1] || "0").split(";").map(Number);
178
+ for (let index = 0; index < codes.length; index += 1) {
179
+ const code = codes[index]!;
180
+ if (code === 0) style = baseStyle();
181
+ else if (code === 1) style.bold = true;
182
+ else if (code === 2) style.dim = true;
183
+ else if (code === 3) style.italic = true;
184
+ else if (code === 4) style.underline = true;
185
+ else if (code === 5) style.blink = true;
186
+ else if (code === 7) style.inverse = true;
187
+ else if (code === 8) style.invisible = true;
188
+ else if (code === 9) style.strikethrough = true;
189
+ else if (code === 22) {
190
+ style.bold = false;
191
+ style.dim = false;
192
+ } else if (code === 23) style.italic = false;
193
+ else if (code === 24) style.underline = false;
194
+ else if (code === 25) style.blink = false;
195
+ else if (code === 27) style.inverse = false;
196
+ else if (code === 28) style.invisible = false;
197
+ else if (code === 29) style.strikethrough = false;
198
+ else if (code === 53) style.overline = true;
199
+ else if (code === 55) style.overline = false;
200
+ else if (code === 39) style.foreground = DEFAULT_FOREGROUND;
201
+ else if (code === 49) style.background = DEFAULT_BACKGROUND;
202
+ else if (color(code)) style.foreground = color(code)!;
203
+ else if (code >= 40 && code <= 47) style.background = color(code - 10)!;
204
+ else if (code >= 100 && code <= 107) style.background = color(code - 10)!;
205
+ else if ((code === 38 || code === 48) && codes[index + 1] === 5 && Number.isInteger(codes[index + 2])) {
206
+ const value = xterm256Color(codes[index + 2]!);
207
+ if (code === 38) style.foreground = value;
208
+ else style.background = value;
209
+ index += 2;
210
+ } else if (
211
+ (code === 38 || code === 48) &&
212
+ codes[index + 1] === 2 &&
213
+ [codes[index + 2], codes[index + 3], codes[index + 4]].every(Number.isInteger)
214
+ ) {
215
+ const value = `rgb(${codes[index + 2]},${codes[index + 3]},${codes[index + 4]})`;
216
+ if (code === 38) style.foreground = value;
217
+ else style.background = value;
218
+ index += 4;
219
+ }
220
+ }
221
+ }
222
+ pushRun(runs, ansi.slice(offset), style);
223
+ return runs;
224
+ }
225
+ const decode = (value: string) =>
226
+ value
227
+ .replace(/&quot;/g, '"')
228
+ .replace(/&amp;/g, "&")
229
+ .replace(/&lt;/g, "<")
230
+ .replace(/&gt;/g, ">");
231
+ function htmlRuns(html: string): Run[] {
232
+ const preMatch = html.match(/<pre>([\s\S]*)<\/pre>/);
233
+ if (preMatch?.[1] === undefined) return fail("HTML pre missing");
234
+ const pre = preMatch[1];
235
+ const runs: Run[] = [];
236
+ let style = baseStyle();
237
+ let offset = 0;
238
+ for (const match of pre.matchAll(/<span style="([^"]*)">|<\/span>/g)) {
239
+ pushRun(runs, decode(pre.slice(offset, match.index)), style);
240
+ offset = (match.index ?? 0) + match[0].length;
241
+ if (match[0] === "</span>") {
242
+ style = baseStyle();
243
+ continue;
244
+ }
245
+ const attributes = new Map<string, string>(
246
+ match[1]!
247
+ .split(";")
248
+ .filter(Boolean)
249
+ .map(part => {
250
+ const separator = part.indexOf(":");
251
+ if (separator < 0) return fail("HTML style declaration malformed");
252
+ return [part.slice(0, separator), part.slice(separator + 1)] as const;
253
+ }),
254
+ );
255
+ if (attributes.has("filter")) fail("HTML inverse must use effective colors, not CSS filter");
256
+ const decorations = new Set((attributes.get("text-decoration") ?? "").split(" "));
257
+ style = {
258
+ ...baseStyle(),
259
+ foreground: attributes.get("color") ?? DEFAULT_FOREGROUND,
260
+ background: attributes.get("background-color") ?? DEFAULT_BACKGROUND,
261
+ bold: attributes.get("font-weight") === "700",
262
+ dim: attributes.get("opacity") === ".65",
263
+ italic: attributes.get("font-style") === "italic",
264
+ underline: decorations.has("underline"),
265
+ blink: attributes.get("animation") === "blink 1s step-end infinite",
266
+ invisible: attributes.get("visibility") === "hidden",
267
+ strikethrough: decorations.has("line-through"),
268
+ overline: decorations.has("overline"),
269
+ };
270
+ }
271
+ pushRun(runs, decode(pre.slice(offset)), style);
272
+ return runs;
273
+ }
274
+ const normalized = (runs: Run[]) => {
275
+ const merged: Run[] = [];
276
+ for (const run of runs) {
277
+ const prior = merged.at(-1);
278
+ if (prior && JSON.stringify(prior.style) === JSON.stringify(run.style)) prior.text += run.text;
279
+ else merged.push({ ...run, style: { ...run.style } });
280
+ }
281
+ return merged;
282
+ };
283
+ const equalRuns = (left: Run[], right: Run[]) => JSON.stringify(normalized(left)) === JSON.stringify(normalized(right));
284
+ const transcriptCapacity = (text: string) => {
285
+ const row = text.split("\n").findIndex(line => line.includes("status:"));
286
+ return row < 0 ? fail("frame omits pinned status row") : row;
287
+ };
288
+ const expectedState = (state: string) => ({
289
+ manual: state !== "live-overflow",
290
+ notice: state === "manual-new-output",
291
+ status: state === "live-overflow" ? "status: live follow" : "status: manual history · composer pinned",
292
+ multiline: state === "multiline-editor-hooks-pet",
293
+ });
294
+ function validateOracle(
295
+ key: string,
296
+ text: string,
297
+ metadata: Record<string, unknown>,
298
+ stateEvidence: Record<string, unknown>,
299
+ ) {
300
+ const state = key.split("/")[0]!;
301
+ const expected = expectedState(state);
302
+ const lines = text.split("\n");
303
+ if (stateEvidence.manual !== expected.manual || stateEvidence.notice !== expected.notice)
304
+ fail(`immutable state oracle mismatch for ${key}`);
305
+ if (lines.filter(line => line.includes(expected.status)).length !== 1)
306
+ fail(`exact status oracle mismatch for ${key}`);
307
+ const markers = [
308
+ expected.status,
309
+ ...(expected.multiline
310
+ ? ["hook: ready", "completed: visual proof", "pet: ◕‿◕", "> ", "first composer line", "second composer line"]
311
+ : ["> "]),
312
+ ];
313
+ let position = -1;
314
+ for (const marker of markers) {
315
+ const next = text.indexOf(marker, position + 1);
316
+ if (next < 0) fail(`ordered suffix oracle missing ${marker} for ${key}`);
317
+ position = next;
318
+ }
319
+ if (text.split("New output — type to follow").length - 1 !== (expected.notice ? 1 : 0))
320
+ fail(`notice cardinality oracle mismatch for ${key}`);
321
+ if (
322
+ expected.multiline !==
323
+ (text.includes("hook: ready") &&
324
+ text.includes("pet: ◕‿◕") &&
325
+ text.includes("first composer line") &&
326
+ text.includes("second composer line"))
327
+ )
328
+ fail(`multiline editor/hooks/pet oracle mismatch for ${key}`);
329
+ if (metadata.output_revision !== (expected.notice ? "1" : "0")) fail(`manual notice invariant mismatch for ${key}`);
330
+ if (state === "selection-boundary") {
331
+ const copied = stateEvidence.selection_copied_text;
332
+ if (
333
+ stateEvidence.selection_scope !== "transcript" ||
334
+ typeof copied !== "string" ||
335
+ !copied.trim() ||
336
+ copied.includes("status:") ||
337
+ copied.includes("> ") ||
338
+ !lines.some(line => line.includes(copied.trim()))
339
+ )
340
+ fail(`selection oracle mismatch for ${key}`);
341
+ } else if (stateEvidence.selection_scope !== "none" || stateEvidence.selection_copied_text !== "")
342
+ fail(`selection oracle mismatch for ${key}`);
343
+ const historicalRows = stateEvidence.manual_historical_rows;
344
+ const preOutputCapacity = stateEvidence.manual_pre_output_capacity;
345
+ if (expected.manual) {
346
+ if (
347
+ !Number.isInteger(preOutputCapacity) ||
348
+ (preOutputCapacity as number) < 0 ||
349
+ !Array.isArray(historicalRows) ||
350
+ historicalRows.length !== ((preOutputCapacity as number) > 0 ? 1 : 0) ||
351
+ historicalRows.some(row => typeof row !== "string" || !row.trim() || !lines.includes(row))
352
+ )
353
+ fail(`manual historical transcript evidence mismatch for ${key}`);
354
+ } else if (preOutputCapacity !== 0 || !Array.isArray(historicalRows) || historicalRows.length !== 0)
355
+ fail(`manual historical transcript evidence mismatch for ${key}`);
356
+ }
357
+ export async function verifyStickyViewportShowcase(rootInput: string, requireIndependentReview = false): Promise<void> {
358
+ const root = path.resolve(rootInput);
359
+ const manifestText = await fs.readFile(path.join(root, "manifest.json"), "utf8");
360
+ const manifest = await readJson(path.join(root, "manifest.json"), "manifest");
361
+ if (
362
+ manifest.schema_version !== 2 ||
363
+ manifest.fixture_revision !== "sticky-viewport-showcase-v2" ||
364
+ manifest.expected_entry_count !== 20 ||
365
+ manifest.entry_count !== 20 ||
366
+ manifest.command !== COMMAND ||
367
+ manifest.capture_timestamp !== TIMESTAMP ||
368
+ manifest.review_input_file !== "review-input.json"
369
+ )
370
+ fail("manifest schema or provenance literals mismatch");
371
+ strings(manifest.ordered_keys, KEYS, "manifest ordered_keys");
372
+ const provenance = object(manifest.provenance, "manifest provenance");
373
+ if (
374
+ provenance.capture_mode !== "production-tui-virtual-terminal" ||
375
+ provenance.live_pty !== false ||
376
+ provenance.network !== false ||
377
+ provenance.fixed_clock !== true ||
378
+ typeof provenance.author_identity !== "string" ||
379
+ !provenance.author_identity.trim() ||
380
+ typeof provenance.executor_identity !== "string" ||
381
+ !provenance.executor_identity.trim()
382
+ )
383
+ fail("manifest provenance mismatch");
384
+ const entries = array(manifest.entries, "manifest entries");
385
+ if (entries.length !== KEYS.length) fail("manifest entries must contain exactly 20 entries");
386
+ for (let index = 0; index < KEYS.length; index += 1) {
387
+ const key = KEYS[index]!;
388
+ const entry = object(entries[index], `entry ${index}`);
389
+ const [state, id, mode] = key.split("/");
390
+ const [columns, rows] = id!.split("x").map(Number);
391
+ if (entry.key !== key || entry.state_id !== state || entry.render_mode !== mode)
392
+ fail(`entry ${key} variant mismatch`);
393
+ const viewport = object(entry.viewport, `entry ${key} viewport`);
394
+ if (viewport.id !== id || viewport.columns !== columns || viewport.rows !== rows)
395
+ fail(`entry ${key} viewport mismatch`);
396
+ const listed = array(entry.files, `entry ${key} files`);
397
+ if (listed.length !== PAYLOADS.length) fail(`entry ${key} file list is not exact`);
398
+ strings(
399
+ listed.map(value => object(value, `entry ${key} file`).path),
400
+ PAYLOADS.map(name => `${key}/${name}`),
401
+ `entry ${key} payload paths`,
402
+ );
403
+ for (const value of listed) {
404
+ const file = object(value, `entry ${key} file`);
405
+ if (typeof file.path !== "string" || typeof file.sha256 !== "string" || !Number.isInteger(file.byte_length))
406
+ fail(`entry ${key} malformed file manifest`);
407
+ const filePath = file.path as string;
408
+ const content = await fs.readFile(path.join(root, filePath), "utf8");
409
+ if (hash(content) !== file.sha256 || Buffer.byteLength(content) !== file.byte_length)
410
+ fail(`entry ${key} hash or byte length mismatch`);
411
+ }
412
+ const text = await fs.readFile(path.join(root, key, "terminal.txt"), "utf8");
413
+ const ansi = await fs.readFile(path.join(root, key, "terminal-ansi.txt"), "utf8");
414
+ const html = await fs.readFile(path.join(root, key, "terminal.html"), "utf8");
415
+ if (Bun.stripANSI(ansi) !== text) fail(`entry ${key} text/ANSI semantic evidence mismatch`);
416
+ if (html !== ansiToHtml(ansi)) fail(`entry ${key} HTML artifact is not canonical ANSI conversion`);
417
+ const ansiStyleRuns = ansiRuns(ansi);
418
+ const htmlStyleRuns = htmlRuns(html);
419
+ if (
420
+ ansiStyleRuns.map(run => run.text).join("") !== text ||
421
+ htmlStyleRuns.map(run => run.text).join("") !== text ||
422
+ !equalRuns(ansiStyleRuns, htmlStyleRuns)
423
+ )
424
+ fail(`entry ${key} ANSI/HTML style-run mismatch`);
425
+ if (state === "multiline-editor-hooks-pet" && (!ansi.includes("\x1b[9m") || !html.includes("line-through")))
426
+ fail(`entry ${key} strikethrough evidence missing`);
427
+ if (state === "selection-boundary" && !ansi.includes("\x1b[7m"))
428
+ fail(`entry ${key} inverse selection evidence missing`);
429
+ if (state === "narrow-cjk" && CJK.some(boundary => !text.includes(boundary)))
430
+ fail("narrow CJK visible terminal evidence missing");
431
+ if (
432
+ text
433
+ .split("\n")
434
+ .slice(0, -1)
435
+ .some(row => Bun.stringWidth(row) !== columns) ||
436
+ text.split("\n").length - 1 !== rows
437
+ )
438
+ fail(`entry ${key} terminal dimensions mismatch`);
439
+ if (mode === "ascii-no-color" ? /\x1b\[/.test(ansi) : !/\x1b\[[0-9;]*(?:3[0-9]|38;)/.test(ansi))
440
+ fail(`entry ${key} ANSI mode/color mismatch`);
441
+ const metadata = await readJson(path.join(root, key, "metadata.json"), `metadata ${key}`);
442
+ exactKeys(
443
+ metadata,
444
+ [
445
+ "schema_version",
446
+ "entry_key",
447
+ "fixture_revision",
448
+ "capture_timestamp",
449
+ "command_or_replay_source",
450
+ "fixture_source",
451
+ "terminal",
452
+ "render_mode",
453
+ "ansi_mode",
454
+ "source_revision",
455
+ "output_revision",
456
+ "state",
457
+ "provenance",
458
+ "cjk_phrase_boundaries",
459
+ ],
460
+ `metadata ${key}`,
461
+ );
462
+ const terminal = object(metadata.terminal, `metadata ${key} terminal`);
463
+ exactKeys(
464
+ terminal,
465
+ ["id", "columns", "rows", "font_rendering_assumptions", "wrapping_truncation_policy"],
466
+ `metadata ${key} terminal`,
467
+ );
468
+ const stateEvidence = object(metadata.state, `metadata ${key} state`);
469
+ const metaProvenance = object(metadata.provenance, `metadata ${key} provenance`);
470
+ if (
471
+ metadata.schema_version !== 2 ||
472
+ metadata.entry_key !== key ||
473
+ metadata.fixture_revision !== "sticky-viewport-showcase-v2" ||
474
+ metadata.capture_timestamp !== TIMESTAMP ||
475
+ metadata.command_or_replay_source !== COMMAND ||
476
+ metadata.fixture_source !== FIXTURE ||
477
+ metadata.render_mode !== mode ||
478
+ metadata.ansi_mode !== (mode === "unicode-color") ||
479
+ metadata.source_revision !== "production-tui-virtual-terminal-v2" ||
480
+ terminal.id !== id ||
481
+ terminal.columns !== columns ||
482
+ terminal.rows !== rows ||
483
+ terminal.font_rendering_assumptions !== FONT_RENDERING_ASSUMPTIONS ||
484
+ terminal.wrapping_truncation_policy !== WRAPPING_TRUNCATION_POLICY ||
485
+ metaProvenance.capture_mode !== provenance.capture_mode ||
486
+ metaProvenance.live_pty !== false ||
487
+ metaProvenance.network !== false ||
488
+ metaProvenance.fixed_clock !== true ||
489
+ metaProvenance.author_identity !== provenance.author_identity ||
490
+ metaProvenance.executor_identity !== provenance.executor_identity ||
491
+ stateEvidence.composer_visible !== true
492
+ )
493
+ fail(`metadata schema mismatch for ${key}`);
494
+ if (stateEvidence.transcript_capacity !== transcriptCapacity(text))
495
+ fail(`capacity metadata/frame mismatch for ${key}`);
496
+ validateOracle(key, text, metadata, stateEvidence);
497
+ if (state === "capacity-zero" && transcriptCapacity(text) !== 0)
498
+ fail(`zero capacity frame invariant mismatch for ${key}`);
499
+ if (state === "capacity-one" && transcriptCapacity(text) !== 1)
500
+ fail(`one capacity frame invariant mismatch for ${key}`);
501
+ if (state === "capacity-many" && transcriptCapacity(text) < 2)
502
+ fail(`many capacity frame invariant mismatch for ${key}`);
503
+ if (state === "narrow-cjk") {
504
+ strings(metadata.cjk_phrase_boundaries, CJK, "narrow CJK boundaries");
505
+ if (CJK.some(boundary => !text.includes(boundary))) fail("narrow CJK visible terminal evidence missing");
506
+ } else strings(metadata.cjk_phrase_boundaries, [], `non-narrow CJK boundaries for ${key}`);
507
+ }
508
+ const required = new Set([
509
+ "manifest.json",
510
+ "review-input.json",
511
+ ...KEYS.flatMap(key => PAYLOADS.map(file => `${key}/${file}`)),
512
+ ...(requireIndependentReview ? ["independent-review.json"] : []),
513
+ ]);
514
+ for (const file of await allFiles(root)) if (!required.has(file)) fail(`unexpected file ${file}`);
515
+ const reviewInput = await readJson(path.join(root, "review-input.json"), "review input");
516
+ if (
517
+ reviewInput.schema_version !== 2 ||
518
+ reviewInput.manifest_sha256 !== hash(manifestText) ||
519
+ reviewInput.command_or_replay_source !== COMMAND ||
520
+ reviewInput.capture_timestamp !== TIMESTAMP ||
521
+ reviewInput.fixture_source !== FIXTURE ||
522
+ reviewInput.fixed_clock !== true ||
523
+ reviewInput.live_pty !== false ||
524
+ reviewInput.network !== false ||
525
+ reviewInput.author_identity !== provenance.author_identity ||
526
+ reviewInput.executor_identity !== provenance.executor_identity
527
+ )
528
+ fail("review input manifest binding mismatch");
529
+ strings(reviewInput.expected_keys, KEYS, "review input expected_keys");
530
+ strings(reviewInput.required_artifacts, PAYLOADS, "review input required_artifacts");
531
+ const reviewHostMatrix = object(reviewInput.host_matrix, "review input host matrix");
532
+ if (
533
+ reviewInput.acceptance_version !== ACCEPTANCE_VERSION ||
534
+ reviewInput.design_version !== DESIGN_VERSION ||
535
+ reviewHostMatrix.capture_host !== HOST_MATRIX.capture_host ||
536
+ reviewHostMatrix.live_pty !== HOST_MATRIX.live_pty ||
537
+ reviewHostMatrix.network !== HOST_MATRIX.network
538
+ )
539
+ fail("review input acceptance, design, or host matrix mismatch");
540
+ const narrow = object(reviewInput.narrow_cjk, "review input narrow CJK");
541
+ if (narrow.entry_key !== "narrow-cjk/48x10/unicode-color") fail("review input narrow CJK mismatch");
542
+ strings(narrow.phrase_boundaries, CJK, "review input narrow CJK boundaries");
543
+ if (requireIndependentReview) {
544
+ const review = await readJson(path.join(root, "independent-review.json"), "independent review");
545
+ exactKeys(review, INDEPENDENT_REVIEW_KEYS, "independent review");
546
+ const reviewer = review.reviewer_identity;
547
+ const canonicalReviewer = typeof reviewer === "string" ? reviewer.trim() : "";
548
+ const canonicalAuthor = (provenance.author_identity as string).trim();
549
+ const canonicalExecutor = (provenance.executor_identity as string).trim();
550
+ const defects = array(review.defects, "independent review defects");
551
+ if (
552
+ review.schema_version !== 2 ||
553
+ review.manifest_sha256 !== hash(manifestText) ||
554
+ review.fixture_revision !== "sticky-viewport-showcase-v2" ||
555
+ review.expected_entry_count !== 20 ||
556
+ review.observed_entry_count !== 20 ||
557
+ review.final !== "accept" ||
558
+ review.reviewer_role !== "independent-terminal-reviewer" ||
559
+ typeof reviewer !== "string" ||
560
+ !canonicalReviewer ||
561
+ reviewer !== canonicalReviewer ||
562
+ canonicalReviewer === canonicalAuthor ||
563
+ canonicalReviewer === canonicalExecutor ||
564
+ review.artifact_decision !== "accept" ||
565
+ review.cjk_semantic_line_breaks !== "accept" ||
566
+ review.host_matrix !== "accept"
567
+ )
568
+ fail("independent review schema or decision mismatch");
569
+ for (const defect of defects) {
570
+ const item = object(defect, "independent review defect");
571
+ exactKeys(item, INDEPENDENT_REVIEW_DEFECT_KEYS, "independent review defect");
572
+ if (
573
+ typeof item.description !== "string" ||
574
+ !item.description.trim() ||
575
+ item.description !== item.description.trim() ||
576
+ item.accepted !== true
577
+ )
578
+ fail("independent review defect mismatch");
579
+ }
580
+ strings(review.checked_keys, KEYS, "independent review checked_keys");
581
+ const results = array(review.per_key_results, "independent review per-key results");
582
+ if (results.length !== KEYS.length) fail("independent review per-key results must contain exactly 20 entries");
583
+ for (let index = 0; index < KEYS.length; index += 1) {
584
+ const result = object(results[index], `independent review result ${index}`);
585
+ exactKeys(result, INDEPENDENT_REVIEW_RESULT_KEYS, `independent review result ${index}`);
586
+ if (
587
+ result.key !== KEYS[index] ||
588
+ result.result !== "accept" ||
589
+ typeof result.notes !== "string" ||
590
+ !result.notes.trim()
591
+ )
592
+ fail("independent review per-key result mismatch");
593
+ const checks = object(result.artifact_checks, "independent review per-key artifact checks");
594
+ exactKeys(checks, ARTIFACT_CHECK_KEYS, "independent review per-key artifact checks");
595
+ for (const [artifact, expected] of Object.entries(ARTIFACT_CHECKS))
596
+ if (checks[artifact] !== expected) fail("independent review per-key artifact checks missing");
597
+ }
598
+ }
599
+ }
600
+ async function main() {
601
+ const args = process.argv.slice(2);
602
+ const required = args.includes("--require-independent-review");
603
+ const rest = args.filter(value => value !== "--require-independent-review");
604
+ if (rest.length !== 2 || rest[0] !== "--root")
605
+ throw new Error(
606
+ "Usage: bun packages/coding-agent/scripts/verify-sticky-viewport-showcase.ts --root <root> [--require-independent-review]",
607
+ );
608
+ await verifyStickyViewportShowcase(rest[1]!, required);
609
+ process.stdout.write("Sticky viewport evidence verified\n");
610
+ }
611
+ if (import.meta.main) await main();