create-walle 0.10.1 → 0.10.2

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 (341) hide show
  1. package/README.md +4 -0
  2. package/lib/owner-write-safety.js +135 -0
  3. package/lib/public-runtime.js +13 -5
  4. package/lib/release-schema.json +3 -2
  5. package/lib/runtime-closure-policy.json +6 -4
  6. package/package.json +1 -1
  7. package/template/bin/deps-doctor.js +1 -1
  8. package/template/bin/node-bin.sh +11 -0
  9. package/template/coding-task-manager/api-prompts.js +10 -22
  10. package/template/coding-task-manager/bin/claude-hook.js +7 -3
  11. package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
  12. package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
  13. package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
  14. package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
  15. package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
  16. package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
  17. package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
  18. package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
  19. package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
  20. package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
  21. package/template/coding-task-manager/db.js +705 -286
  22. package/template/coding-task-manager/git-utils.js +44 -0
  23. package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
  24. package/template/coding-task-manager/lib/agent-presets.js +15 -0
  25. package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
  26. package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
  27. package/template/coding-task-manager/lib/api/host-stats.js +98 -0
  28. package/template/coding-task-manager/lib/api/ingress.js +35 -12
  29. package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
  30. package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
  31. package/template/coding-task-manager/lib/api/machines.js +461 -0
  32. package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
  33. package/template/coding-task-manager/lib/api/providers.js +53 -6
  34. package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
  35. package/template/coding-task-manager/lib/api/sessions.js +160 -8
  36. package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
  37. package/template/coding-task-manager/lib/api/worktrees.js +38 -37
  38. package/template/coding-task-manager/lib/approval-drift.js +16 -1
  39. package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
  40. package/template/coding-task-manager/lib/approval-scope.js +68 -4
  41. package/template/coding-task-manager/lib/auth-context.js +32 -2
  42. package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
  43. package/template/coding-task-manager/lib/auth-rules.js +186 -45
  44. package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
  45. package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
  46. package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
  47. package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
  48. package/template/coding-task-manager/lib/claude-session-title.js +6 -30
  49. package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
  50. package/template/coding-task-manager/lib/client-diag-handler.js +5 -0
  51. package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
  52. package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
  53. package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
  54. package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
  55. package/template/coding-task-manager/lib/codex-paths.js +2 -1
  56. package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
  57. package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
  58. package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
  59. package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
  60. package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
  61. package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
  62. package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
  63. package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
  64. package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
  65. package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
  66. package/template/coding-task-manager/lib/db-domains.js +21 -2
  67. package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
  68. package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
  69. package/template/coding-task-manager/lib/feature-manifest.js +1 -1
  70. package/template/coding-task-manager/lib/fs-watcher.js +3 -2
  71. package/template/coding-task-manager/lib/harness-history-transition.js +3 -3
  72. package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
  73. package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
  74. package/template/coding-task-manager/lib/headless-term-service.js +55 -17
  75. package/template/coding-task-manager/lib/host-control-dial.js +167 -0
  76. package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
  77. package/template/coding-task-manager/lib/host-handoff.js +51 -13
  78. package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
  79. package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
  80. package/template/coding-task-manager/lib/host-stats.js +328 -0
  81. package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
  82. package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
  83. package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
  84. package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
  85. package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
  86. package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
  87. package/template/coding-task-manager/lib/instance-manifest.js +13 -1
  88. package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
  89. package/template/coding-task-manager/lib/launch-model-override.js +160 -1
  90. package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
  91. package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
  92. package/template/coding-task-manager/lib/lead-model-switch.js +3 -2
  93. package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
  94. package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
  95. package/template/coding-task-manager/lib/login-tripwire.js +1 -0
  96. package/template/coding-task-manager/lib/machine-pairing.js +238 -0
  97. package/template/coding-task-manager/lib/machine-pool.js +409 -0
  98. package/template/coding-task-manager/lib/machine-registry.js +749 -0
  99. package/template/coding-task-manager/lib/machine-self.js +66 -0
  100. package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +52 -4
  101. package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
  102. package/template/coding-task-manager/lib/media-journal.js +84 -27
  103. package/template/coding-task-manager/lib/media-store-options.js +43 -15
  104. package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
  105. package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
  106. package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
  107. package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
  108. package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
  109. package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
  110. package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
  111. package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
  112. package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
  113. package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
  114. package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
  115. package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
  116. package/template/coding-task-manager/lib/native-history-control.js +2 -2
  117. package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
  118. package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
  119. package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
  120. package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
  121. package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
  122. package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
  123. package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
  124. package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
  125. package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
  126. package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
  127. package/template/coding-task-manager/lib/read-pool-client.js +5 -2
  128. package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
  129. package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
  130. package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
  131. package/template/coding-task-manager/lib/remote-command-context.js +12 -0
  132. package/template/coding-task-manager/lib/remote-command-runtime.js +13 -1
  133. package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
  134. package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
  135. package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
  136. package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
  137. package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
  138. package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
  139. package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
  140. package/template/coding-task-manager/lib/restart-preflight.js +9 -2
  141. package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
  142. package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
  143. package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
  144. package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
  145. package/template/coding-task-manager/lib/resume-cwd.js +13 -0
  146. package/template/coding-task-manager/lib/resume-from-store.js +12 -1
  147. package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
  148. package/template/coding-task-manager/lib/resume-preflight.js +21 -16
  149. package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
  150. package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
  151. package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
  152. package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
  153. package/template/coding-task-manager/lib/root-prompt-admission.js +33 -2
  154. package/template/coding-task-manager/lib/root-prompt-flow.js +167 -33
  155. package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
  156. package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
  157. package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
  158. package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
  159. package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
  160. package/template/coding-task-manager/lib/session-create/identity.js +20 -1
  161. package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
  162. package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
  163. package/template/coding-task-manager/lib/session-create/provider-process.js +34 -37
  164. package/template/coding-task-manager/lib/session-create/response.js +30 -12
  165. package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
  166. package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
  167. package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
  168. package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
  169. package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
  170. package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
  171. package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
  172. package/template/coding-task-manager/lib/session-host-manager.js +152 -206
  173. package/template/coding-task-manager/lib/session-jobs.js +17 -9
  174. package/template/coding-task-manager/lib/session-lifecycle.js +18 -0
  175. package/template/coding-task-manager/lib/session-model-action-preconditions.js +9 -0
  176. package/template/coding-task-manager/lib/session-resource-sampler.js +19 -9
  177. package/template/coding-task-manager/lib/session-standup.js +67 -4
  178. package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
  179. package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
  180. package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
  181. package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
  182. package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
  183. package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
  184. package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
  185. package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
  186. package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
  187. package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
  188. package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
  189. package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
  190. package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
  191. package/template/coding-task-manager/lib/transcript-link.js +77 -0
  192. package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
  193. package/template/coding-task-manager/lib/transcript-source.js +8 -3
  194. package/template/coding-task-manager/lib/transcript-store.js +40 -0
  195. package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
  196. package/template/coding-task-manager/lib/typing-interaction-trace.js +92 -0
  197. package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
  198. package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
  199. package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
  200. package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
  201. package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
  202. package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
  203. package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
  204. package/template/coding-task-manager/lib/ws-router.js +68 -1
  205. package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
  206. package/template/coding-task-manager/oauth-proxy.js +99 -55
  207. package/template/coding-task-manager/package-lock.json +24 -0
  208. package/template/coding-task-manager/package.json +3 -0
  209. package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
  210. package/template/coding-task-manager/providers/codex-mcp.js +14 -5
  211. package/template/coding-task-manager/public/css/app.css +279 -1
  212. package/template/coding-task-manager/public/css/reviews.css +4 -0
  213. package/template/coding-task-manager/public/index.html +294 -223
  214. package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
  215. package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
  216. package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
  217. package/template/coding-task-manager/public/js/background-work.js +13 -7
  218. package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
  219. package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
  220. package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
  221. package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
  222. package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
  223. package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
  224. package/template/coding-task-manager/public/js/history-scroller.js +187 -9
  225. package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
  226. package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
  227. package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
  228. package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -8
  229. package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
  230. package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
  231. package/template/coding-task-manager/public/js/reviews.js +7 -3
  232. package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
  233. package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
  234. package/template/coding-task-manager/public/js/row-join.js +4 -2
  235. package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
  236. package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
  237. package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
  238. package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
  239. package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
  240. package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
  241. package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
  242. package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
  243. package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
  244. package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
  245. package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
  246. package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
  247. package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
  248. package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -1
  249. package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
  250. package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
  251. package/template/coding-task-manager/public/js/walle-session.js +30 -7
  252. package/template/coding-task-manager/public/m/app.css +226 -8
  253. package/template/coding-task-manager/public/m/app.js +502 -9
  254. package/template/coding-task-manager/public/m/index.html +38 -1
  255. package/template/coding-task-manager/public/m/machines.js +1313 -0
  256. package/template/coding-task-manager/public/m/pool-failover.js +391 -0
  257. package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
  258. package/template/coding-task-manager/public/m/sw.js +5 -0
  259. package/template/coding-task-manager/queue-engine.js +13 -0
  260. package/template/coding-task-manager/server/approvals.js +5 -6
  261. package/template/coding-task-manager/server/boot.js +136 -17
  262. package/template/coding-task-manager/server.js +902 -239
  263. package/template/coding-task-manager/session-integrity.js +7 -9
  264. package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
  265. package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
  266. package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
  267. package/template/coding-task-manager/workers/session-host-process.js +14 -3
  268. package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
  269. package/template/coding-task-manager/workers/worktree-worker.js +34 -0
  270. package/template/package-lock.json +2 -2
  271. package/template/package.json +1 -1
  272. package/template/scripts/conversation-storage-v2-migration.js +78 -11
  273. package/template/shared/conversation-storage-v2-contract.js +42 -6
  274. package/template/shared/fixtures/worker-status-payloads.json +392 -0
  275. package/template/shared/git-remote-key.js +83 -0
  276. package/template/shared/host-identity.js +98 -2
  277. package/template/shared/owner-write-safety.js +135 -0
  278. package/template/shared/public-runtime.js +13 -5
  279. package/template/shared/release-schema.json +3 -2
  280. package/template/shared/report-citations.js +14 -0
  281. package/template/shared/sqlite-write-lock.js +361 -223
  282. package/template/shared/storage/contract.js +35 -3
  283. package/template/wall-e/agent.js +21 -0
  284. package/template/wall-e/api-walle.js +5 -0
  285. package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
  286. package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
  287. package/template/wall-e/brain/helper-rules-schema.js +129 -0
  288. package/template/wall-e/brain/migrations.js +51 -22
  289. package/template/wall-e/brain/model-deployment-facts.js +31 -1
  290. package/template/wall-e/brain/owner-call-whitelist.js +16 -0
  291. package/template/wall-e/brain/schema-ensures.js +22 -0
  292. package/template/wall-e/brain.js +1 -1
  293. package/template/wall-e/coding/journal-dispatcher.js +51 -0
  294. package/template/wall-e/coding/session-journal.js +28 -40
  295. package/template/wall-e/coding-orchestrator.js +23 -26
  296. package/template/wall-e/http/auth.js +18 -1
  297. package/template/wall-e/http/blog-views-api.js +318 -0
  298. package/template/wall-e/http/helper-rules-api.js +321 -0
  299. package/template/wall-e/http/model-proxy-providers.js +3 -1
  300. package/template/wall-e/http/telemetry-api.js +12 -0
  301. package/template/wall-e/lib/blog-view-policy.js +88 -0
  302. package/template/wall-e/lib/blog-view-store.js +169 -0
  303. package/template/wall-e/lib/client-config-lock.js +2 -1
  304. package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
  305. package/template/wall-e/lib/error-kinds.js +10 -1
  306. package/template/wall-e/lib/feature-manifest.js +1 -1
  307. package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
  308. package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
  309. package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
  310. package/template/wall-e/lib/helper-rules/grade.js +277 -0
  311. package/template/wall-e/lib/helper-rules/label.js +247 -0
  312. package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
  313. package/template/wall-e/lib/helper-rules/store.js +667 -0
  314. package/template/wall-e/lib/mcp-integration.js +5 -6
  315. package/template/wall-e/lib/runtime-worker-pool.js +1 -0
  316. package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
  317. package/template/wall-e/lib/telemetry-db-schema.js +37 -0
  318. package/template/wall-e/lib/telemetry-process-client.js +76 -1
  319. package/template/wall-e/llm/default-fallback.js +4 -0
  320. package/template/wall-e/llm/model-catalog.js +13 -4
  321. package/template/wall-e/llm/model-roles.js +6 -0
  322. package/template/wall-e/llm/portkey-http.js +150 -0
  323. package/template/wall-e/llm/portkey-sync.js +15 -145
  324. package/template/wall-e/llm/worker-mcp-routing.js +61 -0
  325. package/template/wall-e/llm/worker-route.js +43 -1
  326. package/template/wall-e/loops/brain-custom-writes.js +45 -0
  327. package/template/wall-e/mcp-protocol-contract.js +41 -1
  328. package/template/wall-e/mcp-server.js +13 -2
  329. package/template/wall-e/mcp-worker-schemas.js +20 -2
  330. package/template/wall-e/memory/ctm-context-client.js +25 -5
  331. package/template/wall-e/shared/release-schema.json +3 -2
  332. package/template/wall-e/shared/sqlite-write-lock.js +361 -223
  333. package/template/wall-e/shared/storage/contract.js +35 -3
  334. package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
  335. package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
  336. package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
  337. package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
  338. package/template/wall-e/tools/local-tools.js +6 -4
  339. package/template/wall-e/workers/brain-owner-worker.js +9 -0
  340. package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
  341. package/template/wall-e/workers/telemetry-worker.js +8 -0
@@ -31,17 +31,14 @@
31
31
  // state across the intervening rows exactly as it should, since these rows
32
32
  // are painted into the pane in that same order.
33
33
 
34
- const { wrapToCells, truncateToCells, stringCellWidth } = require('./terminal-cell-width');
35
- const { collectColumnMetrics, computeColumnWidths } = require('./codex-markdown-table');
34
+ const { wrapToCells, truncateToCells } = require('./terminal-cell-width');
35
+ // WP-1 (reader-claude-table-layout-parity-2026-10-25): tables are laid out by Claude Code
36
+ // 2.1.310's own algorithm, ported in this module's sibling -- never by the Codex allocator this
37
+ // file used to borrow (see `emitTable`).
38
+ const { layoutClaudeTable, cardLines, inkWrapLines } = require('./claude-table-layout');
36
39
 
37
40
  const RESET = '\x1b[0m';
38
41
 
39
- // WP-2 (reader-seam-duplicates): the per-attribute "off" codes this module already closes every
40
- // inline span with (22 un-bold, 23 un-italicize, 29 un-strike, 39 default fg). A table cell that
41
- // WRAPS emits one of these at the end of each of its visual lines so a span left open by the
42
- // wrapped text can never bleed past the `│` that closes the cell into the next column.
43
- const SPAN_OFF = '\x1b[22;23;29;39m';
44
-
45
42
  function _sgrOpen(codes) {
46
43
  const list = (Array.isArray(codes) ? codes : [codes]).filter((c) => c !== undefined && c !== null && c !== '');
47
44
  return list.length ? `\x1b[${list.join(';')}m` : '';
@@ -128,85 +125,30 @@ function emitCode(token, cols, indent, style) {
128
125
  return lines.map((line) => ' '.repeat(indent) + closeRow(styleRow(truncateToCells(line, width), style.code)));
129
126
  }
130
127
 
131
- // Corrected 2026-09-27 (WP-3 live capture, fix round 1): the real screen draws a full
132
- // box-drawing table (┌─┬─┐ / ├─┼─┤ / └─┴─┘ borders, one space of padding either side of each
133
- // cell, column width = the widest cell in that column, HEADER cells centered, body cells
134
- // left-aligned, the whole table indented 2 -- no bold, no other styling on any row, verified
135
- // from the capture (`basic.capture.json`'s table has zero SGR bytes). Replaces the old
136
- // " │ "-joined, unbordered, bold-header rows this renderer invented with no capture to check
137
- // against.
138
- function _cellPad(text, width, align) {
139
- const total = Math.max(0, width - stringCellWidth(text));
140
- if (align === 'center') {
141
- const left = Math.floor(total / 2);
142
- return ' '.repeat(left) + text + ' '.repeat(total - left);
143
- }
144
- return text + ' '.repeat(total); // left-align
145
- }
146
-
147
- // WP-2 (reader-seam-duplicates): a table wider than the pane WRAPS its cells inside their own
148
- // columns instead of truncating the row. Claude itself wraps a wide cell (it never ellipsizes
149
- // one), so the re-drawn transcript and the live screen now agree. The fitting path below is
150
- // byte-identical to the pre-WP-2 emitter; only a table that does not fit takes the wrap path,
151
- // which sizes its columns through the Codex table module's own width allocator (rank cells by
152
- // kind, shrink the slackiest column first) rather than inventing a second policy.
128
+ // Tables: the layout is Claude Code 2.1.310's OWN (design
129
+ // docs/reader-claude-table-layout-parity-2026-10-25.html -- §3.1 the algorithm read from the
130
+ // binary, §5 the rules R-1..R-8, §9 this site). The port lives in lib/claude-table-layout.js; it
131
+ // decides the form (bordered box or stacked key-value cards), the column widths and every line
132
+ // break, and it was verified byte-identical against three live captures
133
+ // (tests/golden/claude-transcript/table-captures/). This function only renders the cells and
134
+ // prefixes the indent -- no local table policy, because any "nicer" table is content the live
135
+ // screen never had and the seam proof then refuses the join (R-1, R-7).
153
136
  function emitTable(token, cols, indent, style) {
154
- const headerPlain = (token.header || []).map((c) => inlineText(c.tokens));
155
- const headerStyled = (token.header || []).map((c) => emitInline(c.tokens, style));
156
- const bodyPlainRows = (token.rows || []).map((row) => row.map((c) => inlineText(c.tokens)));
157
- const bodyStyledRows = (token.rows || []).map((row) => row.map((c) => emitInline(c.tokens, style)));
158
- const colCount = headerPlain.length;
159
- const widths = [];
160
- for (let i = 0; i < colCount; i++) {
161
- let w = stringCellWidth(headerPlain[i] || '');
162
- for (const row of bodyPlainRows) w = Math.max(w, stringCellWidth(row[i] || ''));
163
- widths.push(w);
164
- }
137
+ // Cells are rendered through emitInline, so a link prints `label (href)` exactly like Claude's
138
+ // own `T()`; the port measures widths on that SGR-stripped rendering (R-3 -- never on
139
+ // inlineText, which drops the href and so under-measures every linked cell).
140
+ const header = (token.header || []).map((cell) => emitInline(cell.tokens, style));
141
+ const rows = (token.rows || []).map((row) => row.map((cell) => emitInline(cell.tokens, style)));
142
+ const layout = layoutClaudeTable({ header, rows, align: token.align }, cols);
143
+ // R-5: `cols` is the TERMINAL width; `indent` is a prefix on every row and is never subtracted
144
+ // from it. A bordered table is already inside `cols - 4`; the cards are re-wrapped a second
145
+ // time by Ink's box at `cols - indent` (D-5), which is what turns a 170-cell card line into the
146
+ // three painted rows of the tasks capture.
147
+ const lines = layout.kind === 'bordered'
148
+ ? layout.lines
149
+ : inkWrapLines(cardLines(layout, cols, style), cols - indent);
165
150
  const pad = ' '.repeat(indent);
166
- const budget = Math.max(1, cols - indent);
167
- const tableWidth = widths.reduce((sum, w) => sum + w, 0) + 3 * colCount + 1;
168
- if (tableWidth <= budget) {
169
- const emitRaw = (raw) => pad + closeRow(truncateToCells(raw, budget));
170
- const border = (left, mid, right) => emitRaw(left + widths.map((w) => '─'.repeat(w + 2)).join(mid) + right);
171
- const dataRow = (styledCells, align) => {
172
- const cells = widths.map((w, i) => ` ${_cellPad(styledCells[i] || '', w, align)} `);
173
- return emitRaw(`│${cells.join('│')}│`);
174
- };
175
- const rows = [border('┌', '┬', '┐'), dataRow(headerStyled, 'center')];
176
- for (const row of bodyStyledRows) {
177
- rows.push(border('├', '┼', '┤'));
178
- rows.push(dataRow(row, 'left'));
179
- }
180
- rows.push(border('└', '┴', '┘'));
181
- return rows;
182
- }
183
-
184
- // --- wrap path: the table does not fit, so wrap each cell inside its column ---
185
- const available = budget - (3 * colCount + 1);
186
- const metrics = collectColumnMetrics(headerPlain, bodyPlainRows, colCount, stringCellWidth);
187
- let wrapWidths = computeColumnWidths(metrics, available);
188
- // Null means even MIN_COLUMN_WIDTH (3) per column cannot fit: fall back to an even split (at
189
- // least one cell wide each) rather than dropping columns or truncating.
190
- if (!wrapWidths) wrapWidths = new Array(colCount).fill(Math.max(1, Math.floor(available / colCount)));
191
- const emitWrappedRaw = (raw) => pad + closeRow(raw);
192
- const wrapBorder = (left, mid, right) => emitWrappedRaw(left + wrapWidths.map((w) => '─'.repeat(w + 2)).join(mid) + right);
193
- const wrappedRows = (styledCells, align) => {
194
- const lines = wrapWidths.map((w, i) => wrapToCells(styledCells[i] || '', w));
195
- const height = lines.reduce((max, l) => Math.max(max, l.length), 1);
196
- const out = [];
197
- for (let k = 0; k < height; k++) {
198
- const cells = wrapWidths.map((w, i) => ` ${_cellPad(lines[i][k] || '', w, align)}${SPAN_OFF} `);
199
- out.push(emitWrappedRaw(`│${cells.join('│')}│`));
200
- }
201
- return out;
202
- };
203
- const rows = [wrapBorder('┌', '┬', '┐'), ...wrappedRows(headerStyled, 'center')];
204
- for (const row of bodyStyledRows) {
205
- rows.push(wrapBorder('├', '┼', '┤'));
206
- rows.push(...wrappedRows(row, 'left'));
207
- }
208
- rows.push(wrapBorder('└', '┴', '┘'));
209
- return rows;
151
+ return lines.map((line) => pad + closeRow(line));
210
152
  }
211
153
 
212
154
  function emitBlockquote(token, cols, depth, style) {
@@ -6,8 +6,12 @@
6
6
  // (this worktree), and is asserted by AC-0d (no `claude-agent-sdk` path ever appears in
7
7
  // require.cache after a require() or a call through the `sdk` DI seam).
8
8
  //
9
- // Both exported functions resolve; they never throw — callers get a uniform
9
+ // setClaudeSessionTitle resolves; it never throws — callers get a uniform
10
10
  // { state: 'mirrored'|'unsupported'|'failed', reason, error } outcome instead.
11
+ //
12
+ // WP-2 (D-6): the inbound half (readClaudeSessionTitle, an SDK getSessionInfo round-trip whose
13
+ // merged fields conflate CTM tiers) is deleted. The agent's own name now comes from the
14
+ // transcript records CTM already parses — lib/agent-title-apply.js.
11
15
 
12
16
  const { normalizeSessionTitle } = require('./session-title-signals');
13
17
 
@@ -66,32 +70,4 @@ async function setClaudeSessionTitle({ sessionId, title, dir, sdk } = {}) {
66
70
  }
67
71
  }
68
72
 
69
- async function readClaudeSessionTitle({ sessionId, dir, sdk } = {}) {
70
- let resolvedSdk = sdk;
71
- if (!resolvedSdk) {
72
- try {
73
- resolvedSdk = await _loadSdk();
74
- } catch (error) {
75
- // expected: SDK absent — read has nothing to report, caller treats null as "no data"
76
- void error;
77
- return null;
78
- }
79
- }
80
- let info;
81
- try {
82
- info = await resolvedSdk.getSessionInfo(sessionId, dir ? { dir } : undefined);
83
- } catch (error) {
84
- // expected: read is best-effort — any SDK failure maps to "no data" rather than a throw
85
- void error;
86
- return null;
87
- }
88
- if (!info) return null;
89
- const aiTitle = (!info.customTitle && info.summary && info.summary !== info.firstPrompt) ? info.summary : '';
90
- return {
91
- userName: info.customTitle || '',
92
- aiTitle,
93
- firstPrompt: info.firstPrompt || '',
94
- };
95
- }
96
-
97
- module.exports = { setClaudeSessionTitle, readClaudeSessionTitle, _resetSdkCacheForTests };
73
+ module.exports = { setClaudeSessionTitle, _resetSdkCacheForTests };
@@ -0,0 +1,322 @@
1
+ 'use strict';
2
+
3
+ // Port of Claude Code 2.1.310's Markdown-table layout, read from the installed CLI
4
+ // (the versioned CLI binary under the user's local Claude install, Mach-O arm64; the layout sits at byte
5
+ // offset ~= 243,694,000, the `kind:"vertical"` literal: functions jr / Q / Z / Y / _t / ce,
6
+ // constants Ke=4 _e=3 as=4 Or=200). Design: docs/reader-claude-table-layout-parity-2026-10-25.html
7
+ // §3.1 (the algorithm) and §5 (rules R-1..R-8).
8
+ //
9
+ // WHY THIS EXISTS: the reader re-draws a Claude transcript into rows and then proves the seam
10
+ // against what the live terminal painted. A table the transcript renderer draws differently from
11
+ // the TUI is content the screen never had, and the proof refuses (dup rows / an overlap). So this
12
+ // module reproduces Claude's own layout EXACTLY -- same branch choice, same column widths, same
13
+ // line breaks, same glyphs, same fallback to the stacked key-value "cards", quirks included
14
+ // (R-6: floor rounding in the proportional branch, `max(floor(E*C/W), 3)` in the hard branch,
15
+ // the `> 4` wrapped-line rule, `floor` vertical centring, the 200-row cap). No "improvement" here
16
+ // is a fix; every deviation is a bug (R-1).
17
+ //
18
+ // TWO FORMS: `bordered` (the box, lines carry NO indent and never exceed cols - 4) and `cards`
19
+ // (the vertical key-value form, re-wrapped a second time by Ink's box: see inkWrapLines). The
20
+ // caller (lib/claude-markdown-ansi.js emitTable) prefixes the 2-column message indent and closes
21
+ // each row; `cols` is the TERMINAL width and the indent is never subtracted from it (R-5).
22
+ //
23
+ // VERIFIED against three live captures (golden fixtures under
24
+ // tests/golden/claude-transcript/table-captures/, reproduced byte-for-byte by
25
+ // tests/claude-table-captures.test.js):
26
+ // lid-options-196 -- session 6ea59930 painted rows 4192-4197, cols 196, hard branch -> cards
27
+ // tasks-steps-171 -- session 3320adc3 painted rows 493-517, cols 171, proportional -> cards
28
+ // (the 170-cell card line re-wrapped at 169 by Ink's box)
29
+ // inject-ways-196 -- session 7cf57222 painted rows 8396-8408, cols 196, proportional -> bordered
30
+ // There is no runtime switch on the Claude version (R-8): drift is caught by those fixtures.
31
+
32
+ const { stringCellWidth } = require('./terminal-cell-width');
33
+
34
+ // wrap-ansi is ESM-only; Node's require(esm) (>= 22.12, the pinned 25.2.1 here) hands back the
35
+ // namespace, so `.default` is the function. Loaded ONCE at module top (D-4).
36
+ const wrapAnsiModule = require('wrap-ansi');
37
+ const wrapAnsi = wrapAnsiModule.default || wrapAnsiModule;
38
+
39
+ // Claude's own constants, by their de-minified names (Ke / _e / as / Or) plus the rule cap and
40
+ // the version/offset the port was read from (R-8).
41
+ const CLAUDE_TABLE = Object.freeze({
42
+ MARGIN: 4, // Ke: a bordered table must fit inside cols - 4
43
+ MIN_COL: 3, // _e: never allocate less than 3 columns to a cell
44
+ MAX_CELL_LINES: 4, // as: a cell wrapping to MORE lines than this sends the table to cards
45
+ MAX_ROWS: 200, // Or: rows beyond this are dropped and announced
46
+ RULE_MAX: 40, // the card separator is '─'.repeat(min(cols - 1, 40))
47
+ VERSION: '2.1.310',
48
+ });
49
+
50
+ const SGR_RE = /\x1b\[[0-9;?]*[ -\/]*[@-~]/g;
51
+
52
+ function stripSgr(text) {
53
+ return String(text == null ? '' : text).replace(SGR_RE, '');
54
+ }
55
+
56
+ /**
57
+ * Claude's `ce(text, width, {hard})`: wrap-ansi with `trimEnd()` first, `{hard, trim:false,
58
+ * wordWrap:true}`, empty lines dropped, `['']` when nothing is left. `width <= 0` returns the
59
+ * text untouched (Claude's own early return).
60
+ */
61
+ function wrapCell(text, width, hard) {
62
+ const source = String(text == null ? '' : text);
63
+ if (width <= 0) return [source];
64
+ const lines = wrapAnsi(source.trimEnd(), width, { hard: !!hard, trim: false, wordWrap: true })
65
+ .split('\n')
66
+ .filter((line) => line.length > 0);
67
+ return lines.length > 0 ? carryExtendedColour(lines) : [''];
68
+ }
69
+
70
+ // wrap-ansi closes bold / italic / strike and the 16 basic colours at its own line break and re-opens
71
+ // them on the next line, but it has no closer for an EXTENDED colour selector (`38;5;n`, `38;2;r;g;b`):
72
+ // a coloured span that wraps inside a cell stays open past the cell's `│` and paints the border and
73
+ // the neighbouring cell. The live screen never does that -- painted-rows census 2026-10-26: 556 of
74
+ // 556 bordered rows carrying a 256-colour span close it before every border (Ink styles each text
75
+ // node on its own) -- so carry the colour across the break exactly the way wrap-ansi carries the
76
+ // other attributes: close it (`39`) at the end of the line, re-open it at the start of the next.
77
+ function carryExtendedColour(lines) {
78
+ let open = null;
79
+ return lines.map((line) => {
80
+ const prefix = open || '';
81
+ for (const m of line.matchAll(/\x1b\[([0-9;]*)m/g)) {
82
+ const codes = m[1] === '' ? [0] : m[1].split(';').map(Number);
83
+ for (let i = 0; i < codes.length; i += 1) {
84
+ const code = codes[i];
85
+ if (code === 38 && codes[i + 1] === 5) { open = `\x1b[38;5;${codes[i + 2]}m`; i += 2; }
86
+ else if (code === 38 && codes[i + 1] === 2) { open = `\x1b[38;2;${codes.slice(i + 2, i + 5).join(';')}m`; i += 4; }
87
+ else if (code === 0 || code === 39 || (code >= 30 && code <= 37) || (code >= 90 && code <= 97)) open = null;
88
+ }
89
+ }
90
+ return prefix + line + (open ? '\x1b[39m' : '');
91
+ });
92
+ }
93
+
94
+ // Claude's `bgr(text, width, align)` -- pad by VISIBLE width. `center` puts the odd space on the
95
+ // right (floor on the left), `right` pads all on the left, `left` all on the right.
96
+ function pad(text, width, align, strWidth) {
97
+ const total = Math.max(0, width - strWidth(stripSgr(text)));
98
+ if (align === 'center') {
99
+ const left = Math.floor(total / 2);
100
+ return ' '.repeat(left) + text + ' '.repeat(total - left);
101
+ }
102
+ if (align === 'right') return ' '.repeat(total) + text;
103
+ return text + ' '.repeat(total);
104
+ }
105
+
106
+ /**
107
+ * Lay a table out exactly as Claude Code 2.1.310 does.
108
+ *
109
+ * header: ANSI-rendered header cells (emitInline output) rows: ANSI-rendered body cells
110
+ * align: ('left'|'center'|'right'|null)[] cols: terminal columns (p)
111
+ *
112
+ * Returns the layout DECISION, never the indented rows:
113
+ * { kind:'bordered', widths, hard, branch:'natural'|'proportional'|'hard', lines }
114
+ * -- lines carry no indent; the widest is <= cols - 4
115
+ * { kind:'cards', branch, reason:'cellLines'|'tooWide'|'headerOnly', headers, rows, truncated }
116
+ * -- the vertical form's inputs, before Ink's box wrap (see cardLines/inkWrapLines)
117
+ */
118
+ function layoutClaudeTable({ header, rows, align } = {}, cols, { strWidth = stringCellWidth } = {}) {
119
+ const p = Number(cols) || 0;
120
+ const headerCells = (header || []).map((cell) => String(cell == null ? '' : cell));
121
+ const everyRow = (rows || []).map((row) => (row || []).map((cell) => String(cell == null ? '' : cell)));
122
+ const truncated = Math.max(0, everyRow.length - CLAUDE_TABLE.MAX_ROWS);
123
+ const bodyRows = truncated > 0 ? everyRow.slice(0, CLAUDE_TABLE.MAX_ROWS) : everyRow;
124
+
125
+ const K = headerCells.length;
126
+ if (K === 0) return { kind: 'bordered', widths: [], hard: false, branch: 'natural', lines: [] };
127
+
128
+ // R-3: widths come from the SGR-stripped RENDERED cell (a link counts as `label (href)`).
129
+ // E[c] = the widest whitespace-separated word, H[c] = the widest whole cell, both floored at 3.
130
+ const wordWidth = (cell) => {
131
+ const words = stripSgr(cell).split(/\s+/).filter((word) => word.length > 0);
132
+ if (words.length === 0) return CLAUDE_TABLE.MIN_COL;
133
+ let widest = CLAUDE_TABLE.MIN_COL;
134
+ for (const word of words) widest = Math.max(widest, strWidth(word));
135
+ return widest;
136
+ };
137
+ const cellWidth = (cell) => Math.max(strWidth(stripSgr(cell)), CLAUDE_TABLE.MIN_COL);
138
+
139
+ const E = headerCells.map((cell, i) => {
140
+ let width = wordWidth(cell);
141
+ for (const row of bodyRows) width = Math.max(width, wordWidth(row[i] || ''));
142
+ return width;
143
+ });
144
+ const H = headerCells.map((cell, i) => {
145
+ let width = cellWidth(cell);
146
+ for (const row of bodyRows) width = Math.max(width, cellWidth(row[i] || ''));
147
+ return width;
148
+ });
149
+
150
+ const M = 1 + 3 * K;
151
+ const C = Math.max(p - M - CLAUDE_TABLE.MARGIN, K * CLAUDE_TABLE.MIN_COL);
152
+ const W = E.reduce((sum, w) => sum + w, 0);
153
+ const z = H.reduce((sum, w) => sum + w, 0);
154
+
155
+ let hard = false;
156
+ let branch;
157
+ let D;
158
+ if (z <= C) {
159
+ D = H;
160
+ branch = 'natural';
161
+ } else if (W <= C) {
162
+ // Proportional: hand out the slack in proportion to each column's (natural - minimum) want,
163
+ // floored (R-6: Claude floors, it does not round).
164
+ branch = 'proportional';
165
+ const slack = C - W;
166
+ const want = H.map((w, i) => w - E[i]);
167
+ const U = want.reduce((sum, w) => sum + w, 0);
168
+ D = E.map((w, i) => (U === 0 ? w : w + Math.floor((want[i] / U) * slack)));
169
+ } else {
170
+ // Hard: scale every minimum by C/W, never below 3.
171
+ branch = 'hard';
172
+ hard = true;
173
+ const ratio = C / W;
174
+ D = E.map((w) => Math.max(Math.floor(w * ratio), CLAUDE_TABLE.MIN_COL));
175
+ }
176
+
177
+ // > 4 wrapped lines anywhere -> the whole table becomes cards.
178
+ let maxLines = 1;
179
+ for (let i = 0; i < K; i += 1) maxLines = Math.max(maxLines, wrapCell(headerCells[i], D[i], hard).length);
180
+ for (const row of bodyRows) {
181
+ for (let i = 0; i < row.length; i += 1) maxLines = Math.max(maxLines, wrapCell(row[i] || '', D[i], hard).length);
182
+ }
183
+
184
+ // The vertical form's inputs: a header-only table has no labels and its one row is the header
185
+ // (so it draws as unlabeled lines). `headerOnly` names that shape; the bordered attempt still
186
+ // runs first, exactly as Claude's does (a header-only table that fits stays a box).
187
+ const cards = (cause) => ({
188
+ kind: 'cards',
189
+ branch,
190
+ reason: bodyRows.length === 0 ? 'headerOnly' : cause,
191
+ headers: bodyRows.length === 0 ? [] : headerCells.map((cell) => stripSgr(cell).trim()),
192
+ rows: (bodyRows.length === 0 ? [headerCells] : bodyRows).map((row) => row.slice()),
193
+ truncated,
194
+ });
195
+ if (maxLines > CLAUDE_TABLE.MAX_CELL_LINES) return cards('cellLines');
196
+
197
+ const border = (kind) => {
198
+ const [left, bar, join, right] = {
199
+ top: ['┌', '─', '┬', '┐'],
200
+ middle: ['├', '─', '┼', '┤'],
201
+ bottom: ['└', '─', '┴', '┘'],
202
+ }[kind];
203
+ let line = left;
204
+ D.forEach((width, i) => {
205
+ line += bar.repeat(width + 2);
206
+ line += i < D.length - 1 ? join : right;
207
+ });
208
+ return line;
209
+ };
210
+
211
+ // One table row -> its bordered lines. Cells are vertically centred with floor((G - n)/2).
212
+ // Header cells are centred; body cells follow `align[c] ?? 'left'` (both Claude's rules).
213
+ const drawRow = (cells, isHeader) => {
214
+ const lines = cells.map((cell, i) => wrapCell(cell || '', D[i], hard));
215
+ const height = Math.max(...lines.map((l) => l.length), 1);
216
+ const off = lines.map((l) => Math.floor((height - l.length) / 2));
217
+ const out = [];
218
+ for (let r = 0; r < height; r += 1) {
219
+ let row = '│';
220
+ for (let c = 0; c < cells.length; c += 1) {
221
+ const idx = r - off[c];
222
+ const text = idx >= 0 && idx < lines[c].length ? lines[c][idx] : '';
223
+ row += ` ${pad(text, D[c], isHeader ? 'center' : ((align && align[c]) || 'left'), strWidth)} │`;
224
+ }
225
+ out.push(row);
226
+ }
227
+ return out;
228
+ };
229
+
230
+ const lines = [border('top'), ...drawRow(headerCells, true), border('middle')];
231
+ bodyRows.forEach((row, i) => {
232
+ lines.push(...drawRow(row, false));
233
+ if (i < bodyRows.length - 1) lines.push(border('middle'));
234
+ });
235
+ lines.push(border('bottom'));
236
+
237
+ let widest = 0;
238
+ for (const line of lines) widest = Math.max(widest, strWidth(stripSgr(line)));
239
+ if (widest > p - CLAUDE_TABLE.MARGIN) return cards('tooWide');
240
+
241
+ if (truncated > 0) lines.push(notShown(truncated));
242
+ return { kind: 'bordered', widths: D, hard, branch, lines };
243
+ }
244
+
245
+ // Claude's `lt(n)`: the 200-row cap's footnote.
246
+ function notShown(count) {
247
+ return `… ${count.toLocaleString()} more ${count === 1 ? 'row' : 'rows'} not shown`;
248
+ }
249
+
250
+ /**
251
+ * The vertical form, before Ink's box wrap: one `Bold Header: value` line per non-empty cell,
252
+ * continuation lines verbatim, a `─`.repeat(min(cols - 1, 40)) rule BETWEEN cards only (never
253
+ * before the first, never after the last). `style.bold`/`style.boldOff` label the key (Claude
254
+ * paints `\x1b[1m`…`\x1b[22m`).
255
+ */
256
+ function cardLines(layout, cols, style) {
257
+ const m = Number(cols) || 0;
258
+ const out = [];
259
+ const rule = '─'.repeat(Math.max(0, Math.min(m - 1, CLAUDE_TABLE.RULE_MAX)));
260
+ const headers = (layout && layout.headers) || [];
261
+ for (const row of (layout && layout.rows) || []) {
262
+ const lines = [];
263
+ row.forEach((cell, i) => {
264
+ const label = headers[i] || '';
265
+ // Claude flattens the cell to one line for the FIRST line, then re-wraps the rest.
266
+ const flat = String(cell == null ? '' : cell)
267
+ .trimEnd()
268
+ .replace(/\n+/g, ' ')
269
+ .replace(/\s+/g, ' ')
270
+ .trim();
271
+ if (!label && !flat) return; // an unlabeled empty cell prints nothing at all
272
+ const firstWidth = label ? m - stringCellWidth(label) - 3 : m - 1;
273
+ const contWidth = m - 3;
274
+ const wrapped = wrapCell(flat, Math.max(firstWidth, 10), false);
275
+ const head = wrapped[0] || '';
276
+ const rest = wrapped.length <= 1
277
+ ? wrapped
278
+ : [head, ...wrapCell(wrapped.slice(1).map((line) => line.trim()).join(' '), contWidth, false)];
279
+ lines.push(label
280
+ ? `${styleSpanText(`${label}:`, style)} ${rest[0] || ''}`
281
+ : (rest[0] || ''));
282
+ for (let d = 1; d < rest.length; d += 1) {
283
+ if (!rest[d].trim()) continue;
284
+ lines.push(rest[d]);
285
+ }
286
+ });
287
+ if (!lines.length) continue;
288
+ if (out.length) out.push(rule);
289
+ out.push(...lines);
290
+ }
291
+ if (layout && layout.truncated > 0) {
292
+ if (out.length) out.push(rule);
293
+ out.push(notShown(layout.truncated));
294
+ }
295
+ return out;
296
+ }
297
+
298
+ // The card label's own span: open with `style.bold`, close with `style.boldOff` (never a blanket
299
+ // reset, so a caller's surrounding style survives). Kept local so this module stays pure.
300
+ function styleSpanText(text, style) {
301
+ const open = (style && style.bold) || [];
302
+ const close = (style && style.boldOff) || [];
303
+ const openCodes = (Array.isArray(open) ? open : [open]).filter((c) => c !== undefined && c !== null && c !== '');
304
+ if (!openCodes.length) return text;
305
+ const closeCodes = (Array.isArray(close) ? close : [close]).filter((c) => c !== undefined && c !== null && c !== '');
306
+ return `\x1b[${openCodes.join(';')}m${text}${closeCodes.length ? `\x1b[${closeCodes.join(';')}m` : ''}`;
307
+ }
308
+
309
+ /**
310
+ * Ink's `<Text wrap="wrap">` inside the 2-column message box: every line is re-wrapped with
311
+ * `wrapAnsi(line, boxWidth, {trim:false, hard:true})` and split on '\n' (D-5 -- observed: the
312
+ * tasks capture's 170-cell card line breaks at 169 into `…rubric` / `and` / `0.60 threshold`).
313
+ */
314
+ function inkWrapLines(lines, boxWidth) {
315
+ const out = [];
316
+ for (const line of lines || []) {
317
+ out.push(...wrapAnsi(String(line == null ? '' : line), boxWidth, { trim: false, hard: true }).split('\n'));
318
+ }
319
+ return out;
320
+ }
321
+
322
+ module.exports = { CLAUDE_TABLE, wrapCell, layoutClaudeTable, cardLines, inkWrapLines };
@@ -137,6 +137,11 @@ function createClientDiagHandler(deps = {}) {
137
137
  toCols: nonNegInt(d.toCols),
138
138
  widthPx: nonNegInt(d.widthPx),
139
139
  reason: typeof d.reason === 'string' ? d.reason.slice(0, 40) : '',
140
+ // WP-2 (docs/codex-terminal-geometry-sticky-cols-2026-10-24.html §5): the two
141
+ // layout facts that make an adoption explainable -- browser viewport width and whether
142
+ // split view was on. Whitelisted here or the beacon's producer fields would be dropped.
143
+ viewportWidthPx: nonNegInt(d.viewportWidthPx),
144
+ split: d.split === true,
140
145
  });
141
146
  return;
142
147
  }
@@ -105,20 +105,50 @@ function buildCodexTransportOverrideArgs(names, opts = {}) {
105
105
  return out;
106
106
  }
107
107
 
108
- // Read CODEX_HOME/config.toml and return the override args (best-effort: unreadable/missing → []).
109
- function codexMcpTransportGuardArgs(codexHome, opts = {}) {
108
+ // Read CODEX_HOME/config.toml (best-effort: unreadable/missing → null). The one sync read both
109
+ // guards share; it is the ledgered main-thread site (docs/main-thread-sync-baseline.json).
110
+ function readCodexConfigToml(codexHome) {
110
111
  let text;
111
112
  try {
112
113
  text = fs.readFileSync(path.join(codexHome || '', 'config.toml'), 'utf8');
113
114
  } catch {
114
- return [];
115
+ return null;
115
116
  }
117
+ return text;
118
+ }
119
+
120
+ // Return the override args (unreadable/missing config → []).
121
+ function codexMcpTransportGuardArgs(codexHome, opts = {}) {
122
+ const text = readCodexConfigToml(codexHome);
123
+ if (text === null) return [];
116
124
  return buildCodexTransportOverrideArgs(findTransportlessMcpServers(text), opts);
117
125
  }
118
126
 
127
+ // WP-1 (codex-routed-fork-cold-restore-guard-2026-10-22.html §5 D-2, §9 S-5): the ids a native
128
+ // `codex` config load resolves through `model_providers.get(id)` — Codex merges its built-in
129
+ // providers with this user table. Only the TABLE HEADERS are needed (the values are irrelevant to
130
+ // servability), so this is a line scan, not a TOML parse: `[model_providers.<id>]` and its
131
+ // sub-tables (`[model_providers.<id>.http_headers]`) both name the provider `<id>`; text before a
132
+ // `[model_providers]` header (or after a different table) is never attributed to it. Best-effort
133
+ // exactly like the transport guard: a missing/unreadable config is an empty set, never a throw.
134
+ // `codexHome` is the CODEX_HOME directory (the one that holds config.toml).
135
+ function readModelProviderKeys(codexHome) {
136
+ const text = readCodexConfigToml(codexHome);
137
+ if (text === null) return [];
138
+ const out = [];
139
+ for (const line of String(text || '').split(/\r?\n/)) {
140
+ const segs = _tableHeaderSegments(line);
141
+ if (!segs || segs.length < 2 || _unquote(segs[0]) !== 'model_providers') continue;
142
+ const key = _unquote(segs[1]);
143
+ if (key) out.push(key);
144
+ }
145
+ return [...new Set(out)];
146
+ }
147
+
119
148
  module.exports = {
120
149
  INERT_COMMAND,
121
150
  findTransportlessMcpServers,
122
151
  buildCodexTransportOverrideArgs,
123
152
  codexMcpTransportGuardArgs,
153
+ readModelProviderKeys,
124
154
  };
@@ -43,6 +43,17 @@ const CODEX_CONTROL_ADAPTER = 'codex-app-server-q1';
43
43
  const CODEX_COMPACTION_SCHEMA_RECEIPT = 'codex-model-info-comp-hash-nullable-q1';
44
44
  const CODEX_PRE_TURN_COMPACTION_SCHEMA = 'codex-pre-turn-compaction-q1';
45
45
 
46
+ // Codex's turn_context `cyber_access_program` (protocol/src/turn_input.rs @ rust-v0.163.0) is
47
+ // `standard` when the account's catalog advertises access programs and Daybreak is off
48
+ // (tui/src/daybreak.rs program_for_turn), and core drops any program for a non-OpenAI provider
49
+ // (core/src/cyber_access_program.rs for_provider). Only these values carry no elevated access, so
50
+ // only they may cross to a routed target; daybreak_* and unknown values stay unqualified.
51
+ const NON_ELEVATED_CYBER_ACCESS_PROGRAMS = Object.freeze([null, 'standard']);
52
+
53
+ function isNonElevatedCyberAccessProgram(value) {
54
+ return NON_ELEVATED_CYBER_ACCESS_PROGRAMS.includes(value);
55
+ }
56
+
46
57
  // Exact membership (D-4). Never a prefix/range match: '0.162.10' is not '0.162.1'.
47
58
  function isQualifiedCodexVersion(version) {
48
59
  return typeof version === 'string' && Object.hasOwn(CODEX_QUALIFIED_VERSIONS, version);
@@ -67,5 +78,6 @@ module.exports = {
67
78
  CODEX_COMPACTION_SCHEMA_RECEIPT,
68
79
  CODEX_PRE_TURN_COMPACTION_SCHEMA,
69
80
  isQualifiedCodexVersion,
81
+ isNonElevatedCyberAccessProgram,
70
82
  codexQualification,
71
83
  };