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
@@ -0,0 +1,391 @@
1
+ // public/m/pool-failover.js — WP-6 P-7 (docs/machine-pool-picker-pairing-dashboard-2026-10-24.html
2
+ // §5 P-7, §6.4 "rev 2 P-7 phone pool", §8 WP-6, §9 S-26).
3
+ //
4
+ // The phone signs in (passkey) once per member origin, so passkeys — and the per-origin outbox — are
5
+ // pinned to a hostname. When the origin the phone is on stops answering, this module probes the other
6
+ // pool members' public origins with an opaque `fetch(origin + '/m/manifest.json', {mode:'no-cors'})`
7
+ // and sends the browser to the first that answers, carrying `?poolFrom=<this instance>` so the
8
+ // receiving member can say who it took over from (P-7).
9
+ //
10
+ // It is a classic script, loaded by public/m/index.html BEFORE /m/app.js and listed in sw.js
11
+ // SHELL_ASSETS, because the whole point is that it runs while the app's own API is unreachable.
12
+ //
13
+ // * localStorage holds ONLY the dial cache `ctm.pool.origins`
14
+ // ([{ instanceId, displayName, origin, lastState, lastSeenAt }], last-reached first) and the
15
+ // content-free presence marker `ctm.pool.outboxPending` ('1' while app.js has queued outbox
16
+ // entries, absent otherwise — see below). Never a secret, never a token, never an entry, never a
17
+ // machine setting (D-4: settings live on the machine).
18
+ // * Every dependency is injectable (storage, location, fetch, confirm, setTimeout/clearTimeout,
19
+ // AbortController, clock, DOM host), so both the boot-failure path and the banner are provable
20
+ // without a browser. Nothing here reads Date.now() on a path a test drives: `now` is injected.
21
+ // * Every storage access is wrapped: a private-mode or blocked localStorage returns the empty dial
22
+ // cache and boot continues, it never throws.
23
+ (function (root) {
24
+ 'use strict';
25
+
26
+ var POOL_ORIGINS_KEY = 'ctm.pool.origins';
27
+ // P-7 boot seam. The outbox itself is private: it lives behind the private lease (IndexedDB plus a
28
+ // leased localStorage mirror), and the boot-failure path runs BEFORE any lease exists — so it cannot
29
+ // read the queue and `state.remoteOutbox` is always empty there. app.js therefore mirrors ONLY the
30
+ // queue's presence into plain window.localStorage: this one key, the string '1' while entries are
31
+ // queued, and no key at all the moment the queue empties. Never an entry, an id, a count, a command
32
+ // or a principal — a boolean's worth of state, which is exactly what P-7's "ask before leaving an
33
+ // origin that still holds unsent messages" prompt needs.
34
+ var POOL_OUTBOX_PENDING_KEY = 'ctm.pool.outboxPending';
35
+ var PROBE_PATH = '/m/manifest.json';
36
+ var PROBE_TIMEOUT_MS = 4000;
37
+ var BANNER_ID = 'pool-from-banner';
38
+ // A pool is 2-20 of the user's own machines (design §2). The cache is capped so a runaway roster
39
+ // can never fill the 5 MB localStorage quota the outbox also lives in.
40
+ var ORIGINS_MAX = 24;
41
+
42
+ function trims(value) {
43
+ return String(value == null ? '' : value).trim();
44
+ }
45
+
46
+ // The one escaper. This module deliberately does not depend on the app's escAbsent esc: it runs in
47
+ // the shell before app.js and inside a vm test.
48
+ function poolEsc(value) {
49
+ return String(value == null ? '' : value).replace(/[&<>"']/g, function (ch) {
50
+ return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[ch];
51
+ });
52
+ }
53
+
54
+ // A public origin: scheme + host (+ port), no path, no trailing slash. Anything that is not http(s)
55
+ // is not a dial target (a blob:/data: URL would be a bug, not a member).
56
+ function normalizePoolOrigin(value) {
57
+ var raw = trims(value).replace(/\/+$/, '');
58
+ if (!/^https?:\/\/[^/?#]+/i.test(raw)) return '';
59
+ var match = raw.match(/^(https?:\/\/[^/?#]+)/i);
60
+ return match ? match[1] : '';
61
+ }
62
+
63
+ // One stored row, or null. Exactly the five documented fields — a row that carries anything else
64
+ // (a token, a secret, a session id) is rebuilt from the five, so nothing extra is ever re-persisted.
65
+ function normalizePoolOriginRow(row) {
66
+ if (!row || typeof row !== 'object') return null;
67
+ var origin = normalizePoolOrigin(row.origin);
68
+ if (!origin) return null;
69
+ return {
70
+ instanceId: trims(row.instanceId),
71
+ displayName: trims(row.displayName),
72
+ origin: origin,
73
+ lastState: trims(row.lastState),
74
+ lastSeenAt: Number(row.lastSeenAt) || 0,
75
+ };
76
+ }
77
+
78
+ function poolStorage(storage) {
79
+ if (storage) return storage;
80
+ try {
81
+ return typeof localStorage !== 'undefined' ? localStorage : null;
82
+ } catch (error) {
83
+ return null; // expected: a blocked/opaque context throws on the localStorage getter itself
84
+ }
85
+ }
86
+
87
+ function readPoolOrigins(storage) {
88
+ var store = poolStorage(storage);
89
+ if (!store || typeof store.getItem !== 'function') return [];
90
+ var raw = null;
91
+ try {
92
+ raw = store.getItem(POOL_ORIGINS_KEY);
93
+ } catch (error) {
94
+ return []; // HANDLE: private mode / blocked storage — the dial cache is optional, boot continues
95
+ }
96
+ if (!raw) return [];
97
+ var parsed = null;
98
+ try {
99
+ parsed = JSON.parse(raw);
100
+ } catch (error) {
101
+ return []; // HANDLE: a corrupted cache is dropped, never fatal — the phone boots with no roster
102
+ }
103
+ if (!Array.isArray(parsed)) return [];
104
+ return parsed.map(normalizePoolOriginRow).filter(Boolean).slice(0, ORIGINS_MAX);
105
+ }
106
+
107
+ function writePoolOrigins(storage, rows) {
108
+ var store = poolStorage(storage);
109
+ if (!store || typeof store.setItem !== 'function') return false;
110
+ var clean = (Array.isArray(rows) ? rows : []).map(normalizePoolOriginRow).filter(Boolean).slice(0, ORIGINS_MAX);
111
+ try {
112
+ store.setItem(POOL_ORIGINS_KEY, JSON.stringify(clean));
113
+ } catch (error) {
114
+ return false; // REPORT: quota/blocked storage — the caller keeps the in-memory rows it just built
115
+ }
116
+ return true;
117
+ }
118
+
119
+ // P-7 boot seam, read half: is there anything queued on this origin? `true` only for the presence
120
+ // marker app.js writes; a missing key, a blocked storage or a corrupted value all mean "nothing
121
+ // queued" so the caller can fall through to the ordinary boot. Storage is injectable.
122
+ function readOutboxPendingMarker(storage) {
123
+ var store = poolStorage(storage);
124
+ if (!store || typeof store.getItem !== 'function') return false;
125
+ var raw = null;
126
+ try {
127
+ raw = store.getItem(POOL_OUTBOX_PENDING_KEY);
128
+ } catch (error) {
129
+ return false; // HANDLE: private mode / blocked storage — boot continues as if nothing is queued
130
+ }
131
+ return String(raw) === '1';
132
+ }
133
+
134
+ // P-7 boot seam, write half: presence only — '1' while `pending`, the key removed when not. Called
135
+ // from every app.js outbox persist and from every path that clears the queue.
136
+ function writeOutboxPendingMarker(storage, pending) {
137
+ var store = poolStorage(storage);
138
+ if (!store) return false;
139
+ try {
140
+ if (pending) {
141
+ if (typeof store.setItem !== 'function') return false;
142
+ store.setItem(POOL_OUTBOX_PENDING_KEY, '1');
143
+ } else {
144
+ if (typeof store.removeItem !== 'function') return false;
145
+ store.removeItem(POOL_OUTBOX_PENDING_KEY);
146
+ }
147
+ } catch (error) {
148
+ return false; // HANDLE: quota / blocked storage — the marker is an optimisation, never fatal
149
+ }
150
+ return true;
151
+ }
152
+
153
+ // P-7: called after every successful phone /api/machines load. THIS origin is the one just reached,
154
+ // so it is stamped `now` (and therefore sorts first: "last reached, then the next reachable"); every
155
+ // other member keeps the lastSeenAt it already had. `self` is the phone's own manifest/machine-self
156
+ // row — used for the display name only, never for a credential.
157
+ function rememberPoolOrigins(machines, self, deps) {
158
+ var options = deps || {};
159
+ var at = Number(typeof options.now === 'function' ? options.now() : Date.now()) || 0;
160
+ var store = poolStorage(options.storage);
161
+ var previous = readPoolOrigins(store);
162
+ var selfId = trims((self && self.instanceId) || options.selfInstanceId);
163
+ var selfName = trims(self && (self.displayName || self.hostname));
164
+ var selfOrigin = normalizePoolOrigin((self && machinePoolOrigin(self)) || options.origin || '');
165
+ var reachable = {};
166
+ var rows = [];
167
+ var push = function (row) {
168
+ var clean = normalizePoolOriginRow(row);
169
+ if (!clean || reachable[clean.origin]) return;
170
+ reachable[clean.origin] = true;
171
+ rows.push(clean);
172
+ };
173
+ var lastSeenFor = function (origin) {
174
+ var found = previous.filter(function (row) { return row.origin === origin; })[0];
175
+ return found ? found.lastSeenAt : 0;
176
+ };
177
+ if (selfOrigin) {
178
+ push({ instanceId: selfId, displayName: selfName, origin: selfOrigin, lastState: trims(self && self.health) || 'reachable', lastSeenAt: at });
179
+ }
180
+ (Array.isArray(machines) ? machines : []).forEach(function (machine) {
181
+ if (!machine || !machine.instanceId) return;
182
+ var origin = typeof machinePoolOrigin === 'function' ? machinePoolOrigin(machine) : '';
183
+ if (!origin) return;
184
+ push({
185
+ instanceId: trims(machine.instanceId),
186
+ displayName: trims(machine.displayName || machine.hostname || machine.url),
187
+ origin: origin,
188
+ lastState: trims(machine.health) || 'unknown',
189
+ lastSeenAt: lastSeenFor(origin),
190
+ });
191
+ });
192
+ rows.sort(function (a, b) {
193
+ return (b.lastSeenAt - a.lastSeenAt) || a.displayName.localeCompare(b.displayName) || a.origin.localeCompare(b.origin);
194
+ });
195
+ writePoolOrigins(store, rows);
196
+ return rows;
197
+ }
198
+
199
+ // P-7: `fetch(origin + '/m/manifest.json', { mode:'no-cors', cache:'no-store' })` with an
200
+ // AbortController timeout. An OPAQUE response (type 'opaque') is the reachable signal: a cross-origin
201
+ // no-cors read can never expose a status, and a request that resolved at all proves the origin
202
+ // answered. A rejection, a synchronous throw, or the timeout is `false` — never a throw.
203
+ function probeOrigin(origin, options) {
204
+ var settings = options || {};
205
+ var base = normalizePoolOrigin(origin);
206
+ if (!base) return Promise.resolve(false);
207
+ var fetchImpl = settings.fetchImpl || (typeof fetch === 'function' ? fetch : null);
208
+ if (typeof fetchImpl !== 'function') return Promise.resolve(false);
209
+ var setTimer = settings.setTimeoutImpl || (typeof setTimeout === 'function' ? setTimeout : null);
210
+ var clearTimer = settings.clearTimeoutImpl || (typeof clearTimeout === 'function' ? clearTimeout : null);
211
+ var AbortCtor = settings.AbortControllerImpl || (typeof AbortController === 'function' ? AbortController : null);
212
+ var timeoutMs = Number(settings.timeoutMs == null ? PROBE_TIMEOUT_MS : settings.timeoutMs);
213
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) timeoutMs = PROBE_TIMEOUT_MS;
214
+ var controller = AbortCtor ? new AbortCtor() : null;
215
+ return new Promise(function (resolve) {
216
+ var settled = false;
217
+ var timer = null;
218
+ var finish = function (ok) {
219
+ if (settled) return;
220
+ settled = true;
221
+ if (timer != null && typeof clearTimer === 'function') clearTimer(timer);
222
+ resolve(!!ok);
223
+ };
224
+ if (typeof setTimer === 'function') {
225
+ timer = setTimer(function () {
226
+ // The probe is cut at the timeout: an unresolved fetch is not evidence the origin is up.
227
+ try {
228
+ if (controller && typeof controller.abort === 'function') controller.abort();
229
+ } catch (error) {
230
+ /* expected: aborting a request that already settled is a no-op */
231
+ }
232
+ finish(false);
233
+ }, timeoutMs);
234
+ }
235
+ var request = null;
236
+ try {
237
+ request = fetchImpl(base + PROBE_PATH, {
238
+ mode: 'no-cors',
239
+ cache: 'no-store',
240
+ signal: controller ? controller.signal : undefined,
241
+ });
242
+ } catch (error) {
243
+ finish(false); // HANDLE: a synchronous fetch throw (blocked URL, no CORS) is "not reachable"
244
+ return;
245
+ }
246
+ Promise.resolve(request).then(function (res) {
247
+ // No status is readable through an opaque response, so "it resolved" is the whole signal.
248
+ finish(!!res);
249
+ }, function () {
250
+ finish(false); // HANDLE: a network error is exactly "this member does not answer"
251
+ });
252
+ });
253
+ }
254
+
255
+ function poolOriginsListHtml(rows) {
256
+ var items = (Array.isArray(rows) ? rows : []).map(function (row) {
257
+ var name = row.displayName || row.instanceId || row.origin;
258
+ var state = row.lastState || 'unknown';
259
+ var seen = row.lastSeenAt ? 'last seen ' + new Date(row.lastSeenAt).toLocaleString() : 'never seen';
260
+ return '<li class="pool-origin-row" data-origin="' + poolEsc(row.origin) + '">'
261
+ + '<span class="pool-origin-name">' + poolEsc(name) + '</span>'
262
+ + '<span class="pool-origin-state">' + poolEsc(state + ' · ' + seen) + '</span>'
263
+ + '<span class="pool-origin-address">' + poolEsc(row.origin) + '</span>'
264
+ + '</li>';
265
+ }).join('');
266
+ return '<div class="pool-failover-list" role="status">'
267
+ + '<p class="pool-failover-copy">No machine in this pool answered from this phone. '
268
+ + 'These are their last known states.</p>'
269
+ + '<ul class="pool-origin-rows">' + items + '</ul>'
270
+ + '</div>';
271
+ }
272
+
273
+ function mountPoolOriginsList(html, rows, deps) {
274
+ var host = (deps && deps.document) || (typeof document !== 'undefined' ? document : null);
275
+ if (!host || typeof host.getElementById !== 'function') return null;
276
+ var node = host.getElementById('pool-failover-list');
277
+ if (!node) return null;
278
+ if (typeof node.innerHTML === 'string' || node.innerHTML === '') node.innerHTML = String(html);
279
+ return node;
280
+ }
281
+
282
+ // P-7 boot failure. Called by app.js when the FIRST API call of a boot does not answer (a network
283
+ // error, or a 5xx/offline-tunnel answer from the relay):
284
+ // * with nothing queued, the first member that answers takes over (location.assign, carrying
285
+ // `?poolFrom=<this instance>`);
286
+ // * with unsent outbox items the switch is ASKED for first, because the outbox is per origin and
287
+ // would otherwise be stranded — "no" leaves the user exactly where they are;
288
+ // * when no member answers, the roster renders with its last-known states.
289
+ function failoverOnBootFailure(options) {
290
+ var settings = options || {};
291
+ var loc = settings.location || (typeof location !== 'undefined' ? location : null);
292
+ var rows = readPoolOrigins(settings.storage);
293
+ var selfOrigin = normalizePoolOrigin(settings.origin
294
+ || (loc && (loc.origin || (loc.protocol && loc.host ? loc.protocol + '//' + loc.host : ''))) || '');
295
+ var selfId = trims(settings.selfInstanceId);
296
+ var candidates = rows.filter(function (row) { return row.origin !== selfOrigin; });
297
+ if (!candidates.length) {
298
+ return Promise.resolve({ switched: false, to: '', asked: false, reason: 'no_members', rows: rows });
299
+ }
300
+ var selfName = (rows.filter(function (row) { return row.origin === selfOrigin; })[0] || {}).displayName
301
+ || selfOrigin || selfId;
302
+ if (settings.hasUnsentOutbox) {
303
+ var ask = settings.confirmImpl || (typeof confirm === 'function' ? confirm : null);
304
+ var question = settings.confirmText
305
+ || ('This phone has messages that have not been sent from ' + selfName + '. Switch to another machine anyway?');
306
+ var yes = false;
307
+ if (typeof ask === 'function') {
308
+ try {
309
+ yes = !!ask(question);
310
+ } catch (error) {
311
+ yes = false; // expected: a blocked/dismissed confirm dialog means "do not navigate away"
312
+ }
313
+ }
314
+ if (!yes) {
315
+ return Promise.resolve({ switched: false, to: '', asked: true, reason: 'outbox_unsent', rows: rows });
316
+ }
317
+ }
318
+ var index = 0;
319
+ var attempt = function () {
320
+ if (index >= candidates.length) {
321
+ var html = poolOriginsListHtml(rows);
322
+ var render = settings.renderList || function (markup, list) { return mountPoolOriginsList(markup, list, settings); };
323
+ render(html, rows);
324
+ return { switched: false, to: '', asked: false, reason: 'no_member_answered', html: html, rows: rows };
325
+ }
326
+ var row = candidates[index];
327
+ index += 1;
328
+ return probeOrigin(row.origin, settings).then(function (reachable) {
329
+ if (!reachable) return attempt();
330
+ var target = row.origin + '/m/?poolFrom=' + encodeURIComponent(selfId || selfOrigin);
331
+ if (loc && typeof loc.assign === 'function') loc.assign(target);
332
+ else if (loc) loc.href = target;
333
+ return { switched: true, to: row.origin, asked: false, reason: 'switched', href: target, rows: rows };
334
+ });
335
+ };
336
+ return Promise.resolve().then(attempt);
337
+ }
338
+
339
+ // `?poolFrom=<id>` on arrival: "<from name> is unreachable — switched to <this name>". Both names
340
+ // come from the stored roster (fall back to the id), every string is escaped, and the banner mounts
341
+ // into #pool-from-banner when the page has one.
342
+ function showPoolFromBanner(options) {
343
+ var settings = options || {};
344
+ var loc = settings.location || (typeof location !== 'undefined' ? location : null);
345
+ var search = settings.search != null ? String(settings.search) : String((loc && loc.search) || '');
346
+ var match = search.match(/[?&]poolFrom=([^&#]*)/);
347
+ var from = match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : '';
348
+ if (!from) return null;
349
+ var rows = settings.origins || readPoolOrigins(settings.storage);
350
+ var find = function (id) {
351
+ return rows.filter(function (row) { return row.instanceId === id; })[0] || null;
352
+ };
353
+ var self = settings.self || null;
354
+ var selfId = trims((self && self.instanceId) || settings.selfInstanceId);
355
+ var fromRow = find(from);
356
+ var selfRow = find(selfId);
357
+ var fromName = (fromRow && fromRow.displayName) || from;
358
+ var selfName = (selfRow && selfRow.displayName) || trims(self && self.displayName) || selfId || trims(settings.origin);
359
+ var text = fromName + ' is unreachable — switched to ' + selfName;
360
+ var html = '<div class="pool-from-banner" role="status">' + poolEsc(text) + '</div>';
361
+ var host = settings.document || (typeof document !== 'undefined' ? document : null);
362
+ var node = null;
363
+ if (host && typeof host.getElementById === 'function') {
364
+ node = host.getElementById(BANNER_ID);
365
+ if (node && typeof node.innerHTML === 'string') node.innerHTML = String(html);
366
+ }
367
+ return { from: from, selfId: selfId, fromName: fromName, selfName: selfName, text: text, html: html, node: node };
368
+ }
369
+
370
+ var out = {
371
+ POOL_ORIGINS_KEY: POOL_ORIGINS_KEY,
372
+ POOL_OUTBOX_PENDING_KEY: POOL_OUTBOX_PENDING_KEY,
373
+ PROBE_PATH: PROBE_PATH,
374
+ PROBE_TIMEOUT_MS: PROBE_TIMEOUT_MS,
375
+ BANNER_ID: BANNER_ID,
376
+ poolEsc: poolEsc,
377
+ normalizePoolOrigin: normalizePoolOrigin,
378
+ normalizePoolOriginRow: normalizePoolOriginRow,
379
+ readPoolOrigins: readPoolOrigins,
380
+ writePoolOrigins: writePoolOrigins,
381
+ readOutboxPendingMarker: readOutboxPendingMarker,
382
+ writeOutboxPendingMarker: writeOutboxPendingMarker,
383
+ rememberPoolOrigins: rememberPoolOrigins,
384
+ probeOrigin: probeOrigin,
385
+ poolOriginsListHtml: poolOriginsListHtml,
386
+ failoverOnBootFailure: failoverOnBootFailure,
387
+ showPoolFromBanner: showPoolFromBanner,
388
+ };
389
+ if (typeof module === 'object' && module.exports) module.exports = out;
390
+ else root.CtmPoolFailover = out;
391
+ })(typeof window !== 'undefined' ? window : this);
@@ -167,15 +167,34 @@
167
167
  }
168
168
 
169
169
  function captureSelectedRows(pane, selected) {
170
- return selected.map(({ item }, index) => ({
171
- item,
172
- fingerprint: JSON.stringify(item),
173
- payload: {
170
+ return selected.map(({ item }, index) => {
171
+ const payload = {
174
172
  title: item.title || `Prompt ${index + 1}`,
175
173
  text: dependencies.itemText(item),
176
174
  images: Array.isArray(item.images) ? item.images : [],
177
- },
178
- }));
175
+ };
176
+ // D-7/R-3: posting the pane's own id lets the engine (lib/queue-item.js:32 keeps a
177
+ // supplied id) and every reader match the durable row to this draft row by identity.
178
+ if (typeof item.id === 'string' && item.id) payload.id = item.id;
179
+ return { item, fingerprint: JSON.stringify(item), payload };
180
+ });
181
+ }
182
+
183
+ // R-3: a queue-draft echo or a queue-state delivery frame for the open pane reloads the
184
+ // draft through the existing loadDraft path. Skipped (and retried on the next frame) while
185
+ // the user is mid-operation, so a reload can never clobber an in-flight save/send or an
186
+ // open edit. NOTE: the design text says "editingIndex != null", but the phone stores -1
187
+ // (never null) for "no row being edited" (public/m/app.js:10862, :10835), so a literal
188
+ // `!= null` guard would never reload at all. The guard therefore tests the index
189
+ // (`>= 0`), which is the pane's own meaning of "an edit row is open" (app.js:10747).
190
+ async function reloadIfIdle(sessionId) {
191
+ const pane = getState()?.queueBuilder || null;
192
+ if (!pane || pane.open !== true) return false;
193
+ if (String(pane.sessionId || '') !== String(sessionId ?? '')) return false;
194
+ const editing = Number.isInteger(pane.editingIndex) && pane.editingIndex >= 0;
195
+ if (pane.saving || pane.sending || editing) return false;
196
+ await loadDraft(pane.sessionId);
197
+ return true;
179
198
  }
180
199
 
181
200
  async function sendQueue(options = {}) {
@@ -274,7 +293,7 @@
274
293
  return true;
275
294
  }
276
295
 
277
- return Object.freeze({ captureOrigin, isOriginCurrent, runMutation, confirmStepUp, saveDraft, loadDraft, sendQueue, retire });
296
+ return Object.freeze({ captureOrigin, isOriginCurrent, runMutation, confirmStepUp, saveDraft, loadDraft, reloadIfIdle, sendQueue, retire });
278
297
  }
279
298
 
280
299
  return Object.freeze({ createPrivateQueueActions });
@@ -23,6 +23,11 @@ const SHELL_ASSETS = [
23
23
  '/m/principal-access.js?v=__CTM_MOBILE_ASSET__',
24
24
  '/m/principal-ui-policy.js?v=__CTM_MOBILE_ASSET__',
25
25
  '/m/command-outcome-policy.js?v=__CTM_MOBILE_ASSET__',
26
+ // WP-6 (S-26/P-7): the cached shell must be able to fail over to another pool member with no
27
+ // network, so the failover module and the two machine-pool files ride the precache allowlist.
28
+ '/js/machine-pool-shared.js?v=__CTM_MOBILE_ASSET__',
29
+ '/m/pool-failover.js?v=__CTM_MOBILE_ASSET__',
30
+ '/m/machines.js?v=__CTM_MOBILE_ASSET__',
26
31
  '/m/outbox-persistence.js?v=__CTM_MOBILE_ASSET__',
27
32
  '/js/private-state-scope.js?v=__CTM_MOBILE_ASSET__',
28
33
  '/m/private-state-runtime.js?v=__CTM_MOBILE_ASSET__',
@@ -489,6 +489,18 @@ function getQueue(sessionId) {
489
489
  return queues.get(sessionId) || null;
490
490
  }
491
491
 
492
+ // Durable per-item status for readers that must not see the WS broadcast
493
+ // shape (queue-draft GET overlay, R-1/R-2/D-6). Returns null when the
494
+ // session has no in-memory queue. getState() is deliberately untouched: its
495
+ // item shape feeds the queue-state broadcast.
496
+ function getItemStatusMap(sessionId) {
497
+ const q = queues.get(sessionId);
498
+ if (!q) return null;
499
+ const map = new Map();
500
+ for (const i of q.items) if (i && i.id) map.set(i.id, { status: i.status, statusUpdatedAt: Number(i.statusUpdatedAt) || 0 });
501
+ return map;
502
+ }
503
+
492
504
  function getState(sessionId) {
493
505
  const q = queues.get(sessionId);
494
506
  if (!q) return null;
@@ -1233,6 +1245,7 @@ module.exports = {
1233
1245
  createQueue,
1234
1246
  appendItems,
1235
1247
  getQueue,
1248
+ getItemStatusMap,
1236
1249
  getState,
1237
1250
  getPersistedState,
1238
1251
  stateFromSavedQueue,
@@ -979,6 +979,10 @@ function createApprovals(deps) {
979
979
  policyDecision: `rescue_provider_rejected_${admittedInteraction.reasonCode || 'unknown'}`,
980
980
  keystrokeStatus: 'not_sent',
981
981
  });
982
+ // Drift alarm: the screen is a live approval the rescuer refused to admit. If NO provider
983
+ // recognizes it, the rejection itself is the drift signal — surface it here, not only on
984
+ // the later choice branch (which the very same rejection makes unreachable).
985
+ if (admittedInteraction.reasonCode === 'provider_unknown') _recordApprovalDrift(sessionId, approvalDrift.driftIfUnrecognized({ text, detectProvider: approvalProviders.detectProvider }));
982
986
  return;
983
987
  }
984
988
  // Fully hands-off on plan approvals (ExitPlanMode). The main path skips these
@@ -1008,12 +1012,7 @@ function createApprovals(deps) {
1008
1012
  // passed the isLiveApprovalPrompt gate above). If NO provider recognized it yet
1009
1013
  // its options carry approval verbs, a provider that SHOULD have matched didn't —
1010
1014
  // i.e. the CLI changed its prompt UI. Record it so the miss is loud, not silent.
1011
- try {
1012
- if (!approvalProviders.detectProvider(text)) {
1013
- const drift = approvalDrift.evaluateDrift({ text, providerMatched: false, waitingForInput: true });
1014
- if (drift) _recordApprovalDrift(sessionId, drift);
1015
- }
1016
- } catch { /* alarm is best-effort */ }
1015
+ _recordApprovalDrift(sessionId, approvalDrift.driftIfUnrecognized({ text, detectProvider: approvalProviders.detectProvider }));
1017
1016
  if (!buf._lastRescueChoiceSkipLogAt || Date.now() - buf._lastRescueChoiceSkipLogAt > 30000) {
1018
1017
  buf._lastRescueChoiceSkipLogAt = Date.now();
1019
1018
  logger.log(`[shadow-approver] Ignoring choice/question menu in rescue path for session ${sessionId.slice(0, 8)} — agent is asking the user, not a missed permission (via ${source})`);