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
@@ -5,6 +5,11 @@
5
5
  'use strict';
6
6
 
7
7
  var TERMINAL = new Set(['sent', 'needs_attention', 'blocked', 'failed']);
8
+ // WP-1 (C1, design §6 / R3/R6): the closed vocabulary the server publishes next to a
9
+ // terminal status. `retry` repeats the SAME admitted request, `resend` is an explicit
10
+ // new attempt, `review` restores the preserved prompt and needs a confirmation, and
11
+ // `none` means the user has nothing to do here.
12
+ var RECOVERY_ACTIONS = new Set(['retry', 'resend', 'review', 'none']);
8
13
  var DEFAULT_INACTIVITY_MS = 20000;
9
14
  var LEGACY_DEADLINE_MS = 12000;
10
15
  var DEFAULT_ATTENTION_MS = 600000;
@@ -18,6 +23,18 @@
18
23
  return String(candidate.type || candidate.agentType || candidate.sessionType || '').toLowerCase();
19
24
  }
20
25
 
26
+ // Never invent an action from prose, and never let an unrecognized value grant a
27
+ // resend. A frame the current server produced always carries one of the four; a frame
28
+ // with no usable verdict is a legacy frame, so the historical `retryable: true`
29
+ // verdict keeps its old same-ID meaning and anything else is conservative: review
30
+ // restores the preserved prompt and requires an explicit confirmation before a
31
+ // possible duplicate, and can never mint a fresh id on its own.
32
+ function normalizeRecoveryAction(value, retryable) {
33
+ var clean = typeof value === 'string' ? value.trim().toLowerCase() : '';
34
+ if (RECOVERY_ACTIONS.has(clean)) return clean;
35
+ return retryable === true ? 'retry' : 'review';
36
+ }
37
+
21
38
  function createManager(options) {
22
39
  options = options || {};
23
40
  var records = new Map();
@@ -30,6 +47,18 @@
30
47
  var createId = options.createId || function() {
31
48
  return typeof crypto !== 'undefined' && crypto.randomUUID ? crypto.randomUUID() : fallbackId();
32
49
  };
50
+ // One replacement per original: the gesture is idempotent, so a double click (or a
51
+ // second UI affordance reaching the same original) returns the successor it already
52
+ // started instead of minting a second id. Never published: publicRecord must not
53
+ // expose a live record object.
54
+ var successors = new Map();
55
+ // AC-1b (WP-1): the reentrancy fence. The entry is acquired BEFORE any caller-supplied
56
+ // callback can run (createId, publish/onChange, getSessionType, transport), so a callback
57
+ // that re-enters resend() for the SAME original while the first call is still executing --
58
+ // a synchronous double gesture, or a publish-driven UI re-render -- joins the operation
59
+ // already in flight instead of minting a second identity. It is released on every exit
60
+ // that did not register a successor.
61
+ var operations = new Map();
33
62
 
34
63
  function isCurrent() {
35
64
  if (disposed) return false;
@@ -58,6 +87,13 @@
58
87
  function eraseRecord(record) {
59
88
  clearRecordTimers(record);
60
89
  records.delete(record.clientMessageId);
90
+ successors.delete(record.clientMessageId);
91
+ operations.delete(record.clientMessageId);
92
+ // A retired record must not stay reachable through another record's supersession link:
93
+ // the successor map is a live-object map, never a graveyard of erased records.
94
+ successors.forEach(function(candidate, originalId) {
95
+ if (candidate === record) successors.delete(originalId);
96
+ });
61
97
  record.clientMessageId = '';
62
98
  record.sessionId = '';
63
99
  record.text = '';
@@ -67,6 +103,8 @@
67
103
  record.message = '';
68
104
  record.signal = '';
69
105
  record.status = '';
106
+ record.recoveryAction = 'none';
107
+ record.supersedesClientMessageId = '';
70
108
  record.alarmed = false;
71
109
  record.retryable = false;
72
110
  record.lateConfirmationReported = false;
@@ -129,6 +167,13 @@
129
167
  if (!record || record.settled) return record;
130
168
  Object.assign(record, patch || {});
131
169
  if (record.status !== 'sent') record.alarmed = true;
170
+ // A record that settles into a terminal failure owns its recovery policy, even when
171
+ // the settling path (a transport failure or an inactivity deadline) has no server
172
+ // frame to copy it from.
173
+ if (record.status === 'sent') record.recoveryAction = 'none';
174
+ else if (TERMINAL.has(record.status)) {
175
+ record.recoveryAction = usableRecoveryAction(patch && patch.recoveryAction, record.retryable === true);
176
+ }
132
177
  record.settled = true;
133
178
  clearRecordTimers(record);
134
179
  if (!publish(record)) return record;
@@ -136,6 +181,11 @@
136
181
  return record;
137
182
  }
138
183
 
184
+ function usableRecoveryAction(value, retryable) {
185
+ var clean = typeof value === 'string' ? value.trim().toLowerCase() : '';
186
+ return RECOVERY_ACTIONS.has(clean) ? clean : normalizeRecoveryAction('', retryable);
187
+ }
188
+
139
189
  function ackTruthEnabled() {
140
190
  if (typeof options.isAckTruthEnabled !== 'function') return true;
141
191
  var result = guardedCallback(options.isAckTruthEnabled, null, [], null);
@@ -226,7 +276,13 @@
226
276
  reason: '',
227
277
  message: 'Sending...',
228
278
  signal: '',
279
+ recoveryAction: 'none',
229
280
  };
281
+ // Local supersession link (C1/R6): what this new attempt replaces. It is a client
282
+ // bookkeeping field for the queue/UI lanes, never part of the transport frame.
283
+ if (submitOptions.supersedesClientMessageId) {
284
+ record.supersedesClientMessageId = String(submitOptions.supersedesClientMessageId);
285
+ }
230
286
  record.promise = new Promise(function(resolve) { record.resolve = resolve; });
231
287
  var submissionPromise = record.promise;
232
288
  records.set(clientMessageId, record);
@@ -308,18 +364,35 @@
308
364
  if (record.settled && !TERMINAL.has(status)) return true;
309
365
  if (!record.settled && ackTruthEnabled()) armSubmissionDeadline(record);
310
366
  if (!guardRecord(record)) return false;
367
+ var has = function(name) { return Boolean(message) && Object.prototype.hasOwnProperty.call(message, name); };
368
+ var incomingReason = String((message && (message.reason || message.code)) || '');
369
+ var incomingMessage = String((message && message.message) || '');
370
+ var failure = TERMINAL.has(status) && status !== 'sent';
371
+ // A later duplicate frame for the SAME terminal failure often carries only the
372
+ // status (the direct reply and the broadcast race). It must not erase the rich
373
+ // message/reason/recovery verdict the first frame already published.
374
+ var sameFailure = failure && record.settled === true && String(record.status || '') === status;
375
+ var retryable = has('retryable') ? message.retryable === true : (sameFailure && record.retryable === true);
376
+ var recoveryAction = !failure ? 'none'
377
+ : has('recoveryAction') ? normalizeRecoveryAction(message.recoveryAction, retryable)
378
+ : sameFailure ? normalizeRecoveryAction(record.recoveryAction, retryable)
379
+ : normalizeRecoveryAction('', retryable);
311
380
  var patch = {
312
381
  status: status === 'accepted' ? 'pending' : status,
313
- reason: String(message.reason || ''),
382
+ reason: sameFailure && !incomingReason ? String(record.reason || '') : incomingReason,
314
383
  // Server verdict on whether re-sending the SAME prompt can succeed once
315
384
  // the condition clears. Callers use it instead of matching code strings.
316
- retryable: message.retryable === true,
317
- // A refusal without its own message must still read as a refusal: the tray shows Retry
318
- // for it, and "Sending..." beside Retry told the user a failed prompt was in flight.
319
- message: String(message.message || (status === 'sent' ? 'Sent'
320
- : TERMINAL.has(status) ? 'Prompt not sent: ' + String(message.reason || message.code || status).replace(/_/g, ' ')
321
- : 'Sending...')),
385
+ retryable: retryable,
386
+ // A terminal reply without prose must not look in flight or claim a known no-effect
387
+ // outcome when its typed recovery policy requires uncertainty review.
388
+ message: sameFailure && !incomingMessage ? String(record.message || '')
389
+ : incomingMessage || (status === 'sent' ? 'Sent'
390
+ : TERMINAL.has(status) ? (recoveryAction === 'review' ? 'Delivery unconfirmed: ' : 'Prompt not sent: ') + String(message.reason || message.code || status).replace(/_/g, ' ')
391
+ : 'Sending...'),
322
392
  signal: String(message.signal || ''),
393
+ // WP-1 (AC-1a/AC-1e): the typed recovery verdict. Exact enum; an unrecognized
394
+ // value never grants a fresh resend.
395
+ recoveryAction: recoveryAction,
323
396
  };
324
397
  if (TERMINAL.has(status)) reconcileTerminal(record, patch);
325
398
  else {
@@ -351,6 +424,9 @@
351
424
  return true;
352
425
  }
353
426
 
427
+ // AC-1a: a same-ID retry is only ever correct for the server's `retry` verdict --
428
+ // the admitted request is still executable. Every other policy (resend/review/none)
429
+ // must go through resend(), which mints exactly one fresh id on an explicit gesture.
354
430
  function retry(clientMessageId) {
355
431
  if (!isCurrent()) return Promise.resolve(neutralResult());
356
432
  var record = records.get(String(clientMessageId || ''));
@@ -358,6 +434,12 @@
358
434
  if (!TERMINAL.has(record.status) || record.status === 'sent') {
359
435
  return Promise.resolve({ ok: false, status: record.status, reason: 'submission_in_flight' });
360
436
  }
437
+ var action = normalizeRecoveryAction(record.recoveryAction, record.retryable === true);
438
+ if (action !== 'retry') {
439
+ return Promise.resolve({
440
+ ok: false, status: record.status, reason: 'recovery_action_not_retry', recoveryAction: action,
441
+ });
442
+ }
361
443
  return submit(record.sessionId, record.text, {
362
444
  attachments: record.attachments,
363
445
  source: record.source,
@@ -365,6 +447,79 @@
365
447
  });
366
448
  }
367
449
 
450
+ // AC-1b/AC-1c: the ONE explicit fresh-attempt path. Only a user gesture may call it
451
+ // (nothing here is scheduled, drained or timer-driven), it requires a settled UNSENT
452
+ // original whose server verdict permits a new attempt, and a `review` verdict also
453
+ // requires the caller's explicit confirmation. The id is minted once; text,
454
+ // attachments, source and session are carried over unchanged.
455
+ function resend(clientMessageId, resendOptions) {
456
+ resendOptions = resendOptions || {};
457
+ var confirmUncertain = resendOptions.confirmUncertain === true;
458
+ if (!isCurrent()) return Promise.resolve(neutralResult());
459
+ var originalId = String(clientMessageId || '');
460
+ var record = records.get(originalId);
461
+ if (!record || !guardRecord(record)) {
462
+ return Promise.resolve(!isCurrent() ? neutralResult() : { ok: false, status: 'failed', reason: 'submission_not_found' });
463
+ }
464
+ var started = successors.get(originalId);
465
+ if (started && records.get(started.clientMessageId) === started) return started.promise;
466
+ var inFlight = operations.get(originalId);
467
+ if (inFlight) return inFlight.promise;
468
+ if (!record.settled || record.status === 'sent') {
469
+ return Promise.resolve({ ok: false, status: record.status, reason: 'submission_in_flight' });
470
+ }
471
+ var action = normalizeRecoveryAction(record.recoveryAction, record.retryable === true);
472
+ if (action !== 'resend' && !(action === 'review' && confirmUncertain)) {
473
+ return Promise.resolve({
474
+ ok: false, status: record.status, reason: 'recovery_not_permitted', recoveryAction: action,
475
+ });
476
+ }
477
+ var operation = { released: false, promise: null, resolve: null };
478
+ operation.promise = new Promise(function(resolve) { operation.resolve = resolve; });
479
+ operations.set(originalId, operation);
480
+ function release(result) {
481
+ if (!operation.released) {
482
+ operation.released = true;
483
+ if (operations.get(originalId) === operation) operations.delete(originalId);
484
+ operation.resolve(result);
485
+ }
486
+ return result;
487
+ }
488
+ try {
489
+ var idResult = guardedCallback(createId, null, [], record);
490
+ if (!idResult.current || !idResult.value) return release(neutralResult());
491
+ if (!guardRecord(record)) return release(neutralResult());
492
+ var candidateId = String(idResult.value);
493
+ // The successor must be a NEW identity: the original's own id, or any id already
494
+ // tracked, would overwrite a live record (and silently re-drive a different prompt).
495
+ if (candidateId === originalId || records.has(candidateId)) {
496
+ return release({ ok: false, status: record.status, reason: 'duplicate_client_message_id' });
497
+ }
498
+ var successorPromise = submit(record.sessionId, record.text, {
499
+ attachments: record.attachments,
500
+ source: record.source,
501
+ clientMessageId: candidateId,
502
+ supersedesClientMessageId: originalId,
503
+ });
504
+ // submit() registers and publishes the successor before it returns, so the link is
505
+ // only recorded once the replacement really exists; a denied preflight leaves the
506
+ // original (text, attachments, ids) exactly as it was and frees the fence.
507
+ if (!guardRecord(record)) return release(successorPromise);
508
+ var successor = records.get(candidateId);
509
+ if (!successor || String(successor.supersedesClientMessageId || '') !== originalId) {
510
+ return release(successorPromise);
511
+ }
512
+ successors.set(originalId, successor);
513
+ // One replacement, one promise: the re-entrant gesture and this call resolve to the
514
+ // same successor, and a later gesture gets that successor's own promise back.
515
+ release(successorPromise);
516
+ return successor.promise;
517
+ } catch (error) {
518
+ release({ ok: false, status: 'failed', reason: 'resend_failed' });
519
+ throw error;
520
+ }
521
+ }
522
+
368
523
  function dismiss(clientMessageId) {
369
524
  if (!isCurrent()) return false;
370
525
  var record = records.get(String(clientMessageId || ''));
@@ -381,6 +536,7 @@
381
536
  if (!dismissed.current) return false;
382
537
  }
383
538
  records.delete(record.clientMessageId);
539
+ successors.delete(record.clientMessageId);
384
540
  clearRecordTimers(record);
385
541
  record.clientMessageId = '';
386
542
  record.sessionId = '';
@@ -397,10 +553,17 @@
397
553
  disposed = true;
398
554
  records.forEach(function(record) { denyRecord(record); });
399
555
  records.clear();
556
+ operations.forEach(function(operation) {
557
+ if (operation.released) return;
558
+ operation.released = true;
559
+ operation.resolve(neutralResult());
560
+ });
561
+ operations.clear();
562
+ successors.clear();
400
563
  }
401
564
 
402
565
  var manager = { submit: submit, handleStatus: handleStatus, handleWalleUser: handleWalleUser,
403
- handleInputDropped: handleInputDropped, retry: retry, dismiss: dismiss, dispose: dispose };
566
+ handleInputDropped: handleInputDropped, retry: retry, resend: resend, dismiss: dismiss, dispose: dispose };
404
567
  Object.defineProperty(manager, 'records', { enumerable: true, get: function() {
405
568
  if (!isCurrent()) records.forEach(function(record) { denyRecord(record); });
406
569
  return records;
@@ -411,6 +574,8 @@
411
574
  return {
412
575
  classifySessionType: classifySessionType,
413
576
  createManager: createManager,
577
+ normalizeRecoveryAction: normalizeRecoveryAction,
578
+ RECOVERY_ACTIONS: Array.from(RECOVERY_ACTIONS),
414
579
  DEFAULT_INACTIVITY_MS: DEFAULT_INACTIVITY_MS,
415
580
  LEGACY_DEADLINE_MS: LEGACY_DEADLINE_MS,
416
581
  DEFAULT_ATTENTION_MS: DEFAULT_ATTENTION_MS,
@@ -0,0 +1,281 @@
1
+ (function(root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory();
3
+ else root.PromptSubmissionTray = factory();
4
+ })(typeof globalThis !== 'undefined' ? globalThis : this, function() {
5
+ 'use strict';
6
+
7
+ // WP-1 (C2, design §6 / R6, docs/queue-delivery-recovery-evidence-2026-10-23.html): the
8
+ // per-record submission tray row, extracted from index.html (which sits at its file-size
9
+ // ceiling). Every dependency that can only exist in the page -- the tray element, its
10
+ // composer clearance, the live manager, and the owner-fenced recovery route -- is passed in
11
+ // explicitly, so this module owns no globals and no queue state of its own.
12
+ var QUIET_REVEAL_MS = 5000;
13
+ var SENT_FLASH_MS = 2200;
14
+ var FAILURE_STATUSES = ['needs_attention', 'blocked', 'failed'];
15
+ var ROW_CSS = 'display:flex;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--border);border-radius:6px;background:var(--bg-secondary, var(--bg-lighter));box-shadow:0 6px 20px rgba(0,0,0,.28);font-size:12px;color:var(--text-primary, var(--text))';
16
+
17
+ function normalizeRecoveryAction(value) {
18
+ var clean = typeof value === 'string' ? value.trim().toLowerCase() : '';
19
+ return clean === 'retry' || clean === 'resend' || clean === 'review' ? clean : 'none';
20
+ }
21
+
22
+ function rowId(clientMessageId) {
23
+ return 'prompt-submission-' + String(clientMessageId || '');
24
+ }
25
+
26
+ function trayButton(doc, label, onClick) {
27
+ var el = doc.createElement('button');
28
+ el.className = 'btn small';
29
+ el.textContent = label;
30
+ el.onclick = onClick;
31
+ return el;
32
+ }
33
+
34
+ // AC-1a/AC-1e (WP-1 fix): a row's callbacks and timers are bound to the manager and the record
35
+ // the row was rendered for. The manager identity is captured once, at render time, and re-checked
36
+ // before every DOM/recovery/dismiss effect -- a later getManager() that answers with a NEW manager
37
+ // (a logout, or a fresh lease) can never authorize an old row's timer or handler. A caller may add
38
+ // its own predicate for a record the manager does not track (a queue-owned review record that
39
+ // survived a reload): the clientMessageId is never authority on its own.
40
+ function createLifetime(dependencies) {
41
+ var tracksOwner = typeof dependencies.getManager === 'function';
42
+ var owner = tracksOwner ? dependencies.getManager() : null;
43
+ function ownerCurrent() {
44
+ if (!tracksOwner) return true;
45
+ return !!owner && dependencies.getManager() === owner;
46
+ }
47
+ return {
48
+ owner: owner,
49
+ ownerCurrent: ownerCurrent,
50
+ current: function current(record) {
51
+ if (!ownerCurrent()) return false;
52
+ if (typeof dependencies.isCurrent !== 'function') return true;
53
+ try { return dependencies.isCurrent(record) === true; }
54
+ catch (_) { return false; }
55
+ },
56
+ };
57
+ }
58
+
59
+ // AC-1f (WP-1 fix): a recovery gesture is one-shot WHILE it runs -- a double click cannot start
60
+ // two replacements -- but a refusal, a throw or a rejected callback must hand the button back. An
61
+ // inert Resend/confirm button is a dead end for the user; the row stays locked only when the
62
+ // gesture really committed (its owner retires the row at that point).
63
+ function runGesture(row, flag, record, lifetime, gesture, onCommit) {
64
+ if (row.dataset[flag] === '1') return;
65
+ row.dataset[flag] = '1';
66
+ function release(committed) {
67
+ if (committed === true) return;
68
+ if (!lifetime.current(record)) return;
69
+ row.dataset[flag] = '';
70
+ }
71
+ var result;
72
+ try { result = gesture(); }
73
+ catch (error) { release(false); throw error; }
74
+ Promise.resolve(result).then(function(committed) {
75
+ release(committed === true);
76
+ // A committed successor has nothing left to say here: the surface that was only raised for
77
+ // the uncertain attempt retires itself. The check is the page identity the row was rendered
78
+ // against -- never the record predicate, which the commit itself is allowed to invalidate.
79
+ if (committed === true && typeof onCommit === 'function') onCommit();
80
+ }, function() { release(false); });
81
+ }
82
+
83
+ // R6: an uncertain outcome is never resolved by re-sending on the user's behalf. The Review
84
+ // gesture only opens the preserved prompt (the server's own message is the uncertainty
85
+ // warning); the SEND is a second, explicit click, and it is reported as a confirmed resend.
86
+ function appendReviewPanel(doc, row, record, dependencies, lifetime) {
87
+ var panel = doc.createElement('div');
88
+ panel.dataset.ctmReviewPanel = '1';
89
+ panel.style.cssText = 'flex-basis:100%;display:grid;gap:6px;padding-top:6px;border-top:1px dashed var(--border)';
90
+ var warning = doc.createElement('div');
91
+ warning.dataset.ctmReviewWarning = '1';
92
+ warning.style.cssText = 'color:var(--yellow);font-size:11px';
93
+ warning.textContent = String(record.message || 'CTM could not confirm what happened to this prompt.');
94
+ panel.appendChild(warning);
95
+ var preserved = doc.createElement('pre');
96
+ preserved.dataset.ctmReviewText = '1';
97
+ preserved.style.cssText = 'white-space:pre-wrap;margin:0;max-height:140px;overflow:auto;font:inherit';
98
+ // Exactly the text the user typed, byte for byte -- never re-typed, never re-worded.
99
+ preserved.textContent = String(record.text || '');
100
+ panel.appendChild(preserved);
101
+ var actions = doc.createElement('div');
102
+ actions.dataset.ctmReviewActions = '1';
103
+ actions.style.cssText = 'display:flex;gap:6px';
104
+ actions.appendChild(trayButton(doc, 'Send as new attempt', function() {
105
+ // The explicit confirmation R6 requires, and a one-shot gesture: a double click must not
106
+ // start two replacements. A refused answer re-arms it -- nothing was sent.
107
+ runGesture(row, 'ctmReviewDispatched', record, lifetime, function() {
108
+ row.dataset.ctmReviewOpen = '';
109
+ return dependencies.onRecovery('resend', record, { confirmUncertain: true });
110
+ }, function committedSuccessor() {
111
+ if (!lifetime.ownerCurrent()) return;
112
+ // Only a row this surface created is retired here; a row the manager still renders belongs
113
+ // to the manager's own dismiss path.
114
+ if (row.dataset.ctmReviewRow === '1') row.remove();
115
+ });
116
+ }));
117
+ // Closing the review never touches the prompt: the queue item keeps its text, images and
118
+ // pending state, and Send Next can open the review again.
119
+ actions.appendChild(trayButton(doc, 'Cancel', function() {
120
+ if (!lifetime.current(record)) return;
121
+ row.dataset.ctmReviewOpen = '';
122
+ row.dataset.ctmReviewDispatched = '';
123
+ row.style.flexWrap = '';
124
+ panel.remove();
125
+ if (row.dataset.ctmReviewRow === '1') row.remove();
126
+ }));
127
+ panel.appendChild(actions);
128
+ row.appendChild(panel);
129
+ }
130
+
131
+ function renderStatus(record, dependencies) {
132
+ if (!record || !dependencies || !dependencies.document) return null;
133
+ var doc = dependencies.document;
134
+ var lifetime = createLifetime(dependencies);
135
+ var manager = lifetime.owner;
136
+ if (!lifetime.ownerCurrent()) return null;
137
+ var now = function() { return dependencies.now ? Number(dependencies.now()) : Date.now(); };
138
+ var setTimer = function(callback, delayMs) {
139
+ return dependencies.setTimer ? dependencies.setTimer(callback, delayMs) : setTimeout(callback, delayMs);
140
+ };
141
+ var tray = dependencies.ensureTray();
142
+ dependencies.positionTray(tray);
143
+ var id = rowId(record.clientMessageId);
144
+ var row = doc.getElementById(id);
145
+ if (!row) {
146
+ row = doc.createElement('div');
147
+ row.id = id;
148
+ row.style.cssText = ROW_CSS;
149
+ tray.appendChild(row);
150
+ }
151
+ // Quiet happy path (user feedback 2026-08-20: stacked "Sending prompt..." rows sat over the
152
+ // composer for a whole 21-min turn saying nothing). The tray's real job is the FAILURE lane --
153
+ // Retry/Restore when a prompt would otherwise be silently lost -- so pending/queued rows stay
154
+ // hidden unless a prompt is still unacknowledged after 5s, a 'sent' that was never shown
155
+ // dismisses without the "Prompt sent" flash, and a user-hidden quiet row stays hidden until
156
+ // its status escalates to a failure (loss protection always wins over the quieting).
157
+ var quietStatus = record.status === 'pending' || record.status === 'queued';
158
+ if (!quietStatus && row.dataset.hiddenByUser === '1') delete row.dataset.hiddenByUser;
159
+ if (quietStatus) {
160
+ if (!row.dataset.quietRevealAt) {
161
+ row.dataset.quietRevealAt = String(now() + QUIET_REVEAL_MS);
162
+ row.style.display = 'none';
163
+ setTimer(function() {
164
+ if (!lifetime.current(record)) return;
165
+ var live = doc.getElementById(rowId(record.clientMessageId));
166
+ if (live && live.dataset.quietRevealAt && live.dataset.hiddenByUser !== '1') live.style.display = 'flex';
167
+ }, QUIET_REVEAL_MS);
168
+ } else if (row.dataset.hiddenByUser === '1' || now() < Number(row.dataset.quietRevealAt)) {
169
+ row.style.display = 'none';
170
+ } else {
171
+ row.style.display = 'flex';
172
+ }
173
+ } else if (record.status === 'sent' && row.style.display === 'none') {
174
+ row.remove();
175
+ setTimer(function() {
176
+ if (lifetime.current(record) && manager) manager.dismiss(record.clientMessageId);
177
+ }, 0);
178
+ return null;
179
+ } else {
180
+ delete row.dataset.quietRevealAt;
181
+ row.style.display = 'flex';
182
+ }
183
+ row.textContent = '';
184
+ var label = doc.createElement('span');
185
+ label.style.flex = '1';
186
+ label.textContent = record.status === 'pending' ? 'Sending prompt...'
187
+ : record.status === 'sent' ? 'Prompt sent' : (record.message || 'Prompt needs attention');
188
+ row.appendChild(label);
189
+ var failure = FAILURE_STATUSES.indexOf(record.status) >= 0;
190
+ var action = failure ? normalizeRecoveryAction(record.recoveryAction) : 'none';
191
+ if (action === 'retry') {
192
+ // Same admitted request: the server said this ID is still executable.
193
+ row.appendChild(trayButton(doc, 'Retry', function() {
194
+ if (lifetime.current(record) && manager) manager.retry(record.clientMessageId);
195
+ }));
196
+ } else if (action === 'resend') {
197
+ // Explicit new attempt only -- nothing here is scheduled or automatic.
198
+ row.appendChild(trayButton(doc, 'Resend', function() {
199
+ runGesture(row, 'ctmResendDispatched', record, lifetime, function() {
200
+ return dependencies.onRecovery('resend', record, { confirmUncertain: false });
201
+ });
202
+ }));
203
+ } else if (action === 'review') {
204
+ row.appendChild(trayButton(doc, 'Review', function() {
205
+ if (!lifetime.current(record)) return;
206
+ row.dataset.ctmReviewOpen = '1';
207
+ renderStatus(record, dependencies);
208
+ }));
209
+ }
210
+ if (action === 'review' && row.dataset.ctmReviewOpen === '1') {
211
+ row.style.flexWrap = 'wrap';
212
+ appendReviewPanel(doc, row, record, dependencies, lifetime);
213
+ } else {
214
+ row.style.flexWrap = '';
215
+ }
216
+ if (record.status !== 'pending' && record.status !== 'queued') {
217
+ row.appendChild(trayButton(doc, 'Dismiss', function() {
218
+ if (lifetime.current(record) && manager) manager.dismiss(record.clientMessageId);
219
+ }));
220
+ if (record.status === 'sent') {
221
+ setTimer(function() {
222
+ if (lifetime.current(record) && manager) manager.dismiss(record.clientMessageId);
223
+ }, SENT_FLASH_MS);
224
+ }
225
+ } else {
226
+ // Quiet rows get a HIDE-ONLY dismiss -- never CTMPromptOutbox.dismiss here, that would drop
227
+ // the durable retry record while the prompt is still in flight. The row (and its tracking)
228
+ // stays; only the pixels go, and a failure escalation clears hiddenByUser above.
229
+ row.appendChild(trayButton(doc, 'Dismiss', function() {
230
+ if (!lifetime.current(record)) return;
231
+ row.dataset.hiddenByUser = '1';
232
+ row.style.display = 'none';
233
+ }));
234
+ }
235
+ return row;
236
+ }
237
+
238
+ // AC-1e (WP-1 fix): the review surface for a QUEUE-owned item. The queue owns the item, and the
239
+ // manager may hold no record for it at all (a preserved item after a reload), so the caller passes
240
+ // a read-only snapshot plus its own lifetime predicate. This renderer never mints, sends or
241
+ // persists anything of its own.
242
+ function renderItemReview(record, dependencies) {
243
+ if (!record || !dependencies || !dependencies.document) return null;
244
+ var doc = dependencies.document;
245
+ var lifetime = createLifetime(dependencies);
246
+ if (!lifetime.current(record)) return null;
247
+ var tray = dependencies.ensureTray();
248
+ dependencies.positionTray(tray);
249
+ var row = doc.getElementById(rowId(record.clientMessageId));
250
+ var ownsRow = false;
251
+ if (!row) {
252
+ row = doc.createElement('div');
253
+ row.id = rowId(record.clientMessageId);
254
+ row.style.cssText = ROW_CSS;
255
+ tray.appendChild(row);
256
+ ownsRow = true;
257
+ }
258
+ // Cancel removes a row this surface created itself; a row the manager already renders stays,
259
+ // with its own Review gesture, and is closed back to its normal state instead.
260
+ row.dataset.ctmReviewRow = ownsRow ? '1' : '';
261
+ row.dataset.ctmReviewOpen = '1';
262
+ row.dataset.ctmReviewDispatched = '';
263
+ row.style.display = 'flex';
264
+ row.style.flexWrap = 'wrap';
265
+ row.textContent = '';
266
+ var label = doc.createElement('span');
267
+ label.style.flex = '1';
268
+ label.textContent = 'Uncertain delivery — review this prompt before sending it again';
269
+ row.appendChild(label);
270
+ appendReviewPanel(doc, row, record, dependencies, lifetime);
271
+ return row;
272
+ }
273
+
274
+ return {
275
+ renderStatus: renderStatus,
276
+ renderItemReview: renderItemReview,
277
+ normalizeRecoveryAction: normalizeRecoveryAction,
278
+ QUIET_REVEAL_MS: QUIET_REVEAL_MS,
279
+ SENT_FLASH_MS: SENT_FLASH_MS,
280
+ };
281
+ });