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,436 @@
1
+ // public/js/machine-pool-shared.js — WP-6 (docs/machine-pool-picker-pairing-dashboard-2026-10-24.html
2
+ // §5 D-1/D-2/D-3/D-4/D-9/D-12, P-7, §6.4 client block, §8 WP-6).
3
+ //
4
+ // ONE copy of every DOM-free machine-pool presenter the desktop and the phone both need. It is a
5
+ // classic script (no module system, no bundler) and it is loaded by BOTH pages:
6
+ //
7
+ // desktop public/index.html — before js/core/session-commands.js and js/app/machines-page.js
8
+ // phone public/m/index.html — before /m/app.js
9
+ //
10
+ // Why a shared file and not two copies: the phone is a second renderer of the same machine pool
11
+ // (ruling: phone = desktop parity), so the ORDER (D-1), the SEARCH TEXT (D-2), the GROUPS (D-3),
12
+ // the LOAD LINE (D-12), the sparkline (AC-5b) and the pairing container (§6.3/D-9) must be the same
13
+ // bytes on both. Anything that touches the DOM, the network, a timer or a clock read stays in the
14
+ // surface that owns it; this file is pure and takes `now` from its caller.
15
+ //
16
+ // Nothing here reads localStorage, sessionStorage or a cookie. Nothing here calls Date.now() on a
17
+ // tested path: every presenter that needs a clock is handed one.
18
+
19
+ // D-12: the hub re-reads a box's sample at most once per 60 s, so a sample older than three
20
+ // refreshes is LABELLED, never shown as the box's current number.
21
+ var MACHINE_STATS_STALE_MS = 3 * 60000;
22
+ // D-3 "Recent": a box used within the last 14 days.
23
+ var MACHINE_RECENT_MS = 14 * 24 * 60 * 60 * 1000;
24
+ // D-1: while N = 1 + the visible (non-hidden) registry rows is at most MACHINE_PICKER_CARD_LIMIT the
25
+ // picker keeps the one-click card row; above the limit it keeps This Mac + the top three and adds a
26
+ // fifth "All machines (N)…" card (desktop) or a search sheet (phone).
27
+ var MACHINE_PICKER_CARD_LIMIT = 4;
28
+
29
+ // D-9 verbatim: `ctmpair1:` + base64url(JSON{v,i,n,u,c}).
30
+ var MACHINES_PAGE_PAIR_PREFIX = 'ctmpair1:';
31
+ // RFC 8628 §6.1 (lib/machine-pairing.js CODE_ALPHABET/CODE_LENGTH): the code is 8 characters out of
32
+ // this vowel-free, look-alike-free alphabet, shown as XXXX-XXXX.
33
+ var MACHINES_PAGE_CODE_ALPHABET = 'BCDFGHJKLMNPQRSTVWXZ';
34
+ var MACHINES_PAGE_CODE_LENGTH = 8;
35
+
36
+ // Machine health one-liners. The phone used to carry its own two copies (phoneMachineHealthLabel /
37
+ // phoneMachineLastSeen) — same wording, so they are this pair now.
38
+ function machineHealthLabel(machine) {
39
+ var health = String((machine && machine.health) || 'unknown');
40
+ return health.charAt(0).toUpperCase() + health.slice(1);
41
+ }
42
+
43
+ // Relative age, owned here so desktop and phone say the same thing (the phone never loads
44
+ // js/core/01-util.js's timeAgo, and its own relativeAgeText is private to m/app.js). Same buckets as
45
+ // timeAgo. `at` is a timestamp or ISO string — 0 means the hub has never seen the box; `now` is
46
+ // injectable for tests.
47
+ function machineAgoText(at, now) {
48
+ var ms = typeof at === 'string' && at && !/^\d+$/.test(at) ? Date.parse(at) : Number(at);
49
+ if (!ms || !Number.isFinite(ms)) return 'never seen';
50
+ // The desktop's own helper when the page has it (same buckets), so the two never drift apart.
51
+ if (now == null && typeof timeAgo === 'function') return timeAgo(ms);
52
+ var seconds = Math.floor(((now == null ? Date.now() : Number(now)) - ms) / 1000);
53
+ if (seconds < 60) return 'just now';
54
+ var minutes = Math.floor(seconds / 60);
55
+ if (minutes < 60) return minutes + 'm ago';
56
+ var hours = Math.floor(minutes / 60);
57
+ if (hours < 24) return hours + 'h ago';
58
+ var days = Math.floor(hours / 24);
59
+ if (days < 30) return days + 'd ago';
60
+ return Math.floor(days / 30) + 'mo ago';
61
+ }
62
+
63
+ function machineLastSeenText(machine) {
64
+ var at = Number((machine && machine.lastSeenAt) || 0);
65
+ if (!at) return 'never seen';
66
+ return 'last seen ' + machineAgoText(at);
67
+ }
68
+
69
+ // AC-5a: reachable is selectable; unknown/unhealthy are disabled; unreachable is absent from the
70
+ // card row (HUB AC-5a). `machineIsOffline` is the popover/sheet half of that rule and is the ONE
71
+ // predicate both apps read.
72
+ function machineIsOffline(machine) {
73
+ return String((machine && machine.health) || '').trim() !== 'reachable';
74
+ }
75
+
76
+ function machineIsFavorite(machine) {
77
+ return !!(machine && (machine.favorite === 1 || machine.favorite === true || Number(machine.favorite) === 1));
78
+ }
79
+
80
+ // D-4 "hide from picker". Strictly the 1/true spellings: an absent field is visible.
81
+ function machineIsHidden(machine) {
82
+ return !!(machine && (machine.hidden === 1 || machine.hidden === true || Number(machine.hidden) === 1));
83
+ }
84
+
85
+ // D-1 order: reachable rows first, then favorite DESC, lastUsedAt DESC, displayName ASC. `hidden`
86
+ // rows (D-4 "hide from picker") are dropped here and nowhere else, so no caller can resurrect one.
87
+ function machinePickerOrder(machines) {
88
+ var rows = (Array.isArray(machines) ? machines : []).filter(function (m) { return m && m.instanceId && !machineIsHidden(m); });
89
+ var reachableRank = function (m) { return machineIsOffline(m) ? 1 : 0; };
90
+ var favorite = function (m) { return machineIsFavorite(m) ? 1 : 0; };
91
+ var lastUsed = function (m) { return Number((m && m.lastUsedAt) || 0); };
92
+ var name = function (m) { return String((m && (m.displayName || m.url || m.instanceId)) || ''); };
93
+ return rows.slice().sort(function (a, b) {
94
+ return reachableRank(a) - reachableRank(b)
95
+ || favorite(b) - favorite(a)
96
+ || lastUsed(b) - lastUsed(a)
97
+ || name(a).localeCompare(name(b));
98
+ });
99
+ }
100
+
101
+ // D-2 search: the fields people actually remember, lowercased and joined with ' '. Always the same
102
+ // six slots in the same order, so a field the hub did not send can never shift the ones after it.
103
+ function machineSearchText(machine) {
104
+ if (!machine) return '';
105
+ var sample = machine.stats && machine.stats.sample;
106
+ var gpu = sample && sample.gpu ? sample.gpu.name : '';
107
+ return [machine.displayName, machine.hostname, machine.os, machine.arch, machine.url, gpu]
108
+ .map(function (value) { return String(value == null ? '' : value); })
109
+ .join(' ')
110
+ .toLowerCase();
111
+ }
112
+
113
+ // D-12 load line: 'CPU 12% · 3 running' from the box's newest sample, 'stats stale' once that sample
114
+ // is older than MACHINE_STATS_STALE_MS, '' when the hub holds no sample at all. `now` is passed in
115
+ // by every caller (and by tests), so staleness is never judged against a clock read inside here.
116
+ function machineLoadLine(machine, now) {
117
+ var stats = (machine && machine.stats) || null;
118
+ var sample = stats && stats.sample;
119
+ if (!stats || !sample) return '';
120
+ var at = Number(now == null ? Date.now() : now);
121
+ var checkedAt = Number(stats.checkedAt || 0);
122
+ if (!checkedAt || at - checkedAt > MACHINE_STATS_STALE_MS) return 'stats stale';
123
+ var parts = [];
124
+ var cpu = Number(sample.cpuPct);
125
+ if (sample.cpuPct != null && Number.isFinite(cpu)) parts.push('CPU ' + Math.round(cpu) + '%');
126
+ var running = sample.tasks ? Number(sample.tasks.running) : NaN;
127
+ if (sample.tasks && sample.tasks.running != null && Number.isFinite(running)) parts.push(running + ' running');
128
+ return parts.join(' · ');
129
+ }
130
+
131
+ // D-3 groups, as bare machine rows (the surface renders them). Favorites and Recent are filtered
132
+ // views of All (a box may legitimately appear in two groups); Offline carries the rows HUB AC-5a
133
+ // keeps out of the card row. `hidden` rows are already gone: machinePickerOrder dropped them.
134
+ function machinePickerGroupRows(machines, now) {
135
+ var at = Number(now == null ? Date.now() : now);
136
+ var order = machinePickerOrder(machines);
137
+ var online = order.filter(function (m) { return !machineIsOffline(m); });
138
+ var offline = order.filter(function (m) { return machineIsOffline(m); });
139
+ return [
140
+ { id: 'favorites', label: 'Favorites', rows: online.filter(machineIsFavorite) },
141
+ { id: 'recent', label: 'Recent', rows: online.filter(function (m) {
142
+ var last = Number(m.lastUsedAt || 0);
143
+ return last > 0 && at - last <= MACHINE_RECENT_MS;
144
+ }) },
145
+ { id: 'all', label: 'All', rows: order },
146
+ { id: 'offline', label: 'Offline', rows: offline },
147
+ ].filter(function (group) { return group.rows.length > 0; });
148
+ }
149
+
150
+ // P-7 / §6.2 P-4: the public https origin a phone can actually sign in to. `urls` is the dial list
151
+ // (rev 2); `url` is the legacy single address. A plain-http LAN address is not a passkey origin, so
152
+ // only `https:` counts here.
153
+ function machinePoolOrigin(machine) {
154
+ var urls = (machine && Array.isArray(machine.urls) ? machine.urls : []).slice();
155
+ if (machine && machine.url) urls.push(machine.url);
156
+ for (var i = 0; i < urls.length; i += 1) {
157
+ var candidate = String(urls[i] == null ? '' : urls[i]).trim().replace(/\/+$/, '');
158
+ if (/^https:\/\//i.test(candidate)) return candidate;
159
+ }
160
+ return '';
161
+ }
162
+
163
+ // P-7 "Sign in to <member> too": the origin this device has never reached. `origins` is the parsed
164
+ // ctm.pool.origins dial cache ([{ origin, lastSeenAt }]). '' when the member has no https origin or
165
+ // this device has already been there — i.e. only the unvisited members render the row.
166
+ function machinePoolSignInOrigin(machine, origins) {
167
+ var origin = machinePoolOrigin(machine);
168
+ if (!origin) return '';
169
+ var seen = (Array.isArray(origins) ? origins : []).some(function (row) {
170
+ return row && String(row.origin || '').replace(/\/+$/, '') === origin && Number(row.lastSeenAt || 0) > 0;
171
+ });
172
+ return seen ? '' : origin;
173
+ }
174
+
175
+ // ── AC-5b sparkline ─────────────────────────────────────────────────────────────────────────────
176
+ // ONE <path> per metric. A null sample (a minute the box was off, or the purge gap) CLOSES the run
177
+ // and the next value opens a new one with `M`, so the element count never grows with the data: 1440
178
+ // samples with two gaps is one <path> with three `M` segments.
179
+ function sparklineSvg(values, opts) {
180
+ var options = opts || {};
181
+ var width = Number(options.width || 120) || 120;
182
+ var height = Number(options.height || 28) || 28;
183
+ var raw = Array.isArray(values) ? values : [];
184
+ var nums = raw.map(function (value) {
185
+ if (value == null || value === '') return null;
186
+ var n = Number(value);
187
+ return Number.isFinite(n) ? n : null;
188
+ });
189
+ var present = nums.filter(function (n) { return n != null; });
190
+ var open = '<svg class="machine-spark" width="' + width + '" height="' + height
191
+ + '" viewBox="0 0 ' + width + ' ' + height + '" aria-hidden="true" focusable="false">';
192
+ if (!present.length) return open + '</svg>';
193
+ var min = Math.min.apply(null, present);
194
+ var max = Math.max.apply(null, present);
195
+ var span = (max - min) || 1;
196
+ var count = nums.length;
197
+ var x = function (index) { return count <= 1 ? 0 : (index / (count - 1)) * width; };
198
+ var y = function (value) { return height - ((value - min) / span) * height; };
199
+ var d = '';
200
+ var run = [];
201
+ var flush = function () {
202
+ if (!run.length) return;
203
+ var segment = run.map(function (point, index) {
204
+ return (index === 0 ? 'M' : 'L') + point[0].toFixed(2) + ' ' + point[1].toFixed(2);
205
+ }).join(' ');
206
+ d += (d ? ' ' : '') + segment;
207
+ run = [];
208
+ };
209
+ for (var i = 0; i < count; i += 1) {
210
+ if (nums[i] == null) { flush(); continue; }
211
+ run.push([x(i), y(nums[i])]);
212
+ }
213
+ flush();
214
+ // A single point has no line: emit a degenerate segment so the path still exists (never a throw).
215
+ return open + '<path d="' + (d || ('M0 ' + (height / 2).toFixed(2))) + '"/></svg>';
216
+ }
217
+
218
+ // ── D-9 pairing container (the member side, client-only) ────────────────────────────────────────
219
+ // §6.3 verbatim: uppercase, then drop every character outside the alphabet — hyphens and spaces are
220
+ // formatting, not content. Mirrors lib/machine-pairing.js normalizeCode.
221
+ function machinesNormalizeCode(value) {
222
+ var out = '';
223
+ var raw = String(value == null ? '' : value).toUpperCase();
224
+ for (var i = 0; i < raw.length; i += 1) {
225
+ if (MACHINES_PAGE_CODE_ALPHABET.indexOf(raw.charAt(i)) !== -1) out += raw.charAt(i);
226
+ }
227
+ return out;
228
+ }
229
+
230
+ function machinesFormatCode(value) {
231
+ var code = machinesNormalizeCode(value);
232
+ if (code.length !== MACHINES_PAGE_CODE_LENGTH) return code;
233
+ return code.slice(0, 4) + '-' + code.slice(4);
234
+ }
235
+
236
+ // base64url -> UTF-8. atob() is the browser's decoder; the escape/decodeURIComponent pair is the
237
+ // standard way to recover the UTF-8 bytes it produced (and both exist in a bare vm realm, unlike
238
+ // TextDecoder).
239
+ function machinesBase64UrlDecode(text) {
240
+ var padded = String(text || '').replace(/-/g, '+').replace(/_/g, '/');
241
+ while (padded.length % 4) padded += '=';
242
+ var binary = atob(padded);
243
+ return decodeURIComponent(escape(binary));
244
+ }
245
+
246
+ // D-9: A hand-edited or truncated string is null, never a throw, so the dialog can render its
247
+ // refusal. One copy: the desktop Add dialog and the phone Add sheet both read this.
248
+ function decodePairingStringClient(value) {
249
+ var raw = String(value == null ? '' : value).trim();
250
+ if (raw.indexOf(MACHINES_PAGE_PAIR_PREFIX) !== 0) return null;
251
+ var parsed = null;
252
+ try {
253
+ parsed = JSON.parse(machinesBase64UrlDecode(raw.slice(MACHINES_PAGE_PAIR_PREFIX.length)));
254
+ } catch (error) {
255
+ return null; // expected: a corrupted container is a client error, not a fault to report
256
+ }
257
+ if (!parsed || typeof parsed !== 'object' || parsed.v !== 1) return null;
258
+ var code = machinesNormalizeCode(parsed.c);
259
+ if (code.length !== MACHINES_PAGE_CODE_LENGTH) return null;
260
+ var urls = (Array.isArray(parsed.u) ? parsed.u : [])
261
+ .map(function (url) { return String(url == null ? '' : url).trim().replace(/\/+$/, ''); })
262
+ .filter(Boolean);
263
+ var instanceId = String(parsed.i || '').trim();
264
+ if (!instanceId && !urls.length) return null;
265
+ return {
266
+ version: 1,
267
+ instanceId: instanceId,
268
+ displayName: String(parsed.n || ''),
269
+ urls: urls,
270
+ code: code,
271
+ codeDisplay: machinesFormatCode(code),
272
+ };
273
+ }
274
+
275
+ // What an Add dialog shows while the user pastes (AC-5c): the box's OWN name (`n`) and its first
276
+ // candidate address (`u[0]`) BEFORE Confirm is enabled; a string that does not decode is refused
277
+ // with the same wording the server uses. Shared, so the phone refuses exactly what the desktop does.
278
+ function machinesAddPreview(pairingText, codeText, urlText) {
279
+ var raw = String(pairingText == null ? '' : pairingText).trim();
280
+ if (raw) {
281
+ var parsed = decodePairingStringClient(raw);
282
+ if (!parsed) {
283
+ return { ok: false, mode: 'string', message: 'pairing_string_invalid', name: '', url: '', code: '' };
284
+ }
285
+ return {
286
+ ok: true,
287
+ mode: 'string',
288
+ message: '',
289
+ name: parsed.displayName || parsed.instanceId || '',
290
+ url: parsed.urls[0] || '',
291
+ code: parsed.codeDisplay,
292
+ instanceId: parsed.instanceId,
293
+ pairingString: raw,
294
+ };
295
+ }
296
+ var code = machinesNormalizeCode(codeText);
297
+ var url = String(urlText == null ? '' : urlText).trim().replace(/\/+$/, '');
298
+ if (!code && !url) {
299
+ return { ok: false, mode: 'manual', message: '', name: '', url: '', code: '' };
300
+ }
301
+ if (code.length !== MACHINES_PAGE_CODE_LENGTH) {
302
+ return { ok: false, mode: 'manual', message: 'pairing_code_invalid', name: '', url: url, code: code };
303
+ }
304
+ if (!/^https?:\/\/.+/i.test(url)) {
305
+ return { ok: false, mode: 'manual', message: 'address_required', name: '', url: url, code: code };
306
+ }
307
+ // There is no pre-join name over code + address: the box does not answer its identity until it is
308
+ // dialled with a credential, and there is no server probe route to ask earlier.
309
+ return { ok: false, mode: 'manual', message: '', name: '', url: url, code: code, addressOnly: true };
310
+ }
311
+
312
+ // ── card fact formatters ────────────────────────────────────────────────────────────────────────
313
+ // The Machines page on both apps renders the same facts from the same sample; these are that
314
+ // rendering. They were two copies (machinesCpuSeries/machinesFormatBytes/… in machines-page.js and
315
+ // again in the phone card) — this is the one copy, and both surfaces delegate to it.
316
+ function machineHistoryRows(history) {
317
+ if (Array.isArray(history)) return history;
318
+ if (history && Array.isArray(history.samples)) return history.samples;
319
+ return [];
320
+ }
321
+
322
+ function machineCpuSeries(history) {
323
+ return machineHistoryRows(history).map(function (sample) {
324
+ if (!sample || sample.cpuPct == null) return null;
325
+ var value = Number(sample.cpuPct);
326
+ return Number.isFinite(value) ? value : null;
327
+ });
328
+ }
329
+
330
+ function machineMemSeries(history) {
331
+ return machineHistoryRows(history).map(function (sample) {
332
+ if (!sample) return null;
333
+ var used = Number(sample.memUsedBytes);
334
+ var total = Number(sample.memTotalBytes);
335
+ if (!Number.isFinite(used) || !Number.isFinite(total) || total <= 0) return null;
336
+ return (used / total) * 100;
337
+ });
338
+ }
339
+
340
+ function machineLastValue(series) {
341
+ if (!Array.isArray(series)) return null;
342
+ for (var i = series.length - 1; i >= 0; i -= 1) {
343
+ if (series[i] != null) return series[i];
344
+ }
345
+ return null;
346
+ }
347
+
348
+ function machineFormatBytes(value) {
349
+ var bytes = Number(value);
350
+ if (!Number.isFinite(bytes) || bytes <= 0) return '';
351
+ var units = ['B', 'KB', 'MB', 'GB', 'TB'];
352
+ var index = 0;
353
+ var scaled = bytes;
354
+ while (scaled >= 1024 && index < units.length - 1) { scaled /= 1024; index += 1; }
355
+ return (scaled >= 10 || index === 0 ? Math.round(scaled) : scaled.toFixed(1)) + ' ' + units[index];
356
+ }
357
+
358
+ function machineFormatPct(value) {
359
+ // No sample is no number: Number(null) is 0, which would paint a fake "0%".
360
+ if (value == null || value === '') return '';
361
+ var n = Number(value);
362
+ if (!Number.isFinite(n)) return '';
363
+ return Math.round(n) + '%';
364
+ }
365
+
366
+ // WP-4: a reachable box whose Claude/Codex CLI is signed out says so on its card. Same labels on both
367
+ // surfaces.
368
+ var MACHINE_AGENT_LABELS = { claude: 'Claude', codex: 'Codex' };
369
+
370
+ function machineAgentText(agents) {
371
+ if (!agents || typeof agents !== 'object') return '';
372
+ var parts = [];
373
+ ['claude', 'codex'].forEach(function (key) {
374
+ var state = String(agents[key] || '');
375
+ if (state === 'signed_in') parts.push(MACHINE_AGENT_LABELS[key] + ' signed in');
376
+ else if (state === 'signed_out') parts.push(MACHINE_AGENT_LABELS[key] + ' signed out');
377
+ });
378
+ return parts.join(' · ');
379
+ }
380
+
381
+ function machineTaskLine(tasks) {
382
+ if (!tasks || typeof tasks !== 'object') return '';
383
+ var parts = [];
384
+ if (tasks.running != null) parts.push((Number(tasks.running) || 0) + ' running');
385
+ if (tasks.needsYou != null) parts.push((Number(tasks.needsYou) || 0) + ' needs you');
386
+ if (tasks.idle != null) parts.push((Number(tasks.idle) || 0) + ' idle');
387
+ return parts.join(' · ');
388
+ }
389
+
390
+ function machineGpuText(gpu) {
391
+ if (!gpu || typeof gpu !== 'object') return '';
392
+ var parts = [String(gpu.name || 'GPU')];
393
+ if (gpu.utilPct != null) parts.push(Math.round(Number(gpu.utilPct)) + '%');
394
+ if (gpu.tempC != null) parts.push(Math.round(Number(gpu.tempC)) + '°C');
395
+ if (gpu.powerW != null) parts.push(Math.round(Number(gpu.powerW)) + 'W');
396
+ return parts.join(' · ');
397
+ }
398
+
399
+ if (typeof module === 'object' && module.exports) {
400
+ module.exports = {
401
+ MACHINE_STATS_STALE_MS: MACHINE_STATS_STALE_MS,
402
+ MACHINE_RECENT_MS: MACHINE_RECENT_MS,
403
+ MACHINE_PICKER_CARD_LIMIT: MACHINE_PICKER_CARD_LIMIT,
404
+ MACHINES_PAGE_PAIR_PREFIX: MACHINES_PAGE_PAIR_PREFIX,
405
+ MACHINES_PAGE_CODE_ALPHABET: MACHINES_PAGE_CODE_ALPHABET,
406
+ MACHINES_PAGE_CODE_LENGTH: MACHINES_PAGE_CODE_LENGTH,
407
+ machineHealthLabel: machineHealthLabel,
408
+ machineAgoText: machineAgoText,
409
+ machineLastSeenText: machineLastSeenText,
410
+ machineIsOffline: machineIsOffline,
411
+ machineIsFavorite: machineIsFavorite,
412
+ machineIsHidden: machineIsHidden,
413
+ machinePickerOrder: machinePickerOrder,
414
+ machineSearchText: machineSearchText,
415
+ machineLoadLine: machineLoadLine,
416
+ machinePickerGroupRows: machinePickerGroupRows,
417
+ machinePoolOrigin: machinePoolOrigin,
418
+ machinePoolSignInOrigin: machinePoolSignInOrigin,
419
+ sparklineSvg: sparklineSvg,
420
+ machinesNormalizeCode: machinesNormalizeCode,
421
+ machinesFormatCode: machinesFormatCode,
422
+ machinesBase64UrlDecode: machinesBase64UrlDecode,
423
+ decodePairingStringClient: decodePairingStringClient,
424
+ machinesAddPreview: machinesAddPreview,
425
+ MACHINE_AGENT_LABELS: MACHINE_AGENT_LABELS,
426
+ machineHistoryRows: machineHistoryRows,
427
+ machineCpuSeries: machineCpuSeries,
428
+ machineMemSeries: machineMemSeries,
429
+ machineLastValue: machineLastValue,
430
+ machineFormatBytes: machineFormatBytes,
431
+ machineFormatPct: machineFormatPct,
432
+ machineAgentText: machineAgentText,
433
+ machineTaskLine: machineTaskLine,
434
+ machineGpuText: machineGpuText,
435
+ };
436
+ }
@@ -11,6 +11,11 @@
11
11
  const MAX_ID_LENGTH = 160;
12
12
  const MAX_NAME_LENGTH = 256;
13
13
  const MAX_ORIGIN_LENGTH = 2048;
14
+ // Every identity read gets a deadline that cancels the request (D-1). The
15
+ // value must exceed the slowest bounded server path on these routes — the ps
16
+ // snapshot cap of 5000 ms (PS_SNAPSHOT_TIMEOUT_MS, lib/walle-supervisor.js:183)
17
+ // — 2 × PS_SNAPSHOT_TIMEOUT_MS, and well under the 60 s test timeout.
18
+ const PRIVATE_SCOPE_READ_TIMEOUT_MS = 10000;
14
19
 
15
20
  function object(value) {
16
21
  return value !== null && typeof value === 'object' && !Array.isArray(value);
@@ -98,6 +103,17 @@
98
103
  const subtle = options.crypto && options.crypto.subtle;
99
104
  const storage = options.storage || null;
100
105
  const callback = typeof options.onStateChange === 'function' ? options.onStateChange : null;
106
+ // Production passes neither option. Tests inject a short readTimeoutMs, and
107
+ // an AbortSignal-like object with .timeout(ms) when the runtime lacks one.
108
+ const readTimeoutMs = Number.isFinite(options.readTimeoutMs) && options.readTimeoutMs > 0
109
+ ? options.readTimeoutMs : PRIVATE_SCOPE_READ_TIMEOUT_MS;
110
+ const abortSignalApi = options.AbortSignal
111
+ || (typeof globalThis !== 'undefined' ? globalThis.AbortSignal : null);
112
+ function readSignal() {
113
+ // No AbortSignal.timeout in this runtime: send no signal rather than throw.
114
+ if (!abortSignalApi || typeof abortSignalApi.timeout !== 'function') return null;
115
+ return abortSignalApi.timeout(readTimeoutMs);
116
+ }
101
117
  let epoch = 0;
102
118
  let ready = false;
103
119
  let lease = null;
@@ -163,7 +179,13 @@
163
179
  if (typeof fetcher !== 'function') throw { code: failureCode };
164
180
  let response;
165
181
  try {
166
- response = await fetcher(path, { method: 'GET', credentials: 'same-origin', cache: 'no-store' });
182
+ const signal = readSignal();
183
+ response = await fetcher(path, {
184
+ method: 'GET',
185
+ credentials: 'same-origin',
186
+ cache: 'no-store',
187
+ ...(signal ? { signal } : {}),
188
+ });
167
189
  } catch (error) {
168
190
  // An explicit configuration-error discriminator is not a network outage:
169
191
  // pass its specific typed code through with NO HTTP status, so it stays
@@ -186,7 +208,13 @@
186
208
  let payload;
187
209
  try {
188
210
  payload = await response.json();
189
- } catch {
211
+ } catch (error) {
212
+ // The same signal covers the body read, so an aborted body is a
213
+ // transport failure: report it as "no response" (0), exactly like a
214
+ // rejected fetch. Any other body failure stays status-less/non-transport.
215
+ if (error && (error.name === 'TimeoutError' || error.name === 'AbortError')) {
216
+ throw { code: failureCode, status: 0 };
217
+ }
190
218
  throw { code: failureCode };
191
219
  }
192
220
  if (!stillCurrent()) return null;
@@ -436,5 +464,5 @@
436
464
  });
437
465
  }
438
466
 
439
- return { createPrivateStateScope };
467
+ return { createPrivateStateScope, PRIVATE_SCOPE_READ_TIMEOUT_MS };
440
468
  });