create-walle 0.9.21 → 0.9.23

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 (500) hide show
  1. package/README.md +27 -5
  2. package/package.json +2 -2
  3. package/template/CLAUDE.md +2 -2
  4. package/template/LICENSE +1 -1
  5. package/template/bin/ctm-dev-cleanup.js +24 -3
  6. package/template/bin/ctm-launch.sh +13 -0
  7. package/template/bin/dev.sh +156 -18
  8. package/template/bin/node-bin.sh +84 -0
  9. package/template/bin/pin-node.sh +51 -0
  10. package/template/claude-task-manager/api-prompts.js +1203 -182
  11. package/template/claude-task-manager/api-reviews.js +109 -15
  12. package/template/claude-task-manager/approval-agent.js +1360 -280
  13. package/template/claude-task-manager/bin/restart-ctm.sh +64 -23
  14. package/template/claude-task-manager/bin/storage-migration-supervisor.js +338 -0
  15. package/template/claude-task-manager/db.js +4417 -295
  16. package/template/claude-task-manager/docs/app-update-refresh-protocol.md +69 -0
  17. package/template/claude-task-manager/docs/approval-ai-refinement.md +138 -0
  18. package/template/claude-task-manager/docs/approval-rescue-loop.md +74 -0
  19. package/template/claude-task-manager/docs/codex-operational-warning-health.md +107 -0
  20. package/template/claude-task-manager/docs/codex-resume-state-guard-design.md +17 -12
  21. package/template/claude-task-manager/docs/codex-terminal-render-controller-handoff.md +311 -0
  22. package/template/claude-task-manager/docs/coding-agent-hooks-architecture.md +418 -0
  23. package/template/claude-task-manager/docs/conversation-import-freshness.md +20 -0
  24. package/template/claude-task-manager/docs/google-workspace-auth-health.md +77 -0
  25. package/template/claude-task-manager/docs/image-paste-ux.md +13 -0
  26. package/template/claude-task-manager/docs/ipad-web-preview.md +88 -0
  27. package/template/claude-task-manager/docs/main-loop-offload-architecture.md +66 -0
  28. package/template/claude-task-manager/docs/microsoft-dev-tunnel-phone-access-design.md +274 -519
  29. package/template/claude-task-manager/docs/mobile-live-streaming.md +27 -5
  30. package/template/claude-task-manager/docs/mobile-remote-submission-lifecycle.md +69 -0
  31. package/template/claude-task-manager/docs/phone-access-design.md +53 -15
  32. package/template/claude-task-manager/docs/phone-passkey-identity.md +122 -0
  33. package/template/claude-task-manager/docs/phone-setup.md +3 -0
  34. package/template/claude-task-manager/docs/prompt-editing-tree-design.md +25 -1
  35. package/template/claude-task-manager/docs/remote-desktop-access-design.md +268 -0
  36. package/template/claude-task-manager/docs/restart-lifecycle-architecture.md +95 -0
  37. package/template/claude-task-manager/docs/runtime-work-control-plane.md +53 -0
  38. package/template/claude-task-manager/docs/session-interactive-wait-surfaces.md +38 -0
  39. package/template/claude-task-manager/docs/session-needs-you-dismissal.md +84 -0
  40. package/template/claude-task-manager/docs/session-render-state-management-design.md +91 -3
  41. package/template/claude-task-manager/docs/session-standup-command-center-design.md +25 -1
  42. package/template/claude-task-manager/docs/session-title-authority.md +32 -0
  43. package/template/claude-task-manager/docs/session-workspace-binding.md +33 -0
  44. package/template/claude-task-manager/docs/skill-intent-resolution-design.md +72 -0
  45. package/template/claude-task-manager/docs/walle-mcp-supervisor-health.md +86 -0
  46. package/template/claude-task-manager/docs/walle-relay-phone-access-design.md +24 -15
  47. package/template/claude-task-manager/docs/walle-session-history-hydration.md +114 -0
  48. package/template/claude-task-manager/docs/walle-session-input-queue.md +104 -0
  49. package/template/claude-task-manager/docs/walle-session-model-catalog.md +90 -0
  50. package/template/claude-task-manager/docs/walle-session-model-preferences.md +15 -6
  51. package/template/claude-task-manager/git-utils.js +897 -27
  52. package/template/claude-task-manager/lib/agent-capabilities.js +33 -0
  53. package/template/claude-task-manager/lib/agent-cli-cache.js +37 -7
  54. package/template/claude-task-manager/lib/agent-hooks-installer.js +26 -2
  55. package/template/claude-task-manager/lib/agent-presets.js +17 -1
  56. package/template/claude-task-manager/lib/all-sessions-query.js +108 -0
  57. package/template/claude-task-manager/lib/approval-ai-refinement.js +488 -0
  58. package/template/claude-task-manager/lib/approval-self-adapt.js +168 -0
  59. package/template/claude-task-manager/lib/async-semaphore.js +44 -0
  60. package/template/claude-task-manager/lib/auth-context.js +5 -0
  61. package/template/claude-task-manager/lib/auth-rate-limit.js +47 -4
  62. package/template/claude-task-manager/lib/auth-rules.js +29 -2
  63. package/template/claude-task-manager/lib/auto-approval-verifier.js +129 -16
  64. package/template/claude-task-manager/lib/background-llm.js +144 -17
  65. package/template/claude-task-manager/lib/branch-inventory.js +212 -0
  66. package/template/claude-task-manager/lib/claude-desktop-sessions.js +15 -3
  67. package/template/claude-task-manager/lib/coalesce-sync-frames.js +151 -0
  68. package/template/claude-task-manager/lib/codex-launch-health.js +762 -0
  69. package/template/claude-task-manager/lib/codex-transcript-pager.js +51 -0
  70. package/template/claude-task-manager/lib/codex-zst.js +124 -0
  71. package/template/claude-task-manager/lib/coding-agent-models.js +233 -30
  72. package/template/claude-task-manager/lib/connection-health.js +232 -0
  73. package/template/claude-task-manager/lib/conversation-blob-parser.js +42 -0
  74. package/template/claude-task-manager/lib/conversation-tail-merge.js +89 -26
  75. package/template/claude-task-manager/lib/ctm-session-context-api.js +39 -10
  76. package/template/claude-task-manager/lib/cursor-conversation-store.js +354 -0
  77. package/template/claude-task-manager/lib/db-owner-worker-client.js +315 -0
  78. package/template/claude-task-manager/lib/document-review.js +141 -6
  79. package/template/claude-task-manager/lib/escalation-review.js +152 -0
  80. package/template/claude-task-manager/lib/graceful-shutdown.js +159 -0
  81. package/template/claude-task-manager/lib/headless-term-service.js +678 -0
  82. package/template/claude-task-manager/lib/heavy-worker-fallback.js +38 -0
  83. package/template/claude-task-manager/lib/jsonl-conversation-parser.js +542 -0
  84. package/template/claude-task-manager/lib/jsonl-range-reader.js +112 -0
  85. package/template/claude-task-manager/lib/main-db-census.js +216 -0
  86. package/template/claude-task-manager/lib/message-pagination.js +106 -4
  87. package/template/claude-task-manager/lib/microsoft-dev-tunnel-setup.js +750 -26
  88. package/template/claude-task-manager/lib/mobile-auth-api.js +274 -7
  89. package/template/claude-task-manager/lib/mobile-auth-store.js +592 -10
  90. package/template/claude-task-manager/lib/mobile-notification-dispatcher.js +15 -0
  91. package/template/claude-task-manager/lib/model-overview-brain-fallback.js +311 -0
  92. package/template/claude-task-manager/lib/model-overview-cache.js +141 -0
  93. package/template/claude-task-manager/lib/models-health-routing-notice.js +126 -0
  94. package/template/claude-task-manager/lib/node-pin-guard.js +93 -0
  95. package/template/claude-task-manager/lib/perf-tracker.js +242 -6
  96. package/template/claude-task-manager/lib/permission-match.js +76 -0
  97. package/template/claude-task-manager/lib/permission-sync.js +133 -20
  98. package/template/claude-task-manager/lib/process-title.js +35 -0
  99. package/template/claude-task-manager/lib/prompt-executions-query.js +25 -0
  100. package/template/claude-task-manager/lib/prompt-index-disk-cache.js +44 -0
  101. package/template/claude-task-manager/lib/prompt-intent.js +132 -0
  102. package/template/claude-task-manager/lib/provider-user-context.js +34 -0
  103. package/template/claude-task-manager/lib/read-pool-client.js +313 -0
  104. package/template/claude-task-manager/lib/readpool-breaker.js +31 -0
  105. package/template/claude-task-manager/lib/recent-sessions-breaker.js +12 -0
  106. package/template/claude-task-manager/lib/remote-feedback-client.js +72 -0
  107. package/template/claude-task-manager/lib/remote-relay-protocol.js +37 -4
  108. package/template/claude-task-manager/lib/remote-relay-store.js +159 -0
  109. package/template/claude-task-manager/lib/remote-submission-observer.js +278 -0
  110. package/template/claude-task-manager/lib/restart-guard.js +109 -0
  111. package/template/claude-task-manager/lib/restore-interruption-detector.js +439 -0
  112. package/template/claude-task-manager/lib/restore-policy.js +13 -0
  113. package/template/claude-task-manager/lib/restore-resume-batch.js +74 -0
  114. package/template/claude-task-manager/lib/restore-runtime.js +68 -0
  115. package/template/claude-task-manager/lib/restore-storm.js +34 -0
  116. package/template/claude-task-manager/lib/resume-cwd.js +36 -0
  117. package/template/claude-task-manager/lib/resume-preflight.js +313 -0
  118. package/template/claude-task-manager/lib/runtime-work-registry.js +444 -0
  119. package/template/claude-task-manager/lib/sanitize-openai-auth.js +31 -0
  120. package/template/claude-task-manager/lib/scheduler.js +21 -1
  121. package/template/claude-task-manager/lib/scrollback-snapshot-store.js +159 -0
  122. package/template/claude-task-manager/lib/serial-task-queue.js +64 -0
  123. package/template/claude-task-manager/lib/server-listeners.js +239 -0
  124. package/template/claude-task-manager/lib/session-capture.js +42 -7
  125. package/template/claude-task-manager/lib/session-content-backfill.js +131 -0
  126. package/template/claude-task-manager/lib/session-history.js +388 -43
  127. package/template/claude-task-manager/lib/session-host-manager.js +287 -0
  128. package/template/claude-task-manager/lib/session-image-refs.js +209 -0
  129. package/template/claude-task-manager/lib/session-jobs.js +399 -59
  130. package/template/claude-task-manager/lib/session-prompt-index.js +137 -0
  131. package/template/claude-task-manager/lib/session-restore.js +53 -0
  132. package/template/claude-task-manager/lib/session-standup.js +123 -23
  133. package/template/claude-task-manager/lib/session-state-bus.js +14 -0
  134. package/template/claude-task-manager/lib/session-stream.js +64 -16
  135. package/template/claude-task-manager/lib/session-timeline-summary.js +260 -0
  136. package/template/claude-task-manager/lib/session-token-usage.js +494 -0
  137. package/template/claude-task-manager/lib/session-workspace-binding.js +356 -0
  138. package/template/claude-task-manager/lib/setup-network-config.js +9 -0
  139. package/template/claude-task-manager/lib/size-cap.js +45 -0
  140. package/template/claude-task-manager/lib/size-cap.test.js +62 -0
  141. package/template/claude-task-manager/lib/skill-autocomplete.js +180 -1
  142. package/template/claude-task-manager/lib/skill-intent-resolver.js +304 -0
  143. package/template/claude-task-manager/lib/sqlite-driver.js +19 -3
  144. package/template/claude-task-manager/lib/standup-attention.js +7 -3
  145. package/template/claude-task-manager/lib/status-authority.js +39 -0
  146. package/template/claude-task-manager/lib/status-hooks.js +4 -0
  147. package/template/claude-task-manager/lib/storage-migration.js +235 -0
  148. package/template/claude-task-manager/lib/structured-capture.js +298 -0
  149. package/template/claude-task-manager/lib/sync-io-census.js +163 -0
  150. package/template/claude-task-manager/lib/tailscale-setup.js +6 -0
  151. package/template/claude-task-manager/lib/terminal-activity-evidence.js +33 -0
  152. package/template/claude-task-manager/lib/terminal-choice.js +364 -0
  153. package/template/claude-task-manager/lib/terminal-control-sanitize.js +17 -0
  154. package/template/claude-task-manager/lib/terminal-fingerprint.js +48 -0
  155. package/template/claude-task-manager/lib/terminal-output-flush.js +84 -0
  156. package/template/claude-task-manager/lib/timeline-order.js +122 -0
  157. package/template/claude-task-manager/lib/transcript-store.js +348 -43
  158. package/template/claude-task-manager/lib/transport-security.js +84 -1
  159. package/template/claude-task-manager/lib/wait-state.js +184 -0
  160. package/template/claude-task-manager/lib/walle-client.js +47 -5
  161. package/template/claude-task-manager/lib/walle-ctm-history.js +564 -4
  162. package/template/claude-task-manager/lib/walle-external-actions.js +135 -16
  163. package/template/claude-task-manager/lib/walle-history-hydration.js +46 -0
  164. package/template/claude-task-manager/lib/walle-native-health.js +403 -0
  165. package/template/claude-task-manager/lib/walle-repair.js +701 -0
  166. package/template/claude-task-manager/lib/walle-session-cache.js +109 -0
  167. package/template/claude-task-manager/lib/walle-session-context.js +57 -21
  168. package/template/claude-task-manager/lib/walle-session-model-catalog.js +34 -0
  169. package/template/claude-task-manager/lib/walle-supervisor.js +539 -63
  170. package/template/claude-task-manager/lib/walle-transcript.js +52 -0
  171. package/template/claude-task-manager/lib/worktree-active-sync.js +11 -7
  172. package/template/claude-task-manager/lib/worktree-cwd.js +32 -1
  173. package/template/claude-task-manager/package.json +1 -1
  174. package/template/claude-task-manager/prompt-harvest.js +89 -66
  175. package/template/claude-task-manager/providers/claude-code.js +51 -3
  176. package/template/claude-task-manager/providers/cursor.js +140 -45
  177. package/template/claude-task-manager/public/css/reviews.css +551 -61
  178. package/template/claude-task-manager/public/css/setup.css +191 -0
  179. package/template/claude-task-manager/public/css/walle-session.css +865 -10
  180. package/template/claude-task-manager/public/css/walle.css +154 -0
  181. package/template/claude-task-manager/public/designs/ai-providers-consolidation-v2.html +830 -0
  182. package/template/claude-task-manager/public/index.html +18516 -2058
  183. package/template/claude-task-manager/public/ipad.html +363 -0
  184. package/template/claude-task-manager/public/js/document-review-links.js +301 -0
  185. package/template/claude-task-manager/public/js/image-normalize.js +69 -36
  186. package/template/claude-task-manager/public/js/message-renderer.js +1265 -77
  187. package/template/claude-task-manager/public/js/prompts.js +66 -29
  188. package/template/claude-task-manager/public/js/reviews.js +901 -133
  189. package/template/claude-task-manager/public/js/session-activity-utils.js +11 -1
  190. package/template/claude-task-manager/public/js/session-search-utils.js +94 -10
  191. package/template/claude-task-manager/public/js/session-status-precedence.js +23 -5
  192. package/template/claude-task-manager/public/js/setup.js +1273 -176
  193. package/template/claude-task-manager/public/js/stream-view.js +691 -73
  194. package/template/claude-task-manager/public/js/terminal-reconciler.js +210 -0
  195. package/template/claude-task-manager/public/js/walle-session.js +2455 -158
  196. package/template/claude-task-manager/public/js/walle.js +455 -28
  197. package/template/claude-task-manager/public/m/app.css +2909 -262
  198. package/template/claude-task-manager/public/m/app.js +6601 -398
  199. package/template/claude-task-manager/public/m/claim.html +224 -17
  200. package/template/claude-task-manager/public/m/index.html +117 -21
  201. package/template/claude-task-manager/public/m/sw.js +3 -1
  202. package/template/claude-task-manager/public/manifest.json +2 -2
  203. package/template/claude-task-manager/public/prompts.html +30 -14
  204. package/template/claude-task-manager/queue-engine.js +507 -28
  205. package/template/claude-task-manager/scripts/repair-claude-session-images.js +27 -8
  206. package/template/claude-task-manager/server.js +14341 -2197
  207. package/template/claude-task-manager/session-integrity.js +160 -18
  208. package/template/claude-task-manager/session-search-ranking.js +1 -0
  209. package/template/claude-task-manager/session-utils.js +25 -5
  210. package/template/claude-task-manager/workers/approval-blocklist.js +96 -6
  211. package/template/claude-task-manager/workers/approval-widget-validator.js +14 -8
  212. package/template/claude-task-manager/workers/conversation-import-worker.js +11 -50
  213. package/template/claude-task-manager/workers/db-owner-worker.js +386 -0
  214. package/template/claude-task-manager/workers/harvest-worker.js +9 -55
  215. package/template/claude-task-manager/workers/headless-term-worker.js +9 -530
  216. package/template/claude-task-manager/workers/read-pool-worker.js +387 -0
  217. package/template/claude-task-manager/workers/scrollback-worker.js +11 -72
  218. package/template/claude-task-manager/workers/session-host-process.js +146 -0
  219. package/template/claude-task-manager/workers/session-integrity-worker.js +10 -54
  220. package/template/claude-task-manager/workers/state-detectors/base.js +18 -1
  221. package/template/claude-task-manager/workers/state-detectors/claude-code.js +182 -9
  222. package/template/claude-task-manager/workers/state-detectors/codex.js +150 -2
  223. package/template/claude-task-manager/workers/state-detectors/cursor.js +127 -0
  224. package/template/claude-task-manager/workers/state-detectors/gemini.js +21 -0
  225. package/template/claude-task-manager/workers/state-detectors/index.js +29 -0
  226. package/template/claude-task-manager/workers/state-detectors/opencode.js +103 -0
  227. package/template/docs/design/markdown-review-pane.md +206 -0
  228. package/template/docs/designs/2026-05-17-portkey-gateway-provider-ux.md +129 -38
  229. package/template/docs/designs/2026-05-20-mobile-worktree-finish-command.md +27 -0
  230. package/template/docs/designs/2026-05-22-ai-configuration-consolidation.md +248 -0
  231. package/template/docs/designs/ai-configuration-consolidation-mock.html +812 -0
  232. package/template/docs/private-memory-and-pii-policy.md +69 -0
  233. package/template/package.json +2 -1
  234. package/template/scripts/check-private-data.js +201 -0
  235. package/template/shared/sqlite-owner-guard.js +30 -0
  236. package/template/shared/sqlite-owner-write-queue.js +225 -0
  237. package/template/shared/sqlite-storage-policy.js +111 -0
  238. package/template/shared/sqlite-write-lock.js +428 -0
  239. package/template/wall-e/agent-runners/claude-code.js +5 -0
  240. package/template/wall-e/agent.js +166 -22
  241. package/template/wall-e/api-walle.js +524 -70
  242. package/template/wall-e/auth/provider-flows.js +11 -1
  243. package/template/wall-e/bin/walle-mcp-stdio.js +341 -17
  244. package/template/wall-e/brain.js +1614 -141
  245. package/template/wall-e/chat/attachment-blocks.js +96 -0
  246. package/template/wall-e/chat/attachments.js +2 -1
  247. package/template/wall-e/chat/capability-resolver.js +7 -7
  248. package/template/wall-e/chat/context-messages.js +28 -0
  249. package/template/wall-e/chat/conversation-frame.js +630 -0
  250. package/template/wall-e/chat/provider-messages.js +125 -0
  251. package/template/wall-e/chat.js +1002 -233
  252. package/template/wall-e/coding/acceptance-contract.js +170 -0
  253. package/template/wall-e/coding/acp-adapter.js +1 -1
  254. package/template/wall-e/coding/agent-catalog.js +3 -0
  255. package/template/wall-e/coding/artifact-store.js +93 -0
  256. package/template/wall-e/coding/capability-router.js +120 -0
  257. package/template/wall-e/coding/coding-run-controller.js +423 -0
  258. package/template/wall-e/coding/compaction-service.js +157 -12
  259. package/template/wall-e/coding/frontend-verification.js +258 -0
  260. package/template/wall-e/coding/lifecycle-hooks.js +75 -0
  261. package/template/wall-e/coding/local-preview-contract.js +157 -0
  262. package/template/wall-e/coding/permission-service.js +57 -13
  263. package/template/wall-e/coding/prompt-bundle.js +19 -1
  264. package/template/wall-e/coding/prompt-section-registry.js +227 -0
  265. package/template/wall-e/coding/provider-compat.js +15 -0
  266. package/template/wall-e/coding/runtime-events.js +224 -0
  267. package/template/wall-e/coding/runtime-mode.js +3 -0
  268. package/template/wall-e/coding/side-git-snapshot.js +160 -4
  269. package/template/wall-e/coding/snapshot-service.js +143 -1
  270. package/template/wall-e/coding/stream-processor.js +388 -34
  271. package/template/wall-e/coding/task-tool.js +141 -4
  272. package/template/wall-e/coding/tool-execution-controller.js +365 -0
  273. package/template/wall-e/coding/tool-registry.js +43 -5
  274. package/template/wall-e/coding/user-hooks.js +217 -0
  275. package/template/wall-e/coding-orchestrator.js +1330 -221
  276. package/template/wall-e/coding-prompts.js +20 -4
  277. package/template/wall-e/context/context-builder.js +15 -2
  278. package/template/wall-e/decision/confidence.js +1 -1
  279. package/template/wall-e/docs/coding-acceptance-contract.md +41 -0
  280. package/template/wall-e/docs/external-action-controller.md +26 -6
  281. package/template/wall-e/docs/telemetry-lifecycle.md +8 -2
  282. package/template/wall-e/embeddings.js +591 -53
  283. package/template/wall-e/external-action-controller.js +12 -0
  284. package/template/wall-e/http/auth.js +1 -0
  285. package/template/wall-e/http/chat-api.js +46 -11
  286. package/template/wall-e/http/model-admin.js +836 -34
  287. package/template/wall-e/lib/boot-profile.js +88 -0
  288. package/template/wall-e/lib/event-loop-monitor.js +93 -0
  289. package/template/wall-e/lib/service-health.js +194 -0
  290. package/template/wall-e/llm/anthropic.js +130 -5
  291. package/template/wall-e/llm/client.js +266 -63
  292. package/template/wall-e/llm/default-fallback.js +382 -0
  293. package/template/wall-e/llm/health.js +19 -0
  294. package/template/wall-e/llm/message-guard.js +78 -0
  295. package/template/wall-e/llm/model-catalog.js +252 -1
  296. package/template/wall-e/llm/openai.js +26 -4
  297. package/template/wall-e/llm/portkey-sync.js +654 -0
  298. package/template/wall-e/llm/provider-error.js +30 -2
  299. package/template/wall-e/llm/registry.js +5 -1
  300. package/template/wall-e/llm/request-compat.js +67 -0
  301. package/template/wall-e/loops/backfill.js +79 -23
  302. package/template/wall-e/loops/brain-optimize.js +67 -0
  303. package/template/wall-e/loops/ingest.js +25 -10
  304. package/template/wall-e/loops/question-digest.js +160 -0
  305. package/template/wall-e/loops/reflect.js +6 -4
  306. package/template/wall-e/loops/think.js +39 -12
  307. package/template/wall-e/mcp-server.js +318 -36
  308. package/template/wall-e/memory/ctm-context-client.js +52 -14
  309. package/template/wall-e/memory/ctm-operational-context.js +237 -0
  310. package/template/wall-e/memory/ctm-prompt-executions-client.js +128 -0
  311. package/template/wall-e/memory/ctm-session-context.js +111 -63
  312. package/template/wall-e/prompts/coding/deepseek.txt +3 -0
  313. package/template/wall-e/prompts/coding/gemini.txt +6 -0
  314. package/template/wall-e/prompts/coding/gpt.txt +6 -0
  315. package/template/wall-e/prompts/coding/local.txt +7 -0
  316. package/template/wall-e/runtime/decision-hooks.js +115 -0
  317. package/template/wall-e/runtime/devbox-gateway.js +82 -8
  318. package/template/wall-e/runtime/prompt-manifest.js +86 -0
  319. package/template/wall-e/runtime/tool-executor.js +269 -0
  320. package/template/wall-e/runtime/tool-result-envelope.js +138 -0
  321. package/template/wall-e/runtime/transcript-projection.js +60 -0
  322. package/template/wall-e/runtime/walle-runtime.js +224 -0
  323. package/template/wall-e/scripts/db-optimize/migrate.js +162 -0
  324. package/template/wall-e/scripts/db-optimize/recall-eval.js +117 -0
  325. package/template/wall-e/server.js +15 -0
  326. package/template/wall-e/session-files.js +9 -0
  327. package/template/wall-e/skills/_bundled/google-calendar/run.js +1 -1
  328. package/template/wall-e/skills/_bundled/gws-workspace/run.js +1 -1
  329. package/template/wall-e/skills/_bundled/slack-mentions/run.js +76 -6
  330. package/template/wall-e/skills/claude-code-reader.js +7 -3
  331. package/template/wall-e/skills/script-skill-runner.js +10 -0
  332. package/template/wall-e/skills/skill-planner.js +38 -0
  333. package/template/wall-e/tools/builtin-middleware.js +19 -9
  334. package/template/wall-e/tools/local-tools.js +1428 -16
  335. package/template/wall-e/tools/permission-checker.js +73 -5
  336. package/template/wall-e/tools/question-manager.js +117 -7
  337. package/template/wall-e/training/harvester.js +12 -28
  338. package/template/wall-e/training/replay.js +25 -80
  339. package/template/website/index.html +10 -10
  340. package/template/wall-e/eval/ab-test.js +0 -203
  341. package/template/wall-e/eval/agent-runner.js +0 -772
  342. package/template/wall-e/eval/agent-scorer.js +0 -461
  343. package/template/wall-e/eval/aggregator.js +0 -414
  344. package/template/wall-e/eval/allowed-test-commands.js +0 -34
  345. package/template/wall-e/eval/benchmark-generator.js +0 -113
  346. package/template/wall-e/eval/benchmarks/chat-eval.json +0 -1662
  347. package/template/wall-e/eval/benchmarks/chat.json +0 -82
  348. package/template/wall-e/eval/benchmarks/coding-agent-real.json +0 -1
  349. package/template/wall-e/eval/benchmarks/coding-agent.json +0 -1581
  350. package/template/wall-e/eval/benchmarks/coding.json +0 -122
  351. package/template/wall-e/eval/benchmarks/memory-retrieval.json +0 -234
  352. package/template/wall-e/eval/benchmarks/reasoning.json +0 -82
  353. package/template/wall-e/eval/benchmarks/swebench-lite-30.json +0 -212
  354. package/template/wall-e/eval/benchmarks.js +0 -669
  355. package/template/wall-e/eval/cc-replay.js +0 -719
  356. package/template/wall-e/eval/chat-eval.js +0 -525
  357. package/template/wall-e/eval/check-keys.js +0 -15
  358. package/template/wall-e/eval/check-providers.js +0 -42
  359. package/template/wall-e/eval/codex-cli-baseline.js +0 -669
  360. package/template/wall-e/eval/coding-agent-real.js +0 -570
  361. package/template/wall-e/eval/context-compactor.js +0 -251
  362. package/template/wall-e/eval/debug-agent003.js +0 -68
  363. package/template/wall-e/eval/diagnostics.js +0 -216
  364. package/template/wall-e/eval/eval-orchestrator.js +0 -642
  365. package/template/wall-e/eval/evaluate.js +0 -202
  366. package/template/wall-e/eval/evaluator.js +0 -373
  367. package/template/wall-e/eval/exporter.js +0 -212
  368. package/template/wall-e/eval/fixtures/express-basic/package.json +0 -9
  369. package/template/wall-e/eval/fixtures/express-basic/server.js +0 -115
  370. package/template/wall-e/eval/fixtures/express-basic/test.js +0 -83
  371. package/template/wall-e/eval/fixtures/express-buggy/package.json +0 -9
  372. package/template/wall-e/eval/fixtures/express-buggy/server.js +0 -113
  373. package/template/wall-e/eval/fixtures/express-buggy/test.js +0 -83
  374. package/template/wall-e/eval/fixtures/express-buggy-items/package.json +0 -9
  375. package/template/wall-e/eval/fixtures/express-buggy-items/server.js +0 -112
  376. package/template/wall-e/eval/fixtures/express-buggy-items/test.js +0 -83
  377. package/template/wall-e/eval/fixtures/express-buggy-search/package.json +0 -9
  378. package/template/wall-e/eval/fixtures/express-buggy-search/server.js +0 -121
  379. package/template/wall-e/eval/fixtures/express-buggy-search/test.js +0 -83
  380. package/template/wall-e/eval/fixtures/express-rename-data/data.js +0 -34
  381. package/template/wall-e/eval/fixtures/express-rename-data/package.json +0 -9
  382. package/template/wall-e/eval/fixtures/express-rename-data/server.js +0 -97
  383. package/template/wall-e/eval/fixtures/express-rename-data/test.js +0 -88
  384. package/template/wall-e/eval/fixtures/express-xss/package.json +0 -12
  385. package/template/wall-e/eval/fixtures/express-xss/server.js +0 -90
  386. package/template/wall-e/eval/fixtures/express-xss/test.js +0 -67
  387. package/template/wall-e/eval/fixtures/express-xss/views/profile.ejs +0 -9
  388. package/template/wall-e/eval/fixtures/fullstack-app/config/default.js +0 -9
  389. package/template/wall-e/eval/fixtures/fullstack-app/config/test.js +0 -13
  390. package/template/wall-e/eval/fixtures/fullstack-app/package.json +0 -11
  391. package/template/wall-e/eval/fixtures/fullstack-app/public/css/style.css +0 -137
  392. package/template/wall-e/eval/fixtures/fullstack-app/public/index.html +0 -46
  393. package/template/wall-e/eval/fixtures/fullstack-app/public/js/app.js +0 -121
  394. package/template/wall-e/eval/fixtures/fullstack-app/public/js/auth.js +0 -71
  395. package/template/wall-e/eval/fixtures/fullstack-app/public/js/items.js +0 -80
  396. package/template/wall-e/eval/fixtures/fullstack-app/public/js/users.js +0 -46
  397. package/template/wall-e/eval/fixtures/fullstack-app/public/login.html +0 -45
  398. package/template/wall-e/eval/fixtures/fullstack-app/public/register.html +0 -38
  399. package/template/wall-e/eval/fixtures/fullstack-app/scripts/migrate.js +0 -23
  400. package/template/wall-e/eval/fixtures/fullstack-app/scripts/seed.js +0 -46
  401. package/template/wall-e/eval/fixtures/fullstack-app/server/db.js +0 -99
  402. package/template/wall-e/eval/fixtures/fullstack-app/server/index.js +0 -94
  403. package/template/wall-e/eval/fixtures/fullstack-app/server/middleware/auth.js +0 -19
  404. package/template/wall-e/eval/fixtures/fullstack-app/server/middleware/logger.js +0 -19
  405. package/template/wall-e/eval/fixtures/fullstack-app/server/router.js +0 -50
  406. package/template/wall-e/eval/fixtures/fullstack-app/server/routes/auth.js +0 -69
  407. package/template/wall-e/eval/fixtures/fullstack-app/server/routes/health.js +0 -23
  408. package/template/wall-e/eval/fixtures/fullstack-app/server/routes/items.js +0 -88
  409. package/template/wall-e/eval/fixtures/fullstack-app/server/routes/users.js +0 -75
  410. package/template/wall-e/eval/fixtures/fullstack-app/server/test.js +0 -198
  411. package/template/wall-e/eval/fixtures/fullstack-app/server/utils/response.js +0 -34
  412. package/template/wall-e/eval/fixtures/fullstack-app/server/utils/validate.js +0 -26
  413. package/template/wall-e/eval/fixtures/fullstack-app/server.js +0 -8
  414. package/template/wall-e/eval/fixtures/fullstack-app/test.js +0 -12
  415. package/template/wall-e/eval/fixtures/monorepo-basic/package.json +0 -8
  416. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/data.js +0 -58
  417. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/middleware.js +0 -46
  418. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/package.json +0 -8
  419. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/routes.js +0 -64
  420. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/server.js +0 -56
  421. package/template/wall-e/eval/fixtures/monorepo-basic/packages/api/test.js +0 -116
  422. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/commands.js +0 -61
  423. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/index.js +0 -62
  424. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/output.js +0 -43
  425. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/package.json +0 -11
  426. package/template/wall-e/eval/fixtures/monorepo-basic/packages/cli/test.js +0 -44
  427. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/formatters.js +0 -43
  428. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/index.js +0 -12
  429. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/package.json +0 -5
  430. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/test.js +0 -55
  431. package/template/wall-e/eval/fixtures/monorepo-basic/packages/shared/validators.js +0 -29
  432. package/template/wall-e/eval/fixtures/monorepo-basic/test.js +0 -46
  433. package/template/wall-e/eval/fixtures/node-cli/index.js +0 -78
  434. package/template/wall-e/eval/fixtures/node-cli/package.json +0 -10
  435. package/template/wall-e/eval/fixtures/node-cli/test.js +0 -57
  436. package/template/wall-e/eval/fixtures/node-typed/package.json +0 -8
  437. package/template/wall-e/eval/fixtures/node-typed/src/handlers.js +0 -31
  438. package/template/wall-e/eval/fixtures/node-typed/src/utils.js +0 -33
  439. package/template/wall-e/eval/fixtures/node-typed/test.js +0 -36
  440. package/template/wall-e/eval/fixtures/python-flask/app.py +0 -14
  441. package/template/wall-e/eval/fixtures/python-flask/requirements.txt +0 -2
  442. package/template/wall-e/eval/fixtures/python-flask/test_app.py +0 -25
  443. package/template/wall-e/eval/fixtures/wall-e-subset/brain.js +0 -105
  444. package/template/wall-e/eval/fixtures/wall-e-subset/eval/aggregator.js +0 -101
  445. package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks/chat.json +0 -20
  446. package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks/coding.json +0 -32
  447. package/template/wall-e/eval/fixtures/wall-e-subset/eval/benchmarks.js +0 -64
  448. package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/package.json +0 -6
  449. package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/server.js +0 -31
  450. package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/test.js +0 -18
  451. package/template/wall-e/eval/fixtures/wall-e-subset/eval/fixtures/simple-project/utils.js +0 -34
  452. package/template/wall-e/eval/fixtures/wall-e-subset/eval/runner.js +0 -104
  453. package/template/wall-e/eval/fixtures/wall-e-subset/eval/scorer.js +0 -73
  454. package/template/wall-e/eval/fixtures/wall-e-subset/eval/test.js +0 -134
  455. package/template/wall-e/eval/fixtures/wall-e-subset/llm/client.js +0 -99
  456. package/template/wall-e/eval/fixtures/wall-e-subset/llm/providers.js +0 -63
  457. package/template/wall-e/eval/fixtures/wall-e-subset/llm/test.js +0 -70
  458. package/template/wall-e/eval/fixtures/wall-e-subset/package.json +0 -10
  459. package/template/wall-e/eval/fixtures/wall-e-subset/test.js +0 -86
  460. package/template/wall-e/eval/harvester.js +0 -685
  461. package/template/wall-e/eval/head-to-head.js +0 -388
  462. package/template/wall-e/eval/humaneval-adapter.js +0 -321
  463. package/template/wall-e/eval/list-models.js +0 -31
  464. package/template/wall-e/eval/livecodebench-adapter.js +0 -291
  465. package/template/wall-e/eval/mail-integration.js +0 -443
  466. package/template/wall-e/eval/manifest.js +0 -186
  467. package/template/wall-e/eval/meta-harness/adapters/coding-agent.js +0 -57
  468. package/template/wall-e/eval/meta-harness/bootstrap-snapshot.js +0 -149
  469. package/template/wall-e/eval/meta-harness/candidate-store.js +0 -117
  470. package/template/wall-e/eval/meta-harness/cli.js +0 -86
  471. package/template/wall-e/eval/meta-harness/domain-spec.js +0 -154
  472. package/template/wall-e/eval/meta-harness/domains/coding-agent.domain.json +0 -84
  473. package/template/wall-e/eval/meta-harness/examples/env-bootstrap-candidate.js +0 -29
  474. package/template/wall-e/eval/meta-harness/experience-store.js +0 -174
  475. package/template/wall-e/eval/meta-harness/frontier.js +0 -96
  476. package/template/wall-e/eval/meta-harness/harness-interface.js +0 -90
  477. package/template/wall-e/eval/meta-harness/leakage-guard.js +0 -80
  478. package/template/wall-e/eval/meta-harness/optimizer.js +0 -207
  479. package/template/wall-e/eval/meta-harness/proposer-runner.js +0 -110
  480. package/template/wall-e/eval/meta-harness/reporting.js +0 -58
  481. package/template/wall-e/eval/meta-harness/telemetry.js +0 -27
  482. package/template/wall-e/eval/meta-harness/validation.js +0 -81
  483. package/template/wall-e/eval/promoter.js +0 -228
  484. package/template/wall-e/eval/provider-normalizer.js +0 -33
  485. package/template/wall-e/eval/replay.js +0 -395
  486. package/template/wall-e/eval/run-agent-benchmarks.js +0 -386
  487. package/template/wall-e/eval/run-codex-cli-baseline.js +0 -177
  488. package/template/wall-e/eval/run-coding-agent-real.js +0 -187
  489. package/template/wall-e/eval/run-eval.js +0 -435
  490. package/template/wall-e/eval/run-model-comparison.js +0 -142
  491. package/template/wall-e/eval/session-evaluator.js +0 -187
  492. package/template/wall-e/eval/session-miner.js +0 -207
  493. package/template/wall-e/eval/session-retrieval-benchmark.js +0 -150
  494. package/template/wall-e/eval/session-transcripts.js +0 -509
  495. package/template/wall-e/eval/shadow.js +0 -161
  496. package/template/wall-e/eval/swebench-adapter.js +0 -345
  497. package/template/wall-e/eval/swebench-docker.js +0 -192
  498. package/template/wall-e/eval/train.py +0 -320
  499. package/template/wall-e/eval/trainer.js +0 -232
  500. package/template/wall-e/eval/weekly-eval-loop.js +0 -241
@@ -1,534 +1,13 @@
1
- // --- Headless Terminal Worker Thread ---
2
- // Maintains a @xterm/headless Terminal instance per session (no renderer cost).
3
- // Replaces vterm-worker.js: full xterm.js parser is more accurate for ANSI
4
- // parsing than the custom VTermScreen, and the serialize addon enables instant
5
- // terminal state snapshots for tab-switch restore.
6
- //
7
- // Message protocol:
8
- // Main → Worker:
9
- // { type: 'create', sessionId, cols, rows }
10
- // { type: 'feed', sessionId, data, requestId? }
11
- // { type: 'resize', sessionId, cols, rows }
12
- // { type: 'serialize', sessionId, requestId, scrollback? }
13
- // { type: 'destroy', sessionId }
14
- // { type: 'reset', sessionId }
15
- // { type: 'recheck', sessionId, requestId }
16
- // { type: 'getText', sessionId, requestId }
17
- // { type: 'getRows', sessionId, requestId }
18
- //
19
- // Worker → Main:
20
- // { type: 'feed-result', sessionId, requestId, hasApproval, text?, debugLines }
21
- // { type: 'serialized', sessionId, requestId, data, cols, rows }
22
- // { type: 'text', sessionId, requestId, text }
23
- // { type: 'rows', sessionId, requestId, rows: [{ text, wrapped }] }
1
+ 'use strict';
24
2
 
25
- const { parentPort } = require('worker_threads');
26
- const { Terminal } = require('@xterm/headless');
27
- const { SerializeAddon } = require('@xterm/addon-serialize');
3
+ // Worker-thread wrapper around the shared headless terminal service. The same
4
+ // service also runs inside per-session PTY host processes so snapshot,
5
+ // approval, and row-extraction behavior stays identical across both paths.
28
6
 
29
- const { detectApproval, detectApprovalWithProvider } = require('./approval-patterns');
30
- const { validateWidget } = require('./approval-widget-validator');
31
- const {
32
- MAX_SNAPSHOT_SCROLLBACK_ROWS,
33
- normalizeSnapshotScrollbackRows,
34
- } = require('../lib/terminal-snapshot-options');
7
+ const { parentPort } = require('node:worker_threads');
8
+ const { bindHeadlessTerminalService } = require('../lib/headless-term-service');
35
9
 
36
- // Phase 1 temporal thresholds. Tuned empirically: Claude Code stops
37
- // streaming output ~50ms before showing the prompt; cursor settles within
38
- // a few ms of the final widget draw. We require a margin.
39
- const CURSOR_STABLE_MS = 200;
40
- const OUTPUT_QUIESCENT_MS = 100;
41
- const DIRECT_APPROVAL_SCAN_INTERVAL_MS = 150;
42
-
43
- // Phase 3 cooldown: if the post-keystroke verification fails, we disable
44
- // auto-approval for this session for this window. Prevents a chain of
45
- // false keystrokes from a persistent false positive.
46
- const VERIFY_FAIL_COOLDOWN_MS = 30 * 1000;
47
-
48
- // Per-session headless terminal instances + state
49
- const terminals = new Map(); // sessionId -> { term, serialize, state }
50
-
51
- function getOrCreate(sessionId, cols = 120, rows = 30) {
52
- let entry = terminals.get(sessionId);
53
- if (!entry) {
54
- const term = new Terminal({
55
- cols,
56
- rows,
57
- scrollback: MAX_SNAPSHOT_SCROLLBACK_ROWS,
58
- allowProposedApi: true,
59
- });
60
- const serialize = new SerializeAddon();
61
- term.loadAddon(serialize);
62
- entry = {
63
- term,
64
- serialize,
65
- state: {
66
- cursorY: -1, cursorX: -1,
67
- lastCursorMoveAt: 0,
68
- lastOutputAt: 0,
69
- nextDirectApprovalScanAt: 0,
70
- // Phase 3 verification: set by main thread after it fires a keystroke;
71
- // worker skips emitting approval-alert while this is in the future.
72
- verifyUntil: 0,
73
- // Phase 3 cooldown: set when verification fails; skip all detection
74
- cooldownUntil: 0,
75
- },
76
- };
77
- terminals.set(sessionId, entry);
78
- }
79
- return entry;
80
- }
81
-
82
- /**
83
- * Snapshot the current cursor position; update stability timestamps.
84
- * Called after each feed. Returns the state object.
85
- */
86
- function _trackCursor(entry) {
87
- const now = Date.now();
88
- const buf = entry.term.buffer.active;
89
- const y = buf.cursorY;
90
- const x = buf.cursorX;
91
- const s = entry.state;
92
- if (s.cursorY !== y || s.cursorX !== x) {
93
- s.cursorY = y;
94
- s.cursorX = x;
95
- s.lastCursorMoveAt = now;
96
- }
97
- s.lastOutputAt = now;
98
- return s;
99
- }
100
-
101
- /**
102
- * Phase 1 temporal gate: cursor stable, output quiescent.
103
- */
104
- function _temporalGateOk(state) {
105
- const now = Date.now();
106
- const cursorAge = now - state.lastCursorMoveAt;
107
- const outputAge = now - state.lastOutputAt;
108
- return cursorAge >= CURSOR_STABLE_MS && outputAge >= OUTPUT_QUIESCENT_MS;
109
- }
110
-
111
- /**
112
- * Full gate check — combines Phase 1 temporal + Phase 2 structural +
113
- * Phase 3 cooldown. Returns { ok, reason }.
114
- *
115
- * The order matters for debugging: cheap checks first.
116
- */
117
- function _gateApproval(entry, _text) {
118
- const { state, term } = entry;
119
- const now = Date.now();
120
-
121
- // Phase 3: cooldown after verification failure
122
- if (state.cooldownUntil > now) {
123
- return { ok: false, reason: 'cooldown' };
124
- }
125
-
126
- // Phase 3: in the verification window from a previous keystroke — skip
127
- if (state.verifyUntil > now) {
128
- return { ok: false, reason: 'verify-window' };
129
- }
130
-
131
- // Phase 1: temporal gate (note: temporal is a SOFT signal — we still
132
- // require structural widget detection below, so temporal failure alone
133
- // doesn't reject; we log it as a signal)
134
- // TEMPORAL IS DISABLED IN RECHECK PATH because the recheck fires on a
135
- // timer with no fresh output — both ages would always pass. Keep the
136
- // temporal check advisory only; structural is the primary gate.
137
- // const temporalOk = _temporalGateOk(state);
138
-
139
- // Phase 1+2: structural widget validation. Requires alt-screen active,
140
- // "1. Yes" in bottom rows, widget-like formatting (color or ❯).
141
- const widget = validateWidget(term);
142
- if (!widget.valid) {
143
- return { ok: false, reason: `widget:${widget.reason}` };
144
- }
145
-
146
- return { ok: true, reason: 'ok' };
147
- }
148
-
149
- // Throttle log spam — one line per (session, reason) per 10s.
150
- const _gateMissLog = new Map(); // sessionId -> { reason -> lastLoggedAt }
151
- function _logGateMiss(sessionId, reason) {
152
- const now = Date.now();
153
- let bySession = _gateMissLog.get(sessionId);
154
- if (!bySession) { bySession = new Map(); _gateMissLog.set(sessionId, bySession); }
155
- const last = bySession.get(reason) || 0;
156
- if (now - last < 10000) return;
157
- bySession.set(reason, now);
158
- // Emit a diagnostic to the main thread — main thread logs with session tag
159
- parentPort.postMessage({
160
- type: 'gate-miss',
161
- sessionId,
162
- reason,
163
- });
164
- }
165
-
166
- function _approvalOutputHasHint(text) {
167
- if (!text) return false;
168
- return /do you want|proceed|approve|approval|permission|allow|\byes\b|\bno\b|run this command|bash|edit|tool use|❯|1\.\s*yes|2\.\s*no/i.test(String(text));
169
- }
170
-
171
- // Extract visible text from the terminal buffer (for approval detection).
172
- // Reads the viewport plus a window of scrollback above it so that prompts
173
- // taller than the viewport (e.g. a Codex prompt with a long heredoc command)
174
- // still expose their question/reason/command lines — those scroll above
175
- // viewportY but are still in `buffer.active` for as long as scrollback holds
176
- // them. Without the scrollback window, only the bottom 3-5 lines of the
177
- // option list survive and parsers like codex.parse() fail.
178
- //
179
- // 80 rows = ~2 viewports of headroom on a typical 30-row terminal. Wider
180
- // than any Codex prompt observed in production while bounding the scan cost.
181
- const APPROVAL_SCROLLBACK_ROWS = 80;
182
- function getVisibleText(term) {
183
- const buf = term.buffer.active;
184
- const lines = [];
185
- const start = Math.max(0, buf.viewportY - APPROVAL_SCROLLBACK_ROWS);
186
- const end = buf.viewportY + term.rows;
187
- for (let i = start; i < end; i++) {
188
- const line = buf.getLine(i);
189
- if (line) lines.push(line.translateToString(true));
190
- }
191
- return lines.join('\n');
192
- }
193
-
194
- function getVisibleRows(term) {
195
- const buf = term.buffer.active;
196
- const rows = [];
197
- const start = Math.max(0, buf.viewportY - APPROVAL_SCROLLBACK_ROWS);
198
- const end = buf.viewportY + term.rows;
199
- for (let i = start; i < end; i++) {
200
- const line = buf.getLine(i);
201
- if (line) {
202
- rows.push({
203
- text: line.translateToString(true),
204
- wrapped: !!line.isWrapped,
205
- });
206
- }
207
- }
208
- return rows;
209
- }
210
-
211
- // Queue for pending writes — headless xterm.js write() is async (uses microtask),
212
- // so we need to sequence operations that depend on write completion.
213
- const writeQueues = new Map(); // sessionId -> Promise chain
214
-
215
- // Bound how long a single xterm.js write can block the queue. In rare cases
216
- // (memory pressure, specific ANSI sequences that trip an internal bug)
217
- // `entry.term.write(data, callback)` fails to invoke the callback, which would
218
- // otherwise permanently stall the session's write chain — and with it, all
219
- // approval detection (both direct-feed and recheck await the queue). When
220
- // this fires we force-advance: the terminal state may be slightly stale for
221
- // this one chunk, but new writes unblock and detection resumes.
222
- const WRITE_TIMEOUT_MS = 5000;
223
- // Telemetry: how many times each session tripped the timeout. Surfaced to
224
- // the main thread via 'write-stall' messages so the UI can show a degraded
225
- // badge rather than leaving the user guessing why auto-approve is silent.
226
- const _writeStallCounts = new Map(); // sessionId -> count
227
-
228
- function enqueueWrite(sessionId, data) {
229
- const entry = getOrCreate(sessionId);
230
- const prev = writeQueues.get(sessionId) || Promise.resolve();
231
- const next = prev.then(() => new Promise(resolve => {
232
- let settled = false;
233
- const timer = setTimeout(() => {
234
- if (settled) return;
235
- settled = true;
236
- const count = (_writeStallCounts.get(sessionId) || 0) + 1;
237
- _writeStallCounts.set(sessionId, count);
238
- try {
239
- parentPort.postMessage({ type: 'write-stall', sessionId, count, timeoutMs: WRITE_TIMEOUT_MS });
240
- } catch {}
241
- resolve();
242
- }, WRITE_TIMEOUT_MS);
243
- entry.term.write(data, () => {
244
- if (settled) return;
245
- settled = true;
246
- clearTimeout(timer);
247
- resolve();
248
- });
249
- }));
250
- // Periodically reset the promise chain to prevent unbounded growth.
251
- // After the write completes, replace the chain with a fresh resolved promise.
252
- const reset = next.then(() => {
253
- if (writeQueues.get(sessionId) === reset) writeQueues.set(sessionId, Promise.resolve());
254
- });
255
- writeQueues.set(sessionId, reset);
256
- return next;
257
- }
258
-
259
- // Bounded wait for the pending-writes queue before a detection pass. If the
260
- // queue is stuck behind a slow/never-settling write, proceed with the current
261
- // terminal state (slightly stale, but detection is still useful).
262
- const QUEUE_WAIT_TIMEOUT_MS = 2000;
263
- async function _awaitQueueBounded(sessionId) {
264
- const queue = writeQueues.get(sessionId);
265
- if (!queue) return;
266
- let timer;
267
- const timeoutPromise = new Promise(resolve => {
268
- timer = setTimeout(resolve, QUEUE_WAIT_TIMEOUT_MS);
269
- });
270
- await Promise.race([queue, timeoutPromise]);
271
- if (timer) clearTimeout(timer);
272
- }
273
-
274
- const opQueues = new Map(); // sessionId -> Promise chain for feed/serialize/destroy ordering
275
-
276
- function enqueueSessionOp(sessionId, fn) {
277
- const prev = opQueues.get(sessionId) || Promise.resolve();
278
- let next;
279
- next = prev
280
- .catch(() => {})
281
- .then(fn)
282
- .catch((err) => {
283
- try {
284
- parentPort.postMessage({
285
- type: 'worker-error',
286
- sessionId,
287
- message: err && err.message ? err.message : String(err),
288
- });
289
- } catch {}
290
- })
291
- .finally(() => {
292
- if (opQueues.get(sessionId) === next) opQueues.delete(sessionId);
293
- });
294
- opQueues.set(sessionId, next);
295
- return next;
296
- }
297
-
298
- async function handleMessage(msg) {
299
- switch (msg.type) {
300
- case 'create': {
301
- getOrCreate(msg.sessionId, msg.cols, msg.rows);
302
- break;
303
- }
304
-
305
- case 'feed': {
306
- // Feed data into the headless terminal buffer. Two modes:
307
- //
308
- // 1. Direct feed (no requestId): from PTY onData — keeps headless terminal
309
- // current for snapshots. Also runs lightweight approval detection and sends
310
- // an immediate 'approval-alert' if found. This catches prompts the instant
311
- // they render, regardless of main-thread CPU load or throttle state.
312
- //
313
- // 2. Throttled feed (has requestId): from the approval engine's recheck cycle.
314
- // Sends full feed-result with hasApproval flag. Acts as safety-net fallback
315
- // for prompts missed by the direct-feed path (e.g. multi-chunk rendering).
316
- await enqueueWrite(msg.sessionId, msg.data);
317
-
318
- const entry = terminals.get(msg.sessionId);
319
- if (!entry) break;
320
-
321
- // Phase 1: track cursor/output movement for temporal gating below.
322
- // Called for BOTH direct-feed and throttled-feed so state is always fresh.
323
- _trackCursor(entry);
324
-
325
- if (msg.requestId == null) {
326
- // Direct feed — run real-time approval detection.
327
- if (!_approvalOutputHasHint(msg.data)) break;
328
- const now = Date.now();
329
- if (entry.state.nextDirectApprovalScanAt && now < entry.state.nextDirectApprovalScanAt) break;
330
- entry.state.nextDirectApprovalScanAt = now + DIRECT_APPROVAL_SCAN_INTERVAL_MS;
331
- const text = getVisibleText(entry.term);
332
- const { detected, providerId } = detectApprovalWithProvider(text);
333
- if (!detected) break;
334
- // Phase 1/2/3 gates — see _gateApproval for reasoning.
335
- const gate = _gateApproval(entry, text);
336
- if (!gate.ok) {
337
- // Log once per reason per session to avoid spam.
338
- _logGateMiss(msg.sessionId, gate.reason);
339
- break;
340
- }
341
- parentPort.postMessage({
342
- type: 'approval-alert',
343
- sessionId: msg.sessionId,
344
- providerId,
345
- text,
346
- });
347
- break;
348
- }
349
-
350
- // Throttled recheck path (safety net)
351
- const text = getVisibleText(entry.term);
352
- const { detected: hasApproval, providerId } = detectApprovalWithProvider(text);
353
- // Apply same gating to the throttled path — hasApproval reflects gated decision.
354
- let gatedApproval = hasApproval;
355
- let gateReason = null;
356
- if (hasApproval) {
357
- const gate = _gateApproval(entry, text);
358
- if (!gate.ok) { gatedApproval = false; gateReason = gate.reason; }
359
- }
360
- const allLines = text.split('\n');
361
- const debugLines = allLines.filter(l => l.trim()).slice(-3).map(l => l.trim().slice(0, 80));
362
-
363
- parentPort.postMessage({
364
- type: 'feed-result',
365
- sessionId: msg.sessionId,
366
- requestId: msg.requestId,
367
- hasApproval: gatedApproval,
368
- providerId,
369
- text: gatedApproval ? text : null,
370
- debugLines,
371
- gateReason,
372
- });
373
- break;
374
- }
375
-
376
- case 'recheck': {
377
- // Re-evaluate current screen without feeding new data
378
- const entry = terminals.get(msg.sessionId);
379
- if (!entry) {
380
- // Send empty result so main thread's _workerPending gets cleared
381
- if (msg.requestId != null) {
382
- parentPort.postMessage({
383
- type: 'feed-result', sessionId: msg.sessionId,
384
- requestId: msg.requestId, hasApproval: false, providerId: null, text: null, debugLines: [],
385
- });
386
- }
387
- break;
388
- }
389
- // Wait for any pending writes to complete (bounded — do not hang forever
390
- // on a stuck write queue)
391
- await _awaitQueueBounded(msg.sessionId);
392
-
393
- const text = getVisibleText(entry.term);
394
- const { detected: hasApprovalRaw, providerId } = detectApprovalWithProvider(text);
395
- // Apply full gating on recheck too (structural + cooldown).
396
- // Temporal gate is skipped here because recheck fires without fresh
397
- // output — the structural widget validator is the primary signal.
398
- let hasApproval = hasApprovalRaw;
399
- let gateReason = null;
400
- if (hasApprovalRaw) {
401
- const gate = _gateApproval(entry, text);
402
- if (!gate.ok) { hasApproval = false; gateReason = gate.reason; }
403
- }
404
- const allLines = text.split('\n');
405
- const debugLines = allLines.filter(l => l.trim()).slice(-3).map(l => l.trim().slice(0, 80));
406
-
407
- parentPort.postMessage({
408
- type: 'feed-result',
409
- sessionId: msg.sessionId,
410
- requestId: msg.requestId,
411
- hasApproval,
412
- providerId,
413
- text: hasApproval ? text : null,
414
- debugLines,
415
- gateReason,
416
- });
417
- break;
418
- }
419
-
420
- case 'verify-start': {
421
- // Phase 3: main thread just wrote a keystroke. Enter verification
422
- // window — skip all approval detection until verify-end or window expires.
423
- const entry = terminals.get(msg.sessionId);
424
- if (!entry) break;
425
- entry.state.verifyUntil = Date.now() + (msg.windowMs || 500);
426
- break;
427
- }
428
-
429
- case 'verify-end': {
430
- // Phase 3: main thread observed outcome. If verification failed
431
- // (the keystroke produced no state transition), enter cooldown.
432
- const entry = terminals.get(msg.sessionId);
433
- if (!entry) break;
434
- entry.state.verifyUntil = 0;
435
- if (msg.failed) {
436
- entry.state.cooldownUntil = Date.now() + VERIFY_FAIL_COOLDOWN_MS;
437
- }
438
- break;
439
- }
440
-
441
- case 'resize': {
442
- const entry = terminals.get(msg.sessionId);
443
- if (entry) entry.term.resize(msg.cols, msg.rows);
444
- break;
445
- }
446
-
447
- case 'serialize': {
448
- const entry = terminals.get(msg.sessionId);
449
- if (!entry) {
450
- parentPort.postMessage({
451
- type: 'serialized', sessionId: msg.sessionId,
452
- requestId: msg.requestId, data: '', cols: 120, rows: 30,
453
- });
454
- break;
455
- }
456
- // Wait for any pending writes to complete before serializing (bounded)
457
- await _awaitQueueBounded(msg.sessionId);
458
-
459
- const scrollback = normalizeSnapshotScrollbackRows(msg.scrollback);
460
- const data = entry.serialize.serialize({ scrollback });
461
- parentPort.postMessage({
462
- type: 'serialized',
463
- sessionId: msg.sessionId,
464
- requestId: msg.requestId,
465
- data,
466
- cols: entry.term.cols,
467
- rows: entry.term.rows,
468
- scrollback,
469
- });
470
- break;
471
- }
472
-
473
- case 'getText': {
474
- const entry = terminals.get(msg.sessionId);
475
- if (!entry) {
476
- parentPort.postMessage({ type: 'text', sessionId: msg.sessionId, requestId: msg.requestId, text: '' });
477
- break;
478
- }
479
- await _awaitQueueBounded(msg.sessionId);
480
- const text = getVisibleText(entry.term);
481
- parentPort.postMessage({ type: 'text', sessionId: msg.sessionId, requestId: msg.requestId, text });
482
- break;
483
- }
484
-
485
- case 'getRows': {
486
- const entry = terminals.get(msg.sessionId);
487
- if (!entry) {
488
- parentPort.postMessage({ type: 'rows', sessionId: msg.sessionId, requestId: msg.requestId, rows: [] });
489
- break;
490
- }
491
- await _awaitQueueBounded(msg.sessionId);
492
- const rows = getVisibleRows(entry.term);
493
- parentPort.postMessage({ type: 'rows', sessionId: msg.sessionId, requestId: msg.requestId, rows });
494
- break;
495
- }
496
-
497
- case 'reset': {
498
- const entry = terminals.get(msg.sessionId);
499
- if (entry) {
500
- entry.term.reset();
501
- writeQueues.delete(msg.sessionId);
502
- }
503
- break;
504
- }
505
-
506
- case 'destroy': {
507
- const entry = terminals.get(msg.sessionId);
508
- if (entry) {
509
- await _awaitQueueBounded(msg.sessionId);
510
- entry.term.dispose();
511
- terminals.delete(msg.sessionId);
512
- writeQueues.delete(msg.sessionId);
513
- }
514
- break;
515
- }
516
- }
517
- }
518
-
519
- parentPort.on('message', (msg) => {
520
- const sessionId = msg && msg.sessionId;
521
- if (!sessionId) {
522
- handleMessage(msg).catch((err) => {
523
- try {
524
- parentPort.postMessage({
525
- type: 'worker-error',
526
- sessionId: '',
527
- message: err && err.message ? err.message : String(err),
528
- });
529
- } catch {}
530
- });
531
- return;
532
- }
533
- enqueueSessionOp(sessionId, () => handleMessage(msg));
10
+ bindHeadlessTerminalService({
11
+ postMessage: (msg) => parentPort.postMessage(msg),
12
+ onMessage: (handler) => parentPort.on('message', handler),
534
13
  });