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
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ const CTM_PROCESS_NAME = 'Coding Task Manager';
4
+ const WALLE_PROCESS_NAME = 'Wall-E';
5
+
6
+ function normalizeInstanceTag(tag) {
7
+ const text = String(tag || 'primary').trim();
8
+ return text || 'primary';
9
+ }
10
+
11
+ function legacyProcessTitle(kind, tag = 'primary') {
12
+ const normalized = normalizeInstanceTag(tag);
13
+ return `${kind === 'walle' ? 'walle' : 'ctm'}-${normalized}`;
14
+ }
15
+
16
+ function processTitle(kind, tag = 'primary') {
17
+ const normalized = normalizeInstanceTag(tag);
18
+ const base = kind === 'walle' ? WALLE_PROCESS_NAME : CTM_PROCESS_NAME;
19
+ return normalized === 'primary' ? base : `${base} ${normalized}`;
20
+ }
21
+
22
+ function processTitleCandidates(kind, tag = 'primary') {
23
+ const current = processTitle(kind, tag);
24
+ const legacy = legacyProcessTitle(kind, tag);
25
+ return current === legacy ? [current] : [current, legacy];
26
+ }
27
+
28
+ module.exports = {
29
+ CTM_PROCESS_NAME,
30
+ WALLE_PROCESS_NAME,
31
+ legacyProcessTitle,
32
+ normalizeInstanceTag,
33
+ processTitle,
34
+ processTitleCandidates,
35
+ };
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ // Shared query for /api/prompt-executions, used by BOTH the main-thread handler
4
+ // (api-prompts.js handleListExecutions) and the read-pool worker
5
+ // (read-pool-worker.js 'listPromptExecutions' op) so the two can never diverge —
6
+ // parity by construction. The .all() can return up to 10000 rows each carrying a
7
+ // large message_text, which a CPU profile showed blocking the main event loop
8
+ // ~3.9s on the request path; the worker runs the exact same SQL off-thread.
9
+ function queryPromptExecutions(conn, opts = {}) {
10
+ const limit = Math.max(1, Math.min(parseInt(opts.limit, 10) || 50, 10000));
11
+ const order = String(opts.order || 'desc').toLowerCase() === 'asc' ? 'ASC' : 'DESC';
12
+ const role = opts.role || null;
13
+ const project = opts.project || null;
14
+ const after = opts.after || null;
15
+ let sql = 'SELECT * FROM prompt_executions WHERE 1=1';
16
+ const params = [];
17
+ if (role) { sql += ' AND role = ?'; params.push(role); }
18
+ if (project) { sql += ' AND project_path LIKE ?'; params.push('%' + project + '%'); }
19
+ if (after) { sql += ' AND executed_at > ?'; params.push(after); }
20
+ sql += ` ORDER BY executed_at ${order}, session_id ASC, message_index ASC LIMIT ?`;
21
+ params.push(limit);
22
+ return conn.prepare(sql).all(...params);
23
+ }
24
+
25
+ module.exports = { queryPromptExecutions };
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ // Pure data-shaping for the persisted prompt-index cache (prompt-index-cache.json). The fs I/O,
4
+ // the write throttle, and the live in-memory Map stay in server.js; this module is the testable
5
+ // serialize/deserialize core. Phase 2a: a cold RESTART used to evict the in-memory prompt-index,
6
+ // so every post-restart first-load of apiSessionPrompts paid the ~1.6s compute. Persisting + seeding
7
+ // the last-good indexes lets the storm fallback serve a warm list instead of stormEmpty/_deferred.
8
+
9
+ // Pick the most-recently-remembered N entries (Map iteration order = insertion order; remember()
10
+ // re-inserts on each refresh, so the tail is hottest) and drop pathologically large indexes (keeps
11
+ // the file small + the cold-boot read fast). Returns the on-disk `indexes` object.
12
+ function buildPromptIndexSnapshot(entries, { max = 40, maxPrompts = 2000 } = {}) {
13
+ const list = Array.isArray(entries) ? entries : [];
14
+ const tail = list.slice(Math.max(0, list.length - Math.max(1, max)));
15
+ const indexes = {};
16
+ for (const [sid, r] of tail) {
17
+ if (!sid || !r || !Array.isArray(r.messages)) continue;
18
+ if (r.messages.length > maxPrompts) continue;
19
+ indexes[sid] = { messages: r.messages, summary: r.summary || null };
20
+ }
21
+ return indexes;
22
+ }
23
+
24
+ // Parse a persisted file's JSON text into [{ sid, value }] ready to seed the live Map. Returns []
25
+ // on any malformed/empty input — this is a best-effort cache and must never throw into the boot path.
26
+ function parsePromptIndexSnapshot(jsonText) {
27
+ try {
28
+ const parsed = JSON.parse(jsonText);
29
+ const indexes = parsed && parsed.indexes && typeof parsed.indexes === 'object' ? parsed.indexes : null;
30
+ if (!indexes) return [];
31
+ const out = [];
32
+ for (const sid of Object.keys(indexes)) {
33
+ const r = indexes[sid];
34
+ if (r && Array.isArray(r.messages)) {
35
+ out.push({ sid, value: { messages: r.messages, summary: r.summary || null } });
36
+ }
37
+ }
38
+ return out;
39
+ } catch {
40
+ return [];
41
+ }
42
+ }
43
+
44
+ module.exports = { buildPromptIndexSnapshot, parsePromptIndexSnapshot };
@@ -0,0 +1,132 @@
1
+ 'use strict';
2
+
3
+ // AI accuracy backstop for "what is this terminal frame?" — a prompt-INTENT classifier
4
+ // (approval / choice / none) that the server consults ONLY when the structural detectors
5
+ // conflict (assessAmbiguity), deduped per frame (frameFingerprint), with a pure hold
6
+ // decision (resolveIntentDecision) the server drives. The LLM call itself is
7
+ // classifyPromptIntent (added in Task 2). Pure parts here so they unit-test without I/O.
8
+
9
+ const { evaluateWaitState, _fnv1a } = require('./wait-state');
10
+ const terminalChoice = require('./terminal-choice');
11
+ const { callBackgroundLlm } = require('./background-llm');
12
+ let approvalAgent = null;
13
+ try { approvalAgent = require('../approval-agent'); } catch { approvalAgent = null; }
14
+
15
+ // Stable per-frame key shared by the reconcile and approver paths so a frame is
16
+ // classified ONCE regardless of which sees it first. Hash of the cleaned tail.
17
+ function frameFingerprint(viewportText) {
18
+ const s = String(viewportText || '').replace(/[ \t]+$/gm, '');
19
+ return 'intent:' + _fnv1a(s.slice(-600));
20
+ }
21
+
22
+ // First token of a real shell command. A parsed "command" whose head isn't a plausible
23
+ // binary/builtin (or that reads like prose) signals a low-confidence parse.
24
+ const _COMMAND_HEAD_RE = /^[\w][\w.\/-]*$/; // \w = [A-Za-z0-9_] — allow digit-leading binaries (1password, 2to3)
25
+ function _titleLooksLikeCommand(title) {
26
+ const t = String(title || '').trim();
27
+ if (!t) return false;
28
+ // Prose markers a one-line command would not contain (sentence punctuation + filler).
29
+ if (/[.?!]\s/.test(t) || /\b(but|and|the|allow-list|permission)\b/i.test(t)) return false;
30
+ const head = t.split(/\s+/)[0] || '';
31
+ return _COMMAND_HEAD_RE.test(head);
32
+ }
33
+
34
+ // Pure ambiguity assessment over a settled frame. Returns { ambiguous, reasons }.
35
+ // ambiguous:true ONLY when structural signals conflict / are low-confidence — a
36
+ // confident frame returns false and the AI is never called.
37
+ function assessAmbiguity({ providerId, viewportText } = {}) {
38
+ const text = String(viewportText || '');
39
+ const reasons = [];
40
+ if (!text.trim()) return { ambiguous: false, reasons };
41
+
42
+ const ws = evaluateWaitState({ providerId, viewportText: text });
43
+ const liveApproval = !!(approvalAgent && typeof approvalAgent.isLiveApprovalPrompt === 'function'
44
+ && approvalAgent.isLiveApprovalPrompt(text));
45
+
46
+ // 1) Approver gate matched a live prompt, but the canonical evaluator sees no widget
47
+ // (none/input) — a shape one detector recognizes and the other does not.
48
+ if (liveApproval && (ws.kind === 'none' || ws.kind === 'input')) {
49
+ reasons.push('approver-live-but-evaluator-' + ws.kind);
50
+ }
51
+
52
+ // 2) Parsed an approval context whose derived title does not look like a command
53
+ // (Unknown tool or scraped prose) — low-confidence parse.
54
+ if (approvalAgent && typeof approvalAgent.parseApprovalContext === 'function') {
55
+ let ctx = null;
56
+ try { ctx = approvalAgent.parseApprovalContext(text, providerId); } catch { ctx = null; }
57
+ if (ctx) {
58
+ let title = '';
59
+ try { title = (approvalAgent.escalationCommandParts(ctx).title) || ''; } catch { title = ''; }
60
+ if (ctx.toolName === 'Unknown' || !_titleLooksLikeCommand(title)) reasons.push('low-confidence-parse');
61
+ }
62
+ }
63
+
64
+ // 3) A numbered menu with NON-yes/no options while an approval-style question is on
65
+ // screen — the approval<->choice tie (AskUserQuestion that reads like a prompt).
66
+ let menu = null;
67
+ try { menu = terminalChoice.extractTerminalChoice(text); } catch { menu = null; }
68
+ if (menu && Array.isArray(menu.options) && menu.options.length >= 2) {
69
+ const first = String((menu.options[0] && menu.options[0].label) || '').trim();
70
+ const firstYesNo = /^(yes|no|allow|deny|approve|reject|proceed|cancel|accept)\b/i.test(first);
71
+ const askApproval = /\bdo you want to\b/i.test(text) || /\?\s*$/m.test(text);
72
+ if (!firstYesNo && askApproval) reasons.push('nonyesno-menu-with-approval-question');
73
+ }
74
+
75
+ return { ambiguous: reasons.length > 0, reasons };
76
+ }
77
+
78
+ const INTENT_SYSTEM = `You classify what an AI coding CLI's terminal screen is currently asking for. Reply with ONLY JSON: {"intent":"approval"|"choice"|"none","reason":"<=1 sentence"}.
79
+
80
+ Definitions:
81
+ - "approval": the CLI is asking PERMISSION to run a TOOL or SHELL COMMAND it proposed (e.g. "Do you want to proceed?" with Yes/No, an edit/command confirmation). Acting on it means pressing yes/approve.
82
+ - "choice": the AGENT is asking the USER to answer a question or pick among several non-yes/no options (e.g. an AskUserQuestion menu: "Which approach?" 1/2/3/4). There is nothing to auto-approve; the user must choose.
83
+ - "none": no live interactive prompt — the agent is working/thinking, or the screen is prose/output.
84
+
85
+ When unsure between "approval" and "choice", answer "choice" — never treat a user-facing question as an approval.`;
86
+
87
+ const INTENT_TIMEOUT_MS = 5000;
88
+
89
+ // Async LLM classification. Returns { intent:'approval'|'choice'|'none'|'unknown',
90
+ // reason, durationMs, error? }. ANY failure (disabled provider, timeout, bad JSON,
91
+ // bad value) -> intent:'unknown' so the caller falls back to the structural verdict.
92
+ async function classifyPromptIntent(viewportText, { reasons, goal, cwd } = {}, { callModel, timeoutMs } = {}) {
93
+ const started = Date.now();
94
+ const call = callModel || callBackgroundLlm;
95
+ const screen = String(viewportText || '').replace(/[ \t]+$/gm, '').slice(-1600);
96
+ const ctxLine = (goal || cwd)
97
+ ? `Session goal: ${String(goal || '').slice(0, 200)}\nCwd: ${String(cwd || '').slice(0, 200)}\n`
98
+ : '';
99
+ const why = Array.isArray(reasons) && reasons.length ? `Detectors disagreed: ${reasons.join(', ')}.\n` : '';
100
+ const prompt = `${ctxLine}${why}Terminal screen (bottom of viewport):\n"""\n${screen}\n"""\n\nReturn ONLY: {"intent":"approval|choice|none","reason":"..."}`;
101
+
102
+ let response;
103
+ try {
104
+ response = await call(prompt, { system: INTENT_SYSTEM, maxTokens: 120, temperature: 0, timeoutMs: timeoutMs || INTENT_TIMEOUT_MS });
105
+ } catch (e) {
106
+ return { intent: 'unknown', reason: '', error: e.reason || e.message || String(e), durationMs: Date.now() - started };
107
+ }
108
+ const text = (response && (response.text ?? response)) || '';
109
+ const match = String(text).match(/\{[\s\S]*\}/);
110
+ if (!match) return { intent: 'unknown', reason: '', error: 'no JSON in response', durationMs: Date.now() - started };
111
+ let parsed;
112
+ try { parsed = JSON.parse(match[0]); } catch (e) { return { intent: 'unknown', reason: '', error: `parse: ${e.message}`, durationMs: Date.now() - started }; }
113
+ const intent = ['approval', 'choice', 'none'].includes(parsed.intent) ? parsed.intent : 'unknown';
114
+ const reason = typeof parsed.reason === 'string' ? parsed.reason.slice(0, 200) : '';
115
+ if (intent === 'unknown') return { intent, reason, error: 'bad intent value', durationMs: Date.now() - started };
116
+ return { intent, reason, durationMs: Date.now() - started };
117
+ }
118
+
119
+ // Pure decision the server drives for the brief hold. Inputs are the current cache /
120
+ // pending entries for the session plus the frame fp and clock. Output tells the server
121
+ // what to do this tick. (cachedIntent === null means a prior classification fell back.)
122
+ function resolveIntentDecision({ cachedFp, cachedIntent, pendingFp, pendingDeadline, fp, now, holdMs } = {}) {
123
+ if (cachedFp === fp) {
124
+ return cachedIntent ? { action: 'use', intent: cachedIntent } : { action: 'fallback' };
125
+ }
126
+ if (pendingFp === fp) {
127
+ return now < pendingDeadline ? { action: 'hold' } : { action: 'fallback' };
128
+ }
129
+ return { action: 'start', deadline: now + (holdMs || INTENT_TIMEOUT_MS) };
130
+ }
131
+
132
+ module.exports = { frameFingerprint, assessAmbiguity, classifyPromptIntent, resolveIntentDecision, _titleLooksLikeCommand, INTENT_TIMEOUT_MS };
@@ -0,0 +1,34 @@
1
+ 'use strict';
2
+
3
+ // Provider CLIs sometimes persist operational context as `role=user` so it is
4
+ // available to the model. These rows are not human-authored prompts and should
5
+ // not be projected into CTM timelines, prompt history, or message search.
6
+ const PROVIDER_GENERATED_USER_CONTEXT_PATTERNS = [
7
+ /^<environment_context>/i,
8
+ /^<permissions instructions>/i,
9
+ /^<collaboration_mode>/i,
10
+ /^<skills_instructions>/i,
11
+ /^<plugins_instructions>/i,
12
+ /^<task-notification>/i,
13
+ /^<skill>\s*<name>/i,
14
+ /^# AGENTS\.md instructions for\b/i,
15
+ /^Base directory for this skill:\s+/i,
16
+ /^This session is being continued from a previous conversation\b/i,
17
+ /^Continue from where you left off\b/i,
18
+ /^Compacted\b/i,
19
+ /^\[Image:\s*source:\s*(?:"[^"]+"|'[^']+'|[^\]]+)\]$/i,
20
+ /^\[Image:\s*original\s+\d+(?:\.\d+)?x\d+(?:\.\d+)?,\s*displayed at\s+\d+(?:\.\d+)?x\d+(?:\.\d+)?\.\s*Multiply coordinates by\s+[0-9.]+\s+to map to original image\.?\]$/i,
21
+ /^\[Request interrupted by user(?: for tool use)?\]$/i,
22
+ ];
23
+
24
+ function isProviderGeneratedUserContextText(text) {
25
+ const cleaned = String(text || '').trim();
26
+ if (!cleaned) return false;
27
+ if (/^<turn_aborted>\s*[\s\S]*?<\/turn_aborted>\s*$/i.test(cleaned)) return true;
28
+ return PROVIDER_GENERATED_USER_CONTEXT_PATTERNS.some((pattern) => pattern.test(cleaned));
29
+ }
30
+
31
+ module.exports = {
32
+ PROVIDER_GENERATED_USER_CONTEXT_PATTERNS,
33
+ isProviderGeneratedUserContextText,
34
+ };
@@ -0,0 +1,313 @@
1
+ 'use strict';
2
+
3
+ // Client for the read/parse worker pool (workers/read-pool-worker.js).
4
+ //
5
+ // A small fixed pool of DB-free workers that absorb the CPU/IO-heavy *read*
6
+ // work (JSONL parse, batch fs.stat) that otherwise blocks the main event loop.
7
+ // Unlike the serial db-owner worker, this is a POOL: requests dispatch to the
8
+ // least-busy worker so concurrent Conversation-tab loads + scan jobs run in
9
+ // parallel instead of head-of-line blocking each other.
10
+ //
11
+ // Each worker processes its own queue serially (one op at a time), which is why
12
+ // "least in-flight" is the right load metric. Mirrors the message protocol and
13
+ // robustness (timeouts, fatal/exit handling, reject-all) of
14
+ // lib/db-owner-worker-client.js.
15
+
16
+ const os = require('node:os');
17
+ const path = require('node:path');
18
+ const { Worker } = require('node:worker_threads');
19
+
20
+ const DEFAULT_REQUEST_TIMEOUT_MS = 30 * 1000;
21
+ const DEFAULT_CLOSE_TIMEOUT_MS = 5 * 1000;
22
+ const MIN_POOL_SIZE = 3;
23
+ // Raised 8→12: the cores-2 default wants 14 on a 16-core box but was capped at 8, needlessly
24
+ // throttling heavy-op concurrency (parse / prompt-index / getAllSessionsData all contend). 12
25
+ // leaves ~4 cores for the main loop + db-owner worker. Each worker is a thread + a read-only WAL
26
+ // connection (WAL allows many readers); smaller boxes still clamp to cores-2. CTM_READ_POOL_SIZE
27
+ // overrides up to this cap.
28
+ const MAX_POOL_SIZE = 12;
29
+
30
+ // Ops whose cost scales with transcript/blob size (seconds, not bounded ms) and
31
+ // can monopolize a worker during the cold-boot restore storm. They share the pool
32
+ // with latency-sensitive bounded reads (getAllSessionsData, listRichWorktrees,
33
+ // autoTitleCandidates, statFiles, …). If a heavy op occupies EVERY worker, those
34
+ // small reads queue behind a 10–30s parse, hit their request timeout, and fall
35
+ // back to the MAIN THREAD — which is exactly the [offthread-read:*] "falling back
36
+ // to main" cascade + 28s event-loop freeze seen at boot. We cap concurrent heavy
37
+ // ops below the pool size so ≥1 worker is always free for the light reads.
38
+ const HEAVY_OPS = new Set([
39
+ 'parseSessionFiles',
40
+ 'parseConversationBlob',
41
+ 'computeUserPromptIndex',
42
+ 'loadCursorConversation',
43
+ 'sessionIntegrityDetect', // ~60s full-corpus scan on cold Dropbox
44
+ 'auditRelink', // restore-path relink audit: full scan + per-agent cold-JSONL reads
45
+ ]);
46
+ // Keep this many workers out of heavy reach so light reads never head-of-line
47
+ // block behind a heavy parse. Clamped so tiny pools still allow ≥1 heavy op.
48
+ const RESERVED_LIGHT_WORKERS = 2;
49
+
50
+ function _durationMs(value, fallback) {
51
+ const n = Number(value);
52
+ return Number.isFinite(n) ? Math.max(0, Math.trunc(n)) : fallback;
53
+ }
54
+
55
+ // Core-aware default. A fixed 3 starved the pool during the 20-session restore storm:
56
+ // getAllSessionsData + the prompt-index compute + parseSessionFiles all contend on the same
57
+ // workers, so the small latency-sensitive reads timed out (5s) and fell back to a main-thread
58
+ // build/compute — the early-boot freezes the event-loop budget surfaced. On a 16-core box
59
+ // 3 of 16 cores is a needless bottleneck. Scale to cores-2 (capped at MAX) so the boot
60
+ // concurrency has room; CTM_READ_POOL_SIZE still overrides.
61
+ function _coreAwareDefaultPoolSize() {
62
+ let cores = 0;
63
+ try { cores = (typeof os.availableParallelism === 'function' ? os.availableParallelism() : os.cpus().length) || 0; } catch {}
64
+ return Math.min(MAX_POOL_SIZE, Math.max(MIN_POOL_SIZE, cores - 2));
65
+ }
66
+
67
+ function _resolvePoolSize(requested) {
68
+ const raw = requested ?? process.env.CTM_READ_POOL_SIZE;
69
+ const n = Number(raw);
70
+ if (Number.isFinite(n) && n >= 1) return Math.min(MAX_POOL_SIZE, Math.trunc(n));
71
+ return _coreAwareDefaultPoolSize();
72
+ }
73
+
74
+ // One worker_thread + its in-flight bookkeeping. Lazily (re)spawned on first use
75
+ // and respawned transparently after a crash so a single bad parse can't take the
76
+ // pool down permanently.
77
+ class _PoolWorker {
78
+ constructor(opts) {
79
+ this.workerPath = opts.workerPath;
80
+ this.logger = opts.logger || console;
81
+ this.worker = null;
82
+ this.ready = false;
83
+ this.startPromise = null;
84
+ this.pending = new Map(); // requestId -> { resolve, reject, timer }
85
+ this.nextRequestId = 1;
86
+ this.heavyInFlight = 0; // heavy ops currently running on THIS worker
87
+ }
88
+
89
+ get inFlight() { return this.pending.size; }
90
+
91
+ start() {
92
+ if (this.ready) return Promise.resolve(this);
93
+ if (this.startPromise) return this.startPromise;
94
+ this.startPromise = new Promise((resolve, reject) => {
95
+ const worker = new Worker(this.workerPath, { env: { ...process.env } });
96
+ this.worker = worker;
97
+
98
+ const failStart = (err) => {
99
+ if (this.ready) return;
100
+ this.startPromise = null;
101
+ this.worker = null;
102
+ try { worker.terminate(); } catch {}
103
+ reject(err instanceof Error ? err : new Error(String(err || 'read-pool worker failed to start')));
104
+ };
105
+
106
+ worker.on('message', (msg) => {
107
+ if (!msg || typeof msg !== 'object') return;
108
+ if (msg.type === 'ready') { this.ready = true; resolve(this); return; }
109
+ if (msg.type === 'response') { this._finish(msg.requestId, msg.error, msg.result); return; }
110
+ if (msg.type === 'fatal') {
111
+ const err = new Error(msg.message || 'read-pool worker fatal error');
112
+ if (!this.ready) failStart(err);
113
+ this._rejectAll(err);
114
+ return;
115
+ }
116
+ // 'status' / 'closed' are advisory for the pool — nothing to track.
117
+ });
118
+ worker.on('error', (err) => {
119
+ if (!this.ready) failStart(err);
120
+ this._rejectAll(err);
121
+ });
122
+ worker.on('exit', (code) => {
123
+ const wasReady = this.ready;
124
+ this.ready = false;
125
+ this.worker = null;
126
+ this.startPromise = null;
127
+ const err = new Error(`read-pool worker exited with code ${code}`);
128
+ if (!wasReady) failStart(err);
129
+ // Reject in-flight so callers fail fast and fall back to the main thread;
130
+ // a fresh worker is spawned on the next request.
131
+ if (code !== 0) this._rejectAll(err);
132
+ else this._rejectAll(new Error('read-pool worker closed'));
133
+ });
134
+ });
135
+ return this.startPromise;
136
+ }
137
+
138
+ async request(op, payload, timeoutMs) {
139
+ await this.start();
140
+ if (!this.worker) throw new Error('read-pool worker is not running');
141
+ const requestId = this.nextRequestId++;
142
+ return await new Promise((resolve, reject) => {
143
+ let timer = null;
144
+ if (timeoutMs > 0) {
145
+ timer = setTimeout(() => {
146
+ this.pending.delete(requestId);
147
+ reject(new Error(`read-pool request timed out: ${op}`));
148
+ }, timeoutMs);
149
+ if (typeof timer.unref === 'function') timer.unref();
150
+ }
151
+ this.pending.set(requestId, { resolve, reject, timer });
152
+ try {
153
+ this.worker.postMessage({ type: 'request', requestId, op, payload });
154
+ } catch (err) {
155
+ this._finish(requestId, err);
156
+ }
157
+ });
158
+ }
159
+
160
+ _finish(requestId, error, result) {
161
+ const p = this.pending.get(requestId);
162
+ if (!p) return;
163
+ this.pending.delete(requestId);
164
+ if (p.timer) clearTimeout(p.timer);
165
+ if (error) {
166
+ const err = error instanceof Error ? error : new Error(String(error.message || error || 'read-pool request failed'));
167
+ if (error.code) err.code = error.code;
168
+ p.reject(err);
169
+ } else {
170
+ p.resolve(result);
171
+ }
172
+ }
173
+
174
+ _rejectAll(err) {
175
+ const all = Array.from(this.pending.values());
176
+ this.pending.clear();
177
+ for (const p of all) { if (p.timer) clearTimeout(p.timer); p.reject(err); }
178
+ }
179
+
180
+ async close(timeoutMs) {
181
+ const worker = this.worker;
182
+ if (!worker) { this._rejectAll(new Error('read-pool worker closed')); return; }
183
+ await new Promise((resolve) => {
184
+ let done = false;
185
+ const finish = () => { if (done) return; done = true; resolve(); };
186
+ let timer = null;
187
+ if (timeoutMs > 0) {
188
+ timer = setTimeout(() => { worker.terminate().finally(finish); }, timeoutMs);
189
+ if (typeof timer.unref === 'function') timer.unref();
190
+ }
191
+ const onMessage = (msg) => {
192
+ if (msg?.type !== 'closed') return;
193
+ if (timer) clearTimeout(timer);
194
+ worker.off('message', onMessage);
195
+ finish();
196
+ };
197
+ worker.on('message', onMessage);
198
+ try { worker.postMessage({ type: 'close' }); }
199
+ catch { if (timer) clearTimeout(timer); worker.off('message', onMessage); worker.terminate().finally(finish); }
200
+ });
201
+ this.ready = false;
202
+ this.worker = null;
203
+ this._rejectAll(new Error('read-pool worker closed'));
204
+ }
205
+ }
206
+
207
+ class CtmReadPoolClient {
208
+ constructor(options = {}) {
209
+ this.workerPath = options.workerPath || path.resolve(__dirname, '..', 'workers', 'read-pool-worker.js');
210
+ this.size = _resolvePoolSize(options.size);
211
+ this.requestTimeoutMs = _durationMs(options.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS);
212
+ this.closeTimeoutMs = _durationMs(options.closeTimeoutMs, DEFAULT_CLOSE_TIMEOUT_MS);
213
+ this.logger = options.logger || console;
214
+ this._closed = false;
215
+ this._workers = [];
216
+ for (let i = 0; i < this.size; i++) {
217
+ this._workers.push(new _PoolWorker({ workerPath: this.workerPath, logger: this.logger }));
218
+ }
219
+ // Heavy-op admission control: reserve a couple of workers for latency-sensitive
220
+ // light reads so a heavy parse can't occupy the whole pool (see HEAVY_OPS note).
221
+ this._maxHeavy = Math.max(1, this.size - Math.min(RESERVED_LIGHT_WORKERS, this.size - 1));
222
+ this._heavyInFlight = 0; // heavy ops running across the whole pool
223
+ this._heavyWaiters = []; // FIFO of resolvers waiting for a heavy slot
224
+ }
225
+
226
+ _acquireHeavySlot() {
227
+ if (this._heavyInFlight < this._maxHeavy) {
228
+ this._heavyInFlight++;
229
+ return Promise.resolve();
230
+ }
231
+ return new Promise((resolve) => this._heavyWaiters.push(resolve));
232
+ }
233
+
234
+ _releaseHeavySlot() {
235
+ const next = this._heavyWaiters.shift();
236
+ // Hand the slot directly to the next waiter (count is conserved); otherwise free it.
237
+ if (next) next();
238
+ else this._heavyInFlight = Math.max(0, this._heavyInFlight - 1);
239
+ }
240
+
241
+ async start() {
242
+ if (this._closed) throw new Error('read pool is closed');
243
+ await Promise.all(this._workers.map((w) => w.start()));
244
+ return this;
245
+ }
246
+
247
+ _leastBusy() {
248
+ let best = this._workers[0];
249
+ for (const w of this._workers) {
250
+ if (w.inFlight < best.inFlight) best = w;
251
+ }
252
+ return best;
253
+ }
254
+
255
+ // Pick a worker for a request. Light reads prefer a worker with NO heavy op in
256
+ // flight (the reserved capacity), so they never wait behind a multi-second parse;
257
+ // among eligible workers, least-in-flight wins. Heavy ops just take least-busy.
258
+ _pickWorker(heavy) {
259
+ if (!heavy) {
260
+ let best = null;
261
+ for (const w of this._workers) {
262
+ if (w.heavyInFlight > 0) continue;
263
+ if (!best || w.inFlight < best.inFlight) best = w;
264
+ }
265
+ if (best) return best;
266
+ }
267
+ return this._leastBusy();
268
+ }
269
+
270
+ async request(op, payload = {}, options = {}) {
271
+ if (this._closed) throw new Error('read pool is closed');
272
+ if (!op) throw new Error('read pool request requires op');
273
+ const timeoutMs = _durationMs(options.timeoutMs, this.requestTimeoutMs);
274
+ const heavy = options.heavy ?? HEAVY_OPS.has(op);
275
+ if (!heavy) return await this._pickWorker(false).request(op, payload, timeoutMs);
276
+
277
+ // Heavy op: wait for an admission slot, then dispatch to the least-busy worker.
278
+ await this._acquireHeavySlot();
279
+ const worker = this._pickWorker(true);
280
+ worker.heavyInFlight++;
281
+ try {
282
+ return await worker.request(op, payload, timeoutMs);
283
+ } finally {
284
+ worker.heavyInFlight = Math.max(0, worker.heavyInFlight - 1);
285
+ this._releaseHeavySlot();
286
+ }
287
+ }
288
+
289
+ getStatus() {
290
+ return {
291
+ size: this.size,
292
+ closed: this._closed,
293
+ maxHeavy: this._maxHeavy,
294
+ heavyInFlight: this._heavyInFlight,
295
+ heavyWaiting: this._heavyWaiters.length,
296
+ workers: this._workers.map((w) => ({ ready: w.ready, inFlight: w.inFlight, heavyInFlight: w.heavyInFlight })),
297
+ inFlight: this._workers.reduce((s, w) => s + w.inFlight, 0),
298
+ };
299
+ }
300
+
301
+ async close() {
302
+ if (this._closed) return { ok: true, alreadyClosed: true };
303
+ this._closed = true;
304
+ await Promise.all(this._workers.map((w) => w.close(this.closeTimeoutMs).catch(() => {})));
305
+ return { ok: true };
306
+ }
307
+ }
308
+
309
+ function createReadPoolClient(options = {}) {
310
+ return new CtmReadPoolClient(options);
311
+ }
312
+
313
+ module.exports = { CtmReadPoolClient, createReadPoolClient };
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ // Generic circuit breaker for off-thread read-pool calls (getAllSessionsData, the prompt
4
+ // index compute, message/timeline parse, ...). At early boot a worker's read-only
5
+ // connection can't attach to the WAL shared-memory until a writer is established + the DB
6
+ // settles, so the request times out. Without a breaker, every off-thread call in that
7
+ // window waits the full timeout and then falls back to a cold main-thread build.
8
+ //
9
+ // After `degradeAfter` consecutive failures the breaker OPENS for `cooldownMs`; while open,
10
+ // the caller SKIPS the off-thread attempt (serving cache/SWR) rather than timing out into a
11
+ // main build. One success CLOSES it (half-open: the first attempt after the cooldown probes
12
+ // the pool again). Pure + injectable clock for testing.
13
+
14
+ function createReadPoolBreaker({ degradeAfter = 2, cooldownMs = 30000 } = {}) {
15
+ const _degradeAfter = Math.max(1, Number(degradeAfter) || 1);
16
+ const _cooldownMs = Math.max(0, Number(cooldownMs) || 0);
17
+ let failures = 0;
18
+ let openUntil = 0;
19
+ return {
20
+ isOpen(now) { return Number(now) < openUntil; },
21
+ recordFailure(now) {
22
+ failures += 1;
23
+ if (failures >= _degradeAfter) openUntil = Number(now) + _cooldownMs;
24
+ return { failures, openUntil };
25
+ },
26
+ recordSuccess() { failures = 0; openUntil = 0; },
27
+ getState() { return { failures, openUntil, degradeAfter: _degradeAfter, cooldownMs: _cooldownMs }; },
28
+ };
29
+ }
30
+
31
+ module.exports = { createReadPoolBreaker };
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ // Back-compat re-export. The circuit breaker is now the generic lib/readpool-breaker.js
4
+ // (shared by getAllSessionsData, the prompt-index compute, and future off-thread reads).
5
+ // `createRecentSessionsBreaker` remains as an alias so existing imports keep working.
6
+
7
+ const { createReadPoolBreaker } = require('./readpool-breaker');
8
+
9
+ module.exports = {
10
+ createReadPoolBreaker,
11
+ createRecentSessionsBreaker: createReadPoolBreaker,
12
+ };