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
@@ -39,6 +39,40 @@ function textBlocks(text) {
39
39
  return [{ type: 'text', text: String(text || '') }];
40
40
  }
41
41
 
42
+ function attachmentMetadata(attachments) {
43
+ if (!Array.isArray(attachments) || attachments.length === 0) return [];
44
+ return attachments
45
+ .filter((attachment) => attachment && typeof attachment === 'object')
46
+ .map((attachment, index) => {
47
+ const out = {
48
+ type: attachment.type || 'image',
49
+ label: attachment.label || `[Image #${index + 1}]`,
50
+ };
51
+ const copy = [
52
+ 'name',
53
+ 'filename',
54
+ 'mediaType',
55
+ 'mimeType',
56
+ 'url',
57
+ 'path',
58
+ 'file_path',
59
+ 'id',
60
+ 'imageWidth',
61
+ 'imageHeight',
62
+ 'originalWidth',
63
+ 'originalHeight',
64
+ 'resizedForProvider',
65
+ 'byteSize',
66
+ ];
67
+ for (const key of copy) {
68
+ if (attachment[key] !== undefined && attachment[key] !== null && attachment[key] !== '') {
69
+ out[key] = attachment[key];
70
+ }
71
+ }
72
+ return out;
73
+ });
74
+ }
75
+
42
76
  function appendRecord(filePath, record) {
43
77
  ensureDirForFile(filePath);
44
78
  const offset = fs.existsSync(filePath) ? fs.statSync(filePath).size : 0;
@@ -105,6 +139,8 @@ function appendUserMessage(filePath, opts = {}) {
105
139
  const record = baseMessage(opts, 'user', 'user');
106
140
  if (opts.modelId) record.modelId = opts.modelId;
107
141
  if (opts.modelProvider) record.modelProvider = opts.modelProvider;
142
+ const attachments = attachmentMetadata(opts.attachments);
143
+ if (attachments.length) record.attachments = attachments;
108
144
  return appendRecord(filePath, record);
109
145
  }
110
146
 
@@ -165,6 +201,21 @@ function readLastUuid(filePath) {
165
201
  return '';
166
202
  }
167
203
 
204
+ function readSessionMeta(filePath) {
205
+ let raw;
206
+ try { raw = fs.readFileSync(filePath, 'utf8'); } catch { return null; }
207
+ const lines = raw.split('\n').filter(Boolean);
208
+ for (const line of lines) {
209
+ try {
210
+ const row = JSON.parse(line);
211
+ if (row && row.type === 'session_meta') return row;
212
+ } catch {
213
+ // Ignore malformed tail rows; the transcript writer is append-only.
214
+ }
215
+ }
216
+ return null;
217
+ }
218
+
168
219
  module.exports = {
169
220
  VERSION,
170
221
  WALLE_PROJECT_ENTRY,
@@ -177,4 +228,5 @@ module.exports = {
177
228
  appendPart,
178
229
  extractText,
179
230
  readLastUuid,
231
+ readSessionMeta,
180
232
  };
@@ -1,11 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  function normalizeLiveStatus(status) {
4
- const text = String(status || '').toLowerCase();
4
+ const text = String(status || '').toLowerCase().replace(/[-\s]+/g, '_');
5
5
  if (!text) return '';
6
- if (text === 'busy') return 'running';
7
- if (text === 'waiting-for-input') return 'waiting_input';
8
- if (['running', 'waiting', 'waiting_input', 'idle', 'exited'].includes(text)) return text;
6
+ if (text === 'busy' || text === 'active' || text === 'working' || text === 'thinking') return 'running';
7
+ if (text === 'restoring' || text === 'resuming' || text === 'restore_starting' || text === 'restarting') return 'resuming';
8
+ if (text === 'waiting_for_input') return 'waiting_input';
9
+ if (['running', 'resuming', 'waiting', 'waiting_input', 'idle', 'exited'].includes(text)) return text;
9
10
  return '';
10
11
  }
11
12
 
@@ -59,8 +60,11 @@ function activeSyncWorktreePolicy(wt, quiescence, opts = {}) {
59
60
  if (!wt.branch || wt.branch === 'HEAD' || wt.state === 'detached') {
60
61
  return { ok: false, status: quiescence.status, reason: 'Recover this worktree onto a branch before syncing from main.' };
61
62
  }
62
- if ((wt.dirtyFiles || 0) > 0) {
63
- return { ok: false, status: quiescence.status, reason: 'Commit or stash dirty files before syncing from main.' };
63
+ const trackedDirty = wt.trackedDirtyFiles != null
64
+ ? Number(wt.trackedDirtyFiles || 0)
65
+ : Math.max(0, Number(wt.dirtyFiles || 0) - Number(wt.untrackedFiles || 0));
66
+ if (trackedDirty > 0) {
67
+ return { ok: false, status: quiescence.status, reason: 'Commit or stash tracked dirty files before syncing from main.' };
64
68
  }
65
69
  if ((wt.ahead || 0) > 0 || wt.state === 'diverged') {
66
70
  return {
@@ -75,7 +79,7 @@ function activeSyncWorktreePolicy(wt, quiescence, opts = {}) {
75
79
  return {
76
80
  ok: true,
77
81
  status: quiescence.status,
78
- reason: 'Active session is idle and the worktree is clean; sync can proceed with confirmation.',
82
+ reason: 'Active session is idle and tracked files are clean; sync can proceed with confirmation.',
79
83
  };
80
84
  }
81
85
 
@@ -32,9 +32,19 @@ function realpathOrResolve(p) {
32
32
  }
33
33
  }
34
34
 
35
+ // resolveWorktreeRepoRoot does 2 synchronous git execs (rev-parse --show-toplevel +
36
+ // worktree list --porcelain) plus realpath/stat. It's hit on the worktree API hot path
37
+ // (~per request), and a CPU profile showed these synchronous execFileSync calls blocking
38
+ // the event loop. The repo root for a given cwd is invariant (always the primary checkout,
39
+ // regardless of worktrees being added/removed), so cache successful resolutions briefly.
40
+ const _repoRootCache = new Map(); // raw cwd -> { at, result }
41
+ const _REPO_ROOT_CACHE_TTL_MS = Number(process.env.CTM_WORKTREE_REPO_ROOT_CACHE_TTL_MS || 60000);
42
+
35
43
  function resolveWorktreeRepoRoot(cwd) {
36
44
  if (typeof cwd !== 'string' || !cwd.trim()) return fail('cwd is required');
37
45
  const raw = cwd.trim();
46
+ const cached = _repoRootCache.get(raw);
47
+ if (cached && (Date.now() - cached.at) < _REPO_ROOT_CACHE_TTL_MS) return cached.result;
38
48
  if (raw.includes('~')) {
39
49
  return fail('cwd must be an absolute path with no `~` (the literal-tilde is the source of ghost worktrees).');
40
50
  }
@@ -70,13 +80,34 @@ function resolveWorktreeRepoRoot(cwd) {
70
80
  primaryRoot = '';
71
81
  }
72
82
 
73
- return {
83
+ const result = {
74
84
  ok: true,
75
85
  cwd: realpathOrResolve(primaryRoot || topLevel),
76
86
  requestedCwd: realCwd,
77
87
  };
88
+ // Cache only successful resolutions (a failing cwd may be created later). Bound the map.
89
+ if (_repoRootCache.size > 200) _repoRootCache.clear();
90
+ _repoRootCache.set(raw, { at: Date.now(), result });
91
+ return result;
92
+ }
93
+
94
+ function resolveWorktreeRepoRootWithFallback(cwd, fallbackCwd) {
95
+ const primary = resolveWorktreeRepoRoot(cwd);
96
+ if (primary.ok) return { ...primary, fallbackUsed: false };
97
+
98
+ const fallback = resolveWorktreeRepoRoot(fallbackCwd);
99
+ if (!fallback.ok) return primary;
100
+
101
+ return {
102
+ ...fallback,
103
+ fallbackUsed: true,
104
+ fallbackReason: primary.error,
105
+ fallbackStatus: primary.status || 400,
106
+ requestedCwd: primary.requestedCwd || cwd,
107
+ };
78
108
  }
79
109
 
80
110
  module.exports = {
81
111
  resolveWorktreeRepoRoot,
112
+ resolveWorktreeRepoRootWithFallback,
82
113
  };
@@ -32,7 +32,7 @@
32
32
  "@simplewebauthn/server": "^13.3.0",
33
33
  "@xterm/addon-serialize": "^0.14.0",
34
34
  "@xterm/headless": "^6.0.0",
35
- "better-sqlite3": "^12.8.0",
35
+ "better-sqlite3": "^12.10.0",
36
36
  "node-pty": "^1.2.0-beta.12",
37
37
  "puppeteer": "^24.41.0",
38
38
  "qrcode": "^1.5.4",
@@ -177,8 +177,16 @@ function harvestSession(filePath, projectPath) {
177
177
  `);
178
178
 
179
179
  let count = 0;
180
- const txn = d.transaction(() => {
181
- for (const msg of parsed.messages) {
180
+ // Insert in BOUNDED BATCHES, each its OWN transaction. A long active session can carry
181
+ // thousands of messages; wrapping them all in a single transaction held the db-owner
182
+ // write lock for tens of seconds (observed 34–59s), which busy-waits CTM's main-loop
183
+ // synchronous reads and freezes the loop — long enough that the Wall-E MCP readiness
184
+ // probe times out 3× and CTM raises a false "MCP never became ready". Committing in
185
+ // small batches releases the lock between batches so the main loop + other writers can
186
+ // interleave. INSERT OR IGNORE keeps it idempotent across batches/runs.
187
+ const BATCH = Math.max(1, Number(process.env.CTM_HARVEST_MSG_BATCH || 250));
188
+ const insertBatch = d.transaction((slice) => {
189
+ for (const msg of slice) {
182
190
  // Save images and collect refs
183
191
  const imageRefs = [];
184
192
  if (msg.images) {
@@ -219,7 +227,11 @@ function harvestSession(filePath, projectPath) {
219
227
  }
220
228
  }
221
229
  });
222
- txn();
230
+
231
+ const msgs = parsed.messages;
232
+ for (let i = 0; i < msgs.length; i += BATCH) {
233
+ insertBatch(msgs.slice(i, i + BATCH));
234
+ }
223
235
  return count;
224
236
  }
225
237
 
@@ -1003,84 +1015,95 @@ function refreshLifecycleStatuses() {
1003
1015
  const now = Date.now();
1004
1016
  const STALE_DAYS = 30;
1005
1017
 
1006
- const updateStmt = d.prepare(`UPDATE prompts SET lifecycle_status = ?, updated_at = datetime('now') WHERE id = ?`);
1007
-
1008
- const txn = d.transaction(() => {
1009
- for (const prompt of prompts) {
1010
- const currentStatus = prompt.lifecycle_status || 'draft';
1011
- // Skip manually managed statuses
1012
- if (currentStatus === 'template' || currentStatus === 'archived') continue;
1013
-
1014
- const content = (prompt.content || '').trim();
1015
- if (content.length < 15) continue;
1016
-
1017
- // Find sessions where this prompt's text appears
1018
- const matchedSessions = new Set();
1019
- let latestMatch = null;
1020
-
1021
- // 1. Check explicit sends via prompt_usage
1022
- const explicitSessions = usageByPrompt.get(prompt.id);
1023
- if (explicitSessions) {
1024
- for (const sid of explicitSessions) matchedSessions.add(sid);
1025
- }
1018
+ // Phase 1 MATCH (read + CPU only, NO write lock). This nested loop is
1019
+ // O(prompts × execs × words) substring matching over arrays already loaded
1020
+ // above; it touches no DB and must not hold the SQLite write lock. It used to
1021
+ // run inside d.transaction(), which pinned the write lock for 80-90s on the
1022
+ // db-owner worker and fail-fasted every main-thread write — most visibly the
1023
+ // hotkey screenshot INSERT ("took screenshot, nothing happens"). Computing the
1024
+ // status changes here and applying them in a separate short transaction below
1025
+ // drops the lock hold from ~90s to milliseconds.
1026
+ for (const prompt of prompts) {
1027
+ const currentStatus = prompt.lifecycle_status || 'draft';
1028
+ // Skip manually managed statuses
1029
+ if (currentStatus === 'template' || currentStatus === 'archived') continue;
1030
+
1031
+ const content = (prompt.content || '').trim();
1032
+ if (content.length < 15) continue;
1033
+
1034
+ // Find sessions where this prompt's text appears
1035
+ const matchedSessions = new Set();
1036
+ let latestMatch = null;
1037
+
1038
+ // 1. Check explicit sends via prompt_usage
1039
+ const explicitSessions = usageByPrompt.get(prompt.id);
1040
+ if (explicitSessions) {
1041
+ for (const sid of explicitSessions) matchedSessions.add(sid);
1042
+ }
1026
1043
 
1027
- // 2. Text-match against harvested session messages
1028
- const contentWords = content.toLowerCase().split(/\s+/).filter(w => w.length > 4);
1029
- if (contentWords.length >= 3) {
1030
- const contentNorm = normalizePrompt(content);
1031
- const minMatchCount = Math.max(3, Math.ceil(contentWords.length * 0.5));
1044
+ // 2. Text-match against harvested session messages
1045
+ const contentWords = content.toLowerCase().split(/\s+/).filter(w => w.length > 4);
1046
+ if (contentWords.length >= 3) {
1047
+ const contentNorm = normalizePrompt(content);
1048
+ const minMatchCount = Math.max(3, Math.ceil(contentWords.length * 0.5));
1032
1049
 
1033
- for (const exec of allExecs) {
1034
- if (matchedSessions.has(exec.session_id) && latestMatch) continue;
1050
+ for (const exec of allExecs) {
1051
+ if (matchedSessions.has(exec.session_id) && latestMatch) continue;
1035
1052
 
1036
- const execLower = exec.message_text.toLowerCase();
1053
+ const execLower = exec.message_text.toLowerCase();
1037
1054
 
1038
- let matchCount = 0;
1039
- for (const w of contentWords) {
1040
- if (execLower.includes(w)) matchCount++;
1041
- }
1055
+ let matchCount = 0;
1056
+ for (const w of contentWords) {
1057
+ if (execLower.includes(w)) matchCount++;
1058
+ }
1042
1059
 
1043
- const matched = matchCount >= minMatchCount;
1044
- let substringMatched = false;
1045
- if (!matched) {
1046
- const execNorm = normalizePrompt(exec.message_text);
1047
- substringMatched = execNorm.length >= 30 && (execNorm.includes(contentNorm.slice(0, 80)) || contentNorm.includes(execNorm.slice(0, 80)));
1048
- }
1060
+ const matched = matchCount >= minMatchCount;
1061
+ let substringMatched = false;
1062
+ if (!matched) {
1063
+ const execNorm = normalizePrompt(exec.message_text);
1064
+ substringMatched = execNorm.length >= 30 && (execNorm.includes(contentNorm.slice(0, 80)) || contentNorm.includes(execNorm.slice(0, 80)));
1065
+ }
1049
1066
 
1050
- if (matched || substringMatched) {
1051
- matchedSessions.add(exec.session_id);
1052
- if (!latestMatch || (exec.executed_at && exec.executed_at > latestMatch)) {
1053
- latestMatch = exec.executed_at;
1054
- }
1067
+ if (matched || substringMatched) {
1068
+ matchedSessions.add(exec.session_id);
1069
+ if (!latestMatch || (exec.executed_at && exec.executed_at > latestMatch)) {
1070
+ latestMatch = exec.executed_at;
1055
1071
  }
1056
1072
  }
1057
1073
  }
1074
+ }
1058
1075
 
1059
- const sessionCount = matchedSessions.size;
1060
- let newStatus = currentStatus;
1076
+ const sessionCount = matchedSessions.size;
1077
+ let newStatus = currentStatus;
1061
1078
 
1062
- if (sessionCount >= 3 && (currentStatus === 'draft' || currentStatus === 'used')) {
1063
- newStatus = 'frequent';
1064
- } else if (sessionCount >= 1 && currentStatus === 'draft') {
1065
- newStatus = 'used';
1066
- }
1079
+ if (sessionCount >= 3 && (currentStatus === 'draft' || currentStatus === 'used')) {
1080
+ newStatus = 'frequent';
1081
+ } else if (sessionCount >= 1 && currentStatus === 'draft') {
1082
+ newStatus = 'used';
1083
+ }
1067
1084
 
1068
- if (newStatus !== currentStatus) {
1069
- updateStmt.run(newStatus, prompt.id);
1070
- updated.push({ id: prompt.id, title: prompt.title, from: currentStatus, to: newStatus, sessions: sessionCount });
1071
- }
1085
+ if (newStatus !== currentStatus) {
1086
+ updated.push({ id: prompt.id, title: prompt.title, from: currentStatus, to: newStatus, sessions: sessionCount });
1087
+ }
1072
1088
 
1073
- // Check staleness (for used/frequent prompts only)
1074
- if ((newStatus === 'used' || newStatus === 'frequent') && latestMatch) {
1075
- const lastUsedDate = new Date(latestMatch);
1076
- const daysSince = (now - lastUsedDate.getTime()) / 86400000;
1077
- if (daysSince > STALE_DAYS) {
1078
- stale.push({ id: prompt.id, title: prompt.title, status: newStatus, daysSinceUsed: Math.round(daysSince), lastUsed: latestMatch });
1079
- }
1089
+ // Check staleness (for used/frequent prompts only)
1090
+ if ((newStatus === 'used' || newStatus === 'frequent') && latestMatch) {
1091
+ const lastUsedDate = new Date(latestMatch);
1092
+ const daysSince = (now - lastUsedDate.getTime()) / 86400000;
1093
+ if (daysSince > STALE_DAYS) {
1094
+ stale.push({ id: prompt.id, title: prompt.title, status: newStatus, daysSinceUsed: Math.round(daysSince), lastUsed: latestMatch });
1080
1095
  }
1081
1096
  }
1082
- });
1083
- txn();
1097
+ }
1098
+
1099
+ // Phase 2 — APPLY (write lock held only for the handful of status UPDATEs).
1100
+ if (updated.length > 0) {
1101
+ const updateStmt = d.prepare(`UPDATE prompts SET lifecycle_status = ?, updated_at = datetime('now') WHERE id = ?`);
1102
+ const applyTxn = d.transaction((rows) => {
1103
+ for (const u of rows) updateStmt.run(u.to, u.id);
1104
+ });
1105
+ applyTxn(updated);
1106
+ }
1084
1107
 
1085
1108
  // Update last_lifecycle_refresh_at watermark
1086
1109
  const refreshedAt = new Date().toISOString().replace('T', ' ').replace('Z', '');
@@ -5,12 +5,43 @@
5
5
 
6
6
  const APPROVAL_RE = /Do you want to (proceed|make this edit to .+|create .+|overwrite .+)\??/;
7
7
  const BROAD_APPROVAL_RE = /Do you want to .+\?/;
8
+ // File-operation prompts render only the diff above them — no "Write"/"Edit"
9
+ // tool header. Derive the operation + target file from the prompt line itself so
10
+ // the approver treats it as a normal Edit/Write instead of an "Unknown" shell
11
+ // command that risk-scores the file's CODE CONTENT (and so never cleanly
12
+ // auto-approves / mis-routes to the verifier).
13
+ const FILE_OP_RE = /Do you want to (make this edit to|overwrite|create)\s+(.+?)\s*\??$/i;
14
+ function deriveFileOpTool(proceedLine) {
15
+ const m = FILE_OP_RE.exec(String(proceedLine || ''));
16
+ if (!m) return null;
17
+ return {
18
+ toolName: /make this edit/i.test(m[1]) ? 'Edit' : 'Write',
19
+ command: m[2].trim(),
20
+ };
21
+ }
8
22
  const YES_RE = /^\D*1\.\s*Yes\b/;
9
23
  const ESC_CANCEL_RE = /Esc to cancel/;
24
+ // MCP tool-use prompts have no "Bash command"-style header; the tool identity
25
+ // is the line ending in "(MCP)" (e.g. `plugin:playwright:playwright – Navigate
26
+ // to a URL(url: "…") (MCP)`) or a raw `mcp__…` / `plugin:…` tool name.
27
+ const MCP_TOOL_LINE_RE = /\(MCP\)\s*$/i;
28
+ const MCP_TOOL_NAME_RE = /^(?:[⏺●]\s*)?(?:plugin:|mcp__)/i;
29
+
30
+ // Reduce an MCP tool line to a stable tool name for rule-matching / display:
31
+ // drop the leading bullet, the trailing "(MCP)", and the volatile "(args…)".
32
+ function cleanMcpToolName(line) {
33
+ let s = String(line || '').trim().replace(/^[⏺●]\s*/, '');
34
+ s = s.replace(/\s*\(MCP\)\s*$/i, '');
35
+ const argIdx = s.indexOf('(');
36
+ if (argIdx > 0) s = s.slice(0, argIdx).trim();
37
+ return s || 'MCP tool';
38
+ }
39
+ const DURABLE_YES_OPTION_RE = /^\s*(?:[❯›▶▸>]\s*)?2\.\s*Yes,\s*(allow all|allow\b.*\b(?:for|from) this project\b|(?:and\s+)?allow\s+access\s+to\b.*\b(?:and\s+similar\s+commands|for\s+this\s+session)\b|and\s+allow\s+Claude\b.*\bthis\s+session\b|and don't ask again|and always allow)/i;
10
40
 
11
41
  module.exports = {
12
42
  id: 'claude-code',
13
43
  name: 'Claude Code',
44
+ deriveFileOpTool,
14
45
 
15
46
  detect(text) {
16
47
  const allLines = text.split('\n');
@@ -56,7 +87,7 @@ module.exports = {
56
87
  for (let i = proceedIdx - 1; i >= Math.max(proceedIdx - 3, 0); i--) {
57
88
  const line = lines[i];
58
89
  if (!line) continue;
59
- if (/command contains|could write|could modify|could delete|could overwrite|which can|permission|dangerous|destructive|overwrite|will modify|will delete|will overwrite|execute arbitrary|shell command substitution/i.test(line)) {
90
+ if (/command contains|could write|could modify|could delete|could overwrite|which can|permission|dangerous|destructive|overwrite|will modify|will delete|will overwrite|execute arbitrary|executes commands|modifies files|cannot be auto-allowed|shell command substitution/i.test(line)) {
60
91
  warning = line;
61
92
  break;
62
93
  }
@@ -79,10 +110,27 @@ module.exports = {
79
110
  toolName = line.trim();
80
111
  break;
81
112
  }
113
+ // MCP tool-use prompt: capture the real tool name (no longer "Unknown") so
114
+ // the heuristic, learned rules, and "don't ask again" can target it. Keep
115
+ // the full descriptor (with args/URL) in the command for the reviewer.
116
+ if (MCP_TOOL_LINE_RE.test(line) || MCP_TOOL_NAME_RE.test(line)) {
117
+ toolName = cleanMcpToolName(line);
118
+ contextLines.unshift(line.trim());
119
+ break;
120
+ }
82
121
  contextLines.unshift(line);
83
122
  }
84
123
 
85
- const command = contextLines.join('\n').trim();
124
+ // No tool header above the diff → this is one of Claude's file-operation
125
+ // prompts ("overwrite/create/make this edit to <file>?"). Use the operation
126
+ // and target file as tool/command so it auto-approves as a normal Edit/Write.
127
+ let fileOpCommand = '';
128
+ if (!toolName) {
129
+ const fileOp = deriveFileOpTool(lines[proceedIdx]);
130
+ if (fileOp) { toolName = fileOp.toolName; fileOpCommand = fileOp.command; }
131
+ }
132
+
133
+ const command = (fileOpCommand || contextLines.join('\n')).trim();
86
134
 
87
135
  const ctxStart = Math.max(0, endIdx - (contextLines.length + 1));
88
136
  const ctxEnd = Math.min(lines.length, proceedIdx + 5);
@@ -90,7 +138,7 @@ module.exports = {
90
138
 
91
139
  let hasAllowAll = false;
92
140
  for (let i = proceedIdx + 1; i < Math.min(proceedIdx + 8, lines.length); i++) {
93
- if (/^\s*(?:[❯›▶▸>]\s*)?2\.\s*Yes,\s*(allow all|allow\b.*\b(?:for|from) this project\b|and don't ask again|and always allow)/i.test(lines[i])) { hasAllowAll = true; break; }
141
+ if (DURABLE_YES_OPTION_RE.test(lines[i])) { hasAllowAll = true; break; }
94
142
  }
95
143
 
96
144
  return {