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,162 @@
1
+ 'use strict';
2
+ // Brain-DB space optimization core + CLI. Idempotent, safe to run repeatedly.
3
+ // 1. Embeddings: convert embedding_vec_ollama float32 -> int8 IN PLACE (same table name)
4
+ // 2. memories_fts -> external-content + maintenance triggers
5
+ // 3. content_raw: NULL where byte-identical to content (readers use content_raw ?? content)
6
+ // 4. lost_and_found: drop (orphaned .recover residue) — only when opts.dropLostAndFound
7
+ // 5. VACUUM (opts.vacuum)
8
+ //
9
+ // Exposed as a function so the deferred upgrader loop (loops/brain-optimize.js) and the CLI
10
+ // share one implementation. The caller must have sqlite-vec loaded on `db` (the daemon's
11
+ // connection already does; the CLI loads it below).
12
+ //
13
+ // CLI: <node25> migrate.js <dbPath> [--no-vacuum] [--keep-lost-and-found]
14
+
15
+ function declaredVecType(db, t) {
16
+ const r = db.prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name=?").get(t);
17
+ if (!r || !r.sql) return null;
18
+ if (/\bint8\s*\[/.test(r.sql)) return 'int8';
19
+ if (/\bfloat\s*\[/.test(r.sql)) return 'float';
20
+ return '?';
21
+ }
22
+ function has(db, name) { return !!db.prepare("SELECT 1 FROM sqlite_master WHERE name=?").get(name); }
23
+
24
+ // True if any optimization is still pending (used to skip no-op work / gate the loop).
25
+ function needsOptimization(db) {
26
+ if (has(db, 'embedding_vec_ollama') && declaredVecType(db, 'embedding_vec_ollama') === 'float') return true;
27
+ const fts = db.prepare("SELECT sql FROM sqlite_master WHERE name='memories_fts'").get();
28
+ if (fts && !/content\s*=\s*'memories'/.test(fts.sql)) return true;
29
+ if (has(db, 'memories')) {
30
+ const red = db.prepare("SELECT 1 FROM memories WHERE content_raw IS NOT NULL AND content_raw=content LIMIT 1").get();
31
+ if (red) return true;
32
+ }
33
+ return false;
34
+ }
35
+ function embeddingCount(db) {
36
+ try { return db.prepare("SELECT COUNT(*) c FROM embedding_vec_ollama").get().c; } catch { return 0; }
37
+ }
38
+
39
+ function _migrateEmbeddings(db, log) {
40
+ const T = 'embedding_vec_ollama';
41
+ if (!has(db, T)) { log('embeddings: no', T, '- skip'); return; }
42
+ const type = declaredVecType(db, T);
43
+ if (type === 'int8') { log('embeddings: already int8 - skip'); return; }
44
+ if (type !== 'float') { log('embeddings: unexpected type', type, '- skip'); return; }
45
+ const dims = (db.prepare("SELECT sql FROM sqlite_master WHERE name=?").get(T).sql.match(/\[(\d+)\]/) || [])[1] || '768';
46
+ const n = db.prepare(`SELECT COUNT(*) c FROM ${T}`).get().c;
47
+ const tmp = T + '_i8mig';
48
+ log(`embeddings: quantizing ${n} float32[${dims}] vectors -> int8...`);
49
+ db.exec('BEGIN');
50
+ db.exec(`DROP TABLE IF EXISTS "${tmp}"`);
51
+ db.exec(`CREATE VIRTUAL TABLE "${tmp}" USING vec0(embedding int8[${dims}])`);
52
+ db.exec(`INSERT INTO "${tmp}"(rowid, embedding) SELECT rowid, vec_quantize_int8(embedding,'unit') FROM "${T}"`);
53
+ db.exec(`DROP TABLE "${T}"`);
54
+ db.exec(`CREATE VIRTUAL TABLE "${T}" USING vec0(embedding int8[${dims}])`);
55
+ db.exec(`INSERT INTO "${T}"(rowid, embedding) SELECT rowid, embedding FROM "${tmp}"`);
56
+ db.exec(`DROP TABLE "${tmp}"`);
57
+ db.exec('COMMIT');
58
+ const after = db.prepare(`SELECT COUNT(*) c FROM ${T}`).get().c;
59
+ if (after !== n) throw new Error(`embedding row count changed ${n} -> ${after}`);
60
+ log(`embeddings: done, ${after} int8 vectors`);
61
+ }
62
+
63
+ function _ftsTriggers(db) {
64
+ db.exec(`CREATE TRIGGER memories_fts_insert AFTER INSERT ON memories BEGIN
65
+ INSERT INTO memories_fts(rowid, content, source, participants, source_channel)
66
+ VALUES (NEW.rowid, NEW.content, NEW.source, COALESCE(NEW.participants,''), COALESCE(NEW.source_channel,''));
67
+ END`);
68
+ db.exec(`CREATE TRIGGER memories_fts_delete AFTER DELETE ON memories BEGIN
69
+ INSERT INTO memories_fts(memories_fts, rowid, content, source, participants, source_channel)
70
+ VALUES('delete', OLD.rowid, OLD.content, OLD.source, COALESCE(OLD.participants,''), COALESCE(OLD.source_channel,''));
71
+ END`);
72
+ db.exec(`CREATE TRIGGER memories_fts_update AFTER UPDATE ON memories BEGIN
73
+ INSERT INTO memories_fts(memories_fts, rowid, content, source, participants, source_channel)
74
+ VALUES('delete', OLD.rowid, OLD.content, OLD.source, COALESCE(OLD.participants,''), COALESCE(OLD.source_channel,''));
75
+ INSERT INTO memories_fts(rowid, content, source, participants, source_channel)
76
+ VALUES (NEW.rowid, NEW.content, NEW.source, COALESCE(NEW.participants,''), COALESCE(NEW.source_channel,''));
77
+ END`);
78
+ }
79
+ function _migrateFts(db, log) {
80
+ const cur = db.prepare("SELECT sql FROM sqlite_master WHERE name='memories_fts'").get();
81
+ if (!cur) { log('fts: no memories_fts - skip'); return; }
82
+ if (/content\s*=\s*'memories'/.test(cur.sql)) { log('fts: already external-content - skip'); return; }
83
+ log('fts: converting to external-content...');
84
+ db.exec('BEGIN');
85
+ db.exec('DROP TRIGGER IF EXISTS memories_fts_insert');
86
+ db.exec('DROP TRIGGER IF EXISTS memories_fts_delete');
87
+ db.exec('DROP TRIGGER IF EXISTS memories_fts_update');
88
+ db.exec('DROP TABLE memories_fts');
89
+ db.exec(`CREATE VIRTUAL TABLE memories_fts USING fts5(
90
+ content, source, participants, source_channel,
91
+ content='memories', content_rowid='rowid', tokenize='porter unicode61')`);
92
+ db.exec(`INSERT INTO memories_fts(memories_fts) VALUES('rebuild')`);
93
+ _ftsTriggers(db);
94
+ db.exec('COMMIT');
95
+ log('fts: external-content + triggers installed, rebuilt');
96
+ }
97
+
98
+ function _migrateContentRaw(db, log) {
99
+ if (!has(db, 'memories')) return;
100
+ const n = db.prepare("SELECT COUNT(*) c FROM memories WHERE content_raw IS NOT NULL AND content_raw=content").get().c;
101
+ if (n === 0) { log('content_raw: nothing redundant - skip'); return; }
102
+ const hadTrig = !!db.prepare("SELECT 1 FROM sqlite_master WHERE name='memories_fts_update'").get();
103
+ db.exec('BEGIN');
104
+ if (hadTrig) db.exec('DROP TRIGGER IF EXISTS memories_fts_update'); // content unchanged -> FTS unaffected
105
+ const r = db.prepare("UPDATE memories SET content_raw=NULL WHERE content_raw IS NOT NULL AND content_raw=content").run();
106
+ if (hadTrig) db.exec(`CREATE TRIGGER memories_fts_update AFTER UPDATE ON memories BEGIN
107
+ INSERT INTO memories_fts(memories_fts, rowid, content, source, participants, source_channel)
108
+ VALUES('delete', OLD.rowid, OLD.content, OLD.source, COALESCE(OLD.participants,''), COALESCE(OLD.source_channel,''));
109
+ INSERT INTO memories_fts(rowid, content, source, participants, source_channel)
110
+ VALUES (NEW.rowid, NEW.content, NEW.source, COALESCE(NEW.participants,''), COALESCE(NEW.source_channel,''));
111
+ END`);
112
+ db.exec('COMMIT');
113
+ log(`content_raw: nulled ${r.changes} redundant rows`);
114
+ }
115
+
116
+ function _dropLostAndFound(db, log) {
117
+ if (!has(db, 'lost_and_found')) { log('lost_and_found: absent - skip'); return; }
118
+ db.exec('DROP TABLE lost_and_found');
119
+ log('lost_and_found: dropped');
120
+ }
121
+
122
+ /**
123
+ * Run the space optimization on an open better-sqlite3 `db` that already has sqlite-vec loaded.
124
+ * opts: { vacuum=true, dropLostAndFound=false, log=console.log }
125
+ * Each phase is idempotent and transactional; the float32 vectors are never dropped until the
126
+ * int8 copy is built and verified in the same transaction (a crash rolls back to float32).
127
+ */
128
+ function optimizeBrain(db, opts = {}) {
129
+ const { vacuum = true, dropLostAndFound = false, log = () => {} } = opts;
130
+ _migrateEmbeddings(db, log);
131
+ _migrateFts(db, log);
132
+ _migrateContentRaw(db, log);
133
+ if (dropLostAndFound) _dropLostAndFound(db, log);
134
+ if (vacuum) { log('vacuuming...'); db.exec('VACUUM'); try { db.pragma('wal_checkpoint(TRUNCATE)'); } catch {} }
135
+ }
136
+
137
+ module.exports = { optimizeBrain, needsOptimization, embeddingCount, declaredVecType };
138
+
139
+ // ---- CLI ----
140
+ if (require.main === module) {
141
+ const path = require('path');
142
+ const WE = path.resolve(__dirname, '..', '..');
143
+ const Database = require(path.join(WE, 'node_modules', 'better-sqlite3'));
144
+ const vec = require(path.join(WE, 'node_modules', 'sqlite-vec'));
145
+ const DB = process.argv[2];
146
+ if (!DB) { console.error('usage: migrate.js <dbPath> [--no-vacuum] [--keep-lost-and-found]'); process.exit(1); }
147
+ const db = new Database(DB);
148
+ vec.load(db);
149
+ db.pragma('busy_timeout = 60000');
150
+ const MB = b => (b / 1048576).toFixed(0);
151
+ const before = db.prepare('SELECT SUM(pgsize) b FROM dbstat').get().b;
152
+ const t0 = Date.now();
153
+ optimizeBrain(db, {
154
+ vacuum: !process.argv.includes('--no-vacuum'),
155
+ dropLostAndFound: !process.argv.includes('--keep-lost-and-found'),
156
+ log: (...a) => console.log('[migrate]', ...a),
157
+ });
158
+ const after = db.prepare('SELECT SUM(pgsize) b FROM dbstat').get().b;
159
+ console.log(`[migrate] logical size ${MB(before)} -> ${MB(after)} MB in ${((Date.now()-t0)/1000).toFixed(1)}s`);
160
+ db.close();
161
+ console.log('[migrate] DONE');
162
+ }
@@ -0,0 +1,117 @@
1
+ 'use strict';
2
+ // Phase 1a — embedding quantization recall eval (decision gate).
3
+ // Runs ONLY on a copy. Builds int8 + binary shadow vec tables from the existing
4
+ // float32 vectors, then measures recall@k by using stored vectors as query probes
5
+ // (this isolates *quantization distortion* — how much the quantized index reorders
6
+ // the same neighbors — without needing ollama to embed fresh queries).
7
+ //
8
+ // Usage: <node25> recall-eval.js [copyPath] [sampleN]
9
+ const path = require('path');
10
+ const WE = path.resolve(__dirname, '..', '..');
11
+ const Database = require(path.join(WE, 'node_modules', 'better-sqlite3'));
12
+ const vec = require(path.join(WE, 'node_modules', 'sqlite-vec'));
13
+
14
+ const COPY = process.argv[2] || path.join(process.env.HOME || process.cwd(), '.walle', 'opt-work', 'wall-e-brain.copy.db');
15
+ const SAMPLE = parseInt(process.argv[3] || '80', 10);
16
+ const KMAX = 30;
17
+
18
+ const db = new Database(COPY);
19
+ vec.load(db);
20
+ db.pragma('cache_size = -200000'); // 200MB page cache for the KNN scans
21
+
22
+ const SRC = 'embedding_vec_ollama'; // float[768]
23
+ const I8 = 'embedding_vec_ollama_i8'; // int8[768]
24
+ const BIT = 'embedding_vec_ollama_bit'; // bit[768]
25
+
26
+ function tableBytes(name) {
27
+ // sum pgsize across the vec0 shadow tables for this logical table
28
+ try {
29
+ const r = db.prepare(
30
+ `SELECT COALESCE(SUM(pgsize),0) AS b FROM dbstat WHERE name LIKE ? OR name LIKE ?`
31
+ ).get(name + '%', 'sqlite_autoindex_' + name + '%');
32
+ return r.b;
33
+ } catch (e) { return -1; }
34
+ }
35
+
36
+ function buildQuant(target, type, expr) {
37
+ const exists = db.prepare("SELECT 1 FROM sqlite_master WHERE name=?").get(target);
38
+ if (exists) { db.exec(`DROP TABLE ${target}`); }
39
+ db.exec(`CREATE VIRTUAL TABLE ${target} USING vec0(embedding ${type})`);
40
+ const t0 = Date.now();
41
+ try {
42
+ db.exec(`INSERT INTO ${target}(rowid, embedding) SELECT rowid, ${expr} FROM ${SRC}`);
43
+ } catch (e) {
44
+ // fallback: row-by-row
45
+ const sel = db.prepare(`SELECT rowid, embedding FROM ${SRC}`);
46
+ const ins = db.prepare(`INSERT INTO ${target}(rowid, embedding) VALUES (?, ${expr.replace('embedding', '?')})`);
47
+ const tx = db.transaction(() => { for (const r of sel.iterate()) ins.run(r.rowid, r.embedding); });
48
+ tx();
49
+ }
50
+ return Date.now() - t0;
51
+ }
52
+
53
+ console.log(`# Embedding quantization recall eval`);
54
+ console.log(`copy: ${COPY}`);
55
+ const srcN = db.prepare(`SELECT COUNT(*) n FROM ${SRC}`).get().n;
56
+ console.log(`float32 vectors: ${srcN}, sample queries: ${SAMPLE}, k up to ${KMAX}\n`);
57
+
58
+ console.log('building int8 shadow table...');
59
+ const t8 = buildQuant(I8, 'int8[768]', "vec_quantize_int8(embedding,'unit')");
60
+ console.log(` built in ${t8}ms`);
61
+ console.log('building binary(bit) shadow table...');
62
+ const tb = buildQuant(BIT, 'bit[768]', 'vec_quantize_binary(embedding)');
63
+ console.log(` built in ${tb}ms\n`);
64
+
65
+ const bytesF = tableBytes(SRC), bytes8 = tableBytes(I8), bytesB = tableBytes(BIT);
66
+ const MB = b => (b / 1048576).toFixed(1);
67
+ console.log(`size float32: ${MB(bytesF)} MB int8: ${MB(bytes8)} MB (${(bytesF/bytes8).toFixed(1)}x) bit: ${MB(bytesB)} MB (${(bytesF/bytesB).toFixed(1)}x)\n`);
68
+
69
+ // sample rowids
70
+ const allIds = db.prepare(`SELECT rowid FROM ${SRC}`).all().map(r => r.rowid);
71
+ function pick(n) {
72
+ const out = []; const used = new Set(); let seed = 1234567;
73
+ const rnd = () => { seed = (seed * 1103515245 + 12345) & 0x7fffffff; return seed / 0x7fffffff; };
74
+ while (out.length < n && used.size < allIds.length) {
75
+ const i = Math.floor(rnd() * allIds.length);
76
+ if (!used.has(i)) { used.add(i); out.push(allIds[i]); }
77
+ }
78
+ return out;
79
+ }
80
+ const sample = pick(SAMPLE);
81
+
82
+ const getVec = db.prepare(`SELECT embedding FROM ${SRC} WHERE rowid=?`);
83
+ const knnF = db.prepare(`SELECT rowid FROM ${SRC} WHERE embedding MATCH ? AND k=? ORDER BY distance`);
84
+ const knn8 = db.prepare(`SELECT rowid FROM ${I8} WHERE embedding MATCH vec_quantize_int8(?,'unit') AND k=? ORDER BY distance`);
85
+ const knnB = db.prepare(`SELECT rowid FROM ${BIT} WHERE embedding MATCH vec_quantize_binary(?) AND k=? ORDER BY distance`);
86
+
87
+ function topk(stmt, qv, k, self) {
88
+ const ids = stmt.all(qv, k + 1).map(r => r.rowid).filter(id => id !== self);
89
+ return ids.slice(0, k);
90
+ }
91
+ function recallAt(gt, cand, k) {
92
+ const g = new Set(gt.slice(0, k));
93
+ let hit = 0; for (const id of cand.slice(0, k)) if (g.has(id)) hit++;
94
+ return hit / k;
95
+ }
96
+
97
+ let sum8_10 = 0, sum8_30 = 0, sumB_10 = 0, sumB_30 = 0;
98
+ let tF = 0, t8t = 0, tBt = 0, worst8_10 = 1;
99
+ for (const rid of sample) {
100
+ const qv = getVec.get(rid).embedding;
101
+ let s = Date.now(); const gt = topk(knnF, qv, KMAX, rid); tF += Date.now() - s;
102
+ s = Date.now(); const c8 = topk(knn8, qv, KMAX, rid); t8t += Date.now() - s;
103
+ s = Date.now(); const cB = topk(knnB, qv, KMAX, rid); tBt += Date.now() - s;
104
+ const r8_10 = recallAt(gt, c8, 10); const r8_30 = recallAt(gt, c8, 30);
105
+ sum8_10 += r8_10; sum8_30 += r8_30;
106
+ sumB_10 += recallAt(gt, cB, 10); sumB_30 += recallAt(gt, cB, 30);
107
+ if (r8_10 < worst8_10) worst8_10 = r8_10;
108
+ }
109
+ const N = sample.length;
110
+ const pct = x => (100 * x / N).toFixed(1) + '%';
111
+ console.log('## Recall (quantized vs float32 ground truth), averaged over', N, 'real query probes');
112
+ console.log(`int8 recall@10: ${pct(sum8_10)} recall@30: ${pct(sum8_30)} worst@10: ${(100*worst8_10).toFixed(0)}%`);
113
+ console.log(`binary recall@10: ${pct(sumB_10)} recall@30: ${pct(sumB_30)} (binary normally needs a float rerank pass)`);
114
+ console.log();
115
+ console.log('## KNN latency (avg ms/query, exhaustive over', srcN, 'vectors)');
116
+ console.log(`float32: ${(tF/N).toFixed(1)}ms int8: ${(t8t/N).toFixed(1)}ms bit: ${(tBt/N).toFixed(1)}ms`);
117
+ db.close();
@@ -1,7 +1,10 @@
1
1
  'use strict';
2
+ process.env.WALL_E_PROCESS_ROLE = process.env.WALL_E_PROCESS_ROLE || 'walle-daemon';
3
+
2
4
  const http = require('http');
3
5
  const { handleWalleApi } = require('./api-walle');
4
6
  const { getAllowedOrigin, isAuthorizedRequest } = require('./http/auth');
7
+ const { startPortkeyModelSyncLoop } = require('./llm/portkey-sync');
5
8
 
6
9
  const PORT = parseInt(process.env.WALL_E_PORT) || 3457;
7
10
  const HOST = process.env.WALL_E_HOST || '127.0.0.1';
@@ -155,6 +158,13 @@ function startServer(options = {}) {
155
158
  readyResolve();
156
159
  if (typeof setImmediate === 'function') setImmediate(autoConfigureWallEMcp);
157
160
  else setTimeout(autoConfigureWallEMcp, 0);
161
+ if (process.env.WALLE_DISABLE_PORTKEY_SYNC !== '1') {
162
+ try {
163
+ server.stopPortkeyModelSync = startPortkeyModelSyncLoop();
164
+ } catch (err) {
165
+ console.warn(`[wall-e] Portkey model sync loop failed to start: ${err.message}`);
166
+ }
167
+ }
158
168
  });
159
169
  }
160
170
 
@@ -177,6 +187,11 @@ function startServer(options = {}) {
177
187
  readyReject(err);
178
188
  }
179
189
  });
190
+ server.on('close', () => {
191
+ try {
192
+ if (typeof server.stopPortkeyModelSync === 'function') server.stopPortkeyModelSync();
193
+ } catch {}
194
+ });
180
195
 
181
196
  tryListen();
182
197
  return server;
@@ -116,6 +116,15 @@ class WallESessionRecorder {
116
116
  }));
117
117
  }
118
118
 
119
+ appendFrame(frame, extra = {}) {
120
+ if (!this.enabled) return null;
121
+ this.ensureStarted();
122
+ return this._appendRecord(this._baseRecord('frame_update', {
123
+ ...extra,
124
+ data: normalizeContent(frame),
125
+ }));
126
+ }
127
+
119
128
  appendError(error, extra = {}) {
120
129
  if (!this.enabled) return null;
121
130
  this.ensureStarted();
@@ -141,7 +141,7 @@ function storeToBrain(events) {
141
141
  ).all(windowStart, windowEnd);
142
142
  for (const row of dbEvents) {
143
143
  if (!seenSourceIds.has(row.source_id)) {
144
- brain.getDb().prepare('DELETE FROM memories WHERE id = ?').run(row.id);
144
+ brain.deleteMemory(row.id); // cascades to memory_index + embeddings (no orphan leak)
145
145
  cleaned++;
146
146
  }
147
147
  }
@@ -194,7 +194,7 @@ function syncCalendar(brain, token, profileId) {
194
194
  ).all(timeMin, timeMax);
195
195
  for (const row of dbEvents) {
196
196
  if (!seenSourceIds.has(row.source_id)) {
197
- brain.getDb().prepare('DELETE FROM memories WHERE id = ?').run(row.id);
197
+ brain.deleteMemory(row.id); // cascades to memory_index + embeddings (no orphan leak)
198
198
  cleaned++;
199
199
  }
200
200
  }
@@ -25,6 +25,9 @@ const {
25
25
  const {
26
26
  parseDsmlToolCallBlocks,
27
27
  } = require(path.resolve(__dirname, '..', '..', '..', 'llm', 'text-tool-calls'));
28
+ const ctmOperationalContext = require(path.resolve(__dirname, '..', '..', '..', 'memory', 'ctm-operational-context'));
29
+ let telemetry;
30
+ try { telemetry = require(path.resolve(__dirname, '..', '..', '..', 'telemetry')); } catch { telemetry = { track() {} }; }
28
31
 
29
32
  const WATERMARK_FILE = path.join(__dirname, '.watermark.json');
30
33
  const OWNER_HANDLE = process.env.SLACK_OWNER_HANDLE || '';
@@ -540,6 +543,62 @@ function buildSlackChatOptions(overrides = {}) {
540
543
  };
541
544
  }
542
545
 
546
+ async function buildSlackCtmContextBlock(text, opts = {}) {
547
+ const classification = ctmOperationalContext.classifyCtmOperationalQuery(text);
548
+ if (!classification.required) {
549
+ return { required: false, ok: true, block: '', result: null };
550
+ }
551
+
552
+ let result;
553
+ try {
554
+ result = await ctmOperationalContext.lookupCtmOperationalContext({
555
+ query: text,
556
+ limit: opts.limit || 5,
557
+ force: true,
558
+ }, {
559
+ timeoutMs: opts.timeoutMs || 6000,
560
+ cooldownMs: opts.cooldownMs ?? 0,
561
+ });
562
+ } catch (err) {
563
+ result = {
564
+ required: true,
565
+ ok: false,
566
+ must_not_guess: true,
567
+ reason: err.message,
568
+ context_text: 'CTM operational context lookup failed. Do not guess; reply ONLY NO_REPLY.',
569
+ sources: {
570
+ remote_access: { searched: true, ok: false, reason: err.message },
571
+ ctm_sessions: { searched: true, ok: false, reason: err.message },
572
+ },
573
+ };
574
+ }
575
+
576
+ telemetry.track('slack_ctm_context_preflight', {
577
+ required: true,
578
+ ok: Boolean(result.ok),
579
+ remote_ok: Boolean(result.sources?.remote_access?.ok),
580
+ session_ok: Boolean(result.sources?.ctm_sessions?.ok),
581
+ session_count: Number(result.sources?.ctm_sessions?.count || 0),
582
+ });
583
+
584
+ if (!result.ok) {
585
+ console.warn(`[slack-mentions] Required CTM context unavailable; suppressing guess (${result.sources?.remote_access?.reason || result.sources?.ctm_sessions?.reason || result.reason || 'unknown'})`);
586
+ return {
587
+ required: true,
588
+ ok: false,
589
+ block: '\n\nRequired CTM operational/session-memory context was unavailable. Reply ONLY NO_REPLY. Do not guess from generic memories, DDEV hosts, localhost, or local IP heuristics.',
590
+ result,
591
+ };
592
+ }
593
+
594
+ return {
595
+ required: true,
596
+ ok: true,
597
+ block: `\n\n${result.context_text}`,
598
+ result,
599
+ };
600
+ }
601
+
543
602
  function selectThreadMessagesToProcess(replies, thread, opts = {}) {
544
603
  const lastSeenTs = thread?.last_seen_ts || thread?.thread_ts || null;
545
604
  const ownerReplies = (replies || []).filter(reply => isOwnerReply(reply, opts));
@@ -577,7 +636,7 @@ async function deliverSlackReply({ channelId, threadTs, message, deliveryId }) {
577
636
  conversationId: channelId,
578
637
  threadId: threadTs,
579
638
  source: 'wall_e_outbound',
580
- extractMessageId: extractSlackMessageTs,
639
+ extractMessageId: (result) => extractSlackMessageTs(result),
581
640
  metadata: { slackChannelId: channelId, slackThreadTs: threadTs },
582
641
  },
583
642
  });
@@ -605,20 +664,25 @@ async function generateAndSendReply(msg, threadTs, contextBlock, kind, opts = {}
605
664
  try {
606
665
  const today = new Date().toISOString().split('T')[0];
607
666
  const instruction = slackResponseInstruction(question);
667
+ const ctmContext = await buildSlackCtmContextBlock(question);
668
+ if (ctmContext.required && !ctmContext.ok) return null;
669
+ const effectiveContextBlock = `${contextBlock || ''}${ctmContext.block || ''}`;
608
670
  const locationAware = shouldUseLocationForMessage(question);
609
671
  const explicitCalendar = isExplicitCalendarRequest(question);
610
672
  const locationInstruction = locationAware
611
673
  ? 'For physical location/local weather questions, use Wall-E current-location context only. Do not infer location from calendar, timezone, Slack history, or memories.'
674
+ : ctmContext.required
675
+ ? 'Use the CTM operational context block as authoritative. Do not answer from generic memories if they conflict. Do not guess DDEV, localhost, or local-IP answers unless the CTM context explicitly says so.'
612
676
  : 'Search your memories for relevant info.';
613
677
  // Build a context-aware prompt: greetings/welcomes get a warmer, more proactive prompt
614
678
  let prompt;
615
679
  if (isGreeting) {
616
- prompt = `[SLACK GREETING] ${actorLabel(msg)} said in Slack:\n\n"${question}"${contextBlock}\n\nToday is ${today}. This appears to be a greeting or welcome message. Search your memories (e.g. lookup_person) to learn about the people mentioned. Respond warmly — welcome them, share any relevant context you know about them, and proactively offer to help. Be genuine and concise (2-4 sentences). Do NOT mention any tool failures or technical issues in your response.`;
680
+ prompt = `[SLACK GREETING] ${actorLabel(msg)} said in Slack:\n\n"${question}"${effectiveContextBlock}\n\nToday is ${today}. This appears to be a greeting or welcome message. Search your memories (e.g. lookup_person) to learn about the people mentioned. Respond warmly — welcome them, share any relevant context you know about them, and proactively offer to help. Be genuine and concise (2-4 sentences). Do NOT mention any tool failures or technical issues in your response.`;
617
681
  } else {
618
- prompt = `[SLACK ${kind.toUpperCase()}] ${actorLabel(msg)} asked in Slack:\n\n${question}${contextBlock}\n\nToday is ${today}. ${locationInstruction} For schedule/calendar questions, search with the specific date (e.g. "calendar 2026-04-13") since calendar events are stored as memories with source=calendar. Use mcp_call only if memories don't have what you need. ${instruction}`;
682
+ prompt = `[SLACK ${kind.toUpperCase()}] ${actorLabel(msg)} asked in Slack:\n\n${question}${effectiveContextBlock}\n\nToday is ${today}. ${locationInstruction} For schedule/calendar questions, search with the specific date (e.g. "calendar 2026-04-13") since calendar events are stored as memories with source=calendar. Use ctm_context for CTM operational/session-memory questions. Use mcp_call only if memories don't have what you need. ${instruction}`;
619
683
  }
620
684
 
621
- const allowedTools = ['search_memories', 'think', 'lookup_person', 'mcp_call', 'calendar_events', 'mail_messages', 'mail_read', 'mail_search']
685
+ const allowedTools = ['search_memories', 'ctm_context', 'ctm_remote_access_status', 'ctm_session_search', 'think', 'lookup_person', 'mcp_call', 'calendar_events', 'mail_messages', 'mail_read', 'mail_search']
622
686
  .filter(tool => !(locationAware && !explicitCalendar && tool === 'calendar_events'));
623
687
  const result = await chatModule.chat(prompt, buildSlackChatOptions({
624
688
  channel: 'task',
@@ -675,14 +739,19 @@ async function generateAndSendFollowUp(combinedMessage, thread, threadContext, o
675
739
  const today = new Date().toISOString().split('T')[0];
676
740
  const contextBlock = threadContext ? `\n\nFull Slack thread context:\n${threadContext}` : '';
677
741
  const instruction = slackResponseInstruction(combinedMessage);
742
+ const ctmContext = await buildSlackCtmContextBlock(`${combinedMessage}\n${threadContext || ''}`);
743
+ if (ctmContext.required && !ctmContext.ok) return null;
744
+ const effectiveContextBlock = `${contextBlock}${ctmContext.block || ''}`;
678
745
  const locationAware = shouldUseLocationForMessage(combinedMessage);
679
746
  const explicitCalendar = isExplicitCalendarRequest(combinedMessage);
680
747
  const locationInstruction = locationAware
681
748
  ? 'For physical location/local weather questions, use Wall-E current-location context only. Do not infer location from calendar, timezone, Slack history, or memories.'
749
+ : ctmContext.required
750
+ ? 'Use the CTM operational context block as authoritative. Do not answer from generic memories if they conflict. Do not guess DDEV, localhost, or local-IP answers unless the CTM context explicitly says so.'
682
751
  : 'Search your memories for relevant info.';
683
- const prompt = `[SLACK FOLLOW-UP] ${getConfiguredOwnerName() || 'The owner'} replied in a Slack thread:\n\n${combinedMessage}${contextBlock}\n\nToday is ${today}. ${locationInstruction} ${instruction}`;
752
+ const prompt = `[SLACK FOLLOW-UP] ${getConfiguredOwnerName() || 'The owner'} replied in a Slack thread:\n\n${combinedMessage}${effectiveContextBlock}\n\nToday is ${today}. ${locationInstruction} Use ctm_context for CTM operational/session-memory questions. ${instruction}`;
684
753
 
685
- const allowedTools = ['search_memories', 'think', 'lookup_person', 'mcp_call', 'calendar_events', 'mail_messages', 'mail_read', 'mail_search']
754
+ const allowedTools = ['search_memories', 'ctm_context', 'ctm_remote_access_status', 'ctm_session_search', 'think', 'lookup_person', 'mcp_call', 'calendar_events', 'mail_messages', 'mail_read', 'mail_search']
686
755
  .filter(tool => !(locationAware && !explicitCalendar && tool === 'calendar_events'));
687
756
  const result = await chatModule.chat(prompt, buildSlackChatOptions({
688
757
  channel: 'task',
@@ -1455,6 +1524,7 @@ module.exports = {
1455
1524
  looksLikeToolControlMarkup,
1456
1525
  validateSlackAnswer,
1457
1526
  buildSlackChatOptions,
1527
+ buildSlackCtmContextBlock,
1458
1528
  generateAndSendReply,
1459
1529
  parseChannelMessages,
1460
1530
  parseDmMessages,
@@ -368,10 +368,14 @@ function syncSkillReferences() {
368
368
  fs.existsSync(skill.path) ? fs.readFileSync(skill.path, 'utf8') : content
369
369
  ).digest('hex') : null;
370
370
 
371
- // Check if this reference already exists
371
+ // Check if this reference already exists.
372
+ // NOTE: filter on `source` too — `WHERE source_id = ?` alone can't use the compound
373
+ // index idx_memories_source(source, source_id) and full-scans the (multi-GB) memories
374
+ // table on EVERY skill, which made boot take ~3min. Skill refs are always stored with
375
+ // source='skill_reference', so this is both correct and index-eligible (SEARCH not SCAN).
372
376
  try {
373
377
  const existing = brain.getDb().prepare(
374
- 'SELECT id, content FROM memories WHERE source_id = ? LIMIT 1'
378
+ "SELECT id, content FROM memories WHERE source = 'skill_reference' AND source_id = ? LIMIT 1"
375
379
  ).get(sourceId);
376
380
 
377
381
  if (existing && existing.content === content) continue; // no change
@@ -411,7 +415,7 @@ function syncSkillReferences() {
411
415
  ).all();
412
416
  for (const row of existing) {
413
417
  if (!allIds.has(row.source_id)) {
414
- brain.getDb().prepare('DELETE FROM memories WHERE id = ?').run(row.id);
418
+ brain.deleteMemory(row.id); // cascades to memory_index + embeddings (no orphan leak)
415
419
  }
416
420
  }
417
421
  } catch {}
@@ -30,6 +30,16 @@ function runScriptSkill(skill, task = {}, opts = {}) {
30
30
  WALL_E_SKILL_CONFIG: JSON.stringify(skillConfig),
31
31
  WALL_E_SKILL_DIR: skill.dir,
32
32
  WALL_E_SRC_DIR: WALL_E_DIR,
33
+ // Script skills run as dedicated short-lived subprocesses that open their own
34
+ // brain.db connection (brain.initDb()). The daemon's brain lock defaults to a 0ms
35
+ // fail-fast (correct for the daemon event loop, which must never Atomics.wait), but
36
+ // inherited by a subprocess that means it ABORTS the instant the daemon holds the
37
+ // lock for a single statement — observed as ~272 "SQLite write lock busy" aborts
38
+ // (slack-mentions Exit code 1, dropped calendar/email syncs). A subprocess can
39
+ // safely block-wait briefly and retry, so give it a bounded timeout. In practice
40
+ // the lock frees in <100ms; 5s is just the ceiling. Caller env still wins.
41
+ WALL_E_SQLITE_WRITE_LOCK_TIMEOUT_MS:
42
+ process.env.WALL_E_SQLITE_WRITE_LOCK_TIMEOUT_MS || '5000',
33
43
  ...(opts.env || {}),
34
44
  };
35
45
  if (task.checkpoint) env.WALL_E_CHECKPOINT = task.checkpoint;
@@ -154,6 +154,43 @@ function clearResolvedSlackHealthAlerts({ authenticated = false, ownerConfigured
154
154
  return { cleared: before.length - after.length };
155
155
  }
156
156
 
157
+ function _googleWorkspaceServiceKey(email, profileId) {
158
+ const normalizedEmail = String(email || '').trim().toLowerCase();
159
+ if (!normalizedEmail) return '';
160
+ const normalizedProfile = String(profileId || 'default').trim().toLowerCase() || 'default';
161
+ return `google_workspace:${normalizedProfile}:${normalizedEmail}`;
162
+ }
163
+
164
+ function _sameGoogleWorkspaceAlertAccount(alert, email, profileId) {
165
+ const normalizedEmail = String(email || '').trim().toLowerCase();
166
+ if (!normalizedEmail || !alert) return false;
167
+ const normalizedProfile = String(profileId || 'default').trim().toLowerCase() || 'default';
168
+ const service = String(alert.service || '').trim().toLowerCase();
169
+ if (service === _googleWorkspaceServiceKey(normalizedEmail, normalizedProfile)) return true;
170
+ const alertEmail = String(alert.account_email || alert.email || '').trim().toLowerCase();
171
+ if (alertEmail !== normalizedEmail) return false;
172
+ const alertProfile = String(alert.profile_id || alert.profileId || 'default').trim().toLowerCase() || 'default';
173
+ return alertProfile === normalizedProfile;
174
+ }
175
+
176
+ function clearResolvedGoogleWorkspaceHealthAlerts({ email = '', profileId = null, authenticated = false } = {}) {
177
+ if (!authenticated || !email) return { cleared: 0 };
178
+ const before = getServiceAlerts();
179
+ const after = before.filter((a) => {
180
+ if (!_sameGoogleWorkspaceAlertAccount(a, email, profileId)) return true;
181
+ const action = String(a.action || '');
182
+ const type = String(a.type || '');
183
+ const googleWorkspaceAuthAlert =
184
+ action === 'gws_reauth'
185
+ || type === 'auth_expired';
186
+ return !googleWorkspaceAuthAlert;
187
+ });
188
+ if (after.length !== before.length) {
189
+ brain.setKv('service_alerts', JSON.stringify(after));
190
+ }
191
+ return { cleared: before.length - after.length };
192
+ }
193
+
157
194
  function _hasMissingSlackOwner(validation) {
158
195
  return !!(validation && Array.isArray(validation.missing)
159
196
  && validation.missing.some(m => m.type === 'env' && m.name === SLACK_OWNER_ENV_KEY));
@@ -873,6 +910,7 @@ module.exports = {
873
910
  dismissServiceAlert,
874
911
  clearServiceAlerts,
875
912
  clearResolvedSlackHealthAlerts,
913
+ clearResolvedGoogleWorkspaceHealthAlerts,
876
914
  _test: {
877
915
  isAuthError,
878
916
  getProviderAuthBlock,
@@ -99,8 +99,17 @@ function registerBuiltinMiddleware(mw, opts = {}) {
99
99
  const mode = ctx.mode || opts.mode || 'build';
100
100
  const sections = [];
101
101
 
102
- sections.push(`You are an expert software engineer executing a coding task.
102
+ // When the orchestrator already built the full agent prompt
103
+ // (buildAgentSystemPrompt), keep it as the base and only append the
104
+ // sections it doesn't cover. Replacing it here silently dropped the
105
+ // workflow/quality/frontend/memory discipline from every loop turn.
106
+ const baseSystem = typeof ctx.system === 'string' && ctx.system.trim() ? ctx.system : '';
107
+ if (baseSystem) {
108
+ sections.push(baseSystem);
109
+ } else {
110
+ sections.push(`You are an expert software engineer executing a coding task.
103
111
  Work in: ${cwd}`);
112
+ }
104
113
 
105
114
  // Mode enforcement (belt + suspenders with tool filtering)
106
115
  if (mode === 'plan') {
@@ -111,9 +120,10 @@ You may ONLY read, search, and analyze. This overrides all other instructions.`)
111
120
  Do not make any edits. Review the diff and assess quality.`);
112
121
  }
113
122
 
114
- // Project conventions
115
- if (opts.claudeMd || ctx.claudeMd) {
116
- sections.push(`## Project Conventions (CLAUDE.md)\n${opts.claudeMd || ctx.claudeMd}`);
123
+ // Project conventions (skip if the base prompt already carries them)
124
+ const claudeMd = opts.claudeMd || ctx.claudeMd;
125
+ if (claudeMd && !baseSystem.includes(claudeMd)) {
126
+ sections.push(`## Project Conventions (CLAUDE.md)\n${claudeMd}`);
117
127
  }
118
128
 
119
129
  // Quality rules (ported from OpenCode's prompt patterns)
@@ -143,7 +153,7 @@ Do not make any edits. Review the diff and assess quality.`);
143
153
  if (workflowDocs) sections.push(workflowDocs);
144
154
 
145
155
  const capabilityContext = buildCapabilityContext(ctx.promptCapabilities || opts.promptCapabilities);
146
- if (capabilityContext) sections.push(capabilityContext);
156
+ if (capabilityContext && !baseSystem.includes(capabilityContext)) sections.push(capabilityContext);
147
157
 
148
158
  ctx.system = sections.join('\n\n');
149
159
  });
@@ -185,11 +195,11 @@ Do not make any edits. Review the diff and assess quality.`);
185
195
 
186
196
  // Prioritize tools based on detected coding phase
187
197
  const PHASE_PREFERRED = {
188
- 'coding:exploration': new Set(['read_file', 'glob', 'grep_files', 'list_directory', 'lsp_symbols']),
189
- 'coding:generation': new Set(['edit_file', 'write_file', 'apply_patch', 'multi_edit', 'run_shell']),
198
+ 'coding:exploration': new Set(['read_file', 'glob', 'grep_files', 'list_directory', 'pdf_info', 'pdf_read_pages', 'pdf_render_pages', 'lsp_symbols']),
199
+ 'coding:generation': new Set(['edit_file', 'write_file', 'apply_patch', 'multi_edit', 'run_shell', 'make_pdf']),
190
200
  'coding:debugging': new Set(['read_file', 'run_shell', 'grep_files', 'lsp_diagnostics', 'edit_file']),
191
- 'coding:testing': new Set(['run_shell', 'read_file', 'edit_file']),
192
- 'coding:review': new Set(['read_file', 'grep_files', 'lsp_diagnostics', 'lsp_symbols']),
201
+ 'coding:testing': new Set(['run_shell', 'read_file', 'edit_file', 'pdf_info', 'pdf_render_pages']),
202
+ 'coding:review': new Set(['read_file', 'grep_files', 'pdf_info', 'pdf_read_pages', 'pdf_render_pages', 'lsp_diagnostics', 'lsp_symbols']),
193
203
  };
194
204
 
195
205
  const preferred = PHASE_PREFERRED[phase];