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,354 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const Database = require('better-sqlite3');
7
+
8
+ const CURSOR_HOME = () => path.join(os.homedir(), '.cursor');
9
+ const CACHE = new Map();
10
+ const SHA256_HEX_RE = /^[a-f0-9]{64}$/i;
11
+
12
+ function _decodeMaybeHexJson(value) {
13
+ if (value == null) return null;
14
+ const raw = Buffer.isBuffer(value) ? value.toString('utf8') : String(value);
15
+ const trimmed = raw.trim();
16
+ const candidates = [trimmed];
17
+ if (/^[0-9a-f]+$/i.test(trimmed) && trimmed.length % 2 === 0) {
18
+ try { candidates.unshift(Buffer.from(trimmed, 'hex').toString('utf8')); } catch {}
19
+ }
20
+ for (const value of candidates) {
21
+ const candidate = String(value || '').trim();
22
+ if (!candidate || candidate[0] !== '{') continue;
23
+ try { return JSON.parse(candidate); } catch {}
24
+ }
25
+ return null;
26
+ }
27
+
28
+ function _readMeta(db) {
29
+ const row = db.prepare('SELECT value FROM meta WHERE key = ?').get('0')
30
+ || db.prepare('SELECT value FROM meta LIMIT 1').get();
31
+ return _decodeMaybeHexJson(row?.value);
32
+ }
33
+
34
+ function _bufferFromBlob(value) {
35
+ if (Buffer.isBuffer(value)) return value;
36
+ if (value instanceof Uint8Array) return Buffer.from(value);
37
+ return Buffer.from(String(value || ''), 'utf8');
38
+ }
39
+
40
+ function _orderedBlobRefs(buffer, idSet) {
41
+ if (!Buffer.isBuffer(buffer) || buffer.length < 32 || idSet.size === 0) return [];
42
+ // Find every 32-byte blob-id (graph edge) embedded at any byte offset, in order of first
43
+ // appearance. The naive form allocated a 32-byte subarray AND hex-encoded it at EVERY
44
+ // offset (O(n) Buffer.subarray + hexSlice) — the dominant main-thread freeze in CPU
45
+ // profiles (~26% of non-idle: hexSlice + FastBuffer churn). Hex-encode the WHOLE buffer
46
+ // ONCE (one native call) then slide a 64-char window over the hex string at byte-aligned
47
+ // (even) offsets: no per-offset Buffer allocation, ~3× faster, and O(n) regardless of how
48
+ // many blob ids the session has (the per-id Buffer.indexOf alternative degrades to O(ids×n)
49
+ // as conversations grow). Output is byte-for-byte identical to the naive scan.
50
+ const hexAll = buffer.toString('hex');
51
+ const end = hexAll.length - 64; // byte offset i ↔ hex offset 2i; window is 64 hex chars
52
+ const refs = [];
53
+ const seen = new Set();
54
+ for (let h = 0; h <= end; h += 2) {
55
+ const hex = hexAll.slice(h, h + 64);
56
+ if (!idSet.has(hex) || seen.has(hex)) continue;
57
+ seen.add(hex);
58
+ refs.push(hex);
59
+ }
60
+ return refs;
61
+ }
62
+
63
+ function _reachableBlobIds(rootBlobId, blobsById) {
64
+ const root = String(rootBlobId || '').trim();
65
+ if (!SHA256_HEX_RE.test(root) || !blobsById.has(root)) return [];
66
+ const idSet = new Set(blobsById.keys());
67
+ const seen = new Set([root]);
68
+ const order = [];
69
+ const queue = [root];
70
+ while (queue.length) {
71
+ const id = queue.shift();
72
+ order.push(id);
73
+ const blob = blobsById.get(id);
74
+ if (!blob || blob[0] === 0x7b) continue; // JSON message blobs do not carry graph edges.
75
+ for (const ref of _orderedBlobRefs(blob, idSet)) {
76
+ if (ref === id || seen.has(ref)) continue;
77
+ seen.add(ref);
78
+ queue.push(ref);
79
+ }
80
+ }
81
+ return order;
82
+ }
83
+
84
+ function _contentText(content, role) {
85
+ if (typeof content === 'string') return content;
86
+ if (!Array.isArray(content)) return '';
87
+ const parts = [];
88
+ for (const item of content) {
89
+ if (!item || typeof item !== 'object') continue;
90
+ if (item.type === 'text' && typeof item.text === 'string') parts.push(item.text);
91
+ else if (role === 'tool' && typeof item.result === 'string') parts.push(item.result);
92
+ }
93
+ return parts.join('\n\n').trim();
94
+ }
95
+
96
+ function _normalizeCursorUserText(text) {
97
+ const raw = String(text || '').trim();
98
+ if (!raw) return '';
99
+ const query = raw.match(/<user_query>\s*([\s\S]*?)\s*<\/user_query>/i);
100
+ if (query) return query[1].trim();
101
+ if (/^<user_info>/i.test(raw)) return '';
102
+ if (/^\[Previous conversation summary\]/i.test(raw)) return '';
103
+ if (/^Your conversation was summarized due to context constraints\./i.test(raw)) return '';
104
+ return raw;
105
+ }
106
+
107
+ function _normalizeCursorAssistantText(text) {
108
+ const raw = String(text || '').trim();
109
+ if (!raw) return '';
110
+ if (raw === 'redacted-reasoning' || raw === 'tool-call') return '';
111
+ return raw;
112
+ }
113
+
114
+ function _messageFromBlobJson(value, index, meta) {
115
+ if (!value || typeof value !== 'object') return null;
116
+ const role = String(value.role || '').trim();
117
+ if (role !== 'user' && role !== 'assistant') return null;
118
+ const rawText = _contentText(value.content, role);
119
+ const text = role === 'user'
120
+ ? _normalizeCursorUserText(rawText)
121
+ : _normalizeCursorAssistantText(rawText);
122
+ if (!text) return null;
123
+ const baseMs = Number(meta?.createdAt || 0);
124
+ const timestamp = Number.isFinite(baseMs) && baseMs > 0
125
+ ? new Date(baseMs + index).toISOString()
126
+ : '';
127
+ return {
128
+ role,
129
+ text,
130
+ timestamp,
131
+ provider: 'cursor',
132
+ metadata: {
133
+ provider: 'cursor',
134
+ source: 'cursor-local-store',
135
+ cursorAgentId: String(meta?.agentId || ''),
136
+ cursorMessageId: String(value.id || ''),
137
+ },
138
+ };
139
+ }
140
+
141
+ function _workspaceUriFromBlob(buffer) {
142
+ const text = _bufferFromBlob(buffer).toString('utf8');
143
+ const match = text.match(/file:\/\/[^\x00-\x1f\x7f]+/);
144
+ return match ? match[0] : '';
145
+ }
146
+
147
+ function _workspacePathFromUri(uri) {
148
+ const raw = String(uri || '').trim();
149
+ if (!raw.startsWith('file://')) return '';
150
+ let decoded = '';
151
+ try {
152
+ decoded = decodeURIComponent(raw.replace(/^file:\/\//, ''));
153
+ } catch {
154
+ decoded = raw.replace(/^file:\/\//, '');
155
+ }
156
+ if (!decoded || fs.existsSync(decoded)) return decoded;
157
+ // Cursor's root blob is binary/protobuf-like. The workspace URI is embedded
158
+ // as a string, and the following protobuf bytes can occasionally be printable
159
+ // ASCII, so a raw string scan may capture one or two bytes past the path.
160
+ // Trim only when that recovers a real path; deleted workspaces keep the raw
161
+ // decoded value so callers can still inspect the store metadata.
162
+ for (let i = decoded.length - 1; i > 0; i--) {
163
+ const candidate = decoded.slice(0, i);
164
+ if (fs.existsSync(candidate)) return candidate;
165
+ }
166
+ return decoded;
167
+ }
168
+
169
+ function _statSignature(storeDbPath) {
170
+ const parts = [];
171
+ for (const fp of [storeDbPath, `${storeDbPath}-wal`, `${storeDbPath}-shm`]) {
172
+ try {
173
+ const st = fs.statSync(fp);
174
+ parts.push(`${st.size}:${Math.floor(st.mtimeMs)}`);
175
+ } catch {
176
+ parts.push('0:0');
177
+ }
178
+ }
179
+ return parts.join('|');
180
+ }
181
+
182
+ function loadCursorStore(storeDbPath) {
183
+ const fp = path.resolve(String(storeDbPath || ''));
184
+ const signature = _statSignature(fp);
185
+ const cached = CACHE.get(fp);
186
+ if (cached && cached.signature === signature) return cached.result;
187
+
188
+ const db = new Database(fp, { readonly: true, fileMustExist: true });
189
+ try {
190
+ const meta = _readMeta(db);
191
+ if (!meta?.latestRootBlobId) return null;
192
+ const rows = db.prepare('SELECT id, data FROM blobs').all();
193
+ const blobsById = new Map();
194
+ for (const row of rows) {
195
+ const id = String(row.id || '').trim();
196
+ if (SHA256_HEX_RE.test(id)) blobsById.set(id, _bufferFromBlob(row.data));
197
+ }
198
+ const rootBlob = blobsById.get(String(meta.latestRootBlobId || '').trim()) || null;
199
+ const workspaceUri = rootBlob ? _workspaceUriFromBlob(rootBlob) : '';
200
+ const reachableIds = _reachableBlobIds(meta.latestRootBlobId, blobsById);
201
+ const messages = [];
202
+ reachableIds.forEach((id, index) => {
203
+ const blob = blobsById.get(id);
204
+ if (!blob || blob[0] !== 0x7b) return;
205
+ try {
206
+ const message = _messageFromBlobJson(JSON.parse(blob.toString('utf8')), index, meta);
207
+ if (message) messages.push(message);
208
+ } catch {}
209
+ });
210
+ const result = {
211
+ storeDbPath: fp,
212
+ agentId: String(meta.agentId || ''),
213
+ name: String(meta.name || ''),
214
+ createdAtMs: Number(meta.createdAt || 0) || 0,
215
+ lastUsedModel: String(meta.lastUsedModel || ''),
216
+ workspaceUri,
217
+ workspacePath: _workspacePathFromUri(workspaceUri),
218
+ messages,
219
+ };
220
+ CACHE.set(fp, { signature, result });
221
+ return result;
222
+ } finally {
223
+ db.close();
224
+ }
225
+ }
226
+
227
+ function _listCursorStoreDbPaths(cursorHome = CURSOR_HOME()) {
228
+ const chatsDir = path.join(cursorHome, 'chats');
229
+ let workspaceDirs = [];
230
+ try { workspaceDirs = fs.readdirSync(chatsDir, { withFileTypes: true }); } catch { return []; }
231
+ const paths = [];
232
+ for (const workspaceEntry of workspaceDirs) {
233
+ if (!workspaceEntry.isDirectory()) continue;
234
+ const workspaceDir = path.join(chatsDir, workspaceEntry.name);
235
+ let agentDirs = [];
236
+ try { agentDirs = fs.readdirSync(workspaceDir, { withFileTypes: true }); } catch { continue; }
237
+ for (const agentEntry of agentDirs) {
238
+ if (!agentEntry.isDirectory()) continue;
239
+ const storePath = path.join(workspaceDir, agentEntry.name, 'store.db');
240
+ if (fs.existsSync(storePath)) paths.push(storePath);
241
+ }
242
+ }
243
+ return paths;
244
+ }
245
+
246
+ function _parseTimeMs(value) {
247
+ if (typeof value === 'number') return Number.isFinite(value) ? value : 0;
248
+ const text = String(value || '').trim();
249
+ if (!text) return 0;
250
+ const parsed = Date.parse(/[zZ]|[+-]\d\d:?\d\d$/.test(text) ? text : text.replace(' ', 'T') + 'Z');
251
+ return Number.isFinite(parsed) ? parsed : 0;
252
+ }
253
+
254
+ function _samePath(a, b) {
255
+ if (!a || !b) return false;
256
+ try { return path.resolve(a) === path.resolve(b); } catch { return String(a) === String(b); }
257
+ }
258
+
259
+ function findCursorStoresForSession(options = {}) {
260
+ const cwd = String(options.cwd || '').trim();
261
+ const createdAtMs = _parseTimeMs(options.createdAt || options.created_at);
262
+ const updatedAtMs = _parseTimeMs(options.updatedAt || options.updated_at);
263
+ const targetMs = updatedAtMs || createdAtMs || Date.now();
264
+ const agentIds = new Set((options.agentSessionIds || options.agentIds || [])
265
+ .map(id => String(id || '').trim())
266
+ .filter(Boolean));
267
+ const stores = [];
268
+ for (const storeDbPath of _listCursorStoreDbPaths(options.cursorHome)) {
269
+ let store;
270
+ try { store = loadCursorStore(storeDbPath); } catch { continue; }
271
+ if (!store) continue;
272
+ const agentMatch = store.agentId && agentIds.has(store.agentId);
273
+ const cwdMatch = cwd && _samePath(store.workspacePath, cwd);
274
+ if (!agentMatch && !cwdMatch) continue;
275
+ const created = store.createdAtMs || 0;
276
+ const distanceMs = created && targetMs ? Math.abs(created - targetMs) : Number.MAX_SAFE_INTEGER;
277
+ stores.push({
278
+ ...store,
279
+ _score: {
280
+ agentMatch: agentMatch ? 1 : 0,
281
+ cwdMatch: cwdMatch ? 1 : 0,
282
+ distanceMs,
283
+ createdAtMs: created,
284
+ },
285
+ });
286
+ }
287
+ stores.sort((a, b) => (
288
+ b._score.agentMatch - a._score.agentMatch
289
+ || b._score.cwdMatch - a._score.cwdMatch
290
+ || a._score.distanceMs - b._score.distanceMs
291
+ || b._score.createdAtMs - a._score.createdAtMs
292
+ || a.storeDbPath.localeCompare(b.storeDbPath)
293
+ ));
294
+ return stores;
295
+ }
296
+
297
+ function loadCursorConversationForSession(options = {}) {
298
+ const stores = findCursorStoresForSession(options);
299
+ for (const store of stores) {
300
+ if (store.messages.length > 0) return store;
301
+ }
302
+ return stores[0] || null;
303
+ }
304
+
305
+ // Map a reconstructed cursor store to the fields db.importSessionConversation expects, so a
306
+ // cursor conversation lands in session_conversations exactly like a Claude/Codex import and
307
+ // the normal cache read path serves it. Pure (no I/O) → unit-testable. messages already carry
308
+ // the {role,text,timestamp,provider,metadata} shape the renderer expects.
309
+ function cursorStoreToConversationFields(store) {
310
+ const messages = Array.isArray(store?.messages) ? store.messages : [];
311
+ let user_msg_count = 0;
312
+ let assistant_msg_count = 0;
313
+ let first_message = '';
314
+ let first_assistant_text = '';
315
+ let last_user_content = '';
316
+ for (const m of messages) {
317
+ if (!m || typeof m !== 'object') continue;
318
+ if (m.role === 'user') {
319
+ user_msg_count += 1;
320
+ if (!first_message) first_message = String(m.text || '');
321
+ if (m.text) last_user_content = String(m.text);
322
+ } else if (m.role === 'assistant') {
323
+ assistant_msg_count += 1;
324
+ if (!first_assistant_text) first_assistant_text = String(m.text || '');
325
+ }
326
+ }
327
+ return {
328
+ messages,
329
+ user_msg_count,
330
+ assistant_msg_count,
331
+ first_message,
332
+ last_user_content,
333
+ first_assistant_text,
334
+ project_path: String(store?.workspacePath || ''),
335
+ model_provider: 'cursor',
336
+ model_id: String(store?.lastUsedModel || ''),
337
+ session_created_at: Number(store?.createdAtMs) > 0 ? new Date(Number(store.createdAtMs)).toISOString() : '',
338
+ };
339
+ }
340
+
341
+ module.exports = {
342
+ loadCursorStore,
343
+ findCursorStoresForSession,
344
+ loadCursorConversationForSession,
345
+ cursorStoreToConversationFields,
346
+ statSignature: _statSignature, // cheap size:mtime gate for incremental import
347
+ _test: {
348
+ _decodeMaybeHexJson,
349
+ _orderedBlobRefs,
350
+ _reachableBlobIds,
351
+ _normalizeCursorUserText,
352
+ _parseTimeMs,
353
+ },
354
+ };
@@ -0,0 +1,315 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const { Worker } = require('node:worker_threads');
5
+
6
+ const DEFAULT_REQUEST_TIMEOUT_MS = 30 * 1000;
7
+ const DEFAULT_CLOSE_TIMEOUT_MS = 5 * 1000;
8
+ const DEFAULT_WORKER_WRITE_LOCK_TIMEOUT_MS = 5000;
9
+ // Circuit breaker: after this many consecutive request timeouts the worker is
10
+ // treated as "degraded" (busy/wedged, not merely a one-off slow op), and
11
+ // best-effort ops fail fast WITHOUT being enqueued — so a slow worker stops
12
+ // accumulating a backlog of stale work that re-holds the SQLite write lock.
13
+ const DEFAULT_DEGRADE_AFTER_TIMEOUTS = 3;
14
+ // While degraded, best-effort ops are skipped for this long; after it elapses one
15
+ // is allowed through (half-open probe) — it resets the breaker if it succeeds, or
16
+ // re-arms the cooldown if it times out again.
17
+ const DEFAULT_DEGRADE_COOLDOWN_MS = 5000;
18
+
19
+ function _durationMs(value, fallback) {
20
+ const n = Number(value);
21
+ return Number.isFinite(n) ? Math.max(0, Math.trunc(n)) : fallback;
22
+ }
23
+
24
+ class CtmDbOwnerWorkerClient {
25
+ constructor(options = {}) {
26
+ if (!options.dbPath) throw new Error('CtmDbOwnerWorkerClient requires dbPath');
27
+ this.dbPath = options.dbPath;
28
+ this.workerPath = options.workerPath || path.resolve(__dirname, '..', 'workers', 'db-owner-worker.js');
29
+ this.initDb = !!options.initDb;
30
+ this.requestTimeoutMs = _durationMs(options.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS);
31
+ this.closeTimeoutMs = _durationMs(options.closeTimeoutMs, DEFAULT_CLOSE_TIMEOUT_MS);
32
+ this.workerWriteLockTimeoutMs = _durationMs(
33
+ options.workerWriteLockTimeoutMs ??
34
+ process.env.CTM_DB_OWNER_WORKER_WRITE_LOCK_TIMEOUT_MS,
35
+ DEFAULT_WORKER_WRITE_LOCK_TIMEOUT_MS
36
+ );
37
+ this.logger = options.logger || console;
38
+ this._degradeAfter = Math.max(1, _durationMs(
39
+ options.degradeAfterTimeouts ?? process.env.CTM_DB_OWNER_WORKER_DEGRADE_AFTER,
40
+ DEFAULT_DEGRADE_AFTER_TIMEOUTS
41
+ ));
42
+ this._degradeCooldownMs = _durationMs(
43
+ options.degradeCooldownMs ?? process.env.CTM_DB_OWNER_WORKER_DEGRADE_COOLDOWN_MS,
44
+ DEFAULT_DEGRADE_COOLDOWN_MS
45
+ );
46
+
47
+ this._worker = null;
48
+ this._startPromise = null;
49
+ this._ready = false;
50
+ this._closed = false;
51
+ this._nextRequestId = 1;
52
+ this._pending = new Map();
53
+ // Circuit-breaker state. _consecutiveTimeouts resets on any in-time success.
54
+ // _degradedUntil is the timestamp through which best-effort ops are skipped.
55
+ this._consecutiveTimeouts = 0;
56
+ this._degradedUntil = 0;
57
+ this._status = {
58
+ ready: false,
59
+ pendingClientRequests: 0,
60
+ workerPending: 0,
61
+ workerActive: null,
62
+ completed: 0,
63
+ failed: 0,
64
+ };
65
+ }
66
+
67
+ start() {
68
+ if (this._closed) return Promise.reject(new Error('DB owner worker client is closed'));
69
+ if (this._ready) return Promise.resolve(this);
70
+ if (this._startPromise) return this._startPromise;
71
+
72
+ this._startPromise = new Promise((resolve, reject) => {
73
+ const worker = new Worker(this.workerPath, {
74
+ workerData: {
75
+ dbPath: this.dbPath,
76
+ initDb: this.initDb,
77
+ },
78
+ env: {
79
+ ...process.env,
80
+ CTM_DB_OWNER_WORKER: '1',
81
+ CTM_SQLITE_WRITE_LOCK_TIMEOUT_MS: String(this.workerWriteLockTimeoutMs),
82
+ },
83
+ });
84
+ this._worker = worker;
85
+
86
+ const failStart = (err) => {
87
+ if (this._ready) return;
88
+ this._startPromise = null;
89
+ this._worker = null;
90
+ try { worker.terminate(); } catch {}
91
+ reject(err instanceof Error ? err : new Error(String(err || 'DB owner worker failed to start')));
92
+ };
93
+
94
+ worker.on('message', (msg) => {
95
+ if (!msg || typeof msg !== 'object') return;
96
+ if (msg.type === 'ready') {
97
+ this._ready = true;
98
+ this._status.ready = true;
99
+ this._status.workerPending = 0;
100
+ this._status.workerActive = null;
101
+ resolve(this);
102
+ return;
103
+ }
104
+ if (msg.type === 'status') {
105
+ this._status = {
106
+ ...this._status,
107
+ ...msg.status,
108
+ ready: this._ready,
109
+ pendingClientRequests: this._pending.size,
110
+ };
111
+ return;
112
+ }
113
+ if (msg.type === 'response') {
114
+ this._finishRequest(msg.requestId, msg.error, msg.result);
115
+ return;
116
+ }
117
+ if (msg.type === 'closed') {
118
+ this._ready = false;
119
+ this._closed = true;
120
+ this._status.ready = false;
121
+ this._rejectAllPending(new Error('DB owner worker closed'));
122
+ return;
123
+ }
124
+ if (msg.type === 'fatal') {
125
+ const err = new Error(msg.error || 'DB owner worker fatal error');
126
+ err.code = msg.code || 'CTM_DB_OWNER_WORKER_FATAL';
127
+ if (!this._ready) failStart(err);
128
+ this._rejectAllPending(err);
129
+ return;
130
+ }
131
+ if (msg.type === 'log' && this.logger && typeof this.logger[msg.level || 'log'] === 'function') {
132
+ this.logger[msg.level || 'log'](`[ctm-db-worker] ${msg.message || ''}`);
133
+ }
134
+ });
135
+
136
+ worker.on('error', (err) => {
137
+ if (!this._ready) failStart(err);
138
+ this._rejectAllPending(err);
139
+ });
140
+ worker.on('exit', (code) => {
141
+ const wasReady = this._ready;
142
+ this._ready = false;
143
+ this._worker = null;
144
+ this._startPromise = null;
145
+ this._status.ready = false;
146
+ if (!this._closed && code !== 0) {
147
+ const err = new Error(`DB owner worker exited with code ${code}`);
148
+ err.code = 'CTM_DB_OWNER_WORKER_EXITED';
149
+ if (!wasReady) failStart(err);
150
+ this._rejectAllPending(err);
151
+ }
152
+ });
153
+ });
154
+
155
+ return this._startPromise;
156
+ }
157
+
158
+ isDegraded() {
159
+ return Date.now() < this._degradedUntil;
160
+ }
161
+
162
+ _recordTimeout(op) {
163
+ this._consecutiveTimeouts += 1;
164
+ if (this._consecutiveTimeouts >= this._degradeAfter) {
165
+ const wasDegraded = this.isDegraded();
166
+ this._degradedUntil = Date.now() + this._degradeCooldownMs;
167
+ if (!wasDegraded && this.logger && typeof this.logger.warn === 'function') {
168
+ this.logger.warn(
169
+ `[ctm-db-worker] degraded after ${this._consecutiveTimeouts} consecutive timeouts ` +
170
+ `(last op: ${op}); best-effort ops will be skipped for ${this._degradeCooldownMs}ms`
171
+ );
172
+ }
173
+ }
174
+ }
175
+
176
+ _recordSuccess() {
177
+ if (this._consecutiveTimeouts === 0 && this._degradedUntil === 0) return;
178
+ const wasDegraded = this.isDegraded();
179
+ this._consecutiveTimeouts = 0;
180
+ this._degradedUntil = 0;
181
+ if (wasDegraded && this.logger && typeof this.logger.log === 'function') {
182
+ this.logger.log('[ctm-db-worker] recovered; resuming best-effort ops');
183
+ }
184
+ }
185
+
186
+ async request(op, payload = {}, options = {}) {
187
+ if (!op) throw new Error('DB owner worker request requires op');
188
+ // Circuit breaker: when the worker is degraded, fail best-effort ops fast
189
+ // WITHOUT enqueuing — a wedged worker must not keep accumulating stale
190
+ // best-effort work (e.g. scrollback) that re-holds the write lock later.
191
+ // After the cooldown one best-effort op is allowed through as a half-open probe.
192
+ if (options.bestEffort && this.isDegraded()) {
193
+ const err = new Error(`DB owner worker degraded; skipped best-effort op: ${op}`);
194
+ err.code = 'CTM_DB_OWNER_WORKER_DEGRADED';
195
+ throw err;
196
+ }
197
+ await this.start();
198
+ if (!this._worker) throw new Error('DB owner worker is not running');
199
+ const requestId = this._nextRequestId++;
200
+ const timeoutMs = _durationMs(options.timeoutMs, this.requestTimeoutMs);
201
+ return await new Promise((resolve, reject) => {
202
+ let timer = null;
203
+ if (timeoutMs > 0) {
204
+ timer = setTimeout(() => {
205
+ this._pending.delete(requestId);
206
+ this._recordTimeout(op);
207
+ reject(new Error(`DB owner worker request timed out: ${op}`));
208
+ }, timeoutMs);
209
+ if (typeof timer.unref === 'function') timer.unref();
210
+ }
211
+ this._pending.set(requestId, { op, resolve, reject, timer });
212
+ this._status.pendingClientRequests = this._pending.size;
213
+ try {
214
+ this._worker.postMessage({ type: 'request', requestId, op, payload });
215
+ } catch (err) {
216
+ this._finishRequest(requestId, err);
217
+ }
218
+ });
219
+ }
220
+
221
+ async drain(options = {}) {
222
+ return await this.request('drain', {}, options);
223
+ }
224
+
225
+ getStatus() {
226
+ return {
227
+ ...this._status,
228
+ ready: this._ready,
229
+ closed: this._closed,
230
+ pendingClientRequests: this._pending.size,
231
+ degraded: this.isDegraded(),
232
+ consecutiveTimeouts: this._consecutiveTimeouts,
233
+ dbPath: this.dbPath,
234
+ };
235
+ }
236
+
237
+ async close(options = {}) {
238
+ if (this._closed) return { ok: true, alreadyClosed: true };
239
+ const worker = this._worker;
240
+ this._closed = true;
241
+ if (!worker) {
242
+ this._rejectAllPending(new Error('DB owner worker closed'));
243
+ return { ok: true, alreadyClosed: true };
244
+ }
245
+ const timeoutMs = _durationMs(options.timeoutMs, this.closeTimeoutMs);
246
+ await new Promise((resolve) => {
247
+ let done = false;
248
+ const finish = () => {
249
+ if (done) return;
250
+ done = true;
251
+ resolve();
252
+ };
253
+ let timer = null;
254
+ if (timeoutMs > 0) {
255
+ timer = setTimeout(() => {
256
+ worker.terminate().finally(finish);
257
+ }, timeoutMs);
258
+ if (typeof timer.unref === 'function') timer.unref();
259
+ }
260
+ const onMessage = (msg) => {
261
+ if (msg?.type !== 'closed') return;
262
+ if (timer) clearTimeout(timer);
263
+ worker.off('message', onMessage);
264
+ finish();
265
+ };
266
+ worker.on('message', onMessage);
267
+ try { worker.postMessage({ type: 'close' }); }
268
+ catch {
269
+ if (timer) clearTimeout(timer);
270
+ worker.off('message', onMessage);
271
+ worker.terminate().finally(finish);
272
+ }
273
+ });
274
+ this._ready = false;
275
+ this._worker = null;
276
+ this._rejectAllPending(new Error('DB owner worker closed'));
277
+ return { ok: true };
278
+ }
279
+
280
+ _finishRequest(requestId, error, result) {
281
+ const pending = this._pending.get(requestId);
282
+ if (!pending) return;
283
+ this._pending.delete(requestId);
284
+ this._status.pendingClientRequests = this._pending.size;
285
+ if (pending.timer) clearTimeout(pending.timer);
286
+ if (error) {
287
+ const err = error instanceof Error ? error : new Error(String(error.message || error || 'DB owner worker request failed'));
288
+ if (error.code) err.code = error.code;
289
+ pending.reject(err);
290
+ } else {
291
+ // An in-time reply proves the worker is draining — clear the breaker.
292
+ this._recordSuccess();
293
+ pending.resolve(result);
294
+ }
295
+ }
296
+
297
+ _rejectAllPending(err) {
298
+ const pending = Array.from(this._pending.values());
299
+ this._pending.clear();
300
+ this._status.pendingClientRequests = 0;
301
+ for (const req of pending) {
302
+ if (req.timer) clearTimeout(req.timer);
303
+ req.reject(err);
304
+ }
305
+ }
306
+ }
307
+
308
+ function createDbOwnerWorkerClient(options = {}) {
309
+ return new CtmDbOwnerWorkerClient(options);
310
+ }
311
+
312
+ module.exports = {
313
+ CtmDbOwnerWorkerClient,
314
+ createDbOwnerWorkerClient,
315
+ };