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,68 @@
1
+ 'use strict';
2
+
3
+ const DEFAULT_RESTORE_ACTIVITY_SUPPRESSION_MS = 10_000;
4
+
5
+ function numericMs(value) {
6
+ const n = Number(value || 0);
7
+ return Number.isFinite(n) && n > 0 ? n : 0;
8
+ }
9
+
10
+ function restoreHoldMs(runningHoldMs = 0) {
11
+ return Math.max(DEFAULT_RESTORE_ACTIVITY_SUPPRESSION_MS, numericMs(runningHoldMs));
12
+ }
13
+
14
+ function beginRestoreState(session, opts = {}) {
15
+ if (!session) return null;
16
+ const now = numericMs(opts.now) || Date.now();
17
+ const until = now + restoreHoldMs(opts.runningHoldMs);
18
+ session._restoredFromStartup = true;
19
+ session._restoreStarting = true;
20
+ session._restoreStartingUntil = until;
21
+ session._restoreActivitySuppressUntil = until;
22
+ session._restoreStartedAt = now;
23
+ return { until };
24
+ }
25
+
26
+ function restoreStartingActive(session, now = Date.now()) {
27
+ if (!session || !session._restoreStarting) return false;
28
+ const until = numericMs(session._restoreStartingUntil);
29
+ return !until || now < until;
30
+ }
31
+
32
+ function restoreActivitySuppressed(session, now = Date.now()) {
33
+ if (!session) return false;
34
+ const until = numericMs(session._restoreActivitySuppressUntil);
35
+ if (!until || now >= until) return false;
36
+ const startedAt = numericMs(session._restoreStartedAt);
37
+ const lastUserInputAt = numericMs(session.lastUserInputAt);
38
+ return !(lastUserInputAt && (!startedAt || lastUserInputAt >= startedAt));
39
+ }
40
+
41
+ function clearRestoreState(session) {
42
+ if (!session) return session;
43
+ session._restoredFromStartup = false;
44
+ session._restoreStarting = false;
45
+ session._restoreStartingUntil = 0;
46
+ session._restoreActivitySuppressUntil = 0;
47
+ session._restoreStartedAt = 0;
48
+ return session;
49
+ }
50
+
51
+ function markUserInput(session, now = Date.now()) {
52
+ if (!session) return session;
53
+ session.lastUserInputAt = now;
54
+ if (restoreStartingActive(session, now) || restoreActivitySuppressed(session, now)) {
55
+ clearRestoreState(session);
56
+ }
57
+ return session;
58
+ }
59
+
60
+ module.exports = {
61
+ DEFAULT_RESTORE_ACTIVITY_SUPPRESSION_MS,
62
+ beginRestoreState,
63
+ clearRestoreState,
64
+ markUserInput,
65
+ restoreActivitySuppressed,
66
+ restoreHoldMs,
67
+ restoreStartingActive,
68
+ };
@@ -0,0 +1,34 @@
1
+ 'use strict';
2
+
3
+ // Decision logic for the post-restore read-pool stampede (pure; unit-tested in
4
+ // tests/restore-storm.test.js). See that file's header for the problem statement.
5
+ //
6
+ // Used by server.js to (A) keep the generous off-thread read timeout active through the
7
+ // restore window AND a grace period after it, so cold reads finish ON the pool instead of
8
+ // bailing to a main-thread compute; and (B) when an off-thread read still fails during the
9
+ // storm (pool wedged → breaker open, or even the long timeout exceeded), serve a degraded
10
+ // value instead of freezing the event loop with a synchronous main-thread build.
11
+
12
+ // True for the whole storm window: while the restore loop runs, plus a grace period after
13
+ // it completes. The grace covers the SECOND stampede — the post-restore broadcast +
14
+ // auto-resume + every UI tab cold-loading at once — which lands just after the loop clears
15
+ // _restoreInProgress, exactly when the protection used to switch off.
16
+ function inRestoreStorm({ restoreInProgress, restoreCompletedAt, now, graceMs }) {
17
+ if (restoreInProgress) return true;
18
+ if (!(restoreCompletedAt > 0)) return false;
19
+ return (now - restoreCompletedAt) < graceMs;
20
+ }
21
+
22
+ // Decide what an off-thread read's onFail serves when the pool didn't answer:
23
+ // * a last-good cached value, if present — always preferred, never stale-blocks;
24
+ // * during the storm with no cache — the degraded value (e.g. [] / empty), so the heavy
25
+ // compute NEVER runs on the main loop (the freeze we're eliminating);
26
+ // * only when calm AND cold — build once on the main thread, so a normal cold cache miss
27
+ // still returns an immediate, correct result (boot/first-load recovers without a retry).
28
+ function offthreadFallback({ inStorm, hasCached, cached, mainCompute, stormEmpty }) {
29
+ if (hasCached) return cached;
30
+ if (inStorm) return stormEmpty;
31
+ return mainCompute();
32
+ }
33
+
34
+ module.exports = { inRestoreStorm, offthreadFallback };
@@ -12,6 +12,37 @@ function normalizeCwd(value) {
12
12
  return path.normalize(path.isAbsolute(expanded) ? expanded : path.resolve(expanded));
13
13
  }
14
14
 
15
+ function canonicalizeClaudeProjectPath(cwd, opts = {}) {
16
+ const home = opts.homeDir || process.env.HOME || '';
17
+ const resolved = path.resolve(normalizeCwd(cwd) || home || '.');
18
+ try {
19
+ // Claude Code records the kernel-resolved cwd in JSONL metadata on macOS
20
+ // (/tmp -> /private/tmp). Use the same path for project-entry prediction;
21
+ // callers still pass the original cwd to the spawned process.
22
+ return fs.realpathSync(resolved);
23
+ } catch {
24
+ return resolved;
25
+ }
26
+ }
27
+
28
+ function encodeClaudeProjectEntry(cwd, opts = {}) {
29
+ return canonicalizeClaudeProjectPath(cwd, opts)
30
+ .replace(/\/\./g, '/-')
31
+ .replace(/\//g, '-');
32
+ }
33
+
34
+ function claudeProjectDirForCwd(cwd, opts = {}) {
35
+ const home = opts.homeDir || process.env.HOME || '';
36
+ const configDir = opts.claudeConfigDir || path.join(home, '.claude');
37
+ return path.join(configDir, 'projects', encodeClaudeProjectEntry(cwd, opts));
38
+ }
39
+
40
+ function samePath(a, b) {
41
+ const left = normalizeCwd(a);
42
+ const right = normalizeCwd(b);
43
+ return !!left && !!right && left === right;
44
+ }
45
+
15
46
  function parseAgentWorktreePath(value) {
16
47
  const cwd = normalizeCwd(value);
17
48
  if (!cwd) return null;
@@ -70,7 +101,12 @@ function resolveResumeCwdFallback(cwd, opts = {}) {
70
101
  }
71
102
 
72
103
  module.exports = {
104
+ canonicalizeClaudeProjectPath,
105
+ claudeProjectDirForCwd,
106
+ encodeClaudeProjectEntry,
107
+ normalizeCwd,
73
108
  parseAgentWorktreePath,
74
109
  resolveResumeCwd,
75
110
  resolveResumeCwdFallback,
111
+ samePath,
76
112
  };
@@ -0,0 +1,313 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ const { normalizeAgentType } = require('./agent-capabilities');
7
+ const { claudeProjectDirForCwd, normalizeCwd, samePath } = require('./resume-cwd');
8
+
9
+ function _asString(value) {
10
+ return String(value || '').trim();
11
+ }
12
+
13
+ function _existingFile(filePath) {
14
+ const clean = _asString(filePath);
15
+ if (!clean) return null;
16
+ try {
17
+ const st = fs.statSync(clean);
18
+ if (!st.isFile()) return null;
19
+ return { path: clean, size: st.size || 0, modifiedAt: st.mtime ? st.mtime.toISOString() : '' };
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+
25
+ function _pushUnique(out, value) {
26
+ const clean = _asString(value);
27
+ if (clean && !out.includes(clean)) out.push(clean);
28
+ }
29
+
30
+ // A Claude transcript is "real" only if it carries at least one conversation
31
+ // turn. Claude Code / CTM also write metadata-only sidecar lines (ai-title,
32
+ // agent-name, mode, permission-mode, last-prompt, …); a file that holds ONLY
33
+ // those is a stub that `claude --resume` rejects with "No conversation found".
34
+ const CONVERSATION_LINE_TYPES = new Set(['user', 'assistant', 'summary', 'system']);
35
+ // Bound the scan so a healthy multi-MB transcript early-exits on its first turn
36
+ // and a pathological metadata-only file can't force a full read. A real session
37
+ // hits a conversation line within the first handful of lines.
38
+ const CONVERSATION_SCAN_BYTE_CAP = 512 * 1024;
39
+
40
+ function _lineIsConversation(line) {
41
+ // Cheap substring pre-filter before the JSON.parse.
42
+ if (line.indexOf('"type"') === -1) return false;
43
+ try {
44
+ return CONVERSATION_LINE_TYPES.has(JSON.parse(line).type);
45
+ } catch {
46
+ return false;
47
+ }
48
+ }
49
+
50
+ // Returns true when `filePath` contains at least one real conversation turn.
51
+ // Conservative on ambiguity: an unreadable file, or one whose first
52
+ // CONVERSATION_SCAN_BYTE_CAP bytes hold no turn but which is larger than the
53
+ // cap (so the scan was incomplete), is reported `true` so callers never
54
+ // overwrite a transcript they could not fully inspect.
55
+ function transcriptHasConversation(filePath, opts = {}) {
56
+ const clean = _asString(filePath);
57
+ if (!clean) return false;
58
+ let st;
59
+ try {
60
+ st = fs.statSync(clean);
61
+ } catch {
62
+ return false; // missing/unstattable → no conversation (nothing to preserve)
63
+ }
64
+ if (!st.isFile() || st.size === 0) return false;
65
+ let fd;
66
+ try {
67
+ const cap = opts.byteCap || CONVERSATION_SCAN_BYTE_CAP;
68
+ const toRead = Math.min(st.size, cap);
69
+ fd = fs.openSync(clean, 'r');
70
+ const buf = Buffer.allocUnsafe(toRead);
71
+ const read = fs.readSync(fd, buf, 0, toRead, 0);
72
+ const text = buf.toString('utf8', 0, read);
73
+ const fullyRead = read >= st.size;
74
+ let lineStart = 0;
75
+ for (let i = 0; i < text.length; i++) {
76
+ if (text[i] !== '\n') continue;
77
+ const line = text.slice(lineStart, i).trim();
78
+ lineStart = i + 1;
79
+ if (line && _lineIsConversation(line)) return true;
80
+ }
81
+ // Trailing line without a newline is only trustworthy on a complete read.
82
+ if (fullyRead && lineStart < text.length) {
83
+ const tail = text.slice(lineStart).trim();
84
+ if (tail && _lineIsConversation(tail)) return true;
85
+ }
86
+ // No turn found. Definitively a stub only if we scanned the whole file;
87
+ // otherwise assume conversation exists (never clobber a large transcript).
88
+ return !fullyRead;
89
+ } catch {
90
+ return true; // unreadable → treat as real so we never overwrite it
91
+ } finally {
92
+ if (fd !== undefined) { try { fs.closeSync(fd); } catch {} }
93
+ }
94
+ }
95
+
96
+ // Decide whether to (re)hydrate a live `<id>.jsonl` from its `<id>.jsonl.bak`.
97
+ // Restore when the backup carries a real conversation AND the live transcript
98
+ // is either missing OR a metadata-only stub. Never restore from an empty/stub
99
+ // backup, and never overwrite a live transcript that already has turns.
100
+ function claudeLiveTranscriptShouldRestore(jsonlPath, bakPath) {
101
+ if (!_existingFile(bakPath)) return false;
102
+ if (!transcriptHasConversation(bakPath)) return false;
103
+ if (!_existingFile(jsonlPath)) return true;
104
+ return !transcriptHasConversation(jsonlPath);
105
+ }
106
+
107
+ // Synchronous recovery used by the interactive resume / attach paths. Returns
108
+ // { restored, reason }. The `.bak` is only ever read, never modified, so the
109
+ // operation stays reversible. A clobbered stub is preserved as a `.stub-<n>`
110
+ // sibling (best effort) so the overwrite can be inspected after the fact.
111
+ function restoreClaudeLiveTranscriptFromBak(jsonlPath, bakPath, opts = {}) {
112
+ const live = _asString(jsonlPath);
113
+ const bak = _asString(bakPath);
114
+ if (!live || !bak) return { restored: false, reason: 'missing_paths' };
115
+ const liveExisted = !!_existingFile(live);
116
+ if (!claudeLiveTranscriptShouldRestore(live, bak)) {
117
+ return { restored: false, reason: liveExisted ? 'live_ok' : 'no_source' };
118
+ }
119
+ if (liveExisted) {
120
+ try {
121
+ const stamp = typeof opts.now === 'number' ? opts.now : Date.now();
122
+ fs.renameSync(live, `${live}.stub-${stamp}`);
123
+ } catch { /* best effort — proceed to overwrite */ }
124
+ }
125
+ fs.copyFileSync(bak, live);
126
+ return { restored: true, reason: liveExisted ? 'replaced_stub' : 'restored_missing' };
127
+ }
128
+
129
+ function _candidateClaudeTranscriptPaths(options = {}) {
130
+ const { resumeId, jsonlPath, homeDir, claudeConfigDir } = options;
131
+ const paths = [];
132
+ const id = _asString(resumeId);
133
+ const stored = _asString(jsonlPath);
134
+ if (stored) {
135
+ _pushUnique(paths, stored);
136
+ if (stored.endsWith('.jsonl')) _pushUnique(paths, stored + '.bak');
137
+ if (stored.endsWith('.jsonl.bak')) _pushUnique(paths, stored.replace(/\.bak$/, ''));
138
+ }
139
+ if (!id) return paths;
140
+
141
+ const configDir = _asString(claudeConfigDir) || path.join(homeDir || process.env.HOME || '', '.claude');
142
+ const projectsDir = path.join(configDir, 'projects');
143
+ try {
144
+ for (const entry of fs.readdirSync(projectsDir)) {
145
+ const dir = path.join(projectsDir, entry);
146
+ _pushUnique(paths, path.join(dir, `${id}.jsonl`));
147
+ _pushUnique(paths, path.join(dir, `${id}.jsonl.bak`));
148
+ }
149
+ } catch {
150
+ // Missing ~/.claude/projects is reported as a normal missing-transcript result.
151
+ }
152
+ return paths;
153
+ }
154
+
155
+ function findClaudeResumeTranscript(options = {}) {
156
+ const paths = _candidateClaudeTranscriptPaths(options);
157
+ for (const candidate of paths) {
158
+ const found = _existingFile(candidate);
159
+ if (found) {
160
+ found.restoreFromBak = candidate.endsWith('.jsonl.bak');
161
+ return found;
162
+ }
163
+ }
164
+ return null;
165
+ }
166
+
167
+ function _candidateCwds(options = {}) {
168
+ const candidates = [];
169
+ const row = options.agentRow || {};
170
+ for (const value of [
171
+ options.projectPath,
172
+ row.project_path,
173
+ row.cwd,
174
+ options.cwd,
175
+ ]) {
176
+ const clean = normalizeCwd(value);
177
+ if (clean && !candidates.includes(clean)) candidates.push(clean);
178
+ }
179
+ return candidates;
180
+ }
181
+
182
+ function _existingDirectory(dir, fsExists = fs.existsSync, fsStat = fs.statSync) {
183
+ const clean = normalizeCwd(dir);
184
+ if (!clean) return false;
185
+ try {
186
+ return !!fsExists(clean) && fsStat(clean).isDirectory();
187
+ } catch {
188
+ return false;
189
+ }
190
+ }
191
+
192
+ function resolveClaudeResumeCwd(options = {}) {
193
+ const transcriptPath = _asString(options.transcriptPath);
194
+ const currentCwd = normalizeCwd(options.cwd);
195
+ if (!transcriptPath || !currentCwd) {
196
+ return { cwd: currentCwd, changed: false, reason: '' };
197
+ }
198
+
199
+ const transcriptProjectDir = normalizeCwd(path.dirname(transcriptPath));
200
+ const projectOpts = {
201
+ homeDir: options.homeDir,
202
+ claudeConfigDir: options.claudeConfigDir,
203
+ };
204
+ const currentProjectDir = claudeProjectDirForCwd(currentCwd, projectOpts);
205
+ if (samePath(currentProjectDir, transcriptProjectDir)) {
206
+ return {
207
+ cwd: currentCwd,
208
+ changed: false,
209
+ reason: '',
210
+ transcriptProjectDir,
211
+ cwdProjectDir: currentProjectDir,
212
+ };
213
+ }
214
+
215
+ const fsExists = options.fsExists || fs.existsSync;
216
+ const fsStat = options.fsStat || fs.statSync;
217
+ for (const candidate of _candidateCwds(options)) {
218
+ if (!_existingDirectory(candidate, fsExists, fsStat)) continue;
219
+ const candidateProjectDir = claudeProjectDirForCwd(candidate, projectOpts);
220
+ if (samePath(candidateProjectDir, transcriptProjectDir)) {
221
+ return {
222
+ cwd: candidate,
223
+ changed: !samePath(candidate, currentCwd),
224
+ reason: 'claude_project_transcript_match',
225
+ transcriptProjectDir,
226
+ cwdProjectDir: currentProjectDir,
227
+ effectiveProjectDir: candidateProjectDir,
228
+ };
229
+ }
230
+ }
231
+
232
+ return {
233
+ cwd: currentCwd,
234
+ changed: false,
235
+ blocked: true,
236
+ reason: 'claude_resume_project_mismatch',
237
+ transcriptProjectDir,
238
+ cwdProjectDir: currentProjectDir,
239
+ };
240
+ }
241
+
242
+ function validateResumeTarget(options = {}) {
243
+ const agentType = normalizeAgentType(options.agentType || options.provider || '');
244
+ const resumeId = _asString(options.resumeId);
245
+ if (!resumeId) return { ok: true };
246
+ if (agentType !== 'claude') return { ok: true };
247
+
248
+ const transcript = findClaudeResumeTranscript({
249
+ resumeId,
250
+ jsonlPath: options.jsonlPath || options.agentRow?.jsonl_path,
251
+ homeDir: options.homeDir,
252
+ claudeConfigDir: options.claudeConfigDir,
253
+ });
254
+ if (transcript) {
255
+ const cwdResolution = resolveClaudeResumeCwd({
256
+ ...options,
257
+ transcriptPath: transcript.path,
258
+ });
259
+ if (cwdResolution.blocked) {
260
+ const shortId = resumeId.slice(0, 8);
261
+ return {
262
+ ok: false,
263
+ code: 'claude_resume_project_mismatch',
264
+ resumeId,
265
+ storedPath: transcript.path,
266
+ transcriptPath: transcript.path,
267
+ transcriptProjectDir: cwdResolution.transcriptProjectDir || '',
268
+ cwdProjectDir: cwdResolution.cwdProjectDir || '',
269
+ cwd: normalizeCwd(options.cwd),
270
+ message:
271
+ `Cannot resume Claude session ${shortId}: the transcript exists, but CTM would launch ` +
272
+ `Claude Code from a different project directory. Launching from the wrong cwd makes ` +
273
+ `Claude Code report "No conversation found". CTM needs the original project cwd or a ` +
274
+ `matching agent_sessions.project_path before starting this resume.`,
275
+ };
276
+ }
277
+ return {
278
+ ok: true,
279
+ transcriptPath: transcript.path,
280
+ transcriptSize: transcript.size,
281
+ transcriptModifiedAt: transcript.modifiedAt,
282
+ restoreFromBak: !!transcript.restoreFromBak,
283
+ effectiveCwd: cwdResolution.changed ? cwdResolution.cwd : undefined,
284
+ cwdChanged: !!cwdResolution.changed,
285
+ cwdChangeReason: cwdResolution.reason || '',
286
+ transcriptProjectDir: cwdResolution.transcriptProjectDir || '',
287
+ cwdProjectDir: cwdResolution.cwdProjectDir || '',
288
+ };
289
+ }
290
+
291
+ const storedPath = _asString(options.jsonlPath || options.agentRow?.jsonl_path);
292
+ const shortId = resumeId.slice(0, 8);
293
+ return {
294
+ ok: false,
295
+ code: 'missing_claude_transcript',
296
+ resumeId,
297
+ storedPath,
298
+ message:
299
+ `Cannot resume Claude session ${shortId}: the local Claude transcript file is missing. ` +
300
+ `CTM can still show its cached conversation history, but Claude Code needs ` +
301
+ `~/.claude/projects/<project>/${resumeId}.jsonl to resume. ` +
302
+ `Start a new session from the cached history, or restore the missing transcript from backup.`,
303
+ };
304
+ }
305
+
306
+ module.exports = {
307
+ findClaudeResumeTranscript,
308
+ resolveClaudeResumeCwd,
309
+ validateResumeTarget,
310
+ transcriptHasConversation,
311
+ claudeLiveTranscriptShouldRestore,
312
+ restoreClaudeLiveTranscriptFromBak,
313
+ };