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
@@ -146,6 +146,14 @@ function loadSkill(skillDir, source) {
146
146
  execution: parsed.meta.execution || '',
147
147
  source,
148
148
  agents: declaredAgents.length ? declaredAgents : skillCompatibleAgentsForSource(source),
149
+ capabilities: normalizeSkillCapabilities(
150
+ parsed.meta.capabilities ||
151
+ parsed.meta.capability ||
152
+ parsed.meta.skills_capabilities ||
153
+ parsed.meta.skill_capabilities
154
+ ),
155
+ intents: normalizeSkillCapabilities(parsed.meta.intents || parsed.meta.intent),
156
+ invocation: normalizeSkillInvocation(parsed.meta.invocation || parsed.meta.command_prefix || parsed.meta.prefix),
149
157
  filePath: skillMdPath,
150
158
  path: skillMdPath,
151
159
  };
@@ -170,7 +178,24 @@ function parseFrontmatter(text) {
170
178
  if (!line || line.startsWith('#')) continue;
171
179
  const match = line.match(/^([A-Za-z0-9_.-]+):\s*(.*)$/);
172
180
  if (!match) continue;
173
- const blockStyle = match[2].match(/^([>|])[-+]?$/);
181
+ const valueText = String(match[2] || '').trim();
182
+ if (!valueText) {
183
+ const list = [];
184
+ let j = i + 1;
185
+ for (; j < lines.length; j += 1) {
186
+ const next = lines[j];
187
+ if (!next.trim()) continue;
188
+ const itemMatch = next.match(/^\s*-\s*(.+)$/);
189
+ if (!itemMatch) break;
190
+ list.push(parseFrontmatterValue(itemMatch[1]));
191
+ }
192
+ if (list.length) {
193
+ meta[match[1]] = list.flat ? list.flat(Infinity) : list;
194
+ i = j - 1;
195
+ continue;
196
+ }
197
+ }
198
+ const blockStyle = valueText.match(/^([>|])[-+]?$/);
174
199
  if (blockStyle) {
175
200
  const block = [];
176
201
  let j = i + 1;
@@ -219,6 +244,38 @@ function normalizeSkillAgents(value) {
219
244
  return out;
220
245
  }
221
246
 
247
+ function normalizeSkillCapabilities(value) {
248
+ if (!value) return [];
249
+ const raw = Array.isArray(value)
250
+ ? value
251
+ : typeof value === 'string'
252
+ ? value.split(/[,\s]+/)
253
+ : [value];
254
+ const out = [];
255
+ const seen = new Set();
256
+ for (const item of raw.flat ? raw.flat(Infinity) : raw) {
257
+ const normalized = String(item || '')
258
+ .trim()
259
+ .toLowerCase()
260
+ .replace(/_/g, '.')
261
+ .replace(/:+/g, '.')
262
+ .replace(/[^a-z0-9.-]+/g, '.')
263
+ .replace(/^\.+|\.+$/g, '');
264
+ if (!normalized || seen.has(normalized)) continue;
265
+ seen.add(normalized);
266
+ out.push(normalized);
267
+ }
268
+ return out;
269
+ }
270
+
271
+ function normalizeSkillInvocation(value) {
272
+ const text = String(value || '').trim();
273
+ if (text === '$' || text === '/') return text;
274
+ if (/^dollar$/i.test(text)) return '$';
275
+ if (/^slash$/i.test(text)) return '/';
276
+ return '';
277
+ }
278
+
222
279
  function skillCompatibleAgentsForSource(source) {
223
280
  const s = String(source || '').toLowerCase();
224
281
  if (s.startsWith('agents-')) return ['claude', 'codex', 'gemini', 'opencode', 'walle'];
@@ -260,6 +317,123 @@ function skillSourcePriorityForAgent(source, agentType) {
260
317
  return 20;
261
318
  }
262
319
 
320
+ function normalizeSkillAutocompleteQuery(value) {
321
+ const text = String(value || '').trim().replace(/^[$/]+/, '').toLowerCase();
322
+ return text.replace(/[^a-z0-9_.:-]/g, '');
323
+ }
324
+
325
+ function skillAutocompleteMatch(name, query) {
326
+ const q = normalizeSkillAutocompleteQuery(query);
327
+ const n = normalizeSkillAutocompleteQuery(name);
328
+ if (!n) return null;
329
+ if (!q) return {
330
+ tier: 100,
331
+ index: 0,
332
+ gap: 0,
333
+ lengthDelta: n.length,
334
+ };
335
+
336
+ const qCompact = q.replace(/[_.:-]+/g, '');
337
+ const nCompact = n.replace(/[_.:-]+/g, '');
338
+
339
+ if (n === q) return { tier: 0, index: 0, gap: 0, lengthDelta: 0 };
340
+ if (n.startsWith(q)) return { tier: 1, index: 0, gap: 0, lengthDelta: n.length - q.length };
341
+
342
+ const segments = n.split(/[_.:-]+/).filter(Boolean);
343
+ let bestSegmentDelta = Infinity;
344
+ for (const segment of segments) {
345
+ if (segment.startsWith(q)) bestSegmentDelta = Math.min(bestSegmentDelta, segment.length - q.length);
346
+ }
347
+ if (Number.isFinite(bestSegmentDelta)) {
348
+ return { tier: 2, index: 0, gap: 0, lengthDelta: bestSegmentDelta };
349
+ }
350
+
351
+ if (qCompact && nCompact === qCompact) return { tier: 3, index: 0, gap: 0, lengthDelta: 0 };
352
+ if (qCompact && nCompact.startsWith(qCompact)) {
353
+ return { tier: 4, index: 0, gap: 0, lengthDelta: nCompact.length - qCompact.length };
354
+ }
355
+
356
+ const index = n.indexOf(q);
357
+ if (index >= 0) {
358
+ return { tier: 5, index, gap: 0, lengthDelta: n.length - q.length };
359
+ }
360
+
361
+ const fuzzy = fuzzySubsequenceMatch(n, q);
362
+ if (fuzzy) {
363
+ return {
364
+ tier: 8,
365
+ index: fuzzy.firstIndex,
366
+ gap: fuzzy.gap,
367
+ lengthDelta: n.length - q.length,
368
+ };
369
+ }
370
+
371
+ return null;
372
+ }
373
+
374
+ function fuzzySubsequenceMatch(name, query) {
375
+ if (!query) return { firstIndex: 0, gap: 0 };
376
+ let qi = 0;
377
+ let firstIndex = -1;
378
+ let previousIndex = -1;
379
+ let gap = 0;
380
+ for (let i = 0; i < name.length && qi < query.length; i += 1) {
381
+ if (name[i] !== query[qi]) continue;
382
+ if (firstIndex < 0) firstIndex = i;
383
+ if (previousIndex >= 0) gap += i - previousIndex - 1;
384
+ previousIndex = i;
385
+ qi += 1;
386
+ }
387
+ return qi === query.length ? { firstIndex: Math.max(0, firstIndex), gap } : null;
388
+ }
389
+
390
+ function filterAndSortSkillAutocompleteItems(items, query, agentType) {
391
+ const q = normalizeSkillAutocompleteQuery(query);
392
+ const agent = normalizeSkillAgentType(agentType);
393
+ const matches = [];
394
+ for (const item of safeArray(items)) {
395
+ const match = skillAutocompleteMatch(item?.name, q);
396
+ if (!match) continue;
397
+ matches.push({ item, match });
398
+ }
399
+
400
+ matches.sort((a, b) => compareSkillAutocompleteMatches(a, b, q, agent));
401
+ return matches.map((entry) => entry.item);
402
+ }
403
+
404
+ function compareSkillAutocompleteMatches(a, b, query, agentType) {
405
+ const aMatch = a?.match || {};
406
+ const bMatch = b?.match || {};
407
+ if (query) {
408
+ if (aMatch.tier !== bMatch.tier) return aMatch.tier - bMatch.tier;
409
+ if (aMatch.index !== bMatch.index) return aMatch.index - bMatch.index;
410
+ if (aMatch.gap !== bMatch.gap) return aMatch.gap - bMatch.gap;
411
+ if (aMatch.lengthDelta !== bMatch.lengthDelta) return aMatch.lengthDelta - bMatch.lengthDelta;
412
+ const nameLengthDelta = normalizeSkillAutocompleteQuery(a?.item?.name).length -
413
+ normalizeSkillAutocompleteQuery(b?.item?.name).length;
414
+ if (nameLengthDelta) return nameLengthDelta;
415
+ } else {
416
+ const aFreq = Number(a?.item?.frequency || 0);
417
+ const bFreq = Number(b?.item?.frequency || 0);
418
+ if (bFreq !== aFreq) return bFreq - aFreq;
419
+ }
420
+
421
+ const sourceDelta = skillSourcePriorityForAgent(a?.item?.source, agentType) -
422
+ skillSourcePriorityForAgent(b?.item?.source, agentType);
423
+ if (sourceDelta) return sourceDelta;
424
+
425
+ if (query) {
426
+ const aFreq = Number(a?.item?.frequency || 0);
427
+ const bFreq = Number(b?.item?.frequency || 0);
428
+ if (bFreq !== aFreq) return bFreq - aFreq;
429
+ }
430
+
431
+ return String(a?.item?.name || '').localeCompare(String(b?.item?.name || ''), undefined, {
432
+ numeric: true,
433
+ sensitivity: 'base',
434
+ });
435
+ }
436
+
263
437
  function normalizeSkillName(value) {
264
438
  const name = String(value || '').trim().replace(/^@skill\//, '').replace(/\s+/g, '-');
265
439
  return /^[A-Za-z0-9_.:-]{1,80}$/.test(name) ? name : '';
@@ -290,9 +464,14 @@ function reloadSkills() {
290
464
  }
291
465
 
292
466
  module.exports = {
467
+ filterAndSortSkillAutocompleteItems,
293
468
  filterSkillsForAgent,
469
+ isSkillCompatibleWithAgent,
294
470
  loadAllSkillEntries,
295
471
  normalizeSkillAgentType,
472
+ normalizeSkillAutocompleteQuery,
473
+ normalizeSkillCapabilities,
296
474
  reloadSkills,
475
+ skillAutocompleteMatch,
297
476
  skillSourcePriorityForAgent,
298
477
  };
@@ -0,0 +1,304 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const skillAutocomplete = require('./skill-autocomplete');
5
+
6
+ const SUPPORTED_INTENTS = Object.freeze({
7
+ finish_and_merge: true,
8
+ commit_main: true,
9
+ create_pr: true,
10
+ });
11
+
12
+ const MESSAGE_ONLY_REASON = 'message_only';
13
+ let intentCache = new Map();
14
+
15
+ function normalizeIntent(value) {
16
+ const text = String(value || '').trim().toLowerCase().replace(/[-\s]+/g, '_');
17
+ if (text === 'finish' || text === 'finish_merge' || text === 'merge_main') return 'finish_and_merge';
18
+ if (text === 'commit' || text === 'commit_local' || text === 'main_commit') return 'commit_main';
19
+ if (text === 'pr' || text === 'pull_request' || text === 'create_pull_request') return 'create_pr';
20
+ return SUPPORTED_INTENTS[text] ? text : '';
21
+ }
22
+
23
+ function resolveSkillIntent(options = {}) {
24
+ const intent = normalizeIntent(options.intent);
25
+ if (!intent) {
26
+ return {
27
+ ok: false,
28
+ error: 'unsupported_intent',
29
+ intent: String(options.intent || ''),
30
+ skill: null,
31
+ candidates: [],
32
+ };
33
+ }
34
+
35
+ const agent = skillAutocomplete.normalizeSkillAgentType(options.agent) || 'all';
36
+ const cwd = normalizeCwd(options.cwd);
37
+ const cacheKey = `${cwd}\0${agent}\0${intent}`;
38
+ const cached = intentCache.get(cacheKey);
39
+ if (cached) return cloneResult({ ...cached, cached: true });
40
+
41
+ const raw = skillAutocomplete.loadAllSkillEntries(cwd || undefined);
42
+ const compatible = raw
43
+ .filter((skill) => agent === 'all' || skillAutocomplete.isSkillCompatibleWithAgent(skill, agent))
44
+ .sort((a, b) => {
45
+ const sourceDelta = skillAutocomplete.skillSourcePriorityForAgent(a.source, agent) -
46
+ skillAutocomplete.skillSourcePriorityForAgent(b.source, agent);
47
+ if (sourceDelta) return sourceDelta;
48
+ return String(a.name || '').localeCompare(String(b.name || ''), undefined, {
49
+ numeric: true,
50
+ sensitivity: 'base',
51
+ });
52
+ });
53
+
54
+ const result = resolveSkillIntentFromSkills(compatible, { intent, agent, cwd });
55
+ intentCache.set(cacheKey, cloneResult({ ...result, cached: false }));
56
+ return cloneResult(result);
57
+ }
58
+
59
+ function resolveSkillIntentFromSkills(skills, options = {}) {
60
+ const intent = normalizeIntent(options.intent);
61
+ const agent = skillAutocomplete.normalizeSkillAgentType(options.agent) || 'all';
62
+ const assessed = safeArray(skills)
63
+ .map((skill, index) => assessSkillForIntent(skill, { intent, agent, index }))
64
+ .sort(compareIntentCandidates);
65
+ const candidates = assessed.filter((candidate) => candidate.score > 0 || candidate.eligible || candidate.negative.length > 0).slice(0, 12);
66
+ const selected = assessed.find((candidate) => candidate.eligible) || null;
67
+ return {
68
+ ok: true,
69
+ intent,
70
+ agent,
71
+ cwd: options.cwd || '',
72
+ cached: false,
73
+ generatedAt: new Date().toISOString(),
74
+ skill: selected ? publicCandidate(selected) : null,
75
+ candidates: candidates.map(publicCandidate),
76
+ totalSkills: safeArray(skills).length,
77
+ };
78
+ }
79
+
80
+ function assessSkillForIntent(skill, options = {}) {
81
+ const intent = normalizeIntent(options.intent);
82
+ const agent = skillAutocomplete.normalizeSkillAgentType(options.agent) || 'all';
83
+ const name = String(skill?.name || '').trim();
84
+ const source = String(skill?.source || '');
85
+ const description = String(skill?.description || '');
86
+ const text = searchableSkillText(skill);
87
+ const explicit = explicitCapabilities(skill);
88
+ const inferred = inferCapabilities(skill, explicit);
89
+ const caps = new Set([...explicit, ...inferred]);
90
+ const reasons = [];
91
+ const negative = [];
92
+ const messageOnly = isMessageOnlySkill(skill, text);
93
+ if (messageOnly) negative.push(MESSAGE_ONLY_REASON);
94
+
95
+ let eligible = false;
96
+ let score = 0;
97
+
98
+ if (intent === 'create_pr') {
99
+ eligible = !messageOnly && hasAny(caps, ['github.pr.create', 'git.pr.create', 'pr.create']);
100
+ score += add(capScore(caps, explicit, 'github.pr.create'), 'creates pull requests', reasons);
101
+ score += add(capScore(caps, explicit, 'git.review'), 'reviews changes', reasons);
102
+ score += add(capScore(caps, explicit, 'git.commit'), 'can commit before PR', reasons);
103
+ score += textBonus(/\bgithub\b|\bpull[- ]?request\b|\bcreate[- ]?pr\b|\bpr\b/, text, 8, 'PR language', reasons);
104
+ } else if (intent === 'commit_main') {
105
+ eligible = !messageOnly && hasAny(caps, ['git.commit']);
106
+ score += add(capScore(caps, explicit, 'git.commit'), 'commits local changes', reasons);
107
+ score += add(capScore(caps, explicit, 'git.review'), 'reviews before commit', reasons);
108
+ score += add(capScore(caps, explicit, 'git.quality'), 'quality gate', reasons);
109
+ score += textBonus(/\bsafe[- ]?commit\b|\breview[- ]?and[- ]?commit\b|\bpre[- ]?commit\b|\btl[- ]?commit\b/, text, 10, 'safe commit language', reasons);
110
+ } else if (intent === 'finish_and_merge') {
111
+ const canCommitOrFinish = hasAny(caps, ['git.commit', 'git.branch.finish']);
112
+ const canMerge = hasAny(caps, ['git.merge.main', 'git.branch.finish']);
113
+ eligible = !messageOnly && canCommitOrFinish && canMerge;
114
+ score += add(capScore(caps, explicit, 'git.commit'), 'commits local changes', reasons);
115
+ score += add(capScore(caps, explicit, 'git.merge.main'), 'merges to main', reasons);
116
+ score += add(capScore(caps, explicit, 'git.branch.finish'), 'finishes development branches', reasons);
117
+ score += add(capScore(caps, explicit, 'git.review'), 'reviews before integration', reasons);
118
+ score += add(capScore(caps, explicit, 'git.quality'), 'quality gate', reasons);
119
+ score += textBonus(/\bto main\b|\bmerge\b.*\bmain\b|\bintegrat\w*\b.*\bmain\b|\bfinish(?:ing)?[- ]a[- ]development[- ]branch\b/, text, 12, 'main integration language', reasons);
120
+ }
121
+
122
+ score += sourceBonus(source, agent);
123
+ const frequency = Number(skill?.frequency || 0);
124
+ if (Number.isFinite(frequency) && frequency > 0) score += Math.min(frequency, 20) / 20;
125
+ if (messageOnly) score -= 100;
126
+ if (!eligible) score = Math.max(0, score);
127
+
128
+ const prefix = invocationPrefixForSkill(skill, agent);
129
+ return {
130
+ skill,
131
+ name,
132
+ description,
133
+ source,
134
+ agents: Array.isArray(skill?.agents) ? skill.agents : [],
135
+ prefix,
136
+ intent,
137
+ agent,
138
+ score,
139
+ eligible,
140
+ capabilities: [...caps].sort(),
141
+ explicitCapabilities: [...explicit].sort(),
142
+ reasons,
143
+ negative,
144
+ originalIndex: Number.isFinite(options.index) ? options.index : 0,
145
+ };
146
+ }
147
+
148
+ function inferCapabilities(skill, explicit) {
149
+ const text = searchableSkillText(skill);
150
+ const caps = new Set();
151
+ const messageOnly = isMessageOnlySkill(skill, text);
152
+ if (!messageOnly && /\bcommit\b|\bstaged changes\b|\blocal changes\b/.test(text)) caps.add('git.commit');
153
+ if (/\breview\b|\baudit\b|\bverify\b|\bquality\b|\bpre[- ]?commit\b|\bsafe[- ]?commit\b|\btl[- ]?commit\b/.test(text)) caps.add('git.review');
154
+ if (/\bquality\b|\bsafe\b|\bsecurity\b|\bpii\b|\bsecret\b|\bpre[- ]?commit\b|\btl[- ]?commit\b/.test(text)) caps.add('git.quality');
155
+ if (/\bmerge\b.*\bmain\b|\bmain\b.*\bmerge\b|\bintegrat\w*\b.*\bmain\b|\bto main\b/.test(text)) caps.add('git.merge.main');
156
+ if (/\bfinish(?:ing)?[- ]a[- ]development[- ]branch\b|\bcomplete\b.*\bdevelopment work\b|\bguide\w*\b.*\bmerge\b.*\bpr\b.*\bcleanup\b/.test(text)) {
157
+ caps.add('git.branch.finish');
158
+ caps.add('git.merge.main');
159
+ }
160
+ if (/\bcreate\b.*\b(?:pr|pull[- ]?request)\b|\b(?:pr|pull[- ]?request)\b.*\bcreate\b|\bgithub\b.*\b(?:pr|pull[- ]?request)\b/.test(text)) {
161
+ caps.add('github.pr.create');
162
+ }
163
+ for (const cap of explicit) caps.add(cap);
164
+ return caps;
165
+ }
166
+
167
+ function explicitCapabilities(skill) {
168
+ const raw = [
169
+ ...safeArray(skill?.capabilities),
170
+ ...safeArray(skill?.intents),
171
+ ];
172
+ return new Set(skillAutocomplete.normalizeSkillCapabilities(raw).flatMap(expandCapabilityAlias));
173
+ }
174
+
175
+ function expandCapabilityAlias(value) {
176
+ const cap = String(value || '').toLowerCase();
177
+ const out = [cap];
178
+ if (cap === 'commit' || cap === 'git.commit.local') out.push('git.commit');
179
+ if (cap === 'review' || cap === 'code.review') out.push('git.review');
180
+ if (cap === 'quality' || cap === 'safety') out.push('git.quality');
181
+ if (cap === 'merge' || cap === 'merge.main' || cap === 'git.merge') out.push('git.merge.main');
182
+ if (cap === 'finish' || cap === 'finish.branch' || cap === 'branch.finish') out.push('git.branch.finish');
183
+ if (cap === 'pr' || cap === 'pull.request' || cap === 'github.pr') out.push('github.pr.create');
184
+ return out;
185
+ }
186
+
187
+ function isMessageOnlySkill(skill, text = searchableSkillText(skill)) {
188
+ const name = String(skill?.name || '').toLowerCase();
189
+ return /(?:^|[-_.:])commit[-_.:]?messages?(?:$|[-_.:])/.test(name) ||
190
+ /\bwriting[- ]commit[- ]messages?\b/.test(text) ||
191
+ /\bwrite\w*\b.*\bcommit messages?\b/.test(text) ||
192
+ /\bcommit message quality\b/.test(text) ||
193
+ /\bcommit message help\b/.test(text);
194
+ }
195
+
196
+ function invocationPrefixForSkill(skill, agentType) {
197
+ if (skill?.invocation === '$' || skill?.invocation === '/') return skill.invocation;
198
+ const agent = skillAutocomplete.normalizeSkillAgentType(agentType);
199
+ const source = String(skill?.source || '').toLowerCase();
200
+ if (agent === 'claude') return '/';
201
+ if (agent === 'codex' || agent === 'opencode' || agent === 'gemini') return '$';
202
+ if (source.startsWith('claude-')) return '/';
203
+ return '$';
204
+ }
205
+
206
+ function capScore(caps, explicit, cap) {
207
+ if (explicit.has(cap)) return 34;
208
+ if (caps.has(cap)) return 18;
209
+ return 0;
210
+ }
211
+
212
+ function add(value, reason, reasons) {
213
+ if (value > 0 && reason) reasons.push(reason);
214
+ return value;
215
+ }
216
+
217
+ function textBonus(pattern, text, score, reason, reasons) {
218
+ if (!pattern.test(text)) return 0;
219
+ if (reason) reasons.push(reason);
220
+ return score;
221
+ }
222
+
223
+ function sourceBonus(source, agent) {
224
+ const priority = skillAutocomplete.skillSourcePriorityForAgent(source, agent);
225
+ if (priority <= 1) return 3;
226
+ if (priority <= 3) return 2;
227
+ if (priority <= 5) return 1;
228
+ return 0;
229
+ }
230
+
231
+ function hasAny(caps, values) {
232
+ return values.some((value) => caps.has(value));
233
+ }
234
+
235
+ function compareIntentCandidates(a, b) {
236
+ if (a.eligible !== b.eligible) return a.eligible ? -1 : 1;
237
+ if (b.score !== a.score) return b.score - a.score;
238
+ const agent = a.intent === b.intent ? (a.agent || b.agent || 'all') : 'all';
239
+ const sourceDelta = skillAutocomplete.skillSourcePriorityForAgent(a.source, agent) -
240
+ skillAutocomplete.skillSourcePriorityForAgent(b.source, agent);
241
+ if (sourceDelta) return sourceDelta;
242
+ return String(a.name || '').localeCompare(String(b.name || ''), undefined, {
243
+ numeric: true,
244
+ sensitivity: 'base',
245
+ });
246
+ }
247
+
248
+ function publicCandidate(candidate) {
249
+ if (!candidate) return null;
250
+ return {
251
+ name: candidate.name,
252
+ description: candidate.description,
253
+ source: candidate.source,
254
+ agents: candidate.agents,
255
+ prefix: candidate.prefix,
256
+ invocation: candidate.prefix,
257
+ score: Math.round(candidate.score * 100) / 100,
258
+ eligible: !!candidate.eligible,
259
+ capabilities: candidate.capabilities,
260
+ reasons: candidate.reasons.slice(0, 5),
261
+ negative: candidate.negative,
262
+ };
263
+ }
264
+
265
+ function searchableSkillText(skill) {
266
+ return [
267
+ skill?.name,
268
+ skill?.description,
269
+ skill?.execution,
270
+ ...(Array.isArray(skill?.capabilities) ? skill.capabilities : []),
271
+ ...(Array.isArray(skill?.intents) ? skill.intents : []),
272
+ ].join(' ').toLowerCase().replace(/[_:./]+/g, ' ');
273
+ }
274
+
275
+ function normalizeCwd(value) {
276
+ const text = String(value || '').trim();
277
+ return text ? path.resolve(text) : '';
278
+ }
279
+
280
+ function safeArray(value) {
281
+ return Array.isArray(value) ? value : [];
282
+ }
283
+
284
+ function cloneResult(value) {
285
+ return JSON.parse(JSON.stringify(value));
286
+ }
287
+
288
+ function clearSkillIntentCache() {
289
+ intentCache = new Map();
290
+ }
291
+
292
+ function skillIntentCacheStats() {
293
+ return { entries: intentCache.size };
294
+ }
295
+
296
+ module.exports = {
297
+ assessSkillForIntent,
298
+ clearSkillIntentCache,
299
+ invocationPrefixForSkill,
300
+ normalizeIntent,
301
+ resolveSkillIntent,
302
+ resolveSkillIntentFromSkills,
303
+ skillIntentCacheStats,
304
+ };
@@ -124,7 +124,7 @@ function smokeTestDatabase(Database) {
124
124
  }
125
125
  }
126
126
 
127
- function runNpm(args, label) {
127
+ function runNpm(args, label, extraEnv = {}) {
128
128
  const timeout = Number(process.env.CTM_SQLITE_REPAIR_TIMEOUT_MS || DEFAULT_REPAIR_TIMEOUT_MS);
129
129
  const started = Date.now();
130
130
  try {
@@ -135,9 +135,16 @@ function runNpm(args, label) {
135
135
  timeout: Number.isFinite(timeout) && timeout > 0 ? timeout : DEFAULT_REPAIR_TIMEOUT_MS,
136
136
  env: {
137
137
  ...process.env,
138
+ // Compile/resolve under the SAME Node that's loading the driver. Without this,
139
+ // execFileSync('npm') resolves `npm`/`node-gyp`/`node` from the ambient PATH (often
140
+ // a different Node major), so even a from-source rebuild targets the WRONG ABI and
141
+ // the brick persists. Prepending process.execPath's dir pins the toolchain to the
142
+ // running Node, so the rebuilt binary matches this process. This is the ABI-ping-pong fix.
143
+ PATH: `${path.dirname(process.execPath)}${path.delimiter}${process.env.PATH || ''}`,
138
144
  npm_config_audit: 'false',
139
145
  npm_config_fund: 'false',
140
146
  npm_config_update_notifier: 'false',
147
+ ...extraEnv,
141
148
  },
142
149
  });
143
150
  return { label, ok: true, ms: Date.now() - started, output: String(output || '').slice(-4000) };
@@ -155,9 +162,18 @@ function runNpm(args, label) {
155
162
  function defaultRepairRunner(cause) {
156
163
  const attempts = [];
157
164
  const spec = packageSpec();
165
+ // FROM-SOURCE FIRST. The node-ABI ping-pong: when several processes on different Node
166
+ // majors (e.g. the pinned 25.x primary + a system-26 dev/agent) share one node_modules,
167
+ // each one's load fails the ABI smoke test and triggers repair. Plain `npm rebuild` /
168
+ // `npm install` resolve a PREBUILT binary (or no-op "up to date") that is compiled for
169
+ // SOME other Node ABI — so the smoke test still fails and the primary bricks on restart.
170
+ // Forcing a source compile (`npm_config_build_from_source`) produces a binary matching
171
+ // THIS process's Node, so every process reliably self-heals instead of bricking.
172
+ const fromSource = { npm_config_build_from_source: 'true' };
158
173
  const commands = [
174
+ { label: 'npm rebuild better-sqlite3 (from source)', args: ['rebuild', 'better-sqlite3', '--foreground-scripts'], env: fromSource },
159
175
  { label: 'npm rebuild better-sqlite3', args: ['rebuild', 'better-sqlite3'] },
160
- { label: `npm install better-sqlite3@${spec}`, args: ['install', `better-sqlite3@${spec}`, '--no-audit', '--no-fund'] },
176
+ { label: `npm install better-sqlite3@${spec} (from source)`, args: ['install', `better-sqlite3@${spec}`, '--no-audit', '--no-fund'], env: fromSource },
161
177
  ];
162
178
  if (process.env.CTM_SQLITE_ALLOW_MAJOR_UPGRADE !== '0' && spec !== 'latest') {
163
179
  commands.push({ label: 'npm install better-sqlite3@latest', args: ['install', 'better-sqlite3@latest', '--no-audit', '--no-fund'] });
@@ -168,7 +184,7 @@ function defaultRepairRunner(cause) {
168
184
  action: command.label,
169
185
  cause: String(cause?.message || cause || '').slice(0, 1000),
170
186
  });
171
- const result = runNpm(command.args, command.label);
187
+ const result = runNpm(command.args, command.label, command.env || {});
172
188
  attempts.push(result);
173
189
  recordDriverEvent(result.ok ? 'sqlite_driver_repair_command_ok' : 'sqlite_driver_repair_command_failed', result);
174
190
  if (!result.ok) continue;
@@ -3,6 +3,8 @@
3
3
  const crypto = require('crypto');
4
4
 
5
5
  const STICKY_ATTENTION_MS = 12 * 60 * 60 * 1000;
6
+ const HARD_FAILURE_RE = /\b(cannot proceed|blocked|blocker|stuck|permission denied|fatal|panic|segmentation fault|uncaught|unhandled exception|traceback|command failed|build failed|tests? failed|npm err!|failed to run step|exceeded max retries|max retries|something went wrong)\b/i;
7
+ const HARD_FAILURE_EVIDENCE_RE = /(cannot proceed|blocked|blocker|stuck|permission denied|fatal|unhandled exception|command failed|build failed|tests? failed|failed to run step|exceeded max retries|max retries|something went wrong)/i;
6
8
 
7
9
  function compactText(value) {
8
10
  if (!value) return '';
@@ -68,6 +70,7 @@ function attentionContextHash(text) {
68
70
  function buildStandupAttentionContext({ session = {}, summary = {}, status = {} } = {}) {
69
71
  const evidence = Array.isArray(summary.statusEvidence) ? summary.statusEvidence : [];
70
72
  const progress = summary.progress || {};
73
+ const terminalAttentionText = summary.terminalAttentionText || summary.terminal_attention_text || session.terminalAttentionText || '';
71
74
  const lines = [
72
75
  `Title: ${compactText(session.label || summary.displayPrompt || summary.lastPrompt || session.id || '')}`,
73
76
  `Agent: ${compactText(session.agentType || session.agent || session.type || '')}`,
@@ -77,6 +80,7 @@ function buildStandupAttentionContext({ session = {}, summary = {}, status = {}
77
80
  `Summary: ${compactText(summary.summary || '')}`,
78
81
  `Progress: ${compactText(progress)}`,
79
82
  `Evidence: ${evidence.map(compactText).filter(Boolean).join('; ')}`,
83
+ `Terminal: ${compactText(terminalAttentionText)}`,
80
84
  ].filter(line => !/:\s*$/.test(line));
81
85
  const text = truncateText(lines.join('\n'), 2500);
82
86
  return {
@@ -87,7 +91,7 @@ function buildStandupAttentionContext({ session = {}, summary = {}, status = {}
87
91
  }
88
92
 
89
93
  function hasAttentionLanguage(text) {
90
- return /\b(warn(?:ing|ed)?|caution|risk|blocked|blocker|failed|failing|failure|error|exception|permission denied|cannot proceed|stuck|needs attention)\b/i.test(String(text || ''));
94
+ return /\b(warn(?:ing|ed)?|caution|risk|blocked|blocker|failed|failing|failure|error|exception|permission denied|cannot proceed|stuck|needs attention|exceeded max retries|max retries|something went wrong)\b/i.test(String(text || ''));
91
95
  }
92
96
 
93
97
  function hasResolutionSignal(text) {
@@ -98,7 +102,7 @@ function heuristicStandupAttention(context) {
98
102
  const text = String(context?.text || context || '');
99
103
  const lower = text.toLowerCase();
100
104
  const resolved = hasResolutionSignal(lower);
101
- const hardFailure = /\b(cannot proceed|blocked|blocker|stuck|permission denied|fatal|panic|segmentation fault|uncaught|unhandled exception|traceback|command failed|build failed|tests? failed|npm err!)\b/i.test(lower);
105
+ const hardFailure = HARD_FAILURE_RE.test(lower);
102
106
  const warning = /\b(warn(?:ing|ed)?|caution|risk|heads up|possible issue|needs attention)\b/i.test(lower);
103
107
  const weakFailure = /\b(failed|failing|failure|error|exception)\b/i.test(lower);
104
108
 
@@ -109,7 +113,7 @@ function heuristicStandupAttention(context) {
109
113
  return normalizeAttention({
110
114
  severity: 'failure',
111
115
  recommendation: 'A current blocker or failure appears to need attention.',
112
- evidence: [firstMatchingPhrase(text, /(cannot proceed|blocked|blocker|stuck|permission denied|fatal|unhandled exception|command failed|build failed|tests? failed)/i)],
116
+ evidence: [firstMatchingPhrase(text, HARD_FAILURE_EVIDENCE_RE)],
113
117
  source: 'heuristic',
114
118
  confidence: 'medium',
115
119
  });
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+ // Status authority inversion.
3
+ //
4
+ // CTM derives session status from two kinds of evidence:
5
+ // 1. Structured signals — OTLP telemetry (codex) and provider hooks
6
+ // (claude/gemini), surfaced via lib/telemetry-receiver. These say
7
+ // exactly when a turn starts and ends.
8
+ // 2. PTY byte inference — provider state detectors classifying raw
9
+ // terminal chunks (workers/state-detectors/*).
10
+ //
11
+ // Byte inference is inherently low-precision for full-screen TUIs: an idle
12
+ // codex still repaints (background MCP/rate-limit fetches, focus events,
13
+ // animation frames), and one misclassified chunk holds the sidebar on
14
+ // "Running" for the provider's whole idle-debounce window. So when a
15
+ // structured source owns a session, generic bytes must not CREATE a running
16
+ // state out of idle — only the provider's own busy-status line ("Working …
17
+ // esc to interrupt", matched strictly) or the structured source itself may.
18
+ //
19
+ // Two deliberate escape hatches keep this safe:
20
+ // - No structured source (fresh install, otel/notify not configured):
21
+ // full byte inference remains, it is the only signal available.
22
+ // - Provider without a precise busy channel (no textHasCodexBusyStatus
23
+ // on its detector): never strand it — its hooks can lag and generic
24
+ // output is the only unstick signal it has.
25
+
26
+ function ptyActivityMayDriveRunning({
27
+ hasAuthoritativeSource = false,
28
+ busyEvidenceCapable = false,
29
+ lastBusyStatusAt = 0,
30
+ now = Date.now(),
31
+ busyHoldMs = 15000,
32
+ } = {}) {
33
+ if (!hasAuthoritativeSource) return true;
34
+ if (!busyEvidenceCapable) return true;
35
+ const busyAt = Number(lastBusyStatusAt) || 0;
36
+ return !!(busyAt && (now - busyAt) < busyHoldMs);
37
+ }
38
+
39
+ module.exports = { ptyActivityMayDriveRunning };
@@ -60,6 +60,9 @@ function onApprovalDetected(sessionId) {
60
60
  function onApprovalResolved(sessionId) {
61
61
  bus.onApprovalResolved(sessionId);
62
62
  }
63
+ function clearWaitingInput(sessionId) {
64
+ bus.clearWaitingInput(sessionId);
65
+ }
63
66
 
64
67
  // Wire bus events → hook-executor.
65
68
  bus.on('statechange', async (ev) => {
@@ -101,6 +104,7 @@ module.exports = {
101
104
  onOutput,
102
105
  onApprovalDetected,
103
106
  onApprovalResolved,
107
+ clearWaitingInput,
104
108
  // Introspection / tests
105
109
  _bus: bus,
106
110
  _sessionMeta,