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,258 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+
6
+ const FRONTEND_FILE_RE = /\.(html?|css|scss|sass|less|jsx|tsx|vue|svelte|astro)\b/i;
7
+ const HTML_FILE_RE = /\.html?\b/i;
8
+ const JS_FILE_RE = /\.(?:mjs|cjs|js|jsx|ts|tsx)\b/i;
9
+ const ASSET_ATTR_RE = /\b(?:src|href|poster)\s*=\s*["']([^"']+)["']/gi;
10
+ const SRCSET_RE = /\bsrcset\s*=\s*["']([^"']+)["']/gi;
11
+ const CSS_URL_RE = /url\(\s*(['"]?)([^'")]+)\1\s*\)/gi;
12
+ const EVENT_HANDLER_ATTR_RE = /\bon([a-z][a-z0-9_-]*)\s*=\s*(["'])([\s\S]*?)\2/gi;
13
+ const SCRIPT_SRC_RE = /<script\b[^>]*\bsrc\s*=\s*(["'])([^"']+)\1[^>]*>/gi;
14
+ const INLINE_SCRIPT_RE = /<script\b(?![^>]*\bsrc\b)[^>]*>([\s\S]*?)<\/script>/gi;
15
+ const JS_CALL_RE = /(?:^|[^\w$.\]])(?:window\.|globalThis\.)?([A-Za-z_$][\w$]*)\s*\(/g;
16
+ const JS_KEYWORDS = new Set([
17
+ 'if',
18
+ 'for',
19
+ 'while',
20
+ 'switch',
21
+ 'catch',
22
+ 'function',
23
+ 'return',
24
+ 'typeof',
25
+ 'void',
26
+ 'new',
27
+ 'do',
28
+ 'else',
29
+ 'class',
30
+ 'super',
31
+ 'import',
32
+ 'export',
33
+ ]);
34
+
35
+ function isFrontendFile(filePath = '') {
36
+ return FRONTEND_FILE_RE.test(String(filePath || ''));
37
+ }
38
+
39
+ function isHtmlFile(filePath = '') {
40
+ return HTML_FILE_RE.test(String(filePath || ''));
41
+ }
42
+
43
+ function isScriptFile(filePath = '') {
44
+ return JS_FILE_RE.test(String(filePath || ''));
45
+ }
46
+
47
+ function shouldSkipReference(ref = '') {
48
+ const value = String(ref || '').trim();
49
+ if (!value) return true;
50
+ return value.startsWith('#')
51
+ || /^(?:https?:|data:|mailto:|tel:|javascript:|blob:|about:)/i.test(value);
52
+ }
53
+
54
+ function cleanReference(ref = '') {
55
+ const value = String(ref || '').trim();
56
+ const hashIdx = value.indexOf('#');
57
+ const queryIdx = value.indexOf('?');
58
+ const cut = [hashIdx, queryIdx].filter((n) => n >= 0).sort((a, b) => a - b)[0];
59
+ return cut >= 0 ? value.slice(0, cut) : value;
60
+ }
61
+
62
+ function srcsetReferences(value = '') {
63
+ return String(value || '')
64
+ .split(',')
65
+ .map((entry) => entry.trim().split(/\s+/)[0])
66
+ .filter(Boolean);
67
+ }
68
+
69
+ function extractLocalAssetReferences(content = '') {
70
+ const refs = [];
71
+ let match;
72
+ while ((match = ASSET_ATTR_RE.exec(content))) refs.push(match[1]);
73
+ while ((match = CSS_URL_RE.exec(content))) refs.push(match[2]);
74
+ while ((match = SRCSET_RE.exec(content))) refs.push(...srcsetReferences(match[1]));
75
+ return refs
76
+ .map(cleanReference)
77
+ .filter((ref) => !shouldSkipReference(ref));
78
+ }
79
+
80
+ function resolveReference(cwd, sourceFile, ref) {
81
+ if (/^file:\/\//i.test(ref)) {
82
+ try {
83
+ return new URL(ref).pathname;
84
+ } catch {
85
+ return ref;
86
+ }
87
+ }
88
+ if (ref.startsWith('/')) return path.resolve(cwd, `.${ref}`);
89
+ return path.resolve(path.dirname(sourceFile), ref);
90
+ }
91
+
92
+ function extractInlineHandlerCalls(content = '') {
93
+ const calls = [];
94
+ let match;
95
+ while ((match = EVENT_HANDLER_ATTR_RE.exec(content))) {
96
+ const event = match[1];
97
+ const expression = match[3] || '';
98
+ let callMatch;
99
+ while ((callMatch = JS_CALL_RE.exec(expression))) {
100
+ const name = callMatch[1];
101
+ if (!name || JS_KEYWORDS.has(name)) continue;
102
+ calls.push({ event, expression, name });
103
+ }
104
+ }
105
+ return calls;
106
+ }
107
+
108
+ function extractScriptSources(content = '') {
109
+ const refs = [];
110
+ let match;
111
+ while ((match = SCRIPT_SRC_RE.exec(content))) refs.push(match[2]);
112
+ return refs
113
+ .map(cleanReference)
114
+ .filter((ref) => !shouldSkipReference(ref));
115
+ }
116
+
117
+ function extractInlineScripts(content = '') {
118
+ const scripts = [];
119
+ let match;
120
+ while ((match = INLINE_SCRIPT_RE.exec(content))) scripts.push(match[1] || '');
121
+ return scripts;
122
+ }
123
+
124
+ function extractDeclaredGlobalNames(content = '') {
125
+ const names = new Set();
126
+ const patterns = [
127
+ /\bfunction\s+([A-Za-z_$][\w$]*)\s*\(/g,
128
+ /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:async\s*)?(?:function\b|\([^)]*\)\s*=>|[A-Za-z_$][\w$]*\s*=>)/g,
129
+ /\b(?:window|globalThis)\.([A-Za-z_$][\w$]*)\s*=/g,
130
+ ];
131
+ for (const pattern of patterns) {
132
+ let match;
133
+ while ((match = pattern.exec(content))) names.add(match[1]);
134
+ }
135
+ return names;
136
+ }
137
+
138
+ function checkInlineEventHandlers(cwd, files = []) {
139
+ const missing = [];
140
+ const checked = [];
141
+ const htmlFiles = [...new Set(files || [])]
142
+ .filter(isHtmlFile)
143
+ .map((file) => path.isAbsolute(file) ? file : path.join(cwd, file));
144
+
145
+ for (const sourceFile of htmlFiles) {
146
+ if (!fs.existsSync(sourceFile) || !fs.statSync(sourceFile).isFile()) continue;
147
+ const html = fs.readFileSync(sourceFile, 'utf8');
148
+ const handlers = extractInlineHandlerCalls(html);
149
+ if (!handlers.length) continue;
150
+
151
+ const declared = new Set();
152
+ for (const script of extractInlineScripts(html)) {
153
+ for (const name of extractDeclaredGlobalNames(script)) declared.add(name);
154
+ }
155
+ for (const ref of extractScriptSources(html)) {
156
+ const resolved = resolveReference(cwd, sourceFile, ref);
157
+ if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile()) continue;
158
+ const js = fs.readFileSync(resolved, 'utf8');
159
+ for (const name of extractDeclaredGlobalNames(js)) declared.add(name);
160
+ }
161
+
162
+ for (const handler of handlers) {
163
+ const item = {
164
+ source: path.relative(cwd, sourceFile),
165
+ event: handler.event,
166
+ name: handler.name,
167
+ expression: handler.expression,
168
+ };
169
+ checked.push(item);
170
+ if (!declared.has(handler.name)) missing.push(item);
171
+ }
172
+ }
173
+
174
+ return {
175
+ ok: missing.length === 0,
176
+ checked,
177
+ missing,
178
+ htmlFiles: htmlFiles.map((file) => path.relative(cwd, file)),
179
+ };
180
+ }
181
+
182
+ function checkLocalAssetReferences(cwd, files = []) {
183
+ const missing = [];
184
+ const checked = [];
185
+ const frontendFiles = [...new Set(files || [])]
186
+ .filter(isFrontendFile)
187
+ .map((file) => path.isAbsolute(file) ? file : path.join(cwd, file));
188
+
189
+ for (const sourceFile of frontendFiles) {
190
+ if (!fs.existsSync(sourceFile) || !fs.statSync(sourceFile).isFile()) continue;
191
+ const content = fs.readFileSync(sourceFile, 'utf8');
192
+ for (const ref of extractLocalAssetReferences(content)) {
193
+ const resolved = resolveReference(cwd, sourceFile, ref);
194
+ checked.push({ source: path.relative(cwd, sourceFile), reference: ref, resolved });
195
+ if (!fs.existsSync(resolved)) {
196
+ missing.push({ source: path.relative(cwd, sourceFile), reference: ref, resolved });
197
+ }
198
+ }
199
+ }
200
+
201
+ return {
202
+ ok: missing.length === 0,
203
+ checked,
204
+ missing,
205
+ frontendFiles: frontendFiles.map((file) => path.relative(cwd, file)),
206
+ };
207
+ }
208
+
209
+ function resolveFrontendEntrypoints(cwd, files = [], { limit = 4 } = {}) {
210
+ const entrypoints = [];
211
+ const seen = new Set();
212
+ const add = (file) => {
213
+ if (!file) return;
214
+ const abs = path.isAbsolute(file) ? file : path.join(cwd, file);
215
+ if (!isHtmlFile(abs)) return;
216
+ if (!fs.existsSync(abs) || !fs.statSync(abs).isFile()) return;
217
+ const real = path.resolve(abs);
218
+ if (seen.has(real)) return;
219
+ seen.add(real);
220
+ entrypoints.push(real);
221
+ };
222
+
223
+ for (const file of files || []) add(file);
224
+ for (const file of files || []) {
225
+ const abs = path.isAbsolute(file) ? file : path.join(cwd, file);
226
+ if (!isFrontendFile(abs) && !isScriptFile(abs)) continue;
227
+ add(path.join(path.dirname(abs), 'index.html'));
228
+ }
229
+ add(path.join(cwd, 'index.html'));
230
+ return entrypoints.slice(0, limit);
231
+ }
232
+
233
+ function checkFrontendStaticContracts(cwd, files = []) {
234
+ const assets = checkLocalAssetReferences(cwd, files);
235
+ const handlers = checkInlineEventHandlers(cwd, files);
236
+ return {
237
+ ok: assets.ok && handlers.ok,
238
+ assets,
239
+ handlers,
240
+ concerns: [
241
+ ...assets.missing.map((item) => `[frontend-assets] ${item.source} references missing local asset ${item.reference}`),
242
+ ...handlers.missing.map((item) => `[frontend-js] ${item.source} ${item.event}= handler calls missing ${item.name}()`),
243
+ ],
244
+ };
245
+ }
246
+
247
+ module.exports = {
248
+ isFrontendFile,
249
+ isHtmlFile,
250
+ isScriptFile,
251
+ extractLocalAssetReferences,
252
+ extractInlineHandlerCalls,
253
+ extractDeclaredGlobalNames,
254
+ checkInlineEventHandlers,
255
+ checkLocalAssetReferences,
256
+ checkFrontendStaticContracts,
257
+ resolveFrontendEntrypoints,
258
+ };
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+
3
+ const { RuntimeEventWriter, createRuntimeEvent } = require('./runtime-events');
4
+
5
+ class LifecycleHookBus {
6
+ constructor({ events = null, middleware = null, runtimeEvents = null, now = () => new Date().toISOString(), defaults = {} } = {}) {
7
+ this.events = events;
8
+ this.middleware = middleware;
9
+ this.runtimeEvents = runtimeEvents || new RuntimeEventWriter({ events, now, defaults });
10
+ this.now = now;
11
+ this.defaults = defaults;
12
+ }
13
+
14
+ async emit(type, payload = {}, defaults = {}) {
15
+ const event = this.runtimeEvents.emit({ type, payload }, defaults);
16
+ if (this.events?.emit) {
17
+ this.events.emit(`lifecycle.${type}`, event);
18
+ }
19
+ if (this.middleware?.run) {
20
+ await this.middleware.run('onEvent', {
21
+ ...(this.defaults || {}),
22
+ ...(defaults || {}),
23
+ lifecycleEvent: type,
24
+ }, {
25
+ ...event,
26
+ type: `lifecycle.${type}`,
27
+ });
28
+ }
29
+ return event;
30
+ }
31
+
32
+ async wrap(type, payload, fn, defaults = {}) {
33
+ await this.emit(`${type}_started`, payload, defaults);
34
+ try {
35
+ const result = await fn();
36
+ await this.emit(`${type}_finished`, { ...payload, result: summarizeResult(result) }, defaults);
37
+ return result;
38
+ } catch (err) {
39
+ await this.emit(`${type}_failed`, { ...payload, error: err.message }, defaults);
40
+ throw err;
41
+ }
42
+ }
43
+
44
+ child(defaults = {}) {
45
+ return new LifecycleHookBus({
46
+ events: this.events,
47
+ middleware: this.middleware,
48
+ runtimeEvents: this.runtimeEvents.child(defaults),
49
+ now: this.now,
50
+ defaults: { ...this.defaults, ...defaults },
51
+ });
52
+ }
53
+ }
54
+
55
+ function summarizeResult(result) {
56
+ if (result == null) return null;
57
+ if (typeof result === 'string') return { type: 'string', chars: result.length };
58
+ if (typeof result !== 'object') return { type: typeof result };
59
+ return {
60
+ type: 'object',
61
+ keys: Object.keys(result).sort().slice(0, 20),
62
+ ok: result.ok === true,
63
+ error: result.error ? String(result.error) : '',
64
+ };
65
+ }
66
+
67
+ function normalizeLifecycleEvent(input = {}, defaults = {}) {
68
+ return createRuntimeEvent(input, defaults);
69
+ }
70
+
71
+ module.exports = {
72
+ LifecycleHookBus,
73
+ normalizeLifecycleEvent,
74
+ summarizeResult,
75
+ };
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+
3
+ const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);
4
+
5
+ function extractLoopbackUrls(text) {
6
+ const source = String(text || '');
7
+ const matches = source.match(/https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::\d+)?(?:\/[^\s<>)\]]*)?/gi) || [];
8
+ const seen = new Set();
9
+ const urls = [];
10
+ for (const match of matches) {
11
+ const raw = match.replace(/[.,;:!?]+$/g, '');
12
+ const normalized = normalizeLoopbackUrl(raw);
13
+ if (!normalized || seen.has(normalized.href)) continue;
14
+ seen.add(normalized.href);
15
+ urls.push({ raw, ...normalized });
16
+ }
17
+ return urls;
18
+ }
19
+
20
+ function normalizeLoopbackUrl(raw) {
21
+ try {
22
+ const parsed = new URL(String(raw || '').trim());
23
+ const hostname = parsed.hostname.toLowerCase();
24
+ if (!LOOPBACK_HOSTS.has(hostname) && !LOOPBACK_HOSTS.has(parsed.host.toLowerCase())) return null;
25
+ const port = parsed.port || (parsed.protocol === 'https:' ? '443' : '80');
26
+ const pathname = parsed.pathname || '/';
27
+ const normalizedPath = pathname === '/index.html' ? '/' : pathname.replace(/\/+$/, '') || '/';
28
+ return {
29
+ href: parsed.href,
30
+ origin: `${parsed.protocol}//${hostname}:${port}`,
31
+ protocol: parsed.protocol,
32
+ hostname,
33
+ port,
34
+ pathname,
35
+ routeKey: `${parsed.protocol}//${hostname}:${port}${normalizedPath}`,
36
+ };
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+
42
+ function analyzeLocalPreviewClaims(text, toolCalls = []) {
43
+ const urls = extractLoopbackUrls(text);
44
+ if (urls.length === 0) {
45
+ return { ok: true, hasPositiveClaim: false, urls: [], unsupportedUrls: [], verifiedUrls: [] };
46
+ }
47
+ const positiveUrls = urls.filter((url) => _looksLikePositivePreviewClaim(text, url.raw));
48
+ if (positiveUrls.length === 0) {
49
+ return { ok: true, hasPositiveClaim: false, urls, unsupportedUrls: [], verifiedUrls: [] };
50
+ }
51
+ const evidence = _collectPreviewEvidence(toolCalls);
52
+ const unsupportedUrls = [];
53
+ const verifiedUrls = [];
54
+ for (const url of positiveUrls) {
55
+ const match = evidence.find((item) => _evidenceSupportsUrl(item, url));
56
+ if (match) verifiedUrls.push({ ...url, evidence: match });
57
+ else unsupportedUrls.push(url);
58
+ }
59
+ return {
60
+ ok: unsupportedUrls.length === 0,
61
+ hasPositiveClaim: true,
62
+ urls: positiveUrls,
63
+ unsupportedUrls,
64
+ verifiedUrls,
65
+ evidence,
66
+ };
67
+ }
68
+
69
+ function buildLocalPreviewVerificationNudge(analysis) {
70
+ const urls = (analysis?.unsupportedUrls || []).map((url) => url.raw).join(', ');
71
+ return [
72
+ `[System: Your previous response claimed local preview URL(s) were live or reachable without current successful preview-tool evidence: ${urls || '(local URL)'}.`,
73
+ 'Do not claim HTTP 200, "server is back", "restarted", "serving", "live", or "reachable" from memory, terminal text, or a background/nohup shell command.',
74
+ 'Call check_url for the exact URL now, or call start_static_server for the target directory if you need a managed server, then answer from that tool result.',
75
+ 'If the check fails, say the URL is not reachable and include the actual error. If the URL is localhost/127.0.0.1, say it is only verified from Wall-E host loopback; phone or remote browser access needs CTM remote/tunnel context.]',
76
+ ].join(' ');
77
+ }
78
+
79
+ function buildUnsupportedLocalPreviewReply(analysis) {
80
+ const urls = (analysis?.unsupportedUrls || []).map((url) => url.raw).join(', ') || 'the local preview URL';
81
+ return [
82
+ `I cannot honestly confirm ${urls} is live yet.`,
83
+ '',
84
+ 'The previous answer attempted to claim a local preview was reachable, but this turn has no successful `check_url`, `start_static_server`, or `browser_screenshot` evidence for that URL. A `localhost` or `127.0.0.1` link also only proves Wall-E host loopback access; phone or remote browser access needs the CTM remote/tunnel path.',
85
+ ].join('\n');
86
+ }
87
+
88
+ function _looksLikePositivePreviewClaim(text, rawUrl) {
89
+ const source = String(text || '');
90
+ const idx = source.indexOf(rawUrl);
91
+ const window = idx >= 0
92
+ ? source.slice(Math.max(0, idx - 180), Math.min(source.length, idx + rawUrl.length + 220))
93
+ : source;
94
+ const lower = window.toLowerCase();
95
+ const positive = /\b(?:http\s*200|status\s*200|server(?:\s+is)?\s+(?:back|up|running)|back\s+up|reachable|accessible|available|live|serving|started|restarted|ready|works|open\s+(?:it|this|the)|visit|you\s+can\s+(?:open|use|view|access))\b/.test(lower)
96
+ || /(?:→|->)\s*http\s*200/i.test(window);
97
+ if (!positive) return false;
98
+ const negative = /\b(?:not|isn['’]?t|cannot|can['’]?t|couldn['’]?t|failed|failure|refused|timed\s*out|unreachable|inaccessible|not\s+reachable|not\s+accessible|not\s+available|down|no\s+listener|connection\s+refused|does\s+not)\b/.test(lower);
99
+ if (!negative) return true;
100
+ return /\b(?:now|after|restarted|server(?:\s+is)?\s+back|http\s*200|status\s*200)\b/.test(lower)
101
+ && !/\b(?:still|remains)\s+(?:not\s+)?(?:down|unreachable|inaccessible|broken)\b/.test(lower);
102
+ }
103
+
104
+ function _collectPreviewEvidence(toolCalls = []) {
105
+ const evidence = [];
106
+ for (const call of Array.isArray(toolCalls) ? toolCalls : []) {
107
+ const name = call?.tool || call?.name;
108
+ if (!['check_url', 'start_static_server', 'browser_screenshot'].includes(name)) continue;
109
+ if (call?.ok !== true) continue;
110
+ const result = call.result || {};
111
+ const ok = result.ok === true
112
+ || result.health?.ok === true
113
+ || (name === 'browser_screenshot' && result.path && !result.error);
114
+ if (!ok) continue;
115
+ const candidateUrls = [
116
+ result.url,
117
+ result.health?.url,
118
+ call.args?.url,
119
+ call.input?.url,
120
+ ].filter(Boolean);
121
+ for (const candidate of candidateUrls) {
122
+ const normalized = normalizeLoopbackUrl(candidate);
123
+ if (!normalized) continue;
124
+ evidence.push({
125
+ tool: name,
126
+ url: candidate,
127
+ ...normalized,
128
+ });
129
+ }
130
+ }
131
+ return evidence;
132
+ }
133
+
134
+ function _evidenceSupportsUrl(evidence, claim) {
135
+ if (!evidence || !claim) return false;
136
+ if (evidence.routeKey === claim.routeKey) return true;
137
+ if (evidence.origin !== claim.origin && !_sameLoopbackEndpoint(evidence, claim)) return false;
138
+ const evidencePath = evidence.pathname || '/';
139
+ const claimPath = claim.pathname || '/';
140
+ return (evidencePath === '/index.html' && claimPath === '/')
141
+ || (evidencePath === '/' && claimPath === '/index.html');
142
+ }
143
+
144
+ function _sameLoopbackEndpoint(a, b) {
145
+ return a.protocol === b.protocol
146
+ && String(a.port || '') === String(b.port || '')
147
+ && LOOPBACK_HOSTS.has(String(a.hostname || '').toLowerCase())
148
+ && LOOPBACK_HOSTS.has(String(b.hostname || '').toLowerCase());
149
+ }
150
+
151
+ module.exports = {
152
+ analyzeLocalPreviewClaims,
153
+ buildLocalPreviewVerificationNudge,
154
+ buildUnsupportedLocalPreviewReply,
155
+ extractLoopbackUrls,
156
+ normalizeLoopbackUrl,
157
+ };
@@ -3,11 +3,37 @@
3
3
  const crypto = require('node:crypto');
4
4
  const path = require('node:path');
5
5
  const { checkPermission } = require('../tools/permission-checker');
6
- const { analyzeShellCommand, initParser: initShellParser } = require('../tools/shell-analyzer');
6
+ const { analyzeShellCommand, initParser: initShellParser, bashArityPrefix } = require('../tools/shell-analyzer');
7
+
8
+ // Shell builtins that only navigate; skipped when choosing the approval card's
9
+ // display pattern so a leading `cd` doesn't label the request as "cd *".
10
+ const _DISPLAY_NAV = new Set(['cd', 'pushd', 'popd', 'dirs']);
11
+
12
+ // Pick the pattern shown on the approval card (and stored for "always" rules)
13
+ // for a compound run_shell command: the first meaningful (non-navigation)
14
+ // clause, so `cd /x && git push` is labelled `git push *`, not `cd *`.
15
+ function pickShellDisplayPattern(clauses, command) {
16
+ const meaningful = clauses.find((t) => Array.isArray(t) && t.length > 0 && !_DISPLAY_NAV.has(t[0]))
17
+ || (clauses.length > 0 ? clauses[0] : null);
18
+ if (meaningful && meaningful.length > 0) {
19
+ return `${bashArityPrefix(meaningful).join(' ')} *`;
20
+ }
21
+ return `${String(command).split(/\s+/)[0] || '*'} *`;
22
+ }
7
23
  const { PermissionRulesStore } = require('./permission-rules-store');
8
24
  const { inferPatchPaths } = require('./snapshot-service');
9
25
 
10
26
  const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;
27
+ // Timeout semantics for a permission request:
28
+ // > 0 -> auto-deny after N ms (used for headless/automated runs)
29
+ // === 0 -> headless: resolve immediately via headlessPolicy (no prompt)
30
+ // WAIT_FOR_REPLY (< 0) -> interactive: never auto-deny; stay pending until the user
31
+ // replies or the session is cleared (matches Claude Code /
32
+ // opencode, which wait for the user instead of timing out).
33
+ // The < 0 case needs no special branch: ask() only arms a timer when the effective
34
+ // timeout is > 0, and authorize()'s headless shortcut matches exactly === 0, so a
35
+ // negative value naturally falls through to a no-timer wait.
36
+ const WAIT_FOR_REPLY = -1;
11
37
  const _sharedPending = new Map();
12
38
 
13
39
  class PermissionService {
@@ -27,20 +53,21 @@ class PermissionService {
27
53
  }
28
54
 
29
55
  async authorize({ sessionId = '', tool, input = {}, cwd = '', projectRoot = '', mode = '', metadata = {}, timeoutMs, headless = false } = {}) {
56
+ const permissionContextId = metadata.permissionContextId || metadata.permission_context_id || createPermissionContextId();
30
57
  const requests = await buildToolPermissionRequests(tool, input, {
31
58
  cwd,
32
59
  projectRoot: projectRoot || cwd,
33
60
  sessionId,
34
61
  mode,
35
- metadata,
62
+ metadata: { ...metadata, permissionContextId },
36
63
  });
37
- if (requests.length === 0) return { decision: 'allow', source: 'default', reason: 'No permission required' };
64
+ if (requests.length === 0) return { decision: 'allow', source: 'default', reason: 'No permission required', permissionContextId };
38
65
 
39
66
  for (const request of requests) {
40
67
  const evaluated = await this.evaluatePermission(request.check);
41
68
  if (evaluated.decision === 'allow') continue;
42
69
  if (evaluated.decision === 'deny') {
43
- return { ...evaluated, request };
70
+ return { ...evaluated, request, permissionContextId };
44
71
  }
45
72
 
46
73
  const always = this.rulesStore.findAlways({
@@ -60,6 +87,7 @@ class PermissionService {
60
87
  source: 'headless',
61
88
  reason: `Permission required for ${request.permission}/${request.pattern}`,
62
89
  request,
90
+ permissionContextId,
63
91
  };
64
92
  }
65
93
 
@@ -67,17 +95,19 @@ class PermissionService {
67
95
  ...request,
68
96
  sessionId,
69
97
  metadata: { ...metadata, ...request.metadata, evaluated },
98
+ permissionContextId,
70
99
  timeoutMs,
71
100
  });
72
- if (reply.decision !== 'allow') return { ...reply, request };
101
+ if (reply.decision !== 'allow') return { ...reply, request, permissionContextId };
73
102
  }
74
103
 
75
- return { decision: 'allow', source: 'permissions', reason: 'Permission checks passed' };
104
+ return { decision: 'allow', source: 'permissions', reason: 'Permission checks passed', permissionContextId };
76
105
  }
77
106
 
78
- ask({ sessionId = '', permission, pattern = '*', patterns = null, tool = '', fingerprint = '', metadata = {}, timeoutMs } = {}) {
107
+ ask({ sessionId = '', permission, pattern = '*', patterns = null, tool = '', fingerprint = '', metadata = {}, permissionContextId = '', timeoutMs } = {}) {
79
108
  if (!permission) throw new Error('permission is required');
80
109
  const id = `perm_${crypto.randomUUID().slice(0, 8)}`;
110
+ const contextId = permissionContextId || metadata.permissionContextId || metadata.permission_context_id || createPermissionContextId();
81
111
  const effectiveTimeout = timeoutMs ?? this.timeoutMs;
82
112
 
83
113
  return new Promise((resolve) => {
@@ -92,7 +122,8 @@ class PermissionService {
92
122
  patterns: patterns || [pattern],
93
123
  tool,
94
124
  fingerprint: fingerprint || metadata.fingerprint || '',
95
- metadata,
125
+ permissionContextId: contextId,
126
+ metadata: { ...metadata, permissionContextId: contextId },
96
127
  createdAt: Date.now(),
97
128
  timer,
98
129
  resolve,
@@ -152,8 +183,9 @@ class PermissionService {
152
183
  _resolveEntry(entry, result) {
153
184
  if (entry.timer) clearTimeout(entry.timer);
154
185
  this.pending.delete(entry.id);
155
- this._emit('permission.replied', { ...publicEntry(entry), result });
156
- entry.resolve(result);
186
+ const resolved = { ...result, permissionContextId: entry.permissionContextId || entry.metadata?.permissionContextId || '' };
187
+ this._emit('permission.replied', { ...publicEntry(entry), result: resolved });
188
+ entry.resolve(resolved);
157
189
  }
158
190
 
159
191
  _expire(id) {
@@ -181,14 +213,19 @@ async function buildToolPermissionRequests(tool, input = {}, { cwd = '', project
181
213
  const command = input.command || '';
182
214
  await initShellParser();
183
215
  const analysis = await analyzeShellCommand(command, input.cwd || cwd || root);
184
- const commandTokens = analysis.commandTokens.length > 0 ? analysis.commandTokens[0] : undefined;
185
- const pattern = commandTokens && commandTokens.length > 0 ? `${commandTokens[0]} *` : `${String(command).split(/\s+/)[0] || '*'} *`;
216
+ // commandTokens is an array of per-clause token arrays (split on && ; | etc).
217
+ // The whole compound command must be permission-checked clause-by-clause, so
218
+ // pass the full list through to checkPermission; keep the first clause in
219
+ // metadata.commandTokens so the approval fingerprint stays stable.
220
+ const commandClauses = Array.isArray(analysis.commandTokens) ? analysis.commandTokens : [];
221
+ const commandTokens = commandClauses.length > 0 ? commandClauses[0] : undefined;
222
+ const pattern = pickShellDisplayPattern(commandClauses, command);
186
223
  return withApprovalFingerprints([{
187
224
  ...base,
188
225
  permission: 'bash',
189
226
  pattern,
190
227
  metadata: { ...base.metadata, command, commandTokens },
191
- check: { tool: 'run_shell', command, commandTokens, projectPath: root, sessionId, mode },
228
+ check: { tool: 'run_shell', command, commandTokens, commandClauses, projectPath: root, sessionId, mode },
192
229
  }], input);
193
230
  }
194
231
 
@@ -339,6 +376,7 @@ function publicEntry(entry) {
339
376
  return {
340
377
  id: entry.id,
341
378
  sessionId: entry.sessionId,
379
+ permissionContextId: entry.permissionContextId || entry.metadata?.permissionContextId || '',
342
380
  permission: entry.permission,
343
381
  pattern: entry.pattern,
344
382
  patterns: entry.patterns,
@@ -349,6 +387,10 @@ function publicEntry(entry) {
349
387
  };
350
388
  }
351
389
 
390
+ function createPermissionContextId() {
391
+ return `permctx_${crypto.randomUUID().slice(0, 8)}`;
392
+ }
393
+
352
394
  function getDefaultPermissionService() {
353
395
  return new PermissionService();
354
396
  }
@@ -365,7 +407,9 @@ module.exports = {
365
407
  buildToolPermissionRequests,
366
408
  approvalFingerprint,
367
409
  approvalFingerprintInput,
410
+ createPermissionContextId,
368
411
  getDefaultPermissionService,
369
412
  clearPendingPermissions,
370
413
  DEFAULT_TIMEOUT_MS,
414
+ WAIT_FOR_REPLY,
371
415
  };