@pugi/cli 0.1.0-beta.10 → 0.1.0-beta.101

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 (464) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/README.md +55 -11
  4. package/assets/pugi-prozr2-mascot.ansi +9 -0
  5. package/bin/run.js +33 -1
  6. package/dist/commands/deploy.js +40 -40
  7. package/dist/commands/flatten.js +191 -0
  8. package/dist/commands/jobs-watch.js +201 -0
  9. package/dist/commands/jobs.js +42 -27
  10. package/dist/commands/retro.js +210 -0
  11. package/dist/commands/smoke.js +133 -0
  12. package/dist/core/agent-progress/cleanup.js +134 -0
  13. package/dist/core/agent-progress/schema.js +144 -0
  14. package/dist/core/agent-progress/writer.js +101 -0
  15. package/dist/core/agents/adaptive-router.js +330 -0
  16. package/dist/core/agents/query-decomposer.js +297 -0
  17. package/dist/core/agents/registry.js +3 -3
  18. package/dist/core/approvals/shortcut-resolver.js +98 -0
  19. package/dist/core/artifact-chain/dispatcher.js +148 -0
  20. package/dist/core/artifact-chain/exporter.js +164 -0
  21. package/dist/core/artifact-chain/state.js +243 -0
  22. package/dist/core/artifact-chain/steps.js +169 -0
  23. package/dist/core/ask-user/question.js +92 -0
  24. package/dist/core/audit/audit-trail.js +275 -0
  25. package/dist/core/auth/ensure-authenticated.js +129 -0
  26. package/dist/core/auth/env-provider.js +238 -0
  27. package/dist/core/auto-open-browser.js +4 -4
  28. package/dist/core/auto-update/channels.js +122 -0
  29. package/dist/core/auto-update/checker.js +241 -0
  30. package/dist/core/auto-update/state.js +235 -0
  31. package/dist/core/bare-mode/index.js +107 -0
  32. package/dist/core/bash/redirect.js +281 -0
  33. package/dist/core/bash-classifier.js +436 -40
  34. package/dist/core/checkpoint/resumer.js +149 -0
  35. package/dist/core/checkpoint/rewinder.js +291 -0
  36. package/dist/core/checkpoints/shadow-git.js +670 -0
  37. package/dist/core/citations/parser.js +109 -0
  38. package/dist/core/classifier/yolo-classifier.js +88 -0
  39. package/dist/core/codegraph/db.js +506 -0
  40. package/dist/core/codegraph/decision-store.js +248 -0
  41. package/dist/core/codegraph/detect-repo.js +459 -0
  42. package/dist/core/codegraph/install.js +134 -0
  43. package/dist/core/codegraph/offer-hook.js +220 -0
  44. package/dist/core/codegraph/parser.js +598 -0
  45. package/dist/core/codegraph/queries/go.scm +57 -0
  46. package/dist/core/codegraph/queries/javascript.scm +56 -0
  47. package/dist/core/codegraph/queries/python.scm +55 -0
  48. package/dist/core/codegraph/queries/rust.scm +63 -0
  49. package/dist/core/codegraph/queries/typescript.scm +91 -0
  50. package/dist/core/codegraph/reindex.js +218 -0
  51. package/dist/core/codegraph/resolve-edges.js +107 -0
  52. package/dist/core/codegraph/types.js +34 -0
  53. package/dist/core/codegraph/watcher.js +440 -0
  54. package/dist/core/compact/auto-trigger.js +96 -0
  55. package/dist/core/compact/buffer-rewriter.js +115 -0
  56. package/dist/core/compact/summarizer.js +208 -0
  57. package/dist/core/compact/token-counter.js +108 -0
  58. package/dist/core/consensus/anvil-fanout.js +25 -25
  59. package/dist/core/consensus/diff-capture.js +121 -12
  60. package/dist/core/consensus/rubric.js +21 -21
  61. package/dist/core/context/builder.js +6 -6
  62. package/dist/core/context/compaction-events.js +8 -8
  63. package/dist/core/context/compaction.js +31 -31
  64. package/dist/core/context/index.js +15 -8
  65. package/dist/core/context/invariants.js +51 -51
  66. package/dist/core/context/markdown-loader.js +28 -10
  67. package/dist/core/context/markdown-traverse.js +255 -0
  68. package/dist/core/context/pugiignore.js +41 -41
  69. package/dist/core/context/repo-skeleton.js +37 -37
  70. package/dist/core/context/tool-eviction.js +55 -0
  71. package/dist/core/context/watcher.js +32 -32
  72. package/dist/core/context/working-set.js +23 -23
  73. package/dist/core/coordinator/agent-tools.js +77 -0
  74. package/dist/core/coordinator/agent-toolset.js +65 -0
  75. package/dist/core/coordinator/fsm.js +73 -0
  76. package/dist/core/coordinator/mode-fsm.js +70 -0
  77. package/dist/core/cost/rate-card.js +129 -0
  78. package/dist/core/cost/tracker.js +221 -0
  79. package/dist/core/credentials.js +13 -13
  80. package/dist/core/cron/scheduler.js +138 -0
  81. package/dist/core/denial-tracking/index.js +8 -0
  82. package/dist/core/denial-tracking/state.js +264 -0
  83. package/dist/core/diagnostics/probe-runner.js +93 -0
  84. package/dist/core/diagnostics/probes/api.js +46 -0
  85. package/dist/core/diagnostics/probes/auth.js +93 -0
  86. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  87. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  88. package/dist/core/diagnostics/probes/config.js +72 -0
  89. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  90. package/dist/core/diagnostics/probes/disk.js +81 -0
  91. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  92. package/dist/core/diagnostics/probes/git.js +65 -0
  93. package/dist/core/diagnostics/probes/hooks.js +118 -0
  94. package/dist/core/diagnostics/probes/mcp.js +75 -0
  95. package/dist/core/diagnostics/probes/node.js +59 -0
  96. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  97. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  98. package/dist/core/diagnostics/probes/sandbox.js +67 -0
  99. package/dist/core/diagnostics/probes/session.js +74 -0
  100. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  101. package/dist/core/diagnostics/probes/workspace.js +63 -0
  102. package/dist/core/diagnostics/types.js +70 -0
  103. package/dist/core/dispatch/cache-cleanup.js +197 -0
  104. package/dist/core/dispatch/cache-handoff.js +295 -0
  105. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  106. package/dist/core/edits/dispatch.js +333 -7
  107. package/dist/core/edits/format-detector.js +260 -0
  108. package/dist/core/edits/format-matrix.js +26 -0
  109. package/dist/core/edits/fuzzy-ladder.js +650 -0
  110. package/dist/core/edits/index.js +5 -1
  111. package/dist/core/edits/journal.js +199 -0
  112. package/dist/core/edits/layer-a-apply.js +15 -15
  113. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  114. package/dist/core/edits/layer-b-apply.js +9 -9
  115. package/dist/core/edits/layer-c-apply.js +6 -6
  116. package/dist/core/edits/layer-d-ast.js +557 -14
  117. package/dist/core/edits/marker-parser.js +12 -12
  118. package/dist/core/edits/security-gate.js +27 -27
  119. package/dist/core/edits/verify-hook.js +273 -0
  120. package/dist/core/edits/worktree.js +29 -29
  121. package/dist/core/engine/anvil-client.js +214 -26
  122. package/dist/core/engine/auto-compact.js +247 -0
  123. package/dist/core/engine/budgets.js +220 -0
  124. package/dist/core/engine/compact-llm-summarizer.js +124 -0
  125. package/dist/core/engine/context-prefix.js +155 -0
  126. package/dist/core/engine/index.js +1 -1
  127. package/dist/core/engine/intensity.js +163 -0
  128. package/dist/core/engine/intent.js +260 -0
  129. package/dist/core/engine/native-pugi.js +1559 -227
  130. package/dist/core/engine/prompts.js +219 -19
  131. package/dist/core/engine/strip-internal-fields.js +124 -0
  132. package/dist/core/engine/tool-bridge.js +1887 -59
  133. package/dist/core/engine/verification-patterns.js +195 -0
  134. package/dist/core/eval/v1/ledger.js +83 -0
  135. package/dist/core/eval/v1/runner.js +280 -0
  136. package/dist/core/eval/v1/scoring.js +68 -0
  137. package/dist/core/eval/v1/task-loader.js +191 -0
  138. package/dist/core/eval/v1/types.js +14 -0
  139. package/dist/core/eval/v1/verifier.js +176 -0
  140. package/dist/core/eval/v1/yaml-parser.js +250 -0
  141. package/dist/core/evaluation/golden-dataset.js +293 -0
  142. package/dist/core/feedback/queue.js +177 -0
  143. package/dist/core/feedback/submitter.js +145 -0
  144. package/dist/core/file-cache.js +113 -1
  145. package/dist/core/flatten/flatten-repo.js +439 -0
  146. package/dist/core/format/osc8-link.js +28 -0
  147. package/dist/core/hook-chains.js +392 -0
  148. package/dist/core/hooks/citation-verify-hook.js +138 -0
  149. package/dist/core/hooks/citation-verify.js +112 -0
  150. package/dist/core/hooks/events.js +46 -0
  151. package/dist/core/hooks/index.js +15 -0
  152. package/dist/core/hooks/registry.js +216 -0
  153. package/dist/core/hooks/runner.js +236 -0
  154. package/dist/core/hooks/v2/event-emitter.js +115 -0
  155. package/dist/core/hooks/v2/executor.js +282 -0
  156. package/dist/core/hooks/v2/index.js +25 -0
  157. package/dist/core/hooks/v2/lifecycle.js +104 -0
  158. package/dist/core/hooks/v2/loader.js +216 -0
  159. package/dist/core/hooks/v2/matcher.js +125 -0
  160. package/dist/core/hooks/v2/trust.js +143 -0
  161. package/dist/core/hooks/v2/types.js +86 -0
  162. package/dist/core/hooks/worktree-events.js +158 -0
  163. package/dist/core/image/renderer.js +71 -0
  164. package/dist/core/init/detector.js +582 -0
  165. package/dist/core/init/template-renderer.js +242 -0
  166. package/dist/core/jobs/registry.js +18 -18
  167. package/dist/core/ledger/results-tsv.js +142 -0
  168. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  169. package/dist/core/lsp/cache.js +105 -0
  170. package/dist/core/lsp/client.js +551 -41
  171. package/dist/core/lsp/language-detect.js +66 -0
  172. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  173. package/dist/core/lsp/server-detect.js +173 -0
  174. package/dist/core/lsp/symbol-cache.js +162 -0
  175. package/dist/core/lsp/symbol-tools.js +664 -0
  176. package/dist/core/mcp/client.js +97 -28
  177. package/dist/core/mcp/http-server.js +553 -0
  178. package/dist/core/mcp/orchestrator-config.js +192 -0
  179. package/dist/core/mcp/orchestrator-tools.js +806 -0
  180. package/dist/core/mcp/permission.js +190 -0
  181. package/dist/core/mcp/registry.js +39 -17
  182. package/dist/core/mcp/server-tools.js +219 -0
  183. package/dist/core/mcp/server.js +397 -0
  184. package/dist/core/mcp/trust.js +10 -10
  185. package/dist/core/memory/dual-write.js +416 -0
  186. package/dist/core/memory/passive-extract.js +130 -0
  187. package/dist/core/memory/phase1-kinds.js +20 -0
  188. package/dist/core/memory/secret-scanner.js +304 -0
  189. package/dist/core/memory-sync/queue.js +170 -0
  190. package/dist/core/metrics/extract.js +113 -0
  191. package/dist/core/modes/roo-modes.js +68 -0
  192. package/dist/core/notes/notes-paths.js +113 -0
  193. package/dist/core/notes/notes-recorder.js +140 -0
  194. package/dist/core/notes/notes-writer.js +53 -0
  195. package/dist/core/notes/renderers.js +0 -0
  196. package/dist/core/notes/slug.js +105 -0
  197. package/dist/core/onboarding/ensure-initialized.js +133 -0
  198. package/dist/core/onboarding/marker.js +111 -0
  199. package/dist/core/onboarding/telemetry-state.js +108 -0
  200. package/dist/core/output-style/presets.js +176 -0
  201. package/dist/core/output-style/state.js +185 -0
  202. package/dist/core/path-security.js +287 -5
  203. package/dist/core/permission.js +82 -22
  204. package/dist/core/permissions/auto-classifier.js +124 -0
  205. package/dist/core/permissions/bash-parser.js +371 -0
  206. package/dist/core/permissions/circuit-breaker.js +83 -0
  207. package/dist/core/permissions/constrained-edit.js +91 -0
  208. package/dist/core/permissions/gate.js +278 -0
  209. package/dist/core/permissions/index.js +20 -0
  210. package/dist/core/permissions/mode.js +174 -0
  211. package/dist/core/permissions/network-egress.js +137 -0
  212. package/dist/core/permissions/state.js +241 -0
  213. package/dist/core/permissions/tool-class.js +107 -0
  214. package/dist/core/plan-mode/ui-state.js +51 -0
  215. package/dist/core/plans/plan-artifact.js +721 -0
  216. package/dist/core/policy-limits/etag-store.js +122 -0
  217. package/dist/core/prd-check/parser.js +215 -0
  218. package/dist/core/prd-check/reporter.js +127 -0
  219. package/dist/core/prd-check/session-review.js +557 -0
  220. package/dist/core/prd-check/verifiers.js +223 -0
  221. package/dist/core/prompt-cache/client-cache.js +99 -0
  222. package/dist/core/prompts/assembly.js +29 -0
  223. package/dist/core/prompts/registry.js +364 -0
  224. package/dist/core/pugi-gitignore.js +52 -0
  225. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  226. package/dist/core/pugi-md/context-injector.js +76 -0
  227. package/dist/core/pugi-md/walk-up.js +207 -0
  228. package/dist/core/python/uv-installer.js +270 -0
  229. package/dist/core/python/uv-resolver.js +83 -0
  230. package/dist/core/rate-limit/narrator.js +146 -0
  231. package/dist/core/recipes/cli-types.js +20 -0
  232. package/dist/core/recipes/loader.js +103 -0
  233. package/dist/core/recipes/runner.js +345 -0
  234. package/dist/core/recipes/schema.js +587 -0
  235. package/dist/core/release-notes/parser.js +241 -0
  236. package/dist/core/release-notes/state.js +116 -0
  237. package/dist/core/repl/ask.js +37 -37
  238. package/dist/core/repl/cancellation.js +26 -26
  239. package/dist/core/repl/cap-warning.js +4 -4
  240. package/dist/core/repl/clipboard-read.js +11 -11
  241. package/dist/core/repl/dispatch-fsm.js +12 -12
  242. package/dist/core/repl/engine-bridge.js +303 -0
  243. package/dist/core/repl/history-search.js +15 -15
  244. package/dist/core/repl/history.js +28 -18
  245. package/dist/core/repl/kill-ring.js +5 -5
  246. package/dist/core/repl/model-pricing.js +135 -0
  247. package/dist/core/repl/privacy-banner.js +22 -22
  248. package/dist/core/repl/session.js +2690 -229
  249. package/dist/core/repl/slash-commands.js +540 -41
  250. package/dist/core/repl/store/index.js +1 -1
  251. package/dist/core/repl/store/jsonl-log.js +22 -22
  252. package/dist/core/repl/store/lockfile.js +10 -10
  253. package/dist/core/repl/store/session-store.js +136 -107
  254. package/dist/core/repl/store/types.js +15 -15
  255. package/dist/core/repl/store/uuid-v7.js +12 -12
  256. package/dist/core/repl/tool-route.js +382 -0
  257. package/dist/core/repl/workspace-context.js +43 -21
  258. package/dist/core/repo-map/build.js +125 -0
  259. package/dist/core/repo-map/cache.js +185 -0
  260. package/dist/core/repo-map/extractor.js +254 -0
  261. package/dist/core/repo-map/formatter.js +145 -0
  262. package/dist/core/repo-map/page-rank.js +105 -0
  263. package/dist/core/repo-map/scanner.js +211 -0
  264. package/dist/core/retro/git-collector.js +251 -0
  265. package/dist/core/retro/health-card.js +25 -0
  266. package/dist/core/retro/metrics.js +342 -0
  267. package/dist/core/retro/narrative.js +249 -0
  268. package/dist/core/retro/plane-collector.js +274 -0
  269. package/dist/core/retro/pr-issue-link.js +65 -0
  270. package/dist/core/retro/types.js +16 -0
  271. package/dist/core/retry-budget/budget.js +284 -0
  272. package/dist/core/retry-budget/index.js +5 -0
  273. package/dist/core/retry-budget/retry-cap.js +74 -0
  274. package/dist/core/routing/lead-worker.js +43 -0
  275. package/dist/core/routing/pre-flight-estimator.js +108 -0
  276. package/dist/core/runs/run-tree.js +103 -0
  277. package/dist/core/sandboxing/adapter.js +43 -0
  278. package/dist/core/sandboxing/bubblewrap.js +209 -0
  279. package/dist/core/sandboxing/index.js +78 -0
  280. package/dist/core/sandboxing/none.js +19 -0
  281. package/dist/core/sandboxing/policy.js +97 -0
  282. package/dist/core/sandboxing/seatbelt.js +231 -0
  283. package/dist/core/security/injection-scanner.js +367 -0
  284. package/dist/core/security/output-filter.js +418 -0
  285. package/dist/core/session/env-file.js +105 -0
  286. package/dist/core/session/section-budgets.js +140 -0
  287. package/dist/core/session.js +119 -0
  288. package/dist/core/settings.js +402 -5
  289. package/dist/core/share/formatter.js +271 -0
  290. package/dist/core/share/redactor.js +221 -0
  291. package/dist/core/share/uploader.js +267 -0
  292. package/dist/core/skills/defaults.js +30 -30
  293. package/dist/core/skills/loader.js +22 -22
  294. package/dist/core/skills/sources.js +27 -27
  295. package/dist/core/smoke/headless-driver.js +174 -0
  296. package/dist/core/smoke/orchestrator.js +194 -0
  297. package/dist/core/smoke/runner.js +238 -0
  298. package/dist/core/smoke/scenario-parser.js +316 -0
  299. package/dist/core/statusline.js +99 -0
  300. package/dist/core/subagents/dispatcher-real.js +600 -0
  301. package/dist/core/subagents/dispatcher.js +146 -52
  302. package/dist/core/subagents/index.js +19 -6
  303. package/dist/core/subagents/isolation-matrix.js +213 -0
  304. package/dist/core/subagents/spawn.js +19 -4
  305. package/dist/core/telemetry/emitter.js +229 -0
  306. package/dist/core/telemetry/queue.js +251 -0
  307. package/dist/core/theme/context.js +91 -0
  308. package/dist/core/theme/presets.js +228 -0
  309. package/dist/core/theme/state.js +181 -0
  310. package/dist/core/todos/invariant.js +10 -0
  311. package/dist/core/todos/state.js +177 -0
  312. package/dist/core/tool-schema/compressor.js +89 -0
  313. package/dist/core/transport/version-interceptor.js +166 -0
  314. package/dist/core/trust.js +2 -2
  315. package/dist/core/tui/thinking-block.js +64 -0
  316. package/dist/core/vim/keymap.js +288 -0
  317. package/dist/core/vim/state.js +92 -0
  318. package/dist/core/watch-markers/marker-watcher.js +133 -0
  319. package/dist/core/worktree/include-parser.js +249 -0
  320. package/dist/core/worktree-manager/cleanup.js +123 -0
  321. package/dist/core/worktree-manager/manager.js +303 -0
  322. package/dist/index.js +36 -0
  323. package/dist/runtime/bootstrap.js +190 -0
  324. package/dist/runtime/cli.js +4403 -561
  325. package/dist/runtime/commands/agents.js +31 -31
  326. package/dist/runtime/commands/budget.js +5 -5
  327. package/dist/runtime/commands/cancel.js +231 -0
  328. package/dist/runtime/commands/chain.js +489 -0
  329. package/dist/runtime/commands/codegraph-status.js +227 -0
  330. package/dist/runtime/commands/compact.js +297 -0
  331. package/dist/runtime/commands/config.js +74 -40
  332. package/dist/runtime/commands/cost.js +199 -0
  333. package/dist/runtime/commands/delegate.js +27 -4
  334. package/dist/runtime/commands/dispatch.js +126 -0
  335. package/dist/runtime/commands/doctor.js +579 -0
  336. package/dist/runtime/commands/eval-v1.js +266 -0
  337. package/dist/runtime/commands/feedback.js +184 -0
  338. package/dist/runtime/commands/hooks.js +187 -0
  339. package/dist/runtime/commands/index-cmd.js +459 -0
  340. package/dist/runtime/commands/init.js +254 -0
  341. package/dist/runtime/commands/lsp.js +200 -38
  342. package/dist/runtime/commands/mcp.js +935 -0
  343. package/dist/runtime/commands/memory.js +582 -0
  344. package/dist/runtime/commands/model.js +237 -0
  345. package/dist/runtime/commands/onboarding.js +275 -0
  346. package/dist/runtime/commands/patch.js +12 -12
  347. package/dist/runtime/commands/permissions.js +112 -0
  348. package/dist/runtime/commands/plan.js +143 -0
  349. package/dist/runtime/commands/prd-check.js +285 -0
  350. package/dist/runtime/commands/privacy.js +17 -17
  351. package/dist/runtime/commands/recipe.js +325 -0
  352. package/dist/runtime/commands/redo-blob-store.js +92 -0
  353. package/dist/runtime/commands/redo.js +361 -0
  354. package/dist/runtime/commands/release-notes.js +229 -0
  355. package/dist/runtime/commands/repo-map.js +95 -0
  356. package/dist/runtime/commands/report.js +299 -0
  357. package/dist/runtime/commands/resume.js +118 -0
  358. package/dist/runtime/commands/review-consensus.js +68 -53
  359. package/dist/runtime/commands/rewind.js +333 -0
  360. package/dist/runtime/commands/roster.js +14 -14
  361. package/dist/runtime/commands/servers-cli.js +182 -0
  362. package/dist/runtime/commands/servers.js +236 -0
  363. package/dist/runtime/commands/sessions.js +163 -0
  364. package/dist/runtime/commands/share.js +316 -0
  365. package/dist/runtime/commands/skills.js +31 -31
  366. package/dist/runtime/commands/status.js +186 -0
  367. package/dist/runtime/commands/stickers.js +82 -0
  368. package/dist/runtime/commands/style.js +194 -0
  369. package/dist/runtime/commands/theme.js +196 -0
  370. package/dist/runtime/commands/undo.js +54 -22
  371. package/dist/runtime/commands/update.js +289 -0
  372. package/dist/runtime/commands/vim.js +140 -0
  373. package/dist/runtime/commands/worktree.js +8 -8
  374. package/dist/runtime/commands/worktrees.js +155 -0
  375. package/dist/runtime/deprecation-warning.js +69 -0
  376. package/dist/runtime/engine-exit-code.js +50 -0
  377. package/dist/runtime/headless-repl.js +195 -0
  378. package/dist/runtime/headless.js +548 -0
  379. package/dist/runtime/load-hooks-or-exit.js +71 -0
  380. package/dist/runtime/plan-decompose.js +22 -22
  381. package/dist/runtime/sigint-guard.js +272 -0
  382. package/dist/runtime/stream-renderer.js +195 -0
  383. package/dist/runtime/update-check.js +28 -28
  384. package/dist/runtime/version.js +65 -0
  385. package/dist/runtime/worktree-bootstrap.js +579 -0
  386. package/dist/skills/bundled/batch.js +617 -0
  387. package/dist/skills/bundled/index.js +45 -0
  388. package/dist/skills/bundled/loop.js +358 -0
  389. package/dist/skills/bundled/remember.js +383 -0
  390. package/dist/skills/bundled/simplify.js +289 -0
  391. package/dist/skills/bundled/skillify.js +373 -0
  392. package/dist/skills/bundled/stuck.js +558 -0
  393. package/dist/skills/bundled/verify.js +439 -0
  394. package/dist/testing/vcr.js +486 -0
  395. package/dist/tools/agent-tool.js +229 -0
  396. package/dist/tools/apply-patch.js +89 -28
  397. package/dist/tools/ask-user-question.js +337 -0
  398. package/dist/tools/ask-user.js +115 -0
  399. package/dist/tools/bash.js +811 -49
  400. package/dist/tools/brief.js +224 -0
  401. package/dist/tools/cron.js +433 -0
  402. package/dist/tools/enter-worktree.js +250 -0
  403. package/dist/tools/exit-worktree.js +147 -0
  404. package/dist/tools/file-tools.js +161 -44
  405. package/dist/tools/http-request.js +336 -0
  406. package/dist/tools/lsp-tools.js +377 -1
  407. package/dist/tools/mcp-tool.js +260 -0
  408. package/dist/tools/multi-edit.js +361 -0
  409. package/dist/tools/powershell.js +268 -0
  410. package/dist/tools/registry.js +120 -5
  411. package/dist/tools/server-tools.js +892 -0
  412. package/dist/tools/skill-tool.js +96 -0
  413. package/dist/tools/sleep.js +99 -0
  414. package/dist/tools/synthetic-output.js +133 -0
  415. package/dist/tools/tasks.js +208 -0
  416. package/dist/tools/todo-write.js +184 -0
  417. package/dist/tools/verify-plan-execution.js +295 -0
  418. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  419. package/dist/tools/web-fetch.js +195 -10
  420. package/dist/tools/web-search.js +458 -0
  421. package/dist/tui/agent-progress-card.js +111 -0
  422. package/dist/tui/agent-tree.js +22 -1
  423. package/dist/tui/ask-modal.js +14 -14
  424. package/dist/tui/ask-user-question-chips.js +315 -0
  425. package/dist/tui/ask-user-question-prompt.js +203 -0
  426. package/dist/tui/compact-banner.js +81 -0
  427. package/dist/tui/conversation-pane.js +85 -11
  428. package/dist/tui/cost-table.js +111 -0
  429. package/dist/tui/device-flow.js +2 -2
  430. package/dist/tui/doctor-table.js +46 -0
  431. package/dist/tui/feedback-prompt.js +156 -0
  432. package/dist/tui/input-box.js +247 -32
  433. package/dist/tui/login-picker.js +3 -3
  434. package/dist/tui/markdown-render.js +6 -6
  435. package/dist/tui/multi-file-diff-approval.js +375 -0
  436. package/dist/tui/onboarding-wizard.js +240 -0
  437. package/dist/tui/permissions-picker.js +86 -0
  438. package/dist/tui/render.js +36 -1
  439. package/dist/tui/repl-render.js +239 -25
  440. package/dist/tui/repl-splash-art.js +16 -16
  441. package/dist/tui/repl-splash-mascot.js +48 -24
  442. package/dist/tui/repl-splash.js +22 -22
  443. package/dist/tui/repl.js +125 -45
  444. package/dist/tui/slash-palette.js +6 -6
  445. package/dist/tui/splash.js +2 -2
  446. package/dist/tui/status-bar.js +109 -31
  447. package/dist/tui/status-table.js +7 -0
  448. package/dist/tui/stickers-art.js +136 -0
  449. package/dist/tui/style-table.js +28 -0
  450. package/dist/tui/theme-table.js +29 -0
  451. package/dist/tui/thinking-spinner.js +123 -0
  452. package/dist/tui/tool-stream-pane.js +53 -4
  453. package/dist/tui/update-banner.js +27 -2
  454. package/dist/tui/vim-input.js +267 -0
  455. package/dist/tui/welcome-banner.js +107 -0
  456. package/dist/tui/welcome-data.js +293 -0
  457. package/dist/tui/workspace-context.js +2 -2
  458. package/package.json +29 -6
  459. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  460. package/test/scenarios/compact-force.scenario.txt +12 -0
  461. package/test/scenarios/identity.scenario.txt +11 -0
  462. package/test/scenarios/persona-handoff.scenario.txt +12 -0
  463. package/test/scenarios/walkback.scenario.txt +12 -0
  464. package/dist/core/engine/compaction-hook.js +0 -154
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Pugi CLI ↔ admin-api version handshake — shared constants.
3
+ *
4
+ * The CLI declares its installed version on every outbound request to
5
+ * the admin-api so the server can enforce a minClientVersion floor and
6
+ * surface a soft-warn for stale-but-allowed installs. See ADR-225 and
7
+ * `apps/admin-api/src/runtime/version.contract.ts` for the server side.
8
+ *
9
+ * # Why the constants live here, not in `@pugi/sdk`
10
+ *
11
+ * The SDK ships to customers as part of the public npm package; bumping
12
+ * a header name there would force a coupled CLI ↔ SDK release. Keeping
13
+ * the constants in the CLI gives us room to evolve the handshake
14
+ * without coupling the SDK's release cadence to it.
15
+ */
16
+ /**
17
+ * Defensive semver sanitizer — single source of truth for the
18
+ * `0.0.0-unknown` fallback when a partially-published pnpm release
19
+ * leaks `workspace:*` into the version literal. `runtime/cli.ts`
20
+ * re-exports this under its `__test__` surface so the existing
21
+ * cli.ts test corpus keeps working with zero churn.
22
+ *
23
+ * Lives here (not in cli.ts) because the version handshake interceptor
24
+ * needs the same guarantee without pulling in the heavyweight cli.ts
25
+ * module graph during transport bootstrap.
26
+ */
27
+ export function sanitizeSemver(raw) {
28
+ if (typeof raw !== 'string')
29
+ return '0.0.0-unknown';
30
+ const trimmed = raw.trim();
31
+ if (!trimmed)
32
+ return '0.0.0-unknown';
33
+ const stripped = trimmed.replace(/^(workspace:|npm:|file:)/, '');
34
+ if (/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(stripped)) {
35
+ return stripped;
36
+ }
37
+ return '0.0.0-unknown';
38
+ }
39
+ /**
40
+ * Installed CLI version — single source of truth for the handshake
41
+ * header value. Mirrors the literal in `runtime/cli.ts` (intentional
42
+ * duplication because the cli.ts module pulls in Ink + half the CLI
43
+ * surface and the transport interceptor must remain side-effect-free
44
+ * during import). When bumping the CLI version BOTH literals must be
45
+ * updated; the release smoke-test (`pack:smoke`) verifies they agree.
46
+ */
47
+ export const PUGI_CLI_VERSION = sanitizeSemver('0.1.0-beta.101');
48
+ /**
49
+ * Outbound: the CLI's installed semver. Read at request time by
50
+ * `version-interceptor.ts` and injected on every `fetch` call.
51
+ */
52
+ export const PUGI_CLI_VERSION_HEADER = 'X-Pugi-Cli-Version';
53
+ /**
54
+ * Inbound: the server's recommendation for which CLI version operators
55
+ * should be on. Surfaces through the UpdateBanner alongside the npm
56
+ * registry poll (the higher of the two wins).
57
+ */
58
+ export const PUGI_CLI_UPGRADE_RECOMMENDED_HEADER = 'X-Pugi-Cli-Upgrade-Recommended';
59
+ /**
60
+ * Inbound: server's own admin-api version. Useful for diagnostics
61
+ * (`pugi doctor --json`) but no enforcement logic keys off it — server
62
+ * drift between admin-api releases is normal during rolling deploys.
63
+ */
64
+ export const PUGI_SERVER_VERSION_HEADER = 'X-Pugi-Server-Version';
65
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1,579 @@
1
+ /**
2
+ * `pugi --worktree` bootstrap - PUGI-487.
3
+ *
4
+ * User-facing parity surface for parallel-agent isolation patterns
5
+ * seen across competitor AI coding CLIs. The flag creates an isolated
6
+ * git worktree at `.claude/worktrees/<name>/` on a new branch
7
+ * `worktree-<name>` and starts the REPL inside it. Operators can run
8
+ * several Pugi sessions in parallel without their filesystems
9
+ * colliding.
10
+ *
11
+ * Distinct namespace from the existing dispatcher worktree manager:
12
+ *
13
+ * - This module owns `.claude/worktrees/<name>/` (USER-facing,
14
+ * short kebab names like `feat-x` or auto-generated `bright-fox`).
15
+ * - `core/worktree-manager/` owns `.pugi/worktrees/<agent-id>/`
16
+ * (DISPATCHER-facing, agent-id keyed).
17
+ *
18
+ * Public surface:
19
+ *
20
+ * - `bootstrapWorktree(options)` - validate inputs, run hooks,
21
+ * create the worktree, copy `.worktreeinclude` matches, return
22
+ * a typed envelope ready for the CLI to chdir + REPL.
23
+ * - `generateWhimsicalName()` - adjective + animal pair for the
24
+ * auto-named case (`pugi --worktree` with no name).
25
+ * - `runUserWorktreeCleanup(options)` - the daily sweep that removes
26
+ * user-facing worktrees > N days old with no uncommitted state.
27
+ *
28
+ * Brand voice: ASCII only, no emoji, no banned words.
29
+ */
30
+ import { spawnSync } from 'node:child_process';
31
+ import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync, } from 'node:fs';
32
+ import { dirname, isAbsolute, posix, resolve, sep } from 'node:path';
33
+ import { loadHooksConfig } from '../core/hooks/registry.js';
34
+ import { fireWorktreeHooks, } from '../core/hooks/worktree-events.js';
35
+ import { collectWorktreeIncludeFiles, loadWorktreeInclude, } from '../core/worktree/include-parser.js';
36
+ import { isTrustedWorkspace } from '../core/trust.js';
37
+ /** Canonical directory prefix for user-facing worktrees. */
38
+ export const USER_WORKTREES_PREFIX = '.claude/worktrees';
39
+ /**
40
+ * Branch prefix for user-facing worktree branches. The full name is
41
+ * `worktree-<name>` so the operator can quickly see which branches in
42
+ * `git branch` came from `pugi --worktree`.
43
+ */
44
+ export const USER_WORKTREE_BRANCH_PREFIX = 'worktree-';
45
+ /** Strict slug regex for the operator-supplied name. */
46
+ export const WORKTREE_NAME_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;
47
+ /** Strict regex for the PR-shorthand sugar. */
48
+ export const PR_SHORTHAND_PATTERN = /^#(\d{1,8})$/;
49
+ /**
50
+ * The main entry point invoked by `runtime/cli.ts` when `--worktree`
51
+ * is set on the bare invocation. Returns the typed envelope so the
52
+ * CLI layer can decide whether to chdir + mount the REPL or surface
53
+ * an error.
54
+ */
55
+ export async function bootstrapWorktree(options) {
56
+ const runGit = options.runGit ?? defaultGitRunner;
57
+ const repoRoot = resolve(options.repoRoot);
58
+ // Step 1: confirm we are actually in a git repo. The standard
59
+ // `rev-parse --git-dir` probe surfaces the most useful error when
60
+ // the operator runs `pugi --worktree` in `$HOME` by mistake.
61
+ const probe = runGit(['rev-parse', '--git-dir'], repoRoot);
62
+ if (probe.status !== 0) {
63
+ return failure({
64
+ name: '',
65
+ branch: '',
66
+ directory: '',
67
+ baseRef: options.baseRef ?? 'fresh',
68
+ resolvedBase: '',
69
+ reason: 'not_a_git_repo',
70
+ message: `not a git repository: ${repoRoot}`,
71
+ });
72
+ }
73
+ // Step 2: trust gate. The default-restricted policy (see
74
+ // `core/trust.ts`) refuses to load workspace-scoped hooks unless the
75
+ // operator has explicitly trusted the directory. Worktrees inherit
76
+ // their parent's trust state so a `pugi init`-trusted root carries
77
+ // through to every child created via this flag.
78
+ const trustGate = options.isTrusted ?? isTrustedWorkspace;
79
+ const skipTrust = options.skipTrustGate === true ||
80
+ process.env.PUGI_SKIP_WORKTREE_TRUST === '1';
81
+ if (!skipTrust) {
82
+ const trusted = await trustGate(repoRoot);
83
+ if (!trusted) {
84
+ return failure({
85
+ name: '',
86
+ branch: '',
87
+ directory: '',
88
+ baseRef: options.baseRef ?? 'fresh',
89
+ resolvedBase: '',
90
+ reason: 'untrusted_workspace',
91
+ message: `workspace ${repoRoot} is not trusted. Run \`pugi init\` or \`pugi config trust .\` first.`,
92
+ });
93
+ }
94
+ }
95
+ // Step 3: resolve the requested name. Three shapes:
96
+ // - PR shorthand `#1234`
97
+ // - operator-supplied slug
98
+ // - undefined => auto-generate
99
+ const nameResolution = resolveName(options.nameArg, options.generateName);
100
+ if (typeof nameResolution === 'string') {
101
+ return failure({
102
+ name: typeof options.nameArg === 'string' ? options.nameArg : '',
103
+ branch: '',
104
+ directory: '',
105
+ baseRef: options.baseRef ?? 'fresh',
106
+ resolvedBase: '',
107
+ reason: 'invalid_name',
108
+ message: nameResolution,
109
+ });
110
+ }
111
+ const { name, branch, prNumber } = nameResolution;
112
+ const baseRefMode = options.baseRef ?? 'fresh';
113
+ // Step 4: compute the target directory + resolved base ref.
114
+ const defaultDirectory = resolve(repoRoot, USER_WORKTREES_PREFIX, name);
115
+ if (existsSync(defaultDirectory)) {
116
+ return failure({
117
+ name,
118
+ branch,
119
+ directory: defaultDirectory,
120
+ baseRef: baseRefMode,
121
+ resolvedBase: '',
122
+ reason: 'directory_exists',
123
+ message: `worktree already exists at ${defaultDirectory}`,
124
+ });
125
+ }
126
+ const baseSha = resolveBaseSha(runGit, repoRoot, baseRefMode, prNumber);
127
+ if (typeof baseSha === 'string' && baseSha.startsWith('ERR:')) {
128
+ return failure({
129
+ name,
130
+ branch,
131
+ directory: defaultDirectory,
132
+ baseRef: baseRefMode,
133
+ resolvedBase: '',
134
+ reason: prNumber !== undefined ? 'pr_fetch_failed' : 'git_command_failed',
135
+ message: baseSha.slice('ERR:'.length),
136
+ });
137
+ }
138
+ // Step 5: fire the WorktreeCreate hook. Hooks may veto via non-zero
139
+ // exit (with `blocking: true`) or override the directory location.
140
+ const hooks = (options.loadHooks ?? loadHooksConfig)();
141
+ const createPayload = {
142
+ event: 'WorktreeCreate',
143
+ name,
144
+ defaultDirectory,
145
+ baseRef: typeof baseSha === 'string' ? baseSha : '',
146
+ repoRoot,
147
+ };
148
+ const createOutcome = fireWorktreeHooks(hooks, 'WorktreeCreate', createPayload);
149
+ if (createOutcome.anyBlocked) {
150
+ return failure({
151
+ name,
152
+ branch,
153
+ directory: defaultDirectory,
154
+ baseRef: baseRefMode,
155
+ resolvedBase: typeof baseSha === 'string' ? baseSha : '',
156
+ reason: 'hook_blocked',
157
+ message: `WorktreeCreate hook blocked the operation`,
158
+ });
159
+ }
160
+ // Override resolution: a hook stdout `{ "directory": "<abs-path>" }`
161
+ // wins ONLY when the path is inside the repo root. We refuse
162
+ // out-of-repo overrides defensively because the cleanup sweep would
163
+ // never reach them.
164
+ let directory = defaultDirectory;
165
+ if (createOutcome.directoryOverride) {
166
+ const override = resolve(repoRoot, createOutcome.directoryOverride);
167
+ if (override.startsWith(repoRoot + sep)) {
168
+ directory = override;
169
+ }
170
+ }
171
+ // Step 6: git worktree add. We resolve the base SHA above so the
172
+ // branch ref does not depend on a runtime-mutable `origin/HEAD` at
173
+ // creation time.
174
+ mkdirSync(dirname(directory), { recursive: true });
175
+ const addArgs = [
176
+ 'worktree',
177
+ 'add',
178
+ '-b',
179
+ branch,
180
+ '--',
181
+ directory,
182
+ typeof baseSha === 'string' ? baseSha : 'HEAD',
183
+ ];
184
+ const add = runGit(addArgs, repoRoot);
185
+ if (add.status !== 0) {
186
+ return failure({
187
+ name,
188
+ branch,
189
+ directory,
190
+ baseRef: baseRefMode,
191
+ resolvedBase: typeof baseSha === 'string' ? baseSha : '',
192
+ reason: 'git_command_failed',
193
+ message: (add.stderr || add.stdout || `exit=${add.status}`).trim(),
194
+ });
195
+ }
196
+ // Step 7: copy `.worktreeinclude` matches (e.g. .env). Tracked files
197
+ // are never duplicated - see the include-parser doc-block.
198
+ const includeResult = loadWorktreeInclude(repoRoot);
199
+ const collector = options.collectIncludes ?? collectWorktreeIncludeFiles;
200
+ const copyFile = options.copyFile ?? defaultCopyFile;
201
+ const copyOpts = {};
202
+ const matches = collector(repoRoot, includeResult.rules, copyOpts);
203
+ const copiedFiles = [];
204
+ for (const rel of matches) {
205
+ const src = resolve(repoRoot, rel);
206
+ const dest = resolve(directory, rel);
207
+ try {
208
+ mkdirSync(dirname(dest), { recursive: true });
209
+ copyFile(src, dest);
210
+ copiedFiles.push(rel);
211
+ }
212
+ catch {
213
+ // Best-effort copy. A single failure (e.g. permission denied on
214
+ // one entry) should not abort the bootstrap - surface via the
215
+ // envelope and let the operator decide.
216
+ }
217
+ }
218
+ return {
219
+ ok: true,
220
+ name,
221
+ branch,
222
+ directory,
223
+ baseRef: baseRefMode,
224
+ resolvedBase: typeof baseSha === 'string' ? baseSha : '',
225
+ copiedFiles,
226
+ };
227
+ }
228
+ /**
229
+ * Parse the operator-supplied name argument. Returns a `ResolvedName`
230
+ * on success or a human-readable error string on rejection. Exposed
231
+ * for spec coverage.
232
+ */
233
+ export function resolveName(nameArg, generator) {
234
+ if (nameArg === undefined || nameArg.trim().length === 0) {
235
+ const generated = (generator ?? generateWhimsicalName)();
236
+ if (!WORKTREE_NAME_PATTERN.test(generated)) {
237
+ return `auto-generated name "${generated}" failed validation`;
238
+ }
239
+ return {
240
+ name: generated,
241
+ branch: `${USER_WORKTREE_BRANCH_PREFIX}${generated}`,
242
+ };
243
+ }
244
+ const trimmed = nameArg.trim();
245
+ const prMatch = PR_SHORTHAND_PATTERN.exec(trimmed);
246
+ if (prMatch && typeof prMatch[1] === 'string') {
247
+ const n = Number(prMatch[1]);
248
+ if (!Number.isInteger(n) || n <= 0) {
249
+ return `invalid PR number: ${trimmed}`;
250
+ }
251
+ return {
252
+ name: `pr-${n}`,
253
+ branch: `${USER_WORKTREE_BRANCH_PREFIX}pr-${n}`,
254
+ prNumber: n,
255
+ };
256
+ }
257
+ if (!WORKTREE_NAME_PATTERN.test(trimmed)) {
258
+ return `name must match ${WORKTREE_NAME_PATTERN}`;
259
+ }
260
+ return {
261
+ name: trimmed,
262
+ branch: `${USER_WORKTREE_BRANCH_PREFIX}${trimmed}`,
263
+ };
264
+ }
265
+ /* ------------------------------------------------------------------ */
266
+ /* Base ref resolution */
267
+ /* ------------------------------------------------------------------ */
268
+ /**
269
+ * Resolve the SHA the new branch should point at. PR-shorthand wins
270
+ * regardless of `baseRef` mode (the operator's clear intent). For the
271
+ * `fresh` mode we resolve `origin/<default-branch>` and fall back to
272
+ * local HEAD when no remote is configured. The `head` mode always
273
+ * carries local HEAD.
274
+ *
275
+ * Returns the resolved SHA on success or an `ERR:<detail>` string on
276
+ * failure so the caller can decide whether to surface
277
+ * `git_command_failed` or `pr_fetch_failed`.
278
+ */
279
+ function resolveBaseSha(runGit, repoRoot, baseRef, prNumber) {
280
+ if (prNumber !== undefined) {
281
+ // `pull/N/head` is the GitHub convention. Fetch the PR head into
282
+ // the local refs cache before resolving so the worktree-add can
283
+ // find it.
284
+ const ref = `pull/${prNumber}/head`;
285
+ const fetch = runGit(['fetch', 'origin', ref], repoRoot);
286
+ if (fetch.status !== 0) {
287
+ return `ERR:failed to fetch ${ref} from origin: ${(fetch.stderr || fetch.stdout).trim()}`;
288
+ }
289
+ const sha = runGit(['rev-parse', 'FETCH_HEAD'], repoRoot);
290
+ if (sha.status !== 0) {
291
+ return `ERR:failed to resolve FETCH_HEAD after fetching ${ref}`;
292
+ }
293
+ return sha.stdout.trim();
294
+ }
295
+ if (baseRef === 'head') {
296
+ const sha = runGit(['rev-parse', 'HEAD'], repoRoot);
297
+ if (sha.status !== 0) {
298
+ return `ERR:failed to resolve HEAD: ${(sha.stderr || sha.stdout).trim()}`;
299
+ }
300
+ return sha.stdout.trim();
301
+ }
302
+ // baseRef === 'fresh': try origin/<default-branch>, fall back to HEAD.
303
+ const remoteBranch = detectOriginHead(runGit, repoRoot);
304
+ if (remoteBranch) {
305
+ const sha = runGit(['rev-parse', remoteBranch], repoRoot);
306
+ if (sha.status === 0) {
307
+ return sha.stdout.trim();
308
+ }
309
+ }
310
+ const headSha = runGit(['rev-parse', 'HEAD'], repoRoot);
311
+ if (headSha.status !== 0) {
312
+ return `ERR:failed to resolve any base ref (no origin/HEAD and no local HEAD)`;
313
+ }
314
+ return headSha.stdout.trim();
315
+ }
316
+ function detectOriginHead(runGit, repoRoot) {
317
+ const symRef = runGit(['symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD'], repoRoot);
318
+ if (symRef.status === 0) {
319
+ const value = symRef.stdout.trim();
320
+ if (value.length > 0)
321
+ return value;
322
+ }
323
+ // Common default fallbacks. Try `origin/main`, then `origin/master`.
324
+ for (const candidate of ['origin/main', 'origin/master']) {
325
+ const verify = runGit(['rev-parse', '--verify', candidate], repoRoot);
326
+ if (verify.status === 0)
327
+ return candidate;
328
+ }
329
+ return undefined;
330
+ }
331
+ /* ------------------------------------------------------------------ */
332
+ /* Whimsical name generator */
333
+ /* ------------------------------------------------------------------ */
334
+ const WHIMSICAL_ADJECTIVES = [
335
+ 'bright',
336
+ 'brave',
337
+ 'calm',
338
+ 'clever',
339
+ 'eager',
340
+ 'fancy',
341
+ 'gentle',
342
+ 'happy',
343
+ 'jolly',
344
+ 'keen',
345
+ 'lucky',
346
+ 'mighty',
347
+ 'noble',
348
+ 'quick',
349
+ 'royal',
350
+ 'silent',
351
+ 'swift',
352
+ 'tidy',
353
+ 'vivid',
354
+ 'witty',
355
+ ];
356
+ const WHIMSICAL_VERBS = [
357
+ 'running',
358
+ 'sleeping',
359
+ 'flying',
360
+ 'leaping',
361
+ 'roaring',
362
+ 'singing',
363
+ 'climbing',
364
+ 'gliding',
365
+ 'dancing',
366
+ 'soaring',
367
+ ];
368
+ const WHIMSICAL_ANIMALS = [
369
+ 'fox',
370
+ 'otter',
371
+ 'lynx',
372
+ 'puma',
373
+ 'eagle',
374
+ 'hawk',
375
+ 'whale',
376
+ 'dolphin',
377
+ 'badger',
378
+ 'panda',
379
+ 'tiger',
380
+ 'wolf',
381
+ 'bear',
382
+ 'koala',
383
+ 'raven',
384
+ 'falcon',
385
+ 'crow',
386
+ 'sparrow',
387
+ ];
388
+ /**
389
+ * Three-word adjective-verb-animal slug for the auto-name case.
390
+ * Uses `Math.random` because there is no security boundary at the
391
+ * naming layer - the WORKTREE_NAME_PATTERN regex below validates the
392
+ * shape after generation.
393
+ */
394
+ export function generateWhimsicalName() {
395
+ const adj = pick(WHIMSICAL_ADJECTIVES);
396
+ const verb = pick(WHIMSICAL_VERBS);
397
+ const animal = pick(WHIMSICAL_ANIMALS);
398
+ return `${adj}-${verb}-${animal}`;
399
+ }
400
+ function pick(items) {
401
+ if (items.length === 0) {
402
+ throw new Error('cannot pick from empty list');
403
+ }
404
+ const idx = Math.floor(Math.random() * items.length);
405
+ // Bounded by the modulo above so the result is always defined.
406
+ return items[idx];
407
+ }
408
+ /* ------------------------------------------------------------------ */
409
+ /* Helpers */
410
+ /* ------------------------------------------------------------------ */
411
+ function defaultGitRunner(argv, cwd) {
412
+ const result = spawnSync('git', [...argv], {
413
+ cwd,
414
+ encoding: 'utf8',
415
+ shell: false,
416
+ timeout: 60_000,
417
+ maxBuffer: 16 * 1024 * 1024,
418
+ });
419
+ return {
420
+ status: result.status,
421
+ stdout: typeof result.stdout === 'string' ? result.stdout : '',
422
+ stderr: typeof result.stderr === 'string' ? result.stderr : '',
423
+ };
424
+ }
425
+ function defaultCopyFile(src, dest) {
426
+ copyFileSync(src, dest);
427
+ }
428
+ function failure(args) {
429
+ return {
430
+ ok: false,
431
+ name: args.name,
432
+ branch: args.branch,
433
+ directory: args.directory,
434
+ baseRef: args.baseRef,
435
+ resolvedBase: args.resolvedBase,
436
+ copiedFiles: [],
437
+ reason: args.reason,
438
+ message: args.message,
439
+ };
440
+ }
441
+ /**
442
+ * The daily cleanup sweep. Walks `.claude/worktrees/`, computes each
443
+ * entry's age (mtime), and removes ones older than `periodDays` that
444
+ * have no uncommitted/untracked/unpushed state. Crashed-looking trees
445
+ * with local work are preserved by design.
446
+ */
447
+ export function runUserWorktreeCleanup(options) {
448
+ const repoRoot = resolve(options.repoRoot);
449
+ const now = options.now ?? Date.now;
450
+ const runGit = options.runGit ?? defaultGitRunner;
451
+ const root = resolve(repoRoot, USER_WORKTREES_PREFIX);
452
+ const lister = options.listWorktreeDir ?? defaultListWorktreeDir;
453
+ const remover = options.removeWorktree ?? defaultRemoveWorktree;
454
+ const hooks = (options.loadHooks ?? loadHooksConfig)();
455
+ if (!existsSync(root)) {
456
+ return { scanned: 0, removed: [], preserved: [] };
457
+ }
458
+ const entries = lister(root);
459
+ const removed = [];
460
+ const preserved = [];
461
+ const periodMs = options.periodDays * 24 * 60 * 60 * 1000;
462
+ for (const name of entries) {
463
+ if (!WORKTREE_NAME_PATTERN.test(name))
464
+ continue;
465
+ const dir = resolve(root, name);
466
+ let mtimeMs;
467
+ try {
468
+ mtimeMs = statSync(dir).mtimeMs;
469
+ }
470
+ catch {
471
+ continue;
472
+ }
473
+ const ageMs = now() - mtimeMs;
474
+ const ageDays = Math.floor(ageMs / (24 * 60 * 60 * 1000));
475
+ if (ageMs < periodMs) {
476
+ preserved.push({ name, directory: dir, ageDays, removed: false, preservedReason: 'too-young' });
477
+ continue;
478
+ }
479
+ if (hasUncommittedChanges(runGit, dir)) {
480
+ preserved.push({
481
+ name,
482
+ directory: dir,
483
+ ageDays,
484
+ removed: false,
485
+ preservedReason: 'has-uncommitted-changes',
486
+ });
487
+ continue;
488
+ }
489
+ if (hasUntrackedFiles(runGit, dir)) {
490
+ preserved.push({
491
+ name,
492
+ directory: dir,
493
+ ageDays,
494
+ removed: false,
495
+ preservedReason: 'has-untracked-files',
496
+ });
497
+ continue;
498
+ }
499
+ if (hasUnpushedCommits(runGit, dir)) {
500
+ preserved.push({
501
+ name,
502
+ directory: dir,
503
+ ageDays,
504
+ removed: false,
505
+ preservedReason: 'has-unpushed-commits',
506
+ });
507
+ continue;
508
+ }
509
+ // Fire WorktreeRemove hook before pulling the trigger.
510
+ const removePayload = {
511
+ event: 'WorktreeRemove',
512
+ name,
513
+ directory: dir,
514
+ reason: 'auto-cleanup',
515
+ repoRoot,
516
+ };
517
+ const outcome = fireWorktreeHooks(hooks, 'WorktreeRemove', removePayload);
518
+ if (outcome.anyBlocked) {
519
+ preserved.push({
520
+ name,
521
+ directory: dir,
522
+ ageDays,
523
+ removed: false,
524
+ preservedReason: 'hook-blocked',
525
+ });
526
+ continue;
527
+ }
528
+ if (options.dryRun) {
529
+ removed.push({ name, directory: dir, ageDays, removed: false });
530
+ continue;
531
+ }
532
+ const ok = remover(dir, runGit, repoRoot);
533
+ removed.push({ name, directory: dir, ageDays, removed: ok });
534
+ }
535
+ return {
536
+ scanned: entries.length,
537
+ removed,
538
+ preserved,
539
+ };
540
+ }
541
+ function defaultListWorktreeDir(dir) {
542
+ try {
543
+ return readdirSync(dir);
544
+ }
545
+ catch {
546
+ return [];
547
+ }
548
+ }
549
+ function defaultRemoveWorktree(path, runGit, repoRoot) {
550
+ const result = runGit(['worktree', 'remove', '--force', path], repoRoot);
551
+ return result.status === 0;
552
+ }
553
+ function hasUncommittedChanges(runGit, dir) {
554
+ // `git diff --quiet` only inspects the working tree against the
555
+ // index, so a `git add`-staged but uncommitted hunk passes that
556
+ // check. Catch the staged case explicitly via `--cached` so the
557
+ // cleanup sweep never drops a worktree with staged work.
558
+ const unstaged = runGit(['diff', '--quiet'], dir);
559
+ if (unstaged.status !== 0)
560
+ return true;
561
+ const staged = runGit(['diff', '--cached', '--quiet'], dir);
562
+ return staged.status !== 0;
563
+ }
564
+ function hasUntrackedFiles(runGit, dir) {
565
+ const r = runGit(['ls-files', '--others', '--exclude-standard'], dir);
566
+ return r.status === 0 && r.stdout.trim().length > 0;
567
+ }
568
+ function hasUnpushedCommits(runGit, dir) {
569
+ const r = runGit(['log', '--branches', '--not', '--remotes', '--oneline'], dir);
570
+ return r.status === 0 && r.stdout.trim().length > 0;
571
+ }
572
+ /** Re-export for symmetry with the dispatcher manager. */
573
+ export function userWorktreePathFor(repoRoot, name) {
574
+ // Posix-join the prefix so the slash separators stay correct on
575
+ // every host, then resolve to absolute on the local FS.
576
+ const rel = posix.join(USER_WORKTREES_PREFIX, name);
577
+ return isAbsolute(rel) ? rel : resolve(repoRoot, rel);
578
+ }
579
+ //# sourceMappingURL=worktree-bootstrap.js.map