@pugi/cli 0.1.0-beta.8 → 0.1.0-beta.88

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 (405) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/THIRD_PARTY_NOTICES.md +40 -0
  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/smoke.js +133 -0
  11. package/dist/core/agent-progress/cleanup.js +134 -0
  12. package/dist/core/agent-progress/schema.js +144 -0
  13. package/dist/core/agent-progress/writer.js +101 -0
  14. package/dist/core/agents/adaptive-router.js +330 -0
  15. package/dist/core/agents/query-decomposer.js +297 -0
  16. package/dist/core/agents/registry.js +3 -3
  17. package/dist/core/approvals/shortcut-resolver.js +98 -0
  18. package/dist/core/artifact-chain/dispatcher.js +148 -0
  19. package/dist/core/artifact-chain/exporter.js +164 -0
  20. package/dist/core/artifact-chain/state.js +243 -0
  21. package/dist/core/artifact-chain/steps.js +169 -0
  22. package/dist/core/ask-user/question.js +92 -0
  23. package/dist/core/audit/audit-trail.js +275 -0
  24. package/dist/core/auth/ensure-authenticated.js +129 -0
  25. package/dist/core/auth/env-provider.js +238 -0
  26. package/dist/core/auto-open-browser.js +4 -4
  27. package/dist/core/auto-update/channels.js +122 -0
  28. package/dist/core/auto-update/checker.js +241 -0
  29. package/dist/core/auto-update/state.js +235 -0
  30. package/dist/core/bare-mode/index.js +107 -0
  31. package/dist/core/bash/redirect.js +281 -0
  32. package/dist/core/bash-classifier.js +436 -40
  33. package/dist/core/checkpoint/resumer.js +149 -0
  34. package/dist/core/checkpoint/rewinder.js +291 -0
  35. package/dist/core/checkpoints/shadow-git.js +670 -0
  36. package/dist/core/citations/parser.js +109 -0
  37. package/dist/core/classifier/yolo-classifier.js +88 -0
  38. package/dist/core/codegraph/decision-store.js +248 -0
  39. package/dist/core/codegraph/detect-repo.js +459 -0
  40. package/dist/core/codegraph/install.js +134 -0
  41. package/dist/core/codegraph/offer-hook.js +220 -0
  42. package/dist/core/compact/auto-trigger.js +96 -0
  43. package/dist/core/compact/buffer-rewriter.js +115 -0
  44. package/dist/core/compact/summarizer.js +208 -0
  45. package/dist/core/compact/token-counter.js +108 -0
  46. package/dist/core/consensus/anvil-fanout.js +25 -25
  47. package/dist/core/consensus/diff-capture.js +121 -12
  48. package/dist/core/consensus/rubric.js +21 -21
  49. package/dist/core/context/builder.js +6 -6
  50. package/dist/core/context/compaction-events.js +8 -8
  51. package/dist/core/context/compaction.js +31 -31
  52. package/dist/core/context/index.js +15 -8
  53. package/dist/core/context/invariants.js +51 -51
  54. package/dist/core/context/markdown-loader.js +28 -10
  55. package/dist/core/context/markdown-traverse.js +255 -0
  56. package/dist/core/context/pugiignore.js +41 -41
  57. package/dist/core/context/repo-skeleton.js +37 -37
  58. package/dist/core/context/tool-eviction.js +55 -0
  59. package/dist/core/context/watcher.js +32 -32
  60. package/dist/core/context/working-set.js +23 -23
  61. package/dist/core/coordinator/agent-tools.js +77 -0
  62. package/dist/core/coordinator/agent-toolset.js +65 -0
  63. package/dist/core/coordinator/fsm.js +73 -0
  64. package/dist/core/coordinator/mode-fsm.js +70 -0
  65. package/dist/core/cost/rate-card.js +129 -0
  66. package/dist/core/cost/tracker.js +221 -0
  67. package/dist/core/credentials.js +12 -12
  68. package/dist/core/cron/scheduler.js +138 -0
  69. package/dist/core/denial-tracking/index.js +8 -0
  70. package/dist/core/denial-tracking/state.js +264 -0
  71. package/dist/core/diagnostics/probe-runner.js +93 -0
  72. package/dist/core/diagnostics/probes/api.js +46 -0
  73. package/dist/core/diagnostics/probes/auth.js +93 -0
  74. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  75. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  76. package/dist/core/diagnostics/probes/config.js +72 -0
  77. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  78. package/dist/core/diagnostics/probes/disk.js +81 -0
  79. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  80. package/dist/core/diagnostics/probes/git.js +65 -0
  81. package/dist/core/diagnostics/probes/hooks.js +118 -0
  82. package/dist/core/diagnostics/probes/mcp.js +75 -0
  83. package/dist/core/diagnostics/probes/node.js +59 -0
  84. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  85. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  86. package/dist/core/diagnostics/probes/sandbox.js +40 -0
  87. package/dist/core/diagnostics/probes/session.js +74 -0
  88. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  89. package/dist/core/diagnostics/probes/workspace.js +63 -0
  90. package/dist/core/diagnostics/types.js +70 -0
  91. package/dist/core/dispatch/cache-cleanup.js +197 -0
  92. package/dist/core/dispatch/cache-handoff.js +295 -0
  93. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  94. package/dist/core/edits/dispatch.js +293 -7
  95. package/dist/core/edits/format-matrix.js +26 -0
  96. package/dist/core/edits/fuzzy-ladder.js +650 -0
  97. package/dist/core/edits/index.js +3 -1
  98. package/dist/core/edits/journal.js +199 -0
  99. package/dist/core/edits/layer-a-apply.js +15 -15
  100. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  101. package/dist/core/edits/layer-b-apply.js +9 -9
  102. package/dist/core/edits/layer-c-apply.js +6 -6
  103. package/dist/core/edits/layer-d-ast.js +557 -14
  104. package/dist/core/edits/marker-parser.js +12 -12
  105. package/dist/core/edits/security-gate.js +27 -27
  106. package/dist/core/edits/verify-hook.js +273 -0
  107. package/dist/core/edits/worktree.js +322 -0
  108. package/dist/core/engine/anvil-client.js +151 -26
  109. package/dist/core/engine/auto-compact.js +179 -0
  110. package/dist/core/engine/budgets.js +186 -0
  111. package/dist/core/engine/context-prefix.js +155 -0
  112. package/dist/core/engine/index.js +1 -1
  113. package/dist/core/engine/intensity.js +158 -0
  114. package/dist/core/engine/intent.js +260 -0
  115. package/dist/core/engine/native-pugi.js +1295 -227
  116. package/dist/core/engine/prompts.js +134 -16
  117. package/dist/core/engine/strip-internal-fields.js +124 -0
  118. package/dist/core/engine/tool-bridge.js +1295 -59
  119. package/dist/core/evaluation/golden-dataset.js +293 -0
  120. package/dist/core/feedback/queue.js +177 -0
  121. package/dist/core/feedback/submitter.js +145 -0
  122. package/dist/core/file-cache.js +113 -1
  123. package/dist/core/flatten/flatten-repo.js +439 -0
  124. package/dist/core/format/osc8-link.js +28 -0
  125. package/dist/core/hook-chains.js +392 -0
  126. package/dist/core/hooks/citation-verify-hook.js +138 -0
  127. package/dist/core/hooks/citation-verify.js +112 -0
  128. package/dist/core/hooks/events.js +44 -0
  129. package/dist/core/hooks/index.js +15 -0
  130. package/dist/core/hooks/registry.js +213 -0
  131. package/dist/core/hooks/runner.js +236 -0
  132. package/dist/core/hooks/v2/event-emitter.js +115 -0
  133. package/dist/core/hooks/v2/executor.js +282 -0
  134. package/dist/core/hooks/v2/index.js +25 -0
  135. package/dist/core/hooks/v2/lifecycle.js +104 -0
  136. package/dist/core/hooks/v2/loader.js +216 -0
  137. package/dist/core/hooks/v2/matcher.js +125 -0
  138. package/dist/core/hooks/v2/trust.js +143 -0
  139. package/dist/core/hooks/v2/types.js +86 -0
  140. package/dist/core/image/renderer.js +71 -0
  141. package/dist/core/init/detector.js +582 -0
  142. package/dist/core/init/template-renderer.js +242 -0
  143. package/dist/core/jobs/registry.js +18 -18
  144. package/dist/core/ledger/results-tsv.js +142 -0
  145. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  146. package/dist/core/lsp/cache.js +105 -0
  147. package/dist/core/lsp/client.js +776 -0
  148. package/dist/core/lsp/language-detect.js +66 -0
  149. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  150. package/dist/core/lsp/symbol-tools.js +372 -0
  151. package/dist/core/mcp/client.js +97 -28
  152. package/dist/core/mcp/http-server.js +553 -0
  153. package/dist/core/mcp/orchestrator-tools.js +662 -0
  154. package/dist/core/mcp/permission.js +190 -0
  155. package/dist/core/mcp/registry.js +39 -17
  156. package/dist/core/mcp/server-tools.js +219 -0
  157. package/dist/core/mcp/server.js +397 -0
  158. package/dist/core/mcp/trust.js +10 -10
  159. package/dist/core/memory/dual-write.js +416 -0
  160. package/dist/core/memory/passive-extract.js +130 -0
  161. package/dist/core/memory/phase1-kinds.js +20 -0
  162. package/dist/core/memory/secret-scanner.js +304 -0
  163. package/dist/core/memory-sync/queue.js +170 -0
  164. package/dist/core/metrics/extract.js +113 -0
  165. package/dist/core/modes/roo-modes.js +68 -0
  166. package/dist/core/onboarding/ensure-initialized.js +133 -0
  167. package/dist/core/onboarding/marker.js +111 -0
  168. package/dist/core/onboarding/telemetry-state.js +108 -0
  169. package/dist/core/output-style/presets.js +176 -0
  170. package/dist/core/output-style/state.js +185 -0
  171. package/dist/core/path-security.js +287 -5
  172. package/dist/core/permission.js +82 -22
  173. package/dist/core/permissions/auto-classifier.js +124 -0
  174. package/dist/core/permissions/bash-parser.js +371 -0
  175. package/dist/core/permissions/circuit-breaker.js +83 -0
  176. package/dist/core/permissions/constrained-edit.js +91 -0
  177. package/dist/core/permissions/gate.js +278 -0
  178. package/dist/core/permissions/index.js +20 -0
  179. package/dist/core/permissions/mode.js +174 -0
  180. package/dist/core/permissions/network-egress.js +137 -0
  181. package/dist/core/permissions/state.js +241 -0
  182. package/dist/core/permissions/tool-class.js +93 -0
  183. package/dist/core/plan-mode/ui-state.js +51 -0
  184. package/dist/core/plans/plan-artifact.js +721 -0
  185. package/dist/core/policy-limits/etag-store.js +122 -0
  186. package/dist/core/prd-check/parser.js +215 -0
  187. package/dist/core/prd-check/reporter.js +127 -0
  188. package/dist/core/prd-check/session-review.js +557 -0
  189. package/dist/core/prd-check/verifiers.js +223 -0
  190. package/dist/core/prompt-cache/client-cache.js +99 -0
  191. package/dist/core/prompts/assembly.js +29 -0
  192. package/dist/core/prompts/registry.js +364 -0
  193. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  194. package/dist/core/pugi-md/context-injector.js +76 -0
  195. package/dist/core/pugi-md/walk-up.js +207 -0
  196. package/dist/core/python/uv-installer.js +270 -0
  197. package/dist/core/python/uv-resolver.js +83 -0
  198. package/dist/core/rate-limit/narrator.js +146 -0
  199. package/dist/core/recipes/cli-types.js +20 -0
  200. package/dist/core/recipes/loader.js +103 -0
  201. package/dist/core/recipes/runner.js +345 -0
  202. package/dist/core/recipes/schema.js +587 -0
  203. package/dist/core/release-notes/parser.js +241 -0
  204. package/dist/core/release-notes/state.js +116 -0
  205. package/dist/core/repl/ask.js +37 -37
  206. package/dist/core/repl/cancellation.js +26 -26
  207. package/dist/core/repl/cap-warning.js +4 -4
  208. package/dist/core/repl/clipboard-read.js +11 -11
  209. package/dist/core/repl/dispatch-fsm.js +12 -12
  210. package/dist/core/repl/history-search.js +15 -15
  211. package/dist/core/repl/history.js +28 -18
  212. package/dist/core/repl/kill-ring.js +5 -5
  213. package/dist/core/repl/model-pricing.js +135 -0
  214. package/dist/core/repl/privacy-banner.js +22 -22
  215. package/dist/core/repl/session.js +2157 -214
  216. package/dist/core/repl/slash-commands.js +533 -40
  217. package/dist/core/repl/store/index.js +1 -1
  218. package/dist/core/repl/store/jsonl-log.js +22 -22
  219. package/dist/core/repl/store/lockfile.js +10 -10
  220. package/dist/core/repl/store/session-store.js +136 -107
  221. package/dist/core/repl/store/types.js +15 -15
  222. package/dist/core/repl/store/uuid-v7.js +12 -12
  223. package/dist/core/repl/workspace-context.js +43 -21
  224. package/dist/core/repo-map/build.js +125 -0
  225. package/dist/core/repo-map/cache.js +185 -0
  226. package/dist/core/repo-map/extractor.js +254 -0
  227. package/dist/core/repo-map/formatter.js +145 -0
  228. package/dist/core/repo-map/page-rank.js +105 -0
  229. package/dist/core/repo-map/scanner.js +211 -0
  230. package/dist/core/retry-budget/budget.js +284 -0
  231. package/dist/core/retry-budget/index.js +5 -0
  232. package/dist/core/retry-budget/retry-cap.js +74 -0
  233. package/dist/core/routing/lead-worker.js +43 -0
  234. package/dist/core/routing/pre-flight-estimator.js +108 -0
  235. package/dist/core/runs/run-tree.js +103 -0
  236. package/dist/core/security/injection-scanner.js +367 -0
  237. package/dist/core/security/output-filter.js +418 -0
  238. package/dist/core/session/env-file.js +105 -0
  239. package/dist/core/session/section-budgets.js +140 -0
  240. package/dist/core/session.js +92 -0
  241. package/dist/core/settings.js +298 -5
  242. package/dist/core/share/formatter.js +271 -0
  243. package/dist/core/share/redactor.js +221 -0
  244. package/dist/core/share/uploader.js +267 -0
  245. package/dist/core/skills/defaults.js +457 -0
  246. package/dist/core/skills/loader.js +22 -22
  247. package/dist/core/skills/sources.js +27 -27
  248. package/dist/core/smoke/headless-driver.js +174 -0
  249. package/dist/core/smoke/orchestrator.js +194 -0
  250. package/dist/core/smoke/runner.js +238 -0
  251. package/dist/core/smoke/scenario-parser.js +316 -0
  252. package/dist/core/statusline.js +99 -0
  253. package/dist/core/subagents/dispatcher-real.js +600 -0
  254. package/dist/core/subagents/dispatcher.js +132 -43
  255. package/dist/core/subagents/index.js +19 -6
  256. package/dist/core/subagents/isolation-matrix.js +213 -0
  257. package/dist/core/subagents/spawn.js +19 -4
  258. package/dist/core/telemetry/emitter.js +229 -0
  259. package/dist/core/telemetry/queue.js +251 -0
  260. package/dist/core/theme/context.js +91 -0
  261. package/dist/core/theme/presets.js +228 -0
  262. package/dist/core/theme/state.js +181 -0
  263. package/dist/core/todos/invariant.js +10 -0
  264. package/dist/core/todos/state.js +177 -0
  265. package/dist/core/tool-schema/compressor.js +89 -0
  266. package/dist/core/transport/version-interceptor.js +166 -0
  267. package/dist/core/trust.js +2 -2
  268. package/dist/core/tui/thinking-block.js +64 -0
  269. package/dist/core/vim/keymap.js +288 -0
  270. package/dist/core/vim/state.js +92 -0
  271. package/dist/core/watch-markers/marker-watcher.js +133 -0
  272. package/dist/core/worktree-manager/cleanup.js +123 -0
  273. package/dist/core/worktree-manager/manager.js +303 -0
  274. package/dist/index.js +36 -0
  275. package/dist/runtime/bootstrap.js +190 -0
  276. package/dist/runtime/cli.js +4203 -493
  277. package/dist/runtime/commands/agents.js +30 -30
  278. package/dist/runtime/commands/budget.js +5 -5
  279. package/dist/runtime/commands/cancel.js +231 -0
  280. package/dist/runtime/commands/chain.js +489 -0
  281. package/dist/runtime/commands/codegraph-status.js +227 -0
  282. package/dist/runtime/commands/compact.js +297 -0
  283. package/dist/runtime/commands/config.js +73 -39
  284. package/dist/runtime/commands/cost.js +199 -0
  285. package/dist/runtime/commands/delegate.js +244 -13
  286. package/dist/runtime/commands/dispatch.js +126 -0
  287. package/dist/runtime/commands/doctor.js +579 -0
  288. package/dist/runtime/commands/feedback.js +184 -0
  289. package/dist/runtime/commands/hooks.js +184 -0
  290. package/dist/runtime/commands/init.js +254 -0
  291. package/dist/runtime/commands/lsp.js +368 -0
  292. package/dist/runtime/commands/mcp.js +879 -0
  293. package/dist/runtime/commands/memory.js +582 -0
  294. package/dist/runtime/commands/model.js +237 -0
  295. package/dist/runtime/commands/onboarding.js +275 -0
  296. package/dist/runtime/commands/patch.js +128 -0
  297. package/dist/runtime/commands/permissions.js +112 -0
  298. package/dist/runtime/commands/plan.js +143 -0
  299. package/dist/runtime/commands/prd-check.js +285 -0
  300. package/dist/runtime/commands/privacy.js +17 -17
  301. package/dist/runtime/commands/recipe.js +325 -0
  302. package/dist/runtime/commands/redo-blob-store.js +92 -0
  303. package/dist/runtime/commands/redo.js +361 -0
  304. package/dist/runtime/commands/release-notes.js +229 -0
  305. package/dist/runtime/commands/repo-map.js +95 -0
  306. package/dist/runtime/commands/report.js +299 -0
  307. package/dist/runtime/commands/resume.js +118 -0
  308. package/dist/runtime/commands/review-consensus.js +68 -53
  309. package/dist/runtime/commands/rewind.js +333 -0
  310. package/dist/runtime/commands/roster.js +14 -14
  311. package/dist/runtime/commands/sessions.js +163 -0
  312. package/dist/runtime/commands/share.js +316 -0
  313. package/dist/runtime/commands/skills.js +31 -31
  314. package/dist/runtime/commands/status.js +186 -0
  315. package/dist/runtime/commands/stickers.js +82 -0
  316. package/dist/runtime/commands/style.js +194 -0
  317. package/dist/runtime/commands/theme.js +196 -0
  318. package/dist/runtime/commands/undo.js +54 -22
  319. package/dist/runtime/commands/update.js +289 -0
  320. package/dist/runtime/commands/vim.js +140 -0
  321. package/dist/runtime/commands/worktree.js +177 -0
  322. package/dist/runtime/commands/worktrees.js +155 -0
  323. package/dist/runtime/headless-repl.js +195 -0
  324. package/dist/runtime/headless.js +543 -0
  325. package/dist/runtime/load-hooks-or-exit.js +71 -0
  326. package/dist/runtime/plan-decompose.js +531 -0
  327. package/dist/runtime/sigint-guard.js +272 -0
  328. package/dist/runtime/update-check.js +28 -28
  329. package/dist/runtime/version.js +65 -0
  330. package/dist/skills/bundled/batch.js +617 -0
  331. package/dist/skills/bundled/index.js +45 -0
  332. package/dist/skills/bundled/loop.js +358 -0
  333. package/dist/skills/bundled/remember.js +383 -0
  334. package/dist/skills/bundled/simplify.js +289 -0
  335. package/dist/skills/bundled/skillify.js +373 -0
  336. package/dist/skills/bundled/stuck.js +558 -0
  337. package/dist/skills/bundled/verify.js +439 -0
  338. package/dist/testing/vcr.js +486 -0
  339. package/dist/tools/agent-tool.js +229 -0
  340. package/dist/tools/apply-patch.js +556 -0
  341. package/dist/tools/ask-user-question.js +288 -0
  342. package/dist/tools/ask-user.js +115 -0
  343. package/dist/tools/bash.js +624 -46
  344. package/dist/tools/brief.js +224 -0
  345. package/dist/tools/enter-worktree.js +250 -0
  346. package/dist/tools/exit-worktree.js +147 -0
  347. package/dist/tools/file-tools.js +161 -44
  348. package/dist/tools/lsp-tools.js +189 -0
  349. package/dist/tools/mcp-tool.js +260 -0
  350. package/dist/tools/multi-edit.js +361 -0
  351. package/dist/tools/powershell.js +268 -0
  352. package/dist/tools/registry.js +85 -0
  353. package/dist/tools/skill-tool.js +96 -0
  354. package/dist/tools/sleep.js +99 -0
  355. package/dist/tools/synthetic-output.js +133 -0
  356. package/dist/tools/tasks.js +208 -0
  357. package/dist/tools/todo-write.js +184 -0
  358. package/dist/tools/verify-plan-execution.js +295 -0
  359. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  360. package/dist/tools/web-fetch.js +195 -10
  361. package/dist/tools/web-search.js +458 -0
  362. package/dist/tui/agent-progress-card.js +111 -0
  363. package/dist/tui/agent-tree.js +11 -1
  364. package/dist/tui/ask-modal.js +14 -14
  365. package/dist/tui/ask-user-question-chips.js +257 -0
  366. package/dist/tui/ask-user-question-prompt.js +203 -0
  367. package/dist/tui/compact-banner.js +81 -0
  368. package/dist/tui/conversation-pane.js +85 -11
  369. package/dist/tui/cost-table.js +111 -0
  370. package/dist/tui/device-flow.js +2 -2
  371. package/dist/tui/doctor-table.js +46 -0
  372. package/dist/tui/feedback-prompt.js +156 -0
  373. package/dist/tui/input-box.js +247 -32
  374. package/dist/tui/login-picker.js +3 -3
  375. package/dist/tui/markdown-render.js +6 -6
  376. package/dist/tui/onboarding-wizard.js +240 -0
  377. package/dist/tui/permissions-picker.js +86 -0
  378. package/dist/tui/render.js +35 -0
  379. package/dist/tui/repl-render.js +332 -54
  380. package/dist/tui/repl-splash-art.js +16 -16
  381. package/dist/tui/repl-splash-mascot.js +48 -24
  382. package/dist/tui/repl-splash.js +22 -22
  383. package/dist/tui/repl.js +124 -44
  384. package/dist/tui/slash-palette.js +6 -6
  385. package/dist/tui/splash.js +2 -2
  386. package/dist/tui/status-bar.js +109 -31
  387. package/dist/tui/status-table.js +7 -0
  388. package/dist/tui/stickers-art.js +136 -0
  389. package/dist/tui/style-table.js +28 -0
  390. package/dist/tui/theme-table.js +29 -0
  391. package/dist/tui/thinking-spinner.js +123 -0
  392. package/dist/tui/tool-stream-pane.js +53 -4
  393. package/dist/tui/update-banner.js +27 -2
  394. package/dist/tui/vim-input.js +267 -0
  395. package/dist/tui/welcome-banner.js +107 -0
  396. package/dist/tui/welcome-data.js +293 -0
  397. package/dist/tui/workspace-context.js +2 -2
  398. package/docs/examples/codegraph.mcp.json +10 -0
  399. package/package.json +25 -7
  400. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  401. package/test/scenarios/compact-force.scenario.txt +11 -0
  402. package/test/scenarios/identity.scenario.txt +11 -0
  403. package/test/scenarios/persona-handoff.scenario.txt +11 -0
  404. package/test/scenarios/walkback.scenario.txt +12 -0
  405. package/dist/core/engine/compaction-hook.js +0 -154
@@ -0,0 +1,582 @@
1
+ /**
2
+ * `pugi init` codebase scanner (backlog #82).
3
+ *
4
+ * Zero-dep, depth-bounded probe of a workspace that returns a structured
5
+ * `DetectionResult` consumed by `template-renderer.ts` to materialise a
6
+ * project-aware `PUGI.md`. Detection runs OFFLINE — no fetches, no
7
+ * spawned processes other than the optional `git log` probe (and even
8
+ * that is injectable for tests).
9
+ *
10
+ * Detection rubric (the 7 surfaces):
11
+ *
12
+ * 1. Stack — primary language(s) inferred from manifest files.
13
+ * package.json → Node, pyproject.toml/setup.py/requirements.txt
14
+ * → Python, Cargo.toml → Rust, go.mod → Go, Gemfile → Ruby,
15
+ * composer.json → PHP, pom.xml/build.gradle → Java.
16
+ *
17
+ * 2. Frameworks — derived from package.json deps + config files.
18
+ * Next.js (next.config.*), Vite, NestJS (@nestjs/core), Express,
19
+ * Fastify, Hono, SvelteKit, Nuxt, Remix, React, Vue, Angular,
20
+ * Prisma, Drizzle, tRPC, Zod, FastAPI, Django, Flask, Axum,
21
+ * Actix-web, Gin, Echo, Rails.
22
+ *
23
+ * 3. Test frameworks — Jest, Vitest, Mocha, Playwright, Cypress,
24
+ * node:test, pytest, cargo test (implicit when Rust detected),
25
+ * go test (implicit when Go detected).
26
+ *
27
+ * 4. Commit conventions — sampled from `git log --pretty=format:%s -50`.
28
+ * Conventional commits (`feat:`, `fix(scope):`...), gitmoji
29
+ * (`:sparkles:`), freeform, or unknown when log is empty.
30
+ *
31
+ * 5. Monorepo — pnpm-workspace.yaml / lerna.json / turbo.json /
32
+ * nx.json / yarn workspaces in package.json.
33
+ *
34
+ * 6. Existing AI configs — CLAUDE.md (with content excerpt for
35
+ * template seeding), PUGI.md (read content), .cursorrules,
36
+ * .windsurfrules, .aiderignore.
37
+ *
38
+ * 7. Project layout — top-level dirs the operator should reference.
39
+ *
40
+ * Hard constraints:
41
+ *
42
+ * - Walk depth capped at 4 (root + 3 levels).
43
+ * - Max 3000 nodes visited (giant repos short-circuit gracefully).
44
+ * - Skip dirs: node_modules, dist, .git, target, __pycache__, vendor,
45
+ * .next, coverage, .turbo, .nx, build, out, .cache, tmp, venv,
46
+ * .venv, .vscode, .idea, Pods.
47
+ * - Every fs call wrapped in try/catch; missing manifest = field
48
+ * omitted, never a thrown error.
49
+ *
50
+ * Reuses `languageForExtension`, `topLanguages`, `detectPackageManager`
51
+ * from `../context/repo-skeleton.js` for histogram + package-manager
52
+ * detection so we keep one source-of-truth for those mappings.
53
+ */
54
+ import { execFileSync } from 'node:child_process';
55
+ import { existsSync, readFileSync, readdirSync, statSync, } from 'node:fs';
56
+ import { basename, extname, join } from 'node:path';
57
+ import { detectPackageManager, languageForExtension, topLanguages, } from '../context/repo-skeleton.js';
58
+ /** Hard cap on walker depth. Root counts as depth 0. */
59
+ export const MAX_DETECTION_DEPTH = 4;
60
+ /** Hard cap on nodes visited before we short-circuit the walk. */
61
+ export const MAX_DETECTION_NODES = 3000;
62
+ /** Dirs we never descend into (heavy, generated, IDE state). */
63
+ export const SKIP_DIRS = new Set([
64
+ 'node_modules',
65
+ 'dist',
66
+ '.git',
67
+ 'target',
68
+ '__pycache__',
69
+ 'vendor',
70
+ '.next',
71
+ 'coverage',
72
+ '.turbo',
73
+ '.nx',
74
+ 'build',
75
+ 'out',
76
+ '.cache',
77
+ 'tmp',
78
+ 'venv',
79
+ '.venv',
80
+ '.vscode',
81
+ '.idea',
82
+ 'Pods',
83
+ ]);
84
+ /** Recent git subject sample size. */
85
+ export const GIT_LOG_SAMPLE_SIZE = 50;
86
+ /** Default git log timeout in ms. */
87
+ export const GIT_LOG_TIMEOUT_MS = 3_000;
88
+ /** Run the full detection rubric over a workspace. */
89
+ export function detectWorkspace(cwd, options = {}) {
90
+ const readLog = options.readCommitLog ?? defaultCommitLogReader(options.gitTimeoutMs);
91
+ const stack = detectStack(cwd);
92
+ const walk = walkDetection(cwd);
93
+ const languages = topLanguages(walk.histogram, 6);
94
+ const pkg = readPackageJsonSafe(cwd);
95
+ const frameworks = detectFrameworks(cwd, pkg, walk.fileSet);
96
+ const testFrameworks = detectTestFrameworks(cwd, pkg, stack.kind, walk.fileSet);
97
+ const commitConvention = classifyCommits(readLog(cwd));
98
+ const monorepo = detectMonorepo(cwd, pkg);
99
+ const aiConfigs = detectAiConfigs(cwd);
100
+ const scripts = pickScripts(pkg);
101
+ const topLevelDirs = walk.topLevelDirs;
102
+ return Object.freeze({
103
+ cwd,
104
+ stack,
105
+ languages,
106
+ frameworks,
107
+ testFrameworks,
108
+ commitConvention,
109
+ monorepo,
110
+ aiConfigs,
111
+ scripts,
112
+ topLevelDirs,
113
+ walkVisited: walk.visited,
114
+ walkTruncated: walk.truncated,
115
+ });
116
+ }
117
+ /* ------------------------------------------------------------------ */
118
+ /* Stack detection */
119
+ /* ------------------------------------------------------------------ */
120
+ /** Detect the primary stack via marker manifests. */
121
+ export function detectStack(cwd) {
122
+ const manifests = [];
123
+ let kind = 'unknown';
124
+ let nodeName;
125
+ let nodeVersion;
126
+ if (existsSync(join(cwd, 'package.json'))) {
127
+ manifests.push('package.json');
128
+ kind = 'node';
129
+ const pkg = readPackageJsonSafe(cwd);
130
+ if (pkg) {
131
+ if (typeof pkg.name === 'string')
132
+ nodeName = pkg.name;
133
+ if (typeof pkg.version === 'string')
134
+ nodeVersion = pkg.version;
135
+ }
136
+ }
137
+ if (existsSync(join(cwd, 'pyproject.toml'))) {
138
+ manifests.push('pyproject.toml');
139
+ if (kind === 'unknown')
140
+ kind = 'python';
141
+ }
142
+ if (existsSync(join(cwd, 'setup.py'))) {
143
+ manifests.push('setup.py');
144
+ if (kind === 'unknown')
145
+ kind = 'python';
146
+ }
147
+ if (existsSync(join(cwd, 'requirements.txt'))) {
148
+ manifests.push('requirements.txt');
149
+ if (kind === 'unknown')
150
+ kind = 'python';
151
+ }
152
+ if (existsSync(join(cwd, 'Cargo.toml'))) {
153
+ manifests.push('Cargo.toml');
154
+ if (kind === 'unknown')
155
+ kind = 'rust';
156
+ }
157
+ if (existsSync(join(cwd, 'go.mod'))) {
158
+ manifests.push('go.mod');
159
+ if (kind === 'unknown')
160
+ kind = 'go';
161
+ }
162
+ if (existsSync(join(cwd, 'Gemfile'))) {
163
+ manifests.push('Gemfile');
164
+ if (kind === 'unknown')
165
+ kind = 'ruby';
166
+ }
167
+ if (existsSync(join(cwd, 'composer.json'))) {
168
+ manifests.push('composer.json');
169
+ if (kind === 'unknown')
170
+ kind = 'php';
171
+ }
172
+ if (existsSync(join(cwd, 'pom.xml'))) {
173
+ manifests.push('pom.xml');
174
+ if (kind === 'unknown')
175
+ kind = 'java';
176
+ }
177
+ if (existsSync(join(cwd, 'build.gradle')) || existsSync(join(cwd, 'build.gradle.kts'))) {
178
+ manifests.push(existsSync(join(cwd, 'build.gradle')) ? 'build.gradle' : 'build.gradle.kts');
179
+ if (kind === 'unknown')
180
+ kind = 'java';
181
+ }
182
+ const packageManager = kind === 'node' ? detectPackageManager(cwd) : undefined;
183
+ return Object.freeze({
184
+ kind,
185
+ manifests: Object.freeze(manifests),
186
+ packageManager,
187
+ nodeName,
188
+ nodeVersion,
189
+ });
190
+ }
191
+ const NODE_FRAMEWORK_SPECS = [
192
+ {
193
+ name: 'Next.js',
194
+ depKeys: ['next'],
195
+ configFiles: ['next.config.js', 'next.config.mjs', 'next.config.ts', 'next.config.cjs'],
196
+ },
197
+ {
198
+ name: 'Vite',
199
+ depKeys: ['vite'],
200
+ configFiles: ['vite.config.ts', 'vite.config.js', 'vite.config.mjs', 'vite.config.cjs'],
201
+ },
202
+ { name: 'NestJS', depKeys: ['@nestjs/core'] },
203
+ { name: 'Express', depKeys: ['express'] },
204
+ { name: 'Fastify', depKeys: ['fastify'] },
205
+ { name: 'Hono', depKeys: ['hono'] },
206
+ { name: 'SvelteKit', depKeys: ['@sveltejs/kit'], configFiles: ['svelte.config.js'] },
207
+ { name: 'Nuxt', depKeys: ['nuxt'], configFiles: ['nuxt.config.ts', 'nuxt.config.js'] },
208
+ { name: 'Remix', depKeys: ['@remix-run/react', '@remix-run/node'] },
209
+ { name: 'React', depKeys: ['react'] },
210
+ { name: 'Vue', depKeys: ['vue'] },
211
+ { name: 'Angular', depKeys: ['@angular/core'] },
212
+ { name: 'Prisma', depKeys: ['prisma', '@prisma/client'] },
213
+ { name: 'Drizzle', depKeys: ['drizzle-orm'] },
214
+ { name: 'tRPC', depKeys: ['@trpc/server', '@trpc/client'] },
215
+ { name: 'Zod', depKeys: ['zod'] },
216
+ ];
217
+ const PYTHON_FRAMEWORK_SPECS = [
218
+ { name: 'FastAPI', token: 'fastapi' },
219
+ { name: 'Django', token: 'django' },
220
+ { name: 'Flask', token: 'flask' },
221
+ ];
222
+ const RUST_FRAMEWORK_SPECS = [
223
+ { name: 'Axum', token: 'axum' },
224
+ { name: 'Actix-web', token: 'actix-web' },
225
+ ];
226
+ const GO_FRAMEWORK_SPECS = [
227
+ { name: 'Gin', token: 'github.com/gin-gonic/gin' },
228
+ { name: 'Echo', token: 'github.com/labstack/echo' },
229
+ ];
230
+ function detectFrameworks(cwd, pkg, fileSet) {
231
+ const found = [];
232
+ const seen = new Set();
233
+ if (pkg) {
234
+ const deps = collectDeps(pkg);
235
+ for (const spec of NODE_FRAMEWORK_SPECS) {
236
+ const evidence = matchFramework(spec, deps, cwd);
237
+ if (evidence && !seen.has(spec.name)) {
238
+ found.push({ name: spec.name, evidence });
239
+ seen.add(spec.name);
240
+ }
241
+ }
242
+ }
243
+ // Python frameworks from requirements.txt / pyproject.toml content scan.
244
+ const pyText = safeRead(join(cwd, 'requirements.txt')) ?? safeRead(join(cwd, 'pyproject.toml'));
245
+ if (pyText) {
246
+ const lowered = pyText.toLowerCase();
247
+ for (const spec of PYTHON_FRAMEWORK_SPECS) {
248
+ if (lowered.includes(spec.token) && !seen.has(spec.name)) {
249
+ found.push({ name: spec.name, evidence: `dependency: ${spec.token}` });
250
+ seen.add(spec.name);
251
+ }
252
+ }
253
+ }
254
+ // Rust frameworks from Cargo.toml content scan.
255
+ const cargo = safeRead(join(cwd, 'Cargo.toml'));
256
+ if (cargo) {
257
+ const lowered = cargo.toLowerCase();
258
+ for (const spec of RUST_FRAMEWORK_SPECS) {
259
+ if (lowered.includes(spec.token) && !seen.has(spec.name)) {
260
+ found.push({ name: spec.name, evidence: `dependency: ${spec.token}` });
261
+ seen.add(spec.name);
262
+ }
263
+ }
264
+ }
265
+ // Go frameworks from go.mod content scan.
266
+ const gomod = safeRead(join(cwd, 'go.mod'));
267
+ if (gomod) {
268
+ for (const spec of GO_FRAMEWORK_SPECS) {
269
+ if (gomod.includes(spec.token) && !seen.has(spec.name)) {
270
+ found.push({ name: spec.name, evidence: `dependency: ${spec.token}` });
271
+ seen.add(spec.name);
272
+ }
273
+ }
274
+ }
275
+ // Ruby on Rails — presence of `config/application.rb` is a very strong signal.
276
+ if (existsSync(join(cwd, 'Gemfile')) || fileSet.has('config/application.rb')) {
277
+ const gemfile = safeRead(join(cwd, 'Gemfile')) ?? '';
278
+ if (/rails/i.test(gemfile) && !seen.has('Rails')) {
279
+ found.push({ name: 'Rails', evidence: 'Gemfile: rails' });
280
+ seen.add('Rails');
281
+ }
282
+ }
283
+ return Object.freeze(found);
284
+ }
285
+ function matchFramework(spec, deps, cwd) {
286
+ if (spec.depKeys) {
287
+ for (const key of spec.depKeys) {
288
+ if (deps.has(key))
289
+ return `dependency: ${key}`;
290
+ }
291
+ }
292
+ if (spec.configFiles) {
293
+ for (const file of spec.configFiles) {
294
+ if (existsSync(join(cwd, file)))
295
+ return `config: ${file}`;
296
+ }
297
+ }
298
+ return null;
299
+ }
300
+ /* ------------------------------------------------------------------ */
301
+ /* Test frameworks */
302
+ /* ------------------------------------------------------------------ */
303
+ function detectTestFrameworks(cwd, pkg, stack, fileSet) {
304
+ const found = new Set();
305
+ if (pkg) {
306
+ const deps = collectDeps(pkg);
307
+ if (deps.has('jest'))
308
+ found.add('Jest');
309
+ if (deps.has('vitest'))
310
+ found.add('Vitest');
311
+ if (deps.has('mocha'))
312
+ found.add('Mocha');
313
+ if (deps.has('@playwright/test') || deps.has('playwright'))
314
+ found.add('Playwright');
315
+ if (deps.has('cypress'))
316
+ found.add('Cypress');
317
+ // node:test surfaces via the `node --test` script invocation.
318
+ const scripts = pkg.scripts;
319
+ if (scripts && typeof scripts === 'object') {
320
+ for (const value of Object.values(scripts)) {
321
+ if (typeof value === 'string' && /\bnode\s+--test\b/.test(value)) {
322
+ found.add('node:test');
323
+ break;
324
+ }
325
+ }
326
+ }
327
+ }
328
+ // Pytest by `pytest.ini` / `pyproject.toml [tool.pytest]` / config files.
329
+ if (stack === 'python') {
330
+ if (existsSync(join(cwd, 'pytest.ini')))
331
+ found.add('pytest');
332
+ const pyproject = safeRead(join(cwd, 'pyproject.toml'));
333
+ if (pyproject && /\[tool\.pytest/.test(pyproject))
334
+ found.add('pytest');
335
+ const reqs = safeRead(join(cwd, 'requirements.txt'));
336
+ if (reqs && /pytest/i.test(reqs))
337
+ found.add('pytest');
338
+ }
339
+ // cargo / go test are implicit when stack matches; surface that signal.
340
+ if (stack === 'rust' && existsSync(join(cwd, 'Cargo.toml'))) {
341
+ found.add('cargo test');
342
+ }
343
+ if (stack === 'go' && existsSync(join(cwd, 'go.mod'))) {
344
+ found.add('go test');
345
+ }
346
+ // Test directory heuristic — surface even when nothing else matches.
347
+ if (found.size === 0) {
348
+ if (fileSet.has('tests') || fileSet.has('test') || fileSet.has('__tests__')) {
349
+ // Leave empty rather than guessing a framework name.
350
+ }
351
+ }
352
+ return Object.freeze(Array.from(found).sort((a, b) => a.localeCompare(b)));
353
+ }
354
+ /* ------------------------------------------------------------------ */
355
+ /* Commit convention */
356
+ /* ------------------------------------------------------------------ */
357
+ const CONVENTIONAL_RE = /^(feat|fix|chore|docs|style|refactor|test|build|ci|perf|revert)(\(.+\))?!?:/i;
358
+ const GITMOJI_RE = /^:[a-z0-9_+-]+:/;
359
+ /** Classify a sample of commit subject lines. */
360
+ export function classifyCommits(subjects) {
361
+ if (subjects.length === 0)
362
+ return 'unknown';
363
+ let conventional = 0;
364
+ let gitmoji = 0;
365
+ for (const raw of subjects) {
366
+ const subject = raw.trim();
367
+ if (!subject)
368
+ continue;
369
+ if (CONVENTIONAL_RE.test(subject))
370
+ conventional += 1;
371
+ else if (GITMOJI_RE.test(subject))
372
+ gitmoji += 1;
373
+ }
374
+ const total = subjects.length;
375
+ if (conventional / total >= 0.4)
376
+ return 'conventional';
377
+ if (gitmoji / total >= 0.4)
378
+ return 'gitmoji';
379
+ return 'freeform';
380
+ }
381
+ function defaultCommitLogReader(timeoutMs = GIT_LOG_TIMEOUT_MS) {
382
+ return (cwd) => {
383
+ try {
384
+ const out = execFileSync('git', ['log', `--pretty=format:%s`, `-${GIT_LOG_SAMPLE_SIZE}`], {
385
+ cwd,
386
+ encoding: 'utf8',
387
+ timeout: timeoutMs,
388
+ stdio: ['ignore', 'pipe', 'ignore'],
389
+ });
390
+ return out.split('\n').filter((line) => line.length > 0);
391
+ }
392
+ catch {
393
+ return [];
394
+ }
395
+ };
396
+ }
397
+ /* ------------------------------------------------------------------ */
398
+ /* Monorepo detection */
399
+ /* ------------------------------------------------------------------ */
400
+ function detectMonorepo(cwd, pkg) {
401
+ if (existsSync(join(cwd, 'pnpm-workspace.yaml'))) {
402
+ return { kind: 'pnpm', file: 'pnpm-workspace.yaml' };
403
+ }
404
+ if (existsSync(join(cwd, 'turbo.json'))) {
405
+ return { kind: 'turborepo', file: 'turbo.json' };
406
+ }
407
+ if (existsSync(join(cwd, 'nx.json'))) {
408
+ return { kind: 'nx', file: 'nx.json' };
409
+ }
410
+ if (existsSync(join(cwd, 'lerna.json'))) {
411
+ return { kind: 'lerna', file: 'lerna.json' };
412
+ }
413
+ if (pkg && Array.isArray(pkg.workspaces)) {
414
+ return { kind: 'yarn-workspaces', file: 'package.json' };
415
+ }
416
+ if (pkg &&
417
+ typeof pkg.workspaces === 'object' &&
418
+ pkg.workspaces !== null) {
419
+ return { kind: 'yarn-workspaces', file: 'package.json' };
420
+ }
421
+ return undefined;
422
+ }
423
+ /* ------------------------------------------------------------------ */
424
+ /* AI configs */
425
+ /* ------------------------------------------------------------------ */
426
+ const AI_CONFIG_FILES = [
427
+ { name: 'CLAUDE.md', path: 'CLAUDE.md' },
428
+ { name: 'PUGI.md', path: 'PUGI.md' },
429
+ { name: '.cursorrules', path: '.cursorrules' },
430
+ { name: '.windsurfrules', path: '.windsurfrules' },
431
+ { name: '.aiderignore', path: '.aiderignore' },
432
+ ];
433
+ const AI_EXCERPT_BYTES = 1_500;
434
+ function detectAiConfigs(cwd) {
435
+ const found = [];
436
+ for (const spec of AI_CONFIG_FILES) {
437
+ const absPath = join(cwd, spec.path);
438
+ if (!existsSync(absPath))
439
+ continue;
440
+ const raw = safeRead(absPath);
441
+ let excerpt;
442
+ if (raw && raw.length > 0) {
443
+ excerpt = raw.slice(0, AI_EXCERPT_BYTES);
444
+ }
445
+ found.push({ name: spec.name, path: spec.path, excerpt });
446
+ }
447
+ return Object.freeze(found);
448
+ }
449
+ function walkDetection(cwd) {
450
+ const histogram = new Map();
451
+ const fileSet = new Set();
452
+ const topLevelDirs = [];
453
+ let visited = 0;
454
+ let truncated = false;
455
+ function walk(absPath, depth, relPrefix) {
456
+ if (visited >= MAX_DETECTION_NODES) {
457
+ truncated = true;
458
+ return;
459
+ }
460
+ visited += 1;
461
+ let entries;
462
+ try {
463
+ entries = readdirSync(absPath, { withFileTypes: true });
464
+ }
465
+ catch {
466
+ return;
467
+ }
468
+ entries.sort((a, b) => a.name.localeCompare(b.name));
469
+ for (const entry of entries) {
470
+ const rel = relPrefix.length === 0 ? entry.name : `${relPrefix}/${entry.name}`;
471
+ if (entry.isDirectory()) {
472
+ if (SKIP_DIRS.has(entry.name))
473
+ continue;
474
+ if (depth === 0)
475
+ topLevelDirs.push(entry.name);
476
+ fileSet.add(rel);
477
+ if (depth + 1 < MAX_DETECTION_DEPTH) {
478
+ walk(join(absPath, entry.name), depth + 1, rel);
479
+ }
480
+ }
481
+ else if (entry.isFile()) {
482
+ fileSet.add(rel);
483
+ if (depth === 0) {
484
+ // Already counted above-tree manifests separately.
485
+ }
486
+ const ext = extname(entry.name);
487
+ if (ext.length > 0) {
488
+ const lang = languageForExtension(entry.name);
489
+ if (lang)
490
+ histogram.set(lang, (histogram.get(lang) ?? 0) + 1);
491
+ }
492
+ }
493
+ }
494
+ }
495
+ walk(cwd, 0, '');
496
+ return Object.freeze({
497
+ histogram,
498
+ fileSet,
499
+ topLevelDirs: Object.freeze(topLevelDirs.slice(0, 20)),
500
+ visited,
501
+ truncated,
502
+ });
503
+ }
504
+ /* ------------------------------------------------------------------ */
505
+ /* Helpers */
506
+ /* ------------------------------------------------------------------ */
507
+ function readPackageJsonSafe(cwd) {
508
+ const raw = safeRead(join(cwd, 'package.json'));
509
+ if (!raw)
510
+ return null;
511
+ try {
512
+ const parsed = JSON.parse(raw);
513
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
514
+ return parsed;
515
+ }
516
+ return null;
517
+ }
518
+ catch {
519
+ return null;
520
+ }
521
+ }
522
+ function collectDeps(pkg) {
523
+ const out = new Map();
524
+ for (const key of ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']) {
525
+ const value = pkg[key];
526
+ if (!value || typeof value !== 'object')
527
+ continue;
528
+ for (const [name, version] of Object.entries(value)) {
529
+ if (typeof version === 'string')
530
+ out.set(name, version);
531
+ }
532
+ }
533
+ return out;
534
+ }
535
+ function pickScripts(pkg) {
536
+ if (!pkg)
537
+ return Object.freeze([]);
538
+ const scripts = pkg.scripts;
539
+ if (!scripts || typeof scripts !== 'object')
540
+ return Object.freeze([]);
541
+ const out = [];
542
+ const interesting = new Set([
543
+ 'dev',
544
+ 'start',
545
+ 'build',
546
+ 'test',
547
+ 'typecheck',
548
+ 'lint',
549
+ 'format',
550
+ 'check',
551
+ 'ci',
552
+ ]);
553
+ for (const [name, value] of Object.entries(scripts)) {
554
+ if (typeof value !== 'string')
555
+ continue;
556
+ if (!interesting.has(name))
557
+ continue;
558
+ out.push({ name, command: value });
559
+ }
560
+ out.sort((a, b) => a.name.localeCompare(b.name));
561
+ return Object.freeze(out);
562
+ }
563
+ function safeRead(path) {
564
+ try {
565
+ const st = statSync(path);
566
+ if (!st.isFile())
567
+ return null;
568
+ }
569
+ catch {
570
+ return null;
571
+ }
572
+ try {
573
+ return readFileSync(path, 'utf8');
574
+ }
575
+ catch {
576
+ return null;
577
+ }
578
+ }
579
+ // `basename` is referenced via this binding so the linter does not strip the
580
+ // import when only used indirectly through the manifest manifest array above.
581
+ void basename;
582
+ //# sourceMappingURL=detector.js.map