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

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 (402) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/THIRD_PARTY_NOTICES.md +40 -0
  3. package/assets/pugi-prozr2-mascot.ansi +9 -0
  4. package/bin/run.js +33 -1
  5. package/dist/commands/deploy.js +40 -40
  6. package/dist/commands/flatten.js +191 -0
  7. package/dist/commands/jobs-watch.js +201 -0
  8. package/dist/commands/jobs.js +42 -27
  9. package/dist/commands/smoke.js +133 -0
  10. package/dist/core/agent-progress/cleanup.js +134 -0
  11. package/dist/core/agent-progress/schema.js +144 -0
  12. package/dist/core/agent-progress/writer.js +101 -0
  13. package/dist/core/agents/adaptive-router.js +330 -0
  14. package/dist/core/agents/query-decomposer.js +297 -0
  15. package/dist/core/agents/registry.js +2 -2
  16. package/dist/core/approvals/shortcut-resolver.js +98 -0
  17. package/dist/core/artifact-chain/dispatcher.js +148 -0
  18. package/dist/core/artifact-chain/exporter.js +164 -0
  19. package/dist/core/artifact-chain/state.js +243 -0
  20. package/dist/core/artifact-chain/steps.js +169 -0
  21. package/dist/core/ask-user/question.js +92 -0
  22. package/dist/core/audit/audit-trail.js +275 -0
  23. package/dist/core/auth/ensure-authenticated.js +129 -0
  24. package/dist/core/auth/env-provider.js +238 -0
  25. package/dist/core/auto-open-browser.js +4 -4
  26. package/dist/core/auto-update/channels.js +122 -0
  27. package/dist/core/auto-update/checker.js +241 -0
  28. package/dist/core/auto-update/state.js +235 -0
  29. package/dist/core/bare-mode/index.js +107 -0
  30. package/dist/core/bash/redirect.js +281 -0
  31. package/dist/core/bash-classifier.js +436 -40
  32. package/dist/core/checkpoint/resumer.js +149 -0
  33. package/dist/core/checkpoint/rewinder.js +291 -0
  34. package/dist/core/checkpoints/shadow-git.js +670 -0
  35. package/dist/core/citations/parser.js +109 -0
  36. package/dist/core/classifier/yolo-classifier.js +88 -0
  37. package/dist/core/codegraph/decision-store.js +248 -0
  38. package/dist/core/codegraph/detect-repo.js +459 -0
  39. package/dist/core/codegraph/install.js +134 -0
  40. package/dist/core/codegraph/offer-hook.js +220 -0
  41. package/dist/core/compact/auto-trigger.js +96 -0
  42. package/dist/core/compact/buffer-rewriter.js +115 -0
  43. package/dist/core/compact/summarizer.js +208 -0
  44. package/dist/core/compact/token-counter.js +108 -0
  45. package/dist/core/consensus/anvil-fanout.js +25 -25
  46. package/dist/core/consensus/diff-capture.js +121 -12
  47. package/dist/core/consensus/rubric.js +21 -21
  48. package/dist/core/context/builder.js +6 -6
  49. package/dist/core/context/compaction-events.js +8 -8
  50. package/dist/core/context/compaction.js +31 -31
  51. package/dist/core/context/index.js +15 -8
  52. package/dist/core/context/invariants.js +51 -51
  53. package/dist/core/context/markdown-loader.js +28 -10
  54. package/dist/core/context/markdown-traverse.js +255 -0
  55. package/dist/core/context/pugiignore.js +41 -41
  56. package/dist/core/context/repo-skeleton.js +37 -37
  57. package/dist/core/context/tool-eviction.js +55 -0
  58. package/dist/core/context/watcher.js +32 -32
  59. package/dist/core/context/working-set.js +23 -23
  60. package/dist/core/coordinator/agent-tools.js +77 -0
  61. package/dist/core/coordinator/agent-toolset.js +65 -0
  62. package/dist/core/coordinator/fsm.js +73 -0
  63. package/dist/core/coordinator/mode-fsm.js +70 -0
  64. package/dist/core/cost/rate-card.js +129 -0
  65. package/dist/core/cost/tracker.js +221 -0
  66. package/dist/core/credentials.js +12 -12
  67. package/dist/core/cron/scheduler.js +138 -0
  68. package/dist/core/denial-tracking/index.js +8 -0
  69. package/dist/core/denial-tracking/state.js +264 -0
  70. package/dist/core/diagnostics/probe-runner.js +93 -0
  71. package/dist/core/diagnostics/probes/api.js +46 -0
  72. package/dist/core/diagnostics/probes/auth.js +93 -0
  73. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  74. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  75. package/dist/core/diagnostics/probes/config.js +72 -0
  76. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  77. package/dist/core/diagnostics/probes/disk.js +81 -0
  78. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  79. package/dist/core/diagnostics/probes/git.js +65 -0
  80. package/dist/core/diagnostics/probes/hooks.js +118 -0
  81. package/dist/core/diagnostics/probes/mcp.js +75 -0
  82. package/dist/core/diagnostics/probes/node.js +59 -0
  83. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  84. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  85. package/dist/core/diagnostics/probes/sandbox.js +40 -0
  86. package/dist/core/diagnostics/probes/session.js +74 -0
  87. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  88. package/dist/core/diagnostics/probes/workspace.js +63 -0
  89. package/dist/core/diagnostics/types.js +70 -0
  90. package/dist/core/dispatch/cache-cleanup.js +197 -0
  91. package/dist/core/dispatch/cache-handoff.js +295 -0
  92. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  93. package/dist/core/edits/dispatch.js +293 -7
  94. package/dist/core/edits/format-matrix.js +26 -0
  95. package/dist/core/edits/fuzzy-ladder.js +650 -0
  96. package/dist/core/edits/index.js +3 -1
  97. package/dist/core/edits/journal.js +199 -0
  98. package/dist/core/edits/layer-a-apply.js +15 -15
  99. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  100. package/dist/core/edits/layer-b-apply.js +9 -9
  101. package/dist/core/edits/layer-c-apply.js +6 -6
  102. package/dist/core/edits/layer-d-ast.js +557 -14
  103. package/dist/core/edits/marker-parser.js +12 -12
  104. package/dist/core/edits/security-gate.js +27 -27
  105. package/dist/core/edits/verify-hook.js +273 -0
  106. package/dist/core/edits/worktree.js +322 -0
  107. package/dist/core/engine/anvil-client.js +140 -26
  108. package/dist/core/engine/auto-compact.js +179 -0
  109. package/dist/core/engine/budgets.js +186 -0
  110. package/dist/core/engine/context-prefix.js +155 -0
  111. package/dist/core/engine/index.js +1 -1
  112. package/dist/core/engine/intensity.js +158 -0
  113. package/dist/core/engine/intent.js +260 -0
  114. package/dist/core/engine/native-pugi.js +1295 -227
  115. package/dist/core/engine/prompts.js +134 -16
  116. package/dist/core/engine/strip-internal-fields.js +124 -0
  117. package/dist/core/engine/tool-bridge.js +1295 -59
  118. package/dist/core/evaluation/golden-dataset.js +293 -0
  119. package/dist/core/feedback/queue.js +177 -0
  120. package/dist/core/feedback/submitter.js +145 -0
  121. package/dist/core/file-cache.js +113 -1
  122. package/dist/core/flatten/flatten-repo.js +439 -0
  123. package/dist/core/format/osc8-link.js +28 -0
  124. package/dist/core/hook-chains.js +392 -0
  125. package/dist/core/hooks/citation-verify-hook.js +138 -0
  126. package/dist/core/hooks/citation-verify.js +112 -0
  127. package/dist/core/hooks/events.js +44 -0
  128. package/dist/core/hooks/index.js +15 -0
  129. package/dist/core/hooks/registry.js +213 -0
  130. package/dist/core/hooks/runner.js +236 -0
  131. package/dist/core/hooks/v2/event-emitter.js +115 -0
  132. package/dist/core/hooks/v2/executor.js +282 -0
  133. package/dist/core/hooks/v2/index.js +25 -0
  134. package/dist/core/hooks/v2/lifecycle.js +104 -0
  135. package/dist/core/hooks/v2/loader.js +216 -0
  136. package/dist/core/hooks/v2/matcher.js +125 -0
  137. package/dist/core/hooks/v2/trust.js +143 -0
  138. package/dist/core/hooks/v2/types.js +86 -0
  139. package/dist/core/image/renderer.js +71 -0
  140. package/dist/core/init/detector.js +582 -0
  141. package/dist/core/init/template-renderer.js +242 -0
  142. package/dist/core/jobs/registry.js +18 -18
  143. package/dist/core/ledger/results-tsv.js +142 -0
  144. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  145. package/dist/core/lsp/cache.js +105 -0
  146. package/dist/core/lsp/client.js +776 -0
  147. package/dist/core/lsp/language-detect.js +66 -0
  148. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  149. package/dist/core/lsp/symbol-tools.js +372 -0
  150. package/dist/core/mcp/client.js +97 -28
  151. package/dist/core/mcp/http-server.js +553 -0
  152. package/dist/core/mcp/orchestrator-tools.js +662 -0
  153. package/dist/core/mcp/permission.js +190 -0
  154. package/dist/core/mcp/registry.js +39 -17
  155. package/dist/core/mcp/server-tools.js +219 -0
  156. package/dist/core/mcp/server.js +397 -0
  157. package/dist/core/mcp/trust.js +10 -10
  158. package/dist/core/memory/dual-write.js +416 -0
  159. package/dist/core/memory/passive-extract.js +130 -0
  160. package/dist/core/memory/phase1-kinds.js +20 -0
  161. package/dist/core/memory/secret-scanner.js +304 -0
  162. package/dist/core/memory-sync/queue.js +170 -0
  163. package/dist/core/metrics/extract.js +113 -0
  164. package/dist/core/modes/roo-modes.js +68 -0
  165. package/dist/core/onboarding/ensure-initialized.js +133 -0
  166. package/dist/core/onboarding/marker.js +111 -0
  167. package/dist/core/onboarding/telemetry-state.js +108 -0
  168. package/dist/core/output-style/presets.js +176 -0
  169. package/dist/core/output-style/state.js +185 -0
  170. package/dist/core/path-security.js +287 -5
  171. package/dist/core/permission.js +82 -22
  172. package/dist/core/permissions/auto-classifier.js +124 -0
  173. package/dist/core/permissions/bash-parser.js +371 -0
  174. package/dist/core/permissions/circuit-breaker.js +83 -0
  175. package/dist/core/permissions/constrained-edit.js +91 -0
  176. package/dist/core/permissions/gate.js +278 -0
  177. package/dist/core/permissions/index.js +20 -0
  178. package/dist/core/permissions/mode.js +174 -0
  179. package/dist/core/permissions/network-egress.js +137 -0
  180. package/dist/core/permissions/state.js +241 -0
  181. package/dist/core/permissions/tool-class.js +93 -0
  182. package/dist/core/plan-mode/ui-state.js +51 -0
  183. package/dist/core/plans/plan-artifact.js +721 -0
  184. package/dist/core/policy-limits/etag-store.js +122 -0
  185. package/dist/core/prd-check/parser.js +215 -0
  186. package/dist/core/prd-check/reporter.js +127 -0
  187. package/dist/core/prd-check/session-review.js +557 -0
  188. package/dist/core/prd-check/verifiers.js +223 -0
  189. package/dist/core/prompt-cache/client-cache.js +99 -0
  190. package/dist/core/prompts/assembly.js +29 -0
  191. package/dist/core/prompts/registry.js +364 -0
  192. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  193. package/dist/core/pugi-md/context-injector.js +76 -0
  194. package/dist/core/pugi-md/walk-up.js +207 -0
  195. package/dist/core/python/uv-installer.js +270 -0
  196. package/dist/core/python/uv-resolver.js +83 -0
  197. package/dist/core/rate-limit/narrator.js +146 -0
  198. package/dist/core/recipes/cli-types.js +20 -0
  199. package/dist/core/recipes/loader.js +103 -0
  200. package/dist/core/recipes/runner.js +345 -0
  201. package/dist/core/recipes/schema.js +587 -0
  202. package/dist/core/release-notes/parser.js +241 -0
  203. package/dist/core/release-notes/state.js +116 -0
  204. package/dist/core/repl/ask.js +37 -37
  205. package/dist/core/repl/cancellation.js +26 -26
  206. package/dist/core/repl/cap-warning.js +4 -4
  207. package/dist/core/repl/clipboard-read.js +11 -11
  208. package/dist/core/repl/dispatch-fsm.js +12 -12
  209. package/dist/core/repl/history-search.js +15 -15
  210. package/dist/core/repl/history.js +28 -18
  211. package/dist/core/repl/kill-ring.js +5 -5
  212. package/dist/core/repl/model-pricing.js +135 -0
  213. package/dist/core/repl/privacy-banner.js +22 -22
  214. package/dist/core/repl/session.js +2157 -214
  215. package/dist/core/repl/slash-commands.js +533 -40
  216. package/dist/core/repl/store/index.js +1 -1
  217. package/dist/core/repl/store/jsonl-log.js +22 -22
  218. package/dist/core/repl/store/lockfile.js +10 -10
  219. package/dist/core/repl/store/session-store.js +136 -107
  220. package/dist/core/repl/store/types.js +15 -15
  221. package/dist/core/repl/store/uuid-v7.js +12 -12
  222. package/dist/core/repl/workspace-context.js +43 -21
  223. package/dist/core/repo-map/build.js +125 -0
  224. package/dist/core/repo-map/cache.js +185 -0
  225. package/dist/core/repo-map/extractor.js +254 -0
  226. package/dist/core/repo-map/formatter.js +145 -0
  227. package/dist/core/repo-map/page-rank.js +105 -0
  228. package/dist/core/repo-map/scanner.js +211 -0
  229. package/dist/core/retry-budget/budget.js +284 -0
  230. package/dist/core/retry-budget/index.js +5 -0
  231. package/dist/core/retry-budget/retry-cap.js +74 -0
  232. package/dist/core/routing/lead-worker.js +43 -0
  233. package/dist/core/routing/pre-flight-estimator.js +108 -0
  234. package/dist/core/runs/run-tree.js +103 -0
  235. package/dist/core/security/injection-scanner.js +367 -0
  236. package/dist/core/security/output-filter.js +418 -0
  237. package/dist/core/session/env-file.js +105 -0
  238. package/dist/core/session/section-budgets.js +140 -0
  239. package/dist/core/session.js +92 -0
  240. package/dist/core/settings.js +286 -5
  241. package/dist/core/share/formatter.js +271 -0
  242. package/dist/core/share/redactor.js +221 -0
  243. package/dist/core/share/uploader.js +267 -0
  244. package/dist/core/skills/defaults.js +457 -0
  245. package/dist/core/skills/loader.js +22 -22
  246. package/dist/core/skills/sources.js +27 -27
  247. package/dist/core/smoke/headless-driver.js +174 -0
  248. package/dist/core/smoke/orchestrator.js +194 -0
  249. package/dist/core/smoke/runner.js +238 -0
  250. package/dist/core/smoke/scenario-parser.js +316 -0
  251. package/dist/core/statusline.js +99 -0
  252. package/dist/core/subagents/dispatcher-real.js +600 -0
  253. package/dist/core/subagents/dispatcher.js +132 -43
  254. package/dist/core/subagents/index.js +19 -6
  255. package/dist/core/subagents/isolation-matrix.js +213 -0
  256. package/dist/core/subagents/spawn.js +19 -4
  257. package/dist/core/telemetry/emitter.js +229 -0
  258. package/dist/core/telemetry/queue.js +251 -0
  259. package/dist/core/theme/context.js +91 -0
  260. package/dist/core/theme/presets.js +228 -0
  261. package/dist/core/theme/state.js +181 -0
  262. package/dist/core/todos/invariant.js +10 -0
  263. package/dist/core/todos/state.js +177 -0
  264. package/dist/core/tool-schema/compressor.js +89 -0
  265. package/dist/core/transport/version-interceptor.js +166 -0
  266. package/dist/core/trust.js +2 -2
  267. package/dist/core/tui/thinking-block.js +64 -0
  268. package/dist/core/vim/keymap.js +288 -0
  269. package/dist/core/vim/state.js +92 -0
  270. package/dist/core/watch-markers/marker-watcher.js +133 -0
  271. package/dist/core/worktree-manager/cleanup.js +123 -0
  272. package/dist/core/worktree-manager/manager.js +303 -0
  273. package/dist/index.js +28 -0
  274. package/dist/runtime/bootstrap.js +190 -0
  275. package/dist/runtime/cli.js +4151 -489
  276. package/dist/runtime/commands/agents.js +30 -30
  277. package/dist/runtime/commands/budget.js +5 -5
  278. package/dist/runtime/commands/cancel.js +231 -0
  279. package/dist/runtime/commands/chain.js +489 -0
  280. package/dist/runtime/commands/codegraph-status.js +227 -0
  281. package/dist/runtime/commands/compact.js +297 -0
  282. package/dist/runtime/commands/config.js +32 -32
  283. package/dist/runtime/commands/cost.js +199 -0
  284. package/dist/runtime/commands/delegate.js +244 -13
  285. package/dist/runtime/commands/dispatch.js +126 -0
  286. package/dist/runtime/commands/doctor.js +579 -0
  287. package/dist/runtime/commands/feedback.js +184 -0
  288. package/dist/runtime/commands/hooks.js +184 -0
  289. package/dist/runtime/commands/init.js +254 -0
  290. package/dist/runtime/commands/lsp.js +368 -0
  291. package/dist/runtime/commands/mcp.js +879 -0
  292. package/dist/runtime/commands/memory.js +582 -0
  293. package/dist/runtime/commands/model.js +237 -0
  294. package/dist/runtime/commands/onboarding.js +275 -0
  295. package/dist/runtime/commands/patch.js +128 -0
  296. package/dist/runtime/commands/permissions.js +112 -0
  297. package/dist/runtime/commands/plan.js +143 -0
  298. package/dist/runtime/commands/prd-check.js +285 -0
  299. package/dist/runtime/commands/privacy.js +17 -17
  300. package/dist/runtime/commands/recipe.js +325 -0
  301. package/dist/runtime/commands/redo-blob-store.js +92 -0
  302. package/dist/runtime/commands/redo.js +361 -0
  303. package/dist/runtime/commands/release-notes.js +229 -0
  304. package/dist/runtime/commands/repo-map.js +95 -0
  305. package/dist/runtime/commands/report.js +299 -0
  306. package/dist/runtime/commands/resume.js +118 -0
  307. package/dist/runtime/commands/review-consensus.js +68 -53
  308. package/dist/runtime/commands/rewind.js +333 -0
  309. package/dist/runtime/commands/roster.js +14 -14
  310. package/dist/runtime/commands/sessions.js +163 -0
  311. package/dist/runtime/commands/share.js +316 -0
  312. package/dist/runtime/commands/skills.js +31 -31
  313. package/dist/runtime/commands/status.js +186 -0
  314. package/dist/runtime/commands/stickers.js +82 -0
  315. package/dist/runtime/commands/style.js +194 -0
  316. package/dist/runtime/commands/theme.js +196 -0
  317. package/dist/runtime/commands/undo.js +54 -22
  318. package/dist/runtime/commands/update.js +289 -0
  319. package/dist/runtime/commands/vim.js +140 -0
  320. package/dist/runtime/commands/worktree.js +177 -0
  321. package/dist/runtime/commands/worktrees.js +155 -0
  322. package/dist/runtime/headless-repl.js +195 -0
  323. package/dist/runtime/headless.js +543 -0
  324. package/dist/runtime/load-hooks-or-exit.js +71 -0
  325. package/dist/runtime/plan-decompose.js +531 -0
  326. package/dist/runtime/update-check.js +28 -28
  327. package/dist/runtime/version.js +65 -0
  328. package/dist/skills/bundled/batch.js +617 -0
  329. package/dist/skills/bundled/index.js +45 -0
  330. package/dist/skills/bundled/loop.js +358 -0
  331. package/dist/skills/bundled/remember.js +383 -0
  332. package/dist/skills/bundled/simplify.js +289 -0
  333. package/dist/skills/bundled/skillify.js +373 -0
  334. package/dist/skills/bundled/stuck.js +558 -0
  335. package/dist/skills/bundled/verify.js +439 -0
  336. package/dist/testing/vcr.js +486 -0
  337. package/dist/tools/agent-tool.js +229 -0
  338. package/dist/tools/apply-patch.js +556 -0
  339. package/dist/tools/ask-user-question.js +222 -0
  340. package/dist/tools/ask-user.js +115 -0
  341. package/dist/tools/bash.js +623 -45
  342. package/dist/tools/brief.js +224 -0
  343. package/dist/tools/enter-worktree.js +250 -0
  344. package/dist/tools/exit-worktree.js +147 -0
  345. package/dist/tools/file-tools.js +161 -44
  346. package/dist/tools/lsp-tools.js +189 -0
  347. package/dist/tools/mcp-tool.js +260 -0
  348. package/dist/tools/multi-edit.js +361 -0
  349. package/dist/tools/powershell.js +268 -0
  350. package/dist/tools/registry.js +85 -0
  351. package/dist/tools/skill-tool.js +96 -0
  352. package/dist/tools/sleep.js +99 -0
  353. package/dist/tools/synthetic-output.js +133 -0
  354. package/dist/tools/tasks.js +208 -0
  355. package/dist/tools/todo-write.js +184 -0
  356. package/dist/tools/verify-plan-execution.js +295 -0
  357. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  358. package/dist/tools/web-fetch.js +195 -10
  359. package/dist/tools/web-search.js +458 -0
  360. package/dist/tui/agent-progress-card.js +111 -0
  361. package/dist/tui/agent-tree.js +11 -1
  362. package/dist/tui/ask-modal.js +14 -14
  363. package/dist/tui/ask-user-question-prompt.js +203 -0
  364. package/dist/tui/compact-banner.js +81 -0
  365. package/dist/tui/conversation-pane.js +85 -11
  366. package/dist/tui/cost-table.js +111 -0
  367. package/dist/tui/device-flow.js +2 -2
  368. package/dist/tui/doctor-table.js +46 -0
  369. package/dist/tui/feedback-prompt.js +156 -0
  370. package/dist/tui/input-box.js +247 -32
  371. package/dist/tui/login-picker.js +3 -3
  372. package/dist/tui/markdown-render.js +6 -6
  373. package/dist/tui/onboarding-wizard.js +240 -0
  374. package/dist/tui/permissions-picker.js +86 -0
  375. package/dist/tui/render.js +35 -0
  376. package/dist/tui/repl-render.js +332 -54
  377. package/dist/tui/repl-splash-art.js +16 -16
  378. package/dist/tui/repl-splash-mascot.js +48 -24
  379. package/dist/tui/repl-splash.js +22 -22
  380. package/dist/tui/repl.js +124 -44
  381. package/dist/tui/slash-palette.js +6 -6
  382. package/dist/tui/splash.js +2 -2
  383. package/dist/tui/status-bar.js +109 -31
  384. package/dist/tui/status-table.js +7 -0
  385. package/dist/tui/stickers-art.js +136 -0
  386. package/dist/tui/style-table.js +28 -0
  387. package/dist/tui/theme-table.js +29 -0
  388. package/dist/tui/thinking-spinner.js +123 -0
  389. package/dist/tui/tool-stream-pane.js +53 -4
  390. package/dist/tui/update-banner.js +27 -2
  391. package/dist/tui/vim-input.js +267 -0
  392. package/dist/tui/welcome-banner.js +107 -0
  393. package/dist/tui/welcome-data.js +293 -0
  394. package/dist/tui/workspace-context.js +2 -2
  395. package/docs/examples/codegraph.mcp.json +10 -0
  396. package/package.json +23 -6
  397. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  398. package/test/scenarios/compact-force.scenario.txt +11 -0
  399. package/test/scenarios/identity.scenario.txt +11 -0
  400. package/test/scenarios/persona-handoff.scenario.txt +11 -0
  401. package/test/scenarios/walkback.scenario.txt +12 -0
  402. package/dist/core/engine/compaction-hook.js +0 -154
@@ -0,0 +1,72 @@
1
+ /**
2
+ * CONFIG probe — verifies `~/.pugi/credentials.json` exists, parses,
3
+ * and carries the canonical shape (a `tokens` array). Lighter-weight
4
+ * than the auth probe (no network); catches `corrupted JSON` /
5
+ * `accidentally overwrote with empty file` / `bad permissions` cases
6
+ * that would otherwise surface as confusing errors deeper in the
7
+ * auth path.
8
+ *
9
+ * Absence of the file is NOT an error here — the operator may not
10
+ * have run `pugi login` yet. That case is caught by the AUTH probe
11
+ * with a clean "run pugi login" remediation. CONFIG's job is to
12
+ * verify the file is sane WHEN it exists.
13
+ */
14
+ export function probeConfig(ctx, fs) {
15
+ const credPath = `${ctx.home}/.pugi/credentials.json`;
16
+ if (!fs.existsSync(credPath)) {
17
+ return {
18
+ name: 'CONFIG',
19
+ status: 'skipped',
20
+ detail: '~/.pugi/credentials.json absent (operator has not logged in)',
21
+ };
22
+ }
23
+ let raw;
24
+ try {
25
+ raw = fs.readFileSync(credPath, 'utf8');
26
+ }
27
+ catch (error) {
28
+ const message = error instanceof Error ? error.message : String(error);
29
+ return {
30
+ name: 'CONFIG',
31
+ status: 'error',
32
+ detail: `Cannot read ~/.pugi/credentials.json`,
33
+ remediation: `Fix permissions or delete and re-login: ${message}`,
34
+ };
35
+ }
36
+ let parsed;
37
+ try {
38
+ parsed = JSON.parse(raw);
39
+ }
40
+ catch (error) {
41
+ const message = error instanceof Error ? error.message : String(error);
42
+ return {
43
+ name: 'CONFIG',
44
+ status: 'error',
45
+ detail: `~/.pugi/credentials.json is not valid JSON`,
46
+ remediation: `Delete and re-login: ${message}`,
47
+ };
48
+ }
49
+ if (!parsed || typeof parsed !== 'object') {
50
+ return {
51
+ name: 'CONFIG',
52
+ status: 'error',
53
+ detail: `credentials.json root is not an object`,
54
+ remediation: 'Delete and re-login',
55
+ };
56
+ }
57
+ const tokens = parsed.tokens;
58
+ if (!Array.isArray(tokens)) {
59
+ return {
60
+ name: 'CONFIG',
61
+ status: 'error',
62
+ detail: `credentials.json missing required \`tokens\` array`,
63
+ remediation: 'Delete and re-login',
64
+ };
65
+ }
66
+ return {
67
+ name: 'CONFIG',
68
+ status: 'ok',
69
+ detail: `~/.pugi/credentials.json valid (${tokens.length} token(s) stored)`,
70
+ };
71
+ }
72
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * L11 — DENIAL TRACKING probe for `pugi doctor`.
3
+ *
4
+ * Reports the current session's denial pressure: total denial count,
5
+ * unique (tool, args) patterns, and how many patterns have repeated
6
+ * past the reminder threshold. Operators read this to spot:
7
+ *
8
+ * - A hook script refusing more dispatches than expected (mis-
9
+ * configured `.pugi/hooks.json`).
10
+ * - Plan-mode runs where the model keeps trying mutating tools
11
+ * (a sign the prompt is not anchoring it correctly).
12
+ * - Stale-read loops indicating concurrent multi-agent writes.
13
+ *
14
+ * Status semantics:
15
+ *
16
+ * - `ok` when the tracker is empty OR carries denials but none have
17
+ * repeated past the threshold. Single denials are normal session
18
+ * hygiene; repeats are the signal.
19
+ * - `warn` when one or more patterns repeated >= the reminder
20
+ * threshold. The probe surfaces the count so the operator can act.
21
+ * - `skipped` when no tracker is wired (e.g. doctor invoked outside
22
+ * a live REPL session, top-level `pugi doctor`).
23
+ *
24
+ * Pure: takes a tracker snapshot — no I/O, no module-level state.
25
+ */
26
+ import { DENIAL_REMINDER_THRESHOLD, } from '../../denial-tracking/state.js';
27
+ export function probeDenialTracking(deps) {
28
+ if (!deps.tracker) {
29
+ return {
30
+ name: 'DENIAL TRACKING',
31
+ status: 'skipped',
32
+ detail: 'No live session — run `pugi doctor` from inside the REPL to see denials.',
33
+ };
34
+ }
35
+ const summary = deps.tracker.summary();
36
+ if (summary.totalDenials === 0) {
37
+ return {
38
+ name: 'DENIAL TRACKING',
39
+ status: 'ok',
40
+ detail: 'No tool denials this session.',
41
+ };
42
+ }
43
+ if (summary.repeatedPatterns === 0) {
44
+ return {
45
+ name: 'DENIAL TRACKING',
46
+ status: 'ok',
47
+ detail: `${summary.totalDenials} denial(s), ${summary.uniquePatterns} unique pattern(s), none repeated.`,
48
+ };
49
+ }
50
+ return {
51
+ name: 'DENIAL TRACKING',
52
+ status: 'warn',
53
+ detail: `${summary.totalDenials} denial(s), ${summary.repeatedPatterns} pattern(s) repeated >= ${DENIAL_REMINDER_THRESHOLD}.`,
54
+ remediation: 'Inspect via `/permissions denials` (when L6 lands) or check `.pugi/events.jsonl` for the latest refusals.',
55
+ };
56
+ }
57
+ //# sourceMappingURL=denial-tracking.js.map
@@ -0,0 +1,81 @@
1
+ /**
2
+ * DISK probe — warn the operator when the home partition is dangerously
3
+ * full. The session log, file cache, MCP working dirs, and the engine
4
+ * artifact bundle all land under `~/.pugi/`, so a full disk produces
5
+ * cryptic ENOSPC errors mid-dispatch. We catch that early.
6
+ *
7
+ * Implementation strategy: call `df -k` (POSIX-portable BSD tool with a
8
+ * stable column ordering) on the home dir and parse the available
9
+ * column. Bytes math + 1k blocks = simple integer arithmetic. We
10
+ * deliberately avoid `statvfs` because Node's stable surface for it
11
+ * (`fs.statfs` introduced in Node 18.15) returns BigInts that callers
12
+ * routinely mishandle on cross-platform builds.
13
+ *
14
+ * Thresholds:
15
+ * - `< 256 MiB` available → error (Pugi cannot do meaningful work)
16
+ * - `< 1 GiB` available → warn (operator should clear space soon)
17
+ * - otherwise → ok
18
+ */
19
+ const MIB = 1024 * 1024;
20
+ const GIB = MIB * 1024;
21
+ const ERROR_THRESHOLD_BYTES = 256 * MIB;
22
+ const WARN_THRESHOLD_BYTES = 1 * GIB;
23
+ export function probeDisk(ctx, deps) {
24
+ let freeBytes;
25
+ try {
26
+ freeBytes = deps.getFreeBytes(ctx.home);
27
+ }
28
+ catch (error) {
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ return {
31
+ name: 'DISK',
32
+ status: 'warn',
33
+ detail: `Cannot determine free space on ${ctx.home}`,
34
+ remediation: `Inspection failed: ${message}`,
35
+ };
36
+ }
37
+ if (!Number.isFinite(freeBytes) || freeBytes < 0) {
38
+ return {
39
+ name: 'DISK',
40
+ status: 'warn',
41
+ detail: `df returned implausible value (${freeBytes}) for ${ctx.home}`,
42
+ };
43
+ }
44
+ const human = formatBytes(freeBytes);
45
+ if (freeBytes < ERROR_THRESHOLD_BYTES) {
46
+ return {
47
+ name: 'DISK',
48
+ status: 'error',
49
+ detail: `${human} free on home partition`,
50
+ remediation: 'Free disk space — Pugi writes ~/.pugi/sessions and cache files',
51
+ };
52
+ }
53
+ if (freeBytes < WARN_THRESHOLD_BYTES) {
54
+ return {
55
+ name: 'DISK',
56
+ status: 'warn',
57
+ detail: `${human} free on home partition`,
58
+ remediation: 'Consider clearing ~/.pugi/sessions older entries',
59
+ };
60
+ }
61
+ return {
62
+ name: 'DISK',
63
+ status: 'ok',
64
+ detail: `${human} free on home partition`,
65
+ };
66
+ }
67
+ /**
68
+ * Format bytes as `1.2GB` / `512MB` / `42KB`. Stays in IEC base-1024
69
+ * because that's what `df -k` returns and what operators reading the
70
+ * doctor table expect to see on their `df` follow-up.
71
+ */
72
+ export function formatBytes(bytes) {
73
+ if (bytes >= GIB)
74
+ return `${(bytes / GIB).toFixed(1)}GB`;
75
+ if (bytes >= MIB)
76
+ return `${Math.round(bytes / MIB)}MB`;
77
+ if (bytes >= 1024)
78
+ return `${Math.round(bytes / 1024)}KB`;
79
+ return `${bytes}B`;
80
+ }
81
+ //# sourceMappingURL=disk.js.map
@@ -0,0 +1,46 @@
1
+ const LIVE_PROMPT = 'Reply with the single word OK.';
2
+ const TIMEOUT_MS = 15_000;
3
+ export async function probeEngineLive(ctx, deps) {
4
+ const apiKey = deps.resolveApiKey(ctx.env);
5
+ if (!apiKey) {
6
+ return { name: 'ENGINE LIVE', status: 'skipped', detail: 'no API key (run `pugi login` or set PUGI_API_KEY)' };
7
+ }
8
+ const apiUrl = deps.resolveApiUrl(ctx.env);
9
+ const startedAt = deps.now();
10
+ const url = (apiUrl.endsWith('/') ? apiUrl.slice(0, -1) : apiUrl) + '/api/pugi/engine';
11
+ try {
12
+ const res = await deps.fetchImpl(url, {
13
+ method: 'POST',
14
+ signal: AbortSignal.timeout(TIMEOUT_MS),
15
+ headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
16
+ body: JSON.stringify({
17
+ personaSlug: 'main',
18
+ command: 'explain',
19
+ messages: [{ role: 'user', content: LIVE_PROMPT }],
20
+ tools: [],
21
+ temperature: 0,
22
+ maxTokens: 32,
23
+ }),
24
+ });
25
+ const latencyMs = deps.now() - startedAt;
26
+ if (!res.ok) {
27
+ const body = await res.text().catch(() => '');
28
+ return { name: 'ENGINE LIVE', status: 'error', detail: `engine returned HTTP ${res.status}${body ? `: ${body.slice(0, 200)}` : ''}`, latencyMs };
29
+ }
30
+ const json = (await res.json().catch(() => null));
31
+ if (!json)
32
+ return { name: 'ENGINE LIVE', status: 'error', detail: 'engine returned 2xx but body is not JSON', latencyMs };
33
+ const model = typeof json['model'] === 'string' ? json['model'] : 'unknown';
34
+ const content = typeof json['content'] === 'string' ? json['content'] : '';
35
+ if (!content.toLowerCase().includes('ok')) {
36
+ return { name: 'ENGINE LIVE', status: 'warn', detail: `round-trip OK via ${model} (${latencyMs}ms) but reply did not contain expected token; got "${content.slice(0, 80)}"`, latencyMs };
37
+ }
38
+ return { name: 'ENGINE LIVE', status: 'ok', detail: `round-trip OK via ${model} (${latencyMs}ms)`, latencyMs };
39
+ }
40
+ catch (error) {
41
+ const latencyMs = deps.now() - startedAt;
42
+ const message = error instanceof Error ? error.message : String(error);
43
+ return { name: 'ENGINE LIVE', status: 'error', detail: `engine round-trip failed: ${message}`, latencyMs };
44
+ }
45
+ }
46
+ //# sourceMappingURL=engine-live.js.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * GIT probe — verifies git is on PATH AND the current cwd is inside a
3
+ * git work tree. Reports the short HEAD sha + repo root for context.
4
+ *
5
+ * Pugi treats the workspace as a git project (worktree isolation,
6
+ * /codex review, /triple-review and the entire agent loop assume
7
+ * `git diff origin/main..HEAD` is meaningful). A workspace that is
8
+ * not a git work tree still works for read-only commands but the
9
+ * doctor surface flags this so the operator knows where the limits
10
+ * are.
11
+ */
12
+ export function probeGit(ctx, deps) {
13
+ let version;
14
+ try {
15
+ version = deps.resolveVersion();
16
+ }
17
+ catch (error) {
18
+ const message = error instanceof Error ? error.message : String(error);
19
+ return {
20
+ name: 'GIT',
21
+ status: 'warn',
22
+ detail: 'git not on PATH',
23
+ remediation: `Install git (error: ${message})`,
24
+ };
25
+ }
26
+ let inWorkTree = false;
27
+ try {
28
+ inWorkTree = deps.isInWorkTree(ctx.cwd);
29
+ }
30
+ catch {
31
+ inWorkTree = false;
32
+ }
33
+ if (!inWorkTree) {
34
+ return {
35
+ name: 'GIT',
36
+ status: 'warn',
37
+ detail: `${version} (cwd is not a git work tree)`,
38
+ remediation: 'Run `git init` to enable diff-based commands',
39
+ };
40
+ }
41
+ const sha = (() => {
42
+ try {
43
+ return deps.resolveHeadSha(ctx.cwd);
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ })();
49
+ const root = (() => {
50
+ try {
51
+ return deps.resolveRoot(ctx.cwd);
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ })();
57
+ const shaSuffix = sha ? ` @ ${sha.slice(0, 8)}` : '';
58
+ const rootSuffix = root ? ` (${root})` : '';
59
+ return {
60
+ name: 'GIT',
61
+ status: 'ok',
62
+ detail: `${version}${shaSuffix}${rootSuffix}`,
63
+ };
64
+ }
65
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1,118 @@
1
+ /**
2
+ * HOOKS probe — verifies `.pugi/hooks-mvp.json` and `.pugi/hook-chains.json`
3
+ * exist + parse + carry their declared shape. Absence is OK (most workspaces
4
+ * don't ship hooks); presence с invalid JSON is a deployment-blocking error
5
+ * the operator wants surfaced before a tool dispatch fires a malformed hook
6
+ * and the model sees a confusing failure.
7
+ *
8
+ * Validation tier:
9
+ * 1. JSON.parse — catches typos / trailing commas / bad escapes.
10
+ * 2. Top-level shape sniff — `hooks-mvp.json` MUST be an object с a
11
+ * `hooks` array property; `hook-chains.json` MUST be an object
12
+ * с string-keyed event names mapping to arrays.
13
+ * 3. Per-entry require-fields sniff — minimal так что probe stays cheap.
14
+ *
15
+ * Out of scope: full Zod schema validation. That lives in the hook loader
16
+ * itself (apps/pugi-cli/src/core/hooks/v2/loader.ts). The probe is a
17
+ * fast sanity check; the loader produces the canonical error message
18
+ * when a hook actually fires.
19
+ */
20
+ function loadHookFile(fs, path) {
21
+ if (!fs.existsSync(path))
22
+ return null;
23
+ try {
24
+ const raw = fs.readFileSync(path, 'utf8');
25
+ return { path, parsed: JSON.parse(raw) };
26
+ }
27
+ catch (error) {
28
+ const message = error instanceof Error ? error.message : String(error);
29
+ return { parseError: `${path}: ${message}` };
30
+ }
31
+ }
32
+ function validateMvpShape(parsed) {
33
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
34
+ return 'top-level value must be an object';
35
+ }
36
+ const hooks = parsed['hooks'];
37
+ if (hooks !== undefined && !Array.isArray(hooks)) {
38
+ return '`hooks` property must be an array when present';
39
+ }
40
+ return null;
41
+ }
42
+ function validateChainsShape(parsed) {
43
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
44
+ return 'top-level value must be an object';
45
+ }
46
+ for (const [event, body] of Object.entries(parsed)) {
47
+ if (!Array.isArray(body)) {
48
+ return `event "${event}": value must be an array of hook entries`;
49
+ }
50
+ }
51
+ return null;
52
+ }
53
+ export function probeHooks(ctx, fs) {
54
+ const mvpPath = `${ctx.cwd}/.pugi/hooks-mvp.json`;
55
+ const chainsPath = `${ctx.cwd}/.pugi/hook-chains.json`;
56
+ const mvp = loadHookFile(fs, mvpPath);
57
+ const chains = loadHookFile(fs, chainsPath);
58
+ const issues = [];
59
+ let mvpCount = 0;
60
+ let chainEvents = 0;
61
+ if (mvp !== null) {
62
+ if ('parseError' in mvp) {
63
+ issues.push(`hooks-mvp.json parse failed: ${mvp.parseError}`);
64
+ }
65
+ else {
66
+ const shapeIssue = validateMvpShape(mvp.parsed);
67
+ if (shapeIssue) {
68
+ issues.push(`hooks-mvp.json: ${shapeIssue}`);
69
+ }
70
+ else {
71
+ const hooksArr = mvp.parsed['hooks'];
72
+ mvpCount = Array.isArray(hooksArr) ? hooksArr.length : 0;
73
+ }
74
+ }
75
+ }
76
+ if (chains !== null) {
77
+ if ('parseError' in chains) {
78
+ issues.push(`hook-chains.json parse failed: ${chains.parseError}`);
79
+ }
80
+ else {
81
+ const shapeIssue = validateChainsShape(chains.parsed);
82
+ if (shapeIssue) {
83
+ issues.push(`hook-chains.json: ${shapeIssue}`);
84
+ }
85
+ else {
86
+ chainEvents = Object.keys(chains.parsed).length;
87
+ }
88
+ }
89
+ }
90
+ if (issues.length > 0) {
91
+ return {
92
+ name: 'HOOKS',
93
+ status: 'error',
94
+ detail: issues.join('; '),
95
+ remediation: 'Fix the JSON syntax / shape, or delete the file if hooks are not in use. The hook loader surfaces the canonical error when a hook actually fires; this probe catches the problem before the first dispatch.',
96
+ };
97
+ }
98
+ if (mvp === null && chains === null) {
99
+ return {
100
+ name: 'HOOKS',
101
+ status: 'skipped',
102
+ detail: 'no hook config files in .pugi/ (workspace has not opted into hooks)',
103
+ };
104
+ }
105
+ const parts = [];
106
+ if (mvp !== null && !('parseError' in mvp)) {
107
+ parts.push(`hooks-mvp.json OK (${mvpCount} entr${mvpCount === 1 ? 'y' : 'ies'})`);
108
+ }
109
+ if (chains !== null && !('parseError' in chains)) {
110
+ parts.push(`hook-chains.json OK (${chainEvents} event${chainEvents === 1 ? '' : 's'})`);
111
+ }
112
+ return {
113
+ name: 'HOOKS',
114
+ status: 'ok',
115
+ detail: parts.join('; '),
116
+ };
117
+ }
118
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1,75 @@
1
+ /**
2
+ * MCP probe — reports the configured Model Context Protocol servers
3
+ * along with their trust + connection state.
4
+ *
5
+ * Sibling L13 (MCP server config) ships its own command surface; this
6
+ * probe consumes the existing `loadMcpRegistry` helper в a graceful
7
+ * try/catch so an unconfigured workspace (no `.pugi/mcp.json` OR an
8
+ * empty `servers: {}` map) lands as `ok` with detail "no servers
9
+ * configured" rather than a noisy failure row.
10
+ *
11
+ * Failure modes:
12
+ * - registry helper throws → `warn` with the error message;
13
+ * the table renderer surfaces the remediation hint;
14
+ * - one or more servers report `lastError` → `warn` summarising the
15
+ * count;
16
+ * - all configured servers connected cleanly → `ok` listing them.
17
+ */
18
+ export async function probeMcp(ctx, deps) {
19
+ let registry;
20
+ try {
21
+ // `connect: false` keeps the probe cheap — we only need the
22
+ // declared config + trust ledger entries, not live subprocess
23
+ // handshakes. The doctor sweep budget shouldn't be eaten by
24
+ // server-spawn latency.
25
+ registry = await deps.loadRegistry(ctx.cwd, { connect: false });
26
+ }
27
+ catch (error) {
28
+ const message = error instanceof Error ? error.message : String(error);
29
+ return {
30
+ name: 'MCP SERVERS',
31
+ status: 'warn',
32
+ detail: 'MCP registry not loadable (config or schema error)',
33
+ remediation: `Inspect .pugi/mcp.json: ${message}`,
34
+ };
35
+ }
36
+ const servers = Array.from(registry.servers.values());
37
+ // Best-effort shutdown — even with `connect: false` we still own the
38
+ // registry handle. Swallow errors so a clean-up failure never
39
+ // poisons the probe verdict.
40
+ await registry.shutdown().catch(() => { });
41
+ if (servers.length === 0) {
42
+ return {
43
+ name: 'MCP SERVERS',
44
+ status: 'ok',
45
+ detail: 'No MCP servers configured',
46
+ };
47
+ }
48
+ const labels = servers.map((server) => `${server.name}:${server.trust}`);
49
+ const trusted = servers.filter((server) => server.trust === 'trusted');
50
+ const pending = servers.filter((server) => server.trust === 'pending');
51
+ const denied = servers.filter((server) => server.trust === 'denied');
52
+ const failing = servers.filter((server) => typeof server.lastError === 'string' && server.lastError.length > 0);
53
+ if (failing.length > 0) {
54
+ return {
55
+ name: 'MCP SERVERS',
56
+ status: 'warn',
57
+ detail: `${failing.length}/${servers.length} server(s) reporting errors: ${labels.join(', ')}`,
58
+ remediation: `Inspect: \`pugi mcp list\``,
59
+ };
60
+ }
61
+ if (pending.length > 0) {
62
+ return {
63
+ name: 'MCP SERVERS',
64
+ status: 'warn',
65
+ detail: `${pending.length} pending trust decision(s): ${labels.join(', ')}`,
66
+ remediation: 'Run `pugi mcp trust <name>` or `pugi mcp deny <name>`',
67
+ };
68
+ }
69
+ return {
70
+ name: 'MCP SERVERS',
71
+ status: 'ok',
72
+ detail: `${trusted.length} trusted, ${denied.length} denied (${labels.join(', ')})`,
73
+ };
74
+ }
75
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * NODE probe — verifies the running Node major version meets the
3
+ * `engines.node` floor declared in @pugi/cli's package.json.
4
+ *
5
+ * We bake the floor in as a constant rather than reading package.json
6
+ * at runtime because the published .tgz strips the file from a location
7
+ * the compiled bundle can reach (`--resolveJsonModule` is off for the
8
+ * CLI build). The lockstep is enforced by
9
+ * `scripts/check-version-lockstep.sh` in the publish pipeline.
10
+ */
11
+ /**
12
+ * Minimum supported Node major. Mirrors `engines.node` in
13
+ * apps/pugi-cli/package.json (`">=22.5.0"`).
14
+ */
15
+ export const MIN_NODE_MAJOR = 22;
16
+ export const MIN_NODE_MINOR = 5;
17
+ /**
18
+ * Parse a Node version string of the form `v<major>.<minor>.<patch>`.
19
+ * Returns null when the input doesn't match — the caller treats null
20
+ * as an error condition.
21
+ */
22
+ export function parseNodeVersion(version) {
23
+ const match = /^v(\d+)\.(\d+)\./.exec(version);
24
+ if (!match)
25
+ return null;
26
+ const major = Number(match[1]);
27
+ const minor = Number(match[2]);
28
+ if (!Number.isFinite(major) || !Number.isFinite(minor))
29
+ return null;
30
+ return { major, minor };
31
+ }
32
+ export function probeNode(input) {
33
+ const parsed = parseNodeVersion(input.version);
34
+ if (!parsed) {
35
+ return {
36
+ name: 'NODE',
37
+ status: 'error',
38
+ detail: `Unparseable Node version "${input.version}"`,
39
+ remediation: `Install Node >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}.0 (current binary returns a non-semver version string)`,
40
+ };
41
+ }
42
+ const { major, minor } = parsed;
43
+ const passes = major > MIN_NODE_MAJOR ||
44
+ (major === MIN_NODE_MAJOR && minor >= MIN_NODE_MINOR);
45
+ if (passes) {
46
+ return {
47
+ name: 'NODE',
48
+ status: 'ok',
49
+ detail: `${input.version} (>= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}.0 required)`,
50
+ };
51
+ }
52
+ return {
53
+ name: 'NODE',
54
+ status: 'error',
55
+ detail: `${input.version} below floor >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}.0`,
56
+ remediation: `Upgrade Node: \`nvm install ${MIN_NODE_MAJOR}\` or download from nodejs.org`,
57
+ };
58
+ }
59
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1,36 @@
1
+ /**
2
+ * PNPM probe — verifies pnpm is on PATH and reports its version. The
3
+ * customer-facing CLI doesn't strictly require pnpm at runtime
4
+ * (`@pugi/cli` is published as a regular npm package), but a missing
5
+ * pnpm means `pugi code` cannot run `pnpm test` / `pnpm typecheck`
6
+ * gates the agent loop emits. Surfacing this early prevents the
7
+ * agent from issuing a meaningless `command not found: pnpm` error
8
+ * three turns into a session.
9
+ */
10
+ export function probePnpm(deps) {
11
+ try {
12
+ const version = deps.resolveVersion();
13
+ if (!version) {
14
+ return {
15
+ name: 'PNPM',
16
+ status: 'warn',
17
+ detail: 'pnpm reported empty version string',
18
+ };
19
+ }
20
+ return {
21
+ name: 'PNPM',
22
+ status: 'ok',
23
+ detail: `pnpm ${version}`,
24
+ };
25
+ }
26
+ catch (error) {
27
+ const message = error instanceof Error ? error.message : String(error);
28
+ return {
29
+ name: 'PNPM',
30
+ status: 'warn',
31
+ detail: 'pnpm not on PATH — agent quality gates will be skipped',
32
+ remediation: `Install pnpm: \`npm i -g pnpm\` (error: ${message})`,
33
+ };
34
+ }
35
+ }
36
+ //# sourceMappingURL=pnpm.js.map