@pugi/cli 0.1.0-beta.7 → 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 +4162 -488
  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,145 @@
1
+ /**
2
+ * Default byte cap for the engine system-prompt injection. The L28
3
+ * spec calls for 2000 tokens; conservatively that is ~8 KB of UTF-8
4
+ * (rough Claude tokeniser ratio: ~4 chars per token). We cap at 8 KB
5
+ * so the formatted block stays under the token budget across every
6
+ * supported model family without per-model accounting.
7
+ */
8
+ export const DEFAULT_FORMAT_BYTES_CAP = 8 * 1024;
9
+ /**
10
+ * Maximum symbols per row. The engine row format is:
11
+ *
12
+ * `- path/to/file.ts — summary line — exports: Foo(class), bar(fn)`
13
+ *
14
+ * Beyond 6 symbols the row grows past the readable column budget and
15
+ * the additional names rarely move the needle for the model — the
16
+ * exports tail is signal-bearing only for the first few entries
17
+ * anyway (`index.ts` re-exports tend к pile up).
18
+ */
19
+ export const MAX_SYMBOLS_PER_ROW = 6;
20
+ /**
21
+ * Render the repo-map text. The implementation is intentionally split
22
+ * into:
23
+ *
24
+ * - `prioritise(...)` — pure sort + filter, fully testable in
25
+ * isolation, no I/O of any kind.
26
+ * - `renderRow(...)` — one file's row, byte-counted.
27
+ * - main loop — assembles header + rows + footer, respecting cap.
28
+ *
29
+ * The split lets the spec assert each stage in isolation (priority
30
+ * order, single-row shape, truncation arithmetic).
31
+ */
32
+ export function formatRepoMap(extracts, options = {}) {
33
+ const maxBytes = options.maxBytes ?? DEFAULT_FORMAT_BYTES_CAP;
34
+ const omitHeader = options.omitHeader === true;
35
+ const prioritised = prioritise(extracts);
36
+ const header = omitHeader
37
+ ? ''
38
+ : `## Repo map\n\n${prioritised.length} source files indexed.\n\n`;
39
+ const headerBytes = byteLength(header);
40
+ if (headerBytes >= maxBytes) {
41
+ // Cap is smaller than even the header — emit nothing rather than
42
+ // a truncated header that the engine cannot parse.
43
+ return {
44
+ text: '',
45
+ filesIncluded: 0,
46
+ filesTotal: extracts.length,
47
+ bytes: 0,
48
+ truncated: extracts.length > 0,
49
+ };
50
+ }
51
+ const rows = [];
52
+ let bytesUsed = headerBytes;
53
+ let filesIncluded = 0;
54
+ let truncated = false;
55
+ for (let i = 0; i < prioritised.length; i += 1) {
56
+ const row = renderRow(prioritised[i]);
57
+ const rowBytes = byteLength(row);
58
+ // Reserve space for the footer (`\n... N more files\n`). We
59
+ // overestimate at 64 bytes — the exact number depends on the
60
+ // file count digits but 64 covers any realistic case.
61
+ const footerReserve = i + 1 < prioritised.length ? 64 : 0;
62
+ if (bytesUsed + rowBytes + footerReserve > maxBytes) {
63
+ truncated = true;
64
+ break;
65
+ }
66
+ rows.push(row);
67
+ bytesUsed += rowBytes;
68
+ filesIncluded += 1;
69
+ }
70
+ let text = header + rows.join('');
71
+ if (truncated) {
72
+ const omitted = prioritised.length - filesIncluded;
73
+ text += `\n... ${omitted} more file${omitted === 1 ? '' : 's'}\n`;
74
+ }
75
+ return {
76
+ text,
77
+ filesIncluded,
78
+ filesTotal: extracts.length,
79
+ bytes: byteLength(text),
80
+ truncated,
81
+ };
82
+ }
83
+ /* ----------------------------- helpers ----------------------------- */
84
+ /**
85
+ * Sort the extracts by (exported-symbol count desc, path asc). The
86
+ * engine cares about the public surface; a file with 12 exported
87
+ * symbols carries more signal than 50 private helpers.
88
+ */
89
+ export function prioritise(extracts) {
90
+ return [...extracts].sort((a, b) => {
91
+ const expA = countExports(a);
92
+ const expB = countExports(b);
93
+ if (expA !== expB)
94
+ return expB - expA;
95
+ return a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0;
96
+ });
97
+ }
98
+ function countExports(extract) {
99
+ let n = 0;
100
+ for (const sym of extract.symbols)
101
+ if (sym.exported)
102
+ n += 1;
103
+ return n;
104
+ }
105
+ /**
106
+ * Render a single file row. Format:
107
+ *
108
+ * `- path/to/file.ts — summary — exports: Foo(class), bar(fn), Baz(type)`
109
+ *
110
+ * When there are no exported symbols, the `exports:` tail is dropped.
111
+ * When there is no summary, the dash separator is dropped.
112
+ */
113
+ export function renderRow(extract) {
114
+ const exported = extract.symbols.filter((s) => s.exported);
115
+ const symbolsTail = exported.length > 0
116
+ ? ` — exports: ${formatSymbolList(exported.slice(0, MAX_SYMBOLS_PER_ROW))}`
117
+ : '';
118
+ const summaryTail = extract.summary ? ` — ${extract.summary}` : '';
119
+ return `- ${extract.relPath}${summaryTail}${symbolsTail}\n`;
120
+ }
121
+ function formatSymbolList(symbols) {
122
+ return symbols.map((s) => `${s.name}(${shortKind(s.kind)})`).join(', ');
123
+ }
124
+ function shortKind(kind) {
125
+ switch (kind) {
126
+ case 'function':
127
+ return 'fn';
128
+ case 'class':
129
+ return 'class';
130
+ case 'interface':
131
+ return 'iface';
132
+ case 'type':
133
+ return 'type';
134
+ case 'enum':
135
+ return 'enum';
136
+ case 'const':
137
+ return 'const';
138
+ case 'heading':
139
+ return 'h';
140
+ }
141
+ }
142
+ function byteLength(s) {
143
+ return Buffer.byteLength(s, 'utf8');
144
+ }
145
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1,105 @@
1
+ /**
2
+ * PageRank scorer для repo-map (#60 Phase 2).
3
+ *
4
+ * Thin wrapper around `graphology` + `graphology-metrics` PageRank
5
+ * implementation. We do NOT roll our own power-iteration loop —
6
+ * graphology's centrality module is the maintained, well-tested
7
+ * standard в the JS ecosystem (Yomguithereal, MIT, 2k+ stars).
8
+ *
9
+ * What this module adds on top of the library:
10
+ * - Pugi domain types (PageRankNode / PageRankEdge with optional weight)
11
+ * - File-level aggregation (aggregateByFile) — sums symbol scores per file
12
+ * - Output normalization (normalizeScores) к [0, 100] range для prompt
13
+ * table rendering per docs/features/feat-pugi-ranked-repo-map.md §4
14
+ *
15
+ * No I/O, no globals. Safe to call from worker threads.
16
+ */
17
+ import * as graphologyModule from 'graphology';
18
+ import * as pagerankModule from 'graphology-metrics/centrality/pagerank.js';
19
+ const graphologyAny = graphologyModule;
20
+ const Graph = graphologyAny.default ?? graphologyModule;
21
+ const pagerankAny = pagerankModule;
22
+ const pagerankCentrality = pagerankAny.default ?? pagerankModule;
23
+ const DEFAULT_DAMPING = 0.85;
24
+ const DEFAULT_MAX_ITERATIONS = 100;
25
+ const DEFAULT_TOLERANCE = 1e-6;
26
+ export function pageRank(nodes, edges, options = {}) {
27
+ const damping = options.damping ?? DEFAULT_DAMPING;
28
+ const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
29
+ const tolerance = options.tolerance ?? DEFAULT_TOLERANCE;
30
+ if (damping < 0 || damping >= 1) {
31
+ throw new RangeError(`damping must be в [0, 1), got ${damping}`);
32
+ }
33
+ if (maxIterations < 1) {
34
+ throw new RangeError(`maxIterations must be >= 1, got ${maxIterations}`);
35
+ }
36
+ if (tolerance <= 0) {
37
+ throw new RangeError(`tolerance must be > 0, got ${tolerance}`);
38
+ }
39
+ const scores = new Map();
40
+ if (nodes.length === 0) {
41
+ return { scores };
42
+ }
43
+ const seen = new Set();
44
+ for (const node of nodes) {
45
+ if (seen.has(node.id)) {
46
+ throw new Error('duplicate node ids — pageRank requires unique node.id');
47
+ }
48
+ seen.add(node.id);
49
+ }
50
+ const graph = new Graph({ type: 'directed', multi: true, allowSelfLoops: true });
51
+ for (const node of nodes) {
52
+ graph.addNode(node.id);
53
+ }
54
+ for (const edge of edges) {
55
+ if (!seen.has(edge.from) || !seen.has(edge.to)) {
56
+ continue;
57
+ }
58
+ const weight = edge.weight ?? 1;
59
+ if (weight <= 0)
60
+ continue;
61
+ graph.addEdge(edge.from, edge.to, { weight });
62
+ }
63
+ pagerankCentrality.assign(graph, {
64
+ alpha: damping,
65
+ maxIterations,
66
+ tolerance,
67
+ getEdgeWeight: 'weight',
68
+ nodePageRankAttribute: 'pagerank',
69
+ });
70
+ for (const id of graph.nodes()) {
71
+ const score = graph.getNodeAttribute(id, 'pagerank');
72
+ scores.set(id, typeof score === 'number' ? score : 0);
73
+ }
74
+ return { scores };
75
+ }
76
+ export function aggregateByFile(symbolScores, symbolToFile) {
77
+ const fileScores = new Map();
78
+ for (const [symbolId, score] of symbolScores) {
79
+ const file = symbolToFile.get(symbolId);
80
+ if (file === undefined)
81
+ continue;
82
+ fileScores.set(file, (fileScores.get(file) ?? 0) + score);
83
+ }
84
+ return fileScores;
85
+ }
86
+ export function normalizeScores(scores) {
87
+ const normalized = new Map();
88
+ if (scores.size === 0)
89
+ return normalized;
90
+ let max = 0;
91
+ for (const score of scores.values()) {
92
+ if (score > max)
93
+ max = score;
94
+ }
95
+ if (max === 0) {
96
+ for (const id of scores.keys())
97
+ normalized.set(id, 0);
98
+ return normalized;
99
+ }
100
+ for (const [id, score] of scores) {
101
+ normalized.set(id, (score / max) * 100);
102
+ }
103
+ return normalized;
104
+ }
105
+ //# sourceMappingURL=page-rank.js.map
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Repo-map scanner — .
3
+ *
4
+ * Walks the workspace via `fs.readdirSync` (sync, depth-first), filters
5
+ * to a recognised set of source-language extensions, and applies the
6
+ * shared `PugiIgnore` matcher so the same exclusion rules used by the
7
+ * three-tier context skeleton also gate the repo-map.
8
+ *
9
+ * Why a stand-alone scanner (vs. reusing the skeleton walker):
10
+ *
11
+ * 1. The skeleton walker emits a flat `IndexArtifact[]` of every
12
+ * ignore-respecting file (markdown, configs, schemas, etc.) for
13
+ * the working-set heuristic. The repo-map ONLY needs source
14
+ * files — markdown headings and JSON keys are not "definitions"
15
+ * in the L28 sense. Filtering downstream is cheap, but the
16
+ * scanner gets to short-circuit on extension before stat'ing
17
+ * the file, which matters for monorepos with thousands of
18
+ * non-source artefacts (lockfiles, schemas, fixtures).
19
+ *
20
+ * 2. We need mtime + size per file so `cache.ts` can invalidate
21
+ * stale entries without re-parsing. The skeleton walker
22
+ * surfaces only paths.
23
+ *
24
+ * 3. The L28 contract caps the walk at `MAX_SRC_FILES` (5000) and
25
+ * individual files at `MAX_FILE_BYTES` (200 KiB). When the cap
26
+ * trips the scanner returns a `{ skipped: 'too-large' }`
27
+ * verdict rather than partial data — the consumer must decide
28
+ * whether to fall back to a no-op map or surface a hint к the
29
+ * operator. Surfacing partial data would silently bias the
30
+ * injected summary toward whichever subtree the walker happened
31
+ * to traverse first.
32
+ *
33
+ * The output is sorted (POSIX path string compare) so two runs over
34
+ * the same workspace produce byte-identical `repo-map.json` caches —
35
+ * `cache.ts` relies on stable ordering for its hash-free freshness
36
+ * check. POSIX-style separators are used in `relPath` regardless of
37
+ * platform so the cache file stays portable.
38
+ *
39
+ * Pure module surface: no logging, no network. Errors during readdir
40
+ * on a single subtree (permission denied, symlink loop) are swallowed
41
+ * and the walker continues — repo-map is a best-effort context
42
+ * enrichment, never a gate.
43
+ */
44
+ import { readdirSync, statSync } from 'node:fs';
45
+ import { join, posix, relative, resolve, sep } from 'node:path';
46
+ /**
47
+ * Hard ceiling on total source files surfaced by a single scan. The
48
+ * engine context budget is the binding constraint — a 5K-file repo
49
+ * already overflows the 2K-token injection cap so going higher buys
50
+ * nothing but walker latency. Repos above the cap fall back к the
51
+ * `{ skipped: 'too-large' }` verdict.
52
+ */
53
+ export const MAX_SRC_FILES = 5000;
54
+ /**
55
+ * Per-file size cap. Files larger than this are skipped — they are
56
+ * almost always generated (compiled JS, vendored libs, encoded blobs)
57
+ * and add noise without signal. The 200 KiB threshold mirrors the
58
+ * skeleton walker's own `MAX_FILE_BYTES` so the two scans agree
59
+ * on "what counts as a source file".
60
+ */
61
+ export const MAX_FILE_BYTES = 200 * 1024;
62
+ /**
63
+ * Source-language extensions the extractor knows how to parse. Adding
64
+ * a language here without a matching extractor branch is a silent
65
+ * no-op (the file shows up в the scan but extracts zero symbols);
66
+ * the spec asserts the symmetry so a future PR cannot drift the two
67
+ * lists out of sync.
68
+ */
69
+ export const SUPPORTED_EXTENSIONS = Object.freeze([
70
+ '.ts',
71
+ '.tsx',
72
+ '.js',
73
+ '.jsx',
74
+ '.mjs',
75
+ '.cjs',
76
+ '.md',
77
+ '.mdx',
78
+ ]);
79
+ const defaultReaddir = (path) => readdirSync(path, { withFileTypes: true });
80
+ const defaultStat = (path) => {
81
+ const s = statSync(path);
82
+ return { size: s.size, mtimeMs: s.mtimeMs };
83
+ };
84
+ /**
85
+ * Walk the workspace once and return every source file the extractor
86
+ * is willing to parse. The function is deliberately synchronous —
87
+ * the underlying walks are CPU-bound, не I/O-bound, and the sync
88
+ * call avoids the promise overhead that dominates for thousands of
89
+ * small files. The L28 engine boot path runs this on a Node `setImmediate`
90
+ * so the main thread is not blocked.
91
+ */
92
+ export function scanRepoForMap(options) {
93
+ const root = resolve(options.root);
94
+ const readdir = options.readdir ?? defaultReaddir;
95
+ const stat = options.stat ?? defaultStat;
96
+ const maxFiles = options.maxFiles ?? MAX_SRC_FILES;
97
+ const maxFileBytes = options.maxFileBytes ?? MAX_FILE_BYTES;
98
+ const ignore = options.ignore;
99
+ const files = [];
100
+ let walked = 0;
101
+ let skippedLarge = 0;
102
+ let skippedIgnored = 0;
103
+ let tooLarge = false;
104
+ /**
105
+ * Depth-first recursion. We push dirs into a manual stack instead of
106
+ * recursing in JS because deep monorepos (Nx with 100+ packages)
107
+ * have approached the v8 default stack limit on Windows runners
108
+ * before; an explicit stack is one less thing to debug.
109
+ */
110
+ const stack = [root];
111
+ while (stack.length > 0) {
112
+ const dir = stack.pop();
113
+ let entries;
114
+ try {
115
+ entries = readdir(dir);
116
+ }
117
+ catch {
118
+ // Permission denied / symlink loop / mid-flight delete — keep
119
+ // walking. Repo-map is best-effort context, never a gate.
120
+ continue;
121
+ }
122
+ for (const entry of entries) {
123
+ const abs = join(dir, entry.name);
124
+ const isDir = entry.isDirectory();
125
+ if (ignore.isIgnored(abs, isDir)) {
126
+ skippedIgnored += 1;
127
+ continue;
128
+ }
129
+ if (isDir) {
130
+ stack.push(abs);
131
+ continue;
132
+ }
133
+ if (!entry.isFile()) {
134
+ // Symlinks, sockets, FIFOs etc. Skip silently — they are not
135
+ // source code and stat'ing them can throw on broken links.
136
+ continue;
137
+ }
138
+ walked += 1;
139
+ const ext = extOf(entry.name);
140
+ if (!SUPPORTED_EXTENSIONS.includes(ext)) {
141
+ continue;
142
+ }
143
+ let statResult;
144
+ try {
145
+ statResult = stat(abs);
146
+ }
147
+ catch {
148
+ // File vanished between readdir and stat — skip.
149
+ continue;
150
+ }
151
+ if (statResult.size > maxFileBytes) {
152
+ skippedLarge += 1;
153
+ continue;
154
+ }
155
+ // Workspace-relative POSIX path. `relative` returns the host
156
+ // separator on Windows; normalise to forward slashes so the
157
+ // cache file is portable.
158
+ const rel = relative(root, abs).split(sep).join(posix.sep);
159
+ files.push({
160
+ relPath: rel,
161
+ absPath: abs,
162
+ ext,
163
+ sizeBytes: statResult.size,
164
+ mtimeMs: statResult.mtimeMs,
165
+ });
166
+ if (files.length > maxFiles) {
167
+ tooLarge = true;
168
+ break;
169
+ }
170
+ }
171
+ if (tooLarge)
172
+ break;
173
+ }
174
+ if (tooLarge) {
175
+ return {
176
+ ok: false,
177
+ root,
178
+ skipped: {
179
+ reason: 'too-large',
180
+ walked,
181
+ },
182
+ };
183
+ }
184
+ // Sort by POSIX path for stable cache output. Two runs over the
185
+ // same workspace yield byte-identical JSON so the cache hash check
186
+ // is a simple `mtime + size` per entry without a content digest.
187
+ files.sort((a, b) => (a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0));
188
+ return {
189
+ ok: true,
190
+ root,
191
+ files,
192
+ stats: {
193
+ walked,
194
+ kept: files.length,
195
+ skippedLarge,
196
+ skippedIgnored,
197
+ },
198
+ };
199
+ }
200
+ /**
201
+ * Lowercase extension including the leading dot, or '' when the
202
+ * filename has no extension. Mirrors `node:path.extname` semantics —
203
+ * inlined so the scanner has zero per-iteration call overhead.
204
+ */
205
+ function extOf(name) {
206
+ const dot = name.lastIndexOf('.');
207
+ if (dot < 0 || dot === 0)
208
+ return '';
209
+ return name.slice(dot).toLowerCase();
210
+ }
211
+ //# sourceMappingURL=scanner.js.map