@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,367 @@
1
+ /**
2
+ * Prompt-injection scanner — TypeScript implementation of external
3
+ * `injection_patterns.rs` (Apache-2.0, external).
4
+ *
5
+ * Upstream source:
6
+ * `_primitives/_rust/kei-memory/src/injection_patterns.rs`
7
+ * from https://github.com/an internal mirror.
8
+ *
9
+ * Scope of the port:
10
+ * - Pattern TABLES are ported verbatim (regex + invisible-codepoint
11
+ * set + ChatML tags + role-prefix patterns). The substring/secret
12
+ * rows (curl-with-bearer, aws_secret keyword, api_key URL, openssh
13
+ * PEM markers, long-base64 blob heuristic) are KEPT in this port —
14
+ * they harden writes through memory/audit paths against accidental
15
+ * credential pasting.
16
+ * - Detection logic is rewritten in TypeScript. The Rust upstream
17
+ * uses `regex::Regex` + a separate `injection_guard.rs` that owns
18
+ * the "should I block?" decision. Pugi's port collapses both
19
+ * responsibilities into a single function (`scanForInjection`)
20
+ * because the caller surfaces (audit-trail, file-tools) only need
21
+ * the findings list — they do not block writes today (CEO sign-off
22
+ * gate, separate PR).
23
+ *
24
+ * Severity model:
25
+ * The upstream `Block` / `Warn` enum is mirrored as a Pugi field on
26
+ * each finding so a future PR can wire hard-block behavior without
27
+ * re-shaping the call sites.
28
+ *
29
+ * What this is NOT:
30
+ * - An LLM-output safety filter. This scans CONTENT BOUND FOR DISK
31
+ * (audit payloads + file writes / edits) for accidental or
32
+ * adversarial prompt-injection markers.
33
+ * - A secrets scanner. Real secrets detection lives in
34
+ * `scripts/secret-scanner.mjs` (release gate). The few credential
35
+ * heuristics here exist because the upstream Rust treats memory
36
+ * persistence as a credential-exfil surface too.
37
+ *
38
+ * See bundled LICENSE notices.0 attribution.
39
+ */
40
+ /**
41
+ * Maximum captured-match length recorded in a finding. Bounds the
42
+ * worst-case row size in the audit JSONL stream. Set to 128 because
43
+ * the longest legitimate pattern match (`long_base64_line`) would be
44
+ * 1024+ bytes — the operator can re-scan the source content for the
45
+ * full blob if they need it; we only need enough context to triage.
46
+ */
47
+ export const MAX_MATCH_CAPTURE = 128;
48
+ function clampMatch(matched) {
49
+ if (matched.length <= MAX_MATCH_CAPTURE)
50
+ return matched;
51
+ return `${matched.slice(0, MAX_MATCH_CAPTURE)}…`;
52
+ }
53
+ /**
54
+ * Invisible / bidi / zero-width unicode codepoints ported verbatim
55
+ * from `INVISIBLE_CHARS` in the upstream Rust. Each one is a known
56
+ * vehicle for hiding prompt-override text from a casual reader.
57
+ */
58
+ export const INVISIBLE_CHARS = [
59
+ '​', // ZERO WIDTH SPACE
60
+ '‌', // ZERO WIDTH NON-JOINER
61
+ '‍', // ZERO WIDTH JOINER
62
+ '‎', // LEFT-TO-RIGHT MARK
63
+ '‏', // RIGHT-TO-LEFT MARK
64
+ '‪', // LEFT-TO-RIGHT EMBEDDING
65
+ '‫', // RIGHT-TO-LEFT EMBEDDING
66
+ '‬', // POP DIRECTIONAL FORMATTING
67
+ '‭', // LEFT-TO-RIGHT OVERRIDE
68
+ '‮', // RIGHT-TO-LEFT OVERRIDE
69
+ '⁠', // WORD JOINER
70
+ '', // BYTE ORDER MARK / ZERO WIDTH NO-BREAK SPACE
71
+ ];
72
+ /**
73
+ * Pre-built Set for O(1) codepoint membership tests. The scanner walks
74
+ * the input once and probes this set per character — cheaper than a
75
+ * regex with 12 alternation branches.
76
+ */
77
+ const INVISIBLE_CHAR_SET = new Set(INVISIBLE_CHARS);
78
+ /**
79
+ * Threshold above which a single base64-looking line is flagged.
80
+ * Matches the upstream `BASE64_BLOB_BYTES` constant so the heuristic
81
+ * stays aligned with the Rust spec. The regex below hardcodes the
82
+ * same value for compile-time clarity.
83
+ */
84
+ export const BASE64_BLOB_BYTES = 1024;
85
+ /**
86
+ * PEM begin marker built at runtime so the literal dashes do not
87
+ * trigger over-eager secret-scanners in this very source file (same
88
+ * concern as the upstream `pem_dashes()` helper).
89
+ */
90
+ function pemMarker(label) {
91
+ const d = '-'.repeat(5);
92
+ return `${d}BEGIN ${label}${d}`;
93
+ }
94
+ /**
95
+ * Escape regex metachars in a literal string. We avoid pulling a
96
+ * dependency just for this — the set of metachars is small and
97
+ * well-known.
98
+ */
99
+ function escapeRegex(literal) {
100
+ return literal.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
101
+ }
102
+ /**
103
+ * Prompt-override patterns. Ported verbatim from
104
+ * `prompt_override_patterns()` in the upstream Rust. The regex
105
+ * strings are the same modulo Rust's `(?im)` inline flags being
106
+ * expressed as `i` + `m` on the TS `RegExp`.
107
+ */
108
+ const PROMPT_OVERRIDE_PATTERNS = [
109
+ {
110
+ id: 'prompt_override_ignore_previous',
111
+ kind: 'override-prompt',
112
+ re: /ignore\s+previous\s+instructions/gi,
113
+ severity: 'block',
114
+ source: 'promptguard:override',
115
+ },
116
+ {
117
+ id: 'prompt_override_you_are_now',
118
+ kind: 'override-prompt',
119
+ re: /you\s+are\s+now\b/gi,
120
+ severity: 'block',
121
+ source: 'promptguard:roleplay',
122
+ },
123
+ {
124
+ id: 'prompt_override_disregard',
125
+ kind: 'override-prompt',
126
+ re: /disregard\s+(all|prior|above)/gi,
127
+ severity: 'block',
128
+ source: 'promptguard:override',
129
+ },
130
+ {
131
+ id: 'system_role_prefix',
132
+ kind: 'override-prompt',
133
+ re: /^\s*system\s*:/gim,
134
+ severity: 'block',
135
+ source: 'promptguard:role-prefix',
136
+ },
137
+ {
138
+ id: 'chatml_im_start',
139
+ kind: 'tag-injection',
140
+ re: /<\|im_start\|>/g,
141
+ severity: 'block',
142
+ source: 'chatml:tag',
143
+ },
144
+ {
145
+ id: 'chatml_endoftext',
146
+ kind: 'tag-injection',
147
+ re: /<\|endoftext\|>/g,
148
+ severity: 'block',
149
+ source: 'chatml:tag',
150
+ },
151
+ ];
152
+ /**
153
+ * Secret-shaped patterns. Ported from `secret_patterns()`. The PEM
154
+ * markers are built at runtime so they do not show up verbatim in
155
+ * this file's bytes (anti-self-trigger).
156
+ */
157
+ function buildSecretPatterns() {
158
+ const openssh = escapeRegex(pemMarker('OPENSSH PRIVATE KEY'));
159
+ const rsa = escapeRegex(pemMarker('RSA PRIVATE KEY'));
160
+ return [
161
+ {
162
+ id: 'ssh_openssh_private',
163
+ kind: 'secret-marker',
164
+ re: new RegExp(openssh, 'g'),
165
+ severity: 'block',
166
+ source: 'secret:openssh',
167
+ },
168
+ {
169
+ id: 'ssh_rsa_private',
170
+ kind: 'secret-marker',
171
+ re: new RegExp(rsa, 'g'),
172
+ severity: 'block',
173
+ source: 'secret:rsa',
174
+ },
175
+ {
176
+ // Upstream P2.1.b audit upgraded this to Block tier — long
177
+ // base64 blobs on a memory-write path are a direct exfil
178
+ // surface for attestation / key blobs pasted into transcripts.
179
+ id: 'long_base64_line',
180
+ kind: 'secret-marker',
181
+ re: new RegExp(`^[A-Za-z0-9+/=]{${BASE64_BLOB_BYTES},}$`, 'gm'),
182
+ severity: 'block',
183
+ source: 'heuristic:base64-blob',
184
+ },
185
+ ];
186
+ }
187
+ /**
188
+ * Substring/heuristic patterns. Ported from `build_substring_table()`.
189
+ * Each row demands ALL needles be present in the LOWERCASED copy of
190
+ * the input (AND semantics) — keeps false-positives low.
191
+ */
192
+ const SUBSTRING_PATTERNS = [
193
+ {
194
+ id: 'curl_with_bearer',
195
+ kind: 'secret-marker',
196
+ needles: ['bearer ', '://'],
197
+ severity: 'block',
198
+ source: 'exfil:curl-bearer',
199
+ },
200
+ {
201
+ id: 'aws_secret_keyword',
202
+ kind: 'secret-marker',
203
+ needles: ['aws_secret'],
204
+ severity: 'block',
205
+ source: 'secret:aws',
206
+ },
207
+ {
208
+ id: 'api_key_url',
209
+ kind: 'secret-marker',
210
+ needles: ['api_key=', '://'],
211
+ severity: 'block',
212
+ source: 'exfil:api-key-url',
213
+ },
214
+ ];
215
+ let REGEX_TABLE = null;
216
+ function regexPatterns() {
217
+ if (REGEX_TABLE === null) {
218
+ REGEX_TABLE = [...PROMPT_OVERRIDE_PATTERNS, ...buildSecretPatterns()];
219
+ }
220
+ return REGEX_TABLE;
221
+ }
222
+ /**
223
+ * Maximum input size we scan. Above this we sample the first
224
+ * MAX_SCAN_BYTES bytes and tag the result as `truncated: true`. This
225
+ * keeps a 10 MB log payload from stalling the audit append path.
226
+ *
227
+ * The threshold is deliberately generous (256 KB) — the typical audit
228
+ * `data` payload is a few hundred bytes (a single `tool_call` envelope)
229
+ * and a file write of an HTML page is well under the cap. The cutoff
230
+ * exists only for pathological cases.
231
+ */
232
+ export const MAX_SCAN_BYTES = 256 * 1024;
233
+ /**
234
+ * Scan a string for prompt-injection / invisible-unicode / secret
235
+ * markers. Returns the empty array when clean. Never throws —
236
+ * malformed input (e.g. lone surrogates) falls through to the regex
237
+ * engine and produces zero or more findings, never an exception.
238
+ *
239
+ * Pure function. Safe to call from a hot path (audit-trail append,
240
+ * file-tools writeTool) without worrying about side effects.
241
+ */
242
+ export function scanForInjection(text) {
243
+ if (typeof text !== 'string' || text.length === 0)
244
+ return [];
245
+ const findings = [];
246
+ const scanText = text.length > MAX_SCAN_BYTES ? text.slice(0, MAX_SCAN_BYTES) : text;
247
+ // 1. Invisible unicode scan: O(n) single pass with a Set lookup.
248
+ // We collect per-codepoint hits rather than collapsing them so
249
+ // the operator can see how many bidi marks are present (high
250
+ // counts strongly suggest adversarial intent).
251
+ for (let i = 0; i < scanText.length; i += 1) {
252
+ const ch = scanText[i];
253
+ if (ch === undefined)
254
+ continue;
255
+ if (INVISIBLE_CHAR_SET.has(ch)) {
256
+ const code = ch.charCodeAt(0).toString(16).toUpperCase().padStart(4, '0');
257
+ findings.push({
258
+ kind: 'invisible-unicode',
259
+ id: `invisible_unicode_U+${code}`,
260
+ severity: 'warn',
261
+ matched: ch,
262
+ offset: i,
263
+ source: `unicode:invisible:U+${code}`,
264
+ });
265
+ }
266
+ }
267
+ // 2. Regex table scan. Each pattern uses the `g` flag so we walk
268
+ // every occurrence — a single text can carry multiple ChatML
269
+ // tags or override phrases and the operator needs to see all of
270
+ // them, not just the first.
271
+ for (const pattern of regexPatterns()) {
272
+ // Re-set lastIndex defensively in case a prior call left the
273
+ // regex's stateful cursor mid-string.
274
+ pattern.re.lastIndex = 0;
275
+ let match;
276
+ while ((match = pattern.re.exec(scanText)) !== null) {
277
+ findings.push({
278
+ kind: pattern.kind,
279
+ id: pattern.id,
280
+ severity: pattern.severity,
281
+ matched: clampMatch(match[0]),
282
+ offset: match.index,
283
+ source: pattern.source,
284
+ });
285
+ // Guard against zero-width matches infinite-looping (e.g. a
286
+ // regex that matches the empty string would never advance).
287
+ if (match.index === pattern.re.lastIndex) {
288
+ pattern.re.lastIndex += 1;
289
+ }
290
+ }
291
+ }
292
+ // 3. Substring/heuristic scan. AND semantics: every needle must
293
+ // appear in the lowercased copy. We record the FIRST needle's
294
+ // offset because that is the most actionable index for the
295
+ // operator (the others may be hundreds of bytes away).
296
+ const lower = scanText.toLowerCase();
297
+ for (const pattern of SUBSTRING_PATTERNS) {
298
+ const offsets = pattern.needles.map((n) => lower.indexOf(n));
299
+ if (offsets.every((o) => o >= 0)) {
300
+ const firstOffset = Math.min(...offsets);
301
+ // Reconstruct a useful matched snippet — the needles can be
302
+ // far apart so we cap at the first needle plus a window.
303
+ const snippetEnd = Math.min(firstOffset + MAX_MATCH_CAPTURE, scanText.length);
304
+ findings.push({
305
+ kind: pattern.kind,
306
+ id: pattern.id,
307
+ severity: pattern.severity,
308
+ matched: clampMatch(scanText.slice(firstOffset, snippetEnd)),
309
+ offset: firstOffset,
310
+ source: pattern.source,
311
+ });
312
+ }
313
+ }
314
+ return findings;
315
+ }
316
+ export function summarizeFindings(findings) {
317
+ let score = 0;
318
+ const kindSet = new Set();
319
+ for (const f of findings) {
320
+ if (f.severity === 'block')
321
+ score += 1;
322
+ kindSet.add(f.kind);
323
+ }
324
+ return {
325
+ score,
326
+ total: findings.length,
327
+ kinds: Array.from(kindSet).sort(),
328
+ };
329
+ }
330
+ /**
331
+ * Recursively walk a JSON-shaped value and concatenate every string
332
+ * found. Used by audit-trail to fold the entire `data` payload into a
333
+ * single scannable surface — a tool_result with a deeply nested error
334
+ * object could otherwise hide an override prompt one level deep.
335
+ *
336
+ * Cycles are broken by a WeakSet — a payload that round-trips through
337
+ * a session struct is safe to scan even when it has back-references.
338
+ */
339
+ export function collectStrings(value, seen = new WeakSet()) {
340
+ if (value === null || value === undefined)
341
+ return [];
342
+ if (typeof value === 'string')
343
+ return [value];
344
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
345
+ return [];
346
+ }
347
+ if (typeof value !== 'object')
348
+ return [];
349
+ if (seen.has(value))
350
+ return [];
351
+ seen.add(value);
352
+ const out = [];
353
+ if (Array.isArray(value)) {
354
+ for (const item of value) {
355
+ out.push(...collectStrings(item, seen));
356
+ }
357
+ return out;
358
+ }
359
+ for (const key of Object.keys(value)) {
360
+ // Scan the KEY too — a deliberately-crafted payload could hide
361
+ // an override phrase as an object key.
362
+ out.push(key);
363
+ out.push(...collectStrings(value[key], seen));
364
+ }
365
+ return out;
366
+ }
367
+ //# sourceMappingURL=injection-scanner.js.map