@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,189 @@
1
+ const BEGIN_PATCH = '*** Begin Patch';
2
+ const END_PATCH = '*** End Patch';
3
+ const END_FILE = '*** End File';
4
+ const ADD_FILE_PREFIX = '*** Add File: ';
5
+ const UPDATE_FILE_PREFIX = '*** Update File: ';
6
+ const DELETE_FILE_PREFIX = '*** Delete File: ';
7
+ export function parseApplyPatch(envelope) {
8
+ const ops = [];
9
+ const errors = [];
10
+ const lines = envelope.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n');
11
+ if (envelope.trim().length === 0) {
12
+ return { ops, errors };
13
+ }
14
+ let foundBlock = false;
15
+ let index = 0;
16
+ while (index < lines.length) {
17
+ const line = lines[index];
18
+ if (line === undefined) {
19
+ index += 1;
20
+ continue;
21
+ }
22
+ if (line === BEGIN_PATCH) {
23
+ foundBlock = true;
24
+ const parsed = parseBlock(lines, index + 1);
25
+ ops.push(...parsed.ops);
26
+ if (parsed.error !== null) {
27
+ errors.push(parsed.error);
28
+ }
29
+ index = parsed.nextIndex;
30
+ continue;
31
+ }
32
+ if (line.trim().length > 0) {
33
+ errors.push(`Unexpected content outside patch block at line ${index + 1}: ${line}`);
34
+ }
35
+ index += 1;
36
+ }
37
+ if (!foundBlock) {
38
+ errors.push('No patch block found: expected *** Begin Patch');
39
+ }
40
+ return { ops, errors };
41
+ }
42
+ function parseBlock(lines, startIndex) {
43
+ const ops = [];
44
+ const blockErrors = [];
45
+ let pending = null;
46
+ let index = startIndex;
47
+ const flushPending = () => {
48
+ if (pending === null) {
49
+ return;
50
+ }
51
+ if (pending.kind === 'add') {
52
+ ops.push({
53
+ kind: 'add',
54
+ path: pending.path,
55
+ content: pending.contentLines.join('\n'),
56
+ });
57
+ }
58
+ else if (pending.kind === 'update') {
59
+ ops.push({
60
+ kind: 'update',
61
+ path: pending.path,
62
+ oldContent: pending.oldLines.join('\n'),
63
+ newContent: pending.newLines.join('\n'),
64
+ });
65
+ }
66
+ else {
67
+ ops.push({
68
+ kind: 'delete',
69
+ path: pending.path,
70
+ });
71
+ }
72
+ pending = null;
73
+ };
74
+ while (index < lines.length) {
75
+ const line = lines[index];
76
+ if (line === undefined) {
77
+ index += 1;
78
+ continue;
79
+ }
80
+ if (line === END_PATCH) {
81
+ flushPending();
82
+ return {
83
+ ops,
84
+ error: blockErrors.length > 0 ? blockErrors.join('; ') : null,
85
+ nextIndex: index + 1,
86
+ };
87
+ }
88
+ if (line === BEGIN_PATCH) {
89
+ flushPending();
90
+ blockErrors.push(`Missing ${END_PATCH} before new patch block at line ${index + 1}`);
91
+ return {
92
+ ops,
93
+ error: blockErrors.join('; '),
94
+ nextIndex: index,
95
+ };
96
+ }
97
+ if (line === END_FILE) {
98
+ flushPending();
99
+ index += 1;
100
+ continue;
101
+ }
102
+ if (line.startsWith(ADD_FILE_PREFIX)) {
103
+ flushPending();
104
+ const path = parsePath(line.slice(ADD_FILE_PREFIX.length));
105
+ if (path.length === 0) {
106
+ blockErrors.push(`Missing add file path at line ${index + 1}`);
107
+ }
108
+ pending = { kind: 'add', path, contentLines: [] };
109
+ index += 1;
110
+ continue;
111
+ }
112
+ if (line.startsWith(UPDATE_FILE_PREFIX)) {
113
+ flushPending();
114
+ const path = parsePath(line.slice(UPDATE_FILE_PREFIX.length));
115
+ if (path.length === 0) {
116
+ blockErrors.push(`Missing update file path at line ${index + 1}`);
117
+ }
118
+ pending = { kind: 'update', path, oldLines: [], newLines: [] };
119
+ index += 1;
120
+ continue;
121
+ }
122
+ if (line.startsWith(DELETE_FILE_PREFIX)) {
123
+ flushPending();
124
+ const path = parsePath(line.slice(DELETE_FILE_PREFIX.length));
125
+ if (path.length === 0) {
126
+ blockErrors.push(`Missing delete file path at line ${index + 1}`);
127
+ }
128
+ pending = { kind: 'delete', path };
129
+ index += 1;
130
+ continue;
131
+ }
132
+ if (pending === null) {
133
+ if (line.trim().length > 0) {
134
+ blockErrors.push(`Unexpected line without active file operation at line ${index + 1}: ${line}`);
135
+ }
136
+ index += 1;
137
+ continue;
138
+ }
139
+ if (pending.kind === 'add') {
140
+ if (line.startsWith('+')) {
141
+ pending.contentLines.push(line.slice(1));
142
+ }
143
+ else if (line.trim().length > 0) {
144
+ blockErrors.push(`Unexpected add line at line ${index + 1}: ${line}`);
145
+ }
146
+ index += 1;
147
+ continue;
148
+ }
149
+ if (pending.kind === 'update') {
150
+ if (line.startsWith('-')) {
151
+ pending.oldLines.push(line.slice(1));
152
+ }
153
+ else if (line.startsWith('+')) {
154
+ pending.newLines.push(line.slice(1));
155
+ }
156
+ else if (line.startsWith('@@')) {
157
+ // Context marker; accepted but not included in structured content.
158
+ }
159
+ else if (line.trim().length > 0) {
160
+ // Unchanged context line; accepted but not included in structured content.
161
+ }
162
+ index += 1;
163
+ continue;
164
+ }
165
+ if (line.trim().length > 0) {
166
+ blockErrors.push(`Unexpected delete content at line ${index + 1}: ${line}`);
167
+ }
168
+ index += 1;
169
+ }
170
+ flushPending();
171
+ blockErrors.push(`Missing ${END_PATCH}`);
172
+ return {
173
+ ops,
174
+ error: blockErrors.join('; '),
175
+ nextIndex: index,
176
+ };
177
+ }
178
+ function parsePath(rawPath) {
179
+ const path = rawPath.trim();
180
+ if (path.length >= 2) {
181
+ const first = path[0];
182
+ const last = path[path.length - 1];
183
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
184
+ return path.slice(1, -1);
185
+ }
186
+ }
187
+ return path;
188
+ }
189
+ //# sourceMappingURL=apply-patch-layer-e.js.map
@@ -1,15 +1,16 @@
1
1
  /**
2
- * Diff dispatch — α6.6 escalation Phase 1.
2
+ * Diff dispatch — escalation Phase 1, β1b Pl8 transactional layer
3
+ * .
3
4
  *
4
5
  * Reads a raw model response containing one or more SEARCH/REPLACE
5
6
  * envelopes, normalises them through `marker-parser`, and routes each
6
7
  * parsed edit to the correct applicator:
7
8
  *
8
- * - `layer-a` → applyLayerA
9
- * - `layer-b` → applyLayerB
10
- * - `layer-c` → applyLayerC
11
- * - `layer-d` → throws LayerDDeferredError, surfaced as a clean
12
- * dispatch failure (Layer D ships in α6.6b)
9
+ * - `layer-a` → applyLayerA
10
+ * - `layer-b` → applyLayerB
11
+ * - `layer-c` → applyLayerC
12
+ * - `layer-d` → throws LayerDDeferredError, surfaced as a clean
13
+ * dispatch failure (Layer D ships in )
13
14
  *
14
15
  * Per-edit results are aggregated into `DispatchResult[]` so callers
15
16
  * can render the full apply transcript even when some edits failed.
@@ -21,16 +22,38 @@
21
22
  * the writeFile. A crash between the two leaves a recoverable trail —
22
23
  * the operator (or `pugi resume`) sees the intent and can re-attempt.
23
24
  *
25
+ * β1b Pl8 — transactional rollback: when the caller supplies
26
+ * `transactional: { sessionId, taskId, workspaceRoot }`, the dispatcher
27
+ * wraps the multi-file edits in a session journal (see
28
+ * `core/edits/journal.ts`). On non-zero exit / budget kill / partial
29
+ * fail it runs `rollbackDispatch()`:
30
+ *
31
+ * - tracked files that EXISTED before → `git restore -- <file>`
32
+ * - newly created files (existed=false) → `fs.unlink`
33
+ * - untracked files that EXISTED before → restore from in-memory
34
+ * pre-content snapshot (sha256_before validated)
35
+ *
36
+ * Pattern mirrors `tools/apply-patch.ts::rollbackFiles` (PR). The
37
+ * journal is the durability layer that lets a process crash recover
38
+ * across PIDs; the in-memory snapshot covers the single-process case
39
+ * where the journal write itself failed.
40
+ *
24
41
  * The dispatcher is intentionally side-effect-light: no logging, no
25
42
  * stdout writes, no exit-code mutation. The CLI integration layer in
26
43
  * `cli.ts` owns operator-facing rendering; the dispatcher returns
27
44
  * structured data and lets the caller decide UX.
28
45
  */
46
+ import { spawnSync } from 'node:child_process';
47
+ import { readFileSync, rmSync, writeFileSync } from 'node:fs';
48
+ import { resolve, sep } from 'node:path';
49
+ import { commitCheckpoint, formatCheckpointMessage, initShadowRepo, ShadowGitUnavailableError, } from '../checkpoints/shadow-git.js';
29
50
  import { LayerDDeferredError, applyLayerD } from './layer-d-ast.js';
30
51
  import { applyLayerA } from './layer-a-apply.js';
52
+ import { applyLayerAFuzzy } from './layer-a-fuzzy-apply.js';
31
53
  import { applyLayerB } from './layer-b-apply.js';
32
54
  import { applyLayerC } from './layer-c-apply.js';
33
55
  import { MarkerParseError, parseMarkers, } from './marker-parser.js';
56
+ import { appendEntry, snapshotForDispatch, } from './journal.js';
34
57
  /**
35
58
  * Parse `raw` into edits and apply each in order. Aggregate results,
36
59
  * preserving order. Never throws — parse failures surface as a single
@@ -65,13 +88,254 @@ export async function dispatchEdit(raw, opts) {
65
88
  // render "no edits proposed".
66
89
  return [];
67
90
  }
91
+ // β1b Pl8 — transactional path. When enabled, snapshot every target
92
+ // file BEFORE the first applicator runs so we can roll back if a
93
+ // later edit fails. Snapshot also drives the journal entry so a
94
+ // post-crash recovery can replay rollback in a fresh process.
95
+ //
96
+ // The journal write itself is best-effort: a disk-full / EACCES
97
+ // failure must NOT block the dispatch. The in-memory snapshot
98
+ // still carries every pre-existing file's content, so single-
99
+ // process rollback degrades cleanly. The operator sees the
100
+ // journal-failed warning via the session events mirror (caller's
101
+ // responsibility to emit).
102
+ let snapshot = null;
103
+ let preContent = null;
104
+ if (opts.transactional && !opts.dryRun) {
105
+ const targets = Array.from(new Set(parsed.map((e) => editFile(e))));
106
+ snapshot = snapshotForDispatch(opts.transactional.workspaceRoot, targets);
107
+ preContent = new Map();
108
+ for (const e of snapshot) {
109
+ if (!e.existed)
110
+ continue;
111
+ const abs = resolve(opts.transactional.workspaceRoot, e.path);
112
+ try {
113
+ preContent.set(e.path, readFileSync(abs));
114
+ }
115
+ catch {
116
+ /* file vanished between snapshot + read — treat as not-snapshotted */
117
+ }
118
+ }
119
+ appendEntry(opts.transactional.workspaceRoot, opts.transactional.sessionId, {
120
+ ts: Date.now(),
121
+ taskId: opts.transactional.taskId,
122
+ files: snapshot,
123
+ });
124
+ }
125
+ // Per-task shadow git checkpoint hook (backlog). Init the
126
+ // shadow once per dispatch, then commit after every successful
127
+ // edit. The init is best-effort — a missing `git` binary or a
128
+ // chmod failure surfaces through `onCheckpointError` but does not
129
+ // disable the dispatch.
130
+ let checkpointStep = opts.checkpoint?.stepStart && Number.isFinite(opts.checkpoint.stepStart)
131
+ ? Math.max(1, Math.floor(opts.checkpoint.stepStart))
132
+ : 1;
133
+ let checkpointEnabled = false;
134
+ if (opts.checkpoint && !opts.dryRun) {
135
+ try {
136
+ initShadowRepo(opts.cwd, opts.checkpoint.taskId);
137
+ checkpointEnabled = true;
138
+ }
139
+ catch (error) {
140
+ const err = error instanceof Error ? error : new Error(String(error));
141
+ opts.checkpoint.onCheckpointError?.(err, '');
142
+ }
143
+ }
68
144
  const out = [];
145
+ let crashError = null;
69
146
  for (const edit of parsed) {
70
147
  const intent = makeIntent(edit);
71
148
  opts.onIntent?.(intent);
72
- const result = await applyOne(edit, opts);
149
+ let result;
150
+ try {
151
+ result = await applyOne(edit, opts);
152
+ }
153
+ catch (error) {
154
+ // applyOne does not throw today (errors are returned as
155
+ // `ok: false`), but a future applicator that does throw —
156
+ // or a budget-kill that arrives mid-write — needs deterministic
157
+ // rollback. Catch + record + break so the rollback below runs.
158
+ crashError = error;
159
+ const msg = error instanceof Error ? error.message : String(error);
160
+ result = {
161
+ layer: 'layer-a',
162
+ file: editFile(edit),
163
+ ok: false,
164
+ bytesWritten: 0,
165
+ reason: 'apply_error',
166
+ detail: `dispatch threw: ${msg}`,
167
+ };
168
+ }
73
169
  out.push(result);
74
170
  opts.onResult?.(result);
171
+ if (result.ok && checkpointEnabled && opts.checkpoint && !opts.dryRun) {
172
+ // Best-effort shadow commit. Failures here MUST NOT block the
173
+ // dispatch — the operator already has the edit applied; the
174
+ // checkpoint is a customer-trust safety net, not a hard gate.
175
+ try {
176
+ const absPath = result.absPath ?? resolve(opts.cwd, result.file);
177
+ const message = formatCheckpointMessage({
178
+ taskId: opts.checkpoint.taskId,
179
+ step: checkpointStep,
180
+ toolName: result.layer,
181
+ cwd: opts.cwd,
182
+ absPath,
183
+ });
184
+ commitCheckpoint(opts.cwd, opts.checkpoint.taskId, message);
185
+ }
186
+ catch (error) {
187
+ const err = error instanceof Error ? error : new Error(String(error));
188
+ // Disable the shadow hook for the rest of this dispatch if
189
+ // the git binary is unavailable — repeated probes burn CPU
190
+ // and add no signal beyond the first failure.
191
+ if (err instanceof ShadowGitUnavailableError) {
192
+ checkpointEnabled = false;
193
+ }
194
+ opts.checkpoint.onCheckpointError?.(err, result.file);
195
+ }
196
+ checkpointStep += 1;
197
+ }
198
+ if (!result.ok && opts.transactional && snapshot && preContent) {
199
+ // Rollback every snapshotted file then break out — partial
200
+ // success is unacceptable in transactional mode.
201
+ const rollback = rollbackDispatch(opts.transactional.workspaceRoot, snapshot, preContent);
202
+ if (!rollback.ok) {
203
+ // Surface the rollback failure as an additional synthetic
204
+ // result so the caller can render the operator-facing
205
+ // message without losing the original failure context.
206
+ const failure = {
207
+ layer: 'layer-a',
208
+ file: '',
209
+ ok: false,
210
+ bytesWritten: 0,
211
+ reason: 'rollback_failed',
212
+ detail: rollback.detail,
213
+ };
214
+ out.push(failure);
215
+ opts.onResult?.(failure);
216
+ }
217
+ if (crashError) {
218
+ // Re-throw post-rollback so the caller learns the dispatch
219
+ // crashed (vs returned ok: false). Rollback already completed
220
+ // so the workspace is consistent.
221
+ throw crashError;
222
+ }
223
+ break;
224
+ }
225
+ }
226
+ return out;
227
+ }
228
+ /**
229
+ * Workspace-relative path for a parsed edit, regardless of layer.
230
+ * Hoisted because the snapshot + intent both need the same answer.
231
+ */
232
+ function editFile(edit) {
233
+ switch (edit.kind) {
234
+ case 'layer-a':
235
+ case 'layer-b':
236
+ case 'layer-c':
237
+ case 'layer-d':
238
+ return edit.edit.file;
239
+ }
240
+ }
241
+ /**
242
+ * Roll the workspace back to the pre-dispatch state captured in
243
+ * `snapshot`. Mirrors `tools/apply-patch.ts::rollbackFiles`:
244
+ *
245
+ * - existed-before + git-tracked → `git restore -- <file>` (cheap
246
+ * + atomic against the index).
247
+ * - existed-before + untracked → restore from the in-memory
248
+ * preContent buffer (sha256_before validates the snapshot still
249
+ * matches what we hold; if not we punt with `partial_rollback`).
250
+ * - newly created → fs.unlink (force).
251
+ *
252
+ * Best-effort: every per-file failure is collected into the detail
253
+ * string so the operator can manually fix the residual state. The
254
+ * dispatcher does not abort on the first error so an unrelated
255
+ * permission glitch on one file doesn't strand the others.
256
+ *
257
+ * Exported for the spec suite + a future operator command
258
+ * (`pugi resume --rollback <taskId>` ships in β2).
259
+ */
260
+ export function rollbackDispatch(workspaceRoot, snapshot, preContent) {
261
+ if (snapshot.length === 0)
262
+ return { ok: true };
263
+ // Filter to workspace-internal paths only. A snapshot entry that
264
+ // escaped the workspace would already have aborted upstream; the
265
+ // filter is belt + braces against a future bug.
266
+ const safe = snapshot.filter((e) => {
267
+ const abs = resolve(workspaceRoot, e.path);
268
+ return abs === workspaceRoot || abs.startsWith(workspaceRoot + sep);
269
+ });
270
+ const failures = [];
271
+ const tracked = listTrackedFiles(workspaceRoot, safe.map((e) => e.path));
272
+ for (const entry of safe) {
273
+ const abs = resolve(workspaceRoot, entry.path);
274
+ if (!entry.existed) {
275
+ try {
276
+ // β1b r1: `recursive: true` so rollback handles the case where
277
+ // the dispatcher created an intermediate directory (e.g. a new
278
+ // `src/feature/` tree). Without it the unlink fails on a dir
279
+ // and the journal-replay leaves an orphan workspace path.
280
+ rmSync(abs, { force: true, recursive: true });
281
+ }
282
+ catch (error) {
283
+ failures.push(`${entry.path}: unlink failed: ${error instanceof Error ? error.message : String(error)}`);
284
+ }
285
+ continue;
286
+ }
287
+ if (tracked.has(entry.path)) {
288
+ const result = spawnSync('git', ['restore', '--', entry.path], {
289
+ cwd: workspaceRoot,
290
+ encoding: 'utf8',
291
+ });
292
+ if (result.status !== 0) {
293
+ failures.push(`${entry.path}: git restore failed: ${(result.stderr ?? '').trim() || 'non-zero exit'}`);
294
+ }
295
+ continue;
296
+ }
297
+ // Untracked-but-existed: write back from memory.
298
+ const buf = preContent.get(entry.path);
299
+ if (!buf) {
300
+ failures.push(`${entry.path}: pre-content snapshot missing (partial rollback)`);
301
+ continue;
302
+ }
303
+ try {
304
+ writeFileSync(abs, buf);
305
+ }
306
+ catch (error) {
307
+ failures.push(`${entry.path}: rewrite failed: ${error instanceof Error ? error.message : String(error)}`);
308
+ }
309
+ }
310
+ if (failures.length === 0)
311
+ return { ok: true };
312
+ return { ok: false, detail: failures.join('; ') };
313
+ }
314
+ /**
315
+ * Ask git which of `paths` are tracked. A single `git ls-files
316
+ * --error-unmatch` call would fail-fast on the first untracked path,
317
+ * so we use `git ls-files -- <paths...>` which lists only tracked
318
+ * matches. Returns a Set of workspace-relative paths.
319
+ *
320
+ * Pure-stdlib fallback when git is unavailable: returns an empty
321
+ * Set — every "existed" entry then routes to the untracked-restore
322
+ * path via the in-memory preContent map. Slower per file but still
323
+ * correct.
324
+ */
325
+ function listTrackedFiles(cwd, paths) {
326
+ if (paths.length === 0)
327
+ return new Set();
328
+ const result = spawnSync('git', ['ls-files', '--', ...paths], {
329
+ cwd,
330
+ encoding: 'utf8',
331
+ });
332
+ if (result.status !== 0)
333
+ return new Set();
334
+ const out = new Set();
335
+ for (const line of (result.stdout ?? '').split('\n')) {
336
+ const trimmed = line.trim();
337
+ if (trimmed.length > 0)
338
+ out.add(trimmed);
75
339
  }
76
340
  return out;
77
341
  }
@@ -125,6 +389,28 @@ async function applyOne(edit, opts) {
125
389
  switch (edit.kind) {
126
390
  case 'layer-a': {
127
391
  const r = await applyLayerA(edit.edit, applyOpts);
392
+ // Backlog — Layer A.5 escalation. The fuzzy ladder is the
393
+ // ONLY retry path: every other Layer A failure mode (ambiguous,
394
+ // file_missing, identical_replacement, security gate denial)
395
+ // bubbles up untouched because the ladder can't fix them.
396
+ // ambiguous in particular MUST stay loud — a fuzzy retry on top
397
+ // of an ambiguous strict match would just pick one of the
398
+ // strict candidates silently, defeating the disambiguation
399
+ // contract.
400
+ if (!r.ok && r.reason === 'no_match' && opts.fuzzy === true) {
401
+ const fuzzy = await applyLayerAFuzzy(edit.edit, {
402
+ cwd: opts.cwd,
403
+ dryRun: opts.dryRun,
404
+ minRatio: opts.fuzzyMinRatio,
405
+ lengthFlex: opts.fuzzyLengthFlex,
406
+ });
407
+ const base = toResult('layer-a-fuzzy', edit.edit.file, fuzzy);
408
+ return {
409
+ ...base,
410
+ ...(fuzzy.fuzzyTier ? { fuzzyTier: fuzzy.fuzzyTier } : {}),
411
+ ...(fuzzy.fuzzyScore !== undefined ? { fuzzyScore: fuzzy.fuzzyScore } : {}),
412
+ };
413
+ }
128
414
  return toResult('layer-a', edit.edit.file, r);
129
415
  }
130
416
  case 'layer-b': {
@@ -0,0 +1,26 @@
1
+ export const EDIT_FORMAT_MATRIX = {
2
+ 'claude-opus-4-7': { primary: 'C', fallback: ['A', 'B'] },
3
+ 'claude-sonnet-4-6': { primary: 'C', fallback: ['A', 'B'] },
4
+ 'claude-haiku-4-5': { primary: 'A', fallback: ['B'] },
5
+ 'gpt-5': { primary: 'C', fallback: ['A'] },
6
+ 'gpt-5-mini': { primary: 'A', fallback: ['B'] },
7
+ 'deepseek-v4-pro': { primary: 'A', fallback: ['B', 'C'] },
8
+ 'deepseek-coder-v2': { primary: 'A', fallback: ['B'] },
9
+ 'qwen3-coder-480b': { primary: 'D', fallback: ['A', 'B'] },
10
+ 'qwen3:0.6b': { primary: 'A', fallback: [] },
11
+ 'gemini-2.5-pro': { primary: 'C', fallback: ['A'] },
12
+ 'gemini-2.0-flash': { primary: 'A', fallback: ['B'] },
13
+ 'ollama:qwen3-coder:30b': { primary: 'A', fallback: ['B'] },
14
+ '*': { primary: 'A', fallback: ['B', 'C'] },
15
+ };
16
+ export function pickEditFormat(model, fileSize, isLSPAvailable = () => false) {
17
+ const chain = EDIT_FORMAT_MATRIX[model] ?? EDIT_FORMAT_MATRIX['*'] ?? { primary: 'A', fallback: [] };
18
+ if (chain.primary === 'C' && fileSize > 4000) {
19
+ return { primary: 'A', fallback: ['B'] };
20
+ }
21
+ if (chain.primary === 'D' && !isLSPAvailable()) {
22
+ return { primary: chain.fallback[0] ?? 'A', fallback: chain.fallback.slice(1) };
23
+ }
24
+ return chain;
25
+ }
26
+ //# sourceMappingURL=format-matrix.js.map