@pugi/cli 0.1.0-beta.9 → 0.1.0-beta.90
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.
- package/CHANGELOG.md +132 -0
- package/LICENSE +1 -1
- package/assets/pugi-prozr2-mascot.ansi +9 -0
- package/bin/run.js +33 -1
- package/dist/commands/deploy.js +40 -40
- package/dist/commands/flatten.js +191 -0
- package/dist/commands/jobs-watch.js +201 -0
- package/dist/commands/jobs.js +42 -27
- package/dist/commands/smoke.js +133 -0
- package/dist/core/agent-progress/cleanup.js +134 -0
- package/dist/core/agent-progress/schema.js +144 -0
- package/dist/core/agent-progress/writer.js +101 -0
- package/dist/core/agents/adaptive-router.js +330 -0
- package/dist/core/agents/query-decomposer.js +297 -0
- package/dist/core/agents/registry.js +3 -3
- package/dist/core/approvals/shortcut-resolver.js +98 -0
- package/dist/core/artifact-chain/dispatcher.js +148 -0
- package/dist/core/artifact-chain/exporter.js +164 -0
- package/dist/core/artifact-chain/state.js +243 -0
- package/dist/core/artifact-chain/steps.js +169 -0
- package/dist/core/ask-user/question.js +92 -0
- package/dist/core/audit/audit-trail.js +275 -0
- package/dist/core/auth/ensure-authenticated.js +129 -0
- package/dist/core/auth/env-provider.js +238 -0
- package/dist/core/auto-open-browser.js +4 -4
- package/dist/core/auto-update/channels.js +122 -0
- package/dist/core/auto-update/checker.js +241 -0
- package/dist/core/auto-update/state.js +235 -0
- package/dist/core/bare-mode/index.js +107 -0
- package/dist/core/bash/redirect.js +281 -0
- package/dist/core/bash-classifier.js +436 -40
- package/dist/core/checkpoint/resumer.js +149 -0
- package/dist/core/checkpoint/rewinder.js +291 -0
- package/dist/core/checkpoints/shadow-git.js +670 -0
- package/dist/core/citations/parser.js +109 -0
- package/dist/core/classifier/yolo-classifier.js +88 -0
- package/dist/core/codegraph/decision-store.js +248 -0
- package/dist/core/codegraph/detect-repo.js +459 -0
- package/dist/core/codegraph/install.js +134 -0
- package/dist/core/codegraph/offer-hook.js +220 -0
- package/dist/core/compact/auto-trigger.js +96 -0
- package/dist/core/compact/buffer-rewriter.js +115 -0
- package/dist/core/compact/summarizer.js +208 -0
- package/dist/core/compact/token-counter.js +108 -0
- package/dist/core/consensus/anvil-fanout.js +25 -25
- package/dist/core/consensus/diff-capture.js +121 -12
- package/dist/core/consensus/rubric.js +21 -21
- package/dist/core/context/builder.js +6 -6
- package/dist/core/context/compaction-events.js +8 -8
- package/dist/core/context/compaction.js +31 -31
- package/dist/core/context/index.js +15 -8
- package/dist/core/context/invariants.js +51 -51
- package/dist/core/context/markdown-loader.js +28 -10
- package/dist/core/context/markdown-traverse.js +255 -0
- package/dist/core/context/pugiignore.js +41 -41
- package/dist/core/context/repo-skeleton.js +37 -37
- package/dist/core/context/tool-eviction.js +55 -0
- package/dist/core/context/watcher.js +32 -32
- package/dist/core/context/working-set.js +23 -23
- package/dist/core/coordinator/agent-tools.js +77 -0
- package/dist/core/coordinator/agent-toolset.js +65 -0
- package/dist/core/coordinator/fsm.js +73 -0
- package/dist/core/coordinator/mode-fsm.js +70 -0
- package/dist/core/cost/rate-card.js +129 -0
- package/dist/core/cost/tracker.js +221 -0
- package/dist/core/credentials.js +13 -13
- package/dist/core/cron/scheduler.js +138 -0
- package/dist/core/denial-tracking/index.js +8 -0
- package/dist/core/denial-tracking/state.js +264 -0
- package/dist/core/diagnostics/probe-runner.js +93 -0
- package/dist/core/diagnostics/probes/api.js +46 -0
- package/dist/core/diagnostics/probes/auth.js +93 -0
- package/dist/core/diagnostics/probes/bare-mode.js +42 -0
- package/dist/core/diagnostics/probes/cli-version.js +127 -0
- package/dist/core/diagnostics/probes/config.js +72 -0
- package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
- package/dist/core/diagnostics/probes/disk.js +81 -0
- package/dist/core/diagnostics/probes/engine-live.js +46 -0
- package/dist/core/diagnostics/probes/git.js +65 -0
- package/dist/core/diagnostics/probes/hooks.js +118 -0
- package/dist/core/diagnostics/probes/mcp.js +75 -0
- package/dist/core/diagnostics/probes/node.js +59 -0
- package/dist/core/diagnostics/probes/pnpm.js +36 -0
- package/dist/core/diagnostics/probes/pugi-md.js +89 -0
- package/dist/core/diagnostics/probes/sandbox.js +40 -0
- package/dist/core/diagnostics/probes/session.js +74 -0
- package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
- package/dist/core/diagnostics/probes/workspace.js +63 -0
- package/dist/core/diagnostics/types.js +70 -0
- package/dist/core/dispatch/cache-cleanup.js +197 -0
- package/dist/core/dispatch/cache-handoff.js +295 -0
- package/dist/core/edits/apply-patch-layer-e.js +189 -0
- package/dist/core/edits/dispatch.js +333 -7
- package/dist/core/edits/format-detector.js +260 -0
- package/dist/core/edits/format-matrix.js +26 -0
- package/dist/core/edits/fuzzy-ladder.js +650 -0
- package/dist/core/edits/index.js +5 -1
- package/dist/core/edits/journal.js +199 -0
- package/dist/core/edits/layer-a-apply.js +15 -15
- package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
- package/dist/core/edits/layer-b-apply.js +9 -9
- package/dist/core/edits/layer-c-apply.js +6 -6
- package/dist/core/edits/layer-d-ast.js +557 -14
- package/dist/core/edits/marker-parser.js +12 -12
- package/dist/core/edits/security-gate.js +27 -27
- package/dist/core/edits/verify-hook.js +273 -0
- package/dist/core/edits/worktree.js +29 -29
- package/dist/core/engine/anvil-client.js +214 -26
- package/dist/core/engine/auto-compact.js +179 -0
- package/dist/core/engine/budgets.js +186 -0
- package/dist/core/engine/context-prefix.js +155 -0
- package/dist/core/engine/index.js +1 -1
- package/dist/core/engine/intensity.js +158 -0
- package/dist/core/engine/intent.js +260 -0
- package/dist/core/engine/native-pugi.js +1295 -227
- package/dist/core/engine/prompts.js +129 -19
- package/dist/core/engine/strip-internal-fields.js +124 -0
- package/dist/core/engine/tool-bridge.js +1731 -59
- package/dist/core/evaluation/golden-dataset.js +293 -0
- package/dist/core/feedback/queue.js +177 -0
- package/dist/core/feedback/submitter.js +145 -0
- package/dist/core/file-cache.js +113 -1
- package/dist/core/flatten/flatten-repo.js +439 -0
- package/dist/core/format/osc8-link.js +28 -0
- package/dist/core/hook-chains.js +392 -0
- package/dist/core/hooks/citation-verify-hook.js +138 -0
- package/dist/core/hooks/citation-verify.js +112 -0
- package/dist/core/hooks/events.js +46 -0
- package/dist/core/hooks/index.js +15 -0
- package/dist/core/hooks/registry.js +216 -0
- package/dist/core/hooks/runner.js +236 -0
- package/dist/core/hooks/v2/event-emitter.js +115 -0
- package/dist/core/hooks/v2/executor.js +282 -0
- package/dist/core/hooks/v2/index.js +25 -0
- package/dist/core/hooks/v2/lifecycle.js +104 -0
- package/dist/core/hooks/v2/loader.js +216 -0
- package/dist/core/hooks/v2/matcher.js +125 -0
- package/dist/core/hooks/v2/trust.js +143 -0
- package/dist/core/hooks/v2/types.js +86 -0
- package/dist/core/hooks/worktree-events.js +158 -0
- package/dist/core/image/renderer.js +71 -0
- package/dist/core/init/detector.js +582 -0
- package/dist/core/init/template-renderer.js +242 -0
- package/dist/core/jobs/registry.js +18 -18
- package/dist/core/ledger/results-tsv.js +142 -0
- package/dist/core/log-discipline/stdout-redirect.js +51 -0
- package/dist/core/lsp/cache.js +105 -0
- package/dist/core/lsp/client.js +551 -41
- package/dist/core/lsp/language-detect.js +66 -0
- package/dist/core/lsp/post-edit-diagnostics.js +171 -0
- package/dist/core/lsp/server-detect.js +173 -0
- package/dist/core/lsp/symbol-cache.js +162 -0
- package/dist/core/lsp/symbol-tools.js +664 -0
- package/dist/core/mcp/client.js +97 -28
- package/dist/core/mcp/http-server.js +553 -0
- package/dist/core/mcp/orchestrator-tools.js +662 -0
- package/dist/core/mcp/permission.js +190 -0
- package/dist/core/mcp/registry.js +39 -17
- package/dist/core/mcp/server-tools.js +219 -0
- package/dist/core/mcp/server.js +397 -0
- package/dist/core/mcp/trust.js +10 -10
- package/dist/core/memory/dual-write.js +416 -0
- package/dist/core/memory/passive-extract.js +130 -0
- package/dist/core/memory/phase1-kinds.js +20 -0
- package/dist/core/memory/secret-scanner.js +304 -0
- package/dist/core/memory-sync/queue.js +170 -0
- package/dist/core/metrics/extract.js +113 -0
- package/dist/core/modes/roo-modes.js +68 -0
- package/dist/core/onboarding/ensure-initialized.js +133 -0
- package/dist/core/onboarding/marker.js +111 -0
- package/dist/core/onboarding/telemetry-state.js +108 -0
- package/dist/core/output-style/presets.js +176 -0
- package/dist/core/output-style/state.js +185 -0
- package/dist/core/path-security.js +287 -5
- package/dist/core/permission.js +82 -22
- package/dist/core/permissions/auto-classifier.js +124 -0
- package/dist/core/permissions/bash-parser.js +371 -0
- package/dist/core/permissions/circuit-breaker.js +83 -0
- package/dist/core/permissions/constrained-edit.js +91 -0
- package/dist/core/permissions/gate.js +278 -0
- package/dist/core/permissions/index.js +20 -0
- package/dist/core/permissions/mode.js +174 -0
- package/dist/core/permissions/network-egress.js +137 -0
- package/dist/core/permissions/state.js +241 -0
- package/dist/core/permissions/tool-class.js +93 -0
- package/dist/core/plan-mode/ui-state.js +51 -0
- package/dist/core/plans/plan-artifact.js +721 -0
- package/dist/core/policy-limits/etag-store.js +122 -0
- package/dist/core/prd-check/parser.js +215 -0
- package/dist/core/prd-check/reporter.js +127 -0
- package/dist/core/prd-check/session-review.js +557 -0
- package/dist/core/prd-check/verifiers.js +223 -0
- package/dist/core/prompt-cache/client-cache.js +99 -0
- package/dist/core/prompts/assembly.js +29 -0
- package/dist/core/prompts/registry.js +364 -0
- package/dist/core/pugi-md/cc-compat-rules.js +735 -0
- package/dist/core/pugi-md/context-injector.js +76 -0
- package/dist/core/pugi-md/walk-up.js +207 -0
- package/dist/core/python/uv-installer.js +270 -0
- package/dist/core/python/uv-resolver.js +83 -0
- package/dist/core/rate-limit/narrator.js +146 -0
- package/dist/core/recipes/cli-types.js +20 -0
- package/dist/core/recipes/loader.js +103 -0
- package/dist/core/recipes/runner.js +345 -0
- package/dist/core/recipes/schema.js +587 -0
- package/dist/core/release-notes/parser.js +241 -0
- package/dist/core/release-notes/state.js +116 -0
- package/dist/core/repl/ask.js +37 -37
- package/dist/core/repl/cancellation.js +26 -26
- package/dist/core/repl/cap-warning.js +4 -4
- package/dist/core/repl/clipboard-read.js +11 -11
- package/dist/core/repl/dispatch-fsm.js +12 -12
- package/dist/core/repl/history-search.js +15 -15
- package/dist/core/repl/history.js +28 -18
- package/dist/core/repl/kill-ring.js +5 -5
- package/dist/core/repl/model-pricing.js +135 -0
- package/dist/core/repl/privacy-banner.js +22 -22
- package/dist/core/repl/session.js +2148 -217
- package/dist/core/repl/slash-commands.js +501 -41
- package/dist/core/repl/store/index.js +1 -1
- package/dist/core/repl/store/jsonl-log.js +22 -22
- package/dist/core/repl/store/lockfile.js +10 -10
- package/dist/core/repl/store/session-store.js +136 -107
- package/dist/core/repl/store/types.js +15 -15
- package/dist/core/repl/store/uuid-v7.js +12 -12
- package/dist/core/repl/workspace-context.js +43 -21
- package/dist/core/repo-map/build.js +125 -0
- package/dist/core/repo-map/cache.js +185 -0
- package/dist/core/repo-map/extractor.js +254 -0
- package/dist/core/repo-map/formatter.js +145 -0
- package/dist/core/repo-map/page-rank.js +105 -0
- package/dist/core/repo-map/scanner.js +211 -0
- package/dist/core/retry-budget/budget.js +284 -0
- package/dist/core/retry-budget/index.js +5 -0
- package/dist/core/retry-budget/retry-cap.js +74 -0
- package/dist/core/routing/lead-worker.js +43 -0
- package/dist/core/routing/pre-flight-estimator.js +108 -0
- package/dist/core/runs/run-tree.js +103 -0
- package/dist/core/security/injection-scanner.js +367 -0
- package/dist/core/security/output-filter.js +418 -0
- package/dist/core/session/env-file.js +105 -0
- package/dist/core/session/section-budgets.js +140 -0
- package/dist/core/session.js +92 -0
- package/dist/core/settings.js +324 -5
- package/dist/core/share/formatter.js +271 -0
- package/dist/core/share/redactor.js +221 -0
- package/dist/core/share/uploader.js +267 -0
- package/dist/core/skills/defaults.js +30 -30
- package/dist/core/skills/loader.js +22 -22
- package/dist/core/skills/sources.js +27 -27
- package/dist/core/smoke/headless-driver.js +174 -0
- package/dist/core/smoke/orchestrator.js +194 -0
- package/dist/core/smoke/runner.js +238 -0
- package/dist/core/smoke/scenario-parser.js +316 -0
- package/dist/core/statusline.js +99 -0
- package/dist/core/subagents/dispatcher-real.js +600 -0
- package/dist/core/subagents/dispatcher.js +132 -43
- package/dist/core/subagents/index.js +19 -6
- package/dist/core/subagents/isolation-matrix.js +213 -0
- package/dist/core/subagents/spawn.js +19 -4
- package/dist/core/telemetry/emitter.js +229 -0
- package/dist/core/telemetry/queue.js +251 -0
- package/dist/core/theme/context.js +91 -0
- package/dist/core/theme/presets.js +228 -0
- package/dist/core/theme/state.js +181 -0
- package/dist/core/todos/invariant.js +10 -0
- package/dist/core/todos/state.js +177 -0
- package/dist/core/tool-schema/compressor.js +89 -0
- package/dist/core/transport/version-interceptor.js +166 -0
- package/dist/core/trust.js +2 -2
- package/dist/core/tui/thinking-block.js +64 -0
- package/dist/core/vim/keymap.js +288 -0
- package/dist/core/vim/state.js +92 -0
- package/dist/core/watch-markers/marker-watcher.js +133 -0
- package/dist/core/worktree/include-parser.js +249 -0
- package/dist/core/worktree-manager/cleanup.js +123 -0
- package/dist/core/worktree-manager/manager.js +303 -0
- package/dist/index.js +36 -0
- package/dist/runtime/bootstrap.js +190 -0
- package/dist/runtime/cli.js +4185 -549
- package/dist/runtime/commands/agents.js +31 -31
- package/dist/runtime/commands/budget.js +5 -5
- package/dist/runtime/commands/cancel.js +231 -0
- package/dist/runtime/commands/chain.js +489 -0
- package/dist/runtime/commands/codegraph-status.js +227 -0
- package/dist/runtime/commands/compact.js +297 -0
- package/dist/runtime/commands/config.js +73 -39
- package/dist/runtime/commands/cost.js +199 -0
- package/dist/runtime/commands/delegate.js +27 -4
- package/dist/runtime/commands/dispatch.js +126 -0
- package/dist/runtime/commands/doctor.js +579 -0
- package/dist/runtime/commands/feedback.js +184 -0
- package/dist/runtime/commands/hooks.js +187 -0
- package/dist/runtime/commands/init.js +254 -0
- package/dist/runtime/commands/lsp.js +200 -38
- package/dist/runtime/commands/mcp.js +879 -0
- package/dist/runtime/commands/memory.js +582 -0
- package/dist/runtime/commands/model.js +237 -0
- package/dist/runtime/commands/onboarding.js +275 -0
- package/dist/runtime/commands/patch.js +12 -12
- package/dist/runtime/commands/permissions.js +112 -0
- package/dist/runtime/commands/plan.js +143 -0
- package/dist/runtime/commands/prd-check.js +285 -0
- package/dist/runtime/commands/privacy.js +17 -17
- package/dist/runtime/commands/recipe.js +325 -0
- package/dist/runtime/commands/redo-blob-store.js +92 -0
- package/dist/runtime/commands/redo.js +361 -0
- package/dist/runtime/commands/release-notes.js +229 -0
- package/dist/runtime/commands/repo-map.js +95 -0
- package/dist/runtime/commands/report.js +299 -0
- package/dist/runtime/commands/resume.js +118 -0
- package/dist/runtime/commands/review-consensus.js +68 -53
- package/dist/runtime/commands/rewind.js +333 -0
- package/dist/runtime/commands/roster.js +14 -14
- package/dist/runtime/commands/sessions.js +163 -0
- package/dist/runtime/commands/share.js +316 -0
- package/dist/runtime/commands/skills.js +31 -31
- package/dist/runtime/commands/status.js +186 -0
- package/dist/runtime/commands/stickers.js +82 -0
- package/dist/runtime/commands/style.js +194 -0
- package/dist/runtime/commands/theme.js +196 -0
- package/dist/runtime/commands/undo.js +54 -22
- package/dist/runtime/commands/update.js +289 -0
- package/dist/runtime/commands/vim.js +140 -0
- package/dist/runtime/commands/worktree.js +8 -8
- package/dist/runtime/commands/worktrees.js +155 -0
- package/dist/runtime/headless-repl.js +195 -0
- package/dist/runtime/headless.js +543 -0
- package/dist/runtime/load-hooks-or-exit.js +71 -0
- package/dist/runtime/plan-decompose.js +22 -22
- package/dist/runtime/sigint-guard.js +272 -0
- package/dist/runtime/update-check.js +28 -28
- package/dist/runtime/version.js +65 -0
- package/dist/runtime/worktree-bootstrap.js +579 -0
- package/dist/skills/bundled/batch.js +617 -0
- package/dist/skills/bundled/index.js +45 -0
- package/dist/skills/bundled/loop.js +358 -0
- package/dist/skills/bundled/remember.js +383 -0
- package/dist/skills/bundled/simplify.js +289 -0
- package/dist/skills/bundled/skillify.js +373 -0
- package/dist/skills/bundled/stuck.js +558 -0
- package/dist/skills/bundled/verify.js +439 -0
- package/dist/testing/vcr.js +486 -0
- package/dist/tools/agent-tool.js +229 -0
- package/dist/tools/apply-patch.js +89 -28
- package/dist/tools/ask-user-question.js +337 -0
- package/dist/tools/ask-user.js +115 -0
- package/dist/tools/bash.js +624 -46
- package/dist/tools/brief.js +224 -0
- package/dist/tools/enter-worktree.js +250 -0
- package/dist/tools/exit-worktree.js +147 -0
- package/dist/tools/file-tools.js +161 -44
- package/dist/tools/lsp-tools.js +377 -1
- package/dist/tools/mcp-tool.js +260 -0
- package/dist/tools/multi-edit.js +361 -0
- package/dist/tools/powershell.js +268 -0
- package/dist/tools/registry.js +86 -4
- package/dist/tools/skill-tool.js +96 -0
- package/dist/tools/sleep.js +99 -0
- package/dist/tools/synthetic-output.js +133 -0
- package/dist/tools/tasks.js +208 -0
- package/dist/tools/todo-write.js +184 -0
- package/dist/tools/verify-plan-execution.js +295 -0
- package/dist/tools/web-fetch-injection-scanner.js +207 -0
- package/dist/tools/web-fetch.js +195 -10
- package/dist/tools/web-search.js +458 -0
- package/dist/tui/agent-progress-card.js +111 -0
- package/dist/tui/agent-tree.js +11 -1
- package/dist/tui/ask-modal.js +14 -14
- package/dist/tui/ask-user-question-chips.js +315 -0
- package/dist/tui/ask-user-question-prompt.js +203 -0
- package/dist/tui/compact-banner.js +81 -0
- package/dist/tui/conversation-pane.js +85 -11
- package/dist/tui/cost-table.js +111 -0
- package/dist/tui/device-flow.js +2 -2
- package/dist/tui/doctor-table.js +46 -0
- package/dist/tui/feedback-prompt.js +156 -0
- package/dist/tui/input-box.js +247 -32
- package/dist/tui/login-picker.js +3 -3
- package/dist/tui/markdown-render.js +6 -6
- package/dist/tui/onboarding-wizard.js +240 -0
- package/dist/tui/permissions-picker.js +86 -0
- package/dist/tui/render.js +36 -1
- package/dist/tui/repl-render.js +176 -25
- package/dist/tui/repl-splash-art.js +16 -16
- package/dist/tui/repl-splash-mascot.js +48 -24
- package/dist/tui/repl-splash.js +22 -22
- package/dist/tui/repl.js +125 -45
- package/dist/tui/slash-palette.js +6 -6
- package/dist/tui/splash.js +2 -2
- package/dist/tui/status-bar.js +109 -31
- package/dist/tui/status-table.js +7 -0
- package/dist/tui/stickers-art.js +136 -0
- package/dist/tui/style-table.js +28 -0
- package/dist/tui/theme-table.js +29 -0
- package/dist/tui/thinking-spinner.js +123 -0
- package/dist/tui/tool-stream-pane.js +53 -4
- package/dist/tui/update-banner.js +27 -2
- package/dist/tui/vim-input.js +267 -0
- package/dist/tui/welcome-banner.js +107 -0
- package/dist/tui/welcome-data.js +293 -0
- package/dist/tui/workspace-context.js +2 -2
- package/package.json +31 -16
- package/test/scenarios/codegen-create-file.scenario.txt +13 -0
- package/test/scenarios/compact-force.scenario.txt +12 -0
- package/test/scenarios/identity.scenario.txt +12 -0
- package/test/scenarios/persona-handoff.scenario.txt +12 -0
- package/test/scenarios/walkback.scenario.txt +12 -0
- package/dist/core/engine/compaction-hook.js +0 -154
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agent` tool — β2 S3 .
|
|
3
|
+
*
|
|
4
|
+
* Exposes the subagent spawn primitive as a first-class tool call so
|
|
5
|
+
* the root Pugi persona (or any orchestrator-capable parent loop) can
|
|
6
|
+
* delegate a brief to a specialist child via the standard tool-use
|
|
7
|
+
* grammar instead of via the legacy `<pugi-delegate>` XML sidechannel.
|
|
8
|
+
*
|
|
9
|
+
* Grammar:
|
|
10
|
+
*
|
|
11
|
+
* {
|
|
12
|
+
* "role": "coder" | "verifier" | "reviewer" | "researcher" | ...,
|
|
13
|
+
* "brief": "one-paragraph task description",
|
|
14
|
+
* "isolation": "worktree" | "shared_fs" | "auto" // optional, default "auto"
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* Returns a JSON envelope:
|
|
18
|
+
*
|
|
19
|
+
* {
|
|
20
|
+
* "ok": true,
|
|
21
|
+
* "taskId": "subagent-<uuid>",
|
|
22
|
+
* "role": "coder",
|
|
23
|
+
* "personaSlug": "dev",
|
|
24
|
+
* "status": "shipped" | "blocked" | "failed",
|
|
25
|
+
* "summary": "...",
|
|
26
|
+
* "filesChanged": ["src/...", "src/..."],
|
|
27
|
+
* "toolCallCount": N,
|
|
28
|
+
* "tokensIn": N,
|
|
29
|
+
* "tokensOut": N,
|
|
30
|
+
* "durationMs": N,
|
|
31
|
+
* "worktreePath": "/path/.pugi/worktrees/<uuid>" // only when worktree isolation used
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* Why expose this as a tool rather than baking it into the engine
|
|
35
|
+
* loop directly:
|
|
36
|
+
*
|
|
37
|
+
* - The model's existing tool-use grammar is what every modern Anvil
|
|
38
|
+
* provider speaks natively. Wrapping delegation as a tool means the
|
|
39
|
+
* model can decide WHEN to spawn a child the same way it decides
|
|
40
|
+
* when to read/edit/bash — no special-case prompt engineering.
|
|
41
|
+
* - The `agent` tool is gated by the isolation-matrix capability map
|
|
42
|
+
* (only `orchestrator`-class roles see it in their tools schema).
|
|
43
|
+
* A coder/reviewer/verifier cannot recursively spawn grandchildren
|
|
44
|
+
* because they never see the `agent` tool in the first place.
|
|
45
|
+
* - The audit log threads cleanly: parent's `tool_call: agent(...)`
|
|
46
|
+
* pairs with the child's `subagent.spawned/tool_call/completed`
|
|
47
|
+
* events, and a single SSE replay yields the full tree.
|
|
48
|
+
*/
|
|
49
|
+
import { z } from 'zod';
|
|
50
|
+
import { randomUUID } from 'node:crypto';
|
|
51
|
+
import { relative as relativePath } from 'node:path';
|
|
52
|
+
import { spawnSubagentWithOutcome } from '../core/subagents/spawn.js';
|
|
53
|
+
import { inheritCacheContext } from '../core/dispatch/cache-handoff.js';
|
|
54
|
+
/**
|
|
55
|
+
* Argument schema. `isolation: 'auto'` defers to the role-default
|
|
56
|
+
* isolation tier (set by `isolationForRole` in dispatcher.ts). The
|
|
57
|
+
* explicit `worktree` opt-in forces worktree isolation even for roles
|
|
58
|
+
* whose default is `shared_fs_serialized`; `shared_fs` does the
|
|
59
|
+
* inverse (forces shared-fs even for roles whose default is `worktree`).
|
|
60
|
+
*
|
|
61
|
+
* The role enum mirrors the SDK's SubagentRole — keep both in lockstep.
|
|
62
|
+
*
|
|
63
|
+
* Leak P0 L2 : `z.strictObject` rejects ANY additional or
|
|
64
|
+
* aliased fields at parse time. Matches the the standard file-edit grammar /
|
|
65
|
+
* FileWriteTool posture (). The model-facing JSON
|
|
66
|
+
* schema already declares `additionalProperties: false`; the strict
|
|
67
|
+
* Zod variant is defense-in-depth — if the bridge ever bypasses the
|
|
68
|
+
* model-side gate (raw test fixture, internal dispatch), the runtime
|
|
69
|
+
* still refuses unknown keys instead of silently dropping them.
|
|
70
|
+
*/
|
|
71
|
+
export const agentToolArgsSchema = z.strictObject({
|
|
72
|
+
role: z.enum([
|
|
73
|
+
'orchestrator',
|
|
74
|
+
'architect',
|
|
75
|
+
'coder',
|
|
76
|
+
'verifier',
|
|
77
|
+
'reviewer',
|
|
78
|
+
'researcher',
|
|
79
|
+
'release',
|
|
80
|
+
'devops',
|
|
81
|
+
'design_qa',
|
|
82
|
+
]).describe('SubagentRole — selects persona + isolation tier.'),
|
|
83
|
+
brief: z
|
|
84
|
+
.string()
|
|
85
|
+
.min(1, 'brief must not be empty')
|
|
86
|
+
.max(8000, 'brief must be ≤ 8000 chars')
|
|
87
|
+
.describe('One-paragraph task description forwarded to the child as the user prompt. '
|
|
88
|
+
+ 'Be concrete: include filenames, expected behavior, and acceptance criteria.'),
|
|
89
|
+
isolation: z
|
|
90
|
+
.enum(['worktree', 'shared_fs', 'auto'])
|
|
91
|
+
.optional()
|
|
92
|
+
.describe('Optional override. `worktree` forces a scratch git worktree for write isolation; '
|
|
93
|
+
+ '`shared_fs` forces same-tree execution; `auto` (default) defers to the role tier.'),
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* Dispatch a subagent via the `agent` tool. Returns the JSON envelope
|
|
97
|
+
* the executor wraps into the tool result frame. Throws when the
|
|
98
|
+
* arguments fail schema validation — the executor catches and feeds
|
|
99
|
+
* the message back to the model so it can correct itself.
|
|
100
|
+
*/
|
|
101
|
+
export async function agentTool(args, ctx) {
|
|
102
|
+
const validated = agentToolArgsSchema.parse(args);
|
|
103
|
+
if (!ctx.engineClient) {
|
|
104
|
+
// Hard refusal: the `agent` tool is real-backend-only. Surfacing a
|
|
105
|
+
// structured envelope (instead of throwing) lets the model decide
|
|
106
|
+
// whether to abandon the delegation or to fall back to in-process
|
|
107
|
+
// work. Throwing here would terminate the parent loop on a tool
|
|
108
|
+
// error frame, which is the wrong UX when the issue is config.
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
taskId: `subagent-rejected-${randomUUID()}`,
|
|
112
|
+
role: validated.role,
|
|
113
|
+
personaSlug: '',
|
|
114
|
+
status: 'failed',
|
|
115
|
+
summary: 'agent tool unavailable: no engine client wired through the parent dispatch. '
|
|
116
|
+
+ 'Run pugi via the standard CLI entrypoints; the in-memory test harness does '
|
|
117
|
+
+ 'not currently support real subagent spawn.',
|
|
118
|
+
filesChanged: [],
|
|
119
|
+
toolCallCount: 0,
|
|
120
|
+
tokensIn: 0,
|
|
121
|
+
tokensOut: 0,
|
|
122
|
+
durationMs: 0,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// β2 S10 pre-flight (best-effort): refuse the spawn if the child's
|
|
126
|
+
// role-default token budget exceeds the parent's remaining budget.
|
|
127
|
+
// The check is conservative — it uses the child's DEFAULT envelope
|
|
128
|
+
// because we do not know the actual run cost ahead of time. Roles
|
|
129
|
+
// can downscale via SubagentTask.budget overrides; this gate just
|
|
130
|
+
// catches the gross case (parent has 5k left, child default 80k).
|
|
131
|
+
if (ctx.parentBudgetRemaining?.tokens !== undefined) {
|
|
132
|
+
const { budgetForRole } = await import('../core/subagents/dispatcher.js');
|
|
133
|
+
const childDefault = budgetForRole(validated.role, undefined);
|
|
134
|
+
if (childDefault.tokens > ctx.parentBudgetRemaining.tokens) {
|
|
135
|
+
return {
|
|
136
|
+
ok: false,
|
|
137
|
+
taskId: `subagent-budget-refused-${randomUUID()}`,
|
|
138
|
+
role: validated.role,
|
|
139
|
+
personaSlug: '',
|
|
140
|
+
status: 'blocked',
|
|
141
|
+
summary: `agent spawn refused: child '${validated.role}' default budget is ${childDefault.tokens} tokens `
|
|
142
|
+
+ `but parent has only ${ctx.parentBudgetRemaining.tokens} tokens remaining. `
|
|
143
|
+
+ 'Tighten the child task budget or finish the parent first.',
|
|
144
|
+
filesChanged: [],
|
|
145
|
+
toolCallCount: 0,
|
|
146
|
+
tokensIn: 0,
|
|
147
|
+
tokensOut: 0,
|
|
148
|
+
durationMs: 0,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const task = {
|
|
153
|
+
id: `subagent-${randomUUID()}`,
|
|
154
|
+
role: validated.role,
|
|
155
|
+
prompt: validated.brief,
|
|
156
|
+
// `auto` permission mode matches the parent loop's default; the
|
|
157
|
+
// isolation-matrix capability gate provides the load-bearing
|
|
158
|
+
// restriction layer regardless of permissionMode.
|
|
159
|
+
permissionMode: 'auto',
|
|
160
|
+
};
|
|
161
|
+
// L10 : synthesize a prompt-cache inheritance handle for
|
|
162
|
+
// the child before we dispatch. The handle is persisted under
|
|
163
|
+
// `.pugi/cache-refs/<childAgentId>.json` so:
|
|
164
|
+
// - The child engine loop's first turn (dispatcher-real.ts) can
|
|
165
|
+
// forward parent_cache_id onto Anvil — provider-dependent honour
|
|
166
|
+
// (Anthropic cache_control breakpoints today; OpenAI/Gemini
|
|
167
|
+
// silently ignore until Anvil grows per-provider adapters).
|
|
168
|
+
// - Operators can introspect via `pugi dispatch list-cache-refs`.
|
|
169
|
+
// - `pugi dispatch clear-cache-refs --older-than 1h` can GC after
|
|
170
|
+
// a long session.
|
|
171
|
+
// Failure to persist must NOT block the dispatch — the handle is a
|
|
172
|
+
// best-effort optimisation; if disk is full or the workspace root is
|
|
173
|
+
// read-only, we degrade silently to a cache-miss dispatch.
|
|
174
|
+
try {
|
|
175
|
+
inheritCacheContext(ctx.session.id, task.id, {
|
|
176
|
+
workspaceRoot: ctx.session.root,
|
|
177
|
+
...(ctx.now ? { now: ctx.now } : {}),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// Silent degrade: cache inheritance is forward-compat, not load-bearing.
|
|
182
|
+
}
|
|
183
|
+
const useWorktree = validated.isolation === 'worktree'
|
|
184
|
+
? true
|
|
185
|
+
: validated.isolation === 'shared_fs'
|
|
186
|
+
? false
|
|
187
|
+
: undefined; // 'auto' → defer to role default
|
|
188
|
+
const outcome = await spawnSubagentWithOutcome(task, ctx.session, {
|
|
189
|
+
engineClient: ctx.engineClient,
|
|
190
|
+
...(useWorktree !== undefined ? { useWorktreeIsolation: useWorktree } : {}),
|
|
191
|
+
});
|
|
192
|
+
const envelope = {
|
|
193
|
+
// `ok` = subagent did not crash. Both `shipped` (real work) and
|
|
194
|
+
// `replied` (text-only completion, added) count as
|
|
195
|
+
// non-crash outcomes; the caller can branch on the explicit
|
|
196
|
+
// `status` field below if it needs to distinguish them.
|
|
197
|
+
ok: outcome.result.status === 'shipped' || outcome.result.status === 'replied',
|
|
198
|
+
taskId: outcome.result.taskId,
|
|
199
|
+
role: outcome.result.role,
|
|
200
|
+
personaSlug: outcome.result.personaSlug,
|
|
201
|
+
status: outcome.result.status,
|
|
202
|
+
summary: outcome.result.summary,
|
|
203
|
+
filesChanged: outcome.result.filesChanged,
|
|
204
|
+
toolCallCount: outcome.result.toolCallCount,
|
|
205
|
+
tokensIn: outcome.result.tokensIn,
|
|
206
|
+
tokensOut: outcome.result.tokensOut,
|
|
207
|
+
durationMs: outcome.result.durationMs,
|
|
208
|
+
};
|
|
209
|
+
if (outcome.worktreeHandle) {
|
|
210
|
+
// β2a r2 (Codex P1): emit the worktree path RELATIVE to
|
|
211
|
+
// the parent session's workspace root. The envelope is JSON-stringified
|
|
212
|
+
// into the parent loop's tool_result frame and from there flows to the
|
|
213
|
+
// provider on every subsequent assistant turn — shipping the absolute
|
|
214
|
+
// path (`/Users/<operator>/Web/.../.pugi/worktrees/<uuid>`) leaks the
|
|
215
|
+
// operator's home directory to the upstream provider on every spawn.
|
|
216
|
+
//
|
|
217
|
+
// The composeSummary path (dispatcher-real.ts §β2a r1) already scrubs
|
|
218
|
+
// the summary text via the same `relative()` wrapping; this is the
|
|
219
|
+
// matching fix for the structured envelope field that r1 missed.
|
|
220
|
+
// The relative form (`.pugi/worktrees/<uuid>`) is enough for the
|
|
221
|
+
// operator's local `pugi worktree promote/drop` commands which run
|
|
222
|
+
// resolved against ctx.session.root anyway.
|
|
223
|
+
const relPath = relativePath(ctx.session.root, outcome.worktreeHandle.path)
|
|
224
|
+
|| outcome.worktreeHandle.path;
|
|
225
|
+
envelope.worktreePath = relPath;
|
|
226
|
+
}
|
|
227
|
+
return envelope;
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=agent-tool.js.map
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* apply_patch tool —
|
|
2
|
+
* apply_patch tool — Phase 1.
|
|
3
3
|
*
|
|
4
4
|
* Accepts a unified diff (the format produced by `git diff` and
|
|
5
5
|
* consumed by `git apply`) and lands it atomically into the workspace.
|
|
6
|
-
* This is the third edit primitive alongside the
|
|
6
|
+
* This is the third edit primitive alongside the 4-layer diff
|
|
7
7
|
* escalation: where the layers escalate from minimal `oldString`/
|
|
8
8
|
* `newString` blocks up to full-file rewrites, apply_patch covers the
|
|
9
9
|
* unified-diff dialect that OpenAI Codex and most external tools emit.
|
|
10
10
|
*
|
|
11
11
|
* Why we have both:
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
13
|
+
* - The 4-layer escalation maximises model-side success rate on
|
|
14
|
+
* conversational edits (Claude / Gemini / OpenAI all have a
|
|
15
|
+
* preferred dialect that maps onto one of the layers).
|
|
16
|
+
* - apply_patch is the "external tools speak this" path. A model
|
|
17
|
+
* emits a single unified diff (the format `git diff` produces),
|
|
18
|
+
* and we run it through `git apply` with the same security gate
|
|
19
|
+
* the layers use.
|
|
20
20
|
*
|
|
21
21
|
* Security: every file mentioned in the patch goes through the same
|
|
22
22
|
* `applySecurityGate` chokepoint as the layers (see
|
|
@@ -55,7 +55,7 @@ import { recordToolCall, recordToolResult, recordFileMutation } from '../core/se
|
|
|
55
55
|
* touched paths feeds the security gate — EVERY file goes through
|
|
56
56
|
* `applySecurityGate` before we trust `git apply` to do anything.
|
|
57
57
|
*
|
|
58
|
-
* Security (R1 fix
|
|
58
|
+
* Security (R1 fix, PR r1): git emits C-style quoted
|
|
59
59
|
* path headers when a path contains "unusual" bytes (high bits, control
|
|
60
60
|
* chars, double-quote, backslash) and `core.quotePath` is true (the
|
|
61
61
|
* default). The literal header looks like
|
|
@@ -140,11 +140,11 @@ function stripQuotedHalf(after, prefix) {
|
|
|
140
140
|
* (default) git writes paths with high-bit / control / quote bytes as
|
|
141
141
|
* C-string escapes inside double quotes:
|
|
142
142
|
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
143
|
+
* `"\.env"` -> `.env` (backslash before . is just a literal)
|
|
144
|
+
* `"a\"b"` -> `a"b` (escaped double-quote)
|
|
145
|
+
* `"a\\b"` -> `a\b` (escaped backslash)
|
|
146
|
+
* `"a\tb"` -> `a` + TAB + `b`
|
|
147
|
+
* `"a\341\210\264"` -> `a` + UTF-8 bytes 0xe1 0x88 0xb4
|
|
148
148
|
*
|
|
149
149
|
* Accepts a path that is EITHER already unquoted (passed through) OR an
|
|
150
150
|
* inner string previously stripped of its surrounding quotes. The
|
|
@@ -261,6 +261,25 @@ export function applyPatch(ctx, patch, opts = {}) {
|
|
|
261
261
|
recordToolResult(ctx.session, toolCallId, 'error', 'empty_patch');
|
|
262
262
|
return result;
|
|
263
263
|
}
|
|
264
|
+
// β7 L4: pre-flight conflict-marker check. A patch that still carries
|
|
265
|
+
// unresolved `<<<<<<<`/`=======`/`>>>>>>>` lines is almost always
|
|
266
|
+
// operator error (copy-pasted a half-resolved merge instead of the
|
|
267
|
+
// clean diff). `git apply` would reject it with a confusing
|
|
268
|
+
// "corrupt patch" message; the dedicated reason makes the failure
|
|
269
|
+
// obvious. We only check at body line starts so a legitimate diff
|
|
270
|
+
// that adds a string literal containing `<<<<<<<` for tests still
|
|
271
|
+
// applies.
|
|
272
|
+
if (containsConflictMarkers(patch)) {
|
|
273
|
+
const result = {
|
|
274
|
+
ok: false,
|
|
275
|
+
filesChanged: [],
|
|
276
|
+
reason: 'conflict_markers',
|
|
277
|
+
detail: 'patch body contains unresolved git conflict markers (<<<<<<<, =======, >>>>>>>). ' +
|
|
278
|
+
'Resolve the conflict first or use --3way with --base=<sha> to defer to git.',
|
|
279
|
+
};
|
|
280
|
+
recordToolResult(ctx.session, toolCallId, 'error', 'conflict_markers');
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
264
283
|
const paths = extractPatchPaths(patch);
|
|
265
284
|
if (paths.length === 0) {
|
|
266
285
|
const result = {
|
|
@@ -272,12 +291,12 @@ export function applyPatch(ctx, patch, opts = {}) {
|
|
|
272
291
|
recordToolResult(ctx.session, toolCallId, 'error', 'invalid_patch');
|
|
273
292
|
return result;
|
|
274
293
|
}
|
|
275
|
-
// SECURITY GATE — reuse the
|
|
294
|
+
// SECURITY GATE — reuse the chokepoint. Every path in the patch
|
|
276
295
|
// is validated against:
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
//
|
|
296
|
+
// 1. workspace containment (no ../../ escapes)
|
|
297
|
+
// 2. protected-file basenames (.env, *.pem, id_rsa, etc.)
|
|
298
|
+
// 3. symlink escape (an in-workspace symlink pointing to /etc/hosts
|
|
299
|
+
// or a protected basename gets rejected here)
|
|
281
300
|
for (const file of paths) {
|
|
282
301
|
const gate = applySecurityGate(file, { cwd: ctx.root, toolName: 'layer-c' });
|
|
283
302
|
if (!gate.ok) {
|
|
@@ -349,7 +368,7 @@ export function applyPatch(ctx, patch, opts = {}) {
|
|
|
349
368
|
recordToolResult(ctx.session, toolCallId, 'success', `dry-run ok, ${paths.length} files`);
|
|
350
369
|
return result;
|
|
351
370
|
}
|
|
352
|
-
// R1 fix (2026-05-26, PR
|
|
371
|
+
// R1 fix (2026-05-26, PR r1, Fix 6): snapshot which paths exist
|
|
353
372
|
// BEFORE the apply so rollbackFiles can decide between
|
|
354
373
|
// `git checkout -- <file>` (for files that existed) and `fs.rmSync`
|
|
355
374
|
// (for files the patch was creating that may have been half-written
|
|
@@ -409,16 +428,16 @@ export function applyPatch(ctx, patch, opts = {}) {
|
|
|
409
428
|
* only on the rare path where `git apply` fails AFTER `git apply --check`
|
|
410
429
|
* passed.
|
|
411
430
|
*
|
|
412
|
-
* R1 fix (2026-05-26, PR
|
|
431
|
+
* R1 fix (2026-05-26, PR r1, Fix 6): a multi-file patch that
|
|
413
432
|
* creates new files leaves them on disk when `git apply` fails partway —
|
|
414
433
|
* `git checkout -- <file>` does NOT delete a path that was never tracked
|
|
415
434
|
* (the file was created by the failed apply). We split paths into two
|
|
416
435
|
* groups using the pre-apply snapshot:
|
|
417
436
|
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
437
|
+
* - existed-before -> `git checkout -- <file>` restores tracked content.
|
|
438
|
+
* - created-by-apply -> `fs.rmSync(file, { force: true })` removes the
|
|
439
|
+
* half-written file so the workspace ends up identical to its
|
|
440
|
+
* pre-apply state.
|
|
422
441
|
*
|
|
423
442
|
* This keeps the dispatcher's invariant: a tool result of `ok: false`
|
|
424
443
|
* means the workspace is unchanged.
|
|
@@ -470,7 +489,7 @@ function rollbackFiles(cwd, paths, preExisting) {
|
|
|
470
489
|
return { ok: true };
|
|
471
490
|
}
|
|
472
491
|
function runGit(args, cwd, stdin) {
|
|
473
|
-
// R1 fix (2026-05-26, PR
|
|
492
|
+
// R1 fix (2026-05-26, PR r1, P2 #13): force the English C locale
|
|
474
493
|
// for the git child process. The `already_applied` reason-coding
|
|
475
494
|
// below greps stderr for the literal English string
|
|
476
495
|
// "already exists in working directory"; on a host where git was
|
|
@@ -486,10 +505,52 @@ function runGit(args, cwd, stdin) {
|
|
|
486
505
|
env: { ...process.env, LANG: 'C', LC_ALL: 'C' },
|
|
487
506
|
});
|
|
488
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* β7 L4: detect unresolved git conflict markers in a patch body.
|
|
510
|
+
*
|
|
511
|
+
* Conflict markers in a unified diff are a sign of operator error —
|
|
512
|
+
* someone copy-pasted a half-merged file instead of the clean diff.
|
|
513
|
+
* `git apply` would reject the patch with a confusing parse error
|
|
514
|
+
* ("corrupt patch at line N"). We check at the START of body lines so
|
|
515
|
+
* a legitimate diff that adds a string literal containing `<<<<<<<`
|
|
516
|
+
* (rare but legitimate for tests) still applies.
|
|
517
|
+
*
|
|
518
|
+
* Conflict marker bytes in a unified diff body look like:
|
|
519
|
+
*
|
|
520
|
+
* +<<<<<<< HEAD
|
|
521
|
+
* +=======
|
|
522
|
+
* +>>>>>>> branch
|
|
523
|
+
*
|
|
524
|
+
* The `+` prefix is the unified-diff line-add marker. We strip it
|
|
525
|
+
* before the marker check; without the strip, an INVERSE diff that
|
|
526
|
+
* REMOVES a real conflict marker (legitimate cleanup commit) would be
|
|
527
|
+
* a false positive.
|
|
528
|
+
*
|
|
529
|
+
* Returns true when ANY conflict marker is detected.
|
|
530
|
+
*/
|
|
531
|
+
export function containsConflictMarkers(patch) {
|
|
532
|
+
for (const line of patch.split('\n')) {
|
|
533
|
+
// Only inspect body lines (start with `+` or `-` — the diff add/del
|
|
534
|
+
// markers). Header lines (`diff --git`, `+++`, `---`, `@@`) are
|
|
535
|
+
// skipped because the marker tokens cannot appear in those positions.
|
|
536
|
+
if (!(line.startsWith('+') || line.startsWith('-')))
|
|
537
|
+
continue;
|
|
538
|
+
// Skip diff header lines (`+++ b/foo` / `--- a/foo`).
|
|
539
|
+
if (line.startsWith('+++') || line.startsWith('---'))
|
|
540
|
+
continue;
|
|
541
|
+
const body = line.slice(1);
|
|
542
|
+
if (body.startsWith('<<<<<<<') ||
|
|
543
|
+
body.startsWith('>>>>>>>') ||
|
|
544
|
+
body === '=======') {
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
489
550
|
/**
|
|
490
551
|
* Test-only surface for the apply-patch heuristics. Specs poke
|
|
491
552
|
* `extractPatchPaths` directly to assert on the path-parsing layer
|
|
492
553
|
* without paying for a real git invocation.
|
|
493
554
|
*/
|
|
494
|
-
export const __test__ = { extractPatchPaths, runGit, unquoteGitPath };
|
|
555
|
+
export const __test__ = { extractPatchPaths, runGit, unquoteGitPath, containsConflictMarkers };
|
|
495
556
|
//# sourceMappingURL=apply-patch.js.map
|