@pugi/cli 0.1.0-beta.98 → 1.0.0-alpha.1
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/LICENSE +1 -1
- package/README.md +11 -191
- package/bin/pugi +8 -0
- package/package.json +15 -71
- package/postinstall.mjs +31 -0
- package/CHANGELOG.md +0 -132
- package/THIRD_PARTY_NOTICES.md +0 -40
- package/assets/pugi-mascot.ansi +0 -16
- package/assets/pugi-prozr2-mascot.ansi +0 -9
- package/bin/run.js +0 -34
- package/dist/commands/deploy.js +0 -439
- package/dist/commands/flatten.js +0 -191
- package/dist/commands/jobs-watch.js +0 -201
- package/dist/commands/jobs.js +0 -260
- package/dist/commands/retro.js +0 -210
- package/dist/commands/smoke.js +0 -133
- package/dist/core/agent-progress/cleanup.js +0 -134
- package/dist/core/agent-progress/schema.js +0 -144
- package/dist/core/agent-progress/writer.js +0 -101
- package/dist/core/agents/adaptive-router.js +0 -330
- package/dist/core/agents/loader.js +0 -104
- package/dist/core/agents/query-decomposer.js +0 -297
- package/dist/core/agents/registry.js +0 -69
- package/dist/core/approvals/shortcut-resolver.js +0 -98
- package/dist/core/artifact-chain/dispatcher.js +0 -148
- package/dist/core/artifact-chain/exporter.js +0 -164
- package/dist/core/artifact-chain/state.js +0 -243
- package/dist/core/artifact-chain/steps.js +0 -169
- package/dist/core/ask-user/question.js +0 -92
- package/dist/core/audit/audit-trail.js +0 -275
- package/dist/core/auth/ensure-authenticated.js +0 -129
- package/dist/core/auth/env-provider.js +0 -238
- package/dist/core/auto-open-browser.js +0 -128
- package/dist/core/auto-update/channels.js +0 -122
- package/dist/core/auto-update/checker.js +0 -241
- package/dist/core/auto-update/state.js +0 -235
- package/dist/core/bare-mode/index.js +0 -107
- package/dist/core/bash/redirect.js +0 -281
- package/dist/core/bash-classifier.js +0 -1397
- package/dist/core/checkpoint/resumer.js +0 -149
- package/dist/core/checkpoint/rewinder.js +0 -291
- package/dist/core/checkpoints/shadow-git.js +0 -670
- package/dist/core/citations/parser.js +0 -109
- package/dist/core/classifier/yolo-classifier.js +0 -88
- package/dist/core/clipboard.js +0 -70
- package/dist/core/codegraph/decision-store.js +0 -248
- package/dist/core/codegraph/detect-repo.js +0 -459
- package/dist/core/codegraph/install.js +0 -134
- package/dist/core/codegraph/offer-hook.js +0 -220
- package/dist/core/compact/auto-trigger.js +0 -96
- package/dist/core/compact/buffer-rewriter.js +0 -115
- package/dist/core/compact/summarizer.js +0 -208
- package/dist/core/compact/token-counter.js +0 -108
- package/dist/core/consensus/anvil-fanout.js +0 -276
- package/dist/core/consensus/diff-capture.js +0 -491
- package/dist/core/consensus/rubric.js +0 -233
- package/dist/core/context/builder.js +0 -114
- package/dist/core/context/compaction-events.js +0 -99
- package/dist/core/context/compaction.js +0 -602
- package/dist/core/context/index.js +0 -28
- package/dist/core/context/invariants.js +0 -250
- package/dist/core/context/markdown-loader.js +0 -288
- package/dist/core/context/markdown-traverse.js +0 -255
- package/dist/core/context/pugiignore.js +0 -316
- package/dist/core/context/repo-skeleton.js +0 -533
- package/dist/core/context/tool-eviction.js +0 -55
- package/dist/core/context/watcher.js +0 -342
- package/dist/core/context/working-set.js +0 -165
- package/dist/core/coordinator/agent-tools.js +0 -77
- package/dist/core/coordinator/agent-toolset.js +0 -65
- package/dist/core/coordinator/fsm.js +0 -73
- package/dist/core/coordinator/mode-fsm.js +0 -70
- package/dist/core/cost/rate-card.js +0 -129
- package/dist/core/cost/tracker.js +0 -221
- package/dist/core/credentials.js +0 -355
- package/dist/core/cron/scheduler.js +0 -138
- package/dist/core/denial-tracking/index.js +0 -8
- package/dist/core/denial-tracking/state.js +0 -264
- package/dist/core/diagnostics/probe-runner.js +0 -93
- package/dist/core/diagnostics/probes/api.js +0 -46
- package/dist/core/diagnostics/probes/auth.js +0 -93
- package/dist/core/diagnostics/probes/bare-mode.js +0 -42
- package/dist/core/diagnostics/probes/cli-version.js +0 -127
- package/dist/core/diagnostics/probes/config.js +0 -72
- package/dist/core/diagnostics/probes/denial-tracking.js +0 -57
- package/dist/core/diagnostics/probes/disk.js +0 -81
- package/dist/core/diagnostics/probes/engine-live.js +0 -46
- package/dist/core/diagnostics/probes/git.js +0 -65
- package/dist/core/diagnostics/probes/hooks.js +0 -118
- package/dist/core/diagnostics/probes/mcp.js +0 -75
- package/dist/core/diagnostics/probes/node.js +0 -59
- package/dist/core/diagnostics/probes/pnpm.js +0 -36
- package/dist/core/diagnostics/probes/pugi-md.js +0 -89
- package/dist/core/diagnostics/probes/sandbox.js +0 -72
- package/dist/core/diagnostics/probes/session.js +0 -74
- package/dist/core/diagnostics/probes/status-snapshot.js +0 -488
- package/dist/core/diagnostics/probes/workspace.js +0 -63
- package/dist/core/diagnostics/types.js +0 -70
- package/dist/core/dispatch/cache-cleanup.js +0 -197
- package/dist/core/dispatch/cache-handoff.js +0 -295
- package/dist/core/edits/apply-patch-layer-e.js +0 -189
- package/dist/core/edits/dispatch.js +0 -511
- package/dist/core/edits/format-detector.js +0 -260
- package/dist/core/edits/format-matrix.js +0 -26
- package/dist/core/edits/fuzzy-ladder.js +0 -650
- package/dist/core/edits/index.js +0 -19
- package/dist/core/edits/journal.js +0 -199
- package/dist/core/edits/layer-a-apply.js +0 -217
- package/dist/core/edits/layer-a-fuzzy-apply.js +0 -198
- package/dist/core/edits/layer-b-apply.js +0 -211
- package/dist/core/edits/layer-c-apply.js +0 -160
- package/dist/core/edits/layer-d-ast.js +0 -572
- package/dist/core/edits/marker-parser.js +0 -401
- package/dist/core/edits/security-gate.js +0 -223
- package/dist/core/edits/verify-hook.js +0 -273
- package/dist/core/edits/worktree.js +0 -322
- package/dist/core/engine/adapter-runner.js +0 -8
- package/dist/core/engine/anvil-client.js +0 -344
- package/dist/core/engine/auto-compact.js +0 -179
- package/dist/core/engine/budgets.js +0 -192
- package/dist/core/engine/context-prefix.js +0 -155
- package/dist/core/engine/index.js +0 -12
- package/dist/core/engine/intensity.js +0 -163
- package/dist/core/engine/intent.js +0 -260
- package/dist/core/engine/native-pugi.js +0 -1616
- package/dist/core/engine/noop.js +0 -27
- package/dist/core/engine/prompts.js +0 -236
- package/dist/core/engine/strip-internal-fields.js +0 -124
- package/dist/core/engine/tool-bridge.js +0 -2173
- package/dist/core/engine/verification-patterns.js +0 -195
- package/dist/core/evaluation/golden-dataset.js +0 -293
- package/dist/core/feedback/queue.js +0 -177
- package/dist/core/feedback/submitter.js +0 -145
- package/dist/core/file-cache.js +0 -141
- package/dist/core/flatten/flatten-repo.js +0 -439
- package/dist/core/format/osc8-link.js +0 -28
- package/dist/core/hook-chains.js +0 -392
- package/dist/core/hooks/citation-verify-hook.js +0 -138
- package/dist/core/hooks/citation-verify.js +0 -112
- package/dist/core/hooks/events.js +0 -46
- package/dist/core/hooks/index.js +0 -15
- package/dist/core/hooks/registry.js +0 -216
- package/dist/core/hooks/runner.js +0 -236
- package/dist/core/hooks/v2/event-emitter.js +0 -115
- package/dist/core/hooks/v2/executor.js +0 -282
- package/dist/core/hooks/v2/index.js +0 -25
- package/dist/core/hooks/v2/lifecycle.js +0 -104
- package/dist/core/hooks/v2/loader.js +0 -216
- package/dist/core/hooks/v2/matcher.js +0 -125
- package/dist/core/hooks/v2/trust.js +0 -143
- package/dist/core/hooks/v2/types.js +0 -86
- package/dist/core/hooks/worktree-events.js +0 -158
- package/dist/core/hooks.js +0 -415
- package/dist/core/image/renderer.js +0 -71
- package/dist/core/index-store.js +0 -260
- package/dist/core/init/detector.js +0 -582
- package/dist/core/init/template-renderer.js +0 -242
- package/dist/core/jobs/registry.js +0 -462
- package/dist/core/ledger/results-tsv.js +0 -142
- package/dist/core/log-discipline/stdout-redirect.js +0 -51
- package/dist/core/lsp/cache.js +0 -105
- package/dist/core/lsp/client.js +0 -1229
- package/dist/core/lsp/language-detect.js +0 -66
- package/dist/core/lsp/post-edit-diagnostics.js +0 -171
- package/dist/core/lsp/server-detect.js +0 -173
- package/dist/core/lsp/symbol-cache.js +0 -162
- package/dist/core/lsp/symbol-tools.js +0 -664
- package/dist/core/mcp/client.js +0 -385
- package/dist/core/mcp/http-server.js +0 -553
- package/dist/core/mcp/orchestrator-config.js +0 -192
- package/dist/core/mcp/orchestrator-tools.js +0 -806
- package/dist/core/mcp/permission.js +0 -190
- package/dist/core/mcp/registry.js +0 -193
- package/dist/core/mcp/server-tools.js +0 -219
- package/dist/core/mcp/server.js +0 -397
- package/dist/core/mcp/trust.js +0 -91
- package/dist/core/memory/dual-write.js +0 -416
- package/dist/core/memory/passive-extract.js +0 -130
- package/dist/core/memory/phase1-kinds.js +0 -20
- package/dist/core/memory/secret-scanner.js +0 -304
- package/dist/core/memory-sync/queue.js +0 -170
- package/dist/core/metrics/extract.js +0 -113
- package/dist/core/modes/roo-modes.js +0 -68
- package/dist/core/onboarding/ensure-initialized.js +0 -133
- package/dist/core/onboarding/marker.js +0 -111
- package/dist/core/onboarding/telemetry-state.js +0 -108
- package/dist/core/output-style/presets.js +0 -176
- package/dist/core/output-style/state.js +0 -185
- package/dist/core/path-security.js +0 -345
- package/dist/core/permission.js +0 -369
- package/dist/core/permissions/auto-classifier.js +0 -124
- package/dist/core/permissions/bash-parser.js +0 -371
- package/dist/core/permissions/circuit-breaker.js +0 -83
- package/dist/core/permissions/constrained-edit.js +0 -91
- package/dist/core/permissions/gate.js +0 -278
- package/dist/core/permissions/index.js +0 -20
- package/dist/core/permissions/mode.js +0 -174
- package/dist/core/permissions/network-egress.js +0 -137
- package/dist/core/permissions/state.js +0 -241
- package/dist/core/permissions/tool-class.js +0 -107
- package/dist/core/plan-mode/ui-state.js +0 -51
- package/dist/core/plans/plan-artifact.js +0 -721
- package/dist/core/policy-limits/etag-store.js +0 -122
- package/dist/core/prd-check/parser.js +0 -215
- package/dist/core/prd-check/reporter.js +0 -127
- package/dist/core/prd-check/session-review.js +0 -557
- package/dist/core/prd-check/verifiers.js +0 -223
- package/dist/core/prompt-cache/client-cache.js +0 -99
- package/dist/core/prompts/assembly.js +0 -29
- package/dist/core/prompts/registry.js +0 -364
- package/dist/core/pugi-gitignore.js +0 -52
- package/dist/core/pugi-md/cc-compat-rules.js +0 -735
- package/dist/core/pugi-md/context-injector.js +0 -76
- package/dist/core/pugi-md/walk-up.js +0 -207
- package/dist/core/python/uv-installer.js +0 -270
- package/dist/core/python/uv-resolver.js +0 -83
- package/dist/core/rate-limit/narrator.js +0 -146
- package/dist/core/recipes/cli-types.js +0 -20
- package/dist/core/recipes/loader.js +0 -103
- package/dist/core/recipes/runner.js +0 -345
- package/dist/core/recipes/schema.js +0 -587
- package/dist/core/release-notes/parser.js +0 -241
- package/dist/core/release-notes/state.js +0 -116
- package/dist/core/repl/ask.js +0 -512
- package/dist/core/repl/cancellation.js +0 -98
- package/dist/core/repl/cap-warning.js +0 -91
- package/dist/core/repl/clipboard-read.js +0 -174
- package/dist/core/repl/dispatch-fsm.js +0 -220
- package/dist/core/repl/engine-bridge.js +0 -303
- package/dist/core/repl/history-search.js +0 -175
- package/dist/core/repl/history.js +0 -182
- package/dist/core/repl/kill-ring.js +0 -138
- package/dist/core/repl/model-pricing.js +0 -135
- package/dist/core/repl/privacy-banner.js +0 -71
- package/dist/core/repl/session.js +0 -4962
- package/dist/core/repl/slash-commands.js +0 -747
- package/dist/core/repl/store/index.js +0 -12
- package/dist/core/repl/store/jsonl-log.js +0 -321
- package/dist/core/repl/store/lockfile.js +0 -155
- package/dist/core/repl/store/session-store.js +0 -821
- package/dist/core/repl/store/types.js +0 -44
- package/dist/core/repl/store/uuid-v7.js +0 -68
- package/dist/core/repl/tool-route.js +0 -382
- package/dist/core/repl/workspace-context.js +0 -206
- package/dist/core/repo-map/build.js +0 -125
- package/dist/core/repo-map/cache.js +0 -185
- package/dist/core/repo-map/extractor.js +0 -254
- package/dist/core/repo-map/formatter.js +0 -145
- package/dist/core/repo-map/page-rank.js +0 -105
- package/dist/core/repo-map/scanner.js +0 -211
- package/dist/core/retro/git-collector.js +0 -251
- package/dist/core/retro/health-card.js +0 -25
- package/dist/core/retro/metrics.js +0 -342
- package/dist/core/retro/narrative.js +0 -249
- package/dist/core/retro/plane-collector.js +0 -274
- package/dist/core/retro/pr-issue-link.js +0 -65
- package/dist/core/retro/types.js +0 -16
- package/dist/core/retry-budget/budget.js +0 -284
- package/dist/core/retry-budget/index.js +0 -5
- package/dist/core/retry-budget/retry-cap.js +0 -74
- package/dist/core/routing/lead-worker.js +0 -43
- package/dist/core/routing/pre-flight-estimator.js +0 -108
- package/dist/core/runs/run-tree.js +0 -103
- package/dist/core/sandboxing/adapter.js +0 -29
- package/dist/core/sandboxing/index.js +0 -49
- package/dist/core/sandboxing/none.js +0 -19
- package/dist/core/sandboxing/seatbelt.js +0 -183
- package/dist/core/security/injection-scanner.js +0 -367
- package/dist/core/security/output-filter.js +0 -418
- package/dist/core/session/env-file.js +0 -105
- package/dist/core/session/section-budgets.js +0 -140
- package/dist/core/session.js +0 -377
- package/dist/core/settings.js +0 -400
- package/dist/core/share/formatter.js +0 -271
- package/dist/core/share/redactor.js +0 -221
- package/dist/core/share/uploader.js +0 -267
- package/dist/core/skills/defaults.js +0 -457
- package/dist/core/skills/loader.js +0 -454
- package/dist/core/skills/sources.js +0 -480
- package/dist/core/skills/trust.js +0 -172
- package/dist/core/smoke/headless-driver.js +0 -174
- package/dist/core/smoke/orchestrator.js +0 -194
- package/dist/core/smoke/runner.js +0 -238
- package/dist/core/smoke/scenario-parser.js +0 -316
- package/dist/core/statusline.js +0 -99
- package/dist/core/subagents/dispatcher-real.js +0 -600
- package/dist/core/subagents/dispatcher.js +0 -352
- package/dist/core/subagents/index.js +0 -39
- package/dist/core/subagents/isolation-matrix.js +0 -213
- package/dist/core/subagents/spawn.js +0 -101
- package/dist/core/telemetry/emitter.js +0 -229
- package/dist/core/telemetry/queue.js +0 -251
- package/dist/core/theme/context.js +0 -91
- package/dist/core/theme/presets.js +0 -228
- package/dist/core/theme/state.js +0 -181
- package/dist/core/todos/invariant.js +0 -10
- package/dist/core/todos/state.js +0 -177
- package/dist/core/tool-schema/compressor.js +0 -89
- package/dist/core/transport/version-interceptor.js +0 -166
- package/dist/core/trust.js +0 -109
- package/dist/core/tui/thinking-block.js +0 -64
- package/dist/core/vim/keymap.js +0 -288
- package/dist/core/vim/state.js +0 -92
- package/dist/core/watch-markers/marker-watcher.js +0 -133
- package/dist/core/worktree/include-parser.js +0 -249
- package/dist/core/worktree-manager/cleanup.js +0 -123
- package/dist/core/worktree-manager/manager.js +0 -303
- package/dist/index.js +0 -44
- package/dist/runtime/bootstrap.js +0 -190
- package/dist/runtime/cli.js +0 -8121
- package/dist/runtime/commands/agents.js +0 -385
- package/dist/runtime/commands/budget.js +0 -192
- package/dist/runtime/commands/cancel.js +0 -231
- package/dist/runtime/commands/chain.js +0 -489
- package/dist/runtime/commands/codegraph-status.js +0 -227
- package/dist/runtime/commands/compact.js +0 -297
- package/dist/runtime/commands/config.js +0 -595
- package/dist/runtime/commands/cost.js +0 -199
- package/dist/runtime/commands/delegate.js +0 -312
- package/dist/runtime/commands/dispatch.js +0 -126
- package/dist/runtime/commands/doctor.js +0 -579
- package/dist/runtime/commands/feedback.js +0 -184
- package/dist/runtime/commands/hooks.js +0 -187
- package/dist/runtime/commands/init.js +0 -254
- package/dist/runtime/commands/lsp.js +0 -368
- package/dist/runtime/commands/mcp.js +0 -935
- package/dist/runtime/commands/memory.js +0 -582
- package/dist/runtime/commands/model.js +0 -237
- package/dist/runtime/commands/onboarding.js +0 -275
- package/dist/runtime/commands/patch.js +0 -128
- package/dist/runtime/commands/permissions.js +0 -112
- package/dist/runtime/commands/plan.js +0 -143
- package/dist/runtime/commands/prd-check.js +0 -285
- package/dist/runtime/commands/privacy.js +0 -107
- package/dist/runtime/commands/recipe.js +0 -325
- package/dist/runtime/commands/redo-blob-store.js +0 -92
- package/dist/runtime/commands/redo.js +0 -361
- package/dist/runtime/commands/release-notes.js +0 -229
- package/dist/runtime/commands/repo-map.js +0 -95
- package/dist/runtime/commands/report.js +0 -299
- package/dist/runtime/commands/resume.js +0 -118
- package/dist/runtime/commands/review-consensus.js +0 -414
- package/dist/runtime/commands/rewind.js +0 -333
- package/dist/runtime/commands/roster.js +0 -117
- package/dist/runtime/commands/sessions.js +0 -163
- package/dist/runtime/commands/share.js +0 -316
- package/dist/runtime/commands/skills.js +0 -401
- package/dist/runtime/commands/status.js +0 -186
- package/dist/runtime/commands/stickers.js +0 -82
- package/dist/runtime/commands/style.js +0 -194
- package/dist/runtime/commands/theme.js +0 -196
- package/dist/runtime/commands/undo.js +0 -361
- package/dist/runtime/commands/update.js +0 -289
- package/dist/runtime/commands/vim.js +0 -140
- package/dist/runtime/commands/worktree.js +0 -177
- package/dist/runtime/commands/worktrees.js +0 -155
- package/dist/runtime/deprecation-warning.js +0 -69
- package/dist/runtime/engine-exit-code.js +0 -50
- package/dist/runtime/headless-repl.js +0 -195
- package/dist/runtime/headless.js +0 -548
- package/dist/runtime/load-hooks-or-exit.js +0 -71
- package/dist/runtime/plan-decompose.js +0 -531
- package/dist/runtime/sigint-guard.js +0 -272
- package/dist/runtime/stream-renderer.js +0 -195
- package/dist/runtime/update-check.js +0 -294
- package/dist/runtime/version.js +0 -65
- package/dist/runtime/worktree-bootstrap.js +0 -579
- package/dist/skills/bundled/batch.js +0 -617
- package/dist/skills/bundled/index.js +0 -45
- package/dist/skills/bundled/loop.js +0 -358
- package/dist/skills/bundled/remember.js +0 -383
- package/dist/skills/bundled/simplify.js +0 -289
- package/dist/skills/bundled/skillify.js +0 -373
- package/dist/skills/bundled/stuck.js +0 -558
- package/dist/skills/bundled/verify.js +0 -439
- package/dist/testing/vcr.js +0 -486
- package/dist/tools/agent-tool.js +0 -229
- package/dist/tools/apply-patch.js +0 -556
- package/dist/tools/ask-user-question.js +0 -337
- package/dist/tools/ask-user.js +0 -115
- package/dist/tools/bash.js +0 -1238
- package/dist/tools/brief.js +0 -224
- package/dist/tools/cron.js +0 -433
- package/dist/tools/enter-worktree.js +0 -250
- package/dist/tools/exit-worktree.js +0 -147
- package/dist/tools/file-tools.js +0 -553
- package/dist/tools/http-request.js +0 -336
- package/dist/tools/lsp-tools.js +0 -565
- package/dist/tools/mcp-tool.js +0 -260
- package/dist/tools/multi-edit.js +0 -361
- package/dist/tools/powershell.js +0 -268
- package/dist/tools/registry.js +0 -166
- package/dist/tools/server-tools.js +0 -892
- package/dist/tools/skill-tool.js +0 -96
- package/dist/tools/sleep.js +0 -99
- package/dist/tools/synthetic-output.js +0 -133
- package/dist/tools/tasks.js +0 -208
- package/dist/tools/todo-write.js +0 -184
- package/dist/tools/verify-plan-execution.js +0 -295
- package/dist/tools/web-fetch-injection-scanner.js +0 -207
- package/dist/tools/web-fetch.js +0 -720
- package/dist/tools/web-search.js +0 -458
- package/dist/tui/agent-progress-card.js +0 -111
- package/dist/tui/agent-tree-pane.js +0 -9
- package/dist/tui/agent-tree.js +0 -87
- package/dist/tui/ask-cli.js +0 -52
- package/dist/tui/ask-modal.js +0 -211
- package/dist/tui/ask-user-question-chips.js +0 -315
- package/dist/tui/ask-user-question-prompt.js +0 -203
- package/dist/tui/compact-banner.js +0 -81
- package/dist/tui/conversation-pane.js +0 -164
- package/dist/tui/cost-table.js +0 -111
- package/dist/tui/device-flow.js +0 -142
- package/dist/tui/doctor-table.js +0 -46
- package/dist/tui/feedback-prompt.js +0 -156
- package/dist/tui/input-box.js +0 -732
- package/dist/tui/login-picker.js +0 -69
- package/dist/tui/markdown-render.js +0 -266
- package/dist/tui/multi-file-diff-approval.js +0 -375
- package/dist/tui/onboarding-wizard.js +0 -240
- package/dist/tui/permissions-picker.js +0 -86
- package/dist/tui/render.js +0 -160
- package/dist/tui/repl-render.js +0 -770
- package/dist/tui/repl-splash-art.js +0 -64
- package/dist/tui/repl-splash-mascot.js +0 -154
- package/dist/tui/repl-splash.js +0 -117
- package/dist/tui/repl.js +0 -378
- package/dist/tui/slash-palette.js +0 -106
- package/dist/tui/splash-data.js +0 -61
- package/dist/tui/splash.js +0 -31
- package/dist/tui/status-bar.js +0 -209
- package/dist/tui/status-table.js +0 -7
- package/dist/tui/stickers-art.js +0 -136
- package/dist/tui/style-table.js +0 -28
- package/dist/tui/theme-table.js +0 -29
- package/dist/tui/thinking-spinner.js +0 -123
- package/dist/tui/tool-stream-pane.js +0 -140
- package/dist/tui/update-banner.js +0 -33
- package/dist/tui/vim-input.js +0 -267
- package/dist/tui/welcome-banner.js +0 -107
- package/dist/tui/welcome-data.js +0 -293
- package/dist/tui/workspace-context.js +0 -105
- package/docs/examples/codegraph.mcp.json +0 -10
- package/test/scenarios/codegen-create-file.scenario.txt +0 -13
- package/test/scenarios/compact-force.scenario.txt +0 -12
- package/test/scenarios/identity.scenario.txt +0 -11
- package/test/scenarios/persona-handoff.scenario.txt +0 -12
- package/test/scenarios/walkback.scenario.txt +0 -12
|
@@ -1,491 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Diff capture — `pugi review --consensus` .
|
|
3
|
-
*
|
|
4
|
-
* Captures the diff that the consensus fan-out will send to Anvil. Four
|
|
5
|
-
* supported source kinds (in order of precedence):
|
|
6
|
-
*
|
|
7
|
-
* 1. `--pr <number>` — uses `gh pr diff <num>` (gh CLI required).
|
|
8
|
-
* 2. `--commit <sha>` — diff of that commit vs its first parent.
|
|
9
|
-
* When `--base <ref>` is ALSO provided, the
|
|
10
|
-
* diff is the range `<base>..<commit>` instead
|
|
11
|
-
* (mirrors `git diff base..commit` — covers the
|
|
12
|
-
* full PR-style payload, not just the tip).
|
|
13
|
-
* 3. `--branch <name>` — diff of HEAD vs `origin/<name>` merge-base.
|
|
14
|
-
* 4. (default) — diff of HEAD vs `origin/main` merge-base
|
|
15
|
-
* covering BOTH committed-since-base AND
|
|
16
|
-
* uncommitted (staged + working tree) edits.
|
|
17
|
-
*
|
|
18
|
-
* The shape mirrors the existing `performRemoteTripleReview` flow:
|
|
19
|
-
* uncommitted edits are deliberately included by computing the diff
|
|
20
|
-
* against the merge-base SHA rather than `base...HEAD`, otherwise the
|
|
21
|
-
* common case ("review what I'm about to commit") would lose signal.
|
|
22
|
-
*
|
|
23
|
-
* Protected paths (`.env*`, `*.key`, `*.pem`, `*.sql` etc) are excluded
|
|
24
|
-
* at the git layer so a secret cannot leak into the egress payload even
|
|
25
|
-
* if the operator has it staged.
|
|
26
|
-
*/
|
|
27
|
-
import { execFileSync } from 'node:child_process';
|
|
28
|
-
/**
|
|
29
|
-
* Hard cap on the diff payload sent egress. Anvil enforces its own cap
|
|
30
|
-
* server-side; this is a defense-in-depth so a runaway monorepo merge
|
|
31
|
-
* doesn't OOM the SSE encoder. 1 MiB ≈ 30k LOC, which is well above the
|
|
32
|
-
* largest review the rubric can reason about.
|
|
33
|
-
*/
|
|
34
|
-
export const DIFF_MAX_BYTES = 1 * 1024 * 1024;
|
|
35
|
-
/**
|
|
36
|
-
* Git pathspec exclusions for sensitive blobs. This is the source of truth
|
|
37
|
-
* for both the consensus surface AND the legacy `PROTECTED_DIFF_EXCLUDES`
|
|
38
|
-
* in cli.ts; keep both lists in sync when adding new patterns.
|
|
39
|
-
*
|
|
40
|
-
* Coverage policy: a credential committed under ANY plausible filename
|
|
41
|
-
* pattern must be excluded. Adversarial PRs can stage secrets under
|
|
42
|
-
* unconventional names (deploy.crt, credentials, .netrc) to bypass a
|
|
43
|
-
* narrow exclude list and exfiltrate to the reviewer payload.
|
|
44
|
-
*
|
|
45
|
-
* Pathspec form `:(exclude,glob)<starstar>/<pattern>` (where `<starstar>`
|
|
46
|
-
* is the `*` `*` doubled glob) matches at the repo root AND in any
|
|
47
|
-
* subdirectory; without the doubled-star prefix git's literal pathspec
|
|
48
|
-
* syntax silently misses subdir matches in pnpm/turbo monorepos.
|
|
49
|
-
*/
|
|
50
|
-
export const PROTECTED_PATHSPEC_EXCLUDES = Object.freeze([
|
|
51
|
-
// Dotfiles + RC files that frequently hold tokens.
|
|
52
|
-
':(exclude,glob)**/.env',
|
|
53
|
-
':(exclude,glob)**/.env.*',
|
|
54
|
-
':(exclude,glob)**/.npmrc',
|
|
55
|
-
':(exclude,glob)**/.yarnrc',
|
|
56
|
-
':(exclude,glob)**/.pypirc',
|
|
57
|
-
':(exclude,glob)**/.gitconfig',
|
|
58
|
-
':(exclude,glob)**/.netrc',
|
|
59
|
-
// SSH private keys (every algorithm we have seen committed in the wild).
|
|
60
|
-
':(exclude,glob)**/id_rsa',
|
|
61
|
-
':(exclude,glob)**/id_ed25519',
|
|
62
|
-
':(exclude,glob)**/id_ecdsa',
|
|
63
|
-
':(exclude,glob)**/id_dsa',
|
|
64
|
-
// PEM-encoded + DER-encoded private keys / certs / containers.
|
|
65
|
-
':(exclude,glob)**/*.pem',
|
|
66
|
-
':(exclude,glob)**/*.key',
|
|
67
|
-
':(exclude,glob)**/*.crt',
|
|
68
|
-
':(exclude,glob)**/*.cer',
|
|
69
|
-
':(exclude,glob)**/*.der',
|
|
70
|
-
':(exclude,glob)**/*.pfx',
|
|
71
|
-
':(exclude,glob)**/*.p12',
|
|
72
|
-
// SQL dumps / DB exports often contain real PII + credentials.
|
|
73
|
-
':(exclude,glob)**/*.dump',
|
|
74
|
-
':(exclude,glob)**/*.sql',
|
|
75
|
-
// Generic credential blobs under any directory.
|
|
76
|
-
':(exclude,glob)**/*.secret',
|
|
77
|
-
':(exclude,glob)**/credentials',
|
|
78
|
-
':(exclude,glob)**/credentials.json',
|
|
79
|
-
// `secrets/**` (not `secrets/*`) so nested credential paths recurse:
|
|
80
|
-
// `secrets/prod/token.txt`, `apps/foo/secrets/nested/key`, and any
|
|
81
|
-
// arbitrarily deep `**/secrets/<...>/<file>` get excluded. With glob
|
|
82
|
-
// pathspec magic enabled, a single `*` does NOT cross path separators,
|
|
83
|
-
// so the non-recursive form would leak nested-directory secrets.
|
|
84
|
-
':(exclude,glob)**/secrets/**',
|
|
85
|
-
]);
|
|
86
|
-
/**
|
|
87
|
-
* Captures the diff per the source spec and returns the augmented payload
|
|
88
|
-
* plus narrative context (branch, commit, title) that gets attached to
|
|
89
|
-
* the egress request.
|
|
90
|
-
*
|
|
91
|
-
* Errors are returned as thrown `Error` instances; the caller (the
|
|
92
|
-
* command handler) translates them to JSON error payloads + exit codes
|
|
93
|
-
* so the CLI never crashes on a malformed ref.
|
|
94
|
-
*/
|
|
95
|
-
export function captureDiff(spec) {
|
|
96
|
-
const cwd = spec.cwd ?? process.cwd();
|
|
97
|
-
// Source precedence: pr > commit > branch > default.
|
|
98
|
-
if (typeof spec.pr === 'number' && Number.isFinite(spec.pr) && spec.pr > 0) {
|
|
99
|
-
return captureFromPr(cwd, spec.pr);
|
|
100
|
-
}
|
|
101
|
-
if (typeof spec.commit === 'string' && spec.commit.length > 0) {
|
|
102
|
-
// When `--base` is supplied alongside `--commit`, callers want the
|
|
103
|
-
// full PR-style range diff (`base..commit`), not just the tip
|
|
104
|
-
// commit's parent diff. This matches the convention used by
|
|
105
|
-
// `git diff <base>..<commit>` everywhere else in the toolchain and
|
|
106
|
-
// is the verified-correct mode for reviewing a PR head ref. Without
|
|
107
|
-
// this branch, `--base` was silently ignored when `--commit` was
|
|
108
|
-
// present — see feedback_pugi_review_use_range_diff_not_worktree.
|
|
109
|
-
if (typeof spec.baseRef === 'string' && spec.baseRef.length > 0) {
|
|
110
|
-
return captureFromRange(cwd, spec.baseRef, spec.commit);
|
|
111
|
-
}
|
|
112
|
-
return captureFromCommit(cwd, spec.commit);
|
|
113
|
-
}
|
|
114
|
-
if (typeof spec.branch === 'string' && spec.branch.length > 0) {
|
|
115
|
-
return captureFromBranch(cwd, spec.branch, spec.baseRef ?? 'origin/main');
|
|
116
|
-
}
|
|
117
|
-
return captureFromBase(cwd, spec.baseRef ?? 'origin/main');
|
|
118
|
-
}
|
|
119
|
-
function captureFromPr(cwd, pr) {
|
|
120
|
-
// CRITICAL: `gh pr diff <num>` bypasses PROTECTED_PATHSPEC_EXCLUDES,
|
|
121
|
-
// exfiltrating `.env`, `*.key`, `*.pem`, `*.sql`, secrets/* to the
|
|
122
|
-
// reviewer payload. We instead fetch the PR head ref locally and run
|
|
123
|
-
// `git diff` with the same pathspec excludes as every other capture
|
|
124
|
-
// path. PR metadata still comes from `gh pr view` (read-only).
|
|
125
|
-
const metaRaw = safeExec(cwd, 'gh', ['pr', 'view', String(pr), '--json', 'title,headRefName,headRefOid,baseRefName']);
|
|
126
|
-
const meta = safeParseJson(metaRaw);
|
|
127
|
-
const tempRef = `refs/pugi/consensus-pr-${pr}`;
|
|
128
|
-
// Fetch the PR head into a private ref so we have local objects to
|
|
129
|
-
// diff against. `pull/<num>/head` is GitHub's special refspec exposed
|
|
130
|
-
// to anyone with read access on the repo.
|
|
131
|
-
//
|
|
132
|
-
// The leading `+` (force-update) is REQUIRED: if a prior invocation
|
|
133
|
-
// died before reaching the `finally` cleanup (SIGKILL, host crash,
|
|
134
|
-
// operator Ctrl-C inside a `try` block in a wrapping caller, hung
|
|
135
|
-
// gh CLI), the tempRef survives on disk. Without `+`, the next
|
|
136
|
-
// `fetch <pr>/head:<tempRef>` aborts with
|
|
137
|
-
// `! [rejected] pull/N/head -> refs/pugi/consensus-pr-N (non-fast-forward)`
|
|
138
|
-
// and the entire consensus run fails for an operator who did nothing
|
|
139
|
-
// wrong. `+` semantics: replace the ref unconditionally — exactly
|
|
140
|
-
// the recovery behavior we want for a sandboxed `refs/pugi/...` slot
|
|
141
|
-
// that no human ever reads.
|
|
142
|
-
safeExec(cwd, 'git', ['fetch', 'origin', `+pull/${pr}/head:${tempRef}`]);
|
|
143
|
-
try {
|
|
144
|
-
// Resolve the base ref to diff against. Prefer the PR's declared
|
|
145
|
-
// base; fall back to `origin/main`. We compute the merge-base so a
|
|
146
|
-
// PR that's behind main still shows only the author's hunks.
|
|
147
|
-
const baseRef = meta?.baseRefName ? `origin/${meta.baseRefName}` : 'origin/main';
|
|
148
|
-
const mergeBase = safeExecOptional(cwd, 'git', ['merge-base', baseRef, tempRef]).trim();
|
|
149
|
-
const range = mergeBase ? `${mergeBase}..${tempRef}` : `${baseRef}..${tempRef}`;
|
|
150
|
-
const diff = safeExec(cwd, 'git', [
|
|
151
|
-
'diff',
|
|
152
|
-
range,
|
|
153
|
-
'--',
|
|
154
|
-
'.',
|
|
155
|
-
...PROTECTED_PATHSPEC_EXCLUDES,
|
|
156
|
-
]);
|
|
157
|
-
const cappedDiff = capDiff(diff);
|
|
158
|
-
const stats = computeStats(cappedDiff);
|
|
159
|
-
return {
|
|
160
|
-
diff: cappedDiff,
|
|
161
|
-
context: {
|
|
162
|
-
branch: meta?.headRefName ?? `pr-${pr}`,
|
|
163
|
-
commit: shortSha(meta?.headRefOid ?? ''),
|
|
164
|
-
title: meta?.title ?? `PR #${pr}`,
|
|
165
|
-
ref: `pr:${pr}`,
|
|
166
|
-
stats,
|
|
167
|
-
},
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
finally {
|
|
171
|
-
// Best-effort cleanup of the private ref. Never throw from the
|
|
172
|
-
// cleanup path so the operator's primary error (if any) reaches them.
|
|
173
|
-
try {
|
|
174
|
-
safeExec(cwd, 'git', ['update-ref', '-d', tempRef]);
|
|
175
|
-
}
|
|
176
|
-
catch {
|
|
177
|
-
// Swallow: a leftover ref under refs/pugi/ is harmless. The
|
|
178
|
-
// next run force-overwrites it via `fetch +pull/<n>/head:<ref>`
|
|
179
|
-
// (note the leading `+` in the refspec above), so a stale tempRef
|
|
180
|
-
// never blocks a future invocation even if cleanup never runs.
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
function captureFromCommit(cwd, commit) {
|
|
185
|
-
// `<sha>~1..<sha>` covers exactly that commit's changes. For a ROOT
|
|
186
|
-
// commit (no parent) the `~1` lookup explodes and produces an empty
|
|
187
|
-
// diff masquerading as success. Detect this up front and fall back
|
|
188
|
-
// to the git empty-tree sha so the first commit's introduction shows
|
|
189
|
-
// up in the diff.
|
|
190
|
-
const fullSha = safeExec(cwd, 'git', ['rev-parse', commit]).trim();
|
|
191
|
-
if (!fullSha)
|
|
192
|
-
throw new Error(`Unknown commit ref: ${commit}`);
|
|
193
|
-
// Probe for a parent. `rev-parse --verify <sha>~1` exits non-zero on
|
|
194
|
-
// a root commit; we treat that as "diff against the empty tree".
|
|
195
|
-
const hasParent = safeExecOptional(cwd, 'git', ['rev-parse', '--verify', `${fullSha}~1`]).trim().length > 0;
|
|
196
|
-
// The well-known git "empty tree" SHA. Stable across all git versions
|
|
197
|
-
// since 2005; documented in `git hash-object -t tree /dev/null`.
|
|
198
|
-
const EMPTY_TREE_SHA = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
|
199
|
-
const range = hasParent ? `${fullSha}~1..${fullSha}` : `${EMPTY_TREE_SHA}..${fullSha}`;
|
|
200
|
-
const diff = safeExec(cwd, 'git', [
|
|
201
|
-
'diff',
|
|
202
|
-
range,
|
|
203
|
-
'--',
|
|
204
|
-
'.',
|
|
205
|
-
...PROTECTED_PATHSPEC_EXCLUDES,
|
|
206
|
-
]);
|
|
207
|
-
const cappedDiff = capDiff(diff);
|
|
208
|
-
const subject = safeExec(cwd, 'git', ['log', '-1', '--pretty=%s', fullSha]).trim();
|
|
209
|
-
const branch = safeExec(cwd, 'git', ['name-rev', '--name-only', fullSha]).trim() || 'detached';
|
|
210
|
-
const stats = computeStats(cappedDiff);
|
|
211
|
-
return {
|
|
212
|
-
diff: cappedDiff,
|
|
213
|
-
context: {
|
|
214
|
-
branch,
|
|
215
|
-
commit: shortSha(fullSha),
|
|
216
|
-
title: subject || `commit ${shortSha(fullSha)}`,
|
|
217
|
-
ref: `commit:${shortSha(fullSha)}`,
|
|
218
|
-
stats,
|
|
219
|
-
},
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Range capture for `--commit <X> --base <Y>` — diff equivalent to
|
|
224
|
-
* `git diff <base>..<commit>`. Used when the operator names BOTH endpoints
|
|
225
|
-
* (typical PR review against a remote head SHA).
|
|
226
|
-
*
|
|
227
|
-
* Critical: this MUST be a pure read-only range diff against named refs.
|
|
228
|
-
* The previous behavior fell through to `captureFromCommit` which only
|
|
229
|
-
* showed the tip commit (`commit~1..commit`) — fine for single-commit
|
|
230
|
-
* review, wrong for multi-commit PRs. Worse, a stale fallback path was
|
|
231
|
-
* sending the working tree diff (`git diff` with no args), which caused
|
|
232
|
-
* every review on to surface identical noise from uncommitted
|
|
233
|
-
* `.gitignore` edits instead of the actual PR contents.
|
|
234
|
-
*
|
|
235
|
-
* Working tree integrity: only `git diff <ref>..<ref>` and metadata
|
|
236
|
-
* `log` / `rev-parse` / `name-rev` are used — none of these touch the
|
|
237
|
-
* index, working tree, or HEAD.
|
|
238
|
-
*/
|
|
239
|
-
function captureFromRange(cwd, baseRef, commit) {
|
|
240
|
-
// Resolve both endpoints up front so an unknown ref errors with a
|
|
241
|
-
// clear message before the diff invocation. `rev-parse` is read-only.
|
|
242
|
-
const fullCommit = safeExec(cwd, 'git', ['rev-parse', commit]).trim();
|
|
243
|
-
if (!fullCommit)
|
|
244
|
-
throw new Error(`Unknown commit ref: ${commit}`);
|
|
245
|
-
// Task #63 — refresh the base ref via `git fetch` BEFORE
|
|
246
|
-
// resolving. Previously a stale local `main` (last fetched days ago)
|
|
247
|
-
// would silently produce a diff containing every commit that landed
|
|
248
|
-
// upstream after the fetch, swamping the model's review с unrelated
|
|
249
|
-
// changes. The fetch is opportunistic: failures (offline, auth) are
|
|
250
|
-
// swallowed so the existing rev-parse path stays the safety net и
|
|
251
|
-
// returns the clear "Unknown base ref" error if the stale local copy
|
|
252
|
-
// is also missing.
|
|
253
|
-
//
|
|
254
|
-
// We fetch ONLY the base ref (not all refs) so the overhead is
|
|
255
|
-
// bounded — typical PR-style review payload, base = main, one ref.
|
|
256
|
-
// `--no-tags --quiet` keeps the network footprint minimal.
|
|
257
|
-
const remoteCandidate = baseRef.includes('/') ? baseRef : `origin/${baseRef}`;
|
|
258
|
-
if (remoteCandidate.startsWith('origin/')) {
|
|
259
|
-
const bareRef = remoteCandidate.slice('origin/'.length);
|
|
260
|
-
safeExecOptional(cwd, 'git', [
|
|
261
|
-
'fetch',
|
|
262
|
-
'--no-tags',
|
|
263
|
-
'--quiet',
|
|
264
|
-
'origin',
|
|
265
|
-
bareRef,
|
|
266
|
-
]);
|
|
267
|
-
}
|
|
268
|
-
// Resolve the base: accept already-qualified refs (`origin/main`,
|
|
269
|
-
// `refs/heads/foo`) and bare branch names. If the bare name isn't
|
|
270
|
-
// locally resolvable, retry against `origin/<name>` — the common
|
|
271
|
-
// CI shape where local main is absent but the remote tracking ref is.
|
|
272
|
-
let resolvedBase = safeExecOptional(cwd, 'git', ['rev-parse', baseRef]).trim();
|
|
273
|
-
let effectiveBase = baseRef;
|
|
274
|
-
if (!resolvedBase && !baseRef.includes('/')) {
|
|
275
|
-
const remoteBase = `origin/${baseRef}`;
|
|
276
|
-
resolvedBase = safeExecOptional(cwd, 'git', ['rev-parse', remoteBase]).trim();
|
|
277
|
-
if (resolvedBase)
|
|
278
|
-
effectiveBase = remoteBase;
|
|
279
|
-
}
|
|
280
|
-
if (!resolvedBase)
|
|
281
|
-
throw new Error(`Unknown base ref: ${baseRef}`);
|
|
282
|
-
const diff = safeExec(cwd, 'git', [
|
|
283
|
-
'diff',
|
|
284
|
-
`${resolvedBase}..${fullCommit}`,
|
|
285
|
-
'--',
|
|
286
|
-
'.',
|
|
287
|
-
...PROTECTED_PATHSPEC_EXCLUDES,
|
|
288
|
-
]);
|
|
289
|
-
const cappedDiff = capDiff(diff);
|
|
290
|
-
const subject = safeExec(cwd, 'git', ['log', '-1', '--pretty=%s', fullCommit]).trim();
|
|
291
|
-
const branch = safeExec(cwd, 'git', ['name-rev', '--name-only', fullCommit]).trim() || 'detached';
|
|
292
|
-
const stats = computeStats(cappedDiff);
|
|
293
|
-
return {
|
|
294
|
-
diff: cappedDiff,
|
|
295
|
-
context: {
|
|
296
|
-
branch,
|
|
297
|
-
commit: shortSha(fullCommit),
|
|
298
|
-
title: subject || `commit ${shortSha(fullCommit)}`,
|
|
299
|
-
ref: `range:${effectiveBase}..${shortSha(fullCommit)}`,
|
|
300
|
-
stats,
|
|
301
|
-
},
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
function captureFromBranch(cwd, branch, baseRef) {
|
|
305
|
-
const remoteRef = branch.includes('/') ? branch : `origin/${branch}`;
|
|
306
|
-
const mergeBase = safeExec(cwd, 'git', ['merge-base', baseRef, remoteRef]).trim();
|
|
307
|
-
if (!mergeBase)
|
|
308
|
-
throw new Error(`Cannot compute merge-base of ${baseRef} and ${remoteRef}`);
|
|
309
|
-
const diff = safeExec(cwd, 'git', [
|
|
310
|
-
'diff',
|
|
311
|
-
`${mergeBase}..${remoteRef}`,
|
|
312
|
-
'--',
|
|
313
|
-
'.',
|
|
314
|
-
...PROTECTED_PATHSPEC_EXCLUDES,
|
|
315
|
-
]);
|
|
316
|
-
const cappedDiff = capDiff(diff);
|
|
317
|
-
const head = safeExec(cwd, 'git', ['rev-parse', remoteRef]).trim();
|
|
318
|
-
const subject = safeExec(cwd, 'git', ['log', '-1', '--pretty=%s', remoteRef]).trim();
|
|
319
|
-
const stats = computeStats(cappedDiff);
|
|
320
|
-
return {
|
|
321
|
-
diff: cappedDiff,
|
|
322
|
-
context: {
|
|
323
|
-
branch,
|
|
324
|
-
commit: shortSha(head),
|
|
325
|
-
title: subject || `branch ${branch}`,
|
|
326
|
-
ref: `branch:${branch}`,
|
|
327
|
-
stats,
|
|
328
|
-
},
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
function captureFromBase(cwd, baseRef) {
|
|
332
|
-
// The default surface — diff HEAD against the merge-base of the
|
|
333
|
-
// protected base. When the merge-base lookup fails (shallow clone,
|
|
334
|
-
// no upstream, baseRef not configured), fall back to the working-tree
|
|
335
|
-
// diff so the consensus gate still has signal rather than crashing.
|
|
336
|
-
const mergeBase = safeExecOptional(cwd, 'git', ['merge-base', baseRef, 'HEAD']).trim();
|
|
337
|
-
if (mergeBase) {
|
|
338
|
-
// Two parts (non-overlapping):
|
|
339
|
-
// 1. Committed since base: `<base>..HEAD`
|
|
340
|
-
// 2. Uncommitted (staged + working tree as a single union): `git diff HEAD`
|
|
341
|
-
// `git diff HEAD` already reports BOTH staged AND working-tree
|
|
342
|
-
// changes relative to HEAD, so we MUST NOT add a separate
|
|
343
|
-
// `--cached` invocation: doing so emits the same staged hunks
|
|
344
|
-
// twice, inflating reviewer cost and confusing the rubric on
|
|
345
|
-
// duplicate-finding correlation.
|
|
346
|
-
const committedDiff = safeExec(cwd, 'git', [
|
|
347
|
-
'diff',
|
|
348
|
-
`${mergeBase}..HEAD`,
|
|
349
|
-
'--',
|
|
350
|
-
'.',
|
|
351
|
-
...PROTECTED_PATHSPEC_EXCLUDES,
|
|
352
|
-
]);
|
|
353
|
-
const uncommittedDiff = safeExec(cwd, 'git', [
|
|
354
|
-
'diff',
|
|
355
|
-
'HEAD',
|
|
356
|
-
'--',
|
|
357
|
-
'.',
|
|
358
|
-
...PROTECTED_PATHSPEC_EXCLUDES,
|
|
359
|
-
]);
|
|
360
|
-
const combined = [committedDiff, uncommittedDiff]
|
|
361
|
-
.map((s) => s.trim())
|
|
362
|
-
.filter((s) => s.length > 0)
|
|
363
|
-
.join('\n');
|
|
364
|
-
const cappedDiff = capDiff(combined);
|
|
365
|
-
const branch = safeExec(cwd, 'git', ['branch', '--show-current']).trim() || 'detached';
|
|
366
|
-
const head = safeExec(cwd, 'git', ['rev-parse', 'HEAD']).trim();
|
|
367
|
-
const subject = safeExec(cwd, 'git', ['log', '-1', '--pretty=%s', 'HEAD']).trim();
|
|
368
|
-
const stats = computeStats(cappedDiff);
|
|
369
|
-
return {
|
|
370
|
-
diff: cappedDiff,
|
|
371
|
-
context: {
|
|
372
|
-
branch,
|
|
373
|
-
commit: shortSha(head),
|
|
374
|
-
title: subject || branch,
|
|
375
|
-
ref: `merge-base:${baseRef}`,
|
|
376
|
-
stats,
|
|
377
|
-
},
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
// Fallback path: no merge-base available. `git diff HEAD` reports
|
|
381
|
-
// BOTH staged AND working-tree changes relative to HEAD in a single
|
|
382
|
-
// unified diff, so it's the right one-shot capture for "what would I
|
|
383
|
-
// commit if I ran `git add -A && git commit` right now". A separate
|
|
384
|
-
// `--cached` call would double-report the staged hunks.
|
|
385
|
-
const cappedDiff = capDiff(safeExec(cwd, 'git', ['diff', 'HEAD', '--', '.', ...PROTECTED_PATHSPEC_EXCLUDES]));
|
|
386
|
-
const branch = safeExec(cwd, 'git', ['branch', '--show-current']).trim() || 'detached';
|
|
387
|
-
const head = safeExec(cwd, 'git', ['rev-parse', 'HEAD']).trim();
|
|
388
|
-
const subject = safeExec(cwd, 'git', ['log', '-1', '--pretty=%s', 'HEAD']).trim();
|
|
389
|
-
const stats = computeStats(cappedDiff);
|
|
390
|
-
return {
|
|
391
|
-
diff: cappedDiff,
|
|
392
|
-
context: {
|
|
393
|
-
branch,
|
|
394
|
-
commit: shortSha(head),
|
|
395
|
-
title: subject || branch,
|
|
396
|
-
ref: 'head-only',
|
|
397
|
-
stats,
|
|
398
|
-
},
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Non-throwing variant of `safeExec`. Returns an empty string on
|
|
403
|
-
* non-zero exit instead of throwing. Used for the optional `merge-base`
|
|
404
|
-
* lookup which fails legitimately in shallow clones / no-upstream setups.
|
|
405
|
-
*/
|
|
406
|
-
function safeExecOptional(cwd, file, args) {
|
|
407
|
-
try {
|
|
408
|
-
return safeExec(cwd, file, args);
|
|
409
|
-
}
|
|
410
|
-
catch {
|
|
411
|
-
return '';
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
/** Compute file / insertion / deletion counts from a unified diff. */
|
|
415
|
-
function computeStats(diff) {
|
|
416
|
-
let filesChanged = 0;
|
|
417
|
-
let insertions = 0;
|
|
418
|
-
let deletions = 0;
|
|
419
|
-
for (const line of diff.split(/\r?\n/)) {
|
|
420
|
-
if (line.startsWith('diff --git '))
|
|
421
|
-
filesChanged += 1;
|
|
422
|
-
else if (line.startsWith('+') && !line.startsWith('+++'))
|
|
423
|
-
insertions += 1;
|
|
424
|
-
else if (line.startsWith('-') && !line.startsWith('---'))
|
|
425
|
-
deletions += 1;
|
|
426
|
-
}
|
|
427
|
-
return { filesChanged, insertions, deletions };
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Truncate the diff if it grows past `DIFF_MAX_BYTES`. Truncation is
|
|
431
|
-
* marked with a sentinel comment so reviewers see the cap explicitly
|
|
432
|
-
* instead of silently reasoning over a partial patch.
|
|
433
|
-
*/
|
|
434
|
-
function capDiff(diff) {
|
|
435
|
-
// `Buffer.byteLength` is required — `.length` counts UTF-16 code units
|
|
436
|
-
// and underestimates multi-byte sequences common in diffs that touch
|
|
437
|
-
// i18n / cyrillic content.
|
|
438
|
-
if (Buffer.byteLength(diff, 'utf8') <= DIFF_MAX_BYTES)
|
|
439
|
-
return diff;
|
|
440
|
-
// Slice by code units, then re-check byte length. UTF-8 is variable-
|
|
441
|
-
// width, so 1 MiB of code units can exceed the cap; iterate until it
|
|
442
|
-
// fits. Two passes is the worst case for any reasonable input.
|
|
443
|
-
let slice = diff.slice(0, DIFF_MAX_BYTES);
|
|
444
|
-
while (Buffer.byteLength(slice, 'utf8') > DIFF_MAX_BYTES && slice.length > 0) {
|
|
445
|
-
slice = slice.slice(0, slice.length - 1024);
|
|
446
|
-
}
|
|
447
|
-
return `${slice}\n\n# [pugi-cli] diff truncated at ${DIFF_MAX_BYTES} bytes; reviewers see a partial patch.\n`;
|
|
448
|
-
}
|
|
449
|
-
function shortSha(sha) {
|
|
450
|
-
if (!sha)
|
|
451
|
-
return '';
|
|
452
|
-
return sha.length > 7 ? sha.slice(0, 7) : sha;
|
|
453
|
-
}
|
|
454
|
-
/**
|
|
455
|
-
* Wrapper around `execFileSync` that returns stdout as a UTF-8 string,
|
|
456
|
-
* swallows stderr, and throws with a stable shape on non-zero exit.
|
|
457
|
-
*
|
|
458
|
-
* The `execFileSync` form avoids shell injection (no shell process is
|
|
459
|
-
* spawned), which matters because we pass user-supplied refs / branch
|
|
460
|
-
* names into the command line.
|
|
461
|
-
*/
|
|
462
|
-
function safeExec(cwd, file, args) {
|
|
463
|
-
try {
|
|
464
|
-
const out = execFileSync(file, args, {
|
|
465
|
-
cwd,
|
|
466
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
467
|
-
// 32 MiB buffer — covers the worst-case PR diff before our 1 MiB
|
|
468
|
-
// cap kicks in. The cap is applied after capture so we can report
|
|
469
|
-
// truncation honestly.
|
|
470
|
-
maxBuffer: 32 * 1024 * 1024,
|
|
471
|
-
encoding: 'utf8',
|
|
472
|
-
});
|
|
473
|
-
// Specifying `encoding: 'utf8'` narrows the return type to string,
|
|
474
|
-
// but TS still types `out` as `string` always here — defensively
|
|
475
|
-
// coerce via `String()` to satisfy lint without an `as` cast.
|
|
476
|
-
return String(out);
|
|
477
|
-
}
|
|
478
|
-
catch (error) {
|
|
479
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
480
|
-
throw new Error(`${file} ${args.slice(0, 2).join(' ')} failed: ${message.split('\n')[0]}`);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
function safeParseJson(raw) {
|
|
484
|
-
try {
|
|
485
|
-
return JSON.parse(raw);
|
|
486
|
-
}
|
|
487
|
-
catch {
|
|
488
|
-
return null;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
//# sourceMappingURL=diff-capture.js.map
|