@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,375 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* MultiFileDiffApproval — side-by-side multi-file diff approval modal
|
|
4
|
-
* (PUGI-68).
|
|
5
|
-
*
|
|
6
|
-
* When the engine proposes a batch of edits that touches more than one
|
|
7
|
-
* file, the operator needs to review every diff in a single coherent
|
|
8
|
-
* view, then accept-all / reject-all / per-file approve before the
|
|
9
|
-
* dispatcher applies anything. The single-file approval surfaces in
|
|
10
|
-
* the AskModal / PlanReviewModal family are insufficient — a per-file
|
|
11
|
-
* back-to-back prompt loses the cross-file context the operator needs
|
|
12
|
-
* to spot a regression that spans modules.
|
|
13
|
-
*
|
|
14
|
-
* Layout (matches the AskUserQuestionChips PUGI-130 side-by-side
|
|
15
|
-
* precedent, see `ask-user-question-chips.tsx`):
|
|
16
|
-
*
|
|
17
|
-
* ┌─ Multi-file diff review ───────────────────────────────────────┐
|
|
18
|
-
* │ ┌─ Files ─────────────┐ ┌─ Diff: src/foo/bar.ts ─────────────┐ │
|
|
19
|
-
* │ │ ▸ • src/foo/bar.ts │ │ --- src/foo/bar.ts │ │
|
|
20
|
-
* │ │ ✓ src/baz.ts │ │ +++ src/foo/bar.ts │ │
|
|
21
|
-
* │ │ ✗ src/qux.ts │ │ @@ -1,4 +1,4 @@ │ │
|
|
22
|
-
* │ │ • src/x/y.ts │ │ -const x = 1; │ │
|
|
23
|
-
* │ │ │ │ +const x = 2; │ │
|
|
24
|
-
* │ └─────────────────────┘ └────────────────────────────────────┘ │
|
|
25
|
-
* │ 1/4 approved · 1/4 rejected · 2 remaining · Enter when done │
|
|
26
|
-
* └────────────────────────────────────────────────────────────────┘
|
|
27
|
-
*
|
|
28
|
-
* Key bindings:
|
|
29
|
-
* - ↑ / ↓ ............ navigate the file list
|
|
30
|
-
* - a ................ approve the highlighted file
|
|
31
|
-
* - r ................ reject the highlighted file
|
|
32
|
-
* - A (shift+a) ...... approve every file in the batch
|
|
33
|
-
* - R (shift+r) ...... reject every file in the batch
|
|
34
|
-
* - PgUp / PgDn ...... scroll the diff pane
|
|
35
|
-
* - Enter ............ finalise — emit per-file verdicts
|
|
36
|
-
* - Esc .............. cancel the whole batch (every file → rejected)
|
|
37
|
-
*
|
|
38
|
-
* Contract notes:
|
|
39
|
-
* - The component is PURE (Ink-style). It mounts useState for cursor,
|
|
40
|
-
* per-file verdict map, and diff-pane scroll offset. Emits exactly
|
|
41
|
-
* one `onResolve` callback when the operator presses Enter (or Esc
|
|
42
|
-
* for a cancel).
|
|
43
|
-
* - Per-file diff bodies are rendered verbatim from the provided
|
|
44
|
-
* unified-diff text — the component does NOT compute diffs from raw
|
|
45
|
-
* file contents. Callers (typically the dispatcher result transcript)
|
|
46
|
-
* own the diff text generation.
|
|
47
|
-
* - Long file paths are truncated middle-style so prefix + suffix stay
|
|
48
|
-
* visible (the parts the operator scans for module scope + filename).
|
|
49
|
-
* - Long diff bodies scroll via a single-axis offset; horizontal
|
|
50
|
-
* overflow is left to Ink's text wrapping per line. No mouse support.
|
|
51
|
-
*
|
|
52
|
-
* Brand voice gate: ASCII glyphs only (✓ / ✗ kept for status — already
|
|
53
|
-
* shipped в other TUI components like agent-progress-card). No banned
|
|
54
|
-
* brand words, no em-dashes, no attribution to external AIs.
|
|
55
|
-
*/
|
|
56
|
-
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
57
|
-
import { Box, Text, useInput } from 'ink';
|
|
58
|
-
/* ------------------------------------------------------------------ */
|
|
59
|
-
/* Defensive caps */
|
|
60
|
-
/* ------------------------------------------------------------------ */
|
|
61
|
-
/** Maximum chars rendered per file path in the left pane. */
|
|
62
|
-
export const MULTI_FILE_DIFF_PATH_CAP = 48;
|
|
63
|
-
/** Visible rows in the diff pane viewport. */
|
|
64
|
-
export const MULTI_FILE_DIFF_PANE_HEIGHT = 18;
|
|
65
|
-
/** Width hint for the left file-list column (used for path truncation). */
|
|
66
|
-
export const MULTI_FILE_DIFF_LEFT_WIDTH = 32;
|
|
67
|
-
/** Hard cap on diff body length (chars) — defends against runaway model output. */
|
|
68
|
-
export const MULTI_FILE_DIFF_BODY_CHAR_CAP = 200_000;
|
|
69
|
-
/* ------------------------------------------------------------------ */
|
|
70
|
-
/* Helpers */
|
|
71
|
-
/* ------------------------------------------------------------------ */
|
|
72
|
-
/**
|
|
73
|
-
* Middle-truncate a long file path so both prefix (module scope) and
|
|
74
|
-
* suffix (filename) stay visible. Mirrors the macOS `truncate=middle`
|
|
75
|
-
* convention. Appends `…` in the middle when truncation happens.
|
|
76
|
-
*
|
|
77
|
-
* Examples (cap = 24):
|
|
78
|
-
* "src/foo/bar/baz/qux.ts" → "src/foo/bar/baz/qux.ts" (fits)
|
|
79
|
-
* "src/a-long-module/b/c/d.ts" → "src/a-long-mo…/b/c/d.ts" (cut middle)
|
|
80
|
-
*
|
|
81
|
-
* Exported so the spec can assert the contract directly.
|
|
82
|
-
*/
|
|
83
|
-
export function truncateMiddle(raw, cap) {
|
|
84
|
-
if (cap <= 1)
|
|
85
|
-
return '…';
|
|
86
|
-
if (raw.length <= cap)
|
|
87
|
-
return raw;
|
|
88
|
-
// Reserve one slot for the ellipsis; balance prefix/suffix around it.
|
|
89
|
-
// The suffix gets one extra char on odd budgets so the filename stays
|
|
90
|
-
// longer (operators scan filenames more than the path prefix).
|
|
91
|
-
const remaining = cap - 1;
|
|
92
|
-
const prefixLen = Math.floor(remaining / 2);
|
|
93
|
-
const suffixLen = remaining - prefixLen;
|
|
94
|
-
return `${raw.slice(0, prefixLen)}…${raw.slice(raw.length - suffixLen)}`;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Defensive char cap on the diff body. Schema-level caps live upstream;
|
|
98
|
-
* this is belt + braces against a malformed dispatcher transcript that
|
|
99
|
-
* could otherwise exhaust the terminal scrollback.
|
|
100
|
-
*/
|
|
101
|
-
export function clampDiffBody(raw) {
|
|
102
|
-
if (raw.length <= MULTI_FILE_DIFF_BODY_CHAR_CAP)
|
|
103
|
-
return raw;
|
|
104
|
-
return `${raw.slice(0, MULTI_FILE_DIFF_BODY_CHAR_CAP - 1)}…`;
|
|
105
|
-
}
|
|
106
|
-
export function classifyDiffLine(line) {
|
|
107
|
-
if (line.startsWith('+++') || line.startsWith('---'))
|
|
108
|
-
return 'file-header';
|
|
109
|
-
if (line.startsWith('@@'))
|
|
110
|
-
return 'hunk-header';
|
|
111
|
-
if (line.startsWith('+'))
|
|
112
|
-
return 'addition';
|
|
113
|
-
if (line.startsWith('-'))
|
|
114
|
-
return 'deletion';
|
|
115
|
-
return 'context';
|
|
116
|
-
}
|
|
117
|
-
/** Inline helper — return per-line render props for a diff line. */
|
|
118
|
-
function renderProps(kind) {
|
|
119
|
-
switch (kind) {
|
|
120
|
-
case 'file-header':
|
|
121
|
-
return { bold: true };
|
|
122
|
-
case 'hunk-header':
|
|
123
|
-
return { color: 'blue', bold: true };
|
|
124
|
-
case 'addition':
|
|
125
|
-
return { color: 'green' };
|
|
126
|
-
case 'deletion':
|
|
127
|
-
return { color: 'red' };
|
|
128
|
-
case 'context':
|
|
129
|
-
return { dimColor: true };
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Public verdict-encoder mirror of the AskModal / PlanReviewModal
|
|
134
|
-
* encoders. Surfaces a single human-readable summary string the caller
|
|
135
|
-
* can inject as the next operator turn or log to a session journal.
|
|
136
|
-
*
|
|
137
|
-
* - `cancelled` → "[MULTI-DIFF-VERDICT:cancelled]"
|
|
138
|
-
* - all approved → "[MULTI-DIFF-VERDICT:all-approved] file1; file2"
|
|
139
|
-
* - all rejected → "[MULTI-DIFF-VERDICT:all-rejected] file1; file2"
|
|
140
|
-
* - mixed → "[MULTI-DIFF-VERDICT:mixed] +file1; -file2; ?file3"
|
|
141
|
-
*
|
|
142
|
-
* Each per-file token in mixed mode is prefixed `+` (approved), `-`
|
|
143
|
-
* (rejected), or `?` (still pending — operator hit Enter без deciding).
|
|
144
|
-
*/
|
|
145
|
-
export function encodeMultiFileDiffVerdict(result) {
|
|
146
|
-
if (result.cancelled)
|
|
147
|
-
return '[MULTI-DIFF-VERDICT:cancelled]';
|
|
148
|
-
const total = result.verdicts.length;
|
|
149
|
-
if (total === 0)
|
|
150
|
-
return '[MULTI-DIFF-VERDICT:empty]';
|
|
151
|
-
const allApproved = result.verdicts.every((v) => v.verdict === 'approved');
|
|
152
|
-
const allRejected = result.verdicts.every((v) => v.verdict === 'rejected');
|
|
153
|
-
if (allApproved) {
|
|
154
|
-
return `[MULTI-DIFF-VERDICT:all-approved] ${result.verdicts
|
|
155
|
-
.map((v) => v.path)
|
|
156
|
-
.join('; ')}`;
|
|
157
|
-
}
|
|
158
|
-
if (allRejected) {
|
|
159
|
-
return `[MULTI-DIFF-VERDICT:all-rejected] ${result.verdicts
|
|
160
|
-
.map((v) => v.path)
|
|
161
|
-
.join('; ')}`;
|
|
162
|
-
}
|
|
163
|
-
const tokens = result.verdicts.map((v) => {
|
|
164
|
-
const prefix = v.verdict === 'approved' ? '+' : v.verdict === 'rejected' ? '-' : '?';
|
|
165
|
-
return `${prefix}${v.path}`;
|
|
166
|
-
});
|
|
167
|
-
return `[MULTI-DIFF-VERDICT:mixed] ${tokens.join('; ')}`;
|
|
168
|
-
}
|
|
169
|
-
/* ------------------------------------------------------------------ */
|
|
170
|
-
/* Component */
|
|
171
|
-
/* ------------------------------------------------------------------ */
|
|
172
|
-
/**
|
|
173
|
-
* Build the result object for a given verdict map + entries vector.
|
|
174
|
-
* Hoisted because both the commit (Enter) and cancel (Esc) paths need
|
|
175
|
-
* to project the same shape — cancel just overrides every verdict to
|
|
176
|
-
* `rejected` and stamps `cancelled: true`.
|
|
177
|
-
*/
|
|
178
|
-
function buildResult(entries, verdicts, cancelled) {
|
|
179
|
-
const projected = entries.map((entry, idx) => ({
|
|
180
|
-
path: entry.path,
|
|
181
|
-
verdict: verdicts[idx] ?? 'pending',
|
|
182
|
-
}));
|
|
183
|
-
return {
|
|
184
|
-
verdicts: projected,
|
|
185
|
-
approvedPaths: projected
|
|
186
|
-
.filter((v) => v.verdict === 'approved')
|
|
187
|
-
.map((v) => v.path),
|
|
188
|
-
rejectedPaths: projected
|
|
189
|
-
.filter((v) => v.verdict === 'rejected')
|
|
190
|
-
.map((v) => v.path),
|
|
191
|
-
cancelled,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
export function MultiFileDiffApproval(props) {
|
|
195
|
-
// FIX ( triple-review): the previous `useMemo(() => props.entries,
|
|
196
|
-
// [props.entries])` was a no-op — it returned the same reference it
|
|
197
|
-
// depended on, so the memo never produced a stable identity gain. We
|
|
198
|
-
// reference `props.entries` directly now; downstream useEffect /
|
|
199
|
-
// useMemo hooks key on the real prop, not a redundant wrapper.
|
|
200
|
-
const entries = props.entries;
|
|
201
|
-
const paneHeight = props.paneHeight ?? MULTI_FILE_DIFF_PANE_HEIGHT;
|
|
202
|
-
const [cursor, setCursor] = useState(0);
|
|
203
|
-
const [verdicts, setVerdicts] = useState(() => entries.map(() => 'pending'));
|
|
204
|
-
const [scrollOffset, setScrollOffset] = useState(0);
|
|
205
|
-
// FIX ( triple-review, P1): the lazy useState initialiser
|
|
206
|
-
// captures `entries.length` ONCE at mount. If the caller swaps in
|
|
207
|
-
// a different entries array (length mismatch), the verdicts vector
|
|
208
|
-
// would drift — `setVerdictAt` could index out of range or
|
|
209
|
-
// `buildResult` could project a `pending` for a real entry whose
|
|
210
|
-
// verdict the operator already set. Re-sync on length change while
|
|
211
|
-
// preserving existing per-index verdicts (forgiving variant A).
|
|
212
|
-
useEffect(() => {
|
|
213
|
-
setVerdicts((prev) => {
|
|
214
|
-
if (prev.length === entries.length)
|
|
215
|
-
return prev;
|
|
216
|
-
return entries.map((_, i) => prev[i] ?? 'pending');
|
|
217
|
-
});
|
|
218
|
-
// Also clamp the cursor so it never points past the new end.
|
|
219
|
-
setCursor((c) => {
|
|
220
|
-
if (entries.length === 0)
|
|
221
|
-
return 0;
|
|
222
|
-
return Math.min(c, entries.length - 1);
|
|
223
|
-
});
|
|
224
|
-
}, [entries.length, entries]);
|
|
225
|
-
// FIX ( triple-review, P1): `commit()` is called from inside
|
|
226
|
-
// the useInput closure, which captures the `verdicts` value at the
|
|
227
|
-
// render time the closure was created. With rapid keypresses (e.g.
|
|
228
|
-
// `a` then Enter on the same React tick), React has scheduled the
|
|
229
|
-
// setVerdicts update but the closure still sees the previous array.
|
|
230
|
-
// The emitted MultiFileDiffResult would drop the latest verdict.
|
|
231
|
-
// Fix: track verdicts via a ref synced in a useEffect — the commit
|
|
232
|
-
// path reads `verdictsRef.current` so it always sees the latest map.
|
|
233
|
-
const verdictsRef = useRef(verdicts);
|
|
234
|
-
useEffect(() => {
|
|
235
|
-
verdictsRef.current = verdicts;
|
|
236
|
-
}, [verdicts]);
|
|
237
|
-
// Pre-split the active diff body into lines for the right pane. The
|
|
238
|
-
// body is clamped defensively before splitting so a runaway model
|
|
239
|
-
// payload cannot exhaust the terminal scrollback. useMemo here keeps
|
|
240
|
-
// the line array stable across navigation re-renders on the SAME
|
|
241
|
-
// file — only the cursor changes when the operator presses ↑/↓ on
|
|
242
|
-
// the same diff body.
|
|
243
|
-
const activeEntry = entries[cursor];
|
|
244
|
-
const activeLines = useMemo(() => {
|
|
245
|
-
const body = clampDiffBody(activeEntry?.diff ?? '');
|
|
246
|
-
if (body.length === 0)
|
|
247
|
-
return [];
|
|
248
|
-
return body.split('\n');
|
|
249
|
-
}, [activeEntry?.diff]);
|
|
250
|
-
function commit(cancelled = false) {
|
|
251
|
-
// Read the freshest verdict map via ref — the closure-captured
|
|
252
|
-
// `verdicts` state could be one render behind on rapid keypresses.
|
|
253
|
-
const latest = verdictsRef.current;
|
|
254
|
-
const finalVerdicts = cancelled
|
|
255
|
-
? entries.map(() => 'rejected')
|
|
256
|
-
: latest;
|
|
257
|
-
props.onResolve(buildResult(entries, finalVerdicts, cancelled));
|
|
258
|
-
}
|
|
259
|
-
function setVerdictAt(idx, verdict) {
|
|
260
|
-
setVerdicts((prev) => {
|
|
261
|
-
const next = prev.slice();
|
|
262
|
-
next[idx] = verdict;
|
|
263
|
-
return next;
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
function setAllVerdicts(verdict) {
|
|
267
|
-
setVerdicts(() => entries.map(() => verdict));
|
|
268
|
-
}
|
|
269
|
-
useInput((input, key) => {
|
|
270
|
-
// Esc cancels the whole batch (every file → rejected). Mirrors the
|
|
271
|
-
// AskModal cancel contract so operator muscle memory transfers.
|
|
272
|
-
if (key.escape) {
|
|
273
|
-
commit(true);
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
// Enter commits the current verdict map. Pending files stay
|
|
277
|
-
// pending — the caller decides whether `pending` is treated as
|
|
278
|
-
// approve or reject (dispatcher policy lives upstream).
|
|
279
|
-
if (key.return) {
|
|
280
|
-
commit(false);
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
// ↑ / ↓ navigate file list. Reset scroll on file change so the
|
|
284
|
-
// operator sees the diff header again, not a stale offset from
|
|
285
|
-
// the previous file.
|
|
286
|
-
if (key.upArrow) {
|
|
287
|
-
if (entries.length === 0)
|
|
288
|
-
return;
|
|
289
|
-
setCursor((c) => (c - 1 + entries.length) % entries.length);
|
|
290
|
-
setScrollOffset(0);
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
if (key.downArrow) {
|
|
294
|
-
if (entries.length === 0)
|
|
295
|
-
return;
|
|
296
|
-
setCursor((c) => (c + 1) % entries.length);
|
|
297
|
-
setScrollOffset(0);
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
// PgUp / PgDn scroll the diff pane by a near-full viewport. We
|
|
301
|
-
// keep one row of overlap so the operator's eye anchors across
|
|
302
|
-
// pages. Clamped to [0, max] so over-scroll stops at the bottom
|
|
303
|
-
// line instead of producing an empty pane.
|
|
304
|
-
if (key.pageUp) {
|
|
305
|
-
setScrollOffset((o) => Math.max(0, o - Math.max(1, paneHeight - 1)));
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
if (key.pageDown) {
|
|
309
|
-
setScrollOffset((o) => {
|
|
310
|
-
const maxOffset = Math.max(0, activeLines.length - paneHeight);
|
|
311
|
-
return Math.min(maxOffset, o + Math.max(1, paneHeight - 1));
|
|
312
|
-
});
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
// Capital A / R = bulk verdict. Lowercase a / r = per-file. The
|
|
316
|
-
// order matters: Ink delivers SHIFTed keys as the upper-case
|
|
317
|
-
// glyph in `input`, so we can match с a direct equality.
|
|
318
|
-
if (input === 'A') {
|
|
319
|
-
setAllVerdicts('approved');
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
if (input === 'R') {
|
|
323
|
-
setAllVerdicts('rejected');
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
if (input === 'a') {
|
|
327
|
-
setVerdictAt(cursor, 'approved');
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
if (input === 'r') {
|
|
331
|
-
setVerdictAt(cursor, 'rejected');
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
}, { isActive: props.inert !== true });
|
|
335
|
-
const approvedCount = verdicts.filter((v) => v === 'approved').length;
|
|
336
|
-
const rejectedCount = verdicts.filter((v) => v === 'rejected').length;
|
|
337
|
-
const pendingCount = verdicts.filter((v) => v === 'pending').length;
|
|
338
|
-
const total = entries.length;
|
|
339
|
-
// Diff pane viewport: a window of `paneHeight` lines starting at
|
|
340
|
-
// scrollOffset. Empty entries render с a placeholder so the operator
|
|
341
|
-
// sees the file is intentionally empty (vs the modal being broken).
|
|
342
|
-
const visibleLines = activeLines.slice(scrollOffset, scrollOffset + paneHeight);
|
|
343
|
-
const diffPaneTitle = activeEntry
|
|
344
|
-
? `Diff: ${truncateMiddle(activeEntry.path, MULTI_FILE_DIFF_PATH_CAP)}`
|
|
345
|
-
: 'Diff';
|
|
346
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: '? ' }), _jsx(Text, { bold: true, children: `Multi-file diff review (${total} ${total === 1 ? 'file' : 'files'})` })] }), _jsxs(Box, { flexDirection: "row", marginTop: 1, children: [_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, marginRight: 1, minWidth: MULTI_FILE_DIFF_LEFT_WIDTH, children: [_jsx(Box, { children: _jsx(Text, { bold: true, dimColor: true, children: 'Files' }) }), entries.map((entry, idx) => {
|
|
347
|
-
const isHighlighted = idx === cursor;
|
|
348
|
-
const verdict = verdicts[idx] ?? 'pending';
|
|
349
|
-
// Badge: ✓ approved (green), ✗ rejected (red), • pending (dim).
|
|
350
|
-
// The badge sits BEFORE the cursor arrow so the operator can
|
|
351
|
-
// skim status without scanning the cursor column.
|
|
352
|
-
let badgeGlyph = '•';
|
|
353
|
-
let badgeColor;
|
|
354
|
-
let badgeDim = true;
|
|
355
|
-
if (verdict === 'approved') {
|
|
356
|
-
badgeGlyph = '✓';
|
|
357
|
-
badgeColor = 'green';
|
|
358
|
-
badgeDim = false;
|
|
359
|
-
}
|
|
360
|
-
else if (verdict === 'rejected') {
|
|
361
|
-
badgeGlyph = '✗';
|
|
362
|
-
badgeColor = 'red';
|
|
363
|
-
badgeDim = false;
|
|
364
|
-
}
|
|
365
|
-
// Path budget = left width minus borders, cursor arrow (2),
|
|
366
|
-
// badge + space (2), padding (2). Defensive floor at 8 chars.
|
|
367
|
-
const pathBudget = Math.max(8, MULTI_FILE_DIFF_LEFT_WIDTH - 4 - 2 - 2);
|
|
368
|
-
return (_jsxs(Box, { children: [_jsx(Text, { color: isHighlighted ? 'cyan' : undefined, bold: isHighlighted, children: isHighlighted ? '▸ ' : ' ' }), _jsx(Text, { color: badgeColor, dimColor: badgeDim, bold: !badgeDim, children: `${badgeGlyph} ` }), _jsx(Text, { color: isHighlighted ? 'cyan' : undefined, bold: isHighlighted, children: truncateMiddle(entry.path, pathBudget) }), entry.hint !== undefined && entry.hint.length > 0 ? (_jsx(Text, { dimColor: true, italic: true, children: ` (${entry.hint})` })) : null] }, `file-${idx}-${entry.path}`));
|
|
369
|
-
})] }), _jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, flexGrow: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, dimColor: true, children: diffPaneTitle }), activeLines.length > paneHeight ? (_jsx(Text, { dimColor: true, children: ` · lines ${scrollOffset + 1}-${Math.min(scrollOffset + paneHeight, activeLines.length)}/${activeLines.length}` })) : null] }), visibleLines.length === 0 ? (_jsx(Text, { dimColor: true, italic: true, children: '(empty diff)' })) : (visibleLines.map((line, idx) => {
|
|
370
|
-
const kind = classifyDiffLine(line);
|
|
371
|
-
const rp = renderProps(kind);
|
|
372
|
-
return (_jsx(Text, { color: rp.color, bold: rp.bold, dimColor: rp.dimColor, children: line.length > 0 ? line : ' ' }, `diff-${cursor}-${scrollOffset + idx}`));
|
|
373
|
-
}))] })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "green", children: `${approvedCount}/${total} approved` }), _jsx(Text, { dimColor: true, children: ' · ' }), _jsx(Text, { color: "red", children: `${rejectedCount}/${total} rejected` }), _jsx(Text, { dimColor: true, children: ' · ' }), _jsx(Text, { children: `${pendingCount} remaining` }), _jsx(Text, { dimColor: true, children: ' · Enter when done' })] }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: '[↑↓] navigate · [a] approve · [r] reject · [A] all · [R] none · [PgUp/PgDn] scroll · [Esc] cancel' }) })] })] }));
|
|
374
|
-
}
|
|
375
|
-
//# sourceMappingURL=multi-file-diff-approval.js.map
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* — Onboarding Ink wizard.
|
|
4
|
-
*
|
|
5
|
-
* Six-screen interactive walk:
|
|
6
|
-
*
|
|
7
|
-
* 1. Welcome + auth status (single Enter to continue)
|
|
8
|
-
* 2. Default permission mode (4-row picker)
|
|
9
|
-
* 3. Output style preset (5-row picker)
|
|
10
|
-
* 4. MCP server pointer (informational, Enter to continue)
|
|
11
|
-
* 5. Telemetry consent (3-row picker)
|
|
12
|
-
* 6. Recap card (Enter to commit + exit)
|
|
13
|
-
*
|
|
14
|
-
* Driven entirely by Ink's `useInput`. The component does NOT perform
|
|
15
|
-
* any fs writes — it resolves the verdict back to the caller
|
|
16
|
-
* (`runOnboardingCommand`), which translates verdicts into L6 / L18 /
|
|
17
|
-
* telemetry-state mutations. Single source of truth: the runner.
|
|
18
|
-
*
|
|
19
|
-
* Each picker step pre-selects the CURRENT persisted value (from the
|
|
20
|
-
* snapshot passed in props) so pressing Enter on Step 2/3/5 keeps the
|
|
21
|
-
* current value — that is the idempotency contract.
|
|
22
|
-
*
|
|
23
|
-
* Cancellation:
|
|
24
|
-
* - Esc / Ctrl-C at any step → verdict.cancelled = true, the runner
|
|
25
|
-
* skips ALL writes (including the marker touch) so the next bare
|
|
26
|
-
* `pugi` invocation still surfaces the first-run hint.
|
|
27
|
-
*
|
|
28
|
-
* Keystrokes:
|
|
29
|
-
* - ↑/↓ or j/k — move selection in pickers.
|
|
30
|
-
* - Enter — confirm step (keep current = pass through; new pick
|
|
31
|
-
* = update verdict for that tier).
|
|
32
|
-
* - 's' — skip current step explicitly (verdict slot stays null).
|
|
33
|
-
* - Esc / 'q' — cancel the wizard.
|
|
34
|
-
*/
|
|
35
|
-
import { useState } from 'react';
|
|
36
|
-
import { Box, Text, render, useApp, useInput } from 'ink';
|
|
37
|
-
import { PERMISSION_MODES, PERMISSION_MODE_GLOSS, } from '../core/permissions/index.js';
|
|
38
|
-
import { OUTPUT_STYLES, OUTPUT_STYLE_SLUGS, } from '../core/output-style/presets.js';
|
|
39
|
-
import { TELEMETRY_CHOICES, } from '../core/onboarding/telemetry-state.js';
|
|
40
|
-
const EMPTY_DRAFT = {
|
|
41
|
-
permissionMode: null,
|
|
42
|
-
outputStyle: null,
|
|
43
|
-
telemetry: null,
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Lookup the snapshot value's index within the picker rows so the
|
|
47
|
-
* initial cursor sits on the current value. Returns 0 (safe default)
|
|
48
|
-
* when the snapshot value is outside the closed list — should never
|
|
49
|
-
* happen given the type guards in the state modules, but the index
|
|
50
|
-
* fallback keeps Ink from crashing on a malformed config.
|
|
51
|
-
*/
|
|
52
|
-
function indexOf(rows, value) {
|
|
53
|
-
const idx = rows.indexOf(value);
|
|
54
|
-
return idx === -1 ? 0 : idx;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* The wizard component. Pure: no fs, no env, no network. Verdicts
|
|
58
|
-
* flow up via `onComplete`; the caller owns the writes.
|
|
59
|
-
*/
|
|
60
|
-
export function OnboardingWizard(props) {
|
|
61
|
-
const { snapshot, onComplete } = props;
|
|
62
|
-
const [step, setStep] = useState(1);
|
|
63
|
-
const [permissionIdx, setPermissionIdx] = useState(indexOf(PERMISSION_MODES, snapshot.permissionMode));
|
|
64
|
-
const [styleIdx, setStyleIdx] = useState(indexOf(OUTPUT_STYLE_SLUGS, snapshot.outputStyle));
|
|
65
|
-
const [telemetryIdx, setTelemetryIdx] = useState(indexOf(TELEMETRY_CHOICES, snapshot.telemetry));
|
|
66
|
-
const [draft, setDraft] = useState(EMPTY_DRAFT);
|
|
67
|
-
const finish = (final, cancelled) => {
|
|
68
|
-
onComplete({
|
|
69
|
-
permissionMode: final.permissionMode,
|
|
70
|
-
outputStyle: final.outputStyle,
|
|
71
|
-
telemetry: final.telemetry,
|
|
72
|
-
cancelled,
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
useInput((input, key) => {
|
|
76
|
-
// Universal cancel.
|
|
77
|
-
if (key.escape || (key.ctrl && input === 'c')) {
|
|
78
|
-
finish(EMPTY_DRAFT, true);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
// Universal skip — Enter on a picker means "keep current"; explicit
|
|
82
|
-
// 's' makes the skip intent obvious in the recap.
|
|
83
|
-
const isAdvance = key.return;
|
|
84
|
-
const moveUp = key.upArrow || input === 'k';
|
|
85
|
-
const moveDown = key.downArrow || input === 'j';
|
|
86
|
-
const explicitSkip = input === 's';
|
|
87
|
-
switch (step) {
|
|
88
|
-
case 1: {
|
|
89
|
-
if (isAdvance)
|
|
90
|
-
setStep(2);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
case 2: {
|
|
94
|
-
if (moveUp) {
|
|
95
|
-
setPermissionIdx((i) => (i === 0 ? PERMISSION_MODES.length - 1 : i - 1));
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
if (moveDown) {
|
|
99
|
-
setPermissionIdx((i) => (i === PERMISSION_MODES.length - 1 ? 0 : i + 1));
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (isAdvance || explicitSkip) {
|
|
103
|
-
const picked = PERMISSION_MODES[permissionIdx];
|
|
104
|
-
const verdict = explicitSkip || picked === snapshot.permissionMode ? null : picked ?? null;
|
|
105
|
-
setDraft((d) => ({ ...d, permissionMode: verdict }));
|
|
106
|
-
setStep(3);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
case 3: {
|
|
112
|
-
if (moveUp) {
|
|
113
|
-
setStyleIdx((i) => (i === 0 ? OUTPUT_STYLE_SLUGS.length - 1 : i - 1));
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
if (moveDown) {
|
|
117
|
-
setStyleIdx((i) => (i === OUTPUT_STYLE_SLUGS.length - 1 ? 0 : i + 1));
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
if (isAdvance || explicitSkip) {
|
|
121
|
-
const picked = OUTPUT_STYLE_SLUGS[styleIdx];
|
|
122
|
-
const verdict = explicitSkip || picked === snapshot.outputStyle ? null : picked ?? null;
|
|
123
|
-
setDraft((d) => ({ ...d, outputStyle: verdict }));
|
|
124
|
-
setStep(4);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
case 4: {
|
|
130
|
-
if (isAdvance)
|
|
131
|
-
setStep(5);
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
case 5: {
|
|
135
|
-
if (moveUp) {
|
|
136
|
-
setTelemetryIdx((i) => (i === 0 ? TELEMETRY_CHOICES.length - 1 : i - 1));
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (moveDown) {
|
|
140
|
-
setTelemetryIdx((i) => (i === TELEMETRY_CHOICES.length - 1 ? 0 : i + 1));
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
if (isAdvance || explicitSkip) {
|
|
144
|
-
const picked = TELEMETRY_CHOICES[telemetryIdx];
|
|
145
|
-
const verdict = explicitSkip || picked === snapshot.telemetry ? null : picked ?? null;
|
|
146
|
-
setDraft((d) => ({ ...d, telemetry: verdict }));
|
|
147
|
-
setStep(6);
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
case 6: {
|
|
153
|
-
if (isAdvance)
|
|
154
|
-
finish(draft, false);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(StepHeader, { step: step }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [step === 1 && _jsx(WelcomeStep, { snapshot: snapshot }), step === 2 && (_jsx(ModeStep, { current: snapshot.permissionMode, selectedIdx: permissionIdx })), step === 3 && (_jsx(StyleStep, { current: snapshot.outputStyle, currentSource: snapshot.outputStyleSource, selectedIdx: styleIdx })), step === 4 && _jsx(McpStep, {}), step === 5 && (_jsx(TelemetryStep, { current: snapshot.telemetry, selectedIdx: telemetryIdx })), step === 6 && _jsx(RecapStep, { snapshot: snapshot, draft: draft })] }), _jsx(FooterHints, { step: step })] }));
|
|
160
|
-
}
|
|
161
|
-
function StepHeader({ step }) {
|
|
162
|
-
const titles = {
|
|
163
|
-
1: 'Welcome to Pugi',
|
|
164
|
-
2: 'Step 2 / 5 — Default permission mode',
|
|
165
|
-
3: 'Step 3 / 5 — Output style',
|
|
166
|
-
4: 'Step 4 / 5 — MCP servers',
|
|
167
|
-
5: 'Step 5 / 5 — Telemetry consent',
|
|
168
|
-
6: 'Setup complete',
|
|
169
|
-
};
|
|
170
|
-
return (_jsx(Text, { bold: true, color: "cyan", children: titles[step] }));
|
|
171
|
-
}
|
|
172
|
-
function WelcomeStep({ snapshot }) {
|
|
173
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Brief it. It ships." }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: snapshot.authPresent
|
|
174
|
-
? 'You are signed in. The wizard configures local defaults; values persist to ~/.pugi/config.json.'
|
|
175
|
-
: 'You are NOT signed in. The wizard still configures local defaults, but you should run `pugi login` after.' }) })] }));
|
|
176
|
-
}
|
|
177
|
-
function ModeStep({ current, selectedIdx, }) {
|
|
178
|
-
return (_jsx(Box, { flexDirection: "column", children: PERMISSION_MODES.map((mode, idx) => (_jsx(PickerRow, { isSelected: idx === selectedIdx, isCurrent: mode === current, title: mode, gloss: PERMISSION_MODE_GLOSS[mode] }, mode))) }));
|
|
179
|
-
}
|
|
180
|
-
function StyleStep({ current, currentSource, selectedIdx, }) {
|
|
181
|
-
return (_jsxs(Box, { flexDirection: "column", children: [OUTPUT_STYLE_SLUGS.map((slug, idx) => (_jsx(PickerRow, { isSelected: idx === selectedIdx, isCurrent: slug === current, title: slug, gloss: OUTPUT_STYLES[slug].gloss }, slug))), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: currentSource === 'workspace'
|
|
182
|
-
? 'Active style is currently a workspace override. The wizard writes the user-tier default.'
|
|
183
|
-
: `Active source: ${currentSource}.` }) })] }));
|
|
184
|
-
}
|
|
185
|
-
function McpStep() {
|
|
186
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "MCP servers extend Pugi with extra tools (filesystem, browser, custom APIs)." }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Add one with:" }) }), _jsx(Text, { children: ' pugi mcp add <name> <command>' }), _jsx(Text, { children: ' pugi mcp list' }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "You can skip for now and add servers later." }) })] }));
|
|
187
|
-
}
|
|
188
|
-
function TelemetryStep({ current, selectedIdx, }) {
|
|
189
|
-
const gloss = {
|
|
190
|
-
off: 'No telemetry of any kind.',
|
|
191
|
-
anonymous: 'Counts + error categories only; no payloads.',
|
|
192
|
-
community: 'Anonymous + opt-in usage panels.',
|
|
193
|
-
};
|
|
194
|
-
return (_jsx(Box, { flexDirection: "column", children: TELEMETRY_CHOICES.map((choice, idx) => (_jsx(PickerRow, { isSelected: idx === selectedIdx, isCurrent: choice === current, title: choice, gloss: gloss[choice] }, choice))) }));
|
|
195
|
-
}
|
|
196
|
-
function RecapStep({ snapshot, draft, }) {
|
|
197
|
-
const finalMode = draft.permissionMode ?? snapshot.permissionMode;
|
|
198
|
-
const finalStyle = draft.outputStyle ?? snapshot.outputStyle;
|
|
199
|
-
const finalTelemetry = draft.telemetry ?? snapshot.telemetry;
|
|
200
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: ` Permission mode: ${finalMode}${draft.permissionMode === null ? ' (unchanged)' : ''}` }), _jsx(Text, { children: ` Output style: ${finalStyle}${draft.outputStyle === null ? ' (unchanged)' : ''}` }), _jsx(Text, { children: ` Telemetry: ${finalTelemetry}${draft.telemetry === null ? ' (unchanged)' : ''}` }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press Enter to write defaults + exit. Esc to cancel without saving." }) })] }));
|
|
201
|
-
}
|
|
202
|
-
function PickerRow({ isSelected, isCurrent, title, gloss, }) {
|
|
203
|
-
const indicator = isSelected ? '▸ ' : ' ';
|
|
204
|
-
const currentTag = isCurrent ? ' [current]' : '';
|
|
205
|
-
return (_jsxs(Text, { children: [_jsxs(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: [indicator, title.padEnd(18, ' ')] }), _jsx(Text, { dimColor: true, children: `${gloss}${currentTag}` })] }));
|
|
206
|
-
}
|
|
207
|
-
function FooterHints({ step }) {
|
|
208
|
-
const hint = step === 1 || step === 4
|
|
209
|
-
? 'Enter continue Esc cancel'
|
|
210
|
-
: step === 6
|
|
211
|
-
? 'Enter commit + exit Esc cancel'
|
|
212
|
-
: '↑/↓ select Enter confirm s skip Esc cancel';
|
|
213
|
-
return (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: hint }) }));
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Mount the wizard, await the operator's verdict, unmount Ink, return
|
|
217
|
-
* the verdict to the runner. Wrapped in a `useApp` consumer so we can
|
|
218
|
-
* call `exit()` and let `waitUntilExit()` resolve cleanly.
|
|
219
|
-
*/
|
|
220
|
-
export async function renderOnboardingWizard(opts) {
|
|
221
|
-
return new Promise((resolvePromise) => {
|
|
222
|
-
let resolved = false;
|
|
223
|
-
const handleComplete = (verdict) => {
|
|
224
|
-
if (resolved)
|
|
225
|
-
return;
|
|
226
|
-
resolved = true;
|
|
227
|
-
app.unmount();
|
|
228
|
-
resolvePromise(verdict);
|
|
229
|
-
};
|
|
230
|
-
const Wrapper = () => {
|
|
231
|
-
const { exit } = useApp();
|
|
232
|
-
return (_jsx(OnboardingWizard, { snapshot: opts.snapshot, onComplete: (verdict) => {
|
|
233
|
-
handleComplete(verdict);
|
|
234
|
-
exit();
|
|
235
|
-
} }));
|
|
236
|
-
};
|
|
237
|
-
const app = render(_jsx(Wrapper, {}));
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
//# sourceMappingURL=onboarding-wizard.js.map
|