@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,344 +0,0 @@
|
|
|
1
|
-
// PR-CLI-SERVER-VERSION-HANDSHAKE . The interceptor stamps the
|
|
2
|
-
// outbound X-Pugi-Cli-Version header, inspects the inbound recommended/
|
|
3
|
-
// server-version headers, and throws PugiCliUpgradeRequiredError on a
|
|
4
|
-
// 426 server response. The top-level catch in `runtime/cli.ts` /
|
|
5
|
-
// `index.ts` renders the upgrade message and exits 1.
|
|
6
|
-
import { assertNotUpgradeRequired, injectClientVersionHeader, inspectVersionResponse, } from '../transport/version-interceptor.js';
|
|
7
|
-
import { PUGI_CLI_VERSION } from '../../runtime/version.js';
|
|
8
|
-
/**
|
|
9
|
-
* Anvil-backed engine loop client.
|
|
10
|
-
*
|
|
11
|
-
* Wire format: OpenAI-compatible `/v1/chat/completions` shape proxied
|
|
12
|
-
* through the admin-api Pugi runtime endpoint. The CLI POSTs:
|
|
13
|
-
*
|
|
14
|
-
* POST {apiUrl}/api/pugi/engine
|
|
15
|
-
* Authorization: Bearer {apiKey}
|
|
16
|
-
* {
|
|
17
|
-
* "personaSlug": "oes-dev",
|
|
18
|
-
* "messages": [...],
|
|
19
|
-
* "tools": [...],
|
|
20
|
-
* "maxTokens": 4096,
|
|
21
|
-
* "temperature": 0.2
|
|
22
|
-
* }
|
|
23
|
-
*
|
|
24
|
-
* and expects:
|
|
25
|
-
*
|
|
26
|
-
* 200 OK
|
|
27
|
-
* {
|
|
28
|
-
* "stop": "tool_use" | "text",
|
|
29
|
-
* "content": "...", // present when stop=text
|
|
30
|
-
* "toolCalls": [{id, name, arguments}], // present when stop=tool_use
|
|
31
|
-
* "tokensUsed": 1234,
|
|
32
|
-
* "model": "deepseek-chat-v3.1"
|
|
33
|
-
* }
|
|
34
|
-
*
|
|
35
|
-
* 401/403 -> auth_missing
|
|
36
|
-
* 404 -> endpoint_missing
|
|
37
|
-
* 429 -> rate_limited
|
|
38
|
-
* other -> failed
|
|
39
|
-
*
|
|
40
|
-
* The endpoint itself ships in Sprint 2 (Track 2A). Until then the CLI
|
|
41
|
-
* surfaces `endpoint_missing` cleanly and the operator runs `pugi code`
|
|
42
|
-
* with `PUGI_ENGINE_FIXTURE` to point at a fixture client.
|
|
43
|
-
*/
|
|
44
|
-
export class AnvilEngineLoopClient {
|
|
45
|
-
config;
|
|
46
|
-
constructor(config) {
|
|
47
|
-
this.config = config;
|
|
48
|
-
}
|
|
49
|
-
async send(messages, tools, options) {
|
|
50
|
-
// Use `new URL(path, base)` so an `apiUrl` that already carries a
|
|
51
|
-
// path prefix (rare, but possible for self-hosted deployments)
|
|
52
|
-
// composes correctly instead of double-pathing via raw string
|
|
53
|
-
// concatenation. The leading `/` anchors resolution to the base
|
|
54
|
-
// host. Self-hosted operators who need their engine endpoint
|
|
55
|
-
// nested under a prefix should bake the prefix into `apiUrl`
|
|
56
|
-
// itself and drop the leading slash here.
|
|
57
|
-
const url = new URL('/api/pugi/engine', this.config.apiUrl).toString();
|
|
58
|
-
const controller = new AbortController();
|
|
59
|
-
const onAbort = () => controller.abort();
|
|
60
|
-
if (options.signal)
|
|
61
|
-
options.signal.addEventListener('abort', onAbort);
|
|
62
|
-
const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);
|
|
63
|
-
try {
|
|
64
|
-
// PR-CLI-SERVER-VERSION-HANDSHAKE . Stamp the outbound
|
|
65
|
-
// X-Pugi-Cli-Version header so the admin-api middleware can
|
|
66
|
-
// decide whether to honour, soft-warn, or 426 this request.
|
|
67
|
-
// PUGI-260: also stamp `X-Pugi-Context-Tier: 1m` when the
|
|
68
|
-
// operator opted into the long-context lane. The server reads
|
|
69
|
-
// either the body's `contextTier` field OR this header (header is
|
|
70
|
-
// a fallback for older runtimes / non-CLI clients), so emitting
|
|
71
|
-
// both is harmless и belt-and-suspenders. Only emitted for the
|
|
72
|
-
// `'1m'` value — the absence of the header is wire-equivalent к
|
|
73
|
-
// `'standard'`, keeping the default-lane path header-free.
|
|
74
|
-
const baseHeaders = {
|
|
75
|
-
'content-type': 'application/json',
|
|
76
|
-
authorization: `Bearer ${this.config.apiKey}`,
|
|
77
|
-
'user-agent': 'pugi-cli/0.0.1',
|
|
78
|
-
};
|
|
79
|
-
if (options.contextTier === '1m') {
|
|
80
|
-
baseHeaders['x-pugi-context-tier'] = '1m';
|
|
81
|
-
}
|
|
82
|
-
const outboundHeaders = injectClientVersionHeader(baseHeaders, PUGI_CLI_VERSION);
|
|
83
|
-
const res = await fetch(url, {
|
|
84
|
-
method: 'POST',
|
|
85
|
-
headers: outboundHeaders,
|
|
86
|
-
body: JSON.stringify({
|
|
87
|
-
personaSlug: options.personaSlug,
|
|
88
|
-
messages,
|
|
89
|
-
tools,
|
|
90
|
-
maxTokens: options.maxTokens,
|
|
91
|
-
temperature: options.temperature,
|
|
92
|
-
// β1 (audit E2): the admin-api `EngineRequestDto` accepts
|
|
93
|
-
// these optional fields (see `pugi-engine.controller.ts:230`
|
|
94
|
-
// EngineRequestDto schema). Before this fix the CLI dropped
|
|
95
|
-
// them, which forced the controller to fall back to legacy
|
|
96
|
-
// per-persona resolution + emit `command="(none)"` in its
|
|
97
|
-
// structured logs. `undefined` keys are stripped by
|
|
98
|
-
// `JSON.stringify` so the payload stays clean for fixture
|
|
99
|
-
// clients that exact-match the body shape.
|
|
100
|
-
command: options.command,
|
|
101
|
-
// β1a r1: `tag` is `EngineDispatchTag` object shape now —
|
|
102
|
-
// `JSON.stringify` serialises it as `{tag, priority?,
|
|
103
|
-
// budget_hint?}` matching `EngineDispatchTagDto`. Previously
|
|
104
|
-
// this was a bare string and the server's `IsIn` validator
|
|
105
|
-
// rejected every payload with HTTP 400.
|
|
106
|
-
tag: options.tag,
|
|
107
|
-
model: options.model,
|
|
108
|
-
// Task: server-side tier gate. Stripped by JSON.stringify
|
|
109
|
-
// when undefined so older runtimes без the contextTier DTO
|
|
110
|
-
// field never see an unknown key.
|
|
111
|
-
contextTier: options.contextTier,
|
|
112
|
-
}),
|
|
113
|
-
signal: controller.signal,
|
|
114
|
-
});
|
|
115
|
-
const text = await res.text();
|
|
116
|
-
// PR-CLI-SERVER-VERSION-HANDSHAKE: cache server-recommended +
|
|
117
|
-
// server-version headers so UpdateBanner / `pugi doctor` can
|
|
118
|
-
// surface them, then short-circuit on 426 by throwing
|
|
119
|
-
// PugiCliUpgradeRequiredError. The throw bubbles to the
|
|
120
|
-
// top-level catch in index.ts which renders the upgrade banner.
|
|
121
|
-
// The getter shim handles both real `Response` (`.headers.get`)
|
|
122
|
-
// and minimal fixture/stub responses (`.headers?.[name]`) so
|
|
123
|
-
// existing transport tests that mock `fetch` with `{status, text}`
|
|
124
|
-
// don't need to grow a Headers polyfill just to keep passing.
|
|
125
|
-
//
|
|
126
|
-
// Cache poison guard: skip the inspect step on 426. A hostile
|
|
127
|
-
// upstream (proxy with a compromised cert pin, or a transient MITM
|
|
128
|
-
// on a coffee-shop network) could otherwise forge an
|
|
129
|
-
// `X-Pugi-Cli-Upgrade-Recommended` header alongside a 426 status
|
|
130
|
-
// and poison `cachedServerRecommendation` for the rest of the REPL
|
|
131
|
-
// session — `UpdateBanner` would then surface attacker-chosen
|
|
132
|
-
// version strings to the operator. The 426 body still carries the
|
|
133
|
-
// legitimate `recommendedVersion` field, which assertNotUpgrade-
|
|
134
|
-
// Required parses + throws with, so the operator-facing banner
|
|
135
|
-
// remains accurate via the error path.
|
|
136
|
-
if (res.status !== 426) {
|
|
137
|
-
inspectVersionResponse((name) => {
|
|
138
|
-
const h = res.headers;
|
|
139
|
-
if (h && typeof h.get === 'function') {
|
|
140
|
-
return h.get(name);
|
|
141
|
-
}
|
|
142
|
-
if (h && typeof h === 'object') {
|
|
143
|
-
const lowered = h[name.toLowerCase()];
|
|
144
|
-
return lowered ?? null;
|
|
145
|
-
}
|
|
146
|
-
return null;
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
assertNotUpgradeRequired(res.status, text, PUGI_CLI_VERSION);
|
|
150
|
-
if (res.status === 200) {
|
|
151
|
-
try {
|
|
152
|
-
const json = JSON.parse(text);
|
|
153
|
-
if (json.stop === 'text') {
|
|
154
|
-
return {
|
|
155
|
-
stop: 'text',
|
|
156
|
-
assistantMessage: {
|
|
157
|
-
role: 'assistant',
|
|
158
|
-
content: json.content ?? '',
|
|
159
|
-
},
|
|
160
|
-
content: json.content ?? '',
|
|
161
|
-
tokensUsed: json.tokensUsed ?? 0,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
if (json.stop === 'tool_use') {
|
|
165
|
-
const calls = json.toolCalls ?? [];
|
|
166
|
-
return {
|
|
167
|
-
stop: 'tool_use',
|
|
168
|
-
assistantMessage: {
|
|
169
|
-
role: 'assistant',
|
|
170
|
-
content: json.content ?? '',
|
|
171
|
-
toolCalls: calls,
|
|
172
|
-
},
|
|
173
|
-
tokensUsed: json.tokensUsed ?? 0,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
return {
|
|
177
|
-
stop: 'error',
|
|
178
|
-
code: 'failed',
|
|
179
|
-
message: `runtime returned 200 with unknown stop=${String(json.stop)}`,
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
catch (error) {
|
|
183
|
-
return {
|
|
184
|
-
stop: 'error',
|
|
185
|
-
code: 'failed',
|
|
186
|
-
message: `runtime returned 200 with non-JSON body: ${error.message}`,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (res.status === 404) {
|
|
191
|
-
return {
|
|
192
|
-
stop: 'error',
|
|
193
|
-
code: 'endpoint_missing',
|
|
194
|
-
message: 'POST /api/pugi/engine not deployed on this runtime',
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
if (res.status === 401 || res.status === 403) {
|
|
198
|
-
// 403 has two distinct causes:
|
|
199
|
-
// 1. genuinely invalid / expired token (auth_missing) — the
|
|
200
|
-
// old default.
|
|
201
|
-
// 2. tenant authenticated successfully but the privacy mode
|
|
202
|
-
// (strict / balanced policy) refused upstream LLM dispatch.
|
|
203
|
-
// The admin-api returns
|
|
204
|
-
// `{ code: 'privacy_strict_upstream_blocked', mode, model,
|
|
205
|
-
// message: '...switch via pugi config set privacy=...' }`.
|
|
206
|
-
// Reported as `auth_missing` the user runs `pugi login`
|
|
207
|
-
// again, which does nothing — the actual fix is a privacy-
|
|
208
|
-
// mode change. Parse the body and route accordingly.
|
|
209
|
-
// (2026-05-27 P0.3 — dogfood surfaced this on /api/pugi/engine
|
|
210
|
-
// for a strict-mode tenant; see memory feedback_no_fake_dispatch_promises
|
|
211
|
-
// for the broader "misleading error" pattern.)
|
|
212
|
-
try {
|
|
213
|
-
const parsed = text ? JSON.parse(text) : null;
|
|
214
|
-
// dogfood cycle 2: distinct error code for the
|
|
215
|
-
// infra-side "PII scrubber down" case. Previously the engine
|
|
216
|
-
// server returned `privacy_strict_upstream_blocked` here even
|
|
217
|
-
// when the tenant was on BALANCED (the scrubber crash forced
|
|
218
|
-
// a fail-closed). Operators chased the wrong fix ("switch
|
|
219
|
-
// privacy") for hours. Server now emits
|
|
220
|
-
// `pii_scrubber_unavailable` — surface a distinct remediation
|
|
221
|
-
// that points at the infra side, not the operator's privacy
|
|
222
|
-
// posture.
|
|
223
|
-
if (parsed?.code === 'pii_scrubber_unavailable') {
|
|
224
|
-
return {
|
|
225
|
-
stop: 'error',
|
|
226
|
-
code: 'privacy_blocked',
|
|
227
|
-
message: parsed.message ?? 'PII scrubber unavailable; privacy filter refused dispatch.',
|
|
228
|
-
remediation: 'Infra-side issue (not your tenant privacy mode). Wait for ops to restore ' +
|
|
229
|
-
'the PiiScrubberService, OR temporarily switch your tenant to permissive via ' +
|
|
230
|
-
'`pugi config set privacy=permissive`.',
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
if (parsed?.code === 'privacy_strict_upstream_blocked' || parsed?.code === 'privacy_blocked') {
|
|
234
|
-
return {
|
|
235
|
-
stop: 'error',
|
|
236
|
-
code: 'privacy_blocked',
|
|
237
|
-
message: parsed.message ?? 'Tenant privacy mode forbids upstream LLM dispatch.',
|
|
238
|
-
remediation: 'pugi config set privacy=balanced — OR configure a self-hosted Anvil model.',
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
catch {
|
|
243
|
-
// Body not JSON — fall through to the generic auth_missing
|
|
244
|
-
// branch below; the 200-char text echo on `failed` will at
|
|
245
|
-
// least give the operator the raw response to triage.
|
|
246
|
-
}
|
|
247
|
-
return {
|
|
248
|
-
stop: 'error',
|
|
249
|
-
code: 'auth_missing',
|
|
250
|
-
message: `runtime rejected credentials (HTTP ${res.status})`,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
if (res.status === 429) {
|
|
254
|
-
return {
|
|
255
|
-
stop: 'error',
|
|
256
|
-
code: 'rate_limited',
|
|
257
|
-
message: 'runtime rate limit reached for this tenant',
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
// PUGI-490 (2026-06-03): structured envelope for upstream-proxy
|
|
261
|
-
// static error pages. When the response body is HTML (the upstream
|
|
262
|
-
// proxy's static 5xx page rather than a NestJS JSON envelope), the
|
|
263
|
-
// raw truncated HTML is useless to operators — it cannot point at
|
|
264
|
-
// what failed. Parse the `cf-ray` request id so the operator can
|
|
265
|
-
// look the request up in the proxy dashboard, and surface a
|
|
266
|
-
// remediation hint pointing at the engine VM logs.
|
|
267
|
-
const cfDetails = detectUpstreamProxyError(res, text);
|
|
268
|
-
if (cfDetails) {
|
|
269
|
-
return {
|
|
270
|
-
stop: 'error',
|
|
271
|
-
code: 'failed',
|
|
272
|
-
message: `runtime error (cf-ray: ${cfDetails.cfRay ?? 'unknown'}) — ` +
|
|
273
|
-
`upstream proxy returned ${res.status} static page. ` +
|
|
274
|
-
`Check engine VM logs for the correlating request id.`,
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
return {
|
|
278
|
-
stop: 'error',
|
|
279
|
-
code: 'failed',
|
|
280
|
-
message: `runtime returned HTTP ${res.status}${text ? `: ${text.slice(0, 200)}` : ''}`,
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
catch (error) {
|
|
284
|
-
const message = error instanceof Error
|
|
285
|
-
? error.name === 'AbortError'
|
|
286
|
-
? `runtime call timed out after ${this.config.timeoutMs}ms`
|
|
287
|
-
: error.message
|
|
288
|
-
: 'unknown error';
|
|
289
|
-
return { stop: 'error', code: 'failed', message };
|
|
290
|
-
}
|
|
291
|
-
finally {
|
|
292
|
-
clearTimeout(timeout);
|
|
293
|
-
if (options.signal)
|
|
294
|
-
options.signal.removeEventListener('abort', onAbort);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* PUGI-490 (2026-06-03): detect when the response body is a static HTML
|
|
300
|
-
* error page emitted by the upstream proxy (rather than a JSON envelope
|
|
301
|
-
* produced by admin-api). Returns the cf-ray request id when matched, so
|
|
302
|
-
* the CLI can surface a meaningful runtime-error envelope instead of
|
|
303
|
-
* truncating raw HTML in front of the operator.
|
|
304
|
-
*
|
|
305
|
-
* Heuristic: the body starts with `<!DOCTYPE` or `<html`, or carries the
|
|
306
|
-
* `cf-ray` response header. We require BOTH conditions when the body is
|
|
307
|
-
* non-empty (defense against admin-api accidentally emitting an HTML
|
|
308
|
-
* fragment) and accept just the header when the body is empty (some
|
|
309
|
-
* proxy 5xx variants ship empty bodies). The function is intentionally
|
|
310
|
-
* permissive — false positives produce a clearer error than false
|
|
311
|
-
* negatives, and the message still includes "upstream proxy" so the
|
|
312
|
-
* operator knows the call did not reach a Pugi controller.
|
|
313
|
-
*
|
|
314
|
-
* Exported for unit testing; not for runtime callers.
|
|
315
|
-
*/
|
|
316
|
-
export function detectUpstreamProxyError(res, body) {
|
|
317
|
-
if (res.status < 500)
|
|
318
|
-
return null;
|
|
319
|
-
// Pull cf-ray via the same getter shim the version-interceptor uses;
|
|
320
|
-
// it tolerates both real `Response.headers.get` and fixture/stub
|
|
321
|
-
// headers represented as plain objects.
|
|
322
|
-
const h = res.headers;
|
|
323
|
-
const readHeader = (name) => {
|
|
324
|
-
if (h && typeof h.get === 'function') {
|
|
325
|
-
return h.get(name);
|
|
326
|
-
}
|
|
327
|
-
if (h && typeof h === 'object') {
|
|
328
|
-
const lowered = h[name.toLowerCase()];
|
|
329
|
-
return lowered ?? null;
|
|
330
|
-
}
|
|
331
|
-
return null;
|
|
332
|
-
};
|
|
333
|
-
const cfRay = readHeader('cf-ray');
|
|
334
|
-
const bodyTrimmed = (body ?? '').trimStart();
|
|
335
|
-
const looksHtml = bodyTrimmed.startsWith('<!DOCTYPE') ||
|
|
336
|
-
bodyTrimmed.startsWith('<!doctype') ||
|
|
337
|
-
bodyTrimmed.startsWith('<html');
|
|
338
|
-
if (looksHtml)
|
|
339
|
-
return { cfRay };
|
|
340
|
-
if (cfRay && bodyTrimmed.length === 0)
|
|
341
|
-
return { cfRay };
|
|
342
|
-
return null;
|
|
343
|
-
}
|
|
344
|
-
//# sourceMappingURL=anvil-client.js.map
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Crude token-count heuristic mirroring `runEngineLoop`'s fallback
|
|
3
|
-
* accounting (transcript char count / 4). The CLI does not have access
|
|
4
|
-
* to a real tokenizer pre-flight — the runtime returns `usage.totalTokens`
|
|
5
|
-
* only on the server response, which is too late for our pre-turn gate.
|
|
6
|
-
* char/4 is in the right order of magnitude for English/TS and matches
|
|
7
|
-
* what the loop's own fallback uses on `tokensUsed === 0` upstream.
|
|
8
|
-
*/
|
|
9
|
-
export function estimateTranscriptTokens(messages) {
|
|
10
|
-
let chars = 0;
|
|
11
|
-
for (const m of messages) {
|
|
12
|
-
chars += m.content.length;
|
|
13
|
-
const calls = m.toolCalls ?? [];
|
|
14
|
-
for (const c of calls) {
|
|
15
|
-
chars += c.name.length + c.arguments.length;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return Math.ceil(chars / 4);
|
|
19
|
-
}
|
|
20
|
-
const FILE_TOOL_NAMES = new Set([
|
|
21
|
-
'read',
|
|
22
|
-
'write',
|
|
23
|
-
'edit',
|
|
24
|
-
'multi_edit',
|
|
25
|
-
'multiEdit',
|
|
26
|
-
]);
|
|
27
|
-
/**
|
|
28
|
-
* Walk the dropped slice and pull out tool-call metadata. We parse the
|
|
29
|
-
* `arguments` JSON best-effort — a bad parse is harmless here because
|
|
30
|
-
* the executor surfaced the canonical error to the model already; the
|
|
31
|
-
* gist just under-counts that one call.
|
|
32
|
-
*/
|
|
33
|
-
export function summarizeDroppedTurns(dropped) {
|
|
34
|
-
let toolCalls = 0;
|
|
35
|
-
let bashCalls = 0;
|
|
36
|
-
const files = new Set();
|
|
37
|
-
for (const m of dropped) {
|
|
38
|
-
if (m.role === 'assistant') {
|
|
39
|
-
const calls = m.toolCalls ?? [];
|
|
40
|
-
toolCalls += calls.length;
|
|
41
|
-
for (const c of calls) {
|
|
42
|
-
if (c.name === 'bash') {
|
|
43
|
-
bashCalls += 1;
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (FILE_TOOL_NAMES.has(c.name)) {
|
|
47
|
-
const p = extractPath(c.arguments);
|
|
48
|
-
if (p)
|
|
49
|
-
files.add(p);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return {
|
|
55
|
-
toolCalls,
|
|
56
|
-
fileCount: files.size,
|
|
57
|
-
bashCalls,
|
|
58
|
-
messagesDropped: dropped.length,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function extractPath(rawArgs) {
|
|
62
|
-
if (!rawArgs)
|
|
63
|
-
return null;
|
|
64
|
-
try {
|
|
65
|
-
const parsed = JSON.parse(rawArgs);
|
|
66
|
-
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
67
|
-
const obj = parsed;
|
|
68
|
-
const path = obj['path'] ?? obj['filePath'];
|
|
69
|
-
if (typeof path === 'string' && path.length > 0)
|
|
70
|
-
return path;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Format the deterministic gist string spliced into the synthetic
|
|
80
|
-
* system message. Stable shape so spec assertions and operator
|
|
81
|
-
* logs do not drift turn-over-turn.
|
|
82
|
-
*/
|
|
83
|
-
export function renderAutoCompactSentinel(stats) {
|
|
84
|
-
return (`[auto-compact] Earlier turns ` +
|
|
85
|
-
`(${stats.toolCalls} tool calls, ${stats.fileCount} files read, ${stats.bashCalls} bash commands) ` +
|
|
86
|
-
`summarized to free transcript headroom. ` +
|
|
87
|
-
`Recent turns and the original task remain in context; ` +
|
|
88
|
-
`re-read any earlier file by name if you need its contents again.`);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Minimum transcript length (in messages) before compact is allowed.
|
|
92
|
-
* We always retain `system + user` (the first 2) + the last 2 turns,
|
|
93
|
-
* so anything <= 4 messages has nothing in the middle to drop.
|
|
94
|
-
* Compacting на 4-message transcript would either be a no-op or
|
|
95
|
-
* accidentally drop the user's original task.
|
|
96
|
-
*/
|
|
97
|
-
export const MIN_COMPACT_TRANSCRIPT_LENGTH = 5;
|
|
98
|
-
/**
|
|
99
|
-
* Pure gate. Returns `compact` when ALL of:
|
|
100
|
-
* - `config.enabled` is true
|
|
101
|
-
* - estimated transcript tokens >= `thresholdRatio * maxTokens`
|
|
102
|
-
* - transcript length >= 5 (need history to drop)
|
|
103
|
-
*/
|
|
104
|
-
export function evaluateAutoCompactDecision(input) {
|
|
105
|
-
const usedTokens = estimateTranscriptTokens(input.transcript);
|
|
106
|
-
if (!input.config.enabled) {
|
|
107
|
-
return { kind: 'skip', reason: 'disabled', usedTokens };
|
|
108
|
-
}
|
|
109
|
-
if (input.transcript.length < MIN_COMPACT_TRANSCRIPT_LENGTH) {
|
|
110
|
-
return { kind: 'skip', reason: 'transcript-too-short', usedTokens };
|
|
111
|
-
}
|
|
112
|
-
const thresholdTokens = Math.floor(input.config.thresholdRatio * input.maxTokens);
|
|
113
|
-
if (usedTokens < thresholdTokens) {
|
|
114
|
-
return { kind: 'skip', reason: 'below-threshold', usedTokens };
|
|
115
|
-
}
|
|
116
|
-
return { kind: 'compact', usedTokens, thresholdTokens };
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Rewrite the transcript: keep the first two messages (system + user
|
|
120
|
-
* task), drop the middle (assistant + tool turns), insert a synthetic
|
|
121
|
-
* system sentinel summarizing what was dropped, then re-append the
|
|
122
|
-
* last 2 messages so the model has the most-recent tool result + its
|
|
123
|
-
* own last reply in full fidelity.
|
|
124
|
-
*
|
|
125
|
-
* Precondition: caller has already checked the decision is `compact`
|
|
126
|
-
* (length >= MIN_COMPACT_TRANSCRIPT_LENGTH). The function still guards
|
|
127
|
-
* with a defensive identity-return on shorter transcripts so a careless
|
|
128
|
-
* caller cannot corrupt the prefix.
|
|
129
|
-
*/
|
|
130
|
-
export function compactTranscript(transcript) {
|
|
131
|
-
const preUsedTokens = estimateTranscriptTokens(transcript);
|
|
132
|
-
if (transcript.length < MIN_COMPACT_TRANSCRIPT_LENGTH) {
|
|
133
|
-
return {
|
|
134
|
-
transcript: transcript.slice(),
|
|
135
|
-
droppedCount: 0,
|
|
136
|
-
gist: '',
|
|
137
|
-
stats: { toolCalls: 0, fileCount: 0, bashCalls: 0, messagesDropped: 0 },
|
|
138
|
-
preUsedTokens,
|
|
139
|
-
postUsedTokens: preUsedTokens,
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
// Always retain: index 0 (system) + index 1 (original user task) +
|
|
143
|
-
// last 2 messages. The middle slice is what gets summarised.
|
|
144
|
-
const head = transcript.slice(0, 2);
|
|
145
|
-
const tail = transcript.slice(-2);
|
|
146
|
-
const middle = transcript.slice(2, -2);
|
|
147
|
-
const stats = summarizeDroppedTurns(middle);
|
|
148
|
-
const gist = renderAutoCompactSentinel(stats);
|
|
149
|
-
const sentinelMessage = {
|
|
150
|
-
role: 'system',
|
|
151
|
-
content: gist,
|
|
152
|
-
};
|
|
153
|
-
const next = [...head, sentinelMessage, ...tail];
|
|
154
|
-
const postUsedTokens = estimateTranscriptTokens(next);
|
|
155
|
-
return {
|
|
156
|
-
transcript: next,
|
|
157
|
-
droppedCount: middle.length,
|
|
158
|
-
gist,
|
|
159
|
-
stats,
|
|
160
|
-
preUsedTokens,
|
|
161
|
-
postUsedTokens,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Convenience composer used by `runEngineLoop`: evaluate → compact in
|
|
166
|
-
* one shot. Returns `null` when the decision was `skip` so the loop
|
|
167
|
-
* driver can branch cheaply без destructuring two layers of records.
|
|
168
|
-
*/
|
|
169
|
-
export function maybeCompact(transcript, maxTokens, config) {
|
|
170
|
-
const decision = evaluateAutoCompactDecision({
|
|
171
|
-
transcript,
|
|
172
|
-
maxTokens,
|
|
173
|
-
config,
|
|
174
|
-
});
|
|
175
|
-
if (decision.kind === 'skip')
|
|
176
|
-
return null;
|
|
177
|
-
return compactTranscript(transcript);
|
|
178
|
-
}
|
|
179
|
-
//# sourceMappingURL=auto-compact.js.map
|