@pugi/cli 0.1.0-beta.1 → 0.1.0-beta.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/LICENSE +1 -1
- package/README.md +53 -11
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/assets/pugi-mascot.ansi +15 -40
- package/assets/pugi-prozr2-mascot.ansi +9 -0
- package/bin/run.js +33 -1
- package/dist/commands/deploy.js +40 -40
- package/dist/commands/flatten.js +191 -0
- package/dist/commands/jobs-watch.js +201 -0
- package/dist/commands/jobs.js +42 -27
- package/dist/commands/retro.js +210 -0
- package/dist/commands/smoke.js +133 -0
- package/dist/core/agent-progress/cleanup.js +134 -0
- package/dist/core/agent-progress/schema.js +144 -0
- package/dist/core/agent-progress/writer.js +101 -0
- package/dist/core/agents/adaptive-router.js +330 -0
- package/dist/core/agents/query-decomposer.js +297 -0
- package/dist/core/agents/registry.js +3 -3
- package/dist/core/approvals/shortcut-resolver.js +98 -0
- package/dist/core/artifact-chain/dispatcher.js +148 -0
- package/dist/core/artifact-chain/exporter.js +164 -0
- package/dist/core/artifact-chain/state.js +243 -0
- package/dist/core/artifact-chain/steps.js +169 -0
- package/dist/core/ask-user/question.js +92 -0
- package/dist/core/audit/audit-trail.js +275 -0
- package/dist/core/auth/ensure-authenticated.js +129 -0
- package/dist/core/auth/env-provider.js +238 -0
- package/dist/core/auto-open-browser.js +4 -4
- package/dist/core/auto-update/channels.js +122 -0
- package/dist/core/auto-update/checker.js +241 -0
- package/dist/core/auto-update/state.js +235 -0
- package/dist/core/bare-mode/index.js +107 -0
- package/dist/core/bash/redirect.js +281 -0
- package/dist/core/bash-classifier.js +436 -40
- package/dist/core/checkpoint/resumer.js +149 -0
- package/dist/core/checkpoint/rewinder.js +291 -0
- package/dist/core/checkpoints/shadow-git.js +670 -0
- package/dist/core/citations/parser.js +109 -0
- package/dist/core/classifier/yolo-classifier.js +88 -0
- package/dist/core/codegraph/db.js +506 -0
- package/dist/core/codegraph/decision-store.js +248 -0
- package/dist/core/codegraph/detect-repo.js +459 -0
- package/dist/core/codegraph/install.js +134 -0
- package/dist/core/codegraph/offer-hook.js +220 -0
- package/dist/core/codegraph/parser.js +71 -0
- package/dist/core/codegraph/types.js +34 -0
- package/dist/core/compact/auto-trigger.js +96 -0
- package/dist/core/compact/buffer-rewriter.js +115 -0
- package/dist/core/compact/summarizer.js +208 -0
- package/dist/core/compact/token-counter.js +108 -0
- package/dist/core/consensus/anvil-fanout.js +25 -25
- package/dist/core/consensus/diff-capture.js +121 -12
- package/dist/core/consensus/rubric.js +21 -21
- package/dist/core/context/builder.js +6 -6
- package/dist/core/context/compaction-events.js +8 -8
- package/dist/core/context/compaction.js +31 -31
- package/dist/core/context/index.js +15 -8
- package/dist/core/context/invariants.js +51 -51
- package/dist/core/context/markdown-loader.js +28 -10
- package/dist/core/context/markdown-traverse.js +255 -0
- package/dist/core/context/pugiignore.js +41 -41
- package/dist/core/context/repo-skeleton.js +37 -37
- package/dist/core/context/tool-eviction.js +55 -0
- package/dist/core/context/watcher.js +32 -32
- package/dist/core/context/working-set.js +23 -23
- package/dist/core/coordinator/agent-tools.js +77 -0
- package/dist/core/coordinator/agent-toolset.js +65 -0
- package/dist/core/coordinator/fsm.js +73 -0
- package/dist/core/coordinator/mode-fsm.js +70 -0
- package/dist/core/cost/rate-card.js +129 -0
- package/dist/core/cost/tracker.js +221 -0
- package/dist/core/credentials.js +13 -13
- package/dist/core/cron/scheduler.js +138 -0
- package/dist/core/denial-tracking/index.js +8 -0
- package/dist/core/denial-tracking/state.js +264 -0
- package/dist/core/diagnostics/probe-runner.js +93 -0
- package/dist/core/diagnostics/probes/api.js +46 -0
- package/dist/core/diagnostics/probes/auth.js +93 -0
- package/dist/core/diagnostics/probes/bare-mode.js +42 -0
- package/dist/core/diagnostics/probes/cli-version.js +127 -0
- package/dist/core/diagnostics/probes/config.js +72 -0
- package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
- package/dist/core/diagnostics/probes/disk.js +81 -0
- package/dist/core/diagnostics/probes/engine-live.js +46 -0
- package/dist/core/diagnostics/probes/git.js +65 -0
- package/dist/core/diagnostics/probes/hooks.js +118 -0
- package/dist/core/diagnostics/probes/mcp.js +75 -0
- package/dist/core/diagnostics/probes/node.js +59 -0
- package/dist/core/diagnostics/probes/pnpm.js +36 -0
- package/dist/core/diagnostics/probes/pugi-md.js +89 -0
- package/dist/core/diagnostics/probes/sandbox.js +72 -0
- package/dist/core/diagnostics/probes/session.js +74 -0
- package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
- package/dist/core/diagnostics/probes/workspace.js +63 -0
- package/dist/core/diagnostics/types.js +70 -0
- package/dist/core/dispatch/cache-cleanup.js +197 -0
- package/dist/core/dispatch/cache-handoff.js +295 -0
- package/dist/core/edits/apply-patch-layer-e.js +189 -0
- package/dist/core/edits/dispatch.js +333 -7
- package/dist/core/edits/format-detector.js +260 -0
- package/dist/core/edits/format-matrix.js +26 -0
- package/dist/core/edits/fuzzy-ladder.js +650 -0
- package/dist/core/edits/index.js +5 -1
- package/dist/core/edits/journal.js +199 -0
- package/dist/core/edits/layer-a-apply.js +15 -15
- package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
- package/dist/core/edits/layer-b-apply.js +9 -9
- package/dist/core/edits/layer-c-apply.js +6 -6
- package/dist/core/edits/layer-d-ast.js +557 -14
- package/dist/core/edits/marker-parser.js +12 -12
- package/dist/core/edits/security-gate.js +27 -27
- package/dist/core/edits/verify-hook.js +273 -0
- package/dist/core/edits/worktree.js +322 -0
- package/dist/core/engine/anvil-client.js +214 -26
- package/dist/core/engine/auto-compact.js +247 -0
- package/dist/core/engine/budgets.js +220 -0
- package/dist/core/engine/compact-llm-summarizer.js +124 -0
- package/dist/core/engine/context-prefix.js +155 -0
- package/dist/core/engine/index.js +1 -1
- package/dist/core/engine/intensity.js +163 -0
- package/dist/core/engine/intent.js +260 -0
- package/dist/core/engine/native-pugi.js +1559 -227
- package/dist/core/engine/prompts.js +192 -16
- package/dist/core/engine/strip-internal-fields.js +124 -0
- package/dist/core/engine/tool-bridge.js +1887 -59
- package/dist/core/engine/verification-patterns.js +195 -0
- package/dist/core/evaluation/golden-dataset.js +293 -0
- package/dist/core/feedback/queue.js +177 -0
- package/dist/core/feedback/submitter.js +145 -0
- package/dist/core/file-cache.js +113 -1
- package/dist/core/flatten/flatten-repo.js +439 -0
- package/dist/core/format/osc8-link.js +28 -0
- package/dist/core/hook-chains.js +392 -0
- package/dist/core/hooks/citation-verify-hook.js +138 -0
- package/dist/core/hooks/citation-verify.js +112 -0
- package/dist/core/hooks/events.js +46 -0
- package/dist/core/hooks/index.js +15 -0
- package/dist/core/hooks/registry.js +216 -0
- package/dist/core/hooks/runner.js +236 -0
- package/dist/core/hooks/v2/event-emitter.js +115 -0
- package/dist/core/hooks/v2/executor.js +282 -0
- package/dist/core/hooks/v2/index.js +25 -0
- package/dist/core/hooks/v2/lifecycle.js +104 -0
- package/dist/core/hooks/v2/loader.js +216 -0
- package/dist/core/hooks/v2/matcher.js +125 -0
- package/dist/core/hooks/v2/trust.js +143 -0
- package/dist/core/hooks/v2/types.js +86 -0
- package/dist/core/hooks/worktree-events.js +158 -0
- package/dist/core/image/renderer.js +71 -0
- package/dist/core/init/detector.js +582 -0
- package/dist/core/init/template-renderer.js +242 -0
- package/dist/core/jobs/registry.js +18 -18
- package/dist/core/ledger/results-tsv.js +142 -0
- package/dist/core/log-discipline/stdout-redirect.js +51 -0
- package/dist/core/lsp/cache.js +105 -0
- package/dist/core/lsp/client.js +1229 -0
- package/dist/core/lsp/language-detect.js +66 -0
- package/dist/core/lsp/post-edit-diagnostics.js +171 -0
- package/dist/core/lsp/server-detect.js +173 -0
- package/dist/core/lsp/symbol-cache.js +162 -0
- package/dist/core/lsp/symbol-tools.js +664 -0
- package/dist/core/mcp/client.js +97 -28
- package/dist/core/mcp/http-server.js +553 -0
- package/dist/core/mcp/orchestrator-config.js +192 -0
- package/dist/core/mcp/orchestrator-tools.js +806 -0
- package/dist/core/mcp/permission.js +190 -0
- package/dist/core/mcp/registry.js +39 -17
- package/dist/core/mcp/server-tools.js +219 -0
- package/dist/core/mcp/server.js +397 -0
- package/dist/core/mcp/trust.js +10 -10
- package/dist/core/memory/dual-write.js +416 -0
- package/dist/core/memory/passive-extract.js +130 -0
- package/dist/core/memory/phase1-kinds.js +20 -0
- package/dist/core/memory/secret-scanner.js +304 -0
- package/dist/core/memory-sync/queue.js +170 -0
- package/dist/core/metrics/extract.js +113 -0
- package/dist/core/modes/roo-modes.js +68 -0
- package/dist/core/notes/notes-paths.js +113 -0
- package/dist/core/notes/notes-recorder.js +140 -0
- package/dist/core/notes/notes-writer.js +53 -0
- package/dist/core/notes/renderers.js +0 -0
- package/dist/core/notes/slug.js +105 -0
- package/dist/core/onboarding/ensure-initialized.js +133 -0
- package/dist/core/onboarding/marker.js +111 -0
- package/dist/core/onboarding/telemetry-state.js +108 -0
- package/dist/core/output-style/presets.js +176 -0
- package/dist/core/output-style/state.js +185 -0
- package/dist/core/path-security.js +287 -5
- package/dist/core/permission.js +82 -22
- package/dist/core/permissions/auto-classifier.js +124 -0
- package/dist/core/permissions/bash-parser.js +371 -0
- package/dist/core/permissions/circuit-breaker.js +83 -0
- package/dist/core/permissions/constrained-edit.js +91 -0
- package/dist/core/permissions/gate.js +278 -0
- package/dist/core/permissions/index.js +20 -0
- package/dist/core/permissions/mode.js +174 -0
- package/dist/core/permissions/network-egress.js +137 -0
- package/dist/core/permissions/state.js +241 -0
- package/dist/core/permissions/tool-class.js +107 -0
- package/dist/core/plan-mode/ui-state.js +51 -0
- package/dist/core/plans/plan-artifact.js +721 -0
- package/dist/core/policy-limits/etag-store.js +122 -0
- package/dist/core/prd-check/parser.js +215 -0
- package/dist/core/prd-check/reporter.js +127 -0
- package/dist/core/prd-check/session-review.js +557 -0
- package/dist/core/prd-check/verifiers.js +223 -0
- package/dist/core/prompt-cache/client-cache.js +99 -0
- package/dist/core/prompts/assembly.js +29 -0
- package/dist/core/prompts/registry.js +364 -0
- package/dist/core/pugi-gitignore.js +52 -0
- package/dist/core/pugi-md/cc-compat-rules.js +735 -0
- package/dist/core/pugi-md/context-injector.js +76 -0
- package/dist/core/pugi-md/walk-up.js +207 -0
- package/dist/core/python/uv-installer.js +270 -0
- package/dist/core/python/uv-resolver.js +83 -0
- package/dist/core/rate-limit/narrator.js +146 -0
- package/dist/core/recipes/cli-types.js +20 -0
- package/dist/core/recipes/loader.js +103 -0
- package/dist/core/recipes/runner.js +345 -0
- package/dist/core/recipes/schema.js +587 -0
- package/dist/core/release-notes/parser.js +241 -0
- package/dist/core/release-notes/state.js +116 -0
- package/dist/core/repl/ask.js +37 -37
- package/dist/core/repl/cancellation.js +26 -26
- package/dist/core/repl/cap-warning.js +4 -4
- package/dist/core/repl/clipboard-read.js +11 -11
- package/dist/core/repl/dispatch-fsm.js +12 -12
- package/dist/core/repl/engine-bridge.js +303 -0
- package/dist/core/repl/history-search.js +15 -15
- package/dist/core/repl/history.js +28 -18
- package/dist/core/repl/kill-ring.js +5 -5
- package/dist/core/repl/model-pricing.js +135 -0
- package/dist/core/repl/privacy-banner.js +22 -22
- package/dist/core/repl/session.js +2714 -228
- package/dist/core/repl/slash-commands.js +572 -40
- package/dist/core/repl/store/index.js +1 -1
- package/dist/core/repl/store/jsonl-log.js +22 -22
- package/dist/core/repl/store/lockfile.js +10 -10
- package/dist/core/repl/store/session-store.js +136 -107
- package/dist/core/repl/store/types.js +15 -15
- package/dist/core/repl/store/uuid-v7.js +12 -12
- package/dist/core/repl/tool-route.js +382 -0
- package/dist/core/repl/workspace-context.js +43 -21
- package/dist/core/repo-map/build.js +125 -0
- package/dist/core/repo-map/cache.js +185 -0
- package/dist/core/repo-map/extractor.js +254 -0
- package/dist/core/repo-map/formatter.js +145 -0
- package/dist/core/repo-map/page-rank.js +105 -0
- package/dist/core/repo-map/scanner.js +211 -0
- package/dist/core/retro/git-collector.js +251 -0
- package/dist/core/retro/health-card.js +25 -0
- package/dist/core/retro/metrics.js +342 -0
- package/dist/core/retro/narrative.js +249 -0
- package/dist/core/retro/plane-collector.js +274 -0
- package/dist/core/retro/pr-issue-link.js +65 -0
- package/dist/core/retro/types.js +16 -0
- package/dist/core/retry-budget/budget.js +284 -0
- package/dist/core/retry-budget/index.js +5 -0
- package/dist/core/retry-budget/retry-cap.js +74 -0
- package/dist/core/routing/lead-worker.js +43 -0
- package/dist/core/routing/pre-flight-estimator.js +108 -0
- package/dist/core/runs/run-tree.js +103 -0
- package/dist/core/sandboxing/adapter.js +29 -0
- package/dist/core/sandboxing/index.js +49 -0
- package/dist/core/sandboxing/none.js +19 -0
- package/dist/core/sandboxing/seatbelt.js +183 -0
- package/dist/core/security/injection-scanner.js +367 -0
- package/dist/core/security/output-filter.js +418 -0
- package/dist/core/session/env-file.js +105 -0
- package/dist/core/session/section-budgets.js +140 -0
- package/dist/core/session.js +119 -0
- package/dist/core/settings.js +378 -5
- package/dist/core/share/formatter.js +271 -0
- package/dist/core/share/redactor.js +221 -0
- package/dist/core/share/uploader.js +267 -0
- package/dist/core/skills/defaults.js +457 -0
- package/dist/core/skills/loader.js +22 -22
- package/dist/core/skills/sources.js +27 -27
- package/dist/core/smoke/headless-driver.js +174 -0
- package/dist/core/smoke/orchestrator.js +194 -0
- package/dist/core/smoke/runner.js +238 -0
- package/dist/core/smoke/scenario-parser.js +316 -0
- package/dist/core/statusline.js +99 -0
- package/dist/core/subagents/dispatcher-real.js +600 -0
- package/dist/core/subagents/dispatcher.js +146 -52
- package/dist/core/subagents/index.js +19 -6
- package/dist/core/subagents/isolation-matrix.js +213 -0
- package/dist/core/subagents/spawn.js +19 -4
- package/dist/core/telemetry/emitter.js +229 -0
- package/dist/core/telemetry/queue.js +251 -0
- package/dist/core/theme/context.js +91 -0
- package/dist/core/theme/presets.js +228 -0
- package/dist/core/theme/state.js +181 -0
- package/dist/core/todos/invariant.js +10 -0
- package/dist/core/todos/state.js +177 -0
- package/dist/core/tool-schema/compressor.js +89 -0
- package/dist/core/transport/version-interceptor.js +166 -0
- package/dist/core/trust.js +2 -2
- package/dist/core/tui/thinking-block.js +64 -0
- package/dist/core/vim/keymap.js +288 -0
- package/dist/core/vim/state.js +92 -0
- package/dist/core/watch-markers/marker-watcher.js +133 -0
- package/dist/core/worktree/include-parser.js +249 -0
- package/dist/core/worktree-manager/cleanup.js +123 -0
- package/dist/core/worktree-manager/manager.js +303 -0
- package/dist/index.js +36 -0
- package/dist/runtime/bootstrap.js +190 -0
- package/dist/runtime/cli.js +4536 -477
- package/dist/runtime/commands/agents.js +31 -31
- package/dist/runtime/commands/budget.js +5 -5
- package/dist/runtime/commands/cancel.js +231 -0
- package/dist/runtime/commands/chain.js +489 -0
- package/dist/runtime/commands/codegraph-status.js +227 -0
- package/dist/runtime/commands/compact.js +297 -0
- package/dist/runtime/commands/config.js +74 -40
- package/dist/runtime/commands/cost.js +199 -0
- package/dist/runtime/commands/delegate.js +312 -0
- package/dist/runtime/commands/dispatch.js +126 -0
- package/dist/runtime/commands/doctor.js +579 -0
- package/dist/runtime/commands/feedback.js +184 -0
- package/dist/runtime/commands/hooks.js +187 -0
- package/dist/runtime/commands/index-cmd.js +353 -0
- package/dist/runtime/commands/init.js +254 -0
- package/dist/runtime/commands/lsp.js +368 -0
- package/dist/runtime/commands/mcp.js +935 -0
- package/dist/runtime/commands/memory.js +582 -0
- package/dist/runtime/commands/model.js +237 -0
- package/dist/runtime/commands/onboarding.js +275 -0
- package/dist/runtime/commands/patch.js +128 -0
- package/dist/runtime/commands/permissions.js +112 -0
- package/dist/runtime/commands/plan.js +143 -0
- package/dist/runtime/commands/prd-check.js +285 -0
- package/dist/runtime/commands/privacy.js +17 -17
- package/dist/runtime/commands/recipe.js +325 -0
- package/dist/runtime/commands/redo-blob-store.js +92 -0
- package/dist/runtime/commands/redo.js +361 -0
- package/dist/runtime/commands/release-notes.js +229 -0
- package/dist/runtime/commands/repo-map.js +95 -0
- package/dist/runtime/commands/report.js +299 -0
- package/dist/runtime/commands/resume.js +118 -0
- package/dist/runtime/commands/review-consensus.js +68 -53
- package/dist/runtime/commands/rewind.js +333 -0
- package/dist/runtime/commands/roster.js +117 -0
- package/dist/runtime/commands/servers.js +236 -0
- package/dist/runtime/commands/sessions.js +163 -0
- package/dist/runtime/commands/share.js +316 -0
- package/dist/runtime/commands/skills.js +31 -31
- package/dist/runtime/commands/status.js +186 -0
- package/dist/runtime/commands/stickers.js +82 -0
- package/dist/runtime/commands/style.js +194 -0
- package/dist/runtime/commands/theme.js +196 -0
- package/dist/runtime/commands/undo.js +54 -22
- package/dist/runtime/commands/update.js +289 -0
- package/dist/runtime/commands/vim.js +140 -0
- package/dist/runtime/commands/worktree.js +177 -0
- package/dist/runtime/commands/worktrees.js +155 -0
- package/dist/runtime/deprecation-warning.js +69 -0
- package/dist/runtime/engine-exit-code.js +50 -0
- package/dist/runtime/headless-repl.js +195 -0
- package/dist/runtime/headless.js +548 -0
- package/dist/runtime/load-hooks-or-exit.js +71 -0
- package/dist/runtime/plan-decompose.js +531 -0
- package/dist/runtime/sigint-guard.js +272 -0
- package/dist/runtime/stream-renderer.js +195 -0
- package/dist/runtime/update-check.js +28 -28
- package/dist/runtime/version.js +65 -0
- package/dist/runtime/worktree-bootstrap.js +579 -0
- package/dist/skills/bundled/batch.js +617 -0
- package/dist/skills/bundled/index.js +45 -0
- package/dist/skills/bundled/loop.js +358 -0
- package/dist/skills/bundled/remember.js +383 -0
- package/dist/skills/bundled/simplify.js +289 -0
- package/dist/skills/bundled/skillify.js +373 -0
- package/dist/skills/bundled/stuck.js +558 -0
- package/dist/skills/bundled/verify.js +439 -0
- package/dist/testing/vcr.js +486 -0
- package/dist/tools/agent-tool.js +229 -0
- package/dist/tools/apply-patch.js +556 -0
- package/dist/tools/ask-user-question.js +337 -0
- package/dist/tools/ask-user.js +115 -0
- package/dist/tools/bash.js +624 -46
- package/dist/tools/brief.js +224 -0
- package/dist/tools/cron.js +433 -0
- package/dist/tools/enter-worktree.js +250 -0
- package/dist/tools/exit-worktree.js +147 -0
- package/dist/tools/file-tools.js +161 -44
- package/dist/tools/http-request.js +336 -0
- package/dist/tools/lsp-tools.js +565 -0
- package/dist/tools/mcp-tool.js +260 -0
- package/dist/tools/multi-edit.js +361 -0
- package/dist/tools/powershell.js +268 -0
- package/dist/tools/registry.js +142 -1
- package/dist/tools/server-tools.js +892 -0
- package/dist/tools/skill-tool.js +96 -0
- package/dist/tools/sleep.js +99 -0
- package/dist/tools/synthetic-output.js +133 -0
- package/dist/tools/tasks.js +208 -0
- package/dist/tools/todo-write.js +184 -0
- package/dist/tools/verify-plan-execution.js +295 -0
- package/dist/tools/web-fetch-injection-scanner.js +207 -0
- package/dist/tools/web-fetch.js +195 -10
- package/dist/tools/web-search.js +458 -0
- package/dist/tui/agent-progress-card.js +111 -0
- package/dist/tui/agent-tree.js +22 -1
- package/dist/tui/ask-modal.js +14 -14
- package/dist/tui/ask-user-question-chips.js +315 -0
- package/dist/tui/ask-user-question-prompt.js +203 -0
- package/dist/tui/compact-banner.js +81 -0
- package/dist/tui/conversation-pane.js +85 -11
- package/dist/tui/cost-table.js +111 -0
- package/dist/tui/device-flow.js +2 -2
- package/dist/tui/doctor-table.js +46 -0
- package/dist/tui/feedback-prompt.js +156 -0
- package/dist/tui/input-box.js +247 -32
- package/dist/tui/login-picker.js +3 -3
- package/dist/tui/markdown-render.js +6 -6
- package/dist/tui/multi-file-diff-approval.js +375 -0
- package/dist/tui/onboarding-wizard.js +240 -0
- package/dist/tui/permissions-picker.js +86 -0
- package/dist/tui/render.js +36 -1
- package/dist/tui/repl-render.js +405 -32
- package/dist/tui/repl-splash-art.js +16 -16
- package/dist/tui/repl-splash-mascot.js +48 -24
- package/dist/tui/repl-splash.js +22 -22
- package/dist/tui/repl.js +136 -43
- package/dist/tui/slash-palette.js +6 -6
- package/dist/tui/splash.js +2 -2
- package/dist/tui/status-bar.js +109 -31
- package/dist/tui/status-table.js +7 -0
- package/dist/tui/stickers-art.js +136 -0
- package/dist/tui/style-table.js +28 -0
- package/dist/tui/theme-table.js +29 -0
- package/dist/tui/thinking-spinner.js +123 -0
- package/dist/tui/tool-stream-pane.js +53 -4
- package/dist/tui/update-banner.js +27 -2
- package/dist/tui/vim-input.js +267 -0
- package/dist/tui/welcome-banner.js +107 -0
- package/dist/tui/welcome-data.js +293 -0
- package/dist/tui/workspace-context.js +2 -2
- package/docs/examples/codegraph.mcp.json +10 -0
- package/package.json +25 -7
- package/test/scenarios/codegen-create-file.scenario.txt +13 -0
- package/test/scenarios/compact-force.scenario.txt +12 -0
- package/test/scenarios/identity.scenario.txt +11 -0
- package/test/scenarios/persona-handoff.scenario.txt +12 -0
- package/test/scenarios/walkback.scenario.txt +12 -0
- package/dist/core/engine/compaction-hook.js +0 -154
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegraph MCP install helper — .
|
|
3
|
+
*
|
|
4
|
+
* Writes the codegraph MCP server config к `.pugi/mcp.json` so the
|
|
5
|
+
* registry loader picks it up on the next dispatch. Mirrors the
|
|
6
|
+
* Phase 1 example config at `apps/pugi-cli/docs/examples/codegraph.mcp.json`
|
|
7
|
+
* — same `codegraph serve --mcp` command + `pending` trust state. The
|
|
8
|
+
* operator still has to run `pugi mcp trust codegraph` before tools
|
|
9
|
+
* actually surface; the install path NEVER auto-trusts, by design.
|
|
10
|
+
*
|
|
11
|
+
* Idempotent: re-running on a workspace that already has a `codegraph`
|
|
12
|
+
* entry is a no-op + returns `{ status: 'already-installed' }`. Other
|
|
13
|
+
* MCP servers in the same file are preserved.
|
|
14
|
+
*
|
|
15
|
+
* The function is intentionally NOT bundled into core/mcp/ to keep
|
|
16
|
+
* the codegraph product (install copy, decision store, language gate)
|
|
17
|
+
* one cohesive module. The MCP registry is a generic surface; the
|
|
18
|
+
* codegraph adoption is a feature on top of it.
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
21
|
+
import { resolve } from 'node:path';
|
|
22
|
+
/**
|
|
23
|
+
* Canonical config shape we write into `.pugi/mcp.json` under the
|
|
24
|
+
* `codegraph` key. Matches `mcpServerConfigSchema` (Zod) in
|
|
25
|
+
* core/mcp/client.ts and the published example at docs/examples/
|
|
26
|
+
* codegraph.mcp.json. Drift here MUST land alongside a registry
|
|
27
|
+
* schema change OR the next dispatch crashes with a validation error.
|
|
28
|
+
*/
|
|
29
|
+
export const CODEGRAPH_MCP_ENTRY = Object.freeze({
|
|
30
|
+
command: 'codegraph',
|
|
31
|
+
args: Object.freeze(['serve', '--mcp']),
|
|
32
|
+
env: Object.freeze({}),
|
|
33
|
+
trust: 'pending',
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* Documentation URL surfaced after a successful install so the operator
|
|
37
|
+
* knows how to actually run codegraph index commands. Single source of
|
|
38
|
+
* truth — both the init flow and the /codegraph-status command pull
|
|
39
|
+
* from this constant.
|
|
40
|
+
*/
|
|
41
|
+
export const CODEGRAPH_DOCS_URL = 'https://github.com/colbymchenry/codegraph';
|
|
42
|
+
/**
|
|
43
|
+
* Merge the codegraph entry into `.pugi/mcp.json`. Creates the file
|
|
44
|
+
* (with `{ schema: 1, servers: { codegraph: ... } }`) when it does not
|
|
45
|
+
* exist. Preserves every other server entry on disk.
|
|
46
|
+
*
|
|
47
|
+
* @param workspaceRoot absolute path to the project root that owns the
|
|
48
|
+
* `.pugi/` directory. The caller is responsible for
|
|
49
|
+
* ensuring `.pugi/` exists (the install helper
|
|
50
|
+
* creates it as a defensive fallback).
|
|
51
|
+
*/
|
|
52
|
+
export function installCodegraphMcpEntry(workspaceRoot) {
|
|
53
|
+
const pugiDir = resolve(workspaceRoot, '.pugi');
|
|
54
|
+
const configPath = resolve(pugiDir, 'mcp.json');
|
|
55
|
+
try {
|
|
56
|
+
if (!existsSync(pugiDir)) {
|
|
57
|
+
mkdirSync(pugiDir, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
let existing = {};
|
|
60
|
+
if (existsSync(configPath)) {
|
|
61
|
+
try {
|
|
62
|
+
const raw = readFileSync(configPath, 'utf8');
|
|
63
|
+
if (raw.trim().length > 0) {
|
|
64
|
+
const parsed = JSON.parse(raw);
|
|
65
|
+
if (parsed && typeof parsed === 'object') {
|
|
66
|
+
existing = parsed;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
return {
|
|
72
|
+
status: 'failed',
|
|
73
|
+
reason: `cannot parse existing .pugi/mcp.json: ${error.message}`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const servers = (existing.servers && typeof existing.servers === 'object')
|
|
78
|
+
? { ...existing.servers }
|
|
79
|
+
: {};
|
|
80
|
+
if (servers['codegraph']) {
|
|
81
|
+
return { status: 'already-installed', configPath };
|
|
82
|
+
}
|
|
83
|
+
servers['codegraph'] = {
|
|
84
|
+
command: CODEGRAPH_MCP_ENTRY.command,
|
|
85
|
+
args: [...CODEGRAPH_MCP_ENTRY.args],
|
|
86
|
+
env: { ...CODEGRAPH_MCP_ENTRY.env },
|
|
87
|
+
trust: CODEGRAPH_MCP_ENTRY.trust,
|
|
88
|
+
};
|
|
89
|
+
const out = {
|
|
90
|
+
schema: typeof existing.schema === 'number' ? existing.schema : 1,
|
|
91
|
+
servers,
|
|
92
|
+
};
|
|
93
|
+
writeFileSync(configPath, `${JSON.stringify(out, null, 2)}\n`, { mode: 0o600 });
|
|
94
|
+
return { status: 'installed', configPath };
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
return { status: 'failed', reason: error.message };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Check whether `.pugi/mcp.json` already declares the `codegraph`
|
|
102
|
+
* server. Pure best-effort — a malformed file returns false (we err
|
|
103
|
+
* on the side of "not installed" so the operator can re-trigger the
|
|
104
|
+
* install path instead of being silently locked out).
|
|
105
|
+
*
|
|
106
|
+
* Returns the parsed `trust` state when present so callers can render
|
|
107
|
+
* the right status copy ("declared, awaiting trust" vs "active").
|
|
108
|
+
*/
|
|
109
|
+
export function detectCodegraphInstalled(workspaceRoot) {
|
|
110
|
+
const configPath = resolve(workspaceRoot, '.pugi/mcp.json');
|
|
111
|
+
if (!existsSync(configPath)) {
|
|
112
|
+
return { installed: false, trust: null, configPath };
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const raw = readFileSync(configPath, 'utf8');
|
|
116
|
+
if (raw.trim().length === 0) {
|
|
117
|
+
return { installed: false, trust: null, configPath };
|
|
118
|
+
}
|
|
119
|
+
const parsed = JSON.parse(raw);
|
|
120
|
+
const codegraph = parsed.servers?.['codegraph'];
|
|
121
|
+
if (!codegraph) {
|
|
122
|
+
return { installed: false, trust: null, configPath };
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
installed: true,
|
|
126
|
+
trust: codegraph.trust === 'trusted' || codegraph.trust === 'denied' ? codegraph.trust : 'pending',
|
|
127
|
+
configPath,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return { installed: false, trust: null, configPath };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegraph offer hook — .
|
|
3
|
+
*
|
|
4
|
+
* Single integration point used by both `pugi init` (standalone CLI
|
|
5
|
+
* entry) AND the REPL's `/init` slash so the decision logic + telemetry
|
|
6
|
+
* fan-out stays single-sourced. The hook is split into two halves:
|
|
7
|
+
*
|
|
8
|
+
* 1. `evaluateOffer({ workspaceRoot, nowIso })` — pure: decides if
|
|
9
|
+
* we should prompt, returns the detection result + suggested copy
|
|
10
|
+
* so the UI layer can render it however it likes (Y/n prompt in
|
|
11
|
+
* a TTY, JSON envelope in --no-tty mode, system pane line in the
|
|
12
|
+
* REPL).
|
|
13
|
+
* 2. `applyOfferDecision({ workspaceRoot, accepted, … })` — side-
|
|
14
|
+
* effectful: persists the operator's verdict + runs the install
|
|
15
|
+
* if accepted + emits the right telemetry event.
|
|
16
|
+
*
|
|
17
|
+
* Telemetry events emitted (when consent allows):
|
|
18
|
+
* - `codegraph.offer.shown` — every time we surface the prompt
|
|
19
|
+
* - `codegraph.offer.accepted` — operator said yes
|
|
20
|
+
* - `codegraph.offer.declined` — operator said no
|
|
21
|
+
* - `codegraph.install.success` — mcp.json merge succeeded
|
|
22
|
+
* - `codegraph.install.failed` — mcp.json merge failed (rare)
|
|
23
|
+
* - `codegraph.reminder.shown` — cold-start nudge surfaced
|
|
24
|
+
* - `codegraph.stale-index.shown` — index > STALE_INDEX_DAYS
|
|
25
|
+
*
|
|
26
|
+
* All telemetry is best-effort fire-and-forget; emit() never throws.
|
|
27
|
+
*
|
|
28
|
+
* The hook NEVER prompts directly — it has no TTY contract. The
|
|
29
|
+
* caller MUST resolve the operator's verdict OR call `applyOfferDecision`
|
|
30
|
+
* with `accepted: false` to record a decline.
|
|
31
|
+
*/
|
|
32
|
+
import { detectRepo, buildOfferCopy } from './detect-repo.js';
|
|
33
|
+
import { shouldOfferOnInit, recordDecision, readDecision, shouldNudgeStaleIndex, indexAgeDays, } from './decision-store.js';
|
|
34
|
+
import { installCodegraphMcpEntry, detectCodegraphInstalled, CODEGRAPH_DOCS_URL, } from './install.js';
|
|
35
|
+
import { emit } from '../telemetry/emitter.js';
|
|
36
|
+
/**
|
|
37
|
+
* Pure evaluation. Reads detection + decision store. NEVER writes.
|
|
38
|
+
* Reads NEVER throw — corrupt JSON returns "first-run". Tests rely on
|
|
39
|
+
* this so they can drive `evaluateOffer` repeatedly without setup.
|
|
40
|
+
*/
|
|
41
|
+
export function evaluateOffer(input) {
|
|
42
|
+
const detection = detectRepo(input.workspaceRoot);
|
|
43
|
+
if (!detection.isRepo) {
|
|
44
|
+
return { shouldPrompt: false, reason: detection.reason, detection };
|
|
45
|
+
}
|
|
46
|
+
if (!detection.offerCodegraph) {
|
|
47
|
+
return { shouldPrompt: false, reason: 'size-or-language-gate', detection };
|
|
48
|
+
}
|
|
49
|
+
// If codegraph is already declared в mcp.json, skip — the operator
|
|
50
|
+
// already adopted it (maybe via Phase 1 manual install). Cold-start
|
|
51
|
+
// hook covers the stale-index nudge separately.
|
|
52
|
+
const installed = detectCodegraphInstalled(input.workspaceRoot);
|
|
53
|
+
if (installed.installed) {
|
|
54
|
+
return { shouldPrompt: false, reason: 'already-installed', detection };
|
|
55
|
+
}
|
|
56
|
+
if (!input.ignorePriorDecision) {
|
|
57
|
+
const cadence = shouldOfferOnInit(input.workspaceRoot, input.nowIso);
|
|
58
|
+
if (!cadence.shouldOffer) {
|
|
59
|
+
return { shouldPrompt: false, reason: cadence.reason, detection };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
shouldPrompt: true,
|
|
64
|
+
detection: detection,
|
|
65
|
+
promptCopy: buildOfferCopy(detection),
|
|
66
|
+
docsUrl: CODEGRAPH_DOCS_URL,
|
|
67
|
+
reason: 'first-run',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export function applyOfferDecision(input) {
|
|
71
|
+
const decision = recordDecision(input.workspaceRoot, {
|
|
72
|
+
accepted: input.accepted,
|
|
73
|
+
...(input.nowIso ? { nowIso: input.nowIso } : {}),
|
|
74
|
+
});
|
|
75
|
+
emitOfferTelemetry(input.accepted ? 'codegraph.offer.accepted' : 'codegraph.offer.declined', {
|
|
76
|
+
sizeCategory: input.detection.sizeCategory,
|
|
77
|
+
primaryLanguage: input.detection.languages[0] ?? 'unknown',
|
|
78
|
+
primarySymbolCount: input.detection.primarySymbolCount,
|
|
79
|
+
});
|
|
80
|
+
if (!input.accepted) {
|
|
81
|
+
return { kind: 'declined', decision };
|
|
82
|
+
}
|
|
83
|
+
const install = installCodegraphMcpEntry(input.workspaceRoot);
|
|
84
|
+
if (install.status === 'failed') {
|
|
85
|
+
emitOfferTelemetry('codegraph.install.failed', {
|
|
86
|
+
reason: install.reason.slice(0, 64),
|
|
87
|
+
});
|
|
88
|
+
return { kind: 'accepted-install-failed', decision, install };
|
|
89
|
+
}
|
|
90
|
+
emitOfferTelemetry('codegraph.install.success', {
|
|
91
|
+
sizeCategory: input.detection.sizeCategory,
|
|
92
|
+
primaryLanguage: input.detection.languages[0] ?? 'unknown',
|
|
93
|
+
alreadyInstalled: install.status === 'already-installed',
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
kind: 'accepted-installed',
|
|
97
|
+
decision,
|
|
98
|
+
install,
|
|
99
|
+
docsUrl: CODEGRAPH_DOCS_URL,
|
|
100
|
+
trustCommand: 'pugi mcp trust codegraph',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Surface the offer telemetry "shown" event. Called by the init flow
|
|
105
|
+
* once it has decided to actually render the prompt (so a `--no-tty`
|
|
106
|
+
* invocation that skipped the prompt does not count as a shown event).
|
|
107
|
+
*/
|
|
108
|
+
export function emitOfferShown(detection) {
|
|
109
|
+
emitOfferTelemetry('codegraph.offer.shown', {
|
|
110
|
+
sizeCategory: detection.sizeCategory,
|
|
111
|
+
primaryLanguage: detection.languages[0] ?? 'unknown',
|
|
112
|
+
primarySymbolCount: detection.primarySymbolCount,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Compute the cold-start nudge. Pure read — never writes. The session
|
|
117
|
+
* module decides whether to render the message AND whether to call
|
|
118
|
+
* `markReindexChecked(...)` after the operator dismisses it (so the
|
|
119
|
+
* once-per-day throttle on `shouldNudgeStaleIndex` works).
|
|
120
|
+
*/
|
|
121
|
+
export function evaluateColdStart(input) {
|
|
122
|
+
const detection = detectRepo(input.workspaceRoot);
|
|
123
|
+
if (!detection.isRepo) {
|
|
124
|
+
return { kind: 'silent', reason: detection.reason };
|
|
125
|
+
}
|
|
126
|
+
const decision = readDecision(input.workspaceRoot);
|
|
127
|
+
// Stale-index path takes priority — an accepted operator should be
|
|
128
|
+
// nudged about freshness before a never-asked operator is nudged
|
|
129
|
+
// about installation.
|
|
130
|
+
if (decision && decision.accepted) {
|
|
131
|
+
if (shouldNudgeStaleIndex(decision, input.nowIso)) {
|
|
132
|
+
const age = indexAgeDays(decision, input.nowIso) ?? 0;
|
|
133
|
+
emitOfferTelemetry('codegraph.stale-index.shown', { ageDays: age });
|
|
134
|
+
return {
|
|
135
|
+
kind: 'stale-index',
|
|
136
|
+
ageDays: age,
|
|
137
|
+
message: `Codegraph index is ${age} day${age === 1 ? '' : 's'} old. Run /codegraph-status to refresh.`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return { kind: 'silent', reason: 'fresh-index' };
|
|
141
|
+
}
|
|
142
|
+
if (!detection.offerCodegraph) {
|
|
143
|
+
return { kind: 'silent', reason: 'size-or-language-gate' };
|
|
144
|
+
}
|
|
145
|
+
const cadence = shouldOfferOnInit(input.workspaceRoot, input.nowIso);
|
|
146
|
+
if (!cadence.shouldOffer) {
|
|
147
|
+
return { kind: 'silent', reason: cadence.reason };
|
|
148
|
+
}
|
|
149
|
+
if (cadence.reason !== 'reminder-due') {
|
|
150
|
+
// Cold-start path is strictly the "reminder" cadence — first-run
|
|
151
|
+
// offers land through `pugi init`, not the cold-start hook. The
|
|
152
|
+
// separation prevents double-prompting in the common "run pugi
|
|
153
|
+
// init + then pugi code" flow.
|
|
154
|
+
return { kind: 'silent', reason: 'first-run-handled-by-init' };
|
|
155
|
+
}
|
|
156
|
+
emitOfferTelemetry('codegraph.reminder.shown', {
|
|
157
|
+
sizeCategory: detection.sizeCategory,
|
|
158
|
+
primaryLanguage: detection.languages[0] ?? 'unknown',
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
kind: 'remind',
|
|
162
|
+
detection,
|
|
163
|
+
message: `${buildOfferCopy(detection)} (last declined ${humanAge(decision?.offeredAt, input.nowIso)} ago)`,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Fire one telemetry event. Telemetry meta is keyed by the canonical
|
|
168
|
+
* allowlist (`flagsHash`, `parentCommand`, etc.); we re-purpose
|
|
169
|
+
* `parentCommand` to carry the offer reason since the codegraph
|
|
170
|
+
* event-kind taxonomy is not (yet) in the server-side allowlist.
|
|
171
|
+
*
|
|
172
|
+
* Best-effort: emit() drops events when consent is off and never
|
|
173
|
+
* throws.
|
|
174
|
+
*/
|
|
175
|
+
function emitOfferTelemetry(command, meta) {
|
|
176
|
+
const stringMeta = {};
|
|
177
|
+
for (const [k, v] of Object.entries(meta)) {
|
|
178
|
+
// Promote everything через the canonical `parentCommand` slot OR
|
|
179
|
+
// safe-numeric counters (retryCount). Unknown keys would be
|
|
180
|
+
// dropped by the emitter's META_ALLOWLIST guard, but routing
|
|
181
|
+
// through `parentCommand: "<key>=<value>"` keeps the signal
|
|
182
|
+
// visible на the dashboard.
|
|
183
|
+
if (typeof v === 'number') {
|
|
184
|
+
stringMeta.retryCount = v;
|
|
185
|
+
}
|
|
186
|
+
else if (typeof v === 'boolean') {
|
|
187
|
+
stringMeta.cacheHit = v;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
stringMeta.parentCommand = `${k}=${String(v).slice(0, 32)}`;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
emit({
|
|
194
|
+
command,
|
|
195
|
+
kind: 'tool-call',
|
|
196
|
+
success: true,
|
|
197
|
+
meta: stringMeta,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Format the elapsed time since `priorIso` in human-readable units
|
|
202
|
+
* (days / weeks). Pure — exposed for spec parity. Falls back to
|
|
203
|
+
* "earlier" when prior is missing OR unparseable.
|
|
204
|
+
*/
|
|
205
|
+
function humanAge(priorIso, nowIso) {
|
|
206
|
+
if (!priorIso)
|
|
207
|
+
return 'earlier';
|
|
208
|
+
const now = nowIso ? Date.parse(nowIso) : Date.now();
|
|
209
|
+
const prior = Date.parse(priorIso);
|
|
210
|
+
if (!Number.isFinite(prior))
|
|
211
|
+
return 'earlier';
|
|
212
|
+
const days = Math.max(0, Math.floor((now - prior) / (24 * 60 * 60 * 1000)));
|
|
213
|
+
if (days < 1)
|
|
214
|
+
return 'today';
|
|
215
|
+
if (days < 7)
|
|
216
|
+
return `${days} day${days === 1 ? '' : 's'}`;
|
|
217
|
+
const weeks = Math.floor(days / 7);
|
|
218
|
+
return `${weeks} week${weeks === 1 ? '' : 's'}`;
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=offer-hook.js.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pugi local symbol index - tree-sitter parser stub.
|
|
3
|
+
*
|
|
4
|
+
* This file is intentionally a stub. Real tree-sitter integration ships
|
|
5
|
+
* in follow-up PR L1, which adds:
|
|
6
|
+
*
|
|
7
|
+
* - `tree-sitter` runtime dependency
|
|
8
|
+
* - per-language grammar deps: `tree-sitter-typescript` (covers TS+TSX),
|
|
9
|
+
* `tree-sitter-javascript` (covers JS+JSX), `tree-sitter-python`,
|
|
10
|
+
* `tree-sitter-go`, `tree-sitter-rust`
|
|
11
|
+
* - per-language extractor modules under `./parsers/<lang>.ts` that
|
|
12
|
+
* walk the parsed CST and emit `Symbol[]` + `Edge[]`
|
|
13
|
+
* - file fingerprint (sha256) computation
|
|
14
|
+
* - extension routing (`.ts` / `.tsx` → typescript, `.py` → python, etc.)
|
|
15
|
+
*
|
|
16
|
+
* Keeping the stub deliberately broken (returns empty arrays + a flag)
|
|
17
|
+
* lets the rest of the scaffold ship in this PR without smuggling in
|
|
18
|
+
* tree-sitter native modules. tree-sitter has a prebuilt-binary
|
|
19
|
+
* distribution but it is one more wheel-per-platform surface that
|
|
20
|
+
* compounds the install-time risk the session-store memo warned about
|
|
21
|
+
* (see `core/repl/store/session-store.ts` lines 20-36).
|
|
22
|
+
*
|
|
23
|
+
* The `parseFile` signature is the long-term contract - PR L1 fills
|
|
24
|
+
* the body without changing the type. Other modules (`db.ts`, the
|
|
25
|
+
* future watcher in PR L2) wire against this signature today; the
|
|
26
|
+
* unit tests in `test/codegraph-db.spec.ts` exercise `db.ts` directly
|
|
27
|
+
* via hand-built symbol arrays so they pass without a real parser.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* Parse one source file and return its symbol + edge contribution.
|
|
31
|
+
*
|
|
32
|
+
* TODO(PR L1): replace this body with a real tree-sitter extraction
|
|
33
|
+
* pipeline. The signature is frozen - db.ts + the watcher + the MCP
|
|
34
|
+
* tool layer wire against it as-is today.
|
|
35
|
+
*
|
|
36
|
+
* @param path Absolute or workspace-relative path. The real impl will
|
|
37
|
+
* read the file, sha256 it, route by extension to the right
|
|
38
|
+
* tree-sitter grammar, and walk the resulting CST.
|
|
39
|
+
*/
|
|
40
|
+
export async function parseFile(path) {
|
|
41
|
+
// Touch the parameter so TS strict noUnusedParameters doesn't fire.
|
|
42
|
+
// The real impl in PR L1 reads the file at this path.
|
|
43
|
+
void path;
|
|
44
|
+
return {
|
|
45
|
+
symbols: [],
|
|
46
|
+
edges: [],
|
|
47
|
+
stub: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Stable list of file extensions the v1 parser will support. Exported
|
|
52
|
+
* so the watcher (PR L2) and the CLI command (`pugi index`) can
|
|
53
|
+
* pre-filter the file walk without instantiating a parser. The set
|
|
54
|
+
* mirrors `INDEXED_LANGUAGES` in `./types.ts`.
|
|
55
|
+
*
|
|
56
|
+
* `.cjs` and `.mjs` map to javascript; `.tsx` and `.jsx` map to
|
|
57
|
+
* typescript / javascript respectively (tree-sitter-typescript ships
|
|
58
|
+
* a TSX grammar variant; same for JSX in tree-sitter-javascript).
|
|
59
|
+
*/
|
|
60
|
+
export const PARSEABLE_EXTENSIONS = Object.freeze([
|
|
61
|
+
'.ts',
|
|
62
|
+
'.tsx',
|
|
63
|
+
'.js',
|
|
64
|
+
'.jsx',
|
|
65
|
+
'.mjs',
|
|
66
|
+
'.cjs',
|
|
67
|
+
'.py',
|
|
68
|
+
'.go',
|
|
69
|
+
'.rs',
|
|
70
|
+
]);
|
|
71
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pugi local symbol index - type definitions.
|
|
3
|
+
*
|
|
4
|
+
* Companion to `db.ts` (SQLite + FTS5 wrapper) and `parser.ts` (tree-sitter
|
|
5
|
+
* extractor, stub today, real impl in follow-up PR L1). These types are the
|
|
6
|
+
* cross-module contract: the parser produces `Symbol[]` + `Edge[]`, the db
|
|
7
|
+
* layer inserts them, the MCP tools consume the query result types.
|
|
8
|
+
*
|
|
9
|
+
* Distinct from the third-party CodeGraph install scaffold that already
|
|
10
|
+
* lives in the same directory (`detect-repo.ts`, `offer-hook.ts`,
|
|
11
|
+
* `install.ts`, `decision-store.ts`). Those manage adoption of the upstream
|
|
12
|
+
* colbymchenry/codegraph MCP server. This file is the Pugi-native index.
|
|
13
|
+
* See the design memo at
|
|
14
|
+
* `docs/research/2026-06-05-pugi-index-codegraph-design.md` for the full
|
|
15
|
+
* architecture rationale.
|
|
16
|
+
*
|
|
17
|
+
* Naming convention: every type defined here is `Symbol` / `Edge` /
|
|
18
|
+
* `IndexedFile` / `*Result` / `*Options`. The interface is intentionally
|
|
19
|
+
* narrow - five v1 languages, four MCP tools, one SQLite database file.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Schema version tracked in the `_migrations` table. v1 ships with this
|
|
23
|
+
* PR (files + symbols + edges + FTS5 virtual + triggers). Bumping this
|
|
24
|
+
* MUST land a matching `applyMigration(N, db)` branch in `db.ts`.
|
|
25
|
+
*/
|
|
26
|
+
export const INDEX_SCHEMA_VERSION = 1;
|
|
27
|
+
export const INDEXED_LANGUAGES = Object.freeze([
|
|
28
|
+
'typescript',
|
|
29
|
+
'javascript',
|
|
30
|
+
'python',
|
|
31
|
+
'go',
|
|
32
|
+
'rust',
|
|
33
|
+
]);
|
|
34
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-compact threshold gate.
|
|
3
|
+
*
|
|
4
|
+
* Decides whether the conversation buffer has crossed the threshold
|
|
5
|
+
* percent of the active model's context window. The check runs after
|
|
6
|
+
* every operator/persona turn before the NEXT operator input lands so
|
|
7
|
+
* the compaction completes BEFORE the model would have rejected the
|
|
8
|
+
* request with a context-overflow error.
|
|
9
|
+
*
|
|
10
|
+
* Design choices:
|
|
11
|
+
*
|
|
12
|
+
* - Pure function. The caller passes (tokenCount, windowSize, env).
|
|
13
|
+
* The gate returns a verdict; the session module owns the side
|
|
14
|
+
* effect of invoking the summariser. Pure-function shape keeps the
|
|
15
|
+
* spec exhaustive and the call site readable.
|
|
16
|
+
*
|
|
17
|
+
* - Hysteresis: once a compaction lands, the marker resets the
|
|
18
|
+
* baseline token count to "summary + tail" — the gate looks at the
|
|
19
|
+
* POST-marker tokens only. This is enforced upstream by the caller
|
|
20
|
+
* passing the post-marker count; the gate itself has no memory.
|
|
21
|
+
*
|
|
22
|
+
* - Two env knobs:
|
|
23
|
+
* PUGI_AUTOCOMPACT_DISABLED=1 — kill switch
|
|
24
|
+
* PUGI_AUTOCOMPACT_THRESHOLD=N — float in (0, 1] (default 0.75)
|
|
25
|
+
* Anything outside (0, 1] is rejected and the gate falls back to
|
|
26
|
+
* the default. Bad input never crashes the REPL.
|
|
27
|
+
*/
|
|
28
|
+
/** Default trip point as a fraction of the context window. */
|
|
29
|
+
export const DEFAULT_THRESHOLD = 0.75;
|
|
30
|
+
/**
|
|
31
|
+
* Decide whether to fire `/compact` automatically. Pure; safe to call
|
|
32
|
+
* after every turn.
|
|
33
|
+
*/
|
|
34
|
+
export function evaluateAutoCompact(input) {
|
|
35
|
+
const env = input.env ?? process.env;
|
|
36
|
+
const threshold = resolveThreshold(env);
|
|
37
|
+
if (input.windowSize <= 0 || !Number.isFinite(input.windowSize)) {
|
|
38
|
+
return {
|
|
39
|
+
kind: 'skip',
|
|
40
|
+
reason: 'invalid-window',
|
|
41
|
+
tokenCount: input.tokenCount,
|
|
42
|
+
windowSize: input.windowSize,
|
|
43
|
+
threshold,
|
|
44
|
+
pressure: 0,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (env['PUGI_AUTOCOMPACT_DISABLED'] === '1') {
|
|
48
|
+
return {
|
|
49
|
+
kind: 'skip',
|
|
50
|
+
reason: 'disabled',
|
|
51
|
+
tokenCount: input.tokenCount,
|
|
52
|
+
windowSize: input.windowSize,
|
|
53
|
+
threshold,
|
|
54
|
+
pressure: roundPressure(input.tokenCount / input.windowSize),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const pressure = roundPressure(input.tokenCount / input.windowSize);
|
|
58
|
+
if (pressure >= threshold) {
|
|
59
|
+
return {
|
|
60
|
+
kind: 'fire',
|
|
61
|
+
tokenCount: input.tokenCount,
|
|
62
|
+
windowSize: input.windowSize,
|
|
63
|
+
threshold,
|
|
64
|
+
pressure,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
kind: 'skip',
|
|
69
|
+
reason: 'below-threshold',
|
|
70
|
+
tokenCount: input.tokenCount,
|
|
71
|
+
windowSize: input.windowSize,
|
|
72
|
+
threshold,
|
|
73
|
+
pressure,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Resolve the threshold from env, clamping to the (0, 1] open-closed
|
|
78
|
+
* interval. Bad input silently falls back to DEFAULT_THRESHOLD so the
|
|
79
|
+
* REPL never crashes on a malformed environment variable.
|
|
80
|
+
*/
|
|
81
|
+
function resolveThreshold(env) {
|
|
82
|
+
const raw = env['PUGI_AUTOCOMPACT_THRESHOLD'];
|
|
83
|
+
if (!raw)
|
|
84
|
+
return DEFAULT_THRESHOLD;
|
|
85
|
+
const parsed = Number.parseFloat(raw);
|
|
86
|
+
if (!Number.isFinite(parsed) || parsed <= 0 || parsed > 1) {
|
|
87
|
+
return DEFAULT_THRESHOLD;
|
|
88
|
+
}
|
|
89
|
+
return parsed;
|
|
90
|
+
}
|
|
91
|
+
function roundPressure(raw) {
|
|
92
|
+
if (!Number.isFinite(raw) || raw < 0)
|
|
93
|
+
return 0;
|
|
94
|
+
return Math.round(raw * 1000) / 1000;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=auto-trigger.js.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard: discriminate a SessionEvent against the `compaction`
|
|
3
|
+
* kind. Used by replay code so the boundary marker drives a different
|
|
4
|
+
* code path than `user`/`persona`/`system` transcript rows.
|
|
5
|
+
*/
|
|
6
|
+
export function isCompactBoundary(event) {
|
|
7
|
+
if (event.kind !== 'compaction')
|
|
8
|
+
return false;
|
|
9
|
+
const p = event.payload;
|
|
10
|
+
if (p === null || typeof p !== 'object')
|
|
11
|
+
return false;
|
|
12
|
+
if (p.version !== 1)
|
|
13
|
+
return false;
|
|
14
|
+
if (p.trigger !== 'manual' && p.trigger !== 'auto')
|
|
15
|
+
return false;
|
|
16
|
+
if (typeof p.summary !== 'string' || p.summary.length === 0)
|
|
17
|
+
return false;
|
|
18
|
+
if (typeof p.summaryTokenCount !== 'number')
|
|
19
|
+
return false;
|
|
20
|
+
if (typeof p.summaryTurnsBefore !== 'number')
|
|
21
|
+
return false;
|
|
22
|
+
if (typeof p.keptTailTurns !== 'number')
|
|
23
|
+
return false;
|
|
24
|
+
if (typeof p.coversUntilOffset !== 'number')
|
|
25
|
+
return false;
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Append one `compaction` boundary marker to the SessionStore. Returns
|
|
30
|
+
* the SessionEvent we wrote so the caller can echo it into the in-
|
|
31
|
+
* memory transcript without a re-read. Throws on store error so the
|
|
32
|
+
* caller surfaces the failure inline.
|
|
33
|
+
*/
|
|
34
|
+
export async function appendCompactBoundary(input) {
|
|
35
|
+
const ts = (input.now ?? (() => Date.now()))();
|
|
36
|
+
const payload = {
|
|
37
|
+
version: 1,
|
|
38
|
+
trigger: input.trigger,
|
|
39
|
+
summary: input.summary,
|
|
40
|
+
summaryTokenCount: input.summaryTokenCount,
|
|
41
|
+
summaryTurnsBefore: input.summaryTurnsBefore,
|
|
42
|
+
keptTailTurns: input.keptTailTurns,
|
|
43
|
+
coversUntilOffset: input.coversUntilOffset,
|
|
44
|
+
};
|
|
45
|
+
const event = {
|
|
46
|
+
t: ts,
|
|
47
|
+
kind: 'compaction',
|
|
48
|
+
payload,
|
|
49
|
+
};
|
|
50
|
+
await input.store.appendEvent(event);
|
|
51
|
+
return event;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Apply replay masking to a chronological event list. Given the full
|
|
55
|
+
* ordered events.jsonl content, return only the events the caller
|
|
56
|
+
* should render: every event AFTER the latest `compaction` boundary,
|
|
57
|
+
* plus the boundary itself (so the renderer can show the banner +
|
|
58
|
+
* summary), and the K kept-tail events that landed BEFORE the boundary
|
|
59
|
+
* but were preserved per the marker's `keptTailTurns`.
|
|
60
|
+
*
|
|
61
|
+
* Mask logic:
|
|
62
|
+
* 1. Walk events. Find the LATEST boundary by offset.
|
|
63
|
+
* 2. Index 0 .. coversUntilOffset-1 are masked, EXCEPT the last
|
|
64
|
+
* `keptTailTurns` of that range (which are the verbatim tail).
|
|
65
|
+
* 3. The boundary event itself + everything after it stays.
|
|
66
|
+
*
|
|
67
|
+
* Why we expose this here (and not in session.ts): keeping the mask
|
|
68
|
+
* logic next to the writer means the wire format is owned by one
|
|
69
|
+
* module. session.ts depends on this; this depends on nothing in
|
|
70
|
+
* session.ts. Unidirectional.
|
|
71
|
+
*/
|
|
72
|
+
export function applyCompactMask(events) {
|
|
73
|
+
// Find latest compaction event.
|
|
74
|
+
let latestIdx = -1;
|
|
75
|
+
let latestPayload = null;
|
|
76
|
+
for (let i = events.length - 1; i >= 0; i -= 1) {
|
|
77
|
+
const ev = events[i];
|
|
78
|
+
if (isCompactBoundary(ev)) {
|
|
79
|
+
latestIdx = i;
|
|
80
|
+
latestPayload = ev.payload;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (latestIdx === -1 || latestPayload === null) {
|
|
85
|
+
return events;
|
|
86
|
+
}
|
|
87
|
+
// `coversUntilOffset` is the count of events that existed in the
|
|
88
|
+
// store immediately before the marker append. Events 0 ..
|
|
89
|
+
// coversUntilOffset-1 are summarised; events keptTailTurns of them
|
|
90
|
+
// are surfaced anyway as the verbatim tail.
|
|
91
|
+
const cap = Math.max(0, Math.min(latestPayload.coversUntilOffset, latestIdx));
|
|
92
|
+
const tailKeepCount = Math.max(0, Math.min(latestPayload.keptTailTurns, cap));
|
|
93
|
+
// Take the LAST tailKeepCount events from the masked range, but only
|
|
94
|
+
// those that represent renderable turns (user/persona/system).
|
|
95
|
+
// Boundary markers and tool stream events are NOT counted as turns
|
|
96
|
+
// for the tail-keep window — using them would let the keptTailTurns
|
|
97
|
+
// budget be consumed by infra events and the operator would lose
|
|
98
|
+
// the last K real turns. The spec is about "last K human-visible
|
|
99
|
+
// turns", not "last K events".
|
|
100
|
+
const tailSlice = [];
|
|
101
|
+
for (let i = cap - 1; i >= 0 && tailSlice.length < tailKeepCount; i -= 1) {
|
|
102
|
+
const ev = events[i];
|
|
103
|
+
if (ev.kind === 'user' || ev.kind === 'persona' || ev.kind === 'system') {
|
|
104
|
+
tailSlice.push(ev);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
tailSlice.reverse();
|
|
108
|
+
// After the marker: everything that landed AFTER the boundary
|
|
109
|
+
// append. These are post-compaction events the user has not yet
|
|
110
|
+
// seen folded into a summary; they pass through verbatim.
|
|
111
|
+
const afterMarker = events.slice(latestIdx + 1);
|
|
112
|
+
const markerEvent = events[latestIdx];
|
|
113
|
+
return [...tailSlice, markerEvent, ...afterMarker];
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=buffer-rewriter.js.map
|