@pugi/cli 0.1.0-beta.99 → 1.0.0-alpha.10
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 -195
- 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,572 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Layer D AST-aware diff applicator — β7 .
|
|
3
|
-
*
|
|
4
|
-
* Replaces the stub. Implements structural edits that cannot be
|
|
5
|
-
* expressed safely as text-level Layer A/B/C diffs:
|
|
6
|
-
*
|
|
7
|
-
* - `rename_symbol` — rename every reference to a symbol inside a
|
|
8
|
-
* single file, respecting language identifier
|
|
9
|
-
* boundaries. Cross-file rename is handled by
|
|
10
|
-
* the engine loop dispatching one Layer D edit
|
|
11
|
-
* per affected file (see multi_edit tool).
|
|
12
|
-
* - `add_import` — add an `import`/`use`/`from` statement at
|
|
13
|
-
* the canonical location for the file's
|
|
14
|
-
* language. Idempotent: re-adding an existing
|
|
15
|
-
* import is a no-op success.
|
|
16
|
-
* - `remove_import` — remove an `import`/`use`/`from` statement
|
|
17
|
-
* when present; no-op success when absent.
|
|
18
|
-
* - `extract_function` — currently surfaces `not_supported` (real
|
|
19
|
-
* tree-sitter integration deferred to β8).
|
|
20
|
-
* - `inline_variable` — same; deferred to β8.
|
|
21
|
-
*
|
|
22
|
-
* Why not tree-sitter (yet):
|
|
23
|
-
*
|
|
24
|
-
* The + posture for `apps/pugi-cli` keeps the dep tree intentionally
|
|
25
|
-
* lean (zod + ink + react + undici + tar). Pulling
|
|
26
|
-
* `tree-sitter` + per-language grammars (5 native binding packages,
|
|
27
|
-
* each ~5-15 MiB compiled) would balloon install size from ~80 MiB to
|
|
28
|
-
* ~250 MiB and require native rebuild on every Node major bump. We
|
|
29
|
-
* ship the operations we can do CORRECTLY with a language-aware
|
|
30
|
-
* regex+lexer approach today (rename/add_import/remove_import on
|
|
31
|
-
* identifier boundaries — see `identifierBoundaryReplace` below), and
|
|
32
|
-
* keep the deferred operations behind a structured `not_supported`
|
|
33
|
-
* reason instead of a bogus tree-sitter dep.
|
|
34
|
-
*
|
|
35
|
-
* The grammar of identifiers + import statements is small enough across
|
|
36
|
-
* TS/JS/Python/Go/Rust that the regex approach (with language-aware
|
|
37
|
-
* boundary characters) catches every realistic in-file rename target
|
|
38
|
-
* without false positives — string literals and comments are skipped
|
|
39
|
-
* by a tiny per-language tokenizer. The approach matches what most
|
|
40
|
-
* "find-and-replace symbol" IDEs do for the same operation when no
|
|
41
|
-
* LSP server is available.
|
|
42
|
-
*
|
|
43
|
-
* Security: every operation routes through `applySecurityGate`. Atomic
|
|
44
|
-
* writes via `atomicWrite` (same pattern as Layer A).
|
|
45
|
-
*
|
|
46
|
-
* Spec source: `docs/research/2026-05-21-pugi-cli-architecture.md` §4.4
|
|
47
|
-
* and `docs/research/2026-05-26-pugi-cli-consolidated-sprint-plan.md` β7.
|
|
48
|
-
*/
|
|
49
|
-
import { existsSync, readFileSync, renameSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
50
|
-
import { extname } from 'node:path';
|
|
51
|
-
import { applySecurityGate } from './security-gate.js';
|
|
52
|
-
/**
|
|
53
|
-
* Sentinel error type the dispatcher recognises. Kept for back-compat
|
|
54
|
-
* with callers — never thrown by the new implementation; deferred
|
|
55
|
-
* operations now surface as structured `not_supported` results.
|
|
56
|
-
*/
|
|
57
|
-
export class LayerDDeferredError extends Error {
|
|
58
|
-
code = 'LAYER_D_DEFERRED';
|
|
59
|
-
operation;
|
|
60
|
-
constructor(operation) {
|
|
61
|
-
super(`Layer D operation ${operation} is not yet supported.`);
|
|
62
|
-
this.name = 'LayerDDeferredError';
|
|
63
|
-
this.operation = operation;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
export function detectLanguage(file) {
|
|
67
|
-
const ext = extname(file).toLowerCase();
|
|
68
|
-
if (ext === '.ts' || ext === '.tsx')
|
|
69
|
-
return 'ts';
|
|
70
|
-
if (ext === '.js' || ext === '.jsx' || ext === '.mjs' || ext === '.cjs')
|
|
71
|
-
return 'js';
|
|
72
|
-
if (ext === '.py' || ext === '.pyi')
|
|
73
|
-
return 'py';
|
|
74
|
-
if (ext === '.go')
|
|
75
|
-
return 'go';
|
|
76
|
-
if (ext === '.rs')
|
|
77
|
-
return 'rust';
|
|
78
|
-
return 'other';
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Apply a Layer D structural edit. Returns the standard `ApplyResult`
|
|
82
|
-
* shape so the dispatcher can treat all four layers uniformly.
|
|
83
|
-
*/
|
|
84
|
-
export async function applyLayerD(edit, opts) {
|
|
85
|
-
// SECURITY GATE — fail-fast before ANY filesystem read/write. Same
|
|
86
|
-
// chokepoint Layer A/B/C goes through.
|
|
87
|
-
let gateResult;
|
|
88
|
-
try {
|
|
89
|
-
gateResult = applySecurityGate(edit.file, { cwd: opts.cwd, toolName: 'layer-c' });
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
return {
|
|
93
|
-
ok: false,
|
|
94
|
-
bytesWritten: 0,
|
|
95
|
-
reason: 'write_error',
|
|
96
|
-
absPath: edit.file,
|
|
97
|
-
detail: error instanceof Error ? error.message : String(error),
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
if (!gateResult.ok) {
|
|
101
|
-
return {
|
|
102
|
-
ok: false,
|
|
103
|
-
bytesWritten: 0,
|
|
104
|
-
reason: gateResult.reason,
|
|
105
|
-
absPath: edit.file,
|
|
106
|
-
detail: gateResult.detail,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
const absPath = gateResult.absPath;
|
|
110
|
-
if (!existsSync(absPath)) {
|
|
111
|
-
return {
|
|
112
|
-
ok: false,
|
|
113
|
-
bytesWritten: 0,
|
|
114
|
-
reason: 'file_missing',
|
|
115
|
-
absPath,
|
|
116
|
-
detail: `file does not exist: ${edit.file}`,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
let body;
|
|
120
|
-
try {
|
|
121
|
-
body = readFileSync(absPath, 'utf8');
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
return {
|
|
125
|
-
ok: false,
|
|
126
|
-
bytesWritten: 0,
|
|
127
|
-
reason: 'write_error',
|
|
128
|
-
absPath,
|
|
129
|
-
detail: error instanceof Error ? error.message : String(error),
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
const lang = detectLanguage(edit.file);
|
|
133
|
-
switch (edit.operation) {
|
|
134
|
-
case 'rename_symbol':
|
|
135
|
-
return await renameSymbol(edit, body, absPath, lang, opts);
|
|
136
|
-
case 'add_import':
|
|
137
|
-
return await addImport(edit, body, absPath, lang, opts);
|
|
138
|
-
case 'remove_import':
|
|
139
|
-
return await removeImport(edit, body, absPath, lang, opts);
|
|
140
|
-
case 'extract_function':
|
|
141
|
-
case 'inline_variable':
|
|
142
|
-
return {
|
|
143
|
-
ok: false,
|
|
144
|
-
bytesWritten: 0,
|
|
145
|
-
reason: 'write_error',
|
|
146
|
-
absPath,
|
|
147
|
-
detail: `Layer D operation ${edit.operation} is not yet supported. ` +
|
|
148
|
-
`Use Layer A/B/C for the equivalent text edit, or wait for the ` +
|
|
149
|
-
`β8 tree-sitter integration.`,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
/* ------------------------------------------------------------------ */
|
|
154
|
-
/* rename_symbol */
|
|
155
|
-
/* ------------------------------------------------------------------ */
|
|
156
|
-
async function renameSymbol(edit, body, absPath, lang, opts) {
|
|
157
|
-
const params = parseRenameParams(edit.params);
|
|
158
|
-
if (!params) {
|
|
159
|
-
return {
|
|
160
|
-
ok: false,
|
|
161
|
-
bytesWritten: 0,
|
|
162
|
-
reason: 'write_error',
|
|
163
|
-
absPath,
|
|
164
|
-
detail: 'rename_symbol: params must be { from: string, to: string }',
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
if (!isValidIdentifier(params.from, lang) || !isValidIdentifier(params.to, lang)) {
|
|
168
|
-
return {
|
|
169
|
-
ok: false,
|
|
170
|
-
bytesWritten: 0,
|
|
171
|
-
reason: 'write_error',
|
|
172
|
-
absPath,
|
|
173
|
-
detail: `rename_symbol: identifier validation failed for language ${lang}. ` +
|
|
174
|
-
`Both 'from' and 'to' must be valid identifiers.`,
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
if (params.from === params.to) {
|
|
178
|
-
return {
|
|
179
|
-
ok: false,
|
|
180
|
-
bytesWritten: 0,
|
|
181
|
-
reason: 'identical_replacement',
|
|
182
|
-
absPath,
|
|
183
|
-
detail: 'rename_symbol: from and to are identical',
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
const { result, count } = identifierBoundaryReplace(body, params.from, params.to, lang);
|
|
187
|
-
if (count === 0) {
|
|
188
|
-
return {
|
|
189
|
-
ok: false,
|
|
190
|
-
bytesWritten: 0,
|
|
191
|
-
reason: 'no_match',
|
|
192
|
-
matchCount: 0,
|
|
193
|
-
absPath,
|
|
194
|
-
detail: `rename_symbol: no references to '${params.from}' found in ${edit.file}`,
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
if (opts.dryRun) {
|
|
198
|
-
return { ok: true, bytesWritten: 0, matchCount: count, absPath };
|
|
199
|
-
}
|
|
200
|
-
try {
|
|
201
|
-
atomicWrite(absPath, result);
|
|
202
|
-
}
|
|
203
|
-
catch (error) {
|
|
204
|
-
return {
|
|
205
|
-
ok: false,
|
|
206
|
-
bytesWritten: 0,
|
|
207
|
-
reason: 'write_error',
|
|
208
|
-
absPath,
|
|
209
|
-
detail: error instanceof Error ? error.message : String(error),
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
return {
|
|
213
|
-
ok: true,
|
|
214
|
-
bytesWritten: Buffer.byteLength(result, 'utf8'),
|
|
215
|
-
matchCount: count,
|
|
216
|
-
absPath,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
function parseRenameParams(params) {
|
|
220
|
-
const from = params['from'];
|
|
221
|
-
const to = params['to'];
|
|
222
|
-
if (typeof from !== 'string' || typeof to !== 'string')
|
|
223
|
-
return null;
|
|
224
|
-
if (from.length === 0 || to.length === 0)
|
|
225
|
-
return null;
|
|
226
|
-
return { from, to };
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Replace every standalone identifier occurrence of `from` with `to`.
|
|
230
|
-
* Identifier boundaries are language-aware: in Python `foo.bar` and
|
|
231
|
-
* `foo_bar` are distinct identifiers; in Rust `foo::bar` likewise.
|
|
232
|
-
* Tokens inside string literals and comments are skipped.
|
|
233
|
-
*
|
|
234
|
-
* Returns both the rewritten body and the replacement count so the
|
|
235
|
-
* dispatcher can report `matchCount`.
|
|
236
|
-
*/
|
|
237
|
-
export function identifierBoundaryReplace(body, from, to, lang) {
|
|
238
|
-
const tokens = tokenize(body, lang);
|
|
239
|
-
const parts = [];
|
|
240
|
-
let count = 0;
|
|
241
|
-
for (const tok of tokens) {
|
|
242
|
-
if (tok.kind === 'ident' && tok.text === from) {
|
|
243
|
-
parts.push(to);
|
|
244
|
-
count += 1;
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
parts.push(tok.text);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return { result: parts.join(''), count };
|
|
251
|
-
}
|
|
252
|
-
/* ------------------------------------------------------------------ */
|
|
253
|
-
/* add_import / remove_import */
|
|
254
|
-
/* ------------------------------------------------------------------ */
|
|
255
|
-
async function addImport(edit, body, absPath, lang, opts) {
|
|
256
|
-
const statement = parseImportStatement(edit.params);
|
|
257
|
-
if (statement === null) {
|
|
258
|
-
return {
|
|
259
|
-
ok: false,
|
|
260
|
-
bytesWritten: 0,
|
|
261
|
-
reason: 'write_error',
|
|
262
|
-
absPath,
|
|
263
|
-
detail: 'add_import: params must be { statement: string } (single-line)',
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
// Idempotency — a verbatim line match counts as already-applied.
|
|
267
|
-
const lines = body.split('\n');
|
|
268
|
-
if (lines.some((line) => line === statement)) {
|
|
269
|
-
if (opts.dryRun) {
|
|
270
|
-
return { ok: true, bytesWritten: 0, absPath, matchCount: 1 };
|
|
271
|
-
}
|
|
272
|
-
return { ok: true, bytesWritten: 0, absPath, matchCount: 1 };
|
|
273
|
-
}
|
|
274
|
-
const insertAt = findImportInsertIndex(lines, lang);
|
|
275
|
-
const next = [...lines.slice(0, insertAt), statement, ...lines.slice(insertAt)];
|
|
276
|
-
const result = next.join('\n');
|
|
277
|
-
if (opts.dryRun) {
|
|
278
|
-
return { ok: true, bytesWritten: 0, absPath, matchCount: 1 };
|
|
279
|
-
}
|
|
280
|
-
try {
|
|
281
|
-
atomicWrite(absPath, result);
|
|
282
|
-
}
|
|
283
|
-
catch (error) {
|
|
284
|
-
return {
|
|
285
|
-
ok: false,
|
|
286
|
-
bytesWritten: 0,
|
|
287
|
-
reason: 'write_error',
|
|
288
|
-
absPath,
|
|
289
|
-
detail: error instanceof Error ? error.message : String(error),
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
return {
|
|
293
|
-
ok: true,
|
|
294
|
-
bytesWritten: Buffer.byteLength(result, 'utf8'),
|
|
295
|
-
absPath,
|
|
296
|
-
matchCount: 1,
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
async function removeImport(edit, body, absPath, _lang, opts) {
|
|
300
|
-
const statement = parseImportStatement(edit.params);
|
|
301
|
-
if (statement === null) {
|
|
302
|
-
return {
|
|
303
|
-
ok: false,
|
|
304
|
-
bytesWritten: 0,
|
|
305
|
-
reason: 'write_error',
|
|
306
|
-
absPath,
|
|
307
|
-
detail: 'remove_import: params must be { statement: string } (single-line)',
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
const lines = body.split('\n');
|
|
311
|
-
const filtered = lines.filter((line) => line !== statement);
|
|
312
|
-
if (filtered.length === lines.length) {
|
|
313
|
-
// No-op success — idempotent removal.
|
|
314
|
-
return { ok: true, bytesWritten: 0, absPath, matchCount: 0 };
|
|
315
|
-
}
|
|
316
|
-
const result = filtered.join('\n');
|
|
317
|
-
if (opts.dryRun) {
|
|
318
|
-
return {
|
|
319
|
-
ok: true,
|
|
320
|
-
bytesWritten: 0,
|
|
321
|
-
absPath,
|
|
322
|
-
matchCount: lines.length - filtered.length,
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
try {
|
|
326
|
-
atomicWrite(absPath, result);
|
|
327
|
-
}
|
|
328
|
-
catch (error) {
|
|
329
|
-
return {
|
|
330
|
-
ok: false,
|
|
331
|
-
bytesWritten: 0,
|
|
332
|
-
reason: 'write_error',
|
|
333
|
-
absPath,
|
|
334
|
-
detail: error instanceof Error ? error.message : String(error),
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
return {
|
|
338
|
-
ok: true,
|
|
339
|
-
bytesWritten: Buffer.byteLength(result, 'utf8'),
|
|
340
|
-
absPath,
|
|
341
|
-
matchCount: lines.length - filtered.length,
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
function parseImportStatement(params) {
|
|
345
|
-
const statement = params['statement'];
|
|
346
|
-
if (typeof statement !== 'string')
|
|
347
|
-
return null;
|
|
348
|
-
if (statement.length === 0)
|
|
349
|
-
return null;
|
|
350
|
-
// Single-line invariant: imports SHOULD fit one line. Multi-line
|
|
351
|
-
// import payloads are out of scope (use Layer A/B with explicit
|
|
352
|
-
// anchors instead).
|
|
353
|
-
if (statement.includes('\n'))
|
|
354
|
-
return null;
|
|
355
|
-
return statement;
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Pick the line index at which a new import should land. The heuristic
|
|
359
|
-
* is conservative: after every leading shebang / module-doc comment /
|
|
360
|
-
* existing import line, before the first non-import non-comment line.
|
|
361
|
-
*
|
|
362
|
-
* Per-language nuance is intentionally light — every supported language
|
|
363
|
-
* accepts an import anywhere at file scope; we aim for "next to the
|
|
364
|
-
* other imports" which is what every formatter expects.
|
|
365
|
-
*/
|
|
366
|
-
export function findImportInsertIndex(lines, _lang) {
|
|
367
|
-
// Skip leading shebang.
|
|
368
|
-
let i = 0;
|
|
369
|
-
if (i < lines.length && lines[i].startsWith('#!'))
|
|
370
|
-
i += 1;
|
|
371
|
-
// Skip leading single-line comments / blank lines / module docstring
|
|
372
|
-
// openers. Conservative — never crosses an `import` block boundary
|
|
373
|
-
// because the import check below catches them.
|
|
374
|
-
while (i < lines.length) {
|
|
375
|
-
const line = lines[i];
|
|
376
|
-
const trimmed = line.trim();
|
|
377
|
-
if (trimmed === '') {
|
|
378
|
-
i += 1;
|
|
379
|
-
continue;
|
|
380
|
-
}
|
|
381
|
-
if (isCommentLine(trimmed)) {
|
|
382
|
-
i += 1;
|
|
383
|
-
continue;
|
|
384
|
-
}
|
|
385
|
-
break;
|
|
386
|
-
}
|
|
387
|
-
// Walk past existing import block. We stop at the first non-import
|
|
388
|
-
// non-comment line so the new statement lands tail-of-imports.
|
|
389
|
-
while (i < lines.length) {
|
|
390
|
-
const line = lines[i];
|
|
391
|
-
const trimmed = line.trim();
|
|
392
|
-
if (trimmed === '' || isCommentLine(trimmed) || isImportLine(trimmed)) {
|
|
393
|
-
i += 1;
|
|
394
|
-
continue;
|
|
395
|
-
}
|
|
396
|
-
break;
|
|
397
|
-
}
|
|
398
|
-
// Trim trailing blank lines from the insertion index so the new
|
|
399
|
-
// import lands directly under the existing imports rather than after
|
|
400
|
-
// a stray gap.
|
|
401
|
-
while (i > 0 && lines[i - 1].trim() === '')
|
|
402
|
-
i -= 1;
|
|
403
|
-
return i;
|
|
404
|
-
}
|
|
405
|
-
function isCommentLine(trimmed) {
|
|
406
|
-
return (trimmed.startsWith('//') ||
|
|
407
|
-
trimmed.startsWith('#') ||
|
|
408
|
-
trimmed.startsWith('/*') ||
|
|
409
|
-
trimmed.startsWith('*') ||
|
|
410
|
-
trimmed.startsWith('"""') ||
|
|
411
|
-
trimmed.startsWith("'''"));
|
|
412
|
-
}
|
|
413
|
-
function isImportLine(trimmed) {
|
|
414
|
-
return (trimmed.startsWith('import ') ||
|
|
415
|
-
trimmed.startsWith('from ') ||
|
|
416
|
-
trimmed.startsWith('use ') ||
|
|
417
|
-
trimmed.startsWith('extern crate ') ||
|
|
418
|
-
trimmed.startsWith('const ') && trimmed.includes('require(') ||
|
|
419
|
-
trimmed.startsWith('require ') ||
|
|
420
|
-
trimmed.startsWith('package '));
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Tiny tokenizer that splits a source body into identifier tokens vs.
|
|
424
|
-
* everything else. Skips string-literal interiors and comments so the
|
|
425
|
-
* rename pass never rewrites a string mention of the symbol.
|
|
426
|
-
*
|
|
427
|
-
* Per-language config:
|
|
428
|
-
* - line comment prefix
|
|
429
|
-
* - block comment delimiters
|
|
430
|
-
* - string literal openers (with backslash-escape awareness)
|
|
431
|
-
* - triple-quoted strings (Python)
|
|
432
|
-
* - identifier character set
|
|
433
|
-
*
|
|
434
|
-
* The tokenizer is character-stream linear; complexity O(n).
|
|
435
|
-
*/
|
|
436
|
-
export function tokenize(src, lang) {
|
|
437
|
-
const out = [];
|
|
438
|
-
let buf = '';
|
|
439
|
-
let i = 0;
|
|
440
|
-
const flushOther = () => {
|
|
441
|
-
if (buf.length > 0) {
|
|
442
|
-
out.push({ kind: 'other', text: buf });
|
|
443
|
-
buf = '';
|
|
444
|
-
}
|
|
445
|
-
};
|
|
446
|
-
const lineComment = lang === 'py' ? '#' : '//';
|
|
447
|
-
const tripleQuote = lang === 'py';
|
|
448
|
-
while (i < src.length) {
|
|
449
|
-
const ch = src[i];
|
|
450
|
-
const next = src[i + 1] ?? '';
|
|
451
|
-
// Line comment.
|
|
452
|
-
if (ch === lineComment[0] && (lineComment.length === 1 || next === lineComment[1])) {
|
|
453
|
-
flushOther();
|
|
454
|
-
const start = i;
|
|
455
|
-
while (i < src.length && src[i] !== '\n')
|
|
456
|
-
i += 1;
|
|
457
|
-
out.push({ kind: 'other', text: src.slice(start, i) });
|
|
458
|
-
continue;
|
|
459
|
-
}
|
|
460
|
-
// C-style block comment (TS/JS/Go/Rust). Python uses """ instead.
|
|
461
|
-
if (lang !== 'py' && ch === '/' && next === '*') {
|
|
462
|
-
flushOther();
|
|
463
|
-
const start = i;
|
|
464
|
-
i += 2;
|
|
465
|
-
while (i < src.length - 1 && !(src[i] === '*' && src[i + 1] === '/'))
|
|
466
|
-
i += 1;
|
|
467
|
-
i = Math.min(i + 2, src.length);
|
|
468
|
-
out.push({ kind: 'other', text: src.slice(start, i) });
|
|
469
|
-
continue;
|
|
470
|
-
}
|
|
471
|
-
// Triple-quoted string (Python).
|
|
472
|
-
if (tripleQuote && (ch === '"' || ch === "'") && next === ch && src[i + 2] === ch) {
|
|
473
|
-
flushOther();
|
|
474
|
-
const quote = ch;
|
|
475
|
-
const start = i;
|
|
476
|
-
i += 3;
|
|
477
|
-
while (i < src.length - 2 &&
|
|
478
|
-
!(src[i] === quote && src[i + 1] === quote && src[i + 2] === quote)) {
|
|
479
|
-
i += 1;
|
|
480
|
-
}
|
|
481
|
-
i = Math.min(i + 3, src.length);
|
|
482
|
-
out.push({ kind: 'other', text: src.slice(start, i) });
|
|
483
|
-
continue;
|
|
484
|
-
}
|
|
485
|
-
// Regular string literal.
|
|
486
|
-
if (ch === '"' || ch === "'" || (lang !== 'py' && ch === '`')) {
|
|
487
|
-
flushOther();
|
|
488
|
-
const quote = ch;
|
|
489
|
-
const start = i;
|
|
490
|
-
i += 1;
|
|
491
|
-
while (i < src.length) {
|
|
492
|
-
if (src[i] === '\\') {
|
|
493
|
-
i += 2;
|
|
494
|
-
continue;
|
|
495
|
-
}
|
|
496
|
-
if (src[i] === quote) {
|
|
497
|
-
i += 1;
|
|
498
|
-
break;
|
|
499
|
-
}
|
|
500
|
-
i += 1;
|
|
501
|
-
}
|
|
502
|
-
out.push({ kind: 'other', text: src.slice(start, i) });
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
// Identifier — sequence of identifier characters.
|
|
506
|
-
if (isIdentStart(ch)) {
|
|
507
|
-
flushOther();
|
|
508
|
-
const start = i;
|
|
509
|
-
while (i < src.length && isIdentCont(src[i]))
|
|
510
|
-
i += 1;
|
|
511
|
-
out.push({ kind: 'ident', text: src.slice(start, i) });
|
|
512
|
-
continue;
|
|
513
|
-
}
|
|
514
|
-
buf += ch;
|
|
515
|
-
i += 1;
|
|
516
|
-
}
|
|
517
|
-
flushOther();
|
|
518
|
-
return out;
|
|
519
|
-
}
|
|
520
|
-
function isIdentStart(ch) {
|
|
521
|
-
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch === '_' || ch === '$';
|
|
522
|
-
}
|
|
523
|
-
function isIdentCont(ch) {
|
|
524
|
-
return isIdentStart(ch) || (ch >= '0' && ch <= '9');
|
|
525
|
-
}
|
|
526
|
-
export function isValidIdentifier(name, lang) {
|
|
527
|
-
if (name.length === 0)
|
|
528
|
-
return false;
|
|
529
|
-
if (!isIdentStart(name[0]))
|
|
530
|
-
return false;
|
|
531
|
-
for (let i = 1; i < name.length; i += 1) {
|
|
532
|
-
if (!isIdentCont(name[i]))
|
|
533
|
-
return false;
|
|
534
|
-
}
|
|
535
|
-
// Per-language reserved-word check is intentionally light — the dispatcher
|
|
536
|
-
// is the trust boundary; the operator (or model) supplies the new name
|
|
537
|
-
// and is responsible for it not clashing with a keyword. Catching the
|
|
538
|
-
// obvious cases here would only mask a bigger upstream bug.
|
|
539
|
-
// R7 P2 (Codex): a future refinement could load a per-language
|
|
540
|
-
// reserved-word list from `framework_*` RAG; tracked under β8.
|
|
541
|
-
return name.length <= 128;
|
|
542
|
-
}
|
|
543
|
-
/**
|
|
544
|
-
* Atomic write helper — mirrors Layer A's pattern (writeFileSync to
|
|
545
|
-
* tmp + rename). See `layer-a-apply.ts::atomicWrite` for the rationale.
|
|
546
|
-
*/
|
|
547
|
-
function atomicWrite(absPath, contents) {
|
|
548
|
-
const suffix = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
549
|
-
const tmp = `${absPath}.pugi-tmp-${suffix}`;
|
|
550
|
-
try {
|
|
551
|
-
writeFileSync(tmp, contents, { encoding: 'utf8', mode: 0o600 });
|
|
552
|
-
renameSync(tmp, absPath);
|
|
553
|
-
}
|
|
554
|
-
catch (error) {
|
|
555
|
-
try {
|
|
556
|
-
unlinkSync(tmp);
|
|
557
|
-
}
|
|
558
|
-
catch {
|
|
559
|
-
// tmp file may not exist if writeFileSync itself failed.
|
|
560
|
-
}
|
|
561
|
-
throw error;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
/** Test-only surface for the spec suite. */
|
|
565
|
-
export const __test__ = {
|
|
566
|
-
tokenize,
|
|
567
|
-
identifierBoundaryReplace,
|
|
568
|
-
findImportInsertIndex,
|
|
569
|
-
isValidIdentifier,
|
|
570
|
-
detectLanguage,
|
|
571
|
-
};
|
|
572
|
-
//# sourceMappingURL=layer-d-ast.js.map
|