@pugi/cli 0.1.0-beta.99 → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +11 -191
- package/bin/pugi +8 -0
- package/package.json +15 -71
- package/postinstall.mjs +31 -0
- package/CHANGELOG.md +0 -132
- package/THIRD_PARTY_NOTICES.md +0 -40
- package/assets/pugi-mascot.ansi +0 -16
- package/assets/pugi-prozr2-mascot.ansi +0 -9
- package/bin/run.js +0 -34
- package/dist/commands/deploy.js +0 -439
- package/dist/commands/flatten.js +0 -191
- package/dist/commands/jobs-watch.js +0 -201
- package/dist/commands/jobs.js +0 -260
- package/dist/commands/retro.js +0 -210
- package/dist/commands/smoke.js +0 -133
- package/dist/core/agent-progress/cleanup.js +0 -134
- package/dist/core/agent-progress/schema.js +0 -144
- package/dist/core/agent-progress/writer.js +0 -101
- package/dist/core/agents/adaptive-router.js +0 -330
- package/dist/core/agents/loader.js +0 -104
- package/dist/core/agents/query-decomposer.js +0 -297
- package/dist/core/agents/registry.js +0 -69
- package/dist/core/approvals/shortcut-resolver.js +0 -98
- package/dist/core/artifact-chain/dispatcher.js +0 -148
- package/dist/core/artifact-chain/exporter.js +0 -164
- package/dist/core/artifact-chain/state.js +0 -243
- package/dist/core/artifact-chain/steps.js +0 -169
- package/dist/core/ask-user/question.js +0 -92
- package/dist/core/audit/audit-trail.js +0 -275
- package/dist/core/auth/ensure-authenticated.js +0 -129
- package/dist/core/auth/env-provider.js +0 -238
- package/dist/core/auto-open-browser.js +0 -128
- package/dist/core/auto-update/channels.js +0 -122
- package/dist/core/auto-update/checker.js +0 -241
- package/dist/core/auto-update/state.js +0 -235
- package/dist/core/bare-mode/index.js +0 -107
- package/dist/core/bash/redirect.js +0 -281
- package/dist/core/bash-classifier.js +0 -1397
- package/dist/core/checkpoint/resumer.js +0 -149
- package/dist/core/checkpoint/rewinder.js +0 -291
- package/dist/core/checkpoints/shadow-git.js +0 -670
- package/dist/core/citations/parser.js +0 -109
- package/dist/core/classifier/yolo-classifier.js +0 -88
- package/dist/core/clipboard.js +0 -70
- package/dist/core/codegraph/decision-store.js +0 -248
- package/dist/core/codegraph/detect-repo.js +0 -459
- package/dist/core/codegraph/install.js +0 -134
- package/dist/core/codegraph/offer-hook.js +0 -220
- package/dist/core/compact/auto-trigger.js +0 -96
- package/dist/core/compact/buffer-rewriter.js +0 -115
- package/dist/core/compact/summarizer.js +0 -208
- package/dist/core/compact/token-counter.js +0 -108
- package/dist/core/consensus/anvil-fanout.js +0 -276
- package/dist/core/consensus/diff-capture.js +0 -491
- package/dist/core/consensus/rubric.js +0 -233
- package/dist/core/context/builder.js +0 -114
- package/dist/core/context/compaction-events.js +0 -99
- package/dist/core/context/compaction.js +0 -602
- package/dist/core/context/index.js +0 -28
- package/dist/core/context/invariants.js +0 -250
- package/dist/core/context/markdown-loader.js +0 -288
- package/dist/core/context/markdown-traverse.js +0 -255
- package/dist/core/context/pugiignore.js +0 -316
- package/dist/core/context/repo-skeleton.js +0 -533
- package/dist/core/context/tool-eviction.js +0 -55
- package/dist/core/context/watcher.js +0 -342
- package/dist/core/context/working-set.js +0 -165
- package/dist/core/coordinator/agent-tools.js +0 -77
- package/dist/core/coordinator/agent-toolset.js +0 -65
- package/dist/core/coordinator/fsm.js +0 -73
- package/dist/core/coordinator/mode-fsm.js +0 -70
- package/dist/core/cost/rate-card.js +0 -129
- package/dist/core/cost/tracker.js +0 -221
- package/dist/core/credentials.js +0 -355
- package/dist/core/cron/scheduler.js +0 -138
- package/dist/core/denial-tracking/index.js +0 -8
- package/dist/core/denial-tracking/state.js +0 -264
- package/dist/core/diagnostics/probe-runner.js +0 -93
- package/dist/core/diagnostics/probes/api.js +0 -46
- package/dist/core/diagnostics/probes/auth.js +0 -93
- package/dist/core/diagnostics/probes/bare-mode.js +0 -42
- package/dist/core/diagnostics/probes/cli-version.js +0 -127
- package/dist/core/diagnostics/probes/config.js +0 -72
- package/dist/core/diagnostics/probes/denial-tracking.js +0 -57
- package/dist/core/diagnostics/probes/disk.js +0 -81
- package/dist/core/diagnostics/probes/engine-live.js +0 -46
- package/dist/core/diagnostics/probes/git.js +0 -65
- package/dist/core/diagnostics/probes/hooks.js +0 -118
- package/dist/core/diagnostics/probes/mcp.js +0 -75
- package/dist/core/diagnostics/probes/node.js +0 -59
- package/dist/core/diagnostics/probes/pnpm.js +0 -36
- package/dist/core/diagnostics/probes/pugi-md.js +0 -89
- package/dist/core/diagnostics/probes/sandbox.js +0 -72
- package/dist/core/diagnostics/probes/session.js +0 -74
- package/dist/core/diagnostics/probes/status-snapshot.js +0 -488
- package/dist/core/diagnostics/probes/workspace.js +0 -63
- package/dist/core/diagnostics/types.js +0 -70
- package/dist/core/dispatch/cache-cleanup.js +0 -197
- package/dist/core/dispatch/cache-handoff.js +0 -295
- package/dist/core/edits/apply-patch-layer-e.js +0 -189
- package/dist/core/edits/dispatch.js +0 -511
- package/dist/core/edits/format-detector.js +0 -260
- package/dist/core/edits/format-matrix.js +0 -26
- package/dist/core/edits/fuzzy-ladder.js +0 -650
- package/dist/core/edits/index.js +0 -19
- package/dist/core/edits/journal.js +0 -199
- package/dist/core/edits/layer-a-apply.js +0 -217
- package/dist/core/edits/layer-a-fuzzy-apply.js +0 -198
- package/dist/core/edits/layer-b-apply.js +0 -211
- package/dist/core/edits/layer-c-apply.js +0 -160
- package/dist/core/edits/layer-d-ast.js +0 -572
- package/dist/core/edits/marker-parser.js +0 -401
- package/dist/core/edits/security-gate.js +0 -223
- package/dist/core/edits/verify-hook.js +0 -273
- package/dist/core/edits/worktree.js +0 -322
- package/dist/core/engine/adapter-runner.js +0 -8
- package/dist/core/engine/anvil-client.js +0 -344
- package/dist/core/engine/auto-compact.js +0 -179
- package/dist/core/engine/budgets.js +0 -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,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistent REPL session store — Sprint .
|
|
3
|
-
*
|
|
4
|
-
* Public types consumed by the REPL session module + the `pugi sessions`
|
|
5
|
-
* / `pugi resume` dispatchers. Wire format is stable:
|
|
6
|
-
*
|
|
7
|
-
* - `SessionRow` mirrors the SQLite `sessions` table one-to-one and is
|
|
8
|
-
* also the JSON shape returned by `pugi sessions --json`. Field names
|
|
9
|
-
* are camelCase (PascalCase types, camelCase fields per CLAUDE.md
|
|
10
|
-
* conventions). The SQL columns themselves stay snake_case because
|
|
11
|
-
* they originate from raw SQL.
|
|
12
|
-
*
|
|
13
|
-
* - `SessionEvent` is the on-disk shape of one line in
|
|
14
|
-
* `events.<n>.jsonl`. `kind` is a closed union; `payload` is an
|
|
15
|
-
* opaque JSON value so the producer can attach whatever fields the
|
|
16
|
-
* event type requires without forcing the store to change.
|
|
17
|
-
*
|
|
18
|
-
* - `SessionListOptions` / `SessionLoadEventsOptions` /
|
|
19
|
-
* `SessionSearchOptions` are inputs the store accepts. Defaults are
|
|
20
|
-
* spec'd inline so the test plan can pin them without reading the
|
|
21
|
-
* implementation.
|
|
22
|
-
*
|
|
23
|
-
* The blob store + `pugi undo` + named checkpoints are follow-ups
|
|
24
|
-
* — out of scope for THIS PR per spec. The types here intentionally do
|
|
25
|
-
* NOT model blob refs so a future blob-store landing can extend without
|
|
26
|
-
* a wire break.
|
|
27
|
-
*/
|
|
28
|
-
/**
|
|
29
|
-
* Concrete shape of the lock detection error so the caller can branch
|
|
30
|
-
* on `error.code === 'EBUSY_SESSION_LOCK'` rather than parsing the
|
|
31
|
-
* message. The store is the only thrower of this error.
|
|
32
|
-
*/
|
|
33
|
-
export class SessionLockBusyError extends Error {
|
|
34
|
-
code = 'EBUSY_SESSION_LOCK';
|
|
35
|
-
holderPid;
|
|
36
|
-
lockPath;
|
|
37
|
-
constructor(holderPid, lockPath) {
|
|
38
|
-
super(`Another pugi process (pid ${holderPid}) holds the session lock at ${lockPath}.`);
|
|
39
|
-
this.name = 'SessionLockBusyError';
|
|
40
|
-
this.holderPid = holderPid;
|
|
41
|
-
this.lockPath = lockPath;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
//# sourceMappingURL=types.js.map
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UUID v7 generator — Sprint .
|
|
3
|
-
*
|
|
4
|
-
* uuid v7 (RFC 9562 draft) is a time-sortable 128-bit identifier whose
|
|
5
|
-
* first 48 bits are the unix-epoch milliseconds, the next 4 bits are
|
|
6
|
-
* the version (0b0111), the next 12 bits are sub-millisecond random
|
|
7
|
-
* entropy, the next 2 bits are the IETF variant (0b10), and the last
|
|
8
|
-
* 62 bits are random.
|
|
9
|
-
*
|
|
10
|
-
* Why v7 and not v4 (random) or v6 (gregorian time):
|
|
11
|
-
*
|
|
12
|
-
* - The session id IS the primary key of the SQLite table. We want
|
|
13
|
-
* inserts to land at the end of the b-tree to keep page fanout
|
|
14
|
-
* small. v4 fragments the tree (uniformly random keys); v7 sorts
|
|
15
|
-
* in time order so inserts are append-only.
|
|
16
|
-
* - `pugi sessions` sorts by `updated_at DESC` for display, but the
|
|
17
|
-
* pagination cursor uses the session id directly — a v7 id IS the
|
|
18
|
-
* creation timestamp, so the cursor is a single column compare
|
|
19
|
-
* instead of (updated_at, id) tuple.
|
|
20
|
-
* - Operators see ids in `/resume` picker; v7 prefix is monotonically
|
|
21
|
-
* increasing so the most recent session lands at the bottom of an
|
|
22
|
-
* id sort, matching the human expectation of "newest last".
|
|
23
|
-
*
|
|
24
|
-
* Node 22 does not ship a v7 generator (`crypto.randomUUID()` is v4
|
|
25
|
-
* only). We implement it inline with `crypto.randomBytes(10)` for the
|
|
26
|
-
* entropy bits — 10 bytes covers the 12-bit random + 62-bit random
|
|
27
|
-
* fields with one syscall.
|
|
28
|
-
*
|
|
29
|
-
* Format: `xxxxxxxx-xxxx-7xxx-yxxx-xxxxxxxxxxxx` where `y` is 8/9/a/b.
|
|
30
|
-
*/
|
|
31
|
-
import { randomBytes } from 'node:crypto';
|
|
32
|
-
/**
|
|
33
|
-
* Mint a fresh uuid v7. The `now` parameter is injectable for tests so
|
|
34
|
-
* the generated id is deterministic when the test fixes the clock.
|
|
35
|
-
* Production callers pass `Date.now`.
|
|
36
|
-
*/
|
|
37
|
-
export function uuidV7(now = Date.now) {
|
|
38
|
-
const ms = Math.floor(now());
|
|
39
|
-
// 48-bit timestamp (6 bytes).
|
|
40
|
-
const tsHex = ms.toString(16).padStart(12, '0');
|
|
41
|
-
// 10 bytes of entropy: 12 random bits go into octet 6 (after the 4
|
|
42
|
-
// version bits), 2 variant bits go into octet 8 (high nibble 8/9/a/b),
|
|
43
|
-
// the remaining 62 bits fill octets 9..15.
|
|
44
|
-
const rand = randomBytes(10);
|
|
45
|
-
// Set version (high nibble of octet 6) to 7.
|
|
46
|
-
rand[0] = ((rand[0] ?? 0) & 0x0f) | 0x70;
|
|
47
|
-
// Set IETF variant (high two bits of octet 8) to 0b10.
|
|
48
|
-
rand[2] = ((rand[2] ?? 0) & 0x3f) | 0x80;
|
|
49
|
-
const hex = Array.from(rand, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
50
|
-
// Assemble: 8-4-4-4-12.
|
|
51
|
-
return (`${tsHex.slice(0, 8)}-${tsHex.slice(8, 12)}-${hex.slice(0, 4)}-`
|
|
52
|
-
+ `${hex.slice(4, 8)}-${hex.slice(8, 20)}`);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Extract the unix-ms timestamp from a uuid v7. Returns null when the
|
|
56
|
-
* input is not a v7 id (wrong version nibble, wrong shape). Used by
|
|
57
|
-
* `pugi sessions` to render "created N seconds ago" without reading
|
|
58
|
-
* the SQLite row.
|
|
59
|
-
*/
|
|
60
|
-
export function uuidV7Timestamp(id) {
|
|
61
|
-
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
|
|
62
|
-
.test(id)) {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
const hex = id.slice(0, 8) + id.slice(9, 13);
|
|
66
|
-
return Number.parseInt(hex, 16);
|
|
67
|
-
}
|
|
68
|
-
//# sourceMappingURL=uuid-v7.js.map
|
|
@@ -1,382 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PUGI-538b () — `<pugi-tool-route>` envelope parser.
|
|
3
|
-
*
|
|
4
|
-
* The admin-api Pugi coordinator persona emits an
|
|
5
|
-
* `<pugi-tool-route command="code|fix|build" persona="<slug>" brief="…"/>`
|
|
6
|
-
* envelope on her turn when the operator's brief requires workspace
|
|
7
|
-
* tool use (write/edit/read a file, run a script, install a package,
|
|
8
|
-
* build, test). The CLI consumer parses the envelope, strips it from
|
|
9
|
-
* operator-visible detail, and routes the brief through the local
|
|
10
|
-
* `NativePugiEngineAdapter` → `runEngineLoop` → `POST /api/pugi/engine`
|
|
11
|
-
* flow that already drives `pugi code/fix/build` end-to-end with real
|
|
12
|
-
* tool calls and atomic file writes.
|
|
13
|
-
*
|
|
14
|
-
* Without this envelope the REPL chat path is a single-shot text
|
|
15
|
-
* streamer: customer says "make tic-tac-toe", Pugi responds with a
|
|
16
|
-
* bash heredoc dump as prose, no file is written. (PUGI-538a)
|
|
17
|
-
* lays out the architecture; this parser is the CLI half of the bridge.
|
|
18
|
-
*
|
|
19
|
-
* # Grammar (self-closing form is preferred; paired form also accepted)
|
|
20
|
-
*
|
|
21
|
-
* <pugi-tool-route command="code" persona="dev" brief="One sentence…"/>
|
|
22
|
-
* <pugi-tool-route command="fix" persona="dev" brief="…"></pugi-tool-route>
|
|
23
|
-
*
|
|
24
|
-
* Attributes:
|
|
25
|
-
* - command (required) — exactly one of `code`, `fix`, `build`.
|
|
26
|
-
* - persona (optional) — Tier-1 persona slug hint; defaults to `dev`
|
|
27
|
-
* when omitted. The value `main` is rejected (the REPL
|
|
28
|
-
* coordinator IS Pugi already, routing back to herself
|
|
29
|
-
* would not change behaviour).
|
|
30
|
-
* - brief (required) — single-sentence operational brief,
|
|
31
|
-
* <= 400 chars after entity decoding.
|
|
32
|
-
*
|
|
33
|
-
* # Why a hand-rolled parser, not a generic XML library
|
|
34
|
-
*
|
|
35
|
-
* Same rationale as `ask.ts`: generic XML libraries (sax,
|
|
36
|
-
* fast-xml-parser, xmldoc) carry a large attack surface (external
|
|
37
|
-
* entity expansion, recursive blowup on malformed input, sloppy
|
|
38
|
-
* attribute handling) and require ~50 KB of runtime dependency. The
|
|
39
|
-
* persona-side grammar here is one tag with a closed three-attribute
|
|
40
|
-
* set, so a bounded tokenizer is both safer and smaller. The defences
|
|
41
|
-
* mirror ask.ts: closed entity allowlist, control-char strip, refusal
|
|
42
|
-
* on raw `&` outside `&` / `<` / `>` / `"` / `'`,
|
|
43
|
-
* refusal on nested tags inside attribute blob, hard span cap.
|
|
44
|
-
*
|
|
45
|
-
* # Buffering across streaming chunks
|
|
46
|
-
*
|
|
47
|
-
* The session calls `extractToolRouteTags(buffer)` on the accumulated
|
|
48
|
-
* `agent.step.detail` body. If the close tag (or self-close `/>`) has
|
|
49
|
-
* not arrived yet, the parser returns `{ tags: [], pendingOpenTag: true }`
|
|
50
|
-
* and the session waits for more chunks. This mirrors the
|
|
51
|
-
* `extractAskTags` / `extractPlanReviewTags` shape so `session.ts`
|
|
52
|
-
* routes the three envelope families through one buffer-and-strip
|
|
53
|
-
* machinery.
|
|
54
|
-
*/
|
|
55
|
-
/* ------------------------------------------------------------------ */
|
|
56
|
-
/* Bounded constants */
|
|
57
|
-
/* ------------------------------------------------------------------ */
|
|
58
|
-
/** Hard cap on the brief length after entity decoding. */
|
|
59
|
-
export const TOOL_ROUTE_MAX_BRIEF_LEN = 400;
|
|
60
|
-
/** Hard cap on the persona slug length. */
|
|
61
|
-
export const TOOL_ROUTE_MAX_PERSONA_LEN = 32;
|
|
62
|
-
/** Hard cap on the entire tag span. Long enough for full attrs + a
|
|
63
|
-
* worst-case 400-char brief plus closing form; defends against runaway
|
|
64
|
-
* payloads. */
|
|
65
|
-
const TAG_MAX_SPAN_BYTES = 4 * 1024;
|
|
66
|
-
/** Tag families exhaustively enumerated for the closed-attribute gate. */
|
|
67
|
-
const ALLOWED_ATTRS = new Set([
|
|
68
|
-
'command',
|
|
69
|
-
'persona',
|
|
70
|
-
'brief',
|
|
71
|
-
]);
|
|
72
|
-
/** Accepted `command` literals — locked to the engine adapter contract. */
|
|
73
|
-
const ALLOWED_COMMANDS = new Set(['code', 'fix', 'build']);
|
|
74
|
-
/** Refused personas. `main` would route Pugi back to herself; the engine
|
|
75
|
-
* adapter rejects the slug anyway, so we filter at parse time for clarity. */
|
|
76
|
-
const REFUSED_PERSONAS = new Set(['main', 'pugi']);
|
|
77
|
-
/** Default persona slug when the attribute is omitted. Matches the
|
|
78
|
-
* ENVELOPES_BODY prompt copy ("Defaults to 'dev' when omitted"). */
|
|
79
|
-
const DEFAULT_PERSONA = 'dev';
|
|
80
|
-
/* ------------------------------------------------------------------ */
|
|
81
|
-
/* Public extraction API */
|
|
82
|
-
/* ------------------------------------------------------------------ */
|
|
83
|
-
/**
|
|
84
|
-
* Find every well-formed `<pugi-tool-route>` envelope in `body`.
|
|
85
|
-
* Malformed envelopes are dropped and surfaced via `hadMalformedTag`
|
|
86
|
-
* so the session can log a warning. Streaming-incomplete envelopes
|
|
87
|
-
* (open observed, close/self-close not yet arrived) are withheld from
|
|
88
|
-
* `cleaned` so the raw envelope cannot leak into the transcript if the
|
|
89
|
-
* stream pauses mid-tag.
|
|
90
|
-
*/
|
|
91
|
-
export function extractToolRouteTags(body) {
|
|
92
|
-
const tags = [];
|
|
93
|
-
const segments = [];
|
|
94
|
-
let cursor = 0;
|
|
95
|
-
let pendingOpenTag = false;
|
|
96
|
-
let hadMalformedTag = false;
|
|
97
|
-
// Hard cap on tags per buffer so a hostile (or accidental) flood
|
|
98
|
-
// does not pin the parser. 16 is generous — a real session never
|
|
99
|
-
// has more than one envelope queued per turn.
|
|
100
|
-
const MAX_TAGS_PER_BUFFER = 16;
|
|
101
|
-
// Belt-and-braces safety counter — the body length bounds the
|
|
102
|
-
// iteration count strictly, but a pathological input could otherwise
|
|
103
|
-
// loop until the per-buffer cap fires.
|
|
104
|
-
let safetyIterations = body.length + 16;
|
|
105
|
-
const OPEN_PREFIX = '<pugi-tool-route';
|
|
106
|
-
const PAIR_CLOSE = '</pugi-tool-route>';
|
|
107
|
-
while (cursor < body.length && tags.length < MAX_TAGS_PER_BUFFER) {
|
|
108
|
-
if (safetyIterations-- <= 0)
|
|
109
|
-
break;
|
|
110
|
-
const openIndex = body.indexOf(OPEN_PREFIX, cursor);
|
|
111
|
-
if (openIndex === -1) {
|
|
112
|
-
// No more envelopes. Flush the rest of the body as cleaned prose.
|
|
113
|
-
segments.push(body.slice(cursor));
|
|
114
|
-
cursor = body.length;
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
// Push everything before the opening tag as cleaned prose.
|
|
118
|
-
segments.push(body.slice(cursor, openIndex));
|
|
119
|
-
// Locate the end of the opening tag. The envelope may be self-
|
|
120
|
-
// closing (`/>`) or paired (`>` then `</pugi-tool-route>`).
|
|
121
|
-
// Search for the FIRST unquoted `>` after the OPEN_PREFIX position
|
|
122
|
-
// so a quoted attribute value with an embedded `>` (escaped as
|
|
123
|
-
// `>` per the grammar; raw `>` is rejected below) cannot
|
|
124
|
-
// confuse the boundary scan.
|
|
125
|
-
const openEnd = findUnquotedGt(body, openIndex + OPEN_PREFIX.length);
|
|
126
|
-
if (openEnd === -1) {
|
|
127
|
-
// Open seen, no terminator yet. Withhold from `cleaned` so the
|
|
128
|
-
// raw envelope cannot leak. Same posture as ask.ts.
|
|
129
|
-
pendingOpenTag = true;
|
|
130
|
-
cursor = body.length;
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
const selfClosed = body[openEnd - 1] === '/';
|
|
134
|
-
let tagEnd;
|
|
135
|
-
if (selfClosed) {
|
|
136
|
-
tagEnd = openEnd + 1; // include the closing `>`
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
// Paired form — look for `</pugi-tool-route>`.
|
|
140
|
-
const closeAt = body.indexOf(PAIR_CLOSE, openEnd + 1);
|
|
141
|
-
if (closeAt === -1) {
|
|
142
|
-
pendingOpenTag = true;
|
|
143
|
-
cursor = body.length;
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
tagEnd = closeAt + PAIR_CLOSE.length;
|
|
147
|
-
}
|
|
148
|
-
const span = body.slice(openIndex, tagEnd);
|
|
149
|
-
if (span.length > TAG_MAX_SPAN_BYTES) {
|
|
150
|
-
hadMalformedTag = true;
|
|
151
|
-
cursor = tagEnd;
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
// Reject nested envelopes — the generic "find next close" would
|
|
155
|
-
// otherwise pair an outer open with an inner close.
|
|
156
|
-
const innerOpen = span.indexOf(OPEN_PREFIX, OPEN_PREFIX.length);
|
|
157
|
-
if (innerOpen !== -1) {
|
|
158
|
-
hadMalformedTag = true;
|
|
159
|
-
cursor = tagEnd;
|
|
160
|
-
continue;
|
|
161
|
-
}
|
|
162
|
-
// Slice the attribute blob between OPEN_PREFIX and the closing
|
|
163
|
-
// `>` (excluding the trailing `/` on the self-closed form).
|
|
164
|
-
const attrBlobEnd = selfClosed ? openEnd - 1 : openEnd;
|
|
165
|
-
const attrBlob = body.slice(openIndex + OPEN_PREFIX.length, attrBlobEnd);
|
|
166
|
-
const parsed = parseToolRouteInner(attrBlob, {
|
|
167
|
-
start: openIndex,
|
|
168
|
-
end: tagEnd,
|
|
169
|
-
});
|
|
170
|
-
if (parsed === null) {
|
|
171
|
-
hadMalformedTag = true;
|
|
172
|
-
cursor = tagEnd;
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
tags.push(parsed);
|
|
176
|
-
cursor = tagEnd;
|
|
177
|
-
}
|
|
178
|
-
return {
|
|
179
|
-
tags,
|
|
180
|
-
cleaned: segments.join('').replace(/\s+\n/g, '\n').trimEnd(),
|
|
181
|
-
pendingOpenTag,
|
|
182
|
-
hadMalformedTag,
|
|
183
|
-
};
|
|
184
|
-
}
|
|
185
|
-
/* ------------------------------------------------------------------ */
|
|
186
|
-
/* Inner parser */
|
|
187
|
-
/* ------------------------------------------------------------------ */
|
|
188
|
-
function parseToolRouteInner(attrBlob, span) {
|
|
189
|
-
// Reject CDATA, comments, processing instructions, DOCTYPE inside
|
|
190
|
-
// the attribute blob — none of those appear in the legal grammar.
|
|
191
|
-
if (/<!--|<!\[|<\?|<!DOCTYPE/i.test(attrBlob))
|
|
192
|
-
return null;
|
|
193
|
-
// Reject raw `&` not in a known entity (decoded entities are allowed
|
|
194
|
-
// via decodeEntities below).
|
|
195
|
-
if (containsRawAmpersand(attrBlob))
|
|
196
|
-
return null;
|
|
197
|
-
// Reject raw `<` / `>` inside the attribute blob — they should always
|
|
198
|
-
// be escaped as `<` / `>`. The presence of a raw bracket is a
|
|
199
|
-
// sign of either accidental sloppy output or an injection attempt.
|
|
200
|
-
if (/[<>]/.test(attrBlob))
|
|
201
|
-
return null;
|
|
202
|
-
const attrs = parseAttrBlob(attrBlob);
|
|
203
|
-
if (attrs === null)
|
|
204
|
-
return null;
|
|
205
|
-
// Closed-attribute gate — refuse anything outside the allowlist.
|
|
206
|
-
for (const key of Object.keys(attrs)) {
|
|
207
|
-
if (!ALLOWED_ATTRS.has(key))
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
const command = attrs['command'];
|
|
211
|
-
if (typeof command !== 'string' || command.length === 0)
|
|
212
|
-
return null;
|
|
213
|
-
if (!ALLOWED_COMMANDS.has(command))
|
|
214
|
-
return null;
|
|
215
|
-
const briefRaw = attrs['brief'];
|
|
216
|
-
if (typeof briefRaw !== 'string')
|
|
217
|
-
return null;
|
|
218
|
-
const brief = briefRaw.trim();
|
|
219
|
-
if (brief.length === 0 || brief.length > TOOL_ROUTE_MAX_BRIEF_LEN)
|
|
220
|
-
return null;
|
|
221
|
-
// Persona is optional → default to `dev`. Any explicit non-empty
|
|
222
|
-
// value runs through the slug shape check + refused-persona gate.
|
|
223
|
-
const personaRaw = attrs['persona'];
|
|
224
|
-
let persona = DEFAULT_PERSONA;
|
|
225
|
-
if (typeof personaRaw === 'string' && personaRaw.length > 0) {
|
|
226
|
-
const trimmed = personaRaw.trim();
|
|
227
|
-
if (trimmed.length === 0 || trimmed.length > TOOL_ROUTE_MAX_PERSONA_LEN)
|
|
228
|
-
return null;
|
|
229
|
-
// Slug shape: lowercase ASCII letters + digits + hyphens, must
|
|
230
|
-
// start with a letter. Same shape as the `<pugi-delegate>` slug
|
|
231
|
-
// gate in admin-api so a future engine adapter can reuse the slug
|
|
232
|
-
// verbatim without re-validating.
|
|
233
|
-
if (!/^[a-z][a-z0-9-]*$/.test(trimmed))
|
|
234
|
-
return null;
|
|
235
|
-
if (REFUSED_PERSONAS.has(trimmed))
|
|
236
|
-
return null;
|
|
237
|
-
persona = trimmed;
|
|
238
|
-
}
|
|
239
|
-
const signature = signatureForToolRoute(command, persona, brief);
|
|
240
|
-
return {
|
|
241
|
-
command: command,
|
|
242
|
-
persona,
|
|
243
|
-
brief,
|
|
244
|
-
signature,
|
|
245
|
-
start: span.start,
|
|
246
|
-
end: span.end,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Parse `key="value"` / `key='value'` pairs out of an attribute blob.
|
|
251
|
-
* Returns null on any malformed attribute (unterminated quote, raw
|
|
252
|
-
* entity outside the allowlist, etc). Mirrors the bounded tokenizer
|
|
253
|
-
* in ask.ts so the parsing posture is uniform across envelope families.
|
|
254
|
-
*/
|
|
255
|
-
function parseAttrBlob(blob) {
|
|
256
|
-
const trimmed = blob.trim();
|
|
257
|
-
if (trimmed.length === 0)
|
|
258
|
-
return {};
|
|
259
|
-
const result = {};
|
|
260
|
-
let cursor = 0;
|
|
261
|
-
const maxIterations = trimmed.length + 4;
|
|
262
|
-
let iterations = 0;
|
|
263
|
-
while (cursor < trimmed.length && iterations++ < maxIterations) {
|
|
264
|
-
while (cursor < trimmed.length && /\s/.test(trimmed[cursor] ?? ''))
|
|
265
|
-
cursor += 1;
|
|
266
|
-
if (cursor >= trimmed.length)
|
|
267
|
-
break;
|
|
268
|
-
const nameStart = cursor;
|
|
269
|
-
// Attribute names are lowercase letters; allow `-` for consistency
|
|
270
|
-
// with the rest of the persona grammar even though our allowlist is
|
|
271
|
-
// hyphen-free. Mismatch is caught by the ALLOWED_ATTRS gate.
|
|
272
|
-
while (cursor < trimmed.length &&
|
|
273
|
-
/[a-z-]/.test(trimmed[cursor] ?? '')) {
|
|
274
|
-
cursor += 1;
|
|
275
|
-
}
|
|
276
|
-
if (cursor === nameStart)
|
|
277
|
-
return null;
|
|
278
|
-
const name = trimmed.slice(nameStart, cursor);
|
|
279
|
-
if (trimmed[cursor] !== '=')
|
|
280
|
-
return null;
|
|
281
|
-
cursor += 1;
|
|
282
|
-
const quote = trimmed[cursor];
|
|
283
|
-
if (quote !== '"' && quote !== "'")
|
|
284
|
-
return null;
|
|
285
|
-
cursor += 1;
|
|
286
|
-
const valueStart = cursor;
|
|
287
|
-
const valueEnd = trimmed.indexOf(quote, valueStart);
|
|
288
|
-
if (valueEnd === -1)
|
|
289
|
-
return null;
|
|
290
|
-
const rawValue = trimmed.slice(valueStart, valueEnd);
|
|
291
|
-
// Raw `&` outside a known entity is malformed; raw angle brackets
|
|
292
|
-
// are forbidden inside quoted values (must be escaped). The closed
|
|
293
|
-
// entity allowlist + control-char strip mirrors ask.ts.
|
|
294
|
-
if (containsRawAmpersand(rawValue))
|
|
295
|
-
return null;
|
|
296
|
-
if (/[<>]/.test(rawValue))
|
|
297
|
-
return null;
|
|
298
|
-
result[name] = stripControlChars(decodeEntities(rawValue));
|
|
299
|
-
cursor = valueEnd + 1;
|
|
300
|
-
}
|
|
301
|
-
return result;
|
|
302
|
-
}
|
|
303
|
-
/* ------------------------------------------------------------------ */
|
|
304
|
-
/* Streaming helper — find an unquoted `>` after `from` */
|
|
305
|
-
/* ------------------------------------------------------------------ */
|
|
306
|
-
/**
|
|
307
|
-
* Walk `body` from index `from` looking for the first `>` that is NOT
|
|
308
|
-
* inside a quoted attribute value. Returns the index of the `>` or -1
|
|
309
|
-
* when no such position is found.
|
|
310
|
-
*
|
|
311
|
-
* Quote tracking is necessary because a `brief="…contains > as >…"`
|
|
312
|
-
* value should never confuse the boundary scan. The grammar already
|
|
313
|
-
* forbids raw `>` inside quoted values (escape as `>`) — this is
|
|
314
|
-
* belt-and-braces against a sloppy model emission.
|
|
315
|
-
*/
|
|
316
|
-
function findUnquotedGt(body, from) {
|
|
317
|
-
let quote = null;
|
|
318
|
-
for (let i = from; i < body.length; i += 1) {
|
|
319
|
-
const ch = body[i];
|
|
320
|
-
if (quote !== null) {
|
|
321
|
-
if (ch === quote)
|
|
322
|
-
quote = null;
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
if (ch === '"' || ch === "'") {
|
|
326
|
-
quote = ch;
|
|
327
|
-
continue;
|
|
328
|
-
}
|
|
329
|
-
if (ch === '>')
|
|
330
|
-
return i;
|
|
331
|
-
}
|
|
332
|
-
return -1;
|
|
333
|
-
}
|
|
334
|
-
/* ------------------------------------------------------------------ */
|
|
335
|
-
/* Entity decoding + amp safety + control strip */
|
|
336
|
-
/* ------------------------------------------------------------------ */
|
|
337
|
-
const ENTITY_MAP = Object.freeze({
|
|
338
|
-
amp: '&',
|
|
339
|
-
lt: '<',
|
|
340
|
-
gt: '>',
|
|
341
|
-
quot: '"',
|
|
342
|
-
apos: "'",
|
|
343
|
-
});
|
|
344
|
-
function decodeEntities(input) {
|
|
345
|
-
return input.replace(/&([a-z]+);/g, (whole, name) => {
|
|
346
|
-
const decoded = ENTITY_MAP[name];
|
|
347
|
-
return decoded === undefined ? whole : decoded;
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
function stripControlChars(input) {
|
|
351
|
-
// eslint-disable-next-line no-control-regex -- deliberately matching control range
|
|
352
|
-
return input.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f\x80-\x9f]/g, '');
|
|
353
|
-
}
|
|
354
|
-
function containsRawAmpersand(input) {
|
|
355
|
-
for (let i = 0; i < input.length; i += 1) {
|
|
356
|
-
if (input[i] !== '&')
|
|
357
|
-
continue;
|
|
358
|
-
const semi = input.indexOf(';', i + 1);
|
|
359
|
-
if (semi === -1)
|
|
360
|
-
return true;
|
|
361
|
-
const name = input.slice(i + 1, semi);
|
|
362
|
-
if (!Object.prototype.hasOwnProperty.call(ENTITY_MAP, name))
|
|
363
|
-
return true;
|
|
364
|
-
i = semi;
|
|
365
|
-
}
|
|
366
|
-
return false;
|
|
367
|
-
}
|
|
368
|
-
/* ------------------------------------------------------------------ */
|
|
369
|
-
/* Signature */
|
|
370
|
-
/* ------------------------------------------------------------------ */
|
|
371
|
-
/**
|
|
372
|
-
* Stable dedupe signature for a tool-route tag. Exported so future
|
|
373
|
-
* synthesisers (slash command, local fallback) can produce signatures
|
|
374
|
-
* that collision-match parser-produced ones — without a single source
|
|
375
|
-
* of truth a local synth could share a signature with a persona-emitted
|
|
376
|
-
* envelope and the rolling-seen set would suppress one of them.
|
|
377
|
-
*/
|
|
378
|
-
export function signatureForToolRoute(command, persona, brief) {
|
|
379
|
-
const raw = `${command}::${persona.toLowerCase()}::${brief.trim().toLowerCase()}`;
|
|
380
|
-
return Buffer.from(raw, 'utf8').toString('base64');
|
|
381
|
-
}
|
|
382
|
-
//# sourceMappingURL=tool-route.js.map
|