@kr78/pi-coding-agent 17.2.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/CHANGELOG.md +14861 -0
- package/README.md +35 -0
- package/dist/CHANGELOG-chtdxh1z.md +14861 -0
- package/dist/cli.js +20483 -0
- package/dist/template-c2hyaytt.js +1653 -0
- package/dist/template-f8wx9vfn.css +1355 -0
- package/dist/template-qat058wr.html +55 -0
- package/dist/tool-views.generated-jdfmzwmn.js +35 -0
- package/examples/README.md +21 -0
- package/examples/custom-tools/README.md +104 -0
- package/examples/custom-tools/hello/index.ts +20 -0
- package/examples/extensions/README.md +142 -0
- package/examples/extensions/api-demo.ts +78 -0
- package/examples/extensions/chalk-logger.ts +25 -0
- package/examples/extensions/hello.ts +31 -0
- package/examples/extensions/pirate.ts +43 -0
- package/examples/extensions/plan-mode.ts +549 -0
- package/examples/extensions/reload-runtime.ts +38 -0
- package/examples/extensions/thinking-note.ts +13 -0
- package/examples/extensions/tools.ts +145 -0
- package/examples/extensions/with-deps/index.ts +36 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +17 -0
- package/examples/hooks/README.md +56 -0
- package/examples/hooks/auto-commit-on-exit.ts +48 -0
- package/examples/hooks/confirm-destructive.ts +58 -0
- package/examples/hooks/custom-compaction.ts +115 -0
- package/examples/hooks/dirty-repo-guard.ts +51 -0
- package/examples/hooks/file-trigger.ts +40 -0
- package/examples/hooks/git-checkpoint.ts +52 -0
- package/examples/hooks/handoff.ts +149 -0
- package/examples/hooks/permission-gate.ts +33 -0
- package/examples/hooks/protected-paths.ts +29 -0
- package/examples/hooks/qna.ts +118 -0
- package/examples/hooks/status-line.ts +39 -0
- package/examples/sdk/01-minimal.ts +21 -0
- package/examples/sdk/02-custom-model.ts +49 -0
- package/examples/sdk/03-custom-prompt.ts +46 -0
- package/examples/sdk/04-skills.ts +43 -0
- package/examples/sdk/06-extensions.ts +82 -0
- package/examples/sdk/06-hooks.ts +61 -0
- package/examples/sdk/07-context-files.ts +35 -0
- package/examples/sdk/08-prompt-templates.ts +41 -0
- package/examples/sdk/08-slash-commands.ts +46 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
- package/examples/sdk/11-sessions.ts +47 -0
- package/examples/sdk/12-redis-sessions.ts +54 -0
- package/examples/sdk/13-sql-sessions.ts +61 -0
- package/examples/sdk/README.md +169 -0
- package/package.json +587 -0
- package/scripts/bench-guard.ts +71 -0
- package/scripts/bench-title-models.ts +332 -0
- package/scripts/build-binary.ts +117 -0
- package/scripts/bundle-dist.ts +123 -0
- package/scripts/compile-binary.ts +69 -0
- package/scripts/embed-mupdf-wasm.ts +67 -0
- package/scripts/format-prompts.ts +68 -0
- package/scripts/generate-aria-snapshot.ts +134 -0
- package/scripts/generate-docs-index.ts +58 -0
- package/scripts/generate-share-viewer.ts +34 -0
- package/scripts/legacy-pi-virtual-module.ts +205 -0
- package/scripts/measure-prompt-tokens.ts +63 -0
- package/scripts/omp +51 -0
- package/scripts/omp.ts +19 -0
- package/scripts/security-compare.ts +40 -0
- package/src/advisor/advise-tool.ts +234 -0
- package/src/advisor/config.ts +341 -0
- package/src/advisor/emission-guard.ts +172 -0
- package/src/advisor/index.ts +6 -0
- package/src/advisor/runtime.ts +1412 -0
- package/src/advisor/transcript-recorder.ts +215 -0
- package/src/advisor/watchdog.ts +135 -0
- package/src/async/index.ts +1 -0
- package/src/async/job-manager.ts +847 -0
- package/src/auto-thinking/classifier.ts +220 -0
- package/src/autolearn/controller.ts +152 -0
- package/src/autolearn/managed-skills.ts +255 -0
- package/src/autoresearch/command-resume.md +14 -0
- package/src/autoresearch/dashboard.ts +436 -0
- package/src/autoresearch/git.ts +331 -0
- package/src/autoresearch/helpers.ts +218 -0
- package/src/autoresearch/index.ts +541 -0
- package/src/autoresearch/prompt-setup.md +43 -0
- package/src/autoresearch/prompt.md +103 -0
- package/src/autoresearch/resume-message.md +10 -0
- package/src/autoresearch/state.ts +273 -0
- package/src/autoresearch/storage.ts +700 -0
- package/src/autoresearch/tools/init-experiment.ts +268 -0
- package/src/autoresearch/tools/log-experiment.ts +520 -0
- package/src/autoresearch/tools/run-experiment.ts +407 -0
- package/src/autoresearch/tools/update-notes.ts +109 -0
- package/src/autoresearch/types.ts +168 -0
- package/src/capability/context-file.ts +44 -0
- package/src/capability/extension-module.ts +34 -0
- package/src/capability/extension.ts +47 -0
- package/src/capability/fs.ts +117 -0
- package/src/capability/hook.ts +40 -0
- package/src/capability/index.ts +467 -0
- package/src/capability/instruction.ts +37 -0
- package/src/capability/mcp.ts +115 -0
- package/src/capability/prompt.ts +35 -0
- package/src/capability/rule-buckets.ts +66 -0
- package/src/capability/rule.ts +298 -0
- package/src/capability/settings.ts +34 -0
- package/src/capability/skill.ts +69 -0
- package/src/capability/slash-command.ts +40 -0
- package/src/capability/ssh.ts +41 -0
- package/src/capability/system-prompt.ts +34 -0
- package/src/capability/tool.ts +38 -0
- package/src/capability/types.ts +187 -0
- package/src/cleanse/agent.ts +226 -0
- package/src/cleanse/balance.ts +79 -0
- package/src/cleanse/checkers.ts +996 -0
- package/src/cleanse/index.ts +190 -0
- package/src/cleanse/loop.ts +51 -0
- package/src/cleanse/parsers.ts +726 -0
- package/src/cleanse/progress.ts +50 -0
- package/src/cleanse/prompts/assignment.md +47 -0
- package/src/cleanse/types.ts +72 -0
- package/src/cli/agents-cli.ts +138 -0
- package/src/cli/args.ts +368 -0
- package/src/cli/auth-broker-cli.ts +940 -0
- package/src/cli/auth-gateway-cli.ts +674 -0
- package/src/cli/bench-cli.ts +990 -0
- package/src/cli/browser-relay-cli.ts +119 -0
- package/src/cli/classify-install-target.ts +76 -0
- package/src/cli/claude-trace-cli.ts +795 -0
- package/src/cli/command-help.ts +107 -0
- package/src/cli/commands/init-xdg.ts +27 -0
- package/src/cli/completion-gen.ts +550 -0
- package/src/cli/config-cli.ts +459 -0
- package/src/cli/dry-balance-cli.ts +864 -0
- package/src/cli/extension-flags.ts +48 -0
- package/src/cli/file-processor.ts +132 -0
- package/src/cli/flag-tables.ts +367 -0
- package/src/cli/gallery-cli.ts +272 -0
- package/src/cli/gallery-fixtures/agentic.ts +420 -0
- package/src/cli/gallery-fixtures/codeintel.ts +187 -0
- package/src/cli/gallery-fixtures/edit.ts +254 -0
- package/src/cli/gallery-fixtures/fs.ts +245 -0
- package/src/cli/gallery-fixtures/index.ts +40 -0
- package/src/cli/gallery-fixtures/interaction.ts +46 -0
- package/src/cli/gallery-fixtures/memory.ts +81 -0
- package/src/cli/gallery-fixtures/misc.ts +177 -0
- package/src/cli/gallery-fixtures/search.ts +135 -0
- package/src/cli/gallery-fixtures/shell.ts +241 -0
- package/src/cli/gallery-fixtures/types.ts +57 -0
- package/src/cli/gallery-fixtures/web.ts +158 -0
- package/src/cli/gallery-screenshot.ts +279 -0
- package/src/cli/gc-cli.ts +1566 -0
- package/src/cli/grep-cli.ts +161 -0
- package/src/cli/grievances-cli.ts +256 -0
- package/src/cli/help-extra.ts +89 -0
- package/src/cli/initial-message.ts +58 -0
- package/src/cli/models-cli.ts +385 -0
- package/src/cli/plugin-cli.ts +996 -0
- package/src/cli/profile-alias.ts +369 -0
- package/src/cli/profile-bootstrap.ts +233 -0
- package/src/cli/read-cli.ts +99 -0
- package/src/cli/session-picker.ts +110 -0
- package/src/cli/setup-cli.ts +312 -0
- package/src/cli/setup-model-picker.ts +43 -0
- package/src/cli/shell-cli.ts +176 -0
- package/src/cli/ssh-cli.ts +179 -0
- package/src/cli/startup-cwd.ts +58 -0
- package/src/cli/stats-cli.ts +229 -0
- package/src/cli/thinking-levels.ts +7 -0
- package/src/cli/tiny-models-cli.ts +153 -0
- package/src/cli/ttsr-cli.ts +1013 -0
- package/src/cli/update-cli.ts +1184 -0
- package/src/cli/usage-cli.ts +1084 -0
- package/src/cli/usage-error.ts +7 -0
- package/src/cli/web-search-cli.ts +144 -0
- package/src/cli/worktree-cli.ts +311 -0
- package/src/cli-commands.ts +308 -0
- package/src/cli.ts +428 -0
- package/src/collab/crypto.ts +63 -0
- package/src/collab/display-name.ts +13 -0
- package/src/collab/guest.ts +764 -0
- package/src/collab/host.ts +692 -0
- package/src/collab/protocol.ts +296 -0
- package/src/collab/relay-client.ts +282 -0
- package/src/collab/replication-shrink.ts +111 -0
- package/src/commands/acp.ts +35 -0
- package/src/commands/agents.ts +58 -0
- package/src/commands/auth-broker.ts +100 -0
- package/src/commands/auth-gateway.ts +70 -0
- package/src/commands/bench.ts +64 -0
- package/src/commands/browser-relay.ts +53 -0
- package/src/commands/cleanse.ts +45 -0
- package/src/commands/commit.ts +47 -0
- package/src/commands/complete.ts +67 -0
- package/src/commands/completions.ts +61 -0
- package/src/commands/config.ts +52 -0
- package/src/commands/dry-balance.ts +43 -0
- package/src/commands/gallery.ts +61 -0
- package/src/commands/gc.ts +47 -0
- package/src/commands/grep.ts +49 -0
- package/src/commands/grievances.ts +52 -0
- package/src/commands/install.ts +107 -0
- package/src/commands/join.ts +40 -0
- package/src/commands/launch-help.ts +116 -0
- package/src/commands/launch.ts +34 -0
- package/src/commands/models.ts +61 -0
- package/src/commands/plugin.ts +79 -0
- package/src/commands/read.ts +39 -0
- package/src/commands/say.ts +146 -0
- package/src/commands/setup.ts +68 -0
- package/src/commands/share.ts +71 -0
- package/src/commands/shell.ts +30 -0
- package/src/commands/ssh.ts +61 -0
- package/src/commands/stats.ts +30 -0
- package/src/commands/tiny-models.ts +36 -0
- package/src/commands/token.ts +164 -0
- package/src/commands/ttsr.ts +125 -0
- package/src/commands/update.ts +34 -0
- package/src/commands/usage.ts +55 -0
- package/src/commands/web-search.ts +43 -0
- package/src/commands/worktree.ts +63 -0
- package/src/commit/agentic/agent.ts +322 -0
- package/src/commit/agentic/fallback.ts +96 -0
- package/src/commit/agentic/index.ts +383 -0
- package/src/commit/agentic/lock-files.ts +107 -0
- package/src/commit/agentic/prompts/analyze-file.md +22 -0
- package/src/commit/agentic/prompts/session-user.md +25 -0
- package/src/commit/agentic/prompts/split-confirm.md +1 -0
- package/src/commit/agentic/prompts/system.md +38 -0
- package/src/commit/agentic/state.ts +60 -0
- package/src/commit/agentic/tools/analyze-file.ts +148 -0
- package/src/commit/agentic/tools/git-file-diff.ts +191 -0
- package/src/commit/agentic/tools/git-hunk.ts +52 -0
- package/src/commit/agentic/tools/git-overview.ts +62 -0
- package/src/commit/agentic/tools/index.ts +54 -0
- package/src/commit/agentic/tools/propose-changelog.ts +147 -0
- package/src/commit/agentic/tools/propose-commit.ts +109 -0
- package/src/commit/agentic/tools/recent-commits.ts +81 -0
- package/src/commit/agentic/tools/schemas.ts +11 -0
- package/src/commit/agentic/tools/split-commit.ts +241 -0
- package/src/commit/agentic/topo-sort.ts +44 -0
- package/src/commit/agentic/trivial.ts +51 -0
- package/src/commit/agentic/validation.ts +183 -0
- package/src/commit/analysis/conventional.ts +64 -0
- package/src/commit/analysis/index.ts +4 -0
- package/src/commit/analysis/scope.ts +242 -0
- package/src/commit/analysis/summary.ts +107 -0
- package/src/commit/analysis/validation.ts +66 -0
- package/src/commit/changelog/detect.ts +40 -0
- package/src/commit/changelog/generate.ts +101 -0
- package/src/commit/changelog/index.ts +234 -0
- package/src/commit/changelog/parse.ts +44 -0
- package/src/commit/cli.ts +85 -0
- package/src/commit/git/diff.ts +148 -0
- package/src/commit/index.ts +5 -0
- package/src/commit/map-reduce/index.ts +69 -0
- package/src/commit/map-reduce/map-phase.ts +193 -0
- package/src/commit/map-reduce/reduce-phase.ts +49 -0
- package/src/commit/map-reduce/utils.ts +9 -0
- package/src/commit/message.ts +11 -0
- package/src/commit/model-selection.ts +95 -0
- package/src/commit/pipeline.ts +244 -0
- package/src/commit/prompts/analysis-system.md +148 -0
- package/src/commit/prompts/analysis-user.md +38 -0
- package/src/commit/prompts/changelog-system.md +50 -0
- package/src/commit/prompts/changelog-user.md +18 -0
- package/src/commit/prompts/file-observer-system.md +24 -0
- package/src/commit/prompts/file-observer-user.md +8 -0
- package/src/commit/prompts/reduce-system.md +50 -0
- package/src/commit/prompts/reduce-user.md +17 -0
- package/src/commit/prompts/summary-retry.md +3 -0
- package/src/commit/prompts/summary-system.md +38 -0
- package/src/commit/prompts/summary-user.md +13 -0
- package/src/commit/prompts/types-description.md +2 -0
- package/src/commit/shared-llm.ts +70 -0
- package/src/commit/types.ts +118 -0
- package/src/commit/utils/exclusions.ts +42 -0
- package/src/commit/utils.ts +58 -0
- package/src/config/api-key-resolver.ts +81 -0
- package/src/config/append-only-context-mode.ts +76 -0
- package/src/config/config-file.ts +347 -0
- package/src/config/inline-tool-descriptors-mode.ts +26 -0
- package/src/config/keybindings.ts +703 -0
- package/src/config/mcp-schema.json +252 -0
- package/src/config/model-discovery.ts +1077 -0
- package/src/config/model-registry.ts +2822 -0
- package/src/config/model-resolver.ts +2115 -0
- package/src/config/model-roles.ts +113 -0
- package/src/config/models-config-schema-bundle.ts +315 -0
- package/src/config/models-config-schema.ts +14 -0
- package/src/config/models-config.ts +130 -0
- package/src/config/prompt-templates.ts +205 -0
- package/src/config/provider-globals.ts +25 -0
- package/src/config/resolve-config-value.ts +95 -0
- package/src/config/service-tier.ts +146 -0
- package/src/config/settings-schema.ts +5887 -0
- package/src/config/settings.ts +2394 -0
- package/src/config.ts +242 -0
- package/src/cursor-bridge-tools.ts +81 -0
- package/src/cursor.ts +960 -0
- package/src/dap/client.ts +1043 -0
- package/src/dap/config.ts +480 -0
- package/src/dap/defaults.json +212 -0
- package/src/dap/index.ts +4 -0
- package/src/dap/session.ts +1841 -0
- package/src/dap/types.ts +611 -0
- package/src/debug/index.ts +584 -0
- package/src/debug/log-formatting.ts +58 -0
- package/src/debug/log-viewer.ts +966 -0
- package/src/debug/profiler.ts +168 -0
- package/src/debug/protocol-probe.ts +267 -0
- package/src/debug/raw-sse-buffer.ts +421 -0
- package/src/debug/raw-sse.ts +312 -0
- package/src/debug/remote-debugger.ts +151 -0
- package/src/debug/report-bundle.ts +411 -0
- package/src/debug/system-info.ts +111 -0
- package/src/debug/terminal-info.ts +124 -0
- package/src/discovery/agent-plugin-format.ts +551 -0
- package/src/discovery/agent-plugins.ts +341 -0
- package/src/discovery/agents-md.ts +67 -0
- package/src/discovery/agents.ts +300 -0
- package/src/discovery/at-imports.ts +273 -0
- package/src/discovery/builtin-defaults.ts +39 -0
- package/src/discovery/builtin-rules/go-add-cleanup.md +33 -0
- package/src/discovery/builtin-rules/go-bench-loop.md +36 -0
- package/src/discovery/builtin-rules/go-exp-promoted.md +40 -0
- package/src/discovery/builtin-rules/go-ioutil.md +37 -0
- package/src/discovery/builtin-rules/go-join-hostport.md +30 -0
- package/src/discovery/builtin-rules/go-new-expr.md +44 -0
- package/src/discovery/builtin-rules/go-rand-v2.md +41 -0
- package/src/discovery/builtin-rules/go-range-int.md +45 -0
- package/src/discovery/builtin-rules/index.ts +74 -0
- package/src/discovery/builtin-rules/rs-box-leak.md +49 -0
- package/src/discovery/builtin-rules/rs-future-prelude.md +24 -0
- package/src/discovery/builtin-rules/rs-lazylock.md +52 -0
- package/src/discovery/builtin-rules/rs-match-ergonomics.md +68 -0
- package/src/discovery/builtin-rules/rs-parking-lot.md +45 -0
- package/src/discovery/builtin-rules/rs-result-type.md +20 -0
- package/src/discovery/builtin-rules/ts-bare-catch.md +39 -0
- package/src/discovery/builtin-rules/ts-import-type.md +43 -0
- package/src/discovery/builtin-rules/ts-no-any.md +66 -0
- package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +45 -0
- package/src/discovery/builtin-rules/ts-no-dynamic-import.md +40 -0
- package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +56 -0
- package/src/discovery/builtin-rules/ts-no-local-is-record.md +48 -0
- package/src/discovery/builtin-rules/ts-no-return-type.md +45 -0
- package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +51 -0
- package/src/discovery/builtin-rules/ts-promise-with-resolvers.md +66 -0
- package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
- package/src/discovery/builtin-rules/ts-set-map.md +28 -0
- package/src/discovery/builtin.ts +945 -0
- package/src/discovery/claude-plugins.ts +640 -0
- package/src/discovery/claude.ts +591 -0
- package/src/discovery/cline.ts +83 -0
- package/src/discovery/codex.ts +553 -0
- package/src/discovery/contained-path.ts +78 -0
- package/src/discovery/cursor.ts +223 -0
- package/src/discovery/gemini.ts +386 -0
- package/src/discovery/github.ts +337 -0
- package/src/discovery/helpers.ts +1183 -0
- package/src/discovery/index.ts +82 -0
- package/src/discovery/mcp-json.ts +182 -0
- package/src/discovery/omp-extension-roots.ts +272 -0
- package/src/discovery/omp-plugins.ts +409 -0
- package/src/discovery/opencode.ts +441 -0
- package/src/discovery/plugin-dir-roots.ts +28 -0
- package/src/discovery/ssh.ts +153 -0
- package/src/discovery/substitute-plugin-root.ts +77 -0
- package/src/discovery/vscode.ts +106 -0
- package/src/discovery/windsurf.ts +149 -0
- package/src/edit/apply-patch/index.ts +87 -0
- package/src/edit/apply-patch/parser.ts +174 -0
- package/src/edit/diff.ts +1008 -0
- package/src/edit/edit-clipboard.ts +23 -0
- package/src/edit/file-snapshot-store.ts +148 -0
- package/src/edit/hashline/block-resolver.ts +33 -0
- package/src/edit/hashline/diff.ts +402 -0
- package/src/edit/hashline/execute.ts +313 -0
- package/src/edit/hashline/filesystem.ts +247 -0
- package/src/edit/hashline/index.ts +5 -0
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/edit/hashline/params.ts +12 -0
- package/src/edit/index.ts +699 -0
- package/src/edit/modes/apply-patch.lark +19 -0
- package/src/edit/modes/apply-patch.ts +53 -0
- package/src/edit/modes/patch.ts +1958 -0
- package/src/edit/modes/replace.ts +1191 -0
- package/src/edit/normalize.ts +345 -0
- package/src/edit/notebook.ts +242 -0
- package/src/edit/read-file.ts +25 -0
- package/src/edit/renderer.ts +998 -0
- package/src/edit/snapshot-details.ts +77 -0
- package/src/edit/streaming.ts +710 -0
- package/src/eval/agent-bridge.ts +224 -0
- package/src/eval/backend-helpers.ts +48 -0
- package/src/eval/backend.ts +71 -0
- package/src/eval/bridge-timeout.ts +65 -0
- package/src/eval/budget-bridge.ts +48 -0
- package/src/eval/completion-bridge.ts +212 -0
- package/src/eval/concurrency-bridge.ts +34 -0
- package/src/eval/executor-base.ts +562 -0
- package/src/eval/idle-timeout.ts +91 -0
- package/src/eval/index.ts +6 -0
- package/src/eval/jl/executor.ts +551 -0
- package/src/eval/jl/index.ts +54 -0
- package/src/eval/jl/kernel.ts +236 -0
- package/src/eval/jl/prelude.jl +736 -0
- package/src/eval/jl/prelude.ts +3 -0
- package/src/eval/jl/runner.jl +666 -0
- package/src/eval/jl/runtime.ts +118 -0
- package/src/eval/js/context-manager.ts +872 -0
- package/src/eval/js/executor.ts +178 -0
- package/src/eval/js/index.ts +41 -0
- package/src/eval/js/process-entry.ts +31 -0
- package/src/eval/js/shared/helpers.ts +170 -0
- package/src/eval/js/shared/indirect-eval.ts +30 -0
- package/src/eval/js/shared/local-module-loader.ts +364 -0
- package/src/eval/js/shared/prelude.ts +2 -0
- package/src/eval/js/shared/prelude.txt +294 -0
- package/src/eval/js/shared/rewrite-imports.ts +550 -0
- package/src/eval/js/shared/runtime.ts +590 -0
- package/src/eval/js/shared/types.ts +18 -0
- package/src/eval/js/tool-bridge.ts +163 -0
- package/src/eval/js/worker-core.ts +380 -0
- package/src/eval/js/worker-entry.ts +37 -0
- package/src/eval/js/worker-protocol.ts +47 -0
- package/src/eval/kernel-base.ts +569 -0
- package/src/eval/py/display.ts +71 -0
- package/src/eval/py/executor.ts +643 -0
- package/src/eval/py/index.ts +57 -0
- package/src/eval/py/kernel.ts +235 -0
- package/src/eval/py/prelude.py +673 -0
- package/src/eval/py/prelude.ts +3 -0
- package/src/eval/py/runner.py +1425 -0
- package/src/eval/py/runtime.ts +276 -0
- package/src/eval/py/spawn-options.ts +134 -0
- package/src/eval/py/tool-bridge.ts +201 -0
- package/src/eval/rb/executor.ts +511 -0
- package/src/eval/rb/index.ts +54 -0
- package/src/eval/rb/kernel.ts +231 -0
- package/src/eval/rb/prelude.rb +551 -0
- package/src/eval/rb/prelude.ts +3 -0
- package/src/eval/rb/runner.rb +581 -0
- package/src/eval/rb/runtime.ts +132 -0
- package/src/eval/runtime-env.ts +104 -0
- package/src/eval/session-id.ts +8 -0
- package/src/eval/types.ts +48 -0
- package/src/exa/index.ts +2 -0
- package/src/exa/mcp-client.ts +370 -0
- package/src/exa/types.ts +69 -0
- package/src/exec/bash-executor.ts +627 -0
- package/src/exec/direnv.ts +145 -0
- package/src/exec/exec.ts +53 -0
- package/src/exec/non-interactive-env.ts +118 -0
- package/src/export/custom-share.ts +65 -0
- package/src/export/html/args.ts +20 -0
- package/src/export/html/index.ts +320 -0
- package/src/export/html/share-loader.js +102 -0
- package/src/export/html/template.css +1355 -0
- package/src/export/html/template.html +55 -0
- package/src/export/html/template.js +1653 -0
- package/src/export/html/tool-views.generated.js +35 -0
- package/src/export/html/vendor/highlight.min.js +1213 -0
- package/src/export/html/vendor/marked.min.js +6 -0
- package/src/export/html/web-palette.ts +126 -0
- package/src/export/share.ts +686 -0
- package/src/export/ttsr.ts +590 -0
- package/src/extensibility/custom-commands/bundled/ci-green/index.ts +54 -0
- package/src/extensibility/custom-commands/bundled/review/index.ts +698 -0
- package/src/extensibility/custom-commands/index.ts +2 -0
- package/src/extensibility/custom-commands/loader.ts +242 -0
- package/src/extensibility/custom-commands/types.ts +119 -0
- package/src/extensibility/custom-tools/index.ts +7 -0
- package/src/extensibility/custom-tools/loader.ts +301 -0
- package/src/extensibility/custom-tools/types.ts +287 -0
- package/src/extensibility/custom-tools/wrapper.ts +50 -0
- package/src/extensibility/extensions/compact-handler.ts +40 -0
- package/src/extensibility/extensions/get-commands-handler.ts +78 -0
- package/src/extensibility/extensions/index.ts +16 -0
- package/src/extensibility/extensions/load-errors.ts +13 -0
- package/src/extensibility/extensions/loader.ts +663 -0
- package/src/extensibility/extensions/managed-timers.ts +83 -0
- package/src/extensibility/extensions/model-api.ts +39 -0
- package/src/extensibility/extensions/runner.ts +1396 -0
- package/src/extensibility/extensions/types.ts +1603 -0
- package/src/extensibility/extensions/wrapper.ts +395 -0
- package/src/extensibility/hooks/index.ts +6 -0
- package/src/extensibility/hooks/loader.ts +243 -0
- package/src/extensibility/hooks/runner.ts +425 -0
- package/src/extensibility/hooks/tool-wrapper.ts +124 -0
- package/src/extensibility/hooks/types.ts +612 -0
- package/src/extensibility/legacy-pi-ai-shim.ts +161 -0
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +1460 -0
- package/src/extensibility/legacy-pi-tui-shim.ts +43 -0
- package/src/extensibility/legacy-typebox.ts +101 -0
- package/src/extensibility/plugins/bun-git-cache.ts +91 -0
- package/src/extensibility/plugins/doctor.ts +65 -0
- package/src/extensibility/plugins/git-url.ts +367 -0
- package/src/extensibility/plugins/index.ts +9 -0
- package/src/extensibility/plugins/installer.ts +201 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +2643 -0
- package/src/extensibility/plugins/legacy-pi-virtual-modules.d.ts +4 -0
- package/src/extensibility/plugins/loader.ts +535 -0
- package/src/extensibility/plugins/manager.ts +1142 -0
- package/src/extensibility/plugins/marketplace/cache.ts +136 -0
- package/src/extensibility/plugins/marketplace/fetcher.ts +316 -0
- package/src/extensibility/plugins/marketplace/index.ts +6 -0
- package/src/extensibility/plugins/marketplace/manager.ts +927 -0
- package/src/extensibility/plugins/marketplace/registry.ts +192 -0
- package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
- package/src/extensibility/plugins/marketplace/types.ts +192 -0
- package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
- package/src/extensibility/plugins/parser.ts +107 -0
- package/src/extensibility/plugins/runtime-config.ts +9 -0
- package/src/extensibility/plugins/types.ts +194 -0
- package/src/extensibility/session-handler-types.ts +21 -0
- package/src/extensibility/shared-events.ts +401 -0
- package/src/extensibility/skills.ts +531 -0
- package/src/extensibility/slash-commands.ts +131 -0
- package/src/extensibility/tool-event-input.ts +80 -0
- package/src/extensibility/tool-proxy.ts +28 -0
- package/src/extensibility/utils.ts +192 -0
- package/src/goals/index.ts +3 -0
- package/src/goals/runtime.ts +521 -0
- package/src/goals/state.ts +37 -0
- package/src/goals/tools/goal-tool.ts +251 -0
- package/src/hindsight/backend.ts +354 -0
- package/src/hindsight/bank.ts +156 -0
- package/src/hindsight/client.ts +680 -0
- package/src/hindsight/config.ts +193 -0
- package/src/hindsight/content.ts +266 -0
- package/src/hindsight/index.ts +8 -0
- package/src/hindsight/mental-models.ts +429 -0
- package/src/hindsight/seeds.json +32 -0
- package/src/hindsight/state.ts +530 -0
- package/src/hindsight/transcript.ts +71 -0
- package/src/index.ts +66 -0
- package/src/internal-urls/agent-protocol.ts +180 -0
- package/src/internal-urls/artifact-protocol.ts +151 -0
- package/src/internal-urls/docs-index.ts +102 -0
- package/src/internal-urls/filesystem-resource.ts +34 -0
- package/src/internal-urls/history-protocol.ts +198 -0
- package/src/internal-urls/index.ts +28 -0
- package/src/internal-urls/issue-pr-protocol.ts +594 -0
- package/src/internal-urls/json-query.ts +126 -0
- package/src/internal-urls/local-protocol.ts +471 -0
- package/src/internal-urls/mcp-protocol.ts +168 -0
- package/src/internal-urls/memory-protocol.ts +380 -0
- package/src/internal-urls/omp-protocol.ts +94 -0
- package/src/internal-urls/parse.ts +103 -0
- package/src/internal-urls/registry-helpers.ts +132 -0
- package/src/internal-urls/router.ts +153 -0
- package/src/internal-urls/rule-protocol.ts +45 -0
- package/src/internal-urls/security-protocol.ts +261 -0
- package/src/internal-urls/skill-protocol.ts +131 -0
- package/src/internal-urls/ssh-protocol.ts +368 -0
- package/src/internal-urls/types.ts +196 -0
- package/src/internal-urls/vault-protocol.ts +940 -0
- package/src/internal-urls/xd-protocol.ts +46 -0
- package/src/irc/bus.ts +380 -0
- package/src/jsonrpc/message-framing.ts +142 -0
- package/src/launch/broker.ts +1368 -0
- package/src/launch/client.ts +521 -0
- package/src/launch/ensure.ts +73 -0
- package/src/launch/paths.ts +14 -0
- package/src/launch/presence.ts +82 -0
- package/src/launch/protocol.ts +448 -0
- package/src/launch/spawn-options.ts +17 -0
- package/src/launch/terminal-output-worker-client.ts +53 -0
- package/src/launch/terminal-output-worker-protocol.ts +11 -0
- package/src/launch/terminal-output-worker.ts +23 -0
- package/src/launch/terminal-output.ts +46 -0
- package/src/lib/xai-http.ts +150 -0
- package/src/live/attestation.ts +91 -0
- package/src/live/controller.ts +517 -0
- package/src/live/prompts/agent-final-message.md +3 -0
- package/src/live/prompts/live-instructions.md +23 -0
- package/src/live/protocol.ts +233 -0
- package/src/live/transport.ts +422 -0
- package/src/live/visualizer.ts +221 -0
- package/src/live/voices.ts +18 -0
- package/src/lsp/client.ts +1465 -0
- package/src/lsp/clients/biome-client.ts +263 -0
- package/src/lsp/clients/index.ts +50 -0
- package/src/lsp/clients/lsp-linter-client.ts +85 -0
- package/src/lsp/clients/swiftlint-client.ts +120 -0
- package/src/lsp/config.ts +549 -0
- package/src/lsp/defaults.json +499 -0
- package/src/lsp/deferred-diagnostics.ts +66 -0
- package/src/lsp/diagnostics-ledger.ts +51 -0
- package/src/lsp/edits.ts +288 -0
- package/src/lsp/format-options.ts +119 -0
- package/src/lsp/index.ts +2821 -0
- package/src/lsp/lspmux.ts +233 -0
- package/src/lsp/mux/daemon.ts +348 -0
- package/src/lsp/mux/protocol.ts +96 -0
- package/src/lsp/mux/server.ts +797 -0
- package/src/lsp/render.ts +668 -0
- package/src/lsp/startup-events.ts +13 -0
- package/src/lsp/types.ts +479 -0
- package/src/lsp/utils.ts +747 -0
- package/src/main.ts +1799 -0
- package/src/markit/NOTICE +32 -0
- package/src/markit/converters/docx.ts +56 -0
- package/src/markit/converters/epub.ts +136 -0
- package/src/markit/converters/pdf/columns.ts +103 -0
- package/src/markit/converters/pdf/extract.ts +598 -0
- package/src/markit/converters/pdf/grid.ts +780 -0
- package/src/markit/converters/pdf/headers.ts +106 -0
- package/src/markit/converters/pdf/index.ts +146 -0
- package/src/markit/converters/pdf/render.ts +501 -0
- package/src/markit/converters/pdf/types.ts +84 -0
- package/src/markit/converters/pptx.ts +325 -0
- package/src/markit/converters/xlsx.ts +173 -0
- package/src/markit/index.ts +2 -0
- package/src/markit/registry.ts +59 -0
- package/src/markit/types.ts +35 -0
- package/src/mcp/client.ts +511 -0
- package/src/mcp/config-writer.ts +377 -0
- package/src/mcp/config.ts +385 -0
- package/src/mcp/index.ts +29 -0
- package/src/mcp/json-rpc.ts +122 -0
- package/src/mcp/loader.ts +125 -0
- package/src/mcp/manager.ts +1524 -0
- package/src/mcp/oauth-credentials.ts +104 -0
- package/src/mcp/oauth-discovery.ts +587 -0
- package/src/mcp/oauth-flow.ts +830 -0
- package/src/mcp/render.ts +214 -0
- package/src/mcp/request-id.ts +24 -0
- package/src/mcp/smithery-auth.ts +108 -0
- package/src/mcp/smithery-connect.ts +154 -0
- package/src/mcp/smithery-registry.ts +500 -0
- package/src/mcp/startup-events.ts +116 -0
- package/src/mcp/timeout.ts +59 -0
- package/src/mcp/tool-bridge.ts +691 -0
- package/src/mcp/tool-cache.ts +117 -0
- package/src/mcp/transports/header-policy.ts +95 -0
- package/src/mcp/transports/http.ts +508 -0
- package/src/mcp/transports/index.ts +7 -0
- package/src/mcp/transports/sse.ts +372 -0
- package/src/mcp/transports/stdio.ts +905 -0
- package/src/mcp/types.ts +467 -0
- package/src/memories/index.ts +1434 -0
- package/src/memories/storage.ts +578 -0
- package/src/memory-backend/index.ts +19 -0
- package/src/memory-backend/local-backend.ts +47 -0
- package/src/memory-backend/messages.ts +19 -0
- package/src/memory-backend/off-backend.ts +25 -0
- package/src/memory-backend/resolve.ts +25 -0
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/tool-names.ts +2 -0
- package/src/memory-backend/types.ts +166 -0
- package/src/mnemopi/backend.ts +629 -0
- package/src/mnemopi/config.ts +267 -0
- package/src/mnemopi/embed-client.ts +293 -0
- package/src/mnemopi/embed-protocol.ts +35 -0
- package/src/mnemopi/embed-worker.ts +114 -0
- package/src/mnemopi/index.ts +3 -0
- package/src/mnemopi/state.ts +940 -0
- package/src/modes/acp/acp-agent.ts +2595 -0
- package/src/modes/acp/acp-client-bridge.ts +154 -0
- package/src/modes/acp/acp-event-mapper.ts +1084 -0
- package/src/modes/acp/acp-mode.ts +48 -0
- package/src/modes/acp/index.ts +2 -0
- package/src/modes/acp/terminal-auth.ts +37 -0
- package/src/modes/components/advisor-config.ts +635 -0
- package/src/modes/components/advisor-message.ts +109 -0
- package/src/modes/components/agent-dashboard.ts +1252 -0
- package/src/modes/components/agent-hub-projection.ts +248 -0
- package/src/modes/components/agent-hub-renderer.ts +194 -0
- package/src/modes/components/agent-hub.ts +1126 -0
- package/src/modes/components/agent-transcript-viewer.ts +647 -0
- package/src/modes/components/ask-dialog.ts +1017 -0
- package/src/modes/components/assistant-message.ts +978 -0
- package/src/modes/components/background-tan-message.ts +36 -0
- package/src/modes/components/bash-execution.ts +233 -0
- package/src/modes/components/bordered-loader.ts +41 -0
- package/src/modes/components/btw-panel.ts +161 -0
- package/src/modes/components/cache-invalidation-marker.ts +110 -0
- package/src/modes/components/chat-block.ts +111 -0
- package/src/modes/components/chat-transcript-builder.ts +518 -0
- package/src/modes/components/codex-reset-fireworks.ts +369 -0
- package/src/modes/components/collab-prompt-message.ts +32 -0
- package/src/modes/components/compaction-summary-message.ts +221 -0
- package/src/modes/components/copy-selector.ts +218 -0
- package/src/modes/components/countdown-timer.ts +75 -0
- package/src/modes/components/custom-editor.ts +1036 -0
- package/src/modes/components/custom-message.ts +70 -0
- package/src/modes/components/diff.ts +254 -0
- package/src/modes/components/dynamic-border.ts +37 -0
- package/src/modes/components/error-banner.ts +33 -0
- package/src/modes/components/eval-execution.ts +169 -0
- package/src/modes/components/execution-shared.ts +101 -0
- package/src/modes/components/extensions/extension-dashboard.ts +492 -0
- package/src/modes/components/extensions/extension-list.ts +507 -0
- package/src/modes/components/extensions/index.ts +9 -0
- package/src/modes/components/extensions/inspector-panel.ts +326 -0
- package/src/modes/components/extensions/state-manager.ts +648 -0
- package/src/modes/components/extensions/types.ts +186 -0
- package/src/modes/components/footer.ts +274 -0
- package/src/modes/components/history-search.ts +268 -0
- package/src/modes/components/hook-editor.ts +213 -0
- package/src/modes/components/hook-input.ts +87 -0
- package/src/modes/components/hook-message.ts +67 -0
- package/src/modes/components/hook-selector.ts +691 -0
- package/src/modes/components/index.ts +42 -0
- package/src/modes/components/keybinding-hints.ts +56 -0
- package/src/modes/components/late-diagnostics-message.ts +60 -0
- package/src/modes/components/login-dialog.ts +197 -0
- package/src/modes/components/logout-account-selector.ts +130 -0
- package/src/modes/components/mcp-add-wizard.ts +1413 -0
- package/src/modes/components/message-frame.ts +98 -0
- package/src/modes/components/model-browser.ts +888 -0
- package/src/modes/components/model-hub.ts +2014 -0
- package/src/modes/components/model-picker.ts +237 -0
- package/src/modes/components/move-overlay.ts +293 -0
- package/src/modes/components/oauth-selector.ts +474 -0
- package/src/modes/components/omfg-panel.ts +141 -0
- package/src/modes/components/overlay-box.ts +109 -0
- package/src/modes/components/pause-screen.ts +208 -0
- package/src/modes/components/plan-review-overlay.ts +1226 -0
- package/src/modes/components/plan-toc.ts +138 -0
- package/src/modes/components/plugin-selector.ts +100 -0
- package/src/modes/components/plugin-settings.ts +745 -0
- package/src/modes/components/queue-mode-selector.ts +61 -0
- package/src/modes/components/read-tool-group.ts +856 -0
- package/src/modes/components/reset-usage-selector.ts +161 -0
- package/src/modes/components/segment-track.ts +89 -0
- package/src/modes/components/select-list-mouse-routing.ts +35 -0
- package/src/modes/components/selector-helpers.ts +129 -0
- package/src/modes/components/session-account-selector.ts +62 -0
- package/src/modes/components/session-selector.ts +1035 -0
- package/src/modes/components/settings-defs.ts +267 -0
- package/src/modes/components/settings-selector.ts +1445 -0
- package/src/modes/components/show-images-selector.ts +50 -0
- package/src/modes/components/skill-message.ts +110 -0
- package/src/modes/components/snapcompact-shape-preview-doc.md +14 -0
- package/src/modes/components/snapcompact-shape-preview.ts +192 -0
- package/src/modes/components/status-line/component.ts +1843 -0
- package/src/modes/components/status-line/context-thresholds.ts +86 -0
- package/src/modes/components/status-line/git-utils.ts +42 -0
- package/src/modes/components/status-line/index.ts +5 -0
- package/src/modes/components/status-line/presets.ts +106 -0
- package/src/modes/components/status-line/segments.ts +710 -0
- package/src/modes/components/status-line/separators.ts +55 -0
- package/src/modes/components/status-line/types.ts +159 -0
- package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
- package/src/modes/components/theme-selector.ts +68 -0
- package/src/modes/components/thinking-selector.ts +57 -0
- package/src/modes/components/tiny-title-download-progress.ts +90 -0
- package/src/modes/components/tips.txt +26 -0
- package/src/modes/components/todo-reminder.ts +43 -0
- package/src/modes/components/tool-execution.ts +1467 -0
- package/src/modes/components/transcript-container.ts +527 -0
- package/src/modes/components/tree-selector.ts +1006 -0
- package/src/modes/components/ttsr-notification.ts +123 -0
- package/src/modes/components/usage-row.ts +52 -0
- package/src/modes/components/user-message-selector.ts +227 -0
- package/src/modes/components/user-message.ts +167 -0
- package/src/modes/components/visual-truncate.ts +63 -0
- package/src/modes/components/welcome.ts +578 -0
- package/src/modes/controllers/btw-controller.ts +246 -0
- package/src/modes/controllers/command-controller-shared.ts +109 -0
- package/src/modes/controllers/command-controller.ts +2024 -0
- package/src/modes/controllers/event-controller.ts +2173 -0
- package/src/modes/controllers/extension-ui-controller.ts +1243 -0
- package/src/modes/controllers/input-controller.ts +2037 -0
- package/src/modes/controllers/live-command-controller.ts +261 -0
- package/src/modes/controllers/mcp-command-controller.ts +2552 -0
- package/src/modes/controllers/omfg-controller.ts +287 -0
- package/src/modes/controllers/omfg-rule.ts +647 -0
- package/src/modes/controllers/selector-controller.ts +2058 -0
- package/src/modes/controllers/session-focus-controller.ts +117 -0
- package/src/modes/controllers/ssh-command-controller.ts +385 -0
- package/src/modes/controllers/streaming-reveal.ts +399 -0
- package/src/modes/controllers/tan-command-controller.ts +243 -0
- package/src/modes/controllers/todo-command-controller.ts +487 -0
- package/src/modes/controllers/tool-args-reveal.ts +591 -0
- package/src/modes/data/emojis.json +1 -0
- package/src/modes/emoji-autocomplete.ts +285 -0
- package/src/modes/github-ref-autocomplete.ts +75 -0
- package/src/modes/gradient-highlight.ts +99 -0
- package/src/modes/image-references.ts +137 -0
- package/src/modes/index.ts +10 -0
- package/src/modes/interactive-mode.ts +5055 -0
- package/src/modes/internal-url-autocomplete.ts +158 -0
- package/src/modes/loop-limit.ts +192 -0
- package/src/modes/magic-keyword-boundary.ts +23 -0
- package/src/modes/magic-keywords.ts +42 -0
- package/src/modes/markdown-prose.ts +247 -0
- package/src/modes/oauth-manual-input.ts +69 -0
- package/src/modes/orchestrate.ts +43 -0
- package/src/modes/print-mode.ts +282 -0
- package/src/modes/prompt-action-autocomplete.ts +322 -0
- package/src/modes/queue-input.ts +132 -0
- package/src/modes/rpc/host-tools.ts +204 -0
- package/src/modes/rpc/host-uris.ts +241 -0
- package/src/modes/rpc/rpc-client.ts +1213 -0
- package/src/modes/rpc/rpc-frame.ts +316 -0
- package/src/modes/rpc/rpc-input.ts +38 -0
- package/src/modes/rpc/rpc-messages.ts +127 -0
- package/src/modes/rpc/rpc-mode.ts +1519 -0
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +544 -0
- package/src/modes/running-subagent-badge.ts +13 -0
- package/src/modes/runtime-init.ts +144 -0
- package/src/modes/session-observer-registry.ts +223 -0
- package/src/modes/session-teardown.ts +82 -0
- package/src/modes/setup-version.ts +11 -0
- package/src/modes/setup-wizard/index.ts +103 -0
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +103 -0
- package/src/modes/setup-wizard/scenes/model.ts +132 -0
- package/src/modes/setup-wizard/scenes/outro.ts +35 -0
- package/src/modes/setup-wizard/scenes/providers.ts +105 -0
- package/src/modes/setup-wizard/scenes/sign-in.ts +312 -0
- package/src/modes/setup-wizard/scenes/splash.ts +201 -0
- package/src/modes/setup-wizard/scenes/theme.ts +330 -0
- package/src/modes/setup-wizard/scenes/types.ts +65 -0
- package/src/modes/setup-wizard/scenes/web-search.ts +153 -0
- package/src/modes/setup-wizard/startup-splash.ts +107 -0
- package/src/modes/setup-wizard/wizard-overlay.ts +335 -0
- package/src/modes/shared.ts +49 -0
- package/src/modes/skill-command.ts +91 -0
- package/src/modes/theme/dark.json +95 -0
- package/src/modes/theme/defaults/alabaster.json +93 -0
- package/src/modes/theme/defaults/amethyst.json +96 -0
- package/src/modes/theme/defaults/anthracite.json +93 -0
- package/src/modes/theme/defaults/basalt.json +91 -0
- package/src/modes/theme/defaults/birch.json +95 -0
- package/src/modes/theme/defaults/dark-abyss.json +91 -0
- package/src/modes/theme/defaults/dark-arctic.json +104 -0
- package/src/modes/theme/defaults/dark-aurora.json +95 -0
- package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
- package/src/modes/theme/defaults/dark-cavern.json +91 -0
- package/src/modes/theme/defaults/dark-copper.json +95 -0
- package/src/modes/theme/defaults/dark-cosmos.json +90 -0
- package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
- package/src/modes/theme/defaults/dark-dracula.json +98 -0
- package/src/modes/theme/defaults/dark-eclipse.json +91 -0
- package/src/modes/theme/defaults/dark-ember.json +95 -0
- package/src/modes/theme/defaults/dark-equinox.json +90 -0
- package/src/modes/theme/defaults/dark-forest.json +96 -0
- package/src/modes/theme/defaults/dark-github.json +105 -0
- package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
- package/src/modes/theme/defaults/dark-lavender.json +95 -0
- package/src/modes/theme/defaults/dark-lunar.json +89 -0
- package/src/modes/theme/defaults/dark-midnight.json +95 -0
- package/src/modes/theme/defaults/dark-monochrome.json +94 -0
- package/src/modes/theme/defaults/dark-monokai.json +98 -0
- package/src/modes/theme/defaults/dark-nebula.json +90 -0
- package/src/modes/theme/defaults/dark-nord.json +97 -0
- package/src/modes/theme/defaults/dark-ocean.json +101 -0
- package/src/modes/theme/defaults/dark-one.json +100 -0
- package/src/modes/theme/defaults/dark-poimandres.json +143 -0
- package/src/modes/theme/defaults/dark-rainforest.json +91 -0
- package/src/modes/theme/defaults/dark-reef.json +91 -0
- package/src/modes/theme/defaults/dark-retro.json +92 -0
- package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
- package/src/modes/theme/defaults/dark-sakura.json +95 -0
- package/src/modes/theme/defaults/dark-slate.json +95 -0
- package/src/modes/theme/defaults/dark-solarized.json +97 -0
- package/src/modes/theme/defaults/dark-solstice.json +90 -0
- package/src/modes/theme/defaults/dark-starfall.json +91 -0
- package/src/modes/theme/defaults/dark-sunset.json +99 -0
- package/src/modes/theme/defaults/dark-swamp.json +90 -0
- package/src/modes/theme/defaults/dark-synthwave.json +103 -0
- package/src/modes/theme/defaults/dark-taiga.json +91 -0
- package/src/modes/theme/defaults/dark-terminal.json +95 -0
- package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
- package/src/modes/theme/defaults/dark-tundra.json +91 -0
- package/src/modes/theme/defaults/dark-twilight.json +91 -0
- package/src/modes/theme/defaults/dark-volcanic.json +91 -0
- package/src/modes/theme/defaults/graphite.json +92 -0
- package/src/modes/theme/defaults/index.ts +199 -0
- package/src/modes/theme/defaults/light-arctic.json +107 -0
- package/src/modes/theme/defaults/light-aurora-day.json +91 -0
- package/src/modes/theme/defaults/light-canyon.json +91 -0
- package/src/modes/theme/defaults/light-catppuccin.json +106 -0
- package/src/modes/theme/defaults/light-cirrus.json +90 -0
- package/src/modes/theme/defaults/light-coral.json +95 -0
- package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
- package/src/modes/theme/defaults/light-dawn.json +90 -0
- package/src/modes/theme/defaults/light-dunes.json +91 -0
- package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
- package/src/modes/theme/defaults/light-forest.json +100 -0
- package/src/modes/theme/defaults/light-frost.json +95 -0
- package/src/modes/theme/defaults/light-github.json +115 -0
- package/src/modes/theme/defaults/light-glacier.json +91 -0
- package/src/modes/theme/defaults/light-gruvbox.json +108 -0
- package/src/modes/theme/defaults/light-haze.json +90 -0
- package/src/modes/theme/defaults/light-honeycomb.json +95 -0
- package/src/modes/theme/defaults/light-lagoon.json +91 -0
- package/src/modes/theme/defaults/light-lavender.json +95 -0
- package/src/modes/theme/defaults/light-meadow.json +91 -0
- package/src/modes/theme/defaults/light-mint.json +95 -0
- package/src/modes/theme/defaults/light-monochrome.json +101 -0
- package/src/modes/theme/defaults/light-ocean.json +99 -0
- package/src/modes/theme/defaults/light-one.json +99 -0
- package/src/modes/theme/defaults/light-opal.json +91 -0
- package/src/modes/theme/defaults/light-orchard.json +91 -0
- package/src/modes/theme/defaults/light-paper.json +95 -0
- package/src/modes/theme/defaults/light-poimandres.json +143 -0
- package/src/modes/theme/defaults/light-prism.json +90 -0
- package/src/modes/theme/defaults/light-retro.json +98 -0
- package/src/modes/theme/defaults/light-sand.json +95 -0
- package/src/modes/theme/defaults/light-savanna.json +91 -0
- package/src/modes/theme/defaults/light-solarized.json +102 -0
- package/src/modes/theme/defaults/light-soleil.json +90 -0
- package/src/modes/theme/defaults/light-sunset.json +99 -0
- package/src/modes/theme/defaults/light-synthwave.json +98 -0
- package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
- package/src/modes/theme/defaults/light-wetland.json +91 -0
- package/src/modes/theme/defaults/light-zenith.json +89 -0
- package/src/modes/theme/defaults/limestone.json +94 -0
- package/src/modes/theme/defaults/mahogany.json +97 -0
- package/src/modes/theme/defaults/marble.json +93 -0
- package/src/modes/theme/defaults/obsidian.json +91 -0
- package/src/modes/theme/defaults/onyx.json +91 -0
- package/src/modes/theme/defaults/pearl.json +93 -0
- package/src/modes/theme/defaults/porcelain.json +91 -0
- package/src/modes/theme/defaults/quartz.json +96 -0
- package/src/modes/theme/defaults/sandstone.json +95 -0
- package/src/modes/theme/defaults/titanium.json +90 -0
- package/src/modes/theme/light.json +93 -0
- package/src/modes/theme/mermaid-cache.ts +92 -0
- package/src/modes/theme/shimmer.ts +305 -0
- package/src/modes/theme/theme-schema.json +463 -0
- package/src/modes/theme/theme.ts +3171 -0
- package/src/modes/turn-budget.ts +31 -0
- package/src/modes/types.ts +494 -0
- package/src/modes/ultrathink.ts +42 -0
- package/src/modes/utils/context-usage.ts +518 -0
- package/src/modes/utils/copy-targets.ts +378 -0
- package/src/modes/utils/hotkeys-markdown.ts +65 -0
- package/src/modes/utils/interactive-context-helpers.ts +31 -0
- package/src/modes/utils/keybinding-matchers.ts +86 -0
- package/src/modes/utils/tools-markdown.ts +31 -0
- package/src/modes/utils/transcript-render-helpers.ts +253 -0
- package/src/modes/utils/ui-helpers.ts +976 -0
- package/src/modes/warp-events.ts +232 -0
- package/src/modes/workflow.ts +55 -0
- package/src/plan-mode/approved-plan.ts +194 -0
- package/src/plan-mode/model-transition.ts +51 -0
- package/src/plan-mode/plan-files.ts +40 -0
- package/src/plan-mode/plan-handoff.ts +37 -0
- package/src/plan-mode/plan-protection.ts +31 -0
- package/src/plan-mode/state.ts +6 -0
- package/src/priority.json +60 -0
- package/src/prompts/advisor/active-repo-watchdog.md +6 -0
- package/src/prompts/advisor/advise-tool.md +3 -0
- package/src/prompts/advisor/context-files.md +8 -0
- package/src/prompts/advisor/system.md +98 -0
- package/src/prompts/agents/designer.md +74 -0
- package/src/prompts/agents/frontmatter.md +12 -0
- package/src/prompts/agents/init.md +33 -0
- package/src/prompts/agents/librarian.md +119 -0
- package/src/prompts/agents/reviewer.md +139 -0
- package/src/prompts/agents/scout.md +58 -0
- package/src/prompts/agents/security-reviewer.md +75 -0
- package/src/prompts/agents/task.md +17 -0
- package/src/prompts/bench/cache-prefix-chunk.md +1 -0
- package/src/prompts/bench/cache-prefix.md +3 -0
- package/src/prompts/bench/cache-suffix.md +1 -0
- package/src/prompts/bench.md +6 -0
- package/src/prompts/ci-green-request.md +36 -0
- package/src/prompts/dry-balance-bench.md +8 -0
- package/src/prompts/goals/goal-budget-limit.md +16 -0
- package/src/prompts/goals/goal-continuation.md +28 -0
- package/src/prompts/goals/goal-mode-active.md +23 -0
- package/src/prompts/goals/goal-mode-context.md +4 -0
- package/src/prompts/goals/goal-todo-context.md +12 -0
- package/src/prompts/goals/guided-goal-interview.md +43 -0
- package/src/prompts/memories/consolidation.md +30 -0
- package/src/prompts/memories/consolidation_system.md +4 -0
- package/src/prompts/memories/read-path.md +17 -0
- package/src/prompts/memories/stage_one_input.md +6 -0
- package/src/prompts/memories/stage_one_system.md +21 -0
- package/src/prompts/review-custom-request.md +21 -0
- package/src/prompts/review-headless-request.md +16 -0
- package/src/prompts/review-request.md +68 -0
- package/src/prompts/security/scan-coordinator.md +7 -0
- package/src/prompts/security/scan-request.md +21 -0
- package/src/prompts/security/validate-request.md +8 -0
- package/src/prompts/session/launch-completion.md +1 -0
- package/src/prompts/skills/autoload.md +8 -0
- package/src/prompts/skills/user-invocation.md +11 -0
- package/src/prompts/steering/parent-irc.md +5 -0
- package/src/prompts/steering/user-interjection.md +6 -0
- package/src/prompts/system/active-repo-context.md +4 -0
- package/src/prompts/system/agent-creation-architect.md +50 -0
- package/src/prompts/system/agent-creation-user.md +6 -0
- package/src/prompts/system/auto-continue.md +1 -0
- package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
- package/src/prompts/system/auto-thinking-difficulty.md +14 -0
- package/src/prompts/system/autolearn-guidance-learn.md +1 -0
- package/src/prompts/system/autolearn-guidance.md +7 -0
- package/src/prompts/system/autolearn-nudge-autocontinue.md +5 -0
- package/src/prompts/system/background-tan-dispatch.md +8 -0
- package/src/prompts/system/btw-user.md +8 -0
- package/src/prompts/system/commit-message-system.md +14 -0
- package/src/prompts/system/computer-safety.md +14 -0
- package/src/prompts/system/custom-system-prompt.md +64 -0
- package/src/prompts/system/eager-task.md +7 -0
- package/src/prompts/system/eager-todo.md +18 -0
- package/src/prompts/system/empty-stop-retry.md +4 -0
- package/src/prompts/system/gemini-tool-call-reminder.md +9 -0
- package/src/prompts/system/interrupted-thinking.md +7 -0
- package/src/prompts/system/irc-autoreply.md +6 -0
- package/src/prompts/system/irc-incoming.md +9 -0
- package/src/prompts/system/manual-continue.md +7 -0
- package/src/prompts/system/mcp-xdev-guidance.md +11 -0
- package/src/prompts/system/memory-consolidation-system.md +8 -0
- package/src/prompts/system/memory-extraction-system.md +26 -0
- package/src/prompts/system/mid-run-todo-nudge.md +3 -0
- package/src/prompts/system/omfg-user.md +50 -0
- package/src/prompts/system/orchestrate-notice.md +40 -0
- package/src/prompts/system/personalities/default.md +18 -0
- package/src/prompts/system/personalities/friendly.md +17 -0
- package/src/prompts/system/personalities/pragmatic.md +15 -0
- package/src/prompts/system/plan-mode-active.md +125 -0
- package/src/prompts/system/plan-mode-approved.md +22 -0
- package/src/prompts/system/plan-mode-compact-instructions.md +17 -0
- package/src/prompts/system/plan-mode-reference.md +10 -0
- package/src/prompts/system/plan-mode-subagent.md +33 -0
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
- package/src/prompts/system/plan-yolo-handoff.md +5 -0
- package/src/prompts/system/prewalk-checklist.md +7 -0
- package/src/prompts/system/prewalk-continue.md +1 -0
- package/src/prompts/system/prewalk-plan.md +13 -0
- package/src/prompts/system/project-prompt.md +61 -0
- package/src/prompts/system/recap-user.md +9 -0
- package/src/prompts/system/resolve-device-reminder.md +3 -0
- package/src/prompts/system/rewind-report.md +6 -0
- package/src/prompts/system/side-channel-no-tools.md +3 -0
- package/src/prompts/system/snapcompact-context-frames-note.md +1 -0
- package/src/prompts/system/snapcompact-context-stub.md +1 -0
- package/src/prompts/system/snapcompact-system-frames-note.md +1 -0
- package/src/prompts/system/snapcompact-system-stub.md +1 -0
- package/src/prompts/system/snapcompact-toolresult-note.md +1 -0
- package/src/prompts/system/speech-rewrite.md +15 -0
- package/src/prompts/system/subagent-async-pending.md +6 -0
- package/src/prompts/system/subagent-system-prompt.md +73 -0
- package/src/prompts/system/subagent-user-prompt.md +3 -0
- package/src/prompts/system/subagent-yield-reminder.md +23 -0
- package/src/prompts/system/system-prompt.md +263 -0
- package/src/prompts/system/tan-context-switch.md +17 -0
- package/src/prompts/system/task-label.md +23 -0
- package/src/prompts/system/thinking-loop-redirect.md +10 -0
- package/src/prompts/system/title-marker-instruction.md +1 -0
- package/src/prompts/system/title-system.md +16 -0
- package/src/prompts/system/tool-call-loop-redirect.md +8 -0
- package/src/prompts/system/ttsr-interrupt.md +7 -0
- package/src/prompts/system/ttsr-tool-reminder.md +5 -0
- package/src/prompts/system/ultrathink-notice.md +3 -0
- package/src/prompts/system/unexpected-stop-classifier.md +17 -0
- package/src/prompts/system/unexpected-stop-retry.md +4 -0
- package/src/prompts/system/vibe-mode-active.md +26 -0
- package/src/prompts/system/web-search.md +25 -0
- package/src/prompts/system/workflow-notice.md +112 -0
- package/src/prompts/system/xdev-mount-notice.md +20 -0
- package/src/prompts/tools/apply-patch.md +65 -0
- package/src/prompts/tools/ask.md +22 -0
- package/src/prompts/tools/ast-edit.md +11 -0
- package/src/prompts/tools/ast-grep.md +19 -0
- package/src/prompts/tools/async-result.md +8 -0
- package/src/prompts/tools/bash.md +23 -0
- package/src/prompts/tools/browser.md +29 -0
- package/src/prompts/tools/checkpoint.md +15 -0
- package/src/prompts/tools/computer.md +26 -0
- package/src/prompts/tools/debug.md +3 -0
- package/src/prompts/tools/eval.md +45 -0
- package/src/prompts/tools/github.md +22 -0
- package/src/prompts/tools/glob.md +16 -0
- package/src/prompts/tools/goal.md +11 -0
- package/src/prompts/tools/grep.md +13 -0
- package/src/prompts/tools/hub.md +34 -0
- package/src/prompts/tools/image-attachment-describe-system.md +8 -0
- package/src/prompts/tools/image-attachment-describe.md +10 -0
- package/src/prompts/tools/image-gen.md +7 -0
- package/src/prompts/tools/inspect-image-system.md +20 -0
- package/src/prompts/tools/inspect-image.md +22 -0
- package/src/prompts/tools/learn.md +7 -0
- package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
- package/src/prompts/tools/lsp.md +19 -0
- package/src/prompts/tools/manage-skill.md +9 -0
- package/src/prompts/tools/memory-edit.md +12 -0
- package/src/prompts/tools/patch.md +57 -0
- package/src/prompts/tools/read.md +27 -0
- package/src/prompts/tools/recall.md +7 -0
- package/src/prompts/tools/reflect.md +5 -0
- package/src/prompts/tools/replace.md +30 -0
- package/src/prompts/tools/retain.md +6 -0
- package/src/prompts/tools/rewind.md +14 -0
- package/src/prompts/tools/security-publish.md +1 -0
- package/src/prompts/tools/security-scan.md +1 -0
- package/src/prompts/tools/task-async-contract.md +1 -0
- package/src/prompts/tools/task-summary.md +20 -0
- package/src/prompts/tools/task.md +83 -0
- package/src/prompts/tools/todo.md +42 -0
- package/src/prompts/tools/vibe-kill.md +3 -0
- package/src/prompts/tools/vibe-list.md +3 -0
- package/src/prompts/tools/vibe-send.md +9 -0
- package/src/prompts/tools/vibe-spawn.md +10 -0
- package/src/prompts/tools/vibe-turn-result.md +19 -0
- package/src/prompts/tools/vibe-wait.md +8 -0
- package/src/prompts/tools/web-search.md +8 -0
- package/src/prompts/tools/write.md +14 -0
- package/src/registry/agent-lifecycle.ts +505 -0
- package/src/registry/agent-registry.ts +287 -0
- package/src/registry/persisted-agents.ts +423 -0
- package/src/sdk.ts +3820 -0
- package/src/secrets/index.ts +375 -0
- package/src/secrets/obfuscator.ts +2629 -0
- package/src/secrets/regex.ts +21 -0
- package/src/security/auth.ts +98 -0
- package/src/security/cloud.ts +686 -0
- package/src/security/comparison.ts +255 -0
- package/src/security/contracts/ids.ts +111 -0
- package/src/security/contracts/index.ts +4 -0
- package/src/security/contracts/schemas.ts +219 -0
- package/src/security/contracts/types.ts +254 -0
- package/src/security/contracts/validation.ts +69 -0
- package/src/security/coordinator.ts +708 -0
- package/src/security/importers/codex-security.ts +387 -0
- package/src/security/importers/index.ts +2 -0
- package/src/security/importers/sarif.ts +357 -0
- package/src/security/index.ts +13 -0
- package/src/security/preflight.ts +405 -0
- package/src/security/provenance.ts +106 -0
- package/src/security/publication.ts +326 -0
- package/src/security/remediation.ts +93 -0
- package/src/security/resource-output.ts +50 -0
- package/src/security/sarif.ts +78 -0
- package/src/security/store.ts +430 -0
- package/src/session/acp-permission-gate.ts +165 -0
- package/src/session/agent-session-events.ts +67 -0
- package/src/session/agent-session-types.ts +407 -0
- package/src/session/agent-session.ts +9000 -0
- package/src/session/agent-storage.ts +807 -0
- package/src/session/artifacts.ts +154 -0
- package/src/session/async-job-delivery.ts +82 -0
- package/src/session/auth-broker-config.ts +92 -0
- package/src/session/auth-storage.ts +25 -0
- package/src/session/bash-runner.ts +326 -0
- package/src/session/blob-store.ts +295 -0
- package/src/session/checkpoint-entries.ts +81 -0
- package/src/session/claude-session-store.ts +426 -0
- package/src/session/client-bridge.ts +85 -0
- package/src/session/codex-auto-reset.ts +673 -0
- package/src/session/codex-session-store.ts +673 -0
- package/src/session/compact-modes.ts +105 -0
- package/src/session/credential-pin.ts +93 -0
- package/src/session/eval-runner.ts +219 -0
- package/src/session/exit-diagnostics.ts +310 -0
- package/src/session/foreign-session-import.ts +52 -0
- package/src/session/foreign-session-jsonl.ts +29 -0
- package/src/session/foreign-session-store.ts +26 -0
- package/src/session/history-storage.ts +329 -0
- package/src/session/indexed-session-storage.ts +553 -0
- package/src/session/irc-bridge.ts +203 -0
- package/src/session/launch-completion.ts +37 -0
- package/src/session/messages.ts +1304 -0
- package/src/session/model-controls.ts +757 -0
- package/src/session/prewalk.ts +279 -0
- package/src/session/provider-image-budget.ts +86 -0
- package/src/session/queued-messages.ts +99 -0
- package/src/session/redis-session-storage.ts +257 -0
- package/src/session/retry-fallback-chains.ts +455 -0
- package/src/session/role-models.ts +85 -0
- package/src/session/session-advisors.ts +1896 -0
- package/src/session/session-context.ts +584 -0
- package/src/session/session-dump-format.ts +216 -0
- package/src/session/session-entries.ts +306 -0
- package/src/session/session-handoff.ts +325 -0
- package/src/session/session-history-format.ts +459 -0
- package/src/session/session-listing.ts +715 -0
- package/src/session/session-loader.ts +362 -0
- package/src/session/session-maintenance.ts +3115 -0
- package/src/session/session-manager.ts +2747 -0
- package/src/session/session-memory.ts +222 -0
- package/src/session/session-metadata.ts +53 -0
- package/src/session/session-migrations.ts +78 -0
- package/src/session/session-paths.ts +280 -0
- package/src/session/session-persistence.ts +293 -0
- package/src/session/session-provider-boundary.ts +306 -0
- package/src/session/session-stats.ts +349 -0
- package/src/session/session-storage.ts +774 -0
- package/src/session/session-title-slot.ts +141 -0
- package/src/session/session-tools.ts +1385 -0
- package/src/session/session-workspace.ts +53 -0
- package/src/session/settings-stream-fn.ts +79 -0
- package/src/session/shake-types.ts +43 -0
- package/src/session/snapcompact-inline.ts +545 -0
- package/src/session/snapcompact-savings-journal.ts +113 -0
- package/src/session/sql-session-storage.ts +374 -0
- package/src/session/stream-guards.ts +417 -0
- package/src/session/streaming-output.ts +1459 -0
- package/src/session/todo-tracker.ts +380 -0
- package/src/session/tool-choice-queue.ts +305 -0
- package/src/session/ttsr-coordinator.ts +496 -0
- package/src/session/turn-persistence.ts +142 -0
- package/src/session/turn-recovery.ts +2005 -0
- package/src/session/unexpected-stop-classifier.ts +141 -0
- package/src/session/yield-queue.ts +288 -0
- package/src/slash-commands/acp-builtins.ts +70 -0
- package/src/slash-commands/available-commands.ts +105 -0
- package/src/slash-commands/builtin-registry.ts +3149 -0
- package/src/slash-commands/helpers/active-oauth-account.ts +80 -0
- package/src/slash-commands/helpers/collab-qrcode.ts +28 -0
- package/src/slash-commands/helpers/context-report.ts +66 -0
- package/src/slash-commands/helpers/format.ts +46 -0
- package/src/slash-commands/helpers/logout.ts +108 -0
- package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
- package/src/slash-commands/helpers/mcp.ts +533 -0
- package/src/slash-commands/helpers/parse.ts +85 -0
- package/src/slash-commands/helpers/reset-usage.ts +68 -0
- package/src/slash-commands/helpers/security.ts +451 -0
- package/src/slash-commands/helpers/session-pin.ts +44 -0
- package/src/slash-commands/helpers/ssh.ts +196 -0
- package/src/slash-commands/helpers/stats-dashboard.ts +86 -0
- package/src/slash-commands/helpers/todo.ts +285 -0
- package/src/slash-commands/helpers/usage-report.ts +198 -0
- package/src/slash-commands/marketplace-install-parser.ts +99 -0
- package/src/slash-commands/types.ts +139 -0
- package/src/ssh/config-writer.ts +183 -0
- package/src/ssh/connection-manager.ts +667 -0
- package/src/ssh/file-transfer.ts +214 -0
- package/src/ssh/sshfs-mount.ts +163 -0
- package/src/ssh/utils.ts +51 -0
- package/src/startup-splash.ts +19 -0
- package/src/stt/asr-client.ts +401 -0
- package/src/stt/asr-protocol.ts +65 -0
- package/src/stt/asr-worker.ts +603 -0
- package/src/stt/downloader.ts +142 -0
- package/src/stt/endpointer.ts +259 -0
- package/src/stt/index.ts +6 -0
- package/src/stt/models.ts +150 -0
- package/src/stt/sherpa-runtime.ts +71 -0
- package/src/stt/stt-controller.ts +320 -0
- package/src/stt/submit-trigger.ts +74 -0
- package/src/subprocess/worker-client.ts +463 -0
- package/src/subprocess/worker-runtime.ts +494 -0
- package/src/system-prompt.ts +921 -0
- package/src/task/agents.ts +170 -0
- package/src/task/commands.ts +132 -0
- package/src/task/discovery.ts +145 -0
- package/src/task/executor.ts +3431 -0
- package/src/task/index.ts +1515 -0
- package/src/task/isolation-ownership.ts +106 -0
- package/src/task/isolation-runner.ts +444 -0
- package/src/task/label.ts +40 -0
- package/src/task/name-generator.ts +1577 -0
- package/src/task/omp-command.ts +26 -0
- package/src/task/output-manager.ts +115 -0
- package/src/task/parallel.ts +221 -0
- package/src/task/persisted-revive.ts +173 -0
- package/src/task/prewalk.ts +6 -0
- package/src/task/prompt-policy.ts +8 -0
- package/src/task/provider-concurrency.ts +100 -0
- package/src/task/read-only-policy.ts +27 -0
- package/src/task/render.ts +1830 -0
- package/src/task/renderer.ts +14 -0
- package/src/task/repair-args.ts +118 -0
- package/src/task/spawn-policy.ts +72 -0
- package/src/task/structured-subagent.ts +676 -0
- package/src/task/subprocess-tool-registry.ts +88 -0
- package/src/task/types.ts +555 -0
- package/src/task/worktree.ts +967 -0
- package/src/task/yield-assembly.ts +198 -0
- package/src/telemetry-export.ts +504 -0
- package/src/thinking.ts +377 -0
- package/src/tiny/device.ts +111 -0
- package/src/tiny/dtype.ts +101 -0
- package/src/tiny/message-preproc.ts +155 -0
- package/src/tiny/models.ts +268 -0
- package/src/tiny/text.ts +290 -0
- package/src/tiny/title-client.ts +460 -0
- package/src/tiny/title-protocol.ts +56 -0
- package/src/tiny/worker.ts +354 -0
- package/src/tools/acp-bridge.ts +125 -0
- package/src/tools/approval.ts +245 -0
- package/src/tools/ask.ts +1459 -0
- package/src/tools/ast-edit.ts +718 -0
- package/src/tools/ast-grep.ts +526 -0
- package/src/tools/auto-generated-guard.ts +335 -0
- package/src/tools/bash-interactive.ts +435 -0
- package/src/tools/bash-interceptor.ts +148 -0
- package/src/tools/bash-pty-selection.ts +14 -0
- package/src/tools/bash-skill-urls.ts +350 -0
- package/src/tools/bash.ts +1826 -0
- package/src/tools/browser/aria/aria-snapshot.bundle.txt +7 -0
- package/src/tools/browser/aria/aria-snapshot.ts +131 -0
- package/src/tools/browser/attach.ts +219 -0
- package/src/tools/browser/cmux/cmux-tab.ts +1531 -0
- package/src/tools/browser/cmux/rpc.ts +200 -0
- package/src/tools/browser/cmux/socket-client.ts +445 -0
- package/src/tools/browser/launch.ts +939 -0
- package/src/tools/browser/readable.ts +112 -0
- package/src/tools/browser/registry.ts +447 -0
- package/src/tools/browser/relay/bridge.ts +945 -0
- package/src/tools/browser/relay/daemon.ts +117 -0
- package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
- package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
- package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
- package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
- package/src/tools/browser/relay/kind.ts +41 -0
- package/src/tools/browser/relay/protocol.ts +54 -0
- package/src/tools/browser/relay/server.ts +141 -0
- package/src/tools/browser/render.ts +229 -0
- package/src/tools/browser/run-output.ts +76 -0
- package/src/tools/browser/shared-daemon.ts +139 -0
- package/src/tools/browser/tab-protocol.ts +123 -0
- package/src/tools/browser/tab-supervisor.ts +1077 -0
- package/src/tools/browser/tab-worker-entry.ts +29 -0
- package/src/tools/browser/tab-worker.ts +1982 -0
- package/src/tools/browser.ts +487 -0
- package/src/tools/builtin-names.ts +67 -0
- package/src/tools/checkpoint.ts +137 -0
- package/src/tools/computer/exposure.ts +14 -0
- package/src/tools/computer/protocol.ts +69 -0
- package/src/tools/computer/supervisor.ts +409 -0
- package/src/tools/computer/worker-entry.ts +39 -0
- package/src/tools/computer/worker.ts +745 -0
- package/src/tools/computer-renderer.ts +147 -0
- package/src/tools/computer.ts +222 -0
- package/src/tools/conflict-detect.ts +815 -0
- package/src/tools/context.ts +49 -0
- package/src/tools/debug.ts +1121 -0
- package/src/tools/default-renderer.ts +154 -0
- package/src/tools/essential-tools.ts +46 -0
- package/src/tools/eval-backends.ts +34 -0
- package/src/tools/eval-format/index.ts +24 -0
- package/src/tools/eval-format/javascript.ts +952 -0
- package/src/tools/eval-format/julia.ts +446 -0
- package/src/tools/eval-format/python.ts +544 -0
- package/src/tools/eval-format/ruby.ts +380 -0
- package/src/tools/eval-render.ts +784 -0
- package/src/tools/eval.ts +774 -0
- package/src/tools/fetch.ts +1889 -0
- package/src/tools/file-recorder.ts +35 -0
- package/src/tools/fs-cache-invalidation.ts +28 -0
- package/src/tools/gh-cache-invalidation.ts +175 -0
- package/src/tools/gh-format.ts +12 -0
- package/src/tools/gh-renderer.ts +484 -0
- package/src/tools/gh.ts +3958 -0
- package/src/tools/github-cache.ts +663 -0
- package/src/tools/glob.ts +691 -0
- package/src/tools/grep.ts +1920 -0
- package/src/tools/grouped-file-output.ts +210 -0
- package/src/tools/hub/index.ts +579 -0
- package/src/tools/hub/jobs.ts +714 -0
- package/src/tools/hub/launch.ts +690 -0
- package/src/tools/hub/messaging.ts +735 -0
- package/src/tools/hub/types.ts +117 -0
- package/src/tools/image-gen.ts +1689 -0
- package/src/tools/image-providers.ts +50 -0
- package/src/tools/index.ts +736 -0
- package/src/tools/inspect-image-renderer.ts +133 -0
- package/src/tools/inspect-image.ts +316 -0
- package/src/tools/json-tree.ts +260 -0
- package/src/tools/jtd-to-json-schema.ts +219 -0
- package/src/tools/jtd-to-typescript.ts +136 -0
- package/src/tools/jtd-utils.ts +102 -0
- package/src/tools/learn.ts +141 -0
- package/src/tools/list-limit.ts +40 -0
- package/src/tools/manage-skill.ts +102 -0
- package/src/tools/match-line-format.ts +20 -0
- package/src/tools/memory-edit.ts +61 -0
- package/src/tools/memory-recall.ts +102 -0
- package/src/tools/memory-reflect.ts +88 -0
- package/src/tools/memory-render.ts +211 -0
- package/src/tools/memory-retain.ts +89 -0
- package/src/tools/output-meta.ts +860 -0
- package/src/tools/output-schema-validator.ts +307 -0
- package/src/tools/path-utils.ts +1489 -0
- package/src/tools/plan-mode-guard.ts +155 -0
- package/src/tools/puppeteer/00_stealth_tampering.txt +44 -0
- package/src/tools/puppeteer/01_stealth_activity.txt +80 -0
- package/src/tools/puppeteer/02_stealth_hairline.txt +57 -0
- package/src/tools/puppeteer/03_stealth_botd.txt +380 -0
- package/src/tools/puppeteer/04_stealth_iframe.txt +174 -0
- package/src/tools/puppeteer/05_stealth_webgl.txt +233 -0
- package/src/tools/puppeteer/06_stealth_screen.txt +260 -0
- package/src/tools/puppeteer/07_stealth_fonts.txt +99 -0
- package/src/tools/puppeteer/08_stealth_audio.txt +63 -0
- package/src/tools/puppeteer/09_stealth_locale.txt +51 -0
- package/src/tools/puppeteer/10_stealth_plugins.txt +212 -0
- package/src/tools/puppeteer/11_stealth_hardware.txt +59 -0
- package/src/tools/puppeteer/12_stealth_codecs.txt +42 -0
- package/src/tools/puppeteer/13_stealth_worker.txt +235 -0
- package/src/tools/read.ts +3762 -0
- package/src/tools/render-utils.ts +926 -0
- package/src/tools/renderers.ts +133 -0
- package/src/tools/report-tool-issue.ts +568 -0
- package/src/tools/resolve.ts +423 -0
- package/src/tools/review.ts +103 -0
- package/src/tools/run-scope.ts +417 -0
- package/src/tools/security-scan.ts +287 -0
- package/src/tools/shell-tokenize.ts +213 -0
- package/src/tools/sqlite-reader.ts +884 -0
- package/src/tools/terminal-output.ts +141 -0
- package/src/tools/todo.ts +1226 -0
- package/src/tools/tool-errors.ts +62 -0
- package/src/tools/tool-result.ts +102 -0
- package/src/tools/tool-timeouts.ts +38 -0
- package/src/tools/tts.ts +266 -0
- package/src/tools/vibe.ts +608 -0
- package/src/tools/write.ts +1646 -0
- package/src/tools/xdev.ts +560 -0
- package/src/tools/yield.ts +486 -0
- package/src/tts/downloader.ts +64 -0
- package/src/tts/index.ts +10 -0
- package/src/tts/models.ts +137 -0
- package/src/tts/runtime.ts +21 -0
- package/src/tts/speakable.ts +392 -0
- package/src/tts/speech-enhancer.ts +206 -0
- package/src/tts/streaming-player.ts +120 -0
- package/src/tts/tts-client.ts +475 -0
- package/src/tts/tts-protocol.ts +69 -0
- package/src/tts/tts-worker.ts +434 -0
- package/src/tts/vocalizer.ts +419 -0
- package/src/tts/wav.ts +58 -0
- package/src/tui/code-cell.ts +268 -0
- package/src/tui/file-list.ts +55 -0
- package/src/tui/hyperlink.ts +178 -0
- package/src/tui/index.ts +13 -0
- package/src/tui/output-block.ts +268 -0
- package/src/tui/status-line.ts +54 -0
- package/src/tui/tree-list.ts +172 -0
- package/src/tui/types.ts +15 -0
- package/src/tui/utils.ts +103 -0
- package/src/tui/width-aware-text.ts +58 -0
- package/src/utils/active-repo-context.ts +143 -0
- package/src/utils/block-context.ts +312 -0
- package/src/utils/changelog.ts +373 -0
- package/src/utils/clipboard.ts +361 -0
- package/src/utils/command-args.ts +74 -0
- package/src/utils/commit-message-generator.ts +148 -0
- package/src/utils/cpuprofile.ts +235 -0
- package/src/utils/edit-mode.ts +61 -0
- package/src/utils/enhanced-paste.ts +230 -0
- package/src/utils/event-bus.ts +33 -0
- package/src/utils/external-editor.ts +80 -0
- package/src/utils/fetch-timeout.ts +10 -0
- package/src/utils/file-display-mode.ts +44 -0
- package/src/utils/file-mentions.ts +293 -0
- package/src/utils/git.ts +2472 -0
- package/src/utils/image-loading.ts +236 -0
- package/src/utils/image-resize.ts +420 -0
- package/src/utils/image-vision-fallback.ts +196 -0
- package/src/utils/inspect-image-mode.ts +39 -0
- package/src/utils/ipc.ts +38 -0
- package/src/utils/jj.ts +422 -0
- package/src/utils/lang-from-path.ts +251 -0
- package/src/utils/late-cleanup.ts +17 -0
- package/src/utils/local-date.ts +7 -0
- package/src/utils/mac-file-urls.applescript +37 -0
- package/src/utils/markit-cache.ts +166 -0
- package/src/utils/markit.ts +223 -0
- package/src/utils/mupdf-wasm-embed.ts +12 -0
- package/src/utils/open.ts +126 -0
- package/src/utils/profile-tree.ts +111 -0
- package/src/utils/prompt-path.ts +3 -0
- package/src/utils/qrcode.ts +535 -0
- package/src/utils/sample-profile.ts +437 -0
- package/src/utils/session-color.ts +142 -0
- package/src/utils/shell-snapshot-fn-env.sh +63 -0
- package/src/utils/shell-snapshot.ts +326 -0
- package/src/utils/sixel.ts +69 -0
- package/src/utils/thinking-display.ts +163 -0
- package/src/utils/title-generator.ts +597 -0
- package/src/utils/token-rate.ts +72 -0
- package/src/utils/tool-choice.ts +50 -0
- package/src/utils/tools-manager.ts +411 -0
- package/src/utils/turndown.ts +82 -0
- package/src/utils/zip.ts +1106 -0
- package/src/vibe/runtime.ts +1684 -0
- package/src/vibe/state.ts +4 -0
- package/src/web/kagi.ts +305 -0
- package/src/web/parallel.ts +354 -0
- package/src/web/scrapers/artifacthub.ts +207 -0
- package/src/web/scrapers/arxiv.ts +83 -0
- package/src/web/scrapers/aur.ts +162 -0
- package/src/web/scrapers/biorxiv.ts +133 -0
- package/src/web/scrapers/bluesky.ts +262 -0
- package/src/web/scrapers/brew.ts +172 -0
- package/src/web/scrapers/cheatsh.ts +68 -0
- package/src/web/scrapers/chocolatey.ts +196 -0
- package/src/web/scrapers/choosealicense.ts +95 -0
- package/src/web/scrapers/cisa-kev.ts +87 -0
- package/src/web/scrapers/clojars.ts +154 -0
- package/src/web/scrapers/coingecko.ts +177 -0
- package/src/web/scrapers/crates-io.ts +97 -0
- package/src/web/scrapers/crossref.ts +136 -0
- package/src/web/scrapers/devto.ts +147 -0
- package/src/web/scrapers/discogs.ts +306 -0
- package/src/web/scrapers/discourse.ts +197 -0
- package/src/web/scrapers/dockerhub.ts +138 -0
- package/src/web/scrapers/docs-rs.ts +663 -0
- package/src/web/scrapers/fdroid.ts +134 -0
- package/src/web/scrapers/firefox-addons.ts +191 -0
- package/src/web/scrapers/flathub.ts +223 -0
- package/src/web/scrapers/github-gist.ts +58 -0
- package/src/web/scrapers/github.ts +800 -0
- package/src/web/scrapers/gitlab.ts +401 -0
- package/src/web/scrapers/go-pkg.ts +266 -0
- package/src/web/scrapers/hackage.ts +129 -0
- package/src/web/scrapers/hackernews.ts +189 -0
- package/src/web/scrapers/hex.ts +105 -0
- package/src/web/scrapers/huggingface.ts +321 -0
- package/src/web/scrapers/iacr.ts +89 -0
- package/src/web/scrapers/index.ts +252 -0
- package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
- package/src/web/scrapers/lemmy.ts +203 -0
- package/src/web/scrapers/lobsters.ts +175 -0
- package/src/web/scrapers/mastodon.ts +292 -0
- package/src/web/scrapers/maven.ts +138 -0
- package/src/web/scrapers/mdn.ts +173 -0
- package/src/web/scrapers/metacpan.ts +222 -0
- package/src/web/scrapers/musicbrainz.ts +250 -0
- package/src/web/scrapers/npm.ts +98 -0
- package/src/web/scrapers/nuget.ts +183 -0
- package/src/web/scrapers/nvd.ts +222 -0
- package/src/web/scrapers/ollama.ts +239 -0
- package/src/web/scrapers/open-vsx.ts +106 -0
- package/src/web/scrapers/opencorporates.ts +292 -0
- package/src/web/scrapers/openlibrary.ts +336 -0
- package/src/web/scrapers/orcid.ts +286 -0
- package/src/web/scrapers/osv.ts +176 -0
- package/src/web/scrapers/packagist.ts +160 -0
- package/src/web/scrapers/pub-dev.ts +143 -0
- package/src/web/scrapers/pubmed.ts +211 -0
- package/src/web/scrapers/pypi.ts +112 -0
- package/src/web/scrapers/rawg.ts +110 -0
- package/src/web/scrapers/readthedocs.ts +121 -0
- package/src/web/scrapers/reddit.ts +95 -0
- package/src/web/scrapers/repology.ts +251 -0
- package/src/web/scrapers/rfc.ts +201 -0
- package/src/web/scrapers/rubygems.ts +103 -0
- package/src/web/scrapers/searchcode.ts +189 -0
- package/src/web/scrapers/sec-edgar.ts +261 -0
- package/src/web/scrapers/semantic-scholar.ts +171 -0
- package/src/web/scrapers/snapcraft.ts +187 -0
- package/src/web/scrapers/sourcegraph.ts +336 -0
- package/src/web/scrapers/spdx.ts +108 -0
- package/src/web/scrapers/spotify.ts +198 -0
- package/src/web/scrapers/stackoverflow.ts +120 -0
- package/src/web/scrapers/terraform.ts +277 -0
- package/src/web/scrapers/tldr.ts +47 -0
- package/src/web/scrapers/twitter.ts +94 -0
- package/src/web/scrapers/types.ts +354 -0
- package/src/web/scrapers/utils.ts +109 -0
- package/src/web/scrapers/vimeo.ts +133 -0
- package/src/web/scrapers/vscode-marketplace.ts +187 -0
- package/src/web/scrapers/w3c.ts +156 -0
- package/src/web/scrapers/wikidata.ts +344 -0
- package/src/web/scrapers/wikipedia.ts +84 -0
- package/src/web/scrapers/youtube.ts +325 -0
- package/src/web/search/index.ts +393 -0
- package/src/web/search/provider.ts +272 -0
- package/src/web/search/providers/anthropic.ts +406 -0
- package/src/web/search/providers/base.ts +112 -0
- package/src/web/search/providers/brave.ts +181 -0
- package/src/web/search/providers/browser-headers.ts +82 -0
- package/src/web/search/providers/browser-page.ts +125 -0
- package/src/web/search/providers/codex.ts +788 -0
- package/src/web/search/providers/duckduckgo.ts +382 -0
- package/src/web/search/providers/ecosia.ts +183 -0
- package/src/web/search/providers/exa.ts +513 -0
- package/src/web/search/providers/firecrawl.ts +213 -0
- package/src/web/search/providers/gemini.ts +634 -0
- package/src/web/search/providers/google.ts +195 -0
- package/src/web/search/providers/jina.ts +144 -0
- package/src/web/search/providers/kagi.ts +98 -0
- package/src/web/search/providers/kimi.ts +221 -0
- package/src/web/search/providers/mojeek.ts +220 -0
- package/src/web/search/providers/parallel.ts +186 -0
- package/src/web/search/providers/perplexity-auth.ts +142 -0
- package/src/web/search/providers/perplexity.ts +997 -0
- package/src/web/search/providers/public.ts +199 -0
- package/src/web/search/providers/searxng.ts +467 -0
- package/src/web/search/providers/startpage.ts +225 -0
- package/src/web/search/providers/synthetic.ts +126 -0
- package/src/web/search/providers/tavily.ts +244 -0
- package/src/web/search/providers/tinyfish.ts +166 -0
- package/src/web/search/providers/utils.ts +130 -0
- package/src/web/search/providers/xai.ts +372 -0
- package/src/web/search/providers/zai.ts +452 -0
- package/src/web/search/query.ts +850 -0
- package/src/web/search/render.ts +262 -0
- package/src/web/search/types.ts +518 -0
- package/src/web/search/utils.ts +17 -0
- package/src/workspace-tree.ts +326 -0
|
@@ -0,0 +1,3149 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { getOAuthProviders } from "@oh-my-pi/pi-ai/oauth";
|
|
5
|
+
import { type AutocompleteItem, Spacer } from "@oh-my-pi/pi-tui";
|
|
6
|
+
import { APP_NAME, getMCPConfigPath, getProjectDir, logger, setProjectDir } from "@oh-my-pi/pi-utils";
|
|
7
|
+
import { reset as resetCapabilities } from "../capability";
|
|
8
|
+
import { COLLAB_GUEST_ALLOWED_COMMANDS, CollabGuestLink } from "../collab/guest";
|
|
9
|
+
import { CollabHost } from "../collab/host";
|
|
10
|
+
import {
|
|
11
|
+
expandRoleAlias,
|
|
12
|
+
formatModelString,
|
|
13
|
+
getModelMatchPreferences,
|
|
14
|
+
resolveCliModel,
|
|
15
|
+
} from "../config/model-resolver";
|
|
16
|
+
import { applyProviderGlobalsFromSettings } from "../config/provider-globals";
|
|
17
|
+
import type { SettingPath, SettingValue } from "../config/settings";
|
|
18
|
+
import { settings } from "../config/settings";
|
|
19
|
+
import {
|
|
20
|
+
clearPluginRootsAndCaches,
|
|
21
|
+
resolveActiveProjectRegistryPath,
|
|
22
|
+
resolveOrDefaultProjectRegistryPath,
|
|
23
|
+
} from "../discovery/helpers.js";
|
|
24
|
+
import { parseExportArgs } from "../export/html/args";
|
|
25
|
+
import { shareSession } from "../export/share";
|
|
26
|
+
import { PluginManager } from "../extensibility/plugins";
|
|
27
|
+
import {
|
|
28
|
+
getInstalledPluginsRegistryPath,
|
|
29
|
+
getMarketplacesCacheDir,
|
|
30
|
+
getMarketplacesRegistryPath,
|
|
31
|
+
getPluginsCacheDir,
|
|
32
|
+
MarketplaceManager,
|
|
33
|
+
} from "../extensibility/plugins/marketplace";
|
|
34
|
+
import { readMCPConfigFile } from "../mcp/config-writer";
|
|
35
|
+
import { memoryStatsUnavailableMessage, resolveMemoryBackend } from "../memory-backend";
|
|
36
|
+
import { runPauseScreen } from "../modes/components/pause-screen";
|
|
37
|
+
import { collectMcpServerNames, MCPCommandController } from "../modes/controllers/mcp-command-controller";
|
|
38
|
+
import { describeLoopLimitRuntime } from "../modes/loop-limit";
|
|
39
|
+
import { theme } from "../modes/theme/theme";
|
|
40
|
+
import type { InteractiveModeContext } from "../modes/types";
|
|
41
|
+
import { extractLastCodeBlock, extractLastCommand } from "../modes/utils/copy-targets";
|
|
42
|
+
import type { AgentSession, FreshSessionResult } from "../session/agent-session";
|
|
43
|
+
import type { SessionOAuthAccountList } from "../session/agent-session-types";
|
|
44
|
+
import { COMPACT_MODES, parseCompactArgs } from "../session/compact-modes";
|
|
45
|
+
import { resolveResumableSession } from "../session/session-listing";
|
|
46
|
+
import { formatShakeSummary, type ShakeMode } from "../session/shake-types";
|
|
47
|
+
import type { ComputerTool } from "../tools/computer";
|
|
48
|
+
import { computerExposureMode } from "../tools/computer/exposure";
|
|
49
|
+
import { expandTilde, resolveToCwd } from "../tools/path-utils";
|
|
50
|
+
import { urlHyperlinkAlways } from "../tui";
|
|
51
|
+
import {
|
|
52
|
+
getChangelogPath,
|
|
53
|
+
parseChangelog,
|
|
54
|
+
RECENT_CHANGELOG_ENTRY_LIMIT,
|
|
55
|
+
renderChangelogEntries,
|
|
56
|
+
} from "../utils/changelog";
|
|
57
|
+
import { copyToClipboard } from "../utils/clipboard";
|
|
58
|
+
import type { InspectImageMode } from "../utils/inspect-image-mode";
|
|
59
|
+
import { CollabQrCodeComponent } from "./helpers/collab-qrcode";
|
|
60
|
+
import { buildContextReportText } from "./helpers/context-report";
|
|
61
|
+
import { formatDuration } from "./helpers/format";
|
|
62
|
+
import { createMarketplaceManager } from "./helpers/marketplace-manager";
|
|
63
|
+
import { handleMcpAcp } from "./helpers/mcp";
|
|
64
|
+
import { commandConsumed, errorMessage, parseSlashCommand, parseSubcommand, usage } from "./helpers/parse";
|
|
65
|
+
import { describeRedeemOutcome, type ResetUsageAccount, toResetUsageAccounts } from "./helpers/reset-usage";
|
|
66
|
+
import { handleSecurityCommand } from "./helpers/security";
|
|
67
|
+
import { matchSessionPinAccounts, toSessionPinAccounts } from "./helpers/session-pin";
|
|
68
|
+
import { handleSshAcp } from "./helpers/ssh";
|
|
69
|
+
import { launchStatsDashboard, parseStatsDashboardArgs } from "./helpers/stats-dashboard";
|
|
70
|
+
import { handleTodoAcp } from "./helpers/todo";
|
|
71
|
+
import { buildUsageReportText } from "./helpers/usage-report";
|
|
72
|
+
import { parseMarketplaceInstallArgs, parsePluginScopeArgs } from "./marketplace-install-parser";
|
|
73
|
+
import type {
|
|
74
|
+
BuiltinSlashCommand,
|
|
75
|
+
ParsedSlashCommand,
|
|
76
|
+
SlashCommandResult,
|
|
77
|
+
SlashCommandRuntime,
|
|
78
|
+
SlashCommandSpec,
|
|
79
|
+
SubcommandDef,
|
|
80
|
+
TuiSlashCommandRuntime,
|
|
81
|
+
} from "./types";
|
|
82
|
+
|
|
83
|
+
export type { BuiltinSlashCommand, SubcommandDef } from "./types";
|
|
84
|
+
|
|
85
|
+
/** TUI-specific runtime accepted by `executeBuiltinSlashCommand`. */
|
|
86
|
+
export type BuiltinSlashCommandRuntime = TuiSlashCommandRuntime;
|
|
87
|
+
|
|
88
|
+
export interface TuiBuiltinSlashCommand extends BuiltinSlashCommand {
|
|
89
|
+
getArgumentCompletions?: (prefix: string) => AutocompleteItem[] | null | Promise<AutocompleteItem[] | null>;
|
|
90
|
+
getInlineHint?: (argumentText: string) => string | null;
|
|
91
|
+
getAutocompleteDescription?: () => string | undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function refreshStatusLine(ctx: InteractiveModeContext): void {
|
|
95
|
+
ctx.statusLine.invalidate();
|
|
96
|
+
ctx.ui.requestRender();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** `/fast status` label for the active model: "on" when its family is priority, else "off". */
|
|
100
|
+
function formatFastModeStatus(session: AgentSession): string {
|
|
101
|
+
return session.isFastModeEnabled() ? "on" : "off";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Detailed, session-effective `/computer status` diagnostics. */
|
|
105
|
+
async function formatComputerUseStatus(session: AgentSession): Promise<string> {
|
|
106
|
+
const enabled = session.settings.get("computer.enabled");
|
|
107
|
+
const active = session.getEnabledToolNames().includes("computer");
|
|
108
|
+
const model = session.model;
|
|
109
|
+
const modelName = model ? formatModelString(model) : "none";
|
|
110
|
+
const exposure = !enabled
|
|
111
|
+
? "not exposed (disabled)"
|
|
112
|
+
: !active
|
|
113
|
+
? "not exposed (tool inactive)"
|
|
114
|
+
: computerExposureMode(model);
|
|
115
|
+
const configured = {
|
|
116
|
+
display: session.settings.get("computer.display"),
|
|
117
|
+
maxWidth: session.settings.get("computer.maxWidth"),
|
|
118
|
+
maxHeight: session.settings.get("computer.maxHeight"),
|
|
119
|
+
};
|
|
120
|
+
const computerTool = active
|
|
121
|
+
? (session.getToolByName("computer") as Pick<ComputerTool, "capabilities"> | undefined)
|
|
122
|
+
: undefined;
|
|
123
|
+
const capabilities = await computerTool?.capabilities();
|
|
124
|
+
const capabilityStatus = capabilities
|
|
125
|
+
? [
|
|
126
|
+
`backend=${capabilities.backend}${capabilities.displayServer ? `/${capabilities.displayServer}` : ""}`,
|
|
127
|
+
`capture=${capabilities.capture} (${capabilities.capturePermission})`,
|
|
128
|
+
`input=${capabilities.input} (${capabilities.inputPermission})`,
|
|
129
|
+
`ax=${capabilities.ax} (${capabilities.axPermission})`,
|
|
130
|
+
`backgroundWindowInput=${capabilities.backgroundWindowInput}`,
|
|
131
|
+
`deliveryModes=${capabilities.deliveryModes.join(",") || "none"}`,
|
|
132
|
+
].join(", ")
|
|
133
|
+
: "session not started";
|
|
134
|
+
return [
|
|
135
|
+
`Computer use: ${enabled ? "enabled" : "disabled"}`,
|
|
136
|
+
`tool: ${active ? "active" : "inactive"}`,
|
|
137
|
+
`exposure: ${exposure}`,
|
|
138
|
+
`model: ${modelName}`,
|
|
139
|
+
`configured: display=${configured.display}, maxWidth=${configured.maxWidth}, maxHeight=${configured.maxHeight}`,
|
|
140
|
+
`capabilities: ${capabilityStatus}`,
|
|
141
|
+
].join(" · ");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Apply a session-scoped computer-use toggle: flip the active tool slate first
|
|
146
|
+
* (so a failed enable never leaves a stale settings override), then record the
|
|
147
|
+
* runtime override — never `settings.set`, which would persist to settings.json.
|
|
148
|
+
* Returns the operator feedback line.
|
|
149
|
+
*/
|
|
150
|
+
async function applyComputerUseToggle(session: AgentSession, enable: boolean): Promise<string> {
|
|
151
|
+
const applied = await session.setComputerToolEnabled(enable);
|
|
152
|
+
if (enable && !applied) {
|
|
153
|
+
return "Computer use is unavailable in this session.";
|
|
154
|
+
}
|
|
155
|
+
session.settings.override("computer.enabled", enable);
|
|
156
|
+
return enable
|
|
157
|
+
? `Computer use enabled for this session. ${await formatComputerUseStatus(session)}`
|
|
158
|
+
: "Computer use disabled for this session.";
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Session-effective `/vision status` line. */
|
|
162
|
+
function formatVisionStatus(session: AgentSession): string {
|
|
163
|
+
const { mode, active, model } = session.inspectImageState();
|
|
164
|
+
const override = session.getInspectImageModeOverride();
|
|
165
|
+
const modelObj = session.model;
|
|
166
|
+
const capability = modelObj
|
|
167
|
+
? modelObj.input.includes("image")
|
|
168
|
+
? "native image input"
|
|
169
|
+
: "no native image input"
|
|
170
|
+
: "no active model";
|
|
171
|
+
return [
|
|
172
|
+
`inspect_image: ${active ? "active" : "inactive"}`,
|
|
173
|
+
`mode: ${mode}${override ? " (session override)" : ""}`,
|
|
174
|
+
...(override ? [`configured: ${session.settings.get("inspect_image.mode")}`] : []),
|
|
175
|
+
`model: ${model ?? "none"} (${capability})`,
|
|
176
|
+
].join(" · ");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Applies a `/vision` mode for this session and returns the operator feedback line. */
|
|
180
|
+
async function applyVisionMode(session: AgentSession, mode: InspectImageMode): Promise<string> {
|
|
181
|
+
const applied = await session.setInspectImageMode(mode);
|
|
182
|
+
if (!applied) {
|
|
183
|
+
return "inspect_image is unavailable in this session.";
|
|
184
|
+
}
|
|
185
|
+
return `Vision mode: ${mode}. ${formatVisionStatus(session)}`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const AUTOCOMPLETE_DETAIL_LIMIT = 48;
|
|
189
|
+
|
|
190
|
+
function shortDetail(value: string, limit = AUTOCOMPLETE_DETAIL_LIMIT): string {
|
|
191
|
+
const singleLine = value.replace(/\s+/g, " ").trim();
|
|
192
|
+
return singleLine.length <= limit ? singleLine : `${singleLine.slice(0, limit - 1)}…`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function formatTokenCount(value: number): string {
|
|
196
|
+
return value.toLocaleString();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Scheme-less display form of a browser deep link: accent + underline, OSC-8 linked to the full URL. */
|
|
200
|
+
function collabWebLinkClickable(webLink: string): string {
|
|
201
|
+
const display = theme.fg("accent", `\x1b[4m${webLink.replace(/^https?:\/\//, "")}\x1b[24m`);
|
|
202
|
+
return urlHyperlinkAlways(webLink, display);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Join hint printed by /collab: compact terminal link + clickable browser deep link. */
|
|
206
|
+
function collabLinkHint(host: CollabHost, heading: string, view = false): string {
|
|
207
|
+
const bullet = theme.fg("accent", theme.format.bullet);
|
|
208
|
+
const link = view ? host.viewLink : host.link;
|
|
209
|
+
const webLink = view ? host.webViewLink : host.webLink;
|
|
210
|
+
return [
|
|
211
|
+
theme.fg("success", heading),
|
|
212
|
+
` ${bullet} ${theme.fg("muted", view ? "Watch from another terminal:" : "Join from another terminal:")} ${APP_NAME} join "${link}"`,
|
|
213
|
+
` ${bullet} ${theme.fg("muted", "or any web browser:")} ${collabWebLinkClickable(webLink)}`,
|
|
214
|
+
theme.fg(
|
|
215
|
+
"dim",
|
|
216
|
+
view
|
|
217
|
+
? "Anyone with this link can watch the session but cannot prompt the agent."
|
|
218
|
+
: "Anyone with the link can read the session and prompt the agent. Read-only link: /collab view",
|
|
219
|
+
),
|
|
220
|
+
].join("\n");
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function showCollabQrCode(ctx: InteractiveModeContext, webLink: string): void {
|
|
224
|
+
try {
|
|
225
|
+
ctx.present([new Spacer(1), new CollabQrCodeComponent(webLink)]);
|
|
226
|
+
} catch (err) {
|
|
227
|
+
ctx.showError(`Failed to render collab QR code: ${errorMessage(err)}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function showCollabLink(ctx: InteractiveModeContext, host: CollabHost, heading: string, view = false): void {
|
|
232
|
+
ctx.showStatus(collabLinkHint(host, heading, view), { dim: false });
|
|
233
|
+
showCollabQrCode(ctx, view ? host.webViewLink : host.webLink);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function formatFreshSessionResult(result: FreshSessionResult): string {
|
|
237
|
+
const stateLabel = result.closedProviderSessions === 1 ? "provider state" : "provider states";
|
|
238
|
+
return `Fresh provider session started (${result.closedProviderSessions} ${stateLabel} pruned).`;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const shutdownHandlerTui = (_command: ParsedSlashCommand, runtime: TuiSlashCommandRuntime): SlashCommandResult => {
|
|
242
|
+
runtime.ctx.editor.setText("");
|
|
243
|
+
void runtime.ctx.shutdown();
|
|
244
|
+
return commandConsumed();
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
async function handleUsageResetCommand(
|
|
248
|
+
arg: string,
|
|
249
|
+
session: AgentSession,
|
|
250
|
+
output: SlashCommandRuntime["output"],
|
|
251
|
+
): Promise<void> {
|
|
252
|
+
let accounts: ResetUsageAccount[];
|
|
253
|
+
try {
|
|
254
|
+
accounts = toResetUsageAccounts(await session.listResetCredits());
|
|
255
|
+
} catch (error) {
|
|
256
|
+
await output(`Could not load saved resets: ${errorMessage(error)}`);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (accounts.length === 0) {
|
|
260
|
+
await output("No Codex accounts found. Use /login to add one.");
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const targetArg = arg.trim();
|
|
264
|
+
if (!targetArg) {
|
|
265
|
+
const lines = ["Saved Codex rate-limit resets:"];
|
|
266
|
+
for (const account of accounts) {
|
|
267
|
+
const detail = account.error ? `unavailable (${account.error})` : `${account.availableCount} available`;
|
|
268
|
+
lines.push(`- ${account.label}: ${detail}${account.active ? " (active)" : ""}`);
|
|
269
|
+
}
|
|
270
|
+
lines.push("", "Spend one with `/usage reset <account email>` or `/usage reset active`.");
|
|
271
|
+
await output(lines.join("\n"));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const wanted = targetArg.toLowerCase();
|
|
275
|
+
const target =
|
|
276
|
+
wanted === "active"
|
|
277
|
+
? accounts.find(account => account.active)
|
|
278
|
+
: accounts.find(
|
|
279
|
+
account =>
|
|
280
|
+
account.label.toLowerCase() === wanted ||
|
|
281
|
+
account.target.email?.toLowerCase() === wanted ||
|
|
282
|
+
account.target.accountId?.toLowerCase() === wanted,
|
|
283
|
+
);
|
|
284
|
+
if (!target) {
|
|
285
|
+
await output(`No Codex account matches "${targetArg}".`);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (target.availableCount <= 0) {
|
|
289
|
+
await output(`${target.label}: no saved resets to spend.`);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const outcome = await session.redeemResetCredit(target.target);
|
|
293
|
+
await output(describeRedeemOutcome(outcome, target.label));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function handleSessionPinCommand(
|
|
297
|
+
arg: string,
|
|
298
|
+
session: AgentSession,
|
|
299
|
+
output: SlashCommandRuntime["output"],
|
|
300
|
+
): Promise<void> {
|
|
301
|
+
if (session.isStreaming) {
|
|
302
|
+
await output("Cannot pin an account while the session is streaming.");
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
let accountList: SessionOAuthAccountList | undefined;
|
|
306
|
+
try {
|
|
307
|
+
accountList = await session.listCurrentProviderOAuthAccounts();
|
|
308
|
+
} catch (error) {
|
|
309
|
+
await output(`Could not load provider accounts: ${errorMessage(error)}`);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (!accountList) {
|
|
313
|
+
await output("Select a model before pinning a provider account.");
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const provider = getOAuthProviders().find(candidate => candidate.id === accountList.provider);
|
|
317
|
+
const providerName = provider?.name ?? accountList.provider;
|
|
318
|
+
const accounts = toSessionPinAccounts(accountList.accounts);
|
|
319
|
+
if (accounts.length === 0) {
|
|
320
|
+
const source = session.modelRegistry.authStorage.describeCredentialSource(
|
|
321
|
+
accountList.provider,
|
|
322
|
+
session.sessionId,
|
|
323
|
+
);
|
|
324
|
+
await output(
|
|
325
|
+
source
|
|
326
|
+
? `No stored OAuth accounts for ${providerName}. Current auth comes from ${source}.`
|
|
327
|
+
: `No stored OAuth accounts for ${providerName}. Use /login to add one.`,
|
|
328
|
+
);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const selector = arg.trim();
|
|
333
|
+
if (!selector) {
|
|
334
|
+
const lines = [`OAuth accounts for ${providerName}:`];
|
|
335
|
+
for (const account of accounts) {
|
|
336
|
+
lines.push(`${account.position + 1}. ${account.label}${account.active ? " (active)" : ""}`);
|
|
337
|
+
}
|
|
338
|
+
lines.push("", "Pin one with `/session pin <number|email|account id>`.");
|
|
339
|
+
await output(lines.join("\n"));
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const matches = matchSessionPinAccounts(accounts, selector);
|
|
344
|
+
if (matches.length === 0) {
|
|
345
|
+
await output(`No ${providerName} account matches "${selector}".`);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (matches.length > 1) {
|
|
349
|
+
await output(
|
|
350
|
+
`"${selector}" matches multiple ${providerName} accounts: ${matches
|
|
351
|
+
.map(account => `${account.position + 1}. ${account.label}`)
|
|
352
|
+
.join(", ")}. Use the account number.`,
|
|
353
|
+
);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
const account = matches[0];
|
|
357
|
+
if (!account || !session.pinCurrentProviderOAuthAccount(account.credentialId)) {
|
|
358
|
+
await output(`${account?.label ?? selector} is no longer available to pin.`);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
await output(`Pinned ${account.label} to this session for ${providerName}.`);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/** Parse the `/shake` subcommand into a {@link ShakeMode}; empty defaults to elide. */
|
|
365
|
+
function parseShakeMode(args: string): ShakeMode | { error: string } {
|
|
366
|
+
const verb = args.trim().toLowerCase();
|
|
367
|
+
if (verb === "" || verb === "elide") return "elide";
|
|
368
|
+
if (verb === "images") return "images";
|
|
369
|
+
return { error: `Unknown /shake mode "${verb}". Use elide or images.` };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Format the session's workspace directories (cwd + additional) for display. */
|
|
373
|
+
function formatWorkspaceDirectories(runtime: SlashCommandRuntime, note?: string): string {
|
|
374
|
+
const cwd = runtime.sessionManager.getCwd();
|
|
375
|
+
const additional = runtime.sessionManager.getAdditionalDirectories();
|
|
376
|
+
const lines = ["Workspace directories:", ` ${cwd} (working directory)`, ...additional.map(d => ` ${d}`)];
|
|
377
|
+
return note ? `${note}\n${lines.join("\n")}` : lines.join("\n");
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
381
|
+
{
|
|
382
|
+
name: "security",
|
|
383
|
+
description: "Plan, run, inspect, import, and compare OMP-native security scans",
|
|
384
|
+
allowArgs: true,
|
|
385
|
+
acpInputHint: "<plan|scan|status|cancel|scans|show|import|export|validate|compare|disposition>",
|
|
386
|
+
subcommands: [
|
|
387
|
+
{ name: "plan", description: "Create an immutable security scan plan" },
|
|
388
|
+
{ name: "scan", description: "Start a planned or newly planned native scan" },
|
|
389
|
+
{ name: "status", description: "Show native scan operation status" },
|
|
390
|
+
{ name: "cancel", description: "Cancel a running native scan" },
|
|
391
|
+
{ name: "scans", description: "List stored project security scans" },
|
|
392
|
+
{ name: "show", description: "Render a scan or security:// resource" },
|
|
393
|
+
{ name: "import", description: "Import SARIF or a Codex Security bundle" },
|
|
394
|
+
{ name: "export", description: "Export a canonical bundle, SARIF, or report" },
|
|
395
|
+
{ name: "validate", description: "Validate one finding with OMP-native tools" },
|
|
396
|
+
{ name: "compare", description: "Compare finding lineage across two scans" },
|
|
397
|
+
{ name: "disposition", description: "Set a finding disposition with rationale" },
|
|
398
|
+
],
|
|
399
|
+
handle: handleSecurityCommand,
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
name: "settings",
|
|
403
|
+
description: "Open settings menu",
|
|
404
|
+
handleTui: (_command, runtime) => {
|
|
405
|
+
runtime.ctx.showSettingsSelector();
|
|
406
|
+
runtime.ctx.editor.setText("");
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
name: "setup",
|
|
411
|
+
aliases: ["providers"],
|
|
412
|
+
description: "Open provider setup",
|
|
413
|
+
allowArgs: true,
|
|
414
|
+
subcommands: [{ name: "providers", description: "Configure sign-in and web search providers" }],
|
|
415
|
+
handleTui: async (command, runtime) => {
|
|
416
|
+
const args = command.args.trim().toLowerCase();
|
|
417
|
+
const opensProviders = args === "" || args === "providers";
|
|
418
|
+
if (opensProviders) {
|
|
419
|
+
await runtime.ctx.showProviderSetup();
|
|
420
|
+
} else {
|
|
421
|
+
runtime.ctx.showWarning(`Usage: /${command.name} [providers]`);
|
|
422
|
+
}
|
|
423
|
+
runtime.ctx.editor.setText("");
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
name: "plan",
|
|
428
|
+
description: "Toggle plan mode (agent plans before executing)",
|
|
429
|
+
inlineHint: "[prompt]",
|
|
430
|
+
allowArgs: true,
|
|
431
|
+
getTuiAutocompleteDescription: runtime => {
|
|
432
|
+
if (!runtime.ctx.settings.get("plan.enabled" as SettingPath)) return "Plan: disabled in settings";
|
|
433
|
+
if (runtime.ctx.planModeEnabled) {
|
|
434
|
+
const planFile = runtime.ctx.planModePlanFilePath;
|
|
435
|
+
return `Plan: on${planFile ? ` (${path.basename(planFile)})` : ""}`;
|
|
436
|
+
}
|
|
437
|
+
if (runtime.ctx.goalModeEnabled) return "Plan: blocked by goal mode";
|
|
438
|
+
return "Plan: off";
|
|
439
|
+
},
|
|
440
|
+
handleTui: async (command, runtime) => {
|
|
441
|
+
await runtime.ctx.handlePlanModeCommand(command.args || undefined);
|
|
442
|
+
runtime.ctx.editor.setText("");
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
name: "plan-review",
|
|
447
|
+
description: "Re-open the plan review for the latest plan (plan mode only)",
|
|
448
|
+
getTuiAutocompleteDescription: runtime =>
|
|
449
|
+
runtime.ctx.planModeEnabled ? "Plan review: available" : "Plan review: plan mode inactive",
|
|
450
|
+
handleTui: async (_command, runtime) => {
|
|
451
|
+
await runtime.ctx.openPlanReview();
|
|
452
|
+
runtime.ctx.editor.setText("");
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
name: "vibe",
|
|
457
|
+
description: "Toggle vibe mode (direct persistent fast/good worker sessions; read-only toolset)",
|
|
458
|
+
inlineHint: "[prompt]",
|
|
459
|
+
allowArgs: true,
|
|
460
|
+
getTuiAutocompleteDescription: runtime => {
|
|
461
|
+
if (runtime.ctx.vibeModeEnabled) return "Vibe: on";
|
|
462
|
+
if (runtime.ctx.planModeEnabled) return "Vibe: blocked by plan mode";
|
|
463
|
+
if (runtime.ctx.goalModeEnabled) return "Vibe: blocked by goal mode";
|
|
464
|
+
return "Vibe: off";
|
|
465
|
+
},
|
|
466
|
+
handleTui: async (command, runtime) => {
|
|
467
|
+
await runtime.ctx.handleVibeModeCommand(command.args || undefined);
|
|
468
|
+
runtime.ctx.editor.setText("");
|
|
469
|
+
},
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
name: "goal",
|
|
473
|
+
description: "Toggle goal mode (persistent autonomous objective for this session)",
|
|
474
|
+
subcommands: [
|
|
475
|
+
{ name: "set", description: "Set or replace the goal", usage: "<objective>" },
|
|
476
|
+
{ name: "show", description: "Show current goal details" },
|
|
477
|
+
{ name: "pause", description: "Pause the current goal" },
|
|
478
|
+
{ name: "resume", description: "Resume a paused goal" },
|
|
479
|
+
{ name: "drop", description: "Drop the current goal" },
|
|
480
|
+
{ name: "budget", description: "Adjust the token budget", usage: "<N|off>" },
|
|
481
|
+
],
|
|
482
|
+
inlineHint: "[objective]",
|
|
483
|
+
allowArgs: true,
|
|
484
|
+
getTuiAutocompleteDescription: runtime => {
|
|
485
|
+
if (!runtime.ctx.settings.get("goal.enabled" as SettingPath)) return "Goal: disabled in settings";
|
|
486
|
+
if (runtime.ctx.planModeEnabled) return "Goal: blocked by plan mode";
|
|
487
|
+
const state = runtime.ctx.session.getGoalModeState();
|
|
488
|
+
return state ? `Goal: ${state.goal.status} (${shortDetail(state.goal.objective)})` : "Goal: off";
|
|
489
|
+
},
|
|
490
|
+
handleTui: async (command, runtime) => {
|
|
491
|
+
await runtime.ctx.handleGoalModeCommand(command.args || undefined);
|
|
492
|
+
runtime.ctx.editor.setText("");
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
name: "guided-goal",
|
|
497
|
+
description: "Have the agent interview you in chat, then set up goal mode",
|
|
498
|
+
inlineHint: "[rough objective]",
|
|
499
|
+
allowArgs: true,
|
|
500
|
+
handleTui: async (command, runtime) => {
|
|
501
|
+
// Clear the slash draft BEFORE the await: the handler blocks for the
|
|
502
|
+
// whole kickoff turn, and a post-await clear would wipe an answer the
|
|
503
|
+
// user starts typing while the first interview question streams.
|
|
504
|
+
runtime.ctx.editor.setText("");
|
|
505
|
+
await runtime.ctx.handleGuidedGoalCommand(command.args || undefined);
|
|
506
|
+
},
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
name: "loop",
|
|
510
|
+
description:
|
|
511
|
+
"Toggle loop mode. While enabled, the next prompt you send re-submits after every yield. Esc cancels the current iteration; /loop again to disable.",
|
|
512
|
+
inlineHint: "[count|duration] [prompt]",
|
|
513
|
+
allowArgs: true,
|
|
514
|
+
getTuiAutocompleteDescription: runtime => {
|
|
515
|
+
if (!runtime.ctx.loopModeEnabled) return "Loop: off";
|
|
516
|
+
if (runtime.ctx.loopModePaused) return "Loop: paused";
|
|
517
|
+
if (runtime.ctx.loopLimit) return `Loop: on (${describeLoopLimitRuntime(runtime.ctx.loopLimit)})`;
|
|
518
|
+
if (runtime.ctx.loopPrompt) return "Loop: on (repeating prompt)";
|
|
519
|
+
return "Loop: on (waiting for next prompt)";
|
|
520
|
+
},
|
|
521
|
+
handleTui: async (command, runtime) => {
|
|
522
|
+
const prompt = await runtime.ctx.handleLoopCommand(command.args);
|
|
523
|
+
runtime.ctx.editor.setText("");
|
|
524
|
+
// Surface any inline prompt so the dispatcher returns it and the normal
|
|
525
|
+
// submit flow runs the first loop iteration (recording it as the loop prompt).
|
|
526
|
+
if (prompt) return { prompt };
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
name: "queue",
|
|
531
|
+
description: "Queue a message for after the agent yields",
|
|
532
|
+
inlineHint: "<message>",
|
|
533
|
+
allowArgs: true,
|
|
534
|
+
handleTui: async (command, runtime) => {
|
|
535
|
+
await runtime.ctx.handleQueueCommand(command.args);
|
|
536
|
+
},
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
name: "model",
|
|
540
|
+
aliases: ["models"],
|
|
541
|
+
description: "Switch model for this session",
|
|
542
|
+
acpDescription: "Show current model selection",
|
|
543
|
+
getTuiAutocompleteDescription: runtime => {
|
|
544
|
+
const model = runtime.ctx.session.model;
|
|
545
|
+
return model ? `Model: ${model.provider}/${model.id}` : "Model: none selected";
|
|
546
|
+
},
|
|
547
|
+
handle: async (command, runtime) => {
|
|
548
|
+
if (command.args) {
|
|
549
|
+
const modelId = command.args.trim();
|
|
550
|
+
const availableModels = runtime.session.getAvailableModels?.() ?? [];
|
|
551
|
+
const match = availableModels.find(
|
|
552
|
+
model => model.id === modelId || `${model.provider}/${model.id}` === modelId,
|
|
553
|
+
);
|
|
554
|
+
if (!match) {
|
|
555
|
+
return usage(
|
|
556
|
+
`Unknown model: ${modelId}. Use ACP \`session/setModel\` for picker-driven selection or list available models with /model.`,
|
|
557
|
+
runtime,
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
try {
|
|
561
|
+
await runtime.session.setModel(match);
|
|
562
|
+
await runtime.output(`Model set to ${match.provider}/${match.id}.`);
|
|
563
|
+
await runtime.notifyTitleChanged?.();
|
|
564
|
+
await runtime.notifyConfigChanged?.();
|
|
565
|
+
return commandConsumed();
|
|
566
|
+
} catch (err) {
|
|
567
|
+
return usage(`Failed to set model: ${errorMessage(err)}`, runtime);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const model = runtime.session.model;
|
|
572
|
+
await runtime.output(
|
|
573
|
+
model ? `Current model: ${model.provider}/${model.id}` : "No model is currently selected.",
|
|
574
|
+
);
|
|
575
|
+
return commandConsumed();
|
|
576
|
+
},
|
|
577
|
+
handleTui: (_command, runtime) => {
|
|
578
|
+
runtime.ctx.showModelSelector();
|
|
579
|
+
runtime.ctx.editor.setText("");
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
name: "switch",
|
|
584
|
+
description: "Switch model for this session (same as alt+p)",
|
|
585
|
+
getTuiAutocompleteDescription: runtime => {
|
|
586
|
+
const model = runtime.ctx.session.model;
|
|
587
|
+
return model ? `Model: ${model.provider}/${model.id}` : "Model: none selected";
|
|
588
|
+
},
|
|
589
|
+
handleTui: (_command, runtime) => {
|
|
590
|
+
runtime.ctx.showModelSelector({ temporaryOnly: true });
|
|
591
|
+
runtime.ctx.editor.setText("");
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
name: "fast",
|
|
596
|
+
description: "Toggle priority service tier (OpenAI service_tier=priority, Anthropic speed=fast)",
|
|
597
|
+
acpDescription: "Toggle fast mode",
|
|
598
|
+
acpInputHint: "[on|off|status]",
|
|
599
|
+
subcommands: [
|
|
600
|
+
{ name: "on", description: "Enable fast mode" },
|
|
601
|
+
{ name: "off", description: "Disable fast mode" },
|
|
602
|
+
{ name: "status", description: "Show fast mode status" },
|
|
603
|
+
],
|
|
604
|
+
allowArgs: true,
|
|
605
|
+
getTuiAutocompleteDescription: runtime => `Fast: ${formatFastModeStatus(runtime.ctx.session)}`,
|
|
606
|
+
handle: async (command, runtime) => {
|
|
607
|
+
const arg = command.args.toLowerCase();
|
|
608
|
+
if (!arg || arg === "toggle") {
|
|
609
|
+
const enabled = runtime.session.toggleFastMode();
|
|
610
|
+
await runtime.output(`Fast mode ${enabled ? "enabled" : "disabled"}.`);
|
|
611
|
+
return commandConsumed();
|
|
612
|
+
}
|
|
613
|
+
if (arg === "on") {
|
|
614
|
+
const supported = runtime.session.setFastMode(true);
|
|
615
|
+
await runtime.output(supported ? "Fast mode enabled." : "Fast mode is unavailable for the current model.");
|
|
616
|
+
return commandConsumed();
|
|
617
|
+
}
|
|
618
|
+
if (arg === "off") {
|
|
619
|
+
runtime.session.setFastMode(false);
|
|
620
|
+
await runtime.output("Fast mode disabled.");
|
|
621
|
+
return commandConsumed();
|
|
622
|
+
}
|
|
623
|
+
if (arg === "status") {
|
|
624
|
+
await runtime.output(`Fast mode is ${formatFastModeStatus(runtime.session)}.`);
|
|
625
|
+
return commandConsumed();
|
|
626
|
+
}
|
|
627
|
+
return usage("Usage: /fast [on|off|status]", runtime);
|
|
628
|
+
},
|
|
629
|
+
handleTui: (command, runtime) => {
|
|
630
|
+
const arg = command.args.trim().toLowerCase();
|
|
631
|
+
if (!arg || arg === "toggle") {
|
|
632
|
+
const enabled = runtime.ctx.session.toggleFastMode();
|
|
633
|
+
refreshStatusLine(runtime.ctx);
|
|
634
|
+
runtime.ctx.showStatus(`Fast mode ${enabled ? "enabled" : "disabled"}.`);
|
|
635
|
+
runtime.ctx.editor.setText("");
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
if (arg === "on") {
|
|
639
|
+
const supported = runtime.ctx.session.setFastMode(true);
|
|
640
|
+
refreshStatusLine(runtime.ctx);
|
|
641
|
+
runtime.ctx.showStatus(
|
|
642
|
+
supported ? "Fast mode enabled." : "Fast mode is unavailable for the current model.",
|
|
643
|
+
);
|
|
644
|
+
runtime.ctx.editor.setText("");
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
if (arg === "off") {
|
|
648
|
+
runtime.ctx.session.setFastMode(false);
|
|
649
|
+
refreshStatusLine(runtime.ctx);
|
|
650
|
+
runtime.ctx.showStatus("Fast mode disabled.");
|
|
651
|
+
runtime.ctx.editor.setText("");
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (arg === "status") {
|
|
655
|
+
runtime.ctx.showStatus(`Fast mode is ${formatFastModeStatus(runtime.ctx.session)}.`);
|
|
656
|
+
runtime.ctx.editor.setText("");
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
runtime.ctx.showStatus("Usage: /fast [on|off|status]");
|
|
660
|
+
runtime.ctx.editor.setText("");
|
|
661
|
+
},
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
name: "computer",
|
|
665
|
+
description: "Toggle the native computer-use tool for this session",
|
|
666
|
+
acpDescription: "Toggle computer use",
|
|
667
|
+
acpInputHint: "[on|off|status]",
|
|
668
|
+
subcommands: [
|
|
669
|
+
{ name: "on", description: "Enable computer use for this session" },
|
|
670
|
+
{ name: "off", description: "Disable computer use for this session" },
|
|
671
|
+
{ name: "status", description: "Show computer use status" },
|
|
672
|
+
],
|
|
673
|
+
allowArgs: true,
|
|
674
|
+
getTuiAutocompleteDescription: runtime =>
|
|
675
|
+
`Computer: ${runtime.ctx.session.settings.get("computer.enabled") ? "on" : "off"}`,
|
|
676
|
+
handle: async (command, runtime) => {
|
|
677
|
+
const arg = command.args.trim().toLowerCase();
|
|
678
|
+
if (arg === "status") {
|
|
679
|
+
await runtime.output(await formatComputerUseStatus(runtime.session));
|
|
680
|
+
return commandConsumed();
|
|
681
|
+
}
|
|
682
|
+
if (!arg || arg === "toggle" || arg === "on" || arg === "off") {
|
|
683
|
+
const enable = arg === "off" ? false : arg === "on" || !runtime.session.settings.get("computer.enabled");
|
|
684
|
+
await runtime.output(await applyComputerUseToggle(runtime.session, enable));
|
|
685
|
+
return commandConsumed();
|
|
686
|
+
}
|
|
687
|
+
return usage("Usage: /computer [on|off|status]", runtime);
|
|
688
|
+
},
|
|
689
|
+
handleTui: async (command, runtime) => {
|
|
690
|
+
const arg = command.args.trim().toLowerCase();
|
|
691
|
+
if (arg === "status") {
|
|
692
|
+
runtime.ctx.showStatus(await formatComputerUseStatus(runtime.ctx.session));
|
|
693
|
+
runtime.ctx.editor.setText("");
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (!arg || arg === "toggle" || arg === "on" || arg === "off") {
|
|
697
|
+
const enable =
|
|
698
|
+
arg === "off" ? false : arg === "on" || !runtime.ctx.session.settings.get("computer.enabled");
|
|
699
|
+
runtime.ctx.showStatus(await applyComputerUseToggle(runtime.ctx.session, enable));
|
|
700
|
+
runtime.ctx.editor.setText("");
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
runtime.ctx.showStatus("Usage: /computer [on|off|status]");
|
|
704
|
+
runtime.ctx.editor.setText("");
|
|
705
|
+
},
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
name: "vision",
|
|
709
|
+
description: "Control the inspect_image vision-delegation tool for this session",
|
|
710
|
+
acpDescription: "Toggle vision delegation",
|
|
711
|
+
acpInputHint: "[on|off|auto|status]",
|
|
712
|
+
subcommands: [
|
|
713
|
+
{ name: "on", description: "Always expose inspect_image this session" },
|
|
714
|
+
{ name: "off", description: "Never expose inspect_image this session" },
|
|
715
|
+
{ name: "auto", description: "Follow inspect_image.mode (auto hides it for vision-capable models)" },
|
|
716
|
+
{ name: "status", description: "Show inspect_image status" },
|
|
717
|
+
],
|
|
718
|
+
allowArgs: true,
|
|
719
|
+
getTuiAutocompleteDescription: runtime => `Vision: ${runtime.ctx.session.inspectImageState().mode}`,
|
|
720
|
+
handle: async (command, runtime) => {
|
|
721
|
+
const arg = command.args.trim().toLowerCase();
|
|
722
|
+
if (arg === "status") {
|
|
723
|
+
await runtime.output(formatVisionStatus(runtime.session));
|
|
724
|
+
return commandConsumed();
|
|
725
|
+
}
|
|
726
|
+
if (arg === "on" || arg === "off" || arg === "auto") {
|
|
727
|
+
await runtime.output(await applyVisionMode(runtime.session, arg));
|
|
728
|
+
return commandConsumed();
|
|
729
|
+
}
|
|
730
|
+
return usage("Usage: /vision [on|off|auto|status]", runtime);
|
|
731
|
+
},
|
|
732
|
+
handleTui: async (command, runtime) => {
|
|
733
|
+
const arg = command.args.trim().toLowerCase();
|
|
734
|
+
if (arg === "status") {
|
|
735
|
+
runtime.ctx.showStatus(formatVisionStatus(runtime.ctx.session));
|
|
736
|
+
runtime.ctx.editor.setText("");
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
if (arg === "on" || arg === "off" || arg === "auto") {
|
|
740
|
+
runtime.ctx.showStatus(await applyVisionMode(runtime.ctx.session, arg));
|
|
741
|
+
runtime.ctx.editor.setText("");
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
runtime.ctx.showStatus("Usage: /vision [on|off|auto|status]");
|
|
745
|
+
runtime.ctx.editor.setText("");
|
|
746
|
+
},
|
|
747
|
+
},
|
|
748
|
+
{
|
|
749
|
+
name: "prewalk",
|
|
750
|
+
description: "Switch to a fast/cheap model at the next action (works even without --prewalk)",
|
|
751
|
+
acpDescription: "Prewalk at the next action",
|
|
752
|
+
handle: async (_command, runtime) => {
|
|
753
|
+
const rolePattern = expandRoleAlias("@smol", runtime.settings);
|
|
754
|
+
const resolved = resolveCliModel({
|
|
755
|
+
cliModel: rolePattern,
|
|
756
|
+
modelRegistry: runtime.session.modelRegistry,
|
|
757
|
+
preferences: getModelMatchPreferences(runtime.settings),
|
|
758
|
+
});
|
|
759
|
+
if (resolved.error || !resolved.model) {
|
|
760
|
+
return usage(resolved.error ?? `Model "${rolePattern}" not found`, runtime);
|
|
761
|
+
}
|
|
762
|
+
if (!runtime.session.modelRegistry.hasConfiguredAuth(resolved.model)) {
|
|
763
|
+
return usage(`No API key for ${resolved.model.provider}/${resolved.model.id}`, runtime);
|
|
764
|
+
}
|
|
765
|
+
runtime.session.armPrewalk(resolved.model, resolved.thinkingLevel);
|
|
766
|
+
await runtime.output(
|
|
767
|
+
`Prewalk on: switching to ${resolved.model.provider}/${resolved.model.id} at the next edit/write (todo-gated).`,
|
|
768
|
+
);
|
|
769
|
+
return commandConsumed();
|
|
770
|
+
},
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
name: "advisor",
|
|
774
|
+
description: "Toggle the advisor (a second model that reviews each turn and injects notes)",
|
|
775
|
+
acpDescription: "Toggle advisor",
|
|
776
|
+
acpInputHint: "[on|off|status|dump [raw]|configure]",
|
|
777
|
+
subcommands: [
|
|
778
|
+
{ name: "on", description: "Enable the advisor" },
|
|
779
|
+
{ name: "off", description: "Disable the advisor" },
|
|
780
|
+
{ name: "status", description: "Show advisor status" },
|
|
781
|
+
{ name: "dump", description: "Copy the advisor's transcript to clipboard", usage: "[raw]" },
|
|
782
|
+
{ name: "configure", description: "Open the advisor configuration editor (TUI)" },
|
|
783
|
+
],
|
|
784
|
+
allowArgs: true,
|
|
785
|
+
getTuiAutocompleteDescription: runtime => {
|
|
786
|
+
const stats = runtime.ctx.session.getAdvisorStats();
|
|
787
|
+
if (stats.active && stats.advisors.length > 1) return `Advisor: on (${stats.advisors.length} advisors)`;
|
|
788
|
+
if (stats.active && stats.model) return `Advisor: on (${stats.model.provider}/${stats.model.id})`;
|
|
789
|
+
if (stats.configured) return "Advisor: configured, no model";
|
|
790
|
+
return "Advisor: off";
|
|
791
|
+
},
|
|
792
|
+
handle: async (command, runtime) => {
|
|
793
|
+
const { verb, rest } = parseSubcommand(command.args);
|
|
794
|
+
if (!verb || verb === "toggle") {
|
|
795
|
+
const active = runtime.session.toggleAdvisorEnabled();
|
|
796
|
+
const configured = runtime.session.isAdvisorEnabled();
|
|
797
|
+
if (active) {
|
|
798
|
+
await runtime.output("Advisor enabled.");
|
|
799
|
+
} else if (configured) {
|
|
800
|
+
await runtime.output("Advisor setting enabled, but no model is assigned to the 'advisor' role.");
|
|
801
|
+
} else {
|
|
802
|
+
await runtime.output("Advisor disabled.");
|
|
803
|
+
}
|
|
804
|
+
return commandConsumed();
|
|
805
|
+
}
|
|
806
|
+
if (verb === "on") {
|
|
807
|
+
const active = runtime.session.setAdvisorEnabled(true);
|
|
808
|
+
await runtime.output(
|
|
809
|
+
active ? "Advisor enabled." : "Advisor setting enabled, but no model is assigned to the 'advisor' role.",
|
|
810
|
+
);
|
|
811
|
+
return commandConsumed();
|
|
812
|
+
}
|
|
813
|
+
if (verb === "off") {
|
|
814
|
+
runtime.session.setAdvisorEnabled(false);
|
|
815
|
+
await runtime.output("Advisor disabled.");
|
|
816
|
+
return commandConsumed();
|
|
817
|
+
}
|
|
818
|
+
if (verb === "status") {
|
|
819
|
+
await runtime.output(runtime.session.formatAdvisorStatus());
|
|
820
|
+
return commandConsumed();
|
|
821
|
+
}
|
|
822
|
+
if (verb === "dump") {
|
|
823
|
+
const isRaw = rest.toLowerCase() === "raw";
|
|
824
|
+
const text = runtime.session.formatAdvisorHistoryAsText({ compact: !isRaw });
|
|
825
|
+
await runtime.output(text ?? "Advisor is not active for this session.");
|
|
826
|
+
return commandConsumed();
|
|
827
|
+
}
|
|
828
|
+
if (verb === "configure") {
|
|
829
|
+
await runtime.output(
|
|
830
|
+
"/advisor configure opens an interactive editor and is only available in the interactive TUI.",
|
|
831
|
+
);
|
|
832
|
+
return commandConsumed();
|
|
833
|
+
}
|
|
834
|
+
return usage("Usage: /advisor [on|off|status|dump [raw]|configure]", runtime);
|
|
835
|
+
},
|
|
836
|
+
handleTui: async (command, runtime) => {
|
|
837
|
+
const { verb, rest } = parseSubcommand(command.args);
|
|
838
|
+
if (!verb || verb === "toggle") {
|
|
839
|
+
const active = runtime.ctx.session.toggleAdvisorEnabled();
|
|
840
|
+
const configured = runtime.ctx.session.isAdvisorEnabled();
|
|
841
|
+
if (active) {
|
|
842
|
+
runtime.ctx.showStatus("Advisor enabled.");
|
|
843
|
+
} else if (configured) {
|
|
844
|
+
runtime.ctx.showStatus("Advisor setting enabled, but no model is assigned to the 'advisor' role.");
|
|
845
|
+
} else {
|
|
846
|
+
runtime.ctx.showStatus("Advisor disabled.");
|
|
847
|
+
}
|
|
848
|
+
refreshStatusLine(runtime.ctx);
|
|
849
|
+
runtime.ctx.editor.setText("");
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
if (verb === "on") {
|
|
853
|
+
const active = runtime.ctx.session.setAdvisorEnabled(true);
|
|
854
|
+
runtime.ctx.showStatus(
|
|
855
|
+
active ? "Advisor enabled." : "Advisor setting enabled, but no model is assigned to the 'advisor' role.",
|
|
856
|
+
);
|
|
857
|
+
refreshStatusLine(runtime.ctx);
|
|
858
|
+
runtime.ctx.editor.setText("");
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
if (verb === "off") {
|
|
862
|
+
runtime.ctx.session.setAdvisorEnabled(false);
|
|
863
|
+
runtime.ctx.showStatus("Advisor disabled.");
|
|
864
|
+
refreshStatusLine(runtime.ctx);
|
|
865
|
+
runtime.ctx.editor.setText("");
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
if (verb === "status") {
|
|
869
|
+
await runtime.ctx.handleAdvisorStatusCommand();
|
|
870
|
+
runtime.ctx.editor.setText("");
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (verb === "dump") {
|
|
874
|
+
const isRaw = rest.toLowerCase() === "raw";
|
|
875
|
+
runtime.ctx.handleAdvisorDumpCommand(isRaw);
|
|
876
|
+
runtime.ctx.editor.setText("");
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
if (verb === "configure") {
|
|
880
|
+
runtime.ctx.showAdvisorConfigure();
|
|
881
|
+
runtime.ctx.editor.setText("");
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
runtime.ctx.showStatus("Usage: /advisor [on|off|status|dump [raw]|configure]");
|
|
885
|
+
runtime.ctx.editor.setText("");
|
|
886
|
+
},
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
name: "export",
|
|
890
|
+
description: "Export session to HTML file",
|
|
891
|
+
inlineHint: "[--themes] [path]",
|
|
892
|
+
allowArgs: true,
|
|
893
|
+
handle: async (command, runtime) => {
|
|
894
|
+
try {
|
|
895
|
+
const { outputPath, useUserThemes } = parseExportArgs(command.args);
|
|
896
|
+
if (outputPath === "--copy" || outputPath === "clipboard" || outputPath === "copy") {
|
|
897
|
+
return usage("Use /dump to copy the session to clipboard.", runtime);
|
|
898
|
+
}
|
|
899
|
+
const filePath = await runtime.session.exportToHtml(outputPath, useUserThemes);
|
|
900
|
+
await runtime.output(`Session exported to: ${filePath}`);
|
|
901
|
+
return commandConsumed();
|
|
902
|
+
} catch (err) {
|
|
903
|
+
return usage(`Failed to export session: ${errorMessage(err)}`, runtime);
|
|
904
|
+
}
|
|
905
|
+
},
|
|
906
|
+
handleTui: async (command, runtime) => {
|
|
907
|
+
await runtime.ctx.handleExportCommand(command.text);
|
|
908
|
+
runtime.ctx.editor.setText("");
|
|
909
|
+
},
|
|
910
|
+
},
|
|
911
|
+
{
|
|
912
|
+
name: "dump",
|
|
913
|
+
description: "Copy session transcript to clipboard (and write LLM request JSON to tmp)",
|
|
914
|
+
acpDescription: "Return full transcript as plain text, with LLM request JSON path",
|
|
915
|
+
allowArgs: true,
|
|
916
|
+
handle: async (_command, runtime) => {
|
|
917
|
+
const text = runtime.session.formatSessionAsText();
|
|
918
|
+
if (!text) {
|
|
919
|
+
await runtime.output("No messages to dump yet.");
|
|
920
|
+
return commandConsumed();
|
|
921
|
+
}
|
|
922
|
+
let sidecarPath: string | undefined;
|
|
923
|
+
try {
|
|
924
|
+
sidecarPath = await runtime.session.dumpLlmRequestToTmpDir();
|
|
925
|
+
} catch {
|
|
926
|
+
// Sidecar is best-effort; the transcript is still output below.
|
|
927
|
+
}
|
|
928
|
+
const lines = [text];
|
|
929
|
+
if (sidecarPath)
|
|
930
|
+
lines.push(
|
|
931
|
+
"",
|
|
932
|
+
`LLM request JSON: ${sidecarPath}`,
|
|
933
|
+
"This file persists on disk and may contain raw context/secrets — treat accordingly.",
|
|
934
|
+
);
|
|
935
|
+
await runtime.output(lines.join("\n"));
|
|
936
|
+
return commandConsumed();
|
|
937
|
+
},
|
|
938
|
+
handleTui: async (_command, runtime) => {
|
|
939
|
+
await runtime.ctx.handleDumpCommand();
|
|
940
|
+
runtime.ctx.editor.setText("");
|
|
941
|
+
},
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
name: "share",
|
|
945
|
+
description: "Share session via an encrypted link (share server or secret gist)",
|
|
946
|
+
handle: async (_command, runtime) => {
|
|
947
|
+
try {
|
|
948
|
+
const result = await shareSession(runtime.sessionManager, {
|
|
949
|
+
serverUrl: runtime.settings.get("share.serverUrl"),
|
|
950
|
+
store: runtime.settings.get("share.store"),
|
|
951
|
+
state: runtime.session.state,
|
|
952
|
+
obfuscator: runtime.settings.get("share.redactSecrets") ? runtime.session.obfuscator : undefined,
|
|
953
|
+
});
|
|
954
|
+
const lines = [`Share URL: ${result.url}`];
|
|
955
|
+
if (result.gistUrl) lines.push(`Gist: ${result.gistUrl}`);
|
|
956
|
+
if (result.truncated) lines.push("Note: large content was trimmed to fit the share size limit.");
|
|
957
|
+
await runtime.output(lines.join("\n"));
|
|
958
|
+
return commandConsumed();
|
|
959
|
+
} catch (err) {
|
|
960
|
+
return usage(`Failed to share session: ${errorMessage(err)}`, runtime);
|
|
961
|
+
}
|
|
962
|
+
},
|
|
963
|
+
handleTui: async (_command, runtime) => {
|
|
964
|
+
await runtime.ctx.handleShareCommand();
|
|
965
|
+
runtime.ctx.editor.setText("");
|
|
966
|
+
},
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
name: "collab",
|
|
970
|
+
description: "Share this session live via a relay",
|
|
971
|
+
inlineHint: "[start|view|stop|status] [relayUrl]",
|
|
972
|
+
subcommands: [
|
|
973
|
+
{ name: "view", description: "Share a read-only link (guests can watch, not prompt)" },
|
|
974
|
+
{ name: "status", description: "Show link + participants" },
|
|
975
|
+
{ name: "stop", description: "Stop sharing" },
|
|
976
|
+
],
|
|
977
|
+
allowArgs: true,
|
|
978
|
+
getTuiAutocompleteDescription: runtime => {
|
|
979
|
+
if (runtime.ctx.collabHost) {
|
|
980
|
+
return `Collab: hosting (${Math.max(0, runtime.ctx.collabHost.participants.length - 1)} guests)`;
|
|
981
|
+
}
|
|
982
|
+
if (runtime.ctx.collabGuest?.readOnly) return "Collab: read-only guest";
|
|
983
|
+
if (runtime.ctx.collabGuest) return "Collab: guest";
|
|
984
|
+
return "Collab: off";
|
|
985
|
+
},
|
|
986
|
+
handleTui: async (command, runtime) => {
|
|
987
|
+
const ctx = runtime.ctx;
|
|
988
|
+
ctx.editor.setText("");
|
|
989
|
+
const args = command.args.trim();
|
|
990
|
+
const { verb, rest } = parseSubcommand(args);
|
|
991
|
+
if (verb === "stop") {
|
|
992
|
+
if (!ctx.collabHost) {
|
|
993
|
+
ctx.showStatus("Not hosting a collab session");
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
await ctx.collabHost.stop("host stopped");
|
|
997
|
+
ctx.showStatus("Collab stopped");
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
if (verb === "status") {
|
|
1001
|
+
if (ctx.collabHost) {
|
|
1002
|
+
const names = ctx.collabHost.participants.map(p =>
|
|
1003
|
+
p.role === "host" ? `${p.name} (host)` : p.readOnly ? `${p.name} (view-only)` : p.name,
|
|
1004
|
+
);
|
|
1005
|
+
ctx.showStatus(`Collab: ${names.join(", ")} — ${collabWebLinkClickable(ctx.collabHost.webLink)}`);
|
|
1006
|
+
} else if (ctx.collabGuest) {
|
|
1007
|
+
ctx.showStatus(
|
|
1008
|
+
ctx.collabGuest.readOnly
|
|
1009
|
+
? "In a collab session as a read-only guest (/leave to exit)"
|
|
1010
|
+
: "In a collab session as a guest (/leave to exit)",
|
|
1011
|
+
);
|
|
1012
|
+
} else {
|
|
1013
|
+
ctx.showStatus("Not in a collab session");
|
|
1014
|
+
}
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
if (ctx.collabGuest) {
|
|
1018
|
+
ctx.showError("Already in a collab session as a guest (/leave first)");
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
const knownStartVerb = verb === "start" || verb === "view";
|
|
1022
|
+
const view = verb === "view";
|
|
1023
|
+
if (ctx.collabHost) {
|
|
1024
|
+
showCollabLink(
|
|
1025
|
+
ctx,
|
|
1026
|
+
ctx.collabHost,
|
|
1027
|
+
view ? "Read-only collab session active" : "Collab session active",
|
|
1028
|
+
view,
|
|
1029
|
+
);
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
1032
|
+
const explicitUrl = knownStartVerb ? rest : args;
|
|
1033
|
+
const relayInput = explicitUrl || ctx.settings.get("collab.relayUrl") || "";
|
|
1034
|
+
if (!relayInput) {
|
|
1035
|
+
ctx.showError(
|
|
1036
|
+
"No relay configured. Set collab.relayUrl in /settings or pass one: /collab relay.example.com",
|
|
1037
|
+
);
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
// Scheme-less relay args default to wss (ws:// must be spelled out for localhost).
|
|
1041
|
+
const relayUrl = relayInput.includes("://") ? relayInput : `wss://${relayInput}`;
|
|
1042
|
+
const webUrl = ctx.settings.get("collab.webUrl") || "";
|
|
1043
|
+
const host = new CollabHost(ctx);
|
|
1044
|
+
try {
|
|
1045
|
+
await host.start(relayUrl, webUrl);
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
ctx.showError(`Failed to start collab session: ${errorMessage(err)}`);
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
ctx.collabHost = host;
|
|
1051
|
+
showCollabLink(ctx, host, "Collab session started!", view);
|
|
1052
|
+
},
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
name: "join",
|
|
1056
|
+
description: "Join a shared collab session",
|
|
1057
|
+
inlineHint: "<link>",
|
|
1058
|
+
allowArgs: true,
|
|
1059
|
+
handleTui: async (command, runtime) => {
|
|
1060
|
+
const ctx = runtime.ctx;
|
|
1061
|
+
ctx.editor.setText("");
|
|
1062
|
+
const link = command.args.trim();
|
|
1063
|
+
if (!link) {
|
|
1064
|
+
ctx.showError("Usage: /join <link>");
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
if (ctx.collabHost) {
|
|
1068
|
+
ctx.showError("Stop hosting first (/collab stop)");
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
if (ctx.collabGuest) {
|
|
1072
|
+
ctx.showError("Already in a collab session (/leave first)");
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
try {
|
|
1076
|
+
await new CollabGuestLink(ctx).join(link);
|
|
1077
|
+
} catch (err) {
|
|
1078
|
+
ctx.showError(`Failed to join collab session: ${errorMessage(err)}`);
|
|
1079
|
+
}
|
|
1080
|
+
},
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
name: "leave",
|
|
1084
|
+
description: "Leave the collab session",
|
|
1085
|
+
getTuiAutocompleteDescription: runtime => {
|
|
1086
|
+
if (runtime.ctx.collabHost) return "Leave collab: hosting";
|
|
1087
|
+
if (runtime.ctx.collabGuest) return "Leave collab: guest";
|
|
1088
|
+
return "Leave collab: not in collab";
|
|
1089
|
+
},
|
|
1090
|
+
handleTui: async (_command, runtime) => {
|
|
1091
|
+
const ctx = runtime.ctx;
|
|
1092
|
+
ctx.editor.setText("");
|
|
1093
|
+
if (ctx.collabGuest) {
|
|
1094
|
+
await ctx.collabGuest.leave("left");
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
if (ctx.collabHost) {
|
|
1098
|
+
await ctx.collabHost.stop("host stopped");
|
|
1099
|
+
ctx.showStatus("Collab stopped");
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
ctx.showStatus("Not in a collab session");
|
|
1103
|
+
},
|
|
1104
|
+
},
|
|
1105
|
+
{
|
|
1106
|
+
name: "browser",
|
|
1107
|
+
description: "Toggle browser headless vs visible mode",
|
|
1108
|
+
acpInputHint: "[headless|visible]",
|
|
1109
|
+
subcommands: [
|
|
1110
|
+
{ name: "headless", description: "Switch to headless mode" },
|
|
1111
|
+
{ name: "visible", description: "Switch to visible mode" },
|
|
1112
|
+
],
|
|
1113
|
+
allowArgs: true,
|
|
1114
|
+
getTuiAutocompleteDescription: runtime => {
|
|
1115
|
+
if (!runtime.ctx.settings.get("browser.enabled" as SettingPath)) return "Browser: disabled";
|
|
1116
|
+
return runtime.ctx.settings.get("browser.headless" as SettingPath) ? "Browser: headless" : "Browser: visible";
|
|
1117
|
+
},
|
|
1118
|
+
handle: async (command, runtime) => {
|
|
1119
|
+
const arg = command.args.toLowerCase();
|
|
1120
|
+
const enabled = runtime.settings.get("browser.enabled" as SettingPath) as boolean;
|
|
1121
|
+
if (!enabled) return usage("Browser tool is disabled (enable in settings).", runtime);
|
|
1122
|
+
const current = runtime.settings.get("browser.headless" as SettingPath) as boolean;
|
|
1123
|
+
let next = current;
|
|
1124
|
+
if (!arg) next = !current;
|
|
1125
|
+
else if (arg === "headless" || arg === "hidden") next = true;
|
|
1126
|
+
else if (arg === "visible" || arg === "show" || arg === "headful") next = false;
|
|
1127
|
+
else return usage("Usage: /browser [headless|visible]", runtime);
|
|
1128
|
+
runtime.settings.set("browser.headless" as SettingPath, next as SettingValue<SettingPath>);
|
|
1129
|
+
const tool = runtime.session.getToolByName("browser");
|
|
1130
|
+
if (tool && "restartForModeChange" in tool) {
|
|
1131
|
+
try {
|
|
1132
|
+
await (tool as { restartForModeChange: () => Promise<void> }).restartForModeChange();
|
|
1133
|
+
} catch (err) {
|
|
1134
|
+
// Setting was already mutated; surface the restart failure so the
|
|
1135
|
+
// user knows the browser is in an inconsistent state.
|
|
1136
|
+
await runtime.output(
|
|
1137
|
+
`Browser mode set to ${next ? "headless" : "visible"}, but restart failed: ${errorMessage(err)}`,
|
|
1138
|
+
);
|
|
1139
|
+
return commandConsumed();
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
await runtime.output(`Browser mode: ${next ? "headless" : "visible"}`);
|
|
1143
|
+
return commandConsumed();
|
|
1144
|
+
},
|
|
1145
|
+
handleTui: async (command, runtime) => {
|
|
1146
|
+
const arg = command.args.toLowerCase();
|
|
1147
|
+
const current = settings.get("browser.headless" as SettingPath) as boolean;
|
|
1148
|
+
let next = current;
|
|
1149
|
+
if (!(settings.get("browser.enabled" as SettingPath) as boolean)) {
|
|
1150
|
+
runtime.ctx.showWarning("Browser tool is disabled (enable in settings)");
|
|
1151
|
+
runtime.ctx.editor.setText("");
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
if (!arg) {
|
|
1155
|
+
next = !current;
|
|
1156
|
+
} else if (arg === "headless" || arg === "hidden") {
|
|
1157
|
+
next = true;
|
|
1158
|
+
} else if (arg === "visible" || arg === "show" || arg === "headful") {
|
|
1159
|
+
next = false;
|
|
1160
|
+
} else {
|
|
1161
|
+
runtime.ctx.showStatus("Usage: /browser [headless|visible]");
|
|
1162
|
+
runtime.ctx.editor.setText("");
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
settings.set("browser.headless" as SettingPath, next as SettingValue<SettingPath>);
|
|
1166
|
+
const tool = runtime.ctx.session.getToolByName("browser");
|
|
1167
|
+
if (tool && "restartForModeChange" in tool) {
|
|
1168
|
+
try {
|
|
1169
|
+
await (tool as { restartForModeChange: () => Promise<void> }).restartForModeChange();
|
|
1170
|
+
} catch (error) {
|
|
1171
|
+
runtime.ctx.showWarning(`Failed to restart browser: ${errorMessage(error)}`);
|
|
1172
|
+
runtime.ctx.editor.setText("");
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
runtime.ctx.showStatus(`Browser mode: ${next ? "headless" : "visible"}`);
|
|
1177
|
+
runtime.ctx.editor.setText("");
|
|
1178
|
+
},
|
|
1179
|
+
},
|
|
1180
|
+
{
|
|
1181
|
+
name: "copy",
|
|
1182
|
+
description: "Pick text or code from the conversation to copy",
|
|
1183
|
+
allowArgs: true,
|
|
1184
|
+
handleTui: async (command, runtime) => {
|
|
1185
|
+
const arg = command.args.trim().toLowerCase();
|
|
1186
|
+
if (!arg) {
|
|
1187
|
+
runtime.ctx.showCopySelector();
|
|
1188
|
+
runtime.ctx.editor.setText("");
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
if (arg === "code") {
|
|
1192
|
+
const block = extractLastCodeBlock(runtime.ctx.session.messages);
|
|
1193
|
+
if (!block) {
|
|
1194
|
+
runtime.ctx.showStatus("No code block to copy.");
|
|
1195
|
+
runtime.ctx.editor.setText("");
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
await copyToClipboard(block.code);
|
|
1199
|
+
runtime.ctx.showStatus("Copied code block to clipboard");
|
|
1200
|
+
runtime.ctx.editor.setText("");
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
if (arg === "cmd" || arg === "command") {
|
|
1204
|
+
const lastCommand = extractLastCommand(runtime.ctx.session.messages);
|
|
1205
|
+
if (!lastCommand) {
|
|
1206
|
+
runtime.ctx.showStatus("No command to copy.");
|
|
1207
|
+
runtime.ctx.editor.setText("");
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
await copyToClipboard(lastCommand.code);
|
|
1211
|
+
runtime.ctx.showStatus(`Copied ${lastCommand.kind === "bash" ? "bash command" : "eval code"} to clipboard`);
|
|
1212
|
+
runtime.ctx.editor.setText("");
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
runtime.ctx.showStatus("Usage: /copy [code|cmd]");
|
|
1216
|
+
runtime.ctx.editor.setText("");
|
|
1217
|
+
},
|
|
1218
|
+
},
|
|
1219
|
+
{
|
|
1220
|
+
name: "todo",
|
|
1221
|
+
description: "View or modify the agent's todo list",
|
|
1222
|
+
acpDescription: "Manage todos",
|
|
1223
|
+
acpInputHint: "<subcommand>",
|
|
1224
|
+
subcommands: [
|
|
1225
|
+
{ name: "edit", description: "Open todos in $EDITOR (Markdown round-trip)" },
|
|
1226
|
+
{ name: "copy", description: "Copy todos as Markdown to clipboard" },
|
|
1227
|
+
{ name: "export", description: "Write todos as Markdown to a file (default: TODO.md)", usage: "[<path>]" },
|
|
1228
|
+
{ name: "import", description: "Replace todos from a Markdown file (default: TODO.md)", usage: "[<path>]" },
|
|
1229
|
+
{
|
|
1230
|
+
name: "append",
|
|
1231
|
+
description: "Append a task; phase fuzzy-matched or auto-created",
|
|
1232
|
+
usage: "[<phase>] <task...>",
|
|
1233
|
+
},
|
|
1234
|
+
{ name: "start", description: "Mark task in_progress (fuzzy-matched)", usage: "<task>" },
|
|
1235
|
+
{ name: "done", description: "Mark task/phase/all completed (fuzzy-matched)", usage: "[<task|phase>]" },
|
|
1236
|
+
{ name: "drop", description: "Mark task/phase/all abandoned (fuzzy-matched)", usage: "[<task|phase>]" },
|
|
1237
|
+
{ name: "rm", description: "Remove task/phase/all (fuzzy-matched)", usage: "[<task|phase>]" },
|
|
1238
|
+
],
|
|
1239
|
+
allowArgs: true,
|
|
1240
|
+
getTuiAutocompleteDescription: runtime => {
|
|
1241
|
+
const tasks = runtime.ctx.todoPhases.flatMap(phase => phase.tasks);
|
|
1242
|
+
if (tasks.length === 0) return "Todos: none";
|
|
1243
|
+
const pending = tasks.filter(task => task.status === "pending").length;
|
|
1244
|
+
const inProgress = tasks.filter(task => task.status === "in_progress").length;
|
|
1245
|
+
const completed = tasks.filter(task => task.status === "completed").length;
|
|
1246
|
+
return `Todos: ${pending + inProgress} open (${inProgress} in progress, ${completed} done)`;
|
|
1247
|
+
},
|
|
1248
|
+
handle: handleTodoAcp,
|
|
1249
|
+
handleTui: async (command, runtime) => {
|
|
1250
|
+
await runtime.ctx.handleTodoCommand(command.args);
|
|
1251
|
+
runtime.ctx.editor.setText("");
|
|
1252
|
+
},
|
|
1253
|
+
},
|
|
1254
|
+
{
|
|
1255
|
+
name: "session",
|
|
1256
|
+
description: "Session management commands",
|
|
1257
|
+
acpDescription: "Show or configure the current session",
|
|
1258
|
+
acpInputHint: "[info|delete|pin [account]]",
|
|
1259
|
+
subcommands: [
|
|
1260
|
+
{ name: "info", description: "Show session info and stats" },
|
|
1261
|
+
{ name: "delete", description: "Delete current session and return to selector" },
|
|
1262
|
+
{
|
|
1263
|
+
name: "pin",
|
|
1264
|
+
description: "Pin the current provider to a stored OAuth account",
|
|
1265
|
+
usage: "[account]",
|
|
1266
|
+
},
|
|
1267
|
+
],
|
|
1268
|
+
allowArgs: true,
|
|
1269
|
+
handle: async (command, runtime) => {
|
|
1270
|
+
const { verb, rest } = parseSubcommand(command.args);
|
|
1271
|
+
if (!verb || (verb === "info" && !rest)) {
|
|
1272
|
+
await runtime.output(
|
|
1273
|
+
[
|
|
1274
|
+
`Session: ${runtime.session.sessionId}`,
|
|
1275
|
+
`Title: ${runtime.session.sessionName}`,
|
|
1276
|
+
`CWD: ${runtime.cwd}`,
|
|
1277
|
+
].join("\n"),
|
|
1278
|
+
);
|
|
1279
|
+
return commandConsumed();
|
|
1280
|
+
}
|
|
1281
|
+
if (verb === "delete" && !rest) {
|
|
1282
|
+
if (runtime.session.isStreaming) return usage("Cannot delete the session while streaming.", runtime);
|
|
1283
|
+
const sessionFile = runtime.sessionManager.getSessionFile();
|
|
1284
|
+
if (!sessionFile) return usage("No session file to delete (in-memory session).", runtime);
|
|
1285
|
+
// Route through the active SessionManager so the persist writer is
|
|
1286
|
+
// closed before the file is deleted. Constructing a fresh
|
|
1287
|
+
// FileSessionStorage and calling deleteSessionWithArtifacts leaves
|
|
1288
|
+
// the active writer attached to the now-deleted path, so the next
|
|
1289
|
+
// prompt would silently resurrect or corrupt the "deleted" file.
|
|
1290
|
+
try {
|
|
1291
|
+
await runtime.sessionManager.dropSession(sessionFile);
|
|
1292
|
+
} catch (err) {
|
|
1293
|
+
return usage(`Failed to delete session: ${errorMessage(err)}`, runtime);
|
|
1294
|
+
}
|
|
1295
|
+
await runtime.output(
|
|
1296
|
+
`Session deleted: ${sessionFile}. Use ACP \`session/load\` to switch to another session.`,
|
|
1297
|
+
);
|
|
1298
|
+
return commandConsumed();
|
|
1299
|
+
}
|
|
1300
|
+
if (verb === "pin") {
|
|
1301
|
+
await handleSessionPinCommand(rest, runtime.session, runtime.output);
|
|
1302
|
+
return commandConsumed();
|
|
1303
|
+
}
|
|
1304
|
+
return usage("Usage: /session [info|delete|pin [account]]", runtime);
|
|
1305
|
+
},
|
|
1306
|
+
handleTui: async (command, runtime) => {
|
|
1307
|
+
const { verb, rest } = parseSubcommand(command.args);
|
|
1308
|
+
if (verb === "delete" && !rest) {
|
|
1309
|
+
runtime.ctx.editor.setText("");
|
|
1310
|
+
await runtime.ctx.handleSessionDeleteCommand();
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
if (verb === "pin") {
|
|
1314
|
+
if (rest) {
|
|
1315
|
+
await handleSessionPinCommand(rest, runtime.ctx.session, text => runtime.ctx.showStatus(text));
|
|
1316
|
+
refreshStatusLine(runtime.ctx);
|
|
1317
|
+
} else {
|
|
1318
|
+
await runtime.ctx.showSessionPinSelector();
|
|
1319
|
+
}
|
|
1320
|
+
runtime.ctx.editor.setText("");
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
if (!verb || (verb === "info" && !rest)) {
|
|
1324
|
+
await runtime.ctx.handleSessionCommand();
|
|
1325
|
+
} else {
|
|
1326
|
+
runtime.ctx.showStatus("Usage: /session [info|delete|pin [account]]");
|
|
1327
|
+
}
|
|
1328
|
+
runtime.ctx.editor.setText("");
|
|
1329
|
+
},
|
|
1330
|
+
},
|
|
1331
|
+
{
|
|
1332
|
+
name: "jobs",
|
|
1333
|
+
description: "Show async background jobs status",
|
|
1334
|
+
acpDescription: "Show background jobs",
|
|
1335
|
+
getTuiAutocompleteDescription: runtime => {
|
|
1336
|
+
const snapshot = runtime.ctx.session.getAsyncJobSnapshot({ recentLimit: 5 });
|
|
1337
|
+
if (!snapshot || (snapshot.running.length === 0 && snapshot.recent.length === 0)) return "Jobs: none";
|
|
1338
|
+
return `Jobs: ${snapshot.running.length} running, ${snapshot.recent.length} recent`;
|
|
1339
|
+
},
|
|
1340
|
+
handle: async (_command, runtime) => {
|
|
1341
|
+
const snapshot = runtime.session.getAsyncJobSnapshot({ recentLimit: 5 });
|
|
1342
|
+
if (!snapshot || (snapshot.running.length === 0 && snapshot.recent.length === 0)) {
|
|
1343
|
+
await runtime.output(
|
|
1344
|
+
"No background jobs running. (Background jobs run async tools — e.g. long-running bash, debug, or task subagents that would otherwise tie up a turn. They appear here while alive and for ~5 minutes after.)",
|
|
1345
|
+
);
|
|
1346
|
+
return commandConsumed();
|
|
1347
|
+
}
|
|
1348
|
+
const now = Date.now();
|
|
1349
|
+
const lines: string[] = ["Background Jobs", `Running: ${snapshot.running.length}`];
|
|
1350
|
+
if (snapshot.running.length > 0) {
|
|
1351
|
+
lines.push("", "Running Jobs");
|
|
1352
|
+
for (const job of snapshot.running) {
|
|
1353
|
+
lines.push(` [${job.id}] ${job.type} (${job.status}) — ${formatDuration(now - job.startTime)}`);
|
|
1354
|
+
lines.push(` ${job.label}`);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
if (snapshot.recent.length > 0) {
|
|
1358
|
+
lines.push("", "Recent Jobs");
|
|
1359
|
+
for (const job of snapshot.recent) {
|
|
1360
|
+
lines.push(` [${job.id}] ${job.type} (${job.status}) — ${formatDuration(now - job.startTime)}`);
|
|
1361
|
+
lines.push(` ${job.label}`);
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
await runtime.output(lines.join("\n"));
|
|
1365
|
+
return commandConsumed();
|
|
1366
|
+
},
|
|
1367
|
+
handleTui: async (_command, runtime) => {
|
|
1368
|
+
await runtime.ctx.handleJobsCommand();
|
|
1369
|
+
runtime.ctx.editor.setText("");
|
|
1370
|
+
},
|
|
1371
|
+
},
|
|
1372
|
+
{
|
|
1373
|
+
name: "usage",
|
|
1374
|
+
description: "Show provider usage and limits",
|
|
1375
|
+
acpDescription: "Show token usage",
|
|
1376
|
+
acpInputHint: "[show|reset [account|active]]",
|
|
1377
|
+
subcommands: [
|
|
1378
|
+
{ name: "show", description: "Show provider usage and limits" },
|
|
1379
|
+
{ name: "reset", description: "Spend a saved Codex rate-limit reset", usage: "[account|active]" },
|
|
1380
|
+
],
|
|
1381
|
+
allowArgs: true,
|
|
1382
|
+
handle: async (command, runtime) => {
|
|
1383
|
+
const { verb, rest } = parseSubcommand(command.args);
|
|
1384
|
+
if (!verb || (verb === "show" && !rest)) {
|
|
1385
|
+
await runtime.output(await buildUsageReportText(runtime));
|
|
1386
|
+
return commandConsumed();
|
|
1387
|
+
}
|
|
1388
|
+
if (verb === "reset") {
|
|
1389
|
+
await handleUsageResetCommand(rest, runtime.session, runtime.output);
|
|
1390
|
+
return commandConsumed();
|
|
1391
|
+
}
|
|
1392
|
+
return usage("Usage: /usage [show|reset [account|active]]", runtime);
|
|
1393
|
+
},
|
|
1394
|
+
handleTui: async (command, runtime) => {
|
|
1395
|
+
const { verb, rest } = parseSubcommand(command.args);
|
|
1396
|
+
if (!verb || (verb === "show" && !rest)) {
|
|
1397
|
+
await runtime.ctx.handleUsageCommand();
|
|
1398
|
+
runtime.ctx.editor.setText("");
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
if (verb === "reset") {
|
|
1402
|
+
if (rest) {
|
|
1403
|
+
await handleUsageResetCommand(rest, runtime.ctx.session, text => runtime.ctx.showStatus(text));
|
|
1404
|
+
} else {
|
|
1405
|
+
await runtime.ctx.showResetUsageSelector();
|
|
1406
|
+
}
|
|
1407
|
+
runtime.ctx.editor.setText("");
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
runtime.ctx.showStatus("Usage: /usage [show|reset [account|active]]");
|
|
1411
|
+
runtime.ctx.editor.setText("");
|
|
1412
|
+
},
|
|
1413
|
+
},
|
|
1414
|
+
{
|
|
1415
|
+
name: "stats",
|
|
1416
|
+
description: "Launch the local stats dashboard",
|
|
1417
|
+
inlineHint: "[--port <port>]",
|
|
1418
|
+
allowArgs: true,
|
|
1419
|
+
handle: async (command, runtime) => {
|
|
1420
|
+
const parsed = parseStatsDashboardArgs(command.args);
|
|
1421
|
+
if ("error" in parsed) return usage(parsed.error, runtime);
|
|
1422
|
+
|
|
1423
|
+
await runtime.output("Syncing session files...");
|
|
1424
|
+
try {
|
|
1425
|
+
const result = await launchStatsDashboard(parsed);
|
|
1426
|
+
await runtime.output(result.message);
|
|
1427
|
+
} catch (error) {
|
|
1428
|
+
await runtime.output(`Stats dashboard failed: ${errorMessage(error)}`);
|
|
1429
|
+
}
|
|
1430
|
+
return commandConsumed();
|
|
1431
|
+
},
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
name: "changelog",
|
|
1435
|
+
description: "Show changelog entries",
|
|
1436
|
+
acpDescription: "Show changelog",
|
|
1437
|
+
acpInputHint: "[full]",
|
|
1438
|
+
subcommands: [{ name: "full", description: "Show complete changelog" }],
|
|
1439
|
+
allowArgs: true,
|
|
1440
|
+
handle: async (command, runtime) => {
|
|
1441
|
+
const changelogPath = getChangelogPath();
|
|
1442
|
+
const allEntries = await parseChangelog(changelogPath);
|
|
1443
|
+
const showFull = command.args.trim().toLowerCase() === "full";
|
|
1444
|
+
const entriesToShow = showFull ? allEntries : allEntries.slice(0, RECENT_CHANGELOG_ENTRY_LIMIT);
|
|
1445
|
+
if (entriesToShow.length === 0) {
|
|
1446
|
+
await runtime.output("No changelog entries found.");
|
|
1447
|
+
return commandConsumed();
|
|
1448
|
+
}
|
|
1449
|
+
await runtime.output(renderChangelogEntries(entriesToShow).markdown);
|
|
1450
|
+
return commandConsumed();
|
|
1451
|
+
},
|
|
1452
|
+
handleTui: async (command, runtime) => {
|
|
1453
|
+
const showFull = command.args.split(/\s+/).filter(Boolean).includes("full");
|
|
1454
|
+
await runtime.ctx.handleChangelogCommand(showFull);
|
|
1455
|
+
runtime.ctx.editor.setText("");
|
|
1456
|
+
},
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
name: "hotkeys",
|
|
1460
|
+
description: "Show all keyboard shortcuts",
|
|
1461
|
+
handleTui: (_command, runtime) => {
|
|
1462
|
+
runtime.ctx.handleHotkeysCommand();
|
|
1463
|
+
runtime.ctx.editor.setText("");
|
|
1464
|
+
},
|
|
1465
|
+
},
|
|
1466
|
+
{
|
|
1467
|
+
name: "tools",
|
|
1468
|
+
description: "Show tools currently visible to the agent",
|
|
1469
|
+
acpDescription: "Show available tools",
|
|
1470
|
+
getTuiAutocompleteDescription: runtime => {
|
|
1471
|
+
const active = runtime.ctx.session.getActiveToolNames().length;
|
|
1472
|
+
const all = runtime.ctx.session.getAllToolNames().length;
|
|
1473
|
+
return all === 0 ? "Tools: none available" : `Tools: ${active} active / ${all} available`;
|
|
1474
|
+
},
|
|
1475
|
+
handle: async (_command, runtime) => {
|
|
1476
|
+
const active = runtime.session.getActiveToolNames();
|
|
1477
|
+
const all = runtime.session.getAllToolNames();
|
|
1478
|
+
if (all.length === 0) {
|
|
1479
|
+
await runtime.output("No tools are available.");
|
|
1480
|
+
return commandConsumed();
|
|
1481
|
+
}
|
|
1482
|
+
const lines = all.map(name => `${active.includes(name) ? "*" : "-"} ${name}`);
|
|
1483
|
+
for (const mounted of runtime.session.getXdevToolEntries()) {
|
|
1484
|
+
lines.push(`~ xd://${mounted.name}`);
|
|
1485
|
+
}
|
|
1486
|
+
await runtime.output(lines.join("\n"));
|
|
1487
|
+
return commandConsumed();
|
|
1488
|
+
},
|
|
1489
|
+
handleTui: (_command, runtime) => {
|
|
1490
|
+
runtime.ctx.handleToolsCommand();
|
|
1491
|
+
runtime.ctx.editor.setText("");
|
|
1492
|
+
},
|
|
1493
|
+
},
|
|
1494
|
+
{
|
|
1495
|
+
name: "context",
|
|
1496
|
+
description: "Show estimated context usage breakdown",
|
|
1497
|
+
acpDescription: "Show context usage",
|
|
1498
|
+
getTuiAutocompleteDescription: runtime => {
|
|
1499
|
+
const usage = runtime.ctx.session.getContextUsage();
|
|
1500
|
+
if (!usage) return "Context: unavailable";
|
|
1501
|
+
return `Context: ${Math.round(usage.percent)}% (${formatTokenCount(usage.tokens)}/${formatTokenCount(usage.contextWindow)})`;
|
|
1502
|
+
},
|
|
1503
|
+
handle: async (_command, runtime) => {
|
|
1504
|
+
await runtime.output(buildContextReportText(runtime));
|
|
1505
|
+
return commandConsumed();
|
|
1506
|
+
},
|
|
1507
|
+
handleTui: (_command, runtime) => {
|
|
1508
|
+
runtime.ctx.handleContextCommand();
|
|
1509
|
+
runtime.ctx.editor.setText("");
|
|
1510
|
+
},
|
|
1511
|
+
},
|
|
1512
|
+
{
|
|
1513
|
+
name: "extensions",
|
|
1514
|
+
aliases: ["status"],
|
|
1515
|
+
description: "Open Extension Control Center dashboard",
|
|
1516
|
+
handleTui: (_command, runtime) => {
|
|
1517
|
+
runtime.ctx.showExtensionsDashboard();
|
|
1518
|
+
runtime.ctx.editor.setText("");
|
|
1519
|
+
},
|
|
1520
|
+
},
|
|
1521
|
+
{
|
|
1522
|
+
name: "agents",
|
|
1523
|
+
description: "Open Agent Control Center dashboard",
|
|
1524
|
+
handleTui: (_command, runtime) => {
|
|
1525
|
+
runtime.ctx.showAgentsDashboard();
|
|
1526
|
+
runtime.ctx.editor.setText("");
|
|
1527
|
+
},
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
name: "branch",
|
|
1531
|
+
description: "Create a new branch from a previous message",
|
|
1532
|
+
handleTui: (_command, runtime) => {
|
|
1533
|
+
if (settings.get("doubleEscapeAction") === "tree") {
|
|
1534
|
+
runtime.ctx.showTreeSelector();
|
|
1535
|
+
} else {
|
|
1536
|
+
runtime.ctx.showUserMessageSelector();
|
|
1537
|
+
}
|
|
1538
|
+
runtime.ctx.editor.setText("");
|
|
1539
|
+
},
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
name: "fork",
|
|
1543
|
+
description: "Create a new fork from a previous message",
|
|
1544
|
+
handleTui: async (_command, runtime) => {
|
|
1545
|
+
runtime.ctx.editor.setText("");
|
|
1546
|
+
await runtime.ctx.handleForkCommand();
|
|
1547
|
+
},
|
|
1548
|
+
},
|
|
1549
|
+
{
|
|
1550
|
+
name: "tree",
|
|
1551
|
+
description: "Navigate session tree (switch branches)",
|
|
1552
|
+
handleTui: (_command, runtime) => {
|
|
1553
|
+
runtime.ctx.showTreeSelector();
|
|
1554
|
+
runtime.ctx.editor.setText("");
|
|
1555
|
+
},
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
name: "login",
|
|
1559
|
+
description: "Login with OAuth provider",
|
|
1560
|
+
inlineHint: "[provider|redirect URL]",
|
|
1561
|
+
allowArgs: true,
|
|
1562
|
+
getTuiAutocompleteDescription: runtime =>
|
|
1563
|
+
runtime.ctx.oauthManualInput.hasPending()
|
|
1564
|
+
? `Login: waiting for ${runtime.ctx.oauthManualInput.pendingProviderId ?? "OAuth"} callback`
|
|
1565
|
+
: "Login: choose provider",
|
|
1566
|
+
handleTui: (command, runtime) => {
|
|
1567
|
+
const manualInput = runtime.ctx.oauthManualInput;
|
|
1568
|
+
const args = command.args.trim();
|
|
1569
|
+
if (args.length > 0) {
|
|
1570
|
+
const matchedProvider = getOAuthProviders().find(provider => provider.id === args);
|
|
1571
|
+
if (matchedProvider) {
|
|
1572
|
+
if (manualInput.hasPending()) {
|
|
1573
|
+
const pendingProvider = manualInput.pendingProviderId;
|
|
1574
|
+
const message = pendingProvider
|
|
1575
|
+
? `OAuth login already in progress for ${pendingProvider}. Paste the redirect URL with /login <url>.`
|
|
1576
|
+
: "OAuth login already in progress. Paste the redirect URL with /login <url>.";
|
|
1577
|
+
runtime.ctx.showWarning(message);
|
|
1578
|
+
runtime.ctx.editor.setText("");
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
void runtime.ctx.showOAuthSelector("login", matchedProvider.id);
|
|
1582
|
+
runtime.ctx.editor.setText("");
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
const submitted = manualInput.submit(args);
|
|
1586
|
+
if (submitted) {
|
|
1587
|
+
runtime.ctx.showStatus("OAuth callback received; completing login…");
|
|
1588
|
+
} else {
|
|
1589
|
+
runtime.ctx.showWarning("No OAuth login is waiting for a manual callback.");
|
|
1590
|
+
}
|
|
1591
|
+
runtime.ctx.editor.setText("");
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
if (manualInput.hasPending()) {
|
|
1596
|
+
const provider = manualInput.pendingProviderId;
|
|
1597
|
+
const message = provider
|
|
1598
|
+
? `OAuth login already in progress for ${provider}. Paste the redirect URL with /login <url>.`
|
|
1599
|
+
: "OAuth login already in progress. Paste the redirect URL with /login <url>.";
|
|
1600
|
+
runtime.ctx.showWarning(message);
|
|
1601
|
+
runtime.ctx.editor.setText("");
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
void runtime.ctx.showOAuthSelector("login");
|
|
1606
|
+
runtime.ctx.editor.setText("");
|
|
1607
|
+
},
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
name: "logout",
|
|
1611
|
+
description: "Logout from OAuth provider",
|
|
1612
|
+
inlineHint: "[provider]",
|
|
1613
|
+
allowArgs: true,
|
|
1614
|
+
handleTui: (command, runtime) => {
|
|
1615
|
+
const providerId = command.args.trim();
|
|
1616
|
+
if (providerId) {
|
|
1617
|
+
const matchedProvider = getOAuthProviders().find(provider => provider.id === providerId);
|
|
1618
|
+
if (!matchedProvider) {
|
|
1619
|
+
runtime.ctx.showWarning(`Unknown OAuth provider: ${providerId}`);
|
|
1620
|
+
runtime.ctx.editor.setText("");
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
void runtime.ctx.showOAuthSelector("logout", matchedProvider.id);
|
|
1624
|
+
runtime.ctx.editor.setText("");
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
void runtime.ctx.showOAuthSelector("logout");
|
|
1628
|
+
runtime.ctx.editor.setText("");
|
|
1629
|
+
},
|
|
1630
|
+
},
|
|
1631
|
+
{
|
|
1632
|
+
name: "mcp",
|
|
1633
|
+
description: "Manage MCP servers (add, list, remove, test)",
|
|
1634
|
+
acpDescription: "Manage MCP servers",
|
|
1635
|
+
inlineHint: "<subcommand>",
|
|
1636
|
+
subcommands: [
|
|
1637
|
+
{
|
|
1638
|
+
name: "add",
|
|
1639
|
+
description: "Add a new MCP server",
|
|
1640
|
+
usage: "<name> [--scope project|user] [--url <url>] [-- <command...>]",
|
|
1641
|
+
},
|
|
1642
|
+
{ name: "list", description: "List all configured MCP servers" },
|
|
1643
|
+
{ name: "remove", description: "Remove an MCP server", usage: "<name> [--scope project|user]" },
|
|
1644
|
+
{ name: "test", description: "Test connection to a server", usage: "<name>" },
|
|
1645
|
+
{ name: "reauth", description: "Reauthorize OAuth for a server", usage: "<name>" },
|
|
1646
|
+
{ name: "unauth", description: "Remove OAuth auth from a server", usage: "<name>" },
|
|
1647
|
+
{ name: "enable", description: "Enable an MCP server", usage: "<name>" },
|
|
1648
|
+
{ name: "disable", description: "Disable an MCP server", usage: "<name>" },
|
|
1649
|
+
{
|
|
1650
|
+
name: "smithery-search",
|
|
1651
|
+
description: "Search Smithery registry and deploy an MCP server",
|
|
1652
|
+
usage: "<keyword> [--scope project|user] [--limit <1-100>] [--semantic]",
|
|
1653
|
+
},
|
|
1654
|
+
{ name: "smithery-login", description: "Login to Smithery and cache API key" },
|
|
1655
|
+
{ name: "smithery-logout", description: "Remove cached Smithery API key" },
|
|
1656
|
+
{ name: "reconnect", description: "Reconnect to a specific MCP server", usage: "<name>" },
|
|
1657
|
+
{ name: "reload", description: "Force reload MCP runtime tools" },
|
|
1658
|
+
{ name: "resources", description: "List available resources from connected servers" },
|
|
1659
|
+
{ name: "prompts", description: "List available prompts from connected servers" },
|
|
1660
|
+
{ name: "notifications", description: "Show notification capabilities and subscriptions" },
|
|
1661
|
+
{ name: "help", description: "Show help message" },
|
|
1662
|
+
],
|
|
1663
|
+
allowArgs: true,
|
|
1664
|
+
handle: handleMcpAcp,
|
|
1665
|
+
handleTui: async (command, runtime) => {
|
|
1666
|
+
runtime.ctx.editor.setText("");
|
|
1667
|
+
await runtime.ctx.handleMCPCommand(command.text);
|
|
1668
|
+
},
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
name: "ssh",
|
|
1672
|
+
description: "Manage SSH hosts (add, list, remove)",
|
|
1673
|
+
acpDescription: "Manage SSH connections",
|
|
1674
|
+
inlineHint: "<subcommand>",
|
|
1675
|
+
subcommands: [
|
|
1676
|
+
{
|
|
1677
|
+
name: "add",
|
|
1678
|
+
description: "Add an SSH host",
|
|
1679
|
+
usage: "<name> --host <host> [--user <user>] [--port <port>] [--key <keyPath>]",
|
|
1680
|
+
},
|
|
1681
|
+
{ name: "list", description: "List all configured SSH hosts" },
|
|
1682
|
+
{ name: "remove", description: "Remove an SSH host", usage: "<name> [--scope project|user]" },
|
|
1683
|
+
{ name: "help", description: "Show help message" },
|
|
1684
|
+
],
|
|
1685
|
+
allowArgs: true,
|
|
1686
|
+
handle: handleSshAcp,
|
|
1687
|
+
handleTui: async (command, runtime) => {
|
|
1688
|
+
runtime.ctx.editor.setText("");
|
|
1689
|
+
await runtime.ctx.handleSSHCommand(command.text);
|
|
1690
|
+
},
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
name: "new",
|
|
1694
|
+
description: "Start a new session",
|
|
1695
|
+
handleTui: async (_command, runtime) => {
|
|
1696
|
+
runtime.ctx.editor.setText("");
|
|
1697
|
+
await runtime.ctx.handleClearCommand();
|
|
1698
|
+
},
|
|
1699
|
+
},
|
|
1700
|
+
{
|
|
1701
|
+
name: "fresh",
|
|
1702
|
+
description: "Reset provider stream state without changing the local transcript",
|
|
1703
|
+
getTuiAutocompleteDescription: runtime =>
|
|
1704
|
+
runtime.ctx.session.isStreaming ? "Fresh: unavailable while streaming" : "Fresh: ready",
|
|
1705
|
+
handle: async (_command, runtime) => {
|
|
1706
|
+
const result = runtime.session.freshSession();
|
|
1707
|
+
if (!result) {
|
|
1708
|
+
await runtime.output(
|
|
1709
|
+
"Wait for the current response to finish or abort it before refreshing provider state.",
|
|
1710
|
+
);
|
|
1711
|
+
return commandConsumed();
|
|
1712
|
+
}
|
|
1713
|
+
await runtime.output(formatFreshSessionResult(result));
|
|
1714
|
+
return commandConsumed();
|
|
1715
|
+
},
|
|
1716
|
+
handleTui: async (_command, runtime) => {
|
|
1717
|
+
runtime.ctx.editor.setText("");
|
|
1718
|
+
await runtime.ctx.handleFreshCommand();
|
|
1719
|
+
},
|
|
1720
|
+
},
|
|
1721
|
+
{
|
|
1722
|
+
name: "clear",
|
|
1723
|
+
description: "Clear the conversation context in place, keeping the session",
|
|
1724
|
+
getTuiAutocompleteDescription: runtime =>
|
|
1725
|
+
runtime.ctx.session.isStreaming ? "Clear: unavailable while streaming" : "Clear: drop context, keep session",
|
|
1726
|
+
handleTui: async (_command, runtime) => {
|
|
1727
|
+
runtime.ctx.editor.setText("");
|
|
1728
|
+
await runtime.ctx.handleResetContextCommand();
|
|
1729
|
+
},
|
|
1730
|
+
},
|
|
1731
|
+
{
|
|
1732
|
+
name: "drop",
|
|
1733
|
+
description: "Delete the current session and start a new one",
|
|
1734
|
+
handleTui: async (_command, runtime) => {
|
|
1735
|
+
runtime.ctx.editor.setText("");
|
|
1736
|
+
await runtime.ctx.handleDropCommand();
|
|
1737
|
+
},
|
|
1738
|
+
},
|
|
1739
|
+
{
|
|
1740
|
+
name: "compact",
|
|
1741
|
+
description: "Manually compact the session context",
|
|
1742
|
+
acpDescription: "Compact the conversation",
|
|
1743
|
+
subcommands: COMPACT_MODES.map(mode => ({
|
|
1744
|
+
name: mode.name,
|
|
1745
|
+
description: mode.description,
|
|
1746
|
+
usage: mode.rejectsFocus ? undefined : "[focus]",
|
|
1747
|
+
})),
|
|
1748
|
+
acpInputHint: `[${COMPACT_MODES.map(mode => mode.name).join("|")}] [focus]`,
|
|
1749
|
+
allowArgs: true,
|
|
1750
|
+
getTuiAutocompleteDescription: runtime => {
|
|
1751
|
+
const usage = runtime.ctx.session.getContextUsage();
|
|
1752
|
+
return usage ? `Compact: context ${Math.round(usage.percent)}% used` : "Compact: context unavailable";
|
|
1753
|
+
},
|
|
1754
|
+
handle: async (command, runtime) => {
|
|
1755
|
+
const parsed = parseCompactArgs(command.args);
|
|
1756
|
+
if ("error" in parsed) return usage(parsed.error, runtime);
|
|
1757
|
+
const before = runtime.session.getContextUsage?.();
|
|
1758
|
+
const beforeTokens = before?.tokens;
|
|
1759
|
+
try {
|
|
1760
|
+
await runtime.session.compact(parsed.instructions, parsed.mode ? { mode: parsed.mode } : undefined);
|
|
1761
|
+
} catch (err) {
|
|
1762
|
+
// Compaction precondition failures (no model, already compacted, too
|
|
1763
|
+
// small) and provider errors propagate as plain Errors; surface them
|
|
1764
|
+
// via runtime.output so they don't fail the ACP prompt turn.
|
|
1765
|
+
return usage(`Compaction failed: ${errorMessage(err)}`, runtime);
|
|
1766
|
+
}
|
|
1767
|
+
const after = runtime.session.getContextUsage?.();
|
|
1768
|
+
const afterTokens = after?.tokens;
|
|
1769
|
+
if (beforeTokens != null && afterTokens != null) {
|
|
1770
|
+
const saved = beforeTokens - afterTokens;
|
|
1771
|
+
await runtime.output(`Compaction complete. Tokens: ${beforeTokens} -> ${afterTokens} (saved ${saved}).`);
|
|
1772
|
+
} else {
|
|
1773
|
+
await runtime.output("Compaction complete.");
|
|
1774
|
+
}
|
|
1775
|
+
return commandConsumed();
|
|
1776
|
+
},
|
|
1777
|
+
handleTui: async (command, runtime) => {
|
|
1778
|
+
const parsed = parseCompactArgs(command.args);
|
|
1779
|
+
runtime.ctx.editor.setText("");
|
|
1780
|
+
if ("error" in parsed) {
|
|
1781
|
+
runtime.ctx.showWarning(parsed.error);
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
await runtime.ctx.handleCompactCommand(parsed.instructions, parsed.mode);
|
|
1785
|
+
},
|
|
1786
|
+
},
|
|
1787
|
+
{
|
|
1788
|
+
name: "shake",
|
|
1789
|
+
description: "Drop heavy content from context (tool results, large blocks)",
|
|
1790
|
+
acpDescription: "Shake heavy content out of the conversation context",
|
|
1791
|
+
subcommands: [
|
|
1792
|
+
{ name: "elide", description: "Strip tool results + large blocks (default)" },
|
|
1793
|
+
{ name: "images", description: "Strip image blocks" },
|
|
1794
|
+
],
|
|
1795
|
+
acpInputHint: "[elide|images]",
|
|
1796
|
+
allowArgs: true,
|
|
1797
|
+
handle: async (command, runtime) => {
|
|
1798
|
+
const mode = parseShakeMode(command.args);
|
|
1799
|
+
if (typeof mode !== "string") return usage(mode.error, runtime);
|
|
1800
|
+
const result = await runtime.session.shake(mode);
|
|
1801
|
+
await runtime.output(formatShakeSummary(result));
|
|
1802
|
+
return commandConsumed();
|
|
1803
|
+
},
|
|
1804
|
+
handleTui: async (command, runtime) => {
|
|
1805
|
+
runtime.ctx.editor.setText("");
|
|
1806
|
+
const mode = parseShakeMode(command.args);
|
|
1807
|
+
if (typeof mode !== "string") {
|
|
1808
|
+
runtime.ctx.showWarning(mode.error);
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
await runtime.ctx.handleShakeCommand(mode);
|
|
1812
|
+
},
|
|
1813
|
+
},
|
|
1814
|
+
{
|
|
1815
|
+
name: "handoff",
|
|
1816
|
+
description: "Hand off session context to a new session",
|
|
1817
|
+
inlineHint: "[focus instructions]",
|
|
1818
|
+
allowArgs: true,
|
|
1819
|
+
handleTui: async (command, runtime) => {
|
|
1820
|
+
const customInstructions = command.args || undefined;
|
|
1821
|
+
runtime.ctx.editor.setText("");
|
|
1822
|
+
await runtime.ctx.handleHandoffCommand(customInstructions);
|
|
1823
|
+
},
|
|
1824
|
+
},
|
|
1825
|
+
{
|
|
1826
|
+
name: "resume",
|
|
1827
|
+
description: "Resume a different session",
|
|
1828
|
+
inlineHint: "[session id|@claude|@codex]",
|
|
1829
|
+
allowArgs: true,
|
|
1830
|
+
handleTui: async (command, runtime) => {
|
|
1831
|
+
const sessionArg = command.args.trim();
|
|
1832
|
+
runtime.ctx.editor.setText("");
|
|
1833
|
+
const foreignSource = sessionArg === "@claude" ? "claude" : sessionArg === "@codex" ? "codex" : undefined;
|
|
1834
|
+
if (foreignSource) {
|
|
1835
|
+
runtime.ctx.showSessionSelector(foreignSource);
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1838
|
+
if (!sessionArg) {
|
|
1839
|
+
runtime.ctx.showSessionSelector();
|
|
1840
|
+
return;
|
|
1841
|
+
}
|
|
1842
|
+
const match = await resolveResumableSession(
|
|
1843
|
+
sessionArg,
|
|
1844
|
+
runtime.ctx.sessionManager.getCwd(),
|
|
1845
|
+
runtime.ctx.sessionManager.getSessionDir(),
|
|
1846
|
+
{ allowGlobalFallback: true },
|
|
1847
|
+
);
|
|
1848
|
+
if (!match) {
|
|
1849
|
+
runtime.ctx.showError(`Session "${sessionArg}" not found`);
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
await runtime.ctx.handleResumeSession(match.session.path);
|
|
1853
|
+
},
|
|
1854
|
+
},
|
|
1855
|
+
{
|
|
1856
|
+
name: "btw",
|
|
1857
|
+
description: "Ask an ephemeral side question using the current session context",
|
|
1858
|
+
inlineHint: "<question>",
|
|
1859
|
+
allowArgs: true,
|
|
1860
|
+
handleTui: async (command, runtime) => {
|
|
1861
|
+
const question = command.text.slice(`/${command.name}`.length).trim();
|
|
1862
|
+
runtime.ctx.editor.setText("");
|
|
1863
|
+
await runtime.ctx.handleBtwCommand(question);
|
|
1864
|
+
},
|
|
1865
|
+
},
|
|
1866
|
+
{
|
|
1867
|
+
name: "tan",
|
|
1868
|
+
description: "Run a full background agent on tangential work",
|
|
1869
|
+
inlineHint: "<work>",
|
|
1870
|
+
allowArgs: true,
|
|
1871
|
+
handleTui: async (command, runtime) => {
|
|
1872
|
+
const work = command.text.slice(`/${command.name}`.length).trim();
|
|
1873
|
+
runtime.ctx.editor.setText("");
|
|
1874
|
+
await runtime.ctx.handleTanCommand(work);
|
|
1875
|
+
},
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
name: "omfg",
|
|
1879
|
+
description: "Forge a TTSR rule from a complaint to stop a recurring behavior",
|
|
1880
|
+
inlineHint: "<complaint>",
|
|
1881
|
+
allowArgs: true,
|
|
1882
|
+
handleTui: async (command, runtime) => {
|
|
1883
|
+
const complaint = command.text.slice(`/${command.name}`.length).trim();
|
|
1884
|
+
runtime.ctx.editor.setText("");
|
|
1885
|
+
await runtime.ctx.handleOmfgCommand(complaint);
|
|
1886
|
+
},
|
|
1887
|
+
},
|
|
1888
|
+
{
|
|
1889
|
+
name: "retry",
|
|
1890
|
+
description: "Retry the last failed agent turn",
|
|
1891
|
+
handleTui: async (_command, runtime) => {
|
|
1892
|
+
const didRetry = await runtime.ctx.session.retry();
|
|
1893
|
+
if (!didRetry) {
|
|
1894
|
+
runtime.ctx.showStatus("Nothing to retry");
|
|
1895
|
+
}
|
|
1896
|
+
runtime.ctx.editor.setText("");
|
|
1897
|
+
},
|
|
1898
|
+
},
|
|
1899
|
+
{
|
|
1900
|
+
name: "debug",
|
|
1901
|
+
description: "Open debug tools selector",
|
|
1902
|
+
handleTui: async (_command, runtime) => {
|
|
1903
|
+
await runtime.ctx.showDebugSelector();
|
|
1904
|
+
runtime.ctx.editor.setText("");
|
|
1905
|
+
},
|
|
1906
|
+
},
|
|
1907
|
+
{
|
|
1908
|
+
name: "memory",
|
|
1909
|
+
description: "Inspect and operate memory maintenance",
|
|
1910
|
+
acpDescription: "Manage memory",
|
|
1911
|
+
acpInputHint: "<subcommand>",
|
|
1912
|
+
subcommands: [
|
|
1913
|
+
{ name: "view", description: "Show current memory injection payload" },
|
|
1914
|
+
{ name: "stats", description: "Show memory backend statistics" },
|
|
1915
|
+
{ name: "diagnose", description: "Run memory backend diagnostics" },
|
|
1916
|
+
{ name: "clear", description: "Clear persisted memory data and artifacts" },
|
|
1917
|
+
{ name: "reset", description: "Alias for clear" },
|
|
1918
|
+
{ name: "enqueue", description: "Enqueue memory consolidation maintenance" },
|
|
1919
|
+
{ name: "rebuild", description: "Alias for enqueue" },
|
|
1920
|
+
{ name: "mm list", description: "List mental models on the active bank" },
|
|
1921
|
+
{ name: "mm show", description: "Show one mental model (id required)" },
|
|
1922
|
+
{
|
|
1923
|
+
name: "mm refresh",
|
|
1924
|
+
description: "Refresh auto-refresh models bank-wide, or one model by id",
|
|
1925
|
+
},
|
|
1926
|
+
{ name: "mm history", description: "Diff the change history of a mental model" },
|
|
1927
|
+
{ name: "mm seed", description: "Create any built-in mental models that are missing" },
|
|
1928
|
+
{ name: "mm delete", description: "Delete a mental model from the bank (id required)" },
|
|
1929
|
+
{ name: "mm reload", description: "Re-pull the cached <mental_models> block" },
|
|
1930
|
+
],
|
|
1931
|
+
allowArgs: true,
|
|
1932
|
+
handle: async (command, runtime) => {
|
|
1933
|
+
const verb = (command.args.trim().split(/\s+/)[0] ?? "").toLowerCase() || "view";
|
|
1934
|
+
const backend = await resolveMemoryBackend(runtime.settings);
|
|
1935
|
+
switch (verb) {
|
|
1936
|
+
case "view": {
|
|
1937
|
+
const payload = await backend.buildDeveloperInstructions(
|
|
1938
|
+
runtime.settings.getAgentDir(),
|
|
1939
|
+
runtime.settings,
|
|
1940
|
+
runtime.session,
|
|
1941
|
+
);
|
|
1942
|
+
await runtime.output(payload || "Memory payload is empty.");
|
|
1943
|
+
return commandConsumed();
|
|
1944
|
+
}
|
|
1945
|
+
case "clear":
|
|
1946
|
+
case "reset": {
|
|
1947
|
+
await backend.clear(runtime.settings.getAgentDir(), runtime.cwd, runtime.session);
|
|
1948
|
+
await runtime.session.refreshBaseSystemPrompt();
|
|
1949
|
+
await runtime.output("Memory cleared.");
|
|
1950
|
+
return commandConsumed();
|
|
1951
|
+
}
|
|
1952
|
+
case "enqueue":
|
|
1953
|
+
case "rebuild": {
|
|
1954
|
+
await backend.enqueue(runtime.settings.getAgentDir(), runtime.cwd, runtime.session);
|
|
1955
|
+
await runtime.output("Memory consolidation enqueued.");
|
|
1956
|
+
return commandConsumed();
|
|
1957
|
+
}
|
|
1958
|
+
case "stats":
|
|
1959
|
+
case "diagnose": {
|
|
1960
|
+
const hook = verb === "stats" ? backend.stats : backend.diagnose;
|
|
1961
|
+
const payload = await hook?.(runtime.settings.getAgentDir(), runtime.cwd, runtime.session);
|
|
1962
|
+
await runtime.output(payload ?? memoryStatsUnavailableMessage(backend.id, verb));
|
|
1963
|
+
return commandConsumed();
|
|
1964
|
+
}
|
|
1965
|
+
case "mm":
|
|
1966
|
+
return usage(
|
|
1967
|
+
"Mental-model maintenance via /memory mm is unsupported in ACP mode; use the hindsight HTTP API directly.",
|
|
1968
|
+
runtime,
|
|
1969
|
+
);
|
|
1970
|
+
default:
|
|
1971
|
+
return usage("Usage: /memory <view|stats|diagnose|clear|reset|enqueue|rebuild>", runtime);
|
|
1972
|
+
}
|
|
1973
|
+
},
|
|
1974
|
+
handleTui: async (command, runtime) => {
|
|
1975
|
+
runtime.ctx.editor.setText("");
|
|
1976
|
+
await runtime.ctx.handleMemoryCommand(command.text);
|
|
1977
|
+
},
|
|
1978
|
+
},
|
|
1979
|
+
{
|
|
1980
|
+
name: "rename",
|
|
1981
|
+
description: "Rename the current session",
|
|
1982
|
+
inlineHint: "<title>",
|
|
1983
|
+
allowArgs: true,
|
|
1984
|
+
handle: async (command, runtime) => {
|
|
1985
|
+
if (!command.args) return usage("Usage: /rename <title>", runtime);
|
|
1986
|
+
const ok = await runtime.sessionManager.setSessionName(command.args, "user");
|
|
1987
|
+
if (!ok) {
|
|
1988
|
+
await runtime.output("Session name not changed (a user-set name takes precedence).");
|
|
1989
|
+
return commandConsumed();
|
|
1990
|
+
}
|
|
1991
|
+
await runtime.notifyTitleChanged?.();
|
|
1992
|
+
await runtime.output(`Session renamed to ${command.args}.`);
|
|
1993
|
+
return commandConsumed();
|
|
1994
|
+
},
|
|
1995
|
+
handleTui: async (command, runtime) => {
|
|
1996
|
+
const title = command.args.trim();
|
|
1997
|
+
if (!title) {
|
|
1998
|
+
runtime.ctx.showError("Usage: /rename <title>");
|
|
1999
|
+
runtime.ctx.editor.setText("");
|
|
2000
|
+
return;
|
|
2001
|
+
}
|
|
2002
|
+
runtime.ctx.editor.setText("");
|
|
2003
|
+
await runtime.ctx.handleRenameCommand(title);
|
|
2004
|
+
},
|
|
2005
|
+
},
|
|
2006
|
+
{
|
|
2007
|
+
name: "move",
|
|
2008
|
+
description: "Move the current session to a different directory",
|
|
2009
|
+
acpDescription: "Move the current session to a different directory",
|
|
2010
|
+
inlineHint: "[<path>]",
|
|
2011
|
+
allowArgs: true,
|
|
2012
|
+
handle: async (command, runtime) => {
|
|
2013
|
+
if (runtime.session.isStreaming) return usage("Cannot move while streaming.", runtime);
|
|
2014
|
+
if (!command.args) return usage("Usage: /move <path>", runtime);
|
|
2015
|
+
const resolvedPath = resolveToCwd(command.args, runtime.cwd);
|
|
2016
|
+
try {
|
|
2017
|
+
const stat = await fs.stat(resolvedPath);
|
|
2018
|
+
if (!stat.isDirectory()) {
|
|
2019
|
+
return usage(`Not a directory: ${resolvedPath}`, runtime);
|
|
2020
|
+
}
|
|
2021
|
+
} catch {
|
|
2022
|
+
return usage(`Directory does not exist: ${resolvedPath}`, runtime);
|
|
2023
|
+
}
|
|
2024
|
+
try {
|
|
2025
|
+
await runtime.settings.flush();
|
|
2026
|
+
} catch (err) {
|
|
2027
|
+
return usage(`Failed to save pending settings: ${errorMessage(err)}`, runtime);
|
|
2028
|
+
}
|
|
2029
|
+
try {
|
|
2030
|
+
await runtime.session.moveSession(resolvedPath);
|
|
2031
|
+
} catch (err) {
|
|
2032
|
+
return usage(`Move failed: ${errorMessage(err)}`, runtime);
|
|
2033
|
+
}
|
|
2034
|
+
setProjectDir(resolvedPath);
|
|
2035
|
+
await runtime.settings.reloadForCwd(resolvedPath);
|
|
2036
|
+
applyProviderGlobalsFromSettings(runtime.settings);
|
|
2037
|
+
// Reload plugin/capability caches so the next prompt sees commands and
|
|
2038
|
+
// capabilities scoped to the new cwd.
|
|
2039
|
+
await runtime.reloadPlugins();
|
|
2040
|
+
await runtime.notifyConfigChanged?.();
|
|
2041
|
+
await runtime.notifyTitleChanged?.();
|
|
2042
|
+
await runtime.output(`Moved to ${runtime.sessionManager.getCwd()}.`);
|
|
2043
|
+
return commandConsumed();
|
|
2044
|
+
},
|
|
2045
|
+
handleTui: async (command, runtime) => {
|
|
2046
|
+
runtime.ctx.editor.addToHistory(command.text);
|
|
2047
|
+
runtime.ctx.editor.setText("");
|
|
2048
|
+
await runtime.ctx.handleMoveCommand(command.args || undefined);
|
|
2049
|
+
},
|
|
2050
|
+
},
|
|
2051
|
+
{
|
|
2052
|
+
name: "add-dir",
|
|
2053
|
+
description: "Add a workspace directory to this session (multi-root)",
|
|
2054
|
+
acpDescription: "Add a workspace directory to this session",
|
|
2055
|
+
inlineHint: "<path>",
|
|
2056
|
+
allowArgs: true,
|
|
2057
|
+
handle: async (command, runtime) => {
|
|
2058
|
+
if (runtime.session.isStreaming) return usage("Cannot add a directory while streaming.", runtime);
|
|
2059
|
+
if (!command.args) return usage(formatWorkspaceDirectories(runtime, "Usage: /add-dir <path>"), runtime);
|
|
2060
|
+
const resolved = resolveToCwd(command.args, runtime.cwd);
|
|
2061
|
+
try {
|
|
2062
|
+
const stat = await fs.stat(resolved);
|
|
2063
|
+
if (!stat.isDirectory()) return usage(`Not a directory: ${resolved}`, runtime);
|
|
2064
|
+
} catch {
|
|
2065
|
+
return usage(`Directory does not exist: ${resolved}`, runtime);
|
|
2066
|
+
}
|
|
2067
|
+
let added: string | null;
|
|
2068
|
+
try {
|
|
2069
|
+
added = await runtime.sessionManager.addWorkspaceDirectory(resolved);
|
|
2070
|
+
} catch (err) {
|
|
2071
|
+
return usage(errorMessage(err), runtime);
|
|
2072
|
+
}
|
|
2073
|
+
if (added === null) {
|
|
2074
|
+
await runtime.output(`Already in the workspace: ${resolved}`);
|
|
2075
|
+
return commandConsumed();
|
|
2076
|
+
}
|
|
2077
|
+
await runtime.session.refreshBaseSystemPrompt();
|
|
2078
|
+
await runtime.output(formatWorkspaceDirectories(runtime, `Added ${added}.`));
|
|
2079
|
+
return commandConsumed();
|
|
2080
|
+
},
|
|
2081
|
+
},
|
|
2082
|
+
{
|
|
2083
|
+
name: "remove-dir",
|
|
2084
|
+
description: "Remove a workspace directory from this session",
|
|
2085
|
+
acpDescription: "Remove a workspace directory from this session",
|
|
2086
|
+
inlineHint: "<path>",
|
|
2087
|
+
allowArgs: true,
|
|
2088
|
+
handle: async (command, runtime) => {
|
|
2089
|
+
if (runtime.session.isStreaming) return usage("Cannot remove a directory while streaming.", runtime);
|
|
2090
|
+
if (!command.args) return usage("Usage: /remove-dir <path>", runtime);
|
|
2091
|
+
const resolved = resolveToCwd(command.args, runtime.cwd);
|
|
2092
|
+
if (resolved === path.resolve(runtime.cwd)) {
|
|
2093
|
+
return usage("Cannot remove the working directory; use /move to change it.", runtime);
|
|
2094
|
+
}
|
|
2095
|
+
let removed: string | null;
|
|
2096
|
+
try {
|
|
2097
|
+
removed = await runtime.sessionManager.removeWorkspaceDirectory(resolved);
|
|
2098
|
+
} catch (err) {
|
|
2099
|
+
return usage(errorMessage(err), runtime);
|
|
2100
|
+
}
|
|
2101
|
+
if (removed === null) {
|
|
2102
|
+
await runtime.output(`Not a workspace directory: ${resolved}`);
|
|
2103
|
+
return commandConsumed();
|
|
2104
|
+
}
|
|
2105
|
+
await runtime.session.refreshBaseSystemPrompt();
|
|
2106
|
+
await runtime.output(formatWorkspaceDirectories(runtime, `Removed ${removed}.`));
|
|
2107
|
+
return commandConsumed();
|
|
2108
|
+
},
|
|
2109
|
+
},
|
|
2110
|
+
{
|
|
2111
|
+
name: "dirs",
|
|
2112
|
+
description: "List this session's workspace directories",
|
|
2113
|
+
acpDescription: "List this session's workspace directories",
|
|
2114
|
+
handle: async (_command, runtime) => {
|
|
2115
|
+
await runtime.output(formatWorkspaceDirectories(runtime));
|
|
2116
|
+
return commandConsumed();
|
|
2117
|
+
},
|
|
2118
|
+
},
|
|
2119
|
+
{
|
|
2120
|
+
name: "exit",
|
|
2121
|
+
description: "Exit the application",
|
|
2122
|
+
handleTui: shutdownHandlerTui,
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
name: "marketplace",
|
|
2126
|
+
description: "Manage marketplace plugin sources and installed plugins",
|
|
2127
|
+
acpDescription: "Manage plugins from marketplaces",
|
|
2128
|
+
acpInputHint: "<subcommand>",
|
|
2129
|
+
subcommands: [
|
|
2130
|
+
{ name: "add", description: "Add a marketplace source", usage: "<source>" },
|
|
2131
|
+
{ name: "remove", description: "Remove a marketplace source", usage: "<name>" },
|
|
2132
|
+
{ name: "update", description: "Update marketplace catalog(s)", usage: "[name]" },
|
|
2133
|
+
{ name: "list", description: "List configured marketplaces" },
|
|
2134
|
+
{ name: "discover", description: "Browse available plugins", usage: "[marketplace]" },
|
|
2135
|
+
{
|
|
2136
|
+
name: "install",
|
|
2137
|
+
description: "Install a plugin (interactive browser if no args)",
|
|
2138
|
+
usage: "[--force] [name@marketplace]",
|
|
2139
|
+
},
|
|
2140
|
+
{ name: "uninstall", description: "Uninstall a plugin (selector if no args)", usage: "[name@marketplace]" },
|
|
2141
|
+
{ name: "installed", description: "List installed marketplace plugins" },
|
|
2142
|
+
{ name: "upgrade", description: "Upgrade outdated plugins", usage: "[name@marketplace]" },
|
|
2143
|
+
{ name: "help", description: "Show usage guide" },
|
|
2144
|
+
],
|
|
2145
|
+
allowArgs: true,
|
|
2146
|
+
handle: async (command, runtime) => {
|
|
2147
|
+
const { verb, rest } = parseSubcommand(command.args);
|
|
2148
|
+
if (!verb) {
|
|
2149
|
+
try {
|
|
2150
|
+
const manager = await createMarketplaceManager(runtime);
|
|
2151
|
+
const marketplaces = await manager.listMarketplaces();
|
|
2152
|
+
if (marketplaces.length === 0) {
|
|
2153
|
+
await runtime.output(
|
|
2154
|
+
"No marketplaces configured.\n\nGet started:\n /marketplace add anthropics/claude-plugins-official\n\nThen browse with /marketplace discover",
|
|
2155
|
+
);
|
|
2156
|
+
} else {
|
|
2157
|
+
const lines = marketplaces.map(m => ` ${m.name} ${m.sourceUri}`);
|
|
2158
|
+
await runtime.output(
|
|
2159
|
+
`Marketplaces:\n${lines.join("\n")}\n\nUse /marketplace discover to browse plugins, or /marketplace help for all commands`,
|
|
2160
|
+
);
|
|
2161
|
+
}
|
|
2162
|
+
return commandConsumed();
|
|
2163
|
+
} catch (err) {
|
|
2164
|
+
return usage(`Marketplace error: ${errorMessage(err)}`, runtime);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
if (verb === "help") {
|
|
2168
|
+
await runtime.output(
|
|
2169
|
+
[
|
|
2170
|
+
"Marketplace commands:",
|
|
2171
|
+
" /marketplace List configured marketplaces",
|
|
2172
|
+
" /marketplace add <source> Add a marketplace (e.g. owner/repo)",
|
|
2173
|
+
" /marketplace remove <name> Remove a marketplace",
|
|
2174
|
+
" /marketplace update [name] Re-fetch catalog(s)",
|
|
2175
|
+
" /marketplace list List configured marketplaces",
|
|
2176
|
+
" /marketplace discover [marketplace] Browse available plugins",
|
|
2177
|
+
" /marketplace install <name@marketplace> Install a plugin",
|
|
2178
|
+
" /marketplace uninstall <name@marketplace> Uninstall a plugin",
|
|
2179
|
+
" /marketplace installed List installed plugins",
|
|
2180
|
+
" /marketplace upgrade [name@marketplace] Upgrade plugin(s)",
|
|
2181
|
+
"",
|
|
2182
|
+
"Quick start:",
|
|
2183
|
+
" /marketplace add anthropics/claude-plugins-official",
|
|
2184
|
+
].join("\n"),
|
|
2185
|
+
);
|
|
2186
|
+
return commandConsumed();
|
|
2187
|
+
}
|
|
2188
|
+
if ((verb === "install" || verb === "uninstall") && !rest) {
|
|
2189
|
+
return usage(
|
|
2190
|
+
"Interactive plugin pickers are TUI-only. Pass an explicit name@marketplace argument.",
|
|
2191
|
+
runtime,
|
|
2192
|
+
);
|
|
2193
|
+
}
|
|
2194
|
+
try {
|
|
2195
|
+
const manager = await createMarketplaceManager(runtime);
|
|
2196
|
+
switch (verb) {
|
|
2197
|
+
case "add": {
|
|
2198
|
+
if (!rest) return usage("Usage: /marketplace add <source>", runtime);
|
|
2199
|
+
const entry = await manager.addMarketplace(rest);
|
|
2200
|
+
await runtime.output(`Added marketplace: ${entry.name}`);
|
|
2201
|
+
return commandConsumed();
|
|
2202
|
+
}
|
|
2203
|
+
case "remove":
|
|
2204
|
+
case "rm": {
|
|
2205
|
+
if (!rest) return usage("Usage: /marketplace remove <name>", runtime);
|
|
2206
|
+
await manager.removeMarketplace(rest);
|
|
2207
|
+
await runtime.output(`Removed marketplace: ${rest}`);
|
|
2208
|
+
return commandConsumed();
|
|
2209
|
+
}
|
|
2210
|
+
case "update": {
|
|
2211
|
+
if (rest) {
|
|
2212
|
+
await manager.updateMarketplace(rest);
|
|
2213
|
+
await runtime.output(`Updated marketplace: ${rest}`);
|
|
2214
|
+
} else {
|
|
2215
|
+
const results = await manager.updateAllMarketplaces();
|
|
2216
|
+
await runtime.output(`Updated ${results.length} marketplace(s)`);
|
|
2217
|
+
}
|
|
2218
|
+
return commandConsumed();
|
|
2219
|
+
}
|
|
2220
|
+
case "list": {
|
|
2221
|
+
const marketplaces = await manager.listMarketplaces();
|
|
2222
|
+
if (marketplaces.length === 0) {
|
|
2223
|
+
await runtime.output("No marketplaces configured.");
|
|
2224
|
+
} else {
|
|
2225
|
+
const lines = marketplaces.map(m => ` ${m.name} ${m.sourceUri}`);
|
|
2226
|
+
await runtime.output(`Marketplaces:\n${lines.join("\n")}`);
|
|
2227
|
+
}
|
|
2228
|
+
return commandConsumed();
|
|
2229
|
+
}
|
|
2230
|
+
case "discover": {
|
|
2231
|
+
const plugins = await manager.listAvailablePlugins(rest || undefined);
|
|
2232
|
+
if (plugins.length === 0) {
|
|
2233
|
+
const marketplaces = await manager.listMarketplaces();
|
|
2234
|
+
await runtime.output(
|
|
2235
|
+
marketplaces.length === 0
|
|
2236
|
+
? "No marketplaces configured. Try:\n /marketplace add anthropics/claude-plugins-official"
|
|
2237
|
+
: "No plugins available in configured marketplaces",
|
|
2238
|
+
);
|
|
2239
|
+
return commandConsumed();
|
|
2240
|
+
}
|
|
2241
|
+
const lines = ["Available plugins:"];
|
|
2242
|
+
for (const plugin of plugins) {
|
|
2243
|
+
lines.push(` - ${plugin.name}${plugin.version ? `@${plugin.version}` : ""}`);
|
|
2244
|
+
if (plugin.description) lines.push(` ${plugin.description}`);
|
|
2245
|
+
}
|
|
2246
|
+
await runtime.output(lines.join("\n"));
|
|
2247
|
+
return commandConsumed();
|
|
2248
|
+
}
|
|
2249
|
+
case "install": {
|
|
2250
|
+
const parsed = parseMarketplaceInstallArgs(rest);
|
|
2251
|
+
if ("error" in parsed) return usage(parsed.error, runtime);
|
|
2252
|
+
const atIndex = parsed.installSpec.lastIndexOf("@");
|
|
2253
|
+
const pluginName = parsed.installSpec.slice(0, atIndex);
|
|
2254
|
+
const marketplace = parsed.installSpec.slice(atIndex + 1);
|
|
2255
|
+
await manager.installPlugin(pluginName, marketplace, { force: parsed.force, scope: parsed.scope });
|
|
2256
|
+
await runtime.reloadPlugins();
|
|
2257
|
+
await runtime.output(`Installed ${pluginName} from ${marketplace}`);
|
|
2258
|
+
return commandConsumed();
|
|
2259
|
+
}
|
|
2260
|
+
case "uninstall": {
|
|
2261
|
+
const parsed = parsePluginScopeArgs(
|
|
2262
|
+
rest,
|
|
2263
|
+
"Usage: /marketplace uninstall [--scope user|project] <name@marketplace>",
|
|
2264
|
+
);
|
|
2265
|
+
if ("error" in parsed) return usage(parsed.error, runtime);
|
|
2266
|
+
await manager.uninstallPlugin(parsed.pluginId, parsed.scope);
|
|
2267
|
+
await runtime.reloadPlugins();
|
|
2268
|
+
await runtime.output(`Uninstalled ${parsed.pluginId}`);
|
|
2269
|
+
return commandConsumed();
|
|
2270
|
+
}
|
|
2271
|
+
case "installed": {
|
|
2272
|
+
const installed = await manager.listInstalledPlugins();
|
|
2273
|
+
if (installed.length === 0) {
|
|
2274
|
+
await runtime.output("No marketplace plugins installed");
|
|
2275
|
+
} else {
|
|
2276
|
+
const lines = installed.map(
|
|
2277
|
+
p => ` ${p.id} [${p.scope}]${p.shadowedBy ? " [shadowed]" : ""} (${p.entries.length} entry)`,
|
|
2278
|
+
);
|
|
2279
|
+
await runtime.output(`Installed plugins:\n${lines.join("\n")}`);
|
|
2280
|
+
}
|
|
2281
|
+
return commandConsumed();
|
|
2282
|
+
}
|
|
2283
|
+
case "upgrade": {
|
|
2284
|
+
if (rest) {
|
|
2285
|
+
const parsed = parsePluginScopeArgs(
|
|
2286
|
+
rest,
|
|
2287
|
+
"Usage: /marketplace upgrade [--scope user|project] <name@marketplace>",
|
|
2288
|
+
);
|
|
2289
|
+
if ("error" in parsed) return usage(parsed.error, runtime);
|
|
2290
|
+
const result = await manager.upgradePlugin(parsed.pluginId, parsed.scope);
|
|
2291
|
+
await runtime.reloadPlugins();
|
|
2292
|
+
await runtime.output(`Upgraded ${parsed.pluginId} to ${result.version}`);
|
|
2293
|
+
return commandConsumed();
|
|
2294
|
+
}
|
|
2295
|
+
const results = await manager.upgradeAllPlugins();
|
|
2296
|
+
if (results.length === 0) {
|
|
2297
|
+
await runtime.output("All marketplace plugins are up to date");
|
|
2298
|
+
} else {
|
|
2299
|
+
await runtime.reloadPlugins();
|
|
2300
|
+
const lines = results.map(r => ` ${r.pluginId}: ${r.from} -> ${r.to}`);
|
|
2301
|
+
await runtime.output(`Upgraded ${results.length} plugin(s):\n${lines.join("\n")}`);
|
|
2302
|
+
}
|
|
2303
|
+
return commandConsumed();
|
|
2304
|
+
}
|
|
2305
|
+
default:
|
|
2306
|
+
return usage(
|
|
2307
|
+
`Unknown /marketplace subcommand: ${verb}. Use /marketplace help for available commands.`,
|
|
2308
|
+
runtime,
|
|
2309
|
+
);
|
|
2310
|
+
}
|
|
2311
|
+
} catch (err) {
|
|
2312
|
+
return usage(`Marketplace error: ${errorMessage(err)}`, runtime);
|
|
2313
|
+
}
|
|
2314
|
+
},
|
|
2315
|
+
handleTui: async (command, runtime) => {
|
|
2316
|
+
runtime.ctx.editor.setText("");
|
|
2317
|
+
const args = command.args.trim().split(/\s+/);
|
|
2318
|
+
const sub = args[0] || "install";
|
|
2319
|
+
const rest = args.slice(1).join(" ").trim();
|
|
2320
|
+
|
|
2321
|
+
// /marketplace (no args) or /marketplace install (no args) → interactive browser
|
|
2322
|
+
if ((sub === "install" && !rest) || (!args[0] && !command.args.trim())) {
|
|
2323
|
+
try {
|
|
2324
|
+
runtime.ctx.showPluginSelector("install");
|
|
2325
|
+
} catch (err) {
|
|
2326
|
+
runtime.ctx.showStatus(`Marketplace error: ${err}`);
|
|
2327
|
+
}
|
|
2328
|
+
return;
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2331
|
+
const mgr = new MarketplaceManager({
|
|
2332
|
+
marketplacesRegistryPath: getMarketplacesRegistryPath(),
|
|
2333
|
+
installedRegistryPath: getInstalledPluginsRegistryPath(),
|
|
2334
|
+
projectInstalledRegistryPath: await resolveOrDefaultProjectRegistryPath(
|
|
2335
|
+
runtime.ctx.sessionManager.getCwd(),
|
|
2336
|
+
),
|
|
2337
|
+
marketplacesCacheDir: getMarketplacesCacheDir(),
|
|
2338
|
+
pluginsCacheDir: getPluginsCacheDir(),
|
|
2339
|
+
clearPluginRootsCache: clearPluginRootsAndCaches,
|
|
2340
|
+
});
|
|
2341
|
+
|
|
2342
|
+
try {
|
|
2343
|
+
switch (sub) {
|
|
2344
|
+
case "add": {
|
|
2345
|
+
if (!rest) {
|
|
2346
|
+
runtime.ctx.showStatus("Usage: /marketplace add <source>");
|
|
2347
|
+
return;
|
|
2348
|
+
}
|
|
2349
|
+
const entry = await mgr.addMarketplace(rest);
|
|
2350
|
+
runtime.ctx.showStatus(`Added marketplace: ${entry.name}`);
|
|
2351
|
+
break;
|
|
2352
|
+
}
|
|
2353
|
+
case "remove":
|
|
2354
|
+
case "rm": {
|
|
2355
|
+
if (!rest) {
|
|
2356
|
+
runtime.ctx.showStatus("Usage: /marketplace remove <name>");
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
await mgr.removeMarketplace(rest);
|
|
2360
|
+
runtime.ctx.showStatus(`Removed marketplace: ${rest}`);
|
|
2361
|
+
break;
|
|
2362
|
+
}
|
|
2363
|
+
case "update": {
|
|
2364
|
+
if (rest) {
|
|
2365
|
+
await mgr.updateMarketplace(rest);
|
|
2366
|
+
runtime.ctx.showStatus(`Updated marketplace: ${rest}`);
|
|
2367
|
+
} else {
|
|
2368
|
+
const results = await mgr.updateAllMarketplaces();
|
|
2369
|
+
runtime.ctx.showStatus(`Updated ${results.length} marketplace(s)`);
|
|
2370
|
+
}
|
|
2371
|
+
break;
|
|
2372
|
+
}
|
|
2373
|
+
case "discover": {
|
|
2374
|
+
const plugins = await mgr.listAvailablePlugins(rest || undefined);
|
|
2375
|
+
if (plugins.length === 0) {
|
|
2376
|
+
const marketplaces = await mgr.listMarketplaces();
|
|
2377
|
+
if (marketplaces.length === 0) {
|
|
2378
|
+
runtime.ctx.showStatus(
|
|
2379
|
+
"No marketplaces configured. Try:\n /marketplace add anthropics/claude-plugins-official",
|
|
2380
|
+
);
|
|
2381
|
+
} else {
|
|
2382
|
+
runtime.ctx.showStatus("No plugins available in configured marketplaces");
|
|
2383
|
+
}
|
|
2384
|
+
} else {
|
|
2385
|
+
const lines = plugins.map(
|
|
2386
|
+
p =>
|
|
2387
|
+
` ${p.name}${p.version ? `@${p.version}` : ""}${p.description ? ` - ${p.description}` : ""}`,
|
|
2388
|
+
);
|
|
2389
|
+
runtime.ctx.showStatus(`Available plugins:\n${lines.join("\n")}`);
|
|
2390
|
+
}
|
|
2391
|
+
break;
|
|
2392
|
+
}
|
|
2393
|
+
case "install": {
|
|
2394
|
+
// Parse: /marketplace install [--force] [--scope user|project] name@marketplace
|
|
2395
|
+
const parsed = parseMarketplaceInstallArgs(rest);
|
|
2396
|
+
if ("error" in parsed) {
|
|
2397
|
+
runtime.ctx.showStatus(parsed.error);
|
|
2398
|
+
return;
|
|
2399
|
+
}
|
|
2400
|
+
const atIdx = parsed.installSpec.lastIndexOf("@");
|
|
2401
|
+
const name = parsed.installSpec.slice(0, atIdx);
|
|
2402
|
+
const marketplace = parsed.installSpec.slice(atIdx + 1);
|
|
2403
|
+
await mgr.installPlugin(name, marketplace, { force: parsed.force, scope: parsed.scope });
|
|
2404
|
+
runtime.ctx.showStatus(`Installed ${name} from ${marketplace}`);
|
|
2405
|
+
break;
|
|
2406
|
+
}
|
|
2407
|
+
case "uninstall": {
|
|
2408
|
+
if (!rest) {
|
|
2409
|
+
// No args → open interactive uninstall selector
|
|
2410
|
+
runtime.ctx.showPluginSelector("uninstall");
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
const uninstArgs = parsePluginScopeArgs(
|
|
2414
|
+
rest,
|
|
2415
|
+
"Usage: /marketplace uninstall [--scope user|project] <name@marketplace>",
|
|
2416
|
+
);
|
|
2417
|
+
if ("error" in uninstArgs) {
|
|
2418
|
+
runtime.ctx.showStatus(uninstArgs.error);
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
await mgr.uninstallPlugin(uninstArgs.pluginId, uninstArgs.scope);
|
|
2422
|
+
runtime.ctx.showStatus(`Uninstalled ${uninstArgs.pluginId}`);
|
|
2423
|
+
break;
|
|
2424
|
+
}
|
|
2425
|
+
case "installed": {
|
|
2426
|
+
const installed = await mgr.listInstalledPlugins();
|
|
2427
|
+
if (installed.length === 0) {
|
|
2428
|
+
runtime.ctx.showStatus("No marketplace plugins installed");
|
|
2429
|
+
} else {
|
|
2430
|
+
const lines = installed.map(
|
|
2431
|
+
p => ` ${p.id} [${p.scope}]${p.shadowedBy ? " [shadowed]" : ""} (${p.entries.length} entry)`,
|
|
2432
|
+
);
|
|
2433
|
+
runtime.ctx.showStatus(`Installed plugins:\n${lines.join("\n")}`);
|
|
2434
|
+
}
|
|
2435
|
+
break;
|
|
2436
|
+
}
|
|
2437
|
+
case "upgrade": {
|
|
2438
|
+
if (rest) {
|
|
2439
|
+
const upArgs = parsePluginScopeArgs(
|
|
2440
|
+
rest,
|
|
2441
|
+
"Usage: /marketplace upgrade [--scope user|project] <name@marketplace>",
|
|
2442
|
+
);
|
|
2443
|
+
if ("error" in upArgs) {
|
|
2444
|
+
runtime.ctx.showStatus(upArgs.error);
|
|
2445
|
+
return;
|
|
2446
|
+
}
|
|
2447
|
+
const result = await mgr.upgradePlugin(upArgs.pluginId, upArgs.scope);
|
|
2448
|
+
runtime.ctx.showStatus(`Upgraded ${upArgs.pluginId} to ${result.version}`);
|
|
2449
|
+
} else {
|
|
2450
|
+
const results = await mgr.upgradeAllPlugins();
|
|
2451
|
+
if (results.length === 0) {
|
|
2452
|
+
runtime.ctx.showStatus("All marketplace plugins are up to date");
|
|
2453
|
+
} else {
|
|
2454
|
+
const lines = results.map(r => ` ${r.pluginId}: ${r.from} -> ${r.to}`);
|
|
2455
|
+
runtime.ctx.showStatus(`Upgraded ${results.length} plugin(s):\n${lines.join("\n")}`);
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
break;
|
|
2459
|
+
}
|
|
2460
|
+
case "help": {
|
|
2461
|
+
runtime.ctx.showStatus(
|
|
2462
|
+
[
|
|
2463
|
+
"Marketplace commands:",
|
|
2464
|
+
" /marketplace Browse and install plugins",
|
|
2465
|
+
" /marketplace add <source> Add a marketplace (e.g. owner/repo)",
|
|
2466
|
+
" /marketplace remove <name> Remove a marketplace",
|
|
2467
|
+
" /marketplace update [name] Re-fetch catalog(s)",
|
|
2468
|
+
" /marketplace list List configured marketplaces",
|
|
2469
|
+
" /marketplace discover [marketplace] Browse available plugins",
|
|
2470
|
+
" /marketplace install <name@marketplace> Install a plugin",
|
|
2471
|
+
" /marketplace uninstall <name@marketplace> Uninstall a plugin",
|
|
2472
|
+
" /marketplace installed List installed plugins",
|
|
2473
|
+
" /marketplace upgrade [name@marketplace] Upgrade plugin(s)",
|
|
2474
|
+
"",
|
|
2475
|
+
"Quick start:",
|
|
2476
|
+
" /marketplace add anthropics/claude-plugins-official",
|
|
2477
|
+
" /marketplace (opens interactive browser)",
|
|
2478
|
+
].join("\n"),
|
|
2479
|
+
);
|
|
2480
|
+
break;
|
|
2481
|
+
}
|
|
2482
|
+
default: {
|
|
2483
|
+
const marketplaces = await mgr.listMarketplaces();
|
|
2484
|
+
if (marketplaces.length === 0) {
|
|
2485
|
+
runtime.ctx.showStatus(
|
|
2486
|
+
"No marketplaces configured.\n\nGet started:\n /marketplace add anthropics/claude-plugins-official\n\nThen browse plugins with /marketplace or /marketplace discover",
|
|
2487
|
+
);
|
|
2488
|
+
} else {
|
|
2489
|
+
const lines = marketplaces.map(m => ` ${m.name} ${m.sourceUri}`);
|
|
2490
|
+
runtime.ctx.showStatus(
|
|
2491
|
+
`Marketplaces:\n${lines.join("\n")}\n\nUse /marketplace discover to browse plugins, or /marketplace help for all commands`,
|
|
2492
|
+
);
|
|
2493
|
+
}
|
|
2494
|
+
break;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
} catch (err) {
|
|
2498
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2499
|
+
runtime.ctx.showStatus(`Marketplace error: ${msg}`);
|
|
2500
|
+
}
|
|
2501
|
+
},
|
|
2502
|
+
},
|
|
2503
|
+
{
|
|
2504
|
+
name: "plugins",
|
|
2505
|
+
description: "View and manage installed plugins",
|
|
2506
|
+
acpDescription: "Manage plugins",
|
|
2507
|
+
acpInputHint: "[list|enable|disable]",
|
|
2508
|
+
subcommands: [
|
|
2509
|
+
{ name: "list", description: "List all installed plugins (npm + marketplace)" },
|
|
2510
|
+
{ name: "enable", description: "Enable a marketplace plugin", usage: "<name@marketplace>" },
|
|
2511
|
+
{ name: "disable", description: "Disable a marketplace plugin", usage: "<name@marketplace>" },
|
|
2512
|
+
],
|
|
2513
|
+
allowArgs: true,
|
|
2514
|
+
handle: async (command, runtime) => {
|
|
2515
|
+
const { verb, rest } = parseSubcommand(command.args);
|
|
2516
|
+
try {
|
|
2517
|
+
if (verb === "enable" || verb === "disable") {
|
|
2518
|
+
const parsed = parsePluginScopeArgs(
|
|
2519
|
+
rest,
|
|
2520
|
+
`Usage: /plugins ${verb} [--scope user|project] <name@marketplace>`,
|
|
2521
|
+
);
|
|
2522
|
+
if ("error" in parsed) return usage(parsed.error, runtime);
|
|
2523
|
+
const manager = await createMarketplaceManager(runtime);
|
|
2524
|
+
const isEnable = verb === "enable";
|
|
2525
|
+
await manager.setPluginEnabled(parsed.pluginId, isEnable, parsed.scope);
|
|
2526
|
+
await runtime.reloadPlugins();
|
|
2527
|
+
await runtime.output(`${isEnable ? "Enabled" : "Disabled"} ${parsed.pluginId}`);
|
|
2528
|
+
return commandConsumed();
|
|
2529
|
+
}
|
|
2530
|
+
// Default: list
|
|
2531
|
+
const lines: string[] = [];
|
|
2532
|
+
const npmManager = new PluginManager();
|
|
2533
|
+
const npmPlugins = await npmManager.list();
|
|
2534
|
+
if (npmPlugins.length > 0) {
|
|
2535
|
+
lines.push("npm plugins:");
|
|
2536
|
+
for (const plugin of npmPlugins) {
|
|
2537
|
+
const status = plugin.enabled === false ? " (disabled)" : "";
|
|
2538
|
+
lines.push(` ${plugin.name}@${plugin.version}${status}`);
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
const marketplaceManager = await createMarketplaceManager(runtime);
|
|
2543
|
+
const marketplacePlugins = await marketplaceManager.listInstalledPlugins();
|
|
2544
|
+
if (marketplacePlugins.length > 0) {
|
|
2545
|
+
if (lines.length > 0) lines.push("");
|
|
2546
|
+
lines.push("marketplace plugins:");
|
|
2547
|
+
for (const plugin of marketplacePlugins) {
|
|
2548
|
+
const entry = plugin.entries[0];
|
|
2549
|
+
const status = entry?.enabled === false ? " (disabled)" : "";
|
|
2550
|
+
const shadowed = plugin.shadowedBy ? " [shadowed]" : "";
|
|
2551
|
+
lines.push(` ${plugin.id} v${entry?.version ?? "?"}${status} [${plugin.scope}]${shadowed}`);
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
await runtime.output(lines.length === 0 ? "No plugins installed" : lines.join("\n"));
|
|
2556
|
+
return commandConsumed();
|
|
2557
|
+
} catch (err) {
|
|
2558
|
+
return usage(`Plugin error: ${errorMessage(err)}`, runtime);
|
|
2559
|
+
}
|
|
2560
|
+
},
|
|
2561
|
+
handleTui: async (command, runtime) => {
|
|
2562
|
+
runtime.ctx.editor.setText("");
|
|
2563
|
+
const args = command.args.trim().split(/\s+/);
|
|
2564
|
+
const sub = args[0] || "list";
|
|
2565
|
+
const rest = args.slice(1).join(" ").trim();
|
|
2566
|
+
|
|
2567
|
+
try {
|
|
2568
|
+
const mgr = new MarketplaceManager({
|
|
2569
|
+
marketplacesRegistryPath: getMarketplacesRegistryPath(),
|
|
2570
|
+
installedRegistryPath: getInstalledPluginsRegistryPath(),
|
|
2571
|
+
projectInstalledRegistryPath: await resolveOrDefaultProjectRegistryPath(
|
|
2572
|
+
runtime.ctx.sessionManager.getCwd(),
|
|
2573
|
+
),
|
|
2574
|
+
marketplacesCacheDir: getMarketplacesCacheDir(),
|
|
2575
|
+
pluginsCacheDir: getPluginsCacheDir(),
|
|
2576
|
+
clearPluginRootsCache: clearPluginRootsAndCaches,
|
|
2577
|
+
});
|
|
2578
|
+
|
|
2579
|
+
switch (sub) {
|
|
2580
|
+
case "enable":
|
|
2581
|
+
case "disable": {
|
|
2582
|
+
const parsed = parsePluginScopeArgs(
|
|
2583
|
+
rest ?? "",
|
|
2584
|
+
`Usage: /plugins ${sub} [--scope user|project] <name@marketplace>`,
|
|
2585
|
+
);
|
|
2586
|
+
if ("error" in parsed) {
|
|
2587
|
+
runtime.ctx.showStatus(parsed.error);
|
|
2588
|
+
return;
|
|
2589
|
+
}
|
|
2590
|
+
const isEnable = sub === "enable";
|
|
2591
|
+
await mgr.setPluginEnabled(parsed.pluginId, isEnable, parsed.scope);
|
|
2592
|
+
runtime.ctx.showStatus(`${isEnable ? "Enabled" : "Disabled"} ${parsed.pluginId}`);
|
|
2593
|
+
break;
|
|
2594
|
+
}
|
|
2595
|
+
default: {
|
|
2596
|
+
const lines: string[] = [];
|
|
2597
|
+
|
|
2598
|
+
const npm = new PluginManager();
|
|
2599
|
+
const npmPlugins = await npm.list();
|
|
2600
|
+
if (npmPlugins.length > 0) {
|
|
2601
|
+
lines.push("npm plugins:");
|
|
2602
|
+
for (const p of npmPlugins) {
|
|
2603
|
+
const status = p.enabled === false ? " (disabled)" : "";
|
|
2604
|
+
lines.push(` ${p.name}@${p.version}${status}`);
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
const mktPlugins = await mgr.listInstalledPlugins();
|
|
2609
|
+
if (mktPlugins.length > 0) {
|
|
2610
|
+
if (lines.length > 0) lines.push("");
|
|
2611
|
+
lines.push("marketplace plugins:");
|
|
2612
|
+
for (const p of mktPlugins) {
|
|
2613
|
+
const entry = p.entries[0];
|
|
2614
|
+
const status = entry?.enabled === false ? " (disabled)" : "";
|
|
2615
|
+
const shadowed = p.shadowedBy ? " [shadowed]" : "";
|
|
2616
|
+
lines.push(` ${p.id} v${entry?.version ?? "?"}${status} [${p.scope}]${shadowed}`);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
if (lines.length === 0) {
|
|
2621
|
+
runtime.ctx.showStatus("No plugins installed");
|
|
2622
|
+
} else {
|
|
2623
|
+
runtime.ctx.showStatus(lines.join("\n"));
|
|
2624
|
+
}
|
|
2625
|
+
break;
|
|
2626
|
+
}
|
|
2627
|
+
}
|
|
2628
|
+
} catch (err) {
|
|
2629
|
+
runtime.ctx.showStatus(`Plugin error: ${err}`);
|
|
2630
|
+
}
|
|
2631
|
+
},
|
|
2632
|
+
},
|
|
2633
|
+
{
|
|
2634
|
+
name: "reload-plugins",
|
|
2635
|
+
description: "Reload all plugins (skills, commands, hooks, tools, agents, MCP)",
|
|
2636
|
+
acpDescription: "Reload all plugins",
|
|
2637
|
+
handle: async (_command, runtime) => {
|
|
2638
|
+
await runtime.reloadPlugins();
|
|
2639
|
+
await runtime.output("Plugins reloaded.");
|
|
2640
|
+
return commandConsumed();
|
|
2641
|
+
},
|
|
2642
|
+
handleTui: async (_command, runtime) => {
|
|
2643
|
+
await reloadTuiPluginState(runtime.ctx);
|
|
2644
|
+
runtime.ctx.showStatus("Plugins reloaded.");
|
|
2645
|
+
runtime.ctx.editor.setText("");
|
|
2646
|
+
},
|
|
2647
|
+
},
|
|
2648
|
+
{
|
|
2649
|
+
name: "force",
|
|
2650
|
+
description: "Force next turn to use a specific tool",
|
|
2651
|
+
aliases: ["force:"],
|
|
2652
|
+
inlineHint: "<tool-name> [prompt]",
|
|
2653
|
+
allowArgs: true,
|
|
2654
|
+
getTuiAutocompleteDescription: runtime => {
|
|
2655
|
+
const count = runtime.ctx.session.getActiveToolNames().length;
|
|
2656
|
+
return count === 0 ? "Force: no active tools" : `Force: ${count} active tools`;
|
|
2657
|
+
},
|
|
2658
|
+
handle: async (command, runtime) => {
|
|
2659
|
+
const spaceIdx = command.args.indexOf(" ");
|
|
2660
|
+
const toolName = spaceIdx === -1 ? command.args : command.args.slice(0, spaceIdx);
|
|
2661
|
+
const prompt = spaceIdx === -1 ? "" : command.args.slice(spaceIdx + 1).trim();
|
|
2662
|
+
if (!toolName) return usage("Usage: /force:<tool-name> [prompt]", runtime);
|
|
2663
|
+
try {
|
|
2664
|
+
runtime.session.setForcedToolChoice(toolName);
|
|
2665
|
+
} catch (err) {
|
|
2666
|
+
return usage(errorMessage(err), runtime);
|
|
2667
|
+
}
|
|
2668
|
+
await runtime.output(`Next turn forced to use ${toolName}.`);
|
|
2669
|
+
return prompt ? { prompt } : commandConsumed();
|
|
2670
|
+
},
|
|
2671
|
+
handleTui: (command, runtime) => {
|
|
2672
|
+
const spaceIdx = command.args.indexOf(" ");
|
|
2673
|
+
const toolName = spaceIdx === -1 ? command.args : command.args.slice(0, spaceIdx);
|
|
2674
|
+
const prompt = spaceIdx === -1 ? "" : command.args.slice(spaceIdx + 1).trim();
|
|
2675
|
+
|
|
2676
|
+
if (!toolName) {
|
|
2677
|
+
runtime.ctx.showError("Usage: /force:<tool-name> [prompt]");
|
|
2678
|
+
runtime.ctx.editor.setText("");
|
|
2679
|
+
return;
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
try {
|
|
2683
|
+
runtime.ctx.session.setForcedToolChoice(toolName);
|
|
2684
|
+
runtime.ctx.showStatus(`Next turn forced to use ${toolName}.`);
|
|
2685
|
+
} catch (error) {
|
|
2686
|
+
runtime.ctx.showError(errorMessage(error));
|
|
2687
|
+
runtime.ctx.editor.setText("");
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2691
|
+
runtime.ctx.editor.setText("");
|
|
2692
|
+
|
|
2693
|
+
// If a prompt was provided, pass it through as input
|
|
2694
|
+
if (prompt) return { prompt };
|
|
2695
|
+
},
|
|
2696
|
+
},
|
|
2697
|
+
{
|
|
2698
|
+
name: "live",
|
|
2699
|
+
description: "Start Codex-backed realtime voice mode",
|
|
2700
|
+
handleTui: async (_command, runtime) => {
|
|
2701
|
+
runtime.ctx.editor.setText("");
|
|
2702
|
+
await runtime.ctx.handleLiveCommand();
|
|
2703
|
+
},
|
|
2704
|
+
},
|
|
2705
|
+
{
|
|
2706
|
+
name: "pause",
|
|
2707
|
+
description: "Freeze all agents (main, subagents, advisor) until resumed",
|
|
2708
|
+
handleTui: async (_command, runtime) => {
|
|
2709
|
+
runtime.ctx.editor.setText("");
|
|
2710
|
+
await runPauseScreen(runtime.ctx);
|
|
2711
|
+
},
|
|
2712
|
+
},
|
|
2713
|
+
{
|
|
2714
|
+
name: "quit",
|
|
2715
|
+
aliases: ["q"],
|
|
2716
|
+
description: "Quit the application",
|
|
2717
|
+
handleTui: shutdownHandlerTui,
|
|
2718
|
+
},
|
|
2719
|
+
];
|
|
2720
|
+
|
|
2721
|
+
const BUILTIN_SLASH_COMMAND_LOOKUP = new Map<string, SlashCommandSpec>();
|
|
2722
|
+
for (const command of BUILTIN_SLASH_COMMAND_REGISTRY) {
|
|
2723
|
+
BUILTIN_SLASH_COMMAND_LOOKUP.set(command.name, command);
|
|
2724
|
+
for (const alias of command.aliases ?? []) {
|
|
2725
|
+
BUILTIN_SLASH_COMMAND_LOOKUP.set(alias, command);
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
export const BUILTIN_SLASH_COMMAND_RESERVED_NAMES: ReadonlySet<string> = new Set(BUILTIN_SLASH_COMMAND_LOOKUP.keys());
|
|
2730
|
+
|
|
2731
|
+
/**
|
|
2732
|
+
* Build getArgumentCompletions from declarative subcommand definitions.
|
|
2733
|
+
* Returns subcommand names filtered by prefix in the dropdown.
|
|
2734
|
+
*/
|
|
2735
|
+
function buildArgumentCompletions(subcommands: SubcommandDef[]): (prefix: string) => AutocompleteItem[] | null {
|
|
2736
|
+
return (argumentPrefix: string) => {
|
|
2737
|
+
if (argumentPrefix.includes(" ")) return null; // past the subcommand
|
|
2738
|
+
const lower = argumentPrefix.toLowerCase();
|
|
2739
|
+
const matches = subcommands
|
|
2740
|
+
.filter(s => s.name.startsWith(lower))
|
|
2741
|
+
.map(s => ({
|
|
2742
|
+
value: `${s.name} `,
|
|
2743
|
+
label: s.name,
|
|
2744
|
+
description: s.description,
|
|
2745
|
+
hint: s.usage,
|
|
2746
|
+
}));
|
|
2747
|
+
return matches.length > 0 ? matches : null;
|
|
2748
|
+
};
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
/** /mcp subcommands whose argument is a server name (per their `usage: "<name>..."`). */
|
|
2752
|
+
const MCP_SERVER_NAME_SUBCOMMANDS: Readonly<Record<string, true>> = {
|
|
2753
|
+
enable: true,
|
|
2754
|
+
disable: true,
|
|
2755
|
+
test: true,
|
|
2756
|
+
remove: true,
|
|
2757
|
+
reconnect: true,
|
|
2758
|
+
reauth: true,
|
|
2759
|
+
unauth: true,
|
|
2760
|
+
};
|
|
2761
|
+
|
|
2762
|
+
/** Subcommands that accept names found only in `userConfig.disabledServers`. */
|
|
2763
|
+
const MCP_DISABLED_ONLY_ELIGIBLE_SUBCOMMANDS: Readonly<Record<string, true>> = {
|
|
2764
|
+
enable: true,
|
|
2765
|
+
disable: true,
|
|
2766
|
+
};
|
|
2767
|
+
|
|
2768
|
+
/**
|
|
2769
|
+
* Subcommands that accept configured servers whose `enabled` flag is false.
|
|
2770
|
+
* `unauth` can clear persisted credentials without connecting; test,
|
|
2771
|
+
* reconnect, and reauth explicitly require an enabled server.
|
|
2772
|
+
*/
|
|
2773
|
+
const MCP_DISABLED_CONFIG_ELIGIBLE_SUBCOMMANDS: Readonly<Record<string, true>> = {
|
|
2774
|
+
enable: true,
|
|
2775
|
+
disable: true,
|
|
2776
|
+
unauth: true,
|
|
2777
|
+
};
|
|
2778
|
+
|
|
2779
|
+
/**
|
|
2780
|
+
* Build getArgumentCompletions for /mcp. Delegates to the generic
|
|
2781
|
+
* declarative subcommand completer while the subcommand name itself is
|
|
2782
|
+
* still being typed, then switches to MCP server-name completion (sourced
|
|
2783
|
+
* from {@link collectMcpServerNames}) once a recognized server-name
|
|
2784
|
+
* subcommand (enable/disable/test/remove/reconnect/reauth/unauth) is
|
|
2785
|
+
* followed by a space. `remove` gets its own scope-aware completions (see
|
|
2786
|
+
* {@link buildMcpRemoveCompletions}) since — unlike the others —
|
|
2787
|
+
* it only ever succeeds against a config-file entry. Subcommands with a
|
|
2788
|
+
* different argument shape (add, smithery-search, ...) get no argument
|
|
2789
|
+
* completion.
|
|
2790
|
+
*/
|
|
2791
|
+
function buildMcpArgumentCompletions(
|
|
2792
|
+
subcommands: SubcommandDef[],
|
|
2793
|
+
runtime: TuiSlashCommandRuntime,
|
|
2794
|
+
): (argumentPrefix: string) => Promise<AutocompleteItem[] | null> {
|
|
2795
|
+
const genericCompletions = buildArgumentCompletions(subcommands);
|
|
2796
|
+
return async (argumentPrefix: string) => {
|
|
2797
|
+
const spaceIndex = argumentPrefix.indexOf(" ");
|
|
2798
|
+
if (spaceIndex === -1) return genericCompletions(argumentPrefix);
|
|
2799
|
+
|
|
2800
|
+
const rawSubcommand = argumentPrefix.slice(0, spaceIndex);
|
|
2801
|
+
const lowerSubcommand = rawSubcommand.toLowerCase();
|
|
2802
|
+
if (MCP_SERVER_NAME_SUBCOMMANDS[lowerSubcommand] !== true) return null;
|
|
2803
|
+
const namePrefix = argumentPrefix.slice(spaceIndex + 1).toLowerCase();
|
|
2804
|
+
if (lowerSubcommand === "remove") {
|
|
2805
|
+
return await buildMcpRemoveCompletions(rawSubcommand, namePrefix);
|
|
2806
|
+
}
|
|
2807
|
+
|
|
2808
|
+
let serverNames: string[];
|
|
2809
|
+
try {
|
|
2810
|
+
serverNames = await collectMcpServerNames(
|
|
2811
|
+
runtime.ctx,
|
|
2812
|
+
undefined,
|
|
2813
|
+
MCP_DISABLED_ONLY_ELIGIBLE_SUBCOMMANDS[lowerSubcommand] === true,
|
|
2814
|
+
MCP_DISABLED_CONFIG_ELIGIBLE_SUBCOMMANDS[lowerSubcommand] === true,
|
|
2815
|
+
);
|
|
2816
|
+
} catch (error) {
|
|
2817
|
+
logger.warn("MCP server-name autocomplete failed to read config", { error });
|
|
2818
|
+
return null;
|
|
2819
|
+
}
|
|
2820
|
+
const matches: AutocompleteItem[] = serverNames
|
|
2821
|
+
.filter(name => name.toLowerCase().startsWith(namePrefix))
|
|
2822
|
+
.map(name => ({ value: `${rawSubcommand} ${name} `, label: name }));
|
|
2823
|
+
return matches.length > 0 ? matches : null;
|
|
2824
|
+
};
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
/**
|
|
2828
|
+
* Build `/mcp remove <name>` completions. Unlike the other server-name
|
|
2829
|
+
* subcommands, `#handleRemove` only ever succeeds against a config-file
|
|
2830
|
+
* `mcpServers` entry in the target scope (project by default, user with an
|
|
2831
|
+
* explicit `--scope user`) — a purely runtime-discovered server has no
|
|
2832
|
+
* config entry to remove and always fails with `Server "<name>" not found
|
|
2833
|
+
* in <scope> config.`. Completions are therefore restricted to config-file
|
|
2834
|
+
* names, and a name that exists only in the user config is completed with
|
|
2835
|
+
* `--scope user` appended so the inserted command is directly executable.
|
|
2836
|
+
*/
|
|
2837
|
+
async function buildMcpRemoveCompletions(
|
|
2838
|
+
rawSubcommand: string,
|
|
2839
|
+
namePrefix: string,
|
|
2840
|
+
): Promise<AutocompleteItem[] | null> {
|
|
2841
|
+
const cwd = getProjectDir();
|
|
2842
|
+
let projectNames: string[];
|
|
2843
|
+
let userNames: string[];
|
|
2844
|
+
try {
|
|
2845
|
+
const [projectConfig, userConfig] = await Promise.all([
|
|
2846
|
+
readMCPConfigFile(getMCPConfigPath("project", cwd)),
|
|
2847
|
+
readMCPConfigFile(getMCPConfigPath("user", cwd)),
|
|
2848
|
+
]);
|
|
2849
|
+
projectNames = Object.keys(projectConfig.mcpServers ?? {});
|
|
2850
|
+
userNames = Object.keys(userConfig.mcpServers ?? {});
|
|
2851
|
+
} catch (error) {
|
|
2852
|
+
logger.warn("MCP remove autocomplete failed to read config", { error });
|
|
2853
|
+
return null;
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
const projectNameSet = new Set(projectNames);
|
|
2857
|
+
const allNames = new Set([...projectNames, ...userNames]);
|
|
2858
|
+
const matches: AutocompleteItem[] = [...allNames]
|
|
2859
|
+
.filter(name => name.toLowerCase().startsWith(namePrefix))
|
|
2860
|
+
.map(name =>
|
|
2861
|
+
projectNameSet.has(name)
|
|
2862
|
+
? { value: `${rawSubcommand} ${name} `, label: name }
|
|
2863
|
+
: { value: `${rawSubcommand} ${name} --scope user `, label: `${name} (user)` },
|
|
2864
|
+
)
|
|
2865
|
+
.sort((a, b) => a.label.localeCompare(b.label, undefined, { sensitivity: "base" }));
|
|
2866
|
+
return matches.length > 0 ? matches : null;
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
/**
|
|
2870
|
+
* Build getInlineHint from declarative subcommand definitions.
|
|
2871
|
+
* Shows remaining completion + usage as dim ghost text after cursor.
|
|
2872
|
+
*/
|
|
2873
|
+
function buildSubcommandInlineHint(subcommands: SubcommandDef[]): (argumentText: string) => string | null {
|
|
2874
|
+
return (argumentText: string) => {
|
|
2875
|
+
const trimmed = argumentText.trimStart();
|
|
2876
|
+
const spaceIndex = trimmed.indexOf(" ");
|
|
2877
|
+
|
|
2878
|
+
if (spaceIndex === -1) {
|
|
2879
|
+
// Still typing subcommand name — show remaining chars + usage
|
|
2880
|
+
const prefix = trimmed.toLowerCase();
|
|
2881
|
+
if (prefix.length === 0) return null;
|
|
2882
|
+
const match = subcommands.find(s => s.name.startsWith(prefix));
|
|
2883
|
+
if (!match) return null;
|
|
2884
|
+
const remaining = match.name.slice(prefix.length);
|
|
2885
|
+
return remaining + (match.usage ? ` ${match.usage}` : "");
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
// Subcommand typed — show remaining usage params
|
|
2889
|
+
const subName = trimmed.slice(0, spaceIndex).toLowerCase();
|
|
2890
|
+
const afterSub = trimmed.slice(spaceIndex + 1);
|
|
2891
|
+
const sub = subcommands.find(s => s.name === subName);
|
|
2892
|
+
if (!sub?.usage) return null;
|
|
2893
|
+
|
|
2894
|
+
if (afterSub.length > 0) {
|
|
2895
|
+
const usageParts = sub.usage.split(" ");
|
|
2896
|
+
const inputParts = afterSub.trim().split(/\s+/);
|
|
2897
|
+
const remaining = usageParts.slice(inputParts.length);
|
|
2898
|
+
return remaining.length > 0 ? remaining.join(" ") : null;
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
return sub.usage;
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
/**
|
|
2906
|
+
* Build getInlineHint for commands with a simple static hint string.
|
|
2907
|
+
* Shows the hint only when no arguments have been typed yet.
|
|
2908
|
+
*/
|
|
2909
|
+
function buildStaticInlineHint(hint: string): (argumentText: string) => string | null {
|
|
2910
|
+
return (argumentText: string) => (argumentText.trim().length === 0 ? hint : null);
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2913
|
+
/**
|
|
2914
|
+
* Build getArgumentCompletions that suggests directories relative to the
|
|
2915
|
+
* current project directory. Used by /move so users can Tab-complete the
|
|
2916
|
+
* destination directory.
|
|
2917
|
+
*/
|
|
2918
|
+
function buildDirectoryArgumentCompletions(): (prefix: string) => Promise<AutocompleteItem[] | null> {
|
|
2919
|
+
return async (argumentPrefix: string) => {
|
|
2920
|
+
const prefix = argumentPrefix.trim();
|
|
2921
|
+
|
|
2922
|
+
const cwd = getProjectDir();
|
|
2923
|
+
const expandedPrefix = expandTilde(prefix);
|
|
2924
|
+
const isAbsolute = path.isAbsolute(expandedPrefix);
|
|
2925
|
+
|
|
2926
|
+
let searchDir: string;
|
|
2927
|
+
let searchPrefix: string;
|
|
2928
|
+
if (
|
|
2929
|
+
prefix === "" ||
|
|
2930
|
+
prefix === "." ||
|
|
2931
|
+
prefix === "./" ||
|
|
2932
|
+
prefix === ".." ||
|
|
2933
|
+
prefix === "../" ||
|
|
2934
|
+
prefix === "~" ||
|
|
2935
|
+
prefix === "~/" ||
|
|
2936
|
+
prefix === "/"
|
|
2937
|
+
) {
|
|
2938
|
+
searchDir = isAbsolute ? expandedPrefix : path.join(cwd, expandedPrefix);
|
|
2939
|
+
searchPrefix = "";
|
|
2940
|
+
} else if (expandedPrefix.endsWith("/")) {
|
|
2941
|
+
searchDir = isAbsolute ? expandedPrefix : path.join(cwd, expandedPrefix);
|
|
2942
|
+
searchPrefix = "";
|
|
2943
|
+
} else {
|
|
2944
|
+
const dir = path.dirname(expandedPrefix);
|
|
2945
|
+
searchDir = isAbsolute ? dir : path.join(cwd, dir);
|
|
2946
|
+
searchPrefix = path.basename(expandedPrefix);
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
try {
|
|
2950
|
+
const entries = await fs.readdir(searchDir, { withFileTypes: true });
|
|
2951
|
+
const suggestions: AutocompleteItem[] = [];
|
|
2952
|
+
for (const entry of entries) {
|
|
2953
|
+
if (!entry.name.toLowerCase().startsWith(searchPrefix.toLowerCase())) continue;
|
|
2954
|
+
if (entry.name === ".git") continue;
|
|
2955
|
+
|
|
2956
|
+
let isDirectory = entry.isDirectory();
|
|
2957
|
+
if (!isDirectory && entry.isSymbolicLink()) {
|
|
2958
|
+
try {
|
|
2959
|
+
isDirectory = (await fs.stat(path.join(searchDir, entry.name))).isDirectory();
|
|
2960
|
+
} catch {
|
|
2961
|
+
continue;
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
if (!isDirectory) continue;
|
|
2965
|
+
|
|
2966
|
+
const absoluteValue = path.join(searchDir, entry.name);
|
|
2967
|
+
const displayValue = buildDirectoryCompletionDisplayValue(prefix, absoluteValue, cwd);
|
|
2968
|
+
suggestions.push({ value: displayValue, label: `${entry.name}/` });
|
|
2969
|
+
}
|
|
2970
|
+
suggestions.sort((a, b) => a.label.localeCompare(b.label));
|
|
2971
|
+
return suggestions.length > 0 ? suggestions : null;
|
|
2972
|
+
} catch {
|
|
2973
|
+
return null;
|
|
2974
|
+
}
|
|
2975
|
+
};
|
|
2976
|
+
}
|
|
2977
|
+
function buildDirectoryCompletionDisplayValue(prefix: string, absoluteValue: string, cwd: string): string {
|
|
2978
|
+
// Preserve the user's prefix style where possible, but always return a
|
|
2979
|
+
// value that /move can resolve (absolute or relative) without escaping.
|
|
2980
|
+
const normalized = path.normalize(absoluteValue);
|
|
2981
|
+
|
|
2982
|
+
if (prefix.startsWith("~/")) {
|
|
2983
|
+
const home = os.homedir();
|
|
2984
|
+
const homeRelative = path.relative(home, normalized);
|
|
2985
|
+
return `~/${homeRelative.replaceAll("\\", "/")}/`;
|
|
2986
|
+
}
|
|
2987
|
+
if (prefix === "~") {
|
|
2988
|
+
const home = os.homedir();
|
|
2989
|
+
const homeRelative = path.relative(home, normalized);
|
|
2990
|
+
return `~/${homeRelative.replaceAll("\\", "/")}/`;
|
|
2991
|
+
}
|
|
2992
|
+
if (prefix.startsWith("/")) {
|
|
2993
|
+
return `${normalized.replaceAll("\\", "/")}/`;
|
|
2994
|
+
}
|
|
2995
|
+
if (prefix.startsWith("./")) {
|
|
2996
|
+
const relative = path.relative(cwd, normalized);
|
|
2997
|
+
return `./${relative.replaceAll("\\", "/")}/`;
|
|
2998
|
+
}
|
|
2999
|
+
if (prefix.startsWith("../")) {
|
|
3000
|
+
const relative = path.relative(cwd, normalized);
|
|
3001
|
+
return `${relative.replaceAll("\\", "/")}/`;
|
|
3002
|
+
}
|
|
3003
|
+
if (prefix === "..") {
|
|
3004
|
+
const relative = path.relative(cwd, normalized);
|
|
3005
|
+
return `${relative.replaceAll("\\", "/")}/`;
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
// Default: relative to cwd.
|
|
3009
|
+
const relative = path.relative(cwd, normalized);
|
|
3010
|
+
return `${relative.replaceAll("\\", "/")}/`;
|
|
3011
|
+
}
|
|
3012
|
+
|
|
3013
|
+
/** Builtin command metadata used for slash-command autocomplete and help text. */
|
|
3014
|
+
export const BUILTIN_SLASH_COMMAND_DEFS: ReadonlyArray<BuiltinSlashCommand> = BUILTIN_SLASH_COMMAND_REGISTRY.map(
|
|
3015
|
+
command => ({
|
|
3016
|
+
name: command.name,
|
|
3017
|
+
aliases: command.aliases,
|
|
3018
|
+
allowArgs: command.allowArgs === true,
|
|
3019
|
+
description: command.description,
|
|
3020
|
+
subcommands: command.subcommands,
|
|
3021
|
+
inlineHint: command.inlineHint,
|
|
3022
|
+
getTuiAutocompleteDescription: command.getTuiAutocompleteDescription,
|
|
3023
|
+
}),
|
|
3024
|
+
);
|
|
3025
|
+
|
|
3026
|
+
function materializeTuiBuiltinSlashCommand(
|
|
3027
|
+
cmd: BuiltinSlashCommand,
|
|
3028
|
+
runtime?: TuiSlashCommandRuntime,
|
|
3029
|
+
): TuiBuiltinSlashCommand {
|
|
3030
|
+
const materialized: TuiBuiltinSlashCommand = { ...cmd };
|
|
3031
|
+
if (cmd.subcommands) {
|
|
3032
|
+
materialized.getArgumentCompletions =
|
|
3033
|
+
cmd.name === "mcp" && runtime
|
|
3034
|
+
? buildMcpArgumentCompletions(cmd.subcommands, runtime)
|
|
3035
|
+
: buildArgumentCompletions(cmd.subcommands);
|
|
3036
|
+
materialized.getInlineHint = buildSubcommandInlineHint(cmd.subcommands);
|
|
3037
|
+
} else if (cmd.name === "move") {
|
|
3038
|
+
materialized.getArgumentCompletions = buildDirectoryArgumentCompletions();
|
|
3039
|
+
if (cmd.inlineHint) materialized.getInlineHint = buildStaticInlineHint(cmd.inlineHint);
|
|
3040
|
+
} else if (cmd.inlineHint) {
|
|
3041
|
+
materialized.getInlineHint = buildStaticInlineHint(cmd.inlineHint);
|
|
3042
|
+
}
|
|
3043
|
+
if (runtime && cmd.getTuiAutocompleteDescription) {
|
|
3044
|
+
materialized.getAutocompleteDescription = () => cmd.getTuiAutocompleteDescription?.(runtime);
|
|
3045
|
+
}
|
|
3046
|
+
return materialized;
|
|
3047
|
+
}
|
|
3048
|
+
|
|
3049
|
+
/**
|
|
3050
|
+
* Materialized builtin slash commands with completion functions derived from
|
|
3051
|
+
* declarative subcommand/hint definitions.
|
|
3052
|
+
*/
|
|
3053
|
+
export const BUILTIN_SLASH_COMMANDS: ReadonlyArray<TuiBuiltinSlashCommand> = BUILTIN_SLASH_COMMAND_DEFS.map(cmd =>
|
|
3054
|
+
materializeTuiBuiltinSlashCommand(cmd),
|
|
3055
|
+
);
|
|
3056
|
+
|
|
3057
|
+
export function buildTuiBuiltinSlashCommands(runtime: TuiSlashCommandRuntime): ReadonlyArray<TuiBuiltinSlashCommand> {
|
|
3058
|
+
return BUILTIN_SLASH_COMMAND_DEFS.map(cmd => materializeTuiBuiltinSlashCommand(cmd, runtime));
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
/**
|
|
3062
|
+
* Unified registry exposed for cross-mode tooling. Each spec carries at least
|
|
3063
|
+
* one of `handle` / `handleTui`. The TUI dispatcher prefers `handleTui`; the
|
|
3064
|
+
* ACP dispatcher requires `handle` and skips TUI-only entries.
|
|
3065
|
+
*/
|
|
3066
|
+
export const BUILTIN_SLASH_COMMANDS_INTERNAL: ReadonlyArray<SlashCommandSpec> = BUILTIN_SLASH_COMMAND_REGISTRY;
|
|
3067
|
+
|
|
3068
|
+
/**
|
|
3069
|
+
* Reload the interactive session's plugin runtime: invalidate fs/plugin-root
|
|
3070
|
+
* caches, rediscover skills and file slash commands, reset the capability
|
|
3071
|
+
* cache, and reconnect MCP servers (rebinding the session's MCP tools). Shared
|
|
3072
|
+
* by `/reload-plugins`'s TUI handler and the `handle`-adapter's `reloadPlugins`
|
|
3073
|
+
* hook so both honor the command's documented MCP reload scope (#7189).
|
|
3074
|
+
*/
|
|
3075
|
+
async function reloadTuiPluginState(ctx: InteractiveModeContext): Promise<void> {
|
|
3076
|
+
const projectPath = await resolveActiveProjectRegistryPath(ctx.sessionManager.getCwd());
|
|
3077
|
+
clearPluginRootsAndCaches(projectPath ? [projectPath] : undefined);
|
|
3078
|
+
await ctx.refreshSkillState();
|
|
3079
|
+
await ctx.refreshSlashCommandState();
|
|
3080
|
+
resetCapabilities();
|
|
3081
|
+
if (ctx.mcpManager) {
|
|
3082
|
+
await new MCPCommandController(ctx).reloadServers();
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3086
|
+
/**
|
|
3087
|
+
* Execute a builtin slash command in the interactive TUI.
|
|
3088
|
+
*
|
|
3089
|
+
* Returns `false` when no builtin matched. Returns `true` when a command
|
|
3090
|
+
* consumed the input entirely. Returns a `string` when the command was handled
|
|
3091
|
+
* but remaining text should be sent as a prompt.
|
|
3092
|
+
*/
|
|
3093
|
+
export async function executeBuiltinSlashCommand(
|
|
3094
|
+
text: string,
|
|
3095
|
+
runtime: BuiltinSlashCommandRuntime,
|
|
3096
|
+
): Promise<string | boolean> {
|
|
3097
|
+
const parsed = parseSlashCommand(text);
|
|
3098
|
+
if (!parsed) return false;
|
|
3099
|
+
|
|
3100
|
+
const command = BUILTIN_SLASH_COMMAND_LOOKUP.get(parsed.name);
|
|
3101
|
+
if (!command) return false;
|
|
3102
|
+
if (parsed.args.length > 0 && !command.allowArgs) {
|
|
3103
|
+
return false;
|
|
3104
|
+
}
|
|
3105
|
+
// Collab guests run a read-mostly replica: session-mutating builtins are
|
|
3106
|
+
// host-only; the allowlist covers purely local/read-only commands.
|
|
3107
|
+
if (runtime.ctx.collabGuest && !COLLAB_GUEST_ALLOWED_COMMANDS[command.name]) {
|
|
3108
|
+
runtime.ctx.showStatus(`/${command.name} is host-only during a collab session`);
|
|
3109
|
+
runtime.ctx.editor.setText("");
|
|
3110
|
+
return true;
|
|
3111
|
+
}
|
|
3112
|
+
if (command.handleTui) {
|
|
3113
|
+
const result = await command.handleTui(parsed, runtime);
|
|
3114
|
+
if (result && typeof result === "object" && "prompt" in result) return result.prompt;
|
|
3115
|
+
return true;
|
|
3116
|
+
}
|
|
3117
|
+
if (command.handle) {
|
|
3118
|
+
// No TUI-specific override → adapt the ACP/text-mode `handle` to the
|
|
3119
|
+
// TUI by routing `runtime.output` through `ctx.showStatus`, clearing
|
|
3120
|
+
// the editor after the call, and reusing the active session's plugin
|
|
3121
|
+
// reload pipeline. Spec authors get a single body usable from either
|
|
3122
|
+
// dispatcher without forcing every TUI test to construct the full
|
|
3123
|
+
// `SlashCommandRuntime` shape.
|
|
3124
|
+
const ctx = runtime.ctx;
|
|
3125
|
+
const adapted: SlashCommandRuntime = {
|
|
3126
|
+
session: ctx.session,
|
|
3127
|
+
sessionManager: ctx.sessionManager,
|
|
3128
|
+
settings: ctx.settings,
|
|
3129
|
+
cwd: ctx.sessionManager.getCwd(),
|
|
3130
|
+
output: (text: string) => {
|
|
3131
|
+
ctx.showStatus(text);
|
|
3132
|
+
},
|
|
3133
|
+
refreshCommands: () => ctx.refreshSlashCommandState(),
|
|
3134
|
+
reloadPlugins: () => reloadTuiPluginState(ctx),
|
|
3135
|
+
};
|
|
3136
|
+
const result = await command.handle(parsed, adapted);
|
|
3137
|
+
ctx.editor.setText("");
|
|
3138
|
+
if (result && typeof result === "object" && "prompt" in result) return result.prompt;
|
|
3139
|
+
return true;
|
|
3140
|
+
}
|
|
3141
|
+
return false;
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
/** Look up a unified spec by name or alias. Used by the ACP dispatcher. */
|
|
3145
|
+
export function lookupBuiltinSlashCommand(name: string): SlashCommandSpec | undefined {
|
|
3146
|
+
return BUILTIN_SLASH_COMMAND_LOOKUP.get(name);
|
|
3147
|
+
}
|
|
3148
|
+
|
|
3149
|
+
export type { ParsedSlashCommand, SlashCommandResult, SlashCommandRuntime, SlashCommandSpec, TuiSlashCommandRuntime };
|