@xingular/harness 1.0.0 → 1.2.0
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 +46 -5
- package/README.md +75 -21
- package/dist/cli.js +17421 -8711
- package/dist/sdk/accounts/accounts.d.ts +27 -3
- package/dist/sdk/accounts/accounts.js +78 -24
- package/dist/sdk/accounts/secrets.d.ts +12 -0
- package/dist/sdk/accounts/secrets.js +114 -7
- package/dist/sdk/accounts/store.d.ts +26 -1
- package/dist/sdk/accounts/store.js +1 -1
- package/dist/sdk/agents/builtin.d.ts +2 -0
- package/dist/sdk/agents/builtin.js +48 -0
- package/dist/sdk/agents/narrow.d.ts +13 -0
- package/dist/sdk/agents/narrow.js +29 -0
- package/dist/sdk/agents/planResearch.d.ts +5 -0
- package/dist/sdk/agents/planResearch.js +19 -0
- package/dist/sdk/agents/profiles.d.ts +81 -0
- package/dist/sdk/agents/profiles.js +226 -0
- package/dist/sdk/annotations/bridge.d.ts +42 -0
- package/dist/sdk/annotations/bridge.js +264 -0
- package/dist/sdk/annotations/capture.d.ts +116 -0
- package/dist/sdk/annotations/capture.js +308 -0
- package/dist/sdk/annotations/delivery.d.ts +72 -0
- package/dist/sdk/annotations/delivery.js +130 -0
- package/dist/sdk/annotations/inspect.d.ts +10 -0
- package/dist/sdk/annotations/inspect.js +33 -0
- package/dist/sdk/annotations/isolated.d.ts +6 -0
- package/dist/sdk/annotations/isolated.js +51 -0
- package/dist/sdk/annotations/pageScript.d.ts +28 -0
- package/dist/sdk/annotations/pageScript.js +871 -0
- package/dist/sdk/annotations/part.d.ts +10 -0
- package/dist/sdk/annotations/part.js +155 -0
- package/dist/sdk/annotations/queue.d.ts +4 -0
- package/dist/sdk/annotations/queue.js +40 -0
- package/dist/sdk/annotations/serverMethods.d.ts +3 -0
- package/dist/sdk/annotations/serverMethods.js +62 -0
- package/dist/sdk/annotations/store.d.ts +167 -0
- package/dist/sdk/annotations/store.js +394 -0
- package/dist/sdk/browser/backend.d.ts +16 -0
- package/dist/sdk/browser/backend.js +17 -0
- package/dist/sdk/browser/contracts.d.ts +19 -0
- package/dist/sdk/browser/contracts.js +116 -0
- package/dist/sdk/browser/index.d.ts +14 -3
- package/dist/sdk/browser/index.js +11 -4
- package/dist/sdk/browser/serverMethods.d.ts +3 -0
- package/dist/sdk/browser/serverMethods.js +7 -0
- package/dist/sdk/browser/session.d.ts +1 -0
- package/dist/sdk/browser/session.js +45 -9
- package/dist/sdk/browser/tools.d.ts +1 -4
- package/dist/sdk/browser/tools.js +14 -91
- package/dist/sdk/cli.js +24 -15
- package/dist/sdk/commands/list.d.ts +3 -0
- package/dist/sdk/commands/list.js +75 -0
- package/dist/sdk/commands/registry.d.ts +250 -0
- package/dist/sdk/commands/registry.js +47 -0
- package/dist/sdk/commands/routes.d.ts +16 -0
- package/dist/sdk/commands/routes.js +33 -0
- package/dist/sdk/core/bus.js +1 -1
- package/dist/sdk/core/commandBudget.d.ts +23 -0
- package/dist/sdk/core/commandBudget.js +57 -0
- package/dist/sdk/core/env.d.ts +1 -1
- package/dist/sdk/core/env.js +1 -1
- package/dist/sdk/core/index.js +17 -1
- package/dist/sdk/core/interactiveProfile.d.ts +46 -0
- package/dist/sdk/core/interactiveProfile.js +143 -0
- package/dist/sdk/core/workspace.d.ts +13 -0
- package/dist/sdk/core/workspace.js +88 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +4 -0
- package/dist/sdk/core/workspaceBashTool.js +36 -0
- package/dist/sdk/core/workspaceSandbox.d.ts +31 -0
- package/dist/sdk/core/workspaceSandbox.js +320 -0
- package/dist/sdk/core/workspaceWriteOperations.d.ts +22 -0
- package/dist/sdk/core/workspaceWriteOperations.js +206 -0
- package/dist/sdk/doctor/serverMethods.d.ts +3 -0
- package/dist/sdk/doctor/serverMethods.js +8 -0
- package/dist/sdk/doctor/types.d.ts +2 -2
- package/dist/sdk/harness.d.ts +22 -0
- package/dist/sdk/harness.js +84 -5
- package/dist/sdk/history/recall.js +8 -8
- package/dist/sdk/history/serverMethods.d.ts +3 -0
- package/dist/sdk/history/serverMethods.js +8 -0
- package/dist/sdk/hub/cli.d.ts +1 -1
- package/dist/sdk/hub/cli.js +1 -1
- package/dist/sdk/hub/schema.d.ts +1 -1
- package/dist/sdk/hub/serverMethods.d.ts +3 -0
- package/dist/sdk/hub/serverMethods.js +11 -0
- package/dist/sdk/index.d.ts +16 -1
- package/dist/sdk/index.js +10 -0
- package/dist/sdk/mcp/connections.js +14 -7
- package/dist/sdk/mcp/serverMethods.d.ts +3 -0
- package/dist/sdk/mcp/serverMethods.js +22 -0
- package/dist/sdk/pi/runtime.d.ts +2 -1
- package/dist/sdk/pi/runtime.js +2 -2
- package/dist/sdk/plugins/builtin.d.ts +1 -0
- package/dist/sdk/plugins/builtin.js +145 -33
- package/dist/sdk/plugins/builtinRegistry.d.ts +60 -0
- package/dist/sdk/plugins/builtinRegistry.js +71 -0
- package/dist/sdk/plugins/catalogue.js +2 -1
- package/dist/sdk/plugins/cli.d.ts +1 -1
- package/dist/sdk/plugins/cli.js +4 -3
- package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
- package/dist/sdk/plugins/commandPrefix.js +21 -0
- package/dist/sdk/plugins/firstParty.d.ts +1 -1
- package/dist/sdk/plugins/firstParty.js +8 -2
- package/dist/sdk/plugins/inventory.js +4 -3
- package/dist/sdk/plugins/manifest.d.ts +2 -0
- package/dist/sdk/plugins/manifest.js +2 -1
- package/dist/sdk/plugins/surfaces.d.ts +5 -0
- package/dist/sdk/plugins/surfaces.js +11 -0
- package/dist/sdk/plugins/types.d.ts +15 -0
- package/dist/sdk/prompt/compile.d.ts +19 -2
- package/dist/sdk/prompt/compile.js +79 -26
- package/dist/sdk/prompt/standard.d.ts +17 -0
- package/dist/sdk/prompt/standard.js +21 -0
- package/dist/sdk/refine/cli.d.ts +1 -1
- package/dist/sdk/refine/cli.js +2 -2
- package/dist/sdk/refine/serverMethods.d.ts +3 -0
- package/dist/sdk/refine/serverMethods.js +20 -0
- package/dist/sdk/server/methods.js +27 -86
- package/dist/sdk/server/params.d.ts +4 -0
- package/dist/sdk/server/params.js +11 -0
- package/dist/sdk/server/remote.js +36 -11
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
- package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
- package/dist/sdk/sessions/continuation.d.ts +3 -0
- package/dist/sdk/sessions/continuation.js +5 -1
- package/dist/sdk/sessions/contracts.d.ts +185 -0
- package/dist/sdk/sessions/contracts.js +101 -4
- package/dist/sdk/sessions/control.d.ts +72 -0
- package/dist/sdk/sessions/control.js +158 -0
- package/dist/sdk/sessions/initialBash.d.ts +7 -0
- package/dist/sdk/sessions/initialBash.js +7 -0
- package/dist/sdk/sessions/planMode.d.ts +18 -4
- package/dist/sdk/sessions/planMode.js +82 -16
- package/dist/sdk/sessions/reasoningSummaries.d.ts +2 -2
- package/dist/sdk/sessions/reasoningSummaries.js +3 -3
- package/dist/sdk/sessions/registry.d.ts +2 -1
- package/dist/sdk/sessions/registry.js +6 -3
- package/dist/sdk/sessions/runIndex.js +7 -7
- package/dist/sdk/sessions/runStore.d.ts +14 -0
- package/dist/sdk/sessions/runStore.js +38 -1
- package/dist/sdk/sessions/runner.d.ts +40 -2
- package/dist/sdk/sessions/runner.js +163 -15
- package/dist/sdk/sessions/sessions.d.ts +40 -8
- package/dist/sdk/sessions/sessions.js +279 -27
- package/dist/sdk/sessions/sideQuestionServerMethods.d.ts +3 -0
- package/dist/sdk/sessions/sideQuestionServerMethods.js +19 -0
- package/dist/sdk/sessions/sideQuestions.d.ts +66 -0
- package/dist/sdk/sessions/sideQuestions.js +290 -0
- package/dist/sdk/sessions/subagentServerMethods.d.ts +3 -0
- package/dist/sdk/sessions/subagentServerMethods.js +41 -0
- package/dist/sdk/sessions/subagentService.d.ts +22 -2
- package/dist/sdk/sessions/subagentService.js +93 -16
- package/dist/sdk/sessions/subagents.d.ts +9 -1
- package/dist/sdk/sessions/subagents.js +19 -0
- package/dist/sdk/sessions/workSlice.d.ts +103 -0
- package/dist/sdk/sessions/workSlice.js +297 -0
- package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
- package/dist/sdk/sessions/workspaceBoundary.js +46 -0
- package/dist/sdk/terminal/browser.d.ts +62 -0
- package/dist/sdk/terminal/browser.js +41 -0
- package/dist/sdk/terminal/browserControl.d.ts +29 -0
- package/dist/sdk/terminal/browserControl.js +187 -0
- package/dist/sdk/terminal/commandHelp.d.ts +17 -0
- package/dist/sdk/terminal/commandHelp.js +20 -0
- package/dist/sdk/terminal/controller.d.ts +15 -1
- package/dist/sdk/terminal/controller.js +67 -8
- package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +28 -0
- package/dist/sdk/terminal/opentui/subagentsWidget.js +52 -0
- package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
- package/dist/sdk/terminal/opentui/theme.js +87 -0
- package/dist/sdk/terminal/piExtension.d.ts +6 -1
- package/dist/sdk/terminal/piExtension.js +169 -84
- package/dist/sdk/terminal/socket.d.ts +6 -3
- package/dist/sdk/terminal/socket.js +40 -9
- package/dist/sdk/terminal/standalone.d.ts +9 -0
- package/dist/sdk/terminal/standalone.js +118 -19
- package/dist/sdk/terminal/subagentMonitor.d.ts +47 -0
- package/dist/sdk/terminal/subagentMonitor.js +152 -0
- package/dist/sdk/terminal/terminals.d.ts +60 -7
- package/dist/sdk/terminal/terminals.js +598 -47
- package/dist/sdk/terminal/trajectory.js +2 -2
- package/dist/sdk/terminal/tui/annotateCommand.d.ts +3 -0
- package/dist/sdk/terminal/tui/annotateCommand.js +22 -0
- package/dist/sdk/terminal/tui/commandPages.d.ts +7 -1
- package/dist/sdk/terminal/tui/commandPages.js +57 -6
- package/dist/sdk/terminal/tui/commands.d.ts +10 -4
- package/dist/sdk/terminal/tui/commands.js +269 -65
- package/dist/sdk/terminal/tui/dialogGeometry.d.ts +2 -2
- package/dist/sdk/terminal/tui/dialogGeometry.js +4 -2
- package/dist/sdk/terminal/tui/dialogs.d.ts +6 -1
- package/dist/sdk/terminal/tui/dialogs.js +9 -2
- package/dist/sdk/terminal/tui/list.d.ts +14 -1
- package/dist/sdk/terminal/tui/list.js +96 -14
- package/dist/sdk/terminal/tui/modelPicker.js +1 -6
- package/dist/sdk/terminal/tui/page.d.ts +3 -0
- package/dist/sdk/terminal/tui/pageOverlay.js +27 -7
- package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +26 -4
- package/dist/sdk/terminal/tui/pages/accountsPage.js +264 -36
- package/dist/sdk/terminal/tui/pages/agentsPage.d.ts +74 -0
- package/dist/sdk/terminal/tui/pages/agentsPage.js +190 -0
- package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +94 -0
- package/dist/sdk/terminal/tui/pages/annotatePage.js +341 -0
- package/dist/sdk/terminal/tui/pages/browserPage.d.ts +87 -0
- package/dist/sdk/terminal/tui/pages/browserPage.js +738 -0
- package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +2 -0
- package/dist/sdk/terminal/tui/pages/doctorPage.js +103 -15
- package/dist/sdk/terminal/tui/pages/notesPage.d.ts +75 -0
- package/dist/sdk/terminal/tui/pages/notesPage.js +201 -0
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +0 -5
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +9 -3
- package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +8 -0
- package/dist/sdk/terminal/tui/pages/settingsPage.js +16 -1
- package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +24 -0
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +152 -0
- package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +12 -5
- package/dist/sdk/terminal/tui/pages/trajectoryPage.js +156 -83
- package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
- package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
- package/dist/sdk/terminal/tui/pages/worktreesPage.d.ts +72 -0
- package/dist/sdk/terminal/tui/pages/worktreesPage.js +203 -0
- package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
- package/dist/sdk/terminal/tui/piAdapter.js +3 -5
- package/dist/sdk/terminal/tui/planMode.d.ts +1 -1
- package/dist/sdk/terminal/tui/planMode.js +1 -1
- package/dist/sdk/terminal/tui/pluginCommands.d.ts +16 -0
- package/dist/sdk/terminal/tui/pluginCommands.js +31 -0
- package/dist/sdk/terminal/tui/questions.d.ts +2 -0
- package/dist/sdk/terminal/tui/runtime.js +27 -5
- package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
- package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
- package/dist/sdk/terminal/tui/settingsModel.d.ts +2 -0
- package/dist/sdk/terminal/tui/settingsModel.js +32 -2
- package/dist/sdk/terminal/tui/sideQuestion.d.ts +26 -26
- package/dist/sdk/terminal/tui/sideQuestion.js +131 -98
- package/dist/sdk/terminal/tui/ui.d.ts +2 -0
- package/dist/sdk/terminal/tui/ui.js +1 -0
- package/dist/sdk/tools/askUser.js +26 -8
- package/dist/sdk/tools/checklist.js +3 -2
- package/dist/sdk/tools/checkpoint.d.ts +27 -0
- package/dist/sdk/tools/checkpoint.js +154 -0
- package/dist/sdk/tools/getCapabilities.d.ts +31 -0
- package/dist/sdk/tools/getCapabilities.js +34 -0
- package/dist/sdk/tools/harnessTools.d.ts +2 -0
- package/dist/sdk/tools/harnessTools.js +1 -1
- package/dist/sdk/tools/spawnSubagent.js +14 -4
- package/dist/sdk/usage/analytics.d.ts +20 -0
- package/dist/sdk/usage/analytics.js +151 -0
- package/dist/sdk/usage/ledger.d.ts +38 -0
- package/dist/sdk/usage/ledger.js +142 -0
- package/dist/sdk/usage/limits/adapters.d.ts +11 -0
- package/dist/sdk/usage/limits/adapters.js +349 -0
- package/dist/sdk/usage/limits/capture.d.ts +8 -0
- package/dist/sdk/usage/limits/capture.js +47 -0
- package/dist/sdk/usage/limits/http.d.ts +12 -0
- package/dist/sdk/usage/limits/http.js +51 -0
- package/dist/sdk/usage/limits/normalize.d.ts +15 -0
- package/dist/sdk/usage/limits/normalize.js +211 -0
- package/dist/sdk/usage/limits/service.d.ts +30 -0
- package/dist/sdk/usage/limits/service.js +176 -0
- package/dist/sdk/usage/limits/types.d.ts +65 -0
- package/dist/sdk/usage/limits/types.js +1 -0
- package/dist/sdk/usage/serverMethods.d.ts +3 -0
- package/dist/sdk/usage/serverMethods.js +22 -0
- package/dist/sdk/usage/service.d.ts +32 -0
- package/dist/sdk/usage/service.js +66 -0
- package/dist/sdk/usage/settings.d.ts +7 -0
- package/dist/sdk/usage/settings.js +28 -0
- package/dist/sdk/usage/types.d.ts +60 -0
- package/dist/sdk/usage/types.js +4 -0
- package/dist/sdk/web/part.d.ts +10 -0
- package/dist/sdk/web/part.js +6 -0
- package/dist/sdk/web/serverMethods.d.ts +3 -0
- package/dist/sdk/web/serverMethods.js +7 -0
- package/dist/sdk/wiki/serverMethods.d.ts +3 -0
- package/dist/sdk/wiki/serverMethods.js +26 -0
- package/dist/sdk/worktrees/cli.d.ts +11 -0
- package/dist/sdk/worktrees/cli.js +146 -0
- package/dist/sdk/worktrees/copy.d.ts +9 -0
- package/dist/sdk/worktrees/copy.js +111 -0
- package/dist/sdk/worktrees/git.d.ts +16 -0
- package/dist/sdk/worktrees/git.js +81 -0
- package/dist/sdk/worktrees/serverMethods.d.ts +3 -0
- package/dist/sdk/worktrees/serverMethods.js +30 -0
- package/dist/sdk/worktrees/service.d.ts +73 -0
- package/dist/sdk/worktrees/service.js +483 -0
- package/dist/sdk/worktrees/setup.d.ts +23 -0
- package/dist/sdk/worktrees/setup.js +65 -0
- package/dist/sdk/worktrees/types.d.ts +91 -0
- package/dist/sdk/worktrees/types.js +1 -0
- package/dist/sdk/world/cli.d.ts +2 -2
- package/dist/sdk/world/cli.js +6 -6
- package/dist/sdk/world/world.d.ts +3 -1
- package/dist/sdk/world/world.js +8 -9
- package/dist/terminal-opentui.js +16456 -5966
- package/dist/terminal-pi.js +1579 -573
- package/docs/README.md +22 -2
- package/docs/architecture/00-overview.md +28 -16
- package/docs/architecture/02-sessions-and-runs.md +184 -25
- package/docs/architecture/03-variants.md +10 -2
- package/docs/architecture/04-prompt.md +65 -7
- package/docs/architecture/06-plugins-and-capabilities.md +57 -4
- package/docs/architecture/07-tools-and-gate.md +112 -17
- package/docs/architecture/08-memory-and-history.md +4 -2
- package/docs/architecture/09-accounts-and-connectors.md +39 -1
- package/docs/architecture/10-server-protocol.md +168 -4
- package/docs/architecture/11-terminal.md +251 -8
- package/docs/architecture/12-storage.md +45 -3
- package/docs/architecture/13-world-tools.md +49 -6
- package/docs/architecture/14-surfaces-and-parity.md +136 -0
- package/docs/architecture/README.md +17 -4
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +4 -2
- package/docs/architecture/proposals/PROP-0013-resource-browser.md +58 -0
- package/docs/architecture/proposals/PROP-0014-fullscreen-browser-tabs.md +58 -0
- package/docs/architecture/proposals/PROP-0015-one-capability-surface.md +88 -0
- package/docs/architecture/proposals/PROP-0016-managed-worktrees.md +156 -0
- package/docs/architecture/proposals/PROP-0017-page-annotations.md +131 -0
- package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +179 -0
- package/docs/architecture/proposals/PROP-0019-contextual-side-questions.md +122 -0
- package/docs/architecture/proposals/PROP-0020-builtin-feature-plugins.md +105 -0
- package/docs/architecture/proposals/PROP-0021-command-namespaces-and-duplicates.md +99 -0
- package/docs/architecture/proposals/PROP-0022-plan-only-questions.md +102 -0
- package/docs/architecture/proposals/PROP-0023-xagent-cli-name.md +61 -0
- package/docs/architecture/proposals/PROP-0024-question-sketch-previews.md +130 -0
- package/docs/architecture/proposals/PROP-0025-contextual-question-wireframes.md +49 -0
- package/docs/architecture/proposals/PROP-0026-connected-sketch-display.md +94 -0
- package/docs/architecture/proposals/PROP-0027-xingular-agent-product-identity.md +60 -0
- package/docs/architecture/proposals/PROP-0028-normalize-question-wireframes.md +55 -0
- package/docs/architecture/proposals/PROP-0029-agent-profiles.md +124 -0
- package/docs/architecture/proposals/PROP-0030-subagent-title.md +86 -0
- package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
- package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
- package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
- package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
- package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
- package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
- package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
- package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
- package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
- package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +247 -0
- package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
- package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
- package/docs/architecture/proposals/README.md +39 -0
- package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
- package/docs/decisions/ADR-0009-xharness-command.md +6 -5
- package/docs/decisions/ADR-0014-public-release-baseline.md +3 -2
- package/docs/decisions/ADR-0015-resource-browser.md +28 -0
- package/docs/decisions/ADR-0016-fullscreen-browser-tabs.md +31 -0
- package/docs/decisions/ADR-0017-one-capability-surface.md +34 -0
- package/docs/decisions/ADR-0018-builtin-feature-plugins.md +35 -0
- package/docs/decisions/ADR-0019-managed-git-worktrees.md +31 -0
- package/docs/decisions/ADR-0020-page-annotations.md +37 -0
- package/docs/decisions/ADR-0021-required-command-namespaces.md +40 -0
- package/docs/decisions/ADR-0022-plan-only-question-tools.md +34 -0
- package/docs/decisions/ADR-0023-contextual-side-question-runs.md +35 -0
- package/docs/decisions/ADR-0024-xagent-command.md +40 -0
- package/docs/decisions/ADR-0025-question-choice-sketches.md +49 -0
- package/docs/decisions/ADR-0026-contextual-question-wireframes.md +58 -0
- package/docs/decisions/ADR-0027-connected-sketch-display.md +60 -0
- package/docs/decisions/ADR-0028-xingular-agent-product-identity.md +56 -0
- package/docs/decisions/ADR-0029-normalized-question-wireframe-borders.md +33 -0
- package/docs/decisions/ADR-0030-agent-profiles.md +43 -0
- package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
- package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
- package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
- package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
- package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
- package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
- package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
- package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
- package/docs/doctor.md +10 -4
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
- package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
- package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
- package/docs/features/README.md +26 -0
- package/docs/features/interfaces/README.md +1 -1
- package/docs/future-work.md +48 -0
- package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
- package/docs/parity.md +134 -0
- package/docs/releases/1.0.0.md +2 -2
- package/docs/releases/1.1.1.md +28 -0
- package/docs/releases/1.2.0.md +49 -0
- package/docs/releases/4.0.0.md +47 -0
- package/docs/releases/README.md +37 -27
- package/docs/study/00-index.md +8 -0
- package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
- package/docs/study/autonomous-engineering-sources.md +277 -0
- package/docs/study/autonomy-sources.md +147 -0
- package/docs/study/proactive-autonomy.md +408 -0
- package/docs/study/tui-resource-browser.md +78 -0
- package/docs/terminal-tui.md +386 -113
- package/package.json +6 -5
|
@@ -15,7 +15,7 @@ export function listTerminalTrajectoryRuns(root, sessionId, nativeSessionId) {
|
|
|
15
15
|
if (!nativeSessionId)
|
|
16
16
|
return [];
|
|
17
17
|
return listRuns(root, { sessionId })
|
|
18
|
-
.filter(run => run.nativeSessionId === nativeSessionId)
|
|
18
|
+
.filter(run => run.nativeSessionId === nativeSessionId || run.trigger === 'side-question' && run.sessionId === sessionId)
|
|
19
19
|
.map(summary);
|
|
20
20
|
}
|
|
21
21
|
/** Read a run only when it belongs to both this terminal and its current native conversation. */
|
|
@@ -23,7 +23,7 @@ export function readTerminalTrajectory(root, sessionId, nativeSessionId, runId,
|
|
|
23
23
|
if (!nativeSessionId || !Number.isSafeInteger(afterSequence ?? 0) || (afterSequence ?? 0) < 0)
|
|
24
24
|
throw notFound('Run');
|
|
25
25
|
const run = findRun(root, runId);
|
|
26
|
-
if (!run || run.sessionId !== sessionId || run.nativeSessionId !== nativeSessionId)
|
|
26
|
+
if (!run || run.sessionId !== sessionId || (run.nativeSessionId !== nativeSessionId && run.trigger !== 'side-question'))
|
|
27
27
|
throw notFound('Run');
|
|
28
28
|
const events = readEvents(root, runId).filter(event => afterSequence === undefined || event.sequence > afterSequence);
|
|
29
29
|
return { run: summary(run), events };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** `/annotate:annotate` accepts a page address, DevTools target, or page-bridge target. */
|
|
2
|
+
export function parseAnnotate(argument) {
|
|
3
|
+
const words = argument.trim().split(/\s+/).filter(Boolean);
|
|
4
|
+
if (!words.length)
|
|
5
|
+
return { kind: 'web' };
|
|
6
|
+
if (words[0] === '--app') {
|
|
7
|
+
const endpoint = words[1];
|
|
8
|
+
if (!endpoint)
|
|
9
|
+
return 'Give the app\'s DevTools address: /annotate:annotate --app http://127.0.0.1:9229';
|
|
10
|
+
const address = /^\d+$/.test(endpoint) ? `http://127.0.0.1:${endpoint}` : endpoint;
|
|
11
|
+
const name = words.slice(2).join(' ');
|
|
12
|
+
return { kind: 'cdp', endpoint: address, ...(name ? { name } : {}) };
|
|
13
|
+
}
|
|
14
|
+
if (words[0] === '--bridge') {
|
|
15
|
+
const name = words.slice(1).join(' ');
|
|
16
|
+
return { kind: 'bridge', ...(name ? { name } : {}) };
|
|
17
|
+
}
|
|
18
|
+
if (words.length > 1 || words[0].startsWith('--'))
|
|
19
|
+
return 'Use /annotate:annotate [url], /annotate:annotate --app <DevTools address>, or /annotate:annotate --bridge.';
|
|
20
|
+
const url = /^[a-z][a-z0-9+.-]*:\/\//i.test(words[0]) ? words[0] : /^(localhost|127\.0\.0\.1)(:\d+)?(\/|$)/.test(words[0]) ? `http://${words[0]}` : `https://${words[0]}`;
|
|
21
|
+
return { kind: 'web', url };
|
|
22
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { TerminalPage } from "./page.js";
|
|
2
2
|
import type { TerminalCommandHost } from "./commands.js";
|
|
3
|
-
|
|
3
|
+
import { type AnnotateStart } from "./pages/annotatePage.js";
|
|
4
|
+
export type CommandPageId = 'doctor' | 'accounts' | 'permissions' | 'plugins' | 'hub' | 'components' | 'settings' | 'trajectory' | 'log' | 'harness' | 'skills' | 'connections' | 'tools' | 'worktree' | 'notes' | 'annotate' | 'subagents' | 'agents' | 'usage';
|
|
4
5
|
/** Construct one independent full-screen page for a slash command. */
|
|
5
6
|
export declare function createCommandPage(host: TerminalCommandHost, id: CommandPageId, options?: {
|
|
6
7
|
runId?: string;
|
|
8
|
+
url?: string;
|
|
9
|
+
annotate?: AnnotateStart;
|
|
10
|
+
usageTab?: 'analysis' | 'limit';
|
|
11
|
+
usagePeriod?: 'today' | '7d' | '30d' | 'all';
|
|
12
|
+
close?(): void;
|
|
7
13
|
}): TerminalPage;
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import { DoctorPage } from "./pages/doctorPage.js";
|
|
2
2
|
import { AccountsPage } from "./pages/accountsPage.js";
|
|
3
|
-
import {
|
|
4
|
-
import { HubPage } from "./pages/hubPage.js";
|
|
3
|
+
import { BrowserPage } from "./pages/browserPage.js";
|
|
5
4
|
import { LogPage, formatRunEventLog } from "./pages/logPage.js";
|
|
6
5
|
import { PermissionsPage } from "./pages/permissionsPage.js";
|
|
7
|
-
import { PluginsPage } from "./pages/pluginsPage.js";
|
|
8
6
|
import { SettingsPage } from "./pages/settingsPage.js";
|
|
9
7
|
import { TrajectoryPage } from "./pages/trajectoryPage.js";
|
|
8
|
+
import { WorktreesPage } from "./pages/worktreesPage.js";
|
|
9
|
+
import { NotesPage } from "./pages/notesPage.js";
|
|
10
|
+
import { AnnotatePage } from "./pages/annotatePage.js";
|
|
11
|
+
import { SubagentsPage } from "./pages/subagentsPage.js";
|
|
12
|
+
import { AgentsPage } from "./pages/agentsPage.js";
|
|
13
|
+
import { UsagePage } from "./pages/usagePage.js";
|
|
10
14
|
import { createSettingsModel } from "./settingsModel.js";
|
|
11
15
|
/** Construct one independent full-screen page for a slash command. */
|
|
12
16
|
export function createCommandPage(host, id, options = {}) {
|
|
13
17
|
const theme = () => host.ui.theme;
|
|
14
18
|
const notify = (message, type) => host.ui.notify(message, type === 'error' || type === 'warning' ? type : 'info');
|
|
15
19
|
switch (id) {
|
|
20
|
+
case 'usage':
|
|
21
|
+
return new UsagePage({ theme, call: host.control, changed: host.changed, initialTab: options.usageTab === 'limit' ? 'limits' : 'analysis', ...(options.usagePeriod ? { initialPeriod: options.usagePeriod } : {}) });
|
|
16
22
|
case 'doctor':
|
|
17
23
|
return new DoctorPage({ theme, call: host.control, confirm: host.ui.confirm.bind(host.ui), select: host.ui.select.bind(host.ui), changed: host.changed,
|
|
18
24
|
selection: () => {
|
|
@@ -34,12 +40,50 @@ export function createCommandPage(host, id, options = {}) {
|
|
|
34
40
|
activeTools: () => host.session().getActiveToolNames(),
|
|
35
41
|
confirm: (title, message) => host.ui.confirm(title, message), notify, changed: host.changed
|
|
36
42
|
});
|
|
43
|
+
case 'harness':
|
|
44
|
+
case 'skills':
|
|
45
|
+
case 'connections':
|
|
46
|
+
case 'tools':
|
|
37
47
|
case 'plugins':
|
|
38
|
-
return new PluginsPage({ theme, call: host.control, ui: host.ui, changed: host.changed });
|
|
39
48
|
case 'hub':
|
|
40
|
-
return new HubPage({ theme, call: host.control, ui: host.ui, changed: host.changed });
|
|
41
49
|
case 'components':
|
|
42
|
-
return new
|
|
50
|
+
return new BrowserPage({
|
|
51
|
+
theme, call: host.control, changed: host.changed,
|
|
52
|
+
section: id === 'harness' || id === 'hub' ? 'overview' : id === 'components' ? 'library' : id,
|
|
53
|
+
source: id === 'hub' ? 'discover' : 'installed',
|
|
54
|
+
ui: {
|
|
55
|
+
select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui),
|
|
56
|
+
secretInput: (title, placeholder) => {
|
|
57
|
+
const ui = host.ui;
|
|
58
|
+
if (!ui.secretInput)
|
|
59
|
+
throw new Error('Masked credential entry is unavailable in this host.');
|
|
60
|
+
return ui.secretInput(title, placeholder);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
runtime: () => ({ skills: host.session().resourceLoader.getSkills().skills,
|
|
64
|
+
tools: host.session().getAllTools(), activeTools: host.session().getActiveToolNames(), skillCommands: host.session().settingsManager.getEnableSkillCommands() }),
|
|
65
|
+
permissions: () => host.runtime().permissions(), setGlobalTool: (tool, allowed) => host.runtime().setGlobalTool(tool, allowed),
|
|
66
|
+
useSkill: name => {
|
|
67
|
+
const draft = host.ui.getEditorText();
|
|
68
|
+
host.setEditorText(`$${name}${draft ? ' ' + draft : ' '}`);
|
|
69
|
+
options.close?.();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
case 'worktree':
|
|
73
|
+
return new WorktreesPage({
|
|
74
|
+
theme, call: host.control, changed: host.changed, relaunch: host.shutdown,
|
|
75
|
+
ui: { select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui) }
|
|
76
|
+
});
|
|
77
|
+
case 'notes':
|
|
78
|
+
return new NotesPage({
|
|
79
|
+
theme, call: host.control, changed: host.changed, ...(options.url !== undefined ? { start: options.url ? { url: options.url } : {} } : {}),
|
|
80
|
+
ui: { select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui) }
|
|
81
|
+
});
|
|
82
|
+
case 'annotate':
|
|
83
|
+
return new AnnotatePage({
|
|
84
|
+
theme, call: host.control, changed: host.changed, start: options.annotate ?? { kind: 'web' },
|
|
85
|
+
ui: { select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui) }
|
|
86
|
+
});
|
|
43
87
|
case 'settings':
|
|
44
88
|
return new SettingsPage({ theme, ...createSettingsModel(host), notify, changed: host.changed });
|
|
45
89
|
case 'trajectory':
|
|
@@ -47,6 +91,13 @@ export function createCommandPage(host, id, options = {}) {
|
|
|
47
91
|
theme, runs: host.trajectory.list, read: host.trajectory.read, copy: host.copyText,
|
|
48
92
|
initialRunId: options.runId || undefined, notify, changed: host.changed
|
|
49
93
|
});
|
|
94
|
+
case 'subagents':
|
|
95
|
+
return new SubagentsPage({ theme, snapshot: host.subagents, changed: host.changed });
|
|
96
|
+
case 'agents':
|
|
97
|
+
return new AgentsPage({
|
|
98
|
+
theme, call: host.control, changed: host.changed, ...(host.editFile ? { edit: host.editFile.bind(host) } : {}),
|
|
99
|
+
ui: { select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui) }
|
|
100
|
+
});
|
|
50
101
|
case 'log':
|
|
51
102
|
return new LogPage({
|
|
52
103
|
theme, changed: host.changed,
|
|
@@ -2,6 +2,10 @@ import { type AgentSession, type ExtensionUIContext } from '@earendil-works/pi-c
|
|
|
2
2
|
import { type SkillEntry } from "./skillInvocation.js";
|
|
3
3
|
import type { TerminalRuntime } from "./runtime.js";
|
|
4
4
|
import type { TerminalTrajectoryRun, TerminalTrajectorySnapshot } from "../trajectory.js";
|
|
5
|
+
import type { TerminalSubagentActivity } from "../subagentMonitor.js";
|
|
6
|
+
import { type TerminalCommandCompletion, type TerminalCommandHelpGroup } from "../commandHelp.js";
|
|
7
|
+
export type { TerminalCommandCompletion } from "../commandHelp.js";
|
|
8
|
+
export { parseAnnotate } from "./pluginCommands.js";
|
|
5
9
|
export interface TerminalCommandHost {
|
|
6
10
|
session(): AgentSession;
|
|
7
11
|
/** Navigation is scope checked by the Harness runtime adapter. */
|
|
@@ -11,9 +15,11 @@ export interface TerminalCommandHost {
|
|
|
11
15
|
control: <T = unknown>(method: string, params?: Record<string, unknown>) => Promise<T>;
|
|
12
16
|
ui: ExtensionUIContext;
|
|
13
17
|
cwd(): string;
|
|
18
|
+
branch(): string | null;
|
|
14
19
|
sessionDirectory(): string;
|
|
15
20
|
refresh(): void;
|
|
16
21
|
changed(): void;
|
|
22
|
+
showHelp(groups: TerminalCommandHelpGroup[]): void;
|
|
17
23
|
plan(brief: string): void;
|
|
18
24
|
/** Asks a side question in its own tool-free session; empty text dismisses the one showing. */
|
|
19
25
|
btw(question: string): Promise<void>;
|
|
@@ -21,22 +27,22 @@ export interface TerminalCommandHost {
|
|
|
21
27
|
setEditorText(text: string): void;
|
|
22
28
|
copyText(text: string): Promise<void>;
|
|
23
29
|
suspend?(): Promise<void>;
|
|
30
|
+
/** Opens a file in the person's editor and resolves once the editor closes. */
|
|
31
|
+
editFile?(path: string): Promise<void>;
|
|
24
32
|
hotkeys?(): string;
|
|
25
33
|
logs: {
|
|
26
34
|
read(): Promise<string>;
|
|
27
35
|
};
|
|
36
|
+
subagents(): readonly TerminalSubagentActivity[];
|
|
28
37
|
trajectory: {
|
|
29
38
|
list(): Promise<TerminalTrajectoryRun[]>;
|
|
30
39
|
read(runId: string, afterSequence?: number): Promise<TerminalTrajectorySnapshot>;
|
|
31
40
|
};
|
|
32
41
|
}
|
|
33
|
-
export interface TerminalCommandCompletion {
|
|
34
|
-
name: string;
|
|
35
|
-
description?: string;
|
|
36
|
-
}
|
|
37
42
|
export declare function createTerminalCommands(host: TerminalCommandHost): {
|
|
38
43
|
execute: (text: string) => Promise<boolean>;
|
|
39
44
|
completions: () => TerminalCommandCompletion[];
|
|
40
45
|
skills: () => SkillEntry[];
|
|
41
46
|
expandSkill: (text: string) => string;
|
|
47
|
+
legacyAliases: () => string[];
|
|
42
48
|
};
|
|
@@ -1,41 +1,34 @@
|
|
|
1
1
|
import { isAbsolute, relative, resolve } from 'node:path';
|
|
2
2
|
import { SessionManager } from '@earendil-works/pi-coding-agent';
|
|
3
|
+
import { CORE_COMMANDS, coreCommand } from "../../commands/registry.js";
|
|
4
|
+
import { commandRoutes, promptCommandAvailable } from "../../commands/routes.js";
|
|
5
|
+
import { BUILTIN_PLUGIN_REGISTRY } from "../../plugins/builtin.js";
|
|
6
|
+
import { pluginCommandPrefix } from "../../plugins/commandPrefix.js";
|
|
3
7
|
import { PageOverlay } from "./pageOverlay.js";
|
|
4
8
|
import { ModelPicker } from "./modelPicker.js";
|
|
5
9
|
import { TreePicker } from "./treePicker.js";
|
|
6
10
|
import { createCommandPage } from "./commandPages.js";
|
|
7
11
|
import { pageOverlayOptions } from "./dialogGeometry.js";
|
|
12
|
+
import { ResumeSessionsPage } from "./sessionPicker.js";
|
|
8
13
|
import { expandSkillInvocation } from "./skillInvocation.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{ name: 'reload', description: 'Reload trusted resources and keybindings' },
|
|
28
|
-
{ name: 'accounts', description: 'Sign in, switch, check and remove Pi accounts' },
|
|
29
|
-
{ name: 'permissions', description: 'Full Permission and per-tool approvals' },
|
|
30
|
-
{ name: 'plugins', description: 'Switch plugins on or off and trust their code' },
|
|
31
|
-
{ name: 'hub', description: 'Browse and install reviewed skills, plugins and documents' },
|
|
32
|
-
{ name: 'components', description: 'Browse skills, prompts and rules for this Harness scope' },
|
|
33
|
-
{ name: 'settings', description: 'Session and terminal settings' },
|
|
34
|
-
{ name: 'trajectory', description: 'Inspect the recorded runs of this session' },
|
|
35
|
-
{ name: 'log', description: "Harness diagnostics and this conversation's run events" },
|
|
36
|
-
{ name: 'hotkeys', description: 'Keyboard controls' },
|
|
37
|
-
{ name: 'quit', description: 'Restore the terminal and exit' }
|
|
38
|
-
];
|
|
14
|
+
import { groupTerminalCommands } from "../commandHelp.js";
|
|
15
|
+
import { createBuiltinPluginCommandHandlers } from "./pluginCommands.js";
|
|
16
|
+
export { parseAnnotate } from "./pluginCommands.js";
|
|
17
|
+
const BUILTINS = CORE_COMMANDS.map((command) => ({
|
|
18
|
+
name: command.name,
|
|
19
|
+
...('aliases' in command ? { aliases: [...command.aliases] } : {}),
|
|
20
|
+
description: command.description,
|
|
21
|
+
group: command.group
|
|
22
|
+
}));
|
|
23
|
+
const COMMAND_ALIASES = new Map(BUILTINS.flatMap(command => (command.aliases ?? []).map(alias => [alias, command.name])));
|
|
24
|
+
const CORE_PROMPT_NAMES = new Set([...BUILTINS.map(command => command.name), ...COMMAND_ALIASES.keys()]);
|
|
25
|
+
const LEGACY_BUILTIN_COMMAND_ALIASES = new Map([
|
|
26
|
+
['doctor:doctor', 'doctor'], ['plugin:doctor', 'doctor'],
|
|
27
|
+
['worktrees:worktree', 'worktree'], ['plugin:worktree', 'worktree'],
|
|
28
|
+
['history:trajectory', 'trajectory'], ['plugin:trajectory', 'trajectory'],
|
|
29
|
+
['subagents:subagents', 'subagents'], ['plugin:subagents', 'subagents'],
|
|
30
|
+
['subagents:agents', 'agents'], ['plugin:agents', 'agents']
|
|
31
|
+
]);
|
|
39
32
|
export function createTerminalCommands(host) {
|
|
40
33
|
const notify = (text) => host.ui.notify(text, 'info');
|
|
41
34
|
const choose = async (title, items, label) => {
|
|
@@ -43,19 +36,6 @@ export function createTerminalCommands(host) {
|
|
|
43
36
|
const selected = await host.ui.select(title, labels);
|
|
44
37
|
return selected === undefined ? undefined : items[labels.indexOf(selected)];
|
|
45
38
|
};
|
|
46
|
-
const completions = () => {
|
|
47
|
-
const session = host.session();
|
|
48
|
-
const commands = new Map(BUILTINS.map(command => [command.name, command]));
|
|
49
|
-
for (const command of session.extensionRunner.getRegisteredCommands()) {
|
|
50
|
-
if (!commands.has(command.name))
|
|
51
|
-
commands.set(command.name, { name: command.name, description: command.description });
|
|
52
|
-
}
|
|
53
|
-
for (const prompt of session.resourceLoader.getPrompts().prompts) {
|
|
54
|
-
if (!commands.has(prompt.name))
|
|
55
|
-
commands.set(prompt.name, { name: prompt.name, description: prompt.description });
|
|
56
|
-
}
|
|
57
|
-
return [...commands.values()];
|
|
58
|
-
};
|
|
59
39
|
/** The skills this session may be asked to use, each invoked as `$name`. Off with the "Skill commands" setting. */
|
|
60
40
|
const skills = () => {
|
|
61
41
|
const session = host.session();
|
|
@@ -66,31 +46,223 @@ export function createTerminalCommands(host) {
|
|
|
66
46
|
/** The text to send: a leading `$name` of a loaded skill becomes the `/skill:name` form Pi expands. */
|
|
67
47
|
const expandSkill = (text) => expandSkillInvocation(text, new Set(skills().map((skill) => skill.name)));
|
|
68
48
|
async function openPage(id, options = {}) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
49
|
+
let close = () => { };
|
|
50
|
+
const page = createCommandPage(host, id, { ...options, close: () => close() });
|
|
51
|
+
await host.ui.custom((tui, _theme, _keys, done) => {
|
|
52
|
+
close = () => done(undefined);
|
|
53
|
+
return new PageOverlay({ page, tui, theme: () => host.ui.theme, close, changed: host.changed });
|
|
54
|
+
}, { overlay: true, overlayOptions: pageOverlayOptions(page.presentation) });
|
|
73
55
|
}
|
|
56
|
+
const pluginHandlers = createBuiltinPluginCommandHandlers(host, openPage);
|
|
57
|
+
const pluginCommands = BUILTIN_PLUGIN_REGISTRY.commands();
|
|
58
|
+
const builtinPrefixes = new Map(pluginCommands.map(command => [command.prefix, command.pluginId]));
|
|
59
|
+
const prefixCache = new WeakMap();
|
|
60
|
+
const extensionCommands = () => {
|
|
61
|
+
return commandRoutes(host.session().extensionRunner.getRegisteredCommands().map(command => {
|
|
62
|
+
const source = command.sourceInfo;
|
|
63
|
+
let prefix = prefixCache.get(source);
|
|
64
|
+
if (!prefix) {
|
|
65
|
+
prefix = pluginCommandPrefix(source);
|
|
66
|
+
prefixCache.set(source, prefix);
|
|
67
|
+
}
|
|
68
|
+
const owner = source.origin === 'package'
|
|
69
|
+
? `package:${source.baseDir ?? source.source}`
|
|
70
|
+
: `extension:${source.path}`;
|
|
71
|
+
return { ...command, prefix, owner, path: source.path };
|
|
72
|
+
}));
|
|
73
|
+
};
|
|
74
|
+
const coreCommandNames = (session) => new Set([
|
|
75
|
+
...BUILTINS.flatMap(command => [command.name, ...(command.aliases ?? [])]),
|
|
76
|
+
...session.resourceLoader.getPrompts().prompts.map(prompt => prompt.name)
|
|
77
|
+
]);
|
|
78
|
+
const runBuiltinPluginCommand = async (command, argument) => {
|
|
79
|
+
try {
|
|
80
|
+
const handler = pluginHandlers.get(`${command.pluginId}:${command.name}`);
|
|
81
|
+
if (!handler)
|
|
82
|
+
throw new Error(`No terminal handler for built-in plugin command ${command.pluginId}:${command.name}.`);
|
|
83
|
+
await handler(argument);
|
|
84
|
+
host.refresh();
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
host.ui.notify(error instanceof Error ? error.message : String(error), 'error');
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const runExtensionCommand = async (registered, argument, route) => {
|
|
91
|
+
try {
|
|
92
|
+
const command = host.session().extensionRunner.getCommand(registered.invocationName);
|
|
93
|
+
if (!command)
|
|
94
|
+
throw new Error(`Plugin command /${route} is no longer registered. Reload trusted resources.`);
|
|
95
|
+
await command.handler(argument, host.session().extensionRunner.createCommandContext());
|
|
96
|
+
host.refresh();
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
host.ui.notify(error instanceof Error ? error.message : String(error), 'error');
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const runLegacyPluginCommand = async (name, argument) => {
|
|
103
|
+
const session = host.session();
|
|
104
|
+
if (coreCommandNames(session).has(name)) {
|
|
105
|
+
host.ui.notify(`Use /${name}; /plugin:${name} is unavailable because a core command or prompt already uses that name.`, 'error');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const builtins = BUILTIN_PLUGIN_REGISTRY.commandsNamed(name);
|
|
109
|
+
const extensions = extensionCommands();
|
|
110
|
+
if (builtins.length > 1) {
|
|
111
|
+
host.ui.notify(`Legacy plugin command /plugin:${name} is ambiguous. Use its owner-qualified command.`, 'error');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (builtins.length === 1) {
|
|
115
|
+
const competitors = extensions.byName.get(name) ?? [];
|
|
116
|
+
if (competitors.length) {
|
|
117
|
+
host.ui.notify(`Extension command /plugin:${name} from ${competitors.map(command => command.sourceInfo.path).join(', ')} is unavailable because the name belongs to the built-in ${builtins[0].pluginId} plugin.`, 'error');
|
|
118
|
+
}
|
|
119
|
+
await runBuiltinPluginCommand(builtins[0], argument);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const matches = extensions.byName.get(name) ?? [];
|
|
123
|
+
if (matches.length > 1) {
|
|
124
|
+
host.ui.notify(`Legacy plugin command /plugin:${name} is ambiguous. Registered by: ${matches.map(command => command.sourceInfo.path).join(', ')}. Use its owner-qualified command.`, 'error');
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (matches.length === 1) {
|
|
128
|
+
if (extensions.conflictingPrefixes.has(matches[0].prefix)) {
|
|
129
|
+
host.ui.notify(`Plugin prefix /${matches[0].prefix}: is ambiguous or reserved. Owners: ${extensions.conflictingPrefixes.get(matches[0].prefix).join(', ')}.`, 'error');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
await runExtensionCommand(matches[0], argument, `plugin:${name}`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
host.ui.notify(`Unknown plugin command: /plugin:${name}. Use /help to list the commands.`, 'error');
|
|
136
|
+
};
|
|
137
|
+
const runNamespacedCommand = async (typedName, argument) => {
|
|
138
|
+
const separator = typedName.indexOf(':');
|
|
139
|
+
if (separator < 1)
|
|
140
|
+
return false;
|
|
141
|
+
const prefix = typedName.slice(0, separator);
|
|
142
|
+
const name = typedName.slice(separator + 1);
|
|
143
|
+
if (prefix === 'plugin') {
|
|
144
|
+
await runLegacyPluginCommand(name, argument);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
const builtin = name ? BUILTIN_PLUGIN_REGISTRY.command(prefix, name) : BUILTIN_PLUGIN_REGISTRY.defaultCommand(prefix);
|
|
148
|
+
const extensions = extensionCommands();
|
|
149
|
+
const isBuiltinPrefix = builtinPrefixes.has(prefix);
|
|
150
|
+
const isExtensionPrefix = extensions.ownersByPrefix.has(prefix);
|
|
151
|
+
if (!builtin && !isBuiltinPrefix && !isExtensionPrefix)
|
|
152
|
+
return false;
|
|
153
|
+
if (builtin) {
|
|
154
|
+
const competitors = extensions.routes.get(`${prefix}:${builtin.name}`) ?? [];
|
|
155
|
+
if (competitors.length) {
|
|
156
|
+
host.ui.notify(`Extension command /${prefix}:${builtin.name} from ${competitors.map(command => command.sourceInfo.path).join(', ')} is unavailable because the prefix belongs to built-in ${builtin.pluginId}.`, 'error');
|
|
157
|
+
}
|
|
158
|
+
await runBuiltinPluginCommand(builtin, argument);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
if (extensions.conflictingPrefixes.has(prefix)) {
|
|
162
|
+
host.ui.notify(`Plugin prefix /${prefix}: is ambiguous or reserved. Owners: ${extensions.conflictingPrefixes.get(prefix).join(', ')}.`, 'error');
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
if (!name) {
|
|
166
|
+
host.ui.notify(`Plugin /${prefix}: has no default command. Use /help to list its commands.`, 'error');
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
const matches = extensions.routes.get(`${prefix}:${name}`) ?? [];
|
|
170
|
+
if (matches.length > 1) {
|
|
171
|
+
host.ui.notify(`Plugin command /${prefix}:${name} is ambiguous. Registered by: ${matches.map(command => command.sourceInfo.path).join(', ')}.`, 'error');
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
if (matches.length === 1) {
|
|
175
|
+
await runExtensionCommand(matches[0], argument, `${prefix}:${name}`);
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
host.ui.notify(`Unknown plugin command: /${typedName}. Use /help to list the commands.`, 'error');
|
|
179
|
+
return true;
|
|
180
|
+
};
|
|
181
|
+
const legacyAliases = () => {
|
|
182
|
+
const session = host.session();
|
|
183
|
+
const coreNames = coreCommandNames(session);
|
|
184
|
+
const aliases = new Set(LEGACY_BUILTIN_COMMAND_ALIASES.keys());
|
|
185
|
+
for (const command of pluginCommands) {
|
|
186
|
+
if (coreNames.has(command.name))
|
|
187
|
+
continue;
|
|
188
|
+
aliases.add(`plugin:${command.name}`);
|
|
189
|
+
if (command.legacyBare)
|
|
190
|
+
aliases.add(command.name);
|
|
191
|
+
}
|
|
192
|
+
for (const name of extensionCommands().byName.keys()) {
|
|
193
|
+
if (!coreNames.has(name))
|
|
194
|
+
aliases.add(`plugin:${name}`);
|
|
195
|
+
}
|
|
196
|
+
return [...aliases];
|
|
197
|
+
};
|
|
198
|
+
const completions = () => {
|
|
199
|
+
const session = host.session();
|
|
200
|
+
const prompts = session.resourceLoader.getPrompts().prompts;
|
|
201
|
+
const commands = new Map(BUILTINS.map(command => [command.name, command]));
|
|
202
|
+
for (const command of pluginCommands) {
|
|
203
|
+
const invocation = `${command.prefix}:${command.name}`;
|
|
204
|
+
commands.set(invocation, { name: invocation, description: command.description, group: 'Plugins' });
|
|
205
|
+
}
|
|
206
|
+
for (const module of BUILTIN_PLUGIN_REGISTRY.modules) {
|
|
207
|
+
const defaultCommand = module.defaultCommand && BUILTIN_PLUGIN_REGISTRY.command(module.commandPrefix ?? module.descriptor.id, module.defaultCommand);
|
|
208
|
+
if (defaultCommand) {
|
|
209
|
+
const invocation = `${defaultCommand.prefix}:`;
|
|
210
|
+
commands.set(invocation, { name: invocation, description: defaultCommand.description, group: 'Plugins' });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const extensions = extensionCommands();
|
|
214
|
+
for (const [route, matches] of extensions.routes) {
|
|
215
|
+
const prefix = route.slice(0, route.indexOf(':'));
|
|
216
|
+
if (matches.length !== 1 || extensions.conflictingPrefixes.has(prefix))
|
|
217
|
+
continue;
|
|
218
|
+
if (BUILTIN_PLUGIN_REGISTRY.command(prefix, matches[0].name))
|
|
219
|
+
continue;
|
|
220
|
+
commands.set(route, { name: route, description: matches[0].description, group: 'Plugins' });
|
|
221
|
+
}
|
|
222
|
+
const extensionNames = new Set(extensions.byName.keys());
|
|
223
|
+
for (const prompt of prompts) {
|
|
224
|
+
if (promptCommandAvailable(prompt.name, new Set([...commands.keys(), ...COMMAND_ALIASES.keys()]), extensionNames))
|
|
225
|
+
commands.set(prompt.name, { name: prompt.name, description: prompt.description, group: 'Prompts' });
|
|
226
|
+
}
|
|
227
|
+
return [...commands.values()];
|
|
228
|
+
};
|
|
74
229
|
async function execute(text) {
|
|
75
230
|
const match = /^\/([^\s]+)(?:\s+([\s\S]*))?$/.exec(text.trim());
|
|
76
231
|
if (!match)
|
|
77
232
|
return false;
|
|
78
|
-
const
|
|
233
|
+
const typedName = match[1];
|
|
79
234
|
const argument = match[2]?.trim() ?? '';
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
235
|
+
const legacyBuiltin = LEGACY_BUILTIN_COMMAND_ALIASES.get(typedName);
|
|
236
|
+
if (!legacyBuiltin && await runNamespacedCommand(typedName, argument))
|
|
237
|
+
return true;
|
|
238
|
+
const session = host.session();
|
|
239
|
+
const name = coreCommand(legacyBuiltin ?? typedName)?.name ?? legacyBuiltin ?? typedName;
|
|
240
|
+
const builtin = BUILTINS.find(item => item.name === name);
|
|
241
|
+
if (!builtin && !coreCommandNames(session).has(name)) {
|
|
242
|
+
const legacyBare = BUILTIN_PLUGIN_REGISTRY.commandsNamed(name).filter(command => command.legacyBare);
|
|
243
|
+
if (legacyBare.length > 1) {
|
|
244
|
+
host.ui.notify(`Legacy command /${name} is ambiguous. Use its owner-qualified command.`, 'error');
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
if (legacyBare.length === 1) {
|
|
248
|
+
await runBuiltinPluginCommand(legacyBare[0], argument);
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (!builtin) {
|
|
83
253
|
// A skill is offered as $name; the typed /skill:name form still reaches the SDK, which expands it.
|
|
84
254
|
if (skills().some(skill => `skill:${skill.name}` === name))
|
|
85
255
|
return false;
|
|
256
|
+
const prompt = session.resourceLoader.getPrompts().prompts.some(item => item.name === name);
|
|
257
|
+
if (prompt && promptCommandAvailable(name, CORE_PROMPT_NAMES, new Set(extensionCommands().byName.keys())))
|
|
258
|
+
return false;
|
|
86
259
|
host.ui.notify(`Unknown command: /${name}. Use /help to list commands.`, 'error');
|
|
87
260
|
return true;
|
|
88
261
|
}
|
|
89
262
|
try {
|
|
90
|
-
const session = host.session();
|
|
91
263
|
switch (name) {
|
|
92
264
|
case 'help':
|
|
93
|
-
|
|
265
|
+
host.showHelp(groupTerminalCommands(completions()));
|
|
94
266
|
break;
|
|
95
267
|
case 'plan': {
|
|
96
268
|
if (!argument || ['on', 'off', 'toggle'].includes(argument.toLowerCase()))
|
|
@@ -105,7 +277,7 @@ export function createTerminalCommands(host) {
|
|
|
105
277
|
await host.btw(argument);
|
|
106
278
|
break;
|
|
107
279
|
case 'stop': {
|
|
108
|
-
if (
|
|
280
|
+
if (session.isIdle)
|
|
109
281
|
throw new Error('Nothing is running.');
|
|
110
282
|
await host.runtime().interrupt();
|
|
111
283
|
break;
|
|
@@ -113,14 +285,24 @@ export function createTerminalCommands(host) {
|
|
|
113
285
|
case 'new':
|
|
114
286
|
await host.runtime().newSession();
|
|
115
287
|
break;
|
|
116
|
-
case '
|
|
288
|
+
case 'session': {
|
|
117
289
|
let path = argument;
|
|
118
290
|
if (!path) {
|
|
119
|
-
const
|
|
120
|
-
|
|
291
|
+
const selected = await host.ui.custom((tui, _theme, _keys, done) => {
|
|
292
|
+
const page = new ResumeSessionsPage({
|
|
293
|
+
theme: () => host.ui.theme,
|
|
294
|
+
cwd: () => host.cwd(),
|
|
295
|
+
branch: () => host.branch(),
|
|
296
|
+
listSessions: signal => SessionManager.list(host.cwd(), host.sessionDirectory(), undefined, signal),
|
|
297
|
+
select: done,
|
|
298
|
+
cancel: () => done(undefined),
|
|
299
|
+
changed: host.changed
|
|
300
|
+
});
|
|
301
|
+
return new PageOverlay({ page, tui, theme: () => host.ui.theme, close: () => done(undefined), changed: host.changed });
|
|
302
|
+
}, { overlay: true, overlayOptions: pageOverlayOptions('fullscreen') });
|
|
121
303
|
if (!selected)
|
|
122
304
|
break;
|
|
123
|
-
path = selected
|
|
305
|
+
path = selected;
|
|
124
306
|
}
|
|
125
307
|
const target = resolve(host.cwd(), path);
|
|
126
308
|
const within = relative(host.sessionDirectory(), target);
|
|
@@ -150,7 +332,7 @@ export function createTerminalCommands(host) {
|
|
|
150
332
|
}
|
|
151
333
|
break;
|
|
152
334
|
}
|
|
153
|
-
case '
|
|
335
|
+
case 'history': {
|
|
154
336
|
const tree = session.sessionManager.getTree();
|
|
155
337
|
if (!tree.length)
|
|
156
338
|
throw new Error('No entries in this session');
|
|
@@ -205,11 +387,23 @@ export function createTerminalCommands(host) {
|
|
|
205
387
|
await session.setModel(selected.model, { persist: selected.persist });
|
|
206
388
|
break;
|
|
207
389
|
}
|
|
390
|
+
case 'settings':
|
|
391
|
+
await openPage('settings');
|
|
392
|
+
break;
|
|
208
393
|
case 'doctor':
|
|
209
394
|
await openPage('doctor');
|
|
210
395
|
break;
|
|
211
|
-
case '
|
|
212
|
-
await openPage('
|
|
396
|
+
case 'worktree':
|
|
397
|
+
await openPage('worktree');
|
|
398
|
+
break;
|
|
399
|
+
case 'trajectory':
|
|
400
|
+
await openPage('trajectory', { runId: argument });
|
|
401
|
+
break;
|
|
402
|
+
case 'subagents':
|
|
403
|
+
await openPage('subagents');
|
|
404
|
+
break;
|
|
405
|
+
case 'agents':
|
|
406
|
+
await openPage('agents');
|
|
213
407
|
break;
|
|
214
408
|
case 'permissions':
|
|
215
409
|
await openPage('permissions');
|
|
@@ -217,6 +411,19 @@ export function createTerminalCommands(host) {
|
|
|
217
411
|
case 'accounts':
|
|
218
412
|
await openPage('accounts');
|
|
219
413
|
break;
|
|
414
|
+
case 'harness':
|
|
415
|
+
await openPage('harness');
|
|
416
|
+
break;
|
|
417
|
+
case 'skills':
|
|
418
|
+
await openPage('skills');
|
|
419
|
+
break;
|
|
420
|
+
case 'connections':
|
|
421
|
+
case 'mcp':
|
|
422
|
+
await openPage('connections');
|
|
423
|
+
break;
|
|
424
|
+
case 'tools':
|
|
425
|
+
await openPage('tools');
|
|
426
|
+
break;
|
|
220
427
|
case 'plugins':
|
|
221
428
|
await openPage('plugins');
|
|
222
429
|
break;
|
|
@@ -232,9 +439,6 @@ export function createTerminalCommands(host) {
|
|
|
232
439
|
session.setSessionName(name);
|
|
233
440
|
break;
|
|
234
441
|
}
|
|
235
|
-
case 'trajectory':
|
|
236
|
-
await openPage('trajectory', { runId: argument });
|
|
237
|
-
break;
|
|
238
442
|
case 'log':
|
|
239
443
|
await openPage('log');
|
|
240
444
|
break;
|
|
@@ -272,5 +476,5 @@ export function createTerminalCommands(host) {
|
|
|
272
476
|
}
|
|
273
477
|
return true;
|
|
274
478
|
}
|
|
275
|
-
return { execute, completions, skills, expandSkill };
|
|
479
|
+
return { execute, completions, skills, expandSkill, legacyAliases };
|
|
276
480
|
}
|
|
@@ -23,5 +23,5 @@ export declare function centeredDialogHost(tui: TUI): boolean;
|
|
|
23
23
|
export declare function pageRows(tui: TUI): number;
|
|
24
24
|
/** Centers a rectangle on the screen, clamped so it never starts outside the terminal. */
|
|
25
25
|
export declare function centeredRect(columns: number, rows: number, width: number, height: number): DialogRect;
|
|
26
|
-
/**
|
|
27
|
-
export declare function pageOverlayOptions(): HarnessOverlayOptions;
|
|
26
|
+
/** Page commands declare their presentation; OpenTUI centers only marked dialogs. */
|
|
27
|
+
export declare function pageOverlayOptions(presentation?: 'centered' | 'fullscreen'): HarnessOverlayOptions;
|