@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
|
@@ -44,7 +44,9 @@ export function centeredRect(columns, rows, width, height) {
|
|
|
44
44
|
height: boxHeight
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
-
/**
|
|
48
|
-
export function pageOverlayOptions() {
|
|
47
|
+
/** Page commands declare their presentation; OpenTUI centers only marked dialogs. */
|
|
48
|
+
export function pageOverlayOptions(presentation = 'centered') {
|
|
49
|
+
if (presentation === 'fullscreen')
|
|
50
|
+
return { anchor: 'top-left', width: '100%', maxHeight: '100%' };
|
|
49
51
|
return { anchor: 'top-left', width: '100%', maxHeight: '100%', dialog: 'page' };
|
|
50
52
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { ExtensionUIContext, ExtensionUIDialogOptions, KeybindingsManager, Theme } from '@earendil-works/pi-coding-agent';
|
|
2
2
|
import { Input, type Component, type Focusable, type SelectListTheme, type TUI, type TuiMouseEventResult } from '@earendil-works/pi-tui';
|
|
3
3
|
import type { TerminalMouseInput } from "./mouse.js";
|
|
4
|
+
export interface GroupedSelectOption {
|
|
5
|
+
label: string;
|
|
6
|
+
group?: string;
|
|
7
|
+
}
|
|
4
8
|
/** `page` asks for a full-screen dialog; Pi's own dialogs ignore the field. */
|
|
5
9
|
export type TerminalDialogOptions = ExtensionUIDialogOptions & {
|
|
6
10
|
page?: boolean;
|
|
@@ -19,7 +23,7 @@ export declare class SearchableSelect implements Component, Focusable {
|
|
|
19
23
|
private readonly list;
|
|
20
24
|
private readonly labels;
|
|
21
25
|
private focusedValue;
|
|
22
|
-
constructor(options: string[], tui: TUI, theme: () => Theme, select: (index: number) => void, cancel: () => void, search?: 'always' | 'never');
|
|
26
|
+
constructor(options: string[], tui: TUI, theme: () => Theme, select: (index: number) => void, cancel: () => void, search?: 'always' | 'never', groups?: readonly (string | undefined)[]);
|
|
23
27
|
get focused(): boolean;
|
|
24
28
|
set focused(value: boolean);
|
|
25
29
|
get pinnedRows(): number;
|
|
@@ -66,6 +70,7 @@ export declare class TerminalDialogs {
|
|
|
66
70
|
constructor(tui: TUI, theme: () => Theme, keybindings: KeybindingsManager, changed: () => void);
|
|
67
71
|
private show;
|
|
68
72
|
select(title: string, options: string[], opts?: TerminalDialogOptions): Promise<string | undefined>;
|
|
73
|
+
selectGrouped(title: string, options: readonly GroupedSelectOption[], opts?: ExtensionUIDialogOptions): Promise<string | undefined>;
|
|
69
74
|
confirm(title: string, message: string, opts?: ExtensionUIDialogOptions): Promise<boolean>;
|
|
70
75
|
input(title: string, placeholder?: string, opts?: ExtensionUIDialogOptions, secret?: boolean): Promise<string | undefined>;
|
|
71
76
|
editor(title: string, prefill?: string): Promise<string | undefined>;
|
|
@@ -31,14 +31,14 @@ export class SearchableSelect {
|
|
|
31
31
|
list;
|
|
32
32
|
labels;
|
|
33
33
|
focusedValue = false;
|
|
34
|
-
constructor(options, tui, theme, select, cancel, search = 'always') {
|
|
34
|
+
constructor(options, tui, theme, select, cancel, search = 'always', groups) {
|
|
35
35
|
this.tui = tui;
|
|
36
36
|
this.select = select;
|
|
37
37
|
this.cancel = cancel;
|
|
38
38
|
this.labels = options.map(safe);
|
|
39
39
|
this.list = new FilterList({
|
|
40
40
|
theme, search,
|
|
41
|
-
rows: this.labels.map((label, index) => ({ id: String(index), label, data: index })),
|
|
41
|
+
rows: this.labels.map((label, index) => ({ id: String(index), label, ...(groups?.[index] ? { group: groups[index] } : {}), data: index })),
|
|
42
42
|
limit: () => this.windowRows(),
|
|
43
43
|
noun: ['option', 'options'],
|
|
44
44
|
onActivate: row => this.select(row.data ?? 0),
|
|
@@ -265,6 +265,13 @@ export class TerminalDialogs {
|
|
|
265
265
|
return new DialogPanel(title, list, this.theme, '↑/↓ select · Enter confirm · Esc cancel', undefined, opts?.page ? 'page' : 'block');
|
|
266
266
|
}, opts);
|
|
267
267
|
}
|
|
268
|
+
selectGrouped(title, options, opts) {
|
|
269
|
+
const labels = options.map(option => option.label);
|
|
270
|
+
return this.show(done => {
|
|
271
|
+
const list = new SearchableSelect(labels, this.tui, this.theme, index => done(labels[index]), () => done(undefined), 'always', options.map(option => option.group));
|
|
272
|
+
return new DialogPanel(title, list, this.theme, '↑/↓ select · Enter confirm · Esc cancel');
|
|
273
|
+
}, opts);
|
|
274
|
+
}
|
|
268
275
|
async confirm(title, message, opts) {
|
|
269
276
|
return (await this.show(done => {
|
|
270
277
|
const list = new SearchableSelect(['Yes', 'No'], this.tui, this.theme, index => done(index === 0), () => done(undefined), 'never');
|
|
@@ -2,11 +2,20 @@ import type { Theme } from '@earendil-works/pi-coding-agent';
|
|
|
2
2
|
import { type Component, type Focusable, type TuiMouseEventResult } from '@earendil-works/pi-tui';
|
|
3
3
|
import { type TerminalMouseInput } from "./mouse.js";
|
|
4
4
|
export type RowTone = 'success' | 'warning' | 'error' | 'muted' | 'dim' | 'accent';
|
|
5
|
+
export interface ListLabelPart {
|
|
6
|
+
text: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
tone?: RowTone;
|
|
9
|
+
}
|
|
5
10
|
export interface ListRow<T = unknown> {
|
|
6
11
|
id: string;
|
|
7
12
|
label: string;
|
|
13
|
+
/** Optional colored spans for the label; selected rows keep the shared high-contrast text. */
|
|
14
|
+
labelParts?: readonly ListLabelPart[];
|
|
8
15
|
/** Shown at the right edge, in `tone`. */
|
|
9
16
|
detail?: string;
|
|
17
|
+
/** An optional muted second line beneath the label. */
|
|
18
|
+
subtitle?: string;
|
|
10
19
|
tone?: RowTone;
|
|
11
20
|
/** Rows with the same consecutive group share a heading (not shown while searching). */
|
|
12
21
|
group?: string;
|
|
@@ -22,6 +31,8 @@ export interface FilterListOptions<T> {
|
|
|
22
31
|
search?: 'always' | 'never';
|
|
23
32
|
/** Rows the list may use; the search field is part of it. Defaults to what `render` is given. */
|
|
24
33
|
limit?: () => number;
|
|
34
|
+
/** Blank lines between visible rows. */
|
|
35
|
+
rowGap?: number;
|
|
25
36
|
empty?: string;
|
|
26
37
|
noun?: readonly [string, string];
|
|
27
38
|
/** Short context included in the search row while a query is active. */
|
|
@@ -59,6 +70,7 @@ export declare class FilterList<T = unknown> implements Component, Focusable {
|
|
|
59
70
|
handleMouse(event: TerminalMouseInput): TuiMouseEventResult | undefined;
|
|
60
71
|
invalidate(): void;
|
|
61
72
|
private limit;
|
|
73
|
+
private rowGap;
|
|
62
74
|
private mode;
|
|
63
75
|
private canSearch;
|
|
64
76
|
private searchVisible;
|
|
@@ -67,7 +79,8 @@ export declare class FilterList<T = unknown> implements Component, Focusable {
|
|
|
67
79
|
private move;
|
|
68
80
|
handleInput(data: string): boolean;
|
|
69
81
|
private entries;
|
|
70
|
-
private
|
|
82
|
+
private lines;
|
|
83
|
+
private labelParts;
|
|
71
84
|
/** `rows` is the most the list may use, the search row included. */
|
|
72
85
|
render(width: number, rows?: number): string[];
|
|
73
86
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { fuzzyFilter, matchesKey, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
|
|
1
|
+
import { fuzzyFilter, matchesKey, parseColor, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
|
|
2
2
|
import { safeText, selectedRow, selectionMuted, selectionText } from "./chrome.js";
|
|
3
3
|
import { SEARCH_FIELD_ROWS, SearchField, searchFieldRowsFor } from "./search.js";
|
|
4
4
|
import { isPrimaryClick } from "./mouse.js";
|
|
@@ -25,7 +25,10 @@ export class FilterList {
|
|
|
25
25
|
get total() { return this.rows.length; }
|
|
26
26
|
get shown() { return this.visible.length; }
|
|
27
27
|
/** Rows the list would use if nothing cut it: the search field, headings and rows. */
|
|
28
|
-
get height() {
|
|
28
|
+
get height() {
|
|
29
|
+
return (this.searchVisible() ? this.renderedSearchRows : 0)
|
|
30
|
+
+ this.entries().reduce((height, entry) => height + (entry.row?.subtitle === undefined ? 1 : 2), 0);
|
|
31
|
+
}
|
|
29
32
|
/** Rows at the top of `render` that a frame must keep when it has to cut the list. */
|
|
30
33
|
get pinnedRows() { return this.searchVisible() ? this.renderedSearchRows : 0; }
|
|
31
34
|
setRows(rows) {
|
|
@@ -61,6 +64,10 @@ export class FilterList {
|
|
|
61
64
|
}
|
|
62
65
|
invalidate() { this.search.invalidate(); }
|
|
63
66
|
limit() { return Math.max(1, Math.floor(this.options.limit?.() ?? Number.POSITIVE_INFINITY)); }
|
|
67
|
+
rowGap() {
|
|
68
|
+
const gap = this.options.rowGap ?? 0;
|
|
69
|
+
return Number.isFinite(gap) ? Math.max(0, Math.floor(gap)) : 0;
|
|
70
|
+
}
|
|
64
71
|
mode() { return this.options.search ?? 'always'; }
|
|
65
72
|
canSearch() { return this.mode() === 'always'; }
|
|
66
73
|
searchVisible() { return this.canSearch() || this.query.length > 0; }
|
|
@@ -68,7 +75,7 @@ export class FilterList {
|
|
|
68
75
|
refilter() {
|
|
69
76
|
const query = this.query.trim();
|
|
70
77
|
this.visible = query
|
|
71
|
-
? fuzzyFilter(this.rows, query, row => row.searchText ?? `${row.label} ${row.detail ?? ''} ${row.group ?? ''}`)
|
|
78
|
+
? fuzzyFilter(this.rows, query, row => row.searchText ?? `${row.label} ${row.subtitle ?? ''} ${row.detail ?? ''} ${row.group ?? ''}`)
|
|
72
79
|
: this.rows;
|
|
73
80
|
if (!this.visible.some(row => row.id === this.selectedId && !row.disabled))
|
|
74
81
|
this.selectedId = this.firstSelectable()?.id;
|
|
@@ -136,15 +143,20 @@ export class FilterList {
|
|
|
136
143
|
entries() {
|
|
137
144
|
const entries = [];
|
|
138
145
|
let last;
|
|
139
|
-
|
|
146
|
+
const gap = this.rowGap();
|
|
147
|
+
for (const [index, row] of this.visible.entries()) {
|
|
140
148
|
if (!this.query && row.group && row.group !== last)
|
|
141
149
|
entries.push({ heading: row.group });
|
|
142
150
|
last = row.group;
|
|
143
151
|
entries.push({ row });
|
|
152
|
+
if (index < this.visible.length - 1) {
|
|
153
|
+
for (let line = 0; line < gap; line += 1)
|
|
154
|
+
entries.push({ spacer: true });
|
|
155
|
+
}
|
|
144
156
|
}
|
|
145
157
|
return entries;
|
|
146
158
|
}
|
|
147
|
-
|
|
159
|
+
lines(row, width) {
|
|
148
160
|
const theme = this.options.theme();
|
|
149
161
|
const selected = row.id === this.selectedId;
|
|
150
162
|
const detail = row.detail ? safeText(row.detail) : '';
|
|
@@ -153,10 +165,40 @@ export class FilterList {
|
|
|
153
165
|
const label = truncateToWidth(safeText(row.label), Math.max(0, room - (showDetail ? visibleWidth(detail) + 2 : 0)), '…');
|
|
154
166
|
const gap = ' '.repeat(Math.max(0, room - visibleWidth(label) - (showDetail ? visibleWidth(detail) : 0)));
|
|
155
167
|
const tone = (text) => theme.fg(row.tone ?? 'muted', text);
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
168
|
+
const prefix = selected ? '❯ ' : ' ';
|
|
169
|
+
const labelText = selected || row.disabled || !row.labelParts?.length ? label : this.labelParts(row.labelParts, label, theme);
|
|
170
|
+
const main = prefix + label;
|
|
171
|
+
const primary = selected
|
|
172
|
+
? selectedRow(selectionText(theme, main) + gap + (showDetail ? selectionMuted(theme, detail) : ''), width, theme)
|
|
173
|
+
: (row.disabled ? theme.fg('dim', main) : prefix + labelText) + gap + (showDetail ? tone(detail) : '');
|
|
174
|
+
if (row.subtitle === undefined)
|
|
175
|
+
return [primary];
|
|
176
|
+
const subtitle = truncateToWidth(` ${safeText(row.subtitle)}`, width, '…');
|
|
177
|
+
const secondary = selected
|
|
178
|
+
? selectedRow(selectionMuted(theme, subtitle), width, theme)
|
|
179
|
+
: theme.fg(row.disabled ? 'dim' : 'muted', subtitle);
|
|
180
|
+
return [primary, secondary];
|
|
181
|
+
}
|
|
182
|
+
labelParts(parts, visibleLabel, theme) {
|
|
183
|
+
const source = parts.map(part => safeText(part.text)).join('');
|
|
184
|
+
const truncated = visibleWidth(source) > visibleWidth(visibleLabel);
|
|
185
|
+
let remaining = Math.max(0, visibleWidth(visibleLabel) - (truncated ? 1 : 0));
|
|
186
|
+
const output = [];
|
|
187
|
+
for (const part of parts) {
|
|
188
|
+
if (remaining <= 0)
|
|
189
|
+
break;
|
|
190
|
+
const text = safeText(part.text);
|
|
191
|
+
const fitted = truncateToWidth(text, remaining, '');
|
|
192
|
+
if (fitted) {
|
|
193
|
+
output.push(part.color ? theme.style(fitted, { fg: parseColor(part.color) }) : part.tone ? theme.fg(part.tone, fitted) : fitted);
|
|
194
|
+
}
|
|
195
|
+
remaining -= visibleWidth(fitted);
|
|
196
|
+
if (visibleWidth(fitted) < visibleWidth(text))
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
if (truncated)
|
|
200
|
+
output.push('…');
|
|
201
|
+
return output.join('');
|
|
160
202
|
}
|
|
161
203
|
/** `rows` is the most the list may use, the search row included. */
|
|
162
204
|
render(width, rows) {
|
|
@@ -186,11 +228,51 @@ export class FilterList {
|
|
|
186
228
|
return lines.map(line => truncateToWidth(line, width, ''));
|
|
187
229
|
}
|
|
188
230
|
const at = Math.max(0, entries.findIndex(entry => entry.row?.id === this.selectedId));
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
231
|
+
let start = at;
|
|
232
|
+
let end = at + 1;
|
|
233
|
+
let used = entries[at]?.row?.subtitle === undefined ? 1 : 2;
|
|
234
|
+
let preferBefore = true;
|
|
235
|
+
while (start > 0 || end < entries.length) {
|
|
236
|
+
const before = entries[start - 1];
|
|
237
|
+
const after = entries[end];
|
|
238
|
+
const beforeHeight = before ? (before.row?.subtitle === undefined ? 1 : 2) : Number.POSITIVE_INFINITY;
|
|
239
|
+
const afterHeight = after ? (after.row?.subtitle === undefined ? 1 : 2) : Number.POSITIVE_INFINITY;
|
|
240
|
+
if (preferBefore && before && used + beforeHeight <= budget) {
|
|
241
|
+
start -= 1;
|
|
242
|
+
used += beforeHeight;
|
|
243
|
+
}
|
|
244
|
+
else if (after && used + afterHeight <= budget) {
|
|
245
|
+
end += 1;
|
|
246
|
+
used += afterHeight;
|
|
247
|
+
}
|
|
248
|
+
else if (before && used + beforeHeight <= budget) {
|
|
249
|
+
start -= 1;
|
|
250
|
+
used += beforeHeight;
|
|
251
|
+
}
|
|
252
|
+
else
|
|
253
|
+
break;
|
|
254
|
+
preferBefore = !preferBefore;
|
|
255
|
+
}
|
|
256
|
+
if (entries[start]?.spacer)
|
|
257
|
+
start += 1;
|
|
258
|
+
if (entries[end - 1]?.spacer)
|
|
259
|
+
end -= 1;
|
|
260
|
+
for (const entry of entries.slice(start, end)) {
|
|
261
|
+
if (entry.row) {
|
|
262
|
+
const rendered = this.lines(entry.row, width);
|
|
263
|
+
lines.push(...rendered);
|
|
264
|
+
this.renderedRows.push(...rendered.map(() => entry.row));
|
|
265
|
+
}
|
|
266
|
+
else if (entry.spacer) {
|
|
267
|
+
lines.push('');
|
|
268
|
+
this.renderedRows.push(undefined);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
lines.push(theme.fg('dim', safeText(entry.heading ?? '')));
|
|
272
|
+
this.renderedRows.push(undefined);
|
|
273
|
+
}
|
|
193
274
|
}
|
|
194
|
-
|
|
275
|
+
this.renderedRows = this.renderedRows.slice(0, rowBudget);
|
|
276
|
+
return lines.slice(0, rowBudget).map(line => truncateToWidth(line, width, ''));
|
|
195
277
|
}
|
|
196
278
|
}
|
|
@@ -67,11 +67,8 @@ export class ModelPicker {
|
|
|
67
67
|
this.error = 'Model refresh timed out; showing cached models.';
|
|
68
68
|
else if (result.errors.size)
|
|
69
69
|
this.error = `Could not refresh ${[...result.errors.keys()].join(', ')}; showing cached models.`;
|
|
70
|
-
else
|
|
70
|
+
else
|
|
71
71
|
this.error = this.options.runtime.getError();
|
|
72
|
-
if (!this.error)
|
|
73
|
-
this.status = 'Model catalogs refreshed.';
|
|
74
|
-
}
|
|
75
72
|
this.load();
|
|
76
73
|
}
|
|
77
74
|
catch (error) {
|
|
@@ -135,10 +132,8 @@ export class ModelPicker {
|
|
|
135
132
|
return [];
|
|
136
133
|
const centered = centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
|
|
137
134
|
const inner = centered ? centerDialogContentWidth(width) : contentWidth(width);
|
|
138
|
-
const selected = this.list.selected?.data;
|
|
139
135
|
const notes = [
|
|
140
136
|
this.status ? theme.fg('muted', this.status) : '',
|
|
141
|
-
selected ? theme.fg('muted', `Model name: ${safeText(selected.name ?? selected.id)}`) : '',
|
|
142
137
|
this.error ? theme.fg('error', this.error) : ''
|
|
143
138
|
].filter(Boolean);
|
|
144
139
|
const chromeRows = centered ? centerDialogChromeRows(rows) : 4;
|
|
@@ -2,6 +2,9 @@ import type { TuiMouseEventResult } from '@earendil-works/pi-tui';
|
|
|
2
2
|
import type { TabInfo } from "./chrome.js";
|
|
3
3
|
import type { TerminalMouseInput } from "./mouse.js";
|
|
4
4
|
export interface TerminalPage {
|
|
5
|
+
presentation?: 'centered' | 'fullscreen';
|
|
6
|
+
ownsNavigation?: boolean;
|
|
7
|
+
selectTab?(id: string): void;
|
|
5
8
|
tabs(): readonly TabInfo[];
|
|
6
9
|
activeTab(): string;
|
|
7
10
|
render(width: number, rows: number): string[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { matchesKey } from '@earendil-works/pi-tui';
|
|
1
|
+
import { matchesKey, visibleWidth } from '@earendil-works/pi-tui';
|
|
2
2
|
import { CENTER_DIALOG_PAD, CHROME_PAD, centerDialogBodyRows, centerDialogContentWidth, centerDialogFrame, centerDialogVerticalPad, contentWidth, pageBodyRows, pageFrame, tabIndexAt, tabStrip } from "./chrome.js";
|
|
3
3
|
import { centeredDialogHost, dialogFits, pageRows } from "./dialogGeometry.js";
|
|
4
4
|
export class PageOverlay {
|
|
@@ -23,6 +23,12 @@ export class PageOverlay {
|
|
|
23
23
|
if (this.disposed)
|
|
24
24
|
return undefined;
|
|
25
25
|
if (event.type === 'wheel') {
|
|
26
|
+
const layout = this.pointerLayout;
|
|
27
|
+
if (layout && event.y >= layout.bodyStart) {
|
|
28
|
+
const handled = this.page.handleMouse?.({ ...event, x: event.x - layout.contentX, y: event.y - layout.bodyStart });
|
|
29
|
+
if (handled?.handled)
|
|
30
|
+
return handled;
|
|
31
|
+
}
|
|
26
32
|
const key = event.wheelDelta !== undefined && event.wheelDelta < 0 ? '\x1b[5~' : '\x1b[6~';
|
|
27
33
|
this.handleInput(key);
|
|
28
34
|
return { handled: true, render: true };
|
|
@@ -49,6 +55,11 @@ export class PageOverlay {
|
|
|
49
55
|
const target = tabIndex ?? (tabX < layout.contentWidth / 2
|
|
50
56
|
? (current - 1 + tabs.length) % tabs.length
|
|
51
57
|
: (current + 1) % tabs.length);
|
|
58
|
+
if (this.page.selectTab) {
|
|
59
|
+
this.page.selectTab(tabs[target].id);
|
|
60
|
+
this.hoveredTab = undefined;
|
|
61
|
+
return { handled: true, render: true };
|
|
62
|
+
}
|
|
52
63
|
const delta = (target - Math.max(0, current) + tabs.length) % tabs.length;
|
|
53
64
|
const reverse = (Math.max(0, current) - target + tabs.length) % tabs.length;
|
|
54
65
|
const direction = delta <= reverse ? '\t' : '\x1b[Z';
|
|
@@ -75,9 +86,9 @@ export class PageOverlay {
|
|
|
75
86
|
this.options.close();
|
|
76
87
|
return;
|
|
77
88
|
}
|
|
78
|
-
const centered = centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
|
|
89
|
+
const centered = this.page.presentation !== 'fullscreen' && centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
|
|
79
90
|
const tabs = this.options.page.tabs();
|
|
80
|
-
const input = centered && tabs.length > 1
|
|
91
|
+
const input = centered && tabs.length > 1 && !this.options.page.ownsNavigation
|
|
81
92
|
? matchesKey(data, 'right') ? '\t' : matchesKey(data, 'left') ? '\x1b[Z' : data
|
|
82
93
|
: data;
|
|
83
94
|
if (this.options.page.handleInput(input)) {
|
|
@@ -90,13 +101,13 @@ export class PageOverlay {
|
|
|
90
101
|
render(width) {
|
|
91
102
|
if (this.disposed)
|
|
92
103
|
return [];
|
|
93
|
-
const rows = pageRows(this.options.tui);
|
|
104
|
+
const rows = this.page.presentation === 'fullscreen' ? this.options.tui.terminal.rows : pageRows(this.options.tui);
|
|
94
105
|
const page = this.options.page;
|
|
95
106
|
const tabs = page.tabs();
|
|
96
107
|
if (width < 1 || rows < 1 || !tabs.length)
|
|
97
108
|
return [];
|
|
98
109
|
const theme = this.options.theme();
|
|
99
|
-
const centered = centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
|
|
110
|
+
const centered = this.page.presentation !== 'fullscreen' && centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
|
|
100
111
|
const inner = centered ? centerDialogContentWidth(width) : contentWidth(width);
|
|
101
112
|
if (centered) {
|
|
102
113
|
const tabRows = tabs.length > 1 ? 1 : 0;
|
|
@@ -121,11 +132,20 @@ export class PageOverlay {
|
|
|
121
132
|
contentWidth: contentWidth(width),
|
|
122
133
|
centered
|
|
123
134
|
};
|
|
124
|
-
const
|
|
135
|
+
const escapeHint = page.ownsNavigation ? 'Esc back/close' : 'Esc close';
|
|
136
|
+
const fullFooter = page.ownsNavigation ? `${escapeHint} · ${page.hint()}` : [
|
|
125
137
|
page.hint(),
|
|
126
138
|
tabs.length > 1 ? 'Tab/Shift+Tab sections' : '',
|
|
127
|
-
|
|
139
|
+
escapeHint
|
|
140
|
+
].filter(Boolean).join(' · ');
|
|
141
|
+
const footerWidth = Math.max(0, width - CHROME_PAD * 2);
|
|
142
|
+
const primaryHint = page.hint().split(' · ')[0] ?? '';
|
|
143
|
+
const compactFooter = [
|
|
144
|
+
primaryHint,
|
|
145
|
+
!page.ownsNavigation && tabs.length > 1 ? 'Tab/⇧Tab' : '',
|
|
146
|
+
escapeHint
|
|
128
147
|
].filter(Boolean).join(' · ');
|
|
148
|
+
const footer = visibleWidth(fullFooter) <= footerWidth ? fullFooter : compactFooter;
|
|
129
149
|
return pageFrame({
|
|
130
150
|
title: '',
|
|
131
151
|
headerLine: tabStrip(tabs, page.activeTab(), inner, theme, 'top', this.hoveredTab),
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The Accounts page: one row per account with its health
|
|
3
|
-
*
|
|
4
|
-
* the ones the `/accounts` menu of a native `pi` session uses.
|
|
2
|
+
* The Accounts page: one row per account with its health and Pools as a second section. Opening
|
|
3
|
+
* an account shows its details and grouped actions in a wide inspector or a compact detail page;
|
|
4
|
+
* the actions themselves are the ones the `/accounts` menu of a native `pi` session uses.
|
|
5
5
|
*/
|
|
6
6
|
import type { Theme } from '@earendil-works/pi-coding-agent';
|
|
7
7
|
import { type AccountsCall, type AccountsUi, type SessionAccount } from "../../accountsMenu.js";
|
|
8
|
+
import type { GroupedSelectOption } from "../dialogs.js";
|
|
8
9
|
import type { TerminalPage } from "../page.js";
|
|
9
10
|
import type { TerminalMouseInput } from "../mouse.js";
|
|
10
11
|
export interface AccountsPageOptions {
|
|
@@ -12,19 +13,30 @@ export interface AccountsPageOptions {
|
|
|
12
13
|
call: AccountsCall;
|
|
13
14
|
/** The account this session runs on. */
|
|
14
15
|
session: () => SessionAccount | null;
|
|
15
|
-
ui: AccountsUi
|
|
16
|
+
ui: AccountsUi & {
|
|
17
|
+
selectGrouped?(title: string, options: readonly GroupedSelectOption[]): Promise<string | undefined>;
|
|
18
|
+
};
|
|
16
19
|
/** The session is switching accounts: the host ends it so the launcher can start it again. */
|
|
17
20
|
relaunch(): void;
|
|
18
21
|
changed(): void;
|
|
19
22
|
}
|
|
20
23
|
export declare class AccountsPage implements TerminalPage {
|
|
21
24
|
private readonly options;
|
|
25
|
+
readonly presentation = "fullscreen";
|
|
26
|
+
readonly ownsNavigation = true;
|
|
22
27
|
private overview;
|
|
23
28
|
private error;
|
|
24
29
|
private section;
|
|
30
|
+
private focus;
|
|
31
|
+
private detailOpen;
|
|
32
|
+
private detailAccountId;
|
|
25
33
|
private busy;
|
|
26
34
|
private disposed;
|
|
35
|
+
private compact;
|
|
36
|
+
private wideListWidth;
|
|
37
|
+
private actionRowsStart;
|
|
27
38
|
private readonly list;
|
|
39
|
+
private readonly actionList;
|
|
28
40
|
constructor(options: AccountsPageOptions);
|
|
29
41
|
get focused(): boolean;
|
|
30
42
|
set focused(value: boolean);
|
|
@@ -38,6 +50,7 @@ export declare class AccountsPage implements TerminalPage {
|
|
|
38
50
|
readonly title: "Pools";
|
|
39
51
|
}];
|
|
40
52
|
activeTab(): string;
|
|
53
|
+
selectTab(id: string): void;
|
|
41
54
|
hint(): string;
|
|
42
55
|
private reload;
|
|
43
56
|
/** Searching looks through accounts and pools together; otherwise the page shows the current section. */
|
|
@@ -45,9 +58,18 @@ export declare class AccountsPage implements TerminalPage {
|
|
|
45
58
|
private accountRows;
|
|
46
59
|
private poolRows;
|
|
47
60
|
private account;
|
|
61
|
+
private detailAccount;
|
|
62
|
+
private selectGrouped;
|
|
63
|
+
private accountActionGroup;
|
|
64
|
+
private fillActions;
|
|
65
|
+
private detailLines;
|
|
48
66
|
/** Runs one thing at a time and always reads the accounts again afterwards. */
|
|
49
67
|
private guarded;
|
|
68
|
+
private closeDetails;
|
|
69
|
+
private openDetails;
|
|
50
70
|
private activateRow;
|
|
71
|
+
private activateAction;
|
|
72
|
+
private moveSection;
|
|
51
73
|
handleMouse(event: TerminalMouseInput): import("@earendil-works/pi-tui").TuiMouseEventResult | undefined;
|
|
52
74
|
handleInput(data: string): boolean;
|
|
53
75
|
render(width: number, rows: number): string[];
|