@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
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { matchesKey, stripTerminalSequences, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
2
|
+
import { CHROME_PAD, headerRow, neutralRule, padded } from "../chrome.js";
|
|
3
|
+
import { FilterList } from "../list.js";
|
|
4
|
+
import { ACTIVE_SUBAGENT_STATUSES, terminalSubagentDuration } from "../../subagentMonitor.js";
|
|
5
|
+
import { profileColor, opentuiTheme } from "../../opentui/theme.js";
|
|
6
|
+
import { subagentTasks } from "../../opentui/subagentsWidget.js";
|
|
7
|
+
import { formatTokenCount } from "../status.js";
|
|
8
|
+
import { getWorkingSpinnerFrames, SPINNER_INTERVAL_MS, spinnerFrameAt } from "../workingStatus.js";
|
|
9
|
+
const TABS = [{ id: 'subagents', title: 'Subagents' }];
|
|
10
|
+
function clean(value) {
|
|
11
|
+
return stripTerminalSequences(value).replace(/[\x00-\x08\x0b-\x1f\x7f]/g, ' ').replace(/\s+/g, ' ').trim();
|
|
12
|
+
}
|
|
13
|
+
function statusGlyph(item, now) {
|
|
14
|
+
if (item.status === 'running') {
|
|
15
|
+
const started = Date.parse(item.startedAt);
|
|
16
|
+
return spinnerFrameAt(now - (Number.isFinite(started) ? started : now), getWorkingSpinnerFrames(process.env.TERM), SPINNER_INTERVAL_MS);
|
|
17
|
+
}
|
|
18
|
+
switch (item.status) {
|
|
19
|
+
case 'queued': return '○';
|
|
20
|
+
case 'waiting_for_approval':
|
|
21
|
+
case 'waiting_for_input': return '●';
|
|
22
|
+
case 'completed': return '✓';
|
|
23
|
+
case 'failed': return '✕';
|
|
24
|
+
case 'interrupted': return '!';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function statusGlyphTone(item) {
|
|
28
|
+
if (item.status === 'completed')
|
|
29
|
+
return 'success';
|
|
30
|
+
if (item.status === 'failed')
|
|
31
|
+
return 'error';
|
|
32
|
+
if (item.status === 'waiting_for_approval' || item.status === 'waiting_for_input')
|
|
33
|
+
return 'accent';
|
|
34
|
+
if (item.status === 'running')
|
|
35
|
+
return 'warning';
|
|
36
|
+
return 'muted';
|
|
37
|
+
}
|
|
38
|
+
function effectiveModel(item) {
|
|
39
|
+
const model = item.usage?.model;
|
|
40
|
+
if (model)
|
|
41
|
+
return `${item.usage?.provider ? `${item.usage.provider}/` : ''}${model}`;
|
|
42
|
+
return item.model ?? '—';
|
|
43
|
+
}
|
|
44
|
+
function usageSummary(item) {
|
|
45
|
+
const usage = item.usage;
|
|
46
|
+
if (!usage)
|
|
47
|
+
return 'usage —';
|
|
48
|
+
const cache = [usage.cacheReadTokens, usage.cacheWriteTokens]
|
|
49
|
+
.filter((value) => typeof value === 'number' && value > 0)
|
|
50
|
+
.map(formatTokenCount);
|
|
51
|
+
const cost = typeof usage.costUsd === 'number'
|
|
52
|
+
? `${usage.costSource === 'estimate' ? '~' : ''}$${usage.costUsd.toFixed(usage.costUsd > 0 && usage.costUsd < 0.001 ? 5 : usage.costUsd < 0.01 ? 4 : 2).replace(/0+$/u, '').replace(/\.$/u, '')}`
|
|
53
|
+
: '';
|
|
54
|
+
const fields = [
|
|
55
|
+
typeof usage.inputTokens === 'number' ? `↑${formatTokenCount(usage.inputTokens)}` : '',
|
|
56
|
+
typeof usage.outputTokens === 'number' ? `↓${formatTokenCount(usage.outputTokens)}` : '',
|
|
57
|
+
cache.some(Boolean) ? `c${cache.join('/')}` : '',
|
|
58
|
+
cost,
|
|
59
|
+
typeof usage.contextTokens === 'number' ? `ctx${formatTokenCount(usage.contextTokens)}${typeof usage.contextWindow === 'number' ? `/${formatTokenCount(usage.contextWindow)}` : ''}` : '',
|
|
60
|
+
typeof usage.requests === 'number' ? `req${usage.requests}` : ''
|
|
61
|
+
].filter(Boolean);
|
|
62
|
+
return fields.length ? fields.join(' ') : 'usage —';
|
|
63
|
+
}
|
|
64
|
+
function rowSubtitle(item, width) {
|
|
65
|
+
const available = Math.max(1, width - 2);
|
|
66
|
+
const verbose = width >= 96;
|
|
67
|
+
const account = clean(item.accountLabel ?? '') || '—';
|
|
68
|
+
const model = truncateToWidth(effectiveModel(item), 24, '…');
|
|
69
|
+
const details = verbose
|
|
70
|
+
? [`acct ${account}`, `model ${model}`, `eff ${item.effort ?? '—'}`, usageSummary(item)].join(' · ')
|
|
71
|
+
: [`a:${account}`, `m:${model}`, `e:${item.effort ?? '—'}`, usageSummary(item)].join(' · ');
|
|
72
|
+
return truncateToWidth(details, available, '…');
|
|
73
|
+
}
|
|
74
|
+
export class SubagentsPage {
|
|
75
|
+
options;
|
|
76
|
+
presentation = 'fullscreen';
|
|
77
|
+
list;
|
|
78
|
+
constructor(options) {
|
|
79
|
+
this.options = options;
|
|
80
|
+
this.list = new FilterList({
|
|
81
|
+
theme: options.theme, search: 'always', noun: ['subagent', 'subagents'], rowGap: 1,
|
|
82
|
+
empty: 'No subagents have started in the latest run'
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
get focused() { return this.list.focused; }
|
|
86
|
+
set focused(value) { this.list.focused = value; }
|
|
87
|
+
tabs() { return TABS; }
|
|
88
|
+
activeTab() { return 'subagents'; }
|
|
89
|
+
hint() { return '↑↓ select · type to search'; }
|
|
90
|
+
rows(width = 80, now = this.options.now?.() ?? Date.now()) {
|
|
91
|
+
const ordered = [...this.options.snapshot()].sort((left, right) => {
|
|
92
|
+
const active = Number(ACTIVE_SUBAGENT_STATUSES.has(right.status)) - Number(ACTIVE_SUBAGENT_STATUSES.has(left.status));
|
|
93
|
+
return active || left.startedAt.localeCompare(right.startedAt) || left.id.localeCompare(right.id);
|
|
94
|
+
});
|
|
95
|
+
return ordered.map(item => {
|
|
96
|
+
const profile = clean(item.profile?.name ?? '') || 'subagent';
|
|
97
|
+
const title = clean(item.title) || 'Subagent';
|
|
98
|
+
const color = item.profile?.color ? profileColor(opentuiTheme, item.profile.color) : null;
|
|
99
|
+
const glyph = statusGlyph(item, now);
|
|
100
|
+
const labelParts = [
|
|
101
|
+
{ text: `${glyph} `, ...(item.status === 'running' && color ? { color } : { tone: statusGlyphTone(item) }) },
|
|
102
|
+
{ text: profile, ...(color ? { color } : { tone: 'muted' }) },
|
|
103
|
+
{ text: ` ${title}` }
|
|
104
|
+
];
|
|
105
|
+
return {
|
|
106
|
+
id: item.id,
|
|
107
|
+
label: labelParts.map(part => part.text).join(''),
|
|
108
|
+
labelParts,
|
|
109
|
+
subtitle: rowSubtitle(item, width),
|
|
110
|
+
searchText: `${profile} ${title} ${item.goal ?? ''} ${item.status} ${item.activity} ${item.accountLabel ?? ''} ${effectiveModel(item)} ${item.effort ?? ''} ${usageSummary(item)}`,
|
|
111
|
+
data: item
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
render(width, rows) {
|
|
116
|
+
const items = this.rows(width, this.options.now?.() ?? Date.now());
|
|
117
|
+
this.list.setRows(items);
|
|
118
|
+
const active = items.filter(item => item.data && ACTIVE_SUBAGENT_STATUSES.has(item.data.status)).length;
|
|
119
|
+
const selected = this.list.selected?.data;
|
|
120
|
+
const header = headerRow('Subagents', `${active} active · ${items.length} total`, width, this.options.theme());
|
|
121
|
+
const bodyRows = Math.max(0, rows - 7);
|
|
122
|
+
const listRows = Math.max(1, Math.min(this.list.height, Math.floor(bodyRows * 0.6)));
|
|
123
|
+
const output = [header, '', ...this.list.render(width, listRows), ''];
|
|
124
|
+
if (selected) {
|
|
125
|
+
const theme = this.options.theme();
|
|
126
|
+
const detailIndent = ' '.repeat(CHROME_PAD * 2);
|
|
127
|
+
const detailLines = (text) => wrapTextWithAnsi(theme.fg('text', clean(text)), Math.max(1, width - detailIndent.length))
|
|
128
|
+
.map(line => `${detailIndent}${line}`);
|
|
129
|
+
output.push(neutralRule(width, theme));
|
|
130
|
+
output.push(padded(theme.fg('muted', `Profile: ${clean(selected.profile?.name ?? '') || 'copy of the parent'}`), width));
|
|
131
|
+
output.push(padded(theme.fg('accent', 'Task'), width));
|
|
132
|
+
output.push(...detailLines(selected.goal || 'Subagent'));
|
|
133
|
+
output.push(padded(theme.fg('muted', `Status: ${[selected.status.replaceAll('_', ' '), subagentTasks(selected.checklist), terminalSubagentDuration(selected)].filter(Boolean).join(' · ')}`), width));
|
|
134
|
+
output.push(padded(theme.fg('accent', 'Current activity'), width));
|
|
135
|
+
output.push(...detailLines(selected.activity));
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
output.push(padded(this.options.theme().fg('muted', 'The selected subagent’s task and current activity appear here.'), width));
|
|
139
|
+
}
|
|
140
|
+
return output.slice(0, Math.max(0, rows)).map(line => truncateToWidth(line, width, ''));
|
|
141
|
+
}
|
|
142
|
+
handleInput(data) {
|
|
143
|
+
this.list.setRows(this.rows());
|
|
144
|
+
if (matchesKey(data, 'enter'))
|
|
145
|
+
return this.list.handleInput(data);
|
|
146
|
+
if (this.list.handleInput(data)) {
|
|
147
|
+
this.options.changed();
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -5,7 +5,7 @@ import type { RunEvent } from "../../../sessions/contracts.js";
|
|
|
5
5
|
import type { TerminalTrajectoryRun, TerminalTrajectorySnapshot } from "../../trajectory.js";
|
|
6
6
|
import { type TabInfo } from "../chrome.js";
|
|
7
7
|
import type { TerminalPage } from "../page.js";
|
|
8
|
-
import {
|
|
8
|
+
import type { TerminalMouseInput } from "../mouse.js";
|
|
9
9
|
export interface TrajectoryPageOptions {
|
|
10
10
|
theme: () => Theme;
|
|
11
11
|
runs(): Promise<TerminalTrajectoryRun[]>;
|
|
@@ -18,17 +18,20 @@ export interface TrajectoryPageOptions {
|
|
|
18
18
|
}
|
|
19
19
|
export declare class TrajectoryPage implements TerminalPage {
|
|
20
20
|
private readonly options;
|
|
21
|
+
readonly presentation: "fullscreen";
|
|
21
22
|
private runs;
|
|
22
23
|
private section;
|
|
23
24
|
private readonly runList;
|
|
25
|
+
private readonly eventList;
|
|
24
26
|
private runIndex;
|
|
25
27
|
private run;
|
|
26
28
|
private events;
|
|
27
|
-
private selected;
|
|
28
29
|
private detailOffset;
|
|
29
|
-
private
|
|
30
|
-
private
|
|
31
|
-
private
|
|
30
|
+
private listStart;
|
|
31
|
+
private listEnd;
|
|
32
|
+
private listWidth;
|
|
33
|
+
private detailsStart;
|
|
34
|
+
private wideLayout;
|
|
32
35
|
private loading;
|
|
33
36
|
private loaded;
|
|
34
37
|
private disposed;
|
|
@@ -49,10 +52,14 @@ export declare class TrajectoryPage implements TerminalPage {
|
|
|
49
52
|
private refresh;
|
|
50
53
|
/** `[` is the older run, `]` the newer one. */
|
|
51
54
|
private runRows;
|
|
55
|
+
private eventRows;
|
|
56
|
+
private eventJson;
|
|
52
57
|
private selectRun;
|
|
53
58
|
private changeRun;
|
|
54
59
|
hint(): string;
|
|
55
60
|
handleMouse(event: TerminalMouseInput): TuiMouseEventResult | undefined;
|
|
56
61
|
handleInput(data: string): boolean;
|
|
62
|
+
private runSummary;
|
|
63
|
+
private detailLines;
|
|
57
64
|
render(width: number, rows: number): string[];
|
|
58
65
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { matchesKey, stripTerminalSequences, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
2
|
-
import { selectedRow, selectionText } from "../chrome.js";
|
|
1
|
+
import { matchesKey, stripTerminalSequences, truncateToWidth, visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
3
2
|
import { FilterList } from "../list.js";
|
|
4
|
-
import { isPrimaryClick } from "../mouse.js";
|
|
5
3
|
const ACTIVE = new Set(['queued', 'running', 'waiting_for_approval', 'waiting_for_input']);
|
|
6
4
|
const payloadOf = (event) => event.payload && typeof event.payload === 'object' ? event.payload : {};
|
|
7
5
|
const stringOf = (value) => typeof value === 'string' ? value : undefined;
|
|
@@ -68,17 +66,20 @@ const SECTIONS = [
|
|
|
68
66
|
];
|
|
69
67
|
export class TrajectoryPage {
|
|
70
68
|
options;
|
|
69
|
+
presentation = 'fullscreen';
|
|
71
70
|
runs = [];
|
|
72
71
|
section = 'runs';
|
|
73
72
|
runList;
|
|
73
|
+
eventList;
|
|
74
74
|
runIndex = 0;
|
|
75
75
|
run;
|
|
76
76
|
events = [];
|
|
77
|
-
selected = 0;
|
|
78
77
|
detailOffset = 0;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
listStart = 0;
|
|
79
|
+
listEnd = 0;
|
|
80
|
+
listWidth = 0;
|
|
81
|
+
detailsStart = -1;
|
|
82
|
+
wideLayout = false;
|
|
82
83
|
loading = false;
|
|
83
84
|
loaded = false;
|
|
84
85
|
disposed = false;
|
|
@@ -87,15 +88,19 @@ export class TrajectoryPage {
|
|
|
87
88
|
constructor(options) {
|
|
88
89
|
this.options = options;
|
|
89
90
|
this.runList = new FilterList({
|
|
90
|
-
theme: options.theme, search: '
|
|
91
|
+
theme: options.theme, search: 'always', noun: ['run', 'runs'], empty: 'No runs recorded for this native session yet',
|
|
91
92
|
onActivate: row => { if (row.data)
|
|
92
93
|
void this.selectRun(row.data); }
|
|
93
94
|
});
|
|
95
|
+
this.eventList = new FilterList({
|
|
96
|
+
theme: options.theme, search: 'always', noun: ['event', 'events'], empty: 'No recorded events',
|
|
97
|
+
onActivate: () => { this.detailOffset = 0; this.options.changed(); }
|
|
98
|
+
});
|
|
94
99
|
}
|
|
95
100
|
get selectedRunId() { return this.run?.id; }
|
|
96
|
-
get selectedEvent() { return this.
|
|
97
|
-
get focused() { return this.runList.focused; }
|
|
98
|
-
set focused(value) { this.runList.focused = value; }
|
|
101
|
+
get selectedEvent() { return this.eventList.selected?.data; }
|
|
102
|
+
get focused() { return this.section === 'runs' ? this.runList.focused : this.eventList.focused; }
|
|
103
|
+
set focused(value) { this.runList.focused = value; this.eventList.focused = value; }
|
|
99
104
|
tabs() { return SECTIONS; }
|
|
100
105
|
activeTab() { return this.section; }
|
|
101
106
|
activate() {
|
|
@@ -153,8 +158,11 @@ export class TrajectoryPage {
|
|
|
153
158
|
return;
|
|
154
159
|
this.run = snapshot.run;
|
|
155
160
|
this.events = snapshot.events.slice().sort(bySequence);
|
|
161
|
+
this.eventList.setRows(this.eventRows());
|
|
162
|
+
const latest = this.events.at(-1);
|
|
163
|
+
if (latest)
|
|
164
|
+
this.eventList.select(String(latest.sequence));
|
|
156
165
|
this.runList.select(run.id);
|
|
157
|
-
this.selected = Math.max(0, this.events.length - 1);
|
|
158
166
|
this.detailOffset = 0;
|
|
159
167
|
}
|
|
160
168
|
async refresh() {
|
|
@@ -162,7 +170,8 @@ export class TrajectoryPage {
|
|
|
162
170
|
return;
|
|
163
171
|
this.loading = true;
|
|
164
172
|
const lastSequence = this.events.at(-1)?.sequence;
|
|
165
|
-
const
|
|
173
|
+
const selectedBefore = this.selectedEvent;
|
|
174
|
+
const followedLatest = !selectedBefore || selectedBefore.sequence === lastSequence;
|
|
166
175
|
try {
|
|
167
176
|
const snapshot = await this.options.read(this.run.id, lastSequence);
|
|
168
177
|
if (this.disposed)
|
|
@@ -176,8 +185,14 @@ export class TrajectoryPage {
|
|
|
176
185
|
const existing = new Set(this.events.map(event => event.sequence));
|
|
177
186
|
this.events = [...this.events, ...snapshot.events.filter(event => !existing.has(event.sequence))].sort(bySequence);
|
|
178
187
|
}
|
|
179
|
-
|
|
180
|
-
|
|
188
|
+
this.eventList.setRows(this.eventRows());
|
|
189
|
+
if (followedLatest) {
|
|
190
|
+
const latest = this.events.at(-1);
|
|
191
|
+
if (latest)
|
|
192
|
+
this.eventList.select(String(latest.sequence));
|
|
193
|
+
}
|
|
194
|
+
else if (selectedBefore)
|
|
195
|
+
this.eventList.select(String(selectedBefore.sequence));
|
|
181
196
|
this.error = undefined;
|
|
182
197
|
}
|
|
183
198
|
catch (error) {
|
|
@@ -201,6 +216,18 @@ export class TrajectoryPage {
|
|
|
201
216
|
data: run
|
|
202
217
|
}));
|
|
203
218
|
}
|
|
219
|
+
eventRows() {
|
|
220
|
+
return this.events.map(event => ({
|
|
221
|
+
id: String(event.sequence),
|
|
222
|
+
label: `${timeOf(event.timestamp)} ${event.type}`,
|
|
223
|
+
detail: eventDescription(event),
|
|
224
|
+
searchText: `${event.timestamp} ${event.type} ${eventDescription(event)} ${safe(JSON.stringify(payloadOf(event)))}`,
|
|
225
|
+
data: event
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
eventJson(event) {
|
|
229
|
+
return JSON.stringify({ payload: event.payload, type: event.type, sequence: event.sequence, timestamp: event.timestamp }, null, 2);
|
|
230
|
+
}
|
|
204
231
|
async selectRun(run) {
|
|
205
232
|
const at = this.runs.findIndex(candidate => candidate.id === run.id);
|
|
206
233
|
if (at < 0 || this.loading)
|
|
@@ -209,7 +236,7 @@ export class TrajectoryPage {
|
|
|
209
236
|
this.runList.select(run.id);
|
|
210
237
|
this.run = run;
|
|
211
238
|
this.events = [];
|
|
212
|
-
this.
|
|
239
|
+
this.eventList.setRows([]);
|
|
213
240
|
this.detailOffset = 0;
|
|
214
241
|
this.error = undefined;
|
|
215
242
|
this.loading = true;
|
|
@@ -236,7 +263,7 @@ export class TrajectoryPage {
|
|
|
236
263
|
this.run = this.runs[next];
|
|
237
264
|
this.runList.select(this.run.id);
|
|
238
265
|
this.events = [];
|
|
239
|
-
this.
|
|
266
|
+
this.eventList.setRows([]);
|
|
240
267
|
this.detailOffset = 0;
|
|
241
268
|
this.error = undefined;
|
|
242
269
|
this.loading = true;
|
|
@@ -255,21 +282,38 @@ export class TrajectoryPage {
|
|
|
255
282
|
}
|
|
256
283
|
}
|
|
257
284
|
hint() {
|
|
258
|
-
return this.section === 'runs'
|
|
285
|
+
return this.section === 'runs'
|
|
286
|
+
? '↑/↓ runs · type to search · Enter inspect'
|
|
287
|
+
: '[ ] runs · ↑/↓ events · type to search · PgUp/PgDn details · Shift+C copy';
|
|
259
288
|
}
|
|
260
289
|
handleMouse(event) {
|
|
290
|
+
if (event.type === 'wheel') {
|
|
291
|
+
const down = (event.wheelDelta ?? 1) >= 0;
|
|
292
|
+
if (this.section === 'events' && this.detailsStart >= 0 && (this.wideLayout ? event.x >= this.listWidth + 3 : event.y >= this.detailsStart)) {
|
|
293
|
+
this.detailOffset = Math.max(0, this.detailOffset + (down ? 4 : -4));
|
|
294
|
+
this.options.changed();
|
|
295
|
+
return { handled: true, render: true };
|
|
296
|
+
}
|
|
297
|
+
if (this.section === 'runs')
|
|
298
|
+
this.runList.handleInput(down ? '\x1b[B' : '\x1b[A');
|
|
299
|
+
else
|
|
300
|
+
this.eventList.handleInput(down ? '\x1b[B' : '\x1b[A');
|
|
301
|
+
this.detailOffset = 0;
|
|
302
|
+
this.options.changed();
|
|
303
|
+
return { handled: true, render: true };
|
|
304
|
+
}
|
|
261
305
|
if (event.type === 'click' && event.button !== 'left')
|
|
262
306
|
return undefined;
|
|
263
|
-
if (
|
|
264
|
-
return this.runList.handleMouse({ ...event, y: event.y - 1 });
|
|
265
|
-
const offset = event.y - this.eventRowsStart;
|
|
266
|
-
if (this.eventRowsStart < 0 || offset < 0 || offset >= this.eventRowsCount)
|
|
307
|
+
if (event.type !== 'click' && event.type !== 'move')
|
|
267
308
|
return undefined;
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
309
|
+
if (this.section === 'runs') {
|
|
310
|
+
if (event.y < this.listStart || event.y >= this.listEnd)
|
|
311
|
+
return undefined;
|
|
312
|
+
return this.runList.handleMouse({ ...event, y: event.y - this.listStart });
|
|
313
|
+
}
|
|
314
|
+
if (event.y < this.listStart || event.y >= this.listEnd || (this.wideLayout && event.x >= this.listWidth + 3))
|
|
315
|
+
return undefined;
|
|
316
|
+
return this.eventList.handleMouse({ ...event, y: event.y - this.listStart });
|
|
273
317
|
}
|
|
274
318
|
handleInput(data) {
|
|
275
319
|
if (matchesKey(data, 'tab') || matchesKey(data, 'shift+tab')) {
|
|
@@ -288,16 +332,6 @@ export class TrajectoryPage {
|
|
|
288
332
|
void this.changeRun(-1);
|
|
289
333
|
return true;
|
|
290
334
|
}
|
|
291
|
-
if (matchesKey(data, 'up')) {
|
|
292
|
-
this.selected = Math.max(0, this.selected - 1);
|
|
293
|
-
this.detailOffset = 0;
|
|
294
|
-
return true;
|
|
295
|
-
}
|
|
296
|
-
if (matchesKey(data, 'down')) {
|
|
297
|
-
this.selected = this.events.length ? Math.min(this.events.length - 1, this.selected + 1) : 0;
|
|
298
|
-
this.detailOffset = 0;
|
|
299
|
-
return true;
|
|
300
|
-
}
|
|
301
335
|
if (matchesKey(data, 'pageUp')) {
|
|
302
336
|
this.detailOffset = Math.max(0, this.detailOffset - 8);
|
|
303
337
|
return true;
|
|
@@ -306,71 +340,110 @@ export class TrajectoryPage {
|
|
|
306
340
|
this.detailOffset += 8;
|
|
307
341
|
return true;
|
|
308
342
|
}
|
|
309
|
-
if (data
|
|
310
|
-
const text =
|
|
343
|
+
if (data === 'C' && this.selectedEvent) {
|
|
344
|
+
const text = this.eventJson(this.selectedEvent);
|
|
311
345
|
void this.options.copy(text).then(() => this.options.notify('Copied selected trajectory event')).catch(error => this.options.notify(String(error), 'error'));
|
|
312
346
|
return true;
|
|
313
347
|
}
|
|
314
|
-
|
|
348
|
+
const selected = this.selectedEvent?.sequence;
|
|
349
|
+
if (!this.eventList.handleInput(data))
|
|
350
|
+
return false;
|
|
351
|
+
if (this.selectedEvent?.sequence !== selected)
|
|
352
|
+
this.detailOffset = 0;
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
355
|
+
runSummary(width, rows) {
|
|
356
|
+
if (!this.run || rows < 1)
|
|
357
|
+
return [];
|
|
358
|
+
const runPosition = `${this.runIndex + 1}/${this.runs.length}`;
|
|
359
|
+
const modelEvent = [...this.events].reverse().find(event => event.type === 'usage.updated');
|
|
360
|
+
const usage = modelEvent ? payloadOf(modelEvent) : {};
|
|
361
|
+
const model = stringOf(usage.model) ?? 'model unavailable';
|
|
362
|
+
const theme = this.options.theme();
|
|
363
|
+
const lines = [theme.bold(theme.fg('accent', `Run ${runPosition} · ${this.run.id} · ${this.run.status}${this.loading ? ' · loading' : ''}`))];
|
|
364
|
+
if (rows >= 3)
|
|
365
|
+
lines.push(theme.fg('muted', `${model} · ${durationLine(this.run)} · ${this.run.mode}`));
|
|
366
|
+
if (rows >= 4)
|
|
367
|
+
lines.push(theme.fg('muted', usageLine(this.events)));
|
|
368
|
+
if (rows >= 6)
|
|
369
|
+
lines.push(theme.fg('dim', this.run.goal ? `Prompt: ${this.run.goal.replace(/\s+/g, ' ').slice(0, 140)}` : 'Prompt text unavailable'));
|
|
370
|
+
if (this.error)
|
|
371
|
+
lines.push(theme.fg('error', `Read error: ${this.error}`));
|
|
372
|
+
return lines.slice(0, Math.min(rows, 5)).map(line => truncateToWidth(line, width, ''));
|
|
373
|
+
}
|
|
374
|
+
detailLines(width, rows) {
|
|
375
|
+
if (rows < 1)
|
|
376
|
+
return [];
|
|
377
|
+
const event = this.selectedEvent;
|
|
378
|
+
const theme = this.options.theme();
|
|
379
|
+
const heading = theme.bold(theme.fg('accent', event ? `Event JSON · ${event.type} · #${event.sequence}` : 'Event JSON'));
|
|
380
|
+
const json = event
|
|
381
|
+
? wrapTextWithAnsi(safe(this.eventJson(event)), Math.max(1, width))
|
|
382
|
+
: [this.events.length ? 'No event selected' : this.loading ? 'Loading recorded events…' : 'No recorded events'];
|
|
383
|
+
const visibleRows = Math.max(0, rows - 1);
|
|
384
|
+
this.detailOffset = Math.min(this.detailOffset, Math.max(0, json.length - visibleRows));
|
|
385
|
+
return [heading, ...json.slice(this.detailOffset, this.detailOffset + visibleRows)
|
|
386
|
+
.map(line => this.options.theme().fg('dim', line))].slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
315
387
|
}
|
|
316
388
|
render(width, rows) {
|
|
317
389
|
const theme = this.options.theme();
|
|
318
390
|
if (width < 1 || rows < 1)
|
|
319
391
|
return [];
|
|
320
392
|
if (this.section === 'runs') {
|
|
321
|
-
this.
|
|
322
|
-
this.
|
|
393
|
+
this.wideLayout = false;
|
|
394
|
+
this.detailsStart = -1;
|
|
323
395
|
if (this.error && !this.runs.length)
|
|
324
396
|
return [theme.fg('error', 'Read error: ' + this.error)];
|
|
325
|
-
const lines = [theme.fg('dim', !this.loaded ? 'Loading recorded runs…' : this.runs.length
|
|
326
|
-
|
|
397
|
+
const lines = [theme.fg('dim', !this.loaded ? 'Loading recorded runs…' : `${this.runs.length} recorded runs`)];
|
|
398
|
+
this.listStart = lines.length;
|
|
399
|
+
const list = this.runList.render(width, Math.max(0, rows - lines.length));
|
|
400
|
+
this.listEnd = this.listStart + list.length;
|
|
401
|
+
lines.push(...list);
|
|
327
402
|
return lines.slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
328
403
|
}
|
|
329
404
|
if (!this.run) {
|
|
330
|
-
this.
|
|
331
|
-
this.
|
|
405
|
+
this.listStart = this.listEnd = 0;
|
|
406
|
+
this.detailsStart = -1;
|
|
332
407
|
if (this.error)
|
|
333
408
|
return [theme.fg('error', 'Read error: ' + this.error)];
|
|
334
409
|
return [theme.fg('dim', this.loading || !this.loaded ? 'Loading recorded runs…' : 'No run selected. Choose a run in the Runs tab.')];
|
|
335
410
|
}
|
|
336
|
-
const
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const firstEvent = Math.max(0, Math.min(this.events.length - ledgerBudget, this.selected - Math.floor(ledgerBudget / 2)));
|
|
358
|
-
this.eventRowsStart = lines.length;
|
|
359
|
-
this.eventRowsFirst = firstEvent;
|
|
360
|
-
this.eventRowsCount = ledgerBudget;
|
|
361
|
-
for (let offset = 0; offset < ledgerBudget; offset++) {
|
|
362
|
-
const index = firstEvent + offset;
|
|
363
|
-
const event = this.events[index];
|
|
364
|
-
const prefix = index === this.selected ? '❯' : ' ';
|
|
365
|
-
const label = truncateToWidth(prefix + ' ' + timeOf(event.timestamp) + ' ' + event.type + ' ' + eventDescription(event), width, '');
|
|
366
|
-
lines.push(index === this.selected ? selectedRow(selectionText(theme, label), width, theme) : theme.fg('muted', label));
|
|
411
|
+
const lines = this.runSummary(width, rows);
|
|
412
|
+
const bodyRows = Math.max(0, rows - lines.length);
|
|
413
|
+
const wide = width >= 72;
|
|
414
|
+
this.wideLayout = wide;
|
|
415
|
+
if (wide) {
|
|
416
|
+
const separatorWidth = 3;
|
|
417
|
+
const leftWidth = Math.max(24, Math.floor((width - separatorWidth) * 0.42));
|
|
418
|
+
const rightWidth = Math.max(1, width - leftWidth - separatorWidth);
|
|
419
|
+
const paneStart = lines.length;
|
|
420
|
+
this.listWidth = leftWidth;
|
|
421
|
+
const events = [theme.bold(theme.fg('accent', 'Events')), ...this.eventList.render(leftWidth, Math.max(0, bodyRows - 1))];
|
|
422
|
+
const details = this.detailLines(rightWidth, bodyRows);
|
|
423
|
+
this.listStart = paneStart + 1;
|
|
424
|
+
this.listEnd = this.listStart + events.length - 1;
|
|
425
|
+
this.detailsStart = paneStart;
|
|
426
|
+
const pane = Array.from({ length: Math.max(events.length, details.length) }, (_, index) => {
|
|
427
|
+
const left = truncateToWidth(events[index] ?? '', leftWidth, '');
|
|
428
|
+
const gap = ' '.repeat(Math.max(0, leftWidth - visibleWidth(left)));
|
|
429
|
+
return left + gap + theme.fg('dim', ' │ ') + (details[index] ?? '');
|
|
430
|
+
});
|
|
431
|
+
lines.push(...pane);
|
|
367
432
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
433
|
+
else {
|
|
434
|
+
lines.push(theme.bold(theme.fg('accent', 'Events')));
|
|
435
|
+
this.listStart = lines.length;
|
|
436
|
+
this.listWidth = width;
|
|
437
|
+
const listRows = Math.min(Math.max(0, bodyRows - 1), Math.max(1, Math.floor(bodyRows * 0.58)));
|
|
438
|
+
const events = this.eventList.render(width, listRows);
|
|
439
|
+
this.listEnd = this.listStart + events.length;
|
|
440
|
+
lines.push(...events);
|
|
441
|
+
const hasRoomForDetails = lines.length < rows;
|
|
442
|
+
if (hasRoomForDetails)
|
|
443
|
+
lines.push('');
|
|
444
|
+
this.detailsStart = lines.length;
|
|
445
|
+
const detailRows = Math.max(0, rows - lines.length);
|
|
446
|
+
lines.push(...this.detailLines(width, detailRows));
|
|
374
447
|
}
|
|
375
448
|
return lines.slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
376
449
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Theme } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import type { UsagePeriod } from "../../../usage/types.js";
|
|
3
|
+
import type { TabInfo } from "../chrome.js";
|
|
4
|
+
import type { TerminalPage } from "../page.js";
|
|
5
|
+
type UsageTab = 'analysis' | 'limits';
|
|
6
|
+
interface UsagePageOptions {
|
|
7
|
+
theme(): Theme;
|
|
8
|
+
call(method: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
9
|
+
changed(): void;
|
|
10
|
+
initialTab?: UsageTab;
|
|
11
|
+
initialPeriod?: UsagePeriod;
|
|
12
|
+
}
|
|
13
|
+
export declare class UsagePage implements TerminalPage {
|
|
14
|
+
private readonly options;
|
|
15
|
+
presentation: "centered";
|
|
16
|
+
focused: boolean;
|
|
17
|
+
private tab;
|
|
18
|
+
private period;
|
|
19
|
+
private scope;
|
|
20
|
+
private summary?;
|
|
21
|
+
private limitsSummary?;
|
|
22
|
+
private limits?;
|
|
23
|
+
private busy;
|
|
24
|
+
private error?;
|
|
25
|
+
private refreshLimits;
|
|
26
|
+
private offset;
|
|
27
|
+
private scrollRows;
|
|
28
|
+
private maxOffset;
|
|
29
|
+
private disposed;
|
|
30
|
+
constructor(options: UsagePageOptions);
|
|
31
|
+
tabs(): readonly TabInfo[];
|
|
32
|
+
activeTab(): string;
|
|
33
|
+
selectTab(id: string): void;
|
|
34
|
+
hint(): string;
|
|
35
|
+
activate(): void;
|
|
36
|
+
dispose(): void;
|
|
37
|
+
private load;
|
|
38
|
+
handleInput(data: string): boolean;
|
|
39
|
+
private analysisContent;
|
|
40
|
+
private limitsContent;
|
|
41
|
+
render(width: number, rows: number): string[];
|
|
42
|
+
}
|
|
43
|
+
export {};
|