@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
|
@@ -1,5 +1,35 @@
|
|
|
1
|
-
import { matchesKey, stripTerminalSequences, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
1
|
+
import { matchesKey, stripTerminalSequences, truncateToWidth, visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
2
2
|
import { doctorReportSchema } from "../../../doctor/types.js";
|
|
3
|
+
const STATUSES = ['pass', 'warning', 'fail', 'disabled', 'blocked', 'unverified'];
|
|
4
|
+
const STATUS_TONE = {
|
|
5
|
+
pass: 'success', warning: 'warning', fail: 'error', disabled: 'dim', blocked: 'warning', unverified: 'muted'
|
|
6
|
+
};
|
|
7
|
+
function cleanText(value) {
|
|
8
|
+
return stripTerminalSequences(value).replace(/[\x00-\x08\x0b-\x1f\x7f-\x9f]/g, ' ').replace(/\t/g, ' ');
|
|
9
|
+
}
|
|
10
|
+
function oneLine(value) {
|
|
11
|
+
return cleanText(value).replace(/\s+/g, ' ').trim();
|
|
12
|
+
}
|
|
13
|
+
function padCell(value, width) {
|
|
14
|
+
const fitted = truncateToWidth(value, width, '');
|
|
15
|
+
return fitted + ' '.repeat(Math.max(0, width - visibleWidth(fitted)));
|
|
16
|
+
}
|
|
17
|
+
function tableRow(cells, widths, width) {
|
|
18
|
+
const wrapped = cells.map((cell, index) => {
|
|
19
|
+
const lines = wrapTextWithAnsi(cell, widths[index]);
|
|
20
|
+
return lines.length ? lines : [''];
|
|
21
|
+
});
|
|
22
|
+
const height = Math.max(...wrapped.map(lines => lines.length));
|
|
23
|
+
return Array.from({ length: height }, (_, row) => truncateToWidth(wrapped.map((lines, column) => padCell(lines[row] ?? '', widths[column])).join(' '), width, ''));
|
|
24
|
+
}
|
|
25
|
+
function appendDetails(lines, label, value, width, theme) {
|
|
26
|
+
if (!value?.trim())
|
|
27
|
+
return;
|
|
28
|
+
for (const paragraph of cleanText(value).split('\n')) {
|
|
29
|
+
const wrapped = wrapTextWithAnsi(`${label}: ${paragraph}`, Math.max(1, width - 2));
|
|
30
|
+
lines.push(...(wrapped.length ? wrapped : [`${label}:`]).map(line => theme.fg('muted', ` ${line}`)));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
3
33
|
export class DoctorPage {
|
|
4
34
|
options;
|
|
5
35
|
focused = false;
|
|
@@ -9,12 +39,14 @@ export class DoctorPage {
|
|
|
9
39
|
disposed = false;
|
|
10
40
|
busy = false;
|
|
11
41
|
offset = 0;
|
|
42
|
+
scrollRows = 1;
|
|
43
|
+
maxOffset = 0;
|
|
12
44
|
constructor(options) {
|
|
13
45
|
this.options = options;
|
|
14
46
|
}
|
|
15
47
|
tabs() { return [{ id: 'doctor', title: 'Doctor' }]; }
|
|
16
48
|
activeTab() { return 'doctor'; }
|
|
17
|
-
hint() { return '↑/↓ scroll · r refresh · t retry
|
|
49
|
+
hint() { return '↑/↓ scroll · PgUp/PgDn/wheel page · Home/End · r refresh · t retry · l live · c cancel · Esc close'; }
|
|
18
50
|
activate() { if (!this.report && !this.busy)
|
|
19
51
|
void this.start(); }
|
|
20
52
|
dispose() {
|
|
@@ -104,10 +136,19 @@ export class DoctorPage {
|
|
|
104
136
|
await this.start('local', finding.id === 'doctor' ? [] : [finding.id]);
|
|
105
137
|
}
|
|
106
138
|
handleInput(data) {
|
|
139
|
+
const page = Math.max(1, this.scrollRows - 1);
|
|
107
140
|
if (matchesKey(data, 'up'))
|
|
108
141
|
this.offset = Math.max(0, this.offset - 1);
|
|
109
142
|
else if (matchesKey(data, 'down'))
|
|
110
|
-
this.offset
|
|
143
|
+
this.offset = Math.min(this.maxOffset, this.offset + 1);
|
|
144
|
+
else if (matchesKey(data, 'pageUp'))
|
|
145
|
+
this.offset = Math.max(0, this.offset - page);
|
|
146
|
+
else if (matchesKey(data, 'pageDown'))
|
|
147
|
+
this.offset = Math.min(this.maxOffset, this.offset + page);
|
|
148
|
+
else if (matchesKey(data, 'home'))
|
|
149
|
+
this.offset = 0;
|
|
150
|
+
else if (matchesKey(data, 'end'))
|
|
151
|
+
this.offset = this.maxOffset;
|
|
111
152
|
else if (data === 'r')
|
|
112
153
|
void this.start();
|
|
113
154
|
else if (data === 'l')
|
|
@@ -128,18 +169,65 @@ export class DoctorPage {
|
|
|
128
169
|
render(width, rows) {
|
|
129
170
|
if (width < 1 || rows < 1)
|
|
130
171
|
return [];
|
|
172
|
+
const theme = this.options.theme();
|
|
131
173
|
const report = this.report;
|
|
132
|
-
const counts = report?.findings.reduce((all, finding) => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
])
|
|
141
|
-
]
|
|
142
|
-
|
|
143
|
-
|
|
174
|
+
const counts = report?.findings.reduce((all, finding) => {
|
|
175
|
+
all[finding.status] = (all[finding.status] ?? 0) + 1;
|
|
176
|
+
return all;
|
|
177
|
+
}, {}) ?? {};
|
|
178
|
+
const stateTone = report?.state === 'completed' ? 'success' : report?.state === 'cancelled' ? 'warning' : 'accent';
|
|
179
|
+
const summary = report ? [
|
|
180
|
+
...wrapTextWithAnsi(theme.bold(theme.fg(stateTone, `${report.mode} · ${report.state} · ${report.completed}/${report.total} checks`)), width),
|
|
181
|
+
...wrapTextWithAnsi(theme.fg('muted', `Account ${oneLine(report.context.accountId ?? 'none')} · Model ${oneLine(report.context.model ?? 'none')}`), width),
|
|
182
|
+
...wrapTextWithAnsi(STATUSES.filter(status => counts[status]).map(status => theme.fg(STATUS_TONE[status], `${counts[status]} ${status}`)).join(theme.fg('dim', ' · ')), width)
|
|
183
|
+
] : [theme.fg(this.error ? 'error' : 'dim', this.error ?? 'Preparing diagnostics…')];
|
|
184
|
+
if (this.error && report)
|
|
185
|
+
summary.unshift(...wrapTextWithAnsi(theme.fg('error', this.error), width));
|
|
186
|
+
const content = [];
|
|
187
|
+
if (report?.findings.length) {
|
|
188
|
+
const statusWidth = 11;
|
|
189
|
+
const categoryWidth = 14;
|
|
190
|
+
const verificationWidth = 12;
|
|
191
|
+
const gapsWidth = 6;
|
|
192
|
+
const checkWidth = width - statusWidth - categoryWidth - verificationWidth - gapsWidth;
|
|
193
|
+
if (checkWidth >= 18) {
|
|
194
|
+
const widths = [statusWidth, checkWidth, categoryWidth, verificationWidth];
|
|
195
|
+
content.push(...tableRow([
|
|
196
|
+
theme.bold(theme.fg('dim', 'STATUS')),
|
|
197
|
+
theme.bold(theme.fg('dim', 'CHECK')),
|
|
198
|
+
theme.bold(theme.fg('dim', 'CATEGORY')),
|
|
199
|
+
theme.bold(theme.fg('dim', 'VERIFY'))
|
|
200
|
+
], widths, width));
|
|
201
|
+
for (const [index, finding] of report.findings.entries()) {
|
|
202
|
+
content.push(...tableRow([
|
|
203
|
+
theme.bold(theme.fg(STATUS_TONE[finding.status], finding.status.toUpperCase())),
|
|
204
|
+
oneLine(finding.title), oneLine(finding.category), oneLine(finding.verification)
|
|
205
|
+
], widths, width));
|
|
206
|
+
appendDetails(content, 'Evidence', finding.evidence, width, theme);
|
|
207
|
+
appendDetails(content, 'Next step', finding.remedy, width, theme);
|
|
208
|
+
if (index < report.findings.length - 1)
|
|
209
|
+
content.push('');
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
for (const [index, finding] of report.findings.entries()) {
|
|
214
|
+
const heading = `${theme.bold(theme.fg(STATUS_TONE[finding.status], finding.status.toUpperCase()))} · ${oneLine(finding.title)}`;
|
|
215
|
+
content.push(...wrapTextWithAnsi(heading, width));
|
|
216
|
+
content.push(...wrapTextWithAnsi(theme.fg('dim', `${oneLine(finding.category)} · ${oneLine(finding.verification)}`), width));
|
|
217
|
+
appendDetails(content, 'Evidence', finding.evidence, width, theme);
|
|
218
|
+
appendDetails(content, 'Next step', finding.remedy, width, theme);
|
|
219
|
+
if (index < report.findings.length - 1)
|
|
220
|
+
content.push('');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
content.push(theme.fg('dim', report?.state === 'running' ? 'Waiting for findings…' : 'No findings to show.'));
|
|
226
|
+
}
|
|
227
|
+
const bodyRows = Math.max(0, rows - summary.length);
|
|
228
|
+
this.scrollRows = Math.max(1, bodyRows);
|
|
229
|
+
this.maxOffset = Math.max(0, content.length - bodyRows);
|
|
230
|
+
this.offset = Math.max(0, Math.min(this.offset, this.maxOffset));
|
|
231
|
+
return [...summary, ...content.slice(this.offset, this.offset + bodyRows)].slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
144
232
|
}
|
|
145
233
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Web annotations page (`/annotate:notes`, `/annotate:annotate [url]`): comments a person keeps about web pages. A new annotation
|
|
3
|
+
* is captured in a visible browser window: the whole page, text the person selects, or an element
|
|
4
|
+
* they click. An annotation is private until it is shared with this session, whose agent can then read it
|
|
5
|
+
* with `page_notes_read` (PROP-0017).
|
|
6
|
+
*/
|
|
7
|
+
import type { Theme } from '@earendil-works/pi-coding-agent';
|
|
8
|
+
import type { MenuCall, MenuUi } from "../../pluginMenu.js";
|
|
9
|
+
import type { TabInfo } from "../chrome.js";
|
|
10
|
+
import { type ListRow } from "../list.js";
|
|
11
|
+
import type { TerminalMouseInput } from "../mouse.js";
|
|
12
|
+
import type { TerminalPage } from "../page.js";
|
|
13
|
+
import type { Note } from "../../../annotations/store.js";
|
|
14
|
+
export interface NotesPageOptions {
|
|
15
|
+
theme(): Theme;
|
|
16
|
+
call: MenuCall;
|
|
17
|
+
ui: MenuUi & {
|
|
18
|
+
input(title: string, placeholder?: string): Promise<string | undefined>;
|
|
19
|
+
};
|
|
20
|
+
changed(): void;
|
|
21
|
+
/** Start a new annotation as soon as the page opens (`/annotate:annotate [url]`), on this address when given. */
|
|
22
|
+
start?: {
|
|
23
|
+
url?: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
type Row = {
|
|
27
|
+
kind: 'new';
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'note';
|
|
30
|
+
note: Note;
|
|
31
|
+
};
|
|
32
|
+
export declare const NOTE_KINDS: {
|
|
33
|
+
readonly page: "The whole page";
|
|
34
|
+
readonly text: "Text I select in the window";
|
|
35
|
+
readonly element: "An element I click in the window";
|
|
36
|
+
};
|
|
37
|
+
export declare const NOTE_ACTIONS: {
|
|
38
|
+
readonly reveal: "Show it in the browser window";
|
|
39
|
+
readonly edit: "Edit the annotation";
|
|
40
|
+
readonly resolve: "Mark resolved";
|
|
41
|
+
readonly reopen: "Reopen";
|
|
42
|
+
readonly share: "Let this session's agent read it";
|
|
43
|
+
readonly unshare: "Stop sharing it with this session";
|
|
44
|
+
readonly delete: "Delete";
|
|
45
|
+
};
|
|
46
|
+
export declare class NotesPage implements TerminalPage {
|
|
47
|
+
private readonly options;
|
|
48
|
+
presentation: "centered";
|
|
49
|
+
private notes;
|
|
50
|
+
private sessionId;
|
|
51
|
+
private error;
|
|
52
|
+
private busy;
|
|
53
|
+
private disposed;
|
|
54
|
+
private readonly list;
|
|
55
|
+
constructor(options: NotesPageOptions);
|
|
56
|
+
get focused(): boolean;
|
|
57
|
+
set focused(value: boolean);
|
|
58
|
+
activate(): void;
|
|
59
|
+
dispose(): void;
|
|
60
|
+
tabs(): readonly TabInfo[];
|
|
61
|
+
activeTab(): string;
|
|
62
|
+
hint(): string;
|
|
63
|
+
reload(): Promise<void>;
|
|
64
|
+
private shared;
|
|
65
|
+
rows(): ListRow<Row>[];
|
|
66
|
+
private attempt;
|
|
67
|
+
activateRow(row: Row): Promise<void>;
|
|
68
|
+
/** Opens the capture window, takes what the person points at, and saves their annotation. */
|
|
69
|
+
newNote(startUrl?: string): Promise<void>;
|
|
70
|
+
private noteMenu;
|
|
71
|
+
handleMouse(event: TerminalMouseInput): import("@earendil-works/pi-tui").TuiMouseEventResult | undefined;
|
|
72
|
+
handleInput(data: string): boolean;
|
|
73
|
+
render(width: number, rows: number): string[];
|
|
74
|
+
}
|
|
75
|
+
export {};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { truncateToWidth } from '@earendil-works/pi-tui';
|
|
2
|
+
import { FilterList } from "../list.js";
|
|
3
|
+
const TABS = [{ id: 'notes', title: 'Web annotations' }];
|
|
4
|
+
export const NOTE_KINDS = { page: 'The whole page', text: 'Text I select in the window', element: 'An element I click in the window' };
|
|
5
|
+
export const NOTE_ACTIONS = {
|
|
6
|
+
reveal: 'Show it in the browser window',
|
|
7
|
+
edit: 'Edit the annotation',
|
|
8
|
+
resolve: 'Mark resolved',
|
|
9
|
+
reopen: 'Reopen',
|
|
10
|
+
share: 'Let this session\'s agent read it',
|
|
11
|
+
unshare: 'Stop sharing it with this session',
|
|
12
|
+
delete: 'Delete'
|
|
13
|
+
};
|
|
14
|
+
const clip = (text, size) => (text.length > size ? `${text.slice(0, size - 1)}…` : text);
|
|
15
|
+
function describeTarget(target) {
|
|
16
|
+
if (target.kind === 'text')
|
|
17
|
+
return `“${clip(target.exact.replace(/\s+/g, ' '), 60)}”`;
|
|
18
|
+
if (target.kind === 'element')
|
|
19
|
+
return `<${target.tag}> ${clip(target.name || target.text, 50)}`;
|
|
20
|
+
return 'whole page';
|
|
21
|
+
}
|
|
22
|
+
export class NotesPage {
|
|
23
|
+
options;
|
|
24
|
+
presentation = 'centered';
|
|
25
|
+
notes;
|
|
26
|
+
sessionId = null;
|
|
27
|
+
error;
|
|
28
|
+
busy = false;
|
|
29
|
+
disposed = false;
|
|
30
|
+
list;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
this.options = options;
|
|
33
|
+
this.list = new FilterList({
|
|
34
|
+
theme: options.theme, search: 'always', noun: ['annotation', 'annotations'], empty: 'No web annotations yet',
|
|
35
|
+
onActivate: row => { if (row.data)
|
|
36
|
+
void this.activateRow(row.data); }
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
get focused() { return this.list.focused; }
|
|
40
|
+
set focused(value) { this.list.focused = value; }
|
|
41
|
+
activate() {
|
|
42
|
+
void this.reload().then(() => {
|
|
43
|
+
if (this.options.start)
|
|
44
|
+
void this.newNote(this.options.start.url);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
dispose() { this.disposed = true; }
|
|
48
|
+
tabs() { return TABS; }
|
|
49
|
+
activeTab() { return 'notes'; }
|
|
50
|
+
hint() { return 'Enter choose · type to search · Esc close'; }
|
|
51
|
+
async reload() {
|
|
52
|
+
try {
|
|
53
|
+
const result = await this.options.call('terminal.annotations.list');
|
|
54
|
+
this.notes = result.notes;
|
|
55
|
+
this.sessionId = result.sessionId;
|
|
56
|
+
this.error = undefined;
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
this.error = error instanceof Error ? error.message : String(error);
|
|
60
|
+
}
|
|
61
|
+
if (this.disposed)
|
|
62
|
+
return;
|
|
63
|
+
this.list.setRows(this.rows());
|
|
64
|
+
this.options.changed();
|
|
65
|
+
}
|
|
66
|
+
shared(note) {
|
|
67
|
+
return note.grants.some(grant => grant.principal.sessionId && grant.principal.sessionId === this.sessionId);
|
|
68
|
+
}
|
|
69
|
+
rows() {
|
|
70
|
+
const rows = [{ id: 'new', label: 'New web annotation…', group: 'Actions', detail: 'opens a browser window', tone: 'accent', data: { kind: 'new' } }];
|
|
71
|
+
for (const note of this.notes ?? []) {
|
|
72
|
+
rows.push({
|
|
73
|
+
id: `note:${note.id}`, label: clip(note.body.replace(/\s+/g, ' '), 60), group: 'Annotations',
|
|
74
|
+
detail: `${describeTarget(note.target)} · ${note.status}${this.shared(note) ? ' · shared here' : ''}`,
|
|
75
|
+
tone: note.status === 'resolved' ? 'dim' : this.shared(note) ? 'success' : 'muted',
|
|
76
|
+
searchText: `${note.body} ${note.source.url} ${note.source.title} ${note.tags.join(' ')}`,
|
|
77
|
+
data: { kind: 'note', note }
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return rows;
|
|
81
|
+
}
|
|
82
|
+
async attempt(work) {
|
|
83
|
+
if (this.busy)
|
|
84
|
+
return;
|
|
85
|
+
this.busy = true;
|
|
86
|
+
try {
|
|
87
|
+
const message = await work();
|
|
88
|
+
if (message)
|
|
89
|
+
this.options.ui.notify(message, 'info');
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
this.options.ui.notify(error instanceof Error ? error.message : String(error), 'error');
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
this.busy = false;
|
|
96
|
+
}
|
|
97
|
+
await this.reload();
|
|
98
|
+
}
|
|
99
|
+
async activateRow(row) {
|
|
100
|
+
if (row.kind === 'new')
|
|
101
|
+
return this.newNote();
|
|
102
|
+
return this.noteMenu(row.note);
|
|
103
|
+
}
|
|
104
|
+
/** Opens the capture window, takes what the person points at, and saves their annotation. */
|
|
105
|
+
newNote(startUrl) {
|
|
106
|
+
const { call, ui } = this.options;
|
|
107
|
+
return this.attempt(async () => {
|
|
108
|
+
const url = startUrl ?? await ui.input('Page address', 'https://');
|
|
109
|
+
if (!url)
|
|
110
|
+
return;
|
|
111
|
+
await call('terminal.annotations.open', { url });
|
|
112
|
+
const kind = await ui.select('What does the annotation point at?', Object.values(NOTE_KINDS));
|
|
113
|
+
if (!kind)
|
|
114
|
+
return;
|
|
115
|
+
let envelope;
|
|
116
|
+
if (kind === NOTE_KINDS.page) {
|
|
117
|
+
const identity = await call('terminal.annotations.identity');
|
|
118
|
+
envelope = { ...identity, target: { kind: 'page' } };
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const element = kind === NOTE_KINDS.element;
|
|
122
|
+
const { captureId } = await call('terminal.annotations.begin', { kind: element ? 'element' : 'text' });
|
|
123
|
+
const ready = await ui.confirm(element ? 'Click the element in the browser window' : 'Select the text in the browser window', 'When it is selected, choose Yes to capture it. Choose No to cancel.');
|
|
124
|
+
if (!ready) {
|
|
125
|
+
await call('terminal.annotations.cancel', { captureId });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
envelope = await call('terminal.annotations.capture', { captureId });
|
|
129
|
+
if (!envelope)
|
|
130
|
+
return 'Nothing was selected in the browser window, so no annotation was made.';
|
|
131
|
+
}
|
|
132
|
+
const body = await ui.input('Comment', 'What should change or be remembered?');
|
|
133
|
+
if (!body?.trim())
|
|
134
|
+
return 'An annotation needs a comment; nothing was saved.';
|
|
135
|
+
const tags = (await ui.input('Tags (optional, comma separated)', '') ?? '').split(',').map(tag => tag.trim()).filter(Boolean);
|
|
136
|
+
const share = await ui.confirm('Share it with this session?', 'This session\'s agent can then read the annotation with page_notes_read. You can stop sharing it later.');
|
|
137
|
+
await call('terminal.annotations.create', {
|
|
138
|
+
source: { url: envelope.url, title: envelope.title, capturedAt: new Date().toISOString(), surface: 'terminal', representationHint: envelope.documentId },
|
|
139
|
+
target: envelope.target, body, tags, share
|
|
140
|
+
});
|
|
141
|
+
return share ? 'Annotation saved and shared with this session.' : 'Annotation saved. It stays private until you share it.';
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
async noteMenu(note) {
|
|
145
|
+
const { call, ui } = this.options;
|
|
146
|
+
const choices = [
|
|
147
|
+
NOTE_ACTIONS.reveal,
|
|
148
|
+
NOTE_ACTIONS.edit,
|
|
149
|
+
note.status === 'open' ? NOTE_ACTIONS.resolve : NOTE_ACTIONS.reopen,
|
|
150
|
+
this.shared(note) ? NOTE_ACTIONS.unshare : NOTE_ACTIONS.share,
|
|
151
|
+
NOTE_ACTIONS.delete
|
|
152
|
+
];
|
|
153
|
+
const choice = await ui.select(`${clip(note.source.title || note.source.url, 60)} · ${describeTarget(note.target)}`, choices);
|
|
154
|
+
const id = note.id;
|
|
155
|
+
if (choice === NOTE_ACTIONS.reveal)
|
|
156
|
+
return this.attempt(async () => {
|
|
157
|
+
const result = await call('terminal.annotations.reveal', { id });
|
|
158
|
+
return result.state === 'matched' ? 'Marked in the browser window.' : `The target is ${result.state}${result.reason ? `: ${result.reason}` : ''}.`;
|
|
159
|
+
});
|
|
160
|
+
if (choice === NOTE_ACTIONS.edit)
|
|
161
|
+
return this.attempt(async () => {
|
|
162
|
+
const body = await ui.input('Note', note.body);
|
|
163
|
+
if (!body?.trim() || body === note.body)
|
|
164
|
+
return;
|
|
165
|
+
await call('terminal.annotations.update', { id, expectedVersion: note.version, patch: { body } });
|
|
166
|
+
return 'Annotation saved.';
|
|
167
|
+
});
|
|
168
|
+
if (choice === NOTE_ACTIONS.resolve || choice === NOTE_ACTIONS.reopen)
|
|
169
|
+
return this.attempt(async () => {
|
|
170
|
+
await call('terminal.annotations.update', { id, expectedVersion: note.version, patch: { status: choice === NOTE_ACTIONS.resolve ? 'resolved' : 'open' } });
|
|
171
|
+
});
|
|
172
|
+
if (choice === NOTE_ACTIONS.share || choice === NOTE_ACTIONS.unshare)
|
|
173
|
+
return this.attempt(async () => {
|
|
174
|
+
await call(choice === NOTE_ACTIONS.share ? 'terminal.annotations.share' : 'terminal.annotations.unshare', { id });
|
|
175
|
+
return choice === NOTE_ACTIONS.share ? 'This session\'s agent can read the annotation.' : 'The annotation is no longer shared with this session.';
|
|
176
|
+
});
|
|
177
|
+
if (choice === NOTE_ACTIONS.delete)
|
|
178
|
+
return this.attempt(async () => {
|
|
179
|
+
if (!await ui.confirm('Delete this annotation?', 'It cannot be restored.'))
|
|
180
|
+
return;
|
|
181
|
+
await call('terminal.annotations.delete', { id, expectedVersion: note.version });
|
|
182
|
+
return 'Annotation deleted.';
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
handleMouse(event) {
|
|
186
|
+
return this.list.handleMouse(event);
|
|
187
|
+
}
|
|
188
|
+
handleInput(data) {
|
|
189
|
+
return this.list.handleInput(data);
|
|
190
|
+
}
|
|
191
|
+
render(width, rows) {
|
|
192
|
+
const theme = this.options.theme();
|
|
193
|
+
if (width < 1 || rows < 1)
|
|
194
|
+
return [];
|
|
195
|
+
if (this.error)
|
|
196
|
+
return [theme.fg('error', `Could not read web annotations: ${this.error}`)];
|
|
197
|
+
if (!this.notes)
|
|
198
|
+
return [theme.fg('dim', 'Reading web annotations…')];
|
|
199
|
+
return this.list.render(width, rows).slice(0, rows).map(line => truncateToWidth(line, width, ''));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Plugins page: what this session loads, switched on or off, with trust for plugin code.
|
|
3
|
-
* Enter opens what can be done with a row; nothing changes without a choice made here. A plugin
|
|
4
|
-
* with settings has a Settings row that opens them as a subpage; Esc goes back to the list.
|
|
5
|
-
*/
|
|
6
1
|
import type { Theme } from '@earendil-works/pi-coding-agent';
|
|
7
2
|
import { type MenuCall, type MenuUi } from "../../pluginMenu.js";
|
|
8
3
|
import type { TabInfo } from "../chrome.js";
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Plugins page: what this session loads, switched on or off, with trust for plugin code.
|
|
3
|
+
* Enter opens what can be done with a row; nothing changes without a choice made here. A plugin
|
|
4
|
+
* with settings has a Settings row that opens them as a subpage; Esc goes back to the list.
|
|
5
|
+
*/
|
|
6
|
+
import { describePlugin, surfaceBadge } from "../../../plugins/surfaces.js";
|
|
1
7
|
import { matchesKey, truncateToWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
2
8
|
import { BACK, applyPluginAction, menuRows, rowActions } from "../../pluginMenu.js";
|
|
3
9
|
import { safeText } from "../chrome.js";
|
|
@@ -119,7 +125,7 @@ export class PluginsPage {
|
|
|
119
125
|
const kind = row.whole ? row.note : row.note.replace(/ in .*$/, '');
|
|
120
126
|
return {
|
|
121
127
|
id: this.key(row), group: safeText(row.plugin.title), label: row.whole ? 'Whole plugin' : safeText(row.name),
|
|
122
|
-
detail: `${row.on ? 'on' : 'off'}${kind ? ` · ${kind}` : ''}`, tone: row.on ? 'success' : 'dim',
|
|
128
|
+
detail: `${row.on ? 'on' : 'off'}${kind ? ` · ${kind}` : ''}${row.whole && surfaceBadge(row.plugin.surfaces) ? ` · ${surfaceBadge(row.plugin.surfaces)}` : ''}`, tone: row.on ? 'success' : 'dim',
|
|
123
129
|
searchText: `${row.name} ${row.plugin.title} ${row.note}`
|
|
124
130
|
};
|
|
125
131
|
}
|
|
@@ -136,7 +142,7 @@ export class PluginsPage {
|
|
|
136
142
|
return;
|
|
137
143
|
this.busy = true;
|
|
138
144
|
try {
|
|
139
|
-
const action = await this.options.ui.select(`${row.plugin.title}: ${row.plugin
|
|
145
|
+
const action = await this.options.ui.select(`${row.plugin.title}: ${describePlugin(row.plugin)}`, rowActions(row, this.projectId));
|
|
140
146
|
if (action && action !== BACK && await applyPluginAction(this.options.ui, this.options.call, row, action))
|
|
141
147
|
this.restart = true;
|
|
142
148
|
}
|
|
@@ -220,7 +226,7 @@ export class PluginsPage {
|
|
|
220
226
|
const selected = selectedId?.startsWith(SETTINGS_ROW)
|
|
221
227
|
? this.plugins.find(candidate => `${SETTINGS_ROW}${candidate.id}` === selectedId)
|
|
222
228
|
: this.menu().find(candidate => this.key(candidate) === selectedId)?.plugin;
|
|
223
|
-
const detail = selected && rows >= 8 ? wrapTextWithAnsi(safeText(selected
|
|
229
|
+
const detail = selected && rows >= 8 ? wrapTextWithAnsi(safeText(describePlugin(selected)), width).slice(0, 3) : [];
|
|
224
230
|
const note = this.restart ? ['Saved. Changes apply when this session restarts.'] : [];
|
|
225
231
|
const extra = detail.length + note.length;
|
|
226
232
|
const lines = this.list.render(width, Math.max(2, rows - (extra ? extra + 1 : 0)));
|
|
@@ -16,6 +16,8 @@ export interface TerminalSettingItem {
|
|
|
16
16
|
export interface SettingsPageOptions {
|
|
17
17
|
theme: () => Theme;
|
|
18
18
|
items(): TerminalSettingItem[];
|
|
19
|
+
/** Loads device-local settings that need a protected Harness call. */
|
|
20
|
+
load?(): Promise<void>;
|
|
19
21
|
/** Changes the setting; the page reads the items again afterwards. */
|
|
20
22
|
apply(id: string): Promise<void>;
|
|
21
23
|
notify(message: string, type?: string): void;
|
|
@@ -23,10 +25,13 @@ export interface SettingsPageOptions {
|
|
|
23
25
|
}
|
|
24
26
|
export declare class SettingsPage implements TerminalPage {
|
|
25
27
|
private readonly options;
|
|
28
|
+
readonly presentation = "fullscreen";
|
|
26
29
|
private items;
|
|
27
30
|
private category;
|
|
31
|
+
private disposed;
|
|
28
32
|
private readonly list;
|
|
29
33
|
constructor(options: SettingsPageOptions);
|
|
34
|
+
dispose(): void;
|
|
30
35
|
set focused(value: boolean);
|
|
31
36
|
get focused(): boolean;
|
|
32
37
|
private categories;
|
|
@@ -46,6 +51,9 @@ export declare class SettingsPage implements TerminalPage {
|
|
|
46
51
|
} | {
|
|
47
52
|
readonly id: "context";
|
|
48
53
|
readonly title: "Context";
|
|
54
|
+
} | {
|
|
55
|
+
readonly id: "browser";
|
|
56
|
+
readonly title: "Browser";
|
|
49
57
|
})[];
|
|
50
58
|
activeTab(): string;
|
|
51
59
|
hint(): string;
|
|
@@ -3,13 +3,16 @@ import { safeText } from "../chrome.js";
|
|
|
3
3
|
import { FilterList } from "../list.js";
|
|
4
4
|
const CATEGORIES = [
|
|
5
5
|
{ id: 'appearance', title: 'Appearance' }, { id: 'model', title: 'Model' },
|
|
6
|
-
{ id: 'interaction', title: 'Interaction' }, { id: 'context', title: 'Context' }
|
|
6
|
+
{ id: 'interaction', title: 'Interaction' }, { id: 'context', title: 'Context' },
|
|
7
|
+
{ id: 'browser', title: 'Browser' }
|
|
7
8
|
];
|
|
8
9
|
const tabOf = (item) => item.tab.toLowerCase();
|
|
9
10
|
export class SettingsPage {
|
|
10
11
|
options;
|
|
12
|
+
presentation = 'fullscreen';
|
|
11
13
|
items = [];
|
|
12
14
|
category = '';
|
|
15
|
+
disposed = false;
|
|
13
16
|
list;
|
|
14
17
|
constructor(options) {
|
|
15
18
|
this.options = options;
|
|
@@ -21,6 +24,18 @@ export class SettingsPage {
|
|
|
21
24
|
}
|
|
22
25
|
});
|
|
23
26
|
this.reload();
|
|
27
|
+
if (options.load) {
|
|
28
|
+
void options.load().then(() => {
|
|
29
|
+
if (!this.disposed)
|
|
30
|
+
this.reload();
|
|
31
|
+
}, error => {
|
|
32
|
+
if (!this.disposed)
|
|
33
|
+
options.notify(error instanceof Error ? error.message : String(error), 'error');
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
dispose() {
|
|
38
|
+
this.disposed = true;
|
|
24
39
|
}
|
|
25
40
|
set focused(value) { this.list.focused = value; }
|
|
26
41
|
get focused() { return this.list.focused; }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Theme } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import { type TabInfo } from "../chrome.js";
|
|
3
|
+
import type { TerminalPage } from "../page.js";
|
|
4
|
+
import { type TerminalSubagentActivity } from "../../subagentMonitor.js";
|
|
5
|
+
export interface SubagentsPageOptions {
|
|
6
|
+
theme(): Theme;
|
|
7
|
+
snapshot(): readonly TerminalSubagentActivity[];
|
|
8
|
+
changed(): void;
|
|
9
|
+
now?(): number;
|
|
10
|
+
}
|
|
11
|
+
export declare class SubagentsPage implements TerminalPage {
|
|
12
|
+
private readonly options;
|
|
13
|
+
presentation: "fullscreen";
|
|
14
|
+
private readonly list;
|
|
15
|
+
constructor(options: SubagentsPageOptions);
|
|
16
|
+
get focused(): boolean;
|
|
17
|
+
set focused(value: boolean);
|
|
18
|
+
tabs(): readonly TabInfo[];
|
|
19
|
+
activeTab(): string;
|
|
20
|
+
hint(): string;
|
|
21
|
+
private rows;
|
|
22
|
+
render(width: number, rows: number): string[];
|
|
23
|
+
handleInput(data: string): boolean;
|
|
24
|
+
}
|