@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,32 +1,61 @@
|
|
|
1
1
|
// Starting a session turn: the account, the run record, the compiled prompt, the tools and
|
|
2
2
|
// their gate, then Pi. Everything before Pi answers is synchronous with the caller; the reply
|
|
3
3
|
// itself streams as run events.
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
4
5
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
+
import { isAbsolute, join } from 'node:path';
|
|
6
7
|
import { log } from "../core/bus.js";
|
|
7
8
|
import { HarnessError, invalid } from "../core/errors.js";
|
|
9
|
+
import { formatBashCommandForApproval } from "../core/workspaceBashTool.js";
|
|
8
10
|
import { capabilitySet as parseCapabilitySet, freezeRun } from "../capabilities/runSnapshot.js";
|
|
9
11
|
import { now, writeJson } from "../core/fs.js";
|
|
12
|
+
import { resolveWorkspaceRoot, verifyWorkspaceRoot } from "../core/workspace.js";
|
|
10
13
|
import { takeChars } from "../core/text.js";
|
|
14
|
+
import { BUILTIN_PLUGIN_REGISTRY } from "../plugins/builtin.js";
|
|
11
15
|
import { sessionLaunch } from "../prompt/compile.js";
|
|
12
16
|
import * as attachments from "../plugins/attachments.js";
|
|
13
17
|
import { FIRST_PARTY_PLUGINS, firstPartyExtensions } from "../plugins/firstParty.js";
|
|
14
18
|
import { imagePruning } from "../world/images.js";
|
|
15
19
|
import { materialise } from "../variant/materialise.js";
|
|
16
|
-
import { ASK_USER
|
|
17
|
-
import { CHECKLIST_WRITE
|
|
20
|
+
import { ASK_USER } from "../tools/askUser.js";
|
|
21
|
+
import { CHECKLIST_WRITE } from "../tools/checklist.js";
|
|
22
|
+
import { CHECKPOINT_WRITE, checkpointOf } from "../tools/checkpoint.js";
|
|
18
23
|
import { SESSION_NAME, sessionNameTool } from "../tools/sessionName.js";
|
|
19
|
-
import { subagentTools } from "../tools/spawnSubagent.js";
|
|
20
24
|
import { DEFAULT_TOOL_NAMES } from "../tools/definitions.js";
|
|
21
|
-
import {
|
|
25
|
+
import { GET_CAPABILITIES, getCapabilitiesTool } from "../tools/getCapabilities.js";
|
|
26
|
+
import { isActiveStatus } from "./contracts.js";
|
|
22
27
|
import { SPAWN_SUBAGENT, WAIT_SUBAGENTS, subagentDepth, subagentHistory, subagentNesting } from "./subagents.js";
|
|
23
28
|
import { selectHistory } from "./history.js";
|
|
24
29
|
import { runLineageJoin } from "./lineageJoin.js";
|
|
30
|
+
import { compactionCheckpoint, COMPACTION_CHECKPOINT_EXTENSION } from "./compactionCheckpoint.js";
|
|
31
|
+
import { createSliceState, parseWorkSlice, sliceOf, workSliceGuard, WorkSliceError, WORK_SLICE_EXTENSION } from "./workSlice.js";
|
|
25
32
|
import { piSessionFactory, runTurn, summarize } from "./runner.js";
|
|
26
|
-
import { loadRun, runDir, saveRun, updateRun } from "./runStore.js";
|
|
27
|
-
import {
|
|
33
|
+
import { loadRun, readEvents, runDir, saveRun, updateRun } from "./runStore.js";
|
|
34
|
+
import { combineWorkspaceScope, inspectRunWorkspaceWrite } from "./workspaceBoundary.js";
|
|
35
|
+
import { PLAN_INSTRUCTIONS, PLAN_RESEARCH_SUBAGENT_INSTRUCTIONS, planRefusal, planSection } from "./planMode.js";
|
|
28
36
|
import { CONTINUATION_SECTION_ID, continuationOf, continuationSection } from "./continuation.js";
|
|
29
37
|
import { deliveredSnapshot } from "../prompt/compile.js";
|
|
38
|
+
import { profileSection } from "../agents/profiles.js";
|
|
39
|
+
/** A session command acts on a saved conversation and is never combined with a request of its own. */
|
|
40
|
+
function checkCommand(command, historyFile, input) {
|
|
41
|
+
if (!historyFile)
|
|
42
|
+
throw invalid('There is no saved conversation for this command yet.');
|
|
43
|
+
if (input.plan || input.continueFrom || input.automatic || input.initialBashCommand != null || input.images?.length) {
|
|
44
|
+
throw invalid('A session command runs on its own, without plan mode, a continuation, Bash or images.');
|
|
45
|
+
}
|
|
46
|
+
switch (command?.name) {
|
|
47
|
+
case 'compact': return;
|
|
48
|
+
case 'navigate':
|
|
49
|
+
if (typeof command.entryId !== 'string' || !command.entryId)
|
|
50
|
+
throw invalid('navigate needs the entry to go to.');
|
|
51
|
+
return;
|
|
52
|
+
case 'export':
|
|
53
|
+
if (typeof command.path !== 'string' || !isAbsolute(command.path) || !command.path.endsWith('.html'))
|
|
54
|
+
throw invalid('export needs an absolute .html path.');
|
|
55
|
+
return;
|
|
56
|
+
default: throw invalid('Unknown session command.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
30
59
|
const CONTINUE_TEXT = 'Continue from where you stopped.';
|
|
31
60
|
/** Fills a continuing run's input from the run it continues, refusing anything that would differ. */
|
|
32
61
|
function continueInput(root, input) {
|
|
@@ -34,6 +63,10 @@ function continueInput(root, input) {
|
|
|
34
63
|
if (!continuation.resumable || !continuation.resume)
|
|
35
64
|
throw new HarnessError('continuation_unavailable', `Run ${input.continueFrom} cannot be continued (${continuation.reason ?? 'history_missing'}).`);
|
|
36
65
|
const mismatch = (what) => new HarnessError('continuation_mismatch', `A continuation keeps the earlier run's ${what}.`);
|
|
66
|
+
if (continuation.capabilities?.tools.includes(ASK_USER)
|
|
67
|
+
&& (input.automatic || ['probe', 'improver', 'reflection'].includes(input.run.trigger ?? ''))) {
|
|
68
|
+
throw mismatch('attended question capability');
|
|
69
|
+
}
|
|
37
70
|
if (continuation.sessionId !== input.run.sessionId)
|
|
38
71
|
throw mismatch('session');
|
|
39
72
|
if (input.resume?.nativeSessionId && input.resume.nativeSessionId !== continuation.resume.nativeSessionId)
|
|
@@ -91,7 +124,7 @@ export class Sessions {
|
|
|
91
124
|
diagnosticGate(run, caller) {
|
|
92
125
|
return this.gate(run, caller, new Set(), true);
|
|
93
126
|
}
|
|
94
|
-
gate(run, caller, gated, diagnostic = false) {
|
|
127
|
+
gate(run, caller, gated, diagnostic = false, automatic = false) {
|
|
95
128
|
const { policy } = this.options;
|
|
96
129
|
return {
|
|
97
130
|
ask: (names) => {
|
|
@@ -99,9 +132,19 @@ export class Sessions {
|
|
|
99
132
|
gated.add(name);
|
|
100
133
|
},
|
|
101
134
|
check: async (tool, args) => {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
135
|
+
let record;
|
|
136
|
+
let inspection;
|
|
137
|
+
try {
|
|
138
|
+
record = loadRun(this.env.root, run.runId);
|
|
139
|
+
inspection = inspectRunWorkspaceWrite(record, tool, args);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
return error instanceof Error ? error.message : 'The active project workspace could not be verified.';
|
|
143
|
+
}
|
|
144
|
+
const call = { run: record, caller, tool, args: inspection.input };
|
|
145
|
+
const hostScope = (await policy.scope?.(call)) ?? { allowed: true };
|
|
146
|
+
const scope = combineWorkspaceScope(hostScope, inspection);
|
|
147
|
+
if (!scope.allowed && (scope.automatic || (automatic && inspection.outside) || !scope.requiresApproval))
|
|
105
148
|
return scope.reason ?? 'Outside the approved work scope.';
|
|
106
149
|
try {
|
|
107
150
|
await policy.authorize?.(call);
|
|
@@ -118,11 +161,11 @@ export class Sessions {
|
|
|
118
161
|
return scope.reason ? `Refused in a refinement run: ${scope.reason}` : 'Refused in a refinement run: this call needs a person to approve it.';
|
|
119
162
|
if (call.run.trigger === 'reflection')
|
|
120
163
|
return scope.reason ? `Refused in a reflection run: ${scope.reason}` : 'Refused in a reflection run: this call needs a person to approve it.';
|
|
121
|
-
|
|
164
|
+
const boundaryAction = inspection.outside ? `${inspection.reason} ${summarize(call.args, tool)}` : summarize(call.args);
|
|
122
165
|
const decision = await run.requestApproval({
|
|
123
166
|
target: tool,
|
|
124
|
-
action:
|
|
125
|
-
operation: { tool, args: (args && typeof args === 'object' ? args : {}) },
|
|
167
|
+
action: boundaryAction,
|
|
168
|
+
operation: { tool, args: (call.args && typeof call.args === 'object' ? call.args : {}) },
|
|
126
169
|
rememberable: scope.allowed && !scope.humanOnly,
|
|
127
170
|
standing: scope.humanOnly ? (scope.allowGlobalApproval ? 'switch' : 'none') : undefined
|
|
128
171
|
});
|
|
@@ -135,6 +178,69 @@ export class Sessions {
|
|
|
135
178
|
return error instanceof Error ? error.message : 'Tool was disabled while waiting.';
|
|
136
179
|
}
|
|
137
180
|
return null;
|
|
181
|
+
},
|
|
182
|
+
workspaceBoundaryBypass: async (tool, args) => {
|
|
183
|
+
if (diagnostic || automatic || tool.toLowerCase() !== 'bash')
|
|
184
|
+
return false;
|
|
185
|
+
const record = loadRun(this.env.root, run.runId);
|
|
186
|
+
if (record.trigger != null && record.trigger !== 'user')
|
|
187
|
+
return false;
|
|
188
|
+
if (!await this.options.fullPermission?.(record))
|
|
189
|
+
return false;
|
|
190
|
+
const call = { run: record, caller, tool, args };
|
|
191
|
+
const scope = (await policy.scope?.(call)) ?? { allowed: true };
|
|
192
|
+
if (scope.automatic || (!scope.allowed && !scope.requiresApproval) || (scope.humanOnly && !scope.allowGlobalApproval))
|
|
193
|
+
return false;
|
|
194
|
+
try {
|
|
195
|
+
await policy.authorize?.(call);
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
requestWorkspaceWriteScope: async (tool, args, reason) => {
|
|
203
|
+
if (diagnostic || automatic || tool.toLowerCase() !== 'bash')
|
|
204
|
+
return false;
|
|
205
|
+
const record = loadRun(this.env.root, run.runId);
|
|
206
|
+
if (!isActiveStatus(record.status) || (record.trigger != null && record.trigger !== 'user'))
|
|
207
|
+
return false;
|
|
208
|
+
const operationArgs = (args && typeof args === 'object' && !Array.isArray(args) ? args : {});
|
|
209
|
+
if (operationArgs.workspaceWriteScope !== 'outside' || typeof operationArgs.command !== 'string' || !operationArgs.command)
|
|
210
|
+
return false;
|
|
211
|
+
const call = { run: record, caller, tool, args: operationArgs };
|
|
212
|
+
const scope = (await policy.scope?.(call)) ?? { allowed: true };
|
|
213
|
+
if (scope.automatic || (!scope.allowed && !scope.requiresApproval))
|
|
214
|
+
return false;
|
|
215
|
+
try {
|
|
216
|
+
await policy.authorize?.(call);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
const decision = await run.requestApproval({
|
|
222
|
+
target: 'workspace-write',
|
|
223
|
+
action: `${reason}\n\nCommand to be run once after approval:\n${formatBashCommandForApproval(operationArgs.command)}`,
|
|
224
|
+
operation: { tool, args: operationArgs },
|
|
225
|
+
rememberable: false,
|
|
226
|
+
standing: 'none'
|
|
227
|
+
});
|
|
228
|
+
if (decision !== 'approved')
|
|
229
|
+
return false;
|
|
230
|
+
const currentRecord = loadRun(this.env.root, run.runId);
|
|
231
|
+
if (!isActiveStatus(currentRecord.status) || (currentRecord.trigger != null && currentRecord.trigger !== 'user'))
|
|
232
|
+
return false;
|
|
233
|
+
const currentCall = { run: currentRecord, caller, tool, args: operationArgs };
|
|
234
|
+
const currentScope = (await policy.scope?.(currentCall)) ?? { allowed: true };
|
|
235
|
+
if (currentScope.automatic || (!currentScope.allowed && !currentScope.requiresApproval))
|
|
236
|
+
return false;
|
|
237
|
+
try {
|
|
238
|
+
await policy.authorize?.(currentCall);
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
138
244
|
}
|
|
139
245
|
};
|
|
140
246
|
}
|
|
@@ -147,10 +253,96 @@ export class Sessions {
|
|
|
147
253
|
* session that cannot be opened ends its run as failed and returns no native session id.
|
|
148
254
|
*/
|
|
149
255
|
async run(input) {
|
|
150
|
-
const { root } = this.env;
|
|
151
256
|
if (!input?.run?.id || !input.run.sessionId || typeof input.text !== 'string')
|
|
152
257
|
throw invalid('A session turn needs a run id, a session, and text.');
|
|
153
258
|
input = structuredClone(input);
|
|
259
|
+
const worktree = await this.enterWorktree(input);
|
|
260
|
+
try {
|
|
261
|
+
return await this.start(input);
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
await worktree?.release();
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* A run that names a worktree the harness manages works in that worktree's folder and holds it
|
|
270
|
+
* until the run settles. An id the harness does not know is kept as the caller's own field.
|
|
271
|
+
*/
|
|
272
|
+
async enterWorktree(input) {
|
|
273
|
+
const id = input.run.worktreeId;
|
|
274
|
+
const worktrees = this.options.worktrees;
|
|
275
|
+
if (!id || !worktrees)
|
|
276
|
+
return null;
|
|
277
|
+
const path = worktrees.pathOf(id);
|
|
278
|
+
if (!path)
|
|
279
|
+
return null;
|
|
280
|
+
const holder = input.run.sessionId;
|
|
281
|
+
await worktrees.acquire(id, holder);
|
|
282
|
+
input.cwd = path;
|
|
283
|
+
let released = false;
|
|
284
|
+
const release = async () => {
|
|
285
|
+
if (released)
|
|
286
|
+
return;
|
|
287
|
+
released = true;
|
|
288
|
+
stop();
|
|
289
|
+
await worktrees.release(id, holder).catch(() => undefined);
|
|
290
|
+
};
|
|
291
|
+
const stop = this.options.runs.listen((event) => {
|
|
292
|
+
if (event.runId !== input.run.id)
|
|
293
|
+
return;
|
|
294
|
+
const settled = event.type === 'completed' || event.type === 'failed' || (event.type === 'status.changed' && event.payload.status === 'interrupted');
|
|
295
|
+
if (settled)
|
|
296
|
+
void release();
|
|
297
|
+
});
|
|
298
|
+
return { release };
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Starts the next slice when a reply stopped at its work-slice boundary (PROP-0041). Never for
|
|
302
|
+
* unattended, plan, subagent, command or worktree runs, after a blocked or fruitless slice, or
|
|
303
|
+
* past the policy's slice cap. The earlier record is never reopened; this is a new run with the
|
|
304
|
+
* same pins, exactly as an application-asked continuation.
|
|
305
|
+
*/
|
|
306
|
+
async continueSlice(input) {
|
|
307
|
+
const { root, runId, source, policy } = input;
|
|
308
|
+
if (!policy.enabled || !policy.continue || policy.maxSlices <= 0)
|
|
309
|
+
return;
|
|
310
|
+
if (source.automatic || source.plan || source.command || source.run.relation || source.run.worktreeId)
|
|
311
|
+
return;
|
|
312
|
+
if ((source.depth ?? 0) > 0)
|
|
313
|
+
return;
|
|
314
|
+
const record = loadRun(root, runId);
|
|
315
|
+
if (record.terminalReason !== 'slice_complete')
|
|
316
|
+
return;
|
|
317
|
+
const events = readEvents(root, runId);
|
|
318
|
+
const checkpoint = checkpointOf(events);
|
|
319
|
+
if (checkpoint?.blocked)
|
|
320
|
+
return;
|
|
321
|
+
const progressed = events.some((event) => event.type === 'file.changed')
|
|
322
|
+
|| events.some((event) => {
|
|
323
|
+
const payload = event.payload;
|
|
324
|
+
return event.type === 'tool.completed' && payload.name === 'bash' && payload.ok === true;
|
|
325
|
+
})
|
|
326
|
+
|| (checkpoint?.done.length ?? 0) > 0;
|
|
327
|
+
if (!progressed)
|
|
328
|
+
return;
|
|
329
|
+
if (sliceOf(root, runId) >= policy.maxSlices)
|
|
330
|
+
return;
|
|
331
|
+
const next = {
|
|
332
|
+
...source,
|
|
333
|
+
run: { ...source.run, id: randomUUID(), resumedFromRunId: null, parentRunId: null, relation: null },
|
|
334
|
+
continueFrom: runId,
|
|
335
|
+
text: CONTINUE_TEXT
|
|
336
|
+
};
|
|
337
|
+
next.initialBashCommand = undefined;
|
|
338
|
+
next.initialBashContext = undefined;
|
|
339
|
+
next.images = undefined;
|
|
340
|
+
next.resume = null;
|
|
341
|
+
next.command = undefined;
|
|
342
|
+
await this.run(next).catch((error) => log(`the next work slice did not start: ${error instanceof Error ? error.message : String(error)}`));
|
|
343
|
+
}
|
|
344
|
+
async start(input) {
|
|
345
|
+
const { root } = this.env;
|
|
154
346
|
if ((input.initialBashCommand !== undefined && input.initialBashCommand !== null) || (input.initialBashContext !== undefined && input.initialBashContext !== null)) {
|
|
155
347
|
const request = input.text.trimStart();
|
|
156
348
|
const requestedCommand = /^!\s*([\s\S]+)$/u.exec(request)?.[1];
|
|
@@ -176,8 +368,23 @@ export class Sessions {
|
|
|
176
368
|
throw invalid('An initial Bash command is available only for a new interactive user turn.');
|
|
177
369
|
}
|
|
178
370
|
}
|
|
371
|
+
let slicePolicy;
|
|
372
|
+
try {
|
|
373
|
+
slicePolicy = parseWorkSlice(input.workSlice);
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
if (error instanceof WorkSliceError)
|
|
377
|
+
throw invalid(error.message);
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
179
380
|
const continuation = input.continueFrom ? continueInput(root, input) : null;
|
|
381
|
+
const previousRun = continuation ? loadRun(root, continuation.runId) : null;
|
|
382
|
+
const workspaceRoot = previousRun?.workspaceRoot
|
|
383
|
+
? verifyWorkspaceRoot(previousRun.workspaceRoot)
|
|
384
|
+
: resolveWorkspaceRoot(previousRun?.workingDirectory ?? input.cwd);
|
|
180
385
|
const historyFile = selectHistory({ sessionDir: input.sessionDir, resume: input.resume });
|
|
386
|
+
if (input.command)
|
|
387
|
+
checkCommand(input.command, historyFile, input);
|
|
181
388
|
const account = this.options.accounts.resolve(input.accountId, input.poolId);
|
|
182
389
|
const context = this.options.accounts.context(account);
|
|
183
390
|
const runId = input.run.id;
|
|
@@ -185,9 +392,15 @@ export class Sessions {
|
|
|
185
392
|
const broker = input.connections ? this.options.broker : null;
|
|
186
393
|
const depth = input.depth ?? 0;
|
|
187
394
|
const canSpawn = input.subagents !== null && (!input.automatic || input.subagents !== undefined) && subagentNesting(root, input.run) < subagentDepth(input.subagents ?? undefined);
|
|
395
|
+
const pinnedAskUser = continuation?.capabilities?.tools.includes(ASK_USER) ?? false;
|
|
396
|
+
const interactivePlan = input.plan === true
|
|
397
|
+
&& !input.automatic
|
|
398
|
+
&& (input.run.trigger === undefined || input.run.trigger === null || input.run.trigger === 'user');
|
|
399
|
+
const harnessToolsEnabled = input.harnessTools !== false || pinnedAskUser;
|
|
400
|
+
const canAskUser = pinnedAskUser || (interactivePlan && harnessToolsEnabled);
|
|
188
401
|
const requestedTools = [...new Set([
|
|
189
|
-
...input.tools.allow.filter((name) => name !== SPAWN_SUBAGENT && name !== WAIT_SUBAGENTS),
|
|
190
|
-
...(
|
|
402
|
+
...input.tools.allow.filter((name) => name !== SPAWN_SUBAGENT && name !== WAIT_SUBAGENTS && (name !== ASK_USER || canAskUser)),
|
|
403
|
+
...(harnessToolsEnabled ? [...(canAskUser ? [ASK_USER] : []), CHECKLIST_WRITE, CHECKPOINT_WRITE, SESSION_NAME, GET_CAPABILITIES, ...DEFAULT_TOOL_NAMES] : []),
|
|
191
404
|
...(broker?.toolNames ?? []),
|
|
192
405
|
...(canSpawn ? [SPAWN_SUBAGENT, WAIT_SUBAGENTS] : [])
|
|
193
406
|
])];
|
|
@@ -224,6 +437,7 @@ export class Sessions {
|
|
|
224
437
|
sessionId: input.run.sessionId,
|
|
225
438
|
nativeSessionId: null,
|
|
226
439
|
workingDirectory: input.cwd,
|
|
440
|
+
workspaceRoot,
|
|
227
441
|
worktreeId: input.run.worktreeId ?? null,
|
|
228
442
|
goal: input.run.goal ?? takeChars(input.text, 4000),
|
|
229
443
|
attachmentCount: input.run.attachmentCount ?? 0,
|
|
@@ -236,7 +450,9 @@ export class Sessions {
|
|
|
236
450
|
agentId: input.run.agentId ?? caller.agentId ?? null,
|
|
237
451
|
trigger: input.run.trigger ?? null,
|
|
238
452
|
variantScope: variant?.scope ?? null,
|
|
239
|
-
variantVersion: variant?.fingerprint ?? null
|
|
453
|
+
variantVersion: variant?.fingerprint ?? null,
|
|
454
|
+
...(input.run.profile ? { profile: input.run.profile } : {}),
|
|
455
|
+
...(input.run.title ? { title: input.run.title } : {})
|
|
240
456
|
});
|
|
241
457
|
// What the session is, kept with the run so later consolidation knows which memory it had.
|
|
242
458
|
try {
|
|
@@ -256,10 +472,14 @@ export class Sessions {
|
|
|
256
472
|
if (!existsSync(input.sessionDir))
|
|
257
473
|
mkdirSync(input.sessionDir, { recursive: true });
|
|
258
474
|
const launch = input.launch ?? {};
|
|
259
|
-
const plan = planSection(input.plan === true, historyFile);
|
|
475
|
+
const plan = planSection(input.plan === true, historyFile, input.run.relation === 'subagent');
|
|
260
476
|
const delivered = historyFile ? deliveredSnapshot(historyFile) : null;
|
|
261
477
|
const resumed = continuationSection(continuation, delivered?.some((entry) => entry.id === CONTINUATION_SECTION_ID) ?? false);
|
|
262
|
-
|
|
478
|
+
// The profiles replace the variant's own subagent list, which they include.
|
|
479
|
+
const profiles = capabilities.tools.includes(SPAWN_SUBAGENT) ? profileSection(root, input.cwd, variant?.dir ?? null, input.plan === true) : null;
|
|
480
|
+
if (profiles && variant)
|
|
481
|
+
variant = { ...variant, sections: variant.sections.filter((section) => section.id !== profiles.id) };
|
|
482
|
+
const own = [plan, resumed, profiles].filter((section) => section !== null);
|
|
263
483
|
const effectiveLaunch = {
|
|
264
484
|
...launch,
|
|
265
485
|
sections: own.length ? [...(launch.sections ?? []).filter((section) => !own.some((entry) => entry.id === section.id)), ...own] : launch.sections,
|
|
@@ -273,6 +493,9 @@ export class Sessions {
|
|
|
273
493
|
fail(error);
|
|
274
494
|
throw error;
|
|
275
495
|
}
|
|
496
|
+
// A reply is bounded only when its checkpoint tool is part of the frozen capability set.
|
|
497
|
+
const sliceEnabled = slicePolicy.enabled && capabilities.tools.includes(CHECKPOINT_WRITE);
|
|
498
|
+
const sliceState = createSliceState(slicePolicy, sliceOf(root, runId));
|
|
276
499
|
const run = this.options.runs.start(input.run.sessionId, runId);
|
|
277
500
|
if (run.finished)
|
|
278
501
|
return { runId, nativeSessionId: null };
|
|
@@ -295,9 +518,23 @@ export class Sessions {
|
|
|
295
518
|
});
|
|
296
519
|
try {
|
|
297
520
|
const tools = [
|
|
298
|
-
...(
|
|
299
|
-
|
|
300
|
-
|
|
521
|
+
...(harnessToolsEnabled && allow.includes(GET_CAPABILITIES) ? [getCapabilitiesTool(() => ({
|
|
522
|
+
capabilities,
|
|
523
|
+
active: pi?.getActiveToolNames?.() ?? [],
|
|
524
|
+
registered: pi?.getAllTools?.() ?? []
|
|
525
|
+
}))] : []),
|
|
526
|
+
...BUILTIN_PLUGIN_REGISTRY.tools({
|
|
527
|
+
env: this.options.env,
|
|
528
|
+
caller,
|
|
529
|
+
variantDir: variant?.dir ?? null,
|
|
530
|
+
run,
|
|
531
|
+
runId,
|
|
532
|
+
allowedTools: allow,
|
|
533
|
+
harnessTools: harnessToolsEnabled,
|
|
534
|
+
subagents: this.options.subagents,
|
|
535
|
+
sessionName: naming,
|
|
536
|
+
...(broker ? { connectionTools: () => broker.tools(session, { readOnly: typeof input.connections === 'object' && input.connections.readOnly === true }) } : {})
|
|
537
|
+
})
|
|
301
538
|
];
|
|
302
539
|
if (input.providers !== false) {
|
|
303
540
|
const named = new Set(tools.map((tool) => tool.name));
|
|
@@ -312,12 +549,15 @@ export class Sessions {
|
|
|
312
549
|
}
|
|
313
550
|
}
|
|
314
551
|
const readOnly = new Set(tools.filter((tool) => tool.readOnly).map((tool) => tool.name));
|
|
552
|
+
const checkpointPlanInstructions = input.plan
|
|
553
|
+
? () => input.run.relation === 'subagent' ? PLAN_RESEARCH_SUBAGENT_INSTRUCTIONS : PLAN_INSTRUCTIONS
|
|
554
|
+
: undefined;
|
|
315
555
|
const planModeSafety = new Map();
|
|
316
556
|
for (const tool of tools)
|
|
317
557
|
if (tool.planModeSafe)
|
|
318
558
|
planModeSafety.set(tool.name, tool.planModeSafe);
|
|
319
559
|
const gate = (() => {
|
|
320
|
-
const baseGate = this.gate(run, caller, new Set((input.tools.gated ?? []).filter((name) => capabilities.tools.includes(name))));
|
|
560
|
+
const baseGate = this.gate(run, caller, new Set((input.tools.gated ?? []).filter((name) => capabilities.tools.includes(name))), false, input.automatic === true);
|
|
321
561
|
return {
|
|
322
562
|
...baseGate,
|
|
323
563
|
check: (name, args) => {
|
|
@@ -334,7 +574,9 @@ export class Sessions {
|
|
|
334
574
|
...(input.initialBashContext !== undefined && input.initialBashContext !== null ? { initialBashContext: input.initialBashContext } : {}),
|
|
335
575
|
gate,
|
|
336
576
|
restrictTools: input.run.relation === 'subagent',
|
|
577
|
+
...(input.plan ? { plan: true } : {}),
|
|
337
578
|
cwd: input.cwd,
|
|
579
|
+
workspaceRoot,
|
|
338
580
|
sessionDir: input.sessionDir,
|
|
339
581
|
historyFile,
|
|
340
582
|
model: input.model ?? null,
|
|
@@ -347,10 +589,20 @@ export class Sessions {
|
|
|
347
589
|
account: context,
|
|
348
590
|
resources: { ids: [], skillPaths: variant?.skillPaths ?? [], promptPaths: [] },
|
|
349
591
|
variantExtensions: variant?.extensionPaths ?? [],
|
|
350
|
-
inline: [
|
|
592
|
+
inline: [
|
|
593
|
+
...firstPartyFor(root, capabilities.contributions),
|
|
594
|
+
runLineageJoin(root, runId),
|
|
595
|
+
this.options.subagents.extension(runId),
|
|
596
|
+
{ name: 'image-pruning', factory: imagePruning() },
|
|
597
|
+
{ name: COMPACTION_CHECKPOINT_EXTENSION, factory: compactionCheckpoint({ initialChecklist: continuation?.checklist, planInstructions: checkpointPlanInstructions }) },
|
|
598
|
+
...(sliceEnabled ? [{ name: WORK_SLICE_EXTENSION, factory: workSliceGuard({ policy: slicePolicy, state: sliceState }) }] : [])
|
|
599
|
+
],
|
|
351
600
|
...(plugins ? { plugins: { loading: () => plugins.loading({ cwd: input.cwd, agentDir: context.configDir, install: true, caller: { agentId: caller.agentId ?? null, projectId: caller.projectId ?? null }, contributions: capabilities.contributions }), loaded: (extensions) => plugins.loaded(extensions) } } : {}),
|
|
352
601
|
system,
|
|
353
|
-
|
|
602
|
+
...(sliceEnabled ? { slice: { state: sliceState, maxToolCalls: slicePolicy.maxToolCalls } } : {}),
|
|
603
|
+
// A command sends no request of its own, so the context update waits for the next turn.
|
|
604
|
+
update: input.command ? null : update,
|
|
605
|
+
...(input.command ? { command: input.command } : {})
|
|
354
606
|
};
|
|
355
607
|
pi = await this.factory({
|
|
356
608
|
params,
|
|
@@ -378,7 +630,7 @@ export class Sessions {
|
|
|
378
630
|
if (pi.model?.id && pi.model.provider)
|
|
379
631
|
this.options.subagents.resolvedModel(runId, `${pi.model.provider}/${pi.model.id}`, pi.thinkingLevel);
|
|
380
632
|
params.settle = () => this.options.subagents.verify(runId, opened.sessionManager ? subagentHistory(opened.sessionManager.getBranch()) : undefined);
|
|
381
|
-
void runTurn(run, pi, params);
|
|
633
|
+
void runTurn(run, pi, params).then(() => (sliceEnabled && !input.command ? this.continueSlice({ root, runId, source: input, policy: slicePolicy }) : undefined));
|
|
382
634
|
return { runId, nativeSessionId: pi.sessionId };
|
|
383
635
|
}
|
|
384
636
|
catch (error) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { invalid } from "../core/errors.js";
|
|
2
|
+
export function sideQuestionServerMethods(harness) {
|
|
3
|
+
return {
|
|
4
|
+
'sideQuestions.start': params => harness.sideQuestions.start(params),
|
|
5
|
+
'sideQuestions.read': params => {
|
|
6
|
+
if (typeof params.runId !== 'string' || typeof params.sessionId !== 'string')
|
|
7
|
+
throw invalid('A side-question run and session id are required.');
|
|
8
|
+
const afterSequence = params.afterSequence === undefined ? -1 : params.afterSequence;
|
|
9
|
+
if (typeof afterSequence !== 'number')
|
|
10
|
+
throw invalid('A side-question event sequence is required.');
|
|
11
|
+
return harness.sideQuestions.read(params.runId, params.sessionId, afterSequence);
|
|
12
|
+
},
|
|
13
|
+
'sideQuestions.interrupt': params => {
|
|
14
|
+
if (typeof params.runId !== 'string' || typeof params.sessionId !== 'string')
|
|
15
|
+
throw invalid('A side-question run and session id are required.');
|
|
16
|
+
return harness.sideQuestions.interrupt(params.runId, params.sessionId);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { RunEvent, RunRecord } from "./contracts.js";
|
|
2
|
+
import type { RunRegistry } from "./registry.js";
|
|
3
|
+
import type { SessionRunInput, Sessions } from "./sessions.js";
|
|
4
|
+
import type { HarnessEnv } from "../core/env.js";
|
|
5
|
+
import type { CallerContext } from "../core/caller.js";
|
|
6
|
+
import type { Reference } from "../prompt/compile.js";
|
|
7
|
+
export declare const SIDE_QUESTION_INSTRUCTION: string;
|
|
8
|
+
export interface SideQuestionContext {
|
|
9
|
+
/** Used when the source has no Harness run event containing its effective system prompt. */
|
|
10
|
+
instructions?: string;
|
|
11
|
+
/** Visible conversation text and public progress supplied by the surface. */
|
|
12
|
+
transcript?: string;
|
|
13
|
+
/** References selected specifically for this side question, supplied as untrusted context data. */
|
|
14
|
+
references?: Reference[];
|
|
15
|
+
}
|
|
16
|
+
export interface SideQuestionStartInput {
|
|
17
|
+
/** Optional caller-reserved identifiers; the Harness creates these when omitted. */
|
|
18
|
+
runId?: string;
|
|
19
|
+
sessionId?: string;
|
|
20
|
+
/** The main run whose persisted prompt and public run events should be mirrored. */
|
|
21
|
+
parentRunId?: string | null;
|
|
22
|
+
/** The conversation session that owns parentRunId when the side run uses a fresh session id. */
|
|
23
|
+
parentSessionId?: string | null;
|
|
24
|
+
accountId?: string | null;
|
|
25
|
+
model?: string | null;
|
|
26
|
+
effort?: SessionRunInput['effort'];
|
|
27
|
+
cwd: string;
|
|
28
|
+
caller: CallerContext;
|
|
29
|
+
question: string;
|
|
30
|
+
context?: SideQuestionContext;
|
|
31
|
+
}
|
|
32
|
+
export interface SideQuestionRead {
|
|
33
|
+
run: RunRecord;
|
|
34
|
+
events: RunEvent[];
|
|
35
|
+
}
|
|
36
|
+
export interface BuildSideQuestionTextInput {
|
|
37
|
+
question: string;
|
|
38
|
+
context?: SideQuestionContext;
|
|
39
|
+
references?: readonly string[];
|
|
40
|
+
parentEvents?: readonly RunEvent[];
|
|
41
|
+
parentStatus?: string | null;
|
|
42
|
+
}
|
|
43
|
+
/** Bounded, redacted context copied into the side run's user message. */
|
|
44
|
+
export declare function buildSideQuestionText(input: BuildSideQuestionTextInput): string;
|
|
45
|
+
export interface SideQuestionsOptions {
|
|
46
|
+
env: HarnessEnv;
|
|
47
|
+
sessions: Sessions;
|
|
48
|
+
runs: RunRegistry;
|
|
49
|
+
}
|
|
50
|
+
/** A single Harness-owned side-question capability shared by hosts and the standalone terminal. */
|
|
51
|
+
export declare class SideQuestions {
|
|
52
|
+
private readonly options;
|
|
53
|
+
private readonly sessionDirs;
|
|
54
|
+
private readonly unsubscribe;
|
|
55
|
+
constructor(options: SideQuestionsOptions);
|
|
56
|
+
start(raw: SideQuestionStartInput): Promise<{
|
|
57
|
+
runId: string;
|
|
58
|
+
sessionId: string;
|
|
59
|
+
nativeSessionId: string | null;
|
|
60
|
+
}>;
|
|
61
|
+
read(runId: string, sessionId: string, afterSequence?: number): SideQuestionRead;
|
|
62
|
+
interrupt(runId: string, sessionId: string): Promise<{
|
|
63
|
+
runId: string;
|
|
64
|
+
}>;
|
|
65
|
+
close(): Promise<void>;
|
|
66
|
+
}
|