@xingular/harness 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -5
- package/README.md +75 -21
- package/dist/cli.js +17421 -8711
- package/dist/sdk/accounts/accounts.d.ts +27 -3
- package/dist/sdk/accounts/accounts.js +78 -24
- package/dist/sdk/accounts/secrets.d.ts +12 -0
- package/dist/sdk/accounts/secrets.js +114 -7
- package/dist/sdk/accounts/store.d.ts +26 -1
- package/dist/sdk/accounts/store.js +1 -1
- package/dist/sdk/agents/builtin.d.ts +2 -0
- package/dist/sdk/agents/builtin.js +48 -0
- package/dist/sdk/agents/narrow.d.ts +13 -0
- package/dist/sdk/agents/narrow.js +29 -0
- package/dist/sdk/agents/planResearch.d.ts +5 -0
- package/dist/sdk/agents/planResearch.js +19 -0
- package/dist/sdk/agents/profiles.d.ts +81 -0
- package/dist/sdk/agents/profiles.js +226 -0
- package/dist/sdk/annotations/bridge.d.ts +42 -0
- package/dist/sdk/annotations/bridge.js +264 -0
- package/dist/sdk/annotations/capture.d.ts +116 -0
- package/dist/sdk/annotations/capture.js +308 -0
- package/dist/sdk/annotations/delivery.d.ts +72 -0
- package/dist/sdk/annotations/delivery.js +130 -0
- package/dist/sdk/annotations/inspect.d.ts +10 -0
- package/dist/sdk/annotations/inspect.js +33 -0
- package/dist/sdk/annotations/isolated.d.ts +6 -0
- package/dist/sdk/annotations/isolated.js +51 -0
- package/dist/sdk/annotations/pageScript.d.ts +28 -0
- package/dist/sdk/annotations/pageScript.js +871 -0
- package/dist/sdk/annotations/part.d.ts +10 -0
- package/dist/sdk/annotations/part.js +155 -0
- package/dist/sdk/annotations/queue.d.ts +4 -0
- package/dist/sdk/annotations/queue.js +40 -0
- package/dist/sdk/annotations/serverMethods.d.ts +3 -0
- package/dist/sdk/annotations/serverMethods.js +62 -0
- package/dist/sdk/annotations/store.d.ts +167 -0
- package/dist/sdk/annotations/store.js +394 -0
- package/dist/sdk/browser/backend.d.ts +16 -0
- package/dist/sdk/browser/backend.js +17 -0
- package/dist/sdk/browser/contracts.d.ts +19 -0
- package/dist/sdk/browser/contracts.js +116 -0
- package/dist/sdk/browser/index.d.ts +14 -3
- package/dist/sdk/browser/index.js +11 -4
- package/dist/sdk/browser/serverMethods.d.ts +3 -0
- package/dist/sdk/browser/serverMethods.js +7 -0
- package/dist/sdk/browser/session.d.ts +1 -0
- package/dist/sdk/browser/session.js +45 -9
- package/dist/sdk/browser/tools.d.ts +1 -4
- package/dist/sdk/browser/tools.js +14 -91
- package/dist/sdk/cli.js +24 -15
- package/dist/sdk/commands/list.d.ts +3 -0
- package/dist/sdk/commands/list.js +75 -0
- package/dist/sdk/commands/registry.d.ts +250 -0
- package/dist/sdk/commands/registry.js +47 -0
- package/dist/sdk/commands/routes.d.ts +16 -0
- package/dist/sdk/commands/routes.js +33 -0
- package/dist/sdk/core/bus.js +1 -1
- package/dist/sdk/core/commandBudget.d.ts +23 -0
- package/dist/sdk/core/commandBudget.js +57 -0
- package/dist/sdk/core/env.d.ts +1 -1
- package/dist/sdk/core/env.js +1 -1
- package/dist/sdk/core/index.js +17 -1
- package/dist/sdk/core/interactiveProfile.d.ts +46 -0
- package/dist/sdk/core/interactiveProfile.js +143 -0
- package/dist/sdk/core/workspace.d.ts +13 -0
- package/dist/sdk/core/workspace.js +88 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +4 -0
- package/dist/sdk/core/workspaceBashTool.js +36 -0
- package/dist/sdk/core/workspaceSandbox.d.ts +31 -0
- package/dist/sdk/core/workspaceSandbox.js +320 -0
- package/dist/sdk/core/workspaceWriteOperations.d.ts +22 -0
- package/dist/sdk/core/workspaceWriteOperations.js +206 -0
- package/dist/sdk/doctor/serverMethods.d.ts +3 -0
- package/dist/sdk/doctor/serverMethods.js +8 -0
- package/dist/sdk/doctor/types.d.ts +2 -2
- package/dist/sdk/harness.d.ts +22 -0
- package/dist/sdk/harness.js +84 -5
- package/dist/sdk/history/recall.js +8 -8
- package/dist/sdk/history/serverMethods.d.ts +3 -0
- package/dist/sdk/history/serverMethods.js +8 -0
- package/dist/sdk/hub/cli.d.ts +1 -1
- package/dist/sdk/hub/cli.js +1 -1
- package/dist/sdk/hub/schema.d.ts +1 -1
- package/dist/sdk/hub/serverMethods.d.ts +3 -0
- package/dist/sdk/hub/serverMethods.js +11 -0
- package/dist/sdk/index.d.ts +16 -1
- package/dist/sdk/index.js +10 -0
- package/dist/sdk/mcp/connections.js +14 -7
- package/dist/sdk/mcp/serverMethods.d.ts +3 -0
- package/dist/sdk/mcp/serverMethods.js +22 -0
- package/dist/sdk/pi/runtime.d.ts +2 -1
- package/dist/sdk/pi/runtime.js +2 -2
- package/dist/sdk/plugins/builtin.d.ts +1 -0
- package/dist/sdk/plugins/builtin.js +145 -33
- package/dist/sdk/plugins/builtinRegistry.d.ts +60 -0
- package/dist/sdk/plugins/builtinRegistry.js +71 -0
- package/dist/sdk/plugins/catalogue.js +2 -1
- package/dist/sdk/plugins/cli.d.ts +1 -1
- package/dist/sdk/plugins/cli.js +4 -3
- package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
- package/dist/sdk/plugins/commandPrefix.js +21 -0
- package/dist/sdk/plugins/firstParty.d.ts +1 -1
- package/dist/sdk/plugins/firstParty.js +8 -2
- package/dist/sdk/plugins/inventory.js +4 -3
- package/dist/sdk/plugins/manifest.d.ts +2 -0
- package/dist/sdk/plugins/manifest.js +2 -1
- package/dist/sdk/plugins/surfaces.d.ts +5 -0
- package/dist/sdk/plugins/surfaces.js +11 -0
- package/dist/sdk/plugins/types.d.ts +15 -0
- package/dist/sdk/prompt/compile.d.ts +19 -2
- package/dist/sdk/prompt/compile.js +79 -26
- package/dist/sdk/prompt/standard.d.ts +17 -0
- package/dist/sdk/prompt/standard.js +21 -0
- package/dist/sdk/refine/cli.d.ts +1 -1
- package/dist/sdk/refine/cli.js +2 -2
- package/dist/sdk/refine/serverMethods.d.ts +3 -0
- package/dist/sdk/refine/serverMethods.js +20 -0
- package/dist/sdk/server/methods.js +27 -86
- package/dist/sdk/server/params.d.ts +4 -0
- package/dist/sdk/server/params.js +11 -0
- package/dist/sdk/server/remote.js +36 -11
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
- package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
- package/dist/sdk/sessions/continuation.d.ts +3 -0
- package/dist/sdk/sessions/continuation.js +5 -1
- package/dist/sdk/sessions/contracts.d.ts +185 -0
- package/dist/sdk/sessions/contracts.js +101 -4
- package/dist/sdk/sessions/control.d.ts +72 -0
- package/dist/sdk/sessions/control.js +158 -0
- package/dist/sdk/sessions/initialBash.d.ts +7 -0
- package/dist/sdk/sessions/initialBash.js +7 -0
- package/dist/sdk/sessions/planMode.d.ts +18 -4
- package/dist/sdk/sessions/planMode.js +82 -16
- package/dist/sdk/sessions/reasoningSummaries.d.ts +2 -2
- package/dist/sdk/sessions/reasoningSummaries.js +3 -3
- package/dist/sdk/sessions/registry.d.ts +2 -1
- package/dist/sdk/sessions/registry.js +6 -3
- package/dist/sdk/sessions/runIndex.js +7 -7
- package/dist/sdk/sessions/runStore.d.ts +14 -0
- package/dist/sdk/sessions/runStore.js +38 -1
- package/dist/sdk/sessions/runner.d.ts +40 -2
- package/dist/sdk/sessions/runner.js +163 -15
- package/dist/sdk/sessions/sessions.d.ts +40 -8
- package/dist/sdk/sessions/sessions.js +279 -27
- package/dist/sdk/sessions/sideQuestionServerMethods.d.ts +3 -0
- package/dist/sdk/sessions/sideQuestionServerMethods.js +19 -0
- package/dist/sdk/sessions/sideQuestions.d.ts +66 -0
- package/dist/sdk/sessions/sideQuestions.js +290 -0
- package/dist/sdk/sessions/subagentServerMethods.d.ts +3 -0
- package/dist/sdk/sessions/subagentServerMethods.js +41 -0
- package/dist/sdk/sessions/subagentService.d.ts +22 -2
- package/dist/sdk/sessions/subagentService.js +93 -16
- package/dist/sdk/sessions/subagents.d.ts +9 -1
- package/dist/sdk/sessions/subagents.js +19 -0
- package/dist/sdk/sessions/workSlice.d.ts +103 -0
- package/dist/sdk/sessions/workSlice.js +297 -0
- package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
- package/dist/sdk/sessions/workspaceBoundary.js +46 -0
- package/dist/sdk/terminal/browser.d.ts +62 -0
- package/dist/sdk/terminal/browser.js +41 -0
- package/dist/sdk/terminal/browserControl.d.ts +29 -0
- package/dist/sdk/terminal/browserControl.js +187 -0
- package/dist/sdk/terminal/commandHelp.d.ts +17 -0
- package/dist/sdk/terminal/commandHelp.js +20 -0
- package/dist/sdk/terminal/controller.d.ts +15 -1
- package/dist/sdk/terminal/controller.js +67 -8
- package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +28 -0
- package/dist/sdk/terminal/opentui/subagentsWidget.js +52 -0
- package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
- package/dist/sdk/terminal/opentui/theme.js +87 -0
- package/dist/sdk/terminal/piExtension.d.ts +6 -1
- package/dist/sdk/terminal/piExtension.js +169 -84
- package/dist/sdk/terminal/socket.d.ts +6 -3
- package/dist/sdk/terminal/socket.js +40 -9
- package/dist/sdk/terminal/standalone.d.ts +9 -0
- package/dist/sdk/terminal/standalone.js +118 -19
- package/dist/sdk/terminal/subagentMonitor.d.ts +47 -0
- package/dist/sdk/terminal/subagentMonitor.js +152 -0
- package/dist/sdk/terminal/terminals.d.ts +60 -7
- package/dist/sdk/terminal/terminals.js +598 -47
- package/dist/sdk/terminal/trajectory.js +2 -2
- package/dist/sdk/terminal/tui/annotateCommand.d.ts +3 -0
- package/dist/sdk/terminal/tui/annotateCommand.js +22 -0
- package/dist/sdk/terminal/tui/commandPages.d.ts +7 -1
- package/dist/sdk/terminal/tui/commandPages.js +57 -6
- package/dist/sdk/terminal/tui/commands.d.ts +10 -4
- package/dist/sdk/terminal/tui/commands.js +269 -65
- package/dist/sdk/terminal/tui/dialogGeometry.d.ts +2 -2
- package/dist/sdk/terminal/tui/dialogGeometry.js +4 -2
- package/dist/sdk/terminal/tui/dialogs.d.ts +6 -1
- package/dist/sdk/terminal/tui/dialogs.js +9 -2
- package/dist/sdk/terminal/tui/list.d.ts +14 -1
- package/dist/sdk/terminal/tui/list.js +96 -14
- package/dist/sdk/terminal/tui/modelPicker.js +1 -6
- package/dist/sdk/terminal/tui/page.d.ts +3 -0
- package/dist/sdk/terminal/tui/pageOverlay.js +27 -7
- package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +26 -4
- package/dist/sdk/terminal/tui/pages/accountsPage.js +264 -36
- package/dist/sdk/terminal/tui/pages/agentsPage.d.ts +74 -0
- package/dist/sdk/terminal/tui/pages/agentsPage.js +190 -0
- package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +94 -0
- package/dist/sdk/terminal/tui/pages/annotatePage.js +341 -0
- package/dist/sdk/terminal/tui/pages/browserPage.d.ts +87 -0
- package/dist/sdk/terminal/tui/pages/browserPage.js +738 -0
- package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +2 -0
- package/dist/sdk/terminal/tui/pages/doctorPage.js +103 -15
- package/dist/sdk/terminal/tui/pages/notesPage.d.ts +75 -0
- package/dist/sdk/terminal/tui/pages/notesPage.js +201 -0
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +0 -5
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +9 -3
- package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +8 -0
- package/dist/sdk/terminal/tui/pages/settingsPage.js +16 -1
- package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +24 -0
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +152 -0
- package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +12 -5
- package/dist/sdk/terminal/tui/pages/trajectoryPage.js +156 -83
- package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
- package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
- package/dist/sdk/terminal/tui/pages/worktreesPage.d.ts +72 -0
- package/dist/sdk/terminal/tui/pages/worktreesPage.js +203 -0
- package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
- package/dist/sdk/terminal/tui/piAdapter.js +3 -5
- package/dist/sdk/terminal/tui/planMode.d.ts +1 -1
- package/dist/sdk/terminal/tui/planMode.js +1 -1
- package/dist/sdk/terminal/tui/pluginCommands.d.ts +16 -0
- package/dist/sdk/terminal/tui/pluginCommands.js +31 -0
- package/dist/sdk/terminal/tui/questions.d.ts +2 -0
- package/dist/sdk/terminal/tui/runtime.js +27 -5
- package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
- package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
- package/dist/sdk/terminal/tui/settingsModel.d.ts +2 -0
- package/dist/sdk/terminal/tui/settingsModel.js +32 -2
- package/dist/sdk/terminal/tui/sideQuestion.d.ts +26 -26
- package/dist/sdk/terminal/tui/sideQuestion.js +131 -98
- package/dist/sdk/terminal/tui/ui.d.ts +2 -0
- package/dist/sdk/terminal/tui/ui.js +1 -0
- package/dist/sdk/tools/askUser.js +26 -8
- package/dist/sdk/tools/checklist.js +3 -2
- package/dist/sdk/tools/checkpoint.d.ts +27 -0
- package/dist/sdk/tools/checkpoint.js +154 -0
- package/dist/sdk/tools/getCapabilities.d.ts +31 -0
- package/dist/sdk/tools/getCapabilities.js +34 -0
- package/dist/sdk/tools/harnessTools.d.ts +2 -0
- package/dist/sdk/tools/harnessTools.js +1 -1
- package/dist/sdk/tools/spawnSubagent.js +14 -4
- package/dist/sdk/usage/analytics.d.ts +20 -0
- package/dist/sdk/usage/analytics.js +151 -0
- package/dist/sdk/usage/ledger.d.ts +38 -0
- package/dist/sdk/usage/ledger.js +142 -0
- package/dist/sdk/usage/limits/adapters.d.ts +11 -0
- package/dist/sdk/usage/limits/adapters.js +349 -0
- package/dist/sdk/usage/limits/capture.d.ts +8 -0
- package/dist/sdk/usage/limits/capture.js +47 -0
- package/dist/sdk/usage/limits/http.d.ts +12 -0
- package/dist/sdk/usage/limits/http.js +51 -0
- package/dist/sdk/usage/limits/normalize.d.ts +15 -0
- package/dist/sdk/usage/limits/normalize.js +211 -0
- package/dist/sdk/usage/limits/service.d.ts +30 -0
- package/dist/sdk/usage/limits/service.js +176 -0
- package/dist/sdk/usage/limits/types.d.ts +65 -0
- package/dist/sdk/usage/limits/types.js +1 -0
- package/dist/sdk/usage/serverMethods.d.ts +3 -0
- package/dist/sdk/usage/serverMethods.js +22 -0
- package/dist/sdk/usage/service.d.ts +32 -0
- package/dist/sdk/usage/service.js +66 -0
- package/dist/sdk/usage/settings.d.ts +7 -0
- package/dist/sdk/usage/settings.js +28 -0
- package/dist/sdk/usage/types.d.ts +60 -0
- package/dist/sdk/usage/types.js +4 -0
- package/dist/sdk/web/part.d.ts +10 -0
- package/dist/sdk/web/part.js +6 -0
- package/dist/sdk/web/serverMethods.d.ts +3 -0
- package/dist/sdk/web/serverMethods.js +7 -0
- package/dist/sdk/wiki/serverMethods.d.ts +3 -0
- package/dist/sdk/wiki/serverMethods.js +26 -0
- package/dist/sdk/worktrees/cli.d.ts +11 -0
- package/dist/sdk/worktrees/cli.js +146 -0
- package/dist/sdk/worktrees/copy.d.ts +9 -0
- package/dist/sdk/worktrees/copy.js +111 -0
- package/dist/sdk/worktrees/git.d.ts +16 -0
- package/dist/sdk/worktrees/git.js +81 -0
- package/dist/sdk/worktrees/serverMethods.d.ts +3 -0
- package/dist/sdk/worktrees/serverMethods.js +30 -0
- package/dist/sdk/worktrees/service.d.ts +73 -0
- package/dist/sdk/worktrees/service.js +483 -0
- package/dist/sdk/worktrees/setup.d.ts +23 -0
- package/dist/sdk/worktrees/setup.js +65 -0
- package/dist/sdk/worktrees/types.d.ts +91 -0
- package/dist/sdk/worktrees/types.js +1 -0
- package/dist/sdk/world/cli.d.ts +2 -2
- package/dist/sdk/world/cli.js +6 -6
- package/dist/sdk/world/world.d.ts +3 -1
- package/dist/sdk/world/world.js +8 -9
- package/dist/terminal-opentui.js +16456 -5966
- package/dist/terminal-pi.js +1579 -573
- package/docs/README.md +22 -2
- package/docs/architecture/00-overview.md +28 -16
- package/docs/architecture/02-sessions-and-runs.md +184 -25
- package/docs/architecture/03-variants.md +10 -2
- package/docs/architecture/04-prompt.md +65 -7
- package/docs/architecture/06-plugins-and-capabilities.md +57 -4
- package/docs/architecture/07-tools-and-gate.md +112 -17
- package/docs/architecture/08-memory-and-history.md +4 -2
- package/docs/architecture/09-accounts-and-connectors.md +39 -1
- package/docs/architecture/10-server-protocol.md +168 -4
- package/docs/architecture/11-terminal.md +251 -8
- package/docs/architecture/12-storage.md +45 -3
- package/docs/architecture/13-world-tools.md +49 -6
- package/docs/architecture/14-surfaces-and-parity.md +136 -0
- package/docs/architecture/README.md +17 -4
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +4 -2
- package/docs/architecture/proposals/PROP-0013-resource-browser.md +58 -0
- package/docs/architecture/proposals/PROP-0014-fullscreen-browser-tabs.md +58 -0
- package/docs/architecture/proposals/PROP-0015-one-capability-surface.md +88 -0
- package/docs/architecture/proposals/PROP-0016-managed-worktrees.md +156 -0
- package/docs/architecture/proposals/PROP-0017-page-annotations.md +131 -0
- package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +179 -0
- package/docs/architecture/proposals/PROP-0019-contextual-side-questions.md +122 -0
- package/docs/architecture/proposals/PROP-0020-builtin-feature-plugins.md +105 -0
- package/docs/architecture/proposals/PROP-0021-command-namespaces-and-duplicates.md +99 -0
- package/docs/architecture/proposals/PROP-0022-plan-only-questions.md +102 -0
- package/docs/architecture/proposals/PROP-0023-xagent-cli-name.md +61 -0
- package/docs/architecture/proposals/PROP-0024-question-sketch-previews.md +130 -0
- package/docs/architecture/proposals/PROP-0025-contextual-question-wireframes.md +49 -0
- package/docs/architecture/proposals/PROP-0026-connected-sketch-display.md +94 -0
- package/docs/architecture/proposals/PROP-0027-xingular-agent-product-identity.md +60 -0
- package/docs/architecture/proposals/PROP-0028-normalize-question-wireframes.md +55 -0
- package/docs/architecture/proposals/PROP-0029-agent-profiles.md +124 -0
- package/docs/architecture/proposals/PROP-0030-subagent-title.md +86 -0
- package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
- package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
- package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
- package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
- package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
- package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
- package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
- package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
- package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
- package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +247 -0
- package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
- package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
- package/docs/architecture/proposals/README.md +39 -0
- package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
- package/docs/decisions/ADR-0009-xharness-command.md +6 -5
- package/docs/decisions/ADR-0014-public-release-baseline.md +3 -2
- package/docs/decisions/ADR-0015-resource-browser.md +28 -0
- package/docs/decisions/ADR-0016-fullscreen-browser-tabs.md +31 -0
- package/docs/decisions/ADR-0017-one-capability-surface.md +34 -0
- package/docs/decisions/ADR-0018-builtin-feature-plugins.md +35 -0
- package/docs/decisions/ADR-0019-managed-git-worktrees.md +31 -0
- package/docs/decisions/ADR-0020-page-annotations.md +37 -0
- package/docs/decisions/ADR-0021-required-command-namespaces.md +40 -0
- package/docs/decisions/ADR-0022-plan-only-question-tools.md +34 -0
- package/docs/decisions/ADR-0023-contextual-side-question-runs.md +35 -0
- package/docs/decisions/ADR-0024-xagent-command.md +40 -0
- package/docs/decisions/ADR-0025-question-choice-sketches.md +49 -0
- package/docs/decisions/ADR-0026-contextual-question-wireframes.md +58 -0
- package/docs/decisions/ADR-0027-connected-sketch-display.md +60 -0
- package/docs/decisions/ADR-0028-xingular-agent-product-identity.md +56 -0
- package/docs/decisions/ADR-0029-normalized-question-wireframe-borders.md +33 -0
- package/docs/decisions/ADR-0030-agent-profiles.md +43 -0
- package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
- package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
- package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
- package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
- package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
- package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
- package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
- package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
- package/docs/doctor.md +10 -4
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
- package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
- package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
- package/docs/features/README.md +26 -0
- package/docs/features/interfaces/README.md +1 -1
- package/docs/future-work.md +48 -0
- package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
- package/docs/parity.md +134 -0
- package/docs/releases/1.0.0.md +2 -2
- package/docs/releases/1.1.1.md +28 -0
- package/docs/releases/1.2.0.md +49 -0
- package/docs/releases/4.0.0.md +47 -0
- package/docs/releases/README.md +37 -27
- package/docs/study/00-index.md +8 -0
- package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
- package/docs/study/autonomous-engineering-sources.md +277 -0
- package/docs/study/autonomy-sources.md +147 -0
- package/docs/study/proactive-autonomy.md +408 -0
- package/docs/study/tui-resource-browser.md +78 -0
- package/docs/terminal-tui.md +386 -113
- package/package.json +6 -5
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { constants as fsConstants, realpathSync, statSync } from 'node:fs';
|
|
5
|
+
import { access, readFile } from 'node:fs/promises';
|
|
6
|
+
import { dirname, resolve } from 'node:path';
|
|
7
|
+
import { isWithinWorkspace, resolveWritePath, verifyWorkspaceRoot } from "./workspace.js";
|
|
8
|
+
import { workspaceSandboxCommand } from "./workspaceSandbox.js";
|
|
9
|
+
const writeAuthorization = new AsyncLocalStorage();
|
|
10
|
+
const atomicWriteScript = `
|
|
11
|
+
const fs = require('node:fs')
|
|
12
|
+
const path = require('node:path')
|
|
13
|
+
const crypto = require('node:crypto')
|
|
14
|
+
const input = JSON.parse(fs.readFileSync(0, 'utf8'))
|
|
15
|
+
const target = input.path
|
|
16
|
+
const parent = path.dirname(target)
|
|
17
|
+
fs.mkdirSync(parent, { recursive: true })
|
|
18
|
+
let mode = 0o666
|
|
19
|
+
let preserveMode = false
|
|
20
|
+
try {
|
|
21
|
+
const existing = fs.lstatSync(target)
|
|
22
|
+
if (existing.isSymbolicLink() || !existing.isFile()) throw new Error('The write target is not a regular file.')
|
|
23
|
+
fs.accessSync(target, fs.constants.W_OK)
|
|
24
|
+
if (input.expectedContentHash) {
|
|
25
|
+
const current = fs.readFileSync(target)
|
|
26
|
+
if (crypto.createHash('sha256').update(current).digest('hex') !== input.expectedContentHash) {
|
|
27
|
+
throw new Error('The file changed after the edit tool read it; retry against the current contents.')
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
mode = existing.mode & 0o7777
|
|
31
|
+
preserveMode = true
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error && error.code !== 'ENOENT') throw error
|
|
34
|
+
}
|
|
35
|
+
const temporary = path.join(parent, '.' + path.basename(target) + '.' + process.pid + '.' + crypto.randomBytes(8).toString('hex') + '.tmp')
|
|
36
|
+
let descriptor
|
|
37
|
+
try {
|
|
38
|
+
descriptor = fs.openSync(temporary, 'wx', mode)
|
|
39
|
+
fs.writeFileSync(descriptor, input.content, 'utf8')
|
|
40
|
+
if (preserveMode) fs.fchmodSync(descriptor, mode)
|
|
41
|
+
fs.fsyncSync(descriptor)
|
|
42
|
+
fs.closeSync(descriptor)
|
|
43
|
+
descriptor = undefined
|
|
44
|
+
fs.renameSync(temporary, target)
|
|
45
|
+
try {
|
|
46
|
+
const directory = fs.openSync(parent, 'r')
|
|
47
|
+
try { fs.fsyncSync(directory) } finally { fs.closeSync(directory) }
|
|
48
|
+
} catch {}
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (descriptor !== undefined) fs.closeSync(descriptor)
|
|
51
|
+
try { fs.unlinkSync(temporary) } catch {}
|
|
52
|
+
throw error
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
function shellQuote(value) {
|
|
56
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
57
|
+
}
|
|
58
|
+
function nearestExistingDirectory(path) {
|
|
59
|
+
let current = dirname(path);
|
|
60
|
+
while (true) {
|
|
61
|
+
try {
|
|
62
|
+
const canonical = realpathSync(current);
|
|
63
|
+
if (!statSync(canonical).isDirectory())
|
|
64
|
+
throw new Error(`Write scope is not a directory: ${canonical}`);
|
|
65
|
+
return canonical;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error.code !== 'ENOENT')
|
|
69
|
+
throw error;
|
|
70
|
+
const parent = dirname(current);
|
|
71
|
+
if (parent === current)
|
|
72
|
+
throw new Error(`Could not find a writable parent for ${path}.`);
|
|
73
|
+
current = parent;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function killProcess(child) {
|
|
78
|
+
if (child.pid && process.platform !== 'win32') {
|
|
79
|
+
try {
|
|
80
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Fall back to the direct child if it has already left its process group.
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
child.kill('SIGKILL');
|
|
88
|
+
}
|
|
89
|
+
async function runAtomicWrite(authorization, path, content) {
|
|
90
|
+
const root = verifyWorkspaceRoot(authorization.workspaceRoot);
|
|
91
|
+
const canonicalPath = resolveWritePath(path, authorization.cwd);
|
|
92
|
+
if (canonicalPath !== authorization.path)
|
|
93
|
+
throw new Error('The write target changed after workspace approval; the write was blocked.');
|
|
94
|
+
const outside = !isWithinWorkspace(root, canonicalPath);
|
|
95
|
+
if (outside !== authorization.outside || (outside && !authorization.authorized)) {
|
|
96
|
+
throw new Error('The write authorization no longer matches the active workspace target.');
|
|
97
|
+
}
|
|
98
|
+
const additionalRoots = outside ? [nearestExistingDirectory(canonicalPath)] : [];
|
|
99
|
+
const command = `exec ${shellQuote(process.execPath)} -e ${shellQuote(atomicWriteScript)}`;
|
|
100
|
+
const spec = workspaceSandboxCommand(process.platform, root, root, command, additionalRoots);
|
|
101
|
+
const env = {
|
|
102
|
+
PATH: '/usr/bin:/bin',
|
|
103
|
+
...(process.env.HOME ? { HOME: process.env.HOME } : {})
|
|
104
|
+
};
|
|
105
|
+
await new Promise((resolvePromise, rejectPromise) => {
|
|
106
|
+
const child = spawn(spec.executable, spec.args, {
|
|
107
|
+
cwd: root,
|
|
108
|
+
detached: process.platform !== 'win32',
|
|
109
|
+
env,
|
|
110
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
111
|
+
windowsHide: true
|
|
112
|
+
});
|
|
113
|
+
const output = [];
|
|
114
|
+
let outputBytes = 0;
|
|
115
|
+
let settled = false;
|
|
116
|
+
const timeout = setTimeout(() => {
|
|
117
|
+
killProcess(child);
|
|
118
|
+
finish(new Error('Workspace-contained atomic write timed out.'));
|
|
119
|
+
}, 30_000);
|
|
120
|
+
const capture = (chunk) => {
|
|
121
|
+
if (outputBytes >= 8_192)
|
|
122
|
+
return;
|
|
123
|
+
const remaining = 8_192 - outputBytes;
|
|
124
|
+
output.push(chunk.subarray(0, remaining));
|
|
125
|
+
outputBytes += Math.min(chunk.length, remaining);
|
|
126
|
+
};
|
|
127
|
+
const finish = (error) => {
|
|
128
|
+
if (settled)
|
|
129
|
+
return;
|
|
130
|
+
settled = true;
|
|
131
|
+
clearTimeout(timeout);
|
|
132
|
+
authorization.signal?.removeEventListener('abort', abort);
|
|
133
|
+
if (error)
|
|
134
|
+
rejectPromise(error);
|
|
135
|
+
else
|
|
136
|
+
resolvePromise();
|
|
137
|
+
};
|
|
138
|
+
const abort = () => {
|
|
139
|
+
killProcess(child);
|
|
140
|
+
finish(new Error('Workspace-contained atomic write was aborted.'));
|
|
141
|
+
};
|
|
142
|
+
authorization.signal?.addEventListener('abort', abort, { once: true });
|
|
143
|
+
if (authorization.signal?.aborted) {
|
|
144
|
+
abort();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
child.stdout?.on('data', capture);
|
|
148
|
+
child.stderr?.on('data', capture);
|
|
149
|
+
child.once('error', (error) => finish(error));
|
|
150
|
+
child.once('close', (code) => {
|
|
151
|
+
if (code === 0) {
|
|
152
|
+
finish();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const detail = Buffer.concat(output).toString('utf8').trim();
|
|
156
|
+
finish(new Error(`Workspace-contained atomic write failed${detail ? `: ${detail.slice(-2000)}` : ` with exit code ${code ?? 'unknown'}`}.`));
|
|
157
|
+
});
|
|
158
|
+
child.stdin?.on('error', () => { });
|
|
159
|
+
child.stdin?.end(JSON.stringify({
|
|
160
|
+
path: canonicalPath,
|
|
161
|
+
content,
|
|
162
|
+
...(authorization.expectedContentHash ? { expectedContentHash: authorization.expectedContentHash } : {})
|
|
163
|
+
}));
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
async function writeWorkspaceFile(path, content) {
|
|
167
|
+
const authorization = writeAuthorization.getStore();
|
|
168
|
+
if (!authorization?.authorized)
|
|
169
|
+
throw new Error('The file write has no current workspace authorization.');
|
|
170
|
+
await runAtomicWrite(authorization, path, content);
|
|
171
|
+
}
|
|
172
|
+
export const workspaceWriteOperations = {
|
|
173
|
+
mkdir: async (_directory) => { },
|
|
174
|
+
writeFile: writeWorkspaceFile
|
|
175
|
+
};
|
|
176
|
+
export const workspaceEditOperations = {
|
|
177
|
+
access: async (path) => access(path, fsConstants.R_OK | fsConstants.W_OK),
|
|
178
|
+
readFile: async (path) => {
|
|
179
|
+
const content = await readFile(path);
|
|
180
|
+
const authorization = writeAuthorization.getStore();
|
|
181
|
+
if (authorization && resolve(path) === authorization.path) {
|
|
182
|
+
authorization.expectedContentHash = createHash('sha256').update(content).digest('hex');
|
|
183
|
+
}
|
|
184
|
+
return content;
|
|
185
|
+
},
|
|
186
|
+
writeFile: writeWorkspaceFile
|
|
187
|
+
};
|
|
188
|
+
/** Binds one policy-approved path and abort signal to Pi's native write/edit operation. */
|
|
189
|
+
export function withWorkspaceWriteAuthorization(tool, authorizations) {
|
|
190
|
+
const native = tool;
|
|
191
|
+
const execute = native.execute.bind(tool);
|
|
192
|
+
return {
|
|
193
|
+
...tool,
|
|
194
|
+
execute: (...args) => {
|
|
195
|
+
const toolCallId = String(args[0] ?? '');
|
|
196
|
+
const authorization = authorizations.get(toolCallId);
|
|
197
|
+
authorizations.delete(toolCallId);
|
|
198
|
+
if (!authorization?.authorized)
|
|
199
|
+
throw new Error('The file write has no current workspace authorization.');
|
|
200
|
+
const signal = args[2];
|
|
201
|
+
if (signal && typeof signal === 'object' && 'aborted' in signal)
|
|
202
|
+
authorization.signal = signal;
|
|
203
|
+
return writeAuthorization.run(authorization, () => execute(...args));
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { text } from "../server/params.js";
|
|
2
|
+
export function doctorServerMethods(harness) {
|
|
3
|
+
return {
|
|
4
|
+
'doctor.start': (params) => harness.doctor.start(params),
|
|
5
|
+
'doctor.read': (params) => harness.doctor.read(text(params, 'id')),
|
|
6
|
+
'doctor.cancel': (params) => harness.doctor.cancel(text(params, 'id'))
|
|
7
|
+
};
|
|
8
|
+
}
|
|
@@ -11,9 +11,9 @@ export declare const findingSchema: z.ZodObject<{
|
|
|
11
11
|
status: z.ZodEnum<{
|
|
12
12
|
disabled: "disabled";
|
|
13
13
|
warning: "warning";
|
|
14
|
+
blocked: "blocked";
|
|
14
15
|
pass: "pass";
|
|
15
16
|
fail: "fail";
|
|
16
|
-
blocked: "blocked";
|
|
17
17
|
unverified: "unverified";
|
|
18
18
|
}>;
|
|
19
19
|
verification: z.ZodEnum<{
|
|
@@ -119,9 +119,9 @@ export declare const doctorReportSchema: z.ZodObject<{
|
|
|
119
119
|
status: z.ZodEnum<{
|
|
120
120
|
disabled: "disabled";
|
|
121
121
|
warning: "warning";
|
|
122
|
+
blocked: "blocked";
|
|
122
123
|
pass: "pass";
|
|
123
124
|
fail: "fail";
|
|
124
|
-
blocked: "blocked";
|
|
125
125
|
unverified: "unverified";
|
|
126
126
|
}>;
|
|
127
127
|
verification: z.ZodEnum<{
|
package/dist/sdk/harness.d.ts
CHANGED
|
@@ -21,7 +21,14 @@ import type { ToolPolicy } from "./sessions/policy.js";
|
|
|
21
21
|
import { RunRegistry } from "./sessions/registry.js";
|
|
22
22
|
import type { SessionFactory } from "./sessions/runner.js";
|
|
23
23
|
import { Sessions } from "./sessions/sessions.js";
|
|
24
|
+
import { SideQuestions } from "./sessions/sideQuestions.js";
|
|
24
25
|
import { Terminals, type TerminalAssets } from "./terminal/terminals.js";
|
|
26
|
+
import { Worktrees } from "./worktrees/service.js";
|
|
27
|
+
import { Usage } from "./usage/service.js";
|
|
28
|
+
import { UsageLimits } from "./usage/limits/service.js";
|
|
29
|
+
import { AnnotationCapture } from "./annotations/capture.js";
|
|
30
|
+
import { NoteDeliveries } from "./annotations/delivery.js";
|
|
31
|
+
import type { WorktreesOptions } from "./worktrees/types.js";
|
|
25
32
|
export interface HarnessOptions {
|
|
26
33
|
/** Disable the generic backend when a host supplies its own browser tools. */
|
|
27
34
|
browser?: boolean;
|
|
@@ -60,6 +67,8 @@ export interface HarnessOptions {
|
|
|
60
67
|
oauthClients?: AppOAuthClients;
|
|
61
68
|
/** Replaces how a plugin's hooks file is read as a module, for tests. */
|
|
62
69
|
hookImporter?: (address: string) => Promise<unknown>;
|
|
70
|
+
/** Where managed worktrees are made, the prefix of branches they get, and how many `prune` keeps. */
|
|
71
|
+
worktrees?: WorktreesOptions;
|
|
63
72
|
}
|
|
64
73
|
/** What starting on a data root found and repaired. */
|
|
65
74
|
export interface Recovery {
|
|
@@ -82,6 +91,8 @@ declare class Env implements HarnessEnv {
|
|
|
82
91
|
get root(): string;
|
|
83
92
|
}
|
|
84
93
|
export declare class Harness {
|
|
94
|
+
/** The periodic liveness check, started once with recovery (PROP-0041). */
|
|
95
|
+
private staleRuns?;
|
|
85
96
|
private readonly browserEnabled;
|
|
86
97
|
readonly hub: Hub;
|
|
87
98
|
readonly bus: Bus;
|
|
@@ -100,6 +111,8 @@ export declare class Harness {
|
|
|
100
111
|
applicationPlugins: ReadonlySet<string>;
|
|
101
112
|
readonly subagents: Subagents;
|
|
102
113
|
readonly sessions: Sessions;
|
|
114
|
+
/** Tool-free, run-backed questions over a redacted projection of the main conversation. */
|
|
115
|
+
readonly sideQuestions: SideQuestions;
|
|
103
116
|
/** Web, browser and computer tools (page 13). */
|
|
104
117
|
readonly world: World;
|
|
105
118
|
/** Which plugin code in variants a person trusted. */
|
|
@@ -111,6 +124,15 @@ export declare class Harness {
|
|
|
111
124
|
refineHost: RefineHost | null;
|
|
112
125
|
readonly terminals: Terminals;
|
|
113
126
|
readonly doctor: Doctor;
|
|
127
|
+
/** Usage analytics over the derived ledger, and the provider limits last reported. */
|
|
128
|
+
readonly usage: Usage;
|
|
129
|
+
readonly usageLimits: UsageLimits;
|
|
130
|
+
/** Managed git worktrees sessions can work in (PROP-0016). */
|
|
131
|
+
readonly worktrees: Worktrees;
|
|
132
|
+
/** The terminal's visible browser for capturing page notes (PROP-0017). */
|
|
133
|
+
readonly noteCapture: AnnotationCapture;
|
|
134
|
+
/** Page notes on their way to a session (PROP-0018). */
|
|
135
|
+
readonly pageNotes: NoteDeliveries;
|
|
114
136
|
/** Resolves when what was loaded in the background at construction is in place. */
|
|
115
137
|
readonly ready: Promise<void>;
|
|
116
138
|
recovery: Recovery;
|
package/dist/sdk/harness.js
CHANGED
|
@@ -25,6 +25,7 @@ import { migrateVariantLayout } from "./variant/migrate.js";
|
|
|
25
25
|
import { VariantTrust } from "./variant/trust.js";
|
|
26
26
|
import * as notes from "./wiki/notes.js";
|
|
27
27
|
import * as pluginApi from "./plugins/api.js";
|
|
28
|
+
import * as pluginInstall from "./plugins/install.js";
|
|
28
29
|
import * as attachments from "./plugins/attachments.js";
|
|
29
30
|
import { HARNESS_PLUGINS } from "./plugins/builtin.js";
|
|
30
31
|
import { World } from "./world/world.js";
|
|
@@ -35,9 +36,16 @@ import { Hooks } from "./plugins/hooks.js";
|
|
|
35
36
|
import { packageFolders, Plugins } from "./plugins/plugins.js";
|
|
36
37
|
import { approvalKey, Approvals } from "./sessions/approvals.js";
|
|
37
38
|
import { RunRegistry } from "./sessions/registry.js";
|
|
38
|
-
import { markInterruptedRuns } from "./sessions/runStore.js";
|
|
39
|
+
import { loadRun, markInterruptedRuns, reconcileStaleRuns } from "./sessions/runStore.js";
|
|
39
40
|
import { Sessions } from "./sessions/sessions.js";
|
|
41
|
+
import { SideQuestions } from "./sessions/sideQuestions.js";
|
|
40
42
|
import { Terminals } from "./terminal/terminals.js";
|
|
43
|
+
import { Worktrees } from "./worktrees/service.js";
|
|
44
|
+
import { Usage } from "./usage/service.js";
|
|
45
|
+
import { UsageLimits } from "./usage/limits/service.js";
|
|
46
|
+
import { indexRunUsage, syncUsage } from "./usage/ledger.js";
|
|
47
|
+
import { AnnotationCapture } from "./annotations/capture.js";
|
|
48
|
+
import { NoteDeliveries } from "./annotations/delivery.js";
|
|
41
49
|
class Env {
|
|
42
50
|
directory;
|
|
43
51
|
productName;
|
|
@@ -56,6 +64,8 @@ class Env {
|
|
|
56
64
|
}
|
|
57
65
|
}
|
|
58
66
|
export class Harness {
|
|
67
|
+
/** The periodic liveness check, started once with recovery (PROP-0041). */
|
|
68
|
+
staleRuns;
|
|
59
69
|
browserEnabled;
|
|
60
70
|
hub;
|
|
61
71
|
bus = new Bus();
|
|
@@ -74,6 +84,8 @@ export class Harness {
|
|
|
74
84
|
applicationPlugins = new Set();
|
|
75
85
|
subagents;
|
|
76
86
|
sessions;
|
|
87
|
+
/** Tool-free, run-backed questions over a redacted projection of the main conversation. */
|
|
88
|
+
sideQuestions;
|
|
77
89
|
/** Web, browser and computer tools (page 13). */
|
|
78
90
|
world;
|
|
79
91
|
/** Which plugin code in variants a person trusted. */
|
|
@@ -85,6 +97,15 @@ export class Harness {
|
|
|
85
97
|
refineHost;
|
|
86
98
|
terminals;
|
|
87
99
|
doctor;
|
|
100
|
+
/** Usage analytics over the derived ledger, and the provider limits last reported. */
|
|
101
|
+
usage;
|
|
102
|
+
usageLimits;
|
|
103
|
+
/** Managed git worktrees sessions can work in (PROP-0016). */
|
|
104
|
+
worktrees;
|
|
105
|
+
/** The terminal's visible browser for capturing page notes (PROP-0017). */
|
|
106
|
+
noteCapture;
|
|
107
|
+
/** Page notes on their way to a session (PROP-0018). */
|
|
108
|
+
pageNotes;
|
|
88
109
|
/** Resolves when what was loaded in the background at construction is in place. */
|
|
89
110
|
ready;
|
|
90
111
|
recovery = { interruptedRuns: 0, interruptedRunIds: [], reindexedPages: 0, migrationError: null };
|
|
@@ -103,6 +124,10 @@ export class Harness {
|
|
|
103
124
|
const secrets = options.secrets ?? fileSecretStore(join(this.stateDir, 'secrets.json'));
|
|
104
125
|
this.accounts = new Accounts({ dir: join(this.stateDir, 'accounts'), secrets, bus: this.bus });
|
|
105
126
|
this.approvals = new Approvals(this.stateDir, this.bus);
|
|
127
|
+
this.usageLimits = new UsageLimits({ accounts: this.accounts, root: () => this.env.dataRoot });
|
|
128
|
+
// Response headers are the free, always-fresh limit signal; the account runtime reports them here.
|
|
129
|
+
this.accounts.observeModels = (models, accountId) => this.usageLimits.observeModels(models, accountId);
|
|
130
|
+
this.usage = new Usage({ root: () => this.env.root, accounts: this.accounts });
|
|
106
131
|
this.runs = new RunRegistry({
|
|
107
132
|
root: () => this.env.root,
|
|
108
133
|
automatic: async (run, target, operation, standing) => {
|
|
@@ -146,7 +171,9 @@ export class Harness {
|
|
|
146
171
|
reloadTimer.unref?.();
|
|
147
172
|
});
|
|
148
173
|
this.describe(options.plugins ?? []);
|
|
149
|
-
this.
|
|
174
|
+
this.worktrees = new Worktrees(this.stateDir, options.worktrees);
|
|
175
|
+
this.noteCapture = new AnnotationCapture({ stateDir: this.stateDir });
|
|
176
|
+
this.subagents = new Subagents(this.env, this.runs, (input) => this.sessions.run(input), { descriptors: () => HARNESS_PLUGINS });
|
|
150
177
|
this.sessions = new Sessions({
|
|
151
178
|
subagents: this.subagents,
|
|
152
179
|
env: this.env,
|
|
@@ -156,10 +183,13 @@ export class Harness {
|
|
|
156
183
|
broker: this.apps,
|
|
157
184
|
plugins: this.plugins,
|
|
158
185
|
resolveCapabilities: (caller, tools, cwd) => capabilities.resolve(this, { agentId: caller.agentId ?? null, projectId: caller.projectId ?? null, cwd, tools }),
|
|
186
|
+
fullPermission: (run) => this.approvals.isAuto(approvalKey(run)),
|
|
159
187
|
factory: options.sessionFactory,
|
|
160
|
-
trust: this.trust
|
|
188
|
+
trust: this.trust,
|
|
189
|
+
worktrees: this.worktrees
|
|
161
190
|
});
|
|
162
|
-
this.
|
|
191
|
+
this.sideQuestions = new SideQuestions({ env: this.env, sessions: this.sessions, runs: this.runs });
|
|
192
|
+
this.world = new World({ root: () => this.env.root, stateDir: this.stateDir, secrets, browser: this.browserEnabled ? undefined : false, notesChanged: (sessionId, ids) => this.bus.emit({ type: 'annotations.changed', sessionId, ids }) });
|
|
163
193
|
// The harness's own world tools come first; a tool an application provides under the same name is not added again.
|
|
164
194
|
this.sessions.provide(this.world.provider());
|
|
165
195
|
this.doctor = new Doctor({
|
|
@@ -169,7 +199,8 @@ export class Harness {
|
|
|
169
199
|
const refineRuntime = { root: () => this.env.root, runs: this.runs, run: (input) => this.sessions.run(input) };
|
|
170
200
|
this.refine = new Refinements({ root: () => this.env.root, bus: this.bus, trust: this.trust, host: () => this.refineHost, runtime: refineRuntime });
|
|
171
201
|
this.lessons = new Lessons({ root: () => this.env.root, runtime: refineRuntime });
|
|
172
|
-
this.
|
|
202
|
+
this.pageNotes = new NoteDeliveries({ root: () => this.env.root, bus: this.bus, terminals: () => this.terminals ?? null });
|
|
203
|
+
this.terminals = new Terminals({ trust: this.trust, subagents: this.subagents, sideQuestions: this.sideQuestions, resolveCapabilities: (caller, tools, cwd) => capabilities.resolve(this, { agentId: caller.agentId ?? null, projectId: caller.projectId ?? null, cwd, tools }), env: this.env, stateDir: this.stateDir, accounts: this.accounts, runs: this.runs, approvals: this.approvals, apps: this.apps, policy: this.policy, bus: this.bus, plugins: this.plugins, usage: this.usage, usageLimits: this.usageLimits, pluginControl: { list: (scope) => pluginApi.list(this, scope), attach: (params, on) => pluginApi.attach(this, params, on), trust: (scope) => pluginApi.trust(this, scope), untrust: (scope) => pluginApi.untrust(this, scope), configure: (params) => pluginApi.configure(this, params), install: params => pluginInstall.install(this, params), remove: params => pluginInstall.remove(this, params) }, assets: options.assets, hub: this.hub, world: this.world, doctor: this.doctor, worktrees: this.worktrees, noteCapture: this.noteCapture, pageNotes: this.pageNotes });
|
|
173
204
|
this.ready = this.apps.start().catch((error) => log('connected apps', error instanceof Error ? error.message : String(error)));
|
|
174
205
|
this.runs.listen((event, run) => {
|
|
175
206
|
this.accounts.onRunEvent(event, run);
|
|
@@ -178,6 +209,16 @@ export class Harness {
|
|
|
178
209
|
recall.indexRun(this.env.root, event.runId);
|
|
179
210
|
if (run?.trigger === 'doctor')
|
|
180
211
|
return;
|
|
212
|
+
const runEnded = event.type === 'completed' || event.type === 'failed' || (event.type === 'status.changed' && event.payload.status === 'interrupted');
|
|
213
|
+
// The usage ledger is derived from the same recorded events; a failure never blocks the run.
|
|
214
|
+
// An interrupted run is indexed too, so its spent tokens are not lost until the next start.
|
|
215
|
+
if (runEnded)
|
|
216
|
+
indexRunUsage(this.env.root, event.runId);
|
|
217
|
+
if (runEnded && run?.sessionId) {
|
|
218
|
+
// Notes sent with "Proceed now" while this session was working go out now; the terminal
|
|
219
|
+
// needs a moment to see its run as ended.
|
|
220
|
+
setTimeout(() => void this.pageNotes.runEnded(run.sessionId).catch((error) => log('page notes', error instanceof Error ? error.message : String(error))), 250).unref?.();
|
|
221
|
+
}
|
|
181
222
|
if ((event.type === 'completed' || event.type === 'failed') && run) {
|
|
182
223
|
if (event.type === 'completed')
|
|
183
224
|
this.lessons.consider(run);
|
|
@@ -246,6 +287,19 @@ export class Harness {
|
|
|
246
287
|
let interruptedRunIds = [];
|
|
247
288
|
try {
|
|
248
289
|
interruptedRunIds = markInterruptedRuns(root, `${this.env.productName} stopped before the run settled.`);
|
|
290
|
+
const recoveredSessions = new Set();
|
|
291
|
+
for (const runId of interruptedRunIds) {
|
|
292
|
+
try {
|
|
293
|
+
const sessionId = loadRun(root, runId).sessionId;
|
|
294
|
+
if (!sessionId || recoveredSessions.has(sessionId))
|
|
295
|
+
continue;
|
|
296
|
+
recoveredSessions.add(sessionId);
|
|
297
|
+
setTimeout(() => void this.pageNotes.runEnded(sessionId).catch((error) => log('page notes', error instanceof Error ? error.message : String(error))), 250).unref?.();
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// A malformed run record does not prevent the rest of recovery.
|
|
301
|
+
}
|
|
302
|
+
}
|
|
249
303
|
}
|
|
250
304
|
catch (error) {
|
|
251
305
|
log('run recovery', error instanceof Error ? error.message : String(error));
|
|
@@ -257,23 +311,48 @@ export class Harness {
|
|
|
257
311
|
catch (error) {
|
|
258
312
|
log('recall', error instanceof Error ? error.message : String(error));
|
|
259
313
|
}
|
|
314
|
+
try {
|
|
315
|
+
// Usage rows come from the same run events; the ledger can always be rebuilt from them.
|
|
316
|
+
syncUsage(root);
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
log('usage ledger', error instanceof Error ? error.message : String(error));
|
|
320
|
+
}
|
|
260
321
|
this.recovery = { interruptedRuns: interruptedRunIds.length, interruptedRunIds, reindexedPages: safeCount(root), migrationError, legacyWiki };
|
|
322
|
+
if (!this.staleRuns) {
|
|
323
|
+
// A reply that stops emitting heartbeats while its process lives is settled here, not left
|
|
324
|
+
// `running` for the next restart (PROP-0041).
|
|
325
|
+
this.staleRuns = setInterval(() => {
|
|
326
|
+
try {
|
|
327
|
+
reconcileStaleRuns(root);
|
|
328
|
+
}
|
|
329
|
+
catch (error) {
|
|
330
|
+
log('stale run check', error instanceof Error ? error.message : String(error));
|
|
331
|
+
}
|
|
332
|
+
}, 60_000);
|
|
333
|
+
this.staleRuns.unref?.();
|
|
334
|
+
}
|
|
261
335
|
return this.recovery;
|
|
262
336
|
}
|
|
263
337
|
/** Rebuilds the history index from the run records. Returns the notes in the Wiki. */
|
|
264
338
|
rebuildIndex() {
|
|
265
339
|
recall.sync(this.env.root);
|
|
340
|
+
syncUsage(this.env.root);
|
|
266
341
|
const count = safeCount(this.env.root);
|
|
267
342
|
this.recovery = { ...this.recovery, reindexedPages: count };
|
|
268
343
|
return count;
|
|
269
344
|
}
|
|
270
345
|
/** Stops live runs and refinements and releases the index. */
|
|
271
346
|
async close() {
|
|
347
|
+
if (this.staleRuns)
|
|
348
|
+
clearInterval(this.staleRuns);
|
|
272
349
|
await this.doctor.close();
|
|
273
350
|
this.hub.close();
|
|
274
351
|
await this.refine.close();
|
|
275
352
|
await this.lessons.close();
|
|
276
353
|
await this.terminals.close();
|
|
354
|
+
await this.noteCapture.close();
|
|
355
|
+
await this.sideQuestions.close();
|
|
277
356
|
await this.runs.interruptAll();
|
|
278
357
|
await this.world.close();
|
|
279
358
|
await this.hooks.settled().catch(() => undefined);
|
|
@@ -32,11 +32,11 @@ export function passages(run, events) {
|
|
|
32
32
|
return found;
|
|
33
33
|
}
|
|
34
34
|
function writeRun(database, run, found) {
|
|
35
|
-
execute(database, 'DELETE FROM recall_fts WHERE run_id = ?
|
|
35
|
+
execute(database, 'DELETE FROM recall_fts WHERE run_id = ?', run.id);
|
|
36
36
|
found.forEach((passage, seq) => {
|
|
37
|
-
execute(database, 'INSERT INTO recall_fts (run_id, seq, role, at, mode, session_id, project_id, text) VALUES (
|
|
37
|
+
execute(database, 'INSERT INTO recall_fts (run_id, seq, role, at, mode, session_id, project_id, text) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', run.id, seq, passage.role, passage.at, run.mode, run.sessionId, run.projectId, passage.text);
|
|
38
38
|
});
|
|
39
|
-
execute(database, 'INSERT OR REPLACE INTO recall_runs (run_id, passages, status) VALUES (
|
|
39
|
+
execute(database, 'INSERT OR REPLACE INTO recall_runs (run_id, passages, status) VALUES (?, ?, ?)', run.id, found.length, run.status);
|
|
40
40
|
}
|
|
41
41
|
function eventsOf(root, runId) {
|
|
42
42
|
try {
|
|
@@ -93,13 +93,13 @@ export function search(root, query, scope, limit) {
|
|
|
93
93
|
if (!fts)
|
|
94
94
|
return [];
|
|
95
95
|
return withIndex(root, (database) => all(database, `SELECT run_id, seq, role, at, mode, session_id, project_id, snippet(recall_fts, 7, '', '', '…', 40) AS snippet
|
|
96
|
-
FROM recall_fts WHERE recall_fts MATCH ?
|
|
97
|
-
AND (?
|
|
98
|
-
AND (?
|
|
99
|
-
ORDER BY bm25(recall_fts), at DESC LIMIT
|
|
96
|
+
FROM recall_fts WHERE recall_fts MATCH ?
|
|
97
|
+
AND (? IS NULL OR session_id = ?) AND (? IS NULL OR mode = ?)
|
|
98
|
+
AND (? IS NULL OR project_id = ?) AND (? IS NULL OR at >= ?)
|
|
99
|
+
ORDER BY bm25(recall_fts), at DESC LIMIT ?`, fts, scope.sessionId ?? null, scope.sessionId ?? null, scope.mode ?? null, scope.mode ?? null, scope.projectId ?? null, scope.projectId ?? null, scope.since ?? null, scope.since ?? null, Math.min(Math.max(limit, 1), SEARCH_MAX)).map((row) => ({ runId: row.run_id, seq: Number(row.seq), role: row.role, at: row.at ?? '', mode: row.mode ?? '', sessionId: row.session_id ?? '', projectId: row.project_id, snippet: row.snippet })));
|
|
100
100
|
}
|
|
101
101
|
export function read(root, runId) {
|
|
102
|
-
return withIndex(root, (database) => all(database, 'SELECT seq, role, at, text FROM recall_fts WHERE run_id = ?
|
|
102
|
+
return withIndex(root, (database) => all(database, 'SELECT seq, role, at, text FROM recall_fts WHERE run_id = ? ORDER BY CAST(seq AS INTEGER)', runId).map((row) => ({ seq: Number(row.seq), role: row.role, at: row.at ?? '', text: row.text })));
|
|
103
103
|
}
|
|
104
104
|
function textParam(params, key) {
|
|
105
105
|
const value = params?.[key];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as recall from "./recall.js";
|
|
2
|
+
import { text } from "../server/params.js";
|
|
3
|
+
export function historyServerMethods(harness) {
|
|
4
|
+
return {
|
|
5
|
+
'recall.search': (params) => recall.searchAll(harness.env, typeof params.query === 'string' ? params.query : '', params.filter ?? {}),
|
|
6
|
+
'recall.read': (params) => recall.read(harness.env.root, text(params, 'runId'))
|
|
7
|
+
};
|
|
8
|
+
}
|
package/dist/sdk/hub/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Harness, type HarnessOptions } from "../harness.js";
|
|
2
|
-
export declare const HUB_USAGE = "Usage:
|
|
2
|
+
export declare const HUB_USAGE = "Usage: xagent hub <list | show | install> [id@version] [options]\n\n list [--refresh] Browse the curated catalog and locally installed versions\n show <id@version> Show publisher, license, source, and delivery details\n install <id@version> Install the exact reviewed version, disabled and untrusted\n\n --data <dir> Target data library (default: ~/.xingular-harness/data)\n --state <dir> Target device state (default: ~/.xingular-harness/state)\n --refresh Refresh the public catalog; cached items remain usable offline\n";
|
|
3
3
|
export declare function runHubCli(argv: string[], dependencies?: {
|
|
4
4
|
home?: string;
|
|
5
5
|
write?: (text: string) => void;
|
package/dist/sdk/hub/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
2
|
import { join, resolve } from 'node:path';
|
|
3
3
|
import { Harness } from "../harness.js";
|
|
4
|
-
export const HUB_USAGE = `Usage:
|
|
4
|
+
export const HUB_USAGE = `Usage: xagent hub <list | show | install> [id@version] [options]
|
|
5
5
|
|
|
6
6
|
list [--refresh] Browse the curated catalog and locally installed versions
|
|
7
7
|
show <id@version> Show publisher, license, source, and delivery details
|
package/dist/sdk/hub/schema.d.ts
CHANGED
|
@@ -263,9 +263,9 @@ export declare const hubOverviewSchema: z.ZodObject<{
|
|
|
263
263
|
}>>;
|
|
264
264
|
}, z.core.$strict>>;
|
|
265
265
|
origin: z.ZodEnum<{
|
|
266
|
-
remote: "remote";
|
|
267
266
|
bundled: "bundled";
|
|
268
267
|
cached: "cached";
|
|
268
|
+
remote: "remote";
|
|
269
269
|
}>;
|
|
270
270
|
refreshedAt: z.ZodNullable<z.ZodString>;
|
|
271
271
|
error: z.ZodNullable<z.ZodString>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { text } from "../server/params.js";
|
|
2
|
+
export function hubServerMethods(harness) {
|
|
3
|
+
return {
|
|
4
|
+
'hub.list': (params) => harness.hub.list(params.refresh === true),
|
|
5
|
+
'hub.get': (params) => harness.hub.get(text(params, 'id'), text(params, 'version'), params.preview === true),
|
|
6
|
+
'hub.install': (params) => harness.hub.install(text(params, 'id'), text(params, 'version')),
|
|
7
|
+
'hub.preview': (params) => harness.hub.preview(text(params, 'id'), text(params, 'version'), typeof params.offset === 'number' ? params.offset : 0),
|
|
8
|
+
'hub.uninstall': (params) => harness.hub.uninstall(text(params, 'id'), text(params, 'version')),
|
|
9
|
+
'hub.readDocument': (params) => harness.hub.readDocument(text(params, 'id'), text(params, 'version'))
|
|
10
|
+
};
|
|
11
|
+
}
|
package/dist/sdk/index.d.ts
CHANGED
|
@@ -21,11 +21,18 @@ export type { ApprovalFacts, ApprovalPolicy, AutomaticReason } from "./sessions/
|
|
|
21
21
|
export type { ScopeDecision, ToolCall, ToolPolicy } from "./sessions/policy.js";
|
|
22
22
|
export type { ActiveRun, ApprovalDecision, ApprovalInput, QuestionAnswer, QuestionInput } from "./sessions/registry.js";
|
|
23
23
|
export type { RunFields, SessionRunInput } from "./sessions/sessions.js";
|
|
24
|
+
export type { SessionCommand } from "./sessions/runner.js";
|
|
25
|
+
export type { SessionRef, SessionTree, SessionTreeEntry } from "./sessions/control.js";
|
|
26
|
+
export { CORE_COMMANDS, coreCommand, type CoreCommand, type CoreCommandGroup, type CoreCommandKind, type CoreCommandName, type ListedCommand } from "./commands/registry.js";
|
|
27
|
+
export { STANDARD_CONNECTIONS, type StandardSession } from "./prompt/standard.js";
|
|
28
|
+
export { SideQuestions, SIDE_QUESTION_INSTRUCTION, buildSideQuestionText, type SideQuestionContext, type SideQuestionRead, type SideQuestionStartInput } from "./sessions/sideQuestions.js";
|
|
24
29
|
export type { Effort } from "./sessions/runner.js";
|
|
25
30
|
export { describeTool, HARNESS_TOOLS, DEFAULT_TOOL_NAMES, WIKI_WRITE, type HarnessCall, type HarnessToolDefinition } from "./tools/definitions.js";
|
|
26
31
|
export type { ToolProvider, ToolResult, ToolSession, ToolSpec } from "./tools/types.js";
|
|
27
32
|
export { SPAWN_SUBAGENT, SUBAGENT_RELATION } from "./tools/spawnSubagent.js";
|
|
28
33
|
export { CHECKLIST_WRITE, checklistOf } from "./tools/checklist.js";
|
|
34
|
+
export { BUILTIN_PROFILES } from "./agents/builtin.js";
|
|
35
|
+
export { PROFILE_COLORS, createProfile, listProfiles, parseProfile, profileDirs, removeProfile, resolveProfile, type AgentProfile, type ProfileColor, type ProfileListing, type ProfileProblem, type ProfileScope, type ProfileSource, type ProfileVariant } from "./agents/profiles.js";
|
|
29
36
|
export { continuationOf, type Continuation, type ContinuationBlock } from "./sessions/continuation.js";
|
|
30
37
|
export { webTools, WEB_PLUGIN, WEB_SEARCH_KEY, type WebToolOptions } from "./web/tools.js";
|
|
31
38
|
export { safeRequest, type WebRequest, type WebResponse } from "./web/safeRequest.js";
|
|
@@ -53,11 +60,19 @@ export { HARNESS_PLUGINS } from "./plugins/builtin.js";
|
|
|
53
60
|
export { FIRST_PARTY_PLUGINS } from "./plugins/firstParty.js";
|
|
54
61
|
export type { Found, Resolver } from "./plugins/discover.js";
|
|
55
62
|
export type { Loading, Registered } from "./plugins/plugins.js";
|
|
56
|
-
export { CONTRIBUTION_KINDS, PLUGIN_SOURCES, type ConnectorTemplate, type Contribution, type ContributionKind, type ContributionState, type Delivery, type Inventory, type InventoryItem, type Plugin, type PluginDescriptor, type PluginManage, type PluginSetting, type PluginSource } from "./plugins/types.js";
|
|
63
|
+
export { CONTRIBUTION_KINDS, PLUGIN_SOURCES, type ConnectorTemplate, type Contribution, type ContributionKind, type ContributionState, type Delivery, type Inventory, type InventoryItem, type Plugin, type PluginDescriptor, type PluginManage, type PluginSetting, type PluginSource, type PluginSurfaces } from "./plugins/types.js";
|
|
64
|
+
export { describePlugin, surfaceBadge } from "./plugins/surfaces.js";
|
|
57
65
|
export { methods } from "./server/methods.js";
|
|
58
66
|
export { remoteDirectory, remotePolicy, remoteSecrets, remoteTools } from "./server/remote.js";
|
|
59
67
|
export { PROTOCOL_VERSION, RpcPeer, stdioTransport, type Handler, type Transport } from "./server/rpc.js";
|
|
60
68
|
export { attach, serve, type Served } from "./server/serve.js";
|
|
61
69
|
export { DEFAULT_SUBAGENT_DEPTH, MAX_SUBAGENT_DEPTH, type SubagentOptions, type SubagentInput } from "./sessions/subagents.js";
|
|
62
70
|
export { Subagents } from "./sessions/subagentService.js";
|
|
71
|
+
export { Worktrees } from "./worktrees/service.js";
|
|
72
|
+
export type { CreateWorktreeInput, CreateWorktreeResult, HandoffResult, WorktreeRecord, WorktreeStatus, WorktreesOptions, WorktreeKind } from "./worktrees/types.js";
|
|
63
73
|
export { WAIT_SUBAGENTS, type SubagentResult, type SubagentSelection } from "./sessions/subagents.js";
|
|
74
|
+
export * as pageNotes from "./annotations/store.js";
|
|
75
|
+
export type { Note as PageNote, NoteApp as PageNoteApp, NoteDelivery as PageNoteDelivery, NoteInput as PageNoteInput, NoteSource as PageNoteSource, NoteTarget as PageNoteTarget } from "./annotations/store.js";
|
|
76
|
+
export { PAGE_SCRIPT } from "./annotations/pageScript.js";
|
|
77
|
+
export { NoteDeliveries, type SendResult } from "./annotations/delivery.js";
|
|
78
|
+
export type { CaptureTargetSpec, CaptureWindow, InspectState } from "./annotations/capture.js";
|