@xingular/harness 0.1.7 → 1.0.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 +97 -1
- package/LICENSE +202 -0
- package/NOTICE.md +22 -0
- package/README.md +187 -85
- package/THIRD_PARTY_LICENSES.md +942 -0
- package/dist/cli.js +13701 -13498
- package/dist/sdk/accounts/accounts.d.ts +165 -0
- package/dist/sdk/accounts/accounts.js +730 -0
- package/dist/sdk/accounts/choices.d.ts +23 -0
- package/dist/sdk/accounts/choices.js +62 -0
- package/dist/sdk/accounts/env.d.ts +78 -0
- package/dist/sdk/accounts/env.js +294 -0
- package/dist/sdk/accounts/secrets.d.ts +16 -0
- package/dist/sdk/accounts/secrets.js +40 -0
- package/dist/sdk/accounts/store.d.ts +114 -0
- package/dist/sdk/accounts/store.js +255 -0
- package/dist/sdk/browser/config.d.ts +16 -0
- package/dist/sdk/browser/config.js +22 -0
- package/dist/sdk/browser/diagnostics.d.ts +4 -0
- package/dist/sdk/browser/diagnostics.js +38 -0
- package/dist/sdk/browser/index.d.ts +17 -0
- package/dist/sdk/browser/index.js +65 -0
- package/dist/sdk/browser/network.d.ts +10 -0
- package/dist/sdk/browser/network.js +59 -0
- package/dist/sdk/browser/session.d.ts +84 -0
- package/dist/sdk/browser/session.js +192 -0
- package/dist/sdk/browser/tools.d.ts +8 -0
- package/dist/sdk/browser/tools.js +329 -0
- package/dist/sdk/capabilities/api.d.ts +22 -0
- package/dist/sdk/capabilities/api.js +54 -0
- package/dist/sdk/capabilities/runSnapshot.d.ts +18 -0
- package/dist/sdk/capabilities/runSnapshot.js +47 -0
- package/dist/sdk/capabilities/types.d.ts +29 -0
- package/dist/sdk/capabilities/types.js +1 -0
- package/dist/sdk/cli.d.ts +2 -0
- package/dist/sdk/cli.js +142 -0
- package/dist/sdk/core/bus.d.ts +23 -0
- package/dist/sdk/core/bus.js +76 -0
- package/dist/sdk/core/caller.d.ts +22 -0
- package/dist/sdk/core/caller.js +16 -0
- package/dist/sdk/core/changes.d.ts +15 -0
- package/dist/sdk/core/changes.js +15 -0
- package/dist/sdk/core/effort.d.ts +2 -0
- package/dist/sdk/core/effort.js +1 -0
- package/dist/sdk/core/env.d.ts +18 -0
- package/dist/sdk/core/env.js +8 -0
- package/dist/sdk/core/errors.d.ts +15 -0
- package/dist/sdk/core/errors.js +24 -0
- package/dist/sdk/core/frontmatter.d.ts +12 -0
- package/dist/sdk/core/frontmatter.js +50 -0
- package/dist/sdk/core/fs.d.ts +18 -0
- package/dist/sdk/core/fs.js +106 -0
- package/dist/sdk/core/index.d.ts +24 -0
- package/dist/sdk/core/index.js +187 -0
- package/dist/sdk/core/path.d.ts +7 -0
- package/dist/sdk/core/path.js +79 -0
- package/dist/sdk/core/projects.d.ts +18 -0
- package/dist/sdk/core/projects.js +67 -0
- package/dist/sdk/core/secrets.d.ts +2 -0
- package/dist/sdk/core/secrets.js +5 -0
- package/dist/sdk/core/text.d.ts +7 -0
- package/dist/sdk/core/text.js +40 -0
- package/dist/sdk/doctor/checks.d.ts +5 -0
- package/dist/sdk/doctor/checks.js +208 -0
- package/dist/sdk/doctor/probe.d.ts +4 -0
- package/dist/sdk/doctor/probe.js +92 -0
- package/dist/sdk/doctor/service.d.ts +23 -0
- package/dist/sdk/doctor/service.js +144 -0
- package/dist/sdk/doctor/types.d.ts +141 -0
- package/dist/sdk/doctor/types.js +29 -0
- package/dist/sdk/harness.d.ts +133 -0
- package/dist/sdk/harness.js +299 -0
- package/dist/sdk/history/lessonPrompt.d.ts +2 -0
- package/dist/sdk/history/lessonPrompt.js +15 -0
- package/dist/sdk/history/lessons.d.ts +52 -0
- package/dist/sdk/history/lessons.js +173 -0
- package/dist/sdk/history/recall.d.ts +68 -0
- package/dist/sdk/history/recall.js +199 -0
- package/dist/sdk/history/trajectory.d.ts +7 -0
- package/dist/sdk/history/trajectory.js +216 -0
- package/dist/sdk/hub/catalog.json +123 -0
- package/dist/sdk/hub/cli.d.ts +7 -0
- package/dist/sdk/hub/cli.js +81 -0
- package/dist/sdk/hub/hub.d.ts +74 -0
- package/dist/sdk/hub/hub.js +474 -0
- package/dist/sdk/hub/schema.d.ts +280 -0
- package/dist/sdk/hub/schema.js +78 -0
- package/dist/sdk/index.d.ts +63 -0
- package/dist/sdk/index.js +48 -0
- package/dist/sdk/mcp/connections.d.ts +83 -0
- package/dist/sdk/mcp/connections.js +669 -0
- package/dist/sdk/mcp/manager.d.ts +26 -0
- package/dist/sdk/mcp/manager.js +124 -0
- package/dist/sdk/mcp/oauth.d.ts +35 -0
- package/dist/sdk/mcp/oauth.js +171 -0
- package/dist/sdk/mcp/scopeMigration.d.ts +19 -0
- package/dist/sdk/mcp/scopeMigration.js +198 -0
- package/dist/sdk/mcp/service.d.ts +160 -0
- package/dist/sdk/mcp/service.js +510 -0
- package/dist/sdk/mcp/types.d.ts +131 -0
- package/dist/sdk/mcp/types.js +49 -0
- package/dist/sdk/pi/runtime.d.ts +13 -0
- package/dist/sdk/pi/runtime.js +31 -0
- package/dist/sdk/plugins/api.d.ts +66 -0
- package/dist/sdk/plugins/api.js +155 -0
- package/dist/sdk/plugins/attachments.d.ts +46 -0
- package/dist/sdk/plugins/attachments.js +111 -0
- package/dist/sdk/plugins/builtin.d.ts +6 -0
- package/dist/sdk/plugins/builtin.js +68 -0
- package/dist/sdk/plugins/catalogue.d.ts +29 -0
- package/dist/sdk/plugins/catalogue.js +196 -0
- package/dist/sdk/plugins/cli.d.ts +13 -0
- package/dist/sdk/plugins/cli.js +187 -0
- package/dist/sdk/plugins/discover.d.ts +42 -0
- package/dist/sdk/plugins/discover.js +115 -0
- package/dist/sdk/plugins/firstParty.d.ts +50 -0
- package/dist/sdk/plugins/firstParty.js +113 -0
- package/dist/sdk/plugins/hooks.d.ts +94 -0
- package/dist/sdk/plugins/hooks.js +162 -0
- package/dist/sdk/plugins/identity.d.ts +19 -0
- package/dist/sdk/plugins/identity.js +48 -0
- package/dist/sdk/plugins/install.d.ts +20 -0
- package/dist/sdk/plugins/install.js +110 -0
- package/dist/sdk/plugins/inventory.d.ts +22 -0
- package/dist/sdk/plugins/inventory.js +110 -0
- package/dist/sdk/plugins/manifest.d.ts +13 -0
- package/dist/sdk/plugins/manifest.js +56 -0
- package/dist/sdk/plugins/plugins.d.ts +104 -0
- package/dist/sdk/plugins/plugins.js +164 -0
- package/dist/sdk/plugins/runtime.d.ts +9 -0
- package/dist/sdk/plugins/runtime.js +95 -0
- package/dist/sdk/plugins/trust.d.ts +44 -0
- package/dist/sdk/plugins/trust.js +120 -0
- package/dist/sdk/plugins/types.d.ts +159 -0
- package/dist/sdk/plugins/types.js +7 -0
- package/dist/sdk/prompt/compile.d.ts +174 -0
- package/dist/sdk/prompt/compile.js +396 -0
- package/dist/sdk/refine/cli.d.ts +4 -0
- package/dist/sdk/refine/cli.js +186 -0
- package/dist/sdk/refine/demo.d.ts +21 -0
- package/dist/sdk/refine/demo.js +114 -0
- package/dist/sdk/refine/evidence.d.ts +55 -0
- package/dist/sdk/refine/evidence.js +330 -0
- package/dist/sdk/refine/host.d.ts +51 -0
- package/dist/sdk/refine/host.js +76 -0
- package/dist/sdk/refine/ledger.d.ts +48 -0
- package/dist/sdk/refine/ledger.js +76 -0
- package/dist/sdk/refine/library.d.ts +55 -0
- package/dist/sdk/refine/library.js +177 -0
- package/dist/sdk/refine/pi.d.ts +72 -0
- package/dist/sdk/refine/pi.js +248 -0
- package/dist/sdk/refine/prompts.d.ts +45 -0
- package/dist/sdk/refine/prompts.js +390 -0
- package/dist/sdk/refine/recursion.d.ts +113 -0
- package/dist/sdk/refine/recursion.js +258 -0
- package/dist/sdk/refine/runner.d.ts +81 -0
- package/dist/sdk/refine/runner.js +150 -0
- package/dist/sdk/refine/selection.d.ts +57 -0
- package/dist/sdk/refine/selection.js +251 -0
- package/dist/sdk/refine/service.d.ts +84 -0
- package/dist/sdk/refine/service.js +165 -0
- package/dist/sdk/refine/suite.d.ts +67 -0
- package/dist/sdk/refine/suite.js +174 -0
- package/dist/sdk/refine/trajectory.d.ts +9 -0
- package/dist/sdk/refine/trajectory.js +68 -0
- package/dist/sdk/refine/types.d.ts +77 -0
- package/dist/sdk/refine/types.js +10 -0
- package/dist/sdk/server/methods.d.ts +3 -0
- package/dist/sdk/server/methods.js +370 -0
- package/dist/sdk/server/remote.d.ts +19 -0
- package/dist/sdk/server/remote.js +84 -0
- package/dist/sdk/server/rpc.d.ts +20 -0
- package/dist/sdk/server/rpc.js +102 -0
- package/dist/sdk/server/serve.d.ts +10 -0
- package/dist/sdk/server/serve.js +18 -0
- package/dist/sdk/sessions/approvals.d.ts +47 -0
- package/dist/sdk/sessions/approvals.js +119 -0
- package/dist/sdk/sessions/continuation.d.ts +48 -0
- package/dist/sdk/sessions/continuation.js +85 -0
- package/dist/sdk/sessions/contracts.d.ts +534 -0
- package/dist/sdk/sessions/contracts.js +299 -0
- package/dist/sdk/sessions/extensionUi.d.ts +19 -0
- package/dist/sdk/sessions/extensionUi.js +64 -0
- package/dist/sdk/sessions/history.d.ts +16 -0
- package/dist/sdk/sessions/history.js +68 -0
- package/dist/sdk/sessions/lineageJoin.d.ts +2 -0
- package/dist/sdk/sessions/lineageJoin.js +61 -0
- package/dist/sdk/sessions/planMode.d.ts +36 -0
- package/dist/sdk/sessions/planMode.js +84 -0
- package/dist/sdk/sessions/policy.d.ts +43 -0
- package/dist/sdk/sessions/policy.js +1 -0
- package/dist/sdk/sessions/pricing.d.ts +34 -0
- package/dist/sdk/sessions/pricing.js +40 -0
- package/dist/sdk/sessions/reasoningSummaries.d.ts +11 -0
- package/dist/sdk/sessions/reasoningSummaries.js +61 -0
- package/dist/sdk/sessions/registry.d.ts +102 -0
- package/dist/sdk/sessions/registry.js +383 -0
- package/dist/sdk/sessions/runIndex.d.ts +21 -0
- package/dist/sdk/sessions/runIndex.js +65 -0
- package/dist/sdk/sessions/runStore.d.ts +66 -0
- package/dist/sdk/sessions/runStore.js +335 -0
- package/dist/sdk/sessions/runner.d.ts +213 -0
- package/dist/sdk/sessions/runner.js +589 -0
- package/dist/sdk/sessions/sessions.d.ts +140 -0
- package/dist/sdk/sessions/sessions.js +394 -0
- package/dist/sdk/sessions/subagentService.d.ts +41 -0
- package/dist/sdk/sessions/subagentService.js +247 -0
- package/dist/sdk/sessions/subagents.d.ts +50 -0
- package/dist/sdk/sessions/subagents.js +68 -0
- package/dist/sdk/terminal/accountsMenu.d.ts +46 -0
- package/dist/sdk/terminal/accountsMenu.js +392 -0
- package/dist/sdk/terminal/cli.d.ts +20 -0
- package/dist/sdk/terminal/cli.js +121 -0
- package/dist/sdk/terminal/client.d.ts +15 -0
- package/dist/sdk/terminal/client.js +126 -0
- package/dist/sdk/terminal/control.d.ts +4 -0
- package/dist/sdk/terminal/control.js +25 -0
- package/dist/sdk/terminal/controller.d.ts +72 -0
- package/dist/sdk/terminal/controller.js +351 -0
- package/dist/sdk/terminal/hubMenu.d.ts +10 -0
- package/dist/sdk/terminal/hubMenu.js +34 -0
- package/dist/sdk/terminal/launch.d.ts +5 -0
- package/dist/sdk/terminal/launch.js +27 -0
- package/dist/sdk/terminal/logs.d.ts +14 -0
- package/dist/sdk/terminal/logs.js +59 -0
- package/dist/sdk/terminal/piExtension.d.ts +6 -0
- package/dist/sdk/terminal/piExtension.js +392 -0
- package/dist/sdk/terminal/pluginMenu.d.ts +34 -0
- package/dist/sdk/terminal/pluginMenu.js +101 -0
- package/dist/sdk/terminal/socket.d.ts +70 -0
- package/dist/sdk/terminal/socket.js +256 -0
- package/dist/sdk/terminal/standalone.d.ts +18 -0
- package/dist/sdk/terminal/standalone.js +146 -0
- package/dist/sdk/terminal/terminals.d.ts +176 -0
- package/dist/sdk/terminal/terminals.js +767 -0
- package/dist/sdk/terminal/trajectory.d.ts +10 -0
- package/dist/sdk/terminal/trajectory.js +30 -0
- package/dist/sdk/terminal/tui/chrome.d.ts +64 -0
- package/dist/sdk/terminal/tui/chrome.js +169 -0
- package/dist/sdk/terminal/tui/clipboardFiles.d.ts +11 -0
- package/dist/sdk/terminal/tui/clipboardFiles.js +74 -0
- package/dist/sdk/terminal/tui/commandPages.d.ts +7 -0
- package/dist/sdk/terminal/tui/commandPages.js +63 -0
- package/dist/sdk/terminal/tui/commands.d.ts +42 -0
- package/dist/sdk/terminal/tui/commands.js +276 -0
- package/dist/sdk/terminal/tui/dialogGeometry.d.ts +27 -0
- package/dist/sdk/terminal/tui/dialogGeometry.js +50 -0
- package/dist/sdk/terminal/tui/dialogs.d.ts +75 -0
- package/dist/sdk/terminal/tui/dialogs.js +363 -0
- package/dist/sdk/terminal/tui/keybindings.d.ts +11 -0
- package/dist/sdk/terminal/tui/keybindings.js +49 -0
- package/dist/sdk/terminal/tui/list.d.ts +73 -0
- package/dist/sdk/terminal/tui/list.js +196 -0
- package/dist/sdk/terminal/tui/modeChoices.d.ts +42 -0
- package/dist/sdk/terminal/tui/modeChoices.js +70 -0
- package/dist/sdk/terminal/tui/modelPicker.d.ts +55 -0
- package/dist/sdk/terminal/tui/modelPicker.js +155 -0
- package/dist/sdk/terminal/tui/mouse.d.ts +3 -0
- package/dist/sdk/terminal/tui/mouse.js +3 -0
- package/dist/sdk/terminal/tui/page.d.ts +14 -0
- package/dist/sdk/terminal/tui/page.js +1 -0
- package/dist/sdk/terminal/tui/pageOverlay.d.ts +27 -0
- package/dist/sdk/terminal/tui/pageOverlay.js +145 -0
- package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +54 -0
- package/dist/sdk/terminal/tui/pages/accountsPage.js +181 -0
- package/dist/sdk/terminal/tui/pages/componentsPage.d.ts +47 -0
- package/dist/sdk/terminal/tui/pages/componentsPage.js +119 -0
- package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +37 -0
- package/dist/sdk/terminal/tui/pages/doctorPage.js +145 -0
- package/dist/sdk/terminal/tui/pages/hubPage.d.ts +39 -0
- package/dist/sdk/terminal/tui/pages/hubPage.js +128 -0
- package/dist/sdk/terminal/tui/pages/logPage.d.ts +38 -0
- package/dist/sdk/terminal/tui/pages/logPage.js +189 -0
- package/dist/sdk/terminal/tui/pages/permissionsPage.d.ts +44 -0
- package/dist/sdk/terminal/tui/pages/permissionsPage.js +124 -0
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +57 -0
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +243 -0
- package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +55 -0
- package/dist/sdk/terminal/tui/pages/settingsPage.js +88 -0
- package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +58 -0
- package/dist/sdk/terminal/tui/pages/trajectoryPage.js +377 -0
- package/dist/sdk/terminal/tui/piAdapter.d.ts +18 -0
- package/dist/sdk/terminal/tui/piAdapter.js +48 -0
- package/dist/sdk/terminal/tui/planMode.d.ts +2 -0
- package/dist/sdk/terminal/tui/planMode.js +2 -0
- package/dist/sdk/terminal/tui/questionPicker.d.ts +20 -0
- package/dist/sdk/terminal/tui/questionPicker.js +150 -0
- package/dist/sdk/terminal/tui/questions.d.ts +19 -0
- package/dist/sdk/terminal/tui/questions.js +42 -0
- package/dist/sdk/terminal/tui/runtime.d.ts +114 -0
- package/dist/sdk/terminal/tui/runtime.js +441 -0
- package/dist/sdk/terminal/tui/search.d.ts +22 -0
- package/dist/sdk/terminal/tui/search.js +60 -0
- package/dist/sdk/terminal/tui/selection.d.ts +16 -0
- package/dist/sdk/terminal/tui/selection.js +16 -0
- package/dist/sdk/terminal/tui/sessionUi.d.ts +3 -0
- package/dist/sdk/terminal/tui/sessionUi.js +30 -0
- package/dist/sdk/terminal/tui/settingsModel.d.ts +12 -0
- package/dist/sdk/terminal/tui/settingsModel.js +84 -0
- package/dist/sdk/terminal/tui/sideQuestion.d.ts +53 -0
- package/dist/sdk/terminal/tui/sideQuestion.js +197 -0
- package/dist/sdk/terminal/tui/skillInvocation.d.ts +9 -0
- package/dist/sdk/terminal/tui/skillInvocation.js +43 -0
- package/dist/sdk/terminal/tui/status.d.ts +18 -0
- package/dist/sdk/terminal/tui/status.js +67 -0
- package/dist/sdk/terminal/tui/theme.d.ts +45 -0
- package/dist/sdk/terminal/tui/theme.js +176 -0
- package/dist/sdk/terminal/tui/treeModel.d.ts +79 -0
- package/dist/sdk/terminal/tui/treeModel.js +483 -0
- package/dist/sdk/terminal/tui/treePicker.d.ts +49 -0
- package/dist/sdk/terminal/tui/treePicker.js +251 -0
- package/dist/sdk/terminal/tui/ui.d.ts +47 -0
- package/dist/sdk/terminal/tui/ui.js +148 -0
- package/dist/sdk/terminal/tui/workingStatus.d.ts +9 -0
- package/dist/sdk/terminal/tui/workingStatus.js +229 -0
- package/dist/sdk/tools/askUser.d.ts +6 -0
- package/dist/sdk/tools/askUser.js +74 -0
- package/dist/sdk/tools/checklist.d.ts +9 -0
- package/dist/sdk/tools/checklist.js +54 -0
- package/dist/sdk/tools/definitions.d.ts +30 -0
- package/dist/sdk/tools/definitions.js +117 -0
- package/dist/sdk/tools/dispatch.d.ts +16 -0
- package/dist/sdk/tools/dispatch.js +67 -0
- package/dist/sdk/tools/harnessTools.d.ts +6 -0
- package/dist/sdk/tools/harnessTools.js +20 -0
- package/dist/sdk/tools/sessionName.d.ts +7 -0
- package/dist/sdk/tools/sessionName.js +31 -0
- package/dist/sdk/tools/spawnSubagent.d.ts +4 -0
- package/dist/sdk/tools/spawnSubagent.js +49 -0
- package/dist/sdk/tools/types.d.ts +48 -0
- package/dist/sdk/tools/types.js +1 -0
- package/dist/sdk/variant/components.d.ts +34 -0
- package/dist/sdk/variant/components.js +230 -0
- package/dist/sdk/variant/materialise.d.ts +66 -0
- package/dist/sdk/variant/materialise.js +81 -0
- package/dist/sdk/variant/migrate.d.ts +4 -0
- package/dist/sdk/variant/migrate.js +41 -0
- package/dist/sdk/variant/seed.d.ts +20 -0
- package/dist/sdk/variant/seed.js +116 -0
- package/dist/sdk/variant/store.d.ts +82 -0
- package/dist/sdk/variant/store.js +151 -0
- package/dist/sdk/variant/surface.d.ts +56 -0
- package/dist/sdk/variant/surface.js +81 -0
- package/dist/sdk/variant/trust.d.ts +27 -0
- package/dist/sdk/variant/trust.js +64 -0
- package/dist/sdk/variant/variant.d.ts +71 -0
- package/dist/sdk/variant/variant.js +331 -0
- package/dist/sdk/web/markdown.d.ts +10 -0
- package/dist/sdk/web/markdown.js +66 -0
- package/dist/sdk/web/safeRequest.d.ts +34 -0
- package/dist/sdk/web/safeRequest.js +175 -0
- package/dist/sdk/web/search.d.ts +53 -0
- package/dist/sdk/web/search.js +168 -0
- package/dist/sdk/web/text.d.ts +2 -0
- package/dist/sdk/web/text.js +7 -0
- package/dist/sdk/web/tools.d.ts +22 -0
- package/dist/sdk/web/tools.js +195 -0
- package/dist/sdk/web/turndown-plugin-gfm.d.ts +4 -0
- package/dist/sdk/wiki/notes.d.ts +68 -0
- package/dist/sdk/wiki/notes.js +297 -0
- package/dist/sdk/world/actions.d.ts +23 -0
- package/dist/sdk/world/actions.js +31 -0
- package/dist/sdk/world/cli.d.ts +12 -0
- package/dist/sdk/world/cli.js +166 -0
- package/dist/sdk/world/images.d.ts +20 -0
- package/dist/sdk/world/images.js +48 -0
- package/dist/sdk/world/untrusted.d.ts +12 -0
- package/dist/sdk/world/untrusted.js +20 -0
- package/dist/sdk/world/world.d.ts +65 -0
- package/dist/sdk/world/world.js +80 -0
- package/dist/terminal-opentui.js +13612 -0
- package/dist/terminal-pi.js +808 -151
- package/docs/README.md +22 -0
- package/docs/architecture/00-overview.md +159 -0
- package/docs/architecture/01-extension-points.md +78 -0
- package/docs/architecture/02-sessions-and-runs.md +146 -0
- package/docs/architecture/03-variants.md +95 -0
- package/docs/architecture/04-prompt.md +102 -0
- package/docs/architecture/05-refinement.md +107 -0
- package/docs/architecture/06-plugins-and-capabilities.md +93 -0
- package/docs/architecture/07-tools-and-gate.md +88 -0
- package/docs/architecture/08-memory-and-history.md +94 -0
- package/docs/architecture/09-accounts-and-connectors.md +90 -0
- package/docs/architecture/10-server-protocol.md +84 -0
- package/docs/architecture/11-terminal.md +81 -0
- package/docs/architecture/12-storage.md +61 -0
- package/docs/architecture/13-world-tools.md +23 -0
- package/docs/architecture/README.md +114 -0
- package/docs/architecture/proposals/PROP-0001-reporting-section.md +106 -0
- package/docs/architecture/proposals/PROP-0002-retain-rollout-workspaces.md +104 -0
- package/docs/architecture/proposals/PROP-0003-executor-settings.md +81 -0
- package/docs/architecture/proposals/PROP-0004-flexible-reporting-guidance.md +71 -0
- package/docs/architecture/proposals/PROP-0005-xharness-cli-name.md +78 -0
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +68 -0
- package/docs/architecture/proposals/PROP-0007-run-continuation.md +80 -0
- package/docs/architecture/proposals/PROP-0008-lessons-from-runs.md +80 -0
- package/docs/architecture/proposals/PROP-0009-foundation-and-variants.md +78 -0
- package/docs/architecture/proposals/PROP-0010-session-names.md +73 -0
- package/docs/architecture/proposals/PROP-0011-doctor.md +63 -0
- package/docs/architecture/proposals/PROP-0012-release-baseline.md +56 -0
- package/docs/architecture/proposals/README.md +76 -0
- package/docs/decisions/ADR-0002-native-subagent-lifecycle.md +49 -0
- package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +70 -0
- package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +50 -0
- package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
- package/docs/decisions/ADR-0006-opentui-only-terminal.md +47 -0
- package/docs/decisions/ADR-0007-reporting-section.md +33 -0
- package/docs/decisions/ADR-0008-flexible-reporting-guidance.md +38 -0
- package/docs/decisions/ADR-0009-xharness-command.md +38 -0
- package/docs/decisions/ADR-0010-lessons-in-the-wiki.md +31 -0
- package/docs/decisions/ADR-0011-foundation-and-variants.md +28 -0
- package/docs/decisions/ADR-0012-native-session-names.md +34 -0
- package/docs/decisions/ADR-0013-doctor.md +27 -0
- package/docs/decisions/ADR-0014-public-release-baseline.md +21 -0
- package/docs/doctor.md +74 -0
- package/docs/experiments/EXP-0001-terminal-input-latency/plan.md +81 -0
- package/docs/experiments/EXP-0001-terminal-input-latency/results.md +46 -0
- package/docs/experiments/EXP-0002-opentui-typing-latency/plan.md +70 -0
- package/docs/experiments/EXP-0002-opentui-typing-latency/results.md +92 -0
- package/docs/features/README.md +20 -0
- package/docs/features/automations/README.md +41 -0
- package/docs/features/cores/README.md +39 -0
- package/docs/features/google-harness2/README.md +52 -0
- package/docs/features/integrations/README.md +40 -0
- package/docs/features/interfaces/README.md +29 -0
- package/docs/features/memory/README.md +28 -0
- package/docs/releases/1.0.0.md +40 -0
- package/docs/releases/README.md +36 -0
- package/docs/study/00-index.md +78 -0
- package/docs/study/arms/00-matrix.md +20 -0
- package/docs/study/arms/01-system-prompt.md +211 -0
- package/docs/study/arms/02-tools.md +79 -0
- package/docs/study/arms/03-subagents.md +90 -0
- package/docs/study/arms/04-skills.md +75 -0
- package/docs/study/arms/05-context-management.md +90 -0
- package/docs/study/arms/06-memory.md +90 -0
- package/docs/study/arms/07-governance.md +71 -0
- package/docs/study/arms/08-execution.md +69 -0
- package/docs/study/arms/09-observability.md +60 -0
- package/docs/study/arms/10-refinement.md +110 -0
- package/docs/study/btw-comparison.md +37 -0
- package/docs/study/feature-gap-review.md +42 -0
- package/docs/study/insights.md +123 -0
- package/docs/study/roadmap.md +72 -0
- package/docs/study/sources/claude-code.md +44 -0
- package/docs/study/sources/deepseek-harness.md +102 -0
- package/docs/study/sources/harness2.md +50 -0
- package/docs/study/sources/kimi-cli.md +42 -0
- package/docs/study/sources/omp.md +93 -0
- package/docs/study/sources/opencode.md +43 -0
- package/docs/study/sources/openhands.md +46 -0
- package/docs/study/sources/smolagents.md +40 -0
- package/docs/study/sources/swe-agent.md +34 -0
- package/docs/system-prompt-design.md +196 -0
- package/docs/terminal-tui.md +473 -56
- package/package.json +43 -13
- package/docs/evidence/terminal-2026-10-17/120x40-completed-transcript.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17/40x20-settings-interaction.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17/40x20-settings-keyboard.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17/40x20-welcome.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17/80x24-approval-0.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17/80x24-question.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17/verification.json +0 -130
- package/docs/evidence/terminal-2026-10-17-followup/120x40-completed-transcript.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-interaction.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-keyboard.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/40x20-welcome.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/80x24-approval-0.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/80x24-plugin-light.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/80x24-question-batch.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/80x24-question.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-approval-0.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-plugin-light.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question-batch.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/app-bundle/verification.json +0 -95
- package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-approval-0.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-plugin-light.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question-batch.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/global-install/README.md +0 -27
- package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command-80x24.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command.json +0 -18
- package/docs/evidence/terminal-2026-10-17-followup/global-install/verification.json +0 -95
- package/docs/evidence/terminal-2026-10-17-followup/harness-reference-80x24.json.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/harness-reference-final-80x24.json.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/harness-reference-scenario.json +0 -60
- package/docs/evidence/terminal-2026-10-17-followup/live-codex/README.md +0 -24
- package/docs/evidence/terminal-2026-10-17-followup/live-codex/complete-80x24.ansi.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/live-codex/verification.json +0 -57
- package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24-early.json.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24.json.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/omp-reference-scenario.json +0 -58
- package/docs/evidence/terminal-2026-10-17-followup/omp-supplemental-static.json.gz +0 -0
- package/docs/evidence/terminal-2026-10-17-followup/rea-artifacts.json +0 -320
- package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.json +0 -30
- package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.md +0 -133
- package/docs/evidence/terminal-2026-10-17-followup/reference-source-observations.json +0 -20
- package/docs/evidence/terminal-2026-10-17-followup/verification.json +0 -207
- package/src/accounts/accounts.test.ts +0 -333
- package/src/accounts/accounts.ts +0 -658
- package/src/accounts/env.test.ts +0 -95
- package/src/accounts/env.ts +0 -338
- package/src/accounts/secrets.ts +0 -50
- package/src/accounts/store.ts +0 -338
- package/src/capabilities/api.ts +0 -75
- package/src/capabilities/runSnapshot.ts +0 -59
- package/src/capabilities/types.ts +0 -34
- package/src/cli.ts +0 -118
- package/src/core/bus.ts +0 -34
- package/src/core/changes.ts +0 -33
- package/src/core/env.ts +0 -27
- package/src/core/errors.ts +0 -32
- package/src/core/frontmatter.ts +0 -47
- package/src/core/fs.test.ts +0 -38
- package/src/core/fs.ts +0 -92
- package/src/core/index.ts +0 -193
- package/src/core/path.test.ts +0 -14
- package/src/core/path.ts +0 -79
- package/src/core/projects.ts +0 -90
- package/src/core/text.ts +0 -39
- package/src/harness.ts +0 -312
- package/src/hub/catalog.json +0 -123
- package/src/hub/cli.ts +0 -59
- package/src/hub/hub.test.ts +0 -205
- package/src/hub/hub.ts +0 -256
- package/src/hub/schema.ts +0 -81
- package/src/index.ts +0 -75
- package/src/mcp/connections.ts +0 -614
- package/src/mcp/manager.ts +0 -130
- package/src/mcp/oauth.ts +0 -195
- package/src/mcp/scopeMigration.test.ts +0 -79
- package/src/mcp/scopeMigration.ts +0 -204
- package/src/mcp/service.test.ts +0 -376
- package/src/mcp/service.ts +0 -549
- package/src/mcp/types.ts +0 -108
- package/src/memory/api.test.ts +0 -82
- package/src/memory/api.ts +0 -303
- package/src/memory/blocks.test.ts +0 -78
- package/src/memory/blocks.ts +0 -408
- package/src/memory/caller.ts +0 -69
- package/src/memory/curation.test.ts +0 -163
- package/src/memory/curation.ts +0 -64
- package/src/memory/dispatch.ts +0 -59
- package/src/memory/facts.test.ts +0 -41
- package/src/memory/facts.ts +0 -248
- package/src/memory/graph.ts +0 -103
- package/src/memory/health.test.ts +0 -130
- package/src/memory/health.ts +0 -74
- package/src/memory/maintainer.ts +0 -272
- package/src/memory/maintenance.test.ts +0 -176
- package/src/memory/maintenance.ts +0 -518
- package/src/memory/migrate.ts +0 -79
- package/src/memory/operations.ts +0 -150
- package/src/memory/proposals.test.ts +0 -168
- package/src/memory/proposals.ts +0 -584
- package/src/memory/recall.test.ts +0 -115
- package/src/memory/recall.ts +0 -278
- package/src/memory/references.ts +0 -77
- package/src/memory/runContext.ts +0 -93
- package/src/memory/secrets.ts +0 -6
- package/src/memory/store.test.ts +0 -66
- package/src/memory/store.ts +0 -385
- package/src/memory/wiki.test.ts +0 -47
- package/src/memory/wiki.ts +0 -422
- package/src/memory/wikiIndex.test.ts +0 -88
- package/src/memory/wikiIndex.ts +0 -116
- package/src/plugins/api.ts +0 -181
- package/src/plugins/attachments.test.ts +0 -84
- package/src/plugins/attachments.ts +0 -141
- package/src/plugins/builtin.ts +0 -82
- package/src/plugins/catalogue.test.ts +0 -254
- package/src/plugins/catalogue.ts +0 -251
- package/src/plugins/cli.ts +0 -184
- package/src/plugins/discover.ts +0 -151
- package/src/plugins/firstParty.test.ts +0 -143
- package/src/plugins/firstParty.ts +0 -129
- package/src/plugins/hooks.test.ts +0 -250
- package/src/plugins/hooks.ts +0 -239
- package/src/plugins/identity.ts +0 -37
- package/src/plugins/install.test.ts +0 -107
- package/src/plugins/install.ts +0 -106
- package/src/plugins/inventory.ts +0 -123
- package/src/plugins/manifest.ts +0 -76
- package/src/plugins/plugins.test.ts +0 -205
- package/src/plugins/plugins.ts +0 -189
- package/src/plugins/proposal.ts +0 -121
- package/src/plugins/runtime.test.ts +0 -40
- package/src/plugins/runtime.ts +0 -82
- package/src/plugins/trust.ts +0 -142
- package/src/plugins/types.ts +0 -149
- package/src/prompt/compile.test.ts +0 -261
- package/src/prompt/compile.ts +0 -732
- package/src/server/methods.ts +0 -349
- package/src/server/remote.ts +0 -77
- package/src/server/rpc.ts +0 -116
- package/src/server/serve.ts +0 -28
- package/src/server/server.test.ts +0 -174
- package/src/sessions/approvals.ts +0 -118
- package/src/sessions/contracts.ts +0 -336
- package/src/sessions/conversation.test.ts +0 -177
- package/src/sessions/extensionSession.test.ts +0 -74
- package/src/sessions/extensionUi.test.ts +0 -65
- package/src/sessions/extensionUi.ts +0 -102
- package/src/sessions/history.ts +0 -51
- package/src/sessions/lineageJoin.ts +0 -75
- package/src/sessions/policy.ts +0 -36
- package/src/sessions/pricing.ts +0 -60
- package/src/sessions/questionBatches.test.ts +0 -110
- package/src/sessions/reasoningSummaries.ts +0 -59
- package/src/sessions/registry.ts +0 -381
- package/src/sessions/runIndex.ts +0 -99
- package/src/sessions/runStore.test.ts +0 -152
- package/src/sessions/runStore.ts +0 -332
- package/src/sessions/runner.ts +0 -604
- package/src/sessions/runtimeResources.test.ts +0 -61
- package/src/sessions/sessions.test.ts +0 -549
- package/src/sessions/sessions.ts +0 -339
- package/src/skills/registry.test.ts +0 -104
- package/src/skills/registry.ts +0 -413
- package/src/terminal/accountsMenu.test.ts +0 -225
- package/src/terminal/accountsMenu.ts +0 -382
- package/src/terminal/cli.ts +0 -149
- package/src/terminal/client.ts +0 -74
- package/src/terminal/control.test.ts +0 -23
- package/src/terminal/control.ts +0 -23
- package/src/terminal/controller.ts +0 -291
- package/src/terminal/hubMenu.ts +0 -24
- package/src/terminal/launch.test.ts +0 -25
- package/src/terminal/launch.ts +0 -48
- package/src/terminal/piExtension.lifecycle.test.ts +0 -55
- package/src/terminal/piExtension.ts +0 -259
- package/src/terminal/pluginControl.test.ts +0 -146
- package/src/terminal/pluginMenu.ts +0 -112
- package/src/terminal/socket.test.ts +0 -71
- package/src/terminal/socket.ts +0 -232
- package/src/terminal/standalone.test.ts +0 -167
- package/src/terminal/standalone.ts +0 -153
- package/src/terminal/terminal.test.ts +0 -399
- package/src/terminal/terminals.ts +0 -553
- package/src/terminal/tui/application.test.ts +0 -114
- package/src/terminal/tui/application.ts +0 -491
- package/src/terminal/tui/commands.test.ts +0 -218
- package/src/terminal/tui/commands.ts +0 -361
- package/src/terminal/tui/dialogs.ts +0 -301
- package/src/terminal/tui/editor.test.ts +0 -84
- package/src/terminal/tui/editor.ts +0 -79
- package/src/terminal/tui/keybindings.test.ts +0 -22
- package/src/terminal/tui/keybindings.ts +0 -50
- package/src/terminal/tui/piAdapter.ts +0 -62
- package/src/terminal/tui/presentation.test.ts +0 -79
- package/src/terminal/tui/questions.test.ts +0 -41
- package/src/terminal/tui/questions.ts +0 -47
- package/src/terminal/tui/runtime.socket.test.ts +0 -104
- package/src/terminal/tui/runtime.test.ts +0 -215
- package/src/terminal/tui/runtime.ts +0 -388
- package/src/terminal/tui/sessionUi.ts +0 -24
- package/src/terminal/tui/settings.test.ts +0 -150
- package/src/terminal/tui/settings.ts +0 -188
- package/src/terminal/tui/status.test.ts +0 -70
- package/src/terminal/tui/status.ts +0 -109
- package/src/terminal/tui/theme.ts +0 -174
- package/src/terminal/tui/tools.test.ts +0 -145
- package/src/terminal/tui/tools.ts +0 -142
- package/src/terminal/tui/transcript.test.ts +0 -25
- package/src/terminal/tui/transcript.ts +0 -124
- package/src/terminal/tui/ui.test.ts +0 -313
- package/src/terminal/tui/ui.ts +0 -166
- package/src/terminal/tui/welcome.ts +0 -102
- package/src/tools/askUser.test.ts +0 -69
- package/src/tools/askUser.ts +0 -59
- package/src/tools/definitions.ts +0 -187
- package/src/tools/maintenance.ts +0 -24
- package/src/tools/memoryTools.ts +0 -22
- package/src/tools/pluginPropose.ts +0 -41
- package/src/tools/registryWrite.test.ts +0 -101
- package/src/tools/registryWrite.ts +0 -182
- package/src/tools/spawnSubagent.ts +0 -92
- package/src/tools/types.ts +0 -39
- package/src/web/safeRequest.ts +0 -171
- package/src/web/text.ts +0 -53
- package/src/web/tools.ts +0 -134
- package/src/web/web.test.ts +0 -141
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type SocketConnection } from "./client.js";
|
|
2
|
+
/** A process owns the claim across native session replacement; it never enters the environment. */
|
|
3
|
+
export declare function claimTerminalControl(connection?: SocketConnection): Promise<string>;
|
|
4
|
+
export declare function controlCall<T = unknown>(call: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<T>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { connectionFromEnv, socketCall } from "./client.js";
|
|
2
|
+
const claims = new Map();
|
|
3
|
+
/** A process owns the claim across native session replacement; it never enters the environment. */
|
|
4
|
+
export function claimTerminalControl(connection = connectionFromEnv()) {
|
|
5
|
+
const identity = JSON.stringify([connection.socket, connection.token]);
|
|
6
|
+
let claim = claims.get(identity);
|
|
7
|
+
if (!claim) {
|
|
8
|
+
claim = socketCall(connection, 'control.claim', {}, 15_000).then(({ key }) => {
|
|
9
|
+
if (!key)
|
|
10
|
+
throw new Error('The terminal controller returned no control key.');
|
|
11
|
+
return key;
|
|
12
|
+
}).catch((error) => {
|
|
13
|
+
// A failed claim is retried by the next call; only a claim that succeeded is kept.
|
|
14
|
+
claims.delete(identity);
|
|
15
|
+
throw error;
|
|
16
|
+
});
|
|
17
|
+
claims.set(identity, claim);
|
|
18
|
+
}
|
|
19
|
+
return claim;
|
|
20
|
+
}
|
|
21
|
+
export async function controlCall(call, params = {}, timeoutMs = 120_000) {
|
|
22
|
+
const connection = connectionFromEnv();
|
|
23
|
+
const control = await claimTerminalControl(connection);
|
|
24
|
+
return socketCall(connection, call, params, timeoutMs, control);
|
|
25
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { RunEvent } from "../sessions/contracts.js";
|
|
2
|
+
import type { ActiveRun, ApprovalDecision, QuestionAnswer } from "../sessions/registry.js";
|
|
3
|
+
export interface PolicyReply {
|
|
4
|
+
allowed: boolean;
|
|
5
|
+
reason?: string | null;
|
|
6
|
+
requiresApproval?: boolean;
|
|
7
|
+
rememberable?: boolean;
|
|
8
|
+
standing?: 'full' | 'switch' | 'none';
|
|
9
|
+
}
|
|
10
|
+
export interface ControllerHooks {
|
|
11
|
+
sessionId: string;
|
|
12
|
+
nativeSessionId: string | null;
|
|
13
|
+
/** Reserves or creates the run for a native turn and starts tracking it. */
|
|
14
|
+
begin(input: {
|
|
15
|
+
reservedRunId: string | null;
|
|
16
|
+
nativeTurnId: string;
|
|
17
|
+
text: string;
|
|
18
|
+
}): ActiveRun;
|
|
19
|
+
/** Whether a native tool call may run. */
|
|
20
|
+
policy(run: ActiveRun, tool: string, args: unknown): Promise<PolicyReply>;
|
|
21
|
+
/** Saves a user-selected tool grant in the shared local approval store. */
|
|
22
|
+
allowToolGlobally(target: string): void;
|
|
23
|
+
/** The native conversation identity changed. */
|
|
24
|
+
native(nativeSessionId: string): void;
|
|
25
|
+
telemetry(event: string): void;
|
|
26
|
+
interrupt?(runId: string): Promise<void>;
|
|
27
|
+
resolveApproval?(runId: string, requestId: string, decision: ApprovalDecision): void;
|
|
28
|
+
answerQuestion?(runId: string, requestId: string, answer: QuestionAnswer): void;
|
|
29
|
+
answerQuestions?(runId: string, batchId: string, answers: Array<{
|
|
30
|
+
questionId: string;
|
|
31
|
+
answer: QuestionAnswer;
|
|
32
|
+
}>): void;
|
|
33
|
+
}
|
|
34
|
+
export declare class TerminalController {
|
|
35
|
+
private readonly hooks;
|
|
36
|
+
private run;
|
|
37
|
+
private readonly pending;
|
|
38
|
+
private ready;
|
|
39
|
+
private disposed;
|
|
40
|
+
private dirty;
|
|
41
|
+
private multilineDraft;
|
|
42
|
+
private startupError;
|
|
43
|
+
private startupPhase;
|
|
44
|
+
private delivery;
|
|
45
|
+
private nativeId;
|
|
46
|
+
private readonly seen;
|
|
47
|
+
private readonly commands;
|
|
48
|
+
constructor(hooks: ControllerHooks);
|
|
49
|
+
get nativeSessionId(): string | null;
|
|
50
|
+
get activeRun(): ActiveRun | null;
|
|
51
|
+
state(): {
|
|
52
|
+
ready: boolean;
|
|
53
|
+
dirty: boolean;
|
|
54
|
+
active: boolean;
|
|
55
|
+
};
|
|
56
|
+
private requestId;
|
|
57
|
+
private begin;
|
|
58
|
+
private finish;
|
|
59
|
+
/** Hands the native process an instruction and waits until it acknowledges the prompt. */
|
|
60
|
+
send(runId: string, text: string): Promise<void>;
|
|
61
|
+
/** What the person typed into the terminal, so an instruction is never sent over their draft. */
|
|
62
|
+
onInput(data: string): void;
|
|
63
|
+
/** The native process hung up while it was waiting for a decision. */
|
|
64
|
+
disconnected(): void;
|
|
65
|
+
/** Project registry-owned questions, including grouped requests, into the terminal inbox. */
|
|
66
|
+
observe(event: RunEvent, descendant?: boolean): void;
|
|
67
|
+
/** The socket grants this interface only to the process that owns terminal input. */
|
|
68
|
+
control(call: string, data: Record<string, any>): Promise<unknown>;
|
|
69
|
+
private requestNativeApproval;
|
|
70
|
+
accept(event: string, data: Record<string, any>): Promise<unknown>;
|
|
71
|
+
dispose(): void;
|
|
72
|
+
}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// One `pi` command running in a terminal, as the harness sees it. The terminal itself belongs
|
|
2
|
+
// to whoever embeds the harness; this follows the native process through its extension's
|
|
3
|
+
// telemetry (never by reading the screen), turns each native turn into a run, and answers the
|
|
4
|
+
// extension's questions about policy, approvals, and what to do next.
|
|
5
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
6
|
+
import { HarnessError } from "../core/errors.js";
|
|
7
|
+
const READY_TIMEOUT_MS = 90_000;
|
|
8
|
+
const ACK_TIMEOUT_MS = 25_000;
|
|
9
|
+
export class TerminalController {
|
|
10
|
+
hooks;
|
|
11
|
+
run = null;
|
|
12
|
+
pending = new Map();
|
|
13
|
+
ready = false;
|
|
14
|
+
disposed = false;
|
|
15
|
+
dirty = false;
|
|
16
|
+
multilineDraft = false;
|
|
17
|
+
startupError = null;
|
|
18
|
+
startupPhase = 'Waiting for the native extension';
|
|
19
|
+
delivery = null;
|
|
20
|
+
nativeId;
|
|
21
|
+
seen = new Map();
|
|
22
|
+
commands = [];
|
|
23
|
+
constructor(hooks) {
|
|
24
|
+
this.hooks = hooks;
|
|
25
|
+
this.nativeId = hooks.nativeSessionId;
|
|
26
|
+
}
|
|
27
|
+
get nativeSessionId() {
|
|
28
|
+
return this.nativeId;
|
|
29
|
+
}
|
|
30
|
+
get activeRun() {
|
|
31
|
+
return this.run && !this.run.finished ? this.run : null;
|
|
32
|
+
}
|
|
33
|
+
state() {
|
|
34
|
+
return { ready: this.ready, dirty: this.dirty, active: !!this.activeRun || !!this.delivery };
|
|
35
|
+
}
|
|
36
|
+
requestId(nativeId) {
|
|
37
|
+
return createHash('sha256').update(`${this.hooks.sessionId}:${this.run?.runId}:${nativeId}`).digest('hex');
|
|
38
|
+
}
|
|
39
|
+
begin(nativeTurnId, text) {
|
|
40
|
+
if (this.startupError)
|
|
41
|
+
throw new Error(this.startupError);
|
|
42
|
+
this.dirty = false;
|
|
43
|
+
this.multilineDraft = false;
|
|
44
|
+
if (this.run && !this.run.finished)
|
|
45
|
+
return this.run;
|
|
46
|
+
const delivery = this.delivery;
|
|
47
|
+
if (delivery && text && delivery.text !== text)
|
|
48
|
+
throw new Error('The native prompt did not match the reserved delivery. Inspect the terminal before continuing.');
|
|
49
|
+
const run = this.hooks.begin({ reservedRunId: delivery?.runId ?? null, nativeTurnId, text });
|
|
50
|
+
this.run = run;
|
|
51
|
+
run.onInterrupt(() => void this.commands.push({ type: 'interrupt' }));
|
|
52
|
+
if (text)
|
|
53
|
+
run.emit('message.completed', { messageId: nativeTurnId, role: 'user', text });
|
|
54
|
+
delivery?.resolve();
|
|
55
|
+
this.delivery = null;
|
|
56
|
+
return run;
|
|
57
|
+
}
|
|
58
|
+
finish(outcome, message) {
|
|
59
|
+
this.run?.finish(outcome, message ? { code: 'terminal_attention', message } : undefined);
|
|
60
|
+
this.run = null;
|
|
61
|
+
this.seen.clear();
|
|
62
|
+
this.pending.clear();
|
|
63
|
+
}
|
|
64
|
+
/** Hands the native process an instruction and waits until it acknowledges the prompt. */
|
|
65
|
+
async send(runId, text) {
|
|
66
|
+
if (this.disposed)
|
|
67
|
+
throw new HarnessError('terminal_not_ready', 'Reopen the terminal before sending instructions.');
|
|
68
|
+
if (this.activeRun || this.delivery)
|
|
69
|
+
throw new HarnessError('session_busy', 'This terminal has an active task or delivery.');
|
|
70
|
+
const deadline = Date.now() + READY_TIMEOUT_MS;
|
|
71
|
+
while (!this.ready && !this.startupError && !this.disposed && Date.now() < deadline)
|
|
72
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
73
|
+
if (this.disposed)
|
|
74
|
+
throw new HarnessError('terminal_not_ready', 'The terminal stopped during initialization.');
|
|
75
|
+
if (this.startupError)
|
|
76
|
+
throw new HarnessError('terminal_not_ready', this.startupError);
|
|
77
|
+
if (!this.ready)
|
|
78
|
+
throw new HarnessError('terminal_not_ready', `The native telemetry handshake is missing (${this.startupPhase}). Inspect the terminal sign-in or trust screen.`);
|
|
79
|
+
if (this.dirty)
|
|
80
|
+
throw new HarnessError('terminal_has_draft', 'The terminal contains user input. Submit or clear it before handing back control.');
|
|
81
|
+
let timer;
|
|
82
|
+
const ack = new Promise((resolve, reject) => {
|
|
83
|
+
timer = setTimeout(() => reject(new HarnessError('delivery_uncertain', 'The native prompt acknowledgement was not received. Inspect the terminal; this instruction will not be resent.')), ACK_TIMEOUT_MS);
|
|
84
|
+
this.delivery = { runId, text, resolve, reject };
|
|
85
|
+
});
|
|
86
|
+
// Delivery can fail while the native process is still starting the turn. Observe it immediately.
|
|
87
|
+
void ack.catch(() => { });
|
|
88
|
+
try {
|
|
89
|
+
this.commands.push({ type: 'send', text });
|
|
90
|
+
await ack;
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
this.ready = false;
|
|
94
|
+
this.startupError = error instanceof Error ? error.message : String(error);
|
|
95
|
+
this.delivery = null;
|
|
96
|
+
this.commands.length = 0;
|
|
97
|
+
this.commands.push({ type: 'interrupt' });
|
|
98
|
+
this.finish('failed', this.startupError);
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** What the person typed into the terminal, so an instruction is never sent over their draft. */
|
|
106
|
+
onInput(data) {
|
|
107
|
+
if (!this.ready || this.activeRun || data === '\u0003')
|
|
108
|
+
return;
|
|
109
|
+
if (data.includes('\n') || data.includes('\r'))
|
|
110
|
+
this.multilineDraft = true;
|
|
111
|
+
this.dirty = data !== '\u0015' || this.multilineDraft;
|
|
112
|
+
}
|
|
113
|
+
/** The native process hung up while it was waiting for a decision. */
|
|
114
|
+
disconnected() {
|
|
115
|
+
if (this.disposed)
|
|
116
|
+
return;
|
|
117
|
+
this.ready = false;
|
|
118
|
+
this.commands.push({ type: 'interrupt' });
|
|
119
|
+
this.finish('failed', 'The native decision callback disconnected. Inspect the terminal before continuing.');
|
|
120
|
+
}
|
|
121
|
+
/** Project registry-owned questions, including grouped requests, into the terminal inbox. */
|
|
122
|
+
observe(event, descendant = false) {
|
|
123
|
+
if (this.disposed || !this.activeRun || (!descendant && event.runId !== this.activeRun.runId))
|
|
124
|
+
return;
|
|
125
|
+
if (event.type === 'question.requested') {
|
|
126
|
+
const payload = event.payload;
|
|
127
|
+
this.pending.set(String(payload.questionId), { ...payload, type: 'question', requestId: payload.questionId, runId: event.runId });
|
|
128
|
+
}
|
|
129
|
+
else if (descendant && event.type === 'approval.requested') {
|
|
130
|
+
const payload = event.payload;
|
|
131
|
+
if (!payload.automatic)
|
|
132
|
+
this.pending.set(String(payload.approvalId), { ...payload, type: 'approval', requestId: payload.approvalId, runId: event.runId });
|
|
133
|
+
}
|
|
134
|
+
else if (event.type === 'approval.resolved') {
|
|
135
|
+
this.pending.delete(String(event.payload.approvalId));
|
|
136
|
+
}
|
|
137
|
+
else if (event.type === 'question.answered') {
|
|
138
|
+
this.pending.delete(String(event.payload.questionId));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** The socket grants this interface only to the process that owns terminal input. */
|
|
142
|
+
async control(call, data) {
|
|
143
|
+
if (this.disposed)
|
|
144
|
+
throw new HarnessError('terminal_not_ready', 'This terminal has ended.');
|
|
145
|
+
if (call === 'terminal.draft') {
|
|
146
|
+
this.dirty = data.dirty === true;
|
|
147
|
+
this.multilineDraft = false;
|
|
148
|
+
return {};
|
|
149
|
+
}
|
|
150
|
+
if (call === 'terminal.pending')
|
|
151
|
+
return { requests: [...this.pending.values()] };
|
|
152
|
+
if (call === 'terminal.interrupt')
|
|
153
|
+
return this.activeRun && this.hooks.interrupt ? this.hooks.interrupt(this.activeRun.runId) : {};
|
|
154
|
+
if (call === 'terminal.policy') {
|
|
155
|
+
const run = this.activeRun;
|
|
156
|
+
if (!run || typeof data.tool !== 'string' || !data.tool)
|
|
157
|
+
throw new HarnessError('invalid_request', 'An active run and tool name are required.');
|
|
158
|
+
return this.hooks.policy(run, data.tool, data.args ?? {});
|
|
159
|
+
}
|
|
160
|
+
if (call === 'terminal.approval')
|
|
161
|
+
return this.requestNativeApproval(data);
|
|
162
|
+
if (call === 'terminal.answers' && this.hooks.answerQuestions) {
|
|
163
|
+
const run = this.activeRun;
|
|
164
|
+
const batchId = String(data.batchId ?? '');
|
|
165
|
+
const requests = [...this.pending.values()].filter(request => request.batchId === batchId);
|
|
166
|
+
if (!run || !batchId || !requests.length || !Array.isArray(data.answers))
|
|
167
|
+
throw new HarnessError('invalid_request', 'This question batch is no longer pending.');
|
|
168
|
+
this.hooks.answerQuestions(String(requests[0].runId ?? run.runId), batchId, data.answers);
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
const requestId = String(data.requestId ?? '');
|
|
172
|
+
const request = this.pending.get(requestId);
|
|
173
|
+
const run = this.activeRun;
|
|
174
|
+
if (!request || !run)
|
|
175
|
+
throw new HarnessError('invalid_request', 'This terminal decision is no longer pending.');
|
|
176
|
+
if (call === 'terminal.approve' && request.type === 'approval' && this.hooks.resolveApproval) {
|
|
177
|
+
if (data.decision !== 'approved' && data.decision !== 'denied')
|
|
178
|
+
throw new HarnessError('invalid_request', 'Choose approve or deny.');
|
|
179
|
+
const alwaysAllow = data.alwaysAllow === true;
|
|
180
|
+
if (alwaysAllow && request.rememberable !== true)
|
|
181
|
+
throw new HarnessError('invalid_request', 'This approval cannot be remembered for other sessions.');
|
|
182
|
+
let decision = data.decision;
|
|
183
|
+
if (decision === 'approved' && request.direct === true) {
|
|
184
|
+
const operation = request.operation;
|
|
185
|
+
const tool = typeof operation?.tool === 'string' ? operation.tool : '';
|
|
186
|
+
const current = await this.hooks.policy(run, tool, operation?.args ?? {});
|
|
187
|
+
if (!current.allowed && !current.requiresApproval)
|
|
188
|
+
decision = 'denied';
|
|
189
|
+
if (alwaysAllow && current.rememberable !== true) {
|
|
190
|
+
request.rememberable = false;
|
|
191
|
+
throw new HarnessError('invalid_request', 'This tool can no longer be allowed across sessions. Review the approval again.');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (decision === 'approved' && alwaysAllow)
|
|
195
|
+
this.hooks.allowToolGlobally(String(request.target ?? ''));
|
|
196
|
+
this.hooks.resolveApproval(String(request.runId ?? run.runId), requestId, decision);
|
|
197
|
+
return {};
|
|
198
|
+
}
|
|
199
|
+
if (call === 'terminal.answer' && request.type === 'question' && this.hooks.answerQuestion) {
|
|
200
|
+
if (!data.answer || !Array.isArray(data.answer.selected))
|
|
201
|
+
throw new HarnessError('invalid_request', 'A question answer is required.');
|
|
202
|
+
this.hooks.answerQuestion(String(request.runId ?? run.runId), requestId, data.answer);
|
|
203
|
+
return {};
|
|
204
|
+
}
|
|
205
|
+
throw new HarnessError('unknown_method', `Unknown terminal control ${call}.`);
|
|
206
|
+
}
|
|
207
|
+
async requestNativeApproval(data) {
|
|
208
|
+
const run = this.activeRun;
|
|
209
|
+
const requestId = typeof data.requestId === 'string' ? data.requestId : '';
|
|
210
|
+
const tool = typeof data.tool === 'string' ? data.tool : '';
|
|
211
|
+
if (!run || !requestId || !tool)
|
|
212
|
+
throw new HarnessError('invalid_request', 'An active run, request id, and tool name are required.');
|
|
213
|
+
const args = data.args && typeof data.args === 'object' && !Array.isArray(data.args) ? data.args : {};
|
|
214
|
+
const policy = await this.hooks.policy(run, tool, args);
|
|
215
|
+
if (!policy.allowed && !policy.requiresApproval)
|
|
216
|
+
return { decision: 'denied' };
|
|
217
|
+
if (policy.allowed && !policy.requiresApproval)
|
|
218
|
+
return { decision: 'approved' };
|
|
219
|
+
const key = this.requestId(`approval:${requestId}`);
|
|
220
|
+
const existing = this.seen.get(key);
|
|
221
|
+
if (existing)
|
|
222
|
+
return { decision: await existing };
|
|
223
|
+
const action = JSON.stringify(args);
|
|
224
|
+
const operation = { tool, args };
|
|
225
|
+
const response = run.requestApproval({
|
|
226
|
+
requestId: key,
|
|
227
|
+
target: tool,
|
|
228
|
+
action,
|
|
229
|
+
operation,
|
|
230
|
+
rememberable: policy.rememberable === true,
|
|
231
|
+
standing: policy.standing
|
|
232
|
+
});
|
|
233
|
+
this.pending.set(key, {
|
|
234
|
+
type: 'approval', requestId: key, runId: run.runId, target: tool, action,
|
|
235
|
+
operation, rememberable: policy.rememberable === true, direct: true
|
|
236
|
+
});
|
|
237
|
+
this.seen.set(key, response);
|
|
238
|
+
try {
|
|
239
|
+
return { decision: await response };
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
this.pending.delete(key);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async accept(event, data) {
|
|
246
|
+
if (this.disposed)
|
|
247
|
+
throw new Error('This terminal controller was disposed.');
|
|
248
|
+
if (event !== 'poll')
|
|
249
|
+
this.hooks.telemetry(event);
|
|
250
|
+
if (event === 'startup') {
|
|
251
|
+
this.startupPhase = String(data.phase);
|
|
252
|
+
return {};
|
|
253
|
+
}
|
|
254
|
+
if (event === 'startupFailed') {
|
|
255
|
+
this.startupError = String(data.reason ?? 'The native extension could not initialize.');
|
|
256
|
+
this.ready = false;
|
|
257
|
+
this.finish('failed', this.startupError);
|
|
258
|
+
return {};
|
|
259
|
+
}
|
|
260
|
+
if (event === 'poll')
|
|
261
|
+
return { command: this.commands.shift() ?? null };
|
|
262
|
+
if (event === 'ready') {
|
|
263
|
+
if (!this.ready) {
|
|
264
|
+
this.dirty = false;
|
|
265
|
+
this.multilineDraft = false;
|
|
266
|
+
}
|
|
267
|
+
this.ready = true;
|
|
268
|
+
if (typeof data.nativeSessionId === 'string' && data.nativeSessionId) {
|
|
269
|
+
this.nativeId = data.nativeSessionId;
|
|
270
|
+
this.hooks.native(data.nativeSessionId);
|
|
271
|
+
}
|
|
272
|
+
return {};
|
|
273
|
+
}
|
|
274
|
+
if (event === 'begin') {
|
|
275
|
+
const run = this.begin(String(data.turnId ?? randomUUID()), String(data.text ?? ''));
|
|
276
|
+
return { runId: run.runId };
|
|
277
|
+
}
|
|
278
|
+
if (event === 'shutdown') {
|
|
279
|
+
this.ready = false;
|
|
280
|
+
this.finish('interrupted');
|
|
281
|
+
return {};
|
|
282
|
+
}
|
|
283
|
+
if (event === 'settled') {
|
|
284
|
+
this.finish(data.aborted ? 'interrupted' : data.error ? 'failed' : 'completed', data.error ? String(data.error) : undefined);
|
|
285
|
+
return {};
|
|
286
|
+
}
|
|
287
|
+
const run = this.run;
|
|
288
|
+
if (!run)
|
|
289
|
+
throw new Error('Native telemetry arrived without an active turn.');
|
|
290
|
+
if (event === 'policy')
|
|
291
|
+
return this.hooks.policy(run, String(data.tool), data.args ?? {});
|
|
292
|
+
if (event === 'questions') {
|
|
293
|
+
if (!Array.isArray(data.questions) || !data.questions.length || data.questions.length > 5)
|
|
294
|
+
throw new HarnessError('invalid_request', 'Ask between one and five questions.');
|
|
295
|
+
const questions = data.questions.map(question => ({ ...question, requestId: randomUUID() }));
|
|
296
|
+
return run.requestAnswers(questions);
|
|
297
|
+
}
|
|
298
|
+
if (event === 'approval' || event === 'question') {
|
|
299
|
+
const key = this.requestId(`${event}:${String(data.requestId ?? JSON.stringify(data))}`);
|
|
300
|
+
const existing = this.seen.get(key);
|
|
301
|
+
if (existing)
|
|
302
|
+
return event === 'approval' ? { decision: await existing } : existing;
|
|
303
|
+
if (event === 'question') {
|
|
304
|
+
const response = run.requestAnswer({ requestId: key, question: String(data.question ?? ''), options: data.options ?? [], multiSelect: !!data.multiSelect, allowText: true });
|
|
305
|
+
this.pending.set(key, { type: 'question', requestId: key, question: String(data.question ?? ''), options: data.options ?? [], multiSelect: !!data.multiSelect });
|
|
306
|
+
this.seen.set(key, response);
|
|
307
|
+
return response.finally(() => this.pending.delete(key));
|
|
308
|
+
}
|
|
309
|
+
const response = run.requestApproval({
|
|
310
|
+
requestId: key,
|
|
311
|
+
target: String(data.target ?? 'Native action'),
|
|
312
|
+
action: String(data.action ?? '{}'),
|
|
313
|
+
operation: { tool: String(data.tool ?? data.target), args: data.args ?? {} },
|
|
314
|
+
rememberable: false
|
|
315
|
+
});
|
|
316
|
+
this.pending.set(key, { type: 'approval', requestId: key, target: String(data.target ?? 'Action'), action: String(data.action ?? '{}') });
|
|
317
|
+
this.seen.set(key, response);
|
|
318
|
+
try {
|
|
319
|
+
return { decision: await response };
|
|
320
|
+
}
|
|
321
|
+
finally {
|
|
322
|
+
this.pending.delete(key);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (event === 'usage')
|
|
326
|
+
run.emit('usage.updated', data);
|
|
327
|
+
else if (event === 'file')
|
|
328
|
+
run.emit('file.changed', data);
|
|
329
|
+
else if (event === 'message')
|
|
330
|
+
run.emit('message.completed', { messageId: data.id ?? randomUUID(), role: data.role ?? 'assistant', text: String(data.text) });
|
|
331
|
+
else if (event === 'tool') {
|
|
332
|
+
run.emit(data.phase === 'start' ? 'tool.started' : 'tool.completed', {
|
|
333
|
+
toolCallId: String(data.id),
|
|
334
|
+
name: String(data.name),
|
|
335
|
+
...(data.phase === 'start'
|
|
336
|
+
? { summary: String(data.summary ?? ''), ...(typeof data.input === 'string' ? { input: data.input.slice(0, 24_000) } : {}) }
|
|
337
|
+
: { ok: data.ok !== false, ...(typeof data.durationMs === 'number' ? { durationMs: data.durationMs } : {}), ...(typeof data.resultChars === 'number' ? { resultChars: data.resultChars } : {}), ...(typeof data.output === 'string' ? { output: data.output.slice(0, 24_000) } : {}), ...(data.outputTruncated === true ? { outputTruncated: true } : {}) })
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
return {};
|
|
341
|
+
}
|
|
342
|
+
dispose() {
|
|
343
|
+
if (this.disposed)
|
|
344
|
+
return;
|
|
345
|
+
this.disposed = true;
|
|
346
|
+
this.ready = false;
|
|
347
|
+
this.delivery?.reject(new Error('The terminal stopped before prompt acknowledgement.'));
|
|
348
|
+
this.delivery = null;
|
|
349
|
+
this.finish('interrupted');
|
|
350
|
+
}
|
|
351
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { HubOverview } from "../hub/schema.js";
|
|
2
|
+
import type { MenuCall, MenuUi } from "./pluginMenu.js";
|
|
3
|
+
type HubEntry = HubOverview['entries'][number];
|
|
4
|
+
/** What the person is told before installing: the entry, who published it, and what installing does. */
|
|
5
|
+
export declare function hubSummary(entry: HubEntry): string;
|
|
6
|
+
/** Asks, then installs exactly this version. A refusal or a failure is reported and changes nothing. */
|
|
7
|
+
export declare function installHubEntry(ui: MenuUi, call: MenuCall, entry: HubEntry): Promise<void>;
|
|
8
|
+
/** The terminal's catalog uses the same exact-version installer as embedding applications. */
|
|
9
|
+
export declare function runHubMenu(ui: MenuUi, call: MenuCall): Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** What the person is told before installing: the entry, who published it, and what installing does. */
|
|
2
|
+
export function hubSummary(entry) {
|
|
3
|
+
return `${entry.description}\n\nPublisher: ${entry.publisher}\nLicense: ${entry.license}\nSource: ${entry.sourceUrl}\n\n${entry.delivery.kind === 'document' ? 'Saved as data for a compatible application. Nothing is created or enabled.' : 'Installed switched off. Code remains untrusted and approvals remain unchanged.'}`;
|
|
4
|
+
}
|
|
5
|
+
/** Asks, then installs exactly this version. A refusal or a failure is reported and changes nothing. */
|
|
6
|
+
export async function installHubEntry(ui, call, entry) {
|
|
7
|
+
if (!await ui.confirm(`Install ${entry.title} ${entry.version}?`, hubSummary(entry)))
|
|
8
|
+
return;
|
|
9
|
+
try {
|
|
10
|
+
const receipt = await call('hub.install', { id: entry.id, version: entry.version });
|
|
11
|
+
ui.notify(receipt.document ? 'Saved in this library for a compatible application.' : 'Installed, switched off. Use /plugins to review and attach it. Changes apply after restarting the session.', 'info');
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
ui.notify(error instanceof Error ? error.message : String(error), 'error');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** The terminal's catalog uses the same exact-version installer as embedding applications. */
|
|
18
|
+
export async function runHubMenu(ui, call) {
|
|
19
|
+
for (;;) {
|
|
20
|
+
const catalog = await call('hub.list');
|
|
21
|
+
const labels = catalog.entries.map((entry) => `${entry.title} · ${entry.category} · ${entry.id}@${entry.version}`);
|
|
22
|
+
const picked = await ui.select('Hub', [...labels, 'Refresh catalog', 'Done']);
|
|
23
|
+
if (picked === 'Refresh catalog') {
|
|
24
|
+
const refreshed = await call('hub.list', { refresh: true });
|
|
25
|
+
if (refreshed.error)
|
|
26
|
+
ui.notify(`${refreshed.error} Using ${refreshed.origin} content.`, 'warning');
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const entry = catalog.entries[labels.indexOf(picked ?? '')];
|
|
30
|
+
if (!entry)
|
|
31
|
+
return;
|
|
32
|
+
await installHubEntry(ui, call, entry);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function bashPath(path) {
|
|
2
|
+
const drive = /^([a-z]):[\\/](.*)$/i.exec(path);
|
|
3
|
+
if (drive)
|
|
4
|
+
return `/${drive[1].toLowerCase()}/${drive[2].replaceAll('\\', '/')}`;
|
|
5
|
+
if (path.startsWith('\\\\'))
|
|
6
|
+
return `//${path.slice(2).replaceAll('\\', '/')}`;
|
|
7
|
+
return path;
|
|
8
|
+
}
|
|
9
|
+
function shellQuote(value) {
|
|
10
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
11
|
+
}
|
|
12
|
+
/** Files Pi's Git Bash shell and native Windows shells use to call Harness subcommands. */
|
|
13
|
+
export function terminalCommandFiles(platform, node, cli, name, mode) {
|
|
14
|
+
const shellNode = platform === 'win32' ? bashPath(node) : node;
|
|
15
|
+
const shellCli = platform === 'win32' ? bashPath(cli) : cli;
|
|
16
|
+
const files = [{
|
|
17
|
+
name,
|
|
18
|
+
content: `#!/bin/sh\nexec ${shellQuote(shellNode)} ${shellQuote(shellCli)} ${mode} "$@"\n`
|
|
19
|
+
}];
|
|
20
|
+
if (platform === 'win32') {
|
|
21
|
+
files.push({
|
|
22
|
+
name: `${name}.cmd`,
|
|
23
|
+
content: `@echo off\r\n"%XINGULAR_HARNESS_NODE%" "%XINGULAR_HARNESS_CLI%" ${mode} %*\r\nexit /b %ERRORLEVEL%\r\n`
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return files;
|
|
27
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const LOG_READ_CHUNK_BYTES: number;
|
|
2
|
+
export interface HarnessLogInfo {
|
|
3
|
+
size: number | null;
|
|
4
|
+
}
|
|
5
|
+
export interface HarnessLogChunk {
|
|
6
|
+
data: string;
|
|
7
|
+
nextOffset: number;
|
|
8
|
+
}
|
|
9
|
+
/** Captures the byte length of the host-owned diagnostics file; callers never supply a path. */
|
|
10
|
+
export declare function harnessLogInfo(stateDir: string): HarnessLogInfo;
|
|
11
|
+
/** Reads one bounded range from the file size captured by `harnessLogInfo`. */
|
|
12
|
+
export declare function readHarnessLogChunk(stateDir: string, snapshotSize: number, offset: number): HarnessLogChunk;
|
|
13
|
+
/** Collects a fixed-size snapshot while keeping each socket reply bounded. */
|
|
14
|
+
export declare function readHarnessLogSnapshot(info: () => Promise<HarnessLogInfo>, chunk: (snapshotSize: number, offset: number) => Promise<HarnessLogChunk>): Promise<string>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { closeSync, openSync, readSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
export const LOG_READ_CHUNK_BYTES = 32 * 1024;
|
|
4
|
+
/** Captures the byte length of the host-owned diagnostics file; callers never supply a path. */
|
|
5
|
+
export function harnessLogInfo(stateDir) {
|
|
6
|
+
try {
|
|
7
|
+
const stat = statSync(join(stateDir, 'harness.log'));
|
|
8
|
+
if (!stat.isFile())
|
|
9
|
+
throw new Error('The Harness diagnostics path is not a regular file.');
|
|
10
|
+
return { size: stat.size };
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error.code === 'ENOENT')
|
|
14
|
+
return { size: null };
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Reads one bounded range from the file size captured by `harnessLogInfo`. */
|
|
19
|
+
export function readHarnessLogChunk(stateDir, snapshotSize, offset) {
|
|
20
|
+
if (!Number.isSafeInteger(snapshotSize) || snapshotSize < 0 || !Number.isSafeInteger(offset) || offset < 0 || offset >= snapshotSize) {
|
|
21
|
+
throw new Error('The Harness diagnostics snapshot range is invalid.');
|
|
22
|
+
}
|
|
23
|
+
const path = join(stateDir, 'harness.log');
|
|
24
|
+
const current = statSync(path);
|
|
25
|
+
if (!current.isFile() || current.size < snapshotSize)
|
|
26
|
+
throw new Error('The Harness diagnostics file changed while it was being read.');
|
|
27
|
+
const length = Math.min(LOG_READ_CHUNK_BYTES, snapshotSize - offset);
|
|
28
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
29
|
+
const descriptor = openSync(path, 'r');
|
|
30
|
+
try {
|
|
31
|
+
const bytesRead = readSync(descriptor, buffer, 0, length, offset);
|
|
32
|
+
if (bytesRead !== length)
|
|
33
|
+
throw new Error('The Harness diagnostics file changed while it was being read.');
|
|
34
|
+
return { data: buffer.toString('base64'), nextOffset: offset + bytesRead };
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
closeSync(descriptor);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Collects a fixed-size snapshot while keeping each socket reply bounded. */
|
|
41
|
+
export async function readHarnessLogSnapshot(info, chunk) {
|
|
42
|
+
const { size } = await info();
|
|
43
|
+
if (size === null || size === 0)
|
|
44
|
+
return '';
|
|
45
|
+
if (!Number.isSafeInteger(size) || size < 0)
|
|
46
|
+
throw new Error('The Harness returned an invalid diagnostics file size.');
|
|
47
|
+
const buffers = [];
|
|
48
|
+
let offset = 0;
|
|
49
|
+
while (offset < size) {
|
|
50
|
+
const page = await chunk(size, offset);
|
|
51
|
+
const buffer = Buffer.from(page.data, 'base64');
|
|
52
|
+
if (!buffer.length || page.nextOffset !== offset + buffer.length || page.nextOffset > size) {
|
|
53
|
+
throw new Error('The Harness returned an invalid diagnostics file page.');
|
|
54
|
+
}
|
|
55
|
+
buffers.push(buffer);
|
|
56
|
+
offset = page.nextOffset;
|
|
57
|
+
}
|
|
58
|
+
return Buffer.concat(buffers).toString('utf8');
|
|
59
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AgentSession, ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
export interface TerminalPlanRunState {
|
|
3
|
+
active: boolean;
|
|
4
|
+
allowedTools: ReadonlySet<string>;
|
|
5
|
+
}
|
|
6
|
+
export default function (pi: ExtensionAPI, planRun?: TerminalPlanRunState, getSession?: () => AgentSession): Promise<void>;
|