@xingular/harness 0.1.6 → 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 +107 -0
- package/LICENSE +202 -0
- package/NOTICE.md +60 -0
- package/README.md +265 -71
- package/THIRD_PARTY_LICENSES.md +942 -0
- package/dist/cli.js +14842 -9445
- 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 +1170 -62
- package/docs/README.md +34 -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-0001-owned-terminal.md +87 -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 +671 -0
- package/package.json +48 -12
- package/src/accounts/accounts.test.ts +0 -223
- package/src/accounts/accounts.ts +0 -522
- 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 -114
- 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 -299
- package/src/index.ts +0 -70
- 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 -289
- package/src/memory/blocks.test.ts +0 -78
- package/src/memory/blocks.ts +0 -406
- package/src/memory/caller.ts +0 -57
- 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 -330
- package/src/memory/migrate.ts +0 -79
- package/src/memory/operations.ts +0 -138
- package/src/memory/proposals.test.ts +0 -168
- package/src/memory/proposals.ts +0 -576
- package/src/memory/recall.test.ts +0 -104
- package/src/memory/recall.ts +0 -271
- 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 -314
- 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 -310
- package/src/sessions/conversation.test.ts +0 -150
- 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 -32
- package/src/sessions/pricing.ts +0 -60
- package/src/sessions/reasoningSummaries.ts +0 -59
- package/src/sessions/registry.ts +0 -294
- 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 -569
- package/src/sessions/runtimeResources.test.ts +0 -61
- package/src/sessions/sessions.test.ts +0 -455
- package/src/sessions/sessions.ts +0 -295
- package/src/skills/registry.test.ts +0 -104
- package/src/skills/registry.ts +0 -407
- package/src/terminal/cli.ts +0 -149
- package/src/terminal/client.ts +0 -74
- package/src/terminal/controller.ts +0 -227
- package/src/terminal/launch.test.ts +0 -34
- package/src/terminal/launch.ts +0 -88
- package/src/terminal/piExtension.ts +0 -210
- 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 -221
- package/src/terminal/standalone.test.ts +0 -130
- package/src/terminal/standalone.ts +0 -144
- package/src/terminal/terminal.test.ts +0 -330
- package/src/terminal/terminals.ts +0 -443
- package/src/tools/askUser.ts +0 -45
- package/src/tools/definitions.ts +0 -187
- package/src/tools/memoryTools.ts +0 -22
- package/src/tools/pluginPropose.ts +0 -41
- 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
|
@@ -1,227 +0,0 @@
|
|
|
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
|
-
|
|
7
|
-
import { HarnessError } from '../core/errors'
|
|
8
|
-
import type { ActiveRun, ApprovalDecision, QuestionAnswer } from '../sessions/registry'
|
|
9
|
-
|
|
10
|
-
export interface PolicyReply {
|
|
11
|
-
allowed: boolean
|
|
12
|
-
reason?: string | null
|
|
13
|
-
requiresApproval?: boolean
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface ControllerHooks {
|
|
17
|
-
sessionId: string
|
|
18
|
-
nativeSessionId: string | null
|
|
19
|
-
/** Reserves or creates the run for a native turn and starts tracking it. */
|
|
20
|
-
begin(input: { reservedRunId: string | null; nativeTurnId: string; text: string }): ActiveRun
|
|
21
|
-
/** Whether a native tool call may run. */
|
|
22
|
-
policy(run: ActiveRun, tool: string, args: unknown): Promise<PolicyReply>
|
|
23
|
-
/** The native conversation identity changed. */
|
|
24
|
-
native(nativeSessionId: string): void
|
|
25
|
-
telemetry(event: string): void
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
interface Delivery {
|
|
29
|
-
runId: string
|
|
30
|
-
text: string
|
|
31
|
-
resolve: () => void
|
|
32
|
-
reject: (error: Error) => void
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
type Command = { type: 'interrupt' } | { type: 'send'; text: string }
|
|
36
|
-
|
|
37
|
-
const READY_TIMEOUT_MS = 90_000
|
|
38
|
-
const ACK_TIMEOUT_MS = 25_000
|
|
39
|
-
|
|
40
|
-
export class TerminalController {
|
|
41
|
-
private run: ActiveRun | null = null
|
|
42
|
-
private ready = false
|
|
43
|
-
private disposed = false
|
|
44
|
-
private dirty = false
|
|
45
|
-
private multilineDraft = false
|
|
46
|
-
private startupError: string | null = null
|
|
47
|
-
private startupPhase = 'Waiting for the native extension'
|
|
48
|
-
private delivery: Delivery | null = null
|
|
49
|
-
private nativeId: string | null
|
|
50
|
-
private readonly seen = new Map<string, Promise<unknown>>()
|
|
51
|
-
private readonly commands: Command[] = []
|
|
52
|
-
|
|
53
|
-
constructor(private readonly hooks: ControllerHooks) {
|
|
54
|
-
this.nativeId = hooks.nativeSessionId
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
get nativeSessionId(): string | null {
|
|
58
|
-
return this.nativeId
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
get activeRun(): ActiveRun | null {
|
|
62
|
-
return this.run && !this.run.finished ? this.run : null
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
state(): { ready: boolean; dirty: boolean; active: boolean } {
|
|
66
|
-
return { ready: this.ready, dirty: this.dirty, active: !!this.activeRun || !!this.delivery }
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
private requestId(nativeId: string): string {
|
|
70
|
-
return createHash('sha256').update(`${this.hooks.sessionId}:${this.run?.runId}:${nativeId}`).digest('hex')
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
private begin(nativeTurnId: string, text: string): ActiveRun {
|
|
74
|
-
if (this.startupError) throw new Error(this.startupError)
|
|
75
|
-
this.dirty = false
|
|
76
|
-
this.multilineDraft = false
|
|
77
|
-
if (this.run && !this.run.finished) return this.run
|
|
78
|
-
const delivery = this.delivery
|
|
79
|
-
if (delivery && text && delivery.text !== text) throw new Error('The native prompt did not match the reserved delivery. Inspect the terminal before continuing.')
|
|
80
|
-
const run = this.hooks.begin({ reservedRunId: delivery?.runId ?? null, nativeTurnId, text })
|
|
81
|
-
this.run = run
|
|
82
|
-
run.onInterrupt(() => void this.commands.push({ type: 'interrupt' }))
|
|
83
|
-
if (text) run.emit('message.completed', { messageId: nativeTurnId, role: 'user', text })
|
|
84
|
-
delivery?.resolve()
|
|
85
|
-
this.delivery = null
|
|
86
|
-
return run
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
private finish(outcome: 'completed' | 'failed' | 'interrupted', message?: string): void {
|
|
90
|
-
this.run?.finish(outcome, message ? { code: 'terminal_attention', message } : undefined)
|
|
91
|
-
this.run = null
|
|
92
|
-
this.seen.clear()
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** Hands the native process an instruction and waits until it acknowledges the prompt. */
|
|
96
|
-
async send(runId: string, text: string): Promise<void> {
|
|
97
|
-
if (this.disposed) throw new HarnessError('terminal_not_ready', 'Reopen the terminal before sending instructions.')
|
|
98
|
-
if (this.activeRun || this.delivery) throw new HarnessError('session_busy', 'This terminal has an active task or delivery.')
|
|
99
|
-
const deadline = Date.now() + READY_TIMEOUT_MS
|
|
100
|
-
while (!this.ready && !this.startupError && !this.disposed && Date.now() < deadline) await new Promise((resolve) => setTimeout(resolve, 50))
|
|
101
|
-
if (this.disposed) throw new HarnessError('terminal_not_ready', 'The terminal stopped during initialization.')
|
|
102
|
-
if (this.startupError) throw new HarnessError('terminal_not_ready', this.startupError)
|
|
103
|
-
if (!this.ready) throw new HarnessError('terminal_not_ready', `The native telemetry handshake is missing (${this.startupPhase}). Inspect the terminal sign-in or trust screen.`)
|
|
104
|
-
if (this.dirty) throw new HarnessError('terminal_has_draft', 'The terminal contains user input. Submit or clear it before handing back control.')
|
|
105
|
-
let timer: ReturnType<typeof setTimeout>
|
|
106
|
-
const ack = new Promise<void>((resolve, reject) => {
|
|
107
|
-
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)
|
|
108
|
-
this.delivery = { runId, text, resolve, reject }
|
|
109
|
-
})
|
|
110
|
-
// Delivery can fail while the native process is still starting the turn. Observe it immediately.
|
|
111
|
-
void ack.catch(() => {})
|
|
112
|
-
try {
|
|
113
|
-
this.commands.push({ type: 'send', text })
|
|
114
|
-
await ack
|
|
115
|
-
} catch (error) {
|
|
116
|
-
this.ready = false
|
|
117
|
-
this.startupError = error instanceof Error ? error.message : String(error)
|
|
118
|
-
this.delivery = null
|
|
119
|
-
this.commands.length = 0
|
|
120
|
-
this.commands.push({ type: 'interrupt' })
|
|
121
|
-
this.finish('failed', this.startupError)
|
|
122
|
-
throw error
|
|
123
|
-
} finally {
|
|
124
|
-
clearTimeout(timer!)
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** What the person typed into the terminal, so an instruction is never sent over their draft. */
|
|
129
|
-
onInput(data: string): void {
|
|
130
|
-
if (!this.ready || this.activeRun || data === '\u0003') return
|
|
131
|
-
if (data.includes('\n') || data.includes('\r')) this.multilineDraft = true
|
|
132
|
-
this.dirty = data !== '\u0015' || this.multilineDraft
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/** The native process hung up while it was waiting for a decision. */
|
|
136
|
-
disconnected(): void {
|
|
137
|
-
if (this.disposed) return
|
|
138
|
-
this.ready = false
|
|
139
|
-
this.commands.push({ type: 'interrupt' })
|
|
140
|
-
this.finish('failed', 'The native decision callback disconnected. Inspect the terminal before continuing.')
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
async accept(event: string, data: Record<string, any>): Promise<unknown> {
|
|
144
|
-
if (this.disposed) throw new Error('This terminal controller was disposed.')
|
|
145
|
-
if (event !== 'poll') this.hooks.telemetry(event)
|
|
146
|
-
if (event === 'startup') {
|
|
147
|
-
this.startupPhase = String(data.phase)
|
|
148
|
-
return {}
|
|
149
|
-
}
|
|
150
|
-
if (event === 'startupFailed') {
|
|
151
|
-
this.startupError = String(data.reason ?? 'The native extension could not initialize.')
|
|
152
|
-
this.ready = false
|
|
153
|
-
this.finish('failed', this.startupError)
|
|
154
|
-
return {}
|
|
155
|
-
}
|
|
156
|
-
if (event === 'poll') return { command: this.commands.shift() ?? null }
|
|
157
|
-
if (event === 'ready') {
|
|
158
|
-
if (!this.ready) {
|
|
159
|
-
this.dirty = false
|
|
160
|
-
this.multilineDraft = false
|
|
161
|
-
}
|
|
162
|
-
this.ready = true
|
|
163
|
-
if (typeof data.nativeSessionId === 'string' && data.nativeSessionId) {
|
|
164
|
-
this.nativeId = data.nativeSessionId
|
|
165
|
-
this.hooks.native(data.nativeSessionId)
|
|
166
|
-
}
|
|
167
|
-
return {}
|
|
168
|
-
}
|
|
169
|
-
if (event === 'begin') {
|
|
170
|
-
this.begin(String(data.turnId ?? randomUUID()), String(data.text ?? ''))
|
|
171
|
-
return {}
|
|
172
|
-
}
|
|
173
|
-
if (event === 'shutdown') {
|
|
174
|
-
this.ready = false
|
|
175
|
-
this.finish('interrupted')
|
|
176
|
-
return {}
|
|
177
|
-
}
|
|
178
|
-
if (event === 'settled') {
|
|
179
|
-
this.finish(data.error ? 'failed' : 'completed', data.error ? String(data.error) : undefined)
|
|
180
|
-
return {}
|
|
181
|
-
}
|
|
182
|
-
const run = this.run
|
|
183
|
-
if (!run) throw new Error('Native telemetry arrived without an active turn.')
|
|
184
|
-
if (event === 'policy') return this.hooks.policy(run, String(data.tool), data.args ?? {})
|
|
185
|
-
if (event === 'approval' || event === 'question') {
|
|
186
|
-
const key = this.requestId(String(data.requestId ?? JSON.stringify(data)))
|
|
187
|
-
const existing = this.seen.get(key)
|
|
188
|
-
if (existing) return event === 'approval' ? { decision: await existing } : existing
|
|
189
|
-
if (event === 'question') {
|
|
190
|
-
const response: Promise<QuestionAnswer> = run.requestAnswer({ requestId: key, question: String(data.question ?? ''), options: data.options ?? [], multiSelect: !!data.multiSelect, allowText: true })
|
|
191
|
-
this.seen.set(key, response)
|
|
192
|
-
return response
|
|
193
|
-
}
|
|
194
|
-
const response: Promise<ApprovalDecision> = run.requestApproval({
|
|
195
|
-
requestId: key,
|
|
196
|
-
target: String(data.target ?? 'Native action'),
|
|
197
|
-
action: String(data.action ?? '{}'),
|
|
198
|
-
operation: { tool: String(data.tool ?? data.target), args: data.args ?? {} },
|
|
199
|
-
rememberable: false
|
|
200
|
-
})
|
|
201
|
-
this.seen.set(key, response)
|
|
202
|
-
return { decision: await response }
|
|
203
|
-
}
|
|
204
|
-
if (event === 'usage') run.emit('usage.updated', data)
|
|
205
|
-
else if (event === 'file') run.emit('file.changed', data)
|
|
206
|
-
else if (event === 'message') run.emit('message.completed', { messageId: data.id ?? randomUUID(), role: data.role ?? 'assistant', text: String(data.text) })
|
|
207
|
-
else if (event === 'tool') {
|
|
208
|
-
run.emit(data.phase === 'start' ? 'tool.started' : 'tool.completed', {
|
|
209
|
-
toolCallId: String(data.id),
|
|
210
|
-
name: String(data.name),
|
|
211
|
-
...(data.phase === 'start'
|
|
212
|
-
? { summary: String(data.summary ?? '') }
|
|
213
|
-
: { ok: data.ok !== false, ...(typeof data.durationMs === 'number' ? { durationMs: data.durationMs } : {}), ...(typeof data.resultChars === 'number' ? { resultChars: data.resultChars } : {}) })
|
|
214
|
-
})
|
|
215
|
-
}
|
|
216
|
-
return {}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
dispose(): void {
|
|
220
|
-
if (this.disposed) return
|
|
221
|
-
this.disposed = true
|
|
222
|
-
this.ready = false
|
|
223
|
-
this.delivery?.reject(new Error('The terminal stopped before prompt acknowledgement.'))
|
|
224
|
-
this.delivery = null
|
|
225
|
-
this.finish('interrupted')
|
|
226
|
-
}
|
|
227
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from 'node:child_process'
|
|
2
|
-
import { describe, expect, it } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { bundledPiCli, resolvePiCommand, terminalCommandFiles } from './launch'
|
|
5
|
-
|
|
6
|
-
describe('terminal launch commands', () => {
|
|
7
|
-
it('runs the pinned Pi CLI with the active Node runtime on Windows', () => {
|
|
8
|
-
const launch = resolvePiCommand({ platform: 'win32', node: 'C:\\Program Files\\nodejs\\node.exe' })
|
|
9
|
-
|
|
10
|
-
expect(launch.program).toBe('C:\\Program Files\\nodejs\\node.exe')
|
|
11
|
-
expect(launch.argsPrefix[0]).toMatch(/[\\/]node_modules[\\/]@earendil-works[\\/]pi-coding-agent[\\/]dist[\\/]bundle[\\/]cli\.js$/)
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('runs the package CLI through Node for a no-model help smoke', () => {
|
|
15
|
-
const result = spawnSync(process.execPath, [bundledPiCli(), '--help'], { encoding: 'utf8', timeout: 20_000 })
|
|
16
|
-
|
|
17
|
-
expect(result.error).toBeUndefined()
|
|
18
|
-
expect(result.status).toBe(0)
|
|
19
|
-
expect(`${result.stdout}${result.stderr}`).toMatch(/usage|options|pi/i)
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
it('keeps an explicitly configured executable even on Windows', () => {
|
|
23
|
-
expect(resolvePiCommand({ platform: 'win32', node: 'node.exe', programOverride: () => 'C:\\Tools\\pi.exe' }))
|
|
24
|
-
.toEqual({ program: 'C:\\Tools\\pi.exe', argsPrefix: [] })
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('provides Git Bash and native Windows launchers for each Harness command', () => {
|
|
28
|
-
expect(terminalCommandFiles('win32', 'C:\\Program Files\\nodejs\\node.exe', 'C:\\Harness\\cli.js', 'xagent-wiki', 'wiki'))
|
|
29
|
-
.toEqual([
|
|
30
|
-
{ name: 'xagent-wiki', content: "#!/bin/sh\nexec '/c/Program Files/nodejs/node.exe' '/c/Harness/cli.js' wiki \"$@\"\n" },
|
|
31
|
-
{ name: 'xagent-wiki.cmd', content: '@echo off\r\n"%XINGULAR_HARNESS_NODE%" "%XINGULAR_HARNESS_CLI%" wiki %*\r\nexit /b %ERRORLEVEL%\r\n' }
|
|
32
|
-
])
|
|
33
|
-
})
|
|
34
|
-
})
|
package/src/terminal/launch.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { createRequire } from 'node:module'
|
|
3
|
-
import { join, resolve } from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { HarnessError } from '../core/errors'
|
|
6
|
-
import { findBinary } from '../core/path'
|
|
7
|
-
|
|
8
|
-
const PI_PACKAGE = '@earendil-works/pi-coding-agent'
|
|
9
|
-
|
|
10
|
-
export interface PiCommand {
|
|
11
|
-
program: string
|
|
12
|
-
argsPrefix: string[]
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** Resolve the Pi package's declared command instead of depending on its POSIX npm shim. */
|
|
16
|
-
export function bundledPiCli(): string {
|
|
17
|
-
const require = createRequire(import.meta.url)
|
|
18
|
-
for (const nodeModules of require.resolve.paths(PI_PACKAGE) ?? []) {
|
|
19
|
-
const directory = join(nodeModules, ...PI_PACKAGE.split('/'))
|
|
20
|
-
const manifestPath = join(directory, 'package.json')
|
|
21
|
-
if (!existsSync(manifestPath)) continue
|
|
22
|
-
try {
|
|
23
|
-
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as {
|
|
24
|
-
name?: unknown
|
|
25
|
-
bin?: unknown
|
|
26
|
-
}
|
|
27
|
-
if (manifest.name === PI_PACKAGE) {
|
|
28
|
-
const executable = typeof manifest.bin === 'string'
|
|
29
|
-
? manifest.bin
|
|
30
|
-
: manifest.bin && typeof manifest.bin === 'object' && typeof (manifest.bin as Record<string, unknown>).pi === 'string'
|
|
31
|
-
? (manifest.bin as Record<string, string>).pi
|
|
32
|
-
: null
|
|
33
|
-
if (!executable) throw new Error('the package does not declare its pi command')
|
|
34
|
-
const cli = resolve(directory, executable)
|
|
35
|
-
if (!existsSync(cli)) throw new Error(`the declared command does not exist at ${cli}`)
|
|
36
|
-
return cli
|
|
37
|
-
}
|
|
38
|
-
} catch {
|
|
39
|
-
continue
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
throw new HarnessError('harness_unavailable', `The bundled ${PI_PACKAGE} package does not expose a usable pi command. Reinstall the Harness package and try again.`)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function resolvePiCommand(options: {
|
|
47
|
-
platform: NodeJS.Platform
|
|
48
|
-
node: string
|
|
49
|
-
programOverride?: () => string | null
|
|
50
|
-
}): PiCommand {
|
|
51
|
-
if (options.programOverride) {
|
|
52
|
-
const program = options.programOverride()
|
|
53
|
-
if (!program) throw new HarnessError('harness_unavailable', 'The Pi CLI was not found on PATH.')
|
|
54
|
-
return { program, argsPrefix: [] }
|
|
55
|
-
}
|
|
56
|
-
if (options.platform === 'win32') return { program: options.node, argsPrefix: [bundledPiCli()] }
|
|
57
|
-
const program = findBinary('pi')
|
|
58
|
-
if (!program) throw new HarnessError('harness_unavailable', 'The Pi CLI was not found on PATH.')
|
|
59
|
-
return { program, argsPrefix: [] }
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function bashPath(path: string): string {
|
|
63
|
-
const drive = /^([a-z]):[\\/](.*)$/i.exec(path)
|
|
64
|
-
if (drive) return `/${drive[1].toLowerCase()}/${drive[2].replaceAll('\\', '/')}`
|
|
65
|
-
if (path.startsWith('\\\\')) return `//${path.slice(2).replaceAll('\\', '/')}`
|
|
66
|
-
return path
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function shellQuote(value: string): string {
|
|
70
|
-
return `'${value.replaceAll("'", "'\\''")}'`
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** Files Pi's Git Bash shell and native Windows shells use to call Harness subcommands. */
|
|
74
|
-
export function terminalCommandFiles(platform: NodeJS.Platform, node: string, cli: string, name: string, mode: string): Array<{ name: string; content: string }> {
|
|
75
|
-
const shellNode = platform === 'win32' ? bashPath(node) : node
|
|
76
|
-
const shellCli = platform === 'win32' ? bashPath(cli) : cli
|
|
77
|
-
const files = [{
|
|
78
|
-
name,
|
|
79
|
-
content: `#!/bin/sh\nexec ${shellQuote(shellNode)} ${shellQuote(shellCli)} ${mode} "$@"\n`
|
|
80
|
-
}]
|
|
81
|
-
if (platform === 'win32') {
|
|
82
|
-
files.push({
|
|
83
|
-
name: `${name}.cmd`,
|
|
84
|
-
content: `@echo off\r\n"%XINGULAR_HARNESS_NODE%" "%XINGULAR_HARNESS_CLI%" ${mode} %*\r\nexit /b %ERRORLEVEL%\r\n`
|
|
85
|
-
})
|
|
86
|
-
}
|
|
87
|
-
return files
|
|
88
|
-
}
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
// Loaded by the `pi` command in a terminal session (`--extension`). It reports what the native
|
|
2
|
-
// session does to the harness, asks before each tool call, takes instructions the harness
|
|
3
|
-
// queues for it, and gives the session the harness's own tools. It runs in the `pi` process,
|
|
4
|
-
// so everything it knows about the harness comes through the session socket.
|
|
5
|
-
import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent'
|
|
6
|
-
import { Type } from 'typebox'
|
|
7
|
-
|
|
8
|
-
import { connectionFromEnv, socketCall, terminalCall } from './client'
|
|
9
|
-
import { runPluginsMenu } from './pluginMenu'
|
|
10
|
-
|
|
11
|
-
interface SocketTool {
|
|
12
|
-
name: string
|
|
13
|
-
label: string
|
|
14
|
-
description: string
|
|
15
|
-
parameters: Record<string, unknown>
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** How much text a tool handed back to the model. */
|
|
19
|
-
function resultSize(result: unknown): number | null {
|
|
20
|
-
const content = (result as { content?: unknown } | null | undefined)?.content
|
|
21
|
-
if (!Array.isArray(content)) return typeof result === 'string' ? result.length : null
|
|
22
|
-
return content.reduce((total: number, part: { type?: string; text?: unknown }) => total + (part?.type === 'text' && typeof part.text === 'string' ? part.text.length : 0), 0)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default async function (pi: ExtensionAPI) {
|
|
26
|
-
await terminalCall('startup', { phase: 'Pi extension loaded' })
|
|
27
|
-
let context: ExtensionContext | null = null
|
|
28
|
-
let timer: ReturnType<typeof setInterval> | null = null
|
|
29
|
-
let polling = false
|
|
30
|
-
let failure: string | undefined
|
|
31
|
-
const emptyUsage = () => ({ inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, requests: 0, costUsd: 0 })
|
|
32
|
-
let usage = emptyUsage()
|
|
33
|
-
let reasoningTokens: number | undefined
|
|
34
|
-
let costReported = false
|
|
35
|
-
let requestStartedAt: number | null = null
|
|
36
|
-
const toolStartedAt = new Map<string, number>()
|
|
37
|
-
const fileTools = new Map<string, string>()
|
|
38
|
-
|
|
39
|
-
// The harness's own tools for this session (connected apps and what the application offers).
|
|
40
|
-
let stage = 'Tool discovery'
|
|
41
|
-
try {
|
|
42
|
-
await terminalCall('startup', { phase: stage })
|
|
43
|
-
const connection = connectionFromEnv()
|
|
44
|
-
// Claimed here, before the model has run anything, and kept in this process's memory: a
|
|
45
|
-
// command the model runs can read the session token from its environment, never this key.
|
|
46
|
-
const control = await socketCall<{ key: string }>(connection, 'control.claim', {}, 15_000).then((claimed) => claimed.key).catch(() => null)
|
|
47
|
-
pi.registerCommand('plugins', {
|
|
48
|
-
description: 'See what this session loads, and switch a plugin on or off or trust its code',
|
|
49
|
-
handler: async (_args, ctx) => {
|
|
50
|
-
if (!control) return ctx.ui.notify('This session cannot change plugins.', 'warning')
|
|
51
|
-
const { projectId } = await socketCall<{ projectId: string | null }>(connection, 'plugins.session', {}, 15_000, control).catch(() => ({ projectId: null }))
|
|
52
|
-
await runPluginsMenu(
|
|
53
|
-
{ select: (title, options) => ctx.ui.select(title, options), confirm: (title, message) => ctx.ui.confirm(title, message), notify: (message, level) => ctx.ui.notify(message, level) },
|
|
54
|
-
(method, params) => socketCall(connection, method, params ?? {}, 60_000, control),
|
|
55
|
-
projectId
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
})
|
|
59
|
-
const { tools } = await socketCall<{ tools: SocketTool[] }>(connection, 'tools.list', {}, 15_000)
|
|
60
|
-
stage = 'Tool registration'
|
|
61
|
-
for (const tool of tools) {
|
|
62
|
-
pi.registerTool({
|
|
63
|
-
name: tool.name,
|
|
64
|
-
label: tool.label,
|
|
65
|
-
description: tool.description,
|
|
66
|
-
parameters: Type.Unsafe(tool.parameters),
|
|
67
|
-
async execute(_id, input) {
|
|
68
|
-
const result = await socketCall<{ text: string }>(connection, 'tools.call', { name: tool.name, input: input as Record<string, unknown> }, 1_230_000)
|
|
69
|
-
return { content: [{ type: 'text', text: result.text }], details: undefined }
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
} catch (error) {
|
|
74
|
-
await terminalCall('startupFailed', { reason: `${stage} failed: ${error instanceof Error ? error.message : 'Unavailable'}` }).catch(() => {})
|
|
75
|
-
throw error
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
pi.on('session_start', async (_event, ctx) => {
|
|
79
|
-
context = ctx
|
|
80
|
-
await terminalCall('ready', { nativeSessionId: ctx.sessionManager.getSessionFile() })
|
|
81
|
-
timer = setInterval(() => {
|
|
82
|
-
if (polling || !context) return
|
|
83
|
-
polling = true
|
|
84
|
-
void terminalCall<{ command: { type: string; text?: string } | null }>('poll', {}, 5_000)
|
|
85
|
-
.then(({ command }) => {
|
|
86
|
-
if (command?.type === 'interrupt') context?.abort()
|
|
87
|
-
else if (command?.type === 'send') {
|
|
88
|
-
if (context?.ui.getEditorText().trim()) throw new Error('The terminal contains a user draft.')
|
|
89
|
-
// Pi 1.2 needs deliverAs while a run is busy; a message sent then waits for that run to finish.
|
|
90
|
-
pi.sendUserMessage(command.text!, context?.isIdle() === false ? { deliverAs: 'followUp' } : undefined)
|
|
91
|
-
}
|
|
92
|
-
})
|
|
93
|
-
.catch(() => {
|
|
94
|
-
context?.abort()
|
|
95
|
-
if (timer) clearInterval(timer)
|
|
96
|
-
})
|
|
97
|
-
.finally(() => {
|
|
98
|
-
polling = false
|
|
99
|
-
})
|
|
100
|
-
}, 100)
|
|
101
|
-
})
|
|
102
|
-
pi.on('before_agent_start', async (event, ctx) => {
|
|
103
|
-
context = ctx
|
|
104
|
-
failure = undefined
|
|
105
|
-
usage = emptyUsage()
|
|
106
|
-
reasoningTokens = undefined
|
|
107
|
-
costReported = false
|
|
108
|
-
// A run a plugin starts with a custom message has no user prompt to record; it still begins a turn.
|
|
109
|
-
await terminalCall('begin', { text: event.messageType === 'user' ? event.prompt : '' })
|
|
110
|
-
})
|
|
111
|
-
pi.on('message_end', async (event) => {
|
|
112
|
-
if (event.message.role !== 'assistant') return
|
|
113
|
-
if (event.message.stopReason === 'error' || event.message.stopReason === 'aborted') failure = event.message.errorMessage ?? `Pi stopped: ${event.message.stopReason}`
|
|
114
|
-
const text = event.message.content.filter((part) => part.type === 'text').map((part) => part.text).join('\n')
|
|
115
|
-
if (text) await terminalCall('message', { text })
|
|
116
|
-
if (event.message.usage) {
|
|
117
|
-
const reported = event.message.usage
|
|
118
|
-
usage.inputTokens += reported.input ?? 0
|
|
119
|
-
usage.outputTokens += reported.output ?? 0
|
|
120
|
-
usage.cacheReadTokens += reported.cacheRead ?? 0
|
|
121
|
-
usage.cacheWriteTokens += reported.cacheWrite ?? 0
|
|
122
|
-
usage.requests += 1
|
|
123
|
-
if (typeof reported.reasoning === 'number') reasoningTokens = (reasoningTokens ?? 0) + reported.reasoning
|
|
124
|
-
const cost = reported.cost?.total
|
|
125
|
-
if (typeof cost === 'number') {
|
|
126
|
-
usage.costUsd += cost
|
|
127
|
-
costReported = true
|
|
128
|
-
}
|
|
129
|
-
const identity = { model: event.message.model, provider: event.message.provider }
|
|
130
|
-
const { costUsd, ...tokens } = usage
|
|
131
|
-
await terminalCall('usage', {
|
|
132
|
-
...tokens,
|
|
133
|
-
...(costReported ? { costUsd, costSource: 'harness' } : {}),
|
|
134
|
-
...(reasoningTokens === undefined ? {} : { reasoningTokens }),
|
|
135
|
-
contextTokens: (reported.input ?? 0) + (reported.cacheRead ?? 0) + (reported.cacheWrite ?? 0),
|
|
136
|
-
...(context?.model?.contextWindow ? { contextWindow: context.model.contextWindow } : {}),
|
|
137
|
-
...identity,
|
|
138
|
-
request: {
|
|
139
|
-
index: usage.requests,
|
|
140
|
-
...identity,
|
|
141
|
-
responseId: event.message.responseId,
|
|
142
|
-
inputTokens: reported.input ?? 0,
|
|
143
|
-
cacheReadTokens: reported.cacheRead ?? 0,
|
|
144
|
-
cacheWriteTokens: reported.cacheWrite ?? 0,
|
|
145
|
-
outputTokens: reported.output ?? 0,
|
|
146
|
-
...(typeof reported.reasoning === 'number' ? { reasoningTokens: reported.reasoning } : {}),
|
|
147
|
-
...(typeof cost === 'number' ? { costUsd: cost, costSource: 'harness' } : {}),
|
|
148
|
-
...(requestStartedAt === null ? {} : { durationMs: Date.now() - requestStartedAt }),
|
|
149
|
-
stopReason: event.message.stopReason
|
|
150
|
-
}
|
|
151
|
-
})
|
|
152
|
-
requestStartedAt = null
|
|
153
|
-
}
|
|
154
|
-
})
|
|
155
|
-
pi.on('turn_start', async () => {
|
|
156
|
-
requestStartedAt = Date.now()
|
|
157
|
-
})
|
|
158
|
-
pi.on('tool_call', async (event) => {
|
|
159
|
-
try {
|
|
160
|
-
const policy = await terminalCall<{ allowed: boolean; reason?: string; requiresApproval?: boolean }>('policy', { tool: event.toolName, args: event.input })
|
|
161
|
-
if (policy.requiresApproval) {
|
|
162
|
-
const approval = await terminalCall<{ decision: string }>('approval', { requestId: event.toolCallId, target: event.toolName, action: JSON.stringify(event.input), tool: event.toolName, args: event.input })
|
|
163
|
-
if (approval.decision === 'approved') return
|
|
164
|
-
return { block: true, reason: 'The user denied this action. Ask how they would like to proceed.' }
|
|
165
|
-
}
|
|
166
|
-
if (!policy.allowed) return { block: true, reason: policy.reason ?? 'Outside what this session may do.' }
|
|
167
|
-
} catch {
|
|
168
|
-
return { block: true, reason: 'The terminal controller is unavailable.' }
|
|
169
|
-
}
|
|
170
|
-
})
|
|
171
|
-
pi.on('tool_execution_start', async (event) => {
|
|
172
|
-
if (['edit', 'write'].includes(event.toolName) && typeof event.args.path === 'string') fileTools.set(event.toolCallId, event.args.path)
|
|
173
|
-
toolStartedAt.set(event.toolCallId, Date.now())
|
|
174
|
-
await terminalCall('tool', { phase: 'start', id: event.toolCallId, name: event.toolName, summary: JSON.stringify(event.args).slice(0, 200) })
|
|
175
|
-
})
|
|
176
|
-
pi.on('tool_execution_end', async (event) => {
|
|
177
|
-
const started = toolStartedAt.get(event.toolCallId)
|
|
178
|
-
toolStartedAt.delete(event.toolCallId)
|
|
179
|
-
const resultChars = resultSize(event.result)
|
|
180
|
-
await terminalCall('tool', { phase: 'end', id: event.toolCallId, name: event.toolName, ok: !event.isError, ...(started === undefined ? {} : { durationMs: Date.now() - started }), ...(resultChars === null ? {} : { resultChars }) })
|
|
181
|
-
const path = fileTools.get(event.toolCallId)
|
|
182
|
-
fileTools.delete(event.toolCallId)
|
|
183
|
-
if (!event.isError && path) await terminalCall('file', { path, change: 'modified' })
|
|
184
|
-
})
|
|
185
|
-
pi.on('agent_settled', async () => {
|
|
186
|
-
await terminalCall('settled', { error: failure })
|
|
187
|
-
})
|
|
188
|
-
pi.on('user_bash', async () => {
|
|
189
|
-
throw new Error('Use the bash tool so this action can be checked.')
|
|
190
|
-
})
|
|
191
|
-
pi.on('session_shutdown', async () => {
|
|
192
|
-
if (timer) clearInterval(timer)
|
|
193
|
-
await terminalCall('shutdown').catch(() => {})
|
|
194
|
-
})
|
|
195
|
-
pi.registerTool({
|
|
196
|
-
name: 'ask_user_question',
|
|
197
|
-
label: 'Ask a question',
|
|
198
|
-
description: 'Ask the user a question and wait for their answer.',
|
|
199
|
-
parameters: Type.Object({
|
|
200
|
-
question: Type.String(),
|
|
201
|
-
options: Type.Optional(Type.Array(Type.Object({ label: Type.String(), description: Type.Optional(Type.String()) }))),
|
|
202
|
-
multiSelect: Type.Optional(Type.Boolean())
|
|
203
|
-
}),
|
|
204
|
-
async execute(id, input) {
|
|
205
|
-
const answer = await terminalCall('question', { requestId: id, ...input })
|
|
206
|
-
return { content: [{ type: 'text', text: JSON.stringify(answer) }], details: undefined }
|
|
207
|
-
}
|
|
208
|
-
})
|
|
209
|
-
await terminalCall('startup', { phase: 'Pi hooks registered' })
|
|
210
|
-
}
|