@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
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Installing, updating and removing a package. Pi's own package manager does the work, against
|
|
2
|
+
// the settings every account shares, so the `pi` command and the harness agree on what is
|
|
3
|
+
// installed. Fetching runs none of a package's code, and what was installed is switched off and
|
|
4
|
+
// untrusted until a person has looked at it.
|
|
5
|
+
import { existsSync, mkdirSync, renameSync, statSync } from 'node:fs';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { basename, isAbsolute, join, resolve } from 'node:path';
|
|
8
|
+
import { ensureSharedDir } from "../accounts/env.js";
|
|
9
|
+
import { invalid, notFound } from "../core/errors.js";
|
|
10
|
+
import { now } from "../core/fs.js";
|
|
11
|
+
import { loadPi } from "../pi/runtime.js";
|
|
12
|
+
import { ensureAdopted, list } from "./api.js";
|
|
13
|
+
import * as attachments from "./attachments.js";
|
|
14
|
+
import { withoutInstallScripts } from "./discover.js";
|
|
15
|
+
/** A folder on this machine, or a package as Pi's settings name it. A bare name is an npm package. */
|
|
16
|
+
export function normalizeSource(input) {
|
|
17
|
+
const source = input.trim();
|
|
18
|
+
if (!source)
|
|
19
|
+
throw invalid('Name a package: a folder, an npm name, or a git address.');
|
|
20
|
+
if (source.startsWith('~/'))
|
|
21
|
+
return join(process.env.HOME || homedir(), source.slice(2));
|
|
22
|
+
if (isAbsolute(source))
|
|
23
|
+
return resolve(source);
|
|
24
|
+
if (source.startsWith('./') || source.startsWith('../'))
|
|
25
|
+
throw invalid('Give the whole path of the folder.');
|
|
26
|
+
return /^(npm:|git:|https?:\/\/|ssh:\/\/|git@)/.test(source) ? source : `npm:${source}`;
|
|
27
|
+
}
|
|
28
|
+
async function manager(harness) {
|
|
29
|
+
const pi = await loadPi();
|
|
30
|
+
// The shared folder is where `settings.json` really is; an account's own is a link to it.
|
|
31
|
+
const agentDir = ensureSharedDir(harness.accounts.dir);
|
|
32
|
+
const settings = pi.SettingsManager.create(harness.stateDir, agentDir);
|
|
33
|
+
return { settings, packages: new pi.DefaultPackageManager({ cwd: harness.stateDir, agentDir, settingsManager: settings }) };
|
|
34
|
+
}
|
|
35
|
+
const changed = (harness) => harness.bus.emit({ type: 'plugins.changed' });
|
|
36
|
+
/**
|
|
37
|
+
* Installs a package for every account. It arrives switched off, and if it brings code, not
|
|
38
|
+
* trusted: nothing of it reaches a session until a person switches it on and trusts it.
|
|
39
|
+
*/
|
|
40
|
+
export async function install(harness, params) {
|
|
41
|
+
const source = normalizeSource(params.source);
|
|
42
|
+
if (isAbsolute(source) && !(existsSync(source) && statSync(source).isDirectory()))
|
|
43
|
+
throw invalid('That folder does not exist.');
|
|
44
|
+
// What was already there is taken over as trusted before anything new arrives, never after.
|
|
45
|
+
await ensureAdopted(harness);
|
|
46
|
+
const before = new Set((await list(harness, params)).map((plugin) => plugin.id));
|
|
47
|
+
const { settings, packages } = await manager(harness);
|
|
48
|
+
if (isAbsolute(source)) {
|
|
49
|
+
// Pi would save a folder as a path relative to the settings file, and each account reads
|
|
50
|
+
// that file through a link in its own folder, where a relative path points somewhere else.
|
|
51
|
+
const named = settings.getGlobalSettings().packages ?? [];
|
|
52
|
+
if (!named.some((entry) => (typeof entry === 'string' ? entry : entry.source) === source))
|
|
53
|
+
settings.setPackages([...named, source]);
|
|
54
|
+
await settings.flush();
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
await withoutInstallScripts(() => packages.installAndPersist(source));
|
|
58
|
+
}
|
|
59
|
+
const after = await list(harness, params);
|
|
60
|
+
const added = after.filter((plugin) => plugin.install && !before.has(plugin.id));
|
|
61
|
+
if (added.length) {
|
|
62
|
+
const choices = attachments.load(harness.env.root);
|
|
63
|
+
for (const plugin of added)
|
|
64
|
+
attachments.set(choices, [plugin.id], {}, false, true);
|
|
65
|
+
attachments.save(harness.env.root, choices);
|
|
66
|
+
}
|
|
67
|
+
changed(harness);
|
|
68
|
+
return added.length ? list(harness, params) : after;
|
|
69
|
+
}
|
|
70
|
+
function installed(plugins, pluginId) {
|
|
71
|
+
const plugin = plugins.find((candidate) => candidate.id === pluginId);
|
|
72
|
+
if (!plugin)
|
|
73
|
+
throw notFound('Plugin');
|
|
74
|
+
if (!plugin.install)
|
|
75
|
+
throw invalid(`${plugin.title} was not installed as a package, so it cannot be removed or updated here.`);
|
|
76
|
+
return plugin;
|
|
77
|
+
}
|
|
78
|
+
/** Removes an installed package. One kept as a folder beside a person's data is moved to the trash there. */
|
|
79
|
+
export async function remove(harness, params) {
|
|
80
|
+
const plugin = installed(await list(harness, params), params.pluginId);
|
|
81
|
+
if (plugin.install.kind === 'folder') {
|
|
82
|
+
const trash = join(harness.env.root, 'trash', 'plugins');
|
|
83
|
+
mkdirSync(trash, { recursive: true });
|
|
84
|
+
renameSync(plugin.install.source, join(trash, `${basename(plugin.install.source)}-${now().replace(/[:.]/g, '-')}`));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
await (await manager(harness)).packages.removeAndPersist(plugin.install.source);
|
|
88
|
+
}
|
|
89
|
+
const choices = attachments.load(harness.env.root);
|
|
90
|
+
for (const scope of [choices.global, ...Object.values(choices.agents), ...Object.values(choices.projects)]) {
|
|
91
|
+
scope.on = scope.on.filter((id) => id !== plugin.id && !id.startsWith(`${plugin.id}/`));
|
|
92
|
+
scope.off = scope.off.filter((id) => id !== plugin.id && !id.startsWith(`${plugin.id}/`));
|
|
93
|
+
}
|
|
94
|
+
delete choices.settings[plugin.id];
|
|
95
|
+
attachments.save(harness.env.root, choices);
|
|
96
|
+
if (plugin.code)
|
|
97
|
+
harness.plugins.trust.revoke(plugin.code.hash);
|
|
98
|
+
changed(harness);
|
|
99
|
+
return list(harness, params);
|
|
100
|
+
}
|
|
101
|
+
/** Fetches a newer version of one installed package, or of all of them. Changed code waits for trust again. */
|
|
102
|
+
export async function update(harness, params) {
|
|
103
|
+
const plugin = params.pluginId ? installed(await list(harness, params), params.pluginId) : null;
|
|
104
|
+
if (plugin?.install.kind === 'folder')
|
|
105
|
+
throw invalid(`${plugin.title} is a folder on this machine. Change its files to update it.`);
|
|
106
|
+
const { packages } = await manager(harness);
|
|
107
|
+
await withoutInstallScripts(() => packages.update(plugin?.install.source));
|
|
108
|
+
changed(harness);
|
|
109
|
+
return list(harness, params);
|
|
110
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HarnessEnv } from "../core/env.js";
|
|
2
|
+
import type { Connection } from "../mcp/types.js";
|
|
3
|
+
import type { CallerContext } from "../core/caller.js";
|
|
4
|
+
import { type Launch } from "../prompt/compile.js";
|
|
5
|
+
import type { Materialised } from "../variant/materialise.js";
|
|
6
|
+
import type { Inventory, Plugin, PluginDescriptor } from "./types.js";
|
|
7
|
+
export interface InventoryInput {
|
|
8
|
+
env: HarnessEnv;
|
|
9
|
+
context: CallerContext;
|
|
10
|
+
/** What the application adds to the prompt for this caller, as it would for a session. */
|
|
11
|
+
launch: Launch;
|
|
12
|
+
/** The tools the caller has switched on, as a session's `allow` list. */
|
|
13
|
+
tools: readonly string[];
|
|
14
|
+
/** Whether the caller gets the connected-apps tools. */
|
|
15
|
+
connections: boolean;
|
|
16
|
+
plugins: readonly Plugin[];
|
|
17
|
+
descriptors: readonly PluginDescriptor[];
|
|
18
|
+
saved: readonly Connection[];
|
|
19
|
+
/** The variant the caller runs, when it has one. */
|
|
20
|
+
variant?: Materialised | null;
|
|
21
|
+
}
|
|
22
|
+
export declare function inventory(input: InventoryInput): Inventory;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// What reaches one caller: every prompt section, tool, skill, connection and extension, each
|
|
2
|
+
// attributed to the plugin it comes from. Anything no plugin accounts for is reported, so a new
|
|
3
|
+
// source of model-visible text cannot appear without showing up here.
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { charCount } from "../core/text.js";
|
|
6
|
+
import { allowed } from "../mcp/connections.js";
|
|
7
|
+
import { BUILT_IN_DYNAMIC, compile, toolGroups } from "../prompt/compile.js";
|
|
8
|
+
import { ASK_USER } from "../tools/askUser.js";
|
|
9
|
+
import { CHECKLIST_WRITE } from "../tools/checklist.js";
|
|
10
|
+
import { DEFAULT_TOOL_NAMES } from "../tools/definitions.js";
|
|
11
|
+
import { VARIANT_PLUGIN } from "./builtin.js";
|
|
12
|
+
const size = (path) => {
|
|
13
|
+
if (!path)
|
|
14
|
+
return null;
|
|
15
|
+
try {
|
|
16
|
+
return charCount(readFileSync(path, 'utf8'));
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export function inventory(input) {
|
|
23
|
+
const { env, context, launch, descriptors } = input;
|
|
24
|
+
const items = [];
|
|
25
|
+
const unattributed = [];
|
|
26
|
+
const item = (pluginId, kind, name, delivery, chars, rest = {}) => {
|
|
27
|
+
items.push({ pluginId, contributionId: null, kind, name, delivery, chars, cut: false, ...rest });
|
|
28
|
+
};
|
|
29
|
+
const pack = compile(env, context, launch, input.variant ?? null);
|
|
30
|
+
const dynamic = new Set([...BUILT_IN_DYNAMIC.map((entry) => entry.id), ...(launch.sections ?? []).filter((section) => section.dynamic).map((section) => section.id)]);
|
|
31
|
+
let systemChars = 0;
|
|
32
|
+
let contextChars = 0;
|
|
33
|
+
for (const section of pack.sections) {
|
|
34
|
+
const delivery = dynamic.has(section.id) ? 'context' : 'system';
|
|
35
|
+
if (delivery === 'context')
|
|
36
|
+
contextChars += section.size;
|
|
37
|
+
else
|
|
38
|
+
systemChars += section.size;
|
|
39
|
+
if (section.id === 'tools') {
|
|
40
|
+
// One paragraph per tool group; each belongs to the plugin that provides the group.
|
|
41
|
+
for (const group of toolGroups(context, launch)) {
|
|
42
|
+
if (!group.guidance)
|
|
43
|
+
continue;
|
|
44
|
+
const plugin = descriptors.find((descriptor) => descriptor.toolGroups?.includes(group.group));
|
|
45
|
+
if (!plugin)
|
|
46
|
+
unattributed.push({ kind: 'toolGroup', id: group.group });
|
|
47
|
+
item(plugin?.id ?? '', 'instruction', `Tool guidance: ${group.group}`, delivery, charCount(group.guidance), { cut: section.cut });
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const plugin = descriptors.find((descriptor) => descriptor.sections?.some((declared) => declared.id === section.id));
|
|
52
|
+
if (!plugin)
|
|
53
|
+
unattributed.push({ kind: 'section', id: section.id });
|
|
54
|
+
const name = plugin?.sections?.find((declared) => declared.id === section.id)?.name ?? section.title;
|
|
55
|
+
item(plugin?.id ?? '', 'instruction', name, delivery, section.size, { contributionId: plugin ? `${plugin.id}/instruction/${name}` : null, cut: section.cut });
|
|
56
|
+
}
|
|
57
|
+
// The variant's skills are loaded only when used; its plugins run in the tool loop.
|
|
58
|
+
const variant = input.variant ?? null;
|
|
59
|
+
if (variant) {
|
|
60
|
+
for (const rel of Object.keys(variant.files).filter((path) => /^skills\/[^/]+\/SKILL\.md$/.test(path)).sort()) {
|
|
61
|
+
const name = rel.split('/')[1];
|
|
62
|
+
item(VARIANT_PLUGIN.id, 'skill', name, 'on-demand', charCount(variant.files[rel]), { contributionId: `${VARIANT_PLUGIN.id}/skill/${name}` });
|
|
63
|
+
}
|
|
64
|
+
for (const path of variant.extensionPaths) {
|
|
65
|
+
const name = path.split('/').pop();
|
|
66
|
+
item(VARIANT_PLUGIN.id, 'code', name, 'code', size(path), { contributionId: `${VARIANT_PLUGIN.id}/code/${name}` });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const names = [...input.tools];
|
|
70
|
+
const extensionToolNames = new Set(input.plugins.filter((plugin) => ['project', 'package', 'shared', 'home'].includes(plugin.source)).flatMap((plugin) => plugin.contributions.filter((entry) => entry.kind === 'tool' && entry.state === 'on').map((entry) => entry.name)));
|
|
71
|
+
for (const name of [ASK_USER, CHECKLIST_WRITE, ...DEFAULT_TOOL_NAMES, ...(input.connections ? ['mcp_list_tools', 'mcp_call_tool'] : [])])
|
|
72
|
+
if (!names.includes(name))
|
|
73
|
+
names.push(name);
|
|
74
|
+
for (const name of names) {
|
|
75
|
+
if (extensionToolNames.has(name))
|
|
76
|
+
continue;
|
|
77
|
+
const plugin = descriptors.find((descriptor) => descriptor.tools?.some((tool) => tool.name === name));
|
|
78
|
+
if (!plugin)
|
|
79
|
+
unattributed.push({ kind: 'tool', id: name });
|
|
80
|
+
item(plugin?.id ?? '', 'tool', name, 'tool', null, { contributionId: plugin ? `${plugin.id}/tool/${name}` : null });
|
|
81
|
+
}
|
|
82
|
+
if (input.connections) {
|
|
83
|
+
for (const connection of input.saved.filter((candidate) => allowed(candidate, { agentId: context.agentId ?? null, projectId: context.projectId ?? null }))) {
|
|
84
|
+
item('connected-apps', 'connection', connection.name || connection.id, 'tool', null, { contributionId: `connected-apps/connection/${connection.id}` });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// What the harness found on disk and lets load. Pi's command's own extensions exist only in a terminal.
|
|
88
|
+
const delivered = { code: 'code', skill: 'on-demand', command: 'on-demand', instruction: 'system', theme: 'code', tool: 'tool', connection: 'tool' };
|
|
89
|
+
const terminal = context.surface === 'cli';
|
|
90
|
+
for (const plugin of input.plugins) {
|
|
91
|
+
if (!['project', 'package', 'shared', 'home', 'pi'].includes(plugin.source))
|
|
92
|
+
continue;
|
|
93
|
+
for (const found of plugin.contributions) {
|
|
94
|
+
if (found.state !== 'on' || (plugin.source === 'pi' && (found.kind !== 'code' || !terminal)) || (found.kind === 'theme' && !terminal))
|
|
95
|
+
continue;
|
|
96
|
+
item(plugin.id, found.kind, found.name, found.background ? 'background' : delivered[found.kind], ['instruction', 'skill', 'command'].includes(found.kind) ? size(found.path) : null, { contributionId: found.id });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// The harness's own switched-on extensions.
|
|
100
|
+
for (const plugin of input.plugins) {
|
|
101
|
+
if (plugin.source !== 'builtin')
|
|
102
|
+
continue;
|
|
103
|
+
for (const own of plugin.contributions)
|
|
104
|
+
if (own.kind === 'code' && own.state === 'on')
|
|
105
|
+
item(plugin.id, 'code', own.name, 'code', null, { contributionId: own.id });
|
|
106
|
+
}
|
|
107
|
+
item('pi', 'instruction', 'Base prompt', 'system', null);
|
|
108
|
+
const used = new Set(items.map((entry) => entry.pluginId));
|
|
109
|
+
return { plugins: input.plugins.filter((plugin) => used.has(plugin.id)), others: input.plugins.filter((plugin) => !used.has(plugin.id)), items, unattributed, systemChars, contextChars };
|
|
110
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ConnectorTemplate } from "./types.js";
|
|
2
|
+
export interface PackageManifest {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
version: string | null;
|
|
6
|
+
/** The parts it adds to, by id: `memory`, `wiki`, `history`. */
|
|
7
|
+
extends: string[];
|
|
8
|
+
/** The hooks file, inside the package, or `null` when it has none. */
|
|
9
|
+
hooks: string | null;
|
|
10
|
+
/** Data-only remote connector forms. Invalid templates are ignored; none can carry credentials. */
|
|
11
|
+
connectorTemplates: ConnectorTemplate[];
|
|
12
|
+
}
|
|
13
|
+
export declare function packageManifest(packageRoot: string): PackageManifest;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// What a package says about itself in its `package.json`: Pi's own fields, and under `harness`
|
|
2
|
+
// which part of the harness it extends and the file of hooks the harness runs for it.
|
|
3
|
+
import { basename, join } from 'node:path';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { readJsonOr, safeRelative } from "../core/fs.js";
|
|
6
|
+
const connectorTemplateSchema = z.object({
|
|
7
|
+
id: z.string().regex(/^[a-z0-9-]+$/),
|
|
8
|
+
name: z.string().min(1).max(120),
|
|
9
|
+
description: z.string().max(500),
|
|
10
|
+
url: z.string().url().startsWith('https://'),
|
|
11
|
+
auth: z.enum(['none', 'headers', 'oauth']),
|
|
12
|
+
oauthClient: z.enum(['dynamic', 'user']).nullable(),
|
|
13
|
+
oauthScopes: z.array(z.string().max(500)).max(30),
|
|
14
|
+
docsUrl: z.string().url().startsWith('https://').nullable(),
|
|
15
|
+
fields: z.array(z.object({
|
|
16
|
+
header: z.string().regex(/^[A-Za-z0-9_-]+$/),
|
|
17
|
+
label: z.string().min(1).max(120),
|
|
18
|
+
prefix: z.string().max(100),
|
|
19
|
+
help: z.string().max(500)
|
|
20
|
+
}).strict()).max(12),
|
|
21
|
+
setup: z.array(z.string().max(1000)).max(20),
|
|
22
|
+
notice: z.string().max(1000).nullable()
|
|
23
|
+
}).strict().superRefine((template, context) => {
|
|
24
|
+
const oauth = template.auth === 'oauth';
|
|
25
|
+
const headers = template.auth === 'headers';
|
|
26
|
+
if (oauth !== (template.oauthClient !== null))
|
|
27
|
+
context.addIssue({ code: 'custom', message: 'OAuth templates must state a client type and other templates must not.', path: ['oauthClient'] });
|
|
28
|
+
if (headers !== (template.fields.length > 0))
|
|
29
|
+
context.addIssue({ code: 'custom', message: 'Header templates must declare input fields and other templates must not.', path: ['fields'] });
|
|
30
|
+
});
|
|
31
|
+
/** A path inside the package, or `null` for one that is missing, absolute, or climbs out of it. */
|
|
32
|
+
function inside(path) {
|
|
33
|
+
if (typeof path !== 'string' || !path.trim())
|
|
34
|
+
return null;
|
|
35
|
+
try {
|
|
36
|
+
return safeRelative(path.replace(/^\.\//, ''));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function packageManifest(packageRoot) {
|
|
43
|
+
const manifest = readJsonOr(join(packageRoot, 'package.json'), {});
|
|
44
|
+
const own = (manifest.harness && typeof manifest.harness === 'object' && !Array.isArray(manifest.harness) ? manifest.harness : {});
|
|
45
|
+
return {
|
|
46
|
+
name: typeof manifest.name === 'string' && manifest.name ? manifest.name : basename(packageRoot),
|
|
47
|
+
description: typeof manifest.description === 'string' ? manifest.description : '',
|
|
48
|
+
version: typeof manifest.version === 'string' ? manifest.version : null,
|
|
49
|
+
extends: (Array.isArray(own.extends) ? own.extends : typeof own.extends === 'string' ? [own.extends] : []).filter((id) => typeof id === 'string' && !!id),
|
|
50
|
+
hooks: inside(own.hooks),
|
|
51
|
+
connectorTemplates: (Array.isArray(own.connectors) ? own.connectors : []).flatMap((value) => {
|
|
52
|
+
const parsed = connectorTemplateSchema.safeParse(value);
|
|
53
|
+
return parsed.success ? [parsed.data] : [];
|
|
54
|
+
})
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { Bus } from "../core/bus.js";
|
|
2
|
+
import { type Attachments, type AttachScope } from "./attachments.js";
|
|
3
|
+
import { type Found, type ResolveInput, type Resolver } from "./discover.js";
|
|
4
|
+
import { Trust, type ProjectCode } from "./trust.js";
|
|
5
|
+
/** What one session or terminal loads besides the registry's own items. */
|
|
6
|
+
export interface Loading {
|
|
7
|
+
/** Extension files and folders, in the order Pi would have loaded them. */
|
|
8
|
+
extensionPaths: string[];
|
|
9
|
+
skillPaths: string[];
|
|
10
|
+
promptPaths: string[];
|
|
11
|
+
themePaths: string[];
|
|
12
|
+
/** The `pi` command's own extensions left on, as `builtin:<name>`. Only a terminal has them. */
|
|
13
|
+
builtins: string[];
|
|
14
|
+
/** Hooks files the harness runs itself. Pi is never given them. */
|
|
15
|
+
hooks: {
|
|
16
|
+
path: string;
|
|
17
|
+
packageRoot: string;
|
|
18
|
+
hash: string;
|
|
19
|
+
}[];
|
|
20
|
+
/** Everything found, loaded or not. */
|
|
21
|
+
found: Found[];
|
|
22
|
+
/** Paths of found items a person switched off for this caller. */
|
|
23
|
+
detached: string[];
|
|
24
|
+
/** Applies the same attachment policy to resources supplied by a trusted extension. */
|
|
25
|
+
resourceAllowed?: (item: Found) => boolean;
|
|
26
|
+
/** Code the working folder brings, and whether a person trusted it. */
|
|
27
|
+
projectCode: (ProjectCode & {
|
|
28
|
+
trusted: boolean;
|
|
29
|
+
}) | null;
|
|
30
|
+
/** Each installed package that brings code, by its folder, and whether a person trusted it. */
|
|
31
|
+
packageCode: Record<string, ProjectCode & {
|
|
32
|
+
trusted: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
/** What one loaded extension added to a session. */
|
|
36
|
+
export interface Registered {
|
|
37
|
+
path: string;
|
|
38
|
+
hooks: string[];
|
|
39
|
+
tools: string[];
|
|
40
|
+
commands: string[];
|
|
41
|
+
flags: string[];
|
|
42
|
+
shortcuts: string[];
|
|
43
|
+
/** Fingerprint at observation time; stale registrations are not presented as current. */
|
|
44
|
+
hash?: string | null;
|
|
45
|
+
seenAt?: string;
|
|
46
|
+
resources?: RuntimeResource[];
|
|
47
|
+
}
|
|
48
|
+
export interface RuntimeResource {
|
|
49
|
+
kind: 'skill' | 'command' | 'theme';
|
|
50
|
+
name: string;
|
|
51
|
+
path: string;
|
|
52
|
+
chars: number | null;
|
|
53
|
+
}
|
|
54
|
+
export interface PluginsOptions {
|
|
55
|
+
stateDir: string;
|
|
56
|
+
bus: Bus;
|
|
57
|
+
resolver?: Resolver;
|
|
58
|
+
/** The choices a person made about what is switched on, or `null` while there is no data root. */
|
|
59
|
+
attachments?: () => Attachments | null;
|
|
60
|
+
/** The folder of packages kept with a person's data, or `null` while there is no data root. */
|
|
61
|
+
packagesDir?: () => string | null;
|
|
62
|
+
}
|
|
63
|
+
/** The package folders inside a folder: each direct child that is a folder and not hidden. */
|
|
64
|
+
export declare function packageFolders(directory: string | null): string[];
|
|
65
|
+
export interface LoadingInput extends ResolveInput {
|
|
66
|
+
/** Who the session is for. Something switched off for this agent or project does not load. */
|
|
67
|
+
caller?: AttachScope;
|
|
68
|
+
/** The contributions frozen for a run. When present, this snapshot governs loading. */
|
|
69
|
+
contributions?: readonly string[];
|
|
70
|
+
}
|
|
71
|
+
/** Which code a person trusted: the working folder's as a whole, and each installed package's. */
|
|
72
|
+
export interface Trusted {
|
|
73
|
+
project: boolean;
|
|
74
|
+
/** Folders of installed packages whose code is not trusted. */
|
|
75
|
+
untrustedPackages: ReadonlySet<string>;
|
|
76
|
+
}
|
|
77
|
+
export declare const trustedBy: (loading: Pick<Loading, "projectCode" | "packageCode"> | null) => Trusted;
|
|
78
|
+
/**
|
|
79
|
+
* Whether a found item loads: it is on in Pi's settings, and if it is code, a person trusted it.
|
|
80
|
+
* A loose file in the shared folder was put there by hand and needs no trust. Text always loads.
|
|
81
|
+
*/
|
|
82
|
+
export declare function loads(item: Found, trusted: Trusted): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Whether a person left a found item switched on for a caller. Pi reads its instruction files
|
|
85
|
+
* itself and its command owns its built-in extensions, so neither can be switched off here.
|
|
86
|
+
*/
|
|
87
|
+
export declare function switchable(item: Found): boolean;
|
|
88
|
+
export declare class Plugins {
|
|
89
|
+
private readonly options;
|
|
90
|
+
readonly trust: Trust;
|
|
91
|
+
private readonly resolver;
|
|
92
|
+
private readonly registeredPath;
|
|
93
|
+
constructor(options: PluginsOptions);
|
|
94
|
+
/** Finds what Pi would load in this folder, and chooses what does. */
|
|
95
|
+
loading(input: LoadingInput): Promise<Loading>;
|
|
96
|
+
/** What each extension registered the last time a session loaded it. */
|
|
97
|
+
registered(): Record<string, Registered & {
|
|
98
|
+
seenAt: string;
|
|
99
|
+
}>;
|
|
100
|
+
/** Records what a session's extensions registered, so the list can show it without loading code. */
|
|
101
|
+
loaded(extensions: readonly Registered[]): void;
|
|
102
|
+
}
|
|
103
|
+
/** Removes the skill links an earlier version of the harness kept in a Pi agent folder's `skills/`. */
|
|
104
|
+
export declare function removeLinkedSkills(skillsDir: string): void;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// The harness decides what a Pi session loads. Pi's own discovery is switched off for sessions
|
|
2
|
+
// and terminals; they receive the paths chosen here, so nothing reaches a model unlisted.
|
|
3
|
+
import { chmodSync, lstatSync, readdirSync, rmSync, unlinkSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { now, readJsonOr, writeJson } from "../core/fs.js";
|
|
6
|
+
import { attached } from "./attachments.js";
|
|
7
|
+
import { piResolver } from "./discover.js";
|
|
8
|
+
import { foundIds, pluginIdOf } from "./identity.js";
|
|
9
|
+
import { packageCode, projectCode, Trust } from "./trust.js";
|
|
10
|
+
/** The package folders inside a folder: each direct child that is a folder and not hidden. */
|
|
11
|
+
export function packageFolders(directory) {
|
|
12
|
+
if (!directory)
|
|
13
|
+
return [];
|
|
14
|
+
try {
|
|
15
|
+
return readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith('.')).map((entry) => join(directory, entry.name)).sort();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export const trustedBy = (loading) => ({
|
|
22
|
+
project: !!loading?.projectCode?.trusted,
|
|
23
|
+
untrustedPackages: new Set(Object.entries(loading?.packageCode ?? {}).filter(([, code]) => !code.trusted).map(([root]) => root))
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Whether a found item loads: it is on in Pi's settings, and if it is code, a person trusted it.
|
|
27
|
+
* A loose file in the shared folder was put there by hand and needs no trust. Text always loads.
|
|
28
|
+
*/
|
|
29
|
+
export function loads(item, trusted) {
|
|
30
|
+
if (!item.enabled)
|
|
31
|
+
return false;
|
|
32
|
+
if (item.kind !== 'extension' && item.kind !== 'hook')
|
|
33
|
+
return true;
|
|
34
|
+
if (item.project)
|
|
35
|
+
return trusted.project;
|
|
36
|
+
return !(item.packageRoot && trusted.untrustedPackages.has(item.packageRoot));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Whether a person left a found item switched on for a caller. Pi reads its instruction files
|
|
40
|
+
* itself and its command owns its built-in extensions, so neither can be switched off here.
|
|
41
|
+
*/
|
|
42
|
+
export function switchable(item) {
|
|
43
|
+
return item.kind !== 'context' && item.origin !== 'builtin';
|
|
44
|
+
}
|
|
45
|
+
export class Plugins {
|
|
46
|
+
options;
|
|
47
|
+
trust;
|
|
48
|
+
resolver;
|
|
49
|
+
registeredPath;
|
|
50
|
+
constructor(options) {
|
|
51
|
+
this.options = options;
|
|
52
|
+
this.trust = new Trust(options.stateDir, options.bus);
|
|
53
|
+
this.resolver = options.resolver ?? piResolver;
|
|
54
|
+
this.registeredPath = join(options.stateDir, 'plugin-registered.json');
|
|
55
|
+
}
|
|
56
|
+
/** Finds what Pi would load in this folder, and chooses what does. */
|
|
57
|
+
async loading(input) {
|
|
58
|
+
// Links an earlier version put in the shared skills folder would be found as skills again.
|
|
59
|
+
removeLinkedSkills(join(input.agentDir, 'skills'));
|
|
60
|
+
const found = await this.resolver({ ...input, packages: packageFolders(this.options.packagesDir?.() ?? null) });
|
|
61
|
+
const code = projectCode(found, input.cwd);
|
|
62
|
+
const packages = packageCode(found);
|
|
63
|
+
// Packages that loaded before trust was asked per package keep loading: they are taken over once.
|
|
64
|
+
if (!this.trust.adopted)
|
|
65
|
+
this.trust.adopt([...packages].map(([folder, packaged]) => ({ code: packaged, folder })));
|
|
66
|
+
const trustedHashes = new Set(this.trust.list().map((record) => record.hash));
|
|
67
|
+
const projectCodeState = code ? { ...code, trusted: trustedHashes.has(code.hash) } : null;
|
|
68
|
+
const packageCodeState = Object.fromEntries([...packages].map(([folder, packaged]) => [folder, { ...packaged, trusted: trustedHashes.has(packaged.hash) }]));
|
|
69
|
+
const trusted = trustedBy({ projectCode: projectCodeState, packageCode: packageCodeState });
|
|
70
|
+
const choices = this.options.attachments?.() ?? null;
|
|
71
|
+
const off = (item) => {
|
|
72
|
+
if (!choices || !switchable(item))
|
|
73
|
+
return false;
|
|
74
|
+
// A hook runs for everyone or not at all, so only its plugin's switch for everyone counts.
|
|
75
|
+
if (item.kind === 'hook')
|
|
76
|
+
return !attached(choices, [pluginIdOf(item)], {}, true);
|
|
77
|
+
return !attached(choices, foundIds(item), input.caller ?? {}, true);
|
|
78
|
+
};
|
|
79
|
+
const allowed = (item) => input.contributions === undefined
|
|
80
|
+
? !off(item)
|
|
81
|
+
: input.contributions.includes(foundIds(item)[0]);
|
|
82
|
+
const detached = found.filter((item) => !allowed(item)).map((item) => item.path);
|
|
83
|
+
const chosen = found.filter((item) => loads(item, trusted) && allowed(item));
|
|
84
|
+
const paths = (kind, builtin) => chosen.filter((item) => item.kind === kind && (item.origin === 'builtin') === builtin).map((item) => item.path);
|
|
85
|
+
return {
|
|
86
|
+
extensionPaths: paths('extension', false),
|
|
87
|
+
skillPaths: paths('skill', false),
|
|
88
|
+
promptPaths: paths('prompt', false),
|
|
89
|
+
themePaths: paths('theme', false),
|
|
90
|
+
builtins: paths('extension', true),
|
|
91
|
+
hooks: chosen.filter((item) => item.kind === 'hook' && item.packageRoot).map((item) => ({ path: item.path, packageRoot: item.packageRoot, hash: packageCodeState[item.packageRoot]?.hash ?? '' })),
|
|
92
|
+
found,
|
|
93
|
+
detached,
|
|
94
|
+
resourceAllowed: allowed,
|
|
95
|
+
projectCode: projectCodeState,
|
|
96
|
+
packageCode: packageCodeState
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/** What each extension registered the last time a session loaded it. */
|
|
100
|
+
registered() {
|
|
101
|
+
return readJsonOr(this.registeredPath, {});
|
|
102
|
+
}
|
|
103
|
+
/** Records what a session's extensions registered, so the list can show it without loading code. */
|
|
104
|
+
loaded(extensions) {
|
|
105
|
+
if (!extensions.length)
|
|
106
|
+
return;
|
|
107
|
+
const stored = this.registered();
|
|
108
|
+
let changed = false;
|
|
109
|
+
for (const extension of extensions) {
|
|
110
|
+
const { seenAt: _seenAt, ...before } = stored[extension.path] ?? {};
|
|
111
|
+
if (JSON.stringify(before) === JSON.stringify(extension))
|
|
112
|
+
continue;
|
|
113
|
+
stored[extension.path] = { ...extension, seenAt: now() };
|
|
114
|
+
changed = true;
|
|
115
|
+
}
|
|
116
|
+
if (!changed)
|
|
117
|
+
return;
|
|
118
|
+
writeJson(this.registeredPath, stored);
|
|
119
|
+
chmodSync(this.registeredPath, 0o600);
|
|
120
|
+
this.options.bus.emit({ type: 'plugins.changed' });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Prefix of the entries an earlier version of the harness linked into a Pi agent folder's `skills/`.
|
|
124
|
+
const LINKED_SKILL_PREFIX = 'agentx-';
|
|
125
|
+
function isLinkedSkill(path) {
|
|
126
|
+
let meta;
|
|
127
|
+
try {
|
|
128
|
+
meta = lstatSync(path);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
if (meta.isSymbolicLink())
|
|
134
|
+
return true;
|
|
135
|
+
if (!meta.isDirectory())
|
|
136
|
+
return false;
|
|
137
|
+
// A single-file skill was linked as `agentx-<name>/SKILL.md` inside a folder the harness made.
|
|
138
|
+
try {
|
|
139
|
+
const entries = readdirSync(path);
|
|
140
|
+
return entries.length === 1 && entries[0] === 'SKILL.md' && lstatSync(join(path, 'SKILL.md')).isSymbolicLink();
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** Removes the skill links an earlier version of the harness kept in a Pi agent folder's `skills/`. */
|
|
147
|
+
export function removeLinkedSkills(skillsDir) {
|
|
148
|
+
let names;
|
|
149
|
+
try {
|
|
150
|
+
names = readdirSync(skillsDir);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
for (const name of names) {
|
|
156
|
+
const path = join(skillsDir, name);
|
|
157
|
+
if (!name.startsWith(LINKED_SKILL_PREFIX) || !isLinkedSkill(path))
|
|
158
|
+
continue;
|
|
159
|
+
if (lstatSync(path).isSymbolicLink())
|
|
160
|
+
unlinkSync(path);
|
|
161
|
+
else
|
|
162
|
+
rmSync(path, { recursive: true, force: true });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type * as Pi from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import type { Found } from "./discover.js";
|
|
3
|
+
import type { Loading, Registered, RuntimeResource } from "./plugins.js";
|
|
4
|
+
export declare function runtimeOwner(loading: Loading, path: string): Found | undefined;
|
|
5
|
+
export declare function registrationHash(loading: Loading, path: string): string | null;
|
|
6
|
+
/** A discovered resource has the same identity for its switch, catalogue and load decision. */
|
|
7
|
+
export declare function resourceOf(owner: Found, kind: 'skill' | 'prompt' | 'theme', path: string): RuntimeResource;
|
|
8
|
+
/** Wrap each handler separately so identical extension basenames never lose their owner. */
|
|
9
|
+
export declare function observeResources(pi: typeof Pi, loader: Pi.DefaultResourceLoader, loading: Loading, records: Registered[], publish: () => void): void;
|