@openma/common 0.0.0-stage → 0.9.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/LICENSE +202 -0
- package/README.md +391 -2
- package/dist/acp-artifacts/binary.d.ts +35 -0
- package/dist/acp-artifacts/binary.d.ts.map +1 -0
- package/dist/acp-artifacts/binary.js +120 -0
- package/dist/acp-artifacts/binary.js.map +1 -0
- package/dist/acp-artifacts/index.d.ts +7 -0
- package/dist/acp-artifacts/index.d.ts.map +1 -0
- package/dist/acp-artifacts/index.js +7 -0
- package/dist/acp-artifacts/index.js.map +1 -0
- package/dist/acp-artifacts/node-abi.d.ts +3 -0
- package/dist/acp-artifacts/node-abi.d.ts.map +1 -0
- package/dist/acp-artifacts/node-abi.js +17 -0
- package/dist/acp-artifacts/node-abi.js.map +1 -0
- package/dist/acp-artifacts/npm-cli.d.ts +3 -0
- package/dist/acp-artifacts/npm-cli.d.ts.map +1 -0
- package/dist/acp-artifacts/npm-cli.js +9 -0
- package/dist/acp-artifacts/npm-cli.js.map +1 -0
- package/dist/acp-artifacts/npm.d.ts +37 -0
- package/dist/acp-artifacts/npm.d.ts.map +1 -0
- package/dist/acp-artifacts/npm.js +167 -0
- package/dist/acp-artifacts/npm.js.map +1 -0
- package/dist/acp-artifacts/registry.d.ts +45 -0
- package/dist/acp-artifacts/registry.d.ts.map +1 -0
- package/dist/acp-artifacts/registry.js +206 -0
- package/dist/acp-artifacts/registry.js.map +1 -0
- package/dist/acp-artifacts/shared.d.ts +45 -0
- package/dist/acp-artifacts/shared.d.ts.map +1 -0
- package/dist/acp-artifacts/shared.js +157 -0
- package/dist/acp-artifacts/shared.js.map +1 -0
- package/dist/acp-artifacts/uvx.d.ts +32 -0
- package/dist/acp-artifacts/uvx.d.ts.map +1 -0
- package/dist/acp-artifacts/uvx.js +95 -0
- package/dist/acp-artifacts/uvx.js.map +1 -0
- package/dist/acp-fork/index.d.ts +51 -0
- package/dist/acp-fork/index.d.ts.map +1 -0
- package/dist/acp-fork/index.js +116 -0
- package/dist/acp-fork/index.js.map +1 -0
- package/dist/acp-harnesses/agent-setup.d.ts +118 -0
- package/dist/acp-harnesses/agent-setup.d.ts.map +1 -0
- package/dist/acp-harnesses/agent-setup.js +717 -0
- package/dist/acp-harnesses/agent-setup.js.map +1 -0
- package/dist/acp-harnesses/custom-agents.d.ts +81 -0
- package/dist/acp-harnesses/custom-agents.d.ts.map +1 -0
- package/dist/acp-harnesses/custom-agents.js +361 -0
- package/dist/acp-harnesses/custom-agents.js.map +1 -0
- package/dist/acp-harnesses/headless-launch.d.ts +34 -0
- package/dist/acp-harnesses/headless-launch.d.ts.map +1 -0
- package/dist/acp-harnesses/headless-launch.js +67 -0
- package/dist/acp-harnesses/headless-launch.js.map +1 -0
- package/dist/acp-harnesses/index.d.ts +18 -0
- package/dist/acp-harnesses/index.d.ts.map +1 -0
- package/dist/acp-harnesses/index.js +58 -0
- package/dist/acp-harnesses/index.js.map +1 -0
- package/dist/acp-harnesses/install-state.d.ts +86 -0
- package/dist/acp-harnesses/install-state.d.ts.map +1 -0
- package/dist/acp-harnesses/install-state.js +322 -0
- package/dist/acp-harnesses/install-state.js.map +1 -0
- package/dist/acp-harnesses/installer.d.ts +145 -0
- package/dist/acp-harnesses/installer.d.ts.map +1 -0
- package/dist/acp-harnesses/installer.js +716 -0
- package/dist/acp-harnesses/installer.js.map +1 -0
- package/dist/acp-harnesses/known-agents.d.ts +154 -0
- package/dist/acp-harnesses/known-agents.d.ts.map +1 -0
- package/dist/acp-harnesses/known-agents.js +240 -0
- package/dist/acp-harnesses/known-agents.js.map +1 -0
- package/dist/acp-harnesses/launcher.d.ts +27 -0
- package/dist/acp-harnesses/launcher.d.ts.map +1 -0
- package/dist/acp-harnesses/launcher.js +64 -0
- package/dist/acp-harnesses/launcher.js.map +1 -0
- package/dist/acp-harnesses/registry-fetch.d.ts +42 -0
- package/dist/acp-harnesses/registry-fetch.d.ts.map +1 -0
- package/dist/acp-harnesses/registry-fetch.js +132 -0
- package/dist/acp-harnesses/registry-fetch.js.map +1 -0
- package/dist/acp-harnesses/registry.d.ts +36 -0
- package/dist/acp-harnesses/registry.d.ts.map +1 -0
- package/dist/acp-harnesses/registry.js +307 -0
- package/dist/acp-harnesses/registry.js.map +1 -0
- package/dist/acp-runtime/errors.d.ts +7 -0
- package/dist/acp-runtime/errors.d.ts.map +1 -0
- package/dist/acp-runtime/errors.js +17 -0
- package/dist/acp-runtime/errors.js.map +1 -0
- package/dist/acp-runtime/fork-support.d.ts +8 -0
- package/dist/acp-runtime/fork-support.d.ts.map +1 -0
- package/dist/acp-runtime/fork-support.js +20 -0
- package/dist/acp-runtime/fork-support.js.map +1 -0
- package/dist/acp-runtime/index.d.ts +11 -0
- package/dist/acp-runtime/index.d.ts.map +1 -0
- package/dist/acp-runtime/index.js +6 -0
- package/dist/acp-runtime/index.js.map +1 -0
- package/dist/acp-runtime/probe.d.ts +103 -0
- package/dist/acp-runtime/probe.d.ts.map +1 -0
- package/dist/acp-runtime/probe.js +872 -0
- package/dist/acp-runtime/probe.js.map +1 -0
- package/dist/acp-runtime/runtime.d.ts +7 -0
- package/dist/acp-runtime/runtime.d.ts.map +1 -0
- package/dist/acp-runtime/runtime.js +26 -0
- package/dist/acp-runtime/runtime.js.map +1 -0
- package/dist/acp-runtime/session.d.ts +87 -0
- package/dist/acp-runtime/session.d.ts.map +1 -0
- package/dist/acp-runtime/session.js +1071 -0
- package/dist/acp-runtime/session.js.map +1 -0
- package/dist/acp-runtime/spawners/node.d.ts +5 -0
- package/dist/acp-runtime/spawners/node.d.ts.map +1 -0
- package/dist/acp-runtime/spawners/node.js +244 -0
- package/dist/acp-runtime/spawners/node.js.map +1 -0
- package/dist/acp-runtime/types.d.ts +180 -0
- package/dist/acp-runtime/types.d.ts.map +1 -0
- package/dist/acp-runtime/types.js +2 -0
- package/dist/acp-runtime/types.js.map +1 -0
- package/dist/agent-contract/acp.d.ts +4 -0
- package/dist/agent-contract/acp.d.ts.map +1 -0
- package/dist/agent-contract/acp.js +273 -0
- package/dist/agent-contract/acp.js.map +1 -0
- package/dist/agent-contract/index.d.ts +125 -0
- package/dist/agent-contract/index.d.ts.map +1 -0
- package/dist/agent-contract/index.js +102 -0
- package/dist/agent-contract/index.js.map +1 -0
- package/dist/agent-contract/managed.d.ts +5 -0
- package/dist/agent-contract/managed.d.ts.map +1 -0
- package/dist/agent-contract/managed.js +242 -0
- package/dist/agent-contract/managed.js.map +1 -0
- package/dist/agent-ui/index.d.ts +170 -0
- package/dist/agent-ui/index.d.ts.map +1 -0
- package/dist/agent-ui/index.js +853 -0
- package/dist/agent-ui/index.js.map +1 -0
- package/dist/agent-ui/presentation.d.ts +30 -0
- package/dist/agent-ui/presentation.d.ts.map +1 -0
- package/dist/agent-ui/presentation.js +79 -0
- package/dist/agent-ui/presentation.js.map +1 -0
- package/dist/agent-ui/react.d.ts +50 -0
- package/dist/agent-ui/react.d.ts.map +1 -0
- package/dist/agent-ui/react.js +334 -0
- package/dist/agent-ui/react.js.map +1 -0
- package/dist/brand/index.d.ts +17 -0
- package/dist/brand/index.d.ts.map +1 -0
- package/dist/brand/index.js +119 -0
- package/dist/brand/index.js.map +1 -0
- package/dist/brand/openma-logo-mark.svg +7 -0
- package/dist/brand/tokens.css +77 -0
- package/dist/brand/website.css +67 -0
- package/dist/chat-ui/acp.d.ts +26 -0
- package/dist/chat-ui/acp.d.ts.map +1 -0
- package/dist/chat-ui/acp.js +166 -0
- package/dist/chat-ui/acp.js.map +1 -0
- package/dist/chat-ui/components.d.ts +230 -0
- package/dist/chat-ui/components.d.ts.map +1 -0
- package/dist/chat-ui/components.js +561 -0
- package/dist/chat-ui/components.js.map +1 -0
- package/dist/chat-ui/composer-drafts.d.ts +21 -0
- package/dist/chat-ui/composer-drafts.d.ts.map +1 -0
- package/dist/chat-ui/composer-drafts.js +58 -0
- package/dist/chat-ui/composer-drafts.js.map +1 -0
- package/dist/chat-ui/controller.d.ts +61 -0
- package/dist/chat-ui/controller.d.ts.map +1 -0
- package/dist/chat-ui/controller.js +218 -0
- package/dist/chat-ui/controller.js.map +1 -0
- package/dist/chat-ui/index.d.ts +8 -0
- package/dist/chat-ui/index.d.ts.map +1 -0
- package/dist/chat-ui/index.js +8 -0
- package/dist/chat-ui/index.js.map +1 -0
- package/dist/chat-ui/markdown.d.ts +37 -0
- package/dist/chat-ui/markdown.d.ts.map +1 -0
- package/dist/chat-ui/markdown.js +33 -0
- package/dist/chat-ui/markdown.js.map +1 -0
- package/dist/chat-ui/presentation.d.ts +34 -0
- package/dist/chat-ui/presentation.d.ts.map +1 -0
- package/dist/chat-ui/presentation.js +191 -0
- package/dist/chat-ui/presentation.js.map +1 -0
- package/dist/chat-ui/styles.css +815 -0
- package/dist/chat-ui/utils.d.ts +14 -0
- package/dist/chat-ui/utils.d.ts.map +1 -0
- package/dist/chat-ui/utils.js +71 -0
- package/dist/chat-ui/utils.js.map +1 -0
- package/dist/local-runtime/checkpoint.d.ts +28 -0
- package/dist/local-runtime/checkpoint.d.ts.map +1 -0
- package/dist/local-runtime/checkpoint.js +2 -0
- package/dist/local-runtime/checkpoint.js.map +1 -0
- package/dist/local-runtime/daemon-connection.d.ts +27 -0
- package/dist/local-runtime/daemon-connection.d.ts.map +1 -0
- package/dist/local-runtime/daemon-connection.js +161 -0
- package/dist/local-runtime/daemon-connection.js.map +1 -0
- package/dist/local-runtime/daemon-host.d.ts +39 -0
- package/dist/local-runtime/daemon-host.d.ts.map +1 -0
- package/dist/local-runtime/daemon-host.js +88 -0
- package/dist/local-runtime/daemon-host.js.map +1 -0
- package/dist/local-runtime/index.d.ts +6 -0
- package/dist/local-runtime/index.d.ts.map +1 -0
- package/dist/local-runtime/index.js +5 -0
- package/dist/local-runtime/index.js.map +1 -0
- package/dist/local-runtime/runtime.d.ts +36 -0
- package/dist/local-runtime/runtime.d.ts.map +1 -0
- package/dist/local-runtime/runtime.js +82 -0
- package/dist/local-runtime/runtime.js.map +1 -0
- package/dist/local-runtime/session-host.d.ts +62 -0
- package/dist/local-runtime/session-host.d.ts.map +1 -0
- package/dist/local-runtime/session-host.js +477 -0
- package/dist/local-runtime/session-host.js.map +1 -0
- package/dist/managed-runtime/acp-subagents.d.ts +14 -0
- package/dist/managed-runtime/acp-subagents.d.ts.map +1 -0
- package/dist/managed-runtime/acp-subagents.js +67 -0
- package/dist/managed-runtime/acp-subagents.js.map +1 -0
- package/dist/managed-runtime/claimed-environment-work.d.ts +61 -0
- package/dist/managed-runtime/claimed-environment-work.d.ts.map +1 -0
- package/dist/managed-runtime/claimed-environment-work.js +170 -0
- package/dist/managed-runtime/claimed-environment-work.js.map +1 -0
- package/dist/managed-runtime/contracts.d.ts +31 -0
- package/dist/managed-runtime/contracts.d.ts.map +1 -0
- package/dist/managed-runtime/contracts.js +2 -0
- package/dist/managed-runtime/contracts.js.map +1 -0
- package/dist/managed-runtime/http-control.d.ts +67 -0
- package/dist/managed-runtime/http-control.d.ts.map +1 -0
- package/dist/managed-runtime/http-control.js +465 -0
- package/dist/managed-runtime/http-control.js.map +1 -0
- package/dist/managed-runtime/index.d.ts +89 -0
- package/dist/managed-runtime/index.d.ts.map +1 -0
- package/dist/managed-runtime/index.js +215 -0
- package/dist/managed-runtime/index.js.map +1 -0
- package/dist/managed-runtime/input-identity.d.ts +2 -0
- package/dist/managed-runtime/input-identity.d.ts.map +1 -0
- package/dist/managed-runtime/input-identity.js +2 -0
- package/dist/managed-runtime/input-identity.js.map +1 -0
- package/dist/managed-runtime/managed-event-projector.d.ts +24 -0
- package/dist/managed-runtime/managed-event-projector.d.ts.map +1 -0
- package/dist/managed-runtime/managed-event-projector.js +333 -0
- package/dist/managed-runtime/managed-event-projector.js.map +1 -0
- package/dist/managed-runtime/semantic-recovery.d.ts +61 -0
- package/dist/managed-runtime/semantic-recovery.d.ts.map +1 -0
- package/dist/managed-runtime/semantic-recovery.js +167 -0
- package/dist/managed-runtime/semantic-recovery.js.map +1 -0
- package/dist/project-ui/CreateProjectDialog.d.ts +15 -0
- package/dist/project-ui/CreateProjectDialog.d.ts.map +1 -0
- package/dist/project-ui/CreateProjectDialog.js +87 -0
- package/dist/project-ui/CreateProjectDialog.js.map +1 -0
- package/dist/project-ui/ProjectComposer.d.ts +13 -0
- package/dist/project-ui/ProjectComposer.d.ts.map +1 -0
- package/dist/project-ui/ProjectComposer.js +70 -0
- package/dist/project-ui/ProjectComposer.js.map +1 -0
- package/dist/project-ui/ProjectConversation.d.ts +10 -0
- package/dist/project-ui/ProjectConversation.d.ts.map +1 -0
- package/dist/project-ui/ProjectConversation.js +28 -0
- package/dist/project-ui/ProjectConversation.js.map +1 -0
- package/dist/project-ui/ProjectMessageAttachments.d.ts +4 -0
- package/dist/project-ui/ProjectMessageAttachments.d.ts.map +1 -0
- package/dist/project-ui/ProjectMessageAttachments.js +28 -0
- package/dist/project-ui/ProjectMessageAttachments.js.map +1 -0
- package/dist/project-ui/ProjectSettings.d.ts +8 -0
- package/dist/project-ui/ProjectSettings.d.ts.map +1 -0
- package/dist/project-ui/ProjectSettings.js +65 -0
- package/dist/project-ui/ProjectSettings.js.map +1 -0
- package/dist/project-ui/Projects.d.ts +18 -0
- package/dist/project-ui/Projects.d.ts.map +1 -0
- package/dist/project-ui/Projects.js +377 -0
- package/dist/project-ui/Projects.js.map +1 -0
- package/dist/project-ui/client.d.ts +234 -0
- package/dist/project-ui/client.d.ts.map +1 -0
- package/dist/project-ui/client.js +42 -0
- package/dist/project-ui/client.js.map +1 -0
- package/dist/project-ui/controls.d.ts +15 -0
- package/dist/project-ui/controls.d.ts.map +1 -0
- package/dist/project-ui/controls.js +17 -0
- package/dist/project-ui/controls.js.map +1 -0
- package/dist/project-ui/index.d.ts +20 -0
- package/dist/project-ui/index.d.ts.map +1 -0
- package/dist/project-ui/index.js +17 -0
- package/dist/project-ui/index.js.map +1 -0
- package/dist/project-ui/project-coordinator.d.ts +3 -0
- package/dist/project-ui/project-coordinator.d.ts.map +1 -0
- package/dist/project-ui/project-coordinator.js +12 -0
- package/dist/project-ui/project-coordinator.js.map +1 -0
- package/dist/project-ui/project-goals.d.ts +48 -0
- package/dist/project-ui/project-goals.d.ts.map +1 -0
- package/dist/project-ui/project-goals.js +169 -0
- package/dist/project-ui/project-goals.js.map +1 -0
- package/dist/project-ui/projects-query.d.ts +19 -0
- package/dist/project-ui/projects-query.d.ts.map +1 -0
- package/dist/project-ui/projects-query.js +132 -0
- package/dist/project-ui/projects-query.js.map +1 -0
- package/dist/project-ui/styles.css +847 -0
- package/dist/protocol/acp/index.d.ts +52 -0
- package/dist/protocol/acp/index.d.ts.map +1 -0
- package/dist/protocol/acp/index.js +1056 -0
- package/dist/protocol/acp/index.js.map +1 -0
- package/dist/protocol/cursor-cloud/index.d.ts +74 -0
- package/dist/protocol/cursor-cloud/index.d.ts.map +1 -0
- package/dist/protocol/cursor-cloud/index.js +249 -0
- package/dist/protocol/cursor-cloud/index.js.map +1 -0
- package/dist/protocol/managed/index.d.ts +32 -0
- package/dist/protocol/managed/index.d.ts.map +1 -0
- package/dist/protocol/managed/index.js +646 -0
- package/dist/protocol/managed/index.js.map +1 -0
- package/dist/protocol/managed/input-identity.d.ts +3 -0
- package/dist/protocol/managed/input-identity.d.ts.map +1 -0
- package/dist/protocol/managed/input-identity.js +6 -0
- package/dist/protocol/managed/input-identity.js.map +1 -0
- package/dist/protocol/openai-agents/index.d.ts +102 -0
- package/dist/protocol/openai-agents/index.d.ts.map +1 -0
- package/dist/protocol/openai-agents/index.js +142 -0
- package/dist/protocol/openai-agents/index.js.map +1 -0
- package/dist/session-events/acp-system-notices.d.ts +10 -0
- package/dist/session-events/acp-system-notices.d.ts.map +1 -0
- package/dist/session-events/acp-system-notices.js +46 -0
- package/dist/session-events/acp-system-notices.js.map +1 -0
- package/dist/session-events/acp.d.ts +214 -0
- package/dist/session-events/acp.d.ts.map +1 -0
- package/dist/session-events/acp.js +956 -0
- package/dist/session-events/acp.js.map +1 -0
- package/dist/session-events/managed.d.ts +141 -0
- package/dist/session-events/managed.d.ts.map +1 -0
- package/dist/session-events/managed.js +324 -0
- package/dist/session-events/managed.js.map +1 -0
- package/dist/session-events/openma.d.ts +304 -0
- package/dist/session-events/openma.d.ts.map +1 -0
- package/dist/session-events/openma.js +438 -0
- package/dist/session-events/openma.js.map +1 -0
- package/dist/session-kernel/index.d.ts +118 -0
- package/dist/session-kernel/index.d.ts.map +1 -0
- package/dist/session-kernel/index.js +215 -0
- package/dist/session-kernel/index.js.map +1 -0
- package/dist/session-orchestrator/index.d.ts +71 -0
- package/dist/session-orchestrator/index.d.ts.map +1 -0
- package/dist/session-orchestrator/index.js +177 -0
- package/dist/session-orchestrator/index.js.map +1 -0
- package/dist/session-ui/index.d.ts +96 -0
- package/dist/session-ui/index.d.ts.map +1 -0
- package/dist/session-ui/index.js +277 -0
- package/dist/session-ui/index.js.map +1 -0
- package/package.json +222 -4
|
@@ -0,0 +1,717 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, delimiter, dirname, join } from "node:path";
|
|
4
|
+
import { detectEntry, getKnownAgents, loadRegistry, } from "./registry.js";
|
|
5
|
+
import { installAcpRegistryAgent, installManagedAdapter, latestNpmPackageVersion, npmPackageNameFromSpec, readAcpHarnessInstallState, repairRelocatedAcpRegistryShim, uninstallAcpRegistryAgent, uninstallManagedAdapter, usesOpenMaNpmLatestSource, } from "./installer.js";
|
|
6
|
+
import { authenticateAgent, disposeAllAcpProbes, probeAgentSessionConfig, probeAgentAuthStatus, } from "../acp-runtime/probe.js";
|
|
7
|
+
const NO_LIVE_PROBE_PLAN = {
|
|
8
|
+
trigger: "list",
|
|
9
|
+
refreshRegistry: false,
|
|
10
|
+
auth: { target: "ids", ids: [] },
|
|
11
|
+
capabilities: { target: "ids", ids: [] },
|
|
12
|
+
};
|
|
13
|
+
export function createAcpAgentSetupService(deps) {
|
|
14
|
+
return new AcpAgentSetupServiceImpl(deps);
|
|
15
|
+
}
|
|
16
|
+
class AcpAgentSetupServiceImpl {
|
|
17
|
+
deps;
|
|
18
|
+
nextOperationId = 1;
|
|
19
|
+
probeCachePromise = null;
|
|
20
|
+
probeCacheWrite = Promise.resolve();
|
|
21
|
+
authCache = new Map();
|
|
22
|
+
capabilityInspections = new Map();
|
|
23
|
+
constructor(deps) {
|
|
24
|
+
this.deps = deps;
|
|
25
|
+
}
|
|
26
|
+
dispose() {
|
|
27
|
+
return disposeAllAcpProbes();
|
|
28
|
+
}
|
|
29
|
+
async warmup() {
|
|
30
|
+
await this.repairRelocatedRegistryShims();
|
|
31
|
+
await this.collectAgentSnapshot({
|
|
32
|
+
trigger: "startup",
|
|
33
|
+
refreshRegistry: true,
|
|
34
|
+
auth: { target: "ids", ids: [] },
|
|
35
|
+
capabilities: { target: "detected" },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
async repairRelocatedRegistryShims() {
|
|
39
|
+
const entries = this.catalogEntries().filter((entry) => entry.installSource === "registry" && entry.registryId);
|
|
40
|
+
await Promise.all(entries.map(async (entry) => {
|
|
41
|
+
try {
|
|
42
|
+
await repairRelocatedAcpRegistryShim({
|
|
43
|
+
registryId: entry.registryId,
|
|
44
|
+
shimName: basename(entry.spec.command),
|
|
45
|
+
binDir: this.deps.acpBinDir,
|
|
46
|
+
installRoot: this.deps.acpInstallRoot,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (process.env.NODE_ENV !== "test") {
|
|
51
|
+
process.stderr.write(`! ACP shim repair skipped for ${entry.id}: ${errorMessage(error)}\n`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
async refreshEnabledAgents() {
|
|
57
|
+
const enabledAgentIds = this.deps.getEnabledAgentIds?.() ?? [];
|
|
58
|
+
return this.collectAgentSnapshot({
|
|
59
|
+
trigger: "manual",
|
|
60
|
+
refreshRegistry: true,
|
|
61
|
+
auth: { target: "ids", ids: enabledAgentIds },
|
|
62
|
+
capabilities: { target: "ids", ids: enabledAgentIds },
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async listAgents() {
|
|
66
|
+
return this.collectAgentSnapshot(NO_LIVE_PROBE_PLAN);
|
|
67
|
+
}
|
|
68
|
+
async collectAgentSnapshot(plan) {
|
|
69
|
+
const operationId = `setup-${this.nextOperationId++}`;
|
|
70
|
+
const operationStartedAt = Date.now();
|
|
71
|
+
await this.refreshRegistry({ refresh: plan.refreshRegistry });
|
|
72
|
+
const probeCache = await this.loadProbeCache();
|
|
73
|
+
const entries = this.catalogEntries();
|
|
74
|
+
const detected = (await Promise.all(entries.map((entry) => detectEntry(entry, this.resolveOptions()))))
|
|
75
|
+
.filter((entry) => entry !== null);
|
|
76
|
+
const detectedById = new Map(detected.map((agent) => [agent.id, agent]));
|
|
77
|
+
const authAgentIds = new Set(plan.auth.target === "ids" ? plan.auth.ids : []);
|
|
78
|
+
const capabilityAgentIds = new Set(plan.capabilities.target === "ids" ? plan.capabilities.ids : []);
|
|
79
|
+
const result = await Promise.all(entries.map(async (entry) => {
|
|
80
|
+
const detectedEntry = detectedById.get(entry.id);
|
|
81
|
+
const shouldProbeAuth = Boolean(detectedEntry) &&
|
|
82
|
+
(plan.auth.target === "detected" || authAgentIds.has(entry.id));
|
|
83
|
+
let auth = detectedEntry ? this.authCache.get(entry.id) : undefined;
|
|
84
|
+
const shouldProbeCapabilities = Boolean(detectedEntry) &&
|
|
85
|
+
(plan.capabilities.target === "detected"
|
|
86
|
+
|| capabilityAgentIds.has(entry.id));
|
|
87
|
+
let sessionConfig;
|
|
88
|
+
if (detectedEntry && shouldProbeCapabilities) {
|
|
89
|
+
const startedAt = Date.now();
|
|
90
|
+
let outcome = "settled";
|
|
91
|
+
let errorDetail;
|
|
92
|
+
logSetupOperation({
|
|
93
|
+
operationId,
|
|
94
|
+
trigger: plan.trigger,
|
|
95
|
+
scope: "full",
|
|
96
|
+
agentId: entry.id,
|
|
97
|
+
outcome: "started",
|
|
98
|
+
durationMs: 0,
|
|
99
|
+
});
|
|
100
|
+
try {
|
|
101
|
+
sessionConfig = await this.probeSessionConfig(detectedEntry);
|
|
102
|
+
auth = setupAuthFromProbeStatus(sessionConfig.auth);
|
|
103
|
+
if (auth) {
|
|
104
|
+
this.authCache.set(entry.id, auth);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
this.authCache.delete(entry.id);
|
|
108
|
+
}
|
|
109
|
+
this.capabilityInspections.set(entry.id, {
|
|
110
|
+
status: setupAuthBlocksCapabilities(auth)
|
|
111
|
+
? "blocked-auth"
|
|
112
|
+
: "ready",
|
|
113
|
+
inspected_at: new Date().toISOString(),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
outcome = "degraded";
|
|
118
|
+
errorDetail = errorMessage(error);
|
|
119
|
+
this.capabilityInspections.set(entry.id, {
|
|
120
|
+
status: "degraded",
|
|
121
|
+
error: errorDetail,
|
|
122
|
+
inspected_at: new Date().toISOString(),
|
|
123
|
+
});
|
|
124
|
+
// Keep the last confirmed state across a transient probe failure.
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
logSetupOperation({
|
|
128
|
+
operationId,
|
|
129
|
+
trigger: plan.trigger,
|
|
130
|
+
scope: "full",
|
|
131
|
+
agentId: entry.id,
|
|
132
|
+
outcome,
|
|
133
|
+
durationMs: Date.now() - startedAt,
|
|
134
|
+
...(errorDetail ? { detail: errorDetail } : {}),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else if (detectedEntry && shouldProbeAuth) {
|
|
139
|
+
const startedAt = Date.now();
|
|
140
|
+
let outcome = "settled";
|
|
141
|
+
logSetupOperation({
|
|
142
|
+
operationId,
|
|
143
|
+
trigger: plan.trigger,
|
|
144
|
+
scope: "auth",
|
|
145
|
+
agentId: entry.id,
|
|
146
|
+
outcome: "started",
|
|
147
|
+
durationMs: 0,
|
|
148
|
+
});
|
|
149
|
+
try {
|
|
150
|
+
auth = await this.probeAuth(detectedEntry);
|
|
151
|
+
if (auth) {
|
|
152
|
+
this.authCache.set(entry.id, auth);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
this.authCache.delete(entry.id);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
outcome = "degraded";
|
|
160
|
+
// Keep the last confirmed state across a transient probe failure.
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
logSetupOperation({
|
|
164
|
+
operationId,
|
|
165
|
+
trigger: plan.trigger,
|
|
166
|
+
scope: "auth",
|
|
167
|
+
agentId: entry.id,
|
|
168
|
+
outcome,
|
|
169
|
+
durationMs: Date.now() - startedAt,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const cachedProbe = detectedEntry ? probeCache[entry.id] : undefined;
|
|
174
|
+
if (!auth && cachedProbe?.auth) {
|
|
175
|
+
auth = cachedProbe.auth;
|
|
176
|
+
this.authCache.set(entry.id, auth);
|
|
177
|
+
}
|
|
178
|
+
const usableSessionConfig = sessionConfig && !setupAuthBlocksCapabilities(auth)
|
|
179
|
+
? sessionConfig
|
|
180
|
+
: undefined;
|
|
181
|
+
if (usableSessionConfig) {
|
|
182
|
+
await this.persistProbe(entry.id, {
|
|
183
|
+
config_options: usableSessionConfig.configOptions,
|
|
184
|
+
available_commands: usableSessionConfig.availableCommands,
|
|
185
|
+
...(usableSessionConfig.modes
|
|
186
|
+
? { session_modes: usableSessionConfig.modes }
|
|
187
|
+
: {}),
|
|
188
|
+
...(auth ? { auth } : {}),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
else if (auth && (shouldProbeAuth || shouldProbeCapabilities)) {
|
|
192
|
+
await this.persistProbe(entry.id, { auth });
|
|
193
|
+
}
|
|
194
|
+
const configOptions = usableSessionConfig?.configOptions ??
|
|
195
|
+
cachedProbe?.config_options ??
|
|
196
|
+
entry.configOptions;
|
|
197
|
+
const availableCommands = usableSessionConfig?.availableCommands ??
|
|
198
|
+
cachedProbe?.available_commands;
|
|
199
|
+
const sessionModes = usableSessionConfig?.modes ??
|
|
200
|
+
cachedProbe?.session_modes;
|
|
201
|
+
const installInfo = await readAcpHarnessInstallState({
|
|
202
|
+
entry,
|
|
203
|
+
binDir: this.deps.acpBinDir,
|
|
204
|
+
installRoot: this.deps.acpInstallRoot,
|
|
205
|
+
fetchImpl: this.deps.fetchImpl,
|
|
206
|
+
npmRegistryUrls: this.deps.npmRegistryUrls,
|
|
207
|
+
});
|
|
208
|
+
return {
|
|
209
|
+
id: entry.id,
|
|
210
|
+
label: entry.label,
|
|
211
|
+
...(entry.icon ? { icon: entry.icon } : {}),
|
|
212
|
+
command: detectedEntry?.spec.command ?? entry.spec.command,
|
|
213
|
+
installHint: entry.installHint,
|
|
214
|
+
homepage: entry.homepage,
|
|
215
|
+
featured: entry.featured,
|
|
216
|
+
detected: !!detectedEntry,
|
|
217
|
+
available: !!detectedEntry,
|
|
218
|
+
installed: installInfo.installed,
|
|
219
|
+
...(installInfo.installedVersion ? { installedVersion: installInfo.installedVersion } : {}),
|
|
220
|
+
...(installInfo.latestVersion ? { latestVersion: installInfo.latestVersion } : {}),
|
|
221
|
+
...(installInfo.updateAvailable ? { updateAvailable: true } : {}),
|
|
222
|
+
installable: !entry.custom && Boolean(entry.installSource || entry.downloadUrl || entry.install),
|
|
223
|
+
...(entry.installSource ? { installSource: entry.installSource } : {}),
|
|
224
|
+
...(entry.custom ? { custom: true } : {}),
|
|
225
|
+
...(auth ? { auth } : {}),
|
|
226
|
+
...(configOptions ? { config_options: configOptions } : {}),
|
|
227
|
+
...(availableCommands ? { available_commands: availableCommands } : {}),
|
|
228
|
+
...(sessionModes ? { session_modes: sessionModes } : {}),
|
|
229
|
+
...(detectedEntry && this.capabilityInspections.has(entry.id)
|
|
230
|
+
? {
|
|
231
|
+
capability_inspection: this.capabilityInspections.get(entry.id),
|
|
232
|
+
}
|
|
233
|
+
: {}),
|
|
234
|
+
};
|
|
235
|
+
}));
|
|
236
|
+
logSetupOperation({
|
|
237
|
+
operationId,
|
|
238
|
+
trigger: plan.trigger,
|
|
239
|
+
scope: "snapshot",
|
|
240
|
+
agentId: "*",
|
|
241
|
+
outcome: "settled",
|
|
242
|
+
durationMs: Date.now() - operationStartedAt,
|
|
243
|
+
});
|
|
244
|
+
return result;
|
|
245
|
+
}
|
|
246
|
+
async installAgent(id) {
|
|
247
|
+
await this.refreshRegistry({ refresh: true });
|
|
248
|
+
const entry = this.requireEntry(id);
|
|
249
|
+
const targetVersion = await this.resolveManagedInstallTargetVersion(entry);
|
|
250
|
+
await this.installEntry(entry, targetVersion);
|
|
251
|
+
return this.collectAgentSnapshot({
|
|
252
|
+
trigger: "install",
|
|
253
|
+
refreshRegistry: false,
|
|
254
|
+
auth: { target: "ids", ids: [id] },
|
|
255
|
+
capabilities: { target: "ids", ids: [id] },
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
async upgradeAgent(id) {
|
|
259
|
+
await this.refreshRegistry({ refresh: false });
|
|
260
|
+
const entry = this.requireEntry(id);
|
|
261
|
+
const installInfo = await readAcpHarnessInstallState({
|
|
262
|
+
entry,
|
|
263
|
+
binDir: this.deps.acpBinDir,
|
|
264
|
+
installRoot: this.deps.acpInstallRoot,
|
|
265
|
+
fetchImpl: this.deps.fetchImpl,
|
|
266
|
+
npmRegistryUrls: this.deps.npmRegistryUrls,
|
|
267
|
+
});
|
|
268
|
+
if (!installInfo.installed) {
|
|
269
|
+
throw new Error(`${entry.label} is not installed by ${this.managedByName()}`);
|
|
270
|
+
}
|
|
271
|
+
const targetVersion = await this.resolveManagedInstallTargetVersion(entry, installInfo.latestVersion);
|
|
272
|
+
await this.installEntry(entry, targetVersion);
|
|
273
|
+
return this.collectAgentSnapshot({
|
|
274
|
+
trigger: "update",
|
|
275
|
+
refreshRegistry: false,
|
|
276
|
+
auth: { target: "ids", ids: [id] },
|
|
277
|
+
capabilities: { target: "ids", ids: [id] },
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
async resolveManagedInstallTargetVersion(entry, registryLatestVersion) {
|
|
281
|
+
if (usesOpenMaNpmLatestSource(entry) && entry.registryDistribution?.npx) {
|
|
282
|
+
const packageName = npmPackageNameFromSpec(entry.registryDistribution.npx.package);
|
|
283
|
+
const latest = await latestNpmPackageVersion(packageName, {
|
|
284
|
+
fetchImpl: this.deps.fetchImpl,
|
|
285
|
+
npmRegistryUrls: this.deps.npmRegistryUrls,
|
|
286
|
+
});
|
|
287
|
+
if (!latest) {
|
|
288
|
+
throw new Error(`Could not resolve npm latest version for ${packageName}`);
|
|
289
|
+
}
|
|
290
|
+
return latest;
|
|
291
|
+
}
|
|
292
|
+
return registryLatestVersion ?? entry.version;
|
|
293
|
+
}
|
|
294
|
+
async installEntry(entry, targetVersion) {
|
|
295
|
+
if (entry.installSource === "registry") {
|
|
296
|
+
if (!entry.registryId)
|
|
297
|
+
throw new Error(`${entry.label} is missing an ACP registry id`);
|
|
298
|
+
const registryDistribution = targetVersion && entry.registryDistribution?.npx
|
|
299
|
+
? {
|
|
300
|
+
...entry.registryDistribution,
|
|
301
|
+
npx: {
|
|
302
|
+
...entry.registryDistribution.npx,
|
|
303
|
+
package: `${npmPackageNameFromSpec(entry.registryDistribution.npx.package)}@${targetVersion}`,
|
|
304
|
+
},
|
|
305
|
+
}
|
|
306
|
+
: entry.registryDistribution;
|
|
307
|
+
await installAcpRegistryAgent({
|
|
308
|
+
registryId: entry.registryId,
|
|
309
|
+
...(registryDistribution ? {
|
|
310
|
+
registryAgent: {
|
|
311
|
+
id: entry.registryId,
|
|
312
|
+
name: entry.label,
|
|
313
|
+
...(targetVersion
|
|
314
|
+
? { version: targetVersion }
|
|
315
|
+
: entry.version
|
|
316
|
+
? { version: entry.version }
|
|
317
|
+
: {}),
|
|
318
|
+
distribution: registryDistribution,
|
|
319
|
+
},
|
|
320
|
+
} : {}),
|
|
321
|
+
shimName: basename(entry.spec.command),
|
|
322
|
+
binDir: this.deps.acpBinDir,
|
|
323
|
+
installRoot: this.deps.acpInstallRoot,
|
|
324
|
+
fetchImpl: this.deps.fetchImpl,
|
|
325
|
+
npmCommand: this.deps.npmCommand,
|
|
326
|
+
npmCommandArgs: this.deps.npmCommandArgs,
|
|
327
|
+
npmEnv: this.deps.npmEnv,
|
|
328
|
+
npmRegistryUrls: this.deps.npmRegistryUrls,
|
|
329
|
+
shimArgs: entry.spec.args,
|
|
330
|
+
shimEnv: entry.spec.env,
|
|
331
|
+
env: this.spawnEnv(),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
else if (entry.installSource === "adapter" && entry.downloadUrl) {
|
|
335
|
+
await installManagedAdapter({
|
|
336
|
+
id: entry.id,
|
|
337
|
+
label: entry.label,
|
|
338
|
+
command: entry.spec.command,
|
|
339
|
+
args: entry.spec.args,
|
|
340
|
+
downloadUrl: entry.downloadUrl,
|
|
341
|
+
binDir: this.deps.acpBinDir,
|
|
342
|
+
fetchImpl: this.deps.fetchImpl,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
throw new Error(`${entry.label} is not installable from ${this.managedByName()}`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
async uninstallAgent(id) {
|
|
350
|
+
await this.refreshRegistry({ refresh: true });
|
|
351
|
+
const entry = this.requireEntry(id);
|
|
352
|
+
if (entry.installSource === "registry") {
|
|
353
|
+
if (!entry.registryId)
|
|
354
|
+
throw new Error(`${entry.label} is missing an ACP registry id`);
|
|
355
|
+
await uninstallAcpRegistryAgent({
|
|
356
|
+
registryId: entry.registryId,
|
|
357
|
+
shimName: basename(entry.spec.command),
|
|
358
|
+
binDir: this.deps.acpBinDir,
|
|
359
|
+
installRoot: this.deps.acpInstallRoot,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
else if (entry.installSource === "adapter") {
|
|
363
|
+
await uninstallManagedAdapter({
|
|
364
|
+
command: entry.spec.command,
|
|
365
|
+
binDir: this.deps.acpBinDir,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
throw new Error(`${entry.label} is not managed by ${this.managedByName()}`);
|
|
370
|
+
}
|
|
371
|
+
this.authCache.delete(id);
|
|
372
|
+
return this.collectAgentSnapshot({
|
|
373
|
+
...NO_LIVE_PROBE_PLAN,
|
|
374
|
+
trigger: "uninstall",
|
|
375
|
+
refreshRegistry: true,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
async authenticateAgent(id, options = {}) {
|
|
379
|
+
await this.refreshRegistry({ refresh: false });
|
|
380
|
+
const entry = await this.detectCatalogEntry(id);
|
|
381
|
+
if (!entry)
|
|
382
|
+
throw new Error(`ACP agent is not available: ${id}`);
|
|
383
|
+
const result = await authenticateAgent({
|
|
384
|
+
agent: entry.spec,
|
|
385
|
+
env: this.spawnEnv(),
|
|
386
|
+
...(this.deps.probeCwd ? { cwd: this.deps.probeCwd } : {}),
|
|
387
|
+
timeoutMs: 120_000,
|
|
388
|
+
agentAuthLaunchGraceMs: 2_000,
|
|
389
|
+
backgroundAuthTimeoutMs: 10 * 60_000,
|
|
390
|
+
methodId: options.methodId,
|
|
391
|
+
...(options.secret ? { secret: options.secret } : {}),
|
|
392
|
+
...(options.values ? { values: options.values } : {}),
|
|
393
|
+
...(options.gateway ? { gateway: options.gateway } : {}),
|
|
394
|
+
launchInteractiveAuth: this.deps.launchInteractiveAuth,
|
|
395
|
+
});
|
|
396
|
+
if (result.status === "completed") {
|
|
397
|
+
const existing = this.authCache.get(id);
|
|
398
|
+
const auth = {
|
|
399
|
+
status: "configured",
|
|
400
|
+
message: "Authentication completed",
|
|
401
|
+
...(options.methodId
|
|
402
|
+
? { methodId: options.methodId }
|
|
403
|
+
: existing?.methodId
|
|
404
|
+
? { methodId: existing.methodId }
|
|
405
|
+
: {}),
|
|
406
|
+
...(existing?.methodName ? { methodName: existing.methodName } : {}),
|
|
407
|
+
...(existing?.methods ? { methods: existing.methods } : {}),
|
|
408
|
+
};
|
|
409
|
+
this.authCache.set(id, auth);
|
|
410
|
+
await this.persistProbe(id, { auth });
|
|
411
|
+
}
|
|
412
|
+
// Authentication is an explicit lifecycle of its own. Do not follow it
|
|
413
|
+
// with another disposable ACP probe; the next real session is the source
|
|
414
|
+
// of truth if a browser/terminal flow is still finishing.
|
|
415
|
+
return this.listAgents();
|
|
416
|
+
}
|
|
417
|
+
async observeAuth(id, observation) {
|
|
418
|
+
const auth = mergeObservedAuth(this.authCache.get(id), observation);
|
|
419
|
+
this.authCache.set(id, auth);
|
|
420
|
+
await this.persistProbe(id, { auth });
|
|
421
|
+
return auth;
|
|
422
|
+
}
|
|
423
|
+
async observeSessionConfig(id, snapshot) {
|
|
424
|
+
await this.persistProbe(id, snapshot);
|
|
425
|
+
}
|
|
426
|
+
async refreshRegistry(options) {
|
|
427
|
+
if (this.deps.refreshRegistry) {
|
|
428
|
+
await this.deps.refreshRegistry({ refresh: options.refresh });
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
await loadRegistry({
|
|
432
|
+
cachePath: this.deps.registryCachePath,
|
|
433
|
+
forceRefresh: options.refresh === true,
|
|
434
|
+
cacheOnly: options.refresh !== true,
|
|
435
|
+
}).catch(() => undefined);
|
|
436
|
+
}
|
|
437
|
+
resolveOptions() {
|
|
438
|
+
return {
|
|
439
|
+
env: this.spawnEnv(),
|
|
440
|
+
managedBinDirs: [this.deps.acpBinDir],
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
spawnEnv() {
|
|
444
|
+
const path = [this.deps.acpBinDir, process.env.PATH].filter(Boolean).join(delimiter);
|
|
445
|
+
return {
|
|
446
|
+
...process.env,
|
|
447
|
+
...this.deps.env,
|
|
448
|
+
// A setup probe is a fresh harness process. Do not let a parent Claude
|
|
449
|
+
// session make the child believe it is already running inside one.
|
|
450
|
+
CLAUDECODE: undefined,
|
|
451
|
+
CLAUDE_CODE_ENTRYPOINT: undefined,
|
|
452
|
+
CLAUDE_CODE_SSE_PORT: undefined,
|
|
453
|
+
OPENMA_ACP_BIN_DIR: this.deps.acpBinDir,
|
|
454
|
+
PATH: path,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
requireEntry(id) {
|
|
458
|
+
const entry = this.catalogEntries().find((candidate) => candidate.id === id);
|
|
459
|
+
if (!entry)
|
|
460
|
+
throw new Error(`Unknown ACP agent: ${id}`);
|
|
461
|
+
return entry;
|
|
462
|
+
}
|
|
463
|
+
catalogEntries() {
|
|
464
|
+
return catalogEntriesWithOverrides(getKnownAgents(), this.deps.agentOverrides?.() ?? []);
|
|
465
|
+
}
|
|
466
|
+
async detectCatalogEntry(id) {
|
|
467
|
+
const entry = this.catalogEntries().find((candidate) => candidate.id === id);
|
|
468
|
+
if (!entry)
|
|
469
|
+
return null;
|
|
470
|
+
return await detectEntry(entry, this.resolveOptions());
|
|
471
|
+
}
|
|
472
|
+
async probeAuth(entry) {
|
|
473
|
+
const status = await probeAgentAuthStatus({
|
|
474
|
+
agent: entry.spec,
|
|
475
|
+
env: this.spawnEnv(),
|
|
476
|
+
...(this.deps.probeCwd ? { cwd: this.deps.probeCwd } : {}),
|
|
477
|
+
timeoutMs: this.deps.authInspectionTimeoutMs ?? 15_000,
|
|
478
|
+
});
|
|
479
|
+
return setupAuthFromProbeStatus(status);
|
|
480
|
+
}
|
|
481
|
+
async probeSessionConfig(entry) {
|
|
482
|
+
return probeAgentSessionConfig({
|
|
483
|
+
agent: entry.spec,
|
|
484
|
+
env: this.spawnEnv(),
|
|
485
|
+
...(this.deps.probeCwd ? { cwd: this.deps.probeCwd } : {}),
|
|
486
|
+
timeoutMs: this.deps.capabilityInspectionTimeoutMs ?? 90_000,
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
probeCachePath() {
|
|
490
|
+
return this.deps.probeCachePath ??
|
|
491
|
+
join(dirname(this.deps.registryCachePath), "agent-probe-cache.json");
|
|
492
|
+
}
|
|
493
|
+
loadProbeCache() {
|
|
494
|
+
if (this.probeCachePromise)
|
|
495
|
+
return this.probeCachePromise;
|
|
496
|
+
this.probeCachePromise = readFile(this.probeCachePath(), "utf8")
|
|
497
|
+
.then((raw) => parseProbeCache(raw))
|
|
498
|
+
.catch(() => ({}));
|
|
499
|
+
return this.probeCachePromise;
|
|
500
|
+
}
|
|
501
|
+
async persistProbe(id, patch) {
|
|
502
|
+
const cache = await this.loadProbeCache();
|
|
503
|
+
const prev = cache[id];
|
|
504
|
+
cache[id] = {
|
|
505
|
+
config_options: patch.config_options ?? prev?.config_options ?? [],
|
|
506
|
+
available_commands: patch.available_commands ?? prev?.available_commands ?? [],
|
|
507
|
+
...(patch.session_modes !== undefined
|
|
508
|
+
? { session_modes: patch.session_modes }
|
|
509
|
+
: prev?.session_modes
|
|
510
|
+
? { session_modes: prev.session_modes }
|
|
511
|
+
: {}),
|
|
512
|
+
...(patch.auth ? { auth: patch.auth } : prev?.auth ? { auth: prev.auth } : {}),
|
|
513
|
+
updated_at: new Date().toISOString(),
|
|
514
|
+
};
|
|
515
|
+
const path = this.probeCachePath();
|
|
516
|
+
const tempPath = `${path}.tmp-${process.pid}`;
|
|
517
|
+
const serialized = JSON.stringify({ version: 1, agents: cache }, null, 2);
|
|
518
|
+
const write = async () => {
|
|
519
|
+
await mkdir(dirname(path), { recursive: true });
|
|
520
|
+
await writeFile(tempPath, serialized, "utf8");
|
|
521
|
+
await rename(tempPath, path);
|
|
522
|
+
};
|
|
523
|
+
this.probeCacheWrite = this.probeCacheWrite.then(write, write);
|
|
524
|
+
await this.probeCacheWrite;
|
|
525
|
+
}
|
|
526
|
+
managedByName() {
|
|
527
|
+
return this.deps.managedByName?.trim() || "this host";
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function parseProbeCache(raw) {
|
|
531
|
+
const parsed = JSON.parse(raw);
|
|
532
|
+
if (parsed.version !== 1 || !parsed.agents || typeof parsed.agents !== "object") {
|
|
533
|
+
return {};
|
|
534
|
+
}
|
|
535
|
+
return Object.fromEntries(Object.entries(parsed.agents).flatMap(([id, value]) => Array.isArray(value.config_options) && Array.isArray(value.available_commands)
|
|
536
|
+
? [[id, {
|
|
537
|
+
config_options: value.config_options,
|
|
538
|
+
available_commands: value.available_commands,
|
|
539
|
+
...(value.session_modes ? { session_modes: value.session_modes } : {}),
|
|
540
|
+
...(value.auth ? { auth: value.auth } : {}),
|
|
541
|
+
updated_at: typeof value.updated_at === "string" ? value.updated_at : "",
|
|
542
|
+
}]]
|
|
543
|
+
: value.auth
|
|
544
|
+
? [[id, {
|
|
545
|
+
config_options: Array.isArray(value.config_options) ? value.config_options : [],
|
|
546
|
+
available_commands: Array.isArray(value.available_commands)
|
|
547
|
+
? value.available_commands
|
|
548
|
+
: [],
|
|
549
|
+
...(value.session_modes ? { session_modes: value.session_modes } : {}),
|
|
550
|
+
auth: value.auth,
|
|
551
|
+
updated_at: typeof value.updated_at === "string" ? value.updated_at : "",
|
|
552
|
+
}]]
|
|
553
|
+
: []));
|
|
554
|
+
}
|
|
555
|
+
function catalogEntriesWithOverrides(entries, overrides) {
|
|
556
|
+
const overrideById = new Map(overrides.map((override) => [override.id, override]));
|
|
557
|
+
const knownIds = new Set(entries.map((entry) => entry.id));
|
|
558
|
+
const merged = entries.map((entry) => applyAgentOverride(entry, overrideById.get(entry.id)));
|
|
559
|
+
for (const override of overrides) {
|
|
560
|
+
if (knownIds.has(override.id))
|
|
561
|
+
continue;
|
|
562
|
+
const command = override.command?.trim();
|
|
563
|
+
if (!command)
|
|
564
|
+
continue;
|
|
565
|
+
const env = overrideEnv(override);
|
|
566
|
+
merged.push({
|
|
567
|
+
id: override.id,
|
|
568
|
+
label: override.label?.trim() || override.id,
|
|
569
|
+
spec: {
|
|
570
|
+
command,
|
|
571
|
+
...(override.args ? { args: [...override.args] } : {}),
|
|
572
|
+
...(env ? { env } : {}),
|
|
573
|
+
},
|
|
574
|
+
custom: true,
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
return merged;
|
|
578
|
+
}
|
|
579
|
+
function applyAgentOverride(entry, override) {
|
|
580
|
+
if (!override)
|
|
581
|
+
return entry;
|
|
582
|
+
const env = {
|
|
583
|
+
...(entry.spec.env ?? {}),
|
|
584
|
+
...(overrideEnv(override) ?? {}),
|
|
585
|
+
};
|
|
586
|
+
return {
|
|
587
|
+
...entry,
|
|
588
|
+
...(override.label?.trim() ? { label: override.label.trim() } : {}),
|
|
589
|
+
spec: {
|
|
590
|
+
...entry.spec,
|
|
591
|
+
...(override.command?.trim() ? { command: override.command.trim() } : {}),
|
|
592
|
+
...(override.args ? { args: [...override.args] } : {}),
|
|
593
|
+
...(Object.keys(env).length > 0 ? { env } : {}),
|
|
594
|
+
},
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
function overrideEnv(override) {
|
|
598
|
+
if (!override.env)
|
|
599
|
+
return undefined;
|
|
600
|
+
const entries = Array.isArray(override.env)
|
|
601
|
+
? override.env
|
|
602
|
+
.filter((item) => item.name.length > 0)
|
|
603
|
+
.map((item) => [item.name, item.value])
|
|
604
|
+
: Object.entries(override.env)
|
|
605
|
+
.filter((entry) => entry[0].length > 0 && typeof entry[1] === "string");
|
|
606
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
607
|
+
}
|
|
608
|
+
function mergeObservedAuth(existing, observation) {
|
|
609
|
+
const methodId = observation.methodId ?? existing?.methodId;
|
|
610
|
+
const prefix = observation.status === "configured"
|
|
611
|
+
? methodId ? `ACP auth is configured (${methodId}).` : "ACP auth is configured."
|
|
612
|
+
: observation.status === "needs-auth"
|
|
613
|
+
? methodId ? `Authentication required (${methodId}).` : "Authentication required."
|
|
614
|
+
: "Could not verify auth.";
|
|
615
|
+
return {
|
|
616
|
+
status: observation.status,
|
|
617
|
+
message: observation.message ?? prefix,
|
|
618
|
+
...(methodId ? { methodId } : {}),
|
|
619
|
+
...(existing?.methodName ? { methodName: existing.methodName } : {}),
|
|
620
|
+
...(existing?.methods ? { methods: existing.methods } : {}),
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
function setupAuthFromProbeStatus(status) {
|
|
624
|
+
if (status.status === "none")
|
|
625
|
+
return undefined;
|
|
626
|
+
const method = status.methodName ?? status.methodId;
|
|
627
|
+
const prefix = status.status === "configured"
|
|
628
|
+
? method ? `ACP auth is configured (${method}).` : "ACP auth is configured."
|
|
629
|
+
: status.status === "needs-auth"
|
|
630
|
+
? method ? `Authentication required (${method}).` : "Authentication required."
|
|
631
|
+
: "Could not verify auth.";
|
|
632
|
+
return {
|
|
633
|
+
status: status.status,
|
|
634
|
+
message: status.message ? `${prefix} ${status.message}` : prefix,
|
|
635
|
+
...(status.methodId ? { methodId: status.methodId } : {}),
|
|
636
|
+
...(status.methodName ? { methodName: status.methodName } : {}),
|
|
637
|
+
...(status.methods ? { methods: status.methods.map((methodInfo) => ({
|
|
638
|
+
id: methodInfo.id,
|
|
639
|
+
...(methodInfo.name ? { name: methodInfo.name } : {}),
|
|
640
|
+
...(methodInfo.description ? { description: methodInfo.description } : {}),
|
|
641
|
+
...(methodInfo.type ? { type: methodInfo.type } : {}),
|
|
642
|
+
...(methodInfo.form ? { form: methodInfo.form } : {}),
|
|
643
|
+
...(methodInfo.vars ? { vars: methodInfo.vars } : {}),
|
|
644
|
+
...(methodInfo.link ? { link: methodInfo.link } : {}),
|
|
645
|
+
})) } : {}),
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
function setupAuthBlocksCapabilities(auth) {
|
|
649
|
+
return auth?.status === "needs-auth" || auth?.status === "unknown";
|
|
650
|
+
}
|
|
651
|
+
function logSetupOperation(fields) {
|
|
652
|
+
if (process.env.NODE_ENV === "test")
|
|
653
|
+
return;
|
|
654
|
+
const detail = fields.detail
|
|
655
|
+
? ` error=${JSON.stringify(fields.detail.replace(/\s+/g, " ").slice(0, 500))}`
|
|
656
|
+
: "";
|
|
657
|
+
process.stderr.write(`[agent-lifecycle] op=${fields.operationId} trigger=${fields.trigger} scope=${fields.scope} agent=${fields.agentId} outcome=${fields.outcome} total_ms=${fields.durationMs}${detail}\n`);
|
|
658
|
+
}
|
|
659
|
+
function errorMessage(error) {
|
|
660
|
+
return error instanceof Error ? error.message : String(error);
|
|
661
|
+
}
|
|
662
|
+
export function launchTerminalAuth(options, launchOptions = {}) {
|
|
663
|
+
const shellCommand = terminalAuthShellCommand(options, launchOptions.returnInstruction);
|
|
664
|
+
if (process.platform === "darwin") {
|
|
665
|
+
return spawnDetached("osascript", [
|
|
666
|
+
"-e", `tell application "Terminal"`,
|
|
667
|
+
"-e", "activate",
|
|
668
|
+
"-e", `do script ${JSON.stringify(shellCommand)}`,
|
|
669
|
+
"-e", "end tell",
|
|
670
|
+
], options.env);
|
|
671
|
+
}
|
|
672
|
+
const terminal = process.platform === "win32" ? null : (process.env.TERMINAL || "x-terminal-emulator");
|
|
673
|
+
if (!terminal) {
|
|
674
|
+
throw new Error(`Interactive auth launch is not supported on ${process.platform}. Run ${[options.command, ...options.args].join(" ")} manually.`);
|
|
675
|
+
}
|
|
676
|
+
return spawnDetached(terminal, ["-e", "sh", "-lc", shellCommand], options.env);
|
|
677
|
+
}
|
|
678
|
+
function spawnDetached(command, args, env) {
|
|
679
|
+
return new Promise((resolve, reject) => {
|
|
680
|
+
const child = spawn(command, args, {
|
|
681
|
+
env: {
|
|
682
|
+
...process.env,
|
|
683
|
+
...Object.fromEntries(Object.entries(env ?? {}).filter((entry) => typeof entry[1] === "string")),
|
|
684
|
+
},
|
|
685
|
+
detached: true,
|
|
686
|
+
stdio: "ignore",
|
|
687
|
+
});
|
|
688
|
+
child.once("error", reject);
|
|
689
|
+
child.once("spawn", () => {
|
|
690
|
+
child.unref();
|
|
691
|
+
resolve();
|
|
692
|
+
});
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
function terminalAuthShellCommand(options, returnInstruction) {
|
|
696
|
+
const parts = [];
|
|
697
|
+
if (options.cwd) {
|
|
698
|
+
parts.push("cd", shellQuote(options.cwd), "&&");
|
|
699
|
+
}
|
|
700
|
+
const envEntries = Object.entries(options.env ?? {})
|
|
701
|
+
.filter((entry) => typeof entry[1] === "string" && entry[0].length > 0);
|
|
702
|
+
if (envEntries.length > 0) {
|
|
703
|
+
parts.push("env");
|
|
704
|
+
for (const [key, value] of envEntries)
|
|
705
|
+
parts.push(`${key}=${shellQuote(value)}`);
|
|
706
|
+
}
|
|
707
|
+
parts.push(shellQuote(options.command), ...options.args.map(shellQuote));
|
|
708
|
+
if (returnInstruction?.trim()) {
|
|
709
|
+
parts.push(";");
|
|
710
|
+
parts.push("printf", shellQuote(`\\n${returnInstruction.trim()}\\n`));
|
|
711
|
+
}
|
|
712
|
+
return parts.join(" ");
|
|
713
|
+
}
|
|
714
|
+
function shellQuote(value) {
|
|
715
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
716
|
+
}
|
|
717
|
+
//# sourceMappingURL=agent-setup.js.map
|