@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,872 @@
|
|
|
1
|
+
import { ClientSideConnection, ndJsonStream, PROTOCOL_VERSION, } from "@agentclientprotocol/sdk";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { mkdir } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { isAuthenticationRequiredError } from "./errors.js";
|
|
7
|
+
import { NodeSpawner } from "./spawners/node.js";
|
|
8
|
+
const ACP_CLIENT_CAPABILITIES = {
|
|
9
|
+
fs: { readTextFile: true, writeTextFile: true },
|
|
10
|
+
terminal: true,
|
|
11
|
+
auth: { terminal: true, _meta: { gateway: true } },
|
|
12
|
+
_meta: { "terminal-auth": true, terminal_output: true },
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Disposable capability probe used during product cold start. It deliberately
|
|
16
|
+
* never returns the child as a real session: callers must start a fresh ACP
|
|
17
|
+
* session after consuming this snapshot.
|
|
18
|
+
*/
|
|
19
|
+
export async function probeAcpSession(options) {
|
|
20
|
+
const cwd = options.cwd ?? join(tmpdir(), "openma-acp-probe");
|
|
21
|
+
await mkdir(cwd, { recursive: true });
|
|
22
|
+
let configOptions = [];
|
|
23
|
+
let availableCommands = [];
|
|
24
|
+
let currentModeId;
|
|
25
|
+
let resolveCommands;
|
|
26
|
+
const commandsReady = new Promise((resolve) => {
|
|
27
|
+
resolveCommands = resolve;
|
|
28
|
+
});
|
|
29
|
+
const client = {
|
|
30
|
+
sessionUpdate: async (params) => {
|
|
31
|
+
const update = asRecord(params.update);
|
|
32
|
+
if (!update)
|
|
33
|
+
return;
|
|
34
|
+
if (update.sessionUpdate === "config_option_update" && Array.isArray(update.configOptions)) {
|
|
35
|
+
configOptions = update.configOptions.map((option) => structuredClone(option));
|
|
36
|
+
}
|
|
37
|
+
if (update.sessionUpdate === "available_commands_update") {
|
|
38
|
+
const commands = Array.isArray(update.availableCommands)
|
|
39
|
+
? update.availableCommands
|
|
40
|
+
: Array.isArray(update.available_commands)
|
|
41
|
+
? update.available_commands
|
|
42
|
+
: undefined;
|
|
43
|
+
if (commands) {
|
|
44
|
+
availableCommands = commands.map((command) => structuredClone(command));
|
|
45
|
+
resolveCommands?.();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (update.sessionUpdate === "current_mode_update" && typeof update.currentModeId === "string") {
|
|
49
|
+
currentModeId = update.currentModeId;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
|
|
53
|
+
};
|
|
54
|
+
const connection = await spawnProbeAgent({
|
|
55
|
+
agent: options.agent,
|
|
56
|
+
cwd,
|
|
57
|
+
env: options.env,
|
|
58
|
+
spawner: options.spawner,
|
|
59
|
+
client,
|
|
60
|
+
});
|
|
61
|
+
const timeoutMs = Math.max(1, options.timeoutMs ?? 15_000);
|
|
62
|
+
const settleMs = Math.max(0, options.capabilitySettleMs ?? 750);
|
|
63
|
+
try {
|
|
64
|
+
return await withTimeout((async () => {
|
|
65
|
+
const initialized = await Promise.resolve(connection.agent.initialize({
|
|
66
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
67
|
+
clientCapabilities: ACP_CLIENT_CAPABILITIES,
|
|
68
|
+
}));
|
|
69
|
+
const created = await Promise.resolve(connection.agent.newSession({
|
|
70
|
+
cwd,
|
|
71
|
+
mcpServers: [],
|
|
72
|
+
}));
|
|
73
|
+
await waitForSignalOrTimeout(commandsReady, settleMs);
|
|
74
|
+
const responseOptions = Array.isArray(created.configOptions)
|
|
75
|
+
? created.configOptions.map((option) => structuredClone(option))
|
|
76
|
+
: [];
|
|
77
|
+
const responseModes = created.modes ? structuredClone(created.modes) : null;
|
|
78
|
+
return {
|
|
79
|
+
sessionId: created.sessionId,
|
|
80
|
+
configOptions: responseOptions.length > 0 ? responseOptions : configOptions,
|
|
81
|
+
availableCommands,
|
|
82
|
+
modes: responseModes
|
|
83
|
+
? (currentModeId ? { ...responseModes, currentModeId } : responseModes)
|
|
84
|
+
: null,
|
|
85
|
+
authMethods: Array.isArray(initialized.authMethods)
|
|
86
|
+
? initialized.authMethods.map((method) => structuredClone(method))
|
|
87
|
+
: [],
|
|
88
|
+
};
|
|
89
|
+
})(), timeoutMs, `ACP capability probe timed out after ${timeoutMs}ms`);
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
await connection.dispose();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Disposable session/capability probe that also reports auth status from the same child. */
|
|
96
|
+
export async function probeAgentSessionConfig(options) {
|
|
97
|
+
const cwd = options.cwd ?? join(tmpdir(), "openma-acp-probe");
|
|
98
|
+
await mkdir(cwd, { recursive: true });
|
|
99
|
+
let updatedConfigOptions = [];
|
|
100
|
+
let updatedAvailableCommands = [];
|
|
101
|
+
let updatedModeId = null;
|
|
102
|
+
let resolveAvailableCommands = null;
|
|
103
|
+
const availableCommandsReady = new Promise((resolve) => {
|
|
104
|
+
resolveAvailableCommands = resolve;
|
|
105
|
+
});
|
|
106
|
+
const client = {
|
|
107
|
+
sessionUpdate: async (params) => {
|
|
108
|
+
const next = configOptionsFromSessionUpdate(params.update);
|
|
109
|
+
if (next)
|
|
110
|
+
updatedConfigOptions = next;
|
|
111
|
+
const commands = availableCommandsFromSessionUpdate(params.update);
|
|
112
|
+
if (commands) {
|
|
113
|
+
updatedAvailableCommands = commands;
|
|
114
|
+
resolveAvailableCommands?.();
|
|
115
|
+
}
|
|
116
|
+
const modeId = modeFromSessionUpdate(params.update);
|
|
117
|
+
if (modeId)
|
|
118
|
+
updatedModeId = modeId;
|
|
119
|
+
},
|
|
120
|
+
requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
|
|
121
|
+
};
|
|
122
|
+
const connection = await spawnAuthAgent({
|
|
123
|
+
agent: options.agent,
|
|
124
|
+
cwd,
|
|
125
|
+
env: options.env,
|
|
126
|
+
spawner: options.spawner,
|
|
127
|
+
client,
|
|
128
|
+
});
|
|
129
|
+
const timeoutMs = Math.max(1, options.timeoutMs ?? 15_000);
|
|
130
|
+
const capabilitySettleMs = Math.max(0, options.capabilitySettleMs ?? 750);
|
|
131
|
+
try {
|
|
132
|
+
return await withTimeout((async () => {
|
|
133
|
+
const initResult = await initializeAuthAgent(connection.agent);
|
|
134
|
+
const methods = supportedAuthMethods(initResult.authMethods);
|
|
135
|
+
const method = selectAuthMethod(initResult.authMethods);
|
|
136
|
+
if (!method) {
|
|
137
|
+
const declared = declaredAuthMethods(initResult.authMethods);
|
|
138
|
+
if (declared.length > 0) {
|
|
139
|
+
const unsupported = unsupportedAuthMethodTypes(declared);
|
|
140
|
+
return {
|
|
141
|
+
configOptions: [],
|
|
142
|
+
availableCommands: [],
|
|
143
|
+
auth: {
|
|
144
|
+
status: "unknown",
|
|
145
|
+
message: unsupported.length > 0
|
|
146
|
+
? `No supported ACP auth method is available. Unsupported methods: ${unsupported.join(", ")}.`
|
|
147
|
+
: "No supported ACP auth method is available.",
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const methodFields = method
|
|
153
|
+
? authMethodStatusFields(method, methods, options.agent, connection.env, cwd)
|
|
154
|
+
: {};
|
|
155
|
+
if (method && isCredentialPromptAuthMethod(method)) {
|
|
156
|
+
const missing = missingCredentialVariableNames(method, connection.env);
|
|
157
|
+
if (missing.length > 0) {
|
|
158
|
+
return {
|
|
159
|
+
configOptions: [],
|
|
160
|
+
availableCommands: [],
|
|
161
|
+
auth: {
|
|
162
|
+
status: "needs-auth",
|
|
163
|
+
...methodFields,
|
|
164
|
+
message: missing.length === 1
|
|
165
|
+
? `Missing credential variable: ${missing[0]}.`
|
|
166
|
+
: `Missing credential variables: ${missing.join(", ")}.`,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
const session = await createAuthProbeSession(connection.agent, cwd);
|
|
173
|
+
const responseConfigOptions = configOptionsFromResponse(session);
|
|
174
|
+
const modes = modesFromResponse(session);
|
|
175
|
+
await waitForSignalOrTimeout(availableCommandsReady, capabilitySettleMs);
|
|
176
|
+
await allowDiagnosticsToFlush();
|
|
177
|
+
const diagnostic = unauthenticatedDiagnostic(connection.diagnosticLines);
|
|
178
|
+
return {
|
|
179
|
+
configOptions: responseConfigOptions.length > 0 ? responseConfigOptions : updatedConfigOptions,
|
|
180
|
+
availableCommands: updatedAvailableCommands,
|
|
181
|
+
...(modes ? { modes: updatedModeId ? { ...modes, currentModeId: updatedModeId } : modes } : {}),
|
|
182
|
+
auth: diagnostic
|
|
183
|
+
? { status: "needs-auth", ...methodFields, message: diagnostic }
|
|
184
|
+
: method
|
|
185
|
+
? { status: "configured", ...methodFields }
|
|
186
|
+
: { status: "none" },
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
if (isAuthenticationRequiredError(error)) {
|
|
191
|
+
return {
|
|
192
|
+
configOptions: [],
|
|
193
|
+
availableCommands: [],
|
|
194
|
+
auth: { status: "needs-auth", ...methodFields },
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const message = acpErrorMessage(error);
|
|
198
|
+
if (isAuthFailureMessage(message)) {
|
|
199
|
+
return {
|
|
200
|
+
configOptions: [],
|
|
201
|
+
availableCommands: [],
|
|
202
|
+
auth: { status: "needs-auth", ...methodFields, message },
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
})(), timeoutMs, `ACP agent config probe timed out after ${timeoutMs}ms`);
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
await connection.dispose();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const activeProbes = new Set();
|
|
214
|
+
/** Dispose every in-flight capability probe, auth probe, and background
|
|
215
|
+
* authentication child before a product shuts down. */
|
|
216
|
+
export async function disposeAllAcpProbes() {
|
|
217
|
+
await Promise.allSettled([...activeProbes].map((dispose) => dispose()));
|
|
218
|
+
}
|
|
219
|
+
async function spawnProbeAgent(options) {
|
|
220
|
+
const mergedEnv = {
|
|
221
|
+
...(options.agent.env ?? {}),
|
|
222
|
+
...(options.env ?? {}),
|
|
223
|
+
};
|
|
224
|
+
const child = await (options.spawner ?? new NodeSpawner()).spawn({
|
|
225
|
+
...options.agent,
|
|
226
|
+
cwd: options.cwd,
|
|
227
|
+
env: mergedEnv,
|
|
228
|
+
});
|
|
229
|
+
const stream = ndJsonStream(child.stdin, child.stdout);
|
|
230
|
+
const agent = new ClientSideConnection(() => options.client, stream);
|
|
231
|
+
let disposed;
|
|
232
|
+
const dispose = () => {
|
|
233
|
+
disposed ??= child.kill().catch(() => undefined).finally(() => {
|
|
234
|
+
activeProbes.delete(dispose);
|
|
235
|
+
});
|
|
236
|
+
return disposed;
|
|
237
|
+
};
|
|
238
|
+
activeProbes.add(dispose);
|
|
239
|
+
return { agent, dispose };
|
|
240
|
+
}
|
|
241
|
+
async function withTimeout(promise, timeoutMs, message) {
|
|
242
|
+
let timer;
|
|
243
|
+
try {
|
|
244
|
+
return await Promise.race([
|
|
245
|
+
promise,
|
|
246
|
+
new Promise((_, reject) => {
|
|
247
|
+
timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
248
|
+
if (typeof timer === "object" && "unref" in timer)
|
|
249
|
+
timer.unref();
|
|
250
|
+
}),
|
|
251
|
+
]);
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
if (timer !== undefined)
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async function waitForSignalOrTimeout(signal, timeoutMs) {
|
|
259
|
+
if (timeoutMs === 0)
|
|
260
|
+
return;
|
|
261
|
+
let timer;
|
|
262
|
+
try {
|
|
263
|
+
await Promise.race([
|
|
264
|
+
signal,
|
|
265
|
+
new Promise((resolve) => {
|
|
266
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
267
|
+
if (typeof timer === "object" && "unref" in timer)
|
|
268
|
+
timer.unref();
|
|
269
|
+
}),
|
|
270
|
+
]);
|
|
271
|
+
}
|
|
272
|
+
finally {
|
|
273
|
+
if (timer !== undefined)
|
|
274
|
+
clearTimeout(timer);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function asRecord(value) {
|
|
278
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
279
|
+
? value
|
|
280
|
+
: undefined;
|
|
281
|
+
}
|
|
282
|
+
const SUPPORTED_AUTH_METHOD_TYPES = new Set(["agent", "terminal", "env_var"]);
|
|
283
|
+
export async function probeAgentAuthStatus(options) {
|
|
284
|
+
const cwd = options.cwd ?? join(tmpdir(), "openma-acp-auth-probe");
|
|
285
|
+
await mkdir(cwd, { recursive: true });
|
|
286
|
+
const connection = await spawnAuthAgent({
|
|
287
|
+
agent: options.agent,
|
|
288
|
+
cwd,
|
|
289
|
+
env: options.env,
|
|
290
|
+
spawner: options.spawner,
|
|
291
|
+
});
|
|
292
|
+
const timeoutMs = Math.max(1, options.timeoutMs ?? 15_000);
|
|
293
|
+
try {
|
|
294
|
+
return await withTimeout(readAuthStatus(connection, options.agent, cwd), timeoutMs, `ACP auth probe timed out after ${timeoutMs}ms`);
|
|
295
|
+
}
|
|
296
|
+
finally {
|
|
297
|
+
await connection.dispose();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
export async function authenticateAgent(options) {
|
|
301
|
+
const cwd = options.cwd ?? join(tmpdir(), "openma-acp-auth");
|
|
302
|
+
await mkdir(cwd, { recursive: true });
|
|
303
|
+
const env = mergedStringEnv(options.agent.env, options.env);
|
|
304
|
+
let authTerminalId = 0;
|
|
305
|
+
let activeAuthMethodName = "Agent";
|
|
306
|
+
let resolveTerminalLaunch;
|
|
307
|
+
let rejectTerminalLaunch;
|
|
308
|
+
const terminalLaunch = new Promise((resolve, reject) => {
|
|
309
|
+
resolveTerminalLaunch = resolve;
|
|
310
|
+
rejectTerminalLaunch = reject;
|
|
311
|
+
});
|
|
312
|
+
void terminalLaunch.catch(() => undefined);
|
|
313
|
+
const client = {
|
|
314
|
+
sessionUpdate: async () => undefined,
|
|
315
|
+
requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
|
|
316
|
+
createTerminal: async (params) => {
|
|
317
|
+
if (!options.launchInteractiveAuth) {
|
|
318
|
+
throw new Error("ACP auth requested a terminal, but this host cannot open one.");
|
|
319
|
+
}
|
|
320
|
+
const terminalId = `auth-terminal-${++authTerminalId}`;
|
|
321
|
+
try {
|
|
322
|
+
const terminalEnv = envArrayToRecord(params.env);
|
|
323
|
+
await options.launchInteractiveAuth({
|
|
324
|
+
label: `${activeAuthMethodName} auth`,
|
|
325
|
+
command: params.command,
|
|
326
|
+
args: params.args ?? [],
|
|
327
|
+
...(terminalEnv ? { env: terminalEnv } : {}),
|
|
328
|
+
cwd: params.cwd ?? cwd,
|
|
329
|
+
});
|
|
330
|
+
resolveTerminalLaunch?.();
|
|
331
|
+
return { terminalId };
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
rejectTerminalLaunch?.(error);
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
terminalOutput: async () => ({ output: "", truncated: false }),
|
|
339
|
+
waitForTerminalExit: async () => new Promise(() => undefined),
|
|
340
|
+
releaseTerminal: async () => undefined,
|
|
341
|
+
killTerminal: async () => undefined,
|
|
342
|
+
};
|
|
343
|
+
const connection = await spawnAuthAgent({
|
|
344
|
+
agent: options.agent,
|
|
345
|
+
cwd,
|
|
346
|
+
env: options.env,
|
|
347
|
+
spawner: options.spawner,
|
|
348
|
+
client,
|
|
349
|
+
});
|
|
350
|
+
const timeoutMs = Math.max(1, options.timeoutMs ?? 120_000);
|
|
351
|
+
const agentAuthLaunchGraceMs = options.agentAuthLaunchGraceMs ?? 0;
|
|
352
|
+
const backgroundAuthTimeoutMs = options.backgroundAuthTimeoutMs ?? 10 * 60_000;
|
|
353
|
+
let keepChildAliveForBackgroundAuth = false;
|
|
354
|
+
let timer;
|
|
355
|
+
const keepBackgroundAuthAlive = (authPromise) => {
|
|
356
|
+
keepChildAliveForBackgroundAuth = true;
|
|
357
|
+
let backgroundTimer = setTimeout(() => {
|
|
358
|
+
void connection.dispose();
|
|
359
|
+
backgroundTimer = undefined;
|
|
360
|
+
}, backgroundAuthTimeoutMs);
|
|
361
|
+
backgroundTimer.unref?.();
|
|
362
|
+
void (async () => {
|
|
363
|
+
try {
|
|
364
|
+
await authPromise;
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
// The interactive flow may be cancelled after the host has taken over.
|
|
368
|
+
}
|
|
369
|
+
finally {
|
|
370
|
+
if (backgroundTimer)
|
|
371
|
+
clearTimeout(backgroundTimer);
|
|
372
|
+
await connection.dispose();
|
|
373
|
+
}
|
|
374
|
+
})();
|
|
375
|
+
};
|
|
376
|
+
try {
|
|
377
|
+
return await Promise.race([
|
|
378
|
+
(async () => {
|
|
379
|
+
const initResult = await initializeAuthAgent(connection.agent);
|
|
380
|
+
const method = selectAuthMethod(initResult.authMethods, options.methodId);
|
|
381
|
+
if (!method) {
|
|
382
|
+
throw new Error(options.methodId
|
|
383
|
+
? `ACP auth method is unavailable or not supported: ${options.methodId}`
|
|
384
|
+
: "No supported ACP auth method is available for this agent");
|
|
385
|
+
}
|
|
386
|
+
if (isCredentialPromptAuthMethod(method)) {
|
|
387
|
+
const vars = credentialVariableNames(method);
|
|
388
|
+
throw new Error(vars
|
|
389
|
+
? `ACP auth method ${method.id} requires credential variables (${vars}) and cannot be started as a sign-in flow.`
|
|
390
|
+
: `ACP auth method ${method.id} requires credential variables and cannot be started as a sign-in flow.`);
|
|
391
|
+
}
|
|
392
|
+
const authenticateMeta = authenticateMetaFromMethod(method, options.values ?? {});
|
|
393
|
+
if (authenticateMeta) {
|
|
394
|
+
await Promise.resolve(connection.agent.authenticate({
|
|
395
|
+
methodId: method.id,
|
|
396
|
+
_meta: authenticateMeta,
|
|
397
|
+
})).catch((error) => {
|
|
398
|
+
throw withAcpDetails(error);
|
|
399
|
+
});
|
|
400
|
+
return { status: "completed" };
|
|
401
|
+
}
|
|
402
|
+
const terminalAuth = terminalAuthFromMethod(method, options.agent, env, cwd);
|
|
403
|
+
if (terminalAuth) {
|
|
404
|
+
if (!options.launchInteractiveAuth) {
|
|
405
|
+
throw new Error(`ACP auth method ${method.id} requires an interactive terminal, but this host cannot open one.`);
|
|
406
|
+
}
|
|
407
|
+
await options.launchInteractiveAuth(terminalAuth);
|
|
408
|
+
return { status: "started" };
|
|
409
|
+
}
|
|
410
|
+
activeAuthMethodName = authMethodName(method) ?? "Agent";
|
|
411
|
+
const authPromise = Promise.resolve(connection.agent.authenticate({ methodId: method.id }))
|
|
412
|
+
.catch((error) => {
|
|
413
|
+
throw withAcpDetails(error);
|
|
414
|
+
});
|
|
415
|
+
void authPromise.catch(() => undefined);
|
|
416
|
+
let launchGraceTimer;
|
|
417
|
+
const launchGrace = agentAuthLaunchGraceMs > 0
|
|
418
|
+
? new Promise((resolve) => {
|
|
419
|
+
launchGraceTimer = setTimeout(() => resolve("launched"), agentAuthLaunchGraceMs);
|
|
420
|
+
launchGraceTimer.unref?.();
|
|
421
|
+
})
|
|
422
|
+
: null;
|
|
423
|
+
try {
|
|
424
|
+
const result = await Promise.race([
|
|
425
|
+
authPromise.then(() => "complete"),
|
|
426
|
+
terminalLaunch.then(() => "terminal"),
|
|
427
|
+
...(launchGrace ? [launchGrace] : []),
|
|
428
|
+
]);
|
|
429
|
+
if (result === "launched") {
|
|
430
|
+
keepBackgroundAuthAlive(authPromise);
|
|
431
|
+
return { status: "started" };
|
|
432
|
+
}
|
|
433
|
+
return { status: result === "complete" ? "completed" : "started" };
|
|
434
|
+
}
|
|
435
|
+
finally {
|
|
436
|
+
if (launchGraceTimer)
|
|
437
|
+
clearTimeout(launchGraceTimer);
|
|
438
|
+
}
|
|
439
|
+
})(),
|
|
440
|
+
new Promise((_, reject) => {
|
|
441
|
+
timer = setTimeout(() => {
|
|
442
|
+
reject(new Error(`ACP auth timed out after ${timeoutMs}ms`));
|
|
443
|
+
}, timeoutMs);
|
|
444
|
+
timer.unref?.();
|
|
445
|
+
}),
|
|
446
|
+
]);
|
|
447
|
+
}
|
|
448
|
+
finally {
|
|
449
|
+
if (timer)
|
|
450
|
+
clearTimeout(timer);
|
|
451
|
+
if (!keepChildAliveForBackgroundAuth)
|
|
452
|
+
await connection.dispose();
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
async function readAuthStatus(connection, agent, cwd) {
|
|
456
|
+
const initResult = await initializeAuthAgent(connection.agent);
|
|
457
|
+
const methods = supportedAuthMethods(initResult.authMethods);
|
|
458
|
+
const method = selectAuthMethod(initResult.authMethods);
|
|
459
|
+
if (!method) {
|
|
460
|
+
const declared = declaredAuthMethods(initResult.authMethods);
|
|
461
|
+
if (declared.length > 0) {
|
|
462
|
+
const unsupported = unsupportedAuthMethodTypes(declared);
|
|
463
|
+
return {
|
|
464
|
+
status: "unknown",
|
|
465
|
+
message: unsupported.length > 0
|
|
466
|
+
? `No supported ACP auth method is available. Unsupported methods: ${unsupported.join(", ")}.`
|
|
467
|
+
: "No supported ACP auth method is available.",
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
return { status: "none" };
|
|
471
|
+
}
|
|
472
|
+
const methodFields = authMethodStatusFields(method, methods, agent, connection.env, cwd);
|
|
473
|
+
if (isCredentialPromptAuthMethod(method)) {
|
|
474
|
+
const missing = missingCredentialVariableNames(method, connection.env);
|
|
475
|
+
if (missing.length > 0) {
|
|
476
|
+
const [only] = missing;
|
|
477
|
+
return {
|
|
478
|
+
status: "needs-auth",
|
|
479
|
+
...methodFields,
|
|
480
|
+
message: missing.length === 1 && only
|
|
481
|
+
? `Missing credential variable: ${only}.`
|
|
482
|
+
: `Missing credential variables: ${missing.join(", ")}.`,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
try {
|
|
487
|
+
await createAuthProbeSession(connection.agent, cwd);
|
|
488
|
+
await allowDiagnosticsToFlush();
|
|
489
|
+
const diagnostic = unauthenticatedDiagnostic(connection.diagnosticLines);
|
|
490
|
+
if (diagnostic) {
|
|
491
|
+
return { status: "needs-auth", ...methodFields, message: diagnostic };
|
|
492
|
+
}
|
|
493
|
+
return { status: "configured", ...methodFields };
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
if (!isAuthenticationRequiredError(error)) {
|
|
497
|
+
return { status: "unknown", message: acpErrorMessage(error), ...methodFields };
|
|
498
|
+
}
|
|
499
|
+
return { status: "needs-auth", ...methodFields };
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
async function spawnAuthAgent(options) {
|
|
503
|
+
const env = mergedStringEnv(options.agent.env, options.env);
|
|
504
|
+
const diagnosticLines = [];
|
|
505
|
+
const onDiagnosticLine = options.agent.onDiagnosticLine;
|
|
506
|
+
const child = await (options.spawner ?? new NodeSpawner()).spawn({
|
|
507
|
+
...options.agent,
|
|
508
|
+
cwd: options.cwd,
|
|
509
|
+
env: { ...(options.agent.env ?? {}), ...(options.env ?? {}) },
|
|
510
|
+
onDiagnosticLine: (line) => {
|
|
511
|
+
diagnosticLines.push(line);
|
|
512
|
+
onDiagnosticLine?.(line);
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
const agent = new ClientSideConnection(() => options.client ?? {
|
|
516
|
+
sessionUpdate: async () => undefined,
|
|
517
|
+
requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
|
|
518
|
+
}, ndJsonStream(child.stdin, child.stdout));
|
|
519
|
+
let disposed;
|
|
520
|
+
const dispose = () => {
|
|
521
|
+
disposed ??= withTimeout(child.kill(), 5_000, "ACP setup process disposal timed out after 5000ms").catch(() => undefined).finally(() => {
|
|
522
|
+
activeProbes.delete(dispose);
|
|
523
|
+
});
|
|
524
|
+
return disposed;
|
|
525
|
+
};
|
|
526
|
+
activeProbes.add(dispose);
|
|
527
|
+
return { agent, env, diagnosticLines, dispose };
|
|
528
|
+
}
|
|
529
|
+
function initializeAuthAgent(agent) {
|
|
530
|
+
return Promise.resolve(agent.initialize({
|
|
531
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
532
|
+
clientCapabilities: ACP_CLIENT_CAPABILITIES,
|
|
533
|
+
}));
|
|
534
|
+
}
|
|
535
|
+
function createAuthProbeSession(agent, cwd) {
|
|
536
|
+
return Promise.resolve(agent.newSession({ cwd, mcpServers: [] }));
|
|
537
|
+
}
|
|
538
|
+
function authMethodType(method) {
|
|
539
|
+
const type = method.type;
|
|
540
|
+
if (typeof type === "string" && type.length > 0)
|
|
541
|
+
return type;
|
|
542
|
+
const metaType = authMethodMeta(method)?.type;
|
|
543
|
+
return typeof metaType === "string" && metaType.length > 0 ? metaType : "agent";
|
|
544
|
+
}
|
|
545
|
+
function isSupportedAuthMethod(method) {
|
|
546
|
+
return SUPPORTED_AUTH_METHOD_TYPES.has(authMethodType(method));
|
|
547
|
+
}
|
|
548
|
+
function supportedAuthMethods(authMethods) {
|
|
549
|
+
return declaredAuthMethods(authMethods).filter(isSupportedAuthMethod);
|
|
550
|
+
}
|
|
551
|
+
function declaredAuthMethods(authMethods) {
|
|
552
|
+
if (!Array.isArray(authMethods))
|
|
553
|
+
return [];
|
|
554
|
+
return authMethods.filter((method) => {
|
|
555
|
+
if (!asRecord(method))
|
|
556
|
+
return false;
|
|
557
|
+
const id = method.id;
|
|
558
|
+
return typeof id === "string" && id.length > 0;
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
function unsupportedAuthMethodTypes(methods) {
|
|
562
|
+
return [...new Set(methods
|
|
563
|
+
.filter((method) => !isSupportedAuthMethod(method))
|
|
564
|
+
.map(authMethodType)
|
|
565
|
+
.filter((type) => type.length > 0))];
|
|
566
|
+
}
|
|
567
|
+
function authMethodMeta(method) {
|
|
568
|
+
const record = method;
|
|
569
|
+
return asRecord(record._meta ?? record.meta) ?? null;
|
|
570
|
+
}
|
|
571
|
+
function terminalAuthMeta(method) {
|
|
572
|
+
const terminalAuth = asRecord(authMethodMeta(method)?.["terminal-auth"]);
|
|
573
|
+
if (!terminalAuth)
|
|
574
|
+
return null;
|
|
575
|
+
if (typeof terminalAuth.command !== "string" || terminalAuth.command.length === 0)
|
|
576
|
+
return null;
|
|
577
|
+
const env = stringRecord(terminalAuth.env);
|
|
578
|
+
return {
|
|
579
|
+
label: typeof terminalAuth.label === "string" && terminalAuth.label.length > 0
|
|
580
|
+
? terminalAuth.label
|
|
581
|
+
: authMethodName(method) ?? "Login",
|
|
582
|
+
command: terminalAuth.command,
|
|
583
|
+
args: stringArray(terminalAuth.args),
|
|
584
|
+
...(env ? { env } : {}),
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
function parseGeneratedShellShimCommand(command) {
|
|
588
|
+
try {
|
|
589
|
+
const text = readFileSync(command, "utf8");
|
|
590
|
+
const execLine = text.split("\n").find((line) => line.startsWith("exec ") && line.includes('"$@"'));
|
|
591
|
+
if (!execLine)
|
|
592
|
+
return null;
|
|
593
|
+
const match = execLine.match(/^exec\s+'([^']+)'(?:\s|$)/);
|
|
594
|
+
return match?.[1] ?? null;
|
|
595
|
+
}
|
|
596
|
+
catch {
|
|
597
|
+
return null;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
function terminalAuthCommand(command) {
|
|
601
|
+
return parseGeneratedShellShimCommand(command) ?? command;
|
|
602
|
+
}
|
|
603
|
+
function terminalAuthFromMethod(method, agent, env, cwd) {
|
|
604
|
+
const metaAuth = terminalAuthMeta(method);
|
|
605
|
+
if (metaAuth)
|
|
606
|
+
return { ...metaAuth, cwd };
|
|
607
|
+
if (authMethodType(method) !== "terminal")
|
|
608
|
+
return null;
|
|
609
|
+
const terminalMethod = method;
|
|
610
|
+
const meta = authMethodMeta(method);
|
|
611
|
+
const methodEnv = stringRecord(terminalMethod.env) ?? {};
|
|
612
|
+
const metaEnv = stringRecord(meta?.env) ?? {};
|
|
613
|
+
const metaArgs = meta ? stringArray(meta.args) : [];
|
|
614
|
+
const command = meta && typeof meta.command === "string" && meta.command.length > 0
|
|
615
|
+
? meta.command
|
|
616
|
+
: terminalAuthCommand(agent.command);
|
|
617
|
+
return {
|
|
618
|
+
label: authMethodName(method) ?? "Login",
|
|
619
|
+
command,
|
|
620
|
+
args: metaArgs.length > 0 ? metaArgs : stringArray(terminalMethod.args),
|
|
621
|
+
env: { ...env, ...methodEnv, ...metaEnv },
|
|
622
|
+
cwd,
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
function authEnvVars(method) {
|
|
626
|
+
if (authMethodType(method) !== "env_var")
|
|
627
|
+
return undefined;
|
|
628
|
+
const vars = method.vars;
|
|
629
|
+
if (!Array.isArray(vars))
|
|
630
|
+
return undefined;
|
|
631
|
+
const normalized = vars.flatMap((item) => {
|
|
632
|
+
const typed = asRecord(item);
|
|
633
|
+
if (!typed || typeof typed.name !== "string" || typed.name.length === 0)
|
|
634
|
+
return [];
|
|
635
|
+
return [{
|
|
636
|
+
name: typed.name,
|
|
637
|
+
...(typeof typed.label === "string" && typed.label.length > 0 ? { label: typed.label } : {}),
|
|
638
|
+
...(typeof typed.secret === "boolean" ? { secret: typed.secret } : {}),
|
|
639
|
+
...(typeof typed.optional === "boolean" ? { optional: typed.optional } : {}),
|
|
640
|
+
}];
|
|
641
|
+
});
|
|
642
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
643
|
+
}
|
|
644
|
+
function authMethodLink(method) {
|
|
645
|
+
const link = method.link;
|
|
646
|
+
return typeof link === "string" && link.length > 0 ? link : undefined;
|
|
647
|
+
}
|
|
648
|
+
function apiKeyAuthMeta(method) {
|
|
649
|
+
return asRecord(authMethodMeta(method)?.["api-key"]) ?? null;
|
|
650
|
+
}
|
|
651
|
+
function gatewayAuthMeta(method) {
|
|
652
|
+
return asRecord(authMethodMeta(method)?.gateway) ?? null;
|
|
653
|
+
}
|
|
654
|
+
function authFormVars(method) {
|
|
655
|
+
if (apiKeyAuthMeta(method)) {
|
|
656
|
+
return [{ name: "api-key", label: "API key", secret: true }];
|
|
657
|
+
}
|
|
658
|
+
if (gatewayAuthMeta(method)) {
|
|
659
|
+
return [
|
|
660
|
+
{ name: "baseUrl", label: "Base URL" },
|
|
661
|
+
{ name: "api-key", label: "API key", secret: true },
|
|
662
|
+
{ name: "providerName", label: "Provider", optional: true },
|
|
663
|
+
];
|
|
664
|
+
}
|
|
665
|
+
return undefined;
|
|
666
|
+
}
|
|
667
|
+
function authenticateMetaFromMethod(method, values) {
|
|
668
|
+
if (gatewayAuthMeta(method)) {
|
|
669
|
+
const baseUrl = (values.baseUrl ?? "").trim();
|
|
670
|
+
const apiKey = (values["api-key"] ?? "").trim();
|
|
671
|
+
const providerName = (values.providerName ?? "").trim();
|
|
672
|
+
if (!baseUrl)
|
|
673
|
+
return undefined;
|
|
674
|
+
return {
|
|
675
|
+
gateway: {
|
|
676
|
+
baseUrl,
|
|
677
|
+
headers: apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
|
|
678
|
+
...(providerName ? { providerName } : {}),
|
|
679
|
+
},
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
if (apiKeyAuthMeta(method)) {
|
|
683
|
+
const apiKey = (values["api-key"] ?? "").trim();
|
|
684
|
+
return apiKey ? { "api-key": { apiKey } } : undefined;
|
|
685
|
+
}
|
|
686
|
+
return undefined;
|
|
687
|
+
}
|
|
688
|
+
function selectAuthMethod(authMethods, methodId) {
|
|
689
|
+
const methods = supportedAuthMethods(authMethods);
|
|
690
|
+
if (!methodId)
|
|
691
|
+
return methods[0] ?? null;
|
|
692
|
+
return methods.find((method) => method.id === methodId) ?? null;
|
|
693
|
+
}
|
|
694
|
+
function authMethodName(method) {
|
|
695
|
+
if (!method)
|
|
696
|
+
return undefined;
|
|
697
|
+
const name = method.name;
|
|
698
|
+
return typeof name === "string" && name.length > 0 ? name : undefined;
|
|
699
|
+
}
|
|
700
|
+
function authMethodDescription(method) {
|
|
701
|
+
if (!method)
|
|
702
|
+
return undefined;
|
|
703
|
+
const description = method.description;
|
|
704
|
+
return typeof description === "string" && description.length > 0 ? description : undefined;
|
|
705
|
+
}
|
|
706
|
+
function inferredCredentialVars(method) {
|
|
707
|
+
const description = authMethodDescription(method);
|
|
708
|
+
if (!description || !/\benvironment variable\b|\benv(?:ironment)? var\b/i.test(description)) {
|
|
709
|
+
return undefined;
|
|
710
|
+
}
|
|
711
|
+
const names = [...new Set([...description.matchAll(/\b([A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+)\b/g)]
|
|
712
|
+
.map((match) => match[1])
|
|
713
|
+
.filter((name) => typeof name === "string" && name.length > 0))];
|
|
714
|
+
if (names.length === 0)
|
|
715
|
+
return undefined;
|
|
716
|
+
return names.map((name) => ({
|
|
717
|
+
name,
|
|
718
|
+
secret: /(?:^|_)(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)(?:_|$)/.test(name),
|
|
719
|
+
}));
|
|
720
|
+
}
|
|
721
|
+
function credentialVars(method) {
|
|
722
|
+
return authEnvVars(method) ?? inferredCredentialVars(method);
|
|
723
|
+
}
|
|
724
|
+
function isCredentialPromptAuthMethod(method) {
|
|
725
|
+
const type = authMethodType(method);
|
|
726
|
+
return type === "env_var" || (type === "terminal" && Boolean(inferredCredentialVars(method)));
|
|
727
|
+
}
|
|
728
|
+
function credentialVariableNames(method) {
|
|
729
|
+
const names = credentialVars(method)?.map((item) => item.name).join(", ");
|
|
730
|
+
return names && names.length > 0 ? names : undefined;
|
|
731
|
+
}
|
|
732
|
+
function missingCredentialVariableNames(method, env) {
|
|
733
|
+
return (credentialVars(method) ?? [])
|
|
734
|
+
.filter((variable) => variable.optional !== true)
|
|
735
|
+
.map((variable) => variable.name)
|
|
736
|
+
.filter((name) => !env[name]);
|
|
737
|
+
}
|
|
738
|
+
function publicAuthMethods(methods, agent, env, cwd) {
|
|
739
|
+
return methods.map((method) => {
|
|
740
|
+
const formVars = authFormVars(method);
|
|
741
|
+
const vars = formVars ?? credentialVars(method);
|
|
742
|
+
const type = isCredentialPromptAuthMethod(method) ? "env_var" : authMethodType(method);
|
|
743
|
+
const terminalLaunch = type === "terminal"
|
|
744
|
+
? terminalAuthFromMethod(method, agent, env, cwd)
|
|
745
|
+
: null;
|
|
746
|
+
return {
|
|
747
|
+
id: method.id,
|
|
748
|
+
...(authMethodName(method) ? { name: authMethodName(method) } : {}),
|
|
749
|
+
...(authMethodDescription(method) ? { description: authMethodDescription(method) } : {}),
|
|
750
|
+
type,
|
|
751
|
+
...(formVars ? { form: "fields" } : {}),
|
|
752
|
+
...(vars ? { vars } : {}),
|
|
753
|
+
...(authMethodLink(method) ? { link: authMethodLink(method) } : {}),
|
|
754
|
+
...(terminalLaunch ? { terminalLaunch } : {}),
|
|
755
|
+
};
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
function authMethodStatusFields(method, methods, agent, env, cwd) {
|
|
759
|
+
const methodName = authMethodName(method);
|
|
760
|
+
return {
|
|
761
|
+
methodId: method.id,
|
|
762
|
+
...(methodName ? { methodName } : {}),
|
|
763
|
+
methods: publicAuthMethods(methods, agent, env, cwd),
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
function acpErrorMessage(error) {
|
|
767
|
+
const data = asRecord(error?.data);
|
|
768
|
+
if (typeof data?.details === "string" && data.details.length > 0)
|
|
769
|
+
return data.details;
|
|
770
|
+
if (typeof data?.message === "string" && data.message.length > 0)
|
|
771
|
+
return data.message;
|
|
772
|
+
const message = error?.message;
|
|
773
|
+
if (typeof message === "string" && message.length > 0)
|
|
774
|
+
return message;
|
|
775
|
+
return String(error);
|
|
776
|
+
}
|
|
777
|
+
function withAcpDetails(error) {
|
|
778
|
+
const message = acpErrorMessage(error);
|
|
779
|
+
if (error instanceof Error && message === error.message)
|
|
780
|
+
return error;
|
|
781
|
+
const next = new Error(message);
|
|
782
|
+
if (error && typeof error === "object") {
|
|
783
|
+
const code = error.code;
|
|
784
|
+
const data = error.data;
|
|
785
|
+
if (typeof code === "number")
|
|
786
|
+
next.code = code;
|
|
787
|
+
if (data !== undefined)
|
|
788
|
+
next.data = data;
|
|
789
|
+
}
|
|
790
|
+
return next;
|
|
791
|
+
}
|
|
792
|
+
function mergedStringEnv(...envs) {
|
|
793
|
+
const out = {};
|
|
794
|
+
for (const env of envs) {
|
|
795
|
+
for (const [key, value] of Object.entries(env ?? {})) {
|
|
796
|
+
if (typeof value === "string")
|
|
797
|
+
out[key] = value;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
return out;
|
|
801
|
+
}
|
|
802
|
+
function stringArray(value) {
|
|
803
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
804
|
+
}
|
|
805
|
+
function stringRecord(value) {
|
|
806
|
+
const record = asRecord(value);
|
|
807
|
+
if (!record)
|
|
808
|
+
return undefined;
|
|
809
|
+
const entries = Object.entries(record).filter((entry) => typeof entry[1] === "string");
|
|
810
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
811
|
+
}
|
|
812
|
+
function envArrayToRecord(env) {
|
|
813
|
+
if (!Array.isArray(env))
|
|
814
|
+
return undefined;
|
|
815
|
+
const entries = env.filter((entry) => (typeof entry.name === "string"
|
|
816
|
+
&& entry.name.length > 0
|
|
817
|
+
&& typeof entry.value === "string")).map((entry) => [entry.name, entry.value]);
|
|
818
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
819
|
+
}
|
|
820
|
+
function configOptionsFromResponse(value) {
|
|
821
|
+
return Array.isArray(value?.configOptions)
|
|
822
|
+
? value.configOptions.map((option) => structuredClone(option))
|
|
823
|
+
: [];
|
|
824
|
+
}
|
|
825
|
+
function configOptionsFromSessionUpdate(update) {
|
|
826
|
+
const typed = asRecord(update);
|
|
827
|
+
if (!typed || typed.sessionUpdate !== "config_option_update" || !Array.isArray(typed.configOptions)) {
|
|
828
|
+
return null;
|
|
829
|
+
}
|
|
830
|
+
return typed.configOptions.map((option) => structuredClone(option));
|
|
831
|
+
}
|
|
832
|
+
function availableCommandsFromSessionUpdate(update) {
|
|
833
|
+
const typed = asRecord(update);
|
|
834
|
+
if (!typed || typed.sessionUpdate !== "available_commands_update")
|
|
835
|
+
return null;
|
|
836
|
+
const commands = Array.isArray(typed.availableCommands)
|
|
837
|
+
? typed.availableCommands
|
|
838
|
+
: Array.isArray(typed.available_commands)
|
|
839
|
+
? typed.available_commands
|
|
840
|
+
: null;
|
|
841
|
+
return commands?.map((command) => structuredClone(command)) ?? null;
|
|
842
|
+
}
|
|
843
|
+
function modesFromResponse(value) {
|
|
844
|
+
return value?.modes ? structuredClone(value.modes) : null;
|
|
845
|
+
}
|
|
846
|
+
function modeFromSessionUpdate(update) {
|
|
847
|
+
const typed = asRecord(update);
|
|
848
|
+
if (!typed || typed.sessionUpdate !== "current_mode_update" || typeof typed.currentModeId !== "string") {
|
|
849
|
+
return null;
|
|
850
|
+
}
|
|
851
|
+
return typed.currentModeId;
|
|
852
|
+
}
|
|
853
|
+
function isAuthFailureMessage(message) {
|
|
854
|
+
return typeof message === "string"
|
|
855
|
+
&& /authentication required\b|authentication fails\b|invalid api key|api key[:\s=][^\n]*\binvalid\b/i.test(message);
|
|
856
|
+
}
|
|
857
|
+
function unauthenticatedDiagnostic(lines) {
|
|
858
|
+
for (const line of lines) {
|
|
859
|
+
const plain = line.replace(/\u001b\[[0-9;?]*[A-Za-z]/g, "").trim();
|
|
860
|
+
if (/\bcreating session without credentials\b/i.test(plain)) {
|
|
861
|
+
return plain.replace(/^.*?\bcreating session without credentials\b/i, "Creating session without credentials");
|
|
862
|
+
}
|
|
863
|
+
if (/\bagent may not work\b/i.test(plain) && /\bcredentials?\b/i.test(plain)) {
|
|
864
|
+
return plain;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
return null;
|
|
868
|
+
}
|
|
869
|
+
async function allowDiagnosticsToFlush() {
|
|
870
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
871
|
+
}
|
|
872
|
+
//# sourceMappingURL=probe.js.map
|