@geminilight/mindos 1.0.10 → 1.1.3
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/README_zh.md +3 -3
- package/bin/mindos-shim.cjs +318 -7
- package/dist/agent/prompts.d.ts +1 -1
- package/dist/agent/prompts.d.ts.map +1 -1
- package/dist/agent/prompts.js +14 -0
- package/dist/agent/prompts.js.map +1 -1
- package/dist/agent-runtime/claude-code-cli.d.ts +34 -0
- package/dist/agent-runtime/claude-code-cli.d.ts.map +1 -0
- package/dist/agent-runtime/claude-code-cli.js +259 -0
- package/dist/agent-runtime/claude-code-cli.js.map +1 -0
- package/dist/agent-runtime/claude-code-sdk.d.ts +41 -0
- package/dist/agent-runtime/claude-code-sdk.d.ts.map +1 -0
- package/dist/agent-runtime/claude-code-sdk.js +553 -0
- package/dist/agent-runtime/claude-code-sdk.js.map +1 -0
- package/dist/agent-runtime/codex-app-server.d.ts +154 -0
- package/dist/agent-runtime/codex-app-server.d.ts.map +1 -0
- package/dist/agent-runtime/codex-app-server.js +628 -0
- package/dist/agent-runtime/codex-app-server.js.map +1 -0
- package/dist/agent-runtime/codex-env.d.ts +41 -0
- package/dist/agent-runtime/codex-env.d.ts.map +1 -0
- package/dist/agent-runtime/codex-env.js +278 -0
- package/dist/agent-runtime/codex-env.js.map +1 -0
- package/dist/agent-runtime/index.d.ts +7 -0
- package/dist/agent-runtime/index.d.ts.map +1 -0
- package/dist/agent-runtime/index.js +7 -0
- package/dist/agent-runtime/index.js.map +1 -0
- package/dist/agent-runtime/run.d.ts +111 -0
- package/dist/agent-runtime/run.d.ts.map +1 -0
- package/dist/agent-runtime/run.js +681 -0
- package/dist/agent-runtime/run.js.map +1 -0
- package/dist/agent-runtime/runtime-env.d.ts +28 -0
- package/dist/agent-runtime/runtime-env.d.ts.map +1 -0
- package/dist/agent-runtime/runtime-env.js +66 -0
- package/dist/agent-runtime/runtime-env.js.map +1 -0
- package/dist/agent-runtime.d.ts +2 -0
- package/dist/agent-runtime.d.ts.map +1 -0
- package/dist/agent-runtime.js +2 -0
- package/dist/agent-runtime.js.map +1 -0
- package/dist/client.d.ts +8 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js.map +1 -1
- package/dist/foundation/config/schema.d.ts +30 -141
- package/dist/foundation/config/schema.d.ts.map +1 -1
- package/dist/foundation/config/schema.js +18 -4
- package/dist/foundation/config/schema.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/knowledge/audit/index.d.ts +4 -0
- package/dist/knowledge/audit/index.d.ts.map +1 -1
- package/dist/knowledge/audit/index.js +92 -8
- package/dist/knowledge/audit/index.js.map +1 -1
- package/dist/knowledge/git/index.d.ts.map +1 -1
- package/dist/knowledge/git/index.js +43 -2
- package/dist/knowledge/git/index.js.map +1 -1
- package/dist/protocols/acp/agent-descriptors.d.ts.map +1 -1
- package/dist/protocols/acp/agent-descriptors.js +7 -4
- package/dist/protocols/acp/agent-descriptors.js.map +1 -1
- package/dist/protocols/acp/index.js +39 -28
- package/dist/protocols/acp/session.d.ts.map +1 -1
- package/dist/protocols/acp/session.js +11 -14
- package/dist/protocols/acp/session.js.map +1 -1
- package/dist/protocols/acp/subprocess.d.ts +4 -1
- package/dist/protocols/acp/subprocess.d.ts.map +1 -1
- package/dist/protocols/acp/subprocess.js +37 -10
- package/dist/protocols/acp/subprocess.js.map +1 -1
- package/dist/protocols/mcp-server/index.cjs +80 -68
- package/dist/server/channel-contract.d.ts +13 -0
- package/dist/server/channel-contract.d.ts.map +1 -0
- package/dist/server/channel-contract.js +115 -0
- package/dist/server/channel-contract.js.map +1 -0
- package/dist/server/contract.d.ts.map +1 -1
- package/dist/server/contract.js +12 -0
- package/dist/server/contract.js.map +1 -1
- package/dist/server/handlers/a2a.d.ts +7 -0
- package/dist/server/handlers/a2a.d.ts.map +1 -1
- package/dist/server/handlers/a2a.js +5 -1
- package/dist/server/handlers/a2a.js.map +1 -1
- package/dist/server/handlers/agent-capabilities.d.ts +60 -0
- package/dist/server/handlers/agent-capabilities.d.ts.map +1 -0
- package/dist/server/handlers/agent-capabilities.js +178 -0
- package/dist/server/handlers/agent-capabilities.js.map +1 -0
- package/dist/server/handlers/agent-runtime-codex.d.ts +29 -0
- package/dist/server/handlers/agent-runtime-codex.d.ts.map +1 -0
- package/dist/server/handlers/agent-runtime-codex.js +198 -0
- package/dist/server/handlers/agent-runtime-codex.js.map +1 -0
- package/dist/server/handlers/agent-runtimes.d.ts +136 -0
- package/dist/server/handlers/agent-runtimes.d.ts.map +1 -0
- package/dist/server/handlers/agent-runtimes.js +712 -0
- package/dist/server/handlers/agent-runtimes.js.map +1 -0
- package/dist/server/handlers/agents.d.ts +6 -0
- package/dist/server/handlers/agents.d.ts.map +1 -1
- package/dist/server/handlers/agents.js +41 -6
- package/dist/server/handlers/agents.js.map +1 -1
- package/dist/server/handlers/ask.d.ts +18 -0
- package/dist/server/handlers/ask.d.ts.map +1 -1
- package/dist/server/handlers/ask.js +70 -0
- package/dist/server/handlers/ask.js.map +1 -1
- package/dist/server/handlers/channels-verify.d.ts +1 -1
- package/dist/server/handlers/channels-verify.d.ts.map +1 -1
- package/dist/server/handlers/channels-verify.js +1 -63
- package/dist/server/handlers/channels-verify.js.map +1 -1
- package/dist/server/handlers/extract-docx.d.ts +42 -0
- package/dist/server/handlers/extract-docx.d.ts.map +1 -0
- package/dist/server/handlers/extract-docx.js +101 -0
- package/dist/server/handlers/extract-docx.js.map +1 -0
- package/dist/server/handlers/extract-pdf.d.ts +32 -0
- package/dist/server/handlers/extract-pdf.d.ts.map +1 -0
- package/dist/server/handlers/extract-pdf.js +116 -0
- package/dist/server/handlers/extract-pdf.js.map +1 -0
- package/dist/server/handlers/im-activity.d.ts.map +1 -1
- package/dist/server/handlers/im-activity.js +26 -1
- package/dist/server/handlers/im-activity.js.map +1 -1
- package/dist/server/handlers/im-config.d.ts +1 -1
- package/dist/server/handlers/im-config.d.ts.map +1 -1
- package/dist/server/handlers/im-config.js +69 -59
- package/dist/server/handlers/im-config.js.map +1 -1
- package/dist/server/handlers/im-feishu-oauth.d.ts +55 -0
- package/dist/server/handlers/im-feishu-oauth.d.ts.map +1 -0
- package/dist/server/handlers/im-feishu-oauth.js +218 -0
- package/dist/server/handlers/im-feishu-oauth.js.map +1 -0
- package/dist/server/handlers/im-status.d.ts +15 -0
- package/dist/server/handlers/im-status.d.ts.map +1 -1
- package/dist/server/handlers/im-status.js +41 -24
- package/dist/server/handlers/im-status.js.map +1 -1
- package/dist/server/handlers/inbox-source.d.ts +18 -0
- package/dist/server/handlers/inbox-source.d.ts.map +1 -0
- package/dist/server/handlers/inbox-source.js +108 -0
- package/dist/server/handlers/inbox-source.js.map +1 -0
- package/dist/server/handlers/inbox.d.ts +2 -0
- package/dist/server/handlers/inbox.d.ts.map +1 -1
- package/dist/server/handlers/inbox.js +34 -2
- package/dist/server/handlers/inbox.js.map +1 -1
- package/dist/server/handlers/mcp-agents.d.ts +16 -1
- package/dist/server/handlers/mcp-agents.d.ts.map +1 -1
- package/dist/server/handlers/mcp-agents.js +174 -44
- package/dist/server/handlers/mcp-agents.js.map +1 -1
- package/dist/server/handlers/mcp-install.d.ts +5 -0
- package/dist/server/handlers/mcp-install.d.ts.map +1 -1
- package/dist/server/handlers/mcp-install.js +68 -20
- package/dist/server/handlers/mcp-install.js.map +1 -1
- package/dist/server/handlers/mcp-restart.js +1 -1
- package/dist/server/handlers/mcp-restart.js.map +1 -1
- package/dist/server/handlers/mcp-status.d.ts +7 -1
- package/dist/server/handlers/mcp-status.d.ts.map +1 -1
- package/dist/server/handlers/mcp-status.js +14 -1
- package/dist/server/handlers/mcp-status.js.map +1 -1
- package/dist/server/handlers/settings-list-models.d.ts +1 -1
- package/dist/server/handlers/settings-list-models.d.ts.map +1 -1
- package/dist/server/handlers/settings-list-models.js +6 -5
- package/dist/server/handlers/settings-list-models.js.map +1 -1
- package/dist/server/handlers/settings-test-key.d.ts.map +1 -1
- package/dist/server/handlers/settings-test-key.js +17 -7
- package/dist/server/handlers/settings-test-key.js.map +1 -1
- package/dist/server/handlers/settings.d.ts +5 -1
- package/dist/server/handlers/settings.d.ts.map +1 -1
- package/dist/server/handlers/settings.js +54 -5
- package/dist/server/handlers/settings.js.map +1 -1
- package/dist/server/handlers/skills.d.ts +1 -0
- package/dist/server/handlers/skills.d.ts.map +1 -1
- package/dist/server/handlers/skills.js +7 -5
- package/dist/server/handlers/skills.js.map +1 -1
- package/dist/server/handlers/sync.d.ts +15 -4
- package/dist/server/handlers/sync.d.ts.map +1 -1
- package/dist/server/handlers/sync.js +552 -81
- package/dist/server/handlers/sync.js.map +1 -1
- package/dist/server/handlers/uninstall.js +1 -0
- package/dist/server/handlers/uninstall.js.map +1 -1
- package/dist/server/handlers/update.js +1 -0
- package/dist/server/handlers/update.js.map +1 -1
- package/dist/server/http.d.ts +20 -0
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +228 -25
- package/dist/server/http.js.map +1 -1
- package/dist/server/index.d.ts +14 -5
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +11 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp-agent-registry.d.ts +184 -0
- package/dist/server/mcp-agent-registry.d.ts.map +1 -1
- package/dist/server/mcp-agent-registry.js +100 -9
- package/dist/server/mcp-agent-registry.js.map +1 -1
- package/dist/server/provider-settings.d.ts +38 -0
- package/dist/server/provider-settings.d.ts.map +1 -0
- package/dist/server/provider-settings.js +286 -0
- package/dist/server/provider-settings.js.map +1 -0
- package/dist/server/route-ownership.d.ts.map +1 -1
- package/dist/server/route-ownership.js +18 -2
- package/dist/server/route-ownership.js.map +1 -1
- package/dist/server/runtime.d.ts +1 -0
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/server/runtime.js.map +1 -1
- package/dist/session/index.d.ts +96 -15
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +162 -30
- package/dist/session/index.js.map +1 -1
- package/dist/session/pi-coding-agent-runtime.js +3 -3
- package/dist/session/pi-coding-agent-runtime.js.map +1 -1
- package/dist/session/redaction.d.ts +3 -0
- package/dist/session/redaction.d.ts.map +1 -0
- package/dist/session/redaction.js +47 -0
- package/dist/session/redaction.js.map +1 -0
- package/dist/setup/index.d.ts +1 -0
- package/dist/setup/index.d.ts.map +1 -1
- package/dist/setup/index.js +13 -0
- package/dist/setup/index.js.map +1 -1
- package/package.json +18 -12
- package/src/cli.js +1 -0
|
@@ -0,0 +1,712 @@
|
|
|
1
|
+
import { detectLocalAcpAgents as defaultDetectLocalAcpAgents, resolveCommandPath, } from '../../protocols/acp/index.js';
|
|
2
|
+
import { readCodexConfigText, resolveCodexProviderEnvironment, } from '../../agent-runtime/codex-env.js';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
import { errorResponse, json, privateCacheHeaders } from '../response.js';
|
|
5
|
+
const mindosCapabilities = {
|
|
6
|
+
ownsModelSelection: true,
|
|
7
|
+
supportsResume: true,
|
|
8
|
+
supportsFreshSession: true,
|
|
9
|
+
supportsListSessions: true,
|
|
10
|
+
supportsAttachExisting: false,
|
|
11
|
+
supportsFork: false,
|
|
12
|
+
supportsArchive: false,
|
|
13
|
+
supportsInterrupt: true,
|
|
14
|
+
supportsModelList: true,
|
|
15
|
+
supportsApprovals: false,
|
|
16
|
+
supportsUserInput: true,
|
|
17
|
+
supportsToolEvents: true,
|
|
18
|
+
supportsRuntimeStatus: true,
|
|
19
|
+
supportsDiffs: false,
|
|
20
|
+
supportsCheckpoints: false,
|
|
21
|
+
supportsBackgroundRuns: false,
|
|
22
|
+
supportsMcpConfig: true,
|
|
23
|
+
};
|
|
24
|
+
const nativeBaseCapabilities = {
|
|
25
|
+
ownsModelSelection: true,
|
|
26
|
+
supportsResume: true,
|
|
27
|
+
supportsFreshSession: true,
|
|
28
|
+
supportsListSessions: false,
|
|
29
|
+
supportsAttachExisting: false,
|
|
30
|
+
supportsFork: false,
|
|
31
|
+
supportsArchive: false,
|
|
32
|
+
supportsInterrupt: true,
|
|
33
|
+
supportsModelList: false,
|
|
34
|
+
supportsApprovals: true,
|
|
35
|
+
supportsUserInput: true,
|
|
36
|
+
supportsToolEvents: true,
|
|
37
|
+
supportsRuntimeStatus: true,
|
|
38
|
+
supportsDiffs: false,
|
|
39
|
+
supportsCheckpoints: false,
|
|
40
|
+
supportsBackgroundRuns: false,
|
|
41
|
+
supportsMcpConfig: true,
|
|
42
|
+
};
|
|
43
|
+
const codexCapabilities = {
|
|
44
|
+
...nativeBaseCapabilities,
|
|
45
|
+
supportsListSessions: true,
|
|
46
|
+
supportsAttachExisting: true,
|
|
47
|
+
supportsFork: true,
|
|
48
|
+
supportsArchive: true,
|
|
49
|
+
};
|
|
50
|
+
const claudeCapabilities = {
|
|
51
|
+
...nativeBaseCapabilities,
|
|
52
|
+
};
|
|
53
|
+
const acpCapabilities = {
|
|
54
|
+
ownsModelSelection: true,
|
|
55
|
+
supportsResume: false,
|
|
56
|
+
supportsFreshSession: false,
|
|
57
|
+
supportsListSessions: false,
|
|
58
|
+
supportsAttachExisting: false,
|
|
59
|
+
supportsFork: false,
|
|
60
|
+
supportsArchive: false,
|
|
61
|
+
supportsInterrupt: true,
|
|
62
|
+
supportsModelList: false,
|
|
63
|
+
supportsApprovals: false,
|
|
64
|
+
supportsUserInput: false,
|
|
65
|
+
supportsToolEvents: true,
|
|
66
|
+
supportsRuntimeStatus: false,
|
|
67
|
+
supportsDiffs: false,
|
|
68
|
+
supportsCheckpoints: false,
|
|
69
|
+
supportsBackgroundRuns: false,
|
|
70
|
+
supportsMcpConfig: false,
|
|
71
|
+
};
|
|
72
|
+
const RUNTIME_DETECTION_TIMEOUT_MS = 5000;
|
|
73
|
+
const NATIVE_HEALTH_TIMEOUT_MS = 20000;
|
|
74
|
+
const nativeRuntimeDefinitions = [
|
|
75
|
+
{ id: 'codex-acp', name: 'Codex', runtime: 'codex', command: 'codex', installCmd: 'npm install -g @openai/codex' },
|
|
76
|
+
{ id: 'claude', name: 'Claude Code', runtime: 'claude', command: 'claude', installCmd: 'npm install -g @anthropic-ai/claude-code' },
|
|
77
|
+
];
|
|
78
|
+
function isRecord(value) {
|
|
79
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
80
|
+
}
|
|
81
|
+
function classifyRuntimeFailure(message) {
|
|
82
|
+
const normalized = message.trim() || 'Runtime failed to start.';
|
|
83
|
+
if (/\b(login|log in|signin|sign in|auth|authentication|unauthori[sz]ed|credential|api key|token)\b/i.test(normalized)) {
|
|
84
|
+
return { status: 'signed-out', reason: normalized };
|
|
85
|
+
}
|
|
86
|
+
if (/missing environment variable/i.test(normalized)) {
|
|
87
|
+
return { status: 'signed-out', reason: normalized };
|
|
88
|
+
}
|
|
89
|
+
return { status: 'error', reason: normalized };
|
|
90
|
+
}
|
|
91
|
+
function isResolvedCommandSource(value) {
|
|
92
|
+
return value === 'user-override' || value === 'descriptor' || value === 'registry';
|
|
93
|
+
}
|
|
94
|
+
function isInstalledRuntimeStatus(value) {
|
|
95
|
+
return value === 'available' || value === 'signed-out' || value === 'error';
|
|
96
|
+
}
|
|
97
|
+
function isMissingRuntimeStatus(value) {
|
|
98
|
+
return value === 'missing' || value === 'error';
|
|
99
|
+
}
|
|
100
|
+
function normalizeResolvedCommand(value) {
|
|
101
|
+
if (!isRecord(value))
|
|
102
|
+
return null;
|
|
103
|
+
if (typeof value.cmd !== 'string' || !Array.isArray(value.args) || !value.args.every((arg) => typeof arg === 'string'))
|
|
104
|
+
return null;
|
|
105
|
+
if (!isResolvedCommandSource(value.source))
|
|
106
|
+
return null;
|
|
107
|
+
return {
|
|
108
|
+
cmd: value.cmd,
|
|
109
|
+
args: value.args,
|
|
110
|
+
source: value.source,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function normalizeDiagnosticHints(value) {
|
|
114
|
+
if (!Array.isArray(value))
|
|
115
|
+
return undefined;
|
|
116
|
+
const hints = value
|
|
117
|
+
.filter((hint) => typeof hint === 'string' && hint.trim().length > 0)
|
|
118
|
+
.map((hint) => hint.trim());
|
|
119
|
+
return hints.length > 0 ? Array.from(new Set(hints)) : undefined;
|
|
120
|
+
}
|
|
121
|
+
function normalizeInstalled(value) {
|
|
122
|
+
if (!isRecord(value))
|
|
123
|
+
return null;
|
|
124
|
+
if (typeof value.id !== 'string' || typeof value.name !== 'string' || typeof value.binaryPath !== 'string')
|
|
125
|
+
return null;
|
|
126
|
+
const resolved = normalizeResolvedCommand(value.resolvedCommand);
|
|
127
|
+
const diagnosticHints = normalizeDiagnosticHints(value.diagnosticHints);
|
|
128
|
+
return {
|
|
129
|
+
id: value.id,
|
|
130
|
+
name: value.name,
|
|
131
|
+
binaryPath: value.binaryPath,
|
|
132
|
+
...(resolved ? { resolvedCommand: resolved } : {}),
|
|
133
|
+
...(isInstalledRuntimeStatus(value.status) ? { status: value.status } : {}),
|
|
134
|
+
...(typeof value.reason === 'string' && value.reason.trim() ? { reason: value.reason } : {}),
|
|
135
|
+
...(diagnosticHints ? { diagnosticHints } : {}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
function normalizeMissing(value) {
|
|
139
|
+
if (!isRecord(value))
|
|
140
|
+
return null;
|
|
141
|
+
if (typeof value.id !== 'string' || typeof value.name !== 'string' || typeof value.installCmd !== 'string')
|
|
142
|
+
return null;
|
|
143
|
+
const diagnosticHints = normalizeDiagnosticHints(value.diagnosticHints);
|
|
144
|
+
return {
|
|
145
|
+
id: value.id,
|
|
146
|
+
name: value.name,
|
|
147
|
+
installCmd: value.installCmd,
|
|
148
|
+
...(typeof value.packageName === 'string' ? { packageName: value.packageName } : {}),
|
|
149
|
+
...(isMissingRuntimeStatus(value.status) ? { status: value.status } : {}),
|
|
150
|
+
...(typeof value.reason === 'string' && value.reason.trim() ? { reason: value.reason } : {}),
|
|
151
|
+
...(diagnosticHints ? { diagnosticHints } : {}),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function isCodexAgent(agent) {
|
|
155
|
+
const name = agent.name.toLowerCase();
|
|
156
|
+
return agent.id === 'codex' || agent.id === 'codex-acp' || name === 'codex' || name.includes('codex');
|
|
157
|
+
}
|
|
158
|
+
function isClaudeAgent(agent) {
|
|
159
|
+
const name = agent.name.toLowerCase();
|
|
160
|
+
return agent.id === 'claude' || agent.id === 'claude-code' || name.includes('claude');
|
|
161
|
+
}
|
|
162
|
+
function nativeDescriptor(input) {
|
|
163
|
+
const status = input.source ? input.source.status ?? 'available' : input.missing?.status ?? 'missing';
|
|
164
|
+
const reason = input.source?.reason ?? input.missing?.reason;
|
|
165
|
+
const diagnosticHints = Array.from(new Set([
|
|
166
|
+
...(input.source?.diagnosticHints ?? input.missing?.diagnosticHints ?? []),
|
|
167
|
+
...nativeRuntimeDiagnosticHints({
|
|
168
|
+
id: input.id,
|
|
169
|
+
name: input.name,
|
|
170
|
+
status,
|
|
171
|
+
reason,
|
|
172
|
+
binaryPath: input.source?.binaryPath,
|
|
173
|
+
installCmd: input.missing?.installCmd,
|
|
174
|
+
}),
|
|
175
|
+
]));
|
|
176
|
+
return {
|
|
177
|
+
id: input.id,
|
|
178
|
+
name: input.name,
|
|
179
|
+
kind: input.id,
|
|
180
|
+
adapter: input.id === 'codex' ? 'codex-app-server' : 'claude-sdk',
|
|
181
|
+
modelOwner: 'external',
|
|
182
|
+
authOwner: 'external',
|
|
183
|
+
permissionOwner: 'external',
|
|
184
|
+
sessionOwner: 'external',
|
|
185
|
+
status,
|
|
186
|
+
capabilities: input.id === 'codex' ? codexCapabilities : claudeCapabilities,
|
|
187
|
+
description: input.id === 'codex'
|
|
188
|
+
? 'Local Codex app-server runtime. Model, approval, and thread behavior are owned by Codex.'
|
|
189
|
+
: 'Local Claude Code runtime. Model, permission, and session behavior are owned by Claude Code.',
|
|
190
|
+
aliases: input.id === 'codex' ? ['codex-acp'] : ['claude-code', 'claude'],
|
|
191
|
+
...(input.id === 'codex' ? { mcpAgentKey: 'codex' } : { mcpAgentKey: 'claude-code' }),
|
|
192
|
+
...(input.source ? {
|
|
193
|
+
sourceAgentId: input.source.id,
|
|
194
|
+
canonicalAgentId: input.source.id,
|
|
195
|
+
binaryPath: input.source.binaryPath,
|
|
196
|
+
...(input.source.resolvedCommand ? { resolvedCommand: input.source.resolvedCommand } : {}),
|
|
197
|
+
} : {}),
|
|
198
|
+
...(!input.source && input.missing ? {
|
|
199
|
+
sourceAgentId: input.missing.id,
|
|
200
|
+
canonicalAgentId: input.missing.id,
|
|
201
|
+
installCmd: input.missing.installCmd,
|
|
202
|
+
...(input.missing.packageName ? { packageName: input.missing.packageName } : {}),
|
|
203
|
+
} : {}),
|
|
204
|
+
availability: {
|
|
205
|
+
checkedAt: input.checkedAt,
|
|
206
|
+
sources: ['native-health'],
|
|
207
|
+
...(reason
|
|
208
|
+
? { reason }
|
|
209
|
+
: !input.source
|
|
210
|
+
? { reason: `${input.name} executable was not detected.` }
|
|
211
|
+
: {}),
|
|
212
|
+
...(diagnosticHints.length > 0 ? { diagnosticHints } : {}),
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function nativeRuntimeDiagnosticHints(input) {
|
|
217
|
+
if (input.status === 'available')
|
|
218
|
+
return [];
|
|
219
|
+
const command = input.id === 'codex' ? 'codex' : 'claude';
|
|
220
|
+
const hints = [];
|
|
221
|
+
if (input.status === 'missing') {
|
|
222
|
+
hints.push(`MindOS checked command "${command}" on the server PATH.`);
|
|
223
|
+
hints.push(input.installCmd
|
|
224
|
+
? `Install it or add it to the PATH used to start MindOS: ${input.installCmd}`
|
|
225
|
+
: `Install ${input.name} or add it to the PATH used to start MindOS.`);
|
|
226
|
+
return hints;
|
|
227
|
+
}
|
|
228
|
+
if (input.binaryPath) {
|
|
229
|
+
hints.push(`MindOS detected ${input.name} at ${input.binaryPath}.`);
|
|
230
|
+
}
|
|
231
|
+
if (input.status === 'signed-out') {
|
|
232
|
+
hints.push(input.id === 'codex'
|
|
233
|
+
? 'Run "codex login status" from the same environment that starts MindOS.'
|
|
234
|
+
: 'Run Claude Code once from the same environment that starts MindOS.');
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
hints.push(input.id === 'codex'
|
|
238
|
+
? 'Run "codex app-server --help" from the MindOS server environment.'
|
|
239
|
+
: 'Run "claude --version" from the MindOS server environment.');
|
|
240
|
+
}
|
|
241
|
+
if (input.reason && /(environment variable|cannot see|env)/i.test(input.reason)) {
|
|
242
|
+
hints.push('Restart MindOS after exporting the required environment variable so the server process inherits it.');
|
|
243
|
+
}
|
|
244
|
+
return hints;
|
|
245
|
+
}
|
|
246
|
+
export function buildAgentRuntimesPayload(input) {
|
|
247
|
+
const installed = input.installed.map(normalizeInstalled).filter((agent) => !!agent);
|
|
248
|
+
const notInstalled = input.notInstalled.map(normalizeMissing).filter((agent) => !!agent);
|
|
249
|
+
const codexInstalled = installed.find(isCodexAgent);
|
|
250
|
+
const claudeInstalled = installed.find(isClaudeAgent);
|
|
251
|
+
const codexMissing = notInstalled.find(isCodexAgent);
|
|
252
|
+
const claudeMissing = notInstalled.find(isClaudeAgent);
|
|
253
|
+
const runtimes = [
|
|
254
|
+
{
|
|
255
|
+
id: 'mindos',
|
|
256
|
+
name: 'MindOS',
|
|
257
|
+
kind: 'mindos',
|
|
258
|
+
adapter: 'mindos',
|
|
259
|
+
modelOwner: 'mindos',
|
|
260
|
+
authOwner: 'mindos',
|
|
261
|
+
permissionOwner: 'mindos',
|
|
262
|
+
sessionOwner: 'mindos',
|
|
263
|
+
status: 'available',
|
|
264
|
+
capabilities: mindosCapabilities,
|
|
265
|
+
description: 'MindOS internal agent using the selected provider and model.',
|
|
266
|
+
availability: { checkedAt: input.checkedAt, sources: ['settings'] },
|
|
267
|
+
},
|
|
268
|
+
nativeDescriptor({
|
|
269
|
+
id: 'codex',
|
|
270
|
+
name: 'Codex',
|
|
271
|
+
checkedAt: input.checkedAt,
|
|
272
|
+
...(codexInstalled ? { source: codexInstalled } : {}),
|
|
273
|
+
...(codexMissing ? { missing: codexMissing } : {}),
|
|
274
|
+
}),
|
|
275
|
+
nativeDescriptor({
|
|
276
|
+
id: 'claude',
|
|
277
|
+
name: 'Claude Code',
|
|
278
|
+
checkedAt: input.checkedAt,
|
|
279
|
+
...(claudeInstalled ? { source: claudeInstalled } : {}),
|
|
280
|
+
...(claudeMissing ? { missing: claudeMissing } : {}),
|
|
281
|
+
}),
|
|
282
|
+
...installed
|
|
283
|
+
.filter((agent) => !isCodexAgent(agent) && !isClaudeAgent(agent))
|
|
284
|
+
.map((agent) => ({
|
|
285
|
+
id: agent.id,
|
|
286
|
+
name: agent.name,
|
|
287
|
+
kind: 'acp',
|
|
288
|
+
adapter: 'acp',
|
|
289
|
+
modelOwner: 'external',
|
|
290
|
+
authOwner: 'external',
|
|
291
|
+
permissionOwner: 'external',
|
|
292
|
+
sessionOwner: 'external',
|
|
293
|
+
status: agent.status ?? 'available',
|
|
294
|
+
capabilities: acpCapabilities,
|
|
295
|
+
description: 'ACP agent selected as the Chat Panel runtime.',
|
|
296
|
+
sourceAgentId: agent.id,
|
|
297
|
+
canonicalAgentId: agent.id,
|
|
298
|
+
binaryPath: agent.binaryPath,
|
|
299
|
+
...(agent.resolvedCommand ? { resolvedCommand: agent.resolvedCommand } : {}),
|
|
300
|
+
availability: {
|
|
301
|
+
checkedAt: input.checkedAt,
|
|
302
|
+
sources: agent.status && agent.status !== 'available' ? ['acp-detect', 'native-health'] : ['acp-detect'],
|
|
303
|
+
...(agent.reason ? { reason: agent.reason } : {}),
|
|
304
|
+
},
|
|
305
|
+
})),
|
|
306
|
+
];
|
|
307
|
+
return { runtimes, installed, notInstalled };
|
|
308
|
+
}
|
|
309
|
+
function buildAcpScopedPayload(input) {
|
|
310
|
+
const installed = input.installed
|
|
311
|
+
.map(normalizeInstalled)
|
|
312
|
+
.filter((agent) => !!agent && !isCodexAgent(agent) && !isClaudeAgent(agent));
|
|
313
|
+
const notInstalled = input.notInstalled
|
|
314
|
+
.map(normalizeMissing)
|
|
315
|
+
.filter((agent) => !!agent && !isCodexAgent(agent) && !isClaudeAgent(agent));
|
|
316
|
+
const runtimes = installed.map((agent) => ({
|
|
317
|
+
id: agent.id,
|
|
318
|
+
name: agent.name,
|
|
319
|
+
kind: 'acp',
|
|
320
|
+
adapter: 'acp',
|
|
321
|
+
modelOwner: 'external',
|
|
322
|
+
authOwner: 'external',
|
|
323
|
+
permissionOwner: 'external',
|
|
324
|
+
sessionOwner: 'external',
|
|
325
|
+
status: agent.status ?? 'available',
|
|
326
|
+
capabilities: acpCapabilities,
|
|
327
|
+
description: 'ACP agent selected as the Chat Panel runtime.',
|
|
328
|
+
sourceAgentId: agent.id,
|
|
329
|
+
canonicalAgentId: agent.id,
|
|
330
|
+
binaryPath: agent.binaryPath,
|
|
331
|
+
...(agent.resolvedCommand ? { resolvedCommand: agent.resolvedCommand } : {}),
|
|
332
|
+
availability: {
|
|
333
|
+
checkedAt: input.checkedAt,
|
|
334
|
+
sources: agent.status && agent.status !== 'available' ? ['acp-detect', 'native-health'] : ['acp-detect'],
|
|
335
|
+
...(agent.reason ? { reason: agent.reason } : {}),
|
|
336
|
+
},
|
|
337
|
+
}));
|
|
338
|
+
return { runtimes, installed, notInstalled };
|
|
339
|
+
}
|
|
340
|
+
async function checkProcessVersion(command, args, timeoutMs) {
|
|
341
|
+
return new Promise((resolve) => {
|
|
342
|
+
const child = spawn(command, args, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
343
|
+
let stdout = '';
|
|
344
|
+
let stderr = '';
|
|
345
|
+
let done = false;
|
|
346
|
+
const finish = (result) => {
|
|
347
|
+
if (done)
|
|
348
|
+
return;
|
|
349
|
+
done = true;
|
|
350
|
+
clearTimeout(timer);
|
|
351
|
+
if (!child.killed)
|
|
352
|
+
child.kill();
|
|
353
|
+
resolve(result);
|
|
354
|
+
};
|
|
355
|
+
const timer = setTimeout(() => {
|
|
356
|
+
finish({ status: 'error', reason: `${command} health check timed out after ${timeoutMs}ms.` });
|
|
357
|
+
}, timeoutMs);
|
|
358
|
+
child.stdout.on('data', (chunk) => { stdout += String(chunk); });
|
|
359
|
+
child.stderr.on('data', (chunk) => { stderr += String(chunk); });
|
|
360
|
+
child.once('error', (error) => finish(classifyRuntimeFailure(error.message)));
|
|
361
|
+
child.once('exit', (code) => {
|
|
362
|
+
if (code === 0) {
|
|
363
|
+
finish({ status: 'available' });
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
finish(classifyRuntimeFailure((stderr || stdout || `${command} exited with code ${code ?? 'unknown'}`).trim()));
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
async function checkCodexCliRuntime(command, timeoutMs) {
|
|
371
|
+
const appServerHelp = await checkProcessVersion(command, ['app-server', '--help'], timeoutMs);
|
|
372
|
+
if (appServerHelp.status !== 'available')
|
|
373
|
+
return appServerHelp;
|
|
374
|
+
const providerEnvironment = checkCodexProviderEnvironment();
|
|
375
|
+
if (providerEnvironment.status !== 'available')
|
|
376
|
+
return providerEnvironment;
|
|
377
|
+
const loginStatus = await checkProcessVersion(command, ['login', 'status'], timeoutMs);
|
|
378
|
+
return mergeCodexProviderAndLoginHealth(providerEnvironment, loginStatus);
|
|
379
|
+
}
|
|
380
|
+
export function mergeCodexProviderAndLoginHealth(providerEnvironment, loginStatus) {
|
|
381
|
+
if (providerEnvironment.status !== 'available')
|
|
382
|
+
return providerEnvironment;
|
|
383
|
+
if (loginStatus.status === 'available')
|
|
384
|
+
return providerEnvironment;
|
|
385
|
+
const hints = [
|
|
386
|
+
...(providerEnvironment.diagnosticHints ?? []),
|
|
387
|
+
'Codex app-server is available. If this Codex profile uses account login, run "codex login status" from the same environment that starts MindOS.',
|
|
388
|
+
...(loginStatus.reason ? [`codex login status returned: ${loginStatus.reason}`] : []),
|
|
389
|
+
];
|
|
390
|
+
return {
|
|
391
|
+
status: 'available',
|
|
392
|
+
diagnosticHints: hints,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
export function checkCodexProviderEnvironment(input = {}) {
|
|
396
|
+
const env = input.env ?? process.env;
|
|
397
|
+
const resolution = resolveCodexProviderEnvironment({
|
|
398
|
+
env,
|
|
399
|
+
configText: input.configText,
|
|
400
|
+
configPath: input.configPath,
|
|
401
|
+
readShellEnvValue: input.readShellEnvValue,
|
|
402
|
+
});
|
|
403
|
+
if (!resolution.envKey)
|
|
404
|
+
return { status: 'available' };
|
|
405
|
+
if (resolution.value) {
|
|
406
|
+
return {
|
|
407
|
+
status: 'available',
|
|
408
|
+
...(resolution.source === 'login-shell'
|
|
409
|
+
? { diagnosticHints: [`Codex provider environment key ${resolution.envKey} was found through MindOS runtime environment fallback and will be injected only into Codex app-server.`] }
|
|
410
|
+
: {}),
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
const configText = input.configText ?? readCodexConfigText(input.configPath, env);
|
|
414
|
+
const provider = configText ? extractTomlStringValue(configText, 'model_provider') : undefined;
|
|
415
|
+
return {
|
|
416
|
+
status: 'signed-out',
|
|
417
|
+
reason: provider
|
|
418
|
+
? `Codex model provider "${provider}" requires ${resolution.envKey}, but MindOS cannot see that environment variable in the app process, OS user environment, or login shell. Export ${resolution.envKey} in your shell profile or OS user environment before starting MindOS, or switch Codex to a provider that does not require it.`
|
|
419
|
+
: `Codex requires ${resolution.envKey}, but MindOS cannot see that environment variable in the app process, OS user environment, or login shell.`,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function extractTomlStringValue(text, key) {
|
|
423
|
+
const escapedKey = escapeRegExp(key);
|
|
424
|
+
const match = text.match(new RegExp(`^\\s*${escapedKey}\\s*=\\s*"([^"]*)"\\s*$`, 'm'));
|
|
425
|
+
return match?.[1]?.trim() || undefined;
|
|
426
|
+
}
|
|
427
|
+
function escapeRegExp(value) {
|
|
428
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
429
|
+
}
|
|
430
|
+
export async function defaultCheckNativeRuntimeHealth(input) {
|
|
431
|
+
const timeoutMs = input.timeoutMs ?? NATIVE_HEALTH_TIMEOUT_MS;
|
|
432
|
+
if (input.runtime === 'codex') {
|
|
433
|
+
return checkCodexCliRuntime(input.agent.binaryPath, timeoutMs);
|
|
434
|
+
}
|
|
435
|
+
return checkClaudeRuntimeHealth({ binaryPath: input.agent.binaryPath, timeoutMs });
|
|
436
|
+
}
|
|
437
|
+
export async function checkClaudeRuntimeHealth(input) {
|
|
438
|
+
const timeoutMs = input.timeoutMs ?? NATIVE_HEALTH_TIMEOUT_MS;
|
|
439
|
+
const binaryPath = input.binaryPath;
|
|
440
|
+
const importSdk = input.importSdk ?? (() => import('@anthropic-ai/claude-agent-sdk'));
|
|
441
|
+
const checkCliVersion = input.checkCliVersion ?? ((path, ms) => checkProcessVersion(path, ['--version'], ms));
|
|
442
|
+
if (!binaryPath.trim() || binaryPath.startsWith('sdk:')) {
|
|
443
|
+
return {
|
|
444
|
+
status: 'error',
|
|
445
|
+
reason: 'Claude Code requires a local claude executable on the MindOS server PATH. MindOS does not bundle the Claude Agent SDK native runtime.',
|
|
446
|
+
diagnosticHints: [
|
|
447
|
+
'Install Claude Code locally and restart MindOS so the server process can resolve the claude command.',
|
|
448
|
+
],
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
const cliHealth = await checkCliVersion(binaryPath, timeoutMs);
|
|
452
|
+
if (cliHealth.status !== 'available')
|
|
453
|
+
return cliHealth;
|
|
454
|
+
try {
|
|
455
|
+
const sdk = await withTimeout(importSdk(), timeoutMs, `Claude Agent SDK health check timed out after ${timeoutMs}ms.`);
|
|
456
|
+
if (typeof sdk.query === 'function') {
|
|
457
|
+
return {
|
|
458
|
+
status: 'available',
|
|
459
|
+
diagnosticHints: [
|
|
460
|
+
...(cliHealth.diagnosticHints ?? []),
|
|
461
|
+
`Claude Agent SDK bridge is available and will use the local Claude Code CLI at ${binaryPath}.`,
|
|
462
|
+
],
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
status: 'available',
|
|
467
|
+
diagnosticHints: [
|
|
468
|
+
...(cliHealth.diagnosticHints ?? []),
|
|
469
|
+
`Claude Code CLI is available at ${binaryPath}; Claude Agent SDK bridge did not expose query(), so MindOS will use CLI fallback.`,
|
|
470
|
+
],
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
return {
|
|
475
|
+
status: 'available',
|
|
476
|
+
diagnosticHints: [
|
|
477
|
+
...(cliHealth.diagnosticHints ?? []),
|
|
478
|
+
`Claude Code CLI is available at ${binaryPath}; Claude Agent SDK bridge is unavailable, so MindOS will use CLI fallback. ${error instanceof Error ? error.message : String(error)}`,
|
|
479
|
+
],
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
async function applyNativeRuntimeHealth(installed, services) {
|
|
484
|
+
const checkNativeRuntimeHealth = services.checkNativeRuntimeHealth ?? defaultCheckNativeRuntimeHealth;
|
|
485
|
+
const normalized = installed.map((agent) => ({ raw: agent, detected: normalizeInstalled(agent) }));
|
|
486
|
+
const enriched = await Promise.all(normalized.map(async ({ raw, detected }) => {
|
|
487
|
+
if (!detected)
|
|
488
|
+
return raw;
|
|
489
|
+
const runtime = isCodexAgent(detected) ? 'codex' : isClaudeAgent(detected) ? 'claude' : null;
|
|
490
|
+
if (!runtime)
|
|
491
|
+
return raw;
|
|
492
|
+
if (detected.status)
|
|
493
|
+
return raw;
|
|
494
|
+
try {
|
|
495
|
+
const health = await checkNativeRuntimeHealth({
|
|
496
|
+
runtime,
|
|
497
|
+
agent: detected,
|
|
498
|
+
timeoutMs: NATIVE_HEALTH_TIMEOUT_MS,
|
|
499
|
+
});
|
|
500
|
+
return {
|
|
501
|
+
...(isRecord(raw) ? raw : detected),
|
|
502
|
+
status: health.status,
|
|
503
|
+
...(health.reason ? { reason: health.reason } : {}),
|
|
504
|
+
...(health.diagnosticHints ? { diagnosticHints: health.diagnosticHints } : {}),
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
catch (error) {
|
|
508
|
+
const result = classifyRuntimeFailure(error instanceof Error ? error.message : String(error));
|
|
509
|
+
return {
|
|
510
|
+
...(isRecord(raw) ? raw : detected),
|
|
511
|
+
status: result.status,
|
|
512
|
+
...(result.reason ? { reason: result.reason } : {}),
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
}));
|
|
516
|
+
return enriched;
|
|
517
|
+
}
|
|
518
|
+
async function detectNativeRuntimeDefinition(candidate, services) {
|
|
519
|
+
const checkNativeRuntimeHealth = services.checkNativeRuntimeHealth ?? defaultCheckNativeRuntimeHealth;
|
|
520
|
+
const resolveRuntimeCommand = services.resolveRuntimeCommand ?? resolveCommandPath;
|
|
521
|
+
if (candidate.runtime === 'claude') {
|
|
522
|
+
return detectClaudeNativeRuntimeDefinition(candidate, services);
|
|
523
|
+
}
|
|
524
|
+
const binaryPath = await resolveRuntimeCommand(candidate.command);
|
|
525
|
+
if (!binaryPath) {
|
|
526
|
+
return {
|
|
527
|
+
id: candidate.id,
|
|
528
|
+
name: candidate.name,
|
|
529
|
+
installCmd: candidate.installCmd,
|
|
530
|
+
packageName: candidate.installCmd.match(/npm install -g (.+)/)?.[1],
|
|
531
|
+
status: 'missing',
|
|
532
|
+
reason: `${candidate.name} executable was not detected.`,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
const health = await checkNativeRuntimeHealth({
|
|
537
|
+
runtime: candidate.runtime,
|
|
538
|
+
agent: { id: candidate.id, name: candidate.name, binaryPath },
|
|
539
|
+
timeoutMs: NATIVE_HEALTH_TIMEOUT_MS,
|
|
540
|
+
});
|
|
541
|
+
return {
|
|
542
|
+
id: candidate.id,
|
|
543
|
+
name: candidate.name,
|
|
544
|
+
binaryPath,
|
|
545
|
+
resolvedCommand: { cmd: candidate.command, args: [], source: 'descriptor' },
|
|
546
|
+
status: health.status,
|
|
547
|
+
...(health.reason ? { reason: health.reason } : {}),
|
|
548
|
+
...(health.diagnosticHints ? { diagnosticHints: health.diagnosticHints } : {}),
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
const result = classifyRuntimeFailure(error instanceof Error ? error.message : String(error));
|
|
553
|
+
return {
|
|
554
|
+
id: candidate.id,
|
|
555
|
+
name: candidate.name,
|
|
556
|
+
binaryPath,
|
|
557
|
+
resolvedCommand: { cmd: candidate.command, args: [], source: 'descriptor' },
|
|
558
|
+
status: result.status,
|
|
559
|
+
...(result.reason ? { reason: result.reason } : {}),
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
async function detectClaudeNativeRuntimeDefinition(candidate, services) {
|
|
564
|
+
const checkNativeRuntimeHealth = services.checkNativeRuntimeHealth ?? defaultCheckNativeRuntimeHealth;
|
|
565
|
+
const resolveRuntimeCommand = services.resolveRuntimeCommand ?? resolveCommandPath;
|
|
566
|
+
const commandResolution = { failureReason: undefined };
|
|
567
|
+
const binaryPath = await withTimeout(resolveRuntimeCommand(candidate.command), RUNTIME_DETECTION_TIMEOUT_MS, `Claude Code executable detection timed out after ${RUNTIME_DETECTION_TIMEOUT_MS}ms.`).catch((error) => {
|
|
568
|
+
commandResolution.failureReason = error instanceof Error ? error.message : String(error);
|
|
569
|
+
return null;
|
|
570
|
+
});
|
|
571
|
+
if (!binaryPath) {
|
|
572
|
+
const timedOut = commandResolution.failureReason?.includes('timed out after');
|
|
573
|
+
return {
|
|
574
|
+
id: candidate.id,
|
|
575
|
+
name: candidate.name,
|
|
576
|
+
installCmd: candidate.installCmd,
|
|
577
|
+
packageName: candidate.installCmd.match(/npm install -g (.+)/)?.[1],
|
|
578
|
+
status: 'missing',
|
|
579
|
+
reason: timedOut
|
|
580
|
+
? `${commandResolution.failureReason} MindOS does not bundle the Claude Agent SDK native runtime.`
|
|
581
|
+
: 'Claude Code executable was not detected. MindOS does not bundle the Claude Agent SDK native runtime.',
|
|
582
|
+
diagnosticHints: [
|
|
583
|
+
'Install Claude Code locally or add claude to the PATH used to start MindOS.',
|
|
584
|
+
],
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
try {
|
|
588
|
+
const health = await checkNativeRuntimeHealth({
|
|
589
|
+
runtime: candidate.runtime,
|
|
590
|
+
agent: { id: candidate.id, name: candidate.name, binaryPath },
|
|
591
|
+
timeoutMs: NATIVE_HEALTH_TIMEOUT_MS,
|
|
592
|
+
});
|
|
593
|
+
return {
|
|
594
|
+
id: candidate.id,
|
|
595
|
+
name: candidate.name,
|
|
596
|
+
binaryPath,
|
|
597
|
+
resolvedCommand: { cmd: candidate.command, args: [], source: 'descriptor' },
|
|
598
|
+
status: health.status,
|
|
599
|
+
...(health.reason ? { reason: health.reason } : {}),
|
|
600
|
+
...(health.diagnosticHints ? { diagnosticHints: health.diagnosticHints } : {}),
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
catch (error) {
|
|
604
|
+
const result = classifyRuntimeFailure(error instanceof Error ? error.message : String(error));
|
|
605
|
+
return {
|
|
606
|
+
id: candidate.id,
|
|
607
|
+
name: candidate.name,
|
|
608
|
+
binaryPath,
|
|
609
|
+
resolvedCommand: { cmd: candidate.command, args: [], source: 'descriptor' },
|
|
610
|
+
status: result.status,
|
|
611
|
+
...(result.reason ? { reason: result.reason } : {}),
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
async function detectNativeRuntimes(services) {
|
|
616
|
+
const results = await Promise.all(nativeRuntimeDefinitions.map((candidate) => detectNativeRuntimeDefinition(candidate, services)));
|
|
617
|
+
return {
|
|
618
|
+
installed: results.filter((agent) => 'binaryPath' in agent),
|
|
619
|
+
notInstalled: results.filter((agent) => 'installCmd' in agent),
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
function isNativeRuntimeId(value) {
|
|
623
|
+
return value === 'codex' || value === 'claude';
|
|
624
|
+
}
|
|
625
|
+
async function detectSingleNativeRuntime(runtime, services) {
|
|
626
|
+
const candidate = nativeRuntimeDefinitions.find((definition) => definition.runtime === runtime);
|
|
627
|
+
if (!candidate)
|
|
628
|
+
throw new Error(`Unsupported native runtime: ${runtime}`);
|
|
629
|
+
const result = await detectNativeRuntimeDefinition(candidate, services);
|
|
630
|
+
const checkedAt = new Date(services.now?.() ?? Date.now()).toISOString();
|
|
631
|
+
return nativeDescriptor({
|
|
632
|
+
id: runtime,
|
|
633
|
+
name: candidate.name,
|
|
634
|
+
checkedAt,
|
|
635
|
+
...('binaryPath' in result ? { source: result } : { missing: result }),
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
async function withTimeout(promise, timeoutMs, message) {
|
|
639
|
+
let timer = null;
|
|
640
|
+
try {
|
|
641
|
+
return await Promise.race([
|
|
642
|
+
promise,
|
|
643
|
+
new Promise((_, reject) => {
|
|
644
|
+
timer = setTimeout(() => reject(new Error(message)), timeoutMs);
|
|
645
|
+
}),
|
|
646
|
+
]);
|
|
647
|
+
}
|
|
648
|
+
finally {
|
|
649
|
+
if (timer)
|
|
650
|
+
clearTimeout(timer);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
export async function handleAgentRuntimesGet(searchParams, services = {}) {
|
|
654
|
+
try {
|
|
655
|
+
const scope = searchParams.get('scope');
|
|
656
|
+
if (scope && scope !== 'acp') {
|
|
657
|
+
return json({ error: `Unsupported scope: ${scope}` }, { status: 400 });
|
|
658
|
+
}
|
|
659
|
+
const runtime = searchParams.get('runtime');
|
|
660
|
+
if (runtime) {
|
|
661
|
+
if (!isNativeRuntimeId(runtime)) {
|
|
662
|
+
return json({ error: `Unsupported runtime: ${runtime}` }, { status: 400 });
|
|
663
|
+
}
|
|
664
|
+
const descriptor = await detectSingleNativeRuntime(runtime, services);
|
|
665
|
+
return json({ runtime: descriptor }, { headers: { 'Cache-Control': 'no-store' } });
|
|
666
|
+
}
|
|
667
|
+
const detectLocalAcpAgents = services.detectLocalAcpAgents ?? defaultDetectLocalAcpAgents;
|
|
668
|
+
if (scope === 'acp') {
|
|
669
|
+
const acpDetection = await withTimeout(detectLocalAcpAgents({ overrides: services.readSettings?.().acpAgents }), RUNTIME_DETECTION_TIMEOUT_MS, `Agent runtime detection timed out after ${RUNTIME_DETECTION_TIMEOUT_MS}ms.`);
|
|
670
|
+
return json(buildAcpScopedPayload({
|
|
671
|
+
installed: Array.isArray(acpDetection.installed) ? acpDetection.installed : [],
|
|
672
|
+
notInstalled: Array.isArray(acpDetection.notInstalled) ? acpDetection.notInstalled : [],
|
|
673
|
+
checkedAt: new Date(services.now?.() ?? Date.now()).toISOString(),
|
|
674
|
+
}), { headers: searchParams.get('force') === '1' ? { 'Cache-Control': 'no-store' } : privateCacheHeaders(1800) });
|
|
675
|
+
}
|
|
676
|
+
const nativeDetectionPromise = detectNativeRuntimes(services);
|
|
677
|
+
const acpDetectionPromise = (async () => {
|
|
678
|
+
try {
|
|
679
|
+
return await withTimeout(detectLocalAcpAgents({ overrides: services.readSettings?.().acpAgents }), RUNTIME_DETECTION_TIMEOUT_MS, `Agent runtime detection timed out after ${RUNTIME_DETECTION_TIMEOUT_MS}ms.`);
|
|
680
|
+
}
|
|
681
|
+
catch {
|
|
682
|
+
return { installed: [], notInstalled: [] };
|
|
683
|
+
}
|
|
684
|
+
})();
|
|
685
|
+
const [nativeDetection, acpDetection] = await Promise.all([nativeDetectionPromise, acpDetectionPromise]);
|
|
686
|
+
const acpInstalled = Array.isArray(acpDetection.installed) ? acpDetection.installed : [];
|
|
687
|
+
const acpNotInstalled = Array.isArray(acpDetection.notInstalled) ? acpDetection.notInstalled : [];
|
|
688
|
+
const acpRuntimeInstalled = acpInstalled.filter((agent) => {
|
|
689
|
+
const normalized = normalizeInstalled(agent);
|
|
690
|
+
return !normalized || (!isCodexAgent(normalized) && !isClaudeAgent(normalized));
|
|
691
|
+
});
|
|
692
|
+
const acpRuntimeNotInstalled = acpNotInstalled.filter((agent) => {
|
|
693
|
+
const normalized = normalizeMissing(agent);
|
|
694
|
+
return !normalized || (!isCodexAgent(normalized) && !isClaudeAgent(normalized));
|
|
695
|
+
});
|
|
696
|
+
const installed = await applyNativeRuntimeHealth([...nativeDetection.installed, ...acpRuntimeInstalled], services);
|
|
697
|
+
const payload = buildAgentRuntimesPayload({
|
|
698
|
+
installed,
|
|
699
|
+
notInstalled: [...nativeDetection.notInstalled, ...acpRuntimeNotInstalled],
|
|
700
|
+
checkedAt: new Date(services.now?.() ?? Date.now()).toISOString(),
|
|
701
|
+
});
|
|
702
|
+
return json({
|
|
703
|
+
...payload,
|
|
704
|
+
installed: acpInstalled.map(normalizeInstalled).filter((agent) => !!agent),
|
|
705
|
+
notInstalled: acpNotInstalled.map(normalizeMissing).filter((agent) => !!agent),
|
|
706
|
+
}, { headers: searchParams.get('force') === '1' ? { 'Cache-Control': 'no-store' } : privateCacheHeaders(1800) });
|
|
707
|
+
}
|
|
708
|
+
catch (error) {
|
|
709
|
+
return errorResponse(error);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
//# sourceMappingURL=agent-runtimes.js.map
|