@mcoda/agents 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/README.md +1 -0
- package/dist/AgentService/AgentService.d.ts +3 -1
- package/dist/AgentService/AgentService.d.ts.map +1 -1
- package/dist/AgentService/AgentService.js +189 -24
- package/dist/adapters/AdapterTypes.d.ts +10 -0
- package/dist/adapters/AdapterTypes.d.ts.map +1 -1
- package/dist/adapters/codali/CodaliAdapter.d.ts +19 -0
- package/dist/adapters/codali/CodaliAdapter.d.ts.map +1 -0
- package/dist/adapters/codali/CodaliAdapter.js +290 -0
- package/dist/adapters/codali/CodaliCliRunner.d.ts +36 -0
- package/dist/adapters/codali/CodaliCliRunner.d.ts.map +1 -0
- package/dist/adapters/codali/CodaliCliRunner.js +230 -0
- package/dist/adapters/codex/CodexCliRunner.d.ts.map +1 -1
- package/dist/adapters/codex/CodexCliRunner.js +628 -34
- package/dist/adapters/ollama/OllamaRemoteAdapter.d.ts.map +1 -1
- package/dist/adapters/ollama/OllamaRemoteAdapter.js +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/package.json +3 -3
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { cliHealthy, runCodaliExec, runCodaliStream } from "./CodaliCliRunner.js";
|
|
2
|
+
const resolveString = (value) => (typeof value === "string" && value.trim() ? value : undefined);
|
|
3
|
+
const resolveMetadataValue = (metadata, keys) => {
|
|
4
|
+
for (const key of keys) {
|
|
5
|
+
const resolved = resolveString(metadata[key]);
|
|
6
|
+
if (resolved)
|
|
7
|
+
return resolved;
|
|
8
|
+
}
|
|
9
|
+
return undefined;
|
|
10
|
+
};
|
|
11
|
+
const resolveWorkspaceRoot = (request) => {
|
|
12
|
+
const metadata = request.metadata ?? {};
|
|
13
|
+
return (resolveString(metadata.workspaceRoot) ??
|
|
14
|
+
resolveString(metadata.workspace_root) ??
|
|
15
|
+
resolveString(metadata.repoRoot) ??
|
|
16
|
+
process.cwd());
|
|
17
|
+
};
|
|
18
|
+
const resolveCodaliEnv = (metadata) => {
|
|
19
|
+
const raw = metadata.codaliEnv ?? metadata.codali_env;
|
|
20
|
+
if (!raw || typeof raw !== "object")
|
|
21
|
+
return undefined;
|
|
22
|
+
const env = {};
|
|
23
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
24
|
+
if (value === undefined || value === null)
|
|
25
|
+
continue;
|
|
26
|
+
if (typeof value === "string") {
|
|
27
|
+
if (value.trim().length > 0)
|
|
28
|
+
env[key] = value;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
32
|
+
env[key] = String(value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return Object.keys(env).length ? env : undefined;
|
|
36
|
+
};
|
|
37
|
+
const PROVIDERS_REQUIRING_API_KEY = new Set(["openai-compatible"]);
|
|
38
|
+
const SESSION_AUTH_ADAPTERS = new Set(["codex-cli", "openai-cli", "gemini-cli"]);
|
|
39
|
+
const UNSUPPORTED_CODALI_ADAPTERS = new Set(["gemini-cli", "zhipu-api"]);
|
|
40
|
+
const resolveSourceAdapter = (request, config) => {
|
|
41
|
+
const metadata = request.metadata ?? {};
|
|
42
|
+
return (resolveString(metadata.sourceAdapter) ??
|
|
43
|
+
resolveString(metadata.agentAdapter) ??
|
|
44
|
+
resolveString(metadata.agent_adapter) ??
|
|
45
|
+
resolveString(config.agent?.adapter) ??
|
|
46
|
+
resolveString(config.sourceAdapter));
|
|
47
|
+
};
|
|
48
|
+
const resolveAgentId = (request, config) => {
|
|
49
|
+
const metadata = request.metadata ?? {};
|
|
50
|
+
return (resolveString(metadata.agentId) ??
|
|
51
|
+
resolveString(metadata.agent_id) ??
|
|
52
|
+
resolveString(config.agent?.id));
|
|
53
|
+
};
|
|
54
|
+
const resolveAgentSlug = (request, config) => {
|
|
55
|
+
const metadata = request.metadata ?? {};
|
|
56
|
+
return (resolveString(metadata.agentSlug) ??
|
|
57
|
+
resolveString(metadata.agent_slug) ??
|
|
58
|
+
resolveString(config.agent?.slug));
|
|
59
|
+
};
|
|
60
|
+
export const resolveCodaliProviderFromAdapter = (params) => {
|
|
61
|
+
const sourceAdapter = params.sourceAdapter;
|
|
62
|
+
const explicitProvider = params.explicitProvider;
|
|
63
|
+
if (explicitProvider) {
|
|
64
|
+
const providerRequires = PROVIDERS_REQUIRING_API_KEY.has(explicitProvider);
|
|
65
|
+
const requiresApiKey = providerRequires && !SESSION_AUTH_ADAPTERS.has(sourceAdapter ?? "");
|
|
66
|
+
return {
|
|
67
|
+
provider: explicitProvider,
|
|
68
|
+
sourceAdapter,
|
|
69
|
+
requiresApiKey,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (sourceAdapter) {
|
|
73
|
+
if (UNSUPPORTED_CODALI_ADAPTERS.has(sourceAdapter)) {
|
|
74
|
+
throw new Error(`CODALI_UNSUPPORTED_ADAPTER: ${sourceAdapter} is not supported; configure a codali provider explicitly or use an openai/ollama adapter.`);
|
|
75
|
+
}
|
|
76
|
+
if (sourceAdapter === "openai-api") {
|
|
77
|
+
return { provider: "openai-compatible", sourceAdapter, requiresApiKey: true };
|
|
78
|
+
}
|
|
79
|
+
if (["openai-cli", "codex-cli"].includes(sourceAdapter)) {
|
|
80
|
+
return { provider: "codex-cli", sourceAdapter, requiresApiKey: false };
|
|
81
|
+
}
|
|
82
|
+
if (["ollama-remote", "ollama-cli", "local-model"].includes(sourceAdapter)) {
|
|
83
|
+
return { provider: "ollama-remote", sourceAdapter, requiresApiKey: false };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const requiresApiKey = PROVIDERS_REQUIRING_API_KEY.has("openai-compatible") && !SESSION_AUTH_ADAPTERS.has(sourceAdapter ?? "");
|
|
87
|
+
return { provider: "openai-compatible", sourceAdapter, requiresApiKey };
|
|
88
|
+
};
|
|
89
|
+
const resolveProviderInfo = (request, config) => {
|
|
90
|
+
const anyConfig = config;
|
|
91
|
+
const explicitProvider = resolveString(anyConfig.provider) ?? resolveString(anyConfig.llmProvider);
|
|
92
|
+
const sourceAdapter = resolveSourceAdapter(request, config);
|
|
93
|
+
return resolveCodaliProviderFromAdapter({ sourceAdapter, explicitProvider });
|
|
94
|
+
};
|
|
95
|
+
const ensureApiKey = (provider, sourceAdapter, requiresApiKey, config) => {
|
|
96
|
+
if (!requiresApiKey || !PROVIDERS_REQUIRING_API_KEY.has(provider))
|
|
97
|
+
return;
|
|
98
|
+
if (config.apiKey || process.env.CODALI_API_KEY)
|
|
99
|
+
return;
|
|
100
|
+
const agentLabel = config.agent.slug ?? config.agent.id;
|
|
101
|
+
const sourceLabel = sourceAdapter ? ` (source adapter: ${sourceAdapter})` : "";
|
|
102
|
+
throw new Error(`AUTH_REQUIRED: API key missing for codali provider ${provider}${sourceLabel}; set CODALI_API_KEY or run \\\"mcoda agent auth set ${agentLabel}\\\".`);
|
|
103
|
+
};
|
|
104
|
+
const resolveBaseUrl = (config) => {
|
|
105
|
+
const anyConfig = config;
|
|
106
|
+
const agentConfig = config.agent?.config;
|
|
107
|
+
return (resolveString(anyConfig.baseUrl) ??
|
|
108
|
+
resolveString(anyConfig.endpoint) ??
|
|
109
|
+
resolveString(anyConfig.apiBaseUrl) ??
|
|
110
|
+
resolveString(agentConfig?.baseUrl) ??
|
|
111
|
+
resolveString(agentConfig?.endpoint) ??
|
|
112
|
+
resolveString(agentConfig?.apiBaseUrl));
|
|
113
|
+
};
|
|
114
|
+
const resolveDocdexBaseUrl = (config) => {
|
|
115
|
+
const anyConfig = config;
|
|
116
|
+
return resolveString(anyConfig.docdexBaseUrl) ?? resolveString(anyConfig.docdex?.baseUrl);
|
|
117
|
+
};
|
|
118
|
+
const resolveDocdexRepoId = (config) => {
|
|
119
|
+
const anyConfig = config;
|
|
120
|
+
return resolveString(anyConfig.docdexRepoId) ?? resolveString(anyConfig.docdex?.repoId);
|
|
121
|
+
};
|
|
122
|
+
const resolveDocdexRepoRoot = (config) => {
|
|
123
|
+
const anyConfig = config;
|
|
124
|
+
return resolveString(anyConfig.docdexRepoRoot) ?? resolveString(anyConfig.docdex?.repoRoot);
|
|
125
|
+
};
|
|
126
|
+
const resolveRunId = (metadata) => {
|
|
127
|
+
const explicit = resolveMetadataValue(metadata, ["runId", "run_id"]);
|
|
128
|
+
if (explicit)
|
|
129
|
+
return explicit;
|
|
130
|
+
const commandRunId = resolveMetadataValue(metadata, ["commandRunId", "command_run_id"]);
|
|
131
|
+
const taskKey = resolveMetadataValue(metadata, ["taskKey", "task_key"]);
|
|
132
|
+
if (!commandRunId || !taskKey)
|
|
133
|
+
return undefined;
|
|
134
|
+
const raw = `${commandRunId}-${taskKey}`;
|
|
135
|
+
return raw.replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
136
|
+
};
|
|
137
|
+
export class CodaliAdapter {
|
|
138
|
+
constructor(config) {
|
|
139
|
+
this.config = config;
|
|
140
|
+
}
|
|
141
|
+
async getCapabilities() {
|
|
142
|
+
return this.config.capabilities;
|
|
143
|
+
}
|
|
144
|
+
async healthCheck() {
|
|
145
|
+
const started = Date.now();
|
|
146
|
+
const health = cliHealthy();
|
|
147
|
+
const status = health.ok ? "healthy" : "unreachable";
|
|
148
|
+
return {
|
|
149
|
+
agentId: this.config.agent.id,
|
|
150
|
+
status,
|
|
151
|
+
lastCheckedAt: new Date().toISOString(),
|
|
152
|
+
latencyMs: Date.now() - started,
|
|
153
|
+
details: { adapter: "codali-cli", ...(health.details ?? {}) },
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
async invoke(request) {
|
|
157
|
+
const metadata = (request.metadata ?? {});
|
|
158
|
+
const workspaceRoot = resolveWorkspaceRoot(request);
|
|
159
|
+
const providerInfo = resolveProviderInfo(request, this.config);
|
|
160
|
+
ensureApiKey(providerInfo.provider, providerInfo.sourceAdapter, providerInfo.requiresApiKey, this.config);
|
|
161
|
+
const provider = providerInfo.provider;
|
|
162
|
+
const agentId = resolveAgentId(request, this.config);
|
|
163
|
+
const agentSlug = resolveAgentSlug(request, this.config);
|
|
164
|
+
const baseUrl = resolveBaseUrl(this.config);
|
|
165
|
+
const docdexBaseUrl = resolveMetadataValue(metadata, ["docdexBaseUrl", "docdex_base_url"]) ?? resolveDocdexBaseUrl(this.config);
|
|
166
|
+
const docdexRepoId = resolveMetadataValue(metadata, ["docdexRepoId", "docdex_repo_id"]) ?? resolveDocdexRepoId(this.config);
|
|
167
|
+
const docdexRepoRoot = resolveMetadataValue(metadata, ["docdexRepoRoot", "docdex_repo_root"]) ?? resolveDocdexRepoRoot(this.config);
|
|
168
|
+
const codaliEnv = resolveCodaliEnv(metadata);
|
|
169
|
+
const runId = resolveRunId(metadata);
|
|
170
|
+
const taskId = resolveMetadataValue(metadata, ["taskId", "task_id"]);
|
|
171
|
+
const taskKey = resolveMetadataValue(metadata, ["taskKey", "task_key"]);
|
|
172
|
+
const project = resolveMetadataValue(metadata, ["projectKey", "project_key", "project"]);
|
|
173
|
+
const command = resolveMetadataValue(metadata, ["command"]);
|
|
174
|
+
const commandRunId = resolveMetadataValue(metadata, ["commandRunId", "command_run_id"]);
|
|
175
|
+
const jobId = resolveMetadataValue(metadata, ["jobId", "job_id"]);
|
|
176
|
+
const result = runCodaliExec(request.input, {
|
|
177
|
+
workspaceRoot,
|
|
178
|
+
project,
|
|
179
|
+
command,
|
|
180
|
+
commandRunId,
|
|
181
|
+
jobId,
|
|
182
|
+
runId,
|
|
183
|
+
taskId,
|
|
184
|
+
taskKey,
|
|
185
|
+
agentId,
|
|
186
|
+
agentSlug,
|
|
187
|
+
provider,
|
|
188
|
+
model: this.config.model ?? "default",
|
|
189
|
+
apiKey: this.config.apiKey,
|
|
190
|
+
baseUrl,
|
|
191
|
+
docdexBaseUrl,
|
|
192
|
+
docdexRepoId,
|
|
193
|
+
docdexRepoRoot,
|
|
194
|
+
env: codaliEnv,
|
|
195
|
+
});
|
|
196
|
+
return {
|
|
197
|
+
output: result.output,
|
|
198
|
+
adapter: this.config.adapter ?? "codali-cli",
|
|
199
|
+
model: this.config.model,
|
|
200
|
+
metadata: {
|
|
201
|
+
mode: "cli",
|
|
202
|
+
capabilities: this.config.capabilities,
|
|
203
|
+
adapterType: this.config.adapter ?? "codali-cli",
|
|
204
|
+
authMode: "cli",
|
|
205
|
+
provider,
|
|
206
|
+
sourceAdapter: providerInfo.sourceAdapter,
|
|
207
|
+
baseUrl,
|
|
208
|
+
logPath: result.meta?.logPath,
|
|
209
|
+
touchedFiles: result.meta?.touchedFiles,
|
|
210
|
+
runId: result.meta?.runId,
|
|
211
|
+
command,
|
|
212
|
+
commandRunId,
|
|
213
|
+
jobId,
|
|
214
|
+
agentId,
|
|
215
|
+
agentSlug,
|
|
216
|
+
project,
|
|
217
|
+
taskId,
|
|
218
|
+
taskKey,
|
|
219
|
+
raw: result.raw,
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
async *invokeStream(request) {
|
|
224
|
+
const metadata = (request.metadata ?? {});
|
|
225
|
+
const workspaceRoot = resolveWorkspaceRoot(request);
|
|
226
|
+
const providerInfo = resolveProviderInfo(request, this.config);
|
|
227
|
+
ensureApiKey(providerInfo.provider, providerInfo.sourceAdapter, providerInfo.requiresApiKey, this.config);
|
|
228
|
+
const provider = providerInfo.provider;
|
|
229
|
+
const agentId = resolveAgentId(request, this.config);
|
|
230
|
+
const agentSlug = resolveAgentSlug(request, this.config);
|
|
231
|
+
const baseUrl = resolveBaseUrl(this.config);
|
|
232
|
+
const docdexBaseUrl = resolveMetadataValue(metadata, ["docdexBaseUrl", "docdex_base_url"]) ?? resolveDocdexBaseUrl(this.config);
|
|
233
|
+
const docdexRepoId = resolveMetadataValue(metadata, ["docdexRepoId", "docdex_repo_id"]) ?? resolveDocdexRepoId(this.config);
|
|
234
|
+
const docdexRepoRoot = resolveMetadataValue(metadata, ["docdexRepoRoot", "docdex_repo_root"]) ?? resolveDocdexRepoRoot(this.config);
|
|
235
|
+
const codaliEnv = resolveCodaliEnv(metadata);
|
|
236
|
+
const runId = resolveRunId(metadata);
|
|
237
|
+
const taskId = resolveMetadataValue(metadata, ["taskId", "task_id"]);
|
|
238
|
+
const taskKey = resolveMetadataValue(metadata, ["taskKey", "task_key"]);
|
|
239
|
+
const project = resolveMetadataValue(metadata, ["projectKey", "project_key", "project"]);
|
|
240
|
+
const command = resolveMetadataValue(metadata, ["command"]);
|
|
241
|
+
const commandRunId = resolveMetadataValue(metadata, ["commandRunId", "command_run_id"]);
|
|
242
|
+
const jobId = resolveMetadataValue(metadata, ["jobId", "job_id"]);
|
|
243
|
+
const baseMetadata = {
|
|
244
|
+
mode: "cli",
|
|
245
|
+
capabilities: this.config.capabilities,
|
|
246
|
+
adapterType: this.config.adapter ?? "codali-cli",
|
|
247
|
+
authMode: "cli",
|
|
248
|
+
provider,
|
|
249
|
+
sourceAdapter: providerInfo.sourceAdapter,
|
|
250
|
+
baseUrl,
|
|
251
|
+
command,
|
|
252
|
+
commandRunId,
|
|
253
|
+
jobId,
|
|
254
|
+
agentId,
|
|
255
|
+
agentSlug,
|
|
256
|
+
project,
|
|
257
|
+
taskId,
|
|
258
|
+
taskKey,
|
|
259
|
+
};
|
|
260
|
+
const stream = runCodaliStream(request.input, {
|
|
261
|
+
workspaceRoot,
|
|
262
|
+
project,
|
|
263
|
+
command,
|
|
264
|
+
commandRunId,
|
|
265
|
+
jobId,
|
|
266
|
+
runId,
|
|
267
|
+
taskId,
|
|
268
|
+
taskKey,
|
|
269
|
+
agentId,
|
|
270
|
+
agentSlug,
|
|
271
|
+
provider,
|
|
272
|
+
model: this.config.model ?? "default",
|
|
273
|
+
apiKey: this.config.apiKey,
|
|
274
|
+
baseUrl,
|
|
275
|
+
docdexBaseUrl,
|
|
276
|
+
docdexRepoId,
|
|
277
|
+
docdexRepoRoot,
|
|
278
|
+
env: codaliEnv,
|
|
279
|
+
});
|
|
280
|
+
for await (const chunk of stream) {
|
|
281
|
+
const mergedMetadata = chunk.meta ? { ...baseMetadata, ...chunk.meta } : undefined;
|
|
282
|
+
yield {
|
|
283
|
+
output: chunk.output,
|
|
284
|
+
adapter: this.config.adapter ?? "codali-cli",
|
|
285
|
+
model: this.config.model,
|
|
286
|
+
metadata: mergedMetadata,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface CodaliCliOptions {
|
|
2
|
+
workspaceRoot: string;
|
|
3
|
+
project?: string;
|
|
4
|
+
command?: string;
|
|
5
|
+
commandRunId?: string;
|
|
6
|
+
jobId?: string;
|
|
7
|
+
runId?: string;
|
|
8
|
+
taskId?: string;
|
|
9
|
+
taskKey?: string;
|
|
10
|
+
agentId?: string;
|
|
11
|
+
agentSlug?: string;
|
|
12
|
+
provider: string;
|
|
13
|
+
model: string;
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
docdexBaseUrl?: string;
|
|
17
|
+
docdexRepoId?: string;
|
|
18
|
+
docdexRepoRoot?: string;
|
|
19
|
+
env?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export declare const cliHealthy: (throwOnError?: boolean) => {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
details?: Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
export declare const buildArgs: (options: CodaliCliOptions) => string[];
|
|
26
|
+
export declare const buildEnv: (options: CodaliCliOptions) => NodeJS.ProcessEnv;
|
|
27
|
+
export declare function runCodaliStream(input: string, options: CodaliCliOptions): AsyncGenerator<{
|
|
28
|
+
output: string;
|
|
29
|
+
meta?: Record<string, unknown>;
|
|
30
|
+
}>;
|
|
31
|
+
export declare const runCodaliExec: (input: string, options: CodaliCliOptions) => {
|
|
32
|
+
output: string;
|
|
33
|
+
raw: string;
|
|
34
|
+
meta?: Record<string, unknown>;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=CodaliCliRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodaliCliRunner.d.ts","sourceRoot":"","sources":["../../../src/adapters/codali/CodaliCliRunner.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,eAAO,MAAM,UAAU,GAAI,sBAAoB,KAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAiBjG,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,SAAS,gBAAgB,KAAG,MAAM,EA0C3D,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,SAAS,gBAAgB,KAAG,MAAM,CAAC,UAe3D,CAAC;AAwBF,wBAAuB,eAAe,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,gBAAgB,GACxB,cAAc,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAuGpE;AAED,eAAO,MAAM,aAAa,GACxB,OAAO,MAAM,EACb,SAAS,gBAAgB,KACxB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAgC/D,CAAC"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const CODALI_BIN_ENV = "CODALI_BIN";
|
|
4
|
+
const CODALI_STUB_ENV = "MCODA_CLI_STUB";
|
|
5
|
+
const CODALI_SKIP_CHECKS_ENV = "MCODA_SKIP_CLI_CHECKS";
|
|
6
|
+
export const cliHealthy = (throwOnError = false) => {
|
|
7
|
+
if (process.env[CODALI_STUB_ENV] === "1") {
|
|
8
|
+
return { ok: true, details: { stub: true } };
|
|
9
|
+
}
|
|
10
|
+
if (process.env[CODALI_SKIP_CHECKS_ENV] === "1") {
|
|
11
|
+
return { ok: true, details: { skipped: true } };
|
|
12
|
+
}
|
|
13
|
+
const bin = process.env[CODALI_BIN_ENV] ?? "codali";
|
|
14
|
+
const result = spawnSync(bin, ["--help"], { encoding: "utf8" });
|
|
15
|
+
if (result.error || result.status !== 0) {
|
|
16
|
+
const error = result.error?.message ?? result.stderr ?? "codali CLI unavailable";
|
|
17
|
+
if (throwOnError) {
|
|
18
|
+
throw new Error(`AUTH_ERROR: codali CLI unavailable (${error})`);
|
|
19
|
+
}
|
|
20
|
+
return { ok: false, details: { error } };
|
|
21
|
+
}
|
|
22
|
+
return { ok: true };
|
|
23
|
+
};
|
|
24
|
+
export const buildArgs = (options) => {
|
|
25
|
+
const args = ["run", "--workspace-root", options.workspaceRoot, "--provider", options.provider, "--model", options.model];
|
|
26
|
+
if (options.project) {
|
|
27
|
+
args.push("--project", options.project);
|
|
28
|
+
}
|
|
29
|
+
if (options.command) {
|
|
30
|
+
args.push("--command", options.command);
|
|
31
|
+
}
|
|
32
|
+
if (options.commandRunId) {
|
|
33
|
+
args.push("--command-run-id", options.commandRunId);
|
|
34
|
+
}
|
|
35
|
+
if (options.jobId) {
|
|
36
|
+
args.push("--job-id", options.jobId);
|
|
37
|
+
}
|
|
38
|
+
if (options.runId) {
|
|
39
|
+
args.push("--run-id", options.runId);
|
|
40
|
+
}
|
|
41
|
+
if (options.taskId) {
|
|
42
|
+
args.push("--task-id", options.taskId);
|
|
43
|
+
}
|
|
44
|
+
if (options.taskKey) {
|
|
45
|
+
args.push("--task-key", options.taskKey);
|
|
46
|
+
}
|
|
47
|
+
if (options.agentId) {
|
|
48
|
+
args.push("--agent-id", options.agentId);
|
|
49
|
+
}
|
|
50
|
+
if (options.agentSlug) {
|
|
51
|
+
args.push("--agent-slug", options.agentSlug);
|
|
52
|
+
}
|
|
53
|
+
if (options.baseUrl) {
|
|
54
|
+
args.push("--base-url", options.baseUrl);
|
|
55
|
+
}
|
|
56
|
+
if (options.docdexBaseUrl) {
|
|
57
|
+
args.push("--docdex-base-url", options.docdexBaseUrl);
|
|
58
|
+
}
|
|
59
|
+
if (options.docdexRepoId) {
|
|
60
|
+
args.push("--docdex-repo-id", options.docdexRepoId);
|
|
61
|
+
}
|
|
62
|
+
if (options.docdexRepoRoot) {
|
|
63
|
+
args.push("--docdex-repo-root", options.docdexRepoRoot);
|
|
64
|
+
}
|
|
65
|
+
return args;
|
|
66
|
+
};
|
|
67
|
+
export const buildEnv = (options) => {
|
|
68
|
+
const env = {
|
|
69
|
+
...process.env,
|
|
70
|
+
...(options.env ?? {}),
|
|
71
|
+
};
|
|
72
|
+
// Codali must never run under a sandboxed codex shell.
|
|
73
|
+
env.MCODA_CODEX_NO_SANDBOX = "1";
|
|
74
|
+
const apiKey = options.apiKey ?? env.CODALI_API_KEY;
|
|
75
|
+
if (apiKey) {
|
|
76
|
+
env.CODALI_API_KEY = apiKey;
|
|
77
|
+
}
|
|
78
|
+
if (options.baseUrl && !env.CODALI_BASE_URL) {
|
|
79
|
+
env.CODALI_BASE_URL = options.baseUrl;
|
|
80
|
+
}
|
|
81
|
+
return env;
|
|
82
|
+
};
|
|
83
|
+
const parseRunMetaLine = (line) => {
|
|
84
|
+
if (!line.startsWith("CODALI_RUN_META "))
|
|
85
|
+
return undefined;
|
|
86
|
+
const payload = line.slice("CODALI_RUN_META ".length).trim();
|
|
87
|
+
if (!payload)
|
|
88
|
+
return undefined;
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(payload);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
const parseRunMeta = (stderr) => {
|
|
97
|
+
if (!stderr)
|
|
98
|
+
return undefined;
|
|
99
|
+
const lines = stderr.split(/\r?\n/);
|
|
100
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
101
|
+
const line = lines[i];
|
|
102
|
+
const parsed = parseRunMetaLine(line);
|
|
103
|
+
if (parsed)
|
|
104
|
+
return parsed;
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
};
|
|
108
|
+
export async function* runCodaliStream(input, options) {
|
|
109
|
+
if (process.env[CODALI_STUB_ENV] === "1") {
|
|
110
|
+
yield { output: `codali-stub:${input}` };
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const bin = process.env[CODALI_BIN_ENV] ?? "codali";
|
|
114
|
+
const args = buildArgs(options);
|
|
115
|
+
const env = buildEnv(options);
|
|
116
|
+
const child = spawn(bin, args, {
|
|
117
|
+
cwd: path.resolve(options.workspaceRoot),
|
|
118
|
+
env,
|
|
119
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
120
|
+
});
|
|
121
|
+
let stderrBuffer = "";
|
|
122
|
+
let stderr = "";
|
|
123
|
+
let meta;
|
|
124
|
+
let exitCode = null;
|
|
125
|
+
let spawnError = null;
|
|
126
|
+
let done = false;
|
|
127
|
+
const queue = [];
|
|
128
|
+
let notify = null;
|
|
129
|
+
const push = (line) => {
|
|
130
|
+
if (!line)
|
|
131
|
+
return;
|
|
132
|
+
queue.push(line);
|
|
133
|
+
if (notify) {
|
|
134
|
+
notify();
|
|
135
|
+
notify = null;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const handleStderrLine = (line) => {
|
|
139
|
+
const parsed = parseRunMetaLine(line);
|
|
140
|
+
if (parsed) {
|
|
141
|
+
meta = parsed;
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
stderr += `${line}\n`;
|
|
145
|
+
push(`${line}\n`);
|
|
146
|
+
};
|
|
147
|
+
child.stdout.on("data", (chunk) => {
|
|
148
|
+
push(chunk.toString());
|
|
149
|
+
});
|
|
150
|
+
child.stderr.on("data", (chunk) => {
|
|
151
|
+
stderrBuffer += chunk.toString();
|
|
152
|
+
const lines = stderrBuffer.split(/\r?\n/);
|
|
153
|
+
stderrBuffer = lines.pop() ?? "";
|
|
154
|
+
for (const line of lines) {
|
|
155
|
+
handleStderrLine(line);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
child.on("error", (error) => {
|
|
159
|
+
spawnError = error;
|
|
160
|
+
done = true;
|
|
161
|
+
if (notify) {
|
|
162
|
+
notify();
|
|
163
|
+
notify = null;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
child.on("close", (code) => {
|
|
167
|
+
exitCode = code ?? 0;
|
|
168
|
+
if (stderrBuffer.trim()) {
|
|
169
|
+
handleStderrLine(stderrBuffer.trim());
|
|
170
|
+
}
|
|
171
|
+
done = true;
|
|
172
|
+
if (notify) {
|
|
173
|
+
notify();
|
|
174
|
+
notify = null;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
child.stdin.write(input);
|
|
178
|
+
child.stdin.end();
|
|
179
|
+
while (!done || queue.length > 0) {
|
|
180
|
+
if (queue.length > 0) {
|
|
181
|
+
const next = queue.shift();
|
|
182
|
+
if (next !== undefined) {
|
|
183
|
+
yield { output: next };
|
|
184
|
+
}
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
await new Promise((resolve) => {
|
|
188
|
+
notify = resolve;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (spawnError) {
|
|
192
|
+
throw spawnError;
|
|
193
|
+
}
|
|
194
|
+
if (exitCode !== 0) {
|
|
195
|
+
throw new Error(`codali CLI failed: ${stderr}`.trim());
|
|
196
|
+
}
|
|
197
|
+
if (meta) {
|
|
198
|
+
yield { output: "", meta };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
export const runCodaliExec = (input, options) => {
|
|
202
|
+
if (process.env[CODALI_STUB_ENV] === "1") {
|
|
203
|
+
return {
|
|
204
|
+
output: `codali-stub:${input}`,
|
|
205
|
+
raw: `codali-stub:${input}`,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const bin = process.env[CODALI_BIN_ENV] ?? "codali";
|
|
209
|
+
const args = buildArgs(options);
|
|
210
|
+
const env = buildEnv(options);
|
|
211
|
+
const result = spawnSync(bin, args, {
|
|
212
|
+
cwd: path.resolve(options.workspaceRoot),
|
|
213
|
+
input,
|
|
214
|
+
encoding: "utf8",
|
|
215
|
+
env,
|
|
216
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
217
|
+
});
|
|
218
|
+
if (result.error) {
|
|
219
|
+
throw result.error;
|
|
220
|
+
}
|
|
221
|
+
if (result.status !== 0) {
|
|
222
|
+
const stderr = result.stderr ?? "";
|
|
223
|
+
throw new Error(`codali CLI failed: ${stderr}`);
|
|
224
|
+
}
|
|
225
|
+
const stdout = result.stdout ?? "";
|
|
226
|
+
const stderr = result.stderr ?? "";
|
|
227
|
+
const raw = [stdout, stderr].filter(Boolean).join("\n");
|
|
228
|
+
const meta = parseRunMeta(stderr);
|
|
229
|
+
return { output: stdout.trim(), raw, meta };
|
|
230
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodexCliRunner.d.ts","sourceRoot":"","sources":["../../../src/adapters/codex/CodexCliRunner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CodexCliRunner.d.ts","sourceRoot":"","sources":["../../../src/adapters/codex/CodexCliRunner.ts"],"names":[],"mappings":"AA4hBA,eAAO,MAAM,UAAU,GAAI,sBAAoB,KAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CA2BjG,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,EAAE,QAAQ,MAAM,KAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAuD1F,CAAC;AAEF,wBAAuB,kBAAkB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,cAAc,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CA+GhE"}
|