@mcoda/mswarm 0.1.60 → 0.1.65
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/dist/codali-executor.d.ts +12 -0
- package/dist/codali-executor.d.ts.map +1 -1
- package/dist/codali-executor.js +19 -3
- package/dist/codali-executor.js.map +1 -1
- package/dist/runtime.d.ts +11 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +92 -10
- package/dist/runtime.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +13 -2
- package/dist/server.js.map +1 -1
- package/dist/vendor/codali/docdex/DocdexClient.d.ts +46 -0
- package/dist/vendor/codali/docdex/DocdexClient.d.ts.map +1 -1
- package/dist/vendor/codali/docdex/DocdexClient.js +351 -37
- package/dist/vendor/codali/runtime/CodaliRuntime.d.ts +6 -0
- package/dist/vendor/codali/runtime/CodaliRuntime.d.ts.map +1 -1
- package/dist/vendor/codali/runtime/CodaliRuntime.js +73 -1
- package/dist/vendor/codali/tools/ToolRegistry.d.ts.map +1 -1
- package/dist/vendor/codali/tools/ToolRegistry.js +30 -0
- package/dist/vendor/codali/tools/ToolTypes.d.ts +1 -1
- package/dist/vendor/codali/tools/ToolTypes.d.ts.map +1 -1
- package/dist/vendor/codali/tools/ToolTypes.js +8 -0
- package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts.map +1 -1
- package/dist/vendor/codali/tools/docdex/DocdexTools.js +37 -0
- package/package.json +3 -3
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
+
export class DocdexRuntimeError extends Error {
|
|
5
|
+
constructor(code, message, options = {}) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = code;
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.status = options.status;
|
|
10
|
+
this.retryable = options.retryable ?? code === "docdex_unavailable";
|
|
11
|
+
this.details = options.details;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
4
14
|
const CAPABILITY_KEYS = [
|
|
5
15
|
"score_breakdown",
|
|
6
16
|
"rerank",
|
|
@@ -8,6 +18,110 @@ const CAPABILITY_KEYS = [
|
|
|
8
18
|
"retrieval_explanation",
|
|
9
19
|
"batch_search",
|
|
10
20
|
];
|
|
21
|
+
const DOCDEX_RUNTIME_ERROR_CODES = new Set([
|
|
22
|
+
"docdex_context_missing",
|
|
23
|
+
"docdex_api_key_missing",
|
|
24
|
+
"docdex_operation_not_allowed",
|
|
25
|
+
"docdex_auth_failed",
|
|
26
|
+
"docdex_repo_access_denied",
|
|
27
|
+
"docdex_unavailable",
|
|
28
|
+
]);
|
|
29
|
+
const DOCDEX_RUNTIME_OPERATIONS = new Set([
|
|
30
|
+
"health",
|
|
31
|
+
"initialize",
|
|
32
|
+
"search",
|
|
33
|
+
"snippet",
|
|
34
|
+
"open",
|
|
35
|
+
"symbols",
|
|
36
|
+
"ast",
|
|
37
|
+
"impact_graph",
|
|
38
|
+
"impact_diagnostics",
|
|
39
|
+
"dag_export",
|
|
40
|
+
"tree",
|
|
41
|
+
"memory_save",
|
|
42
|
+
"memory_recall",
|
|
43
|
+
"profile_read",
|
|
44
|
+
"profile_write",
|
|
45
|
+
"web_research",
|
|
46
|
+
"chat_context",
|
|
47
|
+
"rerank",
|
|
48
|
+
"batch_search",
|
|
49
|
+
"capabilities",
|
|
50
|
+
"stats",
|
|
51
|
+
"files",
|
|
52
|
+
"repo_inspect",
|
|
53
|
+
"index_rebuild",
|
|
54
|
+
"index_ingest",
|
|
55
|
+
"delegate",
|
|
56
|
+
"hooks_validate",
|
|
57
|
+
]);
|
|
58
|
+
const MCP_OPERATION_BY_METHOD = {
|
|
59
|
+
docdex_symbols: "symbols",
|
|
60
|
+
docdex_ast: "ast",
|
|
61
|
+
docdex_stats: "stats",
|
|
62
|
+
docdex_files: "files",
|
|
63
|
+
docdex_repo_inspect: "repo_inspect",
|
|
64
|
+
docdex_memory_save: "memory_save",
|
|
65
|
+
docdex_memory_recall: "memory_recall",
|
|
66
|
+
docdex_tree: "tree",
|
|
67
|
+
docdex_open: "open",
|
|
68
|
+
docdex_get_profile: "profile_read",
|
|
69
|
+
docdex_save_preference: "profile_write",
|
|
70
|
+
docdex_web_research: "web_research",
|
|
71
|
+
docdex_rerank: "rerank",
|
|
72
|
+
docdex_batch_search: "batch_search",
|
|
73
|
+
docdex_capabilities: "capabilities",
|
|
74
|
+
};
|
|
75
|
+
export const isDocdexRuntimeErrorCode = (value) => {
|
|
76
|
+
return typeof value === "string" && DOCDEX_RUNTIME_ERROR_CODES.has(value);
|
|
77
|
+
};
|
|
78
|
+
export const normalizeDocdexRuntimeOperation = (value) => {
|
|
79
|
+
const normalized = value.trim().replace(/[.-]/g, "_").toLowerCase();
|
|
80
|
+
const aliases = {
|
|
81
|
+
impact: "impact_graph",
|
|
82
|
+
diagnostics: "impact_diagnostics",
|
|
83
|
+
impact_diagnostics: "impact_diagnostics",
|
|
84
|
+
web: "web_research",
|
|
85
|
+
web_search: "web_research",
|
|
86
|
+
chat: "chat_context",
|
|
87
|
+
chat_completions: "chat_context",
|
|
88
|
+
context_chat: "chat_context",
|
|
89
|
+
open_file: "open",
|
|
90
|
+
snippet_fetch: "snippet",
|
|
91
|
+
profile: "profile_read",
|
|
92
|
+
get_profile: "profile_read",
|
|
93
|
+
save_preference: "profile_write",
|
|
94
|
+
memory: "memory_recall",
|
|
95
|
+
index: "index_rebuild",
|
|
96
|
+
hooks: "hooks_validate",
|
|
97
|
+
};
|
|
98
|
+
const aliased = aliases[normalized];
|
|
99
|
+
if (aliased)
|
|
100
|
+
return aliased;
|
|
101
|
+
return DOCDEX_RUNTIME_OPERATIONS.has(normalized)
|
|
102
|
+
? normalized
|
|
103
|
+
: undefined;
|
|
104
|
+
};
|
|
105
|
+
const escapeRegExp = (value) => {
|
|
106
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
107
|
+
};
|
|
108
|
+
const invalidSearchQueryError = (status, body) => {
|
|
109
|
+
const normalized = body.toLowerCase();
|
|
110
|
+
return status === 400 && /invalid_query|query parse failed|syntax error/.test(normalized);
|
|
111
|
+
};
|
|
112
|
+
const sanitizeSearchRetryQuery = (query) => {
|
|
113
|
+
const original = query.trim();
|
|
114
|
+
if (!original)
|
|
115
|
+
return undefined;
|
|
116
|
+
const sanitized = original
|
|
117
|
+
.replace(/\b[A-Za-z_][\w.-]{0,63}:\s*/g, " ")
|
|
118
|
+
.replace(/\b(?:AND|OR|NOT)\b/gi, " ")
|
|
119
|
+
.replace(/[()[\]{}^~*?]/g, " ")
|
|
120
|
+
.replace(/["'`]/g, " ")
|
|
121
|
+
.replace(/\s+/g, " ")
|
|
122
|
+
.trim();
|
|
123
|
+
return sanitized && sanitized !== original ? sanitized : undefined;
|
|
124
|
+
};
|
|
11
125
|
export class DocdexClient {
|
|
12
126
|
constructor(options) {
|
|
13
127
|
this.options = options;
|
|
@@ -34,14 +148,80 @@ export class DocdexClient {
|
|
|
34
148
|
clearCapabilityCache() {
|
|
35
149
|
this.capabilitySnapshot = undefined;
|
|
36
150
|
}
|
|
151
|
+
runtimeAllowedOperations() {
|
|
152
|
+
if (!this.options.allowedOperations?.length)
|
|
153
|
+
return undefined;
|
|
154
|
+
const operations = this.options.allowedOperations
|
|
155
|
+
.map((entry) => normalizeDocdexRuntimeOperation(entry))
|
|
156
|
+
.filter((entry) => Boolean(entry));
|
|
157
|
+
return operations.length ? new Set(operations) : new Set();
|
|
158
|
+
}
|
|
159
|
+
runtimeCapability(operation) {
|
|
160
|
+
if (!this.options.capabilities)
|
|
161
|
+
return undefined;
|
|
162
|
+
for (const [key, value] of Object.entries(this.options.capabilities)) {
|
|
163
|
+
const normalized = normalizeDocdexRuntimeOperation(key);
|
|
164
|
+
if (normalized === operation && typeof value === "boolean") {
|
|
165
|
+
return value;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
redactSensitiveText(text) {
|
|
171
|
+
let output = text;
|
|
172
|
+
for (const secret of [this.options.apiKey, this.options.authToken]) {
|
|
173
|
+
if (typeof secret === "string" && secret.length >= 4) {
|
|
174
|
+
output = output.replace(new RegExp(escapeRegExp(secret), "g"), "[redacted]");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
output = output.replace(/("(?:x-api-key|authorization|api[_-]?key|token|secret)"\s*:\s*")[^"]+(")/gi, "$1[redacted]$2");
|
|
178
|
+
output = output.replace(/((?:x-api-key|authorization|api[_-]?key|token|secret)\s*[:=]\s*)(?:Bearer\s+)?[^\s,;}]+/gi, "$1[redacted]");
|
|
179
|
+
return output;
|
|
180
|
+
}
|
|
181
|
+
runtimeError(code, message, options = {}) {
|
|
182
|
+
return new DocdexRuntimeError(code, this.redactSensitiveText(message), options);
|
|
183
|
+
}
|
|
184
|
+
assertRuntimeContext(operation) {
|
|
185
|
+
const credentialSource = this.options.credentialSource;
|
|
186
|
+
const requiresAttachedKey = credentialSource === "attached_mswarm_api_key";
|
|
187
|
+
if (requiresAttachedKey && (!this.options.apiKey || this.options.apiKey.trim().length === 0)) {
|
|
188
|
+
throw this.runtimeError("docdex_api_key_missing", "Docdex attached mswarm API key is required but was not provided.", { retryable: false, details: { operation, credential_source: credentialSource } });
|
|
189
|
+
}
|
|
190
|
+
if (this.options.required && this.resolveBaseUrl().length === 0) {
|
|
191
|
+
throw this.runtimeError("docdex_context_missing", "Docdex base_url is required for this job.", {
|
|
192
|
+
retryable: false,
|
|
193
|
+
details: { operation },
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
if (this.options.required && requiresAttachedKey && !this.repoId) {
|
|
197
|
+
throw this.runtimeError("docdex_context_missing", "Docdex repo_id is required for this job.", {
|
|
198
|
+
retryable: false,
|
|
199
|
+
details: { operation },
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
assertOperationAllowed(operation) {
|
|
204
|
+
this.assertRuntimeContext(operation);
|
|
205
|
+
const allowedOperations = this.runtimeAllowedOperations();
|
|
206
|
+
if (allowedOperations && !allowedOperations.has(operation)) {
|
|
207
|
+
throw this.runtimeError("docdex_operation_not_allowed", `Docdex operation is not allowed by this job: ${operation}`, { retryable: false, details: { operation } });
|
|
208
|
+
}
|
|
209
|
+
if (this.runtimeCapability(operation) === false) {
|
|
210
|
+
throw this.runtimeError("docdex_operation_not_allowed", `Docdex operation is disabled by this job capability map: ${operation}`, { retryable: false, details: { operation } });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
37
213
|
resolveBaseUrl() {
|
|
38
214
|
const base = this.options.baseUrl.trim();
|
|
39
215
|
return base.endsWith("/") ? base.slice(0, -1) : base;
|
|
40
216
|
}
|
|
41
217
|
buildHeaders(dagSessionId) {
|
|
42
218
|
const headers = { "content-type": "application/json" };
|
|
43
|
-
if (this.options.
|
|
219
|
+
if (this.options.apiKey) {
|
|
220
|
+
headers["x-api-key"] = this.options.apiKey;
|
|
221
|
+
}
|
|
222
|
+
else if (this.options.authToken) {
|
|
44
223
|
headers.authorization = `Bearer ${this.options.authToken}`;
|
|
224
|
+
}
|
|
45
225
|
if (this.repoId)
|
|
46
226
|
headers["x-docdex-repo-id"] = this.repoId;
|
|
47
227
|
if (this.options.repoRoot)
|
|
@@ -54,17 +234,37 @@ export class DocdexClient {
|
|
|
54
234
|
async ensureHealth() {
|
|
55
235
|
if (this.healthChecked)
|
|
56
236
|
return;
|
|
57
|
-
|
|
237
|
+
let ok = false;
|
|
238
|
+
try {
|
|
239
|
+
ok = await this.healthCheck();
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
if (error instanceof DocdexRuntimeError)
|
|
243
|
+
throw error;
|
|
244
|
+
throw this.runtimeError("docdex_unavailable", `Docdex health check failed: ${error instanceof Error ? error.message : String(error)}`, { retryable: true });
|
|
245
|
+
}
|
|
58
246
|
if (!ok) {
|
|
59
|
-
throw
|
|
247
|
+
throw this.runtimeError("docdex_unavailable", "Docdex health check failed", {
|
|
248
|
+
retryable: true,
|
|
249
|
+
});
|
|
60
250
|
}
|
|
61
251
|
}
|
|
62
252
|
async healthCheck() {
|
|
63
|
-
|
|
253
|
+
let response;
|
|
254
|
+
try {
|
|
255
|
+
response = await fetch(`${this.resolveBaseUrl()}/healthz`);
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
throw this.runtimeError("docdex_unavailable", `Docdex health check failed: ${error instanceof Error ? error.message : String(error)}`, { retryable: true });
|
|
259
|
+
}
|
|
64
260
|
this.healthChecked = response.ok;
|
|
65
261
|
return response.ok;
|
|
66
262
|
}
|
|
67
263
|
async initialize(rootUri) {
|
|
264
|
+
this.assertOperationAllowed("initialize");
|
|
265
|
+
return this.initializeRepo(rootUri);
|
|
266
|
+
}
|
|
267
|
+
async initializeRepo(rootUri) {
|
|
68
268
|
await this.ensureHealth();
|
|
69
269
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/initialize`, {
|
|
70
270
|
method: "POST",
|
|
@@ -72,8 +272,7 @@ export class DocdexClient {
|
|
|
72
272
|
body: JSON.stringify({ rootUri }),
|
|
73
273
|
});
|
|
74
274
|
if (!response.ok) {
|
|
75
|
-
|
|
76
|
-
throw new Error(`Docdex initialize failed (${response.status}): ${body}`);
|
|
275
|
+
await this.throwResponseError(response, "initialize");
|
|
77
276
|
}
|
|
78
277
|
const payload = (await response.json());
|
|
79
278
|
const repoId = (payload.repo_id ?? payload.repoId ?? payload.repo);
|
|
@@ -87,7 +286,7 @@ export class DocdexClient {
|
|
|
87
286
|
return;
|
|
88
287
|
this.repoInitializeAttempted = true;
|
|
89
288
|
try {
|
|
90
|
-
await this.
|
|
289
|
+
await this.initializeRepo(pathToFileURL(path.resolve(this.options.repoRoot)).toString());
|
|
91
290
|
}
|
|
92
291
|
catch {
|
|
93
292
|
// Keep endpoint-specific calls responsible for reporting the final failure.
|
|
@@ -100,26 +299,102 @@ export class DocdexClient {
|
|
|
100
299
|
if (this.options.repoRoot)
|
|
101
300
|
params.set("repo_root", path.resolve(this.options.repoRoot));
|
|
102
301
|
}
|
|
302
|
+
extractErrorCode(body) {
|
|
303
|
+
const parsed = this.tryParseJson(body);
|
|
304
|
+
if (!parsed || typeof parsed !== "object")
|
|
305
|
+
return undefined;
|
|
306
|
+
const record = parsed;
|
|
307
|
+
const error = record.error && typeof record.error === "object"
|
|
308
|
+
? record.error
|
|
309
|
+
: undefined;
|
|
310
|
+
const code = error?.code ?? record.code;
|
|
311
|
+
return typeof code === "string" ? code : undefined;
|
|
312
|
+
}
|
|
313
|
+
mapResponseErrorCode(status, body) {
|
|
314
|
+
const extracted = this.extractErrorCode(body);
|
|
315
|
+
if (isDocdexRuntimeErrorCode(extracted))
|
|
316
|
+
return extracted;
|
|
317
|
+
const normalized = `${extracted ?? ""} ${body}`.toLowerCase();
|
|
318
|
+
if (/introspection_unavailable|unavailable|timeout|timed out|econnrefused|enotfound/.test(normalized)) {
|
|
319
|
+
return "docdex_unavailable";
|
|
320
|
+
}
|
|
321
|
+
if (/repo_access_denied|unknown_repo|repo.*denied|denied.*repo/.test(normalized)) {
|
|
322
|
+
return "docdex_repo_access_denied";
|
|
323
|
+
}
|
|
324
|
+
if (/scope_denied|operation_not_allowed|encrypted_operation_disabled|not allowed|forbidden_operation/.test(normalized)) {
|
|
325
|
+
return "docdex_operation_not_allowed";
|
|
326
|
+
}
|
|
327
|
+
if (status === 401 || status === 403 || /invalid_credentials|missing_credentials|ambiguous_credentials/.test(normalized)) {
|
|
328
|
+
return "docdex_auth_failed";
|
|
329
|
+
}
|
|
330
|
+
return "docdex_unavailable";
|
|
331
|
+
}
|
|
332
|
+
async throwResponseError(response, operation) {
|
|
333
|
+
const body = await response.text();
|
|
334
|
+
this.throwResponseBodyError(response.status, body, operation);
|
|
335
|
+
}
|
|
336
|
+
throwResponseBodyError(status, body, operation) {
|
|
337
|
+
const code = this.mapResponseErrorCode(status, body);
|
|
338
|
+
throw this.runtimeError(code, `Docdex ${operation} failed (${status}): ${body}`, {
|
|
339
|
+
status,
|
|
340
|
+
retryable: code === "docdex_unavailable" && status >= 500,
|
|
341
|
+
details: { operation },
|
|
342
|
+
});
|
|
343
|
+
}
|
|
103
344
|
async search(query, options = {}) {
|
|
345
|
+
this.assertOperationAllowed("search");
|
|
104
346
|
await this.ensureHealth();
|
|
105
347
|
await this.ensureRepoInitialized();
|
|
106
|
-
const params = new URLSearchParams({ q: query });
|
|
107
|
-
if (options.limit !== undefined)
|
|
108
|
-
params.set("limit", String(options.limit));
|
|
109
348
|
const dagSessionId = options.dagSessionId ?? this.dagSessionId;
|
|
110
|
-
|
|
111
|
-
params
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
349
|
+
const executeSearch = (searchQuery) => {
|
|
350
|
+
const params = new URLSearchParams({ q: searchQuery });
|
|
351
|
+
if (options.limit !== undefined)
|
|
352
|
+
params.set("limit", String(options.limit));
|
|
353
|
+
if (dagSessionId)
|
|
354
|
+
params.set("dag_session_id", dagSessionId);
|
|
355
|
+
this.withRepoId(params);
|
|
356
|
+
return fetch(`${this.resolveBaseUrl()}/search?${params.toString()}`, {
|
|
357
|
+
headers: this.buildHeaders(dagSessionId),
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
const response = await executeSearch(query);
|
|
116
361
|
if (!response.ok) {
|
|
117
362
|
const body = await response.text();
|
|
118
|
-
|
|
363
|
+
const retryQuery = invalidSearchQueryError(response.status, body)
|
|
364
|
+
? sanitizeSearchRetryQuery(query)
|
|
365
|
+
: undefined;
|
|
366
|
+
if (retryQuery) {
|
|
367
|
+
const retryResponse = await executeSearch(retryQuery);
|
|
368
|
+
if (retryResponse.ok) {
|
|
369
|
+
const retryPayload = await retryResponse.json();
|
|
370
|
+
if (retryPayload && typeof retryPayload === "object" && !Array.isArray(retryPayload)) {
|
|
371
|
+
const payloadRecord = retryPayload;
|
|
372
|
+
const meta = payloadRecord.meta && typeof payloadRecord.meta === "object" && !Array.isArray(payloadRecord.meta)
|
|
373
|
+
? { ...payloadRecord.meta }
|
|
374
|
+
: {};
|
|
375
|
+
return {
|
|
376
|
+
...payloadRecord,
|
|
377
|
+
meta: {
|
|
378
|
+
...meta,
|
|
379
|
+
codali_query_retry: {
|
|
380
|
+
reason: "invalid_query",
|
|
381
|
+
original_query: query,
|
|
382
|
+
retried_query: retryQuery,
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
return retryPayload;
|
|
388
|
+
}
|
|
389
|
+
const retryBody = await retryResponse.text();
|
|
390
|
+
this.throwResponseBodyError(retryResponse.status, retryBody, "search");
|
|
391
|
+
}
|
|
392
|
+
this.throwResponseBodyError(response.status, body, "search");
|
|
119
393
|
}
|
|
120
394
|
return response.json();
|
|
121
395
|
}
|
|
122
396
|
async openSnippet(docId, options = {}) {
|
|
397
|
+
this.assertOperationAllowed("snippet");
|
|
123
398
|
await this.ensureHealth();
|
|
124
399
|
await this.ensureRepoInitialized();
|
|
125
400
|
const params = new URLSearchParams();
|
|
@@ -132,8 +407,7 @@ export class DocdexClient {
|
|
|
132
407
|
headers: this.buildHeaders(),
|
|
133
408
|
});
|
|
134
409
|
if (!response.ok) {
|
|
135
|
-
|
|
136
|
-
throw new Error(`Docdex snippet failed (${response.status}): ${body}`);
|
|
410
|
+
await this.throwResponseError(response, "snippet");
|
|
137
411
|
}
|
|
138
412
|
const contentType = response.headers.get("content-type") ?? "";
|
|
139
413
|
if (contentType.includes("application/json")) {
|
|
@@ -142,6 +416,7 @@ export class DocdexClient {
|
|
|
142
416
|
return response.text();
|
|
143
417
|
}
|
|
144
418
|
async impactGraph(file, options = {}) {
|
|
419
|
+
this.assertOperationAllowed("impact_graph");
|
|
145
420
|
await this.ensureHealth();
|
|
146
421
|
await this.ensureRepoInitialized();
|
|
147
422
|
const params = new URLSearchParams({ file });
|
|
@@ -156,12 +431,12 @@ export class DocdexClient {
|
|
|
156
431
|
headers: this.buildHeaders(),
|
|
157
432
|
});
|
|
158
433
|
if (!response.ok) {
|
|
159
|
-
|
|
160
|
-
throw new Error(`Docdex impact graph failed (${response.status}): ${body}`);
|
|
434
|
+
await this.throwResponseError(response, "impact graph");
|
|
161
435
|
}
|
|
162
436
|
return response.json();
|
|
163
437
|
}
|
|
164
438
|
async impactDiagnostics(options = {}) {
|
|
439
|
+
this.assertOperationAllowed("impact_diagnostics");
|
|
165
440
|
await this.ensureHealth();
|
|
166
441
|
await this.ensureRepoInitialized();
|
|
167
442
|
const params = new URLSearchParams();
|
|
@@ -176,12 +451,12 @@ export class DocdexClient {
|
|
|
176
451
|
headers: this.buildHeaders(),
|
|
177
452
|
});
|
|
178
453
|
if (!response.ok) {
|
|
179
|
-
|
|
180
|
-
throw new Error(`Docdex impact diagnostics failed (${response.status}): ${body}`);
|
|
454
|
+
await this.throwResponseError(response, "impact diagnostics");
|
|
181
455
|
}
|
|
182
456
|
return response.json();
|
|
183
457
|
}
|
|
184
458
|
async indexRebuild(libsSources) {
|
|
459
|
+
this.assertOperationAllowed("index_rebuild");
|
|
185
460
|
await this.ensureHealth();
|
|
186
461
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/index/rebuild`, {
|
|
187
462
|
method: "POST",
|
|
@@ -189,12 +464,12 @@ export class DocdexClient {
|
|
|
189
464
|
body: JSON.stringify(libsSources ? { libs_sources: libsSources } : {}),
|
|
190
465
|
});
|
|
191
466
|
if (!response.ok) {
|
|
192
|
-
|
|
193
|
-
throw new Error(`Docdex index rebuild failed (${response.status}): ${body}`);
|
|
467
|
+
await this.throwResponseError(response, "index rebuild");
|
|
194
468
|
}
|
|
195
469
|
return response.json();
|
|
196
470
|
}
|
|
197
471
|
async indexIngest(file) {
|
|
472
|
+
this.assertOperationAllowed("index_ingest");
|
|
198
473
|
await this.ensureHealth();
|
|
199
474
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/index/ingest`, {
|
|
200
475
|
method: "POST",
|
|
@@ -202,12 +477,12 @@ export class DocdexClient {
|
|
|
202
477
|
body: JSON.stringify({ file }),
|
|
203
478
|
});
|
|
204
479
|
if (!response.ok) {
|
|
205
|
-
|
|
206
|
-
throw new Error(`Docdex index ingest failed (${response.status}): ${body}`);
|
|
480
|
+
await this.throwResponseError(response, "index ingest");
|
|
207
481
|
}
|
|
208
482
|
return response.json();
|
|
209
483
|
}
|
|
210
484
|
async hooksValidate(files) {
|
|
485
|
+
this.assertOperationAllowed("hooks_validate");
|
|
211
486
|
await this.ensureHealth();
|
|
212
487
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/hooks/validate`, {
|
|
213
488
|
method: "POST",
|
|
@@ -215,12 +490,12 @@ export class DocdexClient {
|
|
|
215
490
|
body: JSON.stringify({ files }),
|
|
216
491
|
});
|
|
217
492
|
if (!response.ok) {
|
|
218
|
-
|
|
219
|
-
throw new Error(`Docdex hooks validate failed (${response.status}): ${body}`);
|
|
493
|
+
await this.throwResponseError(response, "hooks validate");
|
|
220
494
|
}
|
|
221
495
|
return response.json();
|
|
222
496
|
}
|
|
223
497
|
async delegate(payload) {
|
|
498
|
+
this.assertOperationAllowed("delegate");
|
|
224
499
|
await this.ensureHealth();
|
|
225
500
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/delegate`, {
|
|
226
501
|
method: "POST",
|
|
@@ -228,12 +503,38 @@ export class DocdexClient {
|
|
|
228
503
|
body: JSON.stringify(payload),
|
|
229
504
|
});
|
|
230
505
|
if (!response.ok) {
|
|
231
|
-
|
|
232
|
-
|
|
506
|
+
await this.throwResponseError(response, "delegate");
|
|
507
|
+
}
|
|
508
|
+
return response.json();
|
|
509
|
+
}
|
|
510
|
+
async chatContext(messages, options = {}) {
|
|
511
|
+
this.assertOperationAllowed("chat_context");
|
|
512
|
+
await this.ensureHealth();
|
|
513
|
+
await this.ensureRepoInitialized();
|
|
514
|
+
const body = {
|
|
515
|
+
messages,
|
|
516
|
+
stream: false,
|
|
517
|
+
};
|
|
518
|
+
if (options.model)
|
|
519
|
+
body.model = options.model;
|
|
520
|
+
if (options.maxTokens !== undefined)
|
|
521
|
+
body.max_tokens = options.maxTokens;
|
|
522
|
+
if (options.temperature !== undefined)
|
|
523
|
+
body.temperature = options.temperature;
|
|
524
|
+
if (options.docdex)
|
|
525
|
+
body.docdex = options.docdex;
|
|
526
|
+
const response = await fetch(`${this.resolveBaseUrl()}/v1/chat/completions`, {
|
|
527
|
+
method: "POST",
|
|
528
|
+
headers: this.buildHeaders(this.dagSessionId),
|
|
529
|
+
body: JSON.stringify(body),
|
|
530
|
+
});
|
|
531
|
+
if (!response.ok) {
|
|
532
|
+
await this.throwResponseError(response, "chat context");
|
|
233
533
|
}
|
|
234
534
|
return response.json();
|
|
235
535
|
}
|
|
236
536
|
async dagExport(sessionId, options = {}) {
|
|
537
|
+
this.assertOperationAllowed("dag_export");
|
|
237
538
|
await this.ensureHealth();
|
|
238
539
|
await this.ensureRepoInitialized();
|
|
239
540
|
const params = new URLSearchParams({ session_id: sessionId });
|
|
@@ -247,7 +548,12 @@ export class DocdexClient {
|
|
|
247
548
|
});
|
|
248
549
|
const body = await response.text();
|
|
249
550
|
if (!response.ok) {
|
|
250
|
-
|
|
551
|
+
const code = this.mapResponseErrorCode(response.status, body);
|
|
552
|
+
throw this.runtimeError(code, `Docdex dag export failed (${response.status}): ${body}`, {
|
|
553
|
+
status: response.status,
|
|
554
|
+
retryable: code === "docdex_unavailable" && response.status >= 500,
|
|
555
|
+
details: { operation: "dag_export" },
|
|
556
|
+
});
|
|
251
557
|
}
|
|
252
558
|
const contentType = response.headers.get("content-type") ?? "";
|
|
253
559
|
if (contentType.includes("application/json")) {
|
|
@@ -261,6 +567,10 @@ export class DocdexClient {
|
|
|
261
567
|
return body;
|
|
262
568
|
}
|
|
263
569
|
async callMcp(method, params) {
|
|
570
|
+
const operation = MCP_OPERATION_BY_METHOD[method];
|
|
571
|
+
if (operation) {
|
|
572
|
+
this.assertOperationAllowed(operation);
|
|
573
|
+
}
|
|
264
574
|
await this.ensureHealth();
|
|
265
575
|
const payload = {
|
|
266
576
|
jsonrpc: "2.0",
|
|
@@ -274,12 +584,16 @@ export class DocdexClient {
|
|
|
274
584
|
body: JSON.stringify(payload),
|
|
275
585
|
});
|
|
276
586
|
if (!response.ok) {
|
|
277
|
-
|
|
278
|
-
throw new Error(`Docdex MCP failed (${response.status}): ${body}`);
|
|
587
|
+
await this.throwResponseError(response, "MCP");
|
|
279
588
|
}
|
|
280
589
|
const raw = (await response.json());
|
|
281
590
|
if (raw.error) {
|
|
282
|
-
|
|
591
|
+
const body = JSON.stringify(raw.error);
|
|
592
|
+
const code = this.mapResponseErrorCode(500, body);
|
|
593
|
+
throw this.runtimeError(code, raw.error.message ?? "Docdex MCP error", {
|
|
594
|
+
retryable: code === "docdex_unavailable",
|
|
595
|
+
details: { method },
|
|
596
|
+
});
|
|
283
597
|
}
|
|
284
598
|
return this.normalizeMcpResult(raw.result);
|
|
285
599
|
}
|
|
@@ -451,6 +765,7 @@ export class DocdexClient {
|
|
|
451
765
|
})).catch(() => this.webResearchHttp(query, options));
|
|
452
766
|
}
|
|
453
767
|
async webResearchHttp(query, options = {}) {
|
|
768
|
+
this.assertOperationAllowed("web_research");
|
|
454
769
|
await this.ensureHealth();
|
|
455
770
|
await this.ensureRepoInitialized();
|
|
456
771
|
const params = new URLSearchParams({ q: query });
|
|
@@ -469,8 +784,7 @@ export class DocdexClient {
|
|
|
469
784
|
headers: this.buildHeaders(this.dagSessionId),
|
|
470
785
|
});
|
|
471
786
|
if (!response.ok) {
|
|
472
|
-
|
|
473
|
-
throw new Error(`Docdex web research failed (${response.status}): ${body}`);
|
|
787
|
+
await this.throwResponseError(response, "web research");
|
|
474
788
|
}
|
|
475
789
|
return response.json();
|
|
476
790
|
}
|
|
@@ -14,10 +14,16 @@ export interface CodaliRuntimeProviderInput {
|
|
|
14
14
|
timeoutMs?: number;
|
|
15
15
|
}
|
|
16
16
|
export interface CodaliRuntimeDocdexInput {
|
|
17
|
+
enabled?: boolean;
|
|
17
18
|
baseUrl?: string;
|
|
18
19
|
repoRoot?: string;
|
|
19
20
|
repoId?: string;
|
|
20
21
|
dagSessionId?: string;
|
|
22
|
+
apiKey?: string;
|
|
23
|
+
credentialSource?: "attached_mswarm_api_key" | string;
|
|
24
|
+
required?: boolean;
|
|
25
|
+
allowedOperations?: string[];
|
|
26
|
+
capabilities?: Record<string, boolean | undefined>;
|
|
21
27
|
initialize?: boolean;
|
|
22
28
|
allowWeb?: boolean;
|
|
23
29
|
allowMemoryWrite?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodaliRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/CodaliRuntime.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAEV,gBAAgB,EAChB,QAAQ,EAER,eAAe,EAEf,aAAa,EACd,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"CodaliRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/CodaliRuntime.ts"],"names":[],"mappings":"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"}
|