@aliyunrds/ctxdb 1.0.2 → 1.0.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.md +174 -5
- package/dist/chunk-3PFMHU3C.js +442 -0
- package/dist/chunk-BQA7YSXT.js +462 -0
- package/dist/{chunk-2CSEFSLC.js → chunk-BVCDRUU4.js} +1 -1
- package/dist/{chunk-WTP4ZX22.js → chunk-CWGF5D52.js} +2 -2
- package/dist/{chunk-6FZL67GH.js → chunk-JFTKYEVN.js} +333 -45
- package/dist/{chunk-EUQ3OFCQ.js → chunk-Q4JYST7K.js} +3 -3
- package/dist/{chunk-IMYLU5C2.js → chunk-SAQT6VL6.js} +2 -2
- package/dist/{chunk-TGVURF54.js → chunk-USMJLDBD.js} +1 -1
- package/dist/cli/main.js +347 -160
- package/dist/hooks/hermes-post-llm-call.js +3 -3
- package/dist/hooks/hermes-pre-llm-call.js +6 -6
- package/dist/hooks/session-start.js +5 -5
- package/dist/hooks/stop.js +3 -3
- package/dist/hooks/user-prompt-submit.js +5 -5
- package/dist/setup/skills/contextdb-knowledge/SKILL.md +13 -3
- package/dist/workers/version-check.js +65 -0
- package/package.json +1 -1
- package/dist/chunk-UH7AJF6F.js +0 -204
|
@@ -68,37 +68,72 @@ var CtxdbError = class extends Error {
|
|
|
68
68
|
}
|
|
69
69
|
};
|
|
70
70
|
var AuthError = class extends CtxdbError {
|
|
71
|
-
|
|
71
|
+
status = 401;
|
|
72
|
+
errorCode;
|
|
73
|
+
errorMessage;
|
|
74
|
+
data;
|
|
75
|
+
responseBody;
|
|
76
|
+
constructor(message = "Unauthorized (HTTP 401) \u2014 check api_key", fields = {}) {
|
|
72
77
|
super(message);
|
|
73
78
|
this.name = "AuthError";
|
|
79
|
+
this.errorCode = fields.errorCode;
|
|
80
|
+
this.errorMessage = fields.errorMessage;
|
|
81
|
+
this.data = fields.data;
|
|
82
|
+
this.responseBody = fields.responseBody;
|
|
74
83
|
}
|
|
75
84
|
};
|
|
76
85
|
var NotFoundError = class extends CtxdbError {
|
|
86
|
+
status = 404;
|
|
77
87
|
path;
|
|
78
|
-
|
|
88
|
+
errorCode;
|
|
89
|
+
errorMessage;
|
|
90
|
+
data;
|
|
91
|
+
responseBody;
|
|
92
|
+
constructor(path, fields = {}) {
|
|
79
93
|
super(`Not found: ${path}`);
|
|
80
94
|
this.name = "NotFoundError";
|
|
81
95
|
this.path = path;
|
|
96
|
+
this.errorCode = fields.errorCode;
|
|
97
|
+
this.errorMessage = fields.errorMessage;
|
|
98
|
+
this.data = fields.data;
|
|
99
|
+
this.responseBody = fields.responseBody;
|
|
82
100
|
}
|
|
83
101
|
};
|
|
84
102
|
var APIError = class extends CtxdbError {
|
|
103
|
+
status = 400;
|
|
85
104
|
path;
|
|
86
105
|
detail;
|
|
87
|
-
|
|
106
|
+
errorCode;
|
|
107
|
+
errorMessage;
|
|
108
|
+
data;
|
|
109
|
+
responseBody;
|
|
110
|
+
constructor(path, detail, fields = {}) {
|
|
88
111
|
super(`API error at ${path}: ${detail}`);
|
|
89
112
|
this.name = "APIError";
|
|
90
113
|
this.path = path;
|
|
91
114
|
this.detail = detail;
|
|
115
|
+
this.errorCode = fields.errorCode;
|
|
116
|
+
this.errorMessage = fields.errorMessage;
|
|
117
|
+
this.data = fields.data;
|
|
118
|
+
this.responseBody = fields.responseBody;
|
|
92
119
|
}
|
|
93
120
|
};
|
|
94
121
|
var CtxdbHttpError = class extends CtxdbError {
|
|
95
122
|
status;
|
|
96
123
|
detail;
|
|
97
|
-
|
|
124
|
+
errorCode;
|
|
125
|
+
errorMessage;
|
|
126
|
+
data;
|
|
127
|
+
responseBody;
|
|
128
|
+
constructor(status, detail, fields = {}) {
|
|
98
129
|
super(`HTTP ${status}: ${detail}`);
|
|
99
130
|
this.name = "CtxdbHttpError";
|
|
100
131
|
this.status = status;
|
|
101
132
|
this.detail = detail;
|
|
133
|
+
this.errorCode = fields.errorCode;
|
|
134
|
+
this.errorMessage = fields.errorMessage;
|
|
135
|
+
this.data = fields.data;
|
|
136
|
+
this.responseBody = fields.responseBody;
|
|
102
137
|
}
|
|
103
138
|
};
|
|
104
139
|
var HttpClient = class {
|
|
@@ -117,12 +152,13 @@ var HttpClient = class {
|
|
|
117
152
|
const f = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
118
153
|
this.fetchImpl = f;
|
|
119
154
|
}
|
|
120
|
-
buildHeaders(contentType) {
|
|
155
|
+
buildHeaders(contentType, requestHeaders = {}) {
|
|
121
156
|
const h = {
|
|
122
157
|
Authorization: `Token ${this.apiKey}`,
|
|
123
158
|
"User-Agent": this.userAgent,
|
|
124
159
|
Connection: "close",
|
|
125
|
-
...this.extraHeaders
|
|
160
|
+
...this.extraHeaders,
|
|
161
|
+
...requestHeaders
|
|
126
162
|
};
|
|
127
163
|
if (contentType) h["Content-Type"] = contentType;
|
|
128
164
|
return h;
|
|
@@ -151,7 +187,7 @@ var HttpClient = class {
|
|
|
151
187
|
try {
|
|
152
188
|
resp = await this.fetchImpl(url, {
|
|
153
189
|
method,
|
|
154
|
-
headers: this.buildHeaders(init.contentType),
|
|
190
|
+
headers: this.buildHeaders(init.contentType, init.headers),
|
|
155
191
|
body: init.body,
|
|
156
192
|
signal: controller.signal
|
|
157
193
|
});
|
|
@@ -179,12 +215,18 @@ var HttpClient = class {
|
|
|
179
215
|
throw new CtxdbError(`network error reading body from ${url}: ${err?.message ?? err}`);
|
|
180
216
|
}
|
|
181
217
|
if (!resp.ok) {
|
|
182
|
-
const
|
|
183
|
-
if (dbg) debug("http", `\u2190 ${method} ${path} ${resp.status} (${Date.now() - t0}ms) ${detail}`);
|
|
184
|
-
if (resp.status === 401)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
218
|
+
const parsedError = parseErrorResponse(text, `HTTP ${resp.status}`);
|
|
219
|
+
if (dbg) debug("http", `\u2190 ${method} ${path} ${resp.status} (${Date.now() - t0}ms) ${parsedError.detail}`);
|
|
220
|
+
if (resp.status === 401) {
|
|
221
|
+
throw new AuthError(void 0, parsedError);
|
|
222
|
+
}
|
|
223
|
+
if (resp.status === 404) {
|
|
224
|
+
throw new NotFoundError(path, parsedError);
|
|
225
|
+
}
|
|
226
|
+
if (resp.status === 400) {
|
|
227
|
+
throw new APIError(path, parsedError.detail, parsedError);
|
|
228
|
+
}
|
|
229
|
+
throw new CtxdbHttpError(resp.status, parsedError.detail, parsedError);
|
|
188
230
|
}
|
|
189
231
|
if (dbg) debug("http", `\u2190 ${method} ${path} ${resp.status} (${Date.now() - t0}ms) body=${text.length}B`);
|
|
190
232
|
if (!text) return {};
|
|
@@ -197,11 +239,13 @@ var HttpClient = class {
|
|
|
197
239
|
get(path, params) {
|
|
198
240
|
return this.doRequest("GET", path, { params });
|
|
199
241
|
}
|
|
200
|
-
postJson(path, body, params) {
|
|
242
|
+
postJson(path, body, params, options = {}) {
|
|
201
243
|
return this.doRequest("POST", path, {
|
|
202
244
|
body: JSON.stringify(body ?? {}),
|
|
203
245
|
contentType: "application/json",
|
|
204
|
-
params
|
|
246
|
+
params,
|
|
247
|
+
timeoutMs: options.timeoutMs,
|
|
248
|
+
headers: options.headers
|
|
205
249
|
});
|
|
206
250
|
}
|
|
207
251
|
putJson(path, body) {
|
|
@@ -230,7 +274,12 @@ var HttpClient = class {
|
|
|
230
274
|
const blob = part.content instanceof Blob ? part.content : new Blob([part.content], { type: part.mimeType });
|
|
231
275
|
fd.append(name, blob, part.filename);
|
|
232
276
|
}
|
|
233
|
-
return this.doRequest("POST", path, {
|
|
277
|
+
return this.doRequest("POST", path, {
|
|
278
|
+
body: fd,
|
|
279
|
+
params: options.params,
|
|
280
|
+
timeoutMs: options.timeoutMs,
|
|
281
|
+
headers: options.headers
|
|
282
|
+
});
|
|
234
283
|
}
|
|
235
284
|
};
|
|
236
285
|
function maybeJson(text) {
|
|
@@ -240,28 +289,43 @@ function maybeJson(text) {
|
|
|
240
289
|
return text;
|
|
241
290
|
}
|
|
242
291
|
}
|
|
243
|
-
function
|
|
244
|
-
if (!text) return fallback;
|
|
292
|
+
function parseErrorResponse(text, fallback) {
|
|
293
|
+
if (!text) return { detail: fallback };
|
|
245
294
|
let parsed;
|
|
246
295
|
try {
|
|
247
296
|
parsed = JSON.parse(text);
|
|
248
297
|
} catch {
|
|
249
|
-
return text || fallback;
|
|
298
|
+
return { detail: text || fallback, responseBody: text || void 0 };
|
|
250
299
|
}
|
|
251
300
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
252
301
|
const obj = parsed;
|
|
253
|
-
|
|
302
|
+
let detail = "";
|
|
303
|
+
for (const k of ["errorMessage", "detail", "message", "error"]) {
|
|
254
304
|
const v = obj[k];
|
|
255
|
-
if (typeof v === "string" && v)
|
|
305
|
+
if (typeof v === "string" && v) {
|
|
306
|
+
detail = v;
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
256
309
|
}
|
|
257
|
-
|
|
310
|
+
const rawCode = obj.errorCode;
|
|
311
|
+
const numericCode = typeof rawCode === "number" ? rawCode : typeof rawCode === "string" && rawCode.trim() !== "" ? Number(rawCode) : void 0;
|
|
312
|
+
const errorCode = typeof numericCode === "number" && Number.isFinite(numericCode) ? numericCode : void 0;
|
|
313
|
+
const errorMessage = typeof obj.errorMessage === "string" && obj.errorMessage ? obj.errorMessage : void 0;
|
|
314
|
+
return {
|
|
315
|
+
detail: detail || JSON.stringify(parsed),
|
|
316
|
+
errorCode,
|
|
317
|
+
errorMessage,
|
|
318
|
+
data: Object.hasOwn(obj, "data") ? obj.data : void 0,
|
|
319
|
+
responseBody: parsed
|
|
320
|
+
};
|
|
258
321
|
}
|
|
259
|
-
return String(parsed);
|
|
322
|
+
return { detail: String(parsed), responseBody: parsed };
|
|
260
323
|
}
|
|
261
324
|
|
|
262
325
|
// src/lib/agents.ts
|
|
263
326
|
import { homedir as homedir2 } from "os";
|
|
264
|
-
import { join as join3 } from "path";
|
|
327
|
+
import { delimiter, join as join3, sep } from "path";
|
|
328
|
+
import { accessSync, constants, existsSync, statSync } from "fs";
|
|
265
329
|
var SUPPORTED_AGENTS = ["qoder", "qoderwork", "codex", "claude", "opencode", "hermes"];
|
|
266
330
|
function isBuiltinAgent(v) {
|
|
267
331
|
return typeof v === "string" && SUPPORTED_AGENTS.includes(v);
|
|
@@ -270,33 +334,152 @@ function isAgentSlug(v) {
|
|
|
270
334
|
return v === "default" || isBuiltinAgent(v);
|
|
271
335
|
}
|
|
272
336
|
var isAgent = isAgentSlug;
|
|
273
|
-
function agentHomeDir(agent) {
|
|
337
|
+
function agentHomeDir(agent, home = homedir2()) {
|
|
274
338
|
switch (agent) {
|
|
275
339
|
case "qoder":
|
|
276
|
-
return join3(
|
|
340
|
+
return join3(home, ".qoder");
|
|
277
341
|
case "qoderwork":
|
|
278
|
-
return join3(
|
|
342
|
+
return join3(home, ".qoderwork");
|
|
279
343
|
case "codex":
|
|
280
|
-
return join3(
|
|
344
|
+
return join3(home, ".codex");
|
|
281
345
|
case "claude":
|
|
282
|
-
return join3(
|
|
346
|
+
return join3(home, ".claude");
|
|
283
347
|
case "opencode":
|
|
284
|
-
return join3(
|
|
348
|
+
return join3(home, ".config", "opencode");
|
|
285
349
|
case "hermes":
|
|
286
|
-
return join3(
|
|
350
|
+
return join3(home, ".hermes");
|
|
287
351
|
}
|
|
288
352
|
}
|
|
289
353
|
var AGENT_VARIANT_HOMES = {
|
|
290
354
|
qoder: [".qoder-cn"],
|
|
291
355
|
qoderwork: [".qoderworkcn"]
|
|
292
356
|
};
|
|
293
|
-
function agentHomeDirs(agent) {
|
|
294
|
-
const primary = agentHomeDir(agent);
|
|
357
|
+
function agentHomeDirs(agent, home = homedir2()) {
|
|
358
|
+
const primary = agentHomeDir(agent, home);
|
|
295
359
|
const variants = (AGENT_VARIANT_HOMES[agent] ?? []).map(
|
|
296
|
-
(name) => join3(
|
|
360
|
+
(name) => join3(home, name)
|
|
297
361
|
);
|
|
298
362
|
return [primary, ...variants];
|
|
299
363
|
}
|
|
364
|
+
function agentPlatformSupport(agent, platform = process.platform) {
|
|
365
|
+
if (agent === "hermes" && platform === "win32") {
|
|
366
|
+
return {
|
|
367
|
+
supported: false,
|
|
368
|
+
detail: "Hermes integration currently supports macOS/Linux only; Windows Hermes is not yet supported."
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
return { supported: true, detail: `${agent} is supported on ${platform}.` };
|
|
372
|
+
}
|
|
373
|
+
function inspectAgentHomes(agent, options = {}) {
|
|
374
|
+
const exists = options.exists ?? existsSyncAdapter;
|
|
375
|
+
const candidates = agentHomeDirs(agent, options.home);
|
|
376
|
+
const existing = candidates.filter(exists);
|
|
377
|
+
return { exists: existing.length > 0, existing, candidates };
|
|
378
|
+
}
|
|
379
|
+
function existsSyncAdapter(path) {
|
|
380
|
+
try {
|
|
381
|
+
return existsSync(path);
|
|
382
|
+
} catch {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
var EXECUTABLE_AGENT_NAMES = {
|
|
387
|
+
opencode: "opencode",
|
|
388
|
+
hermes: "hermes"
|
|
389
|
+
};
|
|
390
|
+
function isDirectoryAdapter(path) {
|
|
391
|
+
try {
|
|
392
|
+
return statSync(path).isDirectory();
|
|
393
|
+
} catch {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function isExecutableAdapter(path, platform) {
|
|
398
|
+
try {
|
|
399
|
+
if (!statSync(path).isFile()) return false;
|
|
400
|
+
if (platform !== "win32") accessSync(path, constants.X_OK);
|
|
401
|
+
return true;
|
|
402
|
+
} catch {
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function envValue(env, name, platform) {
|
|
407
|
+
if (env[name] !== void 0) return env[name];
|
|
408
|
+
if (platform !== "win32") return void 0;
|
|
409
|
+
const entry = Object.entries(env).find(([key]) => key.toLowerCase() === name.toLowerCase());
|
|
410
|
+
return entry?.[1];
|
|
411
|
+
}
|
|
412
|
+
function resolveAgentExecutable(command, options = {}) {
|
|
413
|
+
const platform = options.platform ?? process.platform;
|
|
414
|
+
const env = options.env ?? process.env;
|
|
415
|
+
const isExecutable = options.isExecutable ?? isExecutableAdapter;
|
|
416
|
+
const pathValue = envValue(env, "PATH", platform) ?? "";
|
|
417
|
+
const pathSeparator = platform === "win32" ? ";" : delimiter;
|
|
418
|
+
const pathEntries = pathValue.split(pathSeparator).map((entry) => entry.trim().replace(/^"(.*)"$/, "$1")).filter(Boolean);
|
|
419
|
+
const suffixes = platform === "win32" ? (envValue(env, "PATHEXT", platform) ?? ".COM;.EXE;.BAT;.CMD").split(";").map((suffix) => suffix.trim()).filter(Boolean) : [""];
|
|
420
|
+
for (const directory of pathEntries) {
|
|
421
|
+
for (const suffix of suffixes) {
|
|
422
|
+
const candidate = join3(directory, `${command}${suffix}`);
|
|
423
|
+
if (isExecutable(candidate, platform)) return candidate;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return void 0;
|
|
427
|
+
}
|
|
428
|
+
function displayHomePath(home, path) {
|
|
429
|
+
if (path === home) return "~";
|
|
430
|
+
return path.startsWith(`${home}${sep}`) ? `~${path.slice(home.length)}` : path;
|
|
431
|
+
}
|
|
432
|
+
function detectInstalledAgents(options = {}) {
|
|
433
|
+
const home = options.home ?? homedir2();
|
|
434
|
+
const platform = options.platform ?? process.platform;
|
|
435
|
+
const env = options.env ?? process.env;
|
|
436
|
+
const isDirectory = options.isDirectory ?? isDirectoryAdapter;
|
|
437
|
+
const observations = [];
|
|
438
|
+
for (const agent of SUPPORTED_AGENTS) {
|
|
439
|
+
const evidence = [];
|
|
440
|
+
for (const candidate of agentHomeDirs(agent, home)) {
|
|
441
|
+
if (isDirectory(candidate)) {
|
|
442
|
+
evidence.push({ kind: "home", value: displayHomePath(home, candidate) });
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
const executableName = EXECUTABLE_AGENT_NAMES[agent];
|
|
446
|
+
if (executableName) {
|
|
447
|
+
const executable = resolveAgentExecutable(executableName, {
|
|
448
|
+
platform,
|
|
449
|
+
env,
|
|
450
|
+
isExecutable: options.isExecutable
|
|
451
|
+
});
|
|
452
|
+
if (executable) {
|
|
453
|
+
evidence.push({ kind: "executable", value: executableName });
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (evidence.length === 0) {
|
|
457
|
+
observations.push({
|
|
458
|
+
agent,
|
|
459
|
+
selected: false,
|
|
460
|
+
reason: "not-detected",
|
|
461
|
+
evidence
|
|
462
|
+
});
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const support = agentPlatformSupport(agent, platform);
|
|
466
|
+
if (!support.supported) {
|
|
467
|
+
observations.push({
|
|
468
|
+
agent,
|
|
469
|
+
selected: false,
|
|
470
|
+
reason: "unsupported-platform",
|
|
471
|
+
evidence,
|
|
472
|
+
detail: support.detail
|
|
473
|
+
});
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
observations.push({ agent, selected: true, reason: "detected", evidence });
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
selected: observations.filter((item) => item.selected).map((item) => item.agent),
|
|
480
|
+
observations
|
|
481
|
+
};
|
|
482
|
+
}
|
|
300
483
|
function agentFromEnv(env = process.env) {
|
|
301
484
|
return isAgentSlug(env.CTXDB_AGENT) ? env.CTXDB_AGENT : "default";
|
|
302
485
|
}
|
|
@@ -315,9 +498,110 @@ function agentFromArgvWithFallback(argv = process.argv.slice(2), env = process.e
|
|
|
315
498
|
}
|
|
316
499
|
|
|
317
500
|
// src/lib/config.ts
|
|
318
|
-
import { readFileSync as readFileSync2,
|
|
501
|
+
import { readFileSync as readFileSync2, existsSync as existsSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
319
502
|
import { homedir as homedir3 } from "os";
|
|
320
|
-
import {
|
|
503
|
+
import { join as join4 } from "path";
|
|
504
|
+
|
|
505
|
+
// src/lib/secure-file.ts
|
|
506
|
+
import {
|
|
507
|
+
chmodSync,
|
|
508
|
+
closeSync,
|
|
509
|
+
copyFileSync,
|
|
510
|
+
existsSync as existsSync2,
|
|
511
|
+
fsyncSync,
|
|
512
|
+
mkdirSync as mkdirSync2,
|
|
513
|
+
openSync,
|
|
514
|
+
renameSync,
|
|
515
|
+
unlinkSync,
|
|
516
|
+
writeFileSync
|
|
517
|
+
} from "fs";
|
|
518
|
+
import { randomBytes } from "crypto";
|
|
519
|
+
import { dirname as dirname3 } from "path";
|
|
520
|
+
var nodeSecureFileSystem = {
|
|
521
|
+
exists: existsSync2,
|
|
522
|
+
mkdir: (path, options) => {
|
|
523
|
+
mkdirSync2(path, options);
|
|
524
|
+
},
|
|
525
|
+
chmod: chmodSync,
|
|
526
|
+
open: openSync,
|
|
527
|
+
write: (fd, data) => {
|
|
528
|
+
writeFileSync(fd, data);
|
|
529
|
+
},
|
|
530
|
+
fsync: fsyncSync,
|
|
531
|
+
close: closeSync,
|
|
532
|
+
copy: copyFileSync,
|
|
533
|
+
rename: renameSync,
|
|
534
|
+
unlink: unlinkSync
|
|
535
|
+
};
|
|
536
|
+
function configBackupPath(target) {
|
|
537
|
+
return `${target}.bak`;
|
|
538
|
+
}
|
|
539
|
+
function secureAtomicWrite(target, content, options = {}) {
|
|
540
|
+
const fs = options.fs ?? nodeSecureFileSystem;
|
|
541
|
+
const platform = options.platform ?? process.platform;
|
|
542
|
+
const posix = platform !== "win32";
|
|
543
|
+
const dir = dirname3(target);
|
|
544
|
+
const backup = configBackupPath(target);
|
|
545
|
+
const suffix = options.tempSuffix ?? `${process.pid}.${randomBytes(6).toString("hex")}`;
|
|
546
|
+
const temp = `${target}.${suffix}.tmp`;
|
|
547
|
+
const hadTarget = fs.exists(target);
|
|
548
|
+
fs.mkdir(dir, { recursive: true, mode: 448 });
|
|
549
|
+
if (posix) {
|
|
550
|
+
fs.chmod(dir, 448);
|
|
551
|
+
if (hadTarget) fs.chmod(target, 384);
|
|
552
|
+
}
|
|
553
|
+
let fd = null;
|
|
554
|
+
let tempExists = false;
|
|
555
|
+
try {
|
|
556
|
+
fd = fs.open(temp, "wx", 384);
|
|
557
|
+
tempExists = true;
|
|
558
|
+
fs.write(fd, Buffer.from(content, "utf-8"));
|
|
559
|
+
fs.fsync(fd);
|
|
560
|
+
fs.close(fd);
|
|
561
|
+
fd = null;
|
|
562
|
+
if (posix) fs.chmod(temp, 384);
|
|
563
|
+
if (hadTarget && options.backup !== false) {
|
|
564
|
+
if (platform === "win32") {
|
|
565
|
+
if (fs.exists(backup)) fs.unlink(backup);
|
|
566
|
+
fs.rename(target, backup);
|
|
567
|
+
try {
|
|
568
|
+
fs.rename(temp, target);
|
|
569
|
+
tempExists = false;
|
|
570
|
+
} catch (error) {
|
|
571
|
+
fs.rename(backup, target);
|
|
572
|
+
throw error;
|
|
573
|
+
}
|
|
574
|
+
} else {
|
|
575
|
+
fs.copy(target, backup);
|
|
576
|
+
fs.chmod(backup, 384);
|
|
577
|
+
fs.rename(temp, target);
|
|
578
|
+
tempExists = false;
|
|
579
|
+
}
|
|
580
|
+
} else {
|
|
581
|
+
fs.rename(temp, target);
|
|
582
|
+
tempExists = false;
|
|
583
|
+
}
|
|
584
|
+
} finally {
|
|
585
|
+
if (fd !== null) {
|
|
586
|
+
try {
|
|
587
|
+
fs.close(fd);
|
|
588
|
+
} catch {
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
if (tempExists && fs.exists(temp)) {
|
|
592
|
+
try {
|
|
593
|
+
fs.unlink(temp);
|
|
594
|
+
} catch {
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// src/lib/secrets.ts
|
|
601
|
+
import { createHmac, randomBytes as randomBytes2 } from "crypto";
|
|
602
|
+
var PROCESS_FINGERPRINT_KEY = randomBytes2(32);
|
|
603
|
+
|
|
604
|
+
// src/lib/config.ts
|
|
321
605
|
function defaultConfigPath() {
|
|
322
606
|
return join4(homedir3(), ".ctxdb", "ctxdb.json");
|
|
323
607
|
}
|
|
@@ -360,7 +644,7 @@ function coerceKbCatalogInjection(v) {
|
|
|
360
644
|
return DEFAULT_KB_CATALOG_INJECTION;
|
|
361
645
|
}
|
|
362
646
|
function readRaw(path) {
|
|
363
|
-
if (!
|
|
647
|
+
if (!existsSync3(path)) return {};
|
|
364
648
|
try {
|
|
365
649
|
const parsed = JSON.parse(readFileSync2(path, "utf-8"));
|
|
366
650
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
@@ -458,7 +742,7 @@ function configToDisk(cfg) {
|
|
|
458
742
|
}
|
|
459
743
|
function removeAgent(agent, path, options = {}) {
|
|
460
744
|
const target = path ?? defaultConfigPath();
|
|
461
|
-
if (!
|
|
745
|
+
if (!existsSync3(target)) {
|
|
462
746
|
return { removed: false, remainingAgents: [], fileDeleted: false };
|
|
463
747
|
}
|
|
464
748
|
const raw = readRaw(target);
|
|
@@ -477,13 +761,14 @@ function removeAgent(agent, path, options = {}) {
|
|
|
477
761
|
const remaining = Object.keys(agents);
|
|
478
762
|
if (remaining.length === 0 && !options.keepEmptyShell) {
|
|
479
763
|
try {
|
|
480
|
-
|
|
764
|
+
unlinkSync2(target);
|
|
481
765
|
return { removed: true, remainingAgents: [], fileDeleted: true };
|
|
482
766
|
} catch {
|
|
483
767
|
}
|
|
484
768
|
}
|
|
485
|
-
const onDisk = { version: 2, agents };
|
|
486
|
-
|
|
769
|
+
const onDisk = { ...raw, version: 2, agents };
|
|
770
|
+
delete onDisk.default_agent;
|
|
771
|
+
secureAtomicWrite(target, JSON.stringify(onDisk, null, 2) + "\n");
|
|
487
772
|
return { removed: true, remainingAgents: remaining, fileDeleted: false };
|
|
488
773
|
}
|
|
489
774
|
function save(cfg, path, options = {}) {
|
|
@@ -493,14 +778,15 @@ function save(cfg, path, options = {}) {
|
|
|
493
778
|
const validRaw = isV2Schema(raw) ? raw : {};
|
|
494
779
|
const existingAgents = validRaw.agents && typeof validRaw.agents === "object" && !Array.isArray(validRaw.agents) ? { ...validRaw.agents } : {};
|
|
495
780
|
const onDisk = {
|
|
781
|
+
...validRaw,
|
|
496
782
|
version: 2,
|
|
497
783
|
agents: {
|
|
498
784
|
...existingAgents,
|
|
499
785
|
[agent]: configToDisk(cfg)
|
|
500
786
|
}
|
|
501
787
|
};
|
|
502
|
-
|
|
503
|
-
|
|
788
|
+
delete onDisk.default_agent;
|
|
789
|
+
secureAtomicWrite(target, JSON.stringify(onDisk, null, 2) + "\n");
|
|
504
790
|
}
|
|
505
791
|
function configuredAgents(path) {
|
|
506
792
|
const target = path ?? defaultConfigPath();
|
|
@@ -512,8 +798,7 @@ function writeInstalledPkgVersion(version, path) {
|
|
|
512
798
|
const target = path ?? defaultConfigPath();
|
|
513
799
|
const raw = readRaw(target);
|
|
514
800
|
const updated = { ...raw, installed_pkg_version: version };
|
|
515
|
-
|
|
516
|
-
writeFileSync(target, JSON.stringify(updated, null, 2) + "\n", "utf-8");
|
|
801
|
+
secureAtomicWrite(target, JSON.stringify(updated, null, 2) + "\n");
|
|
517
802
|
}
|
|
518
803
|
|
|
519
804
|
export {
|
|
@@ -528,6 +813,9 @@ export {
|
|
|
528
813
|
isAgentSlug,
|
|
529
814
|
agentHomeDir,
|
|
530
815
|
agentHomeDirs,
|
|
816
|
+
agentPlatformSupport,
|
|
817
|
+
inspectAgentHomes,
|
|
818
|
+
detectInstalledAgents,
|
|
531
819
|
agentFromEnv,
|
|
532
820
|
agentFromArgvWithFallback,
|
|
533
821
|
configDir,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
listKnowledgeBases
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3PFMHU3C.js";
|
|
5
5
|
import {
|
|
6
6
|
isConnectionError,
|
|
7
7
|
resetCircuit,
|
|
8
8
|
tripCircuit
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-USMJLDBD.js";
|
|
10
10
|
import {
|
|
11
11
|
CtxdbError
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JFTKYEVN.js";
|
|
13
13
|
|
|
14
14
|
// src/lib/kb-catalog.ts
|
|
15
15
|
function sanitizeKeyEntities(raw) {
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
isConnectionError,
|
|
5
5
|
resetCircuit,
|
|
6
6
|
tripCircuit
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-USMJLDBD.js";
|
|
8
8
|
import {
|
|
9
9
|
CtxdbError,
|
|
10
10
|
debug,
|
|
11
11
|
isDebug
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JFTKYEVN.js";
|
|
13
13
|
|
|
14
14
|
// src/lib/capture-orchestrator.ts
|
|
15
15
|
import {
|