@aliyunrds/ctxdb 0.0.1 → 0.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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CtxdbError
4
- } from "./chunk-L4YJ7LDI.js";
4
+ } from "./chunk-QSSNPN3M.js";
5
5
 
6
6
  // src/lib/recall-orchestrator.ts
7
7
  import {
@@ -1,6 +1,54 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/lib/logger.ts
4
+ import { appendFileSync, mkdirSync } from "fs";
5
+ import { homedir } from "os";
6
+ import { dirname, join } from "path";
7
+ function logPath() {
8
+ return join(homedir(), ".ctxdb", "logs", "ctxdb.log");
9
+ }
10
+ var _enabled = null;
11
+ function setDebug(enabled) {
12
+ _enabled = enabled;
13
+ }
14
+ function isDebug() {
15
+ return _enabled === true;
16
+ }
17
+ function debug(tag, msg, data) {
18
+ if (_enabled !== true) return;
19
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
20
+ let line = `${ts} [${tag}] ${msg}`;
21
+ if (data !== void 0) {
22
+ const s = typeof data === "string" ? data : JSON.stringify(data, null, 2);
23
+ line += `
24
+ ${s}`;
25
+ }
26
+ line += "\n";
27
+ const p = logPath();
28
+ try {
29
+ mkdirSync(dirname(p), { recursive: true });
30
+ appendFileSync(p, line, "utf-8");
31
+ } catch {
32
+ }
33
+ }
34
+
3
35
  // src/lib/http-client.ts
36
+ import { readFileSync } from "fs";
37
+ import { fileURLToPath } from "url";
38
+ import { dirname as dirname2, join as join2 } from "path";
39
+ function findPackageVersion() {
40
+ let dir = dirname2(fileURLToPath(import.meta.url));
41
+ for (let i = 0; i < 5; i++) {
42
+ try {
43
+ const pkg = JSON.parse(readFileSync(join2(dir, "package.json"), "utf-8"));
44
+ if (pkg.name === "@aliyunrds/ctxdb") return pkg.version;
45
+ } catch {
46
+ }
47
+ dir = dirname2(dir);
48
+ }
49
+ return "0.0.0";
50
+ }
51
+ var PKG_VERSION = findPackageVersion();
4
52
  var DEFAULT_TIMEOUT_MS = 3e4;
5
53
  var CtxdbError = class extends Error {
6
54
  constructor(message) {
@@ -53,7 +101,7 @@ var HttpClient = class {
53
101
  this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
54
102
  this.apiKey = opts.apiKey;
55
103
  this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
56
- this.userAgent = opts.userAgent ?? "ctxdb-cli/0.0.1";
104
+ this.userAgent = opts.userAgent ?? `ctxdb-cli/${PKG_VERSION}`;
57
105
  this.extraHeaders = { ...opts.extraHeaders ?? {} };
58
106
  const f = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
59
107
  this.fetchImpl = f;
@@ -77,8 +125,15 @@ var HttpClient = class {
77
125
  const s = qs.toString();
78
126
  if (s) url = `${url}?${s}`;
79
127
  }
128
+ const effectiveTimeout = init.timeoutMs ?? this.timeoutMs;
129
+ const dbg = isDebug();
130
+ let t0 = 0;
131
+ if (dbg) {
132
+ t0 = Date.now();
133
+ debug("http", `\u2192 ${method} ${url} (timeout=${effectiveTimeout}ms)`);
134
+ }
80
135
  const controller = new AbortController();
81
- const timer = setTimeout(() => controller.abort(), this.timeoutMs);
136
+ const timer = setTimeout(() => controller.abort(), effectiveTimeout);
82
137
  try {
83
138
  let resp;
84
139
  try {
@@ -90,27 +145,36 @@ var HttpClient = class {
90
145
  });
91
146
  } catch (err) {
92
147
  if (err?.name === "AbortError") {
93
- throw new CtxdbError(`request timeout after ${this.timeoutMs}ms: ${url}`);
148
+ if (dbg) debug("http", `\u2717 ${method} ${path} timeout after ${Date.now() - t0}ms`);
149
+ throw new CtxdbError(`request timeout after ${effectiveTimeout}ms: ${url}`);
94
150
  }
151
+ if (dbg) debug("http", `\u2717 ${method} ${path} network error after ${Date.now() - t0}ms: ${err?.message ?? err}`);
95
152
  throw new CtxdbError(`network error contacting ${url}: ${err?.message ?? err}`);
96
153
  }
97
- if (resp.status === 204) return {};
154
+ if (resp.status === 204) {
155
+ if (dbg) debug("http", `\u2190 ${method} ${path} 204 (${Date.now() - t0}ms)`);
156
+ return {};
157
+ }
98
158
  let text;
99
159
  try {
100
160
  text = await resp.text();
101
161
  } catch (err) {
102
162
  if (err?.name === "AbortError") {
103
- throw new CtxdbError(`request timeout after ${this.timeoutMs}ms (body read): ${url}`);
163
+ if (dbg) debug("http", `\u2717 ${method} ${path} body-read timeout after ${Date.now() - t0}ms`);
164
+ throw new CtxdbError(`request timeout after ${effectiveTimeout}ms (body read): ${url}`);
104
165
  }
166
+ if (dbg) debug("http", `\u2717 ${method} ${path} body-read error after ${Date.now() - t0}ms: ${err?.message ?? err}`);
105
167
  throw new CtxdbError(`network error reading body from ${url}: ${err?.message ?? err}`);
106
168
  }
107
169
  if (!resp.ok) {
108
170
  const detail = extractErrorDetail(text, `HTTP ${resp.status}`);
171
+ if (dbg) debug("http", `\u2190 ${method} ${path} ${resp.status} (${Date.now() - t0}ms) ${detail}`);
109
172
  if (resp.status === 401) throw new AuthError();
110
173
  if (resp.status === 404) throw new NotFoundError(path);
111
174
  if (resp.status === 400) throw new APIError(path, detail);
112
175
  throw new CtxdbHttpError(resp.status, detail);
113
176
  }
177
+ if (dbg) debug("http", `\u2190 ${method} ${path} ${resp.status} (${Date.now() - t0}ms) body=${text.length}B`);
114
178
  if (!text) return {};
115
179
  return maybeJson(text);
116
180
  } finally {
@@ -145,7 +209,7 @@ var HttpClient = class {
145
209
  * header — when fetch sees a FormData body it sets the multipart
146
210
  * boundary itself.
147
211
  */
148
- postMultipart(path, fields = {}, files = {}) {
212
+ postMultipart(path, fields = {}, files = {}, options = {}) {
149
213
  const fd = new FormData();
150
214
  for (const [name, value] of Object.entries(fields)) {
151
215
  fd.append(name, value);
@@ -154,7 +218,7 @@ var HttpClient = class {
154
218
  const blob = part.content instanceof Blob ? part.content : new Blob([part.content], { type: part.mimeType });
155
219
  fd.append(name, blob, part.filename);
156
220
  }
157
- return this.doRequest("POST", path, { body: fd });
221
+ return this.doRequest("POST", path, { body: fd, timeoutMs: options.timeoutMs });
158
222
  }
159
223
  };
160
224
  function maybeJson(text) {
@@ -184,8 +248,8 @@ function extractErrorDetail(text, fallback) {
184
248
  }
185
249
 
186
250
  // src/lib/agents.ts
187
- import { homedir } from "os";
188
- import { join } from "path";
251
+ import { homedir as homedir2 } from "os";
252
+ import { join as join3 } from "path";
189
253
  var SUPPORTED_AGENTS = ["qoder", "codex", "claude"];
190
254
  function isAgent(v) {
191
255
  return typeof v === "string" && SUPPORTED_AGENTS.includes(v);
@@ -193,11 +257,11 @@ function isAgent(v) {
193
257
  function agentHomeDir(agent) {
194
258
  switch (agent) {
195
259
  case "qoder":
196
- return join(homedir(), ".qoder");
260
+ return join3(homedir2(), ".qoder");
197
261
  case "codex":
198
- return join(homedir(), ".codex");
262
+ return join3(homedir2(), ".codex");
199
263
  case "claude":
200
- return join(homedir(), ".claude");
264
+ return join3(homedir2(), ".claude");
201
265
  }
202
266
  }
203
267
  function agentFromEnv(env = process.env) {
@@ -218,13 +282,13 @@ function agentFromArgvWithFallback(argv = process.argv.slice(2), env = process.e
218
282
  }
219
283
 
220
284
  // src/lib/config.ts
221
- import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from "fs";
222
- import { homedir as homedir2 } from "os";
223
- import { dirname, join as join2 } from "path";
285
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync as mkdirSync2, existsSync, unlinkSync } from "fs";
286
+ import { homedir as homedir3 } from "os";
287
+ import { dirname as dirname3, join as join4 } from "path";
224
288
  function defaultConfigPath() {
225
- return join2(homedir2(), ".ctxdb", "ctxdb.json");
289
+ return join4(homedir3(), ".ctxdb", "ctxdb.json");
226
290
  }
227
- var DEFAULT_CONFIG_PATH = join2(homedir2(), ".ctxdb", "ctxdb.json");
291
+ var DEFAULT_CONFIG_PATH = join4(homedir3(), ".ctxdb", "ctxdb.json");
228
292
  var DEFAULT_BASE_URL = "https://context-database.aliyuncs.com";
229
293
  var DEFAULT_USER_ID = "default";
230
294
  var DEFAULT_TOP_K = 5;
@@ -255,7 +319,7 @@ function coerceBool(v, fallback) {
255
319
  function readRaw(path) {
256
320
  if (!existsSync(path)) return {};
257
321
  try {
258
- const parsed = JSON.parse(readFileSync(path, "utf-8"));
322
+ const parsed = JSON.parse(readFileSync2(path, "utf-8"));
259
323
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
260
324
  return parsed;
261
325
  }
@@ -284,7 +348,7 @@ function configFromDisk(raw) {
284
348
  userId: typeof raw.user_id === "string" && raw.user_id ? raw.user_id : DEFAULT_USER_ID,
285
349
  autoCapture: coerceBool(raw.auto_capture, true),
286
350
  autoRecall: coerceBool(raw.auto_recall, true),
287
- warmupRecall: coerceBool(raw.warmup_recall, true),
351
+ warmupRecall: coerceBool(raw.warmup_recall, false),
288
352
  recallKnowledge: coerceBool(raw.recall_knowledge, false),
289
353
  topK: coerceInt(raw.top_k, DEFAULT_TOP_K),
290
354
  threshold: coerceFloat(raw.threshold, DEFAULT_THRESHOLD),
@@ -373,11 +437,19 @@ function save(cfg, path, options = {}) {
373
437
  [agent]: configToDisk(cfg)
374
438
  }
375
439
  };
376
- mkdirSync(dirname(target), { recursive: true });
440
+ mkdirSync2(dirname3(target), { recursive: true });
377
441
  writeFileSync(target, JSON.stringify(onDisk, null, 2) + "\n", "utf-8");
378
442
  }
443
+ function configuredAgents(path) {
444
+ const target = path ?? defaultConfigPath();
445
+ const raw = readRaw(target);
446
+ if (!isV2Schema(raw) || !raw.agents || typeof raw.agents !== "object") return [];
447
+ return Object.keys(raw.agents).filter(isAgent);
448
+ }
379
449
 
380
450
  export {
451
+ setDebug,
452
+ debug,
381
453
  CtxdbError,
382
454
  NotFoundError,
383
455
  HttpClient,
@@ -391,5 +463,6 @@ export {
391
463
  isComplete,
392
464
  load,
393
465
  removeAgent,
394
- save
466
+ save,
467
+ configuredAgents
395
468
  };