@aliyunrds/ctxdb 1.0.8-beta.2 → 1.0.8-beta.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 CHANGED
@@ -31,12 +31,14 @@ Internal login stores its single active connection in owner-only
31
31
  without writing an `api_key` field into the Agent or default profile; an
32
32
  existing field in either updated profile is removed. At runtime this managed
33
33
  credential overrides the API key and DATA URL in the existing v2
34
- `~/.ctxdb/ctxdb.json`; `CTXDB_API_KEY` and `CTXDB_BASE_URL` remain the highest
35
- priority overrides. Re-login replaces the active connection and revokes the
36
- previous key after setup succeeds. The public `@aliyunrds/ctxdb` build does not
37
- contain or advertise these commands and continues to use `ctxdb setup` and the
38
- v2 config exactly as before. Build the internal staging package with
39
- `pnpm build:internal`.
34
+ `~/.ctxdb/ctxdb.json`; `CTXDB_ACCESS_TOKEN`, `CTXDB_API_KEY`, and
35
+ `CTXDB_BASE_URL` remain higher-priority overrides. `ctxdb login` rejects all
36
+ three while `ctxdb logout` rejects the two credential overrides, so command
37
+ output cannot disagree with subsequent DATA requests. Re-login replaces the
38
+ active connection and revokes the previous key after setup succeeds. The
39
+ public `@aliyunrds/ctxdb` build does not contain or advertise these commands and
40
+ continues to use `ctxdb setup` and the v2 config exactly as before. Build the
41
+ internal staging package with `pnpm build:internal`.
40
42
 
41
43
  The distinction is a compile-time distribution manifest, not a runtime
42
44
  environment-variable or file-existence check. The `public` manifest disables
@@ -603,7 +605,9 @@ Field reference:
603
605
  | `knowledge_top_k` | int | `6` | KB chunks pulled per recall (only effective when `recall_knowledge: true`) |
604
606
  | `debug` | bool | `false` | Configured preference for verbose hook logging and full recall tracing. Effective debug is forced on for every final `base_url` outside the exact official-production allowlist; see “Debug control and recall replay”. General logs go to `~/.ctxdb/logs/ctxdb.log`, structured full-content recall records to `~/.ctxdb/logs/recall-trace.jsonl` |
605
607
 
606
- Env-var overrides apply to the selected agent config (env wins): `CTXDB_AGENT` / `CTXDB_API_KEY` / `CTXDB_BASE_URL` / `CTXDB_USER_ID` / `CTXDB_AGENT_ID` / `CTXDB_APP_ID`. The internal login command additionally reads `CTXDB_LOGIN_SERVER` as its provider-neutral login endpoint. The last two default to unset — the request body omits `agent_id`/`app_id` entirely; set them only when you want per-agent / per-app scope isolation on the server.
608
+ Env-var overrides apply to the selected agent config (env wins): `CTXDB_AGENT` / `CTXDB_ACCESS_TOKEN` / `CTXDB_API_KEY` / `CTXDB_BASE_URL` / `CTXDB_USER_ID` / `CTXDB_AGENT_ID` / `CTXDB_APP_ID`. The internal login command additionally reads `CTXDB_LOGIN_SERVER` as its provider-neutral login endpoint. The last two default to unset — the request body omits `agent_id`/`app_id` entirely; set them only when you want per-agent / per-app scope isolation on the server.
609
+
610
+ Downstream Agent hosts can set `CTXDB_ACCESS_TOKEN` to send `Authorization: Bearer <token>` to the Data API. It is runtime-only, never written to `~/.ctxdb/ctxdb.json`, and takes precedence over an API key for CLI, process hooks, and the in-process OpenCode plugin; a rejected token does not fall back to the API key. `ctxdb setup` remains API-key-only and never persists or validates an access token.
607
611
 
608
612
  Hook/plugin escape hatch: set `CTXDB_SKIP_HOOKS=TRUE` on the agent process to make all ctxdb hook entrypoints exit immediately before reading config or calling the API. Direct `ctxdb memory` / `ctxdb kb` / `ctxdb setup` CLI commands are unchanged.
609
613
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CtxdbError
4
- } from "./chunk-DMS5YHIK.js";
4
+ } from "./chunk-BUK4SZC2.js";
5
5
 
6
6
  // src/lib/kb.ts
7
7
  import {
@@ -1,15 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  listKnowledgeBases
4
- } from "./chunk-CULTDVI2.js";
4
+ } from "./chunk-3NJ37TEY.js";
5
5
  import {
6
6
  isConnectionError,
7
7
  resetCircuit,
8
8
  tripCircuit
9
- } from "./chunk-X75B57M2.js";
9
+ } from "./chunk-EI63DQX3.js";
10
10
  import {
11
- CtxdbError
12
- } from "./chunk-DMS5YHIK.js";
11
+ CtxdbError,
12
+ isDataApiReady,
13
+ resolveDataApiCredential
14
+ } from "./chunk-BUK4SZC2.js";
13
15
 
14
16
  // src/lib/kb-catalog.ts
15
17
  function sanitizeKeyEntities(raw) {
@@ -152,12 +154,13 @@ async function recallTurn(prompt, cfg, client, agentOrOptions = "default") {
152
154
  const options = typeof agentOrOptions === "string" ? { agent: agentOrOptions } : agentOrOptions;
153
155
  const agent = options.agent ?? "default";
154
156
  if (!prompt.trim()) return { ...EMPTY, reason: "empty_prompt" };
155
- if (!cfg.apiKey || !cfg.baseUrl) {
157
+ if (!isDataApiReady(cfg)) {
156
158
  return { ...EMPTY, reason: "config_incomplete" };
157
159
  }
158
160
  if (!cfg.autoRecall) {
159
161
  return { ...EMPTY, reason: "auto_recall_disabled" };
160
162
  }
163
+ const credential = resolveDataApiCredential(cfg);
161
164
  const query = stripSystemReminders(prompt);
162
165
  const trace = cfg.debug ? {
163
166
  agent,
@@ -175,7 +178,11 @@ async function recallTurn(prompt, cfg, client, agentOrOptions = "default") {
175
178
  },
176
179
  store: {
177
180
  ...options.traceStore,
178
- secrets: [...options.traceStore?.secrets ?? [], cfg.apiKey]
181
+ secrets: [
182
+ ...options.traceStore?.secrets ?? [],
183
+ cfg.apiKey,
184
+ credential.value
185
+ ]
179
186
  }
180
187
  } : null;
181
188
  if (trace) {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  fetchKbCatalogBlock,
4
4
  recallTurn
5
- } from "./chunk-H33NUAHP.js";
5
+ } from "./chunk-7OX6UVPB.js";
6
6
 
7
7
  // src/lib/user-prompt-submit-compose.ts
8
8
  async function composeUserPromptSubmit(cfg, agent, client, prompt, sessionId = null) {
@@ -3,6 +3,19 @@ import {
3
3
  DISTRIBUTION_MANIFEST
4
4
  } from "./chunk-R67JELM7.js";
5
5
 
6
+ // src/lib/credentials.ts
7
+ function apiKeyCredential(apiKey) {
8
+ return { type: "api-key", value: apiKey };
9
+ }
10
+ function resolveDataApiCredential(cfg, env = process.env) {
11
+ const accessToken = env.CTXDB_ACCESS_TOKEN?.trim();
12
+ if (accessToken) return { type: "access-token", value: accessToken };
13
+ return cfg.apiKey ? apiKeyCredential(cfg.apiKey) : null;
14
+ }
15
+ function isDataApiReady(cfg, env = process.env) {
16
+ return Boolean(cfg.baseUrl && resolveDataApiCredential(cfg, env));
17
+ }
18
+
6
19
  // src/lib/logger.ts
7
20
  import { appendFileSync, mkdirSync } from "fs";
8
21
  import { homedir } from "os";
@@ -82,7 +95,7 @@ var AuthError = class extends CtxdbError {
82
95
  errorMessage;
83
96
  data;
84
97
  responseBody;
85
- constructor(message = "Unauthorized (HTTP 401) \u2014 check api_key", fields = {}) {
98
+ constructor(message = "Unauthorized (HTTP 401) \u2014 check Data API credential", fields = {}) {
86
99
  super(message);
87
100
  this.name = "AuthError";
88
101
  this.errorCode = fields.errorCode;
@@ -147,6 +160,7 @@ var CtxdbHttpError = class extends CtxdbError {
147
160
  };
148
161
  var HttpClient = class {
149
162
  baseUrl;
163
+ credential;
150
164
  apiKey;
151
165
  timeoutMs;
152
166
  userAgent;
@@ -154,10 +168,12 @@ var HttpClient = class {
154
168
  fetchImpl;
155
169
  authorizationProvider;
156
170
  constructor(opts) {
157
- this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
158
- if (!opts.apiKey && !opts.authorizationProvider) {
159
- throw new Error("HttpClient requires apiKey or authorizationProvider");
171
+ const credential = opts.credential ?? (opts.apiKey ? apiKeyCredential(opts.apiKey) : null);
172
+ if (!credential && !opts.authorizationProvider) {
173
+ throw new CtxdbError("DATA API credential is required");
160
174
  }
175
+ this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
176
+ this.credential = credential;
161
177
  this.apiKey = opts.apiKey ?? "";
162
178
  this.authorizationProvider = opts.authorizationProvider;
163
179
  this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
@@ -178,12 +194,19 @@ var HttpClient = class {
178
194
  return h;
179
195
  }
180
196
  async doRequest(method, path, init = {}) {
181
- const authorization = this.authorizationProvider ? await this.authorizationProvider.resolve() : {
182
- scheme: "Token",
183
- value: this.apiKey,
184
- baseUrl: this.baseUrl,
185
- expiresAt: null
186
- };
197
+ let authorization;
198
+ if (this.authorizationProvider) {
199
+ authorization = await this.authorizationProvider.resolve();
200
+ } else {
201
+ const credential = this.credential;
202
+ if (!credential) throw new CtxdbError("DATA API credential is required");
203
+ authorization = {
204
+ scheme: credential.type === "access-token" ? "Bearer" : "Token",
205
+ value: credential.value,
206
+ baseUrl: this.baseUrl,
207
+ expiresAt: null
208
+ };
209
+ }
187
210
  let url = `${authorization.baseUrl.replace(/\/+$/, "")}${path}`;
188
211
  if (init.params) {
189
212
  const qs = new URLSearchParams();
@@ -816,9 +839,6 @@ var DEFAULT_TOP_K = 5;
816
839
  var DEFAULT_THRESHOLD = 0.4;
817
840
  var DEFAULT_KNOWLEDGE_TOP_K = 6;
818
841
  var DEFAULT_KB_CATALOG_INJECTION = "session_start";
819
- function isComplete(cfg) {
820
- return Boolean(cfg.apiKey && cfg.baseUrl);
821
- }
822
842
  function resolveConfigAgent(options = {}, preloadedRaw) {
823
843
  if (isAgentSlug(options.agent)) return options.agent;
824
844
  return agentFromEnv(options.env);
@@ -1061,6 +1081,9 @@ function writeInstalledPkgVersion(version, path) {
1061
1081
  }
1062
1082
 
1063
1083
  export {
1084
+ apiKeyCredential,
1085
+ resolveDataApiCredential,
1086
+ isDataApiReady,
1064
1087
  setDebug,
1065
1088
  isDebug,
1066
1089
  debug,
@@ -1083,7 +1106,6 @@ export {
1083
1106
  configDir,
1084
1107
  DEFAULT_BASE_URL,
1085
1108
  DEFAULT_USER_ID,
1086
- isComplete,
1087
1109
  load,
1088
1110
  removeAgent,
1089
1111
  save,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  configDir
4
- } from "./chunk-DMS5YHIK.js";
4
+ } from "./chunk-BUK4SZC2.js";
5
5
 
6
6
  // src/lib/circuit.ts
7
7
  import { statSync, writeFileSync, unlinkSync, mkdirSync, readdirSync, readFileSync } from "fs";
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  fetchKbCatalogBlock,
4
4
  recallTurn
5
- } from "./chunk-H33NUAHP.js";
5
+ } from "./chunk-7OX6UVPB.js";
6
6
  import {
7
7
  debug
8
- } from "./chunk-DMS5YHIK.js";
8
+ } from "./chunk-BUK4SZC2.js";
9
9
 
10
10
  // src/lib/warmup-recall.ts
11
11
  import { execSync } from "child_process";
@@ -4,12 +4,13 @@ import {
4
4
  isConnectionError,
5
5
  resetCircuit,
6
6
  tripCircuit
7
- } from "./chunk-X75B57M2.js";
7
+ } from "./chunk-EI63DQX3.js";
8
8
  import {
9
9
  CtxdbError,
10
10
  debug,
11
+ isDataApiReady,
11
12
  isDebug
12
- } from "./chunk-DMS5YHIK.js";
13
+ } from "./chunk-BUK4SZC2.js";
13
14
 
14
15
  // src/lib/capture-orchestrator.ts
15
16
  import {
@@ -398,7 +399,7 @@ async function captureParsedMessages(parsed, cfg, client, agent = "default", ses
398
399
  };
399
400
  }
400
401
  function capturePreflight(cfg, agent) {
401
- if (!cfg.apiKey || !cfg.baseUrl) {
402
+ if (!isDataApiReady(cfg)) {
402
403
  return { captured: false, reason: "config_incomplete", messageCount: 0 };
403
404
  }
404
405
  if (!cfg.autoCapture) {
package/dist/cli/main.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  uploadFile,
17
17
  uploadText,
18
18
  validateLocalFile
19
- } from "../chunk-CULTDVI2.js";
19
+ } from "../chunk-3NJ37TEY.js";
20
20
  import {
21
21
  AGENT_CHOICES,
22
22
  CtxdbError,
@@ -31,19 +31,20 @@ import {
31
31
  agentHomeDir,
32
32
  agentHomeDirs,
33
33
  agentPlatformSupport,
34
+ apiKeyCredential,
34
35
  configuredAgents,
35
36
  detectInstalledAgents,
36
37
  hasConfiguredAgent,
37
38
  inspectAgentHomes,
38
39
  isAgentSlug,
39
40
  isBuiltinAgent,
40
- isComplete,
41
41
  load,
42
42
  removeAgent,
43
+ resolveDataApiCredential,
43
44
  save,
44
45
  updateConfiguredDebug,
45
46
  writeInstalledPkgVersion
46
- } from "../chunk-DMS5YHIK.js";
47
+ } from "../chunk-BUK4SZC2.js";
47
48
  import {
48
49
  beginUpdateNotification,
49
50
  completeUpdateNotification,
@@ -275,6 +276,8 @@ function formatStatusResult(r) {
275
276
  ["base_url", r.base_url],
276
277
  ["user_id", r.user_id],
277
278
  ["api_key", r.api_key_set ? "set" : "not set"],
279
+ ["access_token", r.access_token_set ? "set" : "not set"],
280
+ ["credential_type", r.credential_type ?? "none"],
278
281
  ["auto_capture", r.auto_capture],
279
282
  ["auto_recall", r.auto_recall],
280
283
  ["top_k", r.top_k],
@@ -323,15 +326,16 @@ function agentFromFlags(flags) {
323
326
  function buildContext(args) {
324
327
  const agent = agentFromFlags(args?.flags ?? {});
325
328
  const cfg = load({ agent });
326
- if (!isComplete(cfg)) {
327
- const hint = agent === "default" ? "run `ctxdb setup --api-key=<key> --base-url=<url>` or set CTXDB_API_KEY / CTXDB_BASE_URL env vars" : `run \`ctxdb setup --agent ${agent}\` or set CTXDB_API_KEY / CTXDB_BASE_URL / CTXDB_USER_ID env vars`;
329
+ const credential = resolveDataApiCredential(cfg);
330
+ if (!cfg.baseUrl || !credential) {
331
+ const hint = agent === "default" ? "run `ctxdb setup --api-key=<key> --base-url=<url>` or set CTXDB_ACCESS_TOKEN / CTXDB_API_KEY / CTXDB_BASE_URL env vars" : `run \`ctxdb setup --agent ${agent}\` or set CTXDB_ACCESS_TOKEN / CTXDB_API_KEY / CTXDB_BASE_URL / CTXDB_USER_ID env vars`;
328
332
  process.stderr.write(`config incomplete for agent ${agent}: ${hint}
329
333
  `);
330
334
  process.exit(2);
331
335
  }
332
336
  const client = new HttpClient({
333
337
  baseUrl: cfg.baseUrl,
334
- apiKey: cfg.apiKey
338
+ credential
335
339
  });
336
340
  return { cfg, client, agent };
337
341
  }
@@ -724,7 +728,10 @@ async function runSetup(options) {
724
728
  });
725
729
  } else {
726
730
  try {
727
- const client = new HttpClient({ baseUrl: cfg.baseUrl, apiKey: cfg.apiKey });
731
+ const client = new HttpClient({
732
+ baseUrl: cfg.baseUrl,
733
+ credential: apiKeyCredential(cfg.apiKey)
734
+ });
728
735
  await client.get("/v1/ping/");
729
736
  steps.push({ step: "validate-ping", ok: true });
730
737
  } catch (err) {
@@ -2090,12 +2097,13 @@ FLAGS
2090
2097
  `;
2091
2098
  async function inspectStatus(agent) {
2092
2099
  const cfg = load({ agent });
2093
- const complete = isComplete(cfg);
2100
+ const credential = resolveDataApiCredential(cfg);
2101
+ const complete = Boolean(cfg.baseUrl && credential);
2094
2102
  let connected = false;
2095
2103
  let pingError = null;
2096
- if (complete) {
2104
+ if (complete && credential) {
2097
2105
  try {
2098
- const client = new HttpClient({ baseUrl: cfg.baseUrl, apiKey: cfg.apiKey });
2106
+ const client = new HttpClient({ baseUrl: cfg.baseUrl, credential });
2099
2107
  await client.get("/v1/ping/");
2100
2108
  connected = true;
2101
2109
  } catch (err) {
@@ -2110,6 +2118,8 @@ async function inspectStatus(agent) {
2110
2118
  base_url: cfg.baseUrl,
2111
2119
  user_id: cfg.userId,
2112
2120
  api_key_set: Boolean(cfg.apiKey),
2121
+ access_token_set: Boolean(process.env.CTXDB_ACCESS_TOKEN?.trim()),
2122
+ credential_type: credential?.type ?? null,
2113
2123
  auto_capture: cfg.autoCapture,
2114
2124
  auto_recall: cfg.autoRecall,
2115
2125
  top_k: cfg.topK,
@@ -2192,12 +2202,13 @@ ${hint}
2192
2202
  async function ping(args) {
2193
2203
  const agent = agentFromFlags(args.flags);
2194
2204
  const cfg = load({ agent });
2195
- if (!isComplete(cfg)) {
2205
+ const credential = resolveDataApiCredential(cfg);
2206
+ if (!cfg.baseUrl || !credential) {
2196
2207
  fail(
2197
- `config incomplete for agent ${agent} \u2014 run \`ctxdb setup --agent ${agent}\` or set CTXDB_API_KEY / CTXDB_BASE_URL / CTXDB_USER_ID`
2208
+ `config incomplete for agent ${agent} \u2014 run \`ctxdb setup --agent ${agent}\` or set CTXDB_ACCESS_TOKEN / CTXDB_API_KEY / CTXDB_BASE_URL / CTXDB_USER_ID`
2198
2209
  );
2199
2210
  }
2200
- const client = new HttpClient({ baseUrl: cfg.baseUrl, apiKey: cfg.apiKey });
2211
+ const client = new HttpClient({ baseUrl: cfg.baseUrl, credential });
2201
2212
  const resp = await client.get("/v1/ping/");
2202
2213
  printResult(resp, !!args.flags.json);
2203
2214
  return 0;
@@ -4474,6 +4485,7 @@ AGENT RESOLUTION (when --agent is omitted):
4474
4485
  ENV VARS (override selected ~/.ctxdb/ctxdb.json agent config):
4475
4486
  CTXDB_AGENT CTXDB_API_KEY CTXDB_BASE_URL CTXDB_USER_ID
4476
4487
  CTXDB_AGENT_ID CTXDB_APP_ID
4488
+ CTXDB_ACCESS_TOKEN Runtime-only Data API Bearer credential; takes precedence over API key
4477
4489
 
4478
4490
  UPDATE CHECK ENV VARS:
4479
4491
  CTXDB_DISABLE_UPDATE_CHECK=1
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  captureParsedMessages
4
- } from "../chunk-LYHGJOHM.js";
5
- import "../chunk-X75B57M2.js";
4
+ } from "../chunk-ZFS6OMWE.js";
5
+ import "../chunk-EI63DQX3.js";
6
6
  import {
7
7
  HttpClient,
8
8
  agentFromArgvWithFallback,
9
9
  debug,
10
10
  load,
11
+ resolveDataApiCredential,
11
12
  setDebug
12
- } from "../chunk-DMS5YHIK.js";
13
+ } from "../chunk-BUK4SZC2.js";
13
14
  import {
14
15
  shouldSkipHooks
15
16
  } from "../chunk-5ML4VSXN.js";
@@ -170,19 +171,20 @@ async function main() {
170
171
  }
171
172
  const input = extractHermesPostLlmCall(event);
172
173
  const cfg = load({ agent });
174
+ const credential = resolveDataApiCredential(cfg);
173
175
  setDebug(cfg.debug);
174
176
  debug("hermes.post_llm_call", "start", {
175
177
  sessionId: input.sessionId,
176
178
  messageCount: input.messages.length,
177
179
  userId: cfg.userId
178
180
  });
179
- if (!cfg.apiKey || !cfg.baseUrl) {
181
+ if (!cfg.baseUrl || !credential) {
180
182
  debug("hermes.post_llm_call", "skip (config incomplete)");
181
183
  return 0;
182
184
  }
183
185
  const client = new HttpClient({
184
186
  baseUrl: cfg.baseUrl,
185
- apiKey: cfg.apiKey,
187
+ credential,
186
188
  timeoutMs: 5e3
187
189
  });
188
190
  const result = await captureParsedMessages(
@@ -2,25 +2,25 @@
2
2
  import {
3
3
  HOOK_TIMEOUT_MS,
4
4
  composeSessionStart
5
- } from "../chunk-5ZSZMN2T.js";
5
+ } from "../chunk-LZ2LOWZL.js";
6
6
  import {
7
7
  composeUserPromptSubmit
8
- } from "../chunk-4FCZ2TZM.js";
8
+ } from "../chunk-AUBVVYQL.js";
9
9
  import {
10
10
  fetchKbCatalogBlock
11
- } from "../chunk-H33NUAHP.js";
12
- import "../chunk-CULTDVI2.js";
11
+ } from "../chunk-7OX6UVPB.js";
12
+ import "../chunk-3NJ37TEY.js";
13
13
  import {
14
14
  isCircuitOpen
15
- } from "../chunk-X75B57M2.js";
15
+ } from "../chunk-EI63DQX3.js";
16
16
  import {
17
17
  HttpClient,
18
18
  agentFromArgvWithFallback,
19
19
  debug,
20
- isComplete,
21
20
  load,
21
+ resolveDataApiCredential,
22
22
  setDebug
23
- } from "../chunk-DMS5YHIK.js";
23
+ } from "../chunk-BUK4SZC2.js";
24
24
  import {
25
25
  shouldSkipHooks
26
26
  } from "../chunk-5ML4VSXN.js";
@@ -109,6 +109,7 @@ async function main() {
109
109
  }
110
110
  const input = extractHermesPreLlmCall(event);
111
111
  const cfg = load({ agent });
112
+ const credential = resolveDataApiCredential(cfg);
112
113
  setDebug(cfg.debug);
113
114
  debug("hermes.pre_llm_call", "start", {
114
115
  prompt: input.prompt.slice(0, 200),
@@ -120,7 +121,7 @@ async function main() {
120
121
  const wantsRecall = cfg.autoRecall && Boolean(input.prompt.trim());
121
122
  const wantsSessionStart = input.isFirstTurn && Boolean(input.cwd) && (cfg.warmupRecall || cfg.kbCatalogInjection === "session_start");
122
123
  const wantsRepeatedSessionCatalog = cfg.kbCatalogInjection === "session_start";
123
- if (!isComplete(cfg) || !wantsRecall && !wantsSessionStart && !wantsRepeatedSessionCatalog) {
124
+ if (!cfg.baseUrl || !credential || !wantsRecall && !wantsSessionStart && !wantsRepeatedSessionCatalog) {
124
125
  debug("hermes.pre_llm_call", "skip (config incomplete or no enabled injection)");
125
126
  return 0;
126
127
  }
@@ -132,7 +133,7 @@ async function main() {
132
133
  }
133
134
  const client = new HttpClient({
134
135
  baseUrl: cfg.baseUrl,
135
- apiKey: cfg.apiKey,
136
+ credential,
136
137
  timeoutMs: HOOK_TIMEOUT_MS
137
138
  });
138
139
  const composed = await composeHermesPreLlmCall(cfg, agent, client, input);
@@ -3,20 +3,20 @@ import {
3
3
  HOOK_TIMEOUT_MS,
4
4
  composeSessionStart,
5
5
  formatSessionStartStdout
6
- } from "../chunk-5ZSZMN2T.js";
7
- import "../chunk-H33NUAHP.js";
8
- import "../chunk-CULTDVI2.js";
6
+ } from "../chunk-LZ2LOWZL.js";
7
+ import "../chunk-7OX6UVPB.js";
8
+ import "../chunk-3NJ37TEY.js";
9
9
  import {
10
10
  isCircuitOpen
11
- } from "../chunk-X75B57M2.js";
11
+ } from "../chunk-EI63DQX3.js";
12
12
  import {
13
13
  HttpClient,
14
14
  agentFromArgvWithFallback,
15
15
  debug,
16
- isComplete,
17
16
  load,
17
+ resolveDataApiCredential,
18
18
  setDebug
19
- } from "../chunk-DMS5YHIK.js";
19
+ } from "../chunk-BUK4SZC2.js";
20
20
  import {
21
21
  shouldSkipHooks
22
22
  } from "../chunk-5ML4VSXN.js";
@@ -51,10 +51,11 @@ async function main() {
51
51
  const sessionId = typeof event.session_id === "string" ? event.session_id : typeof event.sessionId === "string" ? event.sessionId : null;
52
52
  if (!cwd) return 0;
53
53
  const cfg = load({ agent });
54
+ const credential = resolveDataApiCredential(cfg);
54
55
  setDebug(cfg.debug);
55
56
  debug("warmup", "start", { cwd, userId: cfg.userId });
56
57
  const kbInjectHere = cfg.kbCatalogInjection === "session_start";
57
- if (!isComplete(cfg) || !cfg.warmupRecall && !kbInjectHere) {
58
+ if (!cfg.baseUrl || !credential || !cfg.warmupRecall && !kbInjectHere) {
58
59
  debug("warmup", "skip (config incomplete or both warmup+kb off)");
59
60
  return 0;
60
61
  }
@@ -64,7 +65,7 @@ async function main() {
64
65
  }
65
66
  const client = new HttpClient({
66
67
  baseUrl: cfg.baseUrl,
67
- apiKey: cfg.apiKey,
68
+ credential,
68
69
  timeoutMs: HOOK_TIMEOUT_MS
69
70
  });
70
71
  const composed = await composeSessionStart(
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  captureTurn
4
- } from "../chunk-LYHGJOHM.js";
5
- import "../chunk-X75B57M2.js";
4
+ } from "../chunk-ZFS6OMWE.js";
5
+ import "../chunk-EI63DQX3.js";
6
6
  import {
7
7
  HttpClient,
8
8
  agentFromArgvWithFallback,
9
9
  debug,
10
10
  load,
11
+ resolveDataApiCredential,
11
12
  setDebug
12
- } from "../chunk-DMS5YHIK.js";
13
+ } from "../chunk-BUK4SZC2.js";
13
14
  import {
14
15
  shouldSkipHooks
15
16
  } from "../chunk-5ML4VSXN.js";
@@ -47,13 +48,14 @@ async function main() {
47
48
  if (typeof transcriptPath !== "string" || !transcriptPath) return 0;
48
49
  const sessionId = extractHookSessionId(event);
49
50
  const cfg = load({ agent });
51
+ const credential = resolveDataApiCredential(cfg);
50
52
  setDebug(cfg.debug);
51
53
  debug("capture", "start", { transcriptPath, userId: cfg.userId });
52
- if (!cfg.apiKey || !cfg.baseUrl) {
54
+ if (!cfg.baseUrl || !credential) {
53
55
  debug("capture", "skip (config incomplete)");
54
56
  return 0;
55
57
  }
56
- const client = new HttpClient({ baseUrl: cfg.baseUrl, apiKey: cfg.apiKey, timeoutMs: 5e3 });
58
+ const client = new HttpClient({ baseUrl: cfg.baseUrl, credential, timeoutMs: 5e3 });
57
59
  const result = await captureTurn(transcriptPath, cfg, client, agent, sessionId);
58
60
  if (result.captured) {
59
61
  debug("capture", `ok (${result.messageCount} msgs)`, result);
@@ -2,20 +2,20 @@
2
2
  import {
3
3
  composeUserPromptSubmit,
4
4
  formatUserPromptSubmitStdout
5
- } from "../chunk-4FCZ2TZM.js";
6
- import "../chunk-H33NUAHP.js";
7
- import "../chunk-CULTDVI2.js";
5
+ } from "../chunk-AUBVVYQL.js";
6
+ import "../chunk-7OX6UVPB.js";
7
+ import "../chunk-3NJ37TEY.js";
8
8
  import {
9
9
  isCircuitOpen
10
- } from "../chunk-X75B57M2.js";
10
+ } from "../chunk-EI63DQX3.js";
11
11
  import {
12
12
  HttpClient,
13
13
  agentFromArgvWithFallback,
14
14
  debug,
15
- isComplete,
16
15
  load,
16
+ resolveDataApiCredential,
17
17
  setDebug
18
- } from "../chunk-DMS5YHIK.js";
18
+ } from "../chunk-BUK4SZC2.js";
19
19
  import {
20
20
  shouldSkipHooks
21
21
  } from "../chunk-5ML4VSXN.js";
@@ -50,9 +50,10 @@ async function main() {
50
50
  const sessionId = typeof event.session_id === "string" ? event.session_id : typeof event.sessionId === "string" ? event.sessionId : null;
51
51
  if (!prompt.trim()) return 0;
52
52
  const cfg = load({ agent });
53
+ const credential = resolveDataApiCredential(cfg);
53
54
  setDebug(cfg.debug);
54
55
  debug("recall", "start", { prompt: prompt.slice(0, 200), userId: cfg.userId });
55
- if (!isComplete(cfg) || !cfg.autoRecall) {
56
+ if (!cfg.baseUrl || !credential || !cfg.autoRecall) {
56
57
  debug("recall", "skip (config incomplete or autoRecall=false)");
57
58
  return 0;
58
59
  }
@@ -62,7 +63,7 @@ async function main() {
62
63
  `);
63
64
  return 0;
64
65
  }
65
- const client = new HttpClient({ baseUrl: cfg.baseUrl, apiKey: cfg.apiKey, timeoutMs: 5e3 });
66
+ const client = new HttpClient({ baseUrl: cfg.baseUrl, credential, timeoutMs: 5e3 });
66
67
  const { ctx, recall, kbBlock } = await composeUserPromptSubmit(
67
68
  cfg,
68
69
  agent,
@@ -892,6 +892,9 @@ function agentRaw(raw) {
892
892
  if (!section || typeof section !== "object" || Array.isArray(section)) return {};
893
893
  return section;
894
894
  }
895
+ function accessTokenFromEnv(env = process.env) {
896
+ return env.CTXDB_ACCESS_TOKEN?.trim() || null;
897
+ }
895
898
  function applyEnv(cfg, env) {
896
899
  if (env.CTXDB_API_KEY) cfg.apiKey = env.CTXDB_API_KEY;
897
900
  if (env.CTXDB_BASE_URL) cfg.baseUrl = env.CTXDB_BASE_URL.replace(/\/+$/, "");
@@ -976,8 +979,8 @@ function loadOpencodeConfig(options = {}) {
976
979
  }
977
980
  return applyEnv(cfg, env);
978
981
  }
979
- function isConfigured(cfg) {
980
- return Boolean(cfg.apiKey && cfg.baseUrl);
982
+ function isConfigured(cfg, env = process.env) {
983
+ return Boolean((accessTokenFromEnv(env) || cfg.apiKey) && cfg.baseUrl);
981
984
  }
982
985
 
983
986
  // src/http-client.ts
@@ -995,11 +998,13 @@ var CtxdbHttpError = class extends Error {
995
998
  var HttpClient = class {
996
999
  baseUrl;
997
1000
  apiKey;
1001
+ accessToken;
998
1002
  userAgent;
999
1003
  fetchImpl;
1000
1004
  constructor(opts) {
1001
1005
  this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
1002
1006
  this.apiKey = opts.apiKey;
1007
+ this.accessToken = opts.accessToken ?? null;
1003
1008
  this.userAgent = opts.userAgent ?? "ctxdb-opencode-plugin/0.0.0";
1004
1009
  this.fetchImpl = opts.fetchImpl ?? globalThis.fetch.bind(globalThis);
1005
1010
  }
@@ -1008,7 +1013,8 @@ var HttpClient = class {
1008
1013
  "User-Agent": this.userAgent,
1009
1014
  Connection: "close"
1010
1015
  };
1011
- if (this.apiKey) h.Authorization = `Token ${this.apiKey}`;
1016
+ if (this.accessToken) h.Authorization = `Bearer ${this.accessToken}`;
1017
+ else if (this.apiKey) h.Authorization = `Token ${this.apiKey}`;
1012
1018
  if (contentType) h["Content-Type"] = contentType;
1013
1019
  return h;
1014
1020
  }
@@ -1125,7 +1131,11 @@ async function searchAndFormatRecall(prompt, cfg, client, timeoutMs, traceOption
1125
1131
  },
1126
1132
  store: {
1127
1133
  ...traceOptions.traceStore,
1128
- secrets: [...traceOptions.traceStore?.secrets ?? [], cfg.apiKey]
1134
+ secrets: [
1135
+ ...traceOptions.traceStore?.secrets ?? [],
1136
+ cfg.apiKey,
1137
+ client.accessToken
1138
+ ]
1129
1139
  }
1130
1140
  } : null;
1131
1141
  if (trace) {
@@ -1454,10 +1464,14 @@ var SESSION_TTL_MS = 15 * 60 * 1e3;
1454
1464
  var SESSION_MAX = 100;
1455
1465
  var RECALL_TIMEOUT_MS = 5e3;
1456
1466
  var CAPTURE_TIMEOUT_MS = 8e3;
1457
- function buildRuntime(config, cwd) {
1467
+ function buildRuntime(config, cwd, env = process.env) {
1458
1468
  return {
1459
1469
  config,
1460
- http: new HttpClient({ baseUrl: config.baseUrl, apiKey: config.apiKey }),
1470
+ http: new HttpClient({
1471
+ baseUrl: config.baseUrl,
1472
+ apiKey: config.apiKey,
1473
+ accessToken: accessTokenFromEnv(env)
1474
+ }),
1461
1475
  sessionState: /* @__PURE__ */ new Map(),
1462
1476
  cwd
1463
1477
  };
@@ -1500,7 +1514,7 @@ async function buildHooks(input) {
1500
1514
  logDebug(
1501
1515
  config,
1502
1516
  "config",
1503
- "opencode integration disabled: missing agents.opencode.api_key in ~/.ctxdb/ctxdb.json or CTXDB_API_KEY"
1517
+ "opencode integration disabled: missing CTXDB_ACCESS_TOKEN or API key in agents.opencode.api_key / CTXDB_API_KEY"
1504
1518
  );
1505
1519
  return {};
1506
1520
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aliyunrds/ctxdb",
3
- "version": "1.0.8-beta.2",
3
+ "version": "1.0.8-beta.3",
4
4
  "type": "module",
5
5
  "description": "Unified access layer for RDS ContextDatabase: `ctxdb` CLI (memory + KB ops), one-shot multi-agent installer, per-agent config, hooks/plugins, and SKILL.md.",
6
6
  "license": "Apache-2.0",