@aliyunrds/ctxdb 1.0.6 → 1.0.8-beta.0

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,18 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  captureParsedMessages
4
- } from "../chunk-6BB65W5W.js";
5
- import "../chunk-B7JCQL4O.js";
4
+ } from "../chunk-HF2CWTRU.js";
5
+ import "../chunk-NJJBT52C.js";
6
6
  import {
7
7
  HttpClient,
8
8
  agentFromArgvWithFallback,
9
9
  debug,
10
10
  load,
11
11
  setDebug
12
- } from "../chunk-ARZX2RLR.js";
12
+ } from "../chunk-AAZLOCVB.js";
13
13
  import {
14
14
  shouldSkipHooks
15
- } from "../chunk-UEKR2Z3S.js";
15
+ } from "../chunk-5ML4VSXN.js";
16
+ import "../chunk-R67JELM7.js";
17
+ import "../chunk-VIG4SYLU.js";
16
18
 
17
19
  // src/hooks/hermes-post-llm-call.ts
18
20
  import { pathToFileURL } from "url";
@@ -2,17 +2,17 @@
2
2
  import {
3
3
  HOOK_TIMEOUT_MS,
4
4
  composeSessionStart
5
- } from "../chunk-BHRWAU3E.js";
5
+ } from "../chunk-24CNB3XJ.js";
6
6
  import {
7
7
  composeUserPromptSubmit
8
- } from "../chunk-7EIJB5LA.js";
8
+ } from "../chunk-BBTXHFMD.js";
9
9
  import {
10
10
  fetchKbCatalogBlock
11
- } from "../chunk-VHNHVMCA.js";
12
- import "../chunk-L4GVGVOP.js";
11
+ } from "../chunk-WSMZOFZQ.js";
12
+ import "../chunk-CAXRYH6E.js";
13
13
  import {
14
14
  isCircuitOpen
15
- } from "../chunk-B7JCQL4O.js";
15
+ } from "../chunk-NJJBT52C.js";
16
16
  import {
17
17
  HttpClient,
18
18
  agentFromArgvWithFallback,
@@ -20,10 +20,12 @@ import {
20
20
  isComplete,
21
21
  load,
22
22
  setDebug
23
- } from "../chunk-ARZX2RLR.js";
23
+ } from "../chunk-AAZLOCVB.js";
24
24
  import {
25
25
  shouldSkipHooks
26
- } from "../chunk-UEKR2Z3S.js";
26
+ } from "../chunk-5ML4VSXN.js";
27
+ import "../chunk-R67JELM7.js";
28
+ import "../chunk-VIG4SYLU.js";
27
29
 
28
30
  // src/hooks/hermes-pre-llm-call.ts
29
31
  import { pathToFileURL } from "url";
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  shouldSkipHooks
4
- } from "../chunk-UEKR2Z3S.js";
4
+ } from "../chunk-5ML4VSXN.js";
5
+ import "../chunk-VIG4SYLU.js";
5
6
 
6
7
  // src/hooks/pre-tool-use.ts
7
8
  async function main() {
@@ -3,12 +3,12 @@ import {
3
3
  HOOK_TIMEOUT_MS,
4
4
  composeSessionStart,
5
5
  formatSessionStartStdout
6
- } from "../chunk-BHRWAU3E.js";
7
- import "../chunk-VHNHVMCA.js";
8
- import "../chunk-L4GVGVOP.js";
6
+ } from "../chunk-24CNB3XJ.js";
7
+ import "../chunk-WSMZOFZQ.js";
8
+ import "../chunk-CAXRYH6E.js";
9
9
  import {
10
10
  isCircuitOpen
11
- } from "../chunk-B7JCQL4O.js";
11
+ } from "../chunk-NJJBT52C.js";
12
12
  import {
13
13
  HttpClient,
14
14
  agentFromArgvWithFallback,
@@ -16,10 +16,12 @@ import {
16
16
  isComplete,
17
17
  load,
18
18
  setDebug
19
- } from "../chunk-ARZX2RLR.js";
19
+ } from "../chunk-AAZLOCVB.js";
20
20
  import {
21
21
  shouldSkipHooks
22
- } from "../chunk-UEKR2Z3S.js";
22
+ } from "../chunk-5ML4VSXN.js";
23
+ import "../chunk-R67JELM7.js";
24
+ import "../chunk-VIG4SYLU.js";
23
25
 
24
26
  // src/hooks/session-start.ts
25
27
  import { pathToFileURL } from "url";
@@ -1,18 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  captureTurn
4
- } from "../chunk-6BB65W5W.js";
5
- import "../chunk-B7JCQL4O.js";
4
+ } from "../chunk-HF2CWTRU.js";
5
+ import "../chunk-NJJBT52C.js";
6
6
  import {
7
7
  HttpClient,
8
8
  agentFromArgvWithFallback,
9
9
  debug,
10
10
  load,
11
11
  setDebug
12
- } from "../chunk-ARZX2RLR.js";
12
+ } from "../chunk-AAZLOCVB.js";
13
13
  import {
14
14
  shouldSkipHooks
15
- } from "../chunk-UEKR2Z3S.js";
15
+ } from "../chunk-5ML4VSXN.js";
16
+ import "../chunk-R67JELM7.js";
17
+ import "../chunk-VIG4SYLU.js";
16
18
 
17
19
  // src/hooks/stop.ts
18
20
  async function readStdinJson() {
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  composeUserPromptSubmit,
4
4
  formatUserPromptSubmitStdout
5
- } from "../chunk-7EIJB5LA.js";
6
- import "../chunk-VHNHVMCA.js";
7
- import "../chunk-L4GVGVOP.js";
5
+ } from "../chunk-BBTXHFMD.js";
6
+ import "../chunk-WSMZOFZQ.js";
7
+ import "../chunk-CAXRYH6E.js";
8
8
  import {
9
9
  isCircuitOpen
10
- } from "../chunk-B7JCQL4O.js";
10
+ } from "../chunk-NJJBT52C.js";
11
11
  import {
12
12
  HttpClient,
13
13
  agentFromArgvWithFallback,
@@ -15,10 +15,12 @@ import {
15
15
  isComplete,
16
16
  load,
17
17
  setDebug
18
- } from "../chunk-ARZX2RLR.js";
18
+ } from "../chunk-AAZLOCVB.js";
19
19
  import {
20
20
  shouldSkipHooks
21
- } from "../chunk-UEKR2Z3S.js";
21
+ } from "../chunk-5ML4VSXN.js";
22
+ import "../chunk-R67JELM7.js";
23
+ import "../chunk-VIG4SYLU.js";
22
24
 
23
25
  // src/hooks/user-prompt-submit.ts
24
26
  import { pathToFileURL } from "url";
@@ -1,7 +1,10 @@
1
+ // <define:__CTXDB_DISTRIBUTION_MANIFEST__>
2
+ var define_CTXDB_DISTRIBUTION_MANIFEST_default = { id: "public", packageName: "@aliyunrds/ctxdb", packageRegistry: null, capabilities: { interactiveLogin: false, managedCredentials: false } };
3
+
1
4
  // src/config.ts
2
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
5
+ import { readFileSync as readFileSync2, existsSync as existsSync2, statSync as statSync2 } from "fs";
3
6
  import { homedir as homedir2 } from "os";
4
- import { join as join2 } from "path";
7
+ import { dirname as dirname2, join as join2 } from "path";
5
8
 
6
9
  // ../shared/src/graph-context.ts
7
10
  var GRAPH_CONTEXT_TAG = "graphrag";
@@ -828,6 +831,18 @@ function isRecallTraceRecord(value) {
828
831
  return isNonNegativeFinite(record.duration_ms) && typeof record.outcome === "string" && TRACE_OUTCOMES.has(record.outcome) && (typeof record.failure_reason === "string" || record.failure_reason === null) && Array.isArray(record.returned_memories) && Array.isArray(record.returned_knowledge) && Boolean(selection) && Array.isArray(selection?.selected) && Array.isArray(selection?.excluded) && isNonNegativeFinite(selection?.token_estimate) && typeof record.recall_context === "string";
829
832
  }
830
833
 
834
+ // src/distribution-capabilities.ts
835
+ var PUBLIC_DISTRIBUTION = {
836
+ id: "public",
837
+ packageName: "@aliyunrds/ctxdb",
838
+ packageRegistry: null,
839
+ capabilities: {
840
+ interactiveLogin: false,
841
+ managedCredentials: false
842
+ }
843
+ };
844
+ var DISTRIBUTION_MANIFEST = typeof define_CTXDB_DISTRIBUTION_MANIFEST_default === "undefined" ? PUBLIC_DISTRIBUTION : define_CTXDB_DISTRIBUTION_MANIFEST_default;
845
+
831
846
  // src/config.ts
832
847
  var DEFAULT_BASE_URL = "https://context-database.aliyuncs.com";
833
848
  var DEFAULT_USER_ID = "default";
@@ -893,6 +908,40 @@ function applyDebugPolicy(cfg) {
893
908
  cfg.debugReason = policy.debugReason;
894
909
  return cfg;
895
910
  }
911
+ function managedCredential(path) {
912
+ if (!existsSync2(path)) return null;
913
+ if (process.platform !== "win32" && (statSync2(path).mode & 63) !== 0) {
914
+ throw new Error(`credentials: ${path} must be owner-only (run chmod 600)`);
915
+ }
916
+ const raw = JSON.parse(readFileSync2(path, "utf8"));
917
+ if (raw.version !== 1 || !raw.records || typeof raw.records !== "object") {
918
+ throw new Error("credentials: unsupported credentials.json schema");
919
+ }
920
+ const unknownKeys = Object.keys(raw.records).filter(
921
+ (key) => key !== "contextdb/active"
922
+ );
923
+ if (unknownKeys.length > 0) {
924
+ throw new Error(`credentials: unsupported record key ${unknownKeys[0]}`);
925
+ }
926
+ const record = raw.records["contextdb/active"];
927
+ if (!record) return null;
928
+ if (record.kind !== "api-key" || typeof record.payload?.api_key !== "string" || !record.payload.api_key || typeof record.payload?.base_url !== "string" || !record.payload.base_url) {
929
+ throw new Error("credentials: invalid contextdb/active record");
930
+ }
931
+ let baseUrl;
932
+ try {
933
+ baseUrl = new URL(record.payload.base_url);
934
+ } catch {
935
+ throw new Error("credentials: invalid contextdb/active base_url");
936
+ }
937
+ if (!["https:", "http:"].includes(baseUrl.protocol) || baseUrl.username || baseUrl.password || baseUrl.search || baseUrl.hash) {
938
+ throw new Error("credentials: invalid contextdb/active base_url");
939
+ }
940
+ return {
941
+ apiKey: record.payload.api_key,
942
+ baseUrl: baseUrl.toString().replace(/\/$/, "")
943
+ };
944
+ }
896
945
  function loadOpencodeConfig(options = {}) {
897
946
  const env = options.env ?? process.env;
898
947
  const path = options.path ?? defaultPath(env);
@@ -918,6 +967,13 @@ function loadOpencodeConfig(options = {}) {
918
967
  debugReason: null,
919
968
  kbCatalogInjection: coerceKbCatalogInjection(section.kb_catalog_injection)
920
969
  };
970
+ const managed = DISTRIBUTION_MANIFEST.capabilities.managedCredentials && options.managedCredentials !== false ? managedCredential(
971
+ options.credentialsPath ?? join2(dirname2(path), "credentials.json")
972
+ ) : null;
973
+ if (managed) {
974
+ cfg.apiKey = managed.apiKey;
975
+ cfg.baseUrl = managed.baseUrl;
976
+ }
921
977
  return applyEnv(cfg, env);
922
978
  }
923
979
  function isConfigured(cfg) {
@@ -12,7 +12,8 @@ description: contextdb 知识库高频操作(查询 / 浏览 KB / 上传或更
12
12
  - 用户想**找已有 KB 里的内容** → §2 recipe 1
13
13
  - 用户**不知道有哪些 KB** → §2 recipe 2
14
14
  - 用户想**了解某个 KB 收了哪些文档** → §2 recipe 3
15
- - 用户要**写入/上传/更新内容** → §2 recipe 4/5
15
+ - 用户要**新建/上传内容** → §2 recipe 4/5
16
+ - 用户要**更新已有文档** → §2 recipe 6/7
16
17
 
17
18
  配套 skill:**contextdb-memory**(长期记忆操作)。两者用同一份 `~/.ctxdb/ctxdb.json` 配置和同一个 `--agent` 路由。
18
19
 
@@ -101,7 +102,40 @@ ctxdb kb upload-file <kb-name> <local-path> --agent={{agent}}
101
102
 
102
103
  **何时不适用**:要上传的内容是字符串而非本地文件 → recipe 4。
103
104
 
104
- > **同名文档更新**:同一 KB、同一 `--file-path` 下,以相同文档名再次上传,服务端按更新(替换)语义处理;继续调用对应的 `kb upload-text` / `kb upload-file` 命令即可(`upload-file` 必要时用 `--doc-name` 保持文档名不变)。
105
+ ### Recipe 6:更新已有文本文档
106
+
107
+ **场景**:用户明确要替换某个已存在 KB 文本文档的内容。
108
+
109
+ ```sh
110
+ ctxdb kb update-text <document-id> --text="<new-body>" --agent={{agent}}
111
+
112
+ # 只有拿不到精确 document ID、但已知完整逻辑键时才用:
113
+ ctxdb kb update-text --kb-name=<kb-name> --doc-name=<logical-name> --text="<new-body>" [--file-path=<logical-parent-path>] --agent={{agent}}
114
+ ```
115
+
116
+ 已有精确 `document-id` 时优先用第一种,不需要再向用户索取 KB,也不要同时传
117
+ `--kb-name` / `--doc-name` / `--file-path`。服务端会从文档 ID 校验权限并解析所属 KB。
118
+ 命令返回的 `document.id` 是后续更新的新权威 ID:内容变化时通常会换 ID,相同内容也可能
119
+ 复用原 ID,Agent 都必须以本次返回值为准。只有拿不到 ID、但已确认完整 **KB + 文档名 +
120
+ `file_path`** 逻辑键时才用第二种;目标信息不完整时先核对或向用户确认,不能模糊猜测。
121
+ 重复调用 `upload-text` 是创建冲突,不会自动转成更新。
122
+
123
+ ### Recipe 7:更新已有文件文档
124
+
125
+ **场景**:用户用新的本地文件内容替换某个已存在 KB 文件文档。
126
+
127
+ ```sh
128
+ ctxdb kb update-file <document-id> <local-path> --agent={{agent}}
129
+
130
+ # 只有拿不到精确 document ID、但已知完整逻辑键时才用:
131
+ ctxdb kb update-file <local-path> --kb-name=<kb-name> [--doc-name=<existing-logical-name>] [--file-path=<logical-parent-path>] --agent={{agent}}
132
+ ```
133
+
134
+ ID 模式只用 `document-id` 定位远端文档,本地文件名只是上传的物理文件名;替换文件改了
135
+ 文件名也不需要补远端名称或 KB。逻辑键模式下,远端逻辑文档名默认取本地文件名;若替换
136
+ 文件名不同,必须用 `--doc-name` 继续传已有逻辑名。两种定位方式不能混用。分片更新只在
137
+ init 使用 PUT,part/complete 保持原协议;网络结果不明确时不自动重试或删除旧文档。
138
+ 成功后同样必须保存返回的 `document.id`,不要继续沿用输入 ID。
105
139
 
106
140
  ## 3. 命令速查
107
141
 
@@ -116,6 +150,8 @@ ctxdb kb upload-file <kb-name> <local-path> --agent={{agent}}
116
150
  | `kb create` | `ctxdb kb create <kb-name> --agent=<name>` |
117
151
  | `kb upload-text` | `ctxdb kb upload-text <kb-name> <doc-name> --text="<body>" --agent=<name>` |
118
152
  | `kb upload-file` | `ctxdb kb upload-file <kb-name> <local-path> --agent=<name>` |
153
+ | `kb update-text` | `ctxdb kb update-text <document-id> --text="<body>" --agent=<name>` |
154
+ | `kb update-file` | `ctxdb kb update-file <document-id> <local-path> --agent=<name>` |
119
155
 
120
156
  所有命令 JSON 写 stdout、错误写 stderr 非零退出码。
121
157
 
@@ -127,7 +163,7 @@ ctxdb kb upload-file <kb-name> <local-path> --agent={{agent}}
127
163
 
128
164
  **`<external-knowledge>` 块**:开启 KB 自动召回时,内部按 `## 图谱合成上下文` / `## 文档证据` 分区。图谱区只用于关系理解和检索导航,文档区才是回答与引用证据;图谱区被独立限制长度,不会挤掉已选中的文档证据。
129
165
 
130
- **B-3c 守卫**:含 `kb upload-text` / `kb upload-file` 的对话轮次,其内容**不会**被 autoCapture 写入记忆(防文档原文混进记忆桶)。
166
+ **B-3c 守卫**:含 `kb upload-text` / `kb upload-file` / `kb update-text` / `kb update-file` 的对话轮次,其内容**不会**被 autoCapture 写入记忆(防文档原文混进记忆桶)。
131
167
 
132
168
  **纯 CLI 模式**:对话里没有上面任何块 → 说明当前不在 hook 环境(agent 是裸 CLI 调用),所有信息只能主动调命令拿。
133
169
 
@@ -145,11 +181,12 @@ ctxdb kb upload-file <kb-name> <local-path> --agent={{agent}}
145
181
  - **根因**:shell + python -c 的引号是两层独立 escape,组合时极容易漏
146
182
  - **正确做法**:`ctxdb kb list --agent={{agent}} | jq '.knowledge_bases[].name'`;jq 表达式在单引号里不需要 escape
147
183
 
148
- ### 注意事项 3:`upload-*` / `create` 是副作用,没明示 KB 名前必须先确认
184
+ ### 注意事项 3:创建和逻辑键更新没明示 KB 名前必须先确认
149
185
 
150
186
  - **现象**:用户只说"把这段记进知识库"没指定 KB,agent 直接用了某个猜的 KB 名 → 写到错的桶
151
187
  - **根因**:写命令不会跟 agent 二次确认;KB 不存在时报错,但**KB 名拼错却恰好命中另一个真实 KB**时会静默写错
152
- - **正确做法**:用户没明示 必须先 `kb list` 拿候选清单,跟用户确认目标后才执行
188
+ - **正确做法**:`upload-*` / `create` / 逻辑键 `update-*` 在用户没明示 KB 时,必须先
189
+ `kb list` 拿候选清单并确认;精确 document-ID 更新已经绑定目标,不再额外要求 KB
153
190
 
154
191
  ### 注意事项 4:`kb search` 空结果时降阈值再试一次
155
192
 
@@ -175,12 +212,13 @@ ctxdb kb upload-file <kb-name> <local-path> --agent={{agent}}
175
212
  | `--verbose` | 每个 chunk 加 `doc_name` / `kb_id` / `doc_id` / `tags` | false |
176
213
  | `--raw` | 服务端原始响应(13+ 字段,图结果仍混在 `chunks`,含 tokenizer 细节) | false |
177
214
 
178
- ### `kb upload-file` / `kb upload-text` 全部 flag
215
+ ### `kb upload-*` / `kb update-*` 全部 flag
179
216
 
180
217
  | 参数 | 说明 |
181
218
  |------|------|
182
- | `--doc-name` | (`upload-file`)服务端文档名,默认取本地文件名 |
183
- | `--file-path` | KB 内的逻辑父目录,不包含文档名/文件名 |
219
+ | `--kb-name` | 仅逻辑键更新使用;不能与位置参数中的 document ID 混用 |
220
+ | `--doc-name` | `upload-file` 的逻辑文档名,或逻辑键更新的精确文档名;ID 更新不使用 |
221
+ | `--file-path` | 创建/逻辑键更新时 KB 内的逻辑父目录;ID 更新不使用 |
184
222
  | `--wait` | 等到 ingest 成功、失败或达到原有超时;用于迁移旧的默认等待行为 |
185
223
  | `--no-wait` | 兼容参数;与新的“受理后立即返回”默认行为相同 |
186
224
 
@@ -95,7 +95,7 @@ ctxdb memory delete <memory-id> --agent={{agent}}
95
95
 
96
96
  **autoCapture(Stop / post_llm_call / plugin)**:每轮对话结束后服务端异步提炼事实写记忆,**不用 agent 主动调** `memory add`。`memory add` 用于用户**明确强调**的内容(强加重要性)。
97
97
 
98
- **B-3c 守卫**:含 `kb upload-text` / `kb upload-file` 的轮次,**autoCapture 跳过**这一轮(防文档原文进记忆桶)。
98
+ **B-3c 守卫**:含 `kb upload-text` / `kb upload-file` / `kb update-text` / `kb update-file` 的轮次,**autoCapture 跳过**这一轮(防新建或更新的文档原文进记忆桶)。
99
99
 
100
100
  **纯 CLI 模式**:对话里没 `<recalled-memories>` 块 → 不在 hook 环境(裸 CLI),所有 recall / capture 只能主动 `ctxdb memory search` / `ctxdb memory add`。
101
101
 
@@ -4,7 +4,9 @@ import {
4
4
  recordVersionCheckFailure,
5
5
  recordVersionCheckSuccess,
6
6
  releaseVersionCheckLock
7
- } from "../chunk-Z6OHSEF2.js";
7
+ } from "../chunk-ULAWTBBC.js";
8
+ import "../chunk-R67JELM7.js";
9
+ import "../chunk-VIG4SYLU.js";
8
10
 
9
11
  // src/workers/version-check.ts
10
12
  import { fileURLToPath } from "url";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aliyunrds/ctxdb",
3
- "version": "1.0.6",
3
+ "version": "1.0.8-beta.0",
4
4
  "type": "module",
5
5
  "description": "Unified access layer for RDS ContextDatabase: `ctxdb` CLI (memory + KB ops), one-shot `setup --agent <qoder|qoderwork|codex|claude|opencode|hermes>` installer, per-agent config, hooks/plugins, and SKILL.md.",
6
6
  "license": "Apache-2.0",
@@ -32,7 +32,7 @@
32
32
  "dependencies": {
33
33
  "semver": "^7.8.5",
34
34
  "yaml": "^2.9.0",
35
- "@aliyunrds/ctxdb-shared": "~0.0.6"
35
+ "@aliyunrds/ctxdb-shared": "~0.0.7"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^22.15.0",
@@ -44,6 +44,10 @@
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsup && pnpm --dir ../opencode build && mkdir -p dist/setup dist/opencode && cp ../opencode/dist/index.js dist/opencode/index.js && cp -r src/setup/skills dist/setup/ && chmod +x dist/hooks/*.js dist/cli/main.js",
47
+ "build:internal": "tsup --config tsup.internal.config.ts && pnpm --dir ../opencode build:internal && mkdir -p dist-internal/setup dist-internal/opencode && cp ../opencode/dist-internal/index.js dist-internal/opencode/index.js && cp -r src/setup/skills dist-internal/setup/ && chmod +x dist-internal/hooks/*.js dist-internal/cli/internal-main.js && node scripts/prepare-internal-package.mjs",
48
+ "test:distributions": "node scripts/smoke-distribution-builds.mjs",
49
+ "test:e2e:distributions:prepared": "node scripts/prepare-distribution-e2e.mjs && vitest run --config vitest.e2e.config.ts",
50
+ "test:e2e:distributions": "pnpm --dir ../shared build && pnpm build && pnpm build:internal && pnpm test:e2e:distributions:prepared",
47
51
  "test": "vitest run"
48
52
  }
49
53
  }
File without changes