@aliyunrds/ctxdb 1.0.8 → 1.0.9-beta.1
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 +9 -5
- package/dist/{chunk-YTCXHO4F.js → chunk-2ROMQSPA.js} +56 -2
- package/dist/{chunk-3FAQREIU.js → chunk-2U7G6UXE.js} +2 -1
- package/dist/{chunk-MWAFAK5M.js → chunk-7TPYIT63.js} +1 -1
- package/dist/{chunk-RRDQCZJ4.js → chunk-FD3IPF6R.js} +2 -2
- package/dist/{chunk-LZD55CWE.js → chunk-T5ZJEPR4.js} +1 -1
- package/dist/{chunk-AH2QEUK4.js → chunk-U4DRH4NZ.js} +1 -1
- package/dist/{chunk-AAWG5SPO.js → chunk-V7IZ2UYJ.js} +3 -3
- package/dist/cli/main.js +17 -6
- 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/opencode/index.js +21 -81
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Unified access layer for RDS ContextDatabase. One `ctxdb` CLI (memory + KB ops),
|
|
|
11
11
|
| **claude** | ✅ UserPromptSubmit + Stop + SessionStart | `~/.claude/skills/ctxdb/` | hooks-driven (auto capture/recall) |
|
|
12
12
|
| **opencode** | Plugin shim (`~/.config/opencode/plugins/ctxdb.ts`) | `~/.config/opencode/skills/` | in-process plugin (auto capture/recall + KB catalog injection) |
|
|
13
13
|
| **hermes** | ✅ `pre_llm_call` + `post_llm_call` | `~/.hermes/skills/` | shell hooks (auto capture/recall + first-turn warmup) |
|
|
14
|
-
| **workbuddy** | ✅ UserPromptSubmit + Stop + SessionStart | `~/.workbuddy-ai/skills
|
|
14
|
+
| **workbuddy** | ✅ UserPromptSubmit + Stop + SessionStart | `~/.workbuddy/skills/` and `~/.workbuddy-ai/skills/` (existing homes) | CodeBuddy command hooks (complete shell command, no separate `args`) |
|
|
15
15
|
|
|
16
16
|
Config and logs live under `~/.ctxdb/`. `~/.ctxdb/ctxdb.json` is one file, but runtime config is isolated per agent under `agents.qoder`, `agents.qoderwork`, `agents.qwenwork`, `agents.codex`, `agents.claude`, `agents.opencode`, `agents.hermes`, and `agents.workbuddy`. (Pre-2026-05-23 installs used `~/.ctxdb.json` at the home root; running `ctxdb setup --agent <name>` migrates the file into the selected agent section.)
|
|
17
17
|
|
|
@@ -105,7 +105,11 @@ URLs never come from server discovery. When a console URL is available, login op
|
|
|
105
105
|
browser and keeps polling. It always prints the URL and code; if opening fails, use that URL
|
|
106
106
|
manually. Pass `--no-browser` to print the link without opening a browser.
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
Credential storage trusts the user's local environment and relies on OS access control.
|
|
109
|
+
New POSIX directories/files request modes `0700`/`0600`; Windows uses normal inherited permissions.
|
|
110
|
+
Reads and writes do not reject an accessible file based on its owner, mode bits or ACL, and do not
|
|
111
|
+
invoke PowerShell to inspect or change permissions. File type/symlink checks, JSON validation,
|
|
112
|
+
atomic replacement and concurrency locks still apply.
|
|
109
113
|
Native Windows acceptance remains separate from the macOS local test record.
|
|
110
114
|
|
|
111
115
|
### Internal browser-login distribution
|
|
@@ -117,7 +121,7 @@ and `ctxdb auth status`. The default login uses a browser loopback callback;
|
|
|
117
121
|
provider-neutral protocol and use PKCE. The selected Workspace is represented
|
|
118
122
|
by the returned API key, so the CLI does not persist a separate Workspace id.
|
|
119
123
|
|
|
120
|
-
Internal login stores its single active connection in
|
|
124
|
+
Internal login stores its single active connection in
|
|
121
125
|
`~/.ctxdb/credentials.json`. It then runs the normal Agent setup lifecycle
|
|
122
126
|
without writing an `api_key` field into the Agent or default profile; an
|
|
123
127
|
existing field in either updated profile is removed. At runtime this managed
|
|
@@ -303,7 +307,7 @@ ctxdb setup --agent codex --api-key 'ctxdb-new-...'
|
|
|
303
307
|
ctxdb status --agent codex --json
|
|
304
308
|
```
|
|
305
309
|
|
|
306
|
-
Setup first checks that the target agent home exists (`~/.qoder`, `~/.qoderwork`, `~/.qwenwork`, `~/.codex`, `~/.claude`, or `~/.workbuddy-ai`;
|
|
310
|
+
Setup first checks that the target agent home exists (`~/.qoder`, `~/.qoderwork`, `~/.qwenwork`, `~/.codex`, `~/.claude`, or either WorkBuddy home: `~/.workbuddy` / `~/.workbuddy-ai`; other declared CN variant homes also satisfy this check). Setup writes hooks and skills into every existing home, so a CN-only install does not create the international product home, and vice versa. If no home exists, install or start that agent once before running `ctxdb setup --agent <name>`. OpenCode and Hermes are config-dir style: setup creates `~/.config/opencode` / `~/.hermes` when they are missing.
|
|
307
311
|
|
|
308
312
|
For **qoder**, **qoderwork**, **qwenwork**, **codex**, **claude**, and **workbuddy**, restart the harness (CLI: just exit + restart; app: Cmd+R or quit/relaunch) so it picks up the new hooks/skill. For **codex**, setup also writes `[features].hooks = true` into `~/.codex/config.toml` (creating the file if missing) — Codex won't fire any hook entries without it. On first use Codex may prompt you to trust the new hook commands. For **opencode**, restart OpenCode so it loads `~/.config/opencode/plugins/ctxdb.ts`. For **hermes**, setup also checks `~/.hermes/shell-hooks-allowlist.json`; it reports setup as incomplete until both ctxdb hook commands are approved.
|
|
309
313
|
|
|
@@ -870,7 +874,7 @@ ctxdb uninstall --purge-logs # also deletes ~/.ctxdb/logs/
|
|
|
870
874
|
|
|
871
875
|
### What uninstall does (and doesn't) touch
|
|
872
876
|
|
|
873
|
-
- **Hook entries in `~/.qoder/settings.json`, `~/.qoderwork/settings.json`, `~/.qwenwork/settings.json`, `~/.codex/hooks.json`, `~/.claude/settings.json`, `~/.workbuddy-ai/settings.json`, and `~/.hermes/config.yaml`**: stripped precisely by marker (`_ctxdb = @aliyunrds/ctxdb`, plus legacy keys `_ctxdbQoder` / `_ctxdbPackage` and the legacy `@aliyunrds/ctxdb-qoder` value for installs predating the unified marker). Any hooks you added yourself stay. A timestamped `*.bak-ctxdb-<TS>` is written before each modification (rotation keeps the 5 most recent).
|
|
877
|
+
- **Hook entries in `~/.qoder/settings.json`, `~/.qoderwork/settings.json`, `~/.qwenwork/settings.json`, `~/.codex/hooks.json`, `~/.claude/settings.json`, `~/.workbuddy/settings.json`, `~/.workbuddy-ai/settings.json`, and `~/.hermes/config.yaml`**: stripped precisely by marker (`_ctxdb = @aliyunrds/ctxdb`, plus legacy keys `_ctxdbQoder` / `_ctxdbPackage` and the legacy `@aliyunrds/ctxdb-qoder` value for installs predating the unified marker). Any hooks you added yourself stay. A timestamped `*.bak-ctxdb-<TS>` is written before each modification (rotation keeps the 5 most recent).
|
|
874
878
|
- **Skill directories**: `~/.<agent>/skills/ctxdb/` for each set-up agent, plus legacy dirs (`ctxdb-qoder`, `rds-ctxdb-qoder`, `qoder-ctxdb`) under `~/.qoder/skills/` from older package names.
|
|
875
879
|
- **`~/.ctxdb/` state**: only with `--purge-config` / `--purge-logs` / `--purge-all`. Defensive: `--purge-all` removes the `~/.ctxdb/` root only if it's empty after the named files are deleted (won't blanket-rm an unknown directory).
|
|
876
880
|
- **`~/.codex/config.toml` `[features].hooks`**: **NOT** reverted. Setup adds `hooks = true` so Codex will fire ctxdb's hook entries; uninstall leaves the flag alone because (a) the user may have wanted it on for non-ctxdb hooks, and (b) it's harmless when `~/.codex/hooks.json` is empty. If you want it off, edit the file by hand.
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
isConnectionError,
|
|
5
5
|
resetCircuit,
|
|
6
6
|
tripCircuit
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7TPYIT63.js";
|
|
8
8
|
import {
|
|
9
9
|
CtxdbError,
|
|
10
10
|
debug,
|
|
11
11
|
isDataApiReady,
|
|
12
12
|
isDebug
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-2U7G6UXE.js";
|
|
14
14
|
|
|
15
15
|
// src/lib/capture-orchestrator.ts
|
|
16
16
|
import {
|
|
@@ -64,6 +64,11 @@ function readTranscript(path) {
|
|
|
64
64
|
if (!obj || typeof obj !== "object" || Array.isArray(obj)) continue;
|
|
65
65
|
const o = obj;
|
|
66
66
|
const rawType = typeof o.type === "string" ? o.type : "";
|
|
67
|
+
if (rawType === "message" && typeof o.role === "string" || rawType === "function_call") {
|
|
68
|
+
const row = normalizeWorkBuddyRow(o);
|
|
69
|
+
if (row) out.push(row);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
67
72
|
if (rawType === CODEX_RESPONSE_ITEM) {
|
|
68
73
|
const payload = o.payload;
|
|
69
74
|
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
@@ -79,6 +84,55 @@ function readTranscript(path) {
|
|
|
79
84
|
}
|
|
80
85
|
return out;
|
|
81
86
|
}
|
|
87
|
+
function normalizeWorkBuddyRow(row) {
|
|
88
|
+
if (row.isMeta || row.isSidechain || row.is_synthetic || row._pre_verify_synthetic || row._verify_on_stop_synthetic) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
if (row.type === "function_call") {
|
|
92
|
+
if (typeof row.name !== "string") return null;
|
|
93
|
+
const args = row.arguments && typeof row.arguments === "object" && !Array.isArray(row.arguments) ? row.arguments : parseArgs(row.arguments);
|
|
94
|
+
const command = typeof args.command === "string" ? args.command : typeof args.cmd === "string" ? args.cmd : void 0;
|
|
95
|
+
return {
|
|
96
|
+
...row,
|
|
97
|
+
type: "assistant",
|
|
98
|
+
message: {
|
|
99
|
+
role: "assistant",
|
|
100
|
+
content: [{
|
|
101
|
+
type: "tool_use",
|
|
102
|
+
// WorkBuddy shell tools may use engine-specific names. Reuse
|
|
103
|
+
// the shared detector's shell shape when command args exist;
|
|
104
|
+
// preserve direct tool names such as kb_upload_text and Skill.
|
|
105
|
+
name: command === void 0 ? row.name : "bash",
|
|
106
|
+
input: command === void 0 ? args : { ...args, command }
|
|
107
|
+
}]
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const role = row.role;
|
|
112
|
+
if (role !== "user" && role !== "assistant") return null;
|
|
113
|
+
const content = row.content;
|
|
114
|
+
let text = "";
|
|
115
|
+
if (typeof content === "string") text = content;
|
|
116
|
+
else if (Array.isArray(content)) {
|
|
117
|
+
text = content.flatMap((block) => {
|
|
118
|
+
if (!block || typeof block !== "object") return [];
|
|
119
|
+
const b = block;
|
|
120
|
+
if (b.synthetic || b.ignored) return [];
|
|
121
|
+
if (b.type !== "text" && b.type !== (role === "user" ? "input_text" : "output_text")) return [];
|
|
122
|
+
return typeof b.text === "string" ? [b.text] : [];
|
|
123
|
+
}).join("\n");
|
|
124
|
+
}
|
|
125
|
+
if (role === "user") {
|
|
126
|
+
if (text.trimStart().startsWith("Stop hook feedback:")) return null;
|
|
127
|
+
if (text.includes("<user_query>")) {
|
|
128
|
+
text = /<user_query>([\s\S]*)<\/user_query>/.exec(text)?.[1] ?? "";
|
|
129
|
+
}
|
|
130
|
+
if (text.trimStart().startsWith("Stop hook feedback:")) return null;
|
|
131
|
+
}
|
|
132
|
+
text = text.trim();
|
|
133
|
+
if (!text) return null;
|
|
134
|
+
return { ...row, type: role, message: { role, content: [{ type: "text", text }] } };
|
|
135
|
+
}
|
|
82
136
|
function toKbDetectionMessages(rows) {
|
|
83
137
|
const out = [];
|
|
84
138
|
for (const row of rows) {
|
|
@@ -456,7 +456,8 @@ function agentHomeDir(agent, home = homedir2()) {
|
|
|
456
456
|
var AGENT_VARIANT_HOMES = {
|
|
457
457
|
qoder: [".qoder-cn"],
|
|
458
458
|
qoderwork: [".qoderworkcn"],
|
|
459
|
-
qwenwork: [".qwenworkcn"]
|
|
459
|
+
qwenwork: [".qwenworkcn"],
|
|
460
|
+
workbuddy: [".workbuddy"]
|
|
460
461
|
};
|
|
461
462
|
function agentHomeDirs(agent, home = homedir2()) {
|
|
462
463
|
const primary = agentHomeDir(agent, home);
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
fetchKbCatalogBlock,
|
|
4
4
|
recallTurn
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-V7IZ2UYJ.js";
|
|
6
6
|
import {
|
|
7
7
|
debug
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-2U7G6UXE.js";
|
|
9
9
|
|
|
10
10
|
// src/lib/warmup-recall.ts
|
|
11
11
|
import { execSync } from "child_process";
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
listKnowledgeBases
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-T5ZJEPR4.js";
|
|
5
5
|
import {
|
|
6
6
|
isConnectionError,
|
|
7
7
|
resetCircuit,
|
|
8
8
|
tripCircuit
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-7TPYIT63.js";
|
|
10
10
|
import {
|
|
11
11
|
CtxdbError,
|
|
12
12
|
isDataApiReady,
|
|
13
13
|
resolveDataApiCredential
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-2U7G6UXE.js";
|
|
15
15
|
|
|
16
16
|
// src/lib/kb-catalog.ts
|
|
17
17
|
function sanitizeKeyEntities(raw) {
|
package/dist/cli/main.js
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
uploadFile,
|
|
32
32
|
uploadText,
|
|
33
33
|
validateLocalFile
|
|
34
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-T5ZJEPR4.js";
|
|
35
35
|
import {
|
|
36
36
|
AGENT_CHOICES,
|
|
37
37
|
CtxdbError,
|
|
@@ -61,7 +61,7 @@ import {
|
|
|
61
61
|
save,
|
|
62
62
|
updateConfiguredDebug,
|
|
63
63
|
writeInstalledPkgVersion
|
|
64
|
-
} from "../chunk-
|
|
64
|
+
} from "../chunk-2U7G6UXE.js";
|
|
65
65
|
import {
|
|
66
66
|
beginUpdateNotification,
|
|
67
67
|
completeUpdateNotification,
|
|
@@ -402,6 +402,17 @@ import { fileURLToPath } from "url";
|
|
|
402
402
|
import { execFileSync } from "child_process";
|
|
403
403
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
404
404
|
import { setupAuthentication, oauthProfileStatus, validateDataBaseUrl } from "@aliyunrds/ctxdb-shared";
|
|
405
|
+
|
|
406
|
+
// src/setup/workbuddy-command.ts
|
|
407
|
+
function workbuddyHookCommand(nodePath, scriptPath, platform2 = process.platform) {
|
|
408
|
+
const quotePath = (path) => {
|
|
409
|
+
const normalized = platform2 === "win32" ? path.replace(/\\/g, "/") : path;
|
|
410
|
+
return `"${normalized.replace(/[\\"$`]/g, "\\$&")}"`;
|
|
411
|
+
};
|
|
412
|
+
return `${quotePath(nodePath)} ${quotePath(scriptPath)} --agent=workbuddy`;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// src/setup/installer.ts
|
|
405
416
|
var PACKAGE_UNINSTALL_TARGETS = DISTRIBUTION_MANIFEST.id === "internal" ? DISTRIBUTION_MANIFEST.packageName : `${PACKAGE_NAME} @aliyunrds/ctxdb-shared`;
|
|
406
417
|
var UNINSTALL_NPM_HINT = `To also remove the npm binaries: \`npm uninstall -g ${PACKAGE_UNINSTALL_TARGETS}\``;
|
|
407
418
|
var UNINSTALL_ORDER_HINT = `When you eventually want to uninstall: run \`ctxdb uninstall --purge-all\` FIRST, then \`npm uninstall -g ${PACKAGE_UNINSTALL_TARGETS}\`. (npm 7+ removed uninstall lifecycle hooks, so the order matters \u2014 otherwise agent settings.json hooks + ~/.ctxdb/ residue stay behind.)`;
|
|
@@ -1301,8 +1312,8 @@ function checkHookNodePaths(agent) {
|
|
|
1301
1312
|
const cmd = h.command;
|
|
1302
1313
|
let nodePath;
|
|
1303
1314
|
if (cmd.startsWith('"')) {
|
|
1304
|
-
const
|
|
1305
|
-
if (
|
|
1315
|
+
const quoted = /^"((?:\\.|[^"\\])*)"/.exec(cmd);
|
|
1316
|
+
if (quoted) nodePath = quoted[1].replace(/\\([\\"$`])/g, "$1");
|
|
1306
1317
|
} else {
|
|
1307
1318
|
const parts = cmd.split(" ");
|
|
1308
1319
|
if (parts.length >= 2 && !parts[0].endsWith(".js") && !parts[0].endsWith(".ts") && (parts[0].includes("/") || parts[0].includes("\\"))) {
|
|
@@ -1664,9 +1675,9 @@ var LEGACY_MARKER_VALUES = ["@aliyunrds/ctxdb-qoder"];
|
|
|
1664
1675
|
var TOOL_SCOPED_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse"]);
|
|
1665
1676
|
function appendOne(hooks, event, command, agent) {
|
|
1666
1677
|
if (!Array.isArray(hooks[event])) hooks[event] = [];
|
|
1667
|
-
const useExecForm = agent === "claude"
|
|
1678
|
+
const useExecForm = agent === "claude";
|
|
1668
1679
|
const cmdRunner = agent === "qoder";
|
|
1669
|
-
const shellCmd = process.platform === "win32" ? cmdRunner ? `node ${command.replace(/\\/g, "/")} --agent=${agent}` : `"${process.execPath.replace(/\\/g, "/")}" "${command.replace(/\\/g, "/")}" --agent=${agent}` : `${process.execPath} ${command} --agent=${agent}`;
|
|
1680
|
+
const shellCmd = agent === "workbuddy" ? workbuddyHookCommand(process.execPath, command) : process.platform === "win32" ? cmdRunner ? `node ${command.replace(/\\/g, "/")} --agent=${agent}` : `"${process.execPath.replace(/\\/g, "/")}" "${command.replace(/\\/g, "/")}" --agent=${agent}` : `${process.execPath} ${command} --agent=${agent}`;
|
|
1670
1681
|
const dup = hooks[event].some(
|
|
1671
1682
|
(entry2) => Array.isArray(entry2?.hooks) && entry2.hooks.some(
|
|
1672
1683
|
(h) => h?.type === "command" && (Array.isArray(h.args) && h.args[0] === command || typeof h.command === "string" && h.command.includes(command))
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
captureParsedMessages
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-2ROMQSPA.js";
|
|
5
|
+
import "../chunk-7TPYIT63.js";
|
|
6
6
|
import {
|
|
7
7
|
HttpClient,
|
|
8
8
|
agentFromArgvWithFallback,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
load,
|
|
11
11
|
resolveDataApiCredential,
|
|
12
12
|
setDebug
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-2U7G6UXE.js";
|
|
14
14
|
import {
|
|
15
15
|
shouldSkipHooks
|
|
16
16
|
} from "../chunk-5ML4VSXN.js";
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
import {
|
|
3
3
|
HOOK_TIMEOUT_MS,
|
|
4
4
|
composeSessionStart
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-FD3IPF6R.js";
|
|
6
6
|
import {
|
|
7
7
|
composeUserPromptSubmit
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-U4DRH4NZ.js";
|
|
9
9
|
import {
|
|
10
10
|
fetchKbCatalogBlock
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-V7IZ2UYJ.js";
|
|
12
|
+
import "../chunk-T5ZJEPR4.js";
|
|
13
13
|
import {
|
|
14
14
|
isCircuitOpen
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-7TPYIT63.js";
|
|
16
16
|
import {
|
|
17
17
|
HttpClient,
|
|
18
18
|
agentFromArgvWithFallback,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
load,
|
|
21
21
|
resolveDataApiCredential,
|
|
22
22
|
setDebug
|
|
23
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-2U7G6UXE.js";
|
|
24
24
|
import {
|
|
25
25
|
shouldSkipHooks
|
|
26
26
|
} from "../chunk-5ML4VSXN.js";
|
|
@@ -3,12 +3,12 @@ import {
|
|
|
3
3
|
HOOK_TIMEOUT_MS,
|
|
4
4
|
composeSessionStart,
|
|
5
5
|
formatSessionStartStdout
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-FD3IPF6R.js";
|
|
7
|
+
import "../chunk-V7IZ2UYJ.js";
|
|
8
|
+
import "../chunk-T5ZJEPR4.js";
|
|
9
9
|
import {
|
|
10
10
|
isCircuitOpen
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-7TPYIT63.js";
|
|
12
12
|
import {
|
|
13
13
|
HttpClient,
|
|
14
14
|
agentFromArgvWithFallback,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
load,
|
|
17
17
|
resolveDataApiCredential,
|
|
18
18
|
setDebug
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-2U7G6UXE.js";
|
|
20
20
|
import {
|
|
21
21
|
shouldSkipHooks
|
|
22
22
|
} from "../chunk-5ML4VSXN.js";
|
package/dist/hooks/stop.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
captureTurn
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-2ROMQSPA.js";
|
|
5
|
+
import "../chunk-7TPYIT63.js";
|
|
6
6
|
import {
|
|
7
7
|
HttpClient,
|
|
8
8
|
agentFromArgvWithFallback,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
load,
|
|
11
11
|
resolveDataApiCredential,
|
|
12
12
|
setDebug
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-2U7G6UXE.js";
|
|
14
14
|
import {
|
|
15
15
|
shouldSkipHooks
|
|
16
16
|
} from "../chunk-5ML4VSXN.js";
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import {
|
|
3
3
|
composeUserPromptSubmit,
|
|
4
4
|
formatUserPromptSubmitStdout
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
5
|
+
} from "../chunk-U4DRH4NZ.js";
|
|
6
|
+
import "../chunk-V7IZ2UYJ.js";
|
|
7
|
+
import "../chunk-T5ZJEPR4.js";
|
|
8
8
|
import {
|
|
9
9
|
isCircuitOpen
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-7TPYIT63.js";
|
|
11
11
|
import {
|
|
12
12
|
HttpClient,
|
|
13
13
|
agentFromArgvWithFallback,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
load,
|
|
16
16
|
resolveDataApiCredential,
|
|
17
17
|
setDebug
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-2U7G6UXE.js";
|
|
19
19
|
import {
|
|
20
20
|
shouldSkipHooks
|
|
21
21
|
} from "../chunk-5ML4VSXN.js";
|
package/dist/opencode/index.js
CHANGED
|
@@ -1028,88 +1028,28 @@ import { randomBytes as randomBytes3 } from "crypto";
|
|
|
1028
1028
|
// ../shared/src/credentials/local-credential-provider.ts
|
|
1029
1029
|
import { createHash as createHash2, randomBytes as randomBytes2 } from "crypto";
|
|
1030
1030
|
import { homedir as homedir2 } from "os";
|
|
1031
|
-
import { join as
|
|
1031
|
+
import { join as join2 } from "path";
|
|
1032
1032
|
|
|
1033
1033
|
// ../shared/src/credentials/storage.ts
|
|
1034
1034
|
import { constants, closeSync as closeSync2, existsSync as existsSync2, fstatSync, fsyncSync, lstatSync, mkdirSync as mkdirSync2, openSync as openSync2, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
1035
1035
|
import { randomBytes, createHash } from "crypto";
|
|
1036
1036
|
import { dirname as dirname2 } from "path";
|
|
1037
1037
|
import { setTimeout as delay2 } from "timers/promises";
|
|
1038
|
-
|
|
1039
|
-
// ../shared/src/windows-private-storage.ts
|
|
1040
|
-
import { execFileSync } from "child_process";
|
|
1041
|
-
import { join as join2 } from "path";
|
|
1042
|
-
var SCRIPT = `
|
|
1043
|
-
$ErrorActionPreference = 'Stop'
|
|
1044
|
-
$path = $env:CTXDB_PRIVATE_STORAGE_PATH
|
|
1045
|
-
$sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
1046
|
-
$item = Get-Item -LiteralPath $path -Force
|
|
1047
|
-
if (($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) { throw 'reparse' }
|
|
1048
|
-
if ($env:CTXDB_PRIVATE_STORAGE_INITIALIZE -eq '1') {
|
|
1049
|
-
if (-not $item.PSIsContainer) { throw 'not directory' }
|
|
1050
|
-
$acl = [System.Security.AccessControl.DirectorySecurity]::new()
|
|
1051
|
-
$acl.SetOwner($sid)
|
|
1052
|
-
$acl.SetAccessRuleProtection($true, $false)
|
|
1053
|
-
$rule = [System.Security.AccessControl.FileSystemAccessRule]::new($sid, 'FullControl', 'ContainerInherit,ObjectInherit', 'None', 'Allow')
|
|
1054
|
-
$acl.AddAccessRule($rule)
|
|
1055
|
-
Set-Acl -LiteralPath $path -AclObject $acl
|
|
1056
|
-
}
|
|
1057
|
-
$acl = Get-Acl -LiteralPath $path
|
|
1058
|
-
if ($acl.GetOwner([System.Security.Principal.SecurityIdentifier]).Value -ne $sid.Value) { throw 'owner' }
|
|
1059
|
-
$self = $false
|
|
1060
|
-
foreach ($rule in $acl.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])) {
|
|
1061
|
-
if ($rule.AccessControlType -eq 'Allow') {
|
|
1062
|
-
if ($rule.IdentityReference.Value -ne $sid.Value) { throw 'other principal' }
|
|
1063
|
-
if (($rule.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -eq [System.Security.AccessControl.FileSystemRights]::FullControl) { $self = $true }
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
if (-not $self) { throw 'missing owner access' }
|
|
1067
|
-
Write-Output 'private'
|
|
1068
|
-
`;
|
|
1069
|
-
function checkWindowsPrivateStorage(path, initialize, run = execFileSync) {
|
|
1070
|
-
const systemRoot = process.env.SystemRoot;
|
|
1071
|
-
if (!systemRoot) throw new Error("Private Windows credential storage could not be verified.");
|
|
1072
|
-
try {
|
|
1073
|
-
const result = run(
|
|
1074
|
-
join2(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe"),
|
|
1075
|
-
["-NoProfile", "-NonInteractive", "-EncodedCommand", Buffer.from(SCRIPT, "utf16le").toString("base64")],
|
|
1076
|
-
{
|
|
1077
|
-
env: { ...process.env, CTXDB_PRIVATE_STORAGE_PATH: path, CTXDB_PRIVATE_STORAGE_INITIALIZE: initialize ? "1" : "0" },
|
|
1078
|
-
encoding: "utf8",
|
|
1079
|
-
windowsHide: true,
|
|
1080
|
-
timeout: 1e4,
|
|
1081
|
-
maxBuffer: 4096,
|
|
1082
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
1083
|
-
}
|
|
1084
|
-
);
|
|
1085
|
-
if (String(result).trim() !== "private") throw new Error();
|
|
1086
|
-
} catch {
|
|
1087
|
-
throw new Error("Private Windows credential storage could not be verified.");
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
// ../shared/src/credentials/storage.ts
|
|
1092
|
-
function privatePath(path, directory = false) {
|
|
1038
|
+
function assertStoragePath(path, directory = false) {
|
|
1093
1039
|
const s = lstatSync(path);
|
|
1094
|
-
if (s.isSymbolicLink() || (directory ? !s.isDirectory() : !s.isFile())) throw new Error("credentials: storage
|
|
1095
|
-
if (process.platform === "win32") {
|
|
1096
|
-
checkWindowsPrivateStorage(path, false);
|
|
1097
|
-
return;
|
|
1098
|
-
}
|
|
1099
|
-
if (s.mode & 63 || process.getuid && s.uid !== process.getuid()) throw new Error("credentials: storage must be private and owner-only (run chmod 600 on credentials.json)");
|
|
1040
|
+
if (s.isSymbolicLink() || (directory ? !s.isDirectory() : !s.isFile())) throw new Error("credentials: invalid storage path");
|
|
1100
1041
|
}
|
|
1101
1042
|
function prepareStorage(path) {
|
|
1102
1043
|
const dir = dirname2(path);
|
|
1103
1044
|
if (!existsSync2(dir)) {
|
|
1104
1045
|
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
1105
|
-
if (process.platform === "win32") checkWindowsPrivateStorage(dir, true);
|
|
1106
1046
|
}
|
|
1107
|
-
|
|
1047
|
+
assertStoragePath(dir, true);
|
|
1108
1048
|
}
|
|
1109
|
-
function
|
|
1049
|
+
function readCredentialFile(path) {
|
|
1110
1050
|
if (!existsSync2(path)) return void 0;
|
|
1111
|
-
|
|
1112
|
-
|
|
1051
|
+
assertStoragePath(dirname2(path), true);
|
|
1052
|
+
assertStoragePath(path);
|
|
1113
1053
|
const fd = openSync2(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
1114
1054
|
try {
|
|
1115
1055
|
const stat = fstatSync(fd);
|
|
@@ -1121,7 +1061,7 @@ function readPrivate(path) {
|
|
|
1121
1061
|
}
|
|
1122
1062
|
function atomicCredentialWrite(path, value) {
|
|
1123
1063
|
prepareStorage(path);
|
|
1124
|
-
if (existsSync2(path))
|
|
1064
|
+
if (existsSync2(path)) assertStoragePath(path);
|
|
1125
1065
|
const temp = path + "." + randomBytes(12).toString("hex") + ".tmp";
|
|
1126
1066
|
let fd;
|
|
1127
1067
|
try {
|
|
@@ -1203,7 +1143,7 @@ var ACTIVE_CONTEXTDB_CREDENTIAL = "contextdb/active";
|
|
|
1203
1143
|
|
|
1204
1144
|
// ../shared/src/credentials/local-credential-provider.ts
|
|
1205
1145
|
function defaultCredentialsPath() {
|
|
1206
|
-
return
|
|
1146
|
+
return join2(homedir2(), ".ctxdb", "credentials.json");
|
|
1207
1147
|
}
|
|
1208
1148
|
var object2 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
1209
1149
|
var fail = (message) => {
|
|
@@ -1239,7 +1179,7 @@ function validate(key, raw) {
|
|
|
1239
1179
|
if (raw.kind === "api-key") validateApi(raw, key === ACTIVE_CONTEXTDB_CREDENTIAL);
|
|
1240
1180
|
}
|
|
1241
1181
|
function readDocument(path) {
|
|
1242
|
-
const bytes =
|
|
1182
|
+
const bytes = readCredentialFile(path);
|
|
1243
1183
|
if (bytes === void 0) return { version: 2, records: {} };
|
|
1244
1184
|
let doc;
|
|
1245
1185
|
try {
|
|
@@ -1421,7 +1361,7 @@ var OAuthCredentialError = class extends Error {
|
|
|
1421
1361
|
login_required: "OAuth session needs login; run ctxdb login for this profile.",
|
|
1422
1362
|
credential_busy: "OAuth credential is busy. If its previous process crashed, run ctxdb login for a new credential.",
|
|
1423
1363
|
invalid_profile: "OAuth credential does not belong to this profile.",
|
|
1424
|
-
unsafe_storage: "OAuth credential storage is
|
|
1364
|
+
unsafe_storage: "OAuth credential storage is inaccessible or invalid."
|
|
1425
1365
|
};
|
|
1426
1366
|
super(messages[code]);
|
|
1427
1367
|
this.name = "OAuthCredentialError";
|
|
@@ -1664,7 +1604,7 @@ function authorization(session) {
|
|
|
1664
1604
|
}
|
|
1665
1605
|
|
|
1666
1606
|
// ../shared/src/oauth-profile.ts
|
|
1667
|
-
import { dirname as dirname4, join as
|
|
1607
|
+
import { dirname as dirname4, join as join3, resolve } from "path";
|
|
1668
1608
|
|
|
1669
1609
|
// ../shared/src/auth-config.ts
|
|
1670
1610
|
import { closeSync as closeSync3, existsSync as existsSync3, fsyncSync as fsyncSync2, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync3, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
@@ -1722,7 +1662,7 @@ function oauthProfile(reference, configPath, profile, baseUrl) {
|
|
|
1722
1662
|
reference,
|
|
1723
1663
|
profile,
|
|
1724
1664
|
configPath: path,
|
|
1725
|
-
credentialsPath:
|
|
1665
|
+
credentialsPath: join3(dirname4(path), "credentials.json"),
|
|
1726
1666
|
baseUrl: normalizeCoreOrigin(baseUrl)
|
|
1727
1667
|
};
|
|
1728
1668
|
}
|
|
@@ -1789,10 +1729,10 @@ var OAuthProfileProvider = class {
|
|
|
1789
1729
|
|
|
1790
1730
|
// ../shared/src/login-bindings.ts
|
|
1791
1731
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
1792
|
-
import { dirname as dirname6, join as
|
|
1732
|
+
import { dirname as dirname6, join as join5 } from "path";
|
|
1793
1733
|
|
|
1794
1734
|
// ../shared/src/data-auth.ts
|
|
1795
|
-
import { dirname as dirname5, join as
|
|
1735
|
+
import { dirname as dirname5, join as join4 } from "path";
|
|
1796
1736
|
function selectDataApiCredential(cfg, env = process.env) {
|
|
1797
1737
|
const accessToken = env.CTXDB_ACCESS_TOKEN?.trim();
|
|
1798
1738
|
if (accessToken) return { type: "access-token", value: accessToken };
|
|
@@ -1810,7 +1750,7 @@ var DataApiAuthorizationProvider = class {
|
|
|
1810
1750
|
const c = this.context, raw = readAuthConfig(c.configPath), section = ownAuthProfile(raw, c.agent);
|
|
1811
1751
|
const fallback = c.inheritDefaultKey && c.agent !== "default" ? ownAuthProfile(raw, "default") : {};
|
|
1812
1752
|
if (c.managedCredentials) {
|
|
1813
|
-
const active = readActiveCredentialSync(c.credentialsPath ??
|
|
1753
|
+
const active = readActiveCredentialSync(c.credentialsPath ?? join4(dirname5(c.configPath), "credentials.json"));
|
|
1814
1754
|
if (active) {
|
|
1815
1755
|
const baseUrl2 = c.baseUrlOverride ?? active.metadata.baseUrl;
|
|
1816
1756
|
if (baseUrl2 !== c.baseUrl) throw new OAuthCredentialError("login_required");
|
|
@@ -1836,7 +1776,7 @@ function publicAuthenticationFromConfig(raw, path, agent, baseUrlOverride) {
|
|
|
1836
1776
|
const oauthCredential = oauthProfileFromConfig(raw, path, agent, baseUrlOverride);
|
|
1837
1777
|
return oauthCredential ? { baseUrl: oauthCredential.baseUrl, oauthCredential } : void 0;
|
|
1838
1778
|
}
|
|
1839
|
-
const r = new LocalCredentialProvider(
|
|
1779
|
+
const r = new LocalCredentialProvider(join4(dirname5(path), "credentials.json")).readStoredRecord(section.credential_ref);
|
|
1840
1780
|
if (!r || r.kind !== "api-key" || r.metadata.state !== "ready" || r.metadata.owner.distribution !== "public" || r.metadata.owner.agent !== agent || r.metadata.owner.loginId) {
|
|
1841
1781
|
throw new AuthConfigError("credential_ref is missing, invalid or belongs to another Agent. Use setup --api-key/--login to choose a valid credential.");
|
|
1842
1782
|
}
|
|
@@ -1859,12 +1799,12 @@ function createRequestAuthorizationProvider(credential, baseUrl) {
|
|
|
1859
1799
|
}
|
|
1860
1800
|
|
|
1861
1801
|
// ../shared/src/authorization/public-target.ts
|
|
1862
|
-
import { dirname as dirname7, join as
|
|
1802
|
+
import { dirname as dirname7, join as join6 } from "path";
|
|
1863
1803
|
|
|
1864
1804
|
// src/config.ts
|
|
1865
1805
|
import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
|
|
1866
1806
|
import { homedir as homedir3 } from "os";
|
|
1867
|
-
import { dirname as dirname8, join as
|
|
1807
|
+
import { dirname as dirname8, join as join7 } from "path";
|
|
1868
1808
|
|
|
1869
1809
|
// src/distribution-capabilities.ts
|
|
1870
1810
|
var PUBLIC_DISTRIBUTION = {
|
|
@@ -1888,7 +1828,7 @@ var DEFAULT_KNOWLEDGE_TOP_K = 6;
|
|
|
1888
1828
|
var DEFAULT_KB_CATALOG_INJECTION = "session_start";
|
|
1889
1829
|
function defaultPath(env) {
|
|
1890
1830
|
if (env.CTXDB_CONFIG_PATH) return env.CTXDB_CONFIG_PATH;
|
|
1891
|
-
return
|
|
1831
|
+
return join7(homedir3(), ".ctxdb", "ctxdb.json");
|
|
1892
1832
|
}
|
|
1893
1833
|
function coerceInt(v, fallback) {
|
|
1894
1834
|
if (v === null || v === void 0 || v === "") return fallback;
|
|
@@ -1973,7 +1913,7 @@ function loadOpencodeConfig(options = {}) {
|
|
|
1973
1913
|
kbCatalogInjection: coerceKbCatalogInjection(section.kb_catalog_injection)
|
|
1974
1914
|
};
|
|
1975
1915
|
const managed = DISTRIBUTION_MANIFEST.capabilities.managedCredentials && options.managedCredentials !== false ? readActiveCredentialSync(
|
|
1976
|
-
options.credentialsPath ??
|
|
1916
|
+
options.credentialsPath ?? join7(dirname8(path), "credentials.json")
|
|
1977
1917
|
) : null;
|
|
1978
1918
|
if (managed) {
|
|
1979
1919
|
cfg.apiKey = managed.payload.apiKey;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aliyunrds/ctxdb",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9-beta.1",
|
|
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",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"semver": "^7.8.5",
|
|
36
36
|
"yaml": "^2.9.0",
|
|
37
|
-
"@aliyunrds/ctxdb-shared": "~0.0.
|
|
37
|
+
"@aliyunrds/ctxdb-shared": "~0.0.9-beta.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.15.0",
|