@inetafrica/open-claudia 3.0.44 → 3.1.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/CHANGELOG.md +46 -0
- package/README.md +12 -7
- package/bin/tool.js +15 -5
- package/bot.js +78 -3
- package/core/actions.js +22 -0
- package/core/auth-flow.js +68 -0
- package/core/boot-health.js +84 -0
- package/core/doctor-memory.js +213 -0
- package/core/doctor.js +5 -0
- package/core/dream.js +11 -9
- package/core/entities.js +47 -3
- package/core/handlers.js +160 -2
- package/core/keyring.js +24 -4
- package/core/memory-mutation-queue.js +42 -11
- package/core/pack-review.js +60 -4
- package/core/packs.js +47 -3
- package/core/recall/discoverer.js +22 -6
- package/core/recall/graph.js +84 -52
- package/core/recall/tuning.js +1 -2
- package/core/router.js +18 -0
- package/core/runner.js +21 -0
- package/core/safe-mode.js +227 -0
- package/core/state.js +2 -2
- package/core/system-prompt.js +43 -3
- package/core/tool-graph.js +99 -71
- package/core/tools.js +3 -2
- package/core/turn-observer.js +23 -1
- package/package.json +3 -3
- package/test-extractive-injection.js +21 -0
- package/test-memory-mutation-queue.js +33 -3
- package/test-provider-compaction.js +5 -0
- package/test-provider-core-prompt.js +3 -0
- package/test-provider-language.js +59 -1
- package/test-provider-recall.js +33 -0
- package/test-recall-discoverer.js +8 -0
- package/test-recall-graph.js +66 -11
- package/test-tool-graph.js +67 -16
- package/test-tool-manifest.js +32 -0
- package/test-tools.js +31 -0
package/test-tool-manifest.js
CHANGED
|
@@ -106,5 +106,37 @@ const approvals = require("./core/approvals");
|
|
|
106
106
|
approvals.decide(rec3.id, "denied", "c1");
|
|
107
107
|
assert.strictEqual(await approvals.waitForDecision(rec3.id, { timeoutMs: 5000, pollMs: 50 }), "denied");
|
|
108
108
|
|
|
109
|
+
// ── B10: missing keyring creds are preflighted BEFORE the one-shot approval
|
|
110
|
+
// token is consumed. The old order burned the human's decision on a run that
|
|
111
|
+
// could never start; the same token must survive and redeem after the key
|
|
112
|
+
// is set, with the byte-identical command.
|
|
113
|
+
const toolCli = require("./bin/tool");
|
|
114
|
+
const b10src = path.join(tmp, "vaulted.sh");
|
|
115
|
+
fs.writeFileSync(b10src, "#!/usr/bin/env bash\necho ran-vaulted\n");
|
|
116
|
+
tools.addTool(b10src, { name: "vaulted", description: "needs a cred", risk: "destructive", requires: ["vaulted_api_key"] });
|
|
117
|
+
const b10cmd = approvals.formatApprovedCommand(["open-claudia", "tool", "run", "vaulted", "go"]);
|
|
118
|
+
const b10rec = approvals.create({ tool: "vaulted", tier: "destructive", command: b10cmd, channelId: "c1", adapter: "tg" });
|
|
119
|
+
approvals.decide(b10rec.id, "approved", "c1");
|
|
120
|
+
const errs = [];
|
|
121
|
+
const realErr = console.error;
|
|
122
|
+
console.error = (...a) => errs.push(a.join(" "));
|
|
123
|
+
try {
|
|
124
|
+
process.exitCode = 0;
|
|
125
|
+
await toolCli.run(["run", "vaulted", "go", "--approval", b10rec.id]);
|
|
126
|
+
assert.strictEqual(process.exitCode, 1, "missing creds refuse the run with exit 1, not an approval error");
|
|
127
|
+
assert.ok(errs.some((l) => /missing keyring keys vaulted_api_key/.test(l)), "failure names the missing key");
|
|
128
|
+
assert.ok(errs.some((l) => /NOT consumed/.test(l)), "agent is told the token survived");
|
|
129
|
+
assert.strictEqual(approvals.read(b10rec.id).consumedAt, undefined, "the approval token is NOT burned by the creds failure");
|
|
130
|
+
|
|
131
|
+
fs.writeFileSync(process.env.KEYRING_FILE, JSON.stringify({ vaulted_api_key: "k" }));
|
|
132
|
+
process.exitCode = 0;
|
|
133
|
+
await toolCli.run(["run", "vaulted", "go", "--approval", b10rec.id]);
|
|
134
|
+
assert.strictEqual(process.exitCode, 0, "the same token redeems once the key exists");
|
|
135
|
+
assert.ok(approvals.read(b10rec.id).consumedAt, "token consumed exactly by the real run");
|
|
136
|
+
} finally {
|
|
137
|
+
console.error = realErr;
|
|
138
|
+
process.exitCode = 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
109
141
|
console.log("tool manifest OK");
|
|
110
142
|
})().catch((e) => { console.error(e); process.exit(1); });
|
package/test-tools.js
CHANGED
|
@@ -490,4 +490,35 @@ assert.ok(tools.removeTool("hello"), "removeTool returns the removed tool");
|
|
|
490
490
|
assert.strictEqual(tools.findTool("hello"), null, "removed tool is gone");
|
|
491
491
|
assert.ok(!fs.existsSync(path.join(process.env.TOOLS_DIR, "hello")), "removed tool's directory is gone");
|
|
492
492
|
|
|
493
|
+
// ── keyring durability (B6/B13): atomic save + .bak fallback on corruption ──
|
|
494
|
+
// A half-written keyring must not silently strip every tool of credentials:
|
|
495
|
+
// save() snapshots the last-good file, load() falls back to it and says so
|
|
496
|
+
// loudly on stderr (once per process) instead of returning {} in silence.
|
|
497
|
+
const keyring = require("./core/keyring");
|
|
498
|
+
const KR = process.env.KEYRING_FILE;
|
|
499
|
+
fs.rmSync(KR, { force: true });
|
|
500
|
+
fs.rmSync(KR + ".bak", { force: true });
|
|
501
|
+
keyring.set("kr_a", "1");
|
|
502
|
+
assert.ok(!fs.existsSync(KR + ".bak"), "first save has no previous version to snapshot");
|
|
503
|
+
keyring.set("kr_b", "2");
|
|
504
|
+
assert.deepStrictEqual(JSON.parse(fs.readFileSync(KR + ".bak", "utf-8")), { kr_a: "1" },
|
|
505
|
+
"second save snapshots the previous good version to .bak");
|
|
506
|
+
assert.strictEqual(fs.statSync(KR).mode & 0o777, 0o600, "keyring file is 0600 from birth");
|
|
507
|
+
const krErrs = [];
|
|
508
|
+
const realErr = console.error;
|
|
509
|
+
console.error = (...a) => krErrs.push(a.join(" "));
|
|
510
|
+
try {
|
|
511
|
+
fs.writeFileSync(KR, "{truncated-by-crash"); // simulate a torn write
|
|
512
|
+
assert.deepStrictEqual(keyring.all(), { kr_a: "1" }, "corrupt primary falls back to .bak snapshot");
|
|
513
|
+
assert.strictEqual(keyring.get("kr_a"), "1", "get() reads through the fallback");
|
|
514
|
+
keyring.all();
|
|
515
|
+
assert.strictEqual(krErrs.filter((l) => /corrupt/.test(l)).length, 1, "corruption is warned exactly once per process");
|
|
516
|
+
} finally {
|
|
517
|
+
console.error = realErr;
|
|
518
|
+
}
|
|
519
|
+
keyring.set("kr_c", "3"); // next save repairs the primary from the fallback view
|
|
520
|
+
assert.deepStrictEqual(JSON.parse(fs.readFileSync(KR, "utf-8")), { kr_a: "1", kr_c: "3" },
|
|
521
|
+
"save after corruption rewrites a valid primary from the recovered data");
|
|
522
|
+
assert.ok(!fs.readdirSync(tmp).some((f) => f.endsWith(".tmp")), "no stray temp files left behind by atomic writes");
|
|
523
|
+
|
|
493
524
|
console.log("tools OK");
|