@inetafrica/open-claudia 3.1.28 → 3.2.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.
- package/CHANGELOG.md +18 -0
- package/bin/cli.js +12 -0
- package/bin/entity.js +9 -0
- package/bin/pack.js +10 -0
- package/bin/recall-case.js +90 -0
- package/bin/remind.js +82 -0
- package/bin/tool.js +8 -3
- package/core/apprenticeship.js +104 -0
- package/core/approvals.js +39 -0
- package/core/cost-report.js +140 -0
- package/core/dedup-adjudicator.js +250 -0
- package/core/dream.js +41 -8
- package/core/entities.js +27 -5
- package/core/pack-review.js +115 -12
- package/core/packs.js +102 -4
- package/core/prospective.js +135 -0
- package/core/recall-regressions.js +171 -0
- package/core/system-prompt.js +75 -5
- package/core/tools.js +77 -0
- package/package.json +2 -2
- package/test-provider-language.js +6 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// C2: memory regression suite — every corrected recall miss becomes a
|
|
4
|
+
// permanent test case, re-graded nightly. Cases live in a JSONL store; the
|
|
5
|
+
// nightly runner grades each query against the DETERMINISTIC recall floor
|
|
6
|
+
// (matchPacks + matchEntities — the classic candidate stage every engine
|
|
7
|
+
// builds on; the discoverer's LLM walk only adds to it and is fail-open back
|
|
8
|
+
// to this). No model call anywhere: the suite must run — and mean the same
|
|
9
|
+
// thing — even on nights the providers are down. Pass-rate + delta land in
|
|
10
|
+
// the dream summary's memory-health section.
|
|
11
|
+
|
|
12
|
+
const fs = require("fs");
|
|
13
|
+
const path = require("path");
|
|
14
|
+
const { atomicWriteFileSync } = require("./fsutil");
|
|
15
|
+
const { resolveConfigDir, ensureConfigDir } = require("./config-dir");
|
|
16
|
+
|
|
17
|
+
const NIGHTLY_CAP = Number(process.env.RECALL_REGRESSION_CAP || 20);
|
|
18
|
+
const HISTORY_MAX = 90;
|
|
19
|
+
|
|
20
|
+
function casesPath() { return path.join(resolveConfigDir(), "recall-regressions.jsonl"); }
|
|
21
|
+
function historyPath() { return path.join(resolveConfigDir(), "recall-health-history.json"); }
|
|
22
|
+
|
|
23
|
+
function loadCases() {
|
|
24
|
+
try {
|
|
25
|
+
return fs.readFileSync(casesPath(), "utf-8")
|
|
26
|
+
.split("\n").filter(Boolean)
|
|
27
|
+
.map((l) => { try { return JSON.parse(l); } catch (e) { return null; } })
|
|
28
|
+
.filter(Boolean);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function saveCases(cases) {
|
|
35
|
+
ensureConfigDir();
|
|
36
|
+
atomicWriteFileSync(casesPath(), cases.map((c) => JSON.stringify(c)).join("\n") + (cases.length ? "\n" : ""));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function addCase({ query, expectSlugs, source = "manual", note = "" } = {}) {
|
|
40
|
+
const q = String(query || "").trim();
|
|
41
|
+
if (!q) throw new Error("query is required");
|
|
42
|
+
const expect = [].concat(expectSlugs || []).map((s) => String(s || "").trim()).filter(Boolean);
|
|
43
|
+
if (expect.length === 0) throw new Error("at least one expected slug is required");
|
|
44
|
+
if (source !== "manual" && source !== "live-miss") throw new Error(`source must be manual or live-miss (got ${source})`);
|
|
45
|
+
const entry = {
|
|
46
|
+
id: `rc_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
47
|
+
query: q,
|
|
48
|
+
expectSlugs: expect,
|
|
49
|
+
source,
|
|
50
|
+
note: String(note || ""),
|
|
51
|
+
addedAt: new Date().toISOString(),
|
|
52
|
+
lastRunAt: null,
|
|
53
|
+
lastResult: null,
|
|
54
|
+
};
|
|
55
|
+
const cases = loadCases();
|
|
56
|
+
cases.push(entry);
|
|
57
|
+
saveCases(cases);
|
|
58
|
+
return entry;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function listCases() {
|
|
62
|
+
return loadCases();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function removeCase(id) {
|
|
66
|
+
const cases = loadCases();
|
|
67
|
+
const next = cases.filter((c) => c.id !== id);
|
|
68
|
+
if (next.length === cases.length) return false;
|
|
69
|
+
saveCases(next);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Grade one case against the deterministic floor. Expected slugs that no
|
|
74
|
+
// longer exist anywhere (pack merged away, entity removed) are not recall
|
|
75
|
+
// failures — a case with NO live target is "orphaned"; live targets are
|
|
76
|
+
// graded normally.
|
|
77
|
+
function gradeCase(c, { packLimit, entityLimit } = {}) {
|
|
78
|
+
const packs = require("./packs");
|
|
79
|
+
const entities = require("./entities");
|
|
80
|
+
const pl = packLimit || Number(process.env.PACK_MATCH_LIMIT || 6);
|
|
81
|
+
const el = entityLimit || 4;
|
|
82
|
+
const exists = (slug) => {
|
|
83
|
+
try { if (packs.readPack(slug)) return true; } catch (e) {}
|
|
84
|
+
try { if (entities.readEntity(slug)) return true; } catch (e) {}
|
|
85
|
+
return false;
|
|
86
|
+
};
|
|
87
|
+
const live = c.expectSlugs.filter(exists);
|
|
88
|
+
if (live.length === 0) return { status: "orphaned", missing: c.expectSlugs.slice() };
|
|
89
|
+
const found = new Set();
|
|
90
|
+
try { for (const m of packs.matchPacks(c.query, { limit: pl })) found.add(m.dir); } catch (e) {}
|
|
91
|
+
try { for (const m of entities.matchEntities(c.query, { limit: el })) found.add(m.slug); } catch (e) {}
|
|
92
|
+
const missing = live.filter((s) => !found.has(s));
|
|
93
|
+
return missing.length === 0
|
|
94
|
+
? { status: "pass" }
|
|
95
|
+
: { status: "fail", missing, matched: [...found] };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Nightly-capped, oldest-run-first rotation: a store bigger than the cap
|
|
99
|
+
// still gets full coverage over successive nights. Orphaned cases are
|
|
100
|
+
// dropped from the store (same policy as prospective-reminder GC).
|
|
101
|
+
function runSuite({ cap = NIGHTLY_CAP, packLimit, entityLimit, now = Date.now() } = {}) {
|
|
102
|
+
const all = loadCases();
|
|
103
|
+
if (all.length === 0) return { ran: 0, passed: 0, failed: 0, orphaned: 0, failures: [], total: 0 };
|
|
104
|
+
const order = [...all].sort((x, y) => String(x.lastRunAt || "").localeCompare(String(y.lastRunAt || "")));
|
|
105
|
+
const toRun = order.slice(0, Math.max(1, cap));
|
|
106
|
+
const stamp = new Date(now).toISOString();
|
|
107
|
+
const failures = [];
|
|
108
|
+
const orphanIds = new Set();
|
|
109
|
+
let passed = 0, failed = 0;
|
|
110
|
+
for (const c of toRun) {
|
|
111
|
+
const g = gradeCase(c, { packLimit, entityLimit });
|
|
112
|
+
c.lastRunAt = stamp;
|
|
113
|
+
c.lastResult = g.status;
|
|
114
|
+
if (g.status === "pass") passed++;
|
|
115
|
+
else if (g.status === "fail") { failed++; failures.push({ id: c.id, query: c.query, missing: g.missing }); }
|
|
116
|
+
else orphanIds.add(c.id);
|
|
117
|
+
}
|
|
118
|
+
const kept = all.filter((c) => !orphanIds.has(c.id));
|
|
119
|
+
saveCases(kept);
|
|
120
|
+
return { ran: toRun.length - orphanIds.size, passed, failed, orphaned: orphanIds.size, failures, total: kept.length };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function loadHistory() {
|
|
124
|
+
try {
|
|
125
|
+
const h = JSON.parse(fs.readFileSync(historyPath(), "utf-8"));
|
|
126
|
+
return Array.isArray(h) ? h : [];
|
|
127
|
+
} catch (e) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Dream entry point: grade, record the trend, and return announce lines for
|
|
133
|
+
// the consolidation report. Empty store → zero cost, zero lines.
|
|
134
|
+
function nightlyRun(opts = {}) {
|
|
135
|
+
const res = runSuite(opts);
|
|
136
|
+
if (res.ran === 0 && res.orphaned === 0) return { ...res, passRate: null, lines: [] };
|
|
137
|
+
const history = loadHistory();
|
|
138
|
+
const prev = history.length ? history[history.length - 1] : null;
|
|
139
|
+
const rate = res.ran > 0 ? Math.round((res.passed / res.ran) * 100) : null;
|
|
140
|
+
if (res.ran > 0) {
|
|
141
|
+
history.push({ at: new Date().toISOString(), ran: res.ran, passed: res.passed, failed: res.failed, orphaned: res.orphaned, passRate: rate });
|
|
142
|
+
ensureConfigDir();
|
|
143
|
+
atomicWriteFileSync(historyPath(), JSON.stringify(history.slice(-HISTORY_MAX), null, 2) + "\n");
|
|
144
|
+
}
|
|
145
|
+
const lines = [];
|
|
146
|
+
if (res.ran > 0) {
|
|
147
|
+
const delta = prev && typeof prev.passRate === "number" && rate !== null ? rate - prev.passRate : null;
|
|
148
|
+
const deltaTxt = delta === null ? "" : ` (${delta >= 0 ? "+" : ""}${delta} vs last run)`;
|
|
149
|
+
let line = `🧪 Memory health: ${res.passed}/${res.ran} recall regression case${res.ran === 1 ? "" : "s"} passing — ${rate}%${deltaTxt}.`;
|
|
150
|
+
if (res.failed > 0) {
|
|
151
|
+
const detail = res.failures.slice(0, 3).map((f) => `"${f.query.slice(0, 40)}" (missing ${f.missing.join(", ")})`).join("; ");
|
|
152
|
+
line += ` Failing: ${detail}${res.failures.length > 3 ? ` +${res.failures.length - 3} more` : ""} — open-claudia recall-case list`;
|
|
153
|
+
}
|
|
154
|
+
lines.push(line);
|
|
155
|
+
}
|
|
156
|
+
if (res.orphaned > 0) lines.push(`🧪 Dropped ${res.orphaned} recall regression case${res.orphaned === 1 ? "" : "s"} whose target no longer exists.`);
|
|
157
|
+
return { ...res, passRate: rate, lines };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = {
|
|
161
|
+
NIGHTLY_CAP,
|
|
162
|
+
addCase,
|
|
163
|
+
listCases,
|
|
164
|
+
removeCase,
|
|
165
|
+
gradeCase,
|
|
166
|
+
runSuite,
|
|
167
|
+
nightlyRun,
|
|
168
|
+
loadHistory,
|
|
169
|
+
casesPath,
|
|
170
|
+
historyPath,
|
|
171
|
+
};
|
package/core/system-prompt.js
CHANGED
|
@@ -7,7 +7,7 @@ const { SOUL_FILE, CRONS_FILE, VAULT_FILE, FILES_DIR, BOT_DIR, config } = requir
|
|
|
7
7
|
const { canSpeak } = require("./media");
|
|
8
8
|
const CONFIG_DIR = require("../config-dir");
|
|
9
9
|
const { currentState, getProjectKey, getProviderSession } = require("./state");
|
|
10
|
-
const { currentAdapter, currentChannelId, currentUserId } = require("./context");
|
|
10
|
+
const { currentAdapter, currentChannelId, currentUserId, currentSpeakerName } = require("./context");
|
|
11
11
|
const { vault } = require("./vault-store");
|
|
12
12
|
const {
|
|
13
13
|
transcriptPointerNoteForRun,
|
|
@@ -369,6 +369,20 @@ function buildSpeakerContextBlock() {
|
|
|
369
369
|
const speaker = adapter && channelId
|
|
370
370
|
? people.findByHandle(adapter.type, String(currentUserId() || channelId))
|
|
371
371
|
: null;
|
|
372
|
+
// Without a people record the speaker used to render as "no named profile"
|
|
373
|
+
// even when identity was known: an env-configured owner (KAZEE_OWNER_USER_ID,
|
|
374
|
+
// never auto-contacted) or a not-yet-recorded group member. In group chats
|
|
375
|
+
// the model then rightly refused to attribute their messages. Fall back to
|
|
376
|
+
// the canonical owner resolution the guard stack uses, then to the
|
|
377
|
+
// transport-reported display name. Names never confer privileges (R1):
|
|
378
|
+
// owner standing comes only from the canonical check, and a bare transport
|
|
379
|
+
// name is labelled unverified.
|
|
380
|
+
let canonicalSpeaker = null;
|
|
381
|
+
if (!speaker && adapter && channelId) {
|
|
382
|
+
try { canonicalSpeaker = require("./relationship").speakerFor(adapter.type, String(channelId), currentUserId()); } catch (e) {}
|
|
383
|
+
}
|
|
384
|
+
let transportName = "";
|
|
385
|
+
try { transportName = String(currentSpeakerName() || "").trim(); } catch (e) {}
|
|
372
386
|
if (speaker) {
|
|
373
387
|
const recentNotes = (speaker.notes || [])
|
|
374
388
|
.slice(-3)
|
|
@@ -381,6 +395,23 @@ function buildSpeakerContextBlock() {
|
|
|
381
395
|
speaker.bio ? `Bio: ${speaker.bio}` : "",
|
|
382
396
|
recentNotes ? `Recent notes:\n${recentNotes}` : "",
|
|
383
397
|
);
|
|
398
|
+
} else if (canonicalSpeaker && canonicalSpeaker.isOwner) {
|
|
399
|
+
// Prefer the live transport name: canonicalSpeaker.name falls back to
|
|
400
|
+
// owners()[0], which can be a different owner on multi-owner pods.
|
|
401
|
+
const name = transportName || canonicalSpeaker.name;
|
|
402
|
+
blocks.push(
|
|
403
|
+
"",
|
|
404
|
+
"## Speaker",
|
|
405
|
+
name
|
|
406
|
+
? `You are talking to ${name} (the owner) on ${adapter.type}.`
|
|
407
|
+
: `You are talking to the owner on ${adapter.type}.`,
|
|
408
|
+
);
|
|
409
|
+
} else if (transportName) {
|
|
410
|
+
blocks.push(
|
|
411
|
+
"",
|
|
412
|
+
"## Speaker",
|
|
413
|
+
`The current message is from "${transportName}" on ${adapter.type} — transport-reported name, no saved profile; identity unverified.`,
|
|
414
|
+
);
|
|
384
415
|
} else {
|
|
385
416
|
blocks.push("", "## Speaker", "No named speaker profile is available for this turn.");
|
|
386
417
|
}
|
|
@@ -651,6 +682,22 @@ function formatPackForContext(pack, packsLib, opts = {}) {
|
|
|
651
682
|
return clip(parts.join("\n\n"), PACK_INJECT_MAX_CHARS);
|
|
652
683
|
}
|
|
653
684
|
|
|
685
|
+
// C1 prospective memory: topic-bound reminders ride the recall injection of
|
|
686
|
+
// their target pack/entity. Fetched at render time but CONSUMED only after
|
|
687
|
+
// the budget accepts the committed block — a dropped render must never eat a
|
|
688
|
+
// one-shot reminder. All calls are defensive: reminder machinery failing can
|
|
689
|
+
// never break recall injection itself.
|
|
690
|
+
function pendingRemindersFor(type, slug) {
|
|
691
|
+
try { return require("./prospective").pendingFor(type, slug); } catch (e) { return []; }
|
|
692
|
+
}
|
|
693
|
+
function renderReminders(entries) {
|
|
694
|
+
try { return require("./prospective").renderPendingLines(entries); } catch (e) { return ""; }
|
|
695
|
+
}
|
|
696
|
+
function fireReminders(entries) {
|
|
697
|
+
if (!entries || entries.length === 0) return;
|
|
698
|
+
try { require("./prospective").fire(entries, "recall"); } catch (e) {}
|
|
699
|
+
}
|
|
700
|
+
|
|
654
701
|
function buildPackBlock(matches, budget, opts = {}) {
|
|
655
702
|
try {
|
|
656
703
|
const packsLib = require("./packs");
|
|
@@ -671,17 +718,29 @@ function buildPackBlock(matches, budget, opts = {}) {
|
|
|
671
718
|
used.push(m.dir);
|
|
672
719
|
const key = `${adapter?.id || "?"}:${channelId || "?"}:${m.dir}`;
|
|
673
720
|
const stamp = `${runIdentity}:${pack.updated}`;
|
|
721
|
+
const pending = pendingRemindersFor("pack", m.dir);
|
|
722
|
+
const pendingText = pending.length ? renderReminders(pending) : "";
|
|
674
723
|
// Inject a pack's body once per (channel, session, version). A
|
|
675
724
|
// compaction mints a new session id, which changes the stamp and
|
|
676
725
|
// forces a fresh re-injection on the next turn (same mechanism
|
|
677
726
|
// as the task tree), so the pack survives compaction without paying
|
|
678
727
|
// to re-stamp an anchor on every intervening turn.
|
|
679
|
-
if (packsInjectedFor.get(key) === stamp)
|
|
680
|
-
|
|
728
|
+
if (packsInjectedFor.get(key) === stamp) {
|
|
729
|
+
// C1: a reminder doesn't bump pack.updated, so the dedupe stamp
|
|
730
|
+
// would silently swallow it — surface a tiny standalone block.
|
|
731
|
+
if (pendingText) {
|
|
732
|
+
const note = `### Pack: ${pack.name || m.dir} (${m.dir})\n${pendingText}`;
|
|
733
|
+
if (tryUseRecallBudget(budget, note)) { blocks.push(note); fireReminders(pending); }
|
|
734
|
+
}
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
let block = formatPackForContext(pack, packsLib, { progressive, headline, extractive, matchedLines: extractive ? (matchedByDir.get(m.dir) || []) : undefined });
|
|
738
|
+
if (pendingText) block += `\n\n${pendingText}`;
|
|
681
739
|
if (!tryUseRecallBudget(budget, block)) continue;
|
|
682
740
|
packsInjectedFor.set(key, stamp);
|
|
683
741
|
collector.packs.push(pack.name || m.dir);
|
|
684
742
|
blocks.push(block);
|
|
743
|
+
if (pendingText) fireReminders(pending);
|
|
685
744
|
}
|
|
686
745
|
if (used.length > 0) setImmediate(() => { try { packsLib.touchUsed(used); } catch (e) {} });
|
|
687
746
|
if (blocks.length === 0) return "";
|
|
@@ -738,12 +797,23 @@ function buildEntityBlock(matches, budget, opts = {}) {
|
|
|
738
797
|
seen.push(m.slug);
|
|
739
798
|
const key = `${adapter?.id || "?"}:${channelId || "?"}:${m.slug}`;
|
|
740
799
|
const stamp = `${runIdentity}:${ent.updated}`;
|
|
741
|
-
|
|
742
|
-
const
|
|
800
|
+
const pending = pendingRemindersFor("entity", m.slug);
|
|
801
|
+
const pendingText = pending.length ? renderReminders(pending) : "";
|
|
802
|
+
if (entitiesInjectedFor.get(key) === stamp) {
|
|
803
|
+
// C1: same as packs — a reminder must survive the dedupe stamp.
|
|
804
|
+
if (pendingText) {
|
|
805
|
+
const note = `### ${ent.name} (${m.slug})\n${pendingText}`;
|
|
806
|
+
if (tryUseRecallBudget(budget, note)) { blocks.push(note); fireReminders(pending); }
|
|
807
|
+
}
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
let block = formatEntityForContext(ent, { headline: recallHeadline(), slug: m.slug });
|
|
811
|
+
if (pendingText) block += `\n\n${pendingText}`;
|
|
743
812
|
if (!tryUseRecallBudget(budget, block)) continue;
|
|
744
813
|
entitiesInjectedFor.set(key, stamp);
|
|
745
814
|
collector.entities.push(ent.name || m.slug);
|
|
746
815
|
blocks.push(block);
|
|
816
|
+
if (pendingText) fireReminders(pending);
|
|
747
817
|
}
|
|
748
818
|
if (seen.length > 0) setImmediate(() => { try { entitiesLib.touchSeen(seen); } catch (e) {} });
|
|
749
819
|
if (blocks.length === 0) return "";
|
package/core/tools.js
CHANGED
|
@@ -168,6 +168,82 @@ function fingerprint(name) {
|
|
|
168
168
|
return { status: "changed", current, verified: s.verifiedHash, verifiedAt: s.verifiedAt || "" };
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
// ── Skill certification (C3) ─────────────────────────────────────────────────
|
|
172
|
+
// Per-verb trust tier derived purely from the run telemetry above. Earned, not
|
|
173
|
+
// granted: "certified" needs ≥CERTIFY_CLEAN_RUNS clean runs with no failure in
|
|
174
|
+
// the probation window; any recent failure demotes to "probation"; everything
|
|
175
|
+
// else is "learning". Derived data + report-only proposals ONLY — certification
|
|
176
|
+
// never loosens a gate or grants anything by itself; the owner acts through the
|
|
177
|
+
// existing approval-card/guardrails flows or ignores it.
|
|
178
|
+
const CERTIFY_CLEAN_RUNS = 5;
|
|
179
|
+
const PROBATION_WINDOW_MS = 7 * 86400000;
|
|
180
|
+
|
|
181
|
+
// Mirrors recordRunResult's verb extraction so history lines re-attribute to
|
|
182
|
+
// the same verb key they were counted under.
|
|
183
|
+
function historyVerb(argLine) {
|
|
184
|
+
const first = String(argLine || "").split(/\s+/).find((a) => a && !a.startsWith("-")) || "(default)";
|
|
185
|
+
return first.slice(0, 40);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function cleanRunsSince(verb, history, sinceT) {
|
|
189
|
+
let n = 0;
|
|
190
|
+
for (const h of Array.isArray(history) ? history : []) {
|
|
191
|
+
const t = Date.parse(h.at || "");
|
|
192
|
+
if (!Number.isFinite(t) || t <= sinceT) continue;
|
|
193
|
+
if (h.exit !== 0) continue;
|
|
194
|
+
if (historyVerb(h.args) === verb) n += 1;
|
|
195
|
+
}
|
|
196
|
+
return n;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function verbCertification(verb, v = {}, history = [], now = Date.now()) {
|
|
200
|
+
const runs = Number(v.runs) || 0;
|
|
201
|
+
const lastFailureT = Date.parse(v.lastFailure || "");
|
|
202
|
+
const failed = Number.isFinite(lastFailureT);
|
|
203
|
+
if (failed && now - lastFailureT < PROBATION_WINDOW_MS) {
|
|
204
|
+
return { tier: "probation", cleanRuns: cleanRunsSince(verb, history, lastFailureT), runs };
|
|
205
|
+
}
|
|
206
|
+
// No failure ever → every recorded run was clean. After an old failure only
|
|
207
|
+
// successes SINCE it count toward re-certification (history-capped, so this
|
|
208
|
+
// is an honest lower bound).
|
|
209
|
+
const cleanRuns = failed ? cleanRunsSince(verb, history, lastFailureT) : runs;
|
|
210
|
+
return { tier: cleanRuns >= CERTIFY_CLEAN_RUNS ? "certified" : "learning", cleanRuns, runs };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function certificationForState(s = {}, now = Date.now()) {
|
|
214
|
+
const out = {};
|
|
215
|
+
for (const [verb, v] of Object.entries(s.verbs || {})) {
|
|
216
|
+
out[verb] = verbCertification(verb, v, s.history, now);
|
|
217
|
+
}
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function certification(name, now = Date.now()) {
|
|
222
|
+
return certificationForState(readState(name), now);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Dream phase (report-only, max 2/night): certified verbs on gated tiers are
|
|
226
|
+
// candidates for a standing Always-allow grant. Read-only verbs run freely and
|
|
227
|
+
// need no grant; probation/learning verbs haven't earned a proposal. The line
|
|
228
|
+
// is the ENTIRE output — no grant is created here, ever.
|
|
229
|
+
function certificationProposals({ now = Date.now(), max = 2 } = {}) {
|
|
230
|
+
const candidates = [];
|
|
231
|
+
for (const t of listTools()) {
|
|
232
|
+
if (!t.verbs || !t.manifest || !t.manifest.length) continue;
|
|
233
|
+
const certs = certificationForState({ verbs: t.verbs, history: t.history }, now);
|
|
234
|
+
for (const m of t.manifest) {
|
|
235
|
+
const tier = m.tier || t.risk || "write";
|
|
236
|
+
if (tier === "read-only") continue;
|
|
237
|
+
const c = certs[m.name];
|
|
238
|
+
if (!c || c.tier !== "certified") continue;
|
|
239
|
+
candidates.push({ tool: t.name, verb: m.name, tier, cleanRuns: c.cleanRuns });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
candidates.sort((a, b) => b.cleanRuns - a.cleanRuns);
|
|
243
|
+
return candidates.slice(0, max).map((c) =>
|
|
244
|
+
`🎓 ${c.tool} ${c.verb} is certified (${c.cleanRuns} clean ${c.tier} runs) — candidate for a standing Always-allow grant if you want it; grant via the approval card / guardrails, or ignore.`);
|
|
245
|
+
}
|
|
246
|
+
|
|
171
247
|
// Bump a tool's run counter without outcome detail. Still called at end of turn
|
|
172
248
|
// from the runner's transcript parse; for directory tools that's a no-op (the
|
|
173
249
|
// CLI already stamped the authoritative result — double-counting would lie),
|
|
@@ -1018,6 +1094,7 @@ module.exports = {
|
|
|
1018
1094
|
runEnv, missingRequires, toolNameFromPath, sanitizeName, ensureDir, normalizeRisk,
|
|
1019
1095
|
toolPaths, readState, writeState, recordRunResult, runGate, approvedTierFromArgv,
|
|
1020
1096
|
resolveTier, invokedVerb, sourceHash, fingerprint,
|
|
1097
|
+
CERTIFY_CLEAN_RUNS, PROBATION_WINDOW_MS, verbCertification, certificationForState, certification, certificationProposals,
|
|
1021
1098
|
listLib, readLib, writeLib, libDependents,
|
|
1022
1099
|
matchTools, recordRun, recordCreate, readUsage,
|
|
1023
1100
|
lintToolSource, checkSyntax, envRefsIn, assertNoSecrets,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inetafrica/open-claudia",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "An always-on, provider-agnostic coding-agent harness for Claude Code and OpenAI Codex via chat",
|
|
5
5
|
"main": "bot.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"setup": "node setup.js",
|
|
12
12
|
"start": "node bot.js",
|
|
13
13
|
"pretest": "node test-provider-fixture.js && node test-provider-core-prompt.js && node test-turn-observer.js && node test-provider-prompt-parity.js && node test-provider-env-isolation.js && node test-provider-resume-parity.js && node test-provider-bootstrap.js && node test-provider-registry.js && node test-provider-stream-decoder.js && node test-provider-events.js && node test-provider-claude.js && node test-provider-codex.js && node test-provider-runner.js && node test-provider-refusal-recovery.js && node test-provider-run-lifecycle.js && node test-provider-gateway.js && node test-provider-side-chat.js && node test-single-runtime.js && node test-provider-migration-backup.js && node test-provider-state-migration.js && node test-provider-session-history.js && node test-provider-session-commands.js && node test-provider-compaction.js && node test-provider-scheduler.js && node test-credential-capture.js && node test-cursor-removal.js && node test-utility-provider-policy.js && node test-provider-subagent.js && node test-provider-recall.js && node test-provider-pack-review.js && node test-memory-mutation-queue.js && node test-provider-dream.js && node test-provider-enforcer.js && node test-provider-tool-hooks.js && node test-provider-boot-matrix.js && node test-provider-capabilities.js && node test-provider-language.js && node test-provider-coupling-audit.js && node test-provider-parity-e2e.js && node test-kazee-channel-health.js && node test-kazee-media-caption.js && node test-prompt-budget.js && node test-agency-ledger.js && node test-agency-deliberate.js && node test-guardrail.js && node test-spaces-comment-content.js && node test-boot-health.js && node test-lexical-floor.js && node test-safe-mode.js && node test-logout.js && node test-kazee-call-audio.js && node test-kazee-call-janus.js && node test-kazee-call-webrtc.js && node test-kazee-call-speech.js && node test-kazee-call-manager.js && node test-kazee-call-session.js",
|
|
14
|
-
"test": "OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node -e \"require('./vault'); console.log('OK')\" && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-runner-watchdog-static.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-usage-accounting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-engine.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-discoverer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-query.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-walker-score.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-score-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cokept-warming.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-project-transcripts-smoke.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-abilities.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-extraction.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-couse.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-transfer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-tiers.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-merge-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-learning-e2e.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-pack-nesting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-pack-search.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-extractive-injection.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-journal-dedupe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-read-signal.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tools.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tooling-mode.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-manifest.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-evolution.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-async.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-unified-identity.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-queue-routing.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-packs.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-persona.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-pipeline.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-relationship-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-relationship.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-enforcer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-mandate-hygiene.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-external-rule-scopes.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-cards.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-identity-prune.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-message-id.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-group-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-group-context.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-people-owner-seed.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-delivery-contract.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-run-lock.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-web-sessions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-poll-recovery.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-409-grace.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-conflict-heal-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-single-instance.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-streaming-split.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-spaces-autoenable.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-say-loopback.js"
|
|
14
|
+
"test": "OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node -e \"require('./vault'); console.log('OK')\" && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-runner-watchdog-static.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-usage-accounting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-engine.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-discoverer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-query.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-walker-score.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-score-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cokept-warming.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-project-transcripts-smoke.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-abilities.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-extraction.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-couse.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-transfer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-tiers.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-ability-merge-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-learning-e2e.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-pack-nesting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-pack-search.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-extractive-injection.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-journal-dedupe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-read-signal.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tools.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tooling-mode.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-manifest.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-evolution.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-async.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-unified-identity.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-queue-routing.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-packs.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-persona.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-persona-pipeline.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-relationship-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-relationship.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-enforcer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-mandate-hygiene.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-external-rule-scopes.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-cards.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-identity-prune.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-message-id.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-group-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-kazee-group-context.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-people-owner-seed.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-delivery-contract.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-run-lock.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-web-sessions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-poll-recovery.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-409-grace.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-telegram-conflict-heal-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-single-instance.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-streaming-split.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-spaces-autoenable.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-say-loopback.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-journal-union.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-subst-score.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-section-budgets.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-dedup-adjudicator.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-prospective.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-recall-regressions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-cost-report.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-speaker-context.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-approval-mining.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-tool-certification.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-apprenticeship.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"bot.js",
|
|
@@ -341,7 +341,12 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
|
|
|
341
341
|
// hold so no getUpdates could ever complete, and _armHealthyCheck cleared its
|
|
342
342
|
// own pending timer on every re-arm so the only code that resets _wedgedSince
|
|
343
343
|
// never ran. One ordinary ECONNRESET cost 10 minutes and a process.exit.
|
|
344
|
-
|
|
344
|
+
// 3.2.0 approved by Sumeet 2026-08-03 ("i like them all then go ahead and add
|
|
345
|
+
// to a plan then go ahead and implement all the plans pending from this review
|
|
346
|
+
// into a new version work through till the end and deploy out a new version"):
|
|
347
|
+
// the employee batch — memory adoption A1-A4, the codegraph reusable tool,
|
|
348
|
+
// employee capabilities C1-C6, and the Kazee group speaker-identity fix.
|
|
349
|
+
assert.strictEqual(pkg.version, "3.2.0", "release version must remain unchanged without explicit approval");
|
|
345
350
|
for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
|
|
346
351
|
assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
|
|
347
352
|
}
|