@inetafrica/open-claudia 2.15.0 → 3.0.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/.env.example +30 -4
- package/CHANGELOG.md +12 -0
- package/README.md +87 -66
- package/bin/agent.js +44 -18
- package/bin/cli.js +30 -28
- package/bin/dream.js +5 -11
- package/bin/loopback-client.js +29 -5
- package/bin/schedule.js +19 -5
- package/bin/tool.js +23 -5
- package/bot-agent.js +5 -2350
- package/bot.js +66 -3
- package/channels/telegram/adapter.js +6 -1
- package/channels/voice/adapter.js +1 -0
- package/channels/voice/manage.js +43 -5
- package/config-dir.js +3 -11
- package/core/actions.js +149 -40
- package/core/approvals.js +136 -29
- package/core/auth-flow.js +103 -19
- package/core/config-dir.js +19 -0
- package/core/config.js +115 -69
- package/core/doctor.js +111 -57
- package/core/dream.js +219 -62
- package/core/enforcer.js +0 -0
- package/core/entities.js +2 -1
- package/core/fsutil.js +21 -4
- package/core/handlers.js +503 -217
- package/core/ideas.js +2 -1
- package/core/jobs.js +589 -72
- package/core/lessons.js +3 -2
- package/core/loopback.js +42 -6
- package/core/memory-mutation-queue.js +241 -0
- package/core/migration-backup.js +1060 -0
- package/core/pack-review.js +295 -88
- package/core/packs.js +4 -3
- package/core/persona.js +2 -1
- package/core/process-tree.js +19 -2
- package/core/provider-migration.js +39 -0
- package/core/provider-status.js +80 -0
- package/core/providers/claude-events.js +117 -0
- package/core/providers/claude-hook.js +114 -0
- package/core/providers/claude.js +296 -0
- package/core/providers/codex-events.js +121 -0
- package/core/providers/codex-hook.js +280 -0
- package/core/providers/codex.js +286 -0
- package/core/providers/contract.js +153 -0
- package/core/providers/env.js +148 -0
- package/core/providers/events.js +170 -0
- package/core/providers/hook-command.js +22 -0
- package/core/providers/index.js +240 -0
- package/core/providers/utility-policy.js +269 -0
- package/core/recall/classic.js +2 -2
- package/core/recall/discoverer.js +71 -22
- package/core/recall/metrics.js +27 -1
- package/core/recall/tuning.js +4 -1
- package/core/recall/warm-walker.js +151 -108
- package/core/recall-filter.js +86 -61
- package/core/router.js +79 -7
- package/core/run-context.js +185 -0
- package/core/runner.js +1414 -1290
- package/core/scheduler.js +515 -210
- package/core/side-chat.js +346 -0
- package/core/state.js +1084 -97
- package/core/subagent.js +72 -98
- package/core/system-prompt.js +462 -279
- package/core/tool-guard.js +73 -39
- package/core/tools.js +22 -5
- package/core/transcripts.js +30 -1
- package/core/usage-log.js +19 -4
- package/core/utility-agent.js +654 -0
- package/core/web-auth.js +29 -13
- package/docs/CHANNEL_DESIGN.md +181 -0
- package/docs/MULTI_CHANNEL_PLAN.md +254 -0
- package/docs/PROVIDER_MIGRATION.md +67 -0
- package/health.js +50 -39
- package/package.json +48 -4
- package/setup.js +198 -38
- package/soul.md +39 -0
- package/test-ability-extraction.js +5 -0
- package/test-approval-async.js +63 -4
- package/test-cursor-removal.js +334 -0
- package/test-enforcer.js +70 -27
- package/test-fixtures/current-provider-parity.json +132 -0
- package/test-fixtures/fake-agent-cli.js +477 -0
- package/test-fixtures/migrations/claude-only/jobs.json +3 -0
- package/test-fixtures/migrations/claude-only/sessions.json +5 -0
- package/test-fixtures/migrations/claude-only/state.json +5 -0
- package/test-fixtures/migrations/cursor-selected/crons.json +3 -0
- package/test-fixtures/migrations/cursor-selected/jobs.json +3 -0
- package/test-fixtures/migrations/cursor-selected/sessions.json +5 -0
- package/test-fixtures/migrations/cursor-selected/state.json +6 -0
- package/test-fixtures/migrations/dual-provider/jobs.json +3 -0
- package/test-fixtures/migrations/dual-provider/sessions.json +7 -0
- package/test-fixtures/migrations/dual-provider/state.json +10 -0
- package/test-fixtures/migrations/malformed-partial/jobs.json +1 -0
- package/test-fixtures/migrations/malformed-partial/sessions.json +1 -0
- package/test-fixtures/migrations/malformed-partial/sessions.json.bak +3 -0
- package/test-fixtures/migrations/malformed-partial/state.json +1 -0
- package/test-fixtures/migrations/malformed-partial/state.json.bak +5 -0
- package/test-fixtures/migrations/missing-project/jobs.json +3 -0
- package/test-fixtures/migrations/missing-project/sessions.json +3 -0
- package/test-fixtures/migrations/missing-project/state.json +4 -0
- package/test-fixtures/migrations/multi-user/jobs.json +4 -0
- package/test-fixtures/migrations/multi-user/sessions.json +4 -0
- package/test-fixtures/migrations/multi-user/state.json +6 -0
- package/test-fixtures/provider-event-samples.json +17 -0
- package/test-learning-e2e.js +5 -0
- package/test-memory-mutation-queue.js +191 -0
- package/test-provider-boot-matrix.js +399 -0
- package/test-provider-bootstrap.js +158 -0
- package/test-provider-capabilities.js +232 -0
- package/test-provider-claude.js +206 -0
- package/test-provider-codex.js +228 -0
- package/test-provider-compaction.js +371 -0
- package/test-provider-core-prompt.js +264 -0
- package/test-provider-coupling-audit.js +90 -0
- package/test-provider-dream.js +312 -0
- package/test-provider-enforcer.js +252 -0
- package/test-provider-env-isolation.js +150 -0
- package/test-provider-events.js +141 -0
- package/test-provider-fixture.js +332 -0
- package/test-provider-gateway.js +508 -0
- package/test-provider-language.js +89 -0
- package/test-provider-migration-backup.js +424 -0
- package/test-provider-pack-review.js +436 -0
- package/test-provider-parity-e2e.js +537 -0
- package/test-provider-prompt-parity.js +89 -0
- package/test-provider-recall.js +271 -0
- package/test-provider-registry.js +251 -0
- package/test-provider-resume-parity.js +41 -0
- package/test-provider-run-lifecycle.js +349 -0
- package/test-provider-runner.js +271 -0
- package/test-provider-scheduler.js +689 -0
- package/test-provider-session-commands.js +185 -0
- package/test-provider-session-history.js +205 -0
- package/test-provider-side-chat.js +337 -0
- package/test-provider-state-migration.js +316 -0
- package/test-provider-stream-decoder.js +69 -0
- package/test-provider-subagent.js +228 -0
- package/test-provider-tool-hooks.js +360 -0
- package/test-recall-discoverer.js +1 -0
- package/test-recall-engine.js +3 -3
- package/test-recall-evolution.js +18 -0
- package/test-runner-watchdog-static.js +16 -8
- package/test-single-runtime.js +35 -0
- package/test-telegram-poll-recovery.js +56 -0
- package/test-tool-guard.js +56 -0
- package/test-tools.js +19 -0
- package/test-unified-identity.js +3 -1
- package/test-usage-accounting.js +92 -20
- package/test-utility-provider-policy.js +486 -0
- package/web.js +130 -35
package/bin/dream.js
CHANGED
|
@@ -10,8 +10,8 @@ Run the dream memory-consolidation pass now.
|
|
|
10
10
|
|
|
11
11
|
open-claudia dream [--dry-run]
|
|
12
12
|
|
|
13
|
-
Reviews all context packs and entities with
|
|
14
|
-
|
|
13
|
+
Reviews all context packs and entities with the configured high-tier utility
|
|
14
|
+
provider: merges duplicate packs, builds umbrella/parent trees,
|
|
15
15
|
tightens descriptions and tags, dedupes entities, cross-links notes, and
|
|
16
16
|
may gently evolve the persona. Merged-away packs/entities are backed up
|
|
17
17
|
under ~/.open-claudia/backup/dream-<stamp>/ first.
|
|
@@ -24,17 +24,11 @@ async function run(args) {
|
|
|
24
24
|
const dream = require(path.join(__dirname, "..", "core", "dream"));
|
|
25
25
|
|
|
26
26
|
if (args.includes("--dry-run")) {
|
|
27
|
-
const { spawnSubagent } = require(path.join(__dirname, "..", "core", "subagent"));
|
|
28
27
|
console.error("Dreaming (dry run)… this can take a minute or two.");
|
|
29
28
|
try {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
systemPrompt: "You are a background memory consolidation process. Reply with ONLY the requested JSON object. No prose, no markdown, no tool use.",
|
|
34
|
-
});
|
|
35
|
-
const decision = dream.parseDream(text);
|
|
36
|
-
if (!decision) { console.error("Unparseable model output:"); console.log(text); process.exit(1); }
|
|
37
|
-
console.log(JSON.stringify(decision, null, 2));
|
|
29
|
+
const preview = await dream.previewDream();
|
|
30
|
+
console.error(`Dream provider: ${preview.provider || "unknown"}/${preview.model || "default"}`);
|
|
31
|
+
console.log(JSON.stringify(preview.decision, null, 2));
|
|
38
32
|
process.exit(0);
|
|
39
33
|
} catch (e) { console.error(`dream failed: ${e.message}`); process.exit(1); }
|
|
40
34
|
}
|
package/bin/loopback-client.js
CHANGED
|
@@ -31,6 +31,11 @@ function context() {
|
|
|
31
31
|
const info = readLoopbackInfo();
|
|
32
32
|
if (info) { sendUrl = info.url; sendToken = info.token; }
|
|
33
33
|
}
|
|
34
|
+
let providerSettings = {};
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(process.env.OC_PROVIDER_SETTINGS || "{}");
|
|
37
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) providerSettings = parsed;
|
|
38
|
+
} catch (_) {}
|
|
34
39
|
return {
|
|
35
40
|
sendUrl,
|
|
36
41
|
sendToken,
|
|
@@ -38,8 +43,16 @@ function context() {
|
|
|
38
43
|
adapterId: process.env.OC_CHANNEL_ADAPTER,
|
|
39
44
|
userId: process.env.OC_CHANNEL_USER_ID || null,
|
|
40
45
|
canonicalUserId: process.env.OC_CANONICAL_USER_ID || null,
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
provider: process.env.OC_PROVIDER || null,
|
|
47
|
+
providerSettings,
|
|
48
|
+
project: process.env.OC_PROJECT || null,
|
|
49
|
+
projectDir: process.env.OC_PROJECT_DIR || null,
|
|
50
|
+
runId: process.env.OC_RUN_ID || null,
|
|
51
|
+
sessionId: process.env.OC_SESSION_ID || process.env.OC_LAST_SESSION_ID || null,
|
|
52
|
+
previousSessionId: process.env.OC_PREVIOUS_SESSION_ID || null,
|
|
53
|
+
occurrenceId: process.env.OC_OCCURRENCE_ID || null,
|
|
54
|
+
scheduledJobId: process.env.OC_SCHEDULED_JOB_ID || null,
|
|
55
|
+
originRunId: process.env.OC_ORIGIN_RUN_ID || null,
|
|
43
56
|
};
|
|
44
57
|
}
|
|
45
58
|
|
|
@@ -55,14 +68,25 @@ function requireContext() {
|
|
|
55
68
|
function postJson(kind, body) {
|
|
56
69
|
const ctx = requireContext();
|
|
57
70
|
const u = new URL(ctx.sendUrl);
|
|
71
|
+
const requestedProject = body && body.project ? String(body.project) : ctx.project;
|
|
72
|
+
const sameProject = !ctx.project || !requestedProject || requestedProject === ctx.project;
|
|
58
73
|
const payload = JSON.stringify({
|
|
74
|
+
...body,
|
|
59
75
|
channelId: ctx.channelId,
|
|
60
76
|
adapter: ctx.adapterId,
|
|
61
77
|
userId: ctx.userId,
|
|
62
78
|
canonicalUserId: ctx.canonicalUserId,
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
79
|
+
provider: ctx.provider,
|
|
80
|
+
providerSettings: ctx.providerSettings,
|
|
81
|
+
project: requestedProject,
|
|
82
|
+
projectDir: sameProject ? ctx.projectDir : null,
|
|
83
|
+
originProject: ctx.project,
|
|
84
|
+
originProjectDir: ctx.projectDir,
|
|
85
|
+
originRunId: ctx.runId,
|
|
86
|
+
sessionId: sameProject ? ctx.sessionId : null,
|
|
87
|
+
previousSessionId: sameProject ? ctx.previousSessionId : null,
|
|
88
|
+
parentOccurrenceId: ctx.occurrenceId,
|
|
89
|
+
parentScheduledJobId: ctx.scheduledJobId,
|
|
66
90
|
});
|
|
67
91
|
return new Promise((resolve, reject) => {
|
|
68
92
|
const req = http.request({
|
package/bin/schedule.js
CHANGED
|
@@ -15,8 +15,9 @@ Crons (recurring):
|
|
|
15
15
|
open-claudia cron-list # all wakeups + crons for this channel
|
|
16
16
|
open-claudia cron-remove <id> # remove by id from cron-list
|
|
17
17
|
|
|
18
|
-
Each fire wakes the agent
|
|
19
|
-
|
|
18
|
+
Each fire wakes the agent in the same channel and resumes the selected provider
|
|
19
|
+
session captured when the schedule was created. Provider/project switches made
|
|
20
|
+
later do not retarget already-scheduled work.
|
|
20
21
|
`;
|
|
21
22
|
|
|
22
23
|
const DUR = /^(\d+)\s*(s|sec|secs|m|min|mins|h|hr|hrs|d|day|days)$/i;
|
|
@@ -68,7 +69,9 @@ async function runScheduleWakeup(args) {
|
|
|
68
69
|
const prompt = rest.slice(1).join(" ");
|
|
69
70
|
if (!prompt) { console.error("Missing prompt."); process.exit(2); }
|
|
70
71
|
try {
|
|
71
|
-
const
|
|
72
|
+
const request = { fireAt: when, prompt, label: label || prompt.slice(0, 60) };
|
|
73
|
+
if (project) request.project = project;
|
|
74
|
+
const res = await postJson("schedule-wakeup", request);
|
|
72
75
|
console.log(`Scheduled wakeup ${res.job.id} for ${new Date(when).toISOString()}.`);
|
|
73
76
|
process.exit(0);
|
|
74
77
|
} catch (e) { console.error(e.message); process.exit(1); }
|
|
@@ -83,7 +86,9 @@ async function runCronAdd(args) {
|
|
|
83
86
|
const prompt = rest.slice(1).join(" ");
|
|
84
87
|
if (!schedule || !prompt) { console.error("Usage: cron-add \"<schedule>\" \"<prompt>\""); process.exit(2); }
|
|
85
88
|
try {
|
|
86
|
-
const
|
|
89
|
+
const request = { schedule, prompt, label: label || prompt.slice(0, 60) };
|
|
90
|
+
if (project) request.project = project;
|
|
91
|
+
const res = await postJson("cron-add", request);
|
|
87
92
|
console.log(`Added cron ${res.job.id} (${schedule}).`);
|
|
88
93
|
process.exit(0);
|
|
89
94
|
} catch (e) { console.error(e.message); process.exit(1); }
|
|
@@ -93,8 +98,17 @@ async function runCronList() {
|
|
|
93
98
|
try {
|
|
94
99
|
const res = await postJson("job-list", {});
|
|
95
100
|
const list = res.jobs || [];
|
|
96
|
-
|
|
101
|
+
const archived = res.archived || [];
|
|
102
|
+
if (list.length === 0 && archived.length === 0) { console.log("No jobs."); process.exit(0); }
|
|
97
103
|
for (const j of list) console.log(fmtJob(j));
|
|
104
|
+
if (archived.length) {
|
|
105
|
+
if (list.length) console.log("");
|
|
106
|
+
console.log("Archived (disabled by provider migration — will not fire):");
|
|
107
|
+
for (const j of archived) {
|
|
108
|
+
const label = j.label || (j.prompt ? String(j.prompt).slice(0, 50) : "(no label)");
|
|
109
|
+
console.log(`${j.id} ${j.kind || "job"} ${label} — ${j.archiveReason || "archived"}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
98
112
|
process.exit(0);
|
|
99
113
|
} catch (e) { console.error(e.message); process.exit(1); }
|
|
100
114
|
}
|
package/bin/tool.js
CHANGED
|
@@ -371,7 +371,8 @@ async function run(args) {
|
|
|
371
371
|
// calling this tool) gate on the tier the OUTERMOST invocation approved
|
|
372
372
|
// instead — argv flags can't fabricate approval.
|
|
373
373
|
const gate = tools.runGate(t, toolArgs, process.env);
|
|
374
|
-
const
|
|
374
|
+
const approvals = require("../core/approvals");
|
|
375
|
+
const commandLine = approvals.formatApprovedCommand(["open-claudia", "tool", "run", t.name, ...toolArgs]);
|
|
375
376
|
let approvedVia = "";
|
|
376
377
|
|
|
377
378
|
// ── Phase 3.5: per-speaker external gate ──────────────────────────────
|
|
@@ -403,6 +404,20 @@ async function run(args) {
|
|
|
403
404
|
} else {
|
|
404
405
|
const esc = await enforcer.escalate({
|
|
405
406
|
speaker, kind: "action", command: commandLine, tier: gate.tier, reason: vet.reason,
|
|
407
|
+
canonicalUserId: process.env.OC_CANONICAL_USER_ID || "",
|
|
408
|
+
userId: process.env.OC_CHANNEL_USER_ID || "",
|
|
409
|
+
provider: process.env.OC_PROVIDER || "",
|
|
410
|
+
providerSettings: (() => {
|
|
411
|
+
try {
|
|
412
|
+
const value = JSON.parse(process.env.OC_PROVIDER_SETTINGS || "{}");
|
|
413
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
414
|
+
} catch (_) { return {}; }
|
|
415
|
+
})(),
|
|
416
|
+
project: process.env.OC_PROJECT || "",
|
|
417
|
+
projectDir: process.env.OC_PROJECT_DIR || "",
|
|
418
|
+
sessionId: process.env.OC_SESSION_ID || process.env.OC_LAST_SESSION_ID || "",
|
|
419
|
+
previousSessionId: process.env.OC_PREVIOUS_SESSION_ID || "",
|
|
420
|
+
originRunId: process.env.OC_RUN_ID || process.env.OC_ORIGIN_RUN_ID || "",
|
|
406
421
|
});
|
|
407
422
|
if (esc.escalated) {
|
|
408
423
|
console.error(`🛡️ Held for owner approval — ${speaker.name || "the external contact"} is outside mandate for this ${gate.tier} action.`);
|
|
@@ -416,7 +431,6 @@ async function run(args) {
|
|
|
416
431
|
}
|
|
417
432
|
|
|
418
433
|
if (approvalId) {
|
|
419
|
-
const approvals = require("../core/approvals");
|
|
420
434
|
if (String(process.env.OPEN_CLAUDIA_TOOL_STACK || "").trim()) {
|
|
421
435
|
console.error("⛔ --approval tokens are only honored on top-level runs, not nested tool calls.");
|
|
422
436
|
process.exitCode = 3; return;
|
|
@@ -436,7 +450,7 @@ async function run(args) {
|
|
|
436
450
|
// wakeup carrying a one-shot --approval token. Anything but an explicit
|
|
437
451
|
// approve = the command never runs.
|
|
438
452
|
const canAsk = gate.tier === "destructive" && !gate.nested && !gate.undeclared
|
|
439
|
-
&& process.env.OC_SEND_URL && process.env.
|
|
453
|
+
&& process.env.OC_SEND_URL && process.env.OC_CHANNEL_ID && process.env.OC_CHANNEL_ADAPTER;
|
|
440
454
|
if (!canAsk) { console.error(gate.message); process.exitCode = 3; return; }
|
|
441
455
|
console.error(`Destructive run without --yes-destructive — asking for chat approval of the exact command...`);
|
|
442
456
|
let decision = "denied";
|
|
@@ -447,7 +461,6 @@ async function run(args) {
|
|
|
447
461
|
tool: t.name, verb: tools.invokedVerb(toolArgs), tier: gate.tier, command: commandLine,
|
|
448
462
|
});
|
|
449
463
|
reqId = res.id;
|
|
450
|
-
const approvals = require("../core/approvals");
|
|
451
464
|
decision = await approvals.waitForDecision(res.id);
|
|
452
465
|
if (decision === "timeout") {
|
|
453
466
|
approvals.detach(res.id);
|
|
@@ -464,8 +477,13 @@ async function run(args) {
|
|
|
464
477
|
`Re-run with --yes-destructive only after the user explicitly approves.`);
|
|
465
478
|
process.exitCode = 3; return;
|
|
466
479
|
}
|
|
480
|
+
const redeemed = approvals.consume(reqId, commandLine);
|
|
481
|
+
if (!redeemed.ok) {
|
|
482
|
+
console.error(`⛔ Approval ${reqId || "(missing)"} rejected: ${redeemed.reason}. The run stays blocked.`);
|
|
483
|
+
process.exitCode = 3; return;
|
|
484
|
+
}
|
|
467
485
|
approvedVia = "chat-approval";
|
|
468
|
-
console.error(`✅
|
|
486
|
+
console.error(`✅ Approval ${reqId} redeemed (single use) — running.`);
|
|
469
487
|
}
|
|
470
488
|
|
|
471
489
|
const missing = tools.missingRequires(t);
|