@inetafrica/open-claudia 2.14.8 → 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.
Files changed (157) hide show
  1. package/.env.example +30 -4
  2. package/CHANGELOG.md +21 -0
  3. package/README.md +87 -66
  4. package/bin/agent.js +44 -18
  5. package/bin/cli.js +30 -28
  6. package/bin/dream.js +5 -11
  7. package/bin/loopback-client.js +29 -5
  8. package/bin/schedule.js +19 -5
  9. package/bin/tool.js +23 -5
  10. package/bot-agent.js +5 -2350
  11. package/bot.js +105 -7
  12. package/channels/telegram/adapter.js +6 -1
  13. package/channels/voice/adapter.js +1 -0
  14. package/channels/voice/manage.js +43 -5
  15. package/config-dir.js +3 -11
  16. package/core/actions.js +149 -40
  17. package/core/approvals.js +136 -29
  18. package/core/auth-flow.js +103 -19
  19. package/core/config-dir.js +19 -0
  20. package/core/config.js +127 -69
  21. package/core/doctor.js +111 -57
  22. package/core/dream.js +219 -62
  23. package/core/enforcer.js +0 -0
  24. package/core/entities.js +2 -1
  25. package/core/fsutil.js +55 -0
  26. package/core/handlers.js +503 -217
  27. package/core/ideas.js +2 -1
  28. package/core/identity.js +8 -11
  29. package/core/io.js +24 -3
  30. package/core/jobs.js +589 -72
  31. package/core/lessons.js +3 -2
  32. package/core/loopback.js +45 -8
  33. package/core/memory-mutation-queue.js +241 -0
  34. package/core/migration-backup.js +1060 -0
  35. package/core/pack-review.js +295 -88
  36. package/core/packs.js +4 -3
  37. package/core/persona.js +2 -1
  38. package/core/process-tree.js +19 -2
  39. package/core/provider-migration.js +39 -0
  40. package/core/provider-status.js +80 -0
  41. package/core/providers/claude-events.js +117 -0
  42. package/core/providers/claude-hook.js +114 -0
  43. package/core/providers/claude.js +296 -0
  44. package/core/providers/codex-events.js +121 -0
  45. package/core/providers/codex-hook.js +280 -0
  46. package/core/providers/codex.js +286 -0
  47. package/core/providers/contract.js +153 -0
  48. package/core/providers/env.js +148 -0
  49. package/core/providers/events.js +170 -0
  50. package/core/providers/hook-command.js +22 -0
  51. package/core/providers/index.js +240 -0
  52. package/core/providers/utility-policy.js +269 -0
  53. package/core/recall/classic.js +2 -2
  54. package/core/recall/discoverer.js +71 -22
  55. package/core/recall/metrics.js +27 -1
  56. package/core/recall/tuning.js +4 -1
  57. package/core/recall/warm-walker.js +151 -108
  58. package/core/recall-filter.js +86 -61
  59. package/core/router.js +79 -7
  60. package/core/run-context.js +185 -0
  61. package/core/runner.js +1415 -1282
  62. package/core/scheduler.js +515 -210
  63. package/core/side-chat.js +346 -0
  64. package/core/state.js +1096 -95
  65. package/core/subagent.js +72 -98
  66. package/core/system-prompt.js +462 -279
  67. package/core/tool-guard.js +73 -39
  68. package/core/tools.js +22 -5
  69. package/core/transcripts.js +30 -1
  70. package/core/usage-log.js +19 -4
  71. package/core/utility-agent.js +654 -0
  72. package/core/web-auth.js +29 -13
  73. package/core/web-sessions.js +78 -0
  74. package/docs/CHANNEL_DESIGN.md +181 -0
  75. package/docs/MULTI_CHANNEL_PLAN.md +254 -0
  76. package/docs/PROVIDER_MIGRATION.md +67 -0
  77. package/health.js +50 -39
  78. package/package.json +51 -4
  79. package/setup.js +198 -38
  80. package/soul.md +39 -0
  81. package/test-ability-extraction.js +5 -0
  82. package/test-approval-async.js +63 -4
  83. package/test-cursor-removal.js +334 -0
  84. package/test-delivery-contract.js +88 -0
  85. package/test-enforcer.js +70 -27
  86. package/test-fixtures/current-provider-parity.json +132 -0
  87. package/test-fixtures/fake-agent-cli.js +477 -0
  88. package/test-fixtures/migrations/claude-only/jobs.json +3 -0
  89. package/test-fixtures/migrations/claude-only/sessions.json +5 -0
  90. package/test-fixtures/migrations/claude-only/state.json +5 -0
  91. package/test-fixtures/migrations/cursor-selected/crons.json +3 -0
  92. package/test-fixtures/migrations/cursor-selected/jobs.json +3 -0
  93. package/test-fixtures/migrations/cursor-selected/sessions.json +5 -0
  94. package/test-fixtures/migrations/cursor-selected/state.json +6 -0
  95. package/test-fixtures/migrations/dual-provider/jobs.json +3 -0
  96. package/test-fixtures/migrations/dual-provider/sessions.json +7 -0
  97. package/test-fixtures/migrations/dual-provider/state.json +10 -0
  98. package/test-fixtures/migrations/malformed-partial/jobs.json +1 -0
  99. package/test-fixtures/migrations/malformed-partial/sessions.json +1 -0
  100. package/test-fixtures/migrations/malformed-partial/sessions.json.bak +3 -0
  101. package/test-fixtures/migrations/malformed-partial/state.json +1 -0
  102. package/test-fixtures/migrations/malformed-partial/state.json.bak +5 -0
  103. package/test-fixtures/migrations/missing-project/jobs.json +3 -0
  104. package/test-fixtures/migrations/missing-project/sessions.json +3 -0
  105. package/test-fixtures/migrations/missing-project/state.json +4 -0
  106. package/test-fixtures/migrations/multi-user/jobs.json +4 -0
  107. package/test-fixtures/migrations/multi-user/sessions.json +4 -0
  108. package/test-fixtures/migrations/multi-user/state.json +6 -0
  109. package/test-fixtures/provider-event-samples.json +17 -0
  110. package/test-learning-e2e.js +5 -0
  111. package/test-memory-mutation-queue.js +191 -0
  112. package/test-provider-boot-matrix.js +399 -0
  113. package/test-provider-bootstrap.js +158 -0
  114. package/test-provider-capabilities.js +232 -0
  115. package/test-provider-claude.js +206 -0
  116. package/test-provider-codex.js +228 -0
  117. package/test-provider-compaction.js +371 -0
  118. package/test-provider-core-prompt.js +264 -0
  119. package/test-provider-coupling-audit.js +90 -0
  120. package/test-provider-dream.js +312 -0
  121. package/test-provider-enforcer.js +252 -0
  122. package/test-provider-env-isolation.js +150 -0
  123. package/test-provider-events.js +141 -0
  124. package/test-provider-fixture.js +332 -0
  125. package/test-provider-gateway.js +508 -0
  126. package/test-provider-language.js +89 -0
  127. package/test-provider-migration-backup.js +424 -0
  128. package/test-provider-pack-review.js +436 -0
  129. package/test-provider-parity-e2e.js +537 -0
  130. package/test-provider-prompt-parity.js +89 -0
  131. package/test-provider-recall.js +271 -0
  132. package/test-provider-registry.js +251 -0
  133. package/test-provider-resume-parity.js +41 -0
  134. package/test-provider-run-lifecycle.js +349 -0
  135. package/test-provider-runner.js +271 -0
  136. package/test-provider-scheduler.js +689 -0
  137. package/test-provider-session-commands.js +185 -0
  138. package/test-provider-session-history.js +205 -0
  139. package/test-provider-side-chat.js +337 -0
  140. package/test-provider-state-migration.js +316 -0
  141. package/test-provider-stream-decoder.js +69 -0
  142. package/test-provider-subagent.js +228 -0
  143. package/test-provider-tool-hooks.js +360 -0
  144. package/test-recall-discoverer.js +1 -0
  145. package/test-recall-engine.js +3 -3
  146. package/test-recall-evolution.js +18 -0
  147. package/test-run-lock.js +63 -0
  148. package/test-runner-watchdog-static.js +16 -8
  149. package/test-single-runtime.js +35 -0
  150. package/test-telegram-poll-recovery.js +56 -0
  151. package/test-tool-guard.js +56 -0
  152. package/test-tools.js +19 -0
  153. package/test-unified-identity.js +3 -1
  154. package/test-usage-accounting.js +92 -20
  155. package/test-utility-provider-policy.js +486 -0
  156. package/test-web-sessions.js +74 -0
  157. package/web.js +159 -45
@@ -0,0 +1,67 @@
1
+ # Provider migration snapshots and rollback
2
+
3
+ Open Claudia takes a verified, byte-for-byte snapshot before any provider-aware state, session, or job schema is activated. At startup it then migrates and verifies all three stores before loading the vault, scheduler, router, or channel adapters. Direct and agent modes use the same modular `bot.js` runtime, so there is only one active state writer during this process.
4
+
5
+ Snapshots live under the configured Open Claudia data directory:
6
+
7
+ ```text
8
+ migration-backups/provider-parity-v1.1/snapshots/<timestamp-id>/
9
+ originals/
10
+ manifest.json
11
+ manifest.sha256
12
+ ```
13
+
14
+ The allowlist contains `state.json`, `sessions.json`, `jobs.json`, legacy `crons.json`, an earlier `crons.json.migrated`, and relevant `.bak` siblings. It deliberately excludes `.env`, vault, authentication, identity, transcript, and derived SQLite files. The manifest records relative names, byte sizes, SHA-256 hashes, and advisory schema guesses; it never records source contents or absolute installation paths. Malformed and provider-ambiguous records are preserved as `unresolved` rather than assigned to Claude, Codex, or a project by guesswork. Removed-provider selections, settings, session pointers/history, and jobs are retained only in non-selectable or disabled archives; they are never reassigned to Claude or Codex and never fired.
15
+
16
+ Snapshot directories are private operator data. They can contain conversation titles, prompts, native session identifiers, and scheduled-job text. Keep them mode `0700` with files mode `0600`; do not share, publish, or commit them.
17
+
18
+ ## Rollback procedure
19
+
20
+ Rollback is an offline operation. Do not restore files while any Open Claudia process can write them.
21
+
22
+ 1. Stop every Open Claudia bot and scheduler process. Confirm no old or new runtime remains active.
23
+ 2. Identify the snapshot referenced by `migration-backups/provider-parity-v1.1/journal.json`. Do not select a partial orphan directory merely because its timestamp is newer.
24
+ 3. Validate the complete snapshot with `validateMigrationSnapshot(snapshotDir)`. A manifest mismatch, missing file, corrupt copy, symlink, or checksum failure blocks rollback before any live target changes.
25
+ 4. Call `rollbackMigrationSnapshot` from the installed Open Claudia package with the configured state/session/job/cron paths, as in the example below. The helper stages exact bytes, restores the complete allowlisted set, restores original absence where applicable, and verifies every target against the manifest.
26
+ 5. Validate the snapshot again and verify the restored live files with the same source list. Keep the snapshot; rollback never deletes it.
27
+ 6. If the restored files contain Cursor Agent state, restart the matching older Cursor-capable Open Claudia version. The current runtime intentionally cannot execute that provider. Otherwise restart the upgraded version only after its migration journal and schema expectations have been reviewed.
28
+
29
+ Rollback restores the snapshot's exact pre-upgrade bytes. Post-upgrade changes are not merged into those older files and will be discarded by the restore. If those changes must be audited, make a separate private copy of the current files while every writer is stopped; never combine records from the two schema generations by hand.
30
+
31
+ Example from a Node maintenance script run inside the installed package:
32
+
33
+ ```js
34
+ const migration = require("./core/migration-backup");
35
+ const config = require("./core/config");
36
+ const configDir = config.CONFIG_DIR;
37
+ const snapshotDir = process.env.OPEN_CLAUDIA_MIGRATION_SNAPSHOT;
38
+ const sources = migration.defaultMigrationSources({
39
+ configDir,
40
+ stateFile: config.STATE_FILE,
41
+ sessionsFile: config.SESSIONS_FILE,
42
+ jobsFile: config.JOBS_FILE,
43
+ cronsFile: config.CRONS_FILE,
44
+ });
45
+
46
+ migration.validateMigrationSnapshot(snapshotDir);
47
+ migration.rollbackMigrationSnapshot(snapshotDir, { configDir, sources });
48
+ migration.validateMigrationSnapshot(snapshotDir, { sources, verifySources: true });
49
+ ```
50
+
51
+ Never mark a migration globally activated after migrating only one store. The journal tracks `state`, `sessions`, and `jobs` separately and reaches `activated` only after all three component migrations have completed and verified their writes. Each component certificate records the live file's logical path, byte size, schema version, and SHA-256; readiness recomputes those values, so a legacy, corrupt, or subsequently replaced file cannot satisfy an old activation flag.
52
+
53
+ Startup beyond the migration preflight is gated on that globally activated journal. A missing component, corrupt manifest, stale live-file proof, or partial migration blocks normal runtime initialization. After the gate, an old Cursor selection becomes an explicit “provider selection required” state; the user must choose Claude Code or OpenAI Codex with `/backend`. Old callbacks show a removal notice and do not mutate the provider, model, or session.
54
+
55
+ Each component write is two-phase. Open Claudia records a `pendingComponents` entry against the verified pre-migration snapshot before the atomic live-file rename, validates the new schema after the rename, and only then marks that component activated. If the process stops between those steps, startup keeps the original snapshot pinned; the component migration must validate and finish the pending write instead of creating a mixed-schema replacement snapshot.
56
+
57
+ Provider-blind conversation-history records are retained as non-selectable `legacy` entries unless exactly one provider adapter can prove ownership with a read-only probe. New history is keyed by canonical user, project, and provider. Chat buttons contain only short-lived opaque server-side tokens; provider-native session IDs are never embedded in callback payloads.
58
+
59
+ Provider and project switches restore only that tuple's active conversation, while model, effort, budget, permission mode, and worktree choices remain scoped to the provider. `/new` clears the selected project's active pointer for the current provider only. `/end` closes the project selection and settles transient queued work without deleting provider pointers or conversation history.
60
+
61
+ Compaction captures one immutable canonical-user/project/provider/session tuple. Summary and seed runs cannot persist ordinary transcripts, usage, or session pointers, and queued user turns remain paused until both stages settle. Claude seeds use its native one-turn limit in read-only plan mode. Codex seeds use a read-only sandbox plus a bounded JSON acknowledgement contract; they deliberately use a persistent compaction invocation instead of Codex's ephemeral utility flag because the resulting seed must remain resumable. No unsupported Codex `maxTurns` or complete tool-suppression claim is made.
62
+
63
+ The pointer, provider-tagged history lineage, and tuple-scoped usage checkpoint are committed through a recoverable prepared/committed marker. Restart rolls a prepared operation back to the old pointer and history, while a committed marker is finalized without replaying history. Legacy usage-log records expose their existing `backend` as `provider` when read, without rewriting the original JSONL file.
64
+
65
+ Scheduled work uses a versioned `{schemaVersion, jobs, archived}` document. Every runnable occurrence stores its canonical user, channel, project, provider, provider-settings snapshot, native session lineage, origin run, and stable occurrence ID. A fresh foreground turn can create a job before its native session is known; terminal session persistence binds that job by origin run ID. Compaction descendants are followed only when recorded lineage proves the relationship, and an older scheduled branch cannot replace an unrelated live session pointer.
66
+
67
+ Wakeups and crons wait for terminal provider completion, transcript/usage/session persistence, and required delivery. A one-shot receives a durable success marker before deletion. Busy or failed occurrences retain their occurrence ID and bounded attempt state across restart; exhaustion and wakeups outside the missed-fire grace window remain visible as disabled dead letters. Provider fallback is empty by default. When `PROVIDER_FALLBACKS` is explicitly configured, a fallback starts a fresh provider session with an archived provider-neutral brief and never receives another provider's native session ID. Legacy `crons.json` remains byte-for-byte untouched after its ambiguous records are copied into the disabled archive.
package/health.js CHANGED
@@ -3,6 +3,7 @@ const fs = require("fs");
3
3
  const path = require("path");
4
4
  const https = require("https");
5
5
  const CONFIG_DIR = require("./config-dir");
6
+ const { inspectProviderConfiguration } = require("./core/provider-status");
6
7
 
7
8
  const ENV_FILE = path.join(CONFIG_DIR, ".env");
8
9
  const AUTH_FILE = path.join(CONFIG_DIR, "auth.json");
@@ -12,7 +13,6 @@ const REQUIRED_ENV_KEYS = [
12
13
  "TELEGRAM_BOT_TOKEN",
13
14
  "TELEGRAM_CHAT_ID",
14
15
  "WORKSPACE",
15
- "CLAUDE_PATH",
16
16
  ];
17
17
 
18
18
  // Optional but recommended
@@ -60,24 +60,21 @@ function binaryExists(binPath) {
60
60
  }
61
61
 
62
62
  /**
63
- * Test if Claude CLI is authenticated
63
+ * Test Claude authentication using the provider's local auth-status command.
64
+ * This compatibility export deliberately never sends a model prompt.
64
65
  */
65
- function testClaudeAuth(claudePath) {
66
- try {
67
- execSync(`"${claudePath}" -p "say ok" --max-budget-usd 0.01 --output-format text 2>&1`, {
68
- encoding: "utf-8",
69
- timeout: 30000,
70
- stdio: "pipe",
71
- });
72
- return { ok: true };
73
- } catch (e) {
74
- const errMsg = (e.stderr || e.stdout || e.message || "").toLowerCase();
75
- if (errMsg.includes("auth") || errMsg.includes("login") || errMsg.includes("api key") || errMsg.includes("unauthorized")) {
76
- return { ok: false, reason: "not_authenticated", message: "Claude CLI is not authenticated. Run 'claude auth' or 'claude login'." };
77
- }
78
- // Other errors (like timeout) are OK - Claude is accessible
79
- return { ok: true };
80
- }
66
+ function testClaudeAuth(_claudePath, options = {}) {
67
+ const summary = inspectProviderConfiguration({
68
+ registry: options.registry,
69
+ probeAuth: true,
70
+ });
71
+ const claude = summary.providers.find((provider) => provider.id === "claude");
72
+ if (claude?.auth.state === "authenticated") return { ok: true };
73
+ return {
74
+ ok: false,
75
+ reason: claude?.auth.state || "not_checked",
76
+ message: claude?.recovery || "Claude Code authentication could not be confirmed.",
77
+ };
81
78
  }
82
79
 
83
80
  /**
@@ -228,12 +225,12 @@ function checkAuthFile() {
228
225
  /**
229
226
  * Run all health checks
230
227
  * @param {Object} options - Options
231
- * @param {boolean} options.quick - Skip slow checks (Claude auth, Telegram API)
228
+ * @param {boolean} options.quick - Skip auth and external channel checks
232
229
  * @param {boolean} options.fix - Attempt to fix issues (create directories)
233
230
  * @returns {Promise<Object>} Health check results
234
231
  */
235
232
  async function runHealthChecks(options = {}) {
236
- const { quick = false, fix = false } = options;
233
+ const { quick = false, fix = false, skipNetwork = false } = options;
237
234
  const results = {
238
235
  ok: true,
239
236
  checks: {},
@@ -267,27 +264,41 @@ async function runHealthChecks(options = {}) {
267
264
  results.checks.env = { ok: true };
268
265
  }
269
266
 
270
- // 3. Check Claude CLI exists
271
- const claudePath = env.CLAUDE_PATH;
272
- if (!binaryExists(claudePath)) {
273
- results.checks.claude_binary = { ok: false, reason: "not_found", message: `Claude CLI not found at: ${claudePath}` };
274
- results.ok = false;
275
- results.errors.push(results.checks.claude_binary.message);
276
- } else {
277
- results.checks.claude_binary = { ok: true, path: claudePath };
278
-
279
- // 4. Check Claude authentication (slow)
280
- if (!quick) {
281
- results.checks.claude_auth = testClaudeAuth(claudePath);
282
- if (!results.checks.claude_auth.ok) {
283
- results.ok = false;
284
- results.errors.push(results.checks.claude_auth.message);
285
- }
286
- }
267
+ // 3. Provider availability, compatibility, and authentication. Provider
268
+ // adapters use only local --version/help/auth-status commands here.
269
+ const providerSummary = inspectProviderConfiguration({
270
+ registry: options.registry,
271
+ probeAuth: !quick,
272
+ });
273
+ results.providerSummary = providerSummary;
274
+ for (const provider of providerSummary.providers) {
275
+ const compatible = provider.availability.state === "available"
276
+ && provider.compatibility.state === "compatible";
277
+ const authenticated = quick || provider.auth.state === "authenticated";
278
+ const ok = compatible && authenticated;
279
+ const key = `provider_${provider.id}`;
280
+ results.checks[key] = {
281
+ ok,
282
+ warn: !ok,
283
+ availability: provider.availability.state,
284
+ compatibility: provider.compatibility.state,
285
+ auth: provider.auth.state,
286
+ message: provider.recovery,
287
+ };
288
+ if (!ok && provider.recovery) results.warnings.push(`${provider.label}: ${provider.recovery.split("\n")[0]}`);
289
+ }
290
+ results.checks.default_provider = {
291
+ ok: !!providerSummary.defaultProvider.providerId,
292
+ warn: !providerSummary.defaultProvider.providerId,
293
+ providerId: providerSummary.defaultProvider.providerId,
294
+ message: providerSummary.defaultProvider.reason,
295
+ };
296
+ if (!providerSummary.defaultProvider.providerId) {
297
+ results.warnings.push(`${providerSummary.defaultProvider.reason}. Model turns are unavailable until a provider is configured.`);
287
298
  }
288
299
 
289
- // 5. Check Telegram token (slow)
290
- if (!quick && env.TELEGRAM_BOT_TOKEN) {
300
+ // 4. Check Telegram token (external network; never part of provider health).
301
+ if (!quick && !skipNetwork && env.TELEGRAM_BOT_TOKEN) {
291
302
  results.checks.telegram = await testTelegramToken(env.TELEGRAM_BOT_TOKEN);
292
303
  if (!results.checks.telegram.ok) {
293
304
  results.ok = false;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inetafrica/open-claudia",
3
- "version": "2.14.8",
4
- "description": "Your always-on AI coding assistant Claude Code, Cursor Agent, and OpenAI Codex via Telegram or Kazee Chat",
3
+ "version": "3.0.0",
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": {
7
7
  "open-claudia": "./bin/cli.js"
@@ -9,7 +9,8 @@
9
9
  "scripts": {
10
10
  "setup": "node setup.js",
11
11
  "start": "node bot.js",
12
- "test": "OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node -e \"require('./vault'); console.log('OK')\" && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-runner-watchdog-static.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-usage-accounting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-recall-engine.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-recall-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-recall-discoverer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-project-transcripts-smoke.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-abilities.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-ability-extraction.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-ability-couse.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-ability-transfer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-ability-tiers.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-ability-merge-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-learning-e2e.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-pack-nesting.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-journal-dedupe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-read-signal.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-tools.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-tool-graph.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-tool-guard.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-tooling-mode.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-tool-manifest.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-recall-evolution.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-approval-async.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-unified-identity.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-queue-routing.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-persona-packs.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-speaker-persona.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-persona-pipeline.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-recall-relationship-gate.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-relationship.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-enforcer.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-identity-prune.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=node node test-kazee-message-id.js"
12
+ "pretest": "node test-provider-fixture.js && node test-provider-core-prompt.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-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-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",
13
+ "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-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-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-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-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"
13
14
  },
14
15
  "files": [
15
16
  "bot.js",
@@ -30,6 +31,8 @@
30
31
  ".env.example",
31
32
  "README.md",
32
33
  "CHANGELOG.md",
34
+ "soul.md",
35
+ "docs/",
33
36
  "test-runner-watchdog-static.js",
34
37
  "test-usage-accounting.js",
35
38
  "test-recall-engine.js",
@@ -61,10 +64,54 @@
61
64
  "test-relationship.js",
62
65
  "test-enforcer.js",
63
66
  "test-identity-prune.js",
64
- "test-kazee-message-id.js"
67
+ "test-kazee-message-id.js",
68
+ "test-delivery-contract.js",
69
+ "test-run-lock.js",
70
+ "test-web-sessions.js",
71
+ "test-provider-fixture.js",
72
+ "test-provider-core-prompt.js",
73
+ "test-provider-prompt-parity.js",
74
+ "test-provider-env-isolation.js",
75
+ "test-provider-resume-parity.js",
76
+ "test-provider-bootstrap.js",
77
+ "test-provider-registry.js",
78
+ "test-provider-stream-decoder.js",
79
+ "test-provider-events.js",
80
+ "test-provider-claude.js",
81
+ "test-provider-codex.js",
82
+ "test-provider-runner.js",
83
+ "test-provider-run-lifecycle.js",
84
+ "test-provider-gateway.js",
85
+ "test-provider-side-chat.js",
86
+ "test-single-runtime.js",
87
+ "test-provider-migration-backup.js",
88
+ "test-provider-state-migration.js",
89
+ "test-provider-session-history.js",
90
+ "test-provider-session-commands.js",
91
+ "test-provider-compaction.js",
92
+ "test-provider-scheduler.js",
93
+ "test-cursor-removal.js",
94
+ "test-utility-provider-policy.js",
95
+ "test-provider-subagent.js",
96
+ "test-provider-recall.js",
97
+ "test-provider-pack-review.js",
98
+ "test-memory-mutation-queue.js",
99
+ "test-provider-dream.js",
100
+ "test-provider-enforcer.js",
101
+ "test-provider-tool-hooks.js",
102
+ "test-provider-boot-matrix.js",
103
+ "test-provider-capabilities.js",
104
+ "test-provider-language.js",
105
+ "test-provider-coupling-audit.js",
106
+ "test-provider-parity-e2e.js",
107
+ "test-telegram-poll-recovery.js",
108
+ "test-fixtures/"
65
109
  ],
66
110
  "keywords": [
67
111
  "claude",
112
+ "codex",
113
+ "coding-agent",
114
+ "provider-agnostic",
68
115
  "telegram",
69
116
  "ai",
70
117
  "assistant",