@inetafrica/open-claudia 3.5.1 → 3.5.4
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 +15 -0
- package/bin/cli.js +13 -5
- package/bin/loopback-client.js +4 -0
- package/bin/schedule.js +7 -2
- package/bot.js +6 -2
- package/channels/kazee/adapter.js +462 -64
- package/channels/kazee/state.js +78 -2
- package/channels/types.js +11 -5
- package/core/actions.js +6 -0
- package/core/approvals.js +9 -0
- package/core/context.js +11 -2
- package/core/handlers.js +161 -59
- package/core/identity.js +33 -3
- package/core/io.js +21 -8
- package/core/jobs.js +3 -0
- package/core/loopback.js +55 -7
- package/core/providers/claude.js +6 -2
- package/core/router.js +25 -13
- package/core/run-context.js +49 -8
- package/core/runner.js +302 -120
- package/core/scheduler.js +45 -3
- package/core/side-chat.js +40 -11
- package/core/speaker-attest.js +2 -0
- package/core/state.js +317 -50
- package/core/system-prompt.js +61 -14
- package/core/transcripts.js +23 -6
- package/package.json +3 -3
- package/test-approval-cards.js +24 -0
- package/test-call-speech.js +5 -3
- package/test-fixtures/fake-agent-cli.js +52 -1
- package/test-provider-compaction.js +50 -11
- package/test-provider-gateway.js +31 -10
- package/test-provider-language.js +10 -1
- package/test-provider-scheduler.js +77 -20
- package/test-provider-session-commands.js +11 -2
- package/test-provider-side-chat.js +30 -2
- package/test-run-lock.js +122 -39
- package/test-thread-lanes.js +530 -0
- package/core/queue-drain.js +0 -25
- package/test-queue-routing.js +0 -52
package/core/transcripts.js
CHANGED
|
@@ -7,7 +7,7 @@ const {
|
|
|
7
7
|
CONFIG_DIR, PROJECT_TRANSCRIPTS, TRANSCRIPTS_DIR, TRANSCRIPT_MAX_ENTRY_CHARS,
|
|
8
8
|
} = require("./config");
|
|
9
9
|
const { redactSensitive } = require("./redact");
|
|
10
|
-
const { currentChannelId } = require("./context");
|
|
10
|
+
const { currentChannelId, currentThreadId } = require("./context");
|
|
11
11
|
const { currentState } = require("./state");
|
|
12
12
|
const transcriptIndex = require("./transcript-index");
|
|
13
13
|
|
|
@@ -61,11 +61,16 @@ function appendProjectTranscript(role, text, metadata = {}, state = currentState
|
|
|
61
61
|
if (!state.currentSession) return null;
|
|
62
62
|
try {
|
|
63
63
|
const transport = (state.userId || "").split(":")[0] || "telegram";
|
|
64
|
+
// A chat thread's turns carry its root id; main-timeline entries stay as
|
|
65
|
+
// they always were (no threadId key).
|
|
66
|
+
const threadId = currentThreadId();
|
|
67
|
+
const chat = { transport, id: String(currentChannelId() || "") };
|
|
68
|
+
if (threadId) chat.threadId = String(threadId);
|
|
64
69
|
const result = projectTranscripts.append({
|
|
65
70
|
role,
|
|
66
71
|
text,
|
|
67
72
|
userId: state.userId,
|
|
68
|
-
chat
|
|
73
|
+
chat,
|
|
69
74
|
projectName: state.currentSession.name,
|
|
70
75
|
projectPath: state.currentSession.dir,
|
|
71
76
|
backend: state.settings.backend,
|
|
@@ -84,7 +89,12 @@ function appendProjectTranscript(role, text, metadata = {}, state = currentState
|
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
|
|
87
|
-
// Last few user/assistant turns on THIS channel,
|
|
92
|
+
// Last few user/assistant turns on THIS channel (and, in a chat thread, this
|
|
93
|
+
// thread only; on the main timeline, the main timeline only), for recall
|
|
94
|
+
// context.
|
|
95
|
+
// How far back recentTranscriptText looks for its conversation's entries.
|
|
96
|
+
const RECENT_SCAN_LINES = 4000;
|
|
97
|
+
|
|
88
98
|
// The current turn's user message is already appended by the time the
|
|
89
99
|
// prompt is built, so the trailing user entry is dropped — the live
|
|
90
100
|
// message drives recall directly as origin "user".
|
|
@@ -96,14 +106,21 @@ function recentTranscriptText({ limit = 6, perEntryChars = 280 } = {}, state = c
|
|
|
96
106
|
const raw = fs.readFileSync(info.transcriptPath, "utf-8").trim();
|
|
97
107
|
if (!raw) return "";
|
|
98
108
|
const channel = String(currentChannelId() || "");
|
|
109
|
+
const thread = currentThreadId() ? String(currentThreadId()) : null;
|
|
110
|
+
// This conversation's last 80 entries, not this conversation's share of
|
|
111
|
+
// the file's last 80 lines: busy threads writing to the same transcript
|
|
112
|
+
// would otherwise leave a quiet one (or the main timeline) almost nothing.
|
|
113
|
+
// Newest first, bounded so a huge file is never parsed whole.
|
|
99
114
|
const entries = [];
|
|
100
|
-
|
|
115
|
+
const lines = raw.split("\n");
|
|
116
|
+
for (let i = lines.length - 1; i >= Math.max(0, lines.length - RECENT_SCAN_LINES) && entries.length < 80; i -= 1) {
|
|
101
117
|
try {
|
|
102
|
-
const obj = JSON.parse(
|
|
118
|
+
const obj = JSON.parse(lines[i]);
|
|
103
119
|
if (obj.role !== "user" && obj.role !== "assistant") continue;
|
|
104
120
|
if (channel && obj.chat?.id && String(obj.chat.id) !== channel) continue;
|
|
121
|
+
if (channel && (obj.chat?.threadId ? String(obj.chat.threadId) : null) !== thread) continue;
|
|
105
122
|
if (typeof obj.text !== "string" || !obj.text.trim()) continue;
|
|
106
|
-
entries.
|
|
123
|
+
entries.unshift(obj);
|
|
107
124
|
} catch (e) {}
|
|
108
125
|
}
|
|
109
126
|
if (entries.length > 0 && entries[entries.length - 1].role === "user") entries.pop();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inetafrica/open-claudia",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.4",
|
|
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-upgrade-path.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-kazee-context-media.js && node test-kazee-typing-join.js && node test-kazee-inbound-dedup.js && node test-typing-phase-push.js && node test-socket-reconnect.js && node test-speech-loopback.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-call-speech.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 && node test-codex-rollout.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-transcript-room-scope.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-read-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-typing-heartbeat.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-stream-preview-purpose.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 && 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-attest.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-attest.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-bot-endpoint.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-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-cli-owner-gates.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-verify-contact.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-loopback-owner-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-watch-check-env.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-intro-adoption.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-grants.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-room-provider-settings.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-store-durability.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 && node test-codex-rollout.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-transcript-room-scope.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-read-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-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-kazee-threads.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-thread-lanes.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-thread-stop.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-typing-heartbeat.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-stream-preview-purpose.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-loopback-threads.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-transcript-threads.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 && 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-attest.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-attest.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-bot-endpoint.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-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-cli-owner-gates.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-verify-contact.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-loopback-owner-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-watch-check-env.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-intro-adoption.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-grants.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-room-provider-settings.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-store-durability.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"bot.js",
|
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
"test-approval-async.js",
|
|
63
63
|
"test-recall-evolution.js",
|
|
64
64
|
"test-unified-identity.js",
|
|
65
|
-
"test-queue-routing.js",
|
|
66
65
|
"test-persona-packs.js",
|
|
67
66
|
"test-speaker-persona.js",
|
|
68
67
|
"test-persona-pipeline.js",
|
|
@@ -88,6 +87,7 @@
|
|
|
88
87
|
"test-guardrail.js",
|
|
89
88
|
"test-delivery-contract.js",
|
|
90
89
|
"test-run-lock.js",
|
|
90
|
+
"test-thread-lanes.js",
|
|
91
91
|
"test-web-sessions.js",
|
|
92
92
|
"test-provider-fixture.js",
|
|
93
93
|
"test-provider-core-prompt.js",
|
package/test-approval-cards.js
CHANGED
|
@@ -216,6 +216,30 @@ const lastSend = () => sends[sends.length - 1]?.text || "";
|
|
|
216
216
|
assert.strictEqual(issued[0].principal.channelId, "user-lucy");
|
|
217
217
|
assert.strictEqual(issued[0].room, "kazee:ext-channel");
|
|
218
218
|
|
|
219
|
+
// ── chat threads: an approval raised in a thread turn re-runs in that thread ──
|
|
220
|
+
{
|
|
221
|
+
const ROOT = "66f0a1b2c3d4e5f600000001";
|
|
222
|
+
const { runInChat } = require("./core/context");
|
|
223
|
+
// Raised inside the thread turn (the enforcer's case): taken from the context.
|
|
224
|
+
const inThread = await runInChat({ channelId: "ext-channel", threadId: ROOT }, async () =>
|
|
225
|
+
approvals.create({ ...base, kind: "triage", inboundText: "Check invoice 7?" }));
|
|
226
|
+
assert.strictEqual(inThread.threadId, ROOT, "the origin thread is recorded");
|
|
227
|
+
// A turn in ANOTHER channel never lends its thread to the record.
|
|
228
|
+
const elsewhere = await runInChat({ channelId: "owner-chat", threadId: ROOT }, async () =>
|
|
229
|
+
approvals.create({ ...base, kind: "triage", inboundText: "x" }));
|
|
230
|
+
assert.strictEqual(elsewhere.threadId, null, "no thread when the origin is another channel");
|
|
231
|
+
assert.strictEqual(approvals.create({ ...base, kind: "triage", inboundText: "y" }).threadId, null, "main timeline: null");
|
|
232
|
+
const before = jobsAdded.length;
|
|
233
|
+
await handleAction(envelopeFor(`apr:${inThread.id}:ok`));
|
|
234
|
+
assert.strictEqual(jobsAdded.length, before + 1);
|
|
235
|
+
assert.strictEqual(jobsAdded.at(-1).threadId, ROOT, "the triage wake-up fires in the thread");
|
|
236
|
+
// External action approval (explicit threadId) re-runs in the thread too.
|
|
237
|
+
const act = approvals.create({ ...base, kind: "action", tier: "write", command: "open-claudia tool run kticket create", threadId: ROOT });
|
|
238
|
+
await handleAction(envelopeFor(`apr:${act.id}:ok`));
|
|
239
|
+
assert.strictEqual(jobsAdded.at(-1).threadId, ROOT, "the approval re-run fires in the thread");
|
|
240
|
+
assert.strictEqual(jobsAdded.at(-1).source, "approval");
|
|
241
|
+
}
|
|
242
|
+
|
|
219
243
|
// ── expired card: nothing to decide ──
|
|
220
244
|
await handleAction(envelopeFor("apr:apr_0000_dead:ok"));
|
|
221
245
|
assert.ok(/expired|cleaned up/.test(lastEdit()), "stale card gets a clear ack");
|
package/test-call-speech.js
CHANGED
|
@@ -206,11 +206,13 @@ if (process.env.OC_CALL_SPEECH_FIXTURE === "1") {
|
|
|
206
206
|
const f = fixture();
|
|
207
207
|
const state = { userId: "kazee:caller", currentSession: { name: "call-fixture", dir: process.env.WORKSPACE },
|
|
208
208
|
settings: { backend: "claude", model: "fixture-model", permissionMode: "default" },
|
|
209
|
-
providerSettings: { claude: { model: "fixture-model" } }, activeSessions: {}
|
|
209
|
+
providerSettings: { claude: { model: "fixture-model" } }, activeSessions: {} };
|
|
210
|
+
// The running process is recorded on the run's conversation lane.
|
|
211
|
+
const runningLane = () => [...(state.lanes?.values() || [])].find((lane) => lane.runningProcess) || null;
|
|
210
212
|
const spoken = [];
|
|
211
213
|
f.adapter.suppressStreamPreview = true; f.adapter.suppressChatVisibility = true;
|
|
212
214
|
f.adapter.speakSentence = async text => {
|
|
213
|
-
assert.ok(
|
|
215
|
+
assert.ok(runningLane(), "sentence is spoken before provider completion");
|
|
214
216
|
spoken.push(text); return true;
|
|
215
217
|
};
|
|
216
218
|
f.adapter.send = async (_channel, text) => {
|
|
@@ -224,7 +226,7 @@ if (process.env.OC_CALL_SPEECH_FIXTURE === "1") {
|
|
|
224
226
|
assert.deepStrictEqual(spoken, ["The first result is ready.", "The second result is ready."]);
|
|
225
227
|
const token = lastLease.token;
|
|
226
228
|
assert.strictEqual((await post(info, { ...f.payload, callSpeechToken: token, originRunId: result.runId })).status, 409);
|
|
227
|
-
assert.strictEqual(
|
|
229
|
+
assert.strictEqual(runningLane(), null);
|
|
228
230
|
const capturedService = createForegroundService({ state, store: f.store, stopTyping() {}, capture: true, ownsAdmissionLock: false, persistCapture: false });
|
|
229
231
|
const captured = await context.runInChat(f.store, () => capturedService.runAgentCapture("Capture only.", process.env.WORKSPACE));
|
|
230
232
|
assert.strictEqual(captured.ok, true, JSON.stringify(captured.error));
|
|
@@ -226,7 +226,10 @@ function inferSessionId() {
|
|
|
226
226
|
if (process.env.FAKE_AGENT_SESSION_ID) return process.env.FAKE_AGENT_SESSION_ID;
|
|
227
227
|
if (kind === "claude") {
|
|
228
228
|
const resumeAt = argv.indexOf("--resume");
|
|
229
|
+
// --fork-session resumes into a NEW session, as Claude Code does.
|
|
230
|
+
if (resumeAt >= 0 && argv[resumeAt + 1] && argv.includes("--fork-session")) return `${argv[resumeAt + 1]}-fork-${process.pid}`;
|
|
229
231
|
if (resumeAt >= 0 && argv[resumeAt + 1]) return argv[resumeAt + 1];
|
|
232
|
+
if (boolControl("FAKE_AGENT_UNIQUE_SESSIONS")) return `claude-fresh-session-${process.pid}`;
|
|
230
233
|
if (argv.includes("--continue")) return "claude-continued-session";
|
|
231
234
|
return "claude-fresh-session";
|
|
232
235
|
}
|
|
@@ -421,7 +424,7 @@ async function emitEvents(events) {
|
|
|
421
424
|
line + (index < lines.length - 1 || finalNewline ? ending : "")
|
|
422
425
|
));
|
|
423
426
|
const mode = process.env.FAKE_AGENT_CHUNK_MODE || "lines";
|
|
424
|
-
const delayMs = integerControl("FAKE_AGENT_CHUNK_DELAY_MS", 0);
|
|
427
|
+
const delayMs = chunkDelayOverride ?? integerControl("FAKE_AGENT_CHUNK_DELAY_MS", 0);
|
|
425
428
|
|
|
426
429
|
if (mode === "coalesce") {
|
|
427
430
|
const payload = framed.join("");
|
|
@@ -469,6 +472,48 @@ async function emitEvents(events) {
|
|
|
469
472
|
}
|
|
470
473
|
}
|
|
471
474
|
|
|
475
|
+
// Concurrency probes. FAKE_AGENT_DELAY_MS holds the run before it answers; a
|
|
476
|
+
// prompt containing [[delay:<ms>]] overrides it for that run only, and
|
|
477
|
+
// [[chunkdelay:<ms>]] overrides FAKE_AGENT_CHUNK_DELAY_MS (the pause between
|
|
478
|
+
// streamed events) for that run.
|
|
479
|
+
// FAKE_AGENT_RUN_LOG appends one JSON line when the run starts and one when it
|
|
480
|
+
// answers ({event, at, pid, project, threadId, runId, tag, fork, resume,
|
|
481
|
+
// sessionEnv, lastSessionEnv}), where tag
|
|
482
|
+
// comes from a [[tag:<word>]] marker in the prompt, so a test can prove which
|
|
483
|
+
// runs overlapped and where each one belonged.
|
|
484
|
+
let chunkDelayOverride = null;
|
|
485
|
+
function promptChunkDelay(stdin) {
|
|
486
|
+
const match = /\[\[chunkdelay:(\d{1,5})\]\]/.exec(String(stdin || ""));
|
|
487
|
+
return match ? Math.min(60000, Number(match[1])) : null;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function runDelayMs(stdin) {
|
|
491
|
+
const match = /\[\[delay:(\d{1,5})\]\]/.exec(String(stdin || ""));
|
|
492
|
+
if (match) return Math.min(60000, Number(match[1]));
|
|
493
|
+
return integerControl("FAKE_AGENT_DELAY_MS", 0);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function logRun(event, stdin) {
|
|
497
|
+
const logPath = process.env.FAKE_AGENT_RUN_LOG;
|
|
498
|
+
if (!logPath) return;
|
|
499
|
+
const tag = /\[\[tag:([\w-]{1,40})\]\]/.exec(String(stdin || ""));
|
|
500
|
+
const record = {
|
|
501
|
+
event,
|
|
502
|
+
at: Date.now(),
|
|
503
|
+
pid: process.pid,
|
|
504
|
+
project: process.env.OC_PROJECT || null,
|
|
505
|
+
threadId: process.env.OC_THREAD_ID || null,
|
|
506
|
+
runId: process.env.OC_RUN_ID || null,
|
|
507
|
+
tag: tag ? tag[1] : null,
|
|
508
|
+
fork: argv.includes("--fork-session"),
|
|
509
|
+
resume: argv.indexOf("--resume") >= 0 ? argv[argv.indexOf("--resume") + 1] || null : null,
|
|
510
|
+
sessionEnv: process.env.OC_SESSION_ID || null,
|
|
511
|
+
lastSessionEnv: process.env.OC_LAST_SESSION_ID || null,
|
|
512
|
+
};
|
|
513
|
+
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
514
|
+
fs.appendFileSync(logPath, `${JSON.stringify(record)}\n`);
|
|
515
|
+
}
|
|
516
|
+
|
|
472
517
|
function installSignalControls() {
|
|
473
518
|
const signalCapture = process.env.FAKE_AGENT_SIGNAL_CAPTURE;
|
|
474
519
|
const onSignal = (signal) => {
|
|
@@ -502,9 +547,15 @@ async function main() {
|
|
|
502
547
|
return;
|
|
503
548
|
}
|
|
504
549
|
|
|
550
|
+
// The foreground prompt rides argv, utility prompts ride stdin.
|
|
551
|
+
const promptText = `${argv.join(" ")}\n${stdin}`;
|
|
552
|
+
chunkDelayOverride = promptChunkDelay(promptText);
|
|
553
|
+
logRun("start", promptText);
|
|
554
|
+
await sleep(runDelayMs(promptText));
|
|
505
555
|
const sessionId = inferSessionId();
|
|
506
556
|
const events = kind === "claude" ? claudeEvents(sessionId) : codexEvents(sessionId);
|
|
507
557
|
await emitEvents(events);
|
|
558
|
+
logRun("end", promptText);
|
|
508
559
|
|
|
509
560
|
if (scenario === "auth-failure") {
|
|
510
561
|
process.stderr.write(`${kind} authentication failed\n`);
|
|
@@ -26,6 +26,9 @@ const stateApi = require("./core/state");
|
|
|
26
26
|
const runner = require("./core/runner");
|
|
27
27
|
|
|
28
28
|
const state = stateApi.currentState();
|
|
29
|
+
// Compaction runs in ONE conversation lane: outside a chat turn that is the
|
|
30
|
+
// state's project ("alpha" here).
|
|
31
|
+
const alphaLane = () => stateApi.laneFor(state, "alpha");
|
|
29
32
|
|
|
30
33
|
function result(overrides = {}) {
|
|
31
34
|
return {
|
|
@@ -58,9 +61,7 @@ function resetFixture(provider = "claude") {
|
|
|
58
61
|
state.pendingCompaction = null;
|
|
59
62
|
state.completedCompactions = {};
|
|
60
63
|
state.lastCompactedAt = 0;
|
|
61
|
-
state.
|
|
62
|
-
state.runningProcess = null;
|
|
63
|
-
state.preparingRun = false;
|
|
64
|
+
state.lanes?.clear();
|
|
64
65
|
state.isFirstMessage = false;
|
|
65
66
|
stateApi.replaceProjectSessions(state.userId, "alpha", [
|
|
66
67
|
{
|
|
@@ -92,9 +93,9 @@ function serviceWith(runCapture, extra = {}) {
|
|
|
92
93
|
|
|
93
94
|
async function immutableSuccessProbe() {
|
|
94
95
|
resetFixture("claude");
|
|
95
|
-
|
|
96
|
+
alphaLane().isCompacting = true;
|
|
96
97
|
assert.strictEqual(stateApi.acquireRunLock(state), false, "foreground admission stays closed between compaction stages");
|
|
97
|
-
|
|
98
|
+
alphaLane().isCompacting = false;
|
|
98
99
|
const contexts = [];
|
|
99
100
|
const service = serviceWith(async (_prompt, _cwd, options) => {
|
|
100
101
|
assert.strictEqual(options.persist, false, "compaction provider stages have no ordinary capture persistence");
|
|
@@ -152,17 +153,17 @@ async function immutableSuccessProbe() {
|
|
|
152
153
|
const usage = stateApi.getUsageForSession(state, "alpha", "claude", "new-claude");
|
|
153
154
|
assert.strictEqual(usage.turns, 0, "seed is not billed as a user turn");
|
|
154
155
|
assert.strictEqual(usage.compactionCheckpoint.previousSessionId, "old-claude");
|
|
155
|
-
assert.strictEqual(
|
|
156
|
+
assert.strictEqual(alphaLane().isCompacting, false);
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
async function failureProbe() {
|
|
159
160
|
resetFixture("claude");
|
|
160
|
-
|
|
161
|
+
alphaLane().runningProcess = { pid: 123 };
|
|
161
162
|
let busyCalls = 0;
|
|
162
163
|
const busy = await serviceWith(async () => { busyCalls += 1; return result(); }).compact(alphaDir);
|
|
163
164
|
assert.strictEqual(busy.compacted, false);
|
|
164
165
|
assert.strictEqual(busyCalls, 0, "manual compaction never overlaps an active provider run");
|
|
165
|
-
|
|
166
|
+
alphaLane().runningProcess = null;
|
|
166
167
|
|
|
167
168
|
resetFixture("claude");
|
|
168
169
|
let summaryCalls = 0;
|
|
@@ -354,15 +355,15 @@ async function deferredWatchAcrossCompactionProbe() {
|
|
|
354
355
|
},
|
|
355
356
|
});
|
|
356
357
|
|
|
357
|
-
|
|
358
|
+
alphaLane().runningProcess = { pid: 4242 };
|
|
358
359
|
assert.strictEqual((await scheduler.fireJob("watch-long-turn")).deferred, true, "a watch that passes mid-turn is queued");
|
|
359
360
|
for (let i = 0; i < 3; i++) await timers.at(-1).fn();
|
|
360
|
-
|
|
361
|
+
alphaLane().runningProcess = null;
|
|
361
362
|
let calls = 0;
|
|
362
363
|
const compaction = serviceWith(async () => {
|
|
363
364
|
calls += 1;
|
|
364
365
|
if (calls === 1) {
|
|
365
|
-
assert.strictEqual(
|
|
366
|
+
assert.strictEqual(alphaLane().isCompacting, true);
|
|
366
367
|
assert.strictEqual((await timers.at(-1).fn()).deferred, true, "the delivery waits out the compaction");
|
|
367
368
|
return result({ sessionId: "old-claude" });
|
|
368
369
|
}
|
|
@@ -381,6 +382,43 @@ async function deferredWatchAcrossCompactionProbe() {
|
|
|
381
382
|
}
|
|
382
383
|
}
|
|
383
384
|
|
|
385
|
+
// Compaction is per conversation: compacting one lane keeps only THAT lane
|
|
386
|
+
// closed, and the recent turns it seeds from come from that conversation's
|
|
387
|
+
// transcript — not the state's legacy "Workspace" session.
|
|
388
|
+
async function perLaneProbe() {
|
|
389
|
+
resetFixture("claude");
|
|
390
|
+
const { runInChat } = require("./core/context");
|
|
391
|
+
const convo = "telegram:fixture";
|
|
392
|
+
const thread = "telegram:fixture#thread:eeeeeeeeeeeeeeeeeeeeeeee";
|
|
393
|
+
state.currentSession = stateApi.rootSession();
|
|
394
|
+
stateApi.setProviderSession(state, "claude", convo, "old-claude");
|
|
395
|
+
const views = [];
|
|
396
|
+
let lanesDuringCompaction = null;
|
|
397
|
+
const service = serviceWith(async () => {
|
|
398
|
+
if (!lanesDuringCompaction) {
|
|
399
|
+
lanesDuringCompaction = {
|
|
400
|
+
own: stateApi.acquireRunLock(state, convo),
|
|
401
|
+
thread: stateApi.acquireRunLock(state, thread),
|
|
402
|
+
compacting: stateApi.laneFor(state, convo).isCompacting,
|
|
403
|
+
};
|
|
404
|
+
stateApi.laneFor(state, thread).preparingRun = false;
|
|
405
|
+
return result({ sessionId: "old-claude" });
|
|
406
|
+
}
|
|
407
|
+
return result({ sessionId: "lane-new-claude" });
|
|
408
|
+
}, { collectRecentTurns: (view) => { views.push(view); return null; } });
|
|
409
|
+
const compacted = await runInChat({ channelId: "fixture", conversationKey: convo, roomKey: convo, canonicalUserId: state.userId },
|
|
410
|
+
() => service.compact(workspace, { operationId: "compact-lane" }));
|
|
411
|
+
assert.strictEqual(compacted.compacted, true, compacted.reason);
|
|
412
|
+
assert.deepStrictEqual(lanesDuringCompaction, { own: false, thread: true, compacting: true },
|
|
413
|
+
"only the compacting conversation is closed; a thread of the same chat can start");
|
|
414
|
+
assert.strictEqual(stateApi.laneFor(state, convo).isCompacting, false);
|
|
415
|
+
assert.strictEqual(views.length, 1);
|
|
416
|
+
assert.strictEqual(views[0].currentSession.name, convo, "recent turns are read from the conversation's own transcript");
|
|
417
|
+
assert.strictEqual(stateApi.getProviderSession(state, "claude", convo), "lane-new-claude");
|
|
418
|
+
assert.strictEqual(runner.shouldAutoCompact(state, { laneKey: thread }), false, "a thread with no session never auto-compacts");
|
|
419
|
+
state.lanes.clear();
|
|
420
|
+
}
|
|
421
|
+
|
|
384
422
|
function duplicateCommitProbe() {
|
|
385
423
|
resetFixture("claude");
|
|
386
424
|
const transaction = {
|
|
@@ -457,6 +495,7 @@ function restartRecoveryProbe() {
|
|
|
457
495
|
await failureProbe();
|
|
458
496
|
await codexRestrictionProbe();
|
|
459
497
|
await deferredWatchAcrossCompactionProbe();
|
|
498
|
+
await perLaneProbe();
|
|
460
499
|
duplicateCommitProbe();
|
|
461
500
|
restartRecoveryProbe();
|
|
462
501
|
console.log("provider compaction OK");
|
package/test-provider-gateway.js
CHANGED
|
@@ -37,13 +37,12 @@ async function routerProbe() {
|
|
|
37
37
|
claude: { model: "claude-fixture" },
|
|
38
38
|
codex: { model: "codex-fixture" },
|
|
39
39
|
},
|
|
40
|
-
messageQueue: [],
|
|
41
40
|
pendingCodexAuthProcess: null,
|
|
42
41
|
pendingClaudeAuthProcess: null,
|
|
43
42
|
pendingVaultUnlock: false,
|
|
44
43
|
onboardingStep: null,
|
|
45
|
-
lastInputWasVoice: false,
|
|
46
44
|
};
|
|
45
|
+
const lane = { messageQueue: [], lastInputWasVoice: false, pendingVoiceClone: null };
|
|
47
46
|
const admissions = [];
|
|
48
47
|
const runs = [];
|
|
49
48
|
const sends = [];
|
|
@@ -55,6 +54,10 @@ async function routerProbe() {
|
|
|
55
54
|
autoLinkOwnerChannel: () => null,
|
|
56
55
|
getActiveProvider: (s) => (s || state).settings?.backend || null,
|
|
57
56
|
getProjectKey: (s) => (s || state).currentSession?.name || "",
|
|
57
|
+
laneFor: () => lane,
|
|
58
|
+
peekLane: () => lane,
|
|
59
|
+
laneBusy: (l) => !!(l && (l.runningProcess || l.preparingRun)),
|
|
60
|
+
slotBlocker: () => null,
|
|
58
61
|
});
|
|
59
62
|
// The up-front triage gate is pinned in test-enforcer.js; here it must only
|
|
60
63
|
// be CONSULTED with the routed text + provider/project pinning, then let the
|
|
@@ -327,12 +330,16 @@ async function schedulerProbe() {
|
|
|
327
330
|
getProviderSession: (_state, provider, project) => (
|
|
328
331
|
state.activeSessions?.[project]?.[provider] || null
|
|
329
332
|
),
|
|
333
|
+
peekLane: () => null,
|
|
334
|
+
laneBusy: () => false,
|
|
335
|
+
slotBlocker: () => null,
|
|
330
336
|
userStates: new Map(),
|
|
331
337
|
});
|
|
332
338
|
installStub("./core/identity", {
|
|
333
339
|
canonicalForTelegram: () => "fixture-user",
|
|
334
340
|
canonicalForChannel: () => "fixture-user",
|
|
335
341
|
conversationKeyFor: (transport, channelId) => `${transport}:${channelId}`,
|
|
342
|
+
parseConversationKey: (key) => ({ threadId: null, roomKey: String(key || "") }),
|
|
336
343
|
});
|
|
337
344
|
installStub("./core/io", {
|
|
338
345
|
send: async () => {
|
|
@@ -420,10 +427,15 @@ async function queueProbe() {
|
|
|
420
427
|
claude: { model: "claude-fixture", effort: "high" },
|
|
421
428
|
codex: { model: "codex-fixture", effort: "low" },
|
|
422
429
|
},
|
|
430
|
+
};
|
|
431
|
+
// The conversation's lane is busy preparing a turn, so new work queues in it.
|
|
432
|
+
const lane = {
|
|
433
|
+
key: "project-a",
|
|
423
434
|
messageQueue: [],
|
|
424
435
|
preparingRun: true,
|
|
425
436
|
runningProcess: null,
|
|
426
437
|
isCompacting: false,
|
|
438
|
+
activeRunContext: null,
|
|
427
439
|
lastInputWasVoice: false,
|
|
428
440
|
};
|
|
429
441
|
const store = Object.freeze({
|
|
@@ -441,7 +453,15 @@ async function queueProbe() {
|
|
|
441
453
|
recordSession: () => {},
|
|
442
454
|
userOwnsProviderSession: () => false,
|
|
443
455
|
resetSessionUsage: () => {},
|
|
444
|
-
|
|
456
|
+
admitLane: () => ({ ok: false, reason: "busy", lane }),
|
|
457
|
+
laneFor: () => lane,
|
|
458
|
+
laneForRun: () => lane,
|
|
459
|
+
peekLane: () => lane,
|
|
460
|
+
laneBusy: () => true,
|
|
461
|
+
runLaneKey: (runContext) => runContext?.laneKey || runContext?.project?.name || null,
|
|
462
|
+
waitingLanes: () => [],
|
|
463
|
+
slotBlocker: () => null,
|
|
464
|
+
pruneIdleLanes: () => {},
|
|
445
465
|
});
|
|
446
466
|
installStub("./core/context", {
|
|
447
467
|
chatContext: { getStore: () => store, run: (_store, fn) => fn() },
|
|
@@ -449,6 +469,7 @@ async function queueProbe() {
|
|
|
449
469
|
currentAdapter: () => store.adapter,
|
|
450
470
|
currentUserId: () => store.userId,
|
|
451
471
|
currentConversationKey: () => store.conversationKey || null,
|
|
472
|
+
currentThreadId: () => null,
|
|
452
473
|
});
|
|
453
474
|
installStub("./core/io", {
|
|
454
475
|
send: async () => ({ ok: true, messageId: "queued", editable: true }),
|
|
@@ -462,8 +483,8 @@ async function queueProbe() {
|
|
|
462
483
|
const { runAgent } = require("./core/runner");
|
|
463
484
|
const pending = runAgent("queued prompt", projectA, "message-queued", { runId: "queued-run" });
|
|
464
485
|
assert.strictEqual(typeof pending.then, "function");
|
|
465
|
-
assert.strictEqual(
|
|
466
|
-
const queued =
|
|
486
|
+
assert.strictEqual(lane.messageQueue.length, 1);
|
|
487
|
+
const queued = lane.messageQueue[0];
|
|
467
488
|
assert.ok(Object.isFrozen(queued.runContext));
|
|
468
489
|
assert.ok(Object.isFrozen(queued.runContext.project));
|
|
469
490
|
assert.ok(Object.isFrozen(queued.runContext.providerSettings));
|
|
@@ -483,14 +504,14 @@ async function queueProbe() {
|
|
|
483
504
|
store.adapter.liveCall = true;
|
|
484
505
|
store.adapter.callTurn = { signal: obsoleteCall.signal };
|
|
485
506
|
const callPending = runAgent("obsolete call question", projectA, null, { runId: "obsolete-call" });
|
|
486
|
-
assert.strictEqual(
|
|
507
|
+
assert.strictEqual(lane.messageQueue.length, 2);
|
|
487
508
|
obsoleteCall.abort();
|
|
488
|
-
assert.strictEqual(
|
|
509
|
+
assert.strictEqual(lane.messageQueue.length, 1, "superseded call entry is removed immediately, ordinary queued work is preserved");
|
|
489
510
|
assert.strictEqual((await callPending).status, "cancelled");
|
|
490
|
-
assert.strictEqual(
|
|
511
|
+
assert.strictEqual(lane.messageQueue[0], queued);
|
|
491
512
|
const alreadyEnded = await runAgent("late call dispatch", projectA, null, { runId: "late-call" });
|
|
492
513
|
assert.strictEqual(alreadyEnded.status, "cancelled");
|
|
493
|
-
assert.strictEqual(
|
|
514
|
+
assert.strictEqual(lane.messageQueue.length, 1, "an already-ended call never joins the queue");
|
|
494
515
|
delete store.adapter.callTurn;
|
|
495
516
|
delete store.adapter.liveCall;
|
|
496
517
|
console.log("provider gateway immutable queue OK");
|
|
@@ -521,7 +542,7 @@ function staticChecks() {
|
|
|
521
542
|
}
|
|
522
543
|
assert.match(source["core/router.js"], /\badmitRunContext\b/, "media/text ingress captures before preparation awaits");
|
|
523
544
|
assert.match(source["core/scheduler.js"], /result\.ok/, "scheduler consumes terminal RunResult success");
|
|
524
|
-
assert.match(source["core/runner.js"], /
|
|
545
|
+
assert.match(source["core/runner.js"], /queueInLane\(lane, \{ runContext,/, "queued work stores its immutable run context in its lane");
|
|
525
546
|
assert.match(source["core/runner.js"], /executeAdmittedRun\(item\.runContext,/, "queue drain executes the admitted context");
|
|
526
547
|
assert.match(source["bin/cli.js"], /Open Claudia agent task/);
|
|
527
548
|
assert.ok(!source["bin/cli.js"].includes("inside a running Claude task"));
|
|
@@ -519,7 +519,16 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
|
|
|
519
519
|
// own bot (ancestor listener, not started in a staff turn); staff watch checks
|
|
520
520
|
// get an allowlist env and owner checks the bot's env again; a partial chat
|
|
521
521
|
// origin is a non-owner; wider staff shell screen, documented as no boundary.
|
|
522
|
-
|
|
522
|
+
// 3.5.4 approved by Sumeet 2026-09-29 12:22 EAT ("work through end to end till I
|
|
523
|
+
// can test multiple threads with you on mobile and web"): a Kazee thread is its
|
|
524
|
+
// own conversation, running beside the main chat and other threads (4 per
|
|
525
|
+
// person, 8 in all); replies, files, voice, typing, jobs and approvals stay in
|
|
526
|
+
// their thread; /stop per conversation and /stop all, and /stop drops the
|
|
527
|
+
// messages queued before it (his 26 Sep ask); a new thread also sees the main
|
|
528
|
+
// chat just before it; plus the independent review's fixes. Canary channel
|
|
529
|
+
// only (npm next). 3.5.2 failed this pin and 3.5.3 was cancelled: neither
|
|
530
|
+
// was published.
|
|
531
|
+
assert.strictEqual(pkg.version, "3.5.4", "release version must remain unchanged without explicit approval");
|
|
523
532
|
for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
|
|
524
533
|
assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
|
|
525
534
|
}
|