@inetafrica/open-claudia 3.5.77 → 3.5.79
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 +17 -0
- package/core/limit-pickup.js +69 -5
- package/core/runner.js +42 -1
- package/core/scheduler.js +53 -4
- package/package.json +2 -2
- package/test-provider-language.js +7 -1
- package/test-provider-scheduler.js +60 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.5.79
|
|
4
|
+
|
|
5
|
+
3.5.78 plus one change (Sumeet 13 Nov 13:17 EAT, during Anthropic's Claude Code sign-in incident that began 09:58 UTC: "set up wake ups to keep retrying").
|
|
6
|
+
|
|
7
|
+
- **A reply refused as signed out keeps trying** (`core/limit-pickup.js`, `core/runner.js`): when Claude Code is still signed out after the 25 s of re-checks, the message is not dropped. The bot posts one line ("Claude Code can't sign in right now. I'll try your message again every minute for up to 30 minutes. If you write to me before then, I'll answer that instead."), then tries the original message again every minute without posting each failure, answers as soon as sign-in is back, and stops with one line after 30 tries. It uses the usage-limit pick-up store, so a restart keeps it, and writing again, /stop, /new or /end drops it. `SIGNIN_PICKUP_MS` changes the gap; `LIMIT_PICKUP=off` turns both pick-ups off.
|
|
8
|
+
|
|
9
|
+
Tests: `test-signin-pickup.js` (new, in the suite; fails without the change).
|
|
10
|
+
|
|
11
|
+
## 3.5.78
|
|
12
|
+
|
|
13
|
+
3.5.77 plus one fix (Sumeet 13 Nov 12:57 EAT: "fix this in the bot", after a short internet drop on the Mac lost replies).
|
|
14
|
+
|
|
15
|
+
- **A short drop no longer refuses replies** (`core/runner.js`): before a run, the bot asks Claude Code whether it is signed in. On 13 Nov the Mac's line kept dropping for about four minutes, one "signed out" answer refused about 21 replies on the spot ("Claude Code authentication failed"), and the sign-in was fine once the line came back. Now a "signed out" answer is checked again after 5, 10 and 10 seconds (about 25 s in all); the reply is refused only if every check says signed out. A live call is never held, and /stop during the wait ends the run quietly. `AUTH_RECHECK_MS` (comma-separated waits in ms) changes the waits; an empty list restores the old single check.
|
|
16
|
+
- **Scheduled jobs wait out a signed-out provider** (`core/scheduler.js`): a wake-up, cron or watch whose provider says signed out (or whose run was refused as signed out) now waits a minute and tries again, up to 30 times, without counting a failed try. Before, it spent its 5 tries 30 s apart and gave up (`SCHEDULED_PROVIDER_UNAVAILABLE`), which is how a wake-up died during the same drop. It gives up, with the usual notice, only if sign-in is still down after half an hour.
|
|
17
|
+
|
|
18
|
+
Tests: `test-auth-recheck.js` (new, in the suite) and a sign-in wait probe in `test-provider-scheduler.js`; both fail without the fix.
|
|
19
|
+
|
|
3
20
|
## 3.5.77
|
|
4
21
|
|
|
5
22
|
3.5.76 plus two pieces first run on the Mac build (Sumeet 12 Nov, card 6af54622: one test bot first, then the rest on his word).
|
package/core/limit-pickup.js
CHANGED
|
@@ -29,6 +29,15 @@ const limits = require("./usage-limits");
|
|
|
29
29
|
|
|
30
30
|
const FILE = () => process.env.OC_LIMIT_PICKUPS_FILE || path.join(CONFIG_DIR, "limit-pickups.json");
|
|
31
31
|
const MAX_ATTEMPTS = 5;
|
|
32
|
+
// A reply refused because the provider is signed out (Claude Code's sign-in
|
|
33
|
+
// down: 13 Nov 2026 Anthropic's sign-in incident and a dropping line) is tried
|
|
34
|
+
// again every SIGNIN_PICKUP_MS, quietly, up to SIGNIN_MAX_ATTEMPTS times
|
|
35
|
+
// (Sumeet 13 Nov 13:17 EAT: "set up wake ups to keep retrying").
|
|
36
|
+
const SIGNIN_MAX_ATTEMPTS = 30;
|
|
37
|
+
const signinRetryMs = () => {
|
|
38
|
+
const n = Number(setting("SIGNIN_PICKUP_MS"));
|
|
39
|
+
return Number.isFinite(n) && n > 0 ? n : 60 * 1000;
|
|
40
|
+
};
|
|
32
41
|
// setTimeout's ceiling is ~24.8 days; a plan window is a week at most.
|
|
33
42
|
const MAX_TIMER_MS = 2 ** 31 - 1;
|
|
34
43
|
const BOOT_GRACE_MS = 60000;
|
|
@@ -96,6 +105,8 @@ function limitName(provider, limitType) {
|
|
|
96
105
|
|
|
97
106
|
const PICKUP_PROMPT = (hitAt, provider, original) => `Your ${limits.providerLabel(provider)} usage limit stopped this turn at ${hitAt}. The limit has reset, so pick it up now. The message was: ${original}\n\nCheck what you already did (your history, git, files, tool state, the chat) before acting; never repeat a send, push, deploy or write that already happened; then finish.`;
|
|
98
107
|
|
|
108
|
+
const SIGNIN_PICKUP_PROMPT = (hitAt, original) => `This message came in at ${hitAt}, when the bot could not sign in to answer it. It is signed in again, so answer it now. The message was: ${original}\n\nCheck what you already did (your history, git, files, tool state, the chat) before acting; never repeat a send, push, deploy or write that already happened; then finish.`;
|
|
109
|
+
|
|
99
110
|
/**
|
|
100
111
|
* What a turn stopped by a limit should do: arm a pick-up (armable), wait in
|
|
101
112
|
* the scheduler (waits: a scheduled run), or only say when the limit lifts.
|
|
@@ -111,7 +122,7 @@ function planFor(result, runContext, { now = Date.now(), windows = [], guarded =
|
|
|
111
122
|
const name = guarded ? "My usage limit" : limitName(hit.provider, hit.limitType);
|
|
112
123
|
const runAt = limits.limitRetryAt(hit.resetsAt, { now });
|
|
113
124
|
const known = runAt !== null;
|
|
114
|
-
const pickup = runContext?.limitPickup || null;
|
|
125
|
+
const pickup = runContext?.limitPickup?.kind === "signin" ? null : (runContext?.limitPickup || null);
|
|
115
126
|
const attempts = (pickup?.attempts || 0) + 1;
|
|
116
127
|
const waitable = known && limits.canWaitFor(runAt, { now }) && attempts <= MAX_ATTEMPTS;
|
|
117
128
|
// A scheduled run waits in the jobs store for the reset (core/scheduler.js).
|
|
@@ -148,6 +159,43 @@ function planFor(result, runContext, { now = Date.now(), windows = [], guarded =
|
|
|
148
159
|
return { hit, armable, waits, runAt, attempts, notice };
|
|
149
160
|
}
|
|
150
161
|
|
|
162
|
+
/**
|
|
163
|
+
* A foreground reply refused as signed out: try it again in a minute, quietly,
|
|
164
|
+
* up to SIGNIN_MAX_ATTEMPTS times. `notice` is posted (first refusal, or the
|
|
165
|
+
* last one); `quiet` means a retry that is still signed out posts nothing.
|
|
166
|
+
*/
|
|
167
|
+
function signinPlanFor(result, runContext, { now = Date.now() } = {}) {
|
|
168
|
+
if (result?.ok || result?.error?.code !== "PROVIDER_UNAUTHENTICATED") return null;
|
|
169
|
+
if (runContext?.purpose !== "foreground") return null;
|
|
170
|
+
const provider = runContext?.provider || result?.provider || "claude";
|
|
171
|
+
const prior = runContext?.limitPickup?.kind === "signin" ? runContext.limitPickup : null;
|
|
172
|
+
const attempts = (prior?.attempts || 0) + 1;
|
|
173
|
+
const runAt = now + signinRetryMs();
|
|
174
|
+
const armable = enabled()
|
|
175
|
+
&& attempts <= SIGNIN_MAX_ATTEMPTS
|
|
176
|
+
&& !runContext?.passive
|
|
177
|
+
&& !runContext?.liveCall
|
|
178
|
+
&& !!runContext?.origin?.adapterId
|
|
179
|
+
&& !!runContext?.channelId;
|
|
180
|
+
const label = limits.providerLabel(provider) === "Claude" ? "Claude Code" : limits.providerLabel(provider);
|
|
181
|
+
let notice = null;
|
|
182
|
+
if (armable && !prior) {
|
|
183
|
+
notice = `⏳ ${label} can't sign in right now. I'll try your message again every minute for up to ${SIGNIN_MAX_ATTEMPTS} minutes. If you write to me before then, I'll answer that instead.`;
|
|
184
|
+
} else if (!armable && prior) {
|
|
185
|
+
notice = `⏳ ${label} still can't sign in after ${SIGNIN_MAX_ATTEMPTS} tries. Send your message again once it's back.`;
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
kind: "signin",
|
|
189
|
+
hit: { provider, limitType: null, resetsAt: runAt },
|
|
190
|
+
armable,
|
|
191
|
+
waits: false,
|
|
192
|
+
runAt,
|
|
193
|
+
attempts,
|
|
194
|
+
notice,
|
|
195
|
+
quiet: armable && !!prior,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
151
199
|
// ── arm / cancel ────────────────────────────────────────────────────────
|
|
152
200
|
|
|
153
201
|
const timers = new Map(); // keyFor(person, conversation) -> timeout
|
|
@@ -172,6 +220,7 @@ function arm(runContext, plan, { now = Date.now() } = {}) {
|
|
|
172
220
|
replyToMsgId: runContext.replyToMsgId || null,
|
|
173
221
|
project: runContext.project ? { name: runContext.project.name || null, dir: runContext.project.dir || null } : null,
|
|
174
222
|
},
|
|
223
|
+
kind: plan.kind || "limit",
|
|
175
224
|
provider: plan.hit.provider,
|
|
176
225
|
limitType: plan.hit.limitType || null,
|
|
177
226
|
resetsAt: plan.hit.resetsAt,
|
|
@@ -184,7 +233,8 @@ function arm(runContext, plan, { now = Date.now() } = {}) {
|
|
|
184
233
|
update((pickups) => { pickups[key] = record; });
|
|
185
234
|
index().add(key);
|
|
186
235
|
schedule(key, record, now);
|
|
187
|
-
console.log(`[limit-pickup] armed ${key}: ${record.provider}
|
|
236
|
+
if (record.kind === "signin") console.log(`[limit-pickup] armed ${key}: ${record.provider} signed out, tries again ${new Date(record.runAt).toISOString()} (attempt ${record.attempts} of ${SIGNIN_MAX_ATTEMPTS})`);
|
|
237
|
+
else console.log(`[limit-pickup] armed ${key}: ${record.provider} ${record.limitType || "limit"} resets ${new Date(record.resetsAt).toISOString()}, runs ${new Date(record.runAt).toISOString()} (attempt ${record.attempts})`);
|
|
188
238
|
return record;
|
|
189
239
|
}
|
|
190
240
|
|
|
@@ -271,6 +321,15 @@ async function fire(key, id) {
|
|
|
271
321
|
}
|
|
272
322
|
const scope = deps.chatScope(record.conversation, adapter, deps);
|
|
273
323
|
const hitAt = limits.formatResetTime(record.firstHitAt, { now: deps.now() });
|
|
324
|
+
if (record.kind === "signin") {
|
|
325
|
+
// Quiet: a retry that is still signed out posts nothing and arms the next.
|
|
326
|
+
return deps.runInChat(scope, async () => deps.runAgent(SIGNIN_PICKUP_PROMPT(hitAt, record.turn.prompt), record.turn.project?.dir || null, record.turn.replyToMsgId, {
|
|
327
|
+
purpose: "foreground",
|
|
328
|
+
imagePaths: record.turn.imagePaths || [],
|
|
329
|
+
attachments: record.turn.attachments || [],
|
|
330
|
+
limitPickup: { kind: "signin", originalPrompt: record.turn.prompt, firstHitAt: record.firstHitAt, attempts: record.attempts, limitType: null },
|
|
331
|
+
}));
|
|
332
|
+
}
|
|
274
333
|
return deps.runInChat(scope, async () => {
|
|
275
334
|
// An outside contact is not told which model or plan the bot runs on.
|
|
276
335
|
const which = deps.isGuarded() ? "my usage limit" : limitName(record.provider, record.limitType);
|
|
@@ -302,6 +361,11 @@ function start(adapters, overrides = {}) {
|
|
|
302
361
|
return out;
|
|
303
362
|
}
|
|
304
363
|
|
|
364
|
+
function _setAttemptsForTests(canonicalUserId, laneKey, attempts) {
|
|
365
|
+
const key = keyFor(canonicalUserId, laneKey);
|
|
366
|
+
update((pickups) => { if (pickups[key]) pickups[key].attempts = attempts; });
|
|
367
|
+
}
|
|
368
|
+
|
|
305
369
|
function _resetForTests() {
|
|
306
370
|
for (const timer of timers.values()) clearTimeout(timer);
|
|
307
371
|
timers.clear();
|
|
@@ -310,8 +374,8 @@ function _resetForTests() {
|
|
|
310
374
|
}
|
|
311
375
|
|
|
312
376
|
module.exports = {
|
|
313
|
-
PICKUP_PROMPT, MAX_ATTEMPTS,
|
|
377
|
+
PICKUP_PROMPT, SIGNIN_PICKUP_PROMPT, MAX_ATTEMPTS, SIGNIN_MAX_ATTEMPTS,
|
|
314
378
|
enabled, delayMs, maxWaitMs,
|
|
315
|
-
keyFor, planFor, arm, cancel, cancelAllFor, list, get, start, fire,
|
|
316
|
-
_resetForTests,
|
|
379
|
+
keyFor, planFor, signinPlanFor, arm, cancel, cancelAllFor, list, get, start, fire,
|
|
380
|
+
_resetForTests, _setAttemptsForTests,
|
|
317
381
|
};
|
package/core/runner.js
CHANGED
|
@@ -808,6 +808,21 @@ function lostSigninRace(result) {
|
|
|
808
808
|
}
|
|
809
809
|
|
|
810
810
|
// Wait in short steps so /stop, or a call that hung up, ends the wait.
|
|
811
|
+
// Claude Code's sign-in check can say "signed out" for a moment while the
|
|
812
|
+
// token renews over a line that is dropping: on 13 Nov 2026 the Mac's internet
|
|
813
|
+
// kept dropping for about four minutes and one signed-out answer refused about
|
|
814
|
+
// 21 replies on the spot ("Claude Code authentication failed"), though the
|
|
815
|
+
// sign-in was fine once the line came back. Before refusing, check again after
|
|
816
|
+
// short waits; refuse only when every check says signed out. Never for a live
|
|
817
|
+
// call: its caller would sit through the wait in silence.
|
|
818
|
+
const DEFAULT_AUTH_RECHECK_WAITS_MS = [5 * 1000, 10 * 1000, 10 * 1000];
|
|
819
|
+
function authRecheckWaits() {
|
|
820
|
+
const raw = process.env.AUTH_RECHECK_MS;
|
|
821
|
+
if (raw === undefined || raw === "") return DEFAULT_AUTH_RECHECK_WAITS_MS;
|
|
822
|
+
return String(raw).split(",").map((part) => Number(part.trim()))
|
|
823
|
+
.filter((ms) => Number.isFinite(ms) && ms >= 0);
|
|
824
|
+
}
|
|
825
|
+
|
|
811
826
|
async function waitUnlessStopped(ms, stopped) {
|
|
812
827
|
const deadline = Date.now() + ms;
|
|
813
828
|
while (Date.now() < deadline) {
|
|
@@ -864,7 +879,23 @@ function createRunnerService(dependencies = {}) {
|
|
|
864
879
|
});
|
|
865
880
|
}
|
|
866
881
|
try {
|
|
867
|
-
const
|
|
882
|
+
const preflight = () => (typeof provider.preflightAuth === "function" ? provider.preflightAuth() : null);
|
|
883
|
+
let authFailure = preflight();
|
|
884
|
+
const authWaits = runContext.liveCall === true ? [] : authRecheckWaits();
|
|
885
|
+
for (let i = 0; authFailure?.code === "PROVIDER_UNAUTHENTICATED" && i < authWaits.length; i += 1) {
|
|
886
|
+
console.warn(`[auth-recheck] run ${runContext.runId}: ${provider.id || "provider"} sign-in check said signed out; checking again in ${Math.round(authWaits[i] / 1000)}s (check ${i + 2} of ${authWaits.length + 1})`);
|
|
887
|
+
let ended = null;
|
|
888
|
+
await waitUnlessStopped(authWaits[i], () => {
|
|
889
|
+
if (!capture && dependencies.isObsolete?.()) ended = cancelledCallRunResult(runContext);
|
|
890
|
+
else if (dependencies.shouldAbort && dependencies.shouldAbort(runContext, { capture })) {
|
|
891
|
+
ended = cancelledRunResult(runContext, provider, "Cancelled by /stop while checking the sign-in again");
|
|
892
|
+
}
|
|
893
|
+
return !!ended;
|
|
894
|
+
});
|
|
895
|
+
if (ended) return settleImmediateRunResult(ended, runContext, dependencies, capture);
|
|
896
|
+
authFailure = preflight();
|
|
897
|
+
if (!authFailure) console.warn(`[auth-recheck] run ${runContext.runId}: signed in on check ${i + 2}; going ahead`);
|
|
898
|
+
}
|
|
868
899
|
if (authFailure) return immediateFailure(provider, authFailure);
|
|
869
900
|
} catch (error) {
|
|
870
901
|
return immediateFailure(provider, error);
|
|
@@ -1854,6 +1885,11 @@ function limitPlanFor(result, runContext) {
|
|
|
1854
1885
|
try { guarded = require("./relationship").isCurrentSpeakerGuarded(); } catch (_) {}
|
|
1855
1886
|
try { plan = limitPickup.planFor(result, runContext, { windows: planLimitWindows(result, runContext), guarded }); }
|
|
1856
1887
|
catch (error) { console.warn(`[limit-pickup] plan failed: ${redactSensitive(String(error.message || error))}`); }
|
|
1888
|
+
} else if (!result.ok && result.error?.code === "PROVIDER_UNAUTHENTICATED") {
|
|
1889
|
+
// Signed out even after the pre-run re-checks: keep trying the message
|
|
1890
|
+
// every minute instead of dropping it (core/limit-pickup signinPlanFor).
|
|
1891
|
+
try { plan = limitPickup.signinPlanFor(result, runContext); }
|
|
1892
|
+
catch (error) { console.warn(`[limit-pickup] sign-in plan failed: ${redactSensitive(String(error.message || error))}`); }
|
|
1857
1893
|
}
|
|
1858
1894
|
return keepOnResult(result, "limitPlan", plan);
|
|
1859
1895
|
}
|
|
@@ -1897,6 +1933,8 @@ function providerRunDiagnostic(result, runContext) {
|
|
|
1897
1933
|
const label = provider.label || runContext.provider;
|
|
1898
1934
|
const code = result.error?.code || "PROVIDER_RUN_FAILED";
|
|
1899
1935
|
if (code === "PROVIDER_UNAUTHENTICATED") {
|
|
1936
|
+
const plan = limitPlanFor(result, runContext);
|
|
1937
|
+
if (plan?.notice) return plan.notice;
|
|
1900
1938
|
const help = typeof provider.authHelp === "function" ? provider.authHelp() : "";
|
|
1901
1939
|
return `${label} authentication failed.${help ? `\n\n${help}` : ""}`;
|
|
1902
1940
|
}
|
|
@@ -2199,6 +2237,8 @@ async function deliverForegroundResult(result, runContext, state = currentState(
|
|
|
2199
2237
|
}
|
|
2200
2238
|
// Nobody asked for a passive reply: a limit that stopped one is not news.
|
|
2201
2239
|
if (limitPlan && runContext.passive === true) return { ok: true, held: true, suppressed: "passive" };
|
|
2240
|
+
// A sign-in retry that is still signed out says nothing; the next is armed.
|
|
2241
|
+
if (limitPlan?.quiet) return { ok: true, held: true, suppressed: "signin-retry" };
|
|
2202
2242
|
const diagnostic = providerRunDiagnostic(result, runContext);
|
|
2203
2243
|
if (diagnostic) result.diagnostic = diagnostic;
|
|
2204
2244
|
const cleanAnswer = String(result.finalAnswerText || "").trim();
|
|
@@ -3499,6 +3539,7 @@ module.exports = {
|
|
|
3499
3539
|
shouldRetryMissingConversation,
|
|
3500
3540
|
lostSigninRace,
|
|
3501
3541
|
signinRaceWaits,
|
|
3542
|
+
authRecheckWaits,
|
|
3502
3543
|
retireMissingConversation,
|
|
3503
3544
|
shouldStartSideChat,
|
|
3504
3545
|
runSideChatRequest,
|
package/core/scheduler.js
CHANGED
|
@@ -49,6 +49,13 @@ const LIMIT_WAIT_CLEARED = Object.freeze({
|
|
|
49
49
|
limitWaitCount: 0, limitWaitUntil: null, limitWaitType: null, limitWaitProvider: null, limitFirstHitAt: null,
|
|
50
50
|
});
|
|
51
51
|
const RETRY_DELAY_MS = 30 * 1000;
|
|
52
|
+
// A signed-out provider is waited out, not counted as a failed try: on 13 Nov
|
|
53
|
+
// 2026 the Mac's line kept dropping for about four minutes, Claude Code's token
|
|
54
|
+
// could not renew, and a wake-up spent its 5 tries 30 s apart and gave up
|
|
55
|
+
// (SCHEDULED_PROVIDER_UNAVAILABLE). A job now waits a minute at a time, up to
|
|
56
|
+
// half an hour, and gives up only if sign-in is still down after that.
|
|
57
|
+
const SIGNIN_WAIT_MS = 60 * 1000;
|
|
58
|
+
const SIGNIN_WAIT_MAX = 30;
|
|
52
59
|
const BUSY_DELAY_MS = 30 * 1000;
|
|
53
60
|
// A watch alarm that has waited this long behind a busy room says so in the
|
|
54
61
|
// chat, once per occurrence, so a busy room never hides an alarm for hours
|
|
@@ -243,6 +250,8 @@ function createSchedulerService(dependencies = {}) {
|
|
|
243
250
|
);
|
|
244
251
|
const retryDelayMs = Number.isFinite(dependencies.retryDelayMs) ? dependencies.retryDelayMs : RETRY_DELAY_MS;
|
|
245
252
|
const busyDelayMs = Number.isFinite(dependencies.busyDelayMs) ? dependencies.busyDelayMs : BUSY_DELAY_MS;
|
|
253
|
+
const signinWaitMs = Number.isFinite(dependencies.signinWaitMs) ? dependencies.signinWaitMs : SIGNIN_WAIT_MS;
|
|
254
|
+
const signinWaitMax = Number.isFinite(dependencies.signinWaitMax) ? dependencies.signinWaitMax : SIGNIN_WAIT_MAX;
|
|
246
255
|
const busyNoticeAfterMs = Number.isFinite(dependencies.busyNoticeAfterMs) ? dependencies.busyNoticeAfterMs : BUSY_NOTICE_AFTER_MS;
|
|
247
256
|
const missedGraceMs = Number.isFinite(dependencies.missedGraceMs) ? dependencies.missedGraceMs : MISSED_WAKEUP_GRACE_MS;
|
|
248
257
|
const watchTimeoutMs = Number.isFinite(dependencies.watchTimeoutMs) ? dependencies.watchTimeoutMs : DEFAULT_WATCH_TIMEOUT_MS;
|
|
@@ -666,6 +675,7 @@ function createSchedulerService(dependencies = {}) {
|
|
|
666
675
|
disabled: false,
|
|
667
676
|
occurrenceId: occurrenceIdFactory(latest),
|
|
668
677
|
attemptCount: 0,
|
|
678
|
+
signinWaitCount: 0,
|
|
669
679
|
busyDeferralCount: 0,
|
|
670
680
|
nextAttemptAt: null,
|
|
671
681
|
lastFireAt: now(),
|
|
@@ -707,6 +717,36 @@ function createSchedulerService(dependencies = {}) {
|
|
|
707
717
|
return { ok: false, status: updated.status, job: updated, error: updated.lastError };
|
|
708
718
|
}
|
|
709
719
|
|
|
720
|
+
// Sign-in down (the provider says signed out, or the runner refused the run
|
|
721
|
+
// as signed out after its own re-checks): wait and try again, without
|
|
722
|
+
// counting a failed try, up to signinWaitMax waits. Returns null when the
|
|
723
|
+
// waits are used up, so the caller fails the job as before.
|
|
724
|
+
function markSigninWait(job, failure, { attemptCounted = false } = {}) {
|
|
725
|
+
const latest = jobsStore.get(job.id) || job;
|
|
726
|
+
const waits = Number(latest.signinWaitCount) || 0;
|
|
727
|
+
if (waits >= signinWaitMax) return null;
|
|
728
|
+
const patch = {
|
|
729
|
+
status: "deferred",
|
|
730
|
+
disabled: false,
|
|
731
|
+
attemptCount: Math.max(0, (Number(latest.attemptCount) || 0) - (attemptCounted ? 1 : 0)),
|
|
732
|
+
nextAttemptAt: now() + signinWaitMs,
|
|
733
|
+
lastFireAt: now(),
|
|
734
|
+
lastFireOk: false,
|
|
735
|
+
lastError: stableFailure(failure),
|
|
736
|
+
signinWaitCount: waits + 1,
|
|
737
|
+
};
|
|
738
|
+
const updated = jobsStore.update(job.id, patch) || { ...latest, ...patch };
|
|
739
|
+
armRetry(updated, signinWaitMs);
|
|
740
|
+
console.log(`[scheduler] ${job.id}: provider signed out; waiting ${Math.round(signinWaitMs / 1000)} s for sign-in (wait ${patch.signinWaitCount} of ${signinWaitMax})`);
|
|
741
|
+
return { ok: false, status: "deferred", signinWait: true, job: updated };
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function signedOut(job, state) {
|
|
745
|
+
const current = getActiveProvider(state);
|
|
746
|
+
return [current, job.provider].filter(Boolean)
|
|
747
|
+
.some((id) => providerStatusSafe(id)?.auth?.state === "unauthenticated");
|
|
748
|
+
}
|
|
749
|
+
|
|
710
750
|
function markBusy(job) {
|
|
711
751
|
const latest = jobsStore.get(job.id) || job;
|
|
712
752
|
const busyDeferralCount = (latest.busyDeferralCount || 0) + 1;
|
|
@@ -771,6 +811,7 @@ function createSchedulerService(dependencies = {}) {
|
|
|
771
811
|
|
|
772
812
|
async function settleSuccess(job, result, target) {
|
|
773
813
|
const successPatch = {
|
|
814
|
+
signinWaitCount: 0,
|
|
774
815
|
status: "succeeded",
|
|
775
816
|
disabled: false,
|
|
776
817
|
nextAttemptAt: null,
|
|
@@ -952,11 +993,13 @@ function createSchedulerService(dependencies = {}) {
|
|
|
952
993
|
|
|
953
994
|
const target = executionTarget(job, state);
|
|
954
995
|
if (!target) {
|
|
996
|
+
const failure = {
|
|
997
|
+
code: "SCHEDULED_PROVIDER_UNAVAILABLE",
|
|
998
|
+
message: `Saved provider ${job.provider} is unavailable and no explicit fallback is configured`,
|
|
999
|
+
};
|
|
955
1000
|
try {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
message: `Saved provider ${job.provider} is unavailable and no explicit fallback is configured`,
|
|
959
|
-
});
|
|
1001
|
+
const waiting = signedOut(job, state) ? markSigninWait(job, failure) : null;
|
|
1002
|
+
return waiting || markFailure(job, failure);
|
|
960
1003
|
} catch (error) { return keepRetrying(job, error); }
|
|
961
1004
|
}
|
|
962
1005
|
|
|
@@ -1056,6 +1099,12 @@ function createSchedulerService(dependencies = {}) {
|
|
|
1056
1099
|
try { return markLimitWait(running, limitPlan, result); }
|
|
1057
1100
|
catch (error) { return { ...keepRetrying(running, error), result }; }
|
|
1058
1101
|
}
|
|
1102
|
+
if (result?.error?.code === "PROVIDER_UNAUTHENTICATED") {
|
|
1103
|
+
try {
|
|
1104
|
+
const waiting = markSigninWait(running, result, { attemptCounted: true });
|
|
1105
|
+
if (waiting) return { ...waiting, result };
|
|
1106
|
+
} catch (error) { return { ...keepRetrying(running, error), result }; }
|
|
1107
|
+
}
|
|
1059
1108
|
try { return markFailure(running, result, { attemptAlreadyCounted: true }); }
|
|
1060
1109
|
catch (error) { return { ...keepRetrying(running, error), result }; }
|
|
1061
1110
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inetafrica/open-claudia",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.79",
|
|
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-codex-output-schema.js && node test-codex-device-login.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-effort-reset.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-group-status-notes.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 && node test-call-flags.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-test-run-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-owner-cards-dm.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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 && node test-thread-titles.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-stop-queue.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-quiet-defaults.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-thread-handoff.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-cost-by-part.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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 && node test-sandbox-probe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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 && node test-kazee-cards.js && node test-card-blocks.js && node test-decision-upkeep.js && node test-passive-replies.js && node test-kazee-bot-loops.js && node test-kazee-bot-handoffs.js && node test-placeholder-reply.js && node test-media-speech.js && node test-speech-voices.js && node test-tts-voice.js && node test-passive-replies-router.js && node test-loopback-cards.js && node test-task-injection.js && node test-speaker-extras.js && node test-token-diet.js && node test-dream-tasks.js && node test-task-archive.js && node test-cron-tolerance.js && node test-dream-schedule.js && node test-job-failures.js && node test-scheduled-placeholder.js && node test-lessons-since.js && node test-pack-reinject.js && node test-turn-journal.js && node test-kazee-catchup.js && node test-usage-limits.js && node test-limit-waits.js && node test-signin-race-retry.js && node test-limit-pickup.js && node test-browser-view.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-browser-view.js && node test-browser-address.js && node test-browser-control.js && node test-browser-drive.js && node test-browser-teach.js && node test-kazee-bot-apps.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-browser-app.js && node test-safe-filename.js && node test-media-filename-paths.js && node test-router-document-guard.js && OPEN_CLAUDIA_TEST=1 node test-web-dashboard-escape.js && OPEN_CLAUDIA_TEST=1 node test-web-bad-requests.js && OPEN_CLAUDIA_TEST=1 node test-kazee-download-limit.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-auth-routes.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-otp-link-preview.js && node test-call-quick-voice.js && node test-call-run-stop.js && node test-call-stopped-transcript.js && node test-call-greeting-context.js && node test-call-camera.js && node test-switchboard-calls.js && node test-switchboard-supervisor.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-topic-lessons.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-env-pins.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-session-core.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-related.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-decisions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-external.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-introspection-retry.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-every-cron.js && node test-rust-cli-parity.js && OPEN_CLAUDIA_TEST=1 node test-bot-acts-for-owner.js && node test-walker-idle-stop.js && node test-usage-history-lazy.js && node test-node-flags-entrypoint.js && node test-recall-engine-env.js && node test-review-queue.js && node test-lazy-heavy-libs.js && node test-lessons-meta-keep.js && node test-views.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-test-run-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-owner-cards-dm.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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 && node test-thread-titles.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-stop-queue.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-quiet-defaults.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-thread-handoff.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-cost-by-part.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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 && node test-sandbox-probe.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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 && node test-kazee-cards.js && node test-card-blocks.js && node test-decision-upkeep.js && node test-passive-replies.js && node test-kazee-bot-loops.js && node test-kazee-bot-handoffs.js && node test-placeholder-reply.js && node test-media-speech.js && node test-speech-voices.js && node test-tts-voice.js && node test-passive-replies-router.js && node test-loopback-cards.js && node test-task-injection.js && node test-speaker-extras.js && node test-token-diet.js && node test-dream-tasks.js && node test-task-archive.js && node test-cron-tolerance.js && node test-dream-schedule.js && node test-job-failures.js && node test-scheduled-placeholder.js && node test-lessons-since.js && node test-pack-reinject.js && node test-turn-journal.js && node test-kazee-catchup.js && node test-usage-limits.js && node test-limit-waits.js && node test-signin-race-retry.js && node test-auth-recheck.js && node test-signin-pickup.js && node test-limit-pickup.js && node test-browser-view.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-browser-view.js && node test-browser-address.js && node test-browser-control.js && node test-browser-drive.js && node test-browser-teach.js && node test-kazee-bot-apps.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-browser-app.js && node test-safe-filename.js && node test-media-filename-paths.js && node test-router-document-guard.js && OPEN_CLAUDIA_TEST=1 node test-web-dashboard-escape.js && OPEN_CLAUDIA_TEST=1 node test-web-bad-requests.js && OPEN_CLAUDIA_TEST=1 node test-kazee-download-limit.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-auth-routes.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test node test-web-otp-link-preview.js && node test-call-quick-voice.js && node test-call-run-stop.js && node test-call-stopped-transcript.js && node test-call-greeting-context.js && node test-call-camera.js && node test-switchboard-calls.js && node test-switchboard-supervisor.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-topic-lessons.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-env-pins.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-session-core.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-related.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-decisions.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-external.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/tmp/open-claudia-test CLAUDE_PATH=./test-fixtures/fake-agent-cli.js FAKE_AGENT_KIND=claude AGENT_ENV_PASSTHROUGH=FAKE_AGENT_KIND node test-introspection-retry.js && OPEN_CLAUDIA_TEST=1 WORKSPACE=/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-every-cron.js && node test-rust-cli-parity.js && OPEN_CLAUDIA_TEST=1 node test-bot-acts-for-owner.js && node test-walker-idle-stop.js && node test-usage-history-lazy.js && node test-node-flags-entrypoint.js && node test-recall-engine-env.js && node test-review-queue.js && node test-lazy-heavy-libs.js && node test-lessons-meta-keep.js && node test-views.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"bot.js",
|
|
@@ -669,13 +669,19 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
|
|
|
669
669
|
// one-tap switch-on card (from the Maia build: plan v2 of 25 Oct, SEC-28 of 30 Oct).
|
|
670
670
|
// 3.5.77 = 3.5.76 + Fable 5.2 in the picker and prices, call --help never dials
|
|
671
671
|
// (Sumeet 12 Nov 07:53 EAT, card 6af54622: "Build 3.5.77 with the 3 pieces, test on one bot, roll on your word").
|
|
672
|
+
// 3.5.79 = 3.5.78 + a reply refused as signed out is tried again every minute, quietly,
|
|
673
|
+
// up to 30 times (Sumeet 13 Nov 13:17 EAT, during Anthropic's sign-in incident:
|
|
674
|
+
// "set up wake ups to keep retrying").
|
|
675
|
+
// 3.5.78 = 3.5.77 + sign-in re-checks before a reply is refused, and scheduled
|
|
676
|
+
// jobs wait out a signed-out provider (Sumeet 13 Nov 12:57 EAT, main chat: "fix
|
|
677
|
+
// this in the bot ... ship in the next bot release through the normal release flow").
|
|
672
678
|
// 3.5.76 = 3.5.75 + memory cuts, the lessons ranking fix, the empty-lock fix,
|
|
673
679
|
// handoff --new, HTML views and the type-check guard (Sumeet 9 Nov: "all bots get all features").
|
|
674
680
|
// 3.5.73 = 3.5.72 + a smaller image (Sumeet 31 Oct 15:06, bot resource plan: "proceed ... roll out the others").
|
|
675
681
|
// 3.5.72 = 3.5.71 + the Mac memory fixes of 22-28 Oct:
|
|
676
682
|
// topic lessons ride with their pack, .env recall pins, prompt fixes, past
|
|
677
683
|
// chats reach recall, settled decisions, /engine x|mem0, nightly retry.
|
|
678
|
-
assert.strictEqual(pkg.version, "3.5.
|
|
684
|
+
assert.strictEqual(pkg.version, "3.5.79", "release version must remain unchanged without explicit approval");
|
|
679
685
|
for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
|
|
680
686
|
assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
|
|
681
687
|
}
|
|
@@ -1353,6 +1353,65 @@ async function durablePendingProbe(createSchedulerService, jobsApi) {
|
|
|
1353
1353
|
}
|
|
1354
1354
|
}
|
|
1355
1355
|
|
|
1356
|
+
// A sign-in that is down for a few minutes (13 Nov 2026: the Mac's line kept
|
|
1357
|
+
// dropping 09:47-09:51Z, Claude Code's token could not renew, and a wake-up
|
|
1358
|
+
// burned its 5 tries 30 s apart and "gave up (SCHEDULED_PROVIDER_UNAVAILABLE)")
|
|
1359
|
+
// is a wait, not a failed try: the job waits and fires once sign-in is back.
|
|
1360
|
+
// Only a sign-in that stays down past the most waits gives up.
|
|
1361
|
+
async function signinWaitProbe(createSchedulerService) {
|
|
1362
|
+
let signedIn = false;
|
|
1363
|
+
const h = schedulerHarness(createSchedulerService, [baseJob({ id: "signin", maxAttempts: 5 })], {
|
|
1364
|
+
providerStatus: () => (signedIn
|
|
1365
|
+
? { availability: { state: "available" }, auth: { state: "authenticated" } }
|
|
1366
|
+
: { availability: { state: "available" }, auth: { state: "unauthenticated", reason: "OAuth token has expired" } }),
|
|
1367
|
+
outcomes: [{
|
|
1368
|
+
ok: true,
|
|
1369
|
+
status: "succeeded",
|
|
1370
|
+
persistence: { transcript: { ok: true }, usage: { ok: true }, session: { ok: true } },
|
|
1371
|
+
delivery: { ok: true },
|
|
1372
|
+
}],
|
|
1373
|
+
});
|
|
1374
|
+
for (let i = 0; i < 8; i += 1) {
|
|
1375
|
+
const waiting = await h.service.fireJob("signin");
|
|
1376
|
+
assert.strictEqual(waiting.ok, false);
|
|
1377
|
+
const job = h.jobsStore.get("signin");
|
|
1378
|
+
assert.notStrictEqual(job.status, "dead-letter", `signed out on try ${i + 1} must not give up (the 13 Nov wake-up died after 5 tries)`);
|
|
1379
|
+
assert.strictEqual(job.status, "deferred", "a signed-out provider defers the job");
|
|
1380
|
+
assert.strictEqual(job.disabled, false);
|
|
1381
|
+
assert.strictEqual(job.attemptCount || 0, 0, "a sign-in wait is not a failed try");
|
|
1382
|
+
assert.strictEqual(job.signinWaitCount, i + 1);
|
|
1383
|
+
}
|
|
1384
|
+
assert.strictEqual(h.runCalls.length, 0);
|
|
1385
|
+
assert.strictEqual(h.sends.filter((t) => /gave up/.test(t)).length, 0, "no death notice while waiting");
|
|
1386
|
+
signedIn = true;
|
|
1387
|
+
const ran = await h.service.fireJob("signin");
|
|
1388
|
+
assert.strictEqual(ran.ok, true, "fires once sign-in is back");
|
|
1389
|
+
assert.strictEqual(h.runCalls.length, 1);
|
|
1390
|
+
assert.ok(!h.jobsStore.get("signin")?.signinWaitCount, "the wait count clears on success (a one-shot is removed)");
|
|
1391
|
+
|
|
1392
|
+
// A run the runner refused as signed out (after its own re-checks) waits too.
|
|
1393
|
+
const r = schedulerHarness(createSchedulerService, [baseJob({ id: "refused", maxAttempts: 1 })], {
|
|
1394
|
+
outcomes: [{
|
|
1395
|
+
ok: false,
|
|
1396
|
+
status: "failed",
|
|
1397
|
+
error: { code: "PROVIDER_UNAUTHENTICATED", message: "Claude Code authentication failed" },
|
|
1398
|
+
persistence: { transcript: { ok: true }, usage: { ok: true }, session: { ok: true } },
|
|
1399
|
+
delivery: { ok: true },
|
|
1400
|
+
}],
|
|
1401
|
+
});
|
|
1402
|
+
await r.service.fireJob("refused");
|
|
1403
|
+
const refused = r.jobsStore.get("refused");
|
|
1404
|
+
assert.strictEqual(refused.status, "deferred", "a run refused as signed out waits instead of dead-lettering");
|
|
1405
|
+
assert.strictEqual(refused.signinWaitCount, 1);
|
|
1406
|
+
|
|
1407
|
+
// Signed out past the most waits: gives up once, with the usual notice.
|
|
1408
|
+
const d = schedulerHarness(createSchedulerService, [baseJob({ id: "dead", maxAttempts: 1, signinWaitCount: 30 })], {
|
|
1409
|
+
providerStatus: () => ({ availability: { state: "available" }, auth: { state: "unauthenticated" } }),
|
|
1410
|
+
});
|
|
1411
|
+
await d.service.fireJob("dead");
|
|
1412
|
+
assert.strictEqual(d.jobsStore.get("dead").status, "dead-letter", "a sign-in down past 30 waits gives up");
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1356
1415
|
async function unavailableAndFallbackProbe(createSchedulerService) {
|
|
1357
1416
|
const noFallback = schedulerHarness(createSchedulerService, [baseJob({ id: "unavailable" })], {
|
|
1358
1417
|
providerStatus: () => ({ availability: { state: "missing" }, auth: { state: "not_checked" } }),
|
|
@@ -1713,6 +1772,7 @@ async function main() {
|
|
|
1713
1772
|
listingProbe();
|
|
1714
1773
|
await strandedDeliveryProbe(schedulerApi.createSchedulerService);
|
|
1715
1774
|
await unavailableAndFallbackProbe(schedulerApi.createSchedulerService);
|
|
1775
|
+
await signinWaitProbe(schedulerApi.createSchedulerService);
|
|
1716
1776
|
await cronOccurrenceProbe(schedulerApi.createSchedulerService);
|
|
1717
1777
|
await watchGateProbe(schedulerApi.createSchedulerService);
|
|
1718
1778
|
watchExpiryStampProbe(schedulerApi.createSchedulerService, schedulerApi.DEFAULT_WATCH_TIMEOUT_MS);
|