@inetafrica/open-claudia 3.5.7 → 3.5.8

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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.5.8
4
+
5
+ GPT-6.1 Sol for Codex, and a /codex_login code you can copy. Canary first on network-bot and procurement-specialist, then the fleet.
6
+
7
+ - **GPT-6.1 Sol in the Codex model menu.** OpenAI released `gpt-6.1-sol` on 29 Sep (DevDay) to paid ChatGPT plans in Codex. It is now the first Codex button in `/model`. The default Codex model is unchanged (`gpt-5.6-sol` unless `CODEX_MODEL` is set). Needs Codex CLI 0.159.1 or newer, the first version with the model in its catalog. The bot image installs the newest Codex at build time, so a new image carries it; an operator host on an older Codex must upgrade first. Open Claudia's Codex tool-hook gate passes on 0.159.0 and 0.159.2 (and still on 0.153.4).
8
+ - **Fix: `/codex_login` sends the real one-time code, alone in its own message.** Codex 0.159.2 prints "sign in with ChatGPT using device code authorization:" before the code, and the bot sent "authorization" as the code (Sumeet, 30 Sep). The bot now reads only a real code (upper-case letters and digits in two hyphenated groups, even when it arrives in a later chunk) and sends it on its own after a short lead-in, so a phone's Copy, which copies a whole message, copies exactly the code. The web dashboard's sign-in page had the same bug and now shows the real code too.
9
+
3
10
  ## 3.5.7
4
11
 
5
12
  3.5.6 as it was meant to ship: the same bot, with one test fixed so the release can build. Canary first on network-bot and procurement-specialist, then the fleet.
package/core/auth-flow.js CHANGED
@@ -11,7 +11,7 @@ const {
11
11
  } = require("./config");
12
12
  const { claudeAgentEnv, codexAgentEnv } = require("./providers/env");
13
13
  const { vault } = require("./vault-store");
14
- const { redactSensitive, stripTerminalControls, extractUrls } = require("./redact");
14
+ const { redactSensitive, stripTerminalControls, extractUrls, extractDeviceCode } = require("./redact");
15
15
  const { send } = require("./io");
16
16
  const { currentState } = require("./state");
17
17
 
@@ -464,10 +464,14 @@ async function runCodexDeviceLogin() {
464
464
  await send(`Codex login URL:\n${redactSensitive(url)}\n\nOpen it and enter the device code if shown.`);
465
465
  }
466
466
  }
467
- const codeMatch = cleanChunk.match(/(?:code|device code)[:\s]+([A-Z0-9-]{6,})/i);
468
- if (codeMatch && !sent.has(codeMatch[1])) {
469
- sent.add(codeMatch[1]);
470
- await send(`Codex device code: ${codeMatch[1]}`);
467
+ // Read the whole output so far: the code can arrive in a later chunk than its label.
468
+ const code = extractDeviceCode(redactSensitive(stripTerminalControls(output)));
469
+ if (code && !sent.has(code)) {
470
+ sent.add(code);
471
+ // Alone in its own message: a phone's Copy takes a whole message, so the
472
+ // code must be the only thing in it.
473
+ await send("Codex one-time code. It's alone in the next message so you can copy it:");
474
+ await send(code);
471
475
  }
472
476
  const now = Date.now();
473
477
  if (cleanChunk.trim() && /device|code|login|browser|open|auth|token|error|failed|api key/i.test(cleanChunk) && now - lastSnippetAt > 3000) {
@@ -8,7 +8,9 @@ const { createCodexHookTransport } = require("./codex-hook");
8
8
 
9
9
  // gpt-5.6-sol-pro is rejected on ChatGPT-plan auth (400 from the API); it needs API-key billing.
10
10
  // gpt-6-astra (GPT-6) reached ChatGPT-plan accounts on 2026-09-05; verified live with codex 0.153.
11
- const CODEX_MODELS = Object.freeze(["gpt-6-astra", "gpt-5.6-sol", "gpt-5.6-sol-pro", "gpt-5.6-terra", "gpt-5.6-luna"]);
11
+ // gpt-6.1-sol (OpenAI DevDay, 2026-09-29) is in Codex's bundled catalog from 0.159.1 (found in the
12
+ // 0.159.2 binary, absent from 0.159.0); older CLIs do not list it.
13
+ const CODEX_MODELS = Object.freeze(["gpt-6.1-sol", "gpt-6-astra", "gpt-5.6-sol", "gpt-5.6-sol-pro", "gpt-5.6-terra", "gpt-5.6-luna"]);
12
14
  // max + ultra verified live against codex 0.144 (ultra = proactive multi-agent behavior).
13
15
  const CODEX_EFFORT_VALUES = Object.freeze(["minimal", "low", "medium", "high", "xhigh", "max", "ultra"]);
14
16
  const REQUIRED_EXEC_HELP_FLAGS = Object.freeze(["--config", "--json", "--sandbox", "--image", "--model", "--skip-git-repo-check"]);
package/core/redact.js CHANGED
@@ -45,4 +45,17 @@ function extractUrls(text) {
45
45
  return [...stripTerminalControls(text).matchAll(/https?:\/\/[^\s)]+/g)].map((m) => m[0]);
46
46
  }
47
47
 
48
- module.exports = { redactSensitive, registerSecrets, stripTerminalControls, extractUrls };
48
+ // A device-login one-time code: upper-case letters and digits in two hyphenated
49
+ // groups (Codex prints e.g. 7QK2-M9XPA on the line after "one-time code").
50
+ // Case-sensitive on purpose: Codex 0.159 writes "sign in with ChatGPT using
51
+ // device code authorization:" first, and the old case-insensitive
52
+ // "code <word>" match sent "authorization" as the code (30 Sep 2026).
53
+ function extractDeviceCode(text) {
54
+ const clean = stripTerminalControls(text);
55
+ const labelled = clean.match(/[Oo]ne-time code[^\n]*\n\s*([A-Z0-9]{4,}-[A-Z0-9]{4,})(?![A-Za-z0-9-])/);
56
+ if (labelled) return labelled[1];
57
+ const bare = clean.match(/(?<![A-Za-z0-9./-])([A-Z0-9]{4,}-[A-Z0-9]{4,})(?![A-Za-z0-9-])/);
58
+ return bare ? bare[1] : null;
59
+ }
60
+
61
+ module.exports = { redactSensitive, registerSecrets, stripTerminalControls, extractUrls, extractDeviceCode };
package/core/web-auth.js CHANGED
@@ -8,7 +8,7 @@ const { spawn } = require("child_process");
8
8
  const os = require("os");
9
9
  const { discoverProviderExecutable } = require("./config");
10
10
  const { inspectProviderConfiguration } = require("./provider-status");
11
- const { redactSensitive, stripTerminalControls, extractUrls } = require("./redact");
11
+ const { redactSensitive, stripTerminalControls, extractUrls, extractDeviceCode } = require("./redact");
12
12
  const {
13
13
  claudeSubprocessEnv, codexSubprocessEnv, saveClaudeOAuthToken, getClaudeOAuthToken,
14
14
  extractClaudeToken, isClaudeAuthUrl, looksLikeClaudeToken, looksLikeOpenAIKey,
@@ -102,8 +102,7 @@ function startCodexLogin() {
102
102
  const clean = redactSensitive(stripTerminalControls(buf.toString()));
103
103
  codex.log = (codex.log + clean).slice(-4000);
104
104
  for (const u of extractUrls(clean)) { if (!codex.url) codex.url = u; }
105
- const m = clean.match(/(?:code|device code)[:\s]+([A-Z0-9-]{6,})/i);
106
- if (m && !codex.code) codex.code = m[1];
105
+ if (!codex.code) codex.code = extractDeviceCode(codex.log);
107
106
  };
108
107
  proc.stdout.on("data", onChunk);
109
108
  proc.stderr.on("data", onChunk);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inetafrica/open-claudia",
3
- "version": "3.5.7",
3
+ "version": "3.5.8",
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": {
@@ -10,7 +10,7 @@
10
10
  "test:kazee-call": "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",
11
11
  "setup": "node setup.js",
12
12
  "start": "node bot.js",
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",
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-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-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
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 && 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-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 && 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"
15
15
  },
16
16
  "files": [
@@ -100,6 +100,7 @@
100
100
  "test-provider-events.js",
101
101
  "test-provider-claude.js",
102
102
  "test-provider-codex.js",
103
+ "test-codex-device-login.js",
103
104
  "test-provider-runner.js",
104
105
  "test-provider-run-lifecycle.js",
105
106
  "test-provider-gateway.js",
@@ -0,0 +1,97 @@
1
+ // /codex_login device code: the chat must get the real one-time code, alone in
2
+ // its own message. 30 Sep 2026: Codex 0.159.2 printed "sign in with ChatGPT
3
+ // using device code authorization:" before the code, the old case-insensitive
4
+ // "code <word>" match sent "authorization" as the code, and the real code sat
5
+ // inside a long message that a phone's Copy (whole message only) could not
6
+ // pick out.
7
+
8
+ const assert = require("assert");
9
+ const fs = require("fs");
10
+ const os = require("os");
11
+ const path = require("path");
12
+
13
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "oc-codex-device-"));
14
+ const fakeCodex = path.join(tmp, "codex");
15
+ const CODE = "7QK2-M9XPA";
16
+ const LABEL = [
17
+ "Welcome to Codex [v0.159.2]",
18
+ "OpenAI's command-line coding agent",
19
+ "",
20
+ "Follow these steps to sign in with ChatGPT using device code authorization:",
21
+ "",
22
+ "1. Open this link in your browser and sign in to your account",
23
+ " https://auth.openai.com/codex/device",
24
+ "",
25
+ "2. Enter this one-time code (expires in 15 minutes)",
26
+ "",
27
+ ].join("\n");
28
+ const CODE_PART = ` ${CODE}\n\nContinue only if you started this login in Codex. If a website or another person gave you this code, cancel.\n`;
29
+
30
+ // Prints the label first and the code in a later chunk, as the real CLI can.
31
+ fs.writeFileSync(fakeCodex, `#!/usr/bin/env node
32
+ const args = process.argv.slice(2).join(" ");
33
+ if (args === "--version") { console.log("codex-cli 0.159.2"); process.exit(0); }
34
+ if (args === "login status") { console.log("Not logged in"); process.exit(1); }
35
+ if (args === "login --device-auth") {
36
+ process.stdout.write(${JSON.stringify(LABEL)});
37
+ setTimeout(() => process.stdout.write(${JSON.stringify(CODE_PART)}), 150);
38
+ setTimeout(() => process.exit(0), 300);
39
+ } else { process.exit(2); }
40
+ `);
41
+ fs.chmodSync(fakeCodex, 0o755);
42
+
43
+ process.env.OPEN_CLAUDIA_TEST = "1";
44
+ process.env.WORKSPACE = process.env.WORKSPACE || tmp;
45
+ process.env.CODEX_PATH = fakeCodex;
46
+
47
+ const { extractDeviceCode } = require("./core/redact");
48
+
49
+ // The helper on its own.
50
+ assert.strictEqual(extractDeviceCode(LABEL + CODE_PART), CODE, "the one-time code, not the word after 'device code'");
51
+ assert.strictEqual(extractDeviceCode(LABEL), null, "the label alone holds no code");
52
+ assert.strictEqual(extractDeviceCode("\u001b[1mEnter code: ABCD-1234\u001b[0m\n"), "ABCD-1234", "older single-line form, terminal colours stripped");
53
+ assert.strictEqual(extractDeviceCode("open https://auth.example.com/device/ABCD-1234 now"), null, "never a piece of a URL");
54
+ assert.strictEqual(extractDeviceCode("device code authorization: abcd-efgh"), null, "lower-case words are not codes");
55
+
56
+ // The /codex_login flow end to end, through a fake chat adapter.
57
+ const authFlow = require("./core/auth-flow");
58
+ const { runInChat } = require("./core/context");
59
+
60
+ (async () => {
61
+ const sends = [];
62
+ const adapter = {
63
+ type: "kazee",
64
+ id: "kazee",
65
+ send: async (_channelId, text) => { sends.push(String(text)); return String(sends.length).padStart(24, "0"); },
66
+ };
67
+ await runInChat({ adapter, channelId: "chan-codex", transport: "kazee" }, () => authFlow.runCodexDeviceLogin());
68
+ const deadline = Date.now() + 10000;
69
+ while (!sends.some((t) => t.startsWith("Codex login finished")) && Date.now() < deadline) {
70
+ await new Promise((resolve) => setTimeout(resolve, 25));
71
+ }
72
+ assert.ok(sends.some((t) => t.startsWith("Codex login finished")), `login flow finished; sent: ${JSON.stringify(sends)}`);
73
+
74
+ const codeIndex = sends.indexOf(CODE);
75
+ assert.ok(codeIndex > 0, `the code is sent alone in its own message; sent: ${JSON.stringify(sends)}`);
76
+ assert.match(sends[codeIndex - 1], /one-time code/i, "a short lead-in comes right before the code");
77
+ assert.strictEqual(sends.filter((t) => t === CODE).length, 1, "the code is sent once");
78
+ assert.ok(!sends.some((t) => /device code: authorization|^authorization$/i.test(t)), "never 'authorization' as the code");
79
+ assert.ok(sends.some((t) => t.includes("https://auth.openai.com/codex/device")), "the login link is sent");
80
+
81
+ // The web dashboard's sign-in page runs the same login and shows codexState().code.
82
+ const webAuth = require("./core/web-auth");
83
+ assert.ok(webAuth.startCodexLogin().ok, "web Codex login starts");
84
+ const webDeadline = Date.now() + 10000;
85
+ while (!webAuth.codexState().done && Date.now() < webDeadline) {
86
+ await new Promise((resolve) => setTimeout(resolve, 25));
87
+ }
88
+ assert.strictEqual(webAuth.codexState().code, CODE, "the web sign-in page shows the real code");
89
+ webAuth.cancelCodex();
90
+
91
+ fs.rmSync(tmp, { recursive: true, force: true });
92
+ console.log("codex device login OK");
93
+ })().catch((err) => {
94
+ fs.rmSync(tmp, { recursive: true, force: true });
95
+ console.error(err);
96
+ process.exit(1);
97
+ });
@@ -158,6 +158,7 @@ async function commandProbe() {
158
158
 
159
159
  await dispatch("/model");
160
160
  const modelControls = callbacks(sent.at(-1).options.keyboard.inline_keyboard);
161
+ assert.ok(modelControls.includes("mb:codex:gpt-6.1-sol"));
161
162
  assert.ok(modelControls.includes("mb:codex:gpt-5.6-sol"));
162
163
  assert.ok(modelControls.includes("mb:codex:gpt-5.6-luna"));
163
164
  assert.ok(!modelControls.includes("mb:codex:o4-mini"));
@@ -46,7 +46,7 @@ assert.strictEqual(provider.label, "OpenAI Codex");
46
46
  assert.strictEqual(provider.isAvailable(), true);
47
47
  assert.strictEqual(provider.executable(), "/fixture/codex");
48
48
  assert.strictEqual(provider.defaultModel(), "gpt-5-codex");
49
- assert.deepStrictEqual(provider.modelChoices(), ["gpt-6-astra", "gpt-5.6-sol", "gpt-5.6-sol-pro", "gpt-5.6-terra", "gpt-5.6-luna"]);
49
+ assert.deepStrictEqual(provider.modelChoices(), ["gpt-6.1-sol", "gpt-6-astra", "gpt-5.6-sol", "gpt-5.6-sol-pro", "gpt-5.6-terra", "gpt-5.6-luna"]);
50
50
  assert.ok(!provider.modelChoices().includes("o4-mini"));
51
51
  assert.deepStrictEqual(provider.compatibilityStatus(), {
52
52
  state: "compatible",
@@ -525,7 +525,14 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
525
525
  // only where its sandbox can run (the fleet's containers cannot). 3.5.6 never
526
526
  // built (a test needed Claude Code on the build machine); 3.5.7 = 3.5.6 + that
527
527
  // test fix. Canary on network-bot + procurement-specialist first, then the fleet.
528
- assert.strictEqual(pkg.version, "3.5.7", "release version must remain unchanged without explicit approval");
528
+ // 3.5.8 approved by Sumeet 2026-09-30 15:13 EAT ("Yes do it", answering "Shall I
529
+ // release the Open Claudia update now? It goes to two test bots first, then to me
530
+ // and the rest of the fleet."), after asking at 14:33 EAT ("I also want to add
531
+ // support for codex for 6.1 sol") and at 15:02 EAT ("I can't copy the code here ...
532
+ // what can we do to make that easiest"): gpt-6.1-sol first in the Codex picker
533
+ // (Codex 0.159.1+), and /codex_login sends the real one-time code alone in its own
534
+ // message (Codex 0.159.2's wording made it send "authorization").
535
+ assert.strictEqual(pkg.version, "3.5.8", "release version must remain unchanged without explicit approval");
529
536
  for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
530
537
  assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
531
538
  }