code-context-control 2.59.0__py3-none-any.whl → 2.60.0__py3-none-any.whl

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.
cli/c3.py CHANGED
@@ -92,7 +92,7 @@ console = Console() if HAS_RICH else None
92
92
  # Config
93
93
  CONFIG_DIR = ".c3"
94
94
  CONFIG_FILE = ".c3/config.json"
95
- __version__ = "2.59.0"
95
+ __version__ = "2.60.0"
96
96
 
97
97
 
98
98
  def _command_deps() -> CommandDeps:
@@ -1313,6 +1313,12 @@ def cmd_claudemd(args):
1313
1313
  return common_cmd_claudemd(args, _command_deps())
1314
1314
 
1315
1315
 
1316
+ def cmd_map(args):
1317
+ """Live repo map (.c3/MAP.md) commands."""
1318
+ from cli.commands.common import cmd_map as common_cmd_map
1319
+ return common_cmd_map(args, _command_deps())
1320
+
1321
+
1316
1322
  def cmd_stats(args):
1317
1323
  """Show comprehensive stats."""
1318
1324
  return common_cmd_stats(args, _command_deps())
@@ -7162,6 +7168,7 @@ def main():
7162
7168
  "decode": cmd_decode,
7163
7169
  "session": cmd_session,
7164
7170
  "claudemd": cmd_claudemd,
7171
+ "map": cmd_map,
7165
7172
  "stats": cmd_stats,
7166
7173
  "benchmark": cmd_benchmark,
7167
7174
  "session-benchmark": cmd_session_benchmark,
cli/commands/common.py CHANGED
@@ -159,6 +159,57 @@ def cmd_session(args, deps: CommandDeps):
159
159
  print(context)
160
160
 
161
161
 
162
+ def cmd_map(args, deps: CommandDeps):
163
+ """Live repo map (.c3/MAP.md): status | ensure | refresh."""
164
+ config = deps.load_config()
165
+ project_path = config.get("project_path", ".")
166
+
167
+ from services.repo_map import RepoMapService
168
+
169
+ sm = deps.SessionManager(project_path)
170
+ svc = RepoMapService(project_path, session_mgr=sm)
171
+
172
+ if args.map_cmd == "status":
173
+ result = svc.status()
174
+ elif args.map_cmd == "ensure":
175
+ result = svc.ensure()
176
+ else:
177
+ result = svc.refresh()
178
+
179
+ if getattr(args, "json", False):
180
+ print(json.dumps(result, indent=2))
181
+ return
182
+
183
+ if args.map_cmd == "status":
184
+ state = "STALE" if result["stale"] else ("FRESH" if result["exists"] else "MISSING")
185
+ deps.print_header(f"Repo Map — {state}")
186
+ print(f" Path: {svc.map_path}")
187
+ if result.get("generated_at"):
188
+ print(f" Generated: {result['generated_at']}")
189
+ if result.get("tokens"):
190
+ print(f" Tokens: {result['tokens']}")
191
+ if result.get("reasons"):
192
+ print(f" Stale reasons: {', '.join(result['reasons'])}")
193
+ if result.get("truncated"):
194
+ print(" [WARN] Map is truncated (file cap or token budget hit)")
195
+ else:
196
+ action = result.get("action", "?")
197
+ label = {
198
+ "regenerated": "Map regenerated",
199
+ "meta_only": "Content unchanged (meta refreshed)",
200
+ "fresh": "Already fresh — nothing to do",
201
+ "locked": "Another process is regenerating — skipped",
202
+ "disabled": "Repo map disabled (map.enabled=false in .c3/config.json)",
203
+ }.get(action, action)
204
+ deps.print_header(f"Repo Map — {label}")
205
+ if result.get("tokens"):
206
+ print(f" Tokens: {result['tokens']}, duration: {result.get('duration_ms', '?')}ms")
207
+ if result.get("reasons"):
208
+ print(f" Triggered by: {', '.join(result['reasons'])}")
209
+ if result.get("truncated"):
210
+ print(" [WARN] Map is truncated (file cap or token budget hit)")
211
+
212
+
162
213
  def cmd_claudemd(args, deps: CommandDeps):
163
214
  """Instructions file generation commands."""
164
215
  config = deps.load_config()
cli/commands/parser.py CHANGED
@@ -61,6 +61,10 @@ def build_parser(version: str, parse_cli_ide_arg):
61
61
  p_claudemd.add_argument("claudemd_cmd", choices=["generate", "save", "check"])
62
62
  p_claudemd.add_argument("--nano", action="store_true", help="Generate nano mode (~250 tokens) instead of full compact mode")
63
63
 
64
+ p_map = subparsers.add_parser("map", help="Live repo map (.c3/MAP.md) management")
65
+ p_map.add_argument("map_cmd", choices=["status", "ensure", "refresh"])
66
+ p_map.add_argument("--json", action="store_true", help="Emit JSON result")
67
+
64
68
  subparsers.add_parser("stats", help="Show statistics")
65
69
 
66
70
  p_benchmark = subparsers.add_parser("benchmark", help="Run with/without-C3 workflow benchmark")
cli/guide/tools.html CHANGED
@@ -126,6 +126,7 @@
126
126
  <a href="#c3_task" class="sidebar-link"><span class="icon">✅</span> c3_task</a>
127
127
  <a href="#c3_bitbucket" class="sidebar-link"><span class="icon">🪣</span> c3_bitbucket</a>
128
128
  <a href="#c3_credentials" class="sidebar-link"><span class="icon">🔐</span> c3_credentials</a>
129
+ <a href="#c3_jira" class="sidebar-link"><span class="icon">🎫</span> c3_jira</a>
129
130
  </div>
130
131
  <div class="sidebar-section">
131
132
  <div class="sidebar-label">Cross-project</div>
@@ -163,6 +164,7 @@
163
164
  <a href="#c3_artifacts" class="toc-item">c3_artifacts <span class="cat">Config</span></a>
164
165
  <a href="#c3_bitbucket" class="toc-item">c3_bitbucket <span class="cat">SCM</span></a>
165
166
  <a href="#c3_credentials" class="toc-item">c3_credentials <span class="cat">Secrets</span></a>
167
+ <a href="#c3_jira" class="toc-item">c3_jira <span class="cat">Issues</span></a>
166
168
  <a href="#c3_project" class="toc-item">c3_project <span class="cat">Multi-project</span></a>
167
169
  </div>
168
170
  </div>
@@ -1280,6 +1282,57 @@ c3_shell(cmd=<span class="str">'curl -H "Authorization: Bearer {{cred:API_KEY}}"
1280
1282
  <p class="tool-desc"><strong>Surfaces:</strong> the <code>c3 creds</code> CLI (<code>set</code> / <code>get</code> / <code>list</code> / <code>rm</code> / <code>import .env</code>, <code>--global</code> for the shared scope), a per-project dashboard <strong>Credentials</strong> tab, and — since v2.59.0 — a top-level <strong>Credentials</strong> view in the Hub: a Global-vault manager plus a per-project browser with shadowing shown both ways ("shadows global" on project entries, "shadowed in N projects" on globals); the Hub's per-project drill panel manages too. No HTTP route ever returns a stored value (write-only wire contract, endpoint-sweep tested), every mutation is ledger-logged by name, the vault is hard-excluded from the Oracle Discovery API, and cross-project (<code>c3_project</code>) shells run with credentials disabled.</p>
1281
1283
  </div>
1282
1284
  </div>
1285
+
1286
+ <!-- c3_jira -->
1287
+ <div class="tool-card" id="c3_jira">
1288
+ <div class="tool-card-header">
1289
+ <span class="tool-name">c3_jira</span>
1290
+ <div class="tag-row">
1291
+ <span class="badge badge-purple">issue tracking</span>
1292
+ <span class="badge">v2.56.0</span>
1293
+ </div>
1294
+ <span class="tool-tagline">Jira Cloud + Data Center — search, create, transition, comment through one tool</span>
1295
+ </div>
1296
+ <div class="tool-card-body">
1297
+ <p class="tool-desc">One tool for both Jira deployments: <strong>Cloud</strong> (REST v3, email + API token, ADF bodies handled transparently) and self-hosted <strong>Data Center / Server</strong> (REST v2, PAT Bearer, plain-text bodies) — normalized to a single DTO surface with an opaque pagination cursor. Transport is stdlib <code>urllib</code> (no new dependencies); reads get one bounded 429 retry honoring <code>Retry-After</code>, mutations are <em>never</em> auto-retried. Tokens live in the OS keyring keyed by <code>(base_url, username)</code>; the <code>jira</code> config section resolves project → home <strong>wholesale from a single file</strong>, so a repository's committed config can never field-override a home account's URL or TLS settings (credential-redirect hardening). HTTPS-only.</p>
1298
+
1299
+ <p class="tool-desc"><strong>Setup:</strong> <code>c3 jira login --url https://yoursite.atlassian.net</code> (Cloud inferred for <code>*.atlassian.net</code>; add <code>--deployment data_center</code> for self-hosted, <code>--ca-bundle</code> for enterprise certs, <code>--global</code> for a home config reusable across projects), then <code>c3 jira set-default --project PROJ</code>. Manage accounts with <code>c3 jira status / use / logout</code>.</p>
1300
+
1301
+ <h4>Actions</h4>
1302
+ <table class="params-table">
1303
+ <thead><tr><th>Action</th><th>Group</th><th>Description</th></tr></thead>
1304
+ <tbody>
1305
+ <tr><td class="param-name">status, whoami</td><td>Read</td><td class="param-desc">Active account, deployment, defaults, server probe / authenticated user</td></tr>
1306
+ <tr><td class="param-name">search</td><td>Read</td><td class="param-desc">Raw JQL, paginated (helper-built JQL elsewhere is always quoted)</td></tr>
1307
+ <tr><td class="param-name">my_issues</td><td>Read</td><td class="param-desc">Open issues assigned to the token's user (statusCategory-aware)</td></tr>
1308
+ <tr><td class="param-name">get_issue, list_projects, list_transitions</td><td>Read</td><td class="param-desc">Issue detail with comments / project discovery / legal transitions for an issue</td></tr>
1309
+ <tr><td class="param-name">get_create_metadata, search_users</td><td>Read</td><td class="param-desc">Required + allowed fields per project/type; user lookup for assignment</td></tr>
1310
+ <tr><td class="param-name">create_issue</td><td>Write</td><td class="param-desc">Pre-validates against create metadata and returns machine-readable missing required fields instead of guessing defaults</td></tr>
1311
+ <tr><td class="param-name">comment, transition, assign</td><td>Write</td><td class="param-desc">Comment on / move (accepts transition id <em>or</em> name) / assign an issue</td></tr>
1312
+ </tbody>
1313
+ </table>
1314
+
1315
+ <h4>Examples</h4>
1316
+ <pre><code><span class="com"># Connection + account probe, then my open work</span>
1317
+ c3_jira(action=<span class="str">'status'</span>)
1318
+ c3_jira(action=<span class="str">'my_issues'</span>)
1319
+
1320
+ <span class="com"># Raw JQL search</span>
1321
+ c3_jira(action=<span class="str">'search'</span>, jql=<span class="str">'project = PROJ AND status != Done ORDER BY updated DESC'</span>)
1322
+
1323
+ <span class="com"># Create — required fields come from metadata, not guesses</span>
1324
+ c3_jira(action=<span class="str">'get_create_metadata'</span>, project=<span class="str">'PROJ'</span>, issue_type=<span class="str">'Task'</span>)
1325
+ c3_jira(action=<span class="str">'create_issue'</span>, project=<span class="str">'PROJ'</span>, issue_type=<span class="str">'Task'</span>,
1326
+ summary=<span class="str">'Fix login flow'</span>, description=<span class="str">'Steps in thread'</span>)
1327
+
1328
+ <span class="com"># Move it along — id or name both work</span>
1329
+ c3_jira(action=<span class="str">'list_transitions'</span>, issue=<span class="str">'PROJ-123'</span>)
1330
+ c3_jira(action=<span class="str">'transition'</span>, issue=<span class="str">'PROJ-123'</span>, transition=<span class="str">'In Progress'</span>)
1331
+ c3_jira(action=<span class="str">'comment'</span>, issue=<span class="str">'PROJ-123'</span>, body=<span class="str">'Deployed to staging'</span>)</code></pre>
1332
+
1333
+ <p class="tool-desc"><strong>Surfaces &amp; audit:</strong> the per-project dashboard gets a <strong>Jira tab</strong> (My Work board grouped by statusCategory, JQL search, an issue drawer with transition buttons + comments, and an Activity view) backed by <code>/api/jira/*</code> routes. Issue keys like <code>PROJ-123</code> are auto-linked from branch names and edit-ledger entries (acronym denylist, so UTF-8 / SHA-256 / CVE-2024 never match), and the issue drawer shows the local ledger activity for the open issue — that Activity view works with no account configured. Mutations (<code>create_issue</code>, <code>comment</code>, <code>transition</code>, <code>assign</code>) are edit-ledger-logged with identifiers only — bodies are never logged. Read actions are safe in plan mode.</p>
1334
+ </div>
1335
+ </div>
1283
1336
  </div>
1284
1337
 
1285
1338
  <!-- ═══════════════════════════════════════ CROSS-PROJECT ═════ -->
cli/guide/workflow.html CHANGED
@@ -250,6 +250,7 @@
250
250
  <a href="#session-restart" class="sidebar-link"><span class="icon">🔄</span> Session Restart</a>
251
251
  <a href="#terse-skill" class="sidebar-link"><span class="icon">⚡</span> /terse Skill</a>
252
252
  <a href="#subprojects" class="sidebar-link"><span class="icon">🌳</span> Sub-projects</a>
253
+ <a href="#repo-map" class="sidebar-link"><span class="icon">🗺️</span> Live Repo Map</a>
253
254
  <a href="#native-fallback" class="sidebar-link"><span class="icon">⚠️</span> Native Fallback</a>
254
255
  </div>
255
256
  </aside>
@@ -984,6 +985,53 @@ c3_memory(action=<span class="str">'recall'</span>, query=<span class="str">'pay
984
985
 
985
986
  <hr class="divider">
986
987
 
988
+ <!-- Live repo map -->
989
+ <section class="section" id="repo-map">
990
+ <div class="section-title"><span class="icon">🗺️</span> Live Repo Map (v2.60.0)</div>
991
+
992
+ <p>Instruction docs (CLAUDE.md / AGENTS.md) no longer embed a frozen project tree. They carry a stable pointer to <code>.c3/MAP.md</code> — a machine-owned map C3 keeps fresh automatically. One map serves every consumer: Claude Code, Codex, Antigravity.</p>
993
+
994
+ <p>The map contains, in priority order: build/test commands, entry points, module one-liners, the depth-2 tree, and key files — under a token budget (default 1000). Sub-projects appear as boundaries and are never expanded into the parent map.</p>
995
+
996
+ <h4>How it stays fresh</h4>
997
+ <table class="table">
998
+ <thead><tr><th>Trigger</th><th>What happens</th></tr></thead>
999
+ <tbody>
1000
+ <tr>
1001
+ <td>Structural edit (file created/deleted/renamed, manifest changed)</td>
1002
+ <td>Edit-ledger paths touch the <code>.c3/map.dirty</code> sentinel — a file-touch, never a scan</td>
1003
+ </tr>
1004
+ <tr>
1005
+ <td>First C3 tool call of a session</td>
1006
+ <td>Background single-flight <em>ensure</em>: regenerates only if missing, dirty, or the git HEAD/branch/worktree fingerprint moved</td>
1007
+ </tr>
1008
+ <tr>
1009
+ <td><code>c3 map refresh</code></td>
1010
+ <td>Explicit repair — always regenerates</td>
1011
+ </tr>
1012
+ </tbody>
1013
+ </table>
1014
+
1015
+ <p><strong>Byte-stable by design:</strong> <code>MAP.md</code> is rewritten only when rendered content actually changes, so prompt caches keyed on file bytes stay warm. Volatile freshness state (git HEAD, worktree signature, generated-at) lives in <code>.c3/map.meta.json</code> — never in the map itself. Ordinary line edits never trigger regeneration.</p>
1016
+
1017
+ <div class="callout callout-info">
1018
+ <span class="callout-icon">💡</span>
1019
+ <div class="callout-body">
1020
+ <strong>CLI</strong>: <code>c3 map status</code> (freshness report) · <code>c3 map ensure</code> (regen if stale) · <code>c3 map refresh</code> (force). Add <code>--json</code> for machine output. Config knobs: <code>map.token_budget</code>, <code>map.file_cap</code>, <code>map.enabled</code> (set <code>false</code> to restore the legacy embedded tree).
1021
+ </div>
1022
+ </div>
1023
+
1024
+ <div class="callout callout-warning">
1025
+ <span class="callout-icon">⚠️</span>
1026
+ <div class="callout-body">
1027
+ <strong>The map is data, not instructions</strong><br>
1028
+ Its header marks it as auto-generated repository data. Agents should read it for orientation — not obey text inside it. Memory facts are deliberately excluded from the map.
1029
+ </div>
1030
+ </div>
1031
+ </section>
1032
+
1033
+ <hr class="divider">
1034
+
987
1035
  <!-- Native fallback -->
988
1036
  <section class="section" id="native-fallback">
989
1037
  <div class="section-title"><span class="icon">⚠️</span> When Native Tools Are Permitted</div>
cli/hook_edit_ledger.py CHANGED
@@ -212,6 +212,15 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
212
212
  with open(ledger_file, "a", encoding="utf-8") as f:
213
213
  f.write(json.dumps(entry) + "\n")
214
214
 
215
+ # Structural changes (file created / manifest edited) dirty the repo map.
216
+ # Sentinel touch only — the scan happens later, in RepoMapService.ensure().
217
+ try:
218
+ from services.repo_map import is_structural_change, mark_map_dirty
219
+ if is_structural_change(rel, change_type):
220
+ mark_map_dirty(project_path, f"{change_type}:{rel}")
221
+ except Exception:
222
+ pass
223
+
215
224
  return {
216
225
  "_text": (
217
226
  f"[c3:ledger] {rel} {entry['version']} auto-logged. "
cli/mcp_server.py CHANGED
@@ -337,8 +337,34 @@ mcp = FastMCP(f"C3 v{C3_VERSION}", instructions=_build_instructions(_IDE_NAME),
337
337
 
338
338
  # ─── Helper Functions ─────────────────────────────────────────────
339
339
 
340
+ _repo_map_ensured = False
341
+
342
+
343
+ def _ensure_repo_map_once(rt) -> None:
344
+ """First tool call of this server process kicks a background repo-map
345
+ freshness pass. In-process single-flight here; cross-process single-flight
346
+ via the lock file inside RepoMapService.ensure(). Never blocks the tool
347
+ call that triggered it."""
348
+ global _repo_map_ensured
349
+ if _repo_map_ensured:
350
+ return
351
+ _repo_map_ensured = True
352
+
353
+ def _bg():
354
+ try:
355
+ from services.repo_map import RepoMapService
356
+ RepoMapService(rt.project_path,
357
+ session_mgr=getattr(rt, "session_mgr", None)).ensure()
358
+ except Exception:
359
+ pass
360
+
361
+ threading.Thread(target=_bg, daemon=True, name="repo-map-ensure").start()
362
+
363
+
340
364
  def _svc(ctx: Context) -> C3Runtime:
341
- return ctx.request_context.lifespan_context
365
+ rt = ctx.request_context.lifespan_context
366
+ _ensure_repo_map_once(rt)
367
+ return rt
342
368
 
343
369
 
344
370
  _last_tool_call_time: float = 0.0
cli/tools/agent.py CHANGED
@@ -530,7 +530,7 @@ def _wf_codex_test_gen(scope, context, svc, steps_log):
530
530
  if context:
531
531
  gen_context += f"\n\nAdditional context: {context}"
532
532
 
533
- model = dcfg.get("codex_default_model", "gpt-5.3-codex-spark")
533
+ model = dcfg.get("codex_default_model", "")
534
534
  timeout = int(dcfg.get("codex_timeout", 180))
535
535
 
536
536
  steps_log.append("codex_generate")
@@ -544,7 +544,7 @@ def _wf_codex_test_gen(scope, context, svc, steps_log):
544
544
  parts = [f"--- Test generation for {len(files)} file(s) ---"]
545
545
  parts.append(f"Files: {file_list}")
546
546
  parts.append("Sandbox: workspace-write")
547
- parts.append(f"Model: {model}")
547
+ parts.append(f"Model: {model or 'cli-default'}")
548
548
  if ok:
549
549
  parts.append(f"\n--- Codex output ---\n{output}")
550
550
  else:
@@ -1005,7 +1005,7 @@ def _try_delegate(svc, task_type: str, task: str, context: str, steps_log: list,
1005
1005
  steps_log.append("codex(skipped:health_check_failed)")
1006
1006
  return ""
1007
1007
  cdef = CODEX_MODELS.get(task_type, CODEX_MODELS.get("ask", {}))
1008
- model = dcfg.get("codex_default_model") or cdef.get("model", "gpt-5.3-codex-spark")
1008
+ model = dcfg.get("codex_default_model") or cdef.get("model", "")
1009
1009
  sandbox = dcfg.get("codex_default_sandbox") or cdef.get("sandbox", "read-only")
1010
1010
  reasoning = dcfg.get("codex_reasoning_effort") or cdef.get("reasoning", "high")
1011
1011
  timeout = int(dcfg.get("codex_timeout", 90))
@@ -1109,7 +1109,7 @@ def _try_delegate(svc, task_type: str, task: str, context: str, steps_log: list,
1109
1109
  )
1110
1110
  if _codex_ok and _dm_auto._codex_available is not False:
1111
1111
  cdef = CODEX_MODELS.get(task_type, CODEX_MODELS.get("ask", {}))
1112
- c_model = dcfg.get("codex_default_model") or cdef.get("model", "gpt-5.3-codex-spark")
1112
+ c_model = dcfg.get("codex_default_model") or cdef.get("model", "")
1113
1113
  c_sandbox = dcfg.get("codex_default_sandbox") or cdef.get("sandbox", "read-only")
1114
1114
  c_reason = dcfg.get("codex_reasoning_effort") or cdef.get("reasoning", "high")
1115
1115
  c_timeout = int(dcfg.get("codex_timeout", 90))
cli/tools/delegate.py CHANGED
@@ -115,15 +115,19 @@ def _popen_kwargs():
115
115
  # Codex CLI backend
116
116
  # ---------------------------------------------------------------------------
117
117
 
118
+ # No "model" keys here on purpose: a pinned model name goes stale and breaks
119
+ # accounts that don't support it (ChatGPT-plan logins reject retired models
120
+ # outright). Resolution order: .c3 config codex_default_model → the user's own
121
+ # Codex CLI default (~/.codex/config.toml). Empty model = omit -m entirely.
118
122
  CODEX_MODELS = {
119
- "review": {"model": "gpt-5.3-codex-spark", "sandbox": "read-only", "reasoning": "high"},
120
- "explain": {"model": "gpt-5.3-codex-spark", "sandbox": "read-only", "reasoning": "medium"},
121
- "improve": {"model": "gpt-5.4", "sandbox": "read-only", "reasoning": "high"},
122
- "diagnose": {"model": "gpt-5.3-codex", "sandbox": "read-only", "reasoning": "high"},
123
- "test": {"model": "gpt-5.3-codex-spark", "sandbox": "workspace-write", "reasoning": "medium"},
124
- "summarize":{"model": "gpt-5.3-codex-spark", "sandbox": "read-only", "reasoning": "low"},
125
- "docstring":{"model": "gpt-5.3-codex-spark", "sandbox": "read-only", "reasoning": "low"},
126
- "ask": {"model": "gpt-5.3-codex-spark", "sandbox": "read-only", "reasoning": "medium"},
123
+ "review": {"sandbox": "read-only", "reasoning": "high"},
124
+ "explain": {"sandbox": "read-only", "reasoning": "medium"},
125
+ "improve": {"sandbox": "read-only", "reasoning": "high"},
126
+ "diagnose": {"sandbox": "read-only", "reasoning": "high"},
127
+ "test": {"sandbox": "workspace-write", "reasoning": "medium"},
128
+ "summarize":{"sandbox": "read-only", "reasoning": "low"},
129
+ "docstring":{"sandbox": "read-only", "reasoning": "low"},
130
+ "ask": {"sandbox": "read-only", "reasoning": "medium"},
127
131
  }
128
132
 
129
133
  _codex_available: bool | None = None # cached after first check
@@ -560,6 +564,26 @@ def check_codex() -> dict:
560
564
  return {"status": "error", "detail": str(e)}
561
565
 
562
566
 
567
+ def _codex_cmd(prompt: str, model: str, sandbox: str, reasoning: str) -> list:
568
+ """Build the codex exec argv.
569
+
570
+ An empty/falsy model omits ``-m`` so the user's own Codex CLI default
571
+ (~/.codex/config.toml) applies — never pin a fallback model name here.
572
+ """
573
+ codex_exe = _which("codex") or "codex"
574
+ cmd = [codex_exe, "exec"]
575
+ if model:
576
+ cmd += ["-m", model]
577
+ cmd += [
578
+ "--config", f"model_reasoning_effort={reasoning}",
579
+ "--sandbox", sandbox,
580
+ "--full-auto",
581
+ "--skip-git-repo-check",
582
+ prompt,
583
+ ]
584
+ return cmd
585
+
586
+
563
587
  def _run_codex(task: str, context: str, model: str, sandbox: str,
564
588
  reasoning: str = "high", timeout: int = 120,
565
589
  idle_timeout: int = 20,
@@ -570,16 +594,7 @@ def _run_codex(task: str, context: str, model: str, sandbox: str,
570
594
  seconds (catches MCP startup hangs). Also enforces total timeout.
571
595
  """
572
596
  prompt = f"{task}\n\nContext:\n{context}" if context else task
573
- codex_exe = _which("codex") or "codex"
574
- cmd = [
575
- codex_exe, "exec",
576
- "-m", model,
577
- "--config", f"model_reasoning_effort={reasoning}",
578
- "--sandbox", sandbox,
579
- "--full-auto",
580
- "--skip-git-repo-check",
581
- prompt,
582
- ]
597
+ cmd = _codex_cmd(prompt, model, sandbox, reasoning)
583
598
  try:
584
599
  proc = subprocess.Popen(
585
600
  harden_win_argv(cmd),
@@ -897,7 +912,7 @@ def _handle_codex_delegate(task: str, task_type: str, context: str,
897
912
 
898
913
  # Resolve model/sandbox/reasoning from config or defaults
899
914
  cdef = CODEX_MODELS.get(task_type, CODEX_MODELS.get("ask", {}))
900
- model = dcfg.get("codex_default_model") or cdef.get("model", "gpt-5.3-codex-spark")
915
+ model = dcfg.get("codex_default_model") or cdef.get("model", "")
901
916
  sandbox = dcfg.get("codex_default_sandbox") or cdef.get("sandbox", "read-only")
902
917
  reasoning = dcfg.get("codex_reasoning_effort") or cdef.get("reasoning", "high")
903
918
  timeout = int(dcfg.get("codex_timeout", 120))
@@ -926,7 +941,7 @@ def _handle_codex_delegate(task: str, task_type: str, context: str,
926
941
  cached_resp, "cached")
927
942
 
928
943
  # Run Codex
929
- _log_progress(svc, f"[delegate] Codex {model} ({sandbox}, reasoning={reasoning})...")
944
+ _log_progress(svc, f"[delegate] Codex {model or 'cli-default'} ({sandbox}, reasoning={reasoning})...")
930
945
  t0 = time.monotonic()
931
946
  output, ok = _run_codex(
932
947
  task=task, context=enriched,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.59.0
3
+ Version: 2.60.0
4
4
  Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Copilot, Cursor, Antigravity). Retrieve less, read less, edit safer — version the configs that shape your agent (CLAUDE.md, skills, hooks, MCP), and manage multi-project + sub-project hierarchies from a local hub.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -243,6 +243,8 @@ Manage `CLAUDE.md`, `AGENTS.md` (Codex), `GEMINI.md`, and `.github/copilot-instr
243
243
 
244
244
  C3-generated content is wrapped in a `<!-- C3:BEGIN … -->` / `<!-- C3:END -->` block. Regenerating (or `Compact`) only rewrites that block — **anything you write outside it is preserved**, so it's safe to keep your own notes in the same file.
245
245
 
246
+ **Live repo map (v2.60.0):** generated docs no longer embed a frozen project tree. They carry a stable pointer to `.c3/MAP.md` — a machine-owned, byte-stable map (commands, entry points, module one-liners, tree) that C3 refreshes automatically via edit hooks and a first-tool-call freshness check. Manage it with `c3 map status|ensure|refresh`; set `map.enabled=false` in `.c3/config.json` to restore the embedded tree.
247
+
246
248
  ### 7. Chat — browse prior AI conversations
247
249
 
248
250
  <p align="center">
@@ -1,6 +1,6 @@
1
1
  cli/__init__.py,sha256=ec66drCZGNMRU4V6ov0zVhYZph1us12Vn8OvG_LJyRY,22
2
2
  cli/_hook_utils.py,sha256=tJ4ZmXD5Y-JjFWb0uoR7ycYklYFUMnnjF2G7BO-wyBI,12600
3
- cli/c3.py,sha256=aa7hBkW_gt95oqoy4xQhChHtOdL7cmamdrL_cCrMgX0,322126
3
+ cli/c3.py,sha256=-5rfnwqSWy7DRP69Tsr7JX8AXiMSvlXGKIEMX_ewBNk,322329
4
4
  cli/docs.html,sha256=bNymSz7LatnWHjxSXL92QSUtGvB3jBzNHbOV-bRpAOo,142507
5
5
  cli/edits.html,sha256=UjAhoCmBmQ89cklGvJqzC6eyNP2tc8H6T-e01DVkLvE,43418
6
6
  cli/hook_artifact.py,sha256=Se1CNBfoBFyvJQlRmYdNtdRXIkQp9zaF0O6ndRMo7ts,2198
@@ -8,7 +8,7 @@ cli/hook_auto_snapshot.py,sha256=yGFqRANtw8qNqRNr-oCgpuyaUyTkSzIOFxXt5kauq4I,527
8
8
  cli/hook_c3_signal.py,sha256=FPvs-9nD9ZiKA8r2tmusgj79yT9w9F173cRDKn-PYeI,2149
9
9
  cli/hook_c3read.py,sha256=bXLAVvERR0SoKrwcmZhpz78FyinteZWfm_ZL-QItSqc,3612
10
10
  cli/hook_dispatch.py,sha256=ql3juU4NRQa6s1sooPsnlJqQQzoxDrKraEh3_-aT9rE,10582
11
- cli/hook_edit_ledger.py,sha256=B3_hfHAarTWv7QrItNrreaqqvevwDHEmT-DhogI59hI,8135
11
+ cli/hook_edit_ledger.py,sha256=7YK-v5SfW7W5c7F_Ywcwo6UAuvkOR7hZqmWxVokrOAY,8531
12
12
  cli/hook_edit_unlock.py,sha256=6xrnsbwmD6TuyADuP_Z-QfwM7sUrtOfyLL6R-gAm9iw,6492
13
13
  cli/hook_filter.py,sha256=v8ZSznK5StTfYYqae1l4V2bm-e9sy2RFfpbNr5KwE2U,4988
14
14
  cli/hook_ghost_files.py,sha256=plbedFgIJ5tXEE_8USUE39RmyODh1UjIUFNRbUo4R8w,10291
@@ -21,22 +21,22 @@ cli/hub.html,sha256=Hl-XPZGT1mMiKrbX9c5OsEw6mXEumwIB3vp1WlWaplM,183966
21
21
  cli/hub_server.py,sha256=jfBcqiQlcmwPMmMdNHbaN52l7Qzq-mMkDiy_JI6-Vs0,124815
22
22
  cli/hub_ui.html,sha256=nnGqWhWGCLfNisGUnoAlQFcBr6wPNsq-AEOR7uFtVkE,2942
23
23
  cli/mcp_proxy.py,sha256=92htuT-p0j-cDTbyqlIJpGoQ85_Aw7UuB8L_Toi_u20,17511
24
- cli/mcp_server.py,sha256=mt9ED7TKWttX5yV6fyiRSPAkx0_RcelyTENr67sgCcg,45144
24
+ cli/mcp_server.py,sha256=6TEmJ4KkPNlr8b9jmYRTNuBNsLwbBu7AhSj3vWVSI0I,45948
25
25
  cli/progress.py,sha256=qTkNy0howOD3hXraMo4ok3dYTpBW5yG_tenKfF4UDM0,1470
26
26
  cli/server.py,sha256=xw_vjrALvmQrZC8fOojeojaPIBWwPWgtnwzexa1VNFE,151463
27
27
  cli/ui.html,sha256=xcdt74nlFEXx-0Bx6-Okw-WSVZPAXL0iukxU0ytI6CA,5694
28
28
  cli/ui_legacy.html,sha256=cI8tC6RKmE2NIJOcsu7CY-zT4VznjcbD6NTjxb_fvUY,378460
29
29
  cli/ui_nano.html,sha256=UAwQ6bbTOXAoGq191AZ7slhngR9edJSa3IhqpynveDg,27740
30
30
  cli/commands/__init__.py,sha256=0Z8MABNzwSFJGT4Xv9R5AJVR8XxraTsuVTz5b0bShmo,38
31
- cli/commands/common.py,sha256=fHZWzkd4OLl3vPWTTgaI5vaqMi3Ma3XqAu1Ds_-51_4,11299
32
- cli/commands/parser.py,sha256=xKh5NMx6BFC_tvvREdszVhgMInq4cjdK6LCZWgF5i68,31732
31
+ cli/commands/common.py,sha256=eh9x6r3E2k7qf_ZFFBbsBZ4wh5q7Z3bR4RWp3jcAk-Y,13340
32
+ cli/commands/parser.py,sha256=CiYK9C1BAJQCkFjo0Du-qXlP3Ou5Ry66-h0pS-Jxm8A,31974
33
33
  cli/guide/bitbucket.html,sha256=9vN1VPLmvTLrkqDSrqKmuy7z3BHEmQusY1jkAG0FjnI,33477
34
34
  cli/guide/getting-started.html,sha256=5iS-_iAP1PboU9pFbMsfh8C9Du9usqOfIyawOc-X4Hg,19070
35
35
  cli/guide/index.html,sha256=mUDUBX590TTappvrKT7_eXi0P8G-3YvHjGk9pCcwWzQ,21350
36
36
  cli/guide/oracle.html,sha256=3HSyPB25mH83IwUeKjetykSOK0jwcui7OJkFoJLLWjg,22214
37
37
  cli/guide/shared.css,sha256=Mmm7W6aYxrkDq2RPOcyXiQFYGR-yB3auwX1uIWi6C74,15967
38
- cli/guide/tools.html,sha256=F1Qd38Q4UnSVMcfxJDtDQEfVrHmhK2aqSqKtNNx-jGs,79614
39
- cli/guide/workflow.html,sha256=gFUHUAVES4EG5nB3GARqQz_f62qvHCNfNsX4pvSgcPs,59044
38
+ cli/guide/tools.html,sha256=uQSXx-Kp9ArBLrmsuErqG4n4JV_fH6FUOpq4nboNws0,85341
39
+ cli/guide/workflow.html,sha256=1tTAEbZN0aH_jbD7CQ0L05YoaJCYUSUDgskJHid5QuA,61957
40
40
  cli/hub_ui/app.js,sha256=5W54CwLr60HL-HmKXT2GK8xFzLedZyMqWDYGDY9VtP0,6368
41
41
  cli/hub_ui/state.js,sha256=nlZtBU6WNJCMLiHRuj6AX5vkwWDvrcVjnK0oSaQALqI,6081
42
42
  cli/hub_ui/components/add_project.js,sha256=j5m0mX0gePcEYQW_0vodJkw5v8Vn2lQqPAI0miIGdv4,3182
@@ -62,12 +62,12 @@ cli/hub_ui/components/toasts.js,sha256=caj_x3npcM_wMv9E_xEde88jyfXI-jt8RrDQW_yXz
62
62
  cli/hub_ui/components/topbar.js,sha256=vgQpNB77iJRjd5KTX3BJwvqN0pwd46tiVpKFaMUFoIU,4379
63
63
  cli/tools/__init__.py,sha256=HO6eVKzDm1KPqsKTHY6lfIsnFnv3C7Bd9o3Q_V88idg,127
64
64
  cli/tools/_helpers.py,sha256=Yo_ol8bFT2R5ayjT54pXLVZhW_PgpBVoM8I7pDoomCI,7823
65
- cli/tools/agent.py,sha256=fdt5kmw9O-AEKlYaij-PPmCJ4sI7bmdej56V4NGWaqI,48145
65
+ cli/tools/agent.py,sha256=Fp9XLrOqjSP7_Ihq7VXjYXcGoXjw17-Hx3JMvoOVnhc,48105
66
66
  cli/tools/artifacts.py,sha256=98shRIs3cdC8r0E1gfsEOIDUopqSP1WpYwzFiWfdtg0,7491
67
67
  cli/tools/bitbucket.py,sha256=_hgORCW9-IF5xZJaznoONVfaTGKaX8VcU7ALrBeLhWo,27518
68
68
  cli/tools/compress.py,sha256=aZ4owwqaQLtkszDr_g7yv5KkvtQPuqaSyMk-aM_hsCY,10060
69
69
  cli/tools/credentials.py,sha256=YgrC4-GhuKb77jBokIP7mrMMWy2L391_DPizc3NtIno,10051
70
- cli/tools/delegate.py,sha256=mwsEUsPXlC1ldkhhSk-i4_JUMsXy9ptIwlYV2_-kOoI,53812
70
+ cli/tools/delegate.py,sha256=j82eh1UhvQ0k0lShynngmHiUFxEN1SCQG6LwOxoiYBM,54243
71
71
  cli/tools/edit.py,sha256=_3QosNcdZ_DaFRYn0Pa7qPsOuMaw7A9zcavb2HvgK2U,21493
72
72
  cli/tools/edits.py,sha256=8zM01TzLmjm7ULQlCmXOmitlJd84zQHVzE0z7UHJUdA,5520
73
73
  cli/tools/federate.py,sha256=wmC2QN7A6aay3cT7U9LDPYRCZKL1m_T6qFdZzpZmPx4,4650
@@ -101,7 +101,7 @@ cli/ui/components/sessions.js,sha256=FIKtil76B8tCkAmcFV7hlj6GQ_DCJK2jCzvEmdK7NBE
101
101
  cli/ui/components/settings.js,sha256=ATbAjBlVIwCNpxq7s191b49a_INQV38iwmySqtJLYwY,79066
102
102
  cli/ui/components/sidebar.js,sha256=K2ym2kUgpbyG-EBA_wBIIiqQY8qTatsiBZwzseMWuIQ,9939
103
103
  cli/ui/components/tasks.js,sha256=vyKQ3uwoppMwvdEaHlhWXW4oWcAisx4NveqzMhsYqHo,38438
104
- code_context_control-2.59.0.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
104
+ code_context_control-2.60.0.dist-info/licenses/LICENSE,sha256=l8Kh5QCNWNvR6kIt8L0BUZvc2LAFiHv2c-FnsGnUZf4,11301
105
105
  core/__init__.py,sha256=TSDCEcM4V7gcZVM3w2ykJaqEUch4Dkon-rivV17T73s,2501
106
106
  core/config.py,sha256=YmkcZwedz_lfDM0ZuI_f4xpe98ixPLcSQFcTCHgRiRg,19206
107
107
  core/ide.py,sha256=V6VVMVsFdmmcsMyxikjQp7z9xa42CWiHKS-ya-MAcG4,6172
@@ -150,7 +150,7 @@ oracle/ui/chat/toolbar.js,sha256=ZDexIIpGwsQ6XsY4Tyo082rJoofdD_JBTV97-mLQUVM,120
150
150
  services/__init__.py,sha256=3Kn4cZweLm7at8wFdBdZ-Zwo8hHcnVIsmY5f29nzi2Y,116
151
151
  services/activity_log.py,sha256=PNGeEYlw1Aux-mRU4pKCQdbsSuzLvOg7MYiq-cb4n8g,4473
152
152
  services/agent_base.py,sha256=a-gdSd_jtZtbjXo1WS8CnWCagXgKaGZd5ShcG6s0kT4,4809
153
- services/agents.py,sha256=rqRAwpNMGXPLiMKCuKiWIF0ARD9RGxIBcg9FNlEVKy8,82423
153
+ services/agents.py,sha256=iy0F5-H_rjOTjyy0CaHCbIZG1hPut5YJEajuO7AH0HI,82404
154
154
  services/artifact_defs.py,sha256=M3blGvW3QhKxoVL1bwU7x9DlnXw1_TUHiOahiyp_Wm0,9749
155
155
  services/artifact_store.py,sha256=PAkirolhn6z-agr-V7aJgezfJFHeR5oAjmqC4FBA3yA,28081
156
156
  services/auto_memory.py,sha256=v__ZS1e68533_Yv491mZtvuZnheC63q6_uTvWhBw3Lw,14290
@@ -158,7 +158,7 @@ services/benchmark_dashboard.py,sha256=iR-DnqnoKbqHMJ4d-ZkIvJBYfzwTa7r-jzO6j2BYD
158
158
  services/bitbucket_client.py,sha256=JByovvtVZ6F4NcU611KVuTgKlT1rIsX2A2VlBDfvRV8,17509
159
159
  services/bitbucket_credentials.py,sha256=2qLA9pQMol4y95y4DJMNBsBBPUsJQCKbLFo2iiCnfvI,7364
160
160
  services/circuit_breaker.py,sha256=ES6PpjL40gfDhtK88GeS6GFzsz5EOEEkZsB-DzX_tbw,3179
161
- services/claude_md.py,sha256=Mh5qiWGNCcA1rKpl1lPC3PtcCaNxMMFMjhpacohOIcs,44001
161
+ services/claude_md.py,sha256=HHJo3sKn1KM-DE5b5d3mSyf9PV60EUsQ8015HjkMAq4,45549
162
162
  services/compressor.py,sha256=AK31TqHFpkOD_Lqbp9aEOkOx7zENUwpsQHQ9B2imEHo,33081
163
163
  services/context_snapshot.py,sha256=2f_bxY3xX4ZC653ncYno8YSeSTFSavwBjrorytHA0Ns,16879
164
164
  services/conversation_store.py,sha256=-E2H6f9pMSOHiBjsq7tFUjrFAwWYExf7LJkibi5MRMA,35650
@@ -167,7 +167,7 @@ services/doc_index.py,sha256=ZEQD1kyGCAMm9AY4Kpi1zDWJTul-cAcAdi_4Md43Hpw,19205
167
167
  services/e2e_benchmark.py,sha256=4pDXkOFjq5b2ZwDvMK0CWdUXQli5OE4cOh_OJs7W36c,132970
168
168
  services/e2e_evaluator.py,sha256=FsB4vMzcFUcmicfIwRtA8JZ_XeMpuk2_-86F2iVNEDc,17783
169
169
  services/e2e_tasks.py,sha256=Ln5VbGDIcS3NY3aml5ERbgjfjLxEslmRZ8AyaYxpWEo,34524
170
- services/edit_ledger.py,sha256=LbFDAnqAWKXsc5pUdJ8zSk5-1MNUwJduK3MO8_HUm5E,29018
170
+ services/edit_ledger.py,sha256=Tj8Q14o19VHQHpofRHdbZKKcVs17v-ctZ3LOeVTqvdQ,29362
171
171
  services/embedding_index.py,sha256=WVAmQkpvwbu2GaQfg4iPWyWiW8zQNN0ldQAo9ibsyBc,15908
172
172
  services/error_reporting.py,sha256=HZ3ru8i5RLf8nq2R4iRnTs5sm1blUxknSbv5hdxuxs0,4139
173
173
  services/file_memory.py,sha256=ero1EY_42z0ORzZaOyvRK7Pc_OYxvgijf4BaKhEBPuY,34241
@@ -197,13 +197,14 @@ services/project_manager.py,sha256=LaNWqBeVMx6wcB6iiOQyRWSWhS-JXzfDApJmHFmTCy8,3
197
197
  services/project_runtime.py,sha256=yyftX48BFjq4B2KcR4KGszDAAa4xR6gn6j0SgTyro1s,11603
198
198
  services/protocol.py,sha256=XyUGjTHD9Zouw94IEqwH667pQ1TlroleLzlM3GRlEGk,12843
199
199
  services/proxy_state.py,sha256=u5rd0k6CrOsywZA8FpRu_hMLwhR0TAJhZjy5MdWbCGc,6107
200
+ services/repo_map.py,sha256=QNNXObo9_9GmGCLz1qF5b246kv42VE19WviH7WlG1Ys,22921
200
201
  services/retention.py,sha256=I2_RV233kWBBXox5rc_w-1h1aPua93o9huuPf-pJVuE,18629
201
202
  services/retrieval_broker.py,sha256=9X67VZ_6AkbAzopHuuMFKmP4CGZLnW576kjSKMenBnw,5261
202
203
  services/router.py,sha256=Cz10nx2fKTbaGn14mSBePWIDrw5rdcs_1JFYXeik084,15626
203
204
  services/runtime.py,sha256=b79gN0dFlzBO4rPaUMWier8FZFamMZlwIM3aywLmbB4,12840
204
205
  services/scanner.py,sha256=1wnsH6WAoarf4L0MskRb8CBfjaF0pPw6ZYDX_4y2q3A,5985
205
206
  services/session_benchmark.py,sha256=GX3H8OwKC0X9Kk5U-vfY6Y7qq9Qaz2HwadNA7mjO8RY,105047
206
- services/session_manager.py,sha256=cVsL45nfkAZ5P-elwLMBoesQ9QGwZsCl4ND3tQJXMMI,51838
207
+ services/session_manager.py,sha256=nSZcemk34U4yxn3AvKnOuYrNfiIDRgE3s7FXTNYKG0A,52617
207
208
  services/session_preloader.py,sha256=DsTAXMKVtrX9yu1sEFojYDi9-jkSAj1Ylt9JTy57Dow,9883
208
209
  services/subprojects.py,sha256=KNA-qGVPsd7Tg92Pt_kLWMLyER2YHmdQWO44sOelTIg,25123
209
210
  services/task_store.py,sha256=IHNeLipdyWtbWYu2-3ItIDeSDI9WoMKj6YwPPc1TgW0,46487
@@ -238,8 +239,8 @@ tui/screens/search_view.py,sha256=MMHjVdlk3HZSuDBSvq8IGrqv_Mh5Us6YqXQ80bcWSMk,19
238
239
  tui/screens/session_view.py,sha256=eZ1eDwHTvPOck1wCCviixtOaCxIkBT_95ytNNNriGNA,5991
239
240
  tui/screens/stats.py,sha256=p81PjzdaIv7hllb8f45-rlVe4lJZwSdIMqu7e86_u5s,6223
240
241
  tui/screens/ui_view.py,sha256=1QJCgLh2YfgWIpvzRG1KOGXYEaOYX6ojN61Azjf2oX0,2125
241
- code_context_control-2.59.0.dist-info/METADATA,sha256=--W3obwi4LV8oMlP8tLSGAarOEPTsuPDA8Qe0nG3qJ0,30130
242
- code_context_control-2.59.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
243
- code_context_control-2.59.0.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
244
- code_context_control-2.59.0.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
245
- code_context_control-2.59.0.dist-info/RECORD,,
242
+ code_context_control-2.60.0.dist-info/METADATA,sha256=8zXAPOWM7sdkyIIBIy_MdPePVS7s3rpig_G9hzluLqg,30553
243
+ code_context_control-2.60.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
244
+ code_context_control-2.60.0.dist-info/entry_points.txt,sha256=7kX_WUsDCF2hbXzvbNyscyaBb9AeA-DJY5v_5hN0DlU,93
245
+ code_context_control-2.60.0.dist-info/top_level.txt,sha256=wRt41zBybVF3qAiNXHz9BURbkKvUvfhmWWtKMhaw6eE,29
246
+ code_context_control-2.60.0.dist-info/RECORD,,
services/agents.py CHANGED
@@ -1554,7 +1554,7 @@ class EditLedgerEnricherAgent(BackgroundAgent):
1554
1554
  f"--- {f} ---\n{d}" for _, f, d in batch
1555
1555
  )
1556
1556
  task = "Review these recent edits for regressions, bugs, or issues. Be concise — only flag real problems."
1557
- model = self.delegate_config.get("codex_default_model", "gpt-5.3-codex-spark")
1557
+ model = self.delegate_config.get("codex_default_model", "")
1558
1558
  timeout = int(self.delegate_config.get("codex_timeout", 120))
1559
1559
 
1560
1560
  output, ok = _run_codex(