@open-mercato/cezar 0.9.1-pr725.892 → 0.9.1-pr726.897

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +1 -0
  2. package/dist/agent-config/catalog.d.ts +6 -0
  3. package/dist/agent-config/catalog.js +17 -0
  4. package/dist/agent-config/catalog.js.map +1 -1
  5. package/dist/agent-config/models.d.ts +5 -0
  6. package/dist/agent-config/models.js +96 -0
  7. package/dist/agent-config/models.js.map +1 -0
  8. package/dist/core/agent-model-policy.d.ts +5 -0
  9. package/dist/core/agent-model-policy.js +8 -0
  10. package/dist/core/agent-model-policy.js.map +1 -0
  11. package/dist/core/model-identity.d.ts +4 -3
  12. package/dist/core/model-identity.js +17 -12
  13. package/dist/core/model-identity.js.map +1 -1
  14. package/dist/server/server.d.ts +36 -36
  15. package/dist/server/server.js +44 -19
  16. package/dist/server/server.js.map +1 -1
  17. package/dist/workflows/run.d.ts +16 -3
  18. package/dist/workflows/run.js +165 -43
  19. package/dist/workflows/run.js.map +1 -1
  20. package/package.json +2 -2
  21. package/web/dist/assets/{compare-variants-BnhCYsfo.js → compare-variants-DXfFTtfr.js} +1 -1
  22. package/web/dist/assets/{diff-BYWScKEf2.js → diff-CQY9DbEX2.js} +2 -2
  23. package/web/dist/assets/{diff-view-DQrWNV7l.js → diff-view-D1LKO1xk.js} +1 -1
  24. package/web/dist/assets/{git-toolbar-BWUVZ6yR.js → git-toolbar-BP1Y3NuC.js} +1 -1
  25. package/web/dist/assets/{github-Ox8fCBdG.js → github-BpU1rlah.js} +1 -1
  26. package/web/dist/assets/{index-D-0AJo1h.js → index-CUuvs-FD.js} +4 -4
  27. package/web/dist/assets/new-task-form-B-ifwpi0.js +1 -0
  28. package/web/dist/assets/{repo-git-CKp7XJDH.js → repo-git-3NyrzWNb.js} +1 -1
  29. package/web/dist/assets/{run-diff-Dclf6QqY.js → run-diff-BSEQ5brJ.js} +1 -1
  30. package/web/dist/assets/{run-header-DqjqwW-M.js → run-header-BIRLEI8K.js} +1 -1
  31. package/web/dist/assets/{skills-B6JggT7B.js → skills-CO8z1733.js} +1 -1
  32. package/web/dist/assets/{task-changes-D3WZw6Wm.js → task-changes-CylE3sZ0.js} +1 -1
  33. package/web/dist/assets/{task-commits-kzQcMB61.js → task-commits-D9u9HWm3.js} +1 -1
  34. package/web/dist/assets/{task-files-BuEzgMvG.js → task-files-nYjxrDpA.js} +1 -1
  35. package/web/dist/assets/{task-thread-YqnMa71e.js → task-thread-oz1-VMfl.js} +2 -2
  36. package/web/dist/assets/{use-desktop-CRwfloSK.js → use-desktop-FJpraByx.js} +1 -1
  37. package/web/dist/assets/{workflows-FiXcWMoj.js → workflows-BDnGBDS2.js} +1 -1
  38. package/web/dist/index.html +2 -2
  39. package/web/dist/assets/new-task-form-umhQeDuQ.js +0 -1
package/README.md CHANGED
@@ -426,6 +426,7 @@ Useful environment variables:
426
426
  | Var | Effect |
427
427
  |---|---|
428
428
  | `CEZ_DRY_RUN=1` | Use the bundled mock instead of the real `claude` CLI — the entire cockpit works offline, for demos and development. |
429
+ | `CEZ_AGENT_MODELS_LOCKED=1` | Lock model selection to the models configured in native Claude/Codex/OpenCode settings. Existing Cezar presets are preserved but ignored; only `1` enables it, and a restart is required. |
429
430
  | `CEZ_APPROVAL_GATE=1` | Opt into Claude's interactive approval UI; by default, unapproved tools are denied without interrupting the run. |
430
431
  | `CEZ_FOLLOWUPS=1` | Turn on the global follow-up **Inbox**: agents are asked to leave follow-ups in `todos.json` when they finish, and the Inbox view appears. Off by default — each task's own **Notes** handoff journal runs either way. |
431
432
  | `CEZ_AUTOSAVE=1` | Re-enable the periodic (90 s) autosave commit in task worktrees. Off by default (#471) — turn-end and pre-PR flushes always run, so branches still end complete. Every autosave names its trigger in the commit subject (`cezar autosave (periodic)` vs `(turn end)` / `(run finalize)` / `(pre-PR)`), so the flushes you keep are distinguishable from the timer you disabled. |
@@ -47,6 +47,12 @@ export interface ConfigFileDef {
47
47
  seeded?: boolean;
48
48
  /** True when this file holds MCP server definitions (drives the MCP section's filter). */
49
49
  holdsMcp?: boolean;
50
+ /** Top-level native setting that supplies the agent's new-session model, when present. */
51
+ modelKey?: string;
52
+ /** Native model keys checked in precedence order, including nested `env.*` settings. */
53
+ modelKeys?: readonly string[];
54
+ /** Higher values win when resolving a native default model across config scopes. */
55
+ modelPriority?: number;
50
56
  /** VERBATIM from the vendor docs. Never computed, never generic. */
51
57
  precedence: string;
52
58
  /** Documented mid-run reload behaviour, or undefined when the vendor is silent. */
@@ -21,6 +21,9 @@ export const CONFIG_FILES = [
21
21
  label: '~/.claude/settings.json',
22
22
  format: 'json',
23
23
  tracked: 'outside-repo',
24
+ modelKey: 'model',
25
+ modelKeys: ['env.ANTHROPIC_MODEL', 'model'],
26
+ modelPriority: 1,
24
27
  precedence: 'Lowest priority. Project and local settings override it key by key — except permission rules, which merge across all scopes.',
25
28
  hotReload: 'Edits to most keys — including permissions and hooks — apply to a running session without a restart.',
26
29
  docsUrl: CLAUDE_SETTINGS_DOCS,
@@ -34,6 +37,9 @@ export const CONFIG_FILES = [
34
37
  label: '.claude/settings.json',
35
38
  format: 'json',
36
39
  tracked: 'tracked',
40
+ modelKey: 'model',
41
+ modelKeys: ['env.ANTHROPIC_MODEL', 'model'],
42
+ modelPriority: 2,
37
43
  precedence: 'Overrides user settings key by key (permission rules merge). Local settings override this.',
38
44
  hotReload: 'Edits to most keys — including permissions and hooks — apply to a running session without a restart.',
39
45
  docsUrl: CLAUDE_SETTINGS_DOCS,
@@ -48,6 +54,9 @@ export const CONFIG_FILES = [
48
54
  format: 'json',
49
55
  tracked: 'gitignored',
50
56
  seeded: true,
57
+ modelKey: 'model',
58
+ modelKeys: ['env.ANTHROPIC_MODEL', 'model'],
59
+ modelPriority: 3,
51
60
  precedence: 'Highest of the file scopes — overrides project and user (permission rules merge). Git-ignored; copied into each run’s worktree so it takes effect immediately.',
52
61
  hotReload: 'Edits to most keys — including permissions and hooks — apply to a running session without a restart.',
53
62
  docsUrl: CLAUDE_SETTINGS_DOCS,
@@ -113,6 +122,8 @@ export const CONFIG_FILES = [
113
122
  format: 'toml',
114
123
  tracked: 'outside-repo',
115
124
  holdsMcp: true,
125
+ modelKey: 'model',
126
+ modelPriority: 1,
116
127
  precedence: 'User-level defaults. A trusted project’s .codex/config.toml overrides these; some keys (provider, auth, telemetry) cannot be overridden at project scope. MCP servers live here under [mcp_servers.<id>].',
117
128
  docsUrl: CODEX_CONFIG_DOCS,
118
129
  },
@@ -125,6 +136,8 @@ export const CONFIG_FILES = [
125
136
  label: '.codex/config.toml',
126
137
  format: 'toml',
127
138
  tracked: 'tracked',
139
+ modelKey: 'model',
140
+ modelPriority: 2,
128
141
  holdsMcp: true,
129
142
  precedence: 'Applies only in projects you have trusted. Some keys (provider, auth, telemetry) cannot be overridden here. MCP servers go under [mcp_servers.<id>]. Runs read the committed copy.',
130
143
  docsUrl: CODEX_CONFIG_DOCS,
@@ -152,6 +165,8 @@ export const CONFIG_FILES = [
152
165
  format: 'jsonc',
153
166
  tracked: 'outside-repo',
154
167
  holdsMcp: true,
168
+ modelKey: 'model',
169
+ modelPriority: 1,
155
170
  precedence: 'Global config. Merged with the project config, not replaced — later configs override earlier ones only for conflicting keys. MCP servers live under the "mcp" key.',
156
171
  docsUrl: OPENCODE_CONFIG_DOCS,
157
172
  },
@@ -165,6 +180,8 @@ export const CONFIG_FILES = [
165
180
  format: 'jsonc',
166
181
  tracked: 'tracked',
167
182
  holdsMcp: true,
183
+ modelKey: 'model',
184
+ modelPriority: 2,
168
185
  precedence: 'Merged over the global config per conflicting key (not a wholesale replace). MCP servers live under the "mcp" key. Runs read the committed copy.',
169
186
  docsUrl: OPENCODE_CONFIG_DOCS,
170
187
  },
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/agent-config/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/agent-config/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { RunnerId } from '../core/agent-runner.js';
2
+ /** The model defaults exposed by the coding agents' own settings files. */
3
+ export type AgentModelDefaults = Partial<Record<RunnerId, string>>;
4
+ /** Read the current default model for each installed/configured coding agent. */
5
+ export declare function readAgentModelDefaults(repoRoot: string, env?: NodeJS.ProcessEnv): Promise<AgentModelDefaults>;
@@ -0,0 +1,96 @@
1
+ import { parse as parseToml } from 'smol-toml';
2
+ import { CONFIG_FILES } from './catalog.js';
3
+ import { readConfigFile } from './files.js';
4
+ import { stripJsonComments } from './validate.js';
5
+ /**
6
+ * Native settings are read in the same order in which each agent applies them:
7
+ * the first valid model wins. Cezar deliberately only reads the settings files
8
+ * it already exposes in Settings → Agent config; managed/CLI/environment
9
+ * overrides stay with the agent process itself.
10
+ */
11
+ /** Remove JSONC trailing commas without touching commas inside string values. */
12
+ function stripJsonTrailingCommas(input) {
13
+ let out = '';
14
+ let inString = false;
15
+ let escaped = false;
16
+ for (let i = 0; i < input.length; i++) {
17
+ const ch = input[i];
18
+ if (inString) {
19
+ out += ch;
20
+ if (escaped)
21
+ escaped = false;
22
+ else if (ch === '\\')
23
+ escaped = true;
24
+ else if (ch === '"')
25
+ inString = false;
26
+ continue;
27
+ }
28
+ if (ch === '"') {
29
+ inString = true;
30
+ out += ch;
31
+ continue;
32
+ }
33
+ if (ch === ',') {
34
+ let next = i + 1;
35
+ while (/\s/.test(input[next] ?? ''))
36
+ next++;
37
+ if (input[next] === '}' || input[next] === ']')
38
+ continue;
39
+ }
40
+ out += ch;
41
+ }
42
+ return out;
43
+ }
44
+ function valueAtPath(value, path) {
45
+ return path.split('.').reduce((current, segment) => {
46
+ if (!current || typeof current !== 'object' || Array.isArray(current))
47
+ return undefined;
48
+ return current[segment];
49
+ }, value);
50
+ }
51
+ function modelFromContent(content, format, keys) {
52
+ try {
53
+ const parsed = format === 'toml'
54
+ ? parseToml(content)
55
+ : JSON.parse(format === 'jsonc' ? stripJsonTrailingCommas(stripJsonComments(content)) : content);
56
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
57
+ return undefined;
58
+ for (const key of keys) {
59
+ const model = valueAtPath(parsed, key);
60
+ if (typeof model === 'string' && model.trim())
61
+ return model.trim();
62
+ }
63
+ return undefined;
64
+ }
65
+ catch {
66
+ // A malformed higher-precedence file must not prevent a usable lower-level
67
+ // default from appearing in the cockpit.
68
+ return undefined;
69
+ }
70
+ }
71
+ async function readRunnerModel(runner, repoRoot, env) {
72
+ // Claude Code gives ANTHROPIC_MODEL higher priority than settings-file values.
73
+ // The terminal and cezar must therefore agree when the model is configured in
74
+ // the shell that launched the server.
75
+ if (runner === 'claude' && env.ANTHROPIC_MODEL?.trim())
76
+ return env.ANTHROPIC_MODEL.trim();
77
+ const modelFiles = CONFIG_FILES.filter((def) => def.kind === 'settings' &&
78
+ def.runners.includes(runner) &&
79
+ def.modelKey !== undefined &&
80
+ def.modelPriority !== undefined).sort((a, b) => (b.modelPriority ?? 0) - (a.modelPriority ?? 0));
81
+ for (const def of modelFiles) {
82
+ const file = await readConfigFile(def.id, repoRoot, env);
83
+ if (!file || 'error' in file || !file.exists)
84
+ continue;
85
+ const model = modelFromContent(file.content, def.format, def.modelKeys ?? [def.modelKey]);
86
+ if (model)
87
+ return model;
88
+ }
89
+ return undefined;
90
+ }
91
+ /** Read the current default model for each installed/configured coding agent. */
92
+ export async function readAgentModelDefaults(repoRoot, env = process.env) {
93
+ const entries = await Promise.all(['claude', 'codex', 'opencode'].map(async (runner) => [runner, await readRunnerModel(runner, repoRoot, env)]));
94
+ return Object.fromEntries(entries.filter((entry) => entry[1] !== undefined));
95
+ }
96
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/agent-config/models.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** The server-side switch that makes native agent settings authoritative. */
2
+ export declare const AGENT_MODELS_LOCKED_ENV = "CEZ_AGENT_MODELS_LOCKED";
3
+ /** Only the exact value `1` enables the lock; unset keeps the current behavior. */
4
+ export declare function agentModelsLocked(env?: NodeJS.ProcessEnv): boolean;
5
+ export declare const AGENT_MODELS_LOCKED_ERROR = "agent models are locked \u2014 configure the model in the native coding-agent settings";
@@ -0,0 +1,8 @@
1
+ /** The server-side switch that makes native agent settings authoritative. */
2
+ export const AGENT_MODELS_LOCKED_ENV = 'CEZ_AGENT_MODELS_LOCKED';
3
+ /** Only the exact value `1` enables the lock; unset keeps the current behavior. */
4
+ export function agentModelsLocked(env = process.env) {
5
+ return env[AGENT_MODELS_LOCKED_ENV] === '1';
6
+ }
7
+ export const AGENT_MODELS_LOCKED_ERROR = 'agent models are locked — configure the model in the native coding-agent settings';
8
+ //# sourceMappingURL=agent-model-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-model-policy.js","sourceRoot":"","sources":["../../src/core/agent-model-policy.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,MAAM,CAAC,MAAM,uBAAuB,GAAG,yBAAyB,CAAC;AAEjE,mFAAmF;AACnF,MAAM,UAAU,iBAAiB,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IACpE,OAAO,GAAG,CAAC,uBAAuB,CAAC,KAAK,GAAG,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,MAAM,yBAAyB,GACpC,mFAAmF,CAAC"}
@@ -54,6 +54,8 @@ interface BackendModelMap {
54
54
  * It also selects the wire form in {@link toBackendModel}.
55
55
  */
56
56
  readonly defaultProvider?: string;
57
+ /** Whether explicit foreign provider/model ids are valid backend-native ids. */
58
+ readonly allowExplicitProvider?: boolean;
57
59
  /**
58
60
  * Bare model id → provider override, for the rare backend whose bare ids
59
61
  * span providers. Checked before `defaultProvider`; empty for today's set.
@@ -84,9 +86,8 @@ export declare function parseModelIdentity(raw: string | undefined | null): Mode
84
86
  * explicit choice, not a silent fallback);
85
87
  * - an explicit `provider/model` → that identity, for a multi-provider backend
86
88
  * or when the provider is the single-provider backend's own;
87
- * - an explicit `provider/model` naming a FOREIGN provider on a single-provider
88
- * backend throws {@link ModelIdentityError} (it would be dropped on the wire
89
- * yet persisted, asserting a provider that never ran — #405 review M2);
89
+ * - an explicit `provider/model` naming a FOREIGN provider is preserved when
90
+ * the backend supports custom/gateway model ids;
90
91
  * - a bare id → the backend's default provider;
91
92
  * - a bare id on a backend with no default provider → throws
92
93
  * {@link ModelIdentityError}.
@@ -22,8 +22,10 @@ export const KNOWN_PROVIDERS = ['anthropic', 'openai', 'google', 'openrouter'];
22
22
  * to `claude`.
23
23
  */
24
24
  export const BACKEND_MODEL_MAP = {
25
- claude: { defaultProvider: 'anthropic' },
26
- 'claude-cli': { defaultProvider: 'anthropic' },
25
+ // Claude Code supports custom/gateway model ids such as DeepSeek via an
26
+ // Anthropic-compatible endpoint, so preserve an explicit provider/model.
27
+ claude: { defaultProvider: 'anthropic', allowExplicitProvider: true },
28
+ 'claude-cli': { defaultProvider: 'anthropic', allowExplicitProvider: true },
27
29
  codex: { defaultProvider: 'openai' },
28
30
  // opencode selects across providers, so a bare model is ambiguous: reject it
29
31
  // loudly rather than let the server pick a default the user never asked for.
@@ -59,9 +61,8 @@ export function parseModelIdentity(raw) {
59
61
  * explicit choice, not a silent fallback);
60
62
  * - an explicit `provider/model` → that identity, for a multi-provider backend
61
63
  * or when the provider is the single-provider backend's own;
62
- * - an explicit `provider/model` naming a FOREIGN provider on a single-provider
63
- * backend throws {@link ModelIdentityError} (it would be dropped on the wire
64
- * yet persisted, asserting a provider that never ran — #405 review M2);
64
+ * - an explicit `provider/model` naming a FOREIGN provider is preserved when
65
+ * the backend supports custom/gateway model ids;
65
66
  * - a bare id → the backend's default provider;
66
67
  * - a bare id on a backend with no default provider → throws
67
68
  * {@link ModelIdentityError}.
@@ -72,12 +73,12 @@ export function resolveModelIdentity(backend, raw) {
72
73
  const map = BACKEND_MODEL_MAP[backend] ?? {};
73
74
  const explicit = parseModelIdentity(raw);
74
75
  if (explicit) {
75
- // A single-provider backend (claude/codex) can only serve its own provider. An explicit
76
- // foreign provider would be silently dropped on the wire — `toBackendModel` hands the CLI
77
- // the bare model id while the record persists the foreign provider, asserting one that
78
- // never served the run (#405 review M2). Reject it, the same fail-loud contract a bare id
79
- // gets on a multi-provider backend.
80
- if (map.defaultProvider !== undefined && explicit.provider !== map.defaultProvider) {
76
+ // Most single-provider backends need their bare wire form, but Claude Code
77
+ // also accepts explicit gateway/custom provider ids. Keep rejecting foreign
78
+ // providers for backends that do not advertise that capability.
79
+ if (map.defaultProvider !== undefined &&
80
+ explicit.provider !== map.defaultProvider &&
81
+ !map.allowExplicitProvider) {
81
82
  throw new ModelIdentityError(`provider "${explicit.provider}" can't be served by the ${backend} runner (serves ${map.defaultProvider}) — use "${map.defaultProvider}/${explicit.model}" or a bare model id`);
82
83
  }
83
84
  return explicit;
@@ -98,7 +99,11 @@ export function resolveModelIdentity(backend, raw) {
98
99
  */
99
100
  export function toBackendModel(backend, id) {
100
101
  const map = BACKEND_MODEL_MAP[backend] ?? {};
101
- return map.defaultProvider === undefined ? formatModelIdentity(id) : id.model;
102
+ if (map.defaultProvider === undefined)
103
+ return formatModelIdentity(id);
104
+ if (map.allowExplicitProvider && id.provider !== map.defaultProvider)
105
+ return formatModelIdentity(id);
106
+ return id.model;
102
107
  }
103
108
  /**
104
109
  * Normalise a raw model string for `backend` in one step: the backend-native
@@ -1 +1 @@
1
- {"version":3,"file":"model-identity.js","sourceRoot":"","sources":["../../src/core/model-identity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model-identity.js","sourceRoot":"","sources":["../../src/core/model-identity.ts"],"names":[],"mappings":"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"}
@@ -306,10 +306,14 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
306
306
  "/agent-config/:id": {
307
307
  $put: {
308
308
  output: {
309
- error: string;
309
+ id: string;
310
+ path: string;
311
+ exists: boolean;
312
+ content: string;
313
+ version: string | null;
310
314
  };
311
315
  outputFormat: "json";
312
- status: 404;
316
+ status: import("hono/utils/http-status").ContentfulStatusCode;
313
317
  input: {
314
318
  param: {
315
319
  id: string;
@@ -317,14 +321,10 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
317
321
  };
318
322
  } | {
319
323
  output: {
320
- id: string;
321
- path: string;
322
- exists: boolean;
323
- content: string;
324
- version: string | null;
324
+ error: string;
325
325
  };
326
326
  outputFormat: "json";
327
- status: import("hono/utils/http-status").ContentfulStatusCode;
327
+ status: 404;
328
328
  input: {
329
329
  param: {
330
330
  id: string;
@@ -381,14 +381,6 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
381
381
  } & {
382
382
  "/workflows": {
383
383
  $post: {
384
- output: {
385
- path: string;
386
- name: string;
387
- };
388
- outputFormat: "json";
389
- status: 201;
390
- input: {};
391
- } | {
392
384
  output: {
393
385
  error: string;
394
386
  };
@@ -410,6 +402,14 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
410
402
  outputFormat: "json";
411
403
  status: 500;
412
404
  input: {};
405
+ } | {
406
+ output: {
407
+ path: string;
408
+ name: string;
409
+ };
410
+ outputFormat: "json";
411
+ status: 201;
412
+ input: {};
413
413
  };
414
414
  };
415
415
  } & {
@@ -419,7 +419,7 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
419
419
  error: string;
420
420
  };
421
421
  outputFormat: "json";
422
- status: 400;
422
+ status: 404;
423
423
  input: {
424
424
  param: {
425
425
  name: string;
@@ -430,7 +430,7 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
430
430
  error: string;
431
431
  };
432
432
  outputFormat: "json";
433
- status: 404;
433
+ status: 400;
434
434
  input: {
435
435
  param: {
436
436
  name: string;
@@ -583,10 +583,14 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
583
583
  "/agent-config/:id": {
584
584
  $put: {
585
585
  output: {
586
- error: string;
586
+ id: string;
587
+ path: string;
588
+ exists: boolean;
589
+ content: string;
590
+ version: string | null;
587
591
  };
588
592
  outputFormat: "json";
589
- status: 404;
593
+ status: import("hono/utils/http-status").ContentfulStatusCode;
590
594
  input: {
591
595
  param: {
592
596
  id: string;
@@ -594,14 +598,10 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
594
598
  };
595
599
  } | {
596
600
  output: {
597
- id: string;
598
- path: string;
599
- exists: boolean;
600
- content: string;
601
- version: string | null;
601
+ error: string;
602
602
  };
603
603
  outputFormat: "json";
604
- status: import("hono/utils/http-status").ContentfulStatusCode;
604
+ status: 404;
605
605
  input: {
606
606
  param: {
607
607
  id: string;
@@ -658,14 +658,6 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
658
658
  } & {
659
659
  "/workflows": {
660
660
  $post: {
661
- output: {
662
- path: string;
663
- name: string;
664
- };
665
- outputFormat: "json";
666
- status: 201;
667
- input: {};
668
- } | {
669
661
  output: {
670
662
  error: string;
671
663
  };
@@ -687,6 +679,14 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
687
679
  outputFormat: "json";
688
680
  status: 500;
689
681
  input: {};
682
+ } | {
683
+ output: {
684
+ path: string;
685
+ name: string;
686
+ };
687
+ outputFormat: "json";
688
+ status: 201;
689
+ input: {};
690
690
  };
691
691
  };
692
692
  } & {
@@ -696,7 +696,7 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
696
696
  error: string;
697
697
  };
698
698
  outputFormat: "json";
699
- status: 400;
699
+ status: 404;
700
700
  input: {
701
701
  param: {
702
702
  name: string;
@@ -707,7 +707,7 @@ export declare function createApp(deps: ServerDeps): import("hono/hono-base").Ho
707
707
  error: string;
708
708
  };
709
709
  outputFormat: "json";
710
- status: 404;
710
+ status: 400;
711
711
  input: {
712
712
  param: {
713
713
  name: string;
@@ -9,6 +9,7 @@ import { streamSSE } from 'hono/streaming';
9
9
  import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
10
10
  import { z } from 'zod';
11
11
  import { detectEnvironment } from '../core/backend-detect.js';
12
+ import { AGENT_MODELS_LOCKED_ERROR, agentModelsLocked } from '../core/agent-model-policy.js';
12
13
  import { discoverCodexModels } from '../core/codex-model-catalog.js';
13
14
  import { PROVIDER_IDS, ProviderAuthService, } from '../core/provider-auth.js';
14
15
  import { applyProviderEnablement } from '../core/provider-availability.js';
@@ -30,6 +31,7 @@ import { collectChanges, collectCommitChanges, collectRunCommits, commitAll, cre
30
31
  import { gatedSkillsRepos, loadConfig, resolveWorktreeRetention } from '../config.js';
31
32
  import { findConfigFile } from '../agent-config/catalog.js';
32
33
  import { readConfigFile, writeConfigFile } from '../agent-config/files.js';
34
+ import { readAgentModelDefaults } from '../agent-config/models.js';
33
35
  import { listAgentConfig } from '../agent-config/service.js';
34
36
  import { PROJECT_ID_RE, defaultWorkspaceConfig, effectiveSkillsAutoUpdate, loadWorkspaceConfig, mergeWriteWorkspaceConfig, effectiveComposerDefault, } from '../workspace/config.js';
35
37
  import { allocateProjectSlug, listProjects, probeProjectStatus, registerProject, removeProject, shouldRegisterProject, } from '../workspace/projects.js';
@@ -1942,6 +1944,9 @@ export function createApp(deps) {
1942
1944
  if (!parsed.success) {
1943
1945
  return c.json({ error: parsed.error.issues.map((i) => i.message).join('; ') }, 400);
1944
1946
  }
1947
+ if (agentModelsLocked() && parsed.data?.model?.trim()) {
1948
+ return c.json({ error: AGENT_MODELS_LOCKED_ERROR }, 409);
1949
+ }
1945
1950
  let workflow;
1946
1951
  if (parsed.data.steps) {
1947
1952
  // Inline chain (spec 008): an approved plan runs as an ad-hoc workflow.
@@ -2293,6 +2298,9 @@ export function createApp(deps) {
2293
2298
  if (!parsed.success) {
2294
2299
  return c.json({ error: parsed.error.issues.map((i) => i.message).join('; ') }, 400);
2295
2300
  }
2301
+ if (agentModelsLocked() && parsed.data?.model?.trim()) {
2302
+ return c.json({ error: AGENT_MODELS_LOCKED_ERROR }, 409);
2303
+ }
2296
2304
  const blocked = await providerActionError([providerForExistingRun(run, parsed.data.runner)]);
2297
2305
  if (blocked)
2298
2306
  return c.json({ error: blocked }, 409);
@@ -2768,6 +2776,9 @@ export function createApp(deps) {
2768
2776
  if (!parsed.success) {
2769
2777
  return c.json({ error: parsed.error.issues.map((i) => i.message).join('; ') }, 400);
2770
2778
  }
2779
+ if (agentModelsLocked() && parsed.data?.model?.trim()) {
2780
+ return c.json({ error: AGENT_MODELS_LOCKED_ERROR }, 409);
2781
+ }
2771
2782
  if (todo.startedTaskId)
2772
2783
  return c.json({ error: 'already started' }, 409);
2773
2784
  let task = todoTaskText(todo);
@@ -3168,24 +3179,35 @@ export function createApp(deps) {
3168
3179
  });
3169
3180
  // The Settings → Agents knobs in one read (R6 Step 1.5) — an ADDITIVE
3170
3181
  // sibling of PUT /api/config below; /api/health keeps its protected shape.
3171
- const configAnswer = (config) => ({
3172
- baseBranch: config.baseBranch ?? null,
3173
- defaultRunner: config.defaultRunner,
3174
- systemPrompt: config.systemPrompt ?? null,
3175
- defaultModels: config.defaultModels ?? {},
3176
- maxParallel: config.maxParallel,
3177
- memoryLimitMb: config.memoryLimitMb ?? null,
3178
- // Count-based worktree retention (#483): keep the last N finished worktrees
3179
- // on disk. 0 = unlimited. Always materialized (schema default 10).
3180
- worktreeRetention: config.worktreeRetention,
3181
- // Live title updates (task auto-naming spec): tri-state — null means "no
3182
- // config key, the CEZ_TITLE_UPDATES env default (ON) decides".
3183
- liveTitleUpdates: config.liveTitleUpdates ?? null,
3184
- // Optional review gate (#489): tri-state null means "no config key, the
3185
- // CEZ_REVIEW_GATE env default (OFF) decides".
3186
- reviewGate: config.reviewGate ?? null,
3187
- });
3188
- api.get('/config', async (c) => c.json(configAnswer(await loadConfig(c.get('project').root))));
3182
+ const configAnswer = async (repoRoot, config) => {
3183
+ const nativeModels = await readAgentModelDefaults(repoRoot);
3184
+ return {
3185
+ baseBranch: config.baseBranch ?? null,
3186
+ defaultRunner: config.defaultRunner,
3187
+ systemPrompt: config.systemPrompt ?? null,
3188
+ // Native settings are the initial/default source. In locked mode they are
3189
+ // authoritative; otherwise a Cezar preset remains an explicit override.
3190
+ defaultModels: agentModelsLocked()
3191
+ ? nativeModels
3192
+ : { ...nativeModels, ...(config.defaultModels ?? {}) },
3193
+ modelsLocked: agentModelsLocked(),
3194
+ maxParallel: config.maxParallel,
3195
+ memoryLimitMb: config.memoryLimitMb ?? null,
3196
+ // Count-based worktree retention (#483): keep the last N finished worktrees
3197
+ // on disk. 0 = unlimited. Always materialized (schema default 10).
3198
+ worktreeRetention: config.worktreeRetention,
3199
+ // Live title updates (task auto-naming spec): tri-state null means "no
3200
+ // config key, the CEZ_TITLE_UPDATES env default (ON) decides".
3201
+ liveTitleUpdates: config.liveTitleUpdates ?? null,
3202
+ // Optional review gate (#489): tri-state — null means "no config key, the
3203
+ // CEZ_REVIEW_GATE env default (OFF) decides".
3204
+ reviewGate: config.reviewGate ?? null,
3205
+ };
3206
+ };
3207
+ api.get('/config', async (c) => {
3208
+ const repoRoot = c.get('project').root;
3209
+ return c.json(await configAnswer(repoRoot, await loadConfig(repoRoot)));
3210
+ });
3189
3211
  // Set/clear the agents' config knobs (Settings → Agents; the Repo tab's
3190
3212
  // base-branch picker). Merges into the RAW config.json so user keys
3191
3213
  // (skillsRepos…) survive and schema defaults are never materialized into
@@ -3224,6 +3246,9 @@ export function createApp(deps) {
3224
3246
  if (!parsed.success) {
3225
3247
  return c.json({ error: parsed.error.issues.map((i) => i.message).join('; ') }, 400);
3226
3248
  }
3249
+ if (agentModelsLocked() && parsed.data.defaultModels !== undefined) {
3250
+ return c.json({ error: AGENT_MODELS_LOCKED_ERROR }, 409);
3251
+ }
3227
3252
  const configPath = join(dataDir, 'config.json');
3228
3253
  let raw = {};
3229
3254
  try {
@@ -3308,7 +3333,7 @@ export function createApp(deps) {
3308
3333
  return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
3309
3334
  }
3310
3335
  // Pre-R6 answer shape ({baseBranch, defaultRunner}) + additive R6 fields.
3311
- return c.json(configAnswer(await loadConfig(repoRoot)));
3336
+ return c.json(await configAnswer(repoRoot, await loadConfig(repoRoot)));
3312
3337
  });
3313
3338
  const setAgentConfigSchema = z.object({
3314
3339
  content: z.string().max(2_000_000),