sprag-cli 3.61.0 → 3.62.0

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/docs/CODEX.ko.md CHANGED
@@ -158,19 +158,29 @@ Claude를 설치하지 않은 Codex 첫 사용자도 기록을 쌓기 전에 프
158
158
  sprag seed --agent codex
159
159
  sprag seed accept all --global --agent codex
160
160
  sprag delegate shared status --agent codex
161
+ sprag delegate on --agent codex
162
+ # 자동으로 정해진 난도별 모델을 바꾸고 싶을 때만:
161
163
  sprag delegate shared map T2 --from PARENT_MODEL --model SMALL_MODEL --effort high --agent codex
162
164
  sprag delegate shared map T1 --from PARENT_MODEL --model MEDIUM_MODEL --effort medium --agent codex
163
- sprag delegate on --agent codex
164
165
  ```
165
166
 
166
167
  등록 전에 전역과 프로젝트 범위를 선택합니다. 프로젝트에만 적용하려면 `--global` 대신
167
- `--project`를 지정하십시오. 위 모델명은 예시 자리표시자이므로, 공급자에서 사용할 수 있고
168
- 부모보다 저렴한 실제 모델 ID로 바꿔야 합니다. 매핑을 저장했다는 사실만으로 사용 가능 여부나
169
- 절감 효과를 확인한 것은 아닙니다. 공급자는 Codex 설정에서 읽으며 `--provider ID`로 지정할 수도 있습니다.
170
-
171
- 매핑은 출발 모델·공급자·난도가 일치할 때만 적용하고, 한 번 지정하면 승인된 모든 작업 유형에서
172
- 사용합니다. 매핑하지 않은 난도는 메인 모델이 처리합니다. Codex에서 승인할 때 `.claude` 파일은
173
- 만들지 않으며, 나중에 Claude를 시작하면 같은 정책을 Claude용 모델 표기로 생성합니다.
168
+ `--project`를 지정하십시오.
169
+
170
+ `map` 줄은 선택 사항입니다. 매핑하지 않은 난도는 Claude Code가 `haiku`와 `sonnet`을 실제 모델로
171
+ 풀듯이 자동으로 정해집니다. 부모 모델의 공급자에서 가격이 매겨져 있고(게이트웨이 `/model/info` 가격,
172
+ OpenAI 직접 호출이면 공개 가격), 부모보다 싸며, 이 사용자의 Codex 세션에서 이미 실행된 모델 가운데
173
+ 가장 싼 모델이 T2, 그다음 모델이 T1이 됩니다. 그런 모델이 하나뿐이면 T1은 메인 모델이 처리하고, 하나도
174
+ 없으면 두 난도 모두 메인 모델이 처리합니다. 자동 결정은 `delegate on` 상태에서만 동작하고, route-scan이
175
+ 기록한 실행 모델을 쓰며, 아무것도 저장하지 않으므로 가격이나 실행 이력이 바뀌면 그대로 따라갑니다.
176
+ `delegate shared status`와 설치 출력에 정해진 모델이 표시되고, 정해지지 않으면 그 이유가 표시됩니다.
177
+ 끄려면 `sprag delegate shared auto off --agent codex`를 실행하십시오.
178
+
179
+ 명시한 매핑은 해당 난도에서 자동 결정보다 우선합니다. 매핑은 출발 모델·공급자·난도가 일치할 때만
180
+ 적용하고, 한 번 지정하면 승인된 모든 작업 유형에서 사용합니다. 공급자는 Codex 설정에서 읽으며
181
+ `--provider ID`로 지정할 수도 있습니다. 매핑이나 자동 결정만으로 절감 효과를 확인한 것은 아닙니다.
182
+ Codex에서 승인할 때 `.claude` 파일은 만들지 않으며, 나중에 Claude를 시작하면 같은 정책을 Claude용
183
+ 모델 표기로 생성합니다.
174
184
 
175
185
  프롬프트 훅은 단순 작업에 T2, 여러 단계가 필요한 작업에 T1을 제시하고, 매핑된 난도마다 route 줄을
176
186
  따로 줍니다. 부모는 작업에 맞는 모델 하나를 선택하고 독립적인 작업 명세, 상한, `fork_turns "none"`과
package/docs/CODEX.md CHANGED
@@ -223,16 +223,27 @@ A Codex-first user needs no Claude installation or transcript history:
223
223
  sprag seed --agent codex
224
224
  sprag seed accept all --global --agent codex # or --project, after choosing scope
225
225
  sprag delegate shared status --agent codex
226
+ sprag delegate on --agent codex
227
+ # optional, to override the automatic tier models:
226
228
  sprag delegate shared map T2 --from PARENT_MODEL --model SMALL_MODEL --effort high --agent codex
227
229
  sprag delegate shared map T1 --from PARENT_MODEL --model MEDIUM_MODEL --effort medium --agent codex
228
- sprag delegate on --agent codex
229
230
  ```
230
231
 
231
- Replace the model placeholders with available, lower-cost models from your
232
- provider; mappings do not prove availability or savings. Each mapping applies
233
- to one exact parent model, provider, and tier, across every approved category.
234
- `--provider ID` overrides the provider read from Codex config. Without a mapping,
235
- that tier stays on the main agent. No Haiku/Sonnet-to-GPT equivalence is assumed.
232
+ The map lines are optional. A tier without a mapping resolves automatically,
233
+ the way Claude Code resolves `haiku` and `sonnet`: the cheapest model that is
234
+ priced on the parent's provider (gateway `/model/info` prices, or OpenAI list
235
+ prices for direct calls), costs less than the parent, and has already run in
236
+ your Codex sessions becomes T2, and the next one up becomes T1. With a single
237
+ such model T1 stays on the main agent; with none, both do. Resolution needs
238
+ `delegate on`, uses the route scan's observed models, and follows price or
239
+ history changes without storing anything. `delegate shared status` and the
240
+ install output show the resolved models and, when nothing resolves, why.
241
+ `sprag delegate shared auto off --agent codex` turns it off.
242
+
243
+ An explicit mapping wins for its tier. Each one applies to one exact parent
244
+ model, provider, and tier, across every approved category; `--provider ID`
245
+ overrides the provider read from Codex config. Mappings and automatic choices
246
+ do not prove savings, and no Haiku/Sonnet-to-GPT equivalence is assumed.
236
247
  Codex seed acceptance writes the common registry without creating `.claude`;
237
248
  Claude renders its own view when it is installed or starts later.
238
249
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sprag-cli",
3
- "version": "3.61.0",
3
+ "version": "3.62.0",
4
4
  "description": "Lower your Claude Code bill without changing how you work: simple tasks go to cheaper models, documents go in as compact Markdown, and the statusline shows spend and savings live. Works with Codex too.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,6 +11,8 @@ import { newRouteId, recordCodexDelegation } from './codex-ledger.js';
11
11
  import { readCodexTailLines } from './codex-parser.js';
12
12
  import { loadConfig } from './config.js';
13
13
  import { loadSharedModelRules, sharedModelRulesForProject, sharedRuleBounds, SHARED_RULE_TIERS } from './shared-model-rules.js';
14
+ import { codexPriceBook, readCodexPrices } from './codex-cache-policy.js';
15
+ import { codexRunCost } from './gateway-prices.js';
14
16
 
15
17
  export const CODEX_ROUTE_CATEGORIES = ['paste', 'translate', 'explore', 'read', 'check', 'run'];
16
18
  const MARKER = '<!-- sprag:codex:delegation -->';
@@ -41,10 +43,59 @@ export function codexSharedTargets(cfg) {
41
43
  });
42
44
  }
43
45
 
44
- export function sharedCodexModelRules({ cfg = loadConfig(), dir = userDataDir(), root, start = root,
46
+ // A request of this shape (input to output about 5:1) ranks models by price.
47
+ const RANKING_USAGE = { input: 10000, output: 2000 };
48
+ const routeScanFile = (dir) => join(dir, 'codex-route-scan.json');
49
+
50
+ function observedCodexModels(dir, provider) {
51
+ try {
52
+ const data = JSON.parse(readFileSync(routeScanFile(dir), 'utf8'));
53
+ const prefix = `${provider}|`;
54
+ return (Array.isArray(data?.observedModels) ? data.observedModels : [])
55
+ .filter((key) => typeof key === 'string' && key.startsWith(prefix)).map((key) => key.slice(prefix.length));
56
+ } catch { return []; }
57
+ }
58
+
59
+ /**
60
+ * The models Codex resolves T2 and T1 to when the user mapped none, the way
61
+ * Claude Code resolves `haiku` and `sonnet`. Only a model that is priced on the
62
+ * parent's provider, costs less than the parent, and has already run in this
63
+ * user's Codex sessions qualifies, so the hint never names a model the gateway
64
+ * cannot serve. The cheapest is T2 and the next one up is T1; with a single
65
+ * candidate T1 stays on the main agent. Returns { targets, reason }.
66
+ */
67
+ export function autoCodexSharedTargets({ dir = userDataDir(), home = codexUserDir(), model, provider, now = Date.now() } = {}) {
68
+ if (!safeId(model) || !safeId(provider)) return { targets: [], reason: 'unknown parent model or provider' };
69
+ const book = codexPriceBook(provider, readCodexPrices({ now, home, dir }), { home });
70
+ if (!book) return { targets: [], reason: `no price table for ${provider}` };
71
+ const cost = (m) => codexRunCost(RANKING_USAGE, book.prices[m]);
72
+ const parent = cost(model);
73
+ if (parent === null) return { targets: [], reason: `${model} is not priced on ${provider}` };
74
+ const cheaper = [...new Set(observedCodexModels(dir, provider))]
75
+ .filter((m) => m !== model && safeId(m)).map((m) => ({ model: m, usd: cost(m) }))
76
+ .filter((x) => x.usd !== null && x.usd < parent).sort((a, b) => a.usd - b.usd || a.model.localeCompare(b.model));
77
+ if (!cheaper.length) return { targets: [], reason: `no cheaper priced model has run in your Codex sessions on ${provider}` };
78
+ const targets = cheaper.slice(0, 2).map((x, i) => ({ tier: i === 0 ? 'T2' : 'T1', from: model, model: x.model, provider, auto: true }));
79
+ return { targets, reason: null };
80
+ }
81
+
82
+ /**
83
+ * Explicit mappings win per tier. Without one, a tier resolves automatically
84
+ * unless the user turned that off; resolution runs only for an enabled Codex
85
+ * delegation, so a caller without the hook's config never routes by accident.
86
+ */
87
+ export function codexTierTargets({ cfg = loadConfig(), dir = userDataDir(), home = codexUserDir(), model, provider = codexProviderName() } = {}) {
88
+ const explicit = codexSharedTargets(cfg).filter((t) => t.from === model && t.provider === provider);
89
+ if (cfg.codex?.delegate !== true || cfg.codex?.sharedRules?.auto === false) return explicit;
90
+ const auto = autoCodexSharedTargets({ dir, home, model, provider }).targets
91
+ .filter((t) => !explicit.some((e) => e.tier === t.tier));
92
+ return [...explicit, ...auto];
93
+ }
94
+
95
+ export function sharedCodexModelRules({ cfg = loadConfig(), dir = userDataDir(), home = codexUserDir(), root, start = root,
45
96
  model, provider = codexProviderName() } = {}) {
46
97
  if (cfg.codex?.sharedRules?.enabled === false) return [];
47
- const targets = codexSharedTargets(cfg).filter((t) => t.from === model && t.provider === provider);
98
+ const targets = codexTierTargets({ cfg, dir, home, model, provider });
48
99
  return sharedModelRulesForProject(loadSharedModelRules({ dir }), start).flatMap((rule) => {
49
100
  const target = targets.find((t) => t.tier === rule.tier);
50
101
  return target ? [{ ...rule, ...target, source: 'shared', status: 'active' }] : [];
@@ -210,7 +261,7 @@ export function codexRouteHint(payload, opts = {}) {
210
261
  record({ id, parentSessionId: payload?.session_id ?? null, turnId: payload?.turn_id ?? null, via: 'prompt',
211
262
  source: shared ? 'shared' : 'rule', category: route.category, scope: route.scope, from: payload?.model, to: route.model,
212
263
  provider: route.provider || provider, effort: route.effort ?? null, contextTokens: ctx, targetRoot: route.targetRoot ?? null,
213
- ...(shared ? { tier: route.tier, sharedSignature: route.sharedSignature, ...(offerId ? { offerId } : {}) }
264
+ ...(shared ? { tier: route.tier, sharedSignature: route.sharedSignature, ...(offerId ? { offerId } : {}), ...(route.auto ? { mapping: 'auto' } : {}) }
214
265
  : { ruleCreatedAt: route.createdAt ?? null }) }, { dir: opts.dir });
215
266
  } catch { /* Accounting is optional; the hint still applies. */ }
216
267
  return id;
@@ -268,7 +319,7 @@ export function codexDelegationTool(payload, { cfg = {}, root = payload?.cwd ||
268
319
  let rules = given;
269
320
  if (!rules) { try { rules = loadCodexModelRules({ dir }); } catch { rules = []; } }
270
321
  const provider = payload.model_provider || codexProviderName({ home });
271
- const routes = explicit ? [] : matchingRoutes(input.message, { model: payload.model, provider, root, start: payload.cwd, rules, cfg, dir });
322
+ const routes = explicit ? [] : matchingRoutes(input.message, { model: payload.model, provider, root, start: payload.cwd, rules, cfg, dir, home });
272
323
  // Only the caller can choose a shared policy's tier. A shared match without a
273
324
  // model goes back to the caller with the mapped choices instead of a guessed
274
325
  // downgrade, or a default target that ignores the tier.
@@ -17,13 +17,13 @@ export const CODEX_CAPABILITIES = [
17
17
  { feature: 'korean', support: 'supported', command: 'sprag korean status --agent codex', note: 'Session guidance and recognized write-target lint; shared preference.' },
18
18
  { feature: 'cohesion', support: 'supported', command: 'sprag cohesion status --agent codex', note: 'Shared English guidance preference.' },
19
19
  { feature: 'doc2md', support: 'supported', command: 'sprag doc2md status --agent codex', note: 'Shared converter, prompt paths, supported file reads, and recognized document/cache write guards; not arbitrary shell extraction.' },
20
- { feature: 'delegate', support: 'supported', command: 'sprag delegate on --agent codex', note: 'Native routing and shared delegation policies with explicit Codex tier mappings. Explicit models/custom roles preserved; bounds are guidance, not enforced limits.' },
20
+ { feature: 'delegate', support: 'supported', command: 'sprag delegate on --agent codex', note: 'Native routing and shared delegation policies; tier models resolve from priced models already run in Codex, or from explicit mappings. Explicit models/custom roles preserved; bounds are guidance, not enforced limits.' },
21
21
  { feature: 'routing-saved', support: 'partial', command: 'sprag route-scan savings --agent codex', note: 'Sprag-routed child usage with matching LiteLLM prices; counterfactual estimate, not billed savings. Unpriced runs stay unknown.' },
22
22
  { feature: 'cache-timer', support: 'partial', command: 'sprag cache status --refresh --agent codex', note: 'Documented minimum retention after recorded cache usage; LiteLLM deployments resolved through model/info. Unknown routes show age; exact expiry is not reported.' },
23
23
  { feature: 'mode', support: 'partial', command: 'sprag mode --agent codex', note: 'Labels, color, and timer apply to panel/statusline; Claude TTL buckets do not.' },
24
24
  { feature: 'upgrade', support: 'manual', command: 'sprag upgrade --print --agent codex', note: 'Skip the Claude npm postinstall; reinstall Codex hooks after upgrade.' },
25
25
  { feature: 'route-scan', support: 'supported', command: 'sprag route-scan --agent codex', note: 'Recurring simple turns grouped by project, provider, and parent model; explicit approval before routing.' },
26
- { feature: 'seed', support: 'supported', command: 'sprag seed --agent codex', note: 'Shared delegation policies plus agent-compatible ratchet presets. Explicit scope; Codex model mappings required. No Claude installation needed.' },
26
+ { feature: 'seed', support: 'supported', command: 'sprag seed --agent codex', note: 'Shared delegation policies plus agent-compatible ratchet presets. Explicit scope; tier models resolve automatically or by mapping. No Claude installation needed.' },
27
27
  { feature: 'transcript ratchet', support: 'supported', command: 'sprag --statusline --agent codex', note: 'Recent repeated tool failures become ratchet? candidates; no automatic rule registration.' },
28
28
  { feature: 'compact-window', support: 'native', note: 'Codex uses model_auto_compact_token_limit; no Claude autoCompactWindow heuristic.' },
29
29
  { feature: 'cost / exact cache expiry', support: 'unavailable', note: 'Not measured in rollout logs; never estimated with Anthropic prices.' },
@@ -1,7 +1,8 @@
1
1
  import { loadConfig, saveConfig } from '../config.js';
2
2
  import { configureCodexHooks } from '../codex-installer.js';
3
3
  import { validateCodexTarget, loadCodexModelRules, addCodexModelRule, removeCodexModelRule,
4
- validateCodexSharedTarget, codexSharedTargets, codexDelegateMinContext, DEFAULT_DELEGATE_MIN_CONTEXT } from '../codex-delegation.js';
4
+ validateCodexSharedTarget, codexSharedTargets, codexDelegateMinContext, DEFAULT_DELEGATE_MIN_CONTEXT,
5
+ autoCodexSharedTargets } from '../codex-delegation.js';
5
6
  import { findCodexCandidate, resolveCodexCandidate } from '../codex-route-scan.js';
6
7
  import { codexRoutingSavedTotals, loadCodexLedger } from '../codex-ledger.js';
7
8
  import { codexRuleHealth, codexRulesInReview } from '../codex-rule-health.js';
@@ -23,13 +24,23 @@ function printShared(cfg, { details = false } = {}) {
23
24
  for (const t of targets) console.log(`${t.provider} | ${t.from} | ${t.tier} -> ${t.model}${t.effort ? ` (${t.effort})` : ''}`);
24
25
  }
25
26
  // A mapping routes only sessions on the parent model it names, so a tier
26
- // mapped for another model still leaves the configured model unrouted.
27
- const mapped = (tier) => targets.some((t) => t.provider === provider && t.tier === tier && (!parent || t.from === parent));
28
- const missing = [...new Set(policies.map((r) => r.tier))].filter((tier) => !mapped(tier));
27
+ // mapped for another model still leaves the configured model unrouted. A tier
28
+ // without one resolves automatically, the way Claude Code resolves haiku/sonnet.
29
+ const own = (tier) => targets.find((t) => t.provider === provider && t.tier === tier && (!parent || t.from === parent));
30
+ const autoOn = cfg.codex?.sharedRules?.auto !== false;
31
+ const auto = autoOn && parent ? autoCodexSharedTargets({ model: parent, provider }) : { targets: [], reason: autoOn ? 'Codex config names no default model' : 'off' };
32
+ const tiers = [...new Set(policies.map((r) => r.tier))];
33
+ for (const tier of tiers) {
34
+ const t = own(tier) || auto.targets.find((a) => a.tier === tier);
35
+ if (t) console.log(`${tier} -> ${t.model}${t.effort ? ` (${t.effort})` : ''}${t.auto ? ' (auto: cheaper priced model already run in Codex)' : ''}`);
36
+ }
37
+ const missing = tiers.filter((tier) => !own(tier) && !auto.targets.some((a) => a.tier === tier));
29
38
  if (missing.length) {
30
- console.log(`Unmapped tiers for ${parent || 'any parent model'} on ${provider || 'unknown provider'}: ${missing.join(', ')}. `
39
+ console.log(`Unmapped tiers for ${parent || 'any parent model'} on ${provider || 'unknown provider'}: ${missing.join(', ')}`
40
+ + `${autoOn && auto.reason ? ` (auto: ${auto.reason})` : ''}. `
31
41
  + `Set: sprag delegate shared map <T1|T2> --from ${parent || '<parent-model>'} --model <target-model> --agent codex`);
32
42
  }
43
+ console.log(`Automatic tier models: ${autoOn ? 'on' : 'off'} (turn ${autoOn ? 'off' : 'on'}: sprag delegate shared auto ${autoOn ? 'off' : 'on'} --agent codex)`);
33
44
  if (!parent && targets.length) console.log('Codex config names no default model; each mapping routes only sessions on its --from model.');
34
45
  const minimum = codexDelegateMinContext(cfg);
35
46
  console.log(`Shared prompt guidance starts at ${minimum} parent input tokens${cfg.codex?.delegateMinContext === minimum ? '' : ' (default)'}. `
@@ -48,8 +59,8 @@ export function run({ args, getArg, hasFlag, root }) {
48
59
  const cfg = loadConfig();
49
60
  if (sub === 'shared') {
50
61
  const action = args[2] || 'status';
51
- if (!['status', 'on', 'off', 'map', 'unmap', 'min-context'].includes(action)) {
52
- throw new Error('Usage: delegate shared status|on|off|map <T1|T2>|unmap <T1|T2>|min-context <tokens|default> --agent codex');
62
+ if (!['status', 'on', 'off', 'map', 'unmap', 'min-context', 'auto'].includes(action)) {
63
+ throw new Error('Usage: delegate shared status|on|off|map <T1|T2>|unmap <T1|T2>|min-context <tokens|default>|auto on|off --agent codex');
53
64
  }
54
65
  if (hasFlag('--global') || hasFlag('--project')) throw new Error('Shared policies retain their approved scope; mappings do not change it.');
55
66
  const provided = (flag) => args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
@@ -71,6 +82,9 @@ export function run({ args, getArg, hasFlag, root }) {
71
82
  if (!targets.some(same)) throw new Error('No matching shared tier mapping; specify --from and the correct provider.');
72
83
  cfg.codex = { ...cfg.codex, sharedRules: { ...cfg.codex?.sharedRules, targets: targets.filter((t) => !same(t)) } };
73
84
  }
85
+ } else if (action === 'auto') {
86
+ if (!['on', 'off'].includes(args[3])) throw new Error('Usage: delegate shared auto on|off --agent codex');
87
+ cfg.codex = { ...cfg.codex, sharedRules: { ...cfg.codex?.sharedRules, auto: args[3] === 'on' } };
74
88
  } else if (action === 'min-context') {
75
89
  const value = args[3];
76
90
  if (value === 'default') {
@@ -32,6 +32,7 @@ Usage: sprag <command> --agent codex [options]
32
32
  Optional --provider <id> and --effort <level>
33
33
  delegate shared unmap T1|T2 Remove a mapping: --from <parent> [--provider <id>]
34
34
  delegate shared min-context N Parent input tokens before shared guidance; default resets
35
+ delegate shared auto on|off Resolve unmapped tiers from priced models already run in Codex
35
36
  route-scan [--refresh] Discover recurring simple turns in local logs
36
37
  route-scan dismiss R<N> Dismiss a candidate without registering a rule
37
38
  route-scan savings Attributed routing estimates; --refresh or --format json
@@ -418,7 +419,16 @@ export async function run({ args, version }) {
418
419
  console.log('After approval, start or resume Codex and run: sprag panel doctor --agent codex');
419
420
  if (panel.mode === 'window') console.log('Some Codex versions defer SessionStart until the first prompt. For immediate opening on typing codex: sprag panel shell install --agent codex (optional zsh integration).');
420
421
  console.log('Existing config.toml, Claude Code settings, and ratchet rules are preserved.');
421
- console.log('First-use delegation: sprag seed --agent codex, then sprag delegate shared status --agent codex. Approve a scope and map the tiers before enabling delegation. No Claude installation is required.');
422
+ try {
423
+ const { codexModelName, codexProviderName } = await import('../agent.js');
424
+ const { autoCodexSharedTargets } = await import('../codex-delegation.js');
425
+ const parent = codexModelName(), provider = codexProviderName();
426
+ const auto = parent ? autoCodexSharedTargets({ model: parent, provider }) : { targets: [], reason: 'Codex config names no default model' };
427
+ console.log(auto.targets.length
428
+ ? `Delegation tiers for ${parent} on ${provider} (auto): ${auto.targets.map((t) => `${t.tier} -> ${t.model}`).join(', ')}. Change: sprag delegate shared status --agent codex`
429
+ : `Delegation tiers: not resolved yet (${auto.reason}). They resolve once a cheaper priced model has run in Codex, or map one: sprag delegate shared map T2 --from <parent> --model <target> --agent codex`);
430
+ } catch (e) { debug('codex:auto-tiers', e); }
431
+ console.log('First-use delegation: sprag seed --agent codex to approve policies, then sprag delegate on --agent codex. No Claude installation is required.');
422
432
  console.log('Korean guidance is opt-in: sprag korean on --agent codex');
423
433
  return;
424
434
  }
package/src/seed-rules.js CHANGED
@@ -150,8 +150,8 @@ export function pendingSeeds({ lang = userLanguage(), root = findProjectRoot(),
150
150
 
151
151
  function codexSeedText(p, lang) {
152
152
  const text = lang === 'ko'
153
- ? `"${p.label}" 유형의 ${p.tier === 'T2' ? '단순' : '중간 난도'} 작업은 ${p.tier}에 위임합니다. 실행 모델은 Codex 매핑에서 정합니다.`
154
- : `${p.tier === 'T2' ? 'Simple' : 'Moderate'} "${p.labelEn}" tasks use ${p.tier}. The execution model comes from the Codex mapping.`;
153
+ ? `"${p.label}" 유형의 ${p.tier === 'T2' ? '단순' : '중간 난도'} 작업은 ${p.tier}에 위임합니다. 실행 모델은 Codex가 자동으로 정하거나 매핑으로 지정합니다.`
154
+ : `${p.tier === 'T2' ? 'Simple' : 'Moderate'} "${p.labelEn}" tasks use ${p.tier}. Codex resolves the execution model automatically or from a mapping.`;
155
155
  return composeRuleText(text, p, lang);
156
156
  }
157
157
 
@@ -292,7 +292,7 @@ export function seedOfferBlock({ lang = userLanguage(), root = findProjectRoot()
292
292
  ' 3. Decide one at a time: ask about each rule below and run its command as soon as they answer',
293
293
  ` 4. Register none: ${cmd('skip all')} (never offered again)`,
294
294
  'Always confirm the scope with the user before running an accept command.',
295
- 'Delegation policies are shared across Claude and Codex; approval retains the chosen scope. Codex execution also requires delegate on and explicit tier mappings: sprag delegate shared status --agent codex. Never assume Claude model names are Codex models.',
295
+ 'Delegation policies are shared across Claude and Codex; approval retains the chosen scope. Codex execution also requires delegate on; tier models resolve from cheaper priced models already run in Codex, or from mappings: sprag delegate shared status --agent codex. Never assume Claude model names are Codex models.',
296
296
  ...pending.map((s) => ` [${s.id}] ${s.ruleText}`),
297
297
  ].join('\n');
298
298
  }