@dzhechkov/harness-core 0.8.21 → 0.8.23

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 (54) hide show
  1. package/.dz-manifest.json +68 -48
  2. package/README.md +163 -0
  3. package/dist/amendment-trace.d.ts.map +1 -1
  4. package/dist/amendment-trace.js +5 -140
  5. package/dist/amendment-trace.js.map +1 -1
  6. package/dist/claude-hooks-assets.d.ts +3 -3
  7. package/dist/claude-hooks-assets.d.ts.map +1 -1
  8. package/dist/claude-hooks-assets.js +24 -11
  9. package/dist/claude-hooks-assets.js.map +1 -1
  10. package/dist/discrimination-gate.d.ts.map +1 -1
  11. package/dist/discrimination-gate.js +2 -1
  12. package/dist/discrimination-gate.js.map +1 -1
  13. package/dist/feature-adr-routing.d.ts +3 -1
  14. package/dist/feature-adr-routing.d.ts.map +1 -1
  15. package/dist/feature-adr-routing.js +17 -10
  16. package/dist/feature-adr-routing.js.map +1 -1
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/loop-blobs.generated.js +2 -2
  22. package/dist/loop-blobs.generated.js.map +1 -1
  23. package/dist/markdown-masker.d.ts +21 -0
  24. package/dist/markdown-masker.d.ts.map +1 -0
  25. package/dist/markdown-masker.js +119 -0
  26. package/dist/markdown-masker.js.map +1 -0
  27. package/dist/mutation-gate.d.ts +16 -7
  28. package/dist/mutation-gate.d.ts.map +1 -1
  29. package/dist/mutation-gate.js +141 -30
  30. package/dist/mutation-gate.js.map +1 -1
  31. package/dist/statusline.d.ts +14 -0
  32. package/dist/statusline.d.ts.map +1 -1
  33. package/dist/statusline.js +24 -1
  34. package/dist/statusline.js.map +1 -1
  35. package/dist/store-counts.d.ts +12 -0
  36. package/dist/store-counts.d.ts.map +1 -1
  37. package/dist/store-counts.js +30 -12
  38. package/dist/store-counts.js.map +1 -1
  39. package/dist/swarm-brief.d.ts.map +1 -1
  40. package/dist/swarm-brief.js +13 -144
  41. package/dist/swarm-brief.js.map +1 -1
  42. package/package.json +6 -6
  43. package/sbom.json +97 -47
  44. package/src/amendment-trace.ts +6 -123
  45. package/src/claude-hooks-assets.ts +24 -11
  46. package/src/discrimination-gate.ts +2 -1
  47. package/src/feature-adr-routing.ts +21 -11
  48. package/src/index.ts +2 -0
  49. package/src/loop-blobs.generated.ts +2 -2
  50. package/src/markdown-masker.ts +109 -0
  51. package/src/mutation-gate.ts +167 -31
  52. package/src/statusline.ts +35 -1
  53. package/src/store-counts.ts +44 -13
  54. package/src/swarm-brief.ts +13 -104
@@ -35,7 +35,10 @@
35
35
  import { harnessCoreDistDir } from './harness-core-location.js';
36
36
 
37
37
  /** Bump when the emitted BODY changes. Unlike Codex, Claude has no trust gate — this is provenance. */
38
- export const DZ_CLAUDE_HOOK_VERSION = 1;
38
+ // Поднято до 2 (2026-09-08, фича guard-narrow-unarmed-refusal): урезанный режим меняет наблюдаемое
39
+ // поведение хука у ПОТРЕБИТЕЛЯ. Без подъёма версии установленный хук остаётся старым, блокирующим
40
+ // любую команду в дереве без решателя, и починка до него не доезжает — находка QE major #1.
41
+ export const DZ_CLAUDE_HOOK_VERSION = 2;
39
42
 
40
43
  /**
41
44
  * The OWNERSHIP marker. A file carrying this line is one dz wrote and may replace; a file without it
@@ -99,8 +102,8 @@ export interface ClaudeHookAssetOptions {
99
102
  * The emitted `.claude/hooks/destructive-guard.cjs`.
100
103
  *
101
104
  * Thin by contract: read stdin, hand the payload to `decideDestructiveHook`, print, exit. Runtime
102
- * failures of ours exit 0 with one loud line, but a deterministically missing decision module exits
103
- * 2: setup cannot leave an armed-looking hook that allows every command until somebody builds it.
105
+ * failures of ours exit 0 with one loud line. Without the decision module, only literal recursive
106
+ * deletion is refused; every other request passes with an explicit partial-protection warning.
104
107
  */
105
108
  export function generateClaudeDestructiveHook(opts: ClaudeHookAssetOptions = {}): string {
106
109
  const installed = opts.installedDistDir === undefined ? harnessCoreDistDir() : opts.installedDistDir;
@@ -117,7 +120,7 @@ export function generateClaudeDestructiveHook(opts: ClaudeHookAssetOptions = {})
117
120
  // alone and only '--force' replaces it, after a timestamped backup.
118
121
  //
119
122
  // PreToolUse guard on Bash: a deletion by a LITERAL path into a protected store never runs.
120
- // All of the policy — the three outcomes, the refusal text, the limits the guard must name — lives
123
+ // The full policy — the three outcomes, the refusal text, the limits the guard must name — lives
121
124
  // in @dzhechkov/harness-core (destructive-guard.js classifies, destructive-guard-hook.js decides).
122
125
  // The same module decides for the Codex host, so both runtimes refuse the same commands in the
123
126
  // same words.
@@ -187,22 +190,32 @@ function failOpen(what) {
187
190
  process.exit(0);
188
191
  }
189
192
 
190
- /** One line, exit 2. No decider means the guard installation is incomplete, so nothing may run. */
191
- function failUnarmed(reason) {
192
- const line =
193
- 'DZ-DESTRUCTIVE: страж опасных команд не собран и не может проверить запрос — команда НЕ ВЫПОЛНЕНА. ' +
194
- 'Причина: ' + String(reason).replace(/\\s*\\n\\s*/g, ' ') +
193
+ /** Textual literal check only: no quoting, expansion or nested-shell parsing. */
194
+ function failUnarmed(reason, payload) {
195
+ const command = payload && ['Bash', 'bash', 'shell', 'local_shell'].includes(payload.tool_name) &&
196
+ payload.tool_input && typeof payload.tool_input.command === 'string' ? payload.tool_input.command : '';
197
+ const literalRecursive = /(?:^|[\\s;&|()])rm[ \\t]+(?:(?:-[a-zA-Z]+|--[a-z-]+)[ \\t]+)*(?:-[a-zA-Z]*[rR][a-zA-Z]*|--recursive)(?=[ \\t])/;
198
+ // Инструмент не из семейства Bash страж не судит НИ В ОДНОМ режиме, поэтому и предупреждать тут
199
+ // не о чем: в полном режиме такой вызов пропускается молча. Предупреждение обязано означать
200
+ // «я не смог рассудить КОМАНДУ ОБОЛОЧКИ», иначе оно станет фоном и перестанет читаться
201
+ // (риск R5 шага 3.5) — находка QE minor #3.
202
+ if (command === '') process.exit(0);
203
+ const refuse = literalRecursive.test(command);
204
+ const line = (refuse
205
+ ? 'DZ-DESTRUCTIVE: урезанный режим — буквальное рекурсивное удаление; команда НЕ ВЫПОЛНЕНА. '
206
+ : 'DZ-DESTRUCTIVE-WARN: урезанный режим, защита частичная — проверено только буквальное рекурсивное удаление, без разбора оболочки; команда ПРОПУЩЕНА. ') +
207
+ 'Для полной защиты нужен решатель. Причина: ' + String(reason).replace(/\\s*\\n\\s*/g, ' ') +
195
208
  ' Починка: npm install -g @dzhechkov/harness-cli@latest, затем dz setup --target claude-code.\\n';
196
209
  // Hook stderr is a pipe under the host and under spawnSync. An immediate process.exit can drop a
197
210
  // buffered write entirely, so write this installation verdict synchronously before exiting.
198
211
  writeSync(2, line);
199
- process.exit(2);
212
+ process.exit(refuse ? 2 : 0);
200
213
  }
201
214
 
202
215
  function onDecider(loaded, payload) {
203
216
  const decide = loaded.decide;
204
217
  if (decide === null) {
205
- failUnarmed(loaded.reason);
218
+ failUnarmed(loaded.reason, payload);
206
219
  return;
207
220
  }
208
221
 
@@ -608,7 +608,8 @@ export function classifyExecutionEvidence(
608
608
  const base = {
609
609
  exitCode,
610
610
  runner: toEvidenceRunner(red.runner),
611
- failureKind: red.kind,
611
+ // This gate has no infrastructure policy; preserve its existing unrecognised-run behavior.
612
+ failureKind: red.kind === 'runner-infrastructure' ? 'unrecognised' : red.kind,
612
613
  testsExecuted: countFailingTests(raw),
613
614
  targetSeen,
614
615
  } as const;
@@ -83,6 +83,8 @@ export interface RoutingEnv {
83
83
  readonly budget?: unknown;
84
84
  /** The productive family for design + code; absent defaults to Claude. */
85
85
  readonly primary?: 'claude' | 'codex';
86
+ /** Run tier affects planning only; absent uses the S/M flagship tier (ADR-001). */
87
+ readonly complexityTier?: 'S' | 'M' | 'L' | 'XL';
86
88
  }
87
89
 
88
90
  // ── USAGE-ADAPTIVE ROUTING (pre-emptive codex switch at >= usageThreshold) ────
@@ -186,9 +188,9 @@ export function decideUsageAction(
186
188
  // ── Data tables (data-only extensibility — gpt-5.6-ready) ───────────────────
187
189
 
188
190
  /** Known codex ids. Adding a new id (e.g. `'gpt-5.7'`) is a DATA-ONLY change. */
189
- export const KNOWN_CODEX: Record<string, number> = { auto: 1, 'gpt-5.5': 1, 'gpt-5.6': 1, 'gpt-5.6-luna': 1, 'gpt-5.6-terra': 1, 'gpt-5.6-sol': 1 };
191
+ export const KNOWN_CODEX: Record<string, number> = { auto: 1, 'gpt-5.5': 1, 'gpt-5.6': 1, 'gpt-5.6-luna': 1, 'gpt-5.6-terra': 1, 'gpt-5.6-sol': 1, 'gpt-6-astra': 1 };
190
192
 
191
- export type CodexTier = 'flagship' | 'workhorse' | 'high-volume';
193
+ export type CodexTier = 'premium' | 'flagship' | 'workhorse' | 'high-volume';
192
194
 
193
195
  /**
194
196
  * Capability tiers are routing data, separate from {@link KNOWN_CODEX}'s spellability role.
@@ -197,6 +199,9 @@ export type CodexTier = 'flagship' | 'workhorse' | 'high-volume';
197
199
  * timescale of days (probed 2026-08-18: 3 ids HTTP 400; probed 2026-08-29: all 3 exit 0).
198
200
  */
199
201
  export const CODEX_TIERS: Record<CodexTier, string> = {
202
+ // Astra is the premium tier for consequential decisions; Sol remains the flagship.
203
+ // The owner's live probe (2026-09-09) confirmed gpt-6-astra, not gpt-5.6-astra.
204
+ premium: 'gpt-6-astra',
200
205
  flagship: 'gpt-5.6-sol',
201
206
  workhorse: 'gpt-5.6-terra',
202
207
  'high-volume': 'gpt-5.6-luna',
@@ -320,17 +325,22 @@ export function budgetTable(
320
325
  codexHalf = { ...ROUTING_TABLES.claude.codex[mode.codex], qe: env.codexAvailable === false ? 'opus' : qeSpec };
321
326
  } else {
322
327
  const normal = mode.codex === 'normal';
323
- const design = codexCell(normal ? 'flagship' : 'workhorse', normal ? 'high' : 'medium', env);
328
+ const largePlan = env.complexityTier === 'L' || env.complexityTier === 'XL';
329
+ const work = codexCell(normal ? 'flagship' : 'workhorse', 'high', env);
330
+ const evidence = codexCell(normal ? 'workhorse' : 'high-volume', 'medium', env);
324
331
  codexHalf = {
325
- requirements: design,
326
- research: design,
327
- adr: design,
328
- ideation: design,
329
- ddd: design,
330
- architecture: design,
331
- plan: codexCell(normal ? 'flagship' : 'workhorse', normal ? 'high' : 'low', env),
332
- code: codexCell(normal ? 'flagship' : 'workhorse', 'medium', env),
332
+ router: evidence,
333
+ requirements: codexCell(normal ? 'flagship' : 'workhorse', 'medium', env),
334
+ research: evidence,
335
+ adr: codexCell(normal ? 'premium' : 'flagship', 'high', env),
336
+ ideation: work,
337
+ ddd: work,
338
+ architecture: codexCell(normal ? 'premium' : 'flagship', 'high', env),
339
+ plan: largePlan ? codexCell(normal ? 'premium' : 'flagship', 'high', env) : work,
340
+ code: work,
341
+ fleet: work,
333
342
  };
343
+
334
344
  }
335
345
  return { ...claudeHalf, ...codexHalf };
336
346
  }
package/src/index.ts CHANGED
@@ -1151,3 +1151,5 @@ export {
1151
1151
  } from './claude-hooks-assets.js';
1152
1152
  export type { ClaudeHookAssetOptions } from './claude-hooks-assets.js';
1153
1153
  export { harnessCoreDistDir, harnessCoreModuleDir } from './harness-core-location.js';
1154
+
1155
+ export { maskMarkdown } from './markdown-masker.js';
@@ -61,11 +61,11 @@ export const BLOBS: Record<string, LoopBlob> = {
61
61
  "model-resolver": {
62
62
  name: "model-resolver",
63
63
  version: "1.0.0",
64
- contentHash: "357a258796e553b2fbe94dfab26cf487a9fd189b4927836f261185215392dfaa",
64
+ contentHash: "1a62a5ebe31aaa5fa25ed82cd6e4cde15482c6cb099faa262af518bdd4f8b609",
65
65
  sourcePath: "packages/@dzhechkov/harness-core/src/feature-adr-routing.ts",
66
66
  requires: [],
67
67
  exports: ["specToOpts","resolveStageModel","KNOWN_CODEX","mergeOpts","stageLabel","modelLabel"],
68
- code: "const STAGE_EFFORT = { override: {\n router: 'medium',\n requirements: 'medium',\n research: 'medium',\n adr: 'high',\n ideation: 'medium',\n ddd: 'high',\n architecture: 'high',\n plan: 'high',\n code: 'medium',\n qe: 'high',\n fleet: 'medium',\n } };\nfunction topCodexId(env) {\n return env.CODEX_MODEL !== 'auto' ? env.CODEX_MODEL : CODEX_TIERS.flagship;\n}\nconst KNOWN_CODEX = { auto: 1, 'gpt-5.5': 1, 'gpt-5.6': 1, 'gpt-5.6-luna': 1, 'gpt-5.6-terra': 1, 'gpt-5.6-sol': 1 };\nconst CODEX_TIERS = {\n flagship: 'gpt-5.6-sol',\n workhorse: 'gpt-5.6-terra',\n 'high-volume': 'gpt-5.6-luna',\n};\nfunction codexIdForTier(tier, env) {\n return env.CODEX_MODEL !== 'auto' ? env.CODEX_MODEL : CODEX_TIERS[tier];\n}\nconst BUDGET_PRESETS = {\n normal: { claude: 'normal', codex: 'normal' },\n eco: { claude: 'eco', codex: 'eco' },\n hybrid: { claude: 'eco', codex: 'normal' },\n};\nfunction resolveBudgetMode(raw) {\n if (raw === undefined)\n return BUDGET_PRESETS.normal;\n if (typeof raw === 'string') {\n const preset = BUDGET_PRESETS[raw];\n if (!preset)\n throw new RangeError('budget: unknown preset \"' + raw + '\" — valid: normal|eco|hybrid');\n return preset;\n }\n if (raw && typeof raw === 'object') {\n const value = raw;\n for (const key of Object.keys(value)) {\n if (key !== 'claude' && key !== 'codex') {\n throw new RangeError('budget: unknown family key \"' + key + '\" — valid: claude|codex');\n }\n }\n for (const key of ['claude', 'codex']) {\n const level = value[key];\n if (level !== undefined && level !== 'normal' && level !== 'eco') {\n throw new RangeError('budget.' + key + ': unknown level \"' + level + '\" — valid: normal|eco');\n }\n }\n return {\n claude: value.claude || 'normal',\n codex: value.codex || 'normal',\n };\n }\n throw new RangeError('budget: expected a preset name or {claude,codex} object, got ' + typeof raw);\n}\nconst CLAUDE_NAMES = { fable: 1, opus: 1, sonnet: 1, haiku: 1 };\nconst VALID_REASONING = { none: 1, minimal: 1, low: 1, medium: 1, high: 1, xhigh: 1, max: 1 };\nconst DEFAULT_MODELS = {\n router: 'fable',\n requirements: 'sonnet',\n research: 'sonnet',\n adr: 'opus',\n ideation: 'sonnet',\n ddd: 'opus',\n architecture: 'opus',\n plan: 'sonnet',\n code: null,\n qe: null,\n fleet: 'sonnet',\n};\nconst ROUTING_TABLES = {\n claude: {\n claude: {\n normal: { router: 'sonnet', requirements: 'sonnet', research: 'sonnet', adr: 'fable', ideation: 'sonnet', ddd: 'fable', architecture: 'fable', plan: 'opus', code: 'sonnet', fleet: 'sonnet' },\n eco: { router: 'sonnet', requirements: 'sonnet', research: 'sonnet', adr: 'opus', ideation: 'sonnet', ddd: 'opus', architecture: 'opus', plan: 'sonnet', code: 'sonnet', fleet: 'sonnet' },\n },\n codex: { normal: {}, eco: {} },\n },\n codex: {\n claude: {\n normal: { router: 'sonnet', qe: 'sonnet', fleet: 'sonnet' },\n eco: { router: 'sonnet', qe: 'sonnet', fleet: 'sonnet' },\n },\n codex: { normal: {}, eco: {} },\n },\n};\nfunction codexCell(tier, effort, env) {\n return 'codex:' + codexIdForTier(tier, env) + ':' + effort;\n}\nfunction budgetTable(primary, mode, env) {\n const claudeHalf = ROUTING_TABLES[primary].claude[mode.claude];\n let codexHalf;\n if (primary === 'claude') {\n const qeSpec = mode.codex === 'normal'\n ? codexCell('flagship', 'high', env)\n : codexCell('workhorse', 'medium', env);\n codexHalf = { ...ROUTING_TABLES.claude.codex[mode.codex], qe: env.codexAvailable === false ? 'opus' : qeSpec };\n }\n else {\n const normal = mode.codex === 'normal';\n const design = codexCell(normal ? 'flagship' : 'workhorse', normal ? 'high' : 'medium', env);\n codexHalf = {\n requirements: design,\n research: design,\n adr: design,\n ideation: design,\n ddd: design,\n architecture: design,\n plan: codexCell(normal ? 'flagship' : 'workhorse', normal ? 'high' : 'low', env),\n code: codexCell(normal ? 'flagship' : 'workhorse', 'medium', env),\n };\n }\n return { ...claudeHalf, ...codexHalf };\n}\nfunction specToOpts(spec, env) {\n const log = env.log || function () { };\n if (!spec)\n return {};\n const parts = String(spec).split(':');\n const head = parts[0] || '';\n if (head === 'codex') {\n let id = parts[1] || env.CODEX_MODEL;\n if (id !== 'auto' && !KNOWN_CODEX[id]) {\n log('models: unknown codex id ' + id + ' — using ' + env.CODEX_MODEL);\n id = env.CODEX_MODEL;\n }\n let reasoning = parts[2] || 'high';\n if (!VALID_REASONING[reasoning]) {\n throw new RangeError('models: invalid reasoning \"' + reasoning + '\" — valid: ' + Object.keys(VALID_REASONING).join('|'));\n }\n return { agentType: 'codex:codex-rescue', codexModel: id, _reasoning: reasoning };\n }\n if (CLAUDE_NAMES[head])\n return { model: head };\n log('models: unknown spec ' + spec + ' — session-inherited');\n return {};\n}\nfunction resolveCoderSpec(env) {\n if (env.CODER === 'codex' || env.CODER === 'codex-fallback')\n return 'codex:' + env.CODEX_MODEL + ':high';\n return 'opus';\n}\nfunction coderIsCodex(env) {\n const codeSpec = env.MODELS.code;\n if (codeSpec !== undefined && codeSpec !== null)\n return String(codeSpec).split(':')[0] === 'codex';\n if (env.CODER === 'codex' || env.CODER === 'codex-fallback')\n return true;\n return env.primary === 'codex';\n}\nfunction resolveQeSpecForCoder(coderCodex, env) {\n if (coderCodex)\n return 'sonnet';\n const CODEX_AVAILABLE = env.codexAvailable !== false;\n if (!CODEX_AVAILABLE)\n return 'opus';\n const budget = resolveBudgetMode(env.budget);\n return budget.codex === 'eco'\n ? 'codex:' + codexIdForTier('workhorse', env) + ':medium'\n : 'codex:' + codexIdForTier('flagship', env) + ':high';\n}\nfunction resolveQeSpec(env) {\n return resolveQeSpecForCoder(coderIsCodex(env), env);\n}\nfunction routingRequested(env) {\n return (Object.keys(env.MODELS).length > 0 ||\n env.primary !== undefined ||\n env.budget !== undefined ||\n env.PLANNER === 'codex' ||\n env.CODER === 'codex' ||\n env.CODER === 'codex-fallback' ||\n env.QE_REVIEWER === 'codex' ||\n env.QE_REVIEWER === 'codex-fallback');\n}\nfunction resolveStageModel(stage, env) {\n return resolveStageDecision(stage, env).opts;\n}\nfunction specFamily(spec) {\n return (spec && String(spec).split(':')[0] === 'codex') ? 'codex' : 'claude';\n}\nfunction qeReasonForFamilies(coderCodex, qeSpec) {\n if (specFamily(qeSpec) === (coderCodex ? 'codex' : 'claude'))\n return 'qe-same-family-degraded';\n return 'qe-cross-family';\n}\nfunction effectiveSpec(opts) {\n if (opts && opts.agentType === 'codex:codex-rescue')\n return 'codex:' + opts.codexModel + ':' + opts._reasoning;\n if (opts && opts.model)\n return opts.model;\n return null;\n}\nfunction specDegradation(spec, opts, env) {\n if (!spec)\n return null;\n const parts = String(spec).split(':');\n const head = parts[0] || '';\n if (head === 'codex') {\n const requested = parts[1] || env.CODEX_MODEL;\n if (opts.codexModel !== requested)\n return 'codex-id-substituted';\n return null;\n }\n if (!CLAUDE_NAMES[head])\n return 'spec-unrecognised';\n return null;\n}\nfunction decisionFor(base, spec, opts, env) {\n const deg = specDegradation(spec, opts, env);\n if (deg !== null)\n return { opts: opts, spec: effectiveSpec(opts), reason: deg };\n return { opts: opts, spec: effectiveSpec(opts), reason: base };\n}\nfunction decideFromSpec(base, stage, spec, env) {\n if (stage === 'code' && (spec === null || spec === undefined)) {\n const s = resolveCoderSpec(env);\n return decisionFor(base, s, specToOpts(s, env), env);\n }\n if (stage === 'qe' && (spec === null || spec === undefined)) {\n const s = resolveQeSpec(env);\n return decisionFor(base, s, specToOpts(s, env), env);\n }\n return decisionFor(base, spec, specToOpts(spec, env), env);\n}\nfunction resolveStageDecision(stage, env) {\n if (env.usageOverride) {\n const r = (env.usageReasoning && env.usageReasoning[stage]) || STAGE_EFFORT.override[stage] || 'medium';\n const s = 'codex:' + topCodexId(env) + ':' + r;\n const o = specToOpts(s, env);\n o._usageSwitched = true;\n return decisionFor('usage-override', s, o, env);\n }\n const spec = env.MODELS[stage];\n if (spec !== undefined)\n return decideFromSpec('explicit-models', stage, spec, env);\n if (!routingRequested(env))\n return { opts: {}, spec: null, reason: 'routing-not-requested' };\n if (stage === 'code' && (env.CODER === 'codex' || env.CODER === 'codex-fallback')) {\n const s = resolveCoderSpec(env);\n return decisionFor('coder-knob-codex', s, specToOpts(s, env), env);\n }\n if (stage === 'plan' && env.PLANNER === 'codex') {\n const s = 'codex:' + env.CODEX_MODEL + ':high';\n return decisionFor('planner-knob-codex', s, specToOpts(s, env), env);\n }\n if (stage === 'qe') {\n const s = resolveQeSpec(env);\n return decisionFor(qeReasonForFamilies(coderIsCodex(env), s), s, specToOpts(s, env), env);\n }\n const resolvedPrimary = env.primary || 'claude';\n const cell = budgetTable(resolvedPrimary, resolveBudgetMode(env.budget), env)[stage];\n if (cell !== undefined)\n return decideFromSpec('budget-table-cell', stage, cell, env);\n return decideFromSpec('default-models', stage, DEFAULT_MODELS[stage], env);\n}\nfunction modelLabel(opts) {\n if (opts && opts.agentType === 'codex:codex-rescue') {\n const base = 'codex:' + opts.codexModel + ':' + opts._reasoning;\n return opts._usageSwitched ? base + ' (usage-switched)' : base;\n }\n if (opts && opts.model)\n return opts.model;\n return 'session';\n}\nfunction stageLabel(base, opts) {\n const m = modelLabel(opts);\n return m === 'session' ? base : base + ' · ' + m;\n}\nfunction mergeOpts(base, extra) {\n const out = {};\n for (const k in base)\n out[k] = base[k];\n for (const k in extra)\n out[k] = extra[k];\n return out;\n}",
68
+ code: "const STAGE_EFFORT = { override: {\n router: 'medium',\n requirements: 'medium',\n research: 'medium',\n adr: 'high',\n ideation: 'medium',\n ddd: 'high',\n architecture: 'high',\n plan: 'high',\n code: 'medium',\n qe: 'high',\n fleet: 'medium',\n } };\nfunction topCodexId(env) {\n return env.CODEX_MODEL !== 'auto' ? env.CODEX_MODEL : CODEX_TIERS.flagship;\n}\nconst KNOWN_CODEX = { auto: 1, 'gpt-5.5': 1, 'gpt-5.6': 1, 'gpt-5.6-luna': 1, 'gpt-5.6-terra': 1, 'gpt-5.6-sol': 1, 'gpt-6-astra': 1 };\nconst CODEX_TIERS = {\n premium: 'gpt-6-astra',\n flagship: 'gpt-5.6-sol',\n workhorse: 'gpt-5.6-terra',\n 'high-volume': 'gpt-5.6-luna',\n};\nfunction codexIdForTier(tier, env) {\n return env.CODEX_MODEL !== 'auto' ? env.CODEX_MODEL : CODEX_TIERS[tier];\n}\nconst BUDGET_PRESETS = {\n normal: { claude: 'normal', codex: 'normal' },\n eco: { claude: 'eco', codex: 'eco' },\n hybrid: { claude: 'eco', codex: 'normal' },\n};\nfunction resolveBudgetMode(raw) {\n if (raw === undefined)\n return BUDGET_PRESETS.normal;\n if (typeof raw === 'string') {\n const preset = BUDGET_PRESETS[raw];\n if (!preset)\n throw new RangeError('budget: unknown preset \"' + raw + '\" — valid: normal|eco|hybrid');\n return preset;\n }\n if (raw && typeof raw === 'object') {\n const value = raw;\n for (const key of Object.keys(value)) {\n if (key !== 'claude' && key !== 'codex') {\n throw new RangeError('budget: unknown family key \"' + key + '\" — valid: claude|codex');\n }\n }\n for (const key of ['claude', 'codex']) {\n const level = value[key];\n if (level !== undefined && level !== 'normal' && level !== 'eco') {\n throw new RangeError('budget.' + key + ': unknown level \"' + level + '\" — valid: normal|eco');\n }\n }\n return {\n claude: value.claude || 'normal',\n codex: value.codex || 'normal',\n };\n }\n throw new RangeError('budget: expected a preset name or {claude,codex} object, got ' + typeof raw);\n}\nconst CLAUDE_NAMES = { fable: 1, opus: 1, sonnet: 1, haiku: 1 };\nconst VALID_REASONING = { none: 1, minimal: 1, low: 1, medium: 1, high: 1, xhigh: 1, max: 1 };\nconst DEFAULT_MODELS = {\n router: 'fable',\n requirements: 'sonnet',\n research: 'sonnet',\n adr: 'opus',\n ideation: 'sonnet',\n ddd: 'opus',\n architecture: 'opus',\n plan: 'sonnet',\n code: null,\n qe: null,\n fleet: 'sonnet',\n};\nconst ROUTING_TABLES = {\n claude: {\n claude: {\n normal: { router: 'sonnet', requirements: 'sonnet', research: 'sonnet', adr: 'fable', ideation: 'sonnet', ddd: 'fable', architecture: 'fable', plan: 'opus', code: 'sonnet', fleet: 'sonnet' },\n eco: { router: 'sonnet', requirements: 'sonnet', research: 'sonnet', adr: 'opus', ideation: 'sonnet', ddd: 'opus', architecture: 'opus', plan: 'sonnet', code: 'sonnet', fleet: 'sonnet' },\n },\n codex: { normal: {}, eco: {} },\n },\n codex: {\n claude: {\n normal: { router: 'sonnet', qe: 'sonnet', fleet: 'sonnet' },\n eco: { router: 'sonnet', qe: 'sonnet', fleet: 'sonnet' },\n },\n codex: { normal: {}, eco: {} },\n },\n};\nfunction codexCell(tier, effort, env) {\n return 'codex:' + codexIdForTier(tier, env) + ':' + effort;\n}\nfunction budgetTable(primary, mode, env) {\n const claudeHalf = ROUTING_TABLES[primary].claude[mode.claude];\n let codexHalf;\n if (primary === 'claude') {\n const qeSpec = mode.codex === 'normal'\n ? codexCell('flagship', 'high', env)\n : codexCell('workhorse', 'medium', env);\n codexHalf = { ...ROUTING_TABLES.claude.codex[mode.codex], qe: env.codexAvailable === false ? 'opus' : qeSpec };\n }\n else {\n const normal = mode.codex === 'normal';\n const largePlan = env.complexityTier === 'L' || env.complexityTier === 'XL';\n const work = codexCell(normal ? 'flagship' : 'workhorse', 'high', env);\n const evidence = codexCell(normal ? 'workhorse' : 'high-volume', 'medium', env);\n codexHalf = {\n router: evidence,\n requirements: codexCell(normal ? 'flagship' : 'workhorse', 'medium', env),\n research: evidence,\n adr: codexCell(normal ? 'premium' : 'flagship', 'high', env),\n ideation: work,\n ddd: work,\n architecture: codexCell(normal ? 'premium' : 'flagship', 'high', env),\n plan: largePlan ? codexCell(normal ? 'premium' : 'flagship', 'high', env) : work,\n code: work,\n fleet: work,\n };\n }\n return { ...claudeHalf, ...codexHalf };\n}\nfunction specToOpts(spec, env) {\n const log = env.log || function () { };\n if (!spec)\n return {};\n const parts = String(spec).split(':');\n const head = parts[0] || '';\n if (head === 'codex') {\n let id = parts[1] || env.CODEX_MODEL;\n if (id !== 'auto' && !KNOWN_CODEX[id]) {\n log('models: unknown codex id ' + id + ' — using ' + env.CODEX_MODEL);\n id = env.CODEX_MODEL;\n }\n let reasoning = parts[2] || 'high';\n if (!VALID_REASONING[reasoning]) {\n throw new RangeError('models: invalid reasoning \"' + reasoning + '\" — valid: ' + Object.keys(VALID_REASONING).join('|'));\n }\n return { agentType: 'codex:codex-rescue', codexModel: id, _reasoning: reasoning };\n }\n if (CLAUDE_NAMES[head])\n return { model: head };\n log('models: unknown spec ' + spec + ' — session-inherited');\n return {};\n}\nfunction resolveCoderSpec(env) {\n if (env.CODER === 'codex' || env.CODER === 'codex-fallback')\n return 'codex:' + env.CODEX_MODEL + ':high';\n return 'opus';\n}\nfunction coderIsCodex(env) {\n const codeSpec = env.MODELS.code;\n if (codeSpec !== undefined && codeSpec !== null)\n return String(codeSpec).split(':')[0] === 'codex';\n if (env.CODER === 'codex' || env.CODER === 'codex-fallback')\n return true;\n return env.primary === 'codex';\n}\nfunction resolveQeSpecForCoder(coderCodex, env) {\n if (coderCodex)\n return 'sonnet';\n const CODEX_AVAILABLE = env.codexAvailable !== false;\n if (!CODEX_AVAILABLE)\n return 'opus';\n const budget = resolveBudgetMode(env.budget);\n return budget.codex === 'eco'\n ? 'codex:' + codexIdForTier('workhorse', env) + ':medium'\n : 'codex:' + codexIdForTier('flagship', env) + ':high';\n}\nfunction resolveQeSpec(env) {\n return resolveQeSpecForCoder(coderIsCodex(env), env);\n}\nfunction routingRequested(env) {\n return (Object.keys(env.MODELS).length > 0 ||\n env.primary !== undefined ||\n env.budget !== undefined ||\n env.PLANNER === 'codex' ||\n env.CODER === 'codex' ||\n env.CODER === 'codex-fallback' ||\n env.QE_REVIEWER === 'codex' ||\n env.QE_REVIEWER === 'codex-fallback');\n}\nfunction resolveStageModel(stage, env) {\n return resolveStageDecision(stage, env).opts;\n}\nfunction specFamily(spec) {\n return (spec && String(spec).split(':')[0] === 'codex') ? 'codex' : 'claude';\n}\nfunction qeReasonForFamilies(coderCodex, qeSpec) {\n if (specFamily(qeSpec) === (coderCodex ? 'codex' : 'claude'))\n return 'qe-same-family-degraded';\n return 'qe-cross-family';\n}\nfunction effectiveSpec(opts) {\n if (opts && opts.agentType === 'codex:codex-rescue')\n return 'codex:' + opts.codexModel + ':' + opts._reasoning;\n if (opts && opts.model)\n return opts.model;\n return null;\n}\nfunction specDegradation(spec, opts, env) {\n if (!spec)\n return null;\n const parts = String(spec).split(':');\n const head = parts[0] || '';\n if (head === 'codex') {\n const requested = parts[1] || env.CODEX_MODEL;\n if (opts.codexModel !== requested)\n return 'codex-id-substituted';\n return null;\n }\n if (!CLAUDE_NAMES[head])\n return 'spec-unrecognised';\n return null;\n}\nfunction decisionFor(base, spec, opts, env) {\n const deg = specDegradation(spec, opts, env);\n if (deg !== null)\n return { opts: opts, spec: effectiveSpec(opts), reason: deg };\n return { opts: opts, spec: effectiveSpec(opts), reason: base };\n}\nfunction decideFromSpec(base, stage, spec, env) {\n if (stage === 'code' && (spec === null || spec === undefined)) {\n const s = resolveCoderSpec(env);\n return decisionFor(base, s, specToOpts(s, env), env);\n }\n if (stage === 'qe' && (spec === null || spec === undefined)) {\n const s = resolveQeSpec(env);\n return decisionFor(base, s, specToOpts(s, env), env);\n }\n return decisionFor(base, spec, specToOpts(spec, env), env);\n}\nfunction resolveStageDecision(stage, env) {\n if (env.usageOverride) {\n const r = (env.usageReasoning && env.usageReasoning[stage]) || STAGE_EFFORT.override[stage] || 'medium';\n const s = 'codex:' + topCodexId(env) + ':' + r;\n const o = specToOpts(s, env);\n o._usageSwitched = true;\n return decisionFor('usage-override', s, o, env);\n }\n const spec = env.MODELS[stage];\n if (spec !== undefined)\n return decideFromSpec('explicit-models', stage, spec, env);\n if (!routingRequested(env))\n return { opts: {}, spec: null, reason: 'routing-not-requested' };\n if (stage === 'code' && (env.CODER === 'codex' || env.CODER === 'codex-fallback')) {\n const s = resolveCoderSpec(env);\n return decisionFor('coder-knob-codex', s, specToOpts(s, env), env);\n }\n if (stage === 'plan' && env.PLANNER === 'codex') {\n const s = 'codex:' + env.CODEX_MODEL + ':high';\n return decisionFor('planner-knob-codex', s, specToOpts(s, env), env);\n }\n if (stage === 'qe') {\n const s = resolveQeSpec(env);\n return decisionFor(qeReasonForFamilies(coderIsCodex(env), s), s, specToOpts(s, env), env);\n }\n const resolvedPrimary = env.primary || 'claude';\n const cell = budgetTable(resolvedPrimary, resolveBudgetMode(env.budget), env)[stage];\n if (cell !== undefined)\n return decideFromSpec('budget-table-cell', stage, cell, env);\n return decideFromSpec('default-models', stage, DEFAULT_MODELS[stage], env);\n}\nfunction modelLabel(opts) {\n if (opts && opts.agentType === 'codex:codex-rescue') {\n const base = 'codex:' + opts.codexModel + ':' + opts._reasoning;\n return opts._usageSwitched ? base + ' (usage-switched)' : base;\n }\n if (opts && opts.model)\n return opts.model;\n return 'session';\n}\nfunction stageLabel(base, opts) {\n const m = modelLabel(opts);\n return m === 'session' ? base : base + ' · ' + m;\n}\nfunction mergeOpts(base, extra) {\n const out = {};\n for (const k in base)\n out[k] = base[k];\n for (const k in extra)\n out[k] = extra[k];\n return out;\n}",
69
69
  },
70
70
  "usage-probes": {
71
71
  name: "usage-probes",
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Canonical Markdown block masker; copied byte-for-byte as markdown-masker.mjs beside K2.
3
+ * Keep this file valid JavaScript (inferred TS types, no build needed by the copy).
4
+ *
5
+ * CommonMark fences and type-2 HTML comments; same UTF-16 length and newline positions.
6
+ * Inline code cannot open an HTML block. HTML delimiters within a block are consumed left to
7
+ * right, including close/reopen on one line. This is not a complete CommonMark parser.
8
+ *
9
+ * Reader policies are deliberate: amendment-trace restores unclosed blocks; brief/K2 hide them.
10
+ * Four-space code is still unsupported by default. ONLY brief keeps its pre-existing policy.
11
+ * Containers, tab indentation and HTML block types other than comments remain unsupported.
12
+ * Callbacks expose line facts; callers own semantic diagnostics and list-barrier representation.
13
+ */
14
+ export function maskMarkdown(md = '', {
15
+ unclosed = 'restore',
16
+ indentedCode = false,
17
+ inlineComments = false,
18
+ onMasked = (_line = 0) => {},
19
+ onDisputed = (_line = 0) => {},
20
+ } = {}) {
21
+ const lines = md.split('\n');
22
+ const out = lines.slice();
23
+ const masked = lines.map(() => false);
24
+ let state = 'text';
25
+ let marker = '';
26
+ let markerLength = 0;
27
+ let openedAt = -1;
28
+ let nestedOpener = false;
29
+ let disputed = false;
30
+ for (let i = 0; i < lines.length; i++) {
31
+ const line = lines[i] ?? '';
32
+ const blank = () => { out[i] = ' '.repeat(line.length); masked[i] = true; };
33
+ if (state === 'fence') {
34
+ blank();
35
+ const close = /^ {0,3}(`{3,}|~{3,})\s*$/.exec(line);
36
+ if (close) {
37
+ const run = close[1] ?? '';
38
+ if (run[0] === marker && run.length >= markerLength) {
39
+ state = 'text';
40
+ openedAt = -1;
41
+ }
42
+ }
43
+ continue;
44
+ }
45
+ if (state === 'text') {
46
+ const fence = /^ {0,3}(`{3,}|~{3,})([^\n]*)$/.exec(line);
47
+ if (fence && !(fence[1]?.[0] === '`' && fence[2]?.includes('`'))) {
48
+ const run = fence[1] ?? '';
49
+ state = 'fence';
50
+ marker = run[0] ?? '';
51
+ markerLength = run.length;
52
+ openedAt = i;
53
+ blank();
54
+ continue;
55
+ }
56
+ if (indentedCode && /^ {4,}/.test(line)) {
57
+ blank();
58
+ continue;
59
+ }
60
+ }
61
+ // Outside HTML only a block opener counts: code-spanned delimiters in prose are inert.
62
+ // Inside HTML, backticks are literal and do not protect a delimiter.
63
+ const htmlStart = /^ {0,3}<!--/.test(line);
64
+ const wasDisputed = disputed;
65
+ // Ambiguity is diagnostic state, never permission to scan otherwise-visible prose.
66
+ // Brief deliberately keeps that diagnostic across blocks until the author's outer close;
67
+ // block-only readers must not hide an unrelated arrow or opener because it is pending.
68
+ if (state === 'html' || htmlStart || inlineComments) {
69
+ let maskLine = state === 'html' || htmlStart;
70
+ const tokens = [...line.matchAll(/`+|<!--|-->/g)];
71
+ for (let t = 0; t < tokens.length; t++) {
72
+ const token = tokens[t];
73
+ if (!token) continue;
74
+ if (token[0][0] === '`') {
75
+ // Code spans require an EXACT matching run; a shorter embedded run is literal.
76
+ // HTML blocks treat backticks literally. Inline-comment support is brief's existing
77
+ // policy; other readers only enter this scan at a block opener or while disputed.
78
+ if (state !== 'html') {
79
+ const end = tokens.findIndex((next, j) => j > t && next[0] === token[0]);
80
+ if (end >= 0) t = end;
81
+ }
82
+ continue;
83
+ }
84
+ if (token[0] === '<!--') {
85
+ if (state === 'html') nestedOpener = true;
86
+ else { state = 'html'; openedAt = i; }
87
+ maskLine = true;
88
+ } else if (state === 'html') {
89
+ state = 'text';
90
+ openedAt = -1;
91
+ if (nestedOpener) { disputed = true; nestedOpener = false; }
92
+ } else if (disputed) {
93
+ disputed = false;
94
+ maskLine = true;
95
+ }
96
+ }
97
+ if (maskLine) blank();
98
+ }
99
+ if (wasDisputed || disputed) onDisputed(i);
100
+ }
101
+ if (openedAt >= 0 && unclosed === 'restore') {
102
+ for (let i = openedAt; i < lines.length; i++) {
103
+ out[i] = lines[i] ?? '';
104
+ masked[i] = false;
105
+ }
106
+ }
107
+ for (let i = 0; i < masked.length; i++) if (masked[i]) onMasked(i);
108
+ return out.join('\n');
109
+ }