@kyo-so/cli 0.15.2 → 0.16.1

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/dist/bin/kyoso.js CHANGED
@@ -183964,7 +183964,7 @@ var JUDGE_MAX_OUTPUT_TOKENS = 4096;
183964
183964
  var RAW_OUTPUT_MAX_CHARS = 16384;
183965
183965
  var TRACE_DIR = ".kyoso/traces";
183966
183966
  var KYOSO_CHILD_AGENT = "KYOSO_CHILD_AGENT";
183967
- var KYOSO_VERSION = "0.15.2";
183967
+ var KYOSO_VERSION = "0.16.1";
183968
183968
 
183969
183969
  // src/utils/pathContainment.ts
183970
183970
  import { resolve, sep as sep2 } from "node:path";
@@ -184294,7 +184294,7 @@ var defaultConfig = {
184294
184294
  enabled: true,
184295
184295
  type: "acp",
184296
184296
  command: "npx",
184297
- args: ["-y", "@agentclientprotocol/claude-agent-acp@0.61.0"],
184297
+ args: ["-y", "@agentclientprotocol/claude-agent-acp@0.62.0"],
184298
184298
  role: "architecture_security_reviewer",
184299
184299
  timeoutMs: DEFAULT_AGENT_TIMEOUT_MS,
184300
184300
  env: {
@@ -184405,22 +184405,27 @@ var kyosoConfigOverridePaths = [
184405
184405
  "agents.codex.model",
184406
184406
  "agents.codex.provider",
184407
184407
  "agents.codex.openRouter.streamIdleTimeoutMs",
184408
+ "agents.codex.openRouter.streamIdleTimeoutS",
184408
184409
  "agents.codex.openRouter.streamMaxRetries",
184409
184410
  "agents.codex.openRouter.requestMaxRetries",
184410
184411
  "agents.codex.effort",
184411
184412
  "agents.codex.role",
184412
184413
  "agents.codex.timeoutMs",
184414
+ "agents.codex.timeoutS",
184413
184415
  "agents.claude.enabled",
184414
184416
  "agents.claude.model",
184415
184417
  "agents.claude.effort",
184416
184418
  "agents.claude.role",
184417
184419
  "agents.claude.timeoutMs",
184420
+ "agents.claude.timeoutS",
184418
184421
  "verification.enabled",
184419
184422
  "verification.maxFindings",
184420
184423
  "verification.timeoutMs",
184424
+ "verification.timeoutS",
184421
184425
  "judge.mode",
184422
184426
  "judge.provider",
184423
- "judge.timeoutMs"
184427
+ "judge.timeoutMs",
184428
+ "judge.timeoutS"
184424
184429
  ];
184425
184430
  var CONFIG_OVERRIDE_PATHS = new Set(kyosoConfigOverridePaths);
184426
184431
  function isAllowedConfigOverridePath(path) {
@@ -184893,6 +184898,7 @@ function agentConfigLeafPaths(agent) {
184893
184898
  `agents.${agent}.effort`,
184894
184899
  `agents.${agent}.role`,
184895
184900
  `agents.${agent}.timeoutMs`,
184901
+ `agents.${agent}.timeoutS`,
184896
184902
  `agents.${agent}.env`,
184897
184903
  `agents.${agent}.auth.mode`,
184898
184904
  `agents.${agent}.auth.preferExistingLogin`,
@@ -184901,7 +184907,7 @@ function agentConfigLeafPaths(agent) {
184901
184907
  `agents.${agent}.auth.envWhitelist`
184902
184908
  ];
184903
184909
  if (agent === "codex") {
184904
- paths.push("agents.codex.provider", "agents.codex.allowProjectProvider", "agents.codex.openRouter.streamIdleTimeoutMs", "agents.codex.openRouter.streamMaxRetries", "agents.codex.openRouter.requestMaxRetries");
184910
+ paths.push("agents.codex.provider", "agents.codex.allowProjectProvider", "agents.codex.openRouter.streamIdleTimeoutMs", "agents.codex.openRouter.streamIdleTimeoutS", "agents.codex.openRouter.streamMaxRetries", "agents.codex.openRouter.requestMaxRetries");
184905
184911
  }
184906
184912
  return paths;
184907
184913
  }
@@ -184938,12 +184944,15 @@ var kyosoConfigKnownLeafPaths = [
184938
184944
  "judge.mode",
184939
184945
  "judge.provider",
184940
184946
  "judge.timeoutMs",
184947
+ "judge.timeoutS",
184941
184948
  "verification.enabled",
184942
184949
  "verification.maxFindings",
184943
184950
  "verification.timeoutMs",
184951
+ "verification.timeoutS",
184944
184952
  "verification.allowDemotion",
184945
184953
  "reviewBudget.maxModelCalls",
184946
184954
  "reviewBudget.maxTotalWallTimeMs",
184955
+ "reviewBudget.maxTotalWallTimeS",
184947
184956
  "reviewBudget.warnAgentOutputBytes",
184948
184957
  "reviewBudget.maxAgentOutputBytes",
184949
184958
  "reviewBudget.maxFindingsPerAgent",
@@ -186039,6 +186048,146 @@ function isMissingPathError2(error51) {
186039
186048
  return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
186040
186049
  }
186041
186050
 
186051
+ // src/utils/timeUnits.ts
186052
+ class TimeUnitValidationError extends Error {
186053
+ field;
186054
+ constructor(field, message) {
186055
+ super(`${field} ${message}`);
186056
+ this.name = "TimeUnitValidationError";
186057
+ this.field = field;
186058
+ }
186059
+ }
186060
+ function validateMilliseconds(value, field, constraints = {}) {
186061
+ assertFiniteNumber(value, field);
186062
+ if (!Number.isSafeInteger(value)) {
186063
+ throw new TimeUnitValidationError(field, "must be a safe integer number of milliseconds.");
186064
+ }
186065
+ assertMinimumMilliseconds(value, field, constraints);
186066
+ return value;
186067
+ }
186068
+ function secondsToMilliseconds(value, field, constraints = {}) {
186069
+ assertFiniteNumber(value, field);
186070
+ const milliseconds = value * 1000;
186071
+ if (!Number.isSafeInteger(milliseconds)) {
186072
+ throw new TimeUnitValidationError(field, "must convert to a safe integer number of milliseconds.");
186073
+ }
186074
+ assertMinimumMilliseconds(milliseconds, field, constraints);
186075
+ return milliseconds;
186076
+ }
186077
+ function resolveTimeUnitPair(input2, fields, constraints = {}) {
186078
+ const hasMilliseconds = input2.milliseconds !== undefined;
186079
+ const hasSeconds = input2.seconds !== undefined;
186080
+ if (!hasMilliseconds && !hasSeconds)
186081
+ return;
186082
+ const milliseconds = hasMilliseconds ? validateMilliseconds(input2.milliseconds, fields.milliseconds, constraints) : undefined;
186083
+ const secondsMilliseconds = hasSeconds ? secondsToMilliseconds(input2.seconds, fields.seconds, constraints) : undefined;
186084
+ if (secondsMilliseconds !== undefined) {
186085
+ return {
186086
+ milliseconds: secondsMilliseconds,
186087
+ source: "seconds",
186088
+ sourceField: fields.seconds
186089
+ };
186090
+ }
186091
+ return {
186092
+ milliseconds,
186093
+ source: "milliseconds",
186094
+ sourceField: fields.milliseconds
186095
+ };
186096
+ }
186097
+ function assertFiniteNumber(value, field) {
186098
+ if (typeof value !== "number" || !Number.isFinite(value)) {
186099
+ throw new TimeUnitValidationError(field, "must be a finite number.");
186100
+ }
186101
+ }
186102
+ function assertMinimumMilliseconds(value, field, constraints) {
186103
+ if (constraints.allowZero && value === 0)
186104
+ return;
186105
+ const minimumMilliseconds = constraints.minimumMilliseconds ?? 1;
186106
+ if (value < minimumMilliseconds) {
186107
+ throw new TimeUnitValidationError(field, `must be at least ${minimumMilliseconds} milliseconds.`);
186108
+ }
186109
+ }
186110
+
186111
+ // src/config/timeUnits.ts
186112
+ var configTimeUnitPairs = [
186113
+ {
186114
+ parentPath: ["agents", "codex"],
186115
+ millisecondsKey: "timeoutMs",
186116
+ secondsKey: "timeoutS"
186117
+ },
186118
+ {
186119
+ parentPath: ["agents", "claude"],
186120
+ millisecondsKey: "timeoutMs",
186121
+ secondsKey: "timeoutS"
186122
+ },
186123
+ {
186124
+ parentPath: ["agents", "codex", "openRouter"],
186125
+ millisecondsKey: "streamIdleTimeoutMs",
186126
+ secondsKey: "streamIdleTimeoutS",
186127
+ constraints: { minimumMilliseconds: 1000 }
186128
+ },
186129
+ {
186130
+ parentPath: ["judge"],
186131
+ millisecondsKey: "timeoutMs",
186132
+ secondsKey: "timeoutS"
186133
+ },
186134
+ {
186135
+ parentPath: ["verification"],
186136
+ millisecondsKey: "timeoutMs",
186137
+ secondsKey: "timeoutS"
186138
+ },
186139
+ {
186140
+ parentPath: ["reviewBudget"],
186141
+ millisecondsKey: "maxTotalWallTimeMs",
186142
+ secondsKey: "maxTotalWallTimeS"
186143
+ }
186144
+ ];
186145
+ function normalizeConfigTimeUnits(input2) {
186146
+ let normalized = input2;
186147
+ for (const pair of configTimeUnitPairs) {
186148
+ normalized = updateRecordAtPath(normalized, pair.parentPath, (parent) => normalizePair(parent, pair));
186149
+ }
186150
+ return normalized;
186151
+ }
186152
+ function normalizePair(parent, pair) {
186153
+ const hasSecondsProperty = Object.hasOwn(parent, pair.secondsKey);
186154
+ if (!hasSecondsProperty)
186155
+ return parent;
186156
+ const normalized = { ...parent };
186157
+ if (parent[pair.secondsKey] === undefined) {
186158
+ delete normalized[pair.secondsKey];
186159
+ return normalized;
186160
+ }
186161
+ const parentPath = pair.parentPath.join(".");
186162
+ const resolved = resolveTimeUnitPair({
186163
+ milliseconds: parent[pair.millisecondsKey],
186164
+ seconds: parent[pair.secondsKey]
186165
+ }, {
186166
+ milliseconds: `${parentPath}.${pair.millisecondsKey}`,
186167
+ seconds: `${parentPath}.${pair.secondsKey}`
186168
+ }, pair.constraints);
186169
+ if (resolved)
186170
+ normalized[pair.millisecondsKey] = resolved.milliseconds;
186171
+ delete normalized[pair.secondsKey];
186172
+ return normalized;
186173
+ }
186174
+ function updateRecordAtPath(input2, path, update) {
186175
+ if (path.length === 0) {
186176
+ return isRecord3(input2) ? update(input2) : input2;
186177
+ }
186178
+ if (!isRecord3(input2))
186179
+ return input2;
186180
+ const [key, ...rest] = path;
186181
+ if (key === undefined)
186182
+ return input2;
186183
+ const current = input2[key];
186184
+ const updated = updateRecordAtPath(current, rest, update);
186185
+ return updated === current ? input2 : { ...input2, [key]: updated };
186186
+ }
186187
+ function isRecord3(value) {
186188
+ return typeof value === "object" && value !== null && !Array.isArray(value);
186189
+ }
186190
+
186042
186191
  // src/config/loadConfig.ts
186043
186192
  var configValidationContexts = new WeakMap;
186044
186193
  function getConfigValidationContext(error51) {
@@ -186078,7 +186227,7 @@ async function loadConfig(options = {}) {
186078
186227
  let configTrustStatus = options.ignoreConfig ? "ignored" : "not_found";
186079
186228
  if (!options.ignoreConfig) {
186080
186229
  if (await exists2(globalConfigPath)) {
186081
- const globalConfig2 = await loadTomlConfigFile(globalConfigPath);
186230
+ const globalConfig2 = normalizeConfigTimeUnits(await loadTomlConfigFile(globalConfigPath));
186082
186231
  validateExplicitReviewBudgetThresholds(globalConfig2, defaultConfig);
186083
186232
  const globalConfigWarnings = collectGlobalConfigWarnings(globalConfigPath, globalConfig2);
186084
186233
  const securitySensitiveWarnings = globalConfigWarnings.filter((warning) => warning.startsWith("security-sensitive unknown settings "));
@@ -186205,7 +186354,7 @@ async function loadProjectConfig(input2) {
186205
186354
  const { canonicalDirectory, canonicalPath, requestedPath } = input2.projectConfig;
186206
186355
  const extension = extname3(requestedPath);
186207
186356
  if (extension === ".toml") {
186208
- const projectTomlConfig = await loadTomlConfigFile(canonicalPath);
186357
+ const projectTomlConfig = normalizeConfigTimeUnits(await loadTomlConfigFile(canonicalPath));
186209
186358
  const projectChangesOpenRouterPolicy = projectConfigChangesOpenRouterPolicy(projectTomlConfig, input2.baseConfig);
186210
186359
  await assertProjectOpenRouterAuthorization({
186211
186360
  projectConfig: projectTomlConfig,
@@ -186251,7 +186400,7 @@ function configSelectsOpenRouter(config2) {
186251
186400
  return flattenLeaves(config2).some((leaf) => leaf.path.join(".") === "agents.codex.provider" && leaf.value === CODEX_OPENROUTER_PROVIDER);
186252
186401
  }
186253
186402
  function applyProjectCodexProviderReset(baseConfig, projectConfig, mergedConfig) {
186254
- if (!projectConfigSelectsDefaultProvider(projectConfig) || !configSelectsOpenRouter(baseConfig) || !isRecord3(mergedConfig) || !isRecord3(mergedConfig.agents) || !isRecord3(mergedConfig.agents.codex)) {
186403
+ if (!projectConfigSelectsDefaultProvider(projectConfig) || !configSelectsOpenRouter(baseConfig) || !isRecord4(mergedConfig) || !isRecord4(mergedConfig.agents) || !isRecord4(mergedConfig.agents.codex)) {
186255
186404
  return mergedConfig;
186256
186405
  }
186257
186406
  const shouldClearInheritedModel = !projectConfigSuppliesCodexModel(projectConfig);
@@ -186283,13 +186432,13 @@ async function assertProjectOpenRouterAuthorization(input2) {
186283
186432
  });
186284
186433
  }
186285
186434
  async function projectProviderIsAuthorized(config2, projectDirectory) {
186286
- if (!isRecord3(config2))
186435
+ if (!isRecord4(config2))
186287
186436
  return false;
186288
186437
  const agents = config2.agents;
186289
- if (!isRecord3(agents))
186438
+ if (!isRecord4(agents))
186290
186439
  return false;
186291
186440
  const codex = agents.codex;
186292
- if (!isRecord3(codex) || !Array.isArray(codex.allowProjectProvider)) {
186441
+ if (!isRecord4(codex) || !Array.isArray(codex.allowProjectProvider)) {
186293
186442
  return false;
186294
186443
  }
186295
186444
  for (const directory of codex.allowProjectProvider) {
@@ -186332,7 +186481,7 @@ async function loadProjectTsConfig(input2) {
186332
186481
  options: input2.options
186333
186482
  });
186334
186483
  if (trustDecision.execute) {
186335
- const userConfig = await loadUserConfig(canonicalPath, source);
186484
+ const userConfig = normalizeConfigTimeUnits(await loadUserConfig(canonicalPath, source));
186336
186485
  validateExplicitReviewBudgetThresholds(userConfig, input2.baseConfig);
186337
186486
  const projectChangesOpenRouterPolicy = projectConfigChangesOpenRouterPolicy(userConfig, input2.baseConfig);
186338
186487
  await assertProjectOpenRouterAuthorization({
@@ -186419,7 +186568,7 @@ async function promptForConfigTrust(configPath, configHash) {
186419
186568
  }
186420
186569
  }
186421
186570
  function deepMerge2(base, override) {
186422
- if (!isRecord3(base) || !isRecord3(override))
186571
+ if (!isRecord4(base) || !isRecord4(override))
186423
186572
  return override ?? base;
186424
186573
  const result = { ...base };
186425
186574
  for (const [key, value] of Object.entries(override)) {
@@ -186439,12 +186588,12 @@ function validateExplicitReviewBudgetThresholds(config2, baseConfig) {
186439
186588
  }
186440
186589
  }
186441
186590
  function readRecord(value, key) {
186442
- if (!isRecord3(value))
186591
+ if (!isRecord4(value))
186443
186592
  return;
186444
186593
  const nested = value[key];
186445
- return isRecord3(nested) ? nested : undefined;
186594
+ return isRecord4(nested) ? nested : undefined;
186446
186595
  }
186447
- function isRecord3(value) {
186596
+ function isRecord4(value) {
186448
186597
  return typeof value === "object" && value !== null && !Array.isArray(value);
186449
186598
  }
186450
186599
  async function exists2(path) {
@@ -186479,7 +186628,7 @@ function createModelExecutionIdentity(input2) {
186479
186628
  };
186480
186629
  }
186481
186630
  function normalizeModelExecutionIdentity(value) {
186482
- if (!isRecord4(value) || !isModelProviderRoute(value.providerRoute)) {
186631
+ if (!isRecord5(value) || !isModelProviderRoute(value.providerRoute)) {
186483
186632
  return;
186484
186633
  }
186485
186634
  return createModelExecutionIdentity({
@@ -186501,7 +186650,7 @@ function sanitizeIdentityValue(value) {
186501
186650
  function isModelProviderRoute(value) {
186502
186651
  return typeof value === "string" && MODEL_PROVIDER_ROUTES.has(value);
186503
186652
  }
186504
- function isRecord4(value) {
186653
+ function isRecord5(value) {
186505
186654
  return value !== null && typeof value === "object" && !Array.isArray(value);
186506
186655
  }
186507
186656
 
@@ -186515,7 +186664,7 @@ var TOKEN_USAGE_KEYS = [
186515
186664
  "cachedWriteTokens"
186516
186665
  ];
186517
186666
  function normalizeModelTokenUsage(usage) {
186518
- if (!isRecord5(usage))
186667
+ if (!isRecord6(usage))
186519
186668
  return;
186520
186669
  const normalized = {};
186521
186670
  for (const key of TOKEN_USAGE_KEYS) {
@@ -186528,7 +186677,7 @@ function normalizeModelTokenUsage(usage) {
186528
186677
  function isTokenCount(value) {
186529
186678
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
186530
186679
  }
186531
- function isRecord5(value) {
186680
+ function isRecord6(value) {
186532
186681
  return typeof value === "object" && value !== null && !Array.isArray(value);
186533
186682
  }
186534
186683
 
@@ -186580,7 +186729,7 @@ function parseJudgeOutput(text, fallbackSummaryText) {
186580
186729
  const parsed = JSON.parse(json2);
186581
186730
  const summaryText = typeof parsed.summaryText === "string" && parsed.summaryText.trim().length > 0 ? sanitizeText(parsed.summaryText) : fallbackSummaryText;
186582
186731
  const disagreementComments = Array.isArray(parsed.disagreementComments) ? parsed.disagreementComments.flatMap((item) => {
186583
- if (!isRecord6(item) || typeof item.topic !== "string" || typeof item.judgeComment !== "string") {
186732
+ if (!isRecord7(item) || typeof item.topic !== "string" || typeof item.judgeComment !== "string") {
186584
186733
  return [];
186585
186734
  }
186586
186735
  return [
@@ -186596,7 +186745,7 @@ function parseJudgeOutput(text, fallbackSummaryText) {
186596
186745
  return { summaryText, disagreementComments, analysis };
186597
186746
  }
186598
186747
  function parseAnalysis(value) {
186599
- if (!isRecord6(value))
186748
+ if (!isRecord7(value))
186600
186749
  return;
186601
186750
  if (!Array.isArray(value.blindSpots) || !Array.isArray(value.contradictions) || !Array.isArray(value.partialCoverage)) {
186602
186751
  return;
@@ -186604,7 +186753,7 @@ function parseAnalysis(value) {
186604
186753
  return {
186605
186754
  blindSpots: value.blindSpots.slice(0, ANALYSIS_MAX_ITEMS).flatMap((item) => typeof item === "string" ? [sanitizeAnalysisText(item)] : []),
186606
186755
  contradictions: value.contradictions.slice(0, ANALYSIS_MAX_ITEMS).flatMap((item) => {
186607
- if (!isRecord6(item) || typeof item.topic !== "string" || typeof item.detail !== "string") {
186756
+ if (!isRecord7(item) || typeof item.topic !== "string" || typeof item.detail !== "string") {
186608
186757
  return [];
186609
186758
  }
186610
186759
  return [
@@ -186615,7 +186764,7 @@ function parseAnalysis(value) {
186615
186764
  ];
186616
186765
  }),
186617
186766
  partialCoverage: value.partialCoverage.slice(0, ANALYSIS_MAX_ITEMS).flatMap((item) => {
186618
- if (!isRecord6(item) || typeof item.note !== "string")
186767
+ if (!isRecord7(item) || typeof item.note !== "string")
186619
186768
  return [];
186620
186769
  const findingId = typeof item.findingId === "string" ? sanitizeAnalysisText(item.findingId) : undefined;
186621
186770
  return [
@@ -186662,7 +186811,7 @@ function extractFirstJsonObject(text) {
186662
186811
  }
186663
186812
  return;
186664
186813
  }
186665
- function isRecord6(value) {
186814
+ function isRecord7(value) {
186666
186815
  return typeof value === "object" && value !== null && !Array.isArray(value);
186667
186816
  }
186668
186817
 
@@ -187156,9 +187305,9 @@ var PLUGIN_RUNTIME_COMPATIBILITY_SCHEMA_VERSION = 2;
187156
187305
  var MINIMUM_SUPPORTED_CODEX_VERSION = "0.144.0-alpha.4";
187157
187306
  var PLUGIN_RUNTIME_EXPECTED_CONTRACT = {
187158
187307
  distribution: {
187159
- pluginVersion: "0.7.6",
187308
+ pluginVersion: "0.7.8",
187160
187309
  mcpCommand: "npx",
187161
- mcpPackagePin: "@kyo-so/cli@0.15.1",
187310
+ mcpPackagePin: "@kyo-so/cli@0.16.0",
187162
187311
  mcpExecutable: "kyoso"
187163
187312
  },
187164
187313
  marketplace: {
@@ -187404,7 +187553,7 @@ function parseJson(value) {
187404
187553
  }
187405
187554
  }
187406
187555
  function parsePluginList(value) {
187407
- if (!isRecord7(value))
187556
+ if (!isRecord8(value))
187408
187557
  return;
187409
187558
  const allowedKeys = new Set(PLUGIN_LIST_JSON_SCHEMA.collections);
187410
187559
  if (Object.keys(value).some((key) => !allowedKeys.has(key))) {
@@ -187432,7 +187581,7 @@ function parsePluginEntries(value) {
187432
187581
  return;
187433
187582
  const entries = [];
187434
187583
  for (const item of value) {
187435
- if (!isRecord7(item))
187584
+ if (!isRecord8(item))
187436
187585
  return;
187437
187586
  if (typeof item.pluginId !== "string" || typeof item.installed !== "boolean" || typeof item.enabled !== "boolean") {
187438
187587
  return;
@@ -187458,7 +187607,7 @@ function parseMcpList(value) {
187458
187607
  return;
187459
187608
  const matches = [];
187460
187609
  for (const item of value) {
187461
- if (!isRecord7(item) || typeof item.name !== "string")
187610
+ if (!isRecord8(item) || typeof item.name !== "string")
187462
187611
  return "unknown";
187463
187612
  if (item.name !== "kyoso")
187464
187613
  continue;
@@ -187540,7 +187689,7 @@ function comparePrerelease(left, right) {
187540
187689
  }
187541
187690
  return 0;
187542
187691
  }
187543
- function isRecord7(value) {
187692
+ function isRecord8(value) {
187544
187693
  return typeof value === "object" && value !== null && !Array.isArray(value);
187545
187694
  }
187546
187695
 
@@ -187701,7 +187850,7 @@ function findKyosoPackage(executable) {
187701
187850
  if (existsSync(packagePath)) {
187702
187851
  try {
187703
187852
  const parsed = JSON.parse(readFileSync(packagePath, "utf8"));
187704
- if (isRecord8(parsed) && parsed.name === "@kyo-so/cli" && typeof parsed.version === "string" && parsed.version.trim().length > 0) {
187853
+ if (isRecord9(parsed) && parsed.name === "@kyo-so/cli" && typeof parsed.version === "string" && parsed.version.trim().length > 0) {
187705
187854
  return { directory, version: parsed.version };
187706
187855
  }
187707
187856
  } catch {}
@@ -187870,7 +188019,7 @@ function isWithin(path, parent) {
187870
188019
  const relativePath = relative(resolve5(parent), resolve5(path));
187871
188020
  return relativePath === "" || !relativePath.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) && relativePath !== ".." && !isAbsolute4(relativePath);
187872
188021
  }
187873
- function isRecord8(value) {
188022
+ function isRecord9(value) {
187874
188023
  return typeof value === "object" && value !== null && !Array.isArray(value);
187875
188024
  }
187876
188025
 
@@ -187915,7 +188064,7 @@ var GENERATED_MCP_ENV_VAR_NAMES = new Set([
187915
188064
  "CLAUDE_CODE_OAUTH_TOKEN"
187916
188065
  ]);
187917
188066
  function inspectManualMcpInvocation(value) {
187918
- if (!isRecord9(value)) {
188067
+ if (!isRecord10(value)) {
187919
188068
  return { kind: "unknown", reason: "MCP entry is not an object." };
187920
188069
  }
187921
188070
  if (typeof value.command !== "string" || value.command.length === 0) {
@@ -187961,7 +188110,7 @@ function applyEnvironmentSafety(invocation, environment) {
187961
188110
  return environment ?? invocation;
187962
188111
  }
187963
188112
  function isGeneratedMcpEnvironment(value) {
187964
- if (!isRecord9(value))
188113
+ if (!isRecord10(value))
187965
188114
  return false;
187966
188115
  return Object.entries(value).every(([name, placeholder]) => GENERATED_MCP_ENV_VALUE_NAMES.has(name) && placeholder === `\${${name}}`);
187967
188116
  }
@@ -188069,7 +188218,7 @@ function versionFromKnownPackageSpec(packageSpec) {
188069
188218
  const version2 = packageSpec.slice(prefix.length);
188070
188219
  return isCompleteSemVer(version2) ? version2 : undefined;
188071
188220
  }
188072
- function isRecord9(value) {
188221
+ function isRecord10(value) {
188073
188222
  return typeof value === "object" && value !== null && !Array.isArray(value);
188074
188223
  }
188075
188224
  function isString(value) {
@@ -188102,8 +188251,14 @@ import {
188102
188251
  } from "node:path";
188103
188252
 
188104
188253
  // src/cli/knownSkillDigests.ts
188105
- var CURRENT_SKILL_DIGEST = "sha256:d28acaadf490df9e58e12f195804f181a683d0d33344275d7989efbee26a4504";
188254
+ var CURRENT_SKILL_DIGEST = "sha256:1ea8914f4657741fcd544822326f80e82033078f8e2b11b1f5aad420072dcb39";
188106
188255
  var KNOWN_SKILL_DIGESTS_BY_VERSION = {
188256
+ "0.15.2": [
188257
+ {
188258
+ digest: "sha256:d28acaadf490df9e58e12f195804f181a683d0d33344275d7989efbee26a4504",
188259
+ kind: "historical"
188260
+ }
188261
+ ],
188107
188262
  "0.13.1": [
188108
188263
  {
188109
188264
  digest: "sha256:8654e68ea61f2acea29027056802bf627ad737f084c9a86ab052946943538409",
@@ -189366,7 +189521,7 @@ function parseJsonObject(path, content) {
189366
189521
  if (content.trim().length === 0)
189367
189522
  return {};
189368
189523
  const parsed = JSON.parse(content);
189369
- if (!isRecord10(parsed))
189524
+ if (!isRecord11(parsed))
189370
189525
  throw new Error(`${path} must contain a JSON object`);
189371
189526
  return parsed;
189372
189527
  }
@@ -189375,7 +189530,7 @@ function inspectCodexAppendSafety(content, cwd, home) {
189375
189530
  return { ok: true };
189376
189531
  try {
189377
189532
  const parsed = parse5(content);
189378
- if (!isRecord10(parsed)) {
189533
+ if (!isRecord11(parsed)) {
189379
189534
  return {
189380
189535
  ok: false,
189381
189536
  detail: "Codex config is not a TOML object and was left unchanged."
@@ -189387,13 +189542,13 @@ function inspectCodexAppendSafety(content, cwd, home) {
189387
189542
  detail: "Codex has a project-scoped MCP or Plugin override; the global config was left unchanged."
189388
189543
  };
189389
189544
  }
189390
- if ("mcp_servers" in parsed && !isRecord10(parsed.mcp_servers)) {
189545
+ if ("mcp_servers" in parsed && !isRecord11(parsed.mcp_servers)) {
189391
189546
  return {
189392
189547
  ok: false,
189393
189548
  detail: "Codex mcp_servers is malformed and was left unchanged."
189394
189549
  };
189395
189550
  }
189396
- if (isRecord10(parsed.mcp_servers) && "kyoso" in parsed.mcp_servers) {
189551
+ if (isRecord11(parsed.mcp_servers) && "kyoso" in parsed.mcp_servers) {
189397
189552
  return {
189398
189553
  ok: false,
189399
189554
  detail: "Codex already defines mcp_servers.kyoso in a form setup cannot safely extend; migrate it manually."
@@ -189429,7 +189584,7 @@ function inspectCodexMcpContent(content, path, cwd, home) {
189429
189584
  value: undefined
189430
189585
  });
189431
189586
  }
189432
- if (!isRecord10(parsed) || !isRecord10(parsed.mcp_servers)) {
189587
+ if (!isRecord11(parsed) || !isRecord11(parsed.mcp_servers)) {
189433
189588
  return manualMcpRegistration({
189434
189589
  path,
189435
189590
  scope: "codex-global",
@@ -189457,7 +189612,7 @@ function inspectCodexMcpContent(content, path, cwd, home) {
189457
189612
  function inspectClaudeProjectMcp(current, path) {
189458
189613
  if (!("mcpServers" in current))
189459
189614
  return;
189460
- if (!isRecord10(current.mcpServers)) {
189615
+ if (!isRecord11(current.mcpServers)) {
189461
189616
  return manualMcpRegistration({
189462
189617
  path,
189463
189618
  scope: "claude-project",
@@ -190087,7 +190242,7 @@ function detectCodexMcp(path, cwd, home) {
190087
190242
  value: undefined
190088
190243
  }));
190089
190244
  }
190090
- if (!isRecord10(parsed)) {
190245
+ if (!isRecord11(parsed)) {
190091
190246
  return singleMcpDetection(manualMcpRegistration({
190092
190247
  path,
190093
190248
  scope: "codex-global",
@@ -190097,7 +190252,7 @@ function detectCodexMcp(path, cwd, home) {
190097
190252
  }
190098
190253
  if (!("mcp_servers" in parsed))
190099
190254
  return missingMcpDetection();
190100
- if (!isRecord10(parsed.mcp_servers)) {
190255
+ if (!isRecord11(parsed.mcp_servers)) {
190101
190256
  return singleMcpDetection(manualMcpRegistration({
190102
190257
  path,
190103
190258
  scope: "codex-global",
@@ -190147,7 +190302,7 @@ function detectClaudeMcp(path, cwd, home) {
190147
190302
  }
190148
190303
  function jsonMcpRegistrations(value, path, cwd, home) {
190149
190304
  const directScope = path.endsWith(".mcp.json") ? "claude-project" : "claude-global";
190150
- if (!isRecord10(value)) {
190305
+ if (!isRecord11(value)) {
190151
190306
  return [
190152
190307
  manualMcpRegistration({
190153
190308
  path,
@@ -190160,7 +190315,7 @@ function jsonMcpRegistrations(value, path, cwd, home) {
190160
190315
  const registrations = directMcpRegistrations(value, path, directScope);
190161
190316
  if (!("projects" in value))
190162
190317
  return registrations;
190163
- if (!isRecord10(value.projects)) {
190318
+ if (!isRecord11(value.projects)) {
190164
190319
  return [
190165
190320
  ...registrations,
190166
190321
  manualMcpRegistration({
@@ -190175,7 +190330,7 @@ function jsonMcpRegistrations(value, path, cwd, home) {
190175
190330
  for (const [projectPath, projectConfig] of Object.entries(value.projects)) {
190176
190331
  if (normalizeProjectPath(projectPath, home) !== currentProject)
190177
190332
  continue;
190178
- if (!isRecord10(projectConfig)) {
190333
+ if (!isRecord11(projectConfig)) {
190179
190334
  registrations.push(manualMcpRegistration({
190180
190335
  path,
190181
190336
  scope: "claude-global-project",
@@ -190191,7 +190346,7 @@ function jsonMcpRegistrations(value, path, cwd, home) {
190191
190346
  function directMcpRegistrations(value, path, scope) {
190192
190347
  if (!("mcpServers" in value))
190193
190348
  return [];
190194
- if (!isRecord10(value.mcpServers)) {
190349
+ if (!isRecord11(value.mcpServers)) {
190195
190350
  return [
190196
190351
  manualMcpRegistration({
190197
190352
  path,
@@ -190215,7 +190370,7 @@ function directMcpRegistrations(value, path, scope) {
190215
190370
  function nestedMcpEntryStatus(value, path) {
190216
190371
  let current = value;
190217
190372
  for (const key of path) {
190218
- if (!isRecord10(current))
190373
+ if (!isRecord11(current))
190219
190374
  return "unknown";
190220
190375
  if (!(key in current))
190221
190376
  return "missing";
@@ -190224,11 +190379,11 @@ function nestedMcpEntryStatus(value, path) {
190224
190379
  return mcpEntryStatus(current);
190225
190380
  }
190226
190381
  function hasUnprobedProjectIntegrationOverride(value, cwd, home) {
190227
- if (!isRecord10(value) || !isRecord10(value.projects))
190382
+ if (!isRecord11(value) || !isRecord11(value.projects))
190228
190383
  return false;
190229
190384
  const currentProject = normalizeProjectPath(cwd, home);
190230
190385
  for (const [projectPath, projectConfig] of Object.entries(value.projects)) {
190231
- if (normalizeProjectPath(projectPath, home) !== currentProject || !isRecord10(projectConfig)) {
190386
+ if (normalizeProjectPath(projectPath, home) !== currentProject || !isRecord11(projectConfig)) {
190232
190387
  continue;
190233
190388
  }
190234
190389
  if ("mcp_servers" in projectConfig || "plugins" in projectConfig) {
@@ -190251,7 +190406,7 @@ function normalizeProjectPath(path, home) {
190251
190406
  return process.platform === "win32" ? normalized.toLowerCase() : normalized;
190252
190407
  }
190253
190408
  function mcpEntryStatus(value) {
190254
- if (!isRecord10(value))
190409
+ if (!isRecord11(value))
190255
190410
  return "unknown";
190256
190411
  if (!("enabled" in value))
190257
190412
  return "enabled";
@@ -190302,7 +190457,7 @@ function readTextSync(path) {
190302
190457
  function recordValue(value) {
190303
190458
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
190304
190459
  }
190305
- function isRecord10(value) {
190460
+ function isRecord11(value) {
190306
190461
  return typeof value === "object" && value !== null && !Array.isArray(value);
190307
190462
  }
190308
190463
  function diffForAppend(path, snippet) {
@@ -190506,12 +190661,13 @@ async function runDoctor(options) {
190506
190661
  }
190507
190662
  const judgeRoute = resolveJudgeCallRoute(loaded.config.judge.mode, loaded.config.judge.provider, env);
190508
190663
  const reviewTiming = calculateReviewTiming(loaded.config, judgeRoute.llmAvailable);
190664
+ const recommendedReviewWallTimeS = Math.ceil(reviewTiming.recommendedReviewWallTimeMs / 1000);
190509
190665
  lines.push("", "Review timing");
190510
190666
  lines.push(` review-wide deadline: ${loaded.config.reviewBudget.maxTotalWallTimeMs} ms`, ` sequential phases: primary ${reviewTiming.primaryPhaseMs} + verification ${reviewTiming.verificationPhaseMs} + LLM judge ${reviewTiming.judgePhaseMs} = ${reviewTiming.sequentialPhaseMs} ms`, ` recommended review-wide deadline: ${reviewTiming.recommendedReviewWallTimeMs} ms`);
190511
190667
  if (loaded.config.reviewBudget.maxTotalWallTimeMs < reviewTiming.sequentialPhaseMs) {
190512
- lines.push(` warning: review-wide deadline is insufficient: ${loaded.config.reviewBudget.maxTotalWallTimeMs} ms is below the configured sequential phase time of ${reviewTiming.sequentialPhaseMs} ms; later phases cannot receive their configured timeout.`, ` hint: set user-global reviewBudget.maxTotalWallTimeMs to at least ${reviewTiming.recommendedReviewWallTimeMs}.`);
190668
+ lines.push(` warning: review-wide deadline is insufficient: ${loaded.config.reviewBudget.maxTotalWallTimeMs} ms is below the configured sequential phase time of ${reviewTiming.sequentialPhaseMs} ms; later phases cannot receive their configured timeout.`, ` hint: set user-global reviewBudget.maxTotalWallTimeS to at least ${recommendedReviewWallTimeS}.`);
190513
190669
  } else if (loaded.config.reviewBudget.maxTotalWallTimeMs < reviewTiming.recommendedReviewWallTimeMs) {
190514
- lines.push(` warning: review-wide deadline has low margin: ${loaded.config.reviewBudget.maxTotalWallTimeMs} ms is below the recommended ${reviewTiming.recommendedReviewWallTimeMs} ms; scheduling and finalization margin is reduced.`, ` hint: set user-global reviewBudget.maxTotalWallTimeMs to at least ${reviewTiming.recommendedReviewWallTimeMs}.`);
190670
+ lines.push(` warning: review-wide deadline has low margin: ${loaded.config.reviewBudget.maxTotalWallTimeMs} ms is below the recommended ${reviewTiming.recommendedReviewWallTimeMs} ms; scheduling and finalization margin is reduced.`, ` hint: set user-global reviewBudget.maxTotalWallTimeS to at least ${recommendedReviewWallTimeS}.`);
190515
190671
  }
190516
190672
  const judgeProvider = judgeRoute.llmAvailable ? judgeRoute.provider : "deterministic_fallback";
190517
190673
  lines.push("", "Judge");
@@ -193384,17 +193540,17 @@ function isResponseMessage(value) {
193384
193540
  function isNotificationMessage(value) {
193385
193541
  return isJsonRpcEnvelope(value) && !("id" in value) && typeof value["method"] === "string";
193386
193542
  }
193387
- function isRecord11(value) {
193543
+ function isRecord12(value) {
193388
193544
  return typeof value === "object" && value !== null;
193389
193545
  }
193390
193546
  function isJsonRpcEnvelope(value) {
193391
- return isRecord11(value) && value["jsonrpc"] === "2.0";
193547
+ return isRecord12(value) && value["jsonrpc"] === "2.0";
193392
193548
  }
193393
193549
  function isJsonRpcId(value) {
193394
193550
  return value === null || typeof value === "string" || typeof value === "number" && Number.isFinite(value);
193395
193551
  }
193396
193552
  function isResponseShapedMessage(value) {
193397
- return isRecord11(value) && !("method" in value) && (("id" in value) || ("result" in value) || ("error" in value));
193553
+ return isRecord12(value) && !("method" in value) && (("id" in value) || ("result" in value) || ("error" in value));
193398
193554
  }
193399
193555
  function isResponseBatch(batch) {
193400
193556
  let hasValidCall = false;
@@ -193404,7 +193560,7 @@ function isResponseBatch(batch) {
193404
193560
  for (const entry of batch) {
193405
193561
  hasValidCall ||= isRequestMessage(entry) || isNotificationMessage(entry);
193406
193562
  hasValidResponse ||= isResponseMessage(entry);
193407
- if (!isRecord11(entry)) {
193563
+ if (!isRecord12(entry)) {
193408
193564
  continue;
193409
193565
  }
193410
193566
  hasCallShape ||= "method" in entry;
@@ -193419,13 +193575,13 @@ function isResponseBatch(batch) {
193419
193575
  return hasResponseShape && !hasCallShape;
193420
193576
  }
193421
193577
  function cancelRequestId(params) {
193422
- if (!isRecord11(params) || !isJsonRpcId(params["requestId"])) {
193578
+ if (!isRecord12(params) || !isJsonRpcId(params["requestId"])) {
193423
193579
  return;
193424
193580
  }
193425
193581
  return params["requestId"];
193426
193582
  }
193427
193583
  function isErrorResponse(value) {
193428
- return isRecord11(value) && typeof value["code"] === "number" && Number.isInteger(value["code"]) && typeof value["message"] === "string";
193584
+ return isRecord12(value) && typeof value["code"] === "number" && Number.isInteger(value["code"]) && typeof value["message"] === "string";
193429
193585
  }
193430
193586
  var Handled = {
193431
193587
  yes() {
@@ -193820,7 +193976,7 @@ class Connection {
193820
193976
  this.receiveBatch(message);
193821
193977
  return;
193822
193978
  }
193823
- if (!isRecord11(message)) {
193979
+ if (!isRecord12(message)) {
193824
193980
  console.error("Invalid message", { message });
193825
193981
  return;
193826
193982
  }
@@ -193881,7 +194037,7 @@ class Connection {
193881
194037
  if (this.abortController.signal.aborted) {
193882
194038
  return Promise.resolve();
193883
194039
  }
193884
- if (!isRecord11(message)) {
194040
+ if (!isRecord12(message)) {
193885
194041
  console.error("Invalid message", { message });
193886
194042
  return Promise.resolve();
193887
194043
  }
@@ -194188,7 +194344,7 @@ function ndJsonStream(output2, input2) {
194188
194344
  if (trimmedLine) {
194189
194345
  try {
194190
194346
  const message = JSON.parse(trimmedLine);
194191
- if (isRecord11(message) || Array.isArray(message)) {
194347
+ if (isRecord12(message) || Array.isArray(message)) {
194192
194348
  controller.enqueue(message);
194193
194349
  } else {
194194
194350
  console.warn("Skipping JSON line that is not an object:", trimmedLine);
@@ -195220,12 +195376,12 @@ class AgentOutputAccumulator {
195220
195376
  var RETRY_ATTEMPT_PATTERN = /Reconnecting\.\.\.\s*(\d+)\/(\d+)/;
195221
195377
  var DISPLAY_MESSAGE_FIELDS = ["title", "text", "message", "description"];
195222
195378
  function parseCodexRetryUpdate(update) {
195223
- if (!isRecord12(update) || update.sessionUpdate !== "session_info_update") {
195379
+ if (!isRecord13(update) || update.sessionUpdate !== "session_info_update") {
195224
195380
  return;
195225
195381
  }
195226
- const meta3 = isRecord12(update._meta) ? update._meta : undefined;
195227
- const codex = meta3 && isRecord12(meta3.codex) ? meta3.codex : undefined;
195228
- const error51 = codex && isRecord12(codex.error) ? codex.error : undefined;
195382
+ const meta3 = isRecord13(update._meta) ? update._meta : undefined;
195383
+ const codex = meta3 && isRecord13(meta3.codex) ? meta3.codex : undefined;
195384
+ const error51 = codex && isRecord13(codex.error) ? codex.error : undefined;
195229
195385
  if (error51?.willRetry !== true)
195230
195386
  return;
195231
195387
  const rawMessage = typeof error51.message === "string" ? error51.message : findDisplayMessage(update) ?? "model stream retry";
@@ -195245,7 +195401,7 @@ function findDisplayMessage(update) {
195245
195401
  }
195246
195402
  return;
195247
195403
  }
195248
- function isRecord12(value) {
195404
+ function isRecord13(value) {
195249
195405
  return value !== null && typeof value === "object" && !Array.isArray(value);
195250
195406
  }
195251
195407
 
@@ -195730,7 +195886,7 @@ function isSeverity(value) {
195730
195886
  return typeof value === "string" && severities.includes(value);
195731
195887
  }
195732
195888
  function normalizeCisaSecureByDesign(value) {
195733
- if (!isRecord13(value))
195889
+ if (!isRecord14(value))
195734
195890
  return;
195735
195891
  const normalized = {};
195736
195892
  const customerSecurityOutcomes = normalizeGateStatus(value.customerSecurityOutcomes);
@@ -195771,7 +195927,7 @@ function isEvidenceQuality(value) {
195771
195927
  return typeof value === "string" && evidenceQualities.includes(value);
195772
195928
  }
195773
195929
  function isStrictAgentOpinion(value) {
195774
- if (!isRecord13(value) || !hasOnlyKeys(value, STRICT_ROOT_KEYS))
195930
+ if (!isRecord14(value) || !hasOnlyKeys(value, STRICT_ROOT_KEYS))
195775
195931
  return false;
195776
195932
  if (typeof value.summary !== "string")
195777
195933
  return false;
@@ -195781,7 +195937,7 @@ function isStrictAgentOpinion(value) {
195781
195937
  return value.cisaSecureByDesign === undefined || isStrictCisaSecureByDesign(value.cisaSecureByDesign);
195782
195938
  }
195783
195939
  function isStrictFinding(value) {
195784
- if (!isRecord13(value) || !hasOnlyKeys(value, STRICT_FINDING_KEYS)) {
195940
+ if (!isRecord14(value) || !hasOnlyKeys(value, STRICT_FINDING_KEYS)) {
195785
195941
  return false;
195786
195942
  }
195787
195943
  if (!isSeverity(value.severity) || !isCategory(value.category) || !isNonEmptyString(value.title) || !isNonEmptyString(value.evidence) || !isNonEmptyString(value.recommendation) || !isConfidence(value.confidence)) {
@@ -195793,11 +195949,11 @@ function isStrictFinding(value) {
195793
195949
  return true;
195794
195950
  }
195795
195951
  function isStrictFindingFiles(value) {
195796
- return Array.isArray(value) && value.every((item) => isRecord13(item) && hasOnlyKeys(item, STRICT_FILE_KEYS) && isNonEmptyString(item.path) && isOptionalLineNumber(item.lineStart) && isOptionalLineNumber(item.lineEnd));
195952
+ return Array.isArray(value) && value.every((item) => isRecord14(item) && hasOnlyKeys(item, STRICT_FILE_KEYS) && isNonEmptyString(item.path) && isOptionalLineNumber(item.lineStart) && isOptionalLineNumber(item.lineEnd));
195797
195953
  }
195798
195954
  function isStrictEvidenceRefs(value) {
195799
195955
  return Array.isArray(value) && value.length <= MAX_EVIDENCE_REFS2 && value.every((item) => {
195800
- if (!isRecord13(item) || !hasOnlyKeys(item, STRICT_EVIDENCE_REF_KEYS)) {
195956
+ if (!isRecord14(item) || !hasOnlyKeys(item, STRICT_EVIDENCE_REF_KEYS)) {
195801
195957
  return false;
195802
195958
  }
195803
195959
  if (item.kind !== "file" && item.kind !== "diff_hunk" && item.kind !== "plan_clause") {
@@ -195813,7 +195969,7 @@ function isStrictEvidenceRefs(value) {
195813
195969
  });
195814
195970
  }
195815
195971
  function isStrictCisaSecureByDesign(value) {
195816
- if (!isRecord13(value) || !hasOnlyKeys(value, STRICT_CISA_KEYS))
195972
+ if (!isRecord14(value) || !hasOnlyKeys(value, STRICT_CISA_KEYS))
195817
195973
  return false;
195818
195974
  for (const key of [
195819
195975
  "customerSecurityOutcomes",
@@ -195852,7 +196008,7 @@ function normalizeFindingFiles(value) {
195852
196008
  if (!Array.isArray(value))
195853
196009
  return;
195854
196010
  const files = value.flatMap((item) => {
195855
- if (!isRecord13(item) || typeof item.path !== "string" || item.path.trim().length === 0) {
196011
+ if (!isRecord14(item) || typeof item.path !== "string" || item.path.trim().length === 0) {
195856
196012
  return [];
195857
196013
  }
195858
196014
  const file2 = {
@@ -195872,7 +196028,7 @@ function normalizeEvidenceRefs2(value) {
195872
196028
  if (!Array.isArray(value))
195873
196029
  return;
195874
196030
  const references = value.slice(0, MAX_EVIDENCE_REFS2).flatMap((item) => {
195875
- if (!isRecord13(item) || item.kind !== "file" && item.kind !== "diff_hunk" && item.kind !== "plan_clause") {
196031
+ if (!isRecord14(item) || item.kind !== "file" && item.kind !== "diff_hunk" && item.kind !== "plan_clause") {
195876
196032
  return [];
195877
196033
  }
195878
196034
  const reference = { kind: item.kind };
@@ -195895,7 +196051,7 @@ function normalizeEvidenceRefs2(value) {
195895
196051
  function normalizeLineNumber(value) {
195896
196052
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= MAX_EVIDENCE_LINE2 ? value : undefined;
195897
196053
  }
195898
- function isRecord13(value) {
196054
+ function isRecord14(value) {
195899
196055
  return typeof value === "object" && value !== null && !Array.isArray(value);
195900
196056
  }
195901
196057
 
@@ -196520,7 +196676,7 @@ function normalizeUsage3(usage) {
196520
196676
  return normalizeModelTokenUsage(usage);
196521
196677
  }
196522
196678
  function withReportedExecutionIdentity(identity, metadata) {
196523
- const record2 = isRecord14(metadata) ? metadata : {};
196679
+ const record2 = isRecord15(metadata) ? metadata : {};
196524
196680
  return createModelExecutionIdentity({
196525
196681
  providerRoute: identity.providerRoute,
196526
196682
  requestedModel: identity.requestedModel,
@@ -196529,9 +196685,9 @@ function withReportedExecutionIdentity(identity, metadata) {
196529
196685
  });
196530
196686
  }
196531
196687
  function readChunkMeta(update) {
196532
- const record2 = isRecord14(update) ? update : {};
196533
- const metadata = isRecord14(record2._meta) ? record2._meta : {};
196534
- const codex = isRecord14(metadata.codex) ? metadata.codex : {};
196688
+ const record2 = isRecord15(update) ? update : {};
196689
+ const metadata = isRecord15(record2._meta) ? record2._meta : {};
196690
+ const codex = isRecord15(metadata.codex) ? metadata.codex : {};
196535
196691
  const phase = codex.phase === "commentary" || codex.phase === "final_answer" ? codex.phase : "unknown";
196536
196692
  return {
196537
196693
  ...typeof record2.messageId === "string" ? { messageId: record2.messageId } : {},
@@ -196539,15 +196695,15 @@ function readChunkMeta(update) {
196539
196695
  };
196540
196696
  }
196541
196697
  function readCodexThreadStatus(update) {
196542
- const record2 = isRecord14(update) ? update : {};
196698
+ const record2 = isRecord15(update) ? update : {};
196543
196699
  if (record2.sessionUpdate !== "session_info_update")
196544
196700
  return;
196545
- const metadata = isRecord14(record2._meta) ? record2._meta : {};
196546
- const codex = isRecord14(metadata.codex) ? metadata.codex : {};
196547
- const threadStatus = isRecord14(codex.threadStatus) ? codex.threadStatus : {};
196701
+ const metadata = isRecord15(record2._meta) ? record2._meta : {};
196702
+ const codex = isRecord15(metadata.codex) ? metadata.codex : {};
196703
+ const threadStatus = isRecord15(codex.threadStatus) ? codex.threadStatus : {};
196548
196704
  return typeof threadStatus.type === "string" ? threadStatus.type : undefined;
196549
196705
  }
196550
- function isRecord14(value) {
196706
+ function isRecord15(value) {
196551
196707
  return value !== null && typeof value === "object" && !Array.isArray(value);
196552
196708
  }
196553
196709
  function resolveEffortConfigOption(agent, effort) {
@@ -210950,9 +211106,14 @@ import { resolve as resolve10 } from "node:path";
210950
211106
  // src/config/configOverrides.ts
210951
211107
  var NUMBER_VALUE = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i;
210952
211108
  var UNSET_NUMBER_OVERRIDE_PATHS = new Set([
211109
+ "agents.codex.timeoutS",
211110
+ "agents.claude.timeoutS",
210953
211111
  "agents.codex.openRouter.streamIdleTimeoutMs",
211112
+ "agents.codex.openRouter.streamIdleTimeoutS",
210954
211113
  "agents.codex.openRouter.streamMaxRetries",
210955
- "agents.codex.openRouter.requestMaxRetries"
211114
+ "agents.codex.openRouter.requestMaxRetries",
211115
+ "judge.timeoutS",
211116
+ "verification.timeoutS"
210956
211117
  ]);
210957
211118
  function applyConfigOverrides(config2, assignments) {
210958
211119
  if (assignments.length === 0)
@@ -210963,9 +211124,21 @@ function applyConfigOverrides(config2, assignments) {
210963
211124
  for (const override of overrides) {
210964
211125
  writePath2(overridden, override.path, parseConfigOverrideValue(override.value, readPath2(baseConfig, override.path), override.path));
210965
211126
  }
210966
- clearInheritedOpenRouterConfigForProviderReset(baseConfig, overridden, overrides);
210967
- assertOpenRouterProviderOverrideIncludesModel(baseConfig, overridden, overrides);
210968
- const parsed = kyosoConfigSchema.safeParse(overridden);
211127
+ let normalized;
211128
+ try {
211129
+ normalized = normalizeConfigTimeUnits(overridden);
211130
+ } catch (error51) {
211131
+ if (!(error51 instanceof TimeUnitValidationError))
211132
+ throw error51;
211133
+ const assignment2 = findAssignmentForPath(overrides, error51.field);
211134
+ if (!assignment2) {
211135
+ throw new Error(`Invalid config time value: ${error51.message}`);
211136
+ }
211137
+ throw new Error(`Invalid --set value ${JSON.stringify(assignment2)}: ${error51.message}`);
211138
+ }
211139
+ clearInheritedOpenRouterConfigForProviderReset(baseConfig, normalized, overrides);
211140
+ assertOpenRouterProviderOverrideIncludesModel(baseConfig, normalized, overrides);
211141
+ const parsed = kyosoConfigSchema.safeParse(normalized);
210969
211142
  if (parsed.success)
210970
211143
  return parsed.data;
210971
211144
  const issue2 = parsed.error.issues[0];
@@ -210995,7 +211168,7 @@ function clearInheritedOpenRouterConfigForProviderReset(baseConfig, overridden,
210995
211168
  return;
210996
211169
  }
210997
211170
  const codex = readPath2(overridden, ["agents", "codex"]);
210998
- if (!isRecord15(codex))
211171
+ if (!isRecord16(codex))
210999
211172
  return;
211000
211173
  if (!suppliesModel)
211001
211174
  delete codex.model;
@@ -211044,7 +211217,7 @@ function parseConfigOverrideValue(value, currentValue, path) {
211044
211217
  function readPath2(target, path) {
211045
211218
  let current = target;
211046
211219
  for (const key of path) {
211047
- if (!isRecord15(current))
211220
+ if (!isRecord16(current))
211048
211221
  return;
211049
211222
  current = current[key];
211050
211223
  }
@@ -211054,7 +211227,7 @@ function writePath2(target, path, value) {
211054
211227
  let current = target;
211055
211228
  for (const key of path.slice(0, -1)) {
211056
211229
  const child = current[key];
211057
- if (!isRecord15(child)) {
211230
+ if (!isRecord16(child)) {
211058
211231
  throw new Error(`Cannot apply --set key ${JSON.stringify(path.join("."))}.`);
211059
211232
  }
211060
211233
  current = child;
@@ -211063,7 +211236,7 @@ function writePath2(target, path, value) {
211063
211236
  if (leaf)
211064
211237
  current[leaf] = value;
211065
211238
  }
211066
- function isRecord15(value) {
211239
+ function isRecord16(value) {
211067
211240
  return typeof value === "object" && value !== null && !Array.isArray(value);
211068
211241
  }
211069
211242
 
@@ -212301,7 +212474,7 @@ function validateReviewContract(request) {
212301
212474
  const contract = request.reviewContract;
212302
212475
  if (contract === undefined)
212303
212476
  return;
212304
- if (!isRecord16(contract)) {
212477
+ if (!isRecord17(contract)) {
212305
212478
  throw new KyosoRequestError("reviewContract must be an object", "VALIDATION_ERROR");
212306
212479
  }
212307
212480
  const allowedKeys = new Set(["focus", "nonGoals", "acceptedRisks"]);
@@ -212318,7 +212491,7 @@ function validateReviewContract(request) {
212318
212491
  throw new KyosoRequestError("reviewContract.nonGoals must contain at most 20 non-empty strings of 500 characters or fewer", "VALIDATION_ERROR");
212319
212492
  }
212320
212493
  const acceptedRisks = contract.acceptedRisks;
212321
- if (acceptedRisks !== undefined && (!Array.isArray(acceptedRisks) || acceptedRisks.length > 20 || acceptedRisks.some((risk) => !isRecord16(risk) || typeof risk.findingFingerprint !== "string" || !/^sha256:[0-9a-f]{64}$/.test(risk.findingFingerprint) || typeof risk.rationale !== "string" || risk.rationale.trim().length === 0 || risk.rationale.length > 500))) {
212494
+ if (acceptedRisks !== undefined && (!Array.isArray(acceptedRisks) || acceptedRisks.length > 20 || acceptedRisks.some((risk) => !isRecord17(risk) || typeof risk.findingFingerprint !== "string" || !/^sha256:[0-9a-f]{64}$/.test(risk.findingFingerprint) || typeof risk.rationale !== "string" || risk.rationale.trim().length === 0 || risk.rationale.length > 500))) {
212322
212495
  throw new KyosoRequestError("reviewContract.acceptedRisks must contain valid finding fingerprints and bounded rationales", "VALIDATION_ERROR");
212323
212496
  }
212324
212497
  }
@@ -212330,13 +212503,13 @@ function validateSelectedFiles(request) {
212330
212503
  throw new KyosoRequestError("selectedFiles must be an array", "VALIDATION_ERROR");
212331
212504
  }
212332
212505
  for (const file2 of selectedFiles) {
212333
- if (!isRecord16(file2) || typeof file2.path !== "string" || file2.path.trim().length === 0 || typeof file2.content !== "string" || file2.language !== undefined && typeof file2.language !== "string" || file2.truncated !== undefined && typeof file2.truncated !== "boolean") {
212506
+ if (!isRecord17(file2) || typeof file2.path !== "string" || file2.path.trim().length === 0 || typeof file2.content !== "string" || file2.language !== undefined && typeof file2.language !== "string" || file2.truncated !== undefined && typeof file2.truncated !== "boolean") {
212334
212507
  throw new KyosoRequestError("selectedFiles entries require string path/content and valid optional metadata", "VALIDATION_ERROR");
212335
212508
  }
212336
212509
  normalizeRelativePath(file2.path);
212337
212510
  }
212338
212511
  }
212339
- function isRecord16(value) {
212512
+ function isRecord17(value) {
212340
212513
  return typeof value === "object" && value !== null && !Array.isArray(value);
212341
212514
  }
212342
212515
 
@@ -212867,11 +213040,11 @@ function canonicalJson(value) {
212867
213040
  function canonicalize(value) {
212868
213041
  if (Array.isArray(value))
212869
213042
  return value.map(canonicalize);
212870
- if (!isRecord17(value))
213043
+ if (!isRecord18(value))
212871
213044
  return value;
212872
213045
  return Object.fromEntries(Object.entries(value).filter(([, child]) => child !== undefined).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([key, child]) => [key, canonicalize(child)]));
212873
213046
  }
212874
- function isRecord17(value) {
213047
+ function isRecord18(value) {
212875
213048
  return typeof value === "object" && value !== null && !Array.isArray(value);
212876
213049
  }
212877
213050
 
@@ -212879,19 +213052,24 @@ function isRecord17(value) {
212879
213052
  var REVIEW_BUDGET_KEYS = new Set([
212880
213053
  "maxModelCalls",
212881
213054
  "maxTotalWallTimeMs",
213055
+ "maxTotalWallTimeS",
212882
213056
  "maxAgentOutputBytes",
212883
213057
  "maxFindingsPerAgent",
212884
213058
  "skipOptionalPhasesWhenTokenUsageUnknown"
212885
213059
  ]);
212886
213060
  var MODEL_CALL_KINDS = ["primary", "verifier", "judge"];
212887
213061
  function resolveReviewBudget(ceiling, requested) {
212888
- if (requested !== undefined && !isRecord18(requested)) {
213062
+ if (requested !== undefined && !isRecord19(requested)) {
212889
213063
  throw new KyosoRequestError("options.reviewBudget must be an object.", "REVIEW_BUDGET_INVALID");
212890
213064
  }
213065
+ const hasWallTimeSeconds = requested?.maxTotalWallTimeS !== undefined;
212891
213066
  for (const [key, value] of Object.entries(requested ?? {})) {
212892
213067
  if (!REVIEW_BUDGET_KEYS.has(key)) {
212893
213068
  throw new KyosoRequestError(`options.reviewBudget.${key} is not supported.`, "REVIEW_BUDGET_INVALID");
212894
213069
  }
213070
+ if (key === "maxTotalWallTimeS" || key === "maxTotalWallTimeMs" && hasWallTimeSeconds) {
213071
+ continue;
213072
+ }
212895
213073
  if (key === "skipOptionalPhasesWhenTokenUsageUnknown") {
212896
213074
  if (typeof value !== "boolean") {
212897
213075
  throw new KyosoRequestError(`options.reviewBudget.${key} must be a boolean.`, "REVIEW_BUDGET_INVALID");
@@ -212902,12 +213080,26 @@ function resolveReviewBudget(ceiling, requested) {
212902
213080
  throw new KyosoRequestError(`options.reviewBudget.${key} must be a positive integer.`, "REVIEW_BUDGET_INVALID");
212903
213081
  }
212904
213082
  }
212905
- const numericKeys = [
212906
- "maxModelCalls",
212907
- "maxTotalWallTimeMs",
212908
- "maxAgentOutputBytes",
212909
- "maxFindingsPerAgent"
212910
- ];
213083
+ let requestedWallTime;
213084
+ if (hasWallTimeSeconds) {
213085
+ try {
213086
+ requestedWallTime = resolveTimeUnitPair({
213087
+ milliseconds: requested?.maxTotalWallTimeMs,
213088
+ seconds: requested?.maxTotalWallTimeS
213089
+ }, {
213090
+ milliseconds: "options.reviewBudget.maxTotalWallTimeMs",
213091
+ seconds: "options.reviewBudget.maxTotalWallTimeS"
213092
+ });
213093
+ } catch (error51) {
213094
+ if (error51 instanceof TimeUnitValidationError) {
213095
+ throw new KyosoRequestError(error51.message, "REVIEW_BUDGET_INVALID");
213096
+ }
213097
+ throw error51;
213098
+ }
213099
+ }
213100
+ const numericKeys = ["maxModelCalls", "maxAgentOutputBytes", "maxFindingsPerAgent"];
213101
+ if (!hasWallTimeSeconds)
213102
+ numericKeys.push("maxTotalWallTimeMs");
212911
213103
  for (const key of numericKeys) {
212912
213104
  const value = requested?.[key];
212913
213105
  if (value === undefined)
@@ -212916,13 +213108,19 @@ function resolveReviewBudget(ceiling, requested) {
212916
213108
  throw new KyosoRequestError(`options.reviewBudget.${key} cannot exceed the user-global ceiling.`, "REVIEW_BUDGET_EXCEEDS_CEILING");
212917
213109
  }
212918
213110
  }
213111
+ if (hasWallTimeSeconds && requested?.maxTotalWallTimeMs !== undefined && requested.maxTotalWallTimeMs > ceiling.maxTotalWallTimeMs) {
213112
+ throw new KyosoRequestError("options.reviewBudget.maxTotalWallTimeMs cannot exceed the user-global ceiling.", "REVIEW_BUDGET_EXCEEDS_CEILING");
213113
+ }
213114
+ if (requestedWallTime && requestedWallTime.milliseconds > ceiling.maxTotalWallTimeMs) {
213115
+ throw new KyosoRequestError(`${requestedWallTime.sourceField} cannot exceed the user-global ceiling.`, "REVIEW_BUDGET_EXCEEDS_CEILING");
213116
+ }
212919
213117
  if (ceiling.skipOptionalPhasesWhenTokenUsageUnknown && requested?.skipOptionalPhasesWhenTokenUsageUnknown === false) {
212920
213118
  throw new KyosoRequestError("options.reviewBudget.skipOptionalPhasesWhenTokenUsageUnknown cannot relax the user-global ceiling.", "REVIEW_BUDGET_EXCEEDS_CEILING");
212921
213119
  }
212922
213120
  const maxAgentOutputBytes = requested?.maxAgentOutputBytes ?? ceiling.maxAgentOutputBytes;
212923
213121
  return {
212924
213122
  maxModelCalls: requested?.maxModelCalls ?? ceiling.maxModelCalls,
212925
- maxTotalWallTimeMs: requested?.maxTotalWallTimeMs ?? ceiling.maxTotalWallTimeMs,
213123
+ maxTotalWallTimeMs: requestedWallTime?.milliseconds ?? requested?.maxTotalWallTimeMs ?? ceiling.maxTotalWallTimeMs,
212926
213124
  warnAgentOutputBytes: ceiling.warnAgentOutputBytes,
212927
213125
  maxAgentOutputBytes,
212928
213126
  maxFindingsPerAgent: requested?.maxFindingsPerAgent ?? ceiling.maxFindingsPerAgent,
@@ -213239,10 +213437,63 @@ function emptyReviewModelCallPlan() {
213239
213437
  ceilingEffects: []
213240
213438
  };
213241
213439
  }
213242
- function isRecord18(value) {
213440
+ function isRecord19(value) {
213243
213441
  return typeof value === "object" && value !== null && !Array.isArray(value);
213244
213442
  }
213245
213443
 
213444
+ // src/core/requestTimeUnits.ts
213445
+ function normalizeRequestTimeUnits(request) {
213446
+ if (!request.options)
213447
+ return request;
213448
+ const options = { ...request.options };
213449
+ normalizeRequestTimeUnitField(options, "maxAgentTimeoutMs", "maxAgentTimeoutS", {
213450
+ milliseconds: "options.maxAgentTimeoutMs",
213451
+ seconds: "options.maxAgentTimeoutS"
213452
+ });
213453
+ if (options.reviewBudget) {
213454
+ const reviewBudget = { ...options.reviewBudget };
213455
+ normalizeRequestTimeUnitField(reviewBudget, "maxTotalWallTimeMs", "maxTotalWallTimeS", {
213456
+ milliseconds: "options.reviewBudget.maxTotalWallTimeMs",
213457
+ seconds: "options.reviewBudget.maxTotalWallTimeS"
213458
+ });
213459
+ options.reviewBudget = reviewBudget;
213460
+ }
213461
+ return { ...request, options };
213462
+ }
213463
+ function resolveProgressHeartbeatMs(input2) {
213464
+ if (input2.progressHeartbeatS === undefined) {
213465
+ return input2.progressHeartbeatMs;
213466
+ }
213467
+ return resolveRequestTimeUnit({
213468
+ milliseconds: input2.progressHeartbeatMs,
213469
+ seconds: input2.progressHeartbeatS
213470
+ }, {
213471
+ milliseconds: "progressHeartbeatMs",
213472
+ seconds: "progressHeartbeatS"
213473
+ }, { allowZero: true })?.milliseconds;
213474
+ }
213475
+ function normalizeRequestTimeUnitField(target, millisecondsKey, secondsKey, fields) {
213476
+ if (target[secondsKey] !== undefined) {
213477
+ const resolved = resolveRequestTimeUnit({
213478
+ milliseconds: target[millisecondsKey],
213479
+ seconds: target[secondsKey]
213480
+ }, fields);
213481
+ if (resolved)
213482
+ target[millisecondsKey] = resolved.milliseconds;
213483
+ }
213484
+ delete target[secondsKey];
213485
+ }
213486
+ function resolveRequestTimeUnit(input2, fields, constraints) {
213487
+ try {
213488
+ return resolveTimeUnitPair(input2, fields, constraints);
213489
+ } catch (error51) {
213490
+ if (error51 instanceof TimeUnitValidationError) {
213491
+ throw new KyosoRequestError(error51.message, "VALIDATION_ERROR");
213492
+ }
213493
+ throw error51;
213494
+ }
213495
+ }
213496
+
213246
213497
  // src/core/verification.ts
213247
213498
  var REAL_AGENTS = ["codex", "claude"];
213248
213499
  var VERIFIABLE_SEVERITIES = new Set(["critical", "high"]);
@@ -213301,7 +213552,7 @@ function parseVerificationVerdicts(rawText) {
213301
213552
  if (!Array.isArray(parsed.verdicts))
213302
213553
  return;
213303
213554
  return parsed.verdicts.flatMap((item) => {
213304
- if (!isRecord19(item))
213555
+ if (!isRecord20(item))
213305
213556
  return [];
213306
213557
  if (typeof item.findingId !== "string")
213307
213558
  return [];
@@ -213379,7 +213630,7 @@ function verificationNote(reasoning) {
213379
213630
  function isVerdict(value) {
213380
213631
  return value === "confirmed" || value === "refuted" || value === "uncertain";
213381
213632
  }
213382
- function isRecord19(value) {
213633
+ function isRecord20(value) {
213383
213634
  return typeof value === "object" && value !== null && !Array.isArray(value);
213384
213635
  }
213385
213636
 
@@ -213387,7 +213638,7 @@ function isRecord19(value) {
213387
213638
  var MAX_AGENT_RETRY_PROGRESS_EVENTS = 100;
213388
213639
  function requestForRecursionFingerprint(request) {
213389
213640
  try {
213390
- return scanAndRedactSecrets(request).redactedRequest;
213641
+ return scanAndRedactSecrets(normalizeRequestTimeUnits(request)).redactedRequest;
213391
213642
  } catch {
213392
213643
  return { goal: "" };
213393
213644
  }
@@ -213647,15 +213898,17 @@ async function runReview(tool, request, options = {}) {
213647
213898
  });
213648
213899
  validateReviewRequest(tool, request);
213649
213900
  const reviewBudget = resolveReviewBudget(loaded.config.reviewBudget, request.options?.reviewBudget);
213650
- const budgetTracker = new ReviewBudgetTracker(reviewBudget, startedAtEpochMs, configuredReviewModelCallPlan(loaded.config, reviewBudget, options.env ?? process.env, request.options?.judgeProvider));
213651
- assertTrustedWorkspaceRoot(request.workspace?.root, loaded.config.workspace.root, cwd);
213652
- const networkMode = resolveNetworkMode(request.options?.network, loaded.config.network.defaultMode, options.mcpNetworkMode);
213901
+ const normalizedRequest = normalizeRequestTimeUnits(request);
213902
+ const progressHeartbeatMs = resolveProgressHeartbeatMs(options);
213903
+ const budgetTracker = new ReviewBudgetTracker(reviewBudget, startedAtEpochMs, configuredReviewModelCallPlan(loaded.config, reviewBudget, options.env ?? process.env, normalizedRequest.options?.judgeProvider));
213904
+ assertTrustedWorkspaceRoot(normalizedRequest.workspace?.root, loaded.config.workspace.root, cwd);
213905
+ const networkMode = resolveNetworkMode(normalizedRequest.options?.network, loaded.config.network.defaultMode, options.mcpNetworkMode);
213653
213906
  if (networkMode === "unrestricted" && !loaded.config.network.allowUnrestricted) {
213654
213907
  throw new KyosoRequestError("unrestricted network mode is disabled by config", "NETWORK_MODE_DISABLED");
213655
213908
  }
213656
213909
  const disabledPolicy = disabledReviewPolicy(tool, loaded.config, options.entrypoint);
213657
213910
  if (disabledPolicy) {
213658
- const redactedRequest = requestForRecursionFingerprint(request);
213911
+ const redactedRequest = requestForRecursionFingerprint(normalizedRequest);
213659
213912
  const requestFingerprint2 = createRequestFingerprint({
213660
213913
  tool,
213661
213914
  request: redactedRequest,
@@ -213706,7 +213959,7 @@ async function runReview(tool, request, options = {}) {
213706
213959
  warnings.push("Network mode is unrestricted; write policy remains denied.");
213707
213960
  }
213708
213961
  startPhase("context");
213709
- const secretScan = scanAndRedactSecrets(request);
213962
+ const secretScan = scanAndRedactSecrets(normalizedRequest);
213710
213963
  await trace.write({
213711
213964
  type: "secret_scan_completed",
213712
213965
  traceId,
@@ -213714,7 +213967,7 @@ async function runReview(tool, request, options = {}) {
213714
213967
  redactions: secretScan.redactions,
213715
213968
  timestamp: new Date().toISOString()
213716
213969
  });
213717
- const allowSecretOverride = loaded.config.secrets.allowOverride && request.options?.allowSecretRedaction === true;
213970
+ const allowSecretOverride = loaded.config.secrets.allowOverride && normalizedRequest.options?.allowSecretRedaction === true;
213718
213971
  if (secretScan.detected && loaded.config.secrets.blockOnDetectedSecret && !allowSecretOverride) {
213719
213972
  const requestFingerprint2 = createRequestFingerprint({
213720
213973
  tool,
@@ -213801,7 +214054,7 @@ async function runReview(tool, request, options = {}) {
213801
214054
  budgetTracker,
213802
214055
  progressDispatcher: dispatcher,
213803
214056
  signal: options.signal,
213804
- progressHeartbeatMs: options.progressHeartbeatMs
214057
+ progressHeartbeatMs
213805
214058
  });
213806
214059
  completePhase("primary");
213807
214060
  warnings.push(...agentResults.flatMap((result) => (result.warnings ?? []).map((warning) => `Agent ${result.agent} ${warning}`)));
@@ -215349,9 +215602,11 @@ var kyosoReviewRequestSchema = object({
215349
215602
  options: object({
215350
215603
  network: _enum2(["model_only", "unrestricted"]).optional(),
215351
215604
  maxAgentTimeoutMs: number2().int().positive().optional(),
215605
+ maxAgentTimeoutS: secondsSchema("options.maxAgentTimeoutS").optional(),
215352
215606
  reviewBudget: object({
215353
215607
  maxModelCalls: number2().int().positive().optional(),
215354
215608
  maxTotalWallTimeMs: number2().int().positive().optional(),
215609
+ maxTotalWallTimeS: secondsSchema("options.reviewBudget.maxTotalWallTimeS").optional(),
215355
215610
  maxAgentOutputBytes: number2().int().positive().optional(),
215356
215611
  maxFindingsPerAgent: number2().int().positive().optional(),
215357
215612
  skipOptionalPhasesWhenTokenUsageUnknown: boolean2().optional()
@@ -215361,6 +215616,18 @@ var kyosoReviewRequestSchema = object({
215361
215616
  allowSecretRedaction: boolean2().optional()
215362
215617
  }).optional()
215363
215618
  });
215619
+ function secondsSchema(field) {
215620
+ return number2().superRefine((value, context) => {
215621
+ try {
215622
+ secondsToMilliseconds(value, field);
215623
+ } catch (error51) {
215624
+ context.addIssue({
215625
+ code: "custom",
215626
+ message: error51 instanceof TimeUnitValidationError ? error51.message : `${field} is invalid.`
215627
+ });
215628
+ }
215629
+ });
215630
+ }
215364
215631
 
215365
215632
  // src/mcp/server.ts
215366
215633
  var KYOSO_MCP_INSTRUCTIONS = "Kyoso is a multi-agent planning and review gate. Use it only when the user explicitly asks for Kyoso, multi-agent review, plan review, security review, CISA Secure by Design review, or diff review. Kyoso does not apply code changes. It returns structured review results and Markdown summaries.";