johns-harness 2026.9.16 → 2026.9.18

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 (49) hide show
  1. package/README.md +3 -3
  2. package/dist/audio-transcription-runner-DfRfzdqH.js +4 -3
  3. package/dist/audio-transcription-runner-DldZwQqa.js +4 -3
  4. package/dist/auth-profiles-5CHn7vq1.js +4 -1
  5. package/dist/catalog-refresh.js +90 -0
  6. package/dist/config-koj5M_EO.js +2 -1
  7. package/dist/daemon-cli.js +2 -1
  8. package/dist/gateway-cli-B7fBU7gD.js +9 -0
  9. package/dist/gateway-cli-BCNMwzNq.js +9 -0
  10. package/dist/image-fMgabouP.js +4 -22
  11. package/dist/image-u5AOhmHp.js +4 -22
  12. package/dist/model-catalog-D1QJl-qH.js +4 -3
  13. package/dist/model-catalog-Ezhj-HLy.js +4 -3
  14. package/dist/model-selection-BGlGpPgM.js +4 -1
  15. package/dist/model-selection-BU6wl1le.js +4 -1
  16. package/dist/model-selection-L7RMwsG-.js +4 -1
  17. package/dist/models-config-CAmcg63r.js +4 -22
  18. package/dist/models-config-DXA5BkaM.js +4 -22
  19. package/dist/plugin-sdk/audio-transcription-runner-BKRoAe2_.js +4 -3
  20. package/dist/plugin-sdk/audio-transcription-runner-BRykE3qr.js +4 -3
  21. package/dist/plugin-sdk/audio-transcription-runner-BktijAfd.js +4 -3
  22. package/dist/plugin-sdk/audio-transcription-runner-Bsyu4xAK.js +4 -3
  23. package/dist/plugin-sdk/audio-transcription-runner-DDBSv70C.js +4 -3
  24. package/dist/plugin-sdk/audio-transcription-runner-SuEVMoyi.js +4 -3
  25. package/dist/plugin-sdk/config-4Fgm-yEH.js +4 -1
  26. package/dist/plugin-sdk/config-Di-lyCdh.js +4 -1
  27. package/dist/plugin-sdk/discord.js +2 -1
  28. package/dist/plugin-sdk/image-DWTI1M2u.js +4 -22
  29. package/dist/plugin-sdk/image-DkrZMq9n.js +4 -22
  30. package/dist/plugin-sdk/image-GobYx2eE.js +4 -22
  31. package/dist/plugin-sdk/image-gMD4OQpH.js +4 -22
  32. package/dist/plugin-sdk/image-gqHdJiG1.js +4 -22
  33. package/dist/plugin-sdk/image-sUXMwrTj.js +4 -22
  34. package/dist/plugin-sdk/mattermost.js +6 -25
  35. package/dist/plugin-sdk/model-auth-CX9cPHdC.js +4 -1
  36. package/dist/plugin-sdk/model-auth-Ciehz0x5.js +4 -1
  37. package/dist/plugin-sdk/model-auth-DVyo6JSX.js +4 -1
  38. package/dist/plugin-sdk/model-auth-kiHYHGrs.js +4 -1
  39. package/dist/plugin-sdk/model-selection-Dbj4jDYM.js +4 -1
  40. package/dist/runtime-integrity.js +53 -0
  41. package/dist/runtime-path.js +9 -3
  42. package/dist/update-cli-Cm_l3W29.js +2 -0
  43. package/dist/update-command.js +30 -6
  44. package/dist/volume-update.js +208 -0
  45. package/docs/PATCHES.md +96 -1
  46. package/package.json +1 -1
  47. package/scripts/postinstall.mjs +8 -1
  48. package/vendor/patched-deps/@mariozechner/pi-coding-agent/dist/core/model-registry.js +561 -0
  49. package/vendor/patched-deps/@mariozechner/pi-coding-agent/package.json +5 -0
package/README.md CHANGED
@@ -73,8 +73,8 @@ node johnness.mjs --help
73
73
  ### Verify
74
74
 
75
75
  ```bash
76
- npm test # 767 tests against the installed dependency tree
77
- bash scripts/verify-patches.sh # 395 checks across every patch family
76
+ npm test # 850 tests against the installed dependency tree
77
+ bash scripts/verify-patches.sh # 417 checks across every patch family
78
78
  ```
79
79
 
80
80
  ## Launch a swarm with one command
@@ -187,7 +187,7 @@ The log is a [`RULES.md`](RULES.md) workspace convention enforced through the ac
187
187
 
188
188
  ## Patch families
189
189
 
190
- The runtime carries 64 patch families. Each is a production fix applied at the source with a regression test, a durable patch marker, and a rollback path. A verifier runs 395 checks against the package tree and installed dependencies, and 767 tests run against the installed dependency tree.
190
+ The runtime carries 65 patch families plus the 65.1 safe-update amendment. Each is a production fix applied at the source with a regression test, a durable patch marker, and a rollback path. A verifier runs 417 checks against the package tree and installed dependencies, and 850 tests run against the installed dependency tree.
191
191
 
192
192
  Every family follows the same six steps: reproduce the failure, trace the exact runtime path, make the smallest source-level change that restores the invariant, add a regression test and a patch marker, run the verifier, and retain rollback artifacts. The full index: [`docs/PATCHES.md`](docs/PATCHES.md).
193
193
 
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "./catalog-refresh.js";
1
3
  import { detectLocalWhisper, runNativeWhisper } from "./native-whisper.js";
2
4
  import { b as resolveAgentModelPrimaryValue, y as resolveAgentModelFallbackValues } from "./run-with-concurrency-Cuc1THN9.js";
3
5
  import { T as resolvePreferredJohnnessTmpDir, d as logVerbose, m as shouldLogVerbose, t as createSubsystemLogger } from "./subsystem-C-Cf_MFK.js";
@@ -136,7 +138,7 @@ async function loadModelCatalog(params) {
136
138
  const { join } = await import("node:path");
137
139
  const authStorage = piSdk.discoverAuthStorage(agentDir);
138
140
  const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
139
- const entries = Array.isArray(registry) ? registry : registry.getAll();
141
+ const entries = mergeShippedCatalog65(Array.isArray(registry) ? registry : registry.getAll());
140
142
  for (const entry of entries) {
141
143
  const id = String(entry?.id ?? "").trim();
142
144
  if (!id) continue;
@@ -168,8 +170,7 @@ async function loadModelCatalog(params) {
168
170
  log.warn(`Failed to load model catalog: ${String(error)}`);
169
171
  }
170
172
  modelCatalogPromise = null;
171
- if (models.length > 0) return sortModels(models);
172
- return [];
173
+ return sortModels(mergeShippedCatalog65(models));
173
174
  }
174
175
  })();
175
176
  return modelCatalogPromise;
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "./catalog-refresh.js";
1
3
  import { detectLocalWhisper, runNativeWhisper } from "./native-whisper.js";
2
4
  import { O as runExec, _t as resolveAgentModelFallbackValues, vt as resolveAgentModelPrimaryValue } from "./run-with-concurrency-BXSUl5Nj.js";
3
5
  import { B as shouldLogVerbose, O as createSubsystemLogger, R as logVerbose, X as resolvePreferredJohnnessTmpDir } from "./logger-Bj0Xl6pn.js";
@@ -135,7 +137,7 @@ async function loadModelCatalog(params) {
135
137
  const { join } = await import("node:path");
136
138
  const authStorage = piSdk.discoverAuthStorage(agentDir);
137
139
  const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
138
- const entries = Array.isArray(registry) ? registry : registry.getAll();
140
+ const entries = mergeShippedCatalog65(Array.isArray(registry) ? registry : registry.getAll());
139
141
  for (const entry of entries) {
140
142
  const id = String(entry?.id ?? "").trim();
141
143
  if (!id) continue;
@@ -167,8 +169,7 @@ async function loadModelCatalog(params) {
167
169
  log.warn(`Failed to load model catalog: ${String(error)}`);
168
170
  }
169
171
  modelCatalogPromise = null;
170
- if (models.length > 0) return sortModels(models);
171
- return [];
172
+ return sortModels(mergeShippedCatalog65(models));
172
173
  }
173
174
  })();
174
175
  return modelCatalogPromise;
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "./catalog-refresh.js";
1
3
  import { refreshManagedCodexProfile, readManagedCodexStore, mutateAuthProfile, updateAuthStoreMetadata, saveAuthStoreSnapshot } from "./codex-oauth-owner.js";
2
4
  import { t as __exportAll } from "./rolldown-runtime-DUslC3ob.js";
3
5
  import { _ as expandHomePrefix, a as resolveCanonicalConfigPath, c as resolveDefaultConfigCandidates, d as resolveIsNixMode, f as resolveLegacyStateDirs, g as resolveStateDir, h as resolveOAuthPath, i as isNixMode, l as resolveGatewayLockDir, m as resolveOAuthDir, n as DEFAULT_GATEWAY_PORT, o as resolveConfigPath, p as resolveNewStateDir, r as STATE_DIR, s as resolveConfigPathCandidate, t as CONFIG_PATH, u as resolveGatewayPort, y as resolveRequiredHomeDir } from "./paths-BfR2LXbA.js";
@@ -3783,6 +3785,7 @@ function resolveSubagentSpawnModelSelection(params) {
3783
3785
  }) ?? normalizeModelSelection(resolveAgentModelPrimaryValue(params.cfg.agents?.defaults?.model)) ?? `${runtimeDefault.provider}/${runtimeDefault.model}`;
3784
3786
  }
3785
3787
  function buildAllowedModelSet(params) {
3788
+ params = { ...params, catalog: mergeShippedCatalog65(params.catalog) };
3786
3789
  const rawAllowlist = (() => {
3787
3790
  const modelMap = params.cfg.agents?.defaults?.models ?? {};
3788
3791
  return Object.keys(modelMap);
@@ -5391,7 +5394,7 @@ function applyContextPruningDefaults(cfg) {
5391
5394
  };
5392
5395
  mutated = true;
5393
5396
  }
5394
- if (authMode === "api_key") {
5397
+ if (authMode === "api_key" && Object.keys(defaults.models ?? {}).length > 0) {
5395
5398
  const nextModels = defaults.models ? { ...defaults.models } : {};
5396
5399
  let modelsMutated = false;
5397
5400
  const isAnthropicCacheRetentionTarget = (parsed) => Boolean(parsed && (parsed.provider === "anthropic" || parsed.provider === "amazon-bedrock" && parsed.model.toLowerCase().includes("anthropic.claude")));
@@ -0,0 +1,90 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import fs from "node:fs/promises";
3
+ import { readFileSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { createHash, randomUUID } from "node:crypto";
6
+ import { getModels, getProviders } from "@mariozechner/pi-ai";
7
+ const MODELS = Object.fromEntries(getProviders().map((provider) => [provider, Object.fromEntries(getModels(provider).map((model) => [model.id, model]))]));
8
+
9
+ const VERSION = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
10
+ const SHIPPED = Object.values(MODELS).flatMap((models) => Object.values(models));
11
+ const keyOf = (model) => `${model.provider}/${model.id}`;
12
+ const digest = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
13
+ const locks = globalThis[Symbol.for("johnness.catalog-refresh.65.locks")] ??= new Map();
14
+ const record = (value) => value && typeof value === "object" && !Array.isArray(value);
15
+
16
+ // Selection is independent of disk freshness or writability. Custom descriptors win.
17
+ export function mergeShippedCatalog65(entries = []) {
18
+ const merged = new Map(SHIPPED.map((entry) => [keyOf(entry), entry]));
19
+ for (const entry of entries) {
20
+ if (!entry?.provider || !entry?.id) continue;
21
+ const key = keyOf(entry);
22
+ merged.set(key, { ...merged.get(key), ...entry });
23
+ }
24
+ return [...merged.values()];
25
+ }
26
+
27
+ export function buildCatalogDocument65(existing = {}, providers = {}, version = VERSION) {
28
+ const generated = {};
29
+ const merged = {};
30
+ const previousGenerated = existing._johnness?.generated ?? {};
31
+ for (const [provider, models] of Object.entries(MODELS)) {
32
+ const entries = Object.values(models).map((model) => ({ ...model }));
33
+ merged[provider] = { models: entries };
34
+ for (const model of entries) generated[`${provider}/${model.id}`] = digest(model);
35
+ }
36
+ for (const source of [existing.providers, providers]) {
37
+ for (const [provider, config] of Object.entries(record(source) ? source : {})) {
38
+ if (!record(config)) continue;
39
+ const prior = merged[provider] ?? { models: [] };
40
+ const models = new Map(prior.models.map((model) => [model.id, model]));
41
+ for (const model of Array.isArray(config.models) ? config.models : []) {
42
+ if (!model?.id) continue;
43
+ const key = `${provider}/${model.id}`;
44
+ // Unedited generated entries follow the new release; custom tuning survives.
45
+ if (previousGenerated[key] === digest(model)) continue;
46
+ const base = models.get(model.id);
47
+ models.set(model.id, { ...base, ...model, ...(base?.cost && model.cost ? { cost: { ...base.cost, ...model.cost } } : {}) });
48
+ }
49
+ merged[provider] = { ...prior, ...config, models: [...models.values()] };
50
+ }
51
+ }
52
+ return { ...existing, providers: merged, _johnness: { version, generated } };
53
+ }
54
+
55
+ // Called at gateway startup and every derived-model ensure. No config/auth writes.
56
+ export async function refreshJohnnessCatalog65({ agentDir, providers = {}, log = console, version = VERSION }) {
57
+ const target = path.join(agentDir, "models.json");
58
+ const prior = locks.get(target) ?? Promise.resolve();
59
+ const run = prior.catch(() => {}).then(async () => {
60
+ let existing = {};
61
+ let raw = "";
62
+ let temporary;
63
+ try {
64
+ try {
65
+ raw = await fs.readFile(target, "utf8");
66
+ const parsed = JSON.parse(raw);
67
+ if (record(parsed)) existing = parsed;
68
+ } catch (error) {
69
+ if (error.code !== "ENOENT" && !(error instanceof SyntaxError)) throw error;
70
+ }
71
+ const document = buildCatalogDocument65(existing, providers, version);
72
+ const next = `${JSON.stringify(document, null, 2)}\n`;
73
+ if (raw === next) return { agentDir, wrote: false };
74
+ await fs.mkdir(agentDir, { recursive: true, mode: 0o700 });
75
+ temporary = `${target}.${randomUUID()}.tmp`;
76
+ await fs.writeFile(temporary, next, { mode: 0o600, flag: "wx" });
77
+ await fs.rename(temporary, target);
78
+ return { agentDir, wrote: true };
79
+ } catch (error) {
80
+ // Never echo provider configuration, credentials, file content or error prose.
81
+ log.warn?.(`model-catalog: refresh unavailable (${String(error?.code ?? "WRITE_FAILED").replace(/[^A-Z0-9_]/g, "")}); using merged shipped catalog`);
82
+ return { agentDir, wrote: false };
83
+ } finally {
84
+ if (temporary) await fs.unlink(temporary).catch(() => {});
85
+ }
86
+ });
87
+ locks.set(target, run);
88
+ try { return await run; }
89
+ finally { if (locks.get(target) === run) locks.delete(target); }
90
+ }
@@ -1,3 +1,4 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
1
2
  // JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
2
3
  import { i as isBlockedObjectKey } from "./account-id-DQE6gyMr.js";
3
4
  import { a as normalizeAgentId, i as DEFAULT_AGENT_ID, n as hasConfiguredSecretInput, t as coerceSecretRef } from "./types.secrets-D9YNIyIP.js";
@@ -2088,7 +2089,7 @@ function applyContextPruningDefaults(cfg) {
2088
2089
  };
2089
2090
  mutated = true;
2090
2091
  }
2091
- if (authMode === "api_key") {
2092
+ if (authMode === "api_key" && Object.keys(defaults.models ?? {}).length > 0) {
2092
2093
  const nextModels = defaults.models ? { ...defaults.models } : {};
2093
2094
  let modelsMutated = false;
2094
2095
  const isAnthropicCacheRetentionTarget = (parsed) => Boolean(parsed && (parsed.provider === "anthropic" || parsed.provider === "amazon-bedrock" && parsed.model.toLowerCase().includes("anthropic.claude")));
@@ -1,3 +1,4 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
1
2
  // JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
2
3
  import { createRequire } from "node:module";
3
4
  import fsSync from "node:fs";
@@ -5239,7 +5240,7 @@ function applyContextPruningDefaults(cfg) {
5239
5240
  };
5240
5241
  mutated = true;
5241
5242
  }
5242
- if (authMode === "api_key") {
5243
+ if (authMode === "api_key" && Object.keys(defaults.models ?? {}).length > 0) {
5243
5244
  const nextModels = defaults.models ? { ...defaults.models } : {};
5244
5245
  let modelsMutated = false;
5245
5246
  const isAnthropicCacheRetentionTarget = (parsed) => Boolean(parsed && (parsed.provider === "anthropic" || parsed.provider === "amazon-bedrock" && parsed.model.toLowerCase().includes("anthropic.claude")));
@@ -1,3 +1,7 @@
1
+ // JOHNNESS_PATCH_SAFE_VOLUME_UPDATE_65_1
2
+ import { readInstalledVersion as readUpdatedRuntimeVersion } from "./update-command.js";
3
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
4
+ import { refreshJohnnessCatalog65 } from "./catalog-refresh.js";
1
5
  import { g as resolveStateDir, i as isNixMode, l as resolveGatewayLockDir, o as resolveConfigPath, r as STATE_DIR, t as CONFIG_PATH, u as resolveGatewayPort } from "./paths-BJV7vkaX.js";
2
6
  import { a as logVerbose, d as colorize, f as isRich, g as getResolvedLoggerSettings, h as getLogger, m as getChildLogger, p as theme, s as setVerbose } from "./globals-BM8hKFm0.js";
3
7
  import { C as sleep, D as isPlainObject, E as truncateUtf16Safe, S as shortenHomePath, c as ensureDir, r as clamp, y as resolveUserPath } from "./utils-DC4zYvW0.js";
@@ -21752,6 +21756,10 @@ async function scheduleRestartSentinelWake(_params) {
21752
21756
  const sentinel = await consumeRestartSentinel();
21753
21757
  if (!sentinel) return;
21754
21758
  const payload = sentinel.payload;
21759
+ if (payload.stats?.mode === "chat.update") {
21760
+ const running = readUpdatedRuntimeVersion();
21761
+ payload.message = running === payload.stats.targetVersion ? `johns-harness is now on ${running}. The new runtime has booted.` : `Update restart complete. Running johns-harness ${running}; requested ${payload.stats.targetVersion ?? "unknown"}.`;
21762
+ }
21755
21763
  const sessionKey = payload.sessionKey?.trim();
21756
21764
  const message = formatRestartSentinelMessage(payload);
21757
21765
  const summary = summarizeRestartSentinel(payload);
@@ -23553,6 +23561,7 @@ async function startGatewayServer(port = 18789, opts = {}) {
23553
23561
  });
23554
23562
  initSubagentRegistry();
23555
23563
  const defaultAgentId = resolveDefaultAgentId(cfgAtStart);
23564
+ for (const agentId of listAgentIds(cfgAtStart)) await refreshJohnnessCatalog65({ agentDir: resolveAgentDir(cfgAtStart, agentId), log });
23556
23565
  const defaultWorkspaceDir = resolveAgentWorkspaceDir(cfgAtStart, defaultAgentId);
23557
23566
  const baseMethods = listGatewayMethods();
23558
23567
  const emptyPluginRegistry = createEmptyPluginRegistry();
@@ -1,3 +1,7 @@
1
+ // JOHNNESS_PATCH_SAFE_VOLUME_UPDATE_65_1
2
+ import { readInstalledVersion as readUpdatedRuntimeVersion } from "./update-command.js";
3
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
4
+ import { refreshJohnnessCatalog65 } from "./catalog-refresh.js";
1
5
  import { a as logVerbose, d as colorize, f as isRich, g as getResolvedLoggerSettings, h as getLogger, m as getChildLogger, p as theme, s as setVerbose } from "./globals-Bv4ZcVWM.js";
2
6
  import { g as resolveStateDir, i as isNixMode, l as resolveGatewayLockDir, o as resolveConfigPath, r as STATE_DIR, t as CONFIG_PATH, u as resolveGatewayPort } from "./paths-BfR2LXbA.js";
3
7
  import { a as setConsoleSubsystemFilter, f as defaultRuntime, n as runtimeForLogger, o as setConsoleTimestampPrefix, t as createSubsystemLogger } from "./subsystem-Cf9yS0UI.js";
@@ -21754,6 +21758,10 @@ async function scheduleRestartSentinelWake(_params) {
21754
21758
  const sentinel = await consumeRestartSentinel();
21755
21759
  if (!sentinel) return;
21756
21760
  const payload = sentinel.payload;
21761
+ if (payload.stats?.mode === "chat.update") {
21762
+ const running = readUpdatedRuntimeVersion();
21763
+ payload.message = running === payload.stats.targetVersion ? `johns-harness is now on ${running}. The new runtime has booted.` : `Update restart complete. Running johns-harness ${running}; requested ${payload.stats.targetVersion ?? "unknown"}.`;
21764
+ }
21757
21765
  const sessionKey = payload.sessionKey?.trim();
21758
21766
  const message = formatRestartSentinelMessage(payload);
21759
21767
  const summary = summarizeRestartSentinel(payload);
@@ -23555,6 +23563,7 @@ async function startGatewayServer(port = 18789, opts = {}) {
23555
23563
  });
23556
23564
  initSubagentRegistry();
23557
23565
  const defaultAgentId = resolveDefaultAgentId(cfgAtStart);
23566
+ for (const agentId of listAgentIds(cfgAtStart)) await refreshJohnnessCatalog65({ agentDir: resolveAgentDir(cfgAtStart, agentId), log });
23558
23567
  const defaultWorkspaceDir = resolveAgentWorkspaceDir(cfgAtStart, defaultAgentId);
23559
23568
  const baseMethods = listGatewayMethods();
23560
23569
  const emptyPluginRegistry = createEmptyPluginRegistry();
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { refreshJohnnessCatalog65 } from "./catalog-refresh.js";
1
3
  import { b as resolveAgentModelPrimaryValue, y as resolveAgentModelFallbackValues } from "./run-with-concurrency-Cuc1THN9.js";
2
4
  import { f as isRecord, x as shortenHomeInString } from "./logger-BW8uLq6f.js";
3
5
  import { $ as getRuntimeConfigSnapshot, A as requireApiKey, Cr as normalizeSecretInput, O as getApiKeyForModel, P as isNonSecretApiKeyMarker, _ as normalizeProviders, b as resolveImplicitProviders, er as applyConfigEnvVars, et as getRuntimeConfigSourceSnapshot, mr as resolveJohnnessAgentDir, s as normalizeModelRef, tt as loadConfig, v as resolveImplicitBedrockProvider, y as resolveImplicitCopilotProvider } from "./model-selection-BU6wl1le.js";
@@ -183,10 +185,7 @@ async function ensureJohnnessModelsJson(config, agentDirOverride) {
183
185
  cfg,
184
186
  agentDir
185
187
  });
186
- if (Object.keys(providers).length === 0) return {
187
- agentDir,
188
- wrote: false
189
- };
188
+ // Empty provider config still needs the shipped catalog.
190
189
  const mode = cfg.models?.mode ?? DEFAULT_MODE;
191
190
  const secretRefManagedProviders = /* @__PURE__ */ new Set();
192
191
  const explicitBaseUrlProviders = new Set(Object.entries(cfg.models?.providers ?? {}).map(([key, provider]) => [key.trim(), provider]).filter(([key, provider]) => Boolean(key) && typeof provider?.baseUrl === "string" && provider.baseUrl.trim()).map(([key]) => key));
@@ -202,24 +201,7 @@ async function ensureJohnnessModelsJson(config, agentDirOverride) {
202
201
  secretRefManagedProviders,
203
202
  explicitBaseUrlProviders
204
203
  });
205
- const next = `${JSON.stringify({ providers: mergedProviders }, null, 2)}\n`;
206
- if (await readRawFile(targetPath) === next) {
207
- await ensureModelsFileMode(targetPath);
208
- return {
209
- agentDir,
210
- wrote: false
211
- };
212
- }
213
- await fs.mkdir(agentDir, {
214
- recursive: true,
215
- mode: 448
216
- });
217
- await fs.writeFile(targetPath, next, { mode: 384 });
218
- await ensureModelsFileMode(targetPath);
219
- return {
220
- agentDir,
221
- wrote: true
222
- };
204
+ return await refreshJohnnessCatalog65({ agentDir, providers: mergedProviders });
223
205
  });
224
206
  }
225
207
  //#endregion
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { refreshJohnnessCatalog65 } from "./catalog-refresh.js";
1
3
  import { _t as resolveAgentModelFallbackValues, vt as resolveAgentModelPrimaryValue } from "./run-with-concurrency-BXSUl5Nj.js";
2
4
  import { f as isRecord, x as shortenHomeInString } from "./logger-Bj0Xl6pn.js";
3
5
  import { $ as getRuntimeConfigSourceSnapshot, D as getApiKeyForModel, Dr as normalizeSecretInput, N as isNonSecretApiKeyMarker, Q as getRuntimeConfigSnapshot, _ as resolveImplicitBedrockProvider, et as loadConfig, g as normalizeProviders, k as requireApiKey, rr as applyConfigEnvVars, s as normalizeModelRef, v as resolveImplicitCopilotProvider, vr as resolveJohnnessAgentDir, y as resolveImplicitProviders } from "./model-selection-BGlGpPgM.js";
@@ -183,10 +185,7 @@ async function ensureJohnnessModelsJson(config, agentDirOverride) {
183
185
  cfg,
184
186
  agentDir
185
187
  });
186
- if (Object.keys(providers).length === 0) return {
187
- agentDir,
188
- wrote: false
189
- };
188
+ // Empty provider config still needs the shipped catalog.
190
189
  const mode = cfg.models?.mode ?? DEFAULT_MODE;
191
190
  const secretRefManagedProviders = /* @__PURE__ */ new Set();
192
191
  const explicitBaseUrlProviders = new Set(Object.entries(cfg.models?.providers ?? {}).map(([key, provider]) => [key.trim(), provider]).filter(([key, provider]) => Boolean(key) && typeof provider?.baseUrl === "string" && provider.baseUrl.trim()).map(([key]) => key));
@@ -202,24 +201,7 @@ async function ensureJohnnessModelsJson(config, agentDirOverride) {
202
201
  secretRefManagedProviders,
203
202
  explicitBaseUrlProviders
204
203
  });
205
- const next = `${JSON.stringify({ providers: mergedProviders }, null, 2)}\n`;
206
- if (await readRawFile(targetPath) === next) {
207
- await ensureModelsFileMode(targetPath);
208
- return {
209
- agentDir,
210
- wrote: false
211
- };
212
- }
213
- await fs.mkdir(agentDir, {
214
- recursive: true,
215
- mode: 448
216
- });
217
- await fs.writeFile(targetPath, next, { mode: 384 });
218
- await ensureModelsFileMode(targetPath);
219
- return {
220
- agentDir,
221
- wrote: true
222
- };
204
+ return await refreshJohnnessCatalog65({ agentDir, providers: mergedProviders });
223
205
  });
224
206
  }
225
207
  //#endregion
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "./catalog-refresh.js";
1
3
  import { t as createSubsystemLogger } from "./subsystem-C9Xgeyrw.js";
2
4
  import { Ai as resolveJohnnessAgentDir, rn as loadConfig } from "./model-selection-L7RMwsG-.js";
3
5
  import { t as ensureJohnnessModelsJson } from "./models-config-CAmcg63r.js";
@@ -119,7 +121,7 @@ async function loadModelCatalog(params) {
119
121
  const { join } = await import("node:path");
120
122
  const authStorage = piSdk.discoverAuthStorage(agentDir);
121
123
  const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
122
- const entries = Array.isArray(registry) ? registry : registry.getAll();
124
+ const entries = mergeShippedCatalog65(Array.isArray(registry) ? registry : registry.getAll());
123
125
  for (const entry of entries) {
124
126
  const id = String(entry?.id ?? "").trim();
125
127
  if (!id) continue;
@@ -151,8 +153,7 @@ async function loadModelCatalog(params) {
151
153
  log.warn(`Failed to load model catalog: ${String(error)}`);
152
154
  }
153
155
  modelCatalogPromise = null;
154
- if (models.length > 0) return sortModels(models);
155
- return [];
156
+ return sortModels(mergeShippedCatalog65(models));
156
157
  }
157
158
  })();
158
159
  return modelCatalogPromise;
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "./catalog-refresh.js";
1
3
  import { t as createSubsystemLogger } from "./subsystem-Cf9yS0UI.js";
2
4
  import { H as loadConfig, lr as resolveJohnnessAgentDir } from "./auth-profiles-5CHn7vq1.js";
3
5
  import { t as ensureJohnnessModelsJson } from "./models-config-DXA5BkaM.js";
@@ -119,7 +121,7 @@ async function loadModelCatalog(params) {
119
121
  const { join } = await import("node:path");
120
122
  const authStorage = piSdk.discoverAuthStorage(agentDir);
121
123
  const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
122
- const entries = Array.isArray(registry) ? registry : registry.getAll();
124
+ const entries = mergeShippedCatalog65(Array.isArray(registry) ? registry : registry.getAll());
123
125
  for (const entry of entries) {
124
126
  const id = String(entry?.id ?? "").trim();
125
127
  if (!id) continue;
@@ -151,8 +153,7 @@ async function loadModelCatalog(params) {
151
153
  log.warn(`Failed to load model catalog: ${String(error)}`);
152
154
  }
153
155
  modelCatalogPromise = null;
154
- if (models.length > 0) return sortModels(models);
155
- return [];
156
+ return sortModels(mergeShippedCatalog65(models));
156
157
  }
157
158
  })();
158
159
  return modelCatalogPromise;
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "./catalog-refresh.js";
1
3
  // JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
2
4
  import { refreshManagedCodexProfile, readManagedCodexStore, mutateAuthProfile, updateAuthStoreMetadata, saveAuthStoreSnapshot } from "./codex-oauth-owner.js";
3
5
  import { t as __exportAll } from "./rolldown-runtime-DUslC3ob.js";
@@ -1956,7 +1958,7 @@ function applyContextPruningDefaults(cfg) {
1956
1958
  };
1957
1959
  mutated = true;
1958
1960
  }
1959
- if (authMode === "api_key") {
1961
+ if (authMode === "api_key" && Object.keys(defaults.models ?? {}).length > 0) {
1960
1962
  const nextModels = defaults.models ? { ...defaults.models } : {};
1961
1963
  let modelsMutated = false;
1962
1964
  const isAnthropicCacheRetentionTarget = (parsed) => Boolean(parsed && (parsed.provider === "anthropic" || parsed.provider === "amazon-bedrock" && parsed.model.toLowerCase().includes("anthropic.claude")));
@@ -18582,6 +18584,7 @@ function resolveSubagentSpawnModelSelection(params) {
18582
18584
  }) ?? normalizeModelSelection(resolveAgentModelPrimaryValue(params.cfg.agents?.defaults?.model)) ?? `${runtimeDefault.provider}/${runtimeDefault.model}`;
18583
18585
  }
18584
18586
  function buildAllowedModelSet(params) {
18587
+ params = { ...params, catalog: mergeShippedCatalog65(params.catalog) };
18585
18588
  const rawAllowlist = (() => {
18586
18589
  const modelMap = params.cfg.agents?.defaults?.models ?? {};
18587
18590
  return Object.keys(modelMap);
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "./catalog-refresh.js";
1
3
  // JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
2
4
  import { refreshManagedCodexProfile, readManagedCodexStore, mutateAuthProfile, updateAuthStoreMetadata, saveAuthStoreSnapshot } from "./codex-oauth-owner.js";
3
5
  import { t as __exportAll } from "./rolldown-runtime-DUslC3ob.js";
@@ -1931,7 +1933,7 @@ function applyContextPruningDefaults(cfg) {
1931
1933
  };
1932
1934
  mutated = true;
1933
1935
  }
1934
- if (authMode === "api_key") {
1936
+ if (authMode === "api_key" && Object.keys(defaults.models ?? {}).length > 0) {
1935
1937
  const nextModels = defaults.models ? { ...defaults.models } : {};
1936
1938
  let modelsMutated = false;
1937
1939
  const isAnthropicCacheRetentionTarget = (parsed) => Boolean(parsed && (parsed.provider === "anthropic" || parsed.provider === "amazon-bedrock" && parsed.model.toLowerCase().includes("anthropic.claude")));
@@ -18471,6 +18473,7 @@ function resolveSubagentSpawnModelSelection(params) {
18471
18473
  }) ?? normalizeModelSelection(resolveAgentModelPrimaryValue(params.cfg.agents?.defaults?.model)) ?? `${runtimeDefault.provider}/${runtimeDefault.model}`;
18472
18474
  }
18473
18475
  function buildAllowedModelSet(params) {
18476
+ params = { ...params, catalog: mergeShippedCatalog65(params.catalog) };
18474
18477
  const rawAllowlist = (() => {
18475
18478
  const modelMap = params.cfg.agents?.defaults?.models ?? {};
18476
18479
  return Object.keys(modelMap);
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "./catalog-refresh.js";
1
3
  import { refreshManagedCodexProfile, readManagedCodexStore, mutateAuthProfile, updateAuthStoreMetadata, saveAuthStoreSnapshot } from "./codex-oauth-owner.js";
2
4
  import { t as __exportAll } from "./rolldown-runtime-DUslC3ob.js";
3
5
  import { _ as expandHomePrefix, a as resolveCanonicalConfigPath, c as resolveDefaultConfigCandidates, d as resolveIsNixMode, f as resolveLegacyStateDirs, g as resolveStateDir, h as resolveOAuthPath, i as isNixMode, l as resolveGatewayLockDir, m as resolveOAuthDir, n as DEFAULT_GATEWAY_PORT, o as resolveConfigPath, p as resolveNewStateDir, r as STATE_DIR, s as resolveConfigPathCandidate, t as CONFIG_PATH, u as resolveGatewayPort, y as resolveRequiredHomeDir } from "./paths-BJV7vkaX.js";
@@ -1862,7 +1864,7 @@ function applyContextPruningDefaults(cfg) {
1862
1864
  };
1863
1865
  mutated = true;
1864
1866
  }
1865
- if (authMode === "api_key") {
1867
+ if (authMode === "api_key" && Object.keys(defaults.models ?? {}).length > 0) {
1866
1868
  const nextModels = defaults.models ? { ...defaults.models } : {};
1867
1869
  let modelsMutated = false;
1868
1870
  const isAnthropicCacheRetentionTarget = (parsed) => Boolean(parsed && (parsed.provider === "anthropic" || parsed.provider === "amazon-bedrock" && parsed.model.toLowerCase().includes("anthropic.claude")));
@@ -16902,6 +16904,7 @@ function resolveSubagentSpawnModelSelection(params) {
16902
16904
  }) ?? normalizeModelSelection(resolveAgentModelPrimaryValue(params.cfg.agents?.defaults?.model)) ?? `${runtimeDefault.provider}/${runtimeDefault.model}`;
16903
16905
  }
16904
16906
  function buildAllowedModelSet(params) {
16907
+ params = { ...params, catalog: mergeShippedCatalog65(params.catalog) };
16905
16908
  const rawAllowlist = (() => {
16906
16909
  const modelMap = params.cfg.agents?.defaults?.models ?? {};
16907
16910
  return Object.keys(modelMap);
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { refreshJohnnessCatalog65 } from "./catalog-refresh.js";
1
3
  import { d as isRecord } from "./utils-DC4zYvW0.js";
2
4
  import { Ai as resolveJohnnessAgentDir, M as resolveImplicitBedrockProvider, N as resolveImplicitCopilotProvider, P as resolveImplicitProviders, ei as applyConfigEnvVars, j as normalizeProviders, nn as getRuntimeConfigSourceSnapshot, ot as isNonSecretApiKeyMarker, rn as loadConfig, tn as getRuntimeConfigSnapshot } from "./model-selection-L7RMwsG-.js";
3
5
  import path from "node:path";
@@ -208,10 +210,7 @@ async function ensureJohnnessModelsJson(config, agentDirOverride) {
208
210
  cfg,
209
211
  agentDir
210
212
  });
211
- if (Object.keys(providers).length === 0) return {
212
- agentDir,
213
- wrote: false
214
- };
213
+ // Empty provider config still needs the shipped catalog.
215
214
  const mode = cfg.models?.mode ?? DEFAULT_MODE;
216
215
  const secretRefManagedProviders = /* @__PURE__ */ new Set();
217
216
  const explicitBaseUrlProviders = new Set(Object.entries(cfg.models?.providers ?? {}).map(([key, provider]) => [key.trim(), provider]).filter(([key, provider]) => Boolean(key) && typeof provider?.baseUrl === "string" && provider.baseUrl.trim()).map(([key]) => key));
@@ -227,24 +226,7 @@ async function ensureJohnnessModelsJson(config, agentDirOverride) {
227
226
  secretRefManagedProviders,
228
227
  explicitBaseUrlProviders
229
228
  });
230
- const next = `${JSON.stringify({ providers: mergedProviders }, null, 2)}\n`;
231
- if (await readRawFile(targetPath) === next) {
232
- await ensureModelsFileMode(targetPath);
233
- return {
234
- agentDir,
235
- wrote: false
236
- };
237
- }
238
- await fs.mkdir(agentDir, {
239
- recursive: true,
240
- mode: 448
241
- });
242
- await fs.writeFile(targetPath, next, { mode: 384 });
243
- await ensureModelsFileMode(targetPath);
244
- return {
245
- agentDir,
246
- wrote: true
247
- };
229
+ return await refreshJohnnessCatalog65({ agentDir, providers: mergedProviders });
248
230
  });
249
231
  }
250
232
  //#endregion
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { refreshJohnnessCatalog65 } from "./catalog-refresh.js";
1
3
  import { B as getRuntimeConfigSnapshot, Ci as isNonSecretApiKeyMarker, Gr as resolveImplicitBedrockProvider, H as loadConfig, Kr as resolveImplicitCopilotProvider, V as getRuntimeConfigSourceSnapshot, Wr as normalizeProviders, lr as resolveJohnnessAgentDir, qr as resolveImplicitProviders, zn as applyConfigEnvVars } from "./auth-profiles-5CHn7vq1.js";
2
4
  import { u as isRecord } from "./utils-C5WN6czr.js";
3
5
  import path from "node:path";
@@ -208,10 +210,7 @@ async function ensureJohnnessModelsJson(config, agentDirOverride) {
208
210
  cfg,
209
211
  agentDir
210
212
  });
211
- if (Object.keys(providers).length === 0) return {
212
- agentDir,
213
- wrote: false
214
- };
213
+ // Empty provider config still needs the shipped catalog.
215
214
  const mode = cfg.models?.mode ?? DEFAULT_MODE;
216
215
  const secretRefManagedProviders = /* @__PURE__ */ new Set();
217
216
  const explicitBaseUrlProviders = new Set(Object.entries(cfg.models?.providers ?? {}).map(([key, provider]) => [key.trim(), provider]).filter(([key, provider]) => Boolean(key) && typeof provider?.baseUrl === "string" && provider.baseUrl.trim()).map(([key]) => key));
@@ -227,24 +226,7 @@ async function ensureJohnnessModelsJson(config, agentDirOverride) {
227
226
  secretRefManagedProviders,
228
227
  explicitBaseUrlProviders
229
228
  });
230
- const next = `${JSON.stringify({ providers: mergedProviders }, null, 2)}\n`;
231
- if (await readRawFile(targetPath) === next) {
232
- await ensureModelsFileMode(targetPath);
233
- return {
234
- agentDir,
235
- wrote: false
236
- };
237
- }
238
- await fs.mkdir(agentDir, {
239
- recursive: true,
240
- mode: 448
241
- });
242
- await fs.writeFile(targetPath, next, { mode: 384 });
243
- await ensureModelsFileMode(targetPath);
244
- return {
245
- agentDir,
246
- wrote: true
247
- };
229
+ return await refreshJohnnessCatalog65({ agentDir, providers: mergedProviders });
248
230
  });
249
231
  }
250
232
  //#endregion
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "../catalog-refresh.js";
1
3
  import { detectLocalWhisper, runNativeWhisper } from "../native-whisper.js";
2
4
  import { J as resolveAgentModelPrimaryValue, O as runExec, q as resolveAgentModelFallbackValues } from "./run-with-concurrency-D4zr_gVN.js";
3
5
  import { B as resolveIMessageAttachmentRoots, D as loadConfig, L as DEFAULT_IMESSAGE_ATTACHMENT_ROOTS, R as isInboundPathAllowed, Yn as resolveJohnnessAgentDir, i as resolveApiKeyForProvider, mr as normalizeGoogleModelId, r as requireApiKey, sr as normalizeProviderId, z as mergeInboundPathRoots } from "./model-auth-DVyo6JSX.js";
@@ -1073,7 +1075,7 @@ async function loadModelCatalog(params) {
1073
1075
  const { join } = await import("node:path");
1074
1076
  const authStorage = piSdk.discoverAuthStorage(agentDir);
1075
1077
  const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
1076
- const entries = Array.isArray(registry) ? registry : registry.getAll();
1078
+ const entries = mergeShippedCatalog65(Array.isArray(registry) ? registry : registry.getAll());
1077
1079
  for (const entry of entries) {
1078
1080
  const id = String(entry?.id ?? "").trim();
1079
1081
  if (!id) continue;
@@ -1105,8 +1107,7 @@ async function loadModelCatalog(params) {
1105
1107
  log.warn(`Failed to load model catalog: ${String(error)}`);
1106
1108
  }
1107
1109
  modelCatalogPromise = null;
1108
- if (models.length > 0) return sortModels(models);
1109
- return [];
1110
+ return sortModels(mergeShippedCatalog65(models));
1110
1111
  }
1111
1112
  })();
1112
1113
  return modelCatalogPromise;
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "../catalog-refresh.js";
1
3
  import { detectLocalWhisper, runNativeWhisper } from "../native-whisper.js";
2
4
  import { O as runExec, U as resolveAgentModelFallbackValues, W as resolveAgentModelPrimaryValue } from "./run-with-concurrency-8rEOAFIb.js";
3
5
  import { Bn as resolveJohnnessAgentDir, Gt as normalizeProviderId, Qt as normalizeGoogleModelId, _ as mergeInboundPathRoots, fn as requireApiKey, g as isInboundPathAllowed, h as DEFAULT_IMESSAGE_ATTACHMENT_ROOTS, i as loadConfig, pn as resolveApiKeyForProvider, v as resolveIMessageAttachmentRoots } from "./config-Di-lyCdh.js";
@@ -1073,7 +1075,7 @@ async function loadModelCatalog(params) {
1073
1075
  const { join } = await import("node:path");
1074
1076
  const authStorage = piSdk.discoverAuthStorage(agentDir);
1075
1077
  const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
1076
- const entries = Array.isArray(registry) ? registry : registry.getAll();
1078
+ const entries = mergeShippedCatalog65(Array.isArray(registry) ? registry : registry.getAll());
1077
1079
  for (const entry of entries) {
1078
1080
  const id = String(entry?.id ?? "").trim();
1079
1081
  if (!id) continue;
@@ -1105,8 +1107,7 @@ async function loadModelCatalog(params) {
1105
1107
  log.warn(`Failed to load model catalog: ${String(error)}`);
1106
1108
  }
1107
1109
  modelCatalogPromise = null;
1108
- if (models.length > 0) return sortModels(models);
1109
- return [];
1110
+ return sortModels(mergeShippedCatalog65(models));
1110
1111
  }
1111
1112
  })();
1112
1113
  return modelCatalogPromise;
@@ -1,3 +1,5 @@
1
+ // JOHNNESS_PATCH_CATALOG_REFRESH_65
2
+ import { mergeShippedCatalog65 } from "../catalog-refresh.js";
1
3
  import { detectLocalWhisper, runNativeWhisper } from "../native-whisper.js";
2
4
  import { E as kindFromMime, S as getFileExtension, b as detectMime, w as isAudioFileName } from "./message-channel-DfmYEnql.js";
3
5
  import { B as shouldLogVerbose, O as createSubsystemLogger, R as logVerbose, X as resolvePreferredJohnnessTmpDir } from "./utils-B0IyLNx9.js";
@@ -1073,7 +1075,7 @@ async function loadModelCatalog(params) {
1073
1075
  const { join } = await import("node:path");
1074
1076
  const authStorage = piSdk.discoverAuthStorage(agentDir);
1075
1077
  const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
1076
- const entries = Array.isArray(registry) ? registry : registry.getAll();
1078
+ const entries = mergeShippedCatalog65(Array.isArray(registry) ? registry : registry.getAll());
1077
1079
  for (const entry of entries) {
1078
1080
  const id = String(entry?.id ?? "").trim();
1079
1081
  if (!id) continue;
@@ -1105,8 +1107,7 @@ async function loadModelCatalog(params) {
1105
1107
  log.warn(`Failed to load model catalog: ${String(error)}`);
1106
1108
  }
1107
1109
  modelCatalogPromise = null;
1108
- if (models.length > 0) return sortModels(models);
1109
- return [];
1110
+ return sortModels(mergeShippedCatalog65(models));
1110
1111
  }
1111
1112
  })();
1112
1113
  return modelCatalogPromise;