johns-harness 2026.9.12 → 2026.9.13

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 (32) hide show
  1. package/README.md +4 -0
  2. package/dist/auth-profiles-5CHn7vq1.js +26 -3
  3. package/dist/compact-B247y5Qt.js +9 -1
  4. package/dist/config-koj5M_EO.js +64 -4
  5. package/dist/daemon-cli.js +64 -4
  6. package/dist/manifest-registry-BMEqbkWA.js +48 -1
  7. package/dist/manifest-registry-Ba187z7Z.js +48 -1
  8. package/dist/model-selection-BGlGpPgM.js +74 -4
  9. package/dist/model-selection-BU6wl1le.js +74 -4
  10. package/dist/model-selection-L7RMwsG-.js +26 -3
  11. package/dist/pi-embedded-C6ITuRXf.js +9 -1
  12. package/dist/pi-embedded-DoQsYfIY.js +9 -1
  13. package/dist/plugin-sdk/config-4Fgm-yEH.js +74 -4
  14. package/dist/plugin-sdk/config-Di-lyCdh.js +74 -4
  15. package/dist/plugin-sdk/discord.js +64 -4
  16. package/dist/plugin-sdk/dispatch-BP0viZiL.js +9 -1
  17. package/dist/plugin-sdk/dispatch-CQsjmw7g.js +9 -1
  18. package/dist/plugin-sdk/dispatch-Cerq29sy.js +9 -1
  19. package/dist/plugin-sdk/dispatch-Cndjtt0g.js +9 -1
  20. package/dist/plugin-sdk/dispatch-UogiJYul.js +9 -1
  21. package/dist/plugin-sdk/model-auth-CX9cPHdC.js +74 -4
  22. package/dist/plugin-sdk/model-auth-Ciehz0x5.js +74 -4
  23. package/dist/plugin-sdk/model-auth-DVyo6JSX.js +74 -4
  24. package/dist/plugin-sdk/model-auth-kiHYHGrs.js +74 -4
  25. package/dist/plugin-sdk/model-selection-Dbj4jDYM.js +74 -4
  26. package/dist/plugin-sdk/reply-DbZnH8-h.js +9 -1
  27. package/dist/reply-C5LKjXcC.js +9 -1
  28. package/docs/PATCHES.md +17 -0
  29. package/extensions/mr-memory/johnness.plugin.json +1 -0
  30. package/package.json +1 -1
  31. package/vendor/patched-deps/@mariozechner/pi-ai/dist/models.generated.js +242 -0
  32. package/vendor/patched-deps/@mariozechner/pi-ai/dist/models.js +5 -0
package/README.md CHANGED
@@ -53,6 +53,10 @@ Enable "Device code authorization for Codex" once in chatgpt.com > Settings > Se
53
53
  For headless installs, run `johnness models auth login --device`; no browser or localhost callback needed.
54
54
  Expired ChatGPT credentials trigger an owner notice with the `/login` recovery command.
55
55
 
56
+ <!-- JOHNNESS_PATCH_DEFAULTS_61 -->
57
+ ### Batteries included
58
+ The harness ships the current model catalog and the short aliases `opus`, `sonnet`, `fable`, `astra`, `sol`, `luna`, `terra`, and `gpt`, so `/model opus` works on a fresh install with no `models.providers` block. Channels you configure load without a `plugins.allow` list; only an explicit `enabled: false` or `plugins.deny` turns one off. Updating the harness updates the catalog and aliases for every agent.
59
+
56
60
  ### From source
57
61
 
58
62
  ```bash
@@ -3536,6 +3536,9 @@ async function resolveImplicitBedrockProvider(params) {
3536
3536
  //#region src/agents/model-selection.ts
3537
3537
  const log$1 = createSubsystemLogger("model-selection");
3538
3538
  const ANTHROPIC_MODEL_ALIASES = {
3539
+ "opus-5": "claude-opus-5", // JOHNNESS_PATCH_DEFAULTS_61
3540
+ "sonnet-5": "claude-sonnet-5",
3541
+ "fable-5.1": "claude-fable-5-1",
3539
3542
  "opus-4.6": "claude-opus-4-6",
3540
3543
  "opus-4.5": "claude-opus-4-5",
3541
3544
  "sonnet-4.6": "claude-sonnet-4-6",
@@ -3683,6 +3686,16 @@ function resolveModelRefFromString(params) {
3683
3686
  ref: aliasMatch.ref,
3684
3687
  alias: aliasMatch.alias
3685
3688
  };
3689
+ // JOHNNESS_PATCH_DEFAULTS_61: fall back to the shipped aliases (opus, sonnet, fable,
3690
+ // astra, sol, luna, terra, gpt) when the user config defines none.
3691
+ const builtinTarget = DEFAULT_MODEL_ALIASES[aliasKey];
3692
+ if (builtinTarget) {
3693
+ const builtinRef = parseModelRef(builtinTarget, params.defaultProvider);
3694
+ if (builtinRef) return {
3695
+ ref: builtinRef,
3696
+ alias: aliasKey
3697
+ };
3698
+ }
3686
3699
  }
3687
3700
  const parsed = parseModelRef(model, params.defaultProvider);
3688
3701
  if (!parsed) return null;
@@ -5081,9 +5094,18 @@ let defaultWarnState = { warned: false };
5081
5094
  const DEFAULT_MODEL_ALIASES = {
5082
5095
  muse: "meta/muse-spark-1.3", // JOHNNESS_PATCH_MUSE_SPARK
5083
5096
  "muse-spark": "meta/muse-spark-1.3",
5084
- opus: "anthropic/claude-opus-4-6",
5085
- sonnet: "anthropic/claude-sonnet-4-6",
5086
- gpt: "openai/gpt-5.4",
5097
+ // JOHNNESS_PATCH_DEFAULTS_61: current model aliases ship with the harness; user config
5098
+ // aliases (agents.defaults.models[*].alias) still take precedence.
5099
+ opus: "anthropic/claude-opus-5",
5100
+ sonnet: "anthropic/claude-sonnet-5",
5101
+ opus46: "anthropic/claude-opus-4-6",
5102
+ sonnet46: "anthropic/claude-sonnet-4-6",
5103
+ fable: "anthropic/claude-fable-5-1",
5104
+ astra: "openai-codex/gpt-6-astra",
5105
+ sol: "openai-codex/gpt-5.6-sol",
5106
+ luna: "openai-codex/gpt-5.6-luna",
5107
+ terra: "openai-codex/gpt-5.6-terra",
5108
+ gpt: "openai-codex/gpt-5.5",
5087
5109
  "gpt-mini": "openai/gpt-5-mini",
5088
5110
  gemini: "google/gemini-3.1-pro-preview",
5089
5111
  "gemini-flash": "google/gemini-3-flash-preview",
@@ -13762,6 +13784,7 @@ function validateConfigObjectWithPluginsBase(raw, opts) {
13762
13784
  workspaceDir: resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)) ?? void 0
13763
13785
  });
13764
13786
  for (const diag of registry.diagnostics) {
13787
+ if (diag.level === "info") continue; // JOHNNESS_PATCH_DEFAULTS_61
13765
13788
  let path = diag.pluginId ? `plugins.entries.${diag.pluginId}` : "plugins";
13766
13789
  if (!diag.pluginId && diag.message.includes("plugin path not found")) path = "plugins.load.paths";
13767
13790
  const message = `${diag.pluginId ? `plugin ${diag.pluginId}` : "plugin"}: ${diag.message}`;
@@ -92632,7 +92632,10 @@ function isTrackedByProvenance(params) {
92632
92632
  function warnWhenAllowlistIsOpen(params) {
92633
92633
  if (!params.pluginsEnabled) return;
92634
92634
  if (params.allow.length > 0) return;
92635
- const nonBundled = params.discoverablePlugins.filter((entry) => entry.origin !== "bundled");
92635
+ // JOHNNESS_PATCH_DEFAULTS_61: plugins the config already implies (memory slot, enabled
92636
+ // entries, install records) are trusted by construction and never warned about.
92637
+ const implied = params.impliedIds ?? new Set();
92638
+ const nonBundled = params.discoverablePlugins.filter((entry) => entry.origin !== "bundled" && !implied.has(entry.id));
92636
92639
  if (nonBundled.length === 0) return;
92637
92640
  const preview = nonBundled.slice(0, 6).map((entry) => `${entry.id} (${entry.source})`).join(", ");
92638
92641
  const extra = nonBundled.length > 6 ? ` (+${nonBundled.length - 6} more)` : "";
@@ -92730,6 +92733,11 @@ function loadJohnnessPlugins(options = {}) {
92730
92733
  logger,
92731
92734
  pluginsEnabled: normalized.enabled,
92732
92735
  allow: normalized.allow,
92736
+ impliedIds: new Set([
92737
+ ...typeof normalized.slots.memory === "string" ? [normalized.slots.memory] : [],
92738
+ ...Object.entries(normalized.entries).filter(([, entry]) => entry?.enabled === true).map(([id]) => id),
92739
+ ...Object.keys(cfg.plugins?.installs ?? {})
92740
+ ]), // JOHNNESS_PATCH_DEFAULTS_61
92733
92741
  discoverablePlugins: manifestRegistry.plugins.map((plugin) => ({
92734
92742
  id: plugin.id,
92735
92743
  source: plugin.source,
@@ -1573,6 +1573,9 @@ function normalizeGoogleModelId(id) {
1573
1573
  }
1574
1574
  createSubsystemLogger("model-selection");
1575
1575
  const ANTHROPIC_MODEL_ALIASES = {
1576
+ "opus-5": "claude-opus-5", // JOHNNESS_PATCH_DEFAULTS_61
1577
+ "sonnet-5": "claude-sonnet-5",
1578
+ "fable-5.1": "claude-fable-5-1",
1576
1579
  "opus-4.6": "claude-opus-4-6",
1577
1580
  "opus-4.5": "claude-opus-4-5",
1578
1581
  "sonnet-4.6": "claude-sonnet-4-6",
@@ -1788,9 +1791,18 @@ let defaultWarnState = { warned: false };
1788
1791
  const DEFAULT_MODEL_ALIASES = {
1789
1792
  muse: "meta/muse-spark-1.3", // JOHNNESS_PATCH_MUSE_SPARK
1790
1793
  "muse-spark": "meta/muse-spark-1.3",
1791
- opus: "anthropic/claude-opus-4-6",
1792
- sonnet: "anthropic/claude-sonnet-4-6",
1793
- gpt: "openai/gpt-5.4",
1794
+ // JOHNNESS_PATCH_DEFAULTS_61: current model aliases ship with the harness; user config
1795
+ // aliases (agents.defaults.models[*].alias) still take precedence.
1796
+ opus: "anthropic/claude-opus-5",
1797
+ sonnet: "anthropic/claude-sonnet-5",
1798
+ opus46: "anthropic/claude-opus-4-6",
1799
+ sonnet46: "anthropic/claude-sonnet-4-6",
1800
+ fable: "anthropic/claude-fable-5-1",
1801
+ astra: "openai-codex/gpt-6-astra",
1802
+ sol: "openai-codex/gpt-5.6-sol",
1803
+ luna: "openai-codex/gpt-5.6-luna",
1804
+ terra: "openai-codex/gpt-5.6-terra",
1805
+ gpt: "openai-codex/gpt-5.5",
1794
1806
  "gpt-mini": "openai/gpt-5-mini",
1795
1807
  gemini: "google/gemini-3.1-pro-preview",
1796
1808
  "gemini-flash": "google/gemini-3-flash-preview",
@@ -4407,7 +4419,9 @@ function isBundledChannelEnabledByChannelConfig(cfg, pluginId) {
4407
4419
  if (!channelId) return false;
4408
4420
  const entry = cfg.channels?.[channelId];
4409
4421
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
4410
- return entry.enabled === true;
4422
+ // JOHNNESS_PATCH_DEFAULTS_61: a configured channel block implies the bundled channel
4423
+ // plugin. Only an explicit enabled:false opts out; no plugins.allow needed.
4424
+ return entry.enabled !== false;
4411
4425
  }
4412
4426
  function resolveEffectiveEnableState(params) {
4413
4427
  const base = resolveEnableState(params.id, params.origin, params.config);
@@ -5091,6 +5105,18 @@ function safeStatMtimeMs(filePath) {
5091
5105
  return null;
5092
5106
  }
5093
5107
  }
5108
+ // JOHNNESS_PATCH_DEFAULTS_61: loose semver compare for bundled-vs-installed plugin dedupe.
5109
+ function compareJohnnessPluginVersions(a, b) {
5110
+ const parse = (value) => String(value ?? "").trim().replace(/^v/i, "").split(/[-+]/)[0].split(".").map((part) => Number.parseInt(part, 10)).map((part) => Number.isFinite(part) ? part : 0);
5111
+ const left = parse(a);
5112
+ const right = parse(b);
5113
+ const len = Math.max(left.length, right.length, 1);
5114
+ for (let i = 0; i < len; i += 1) {
5115
+ const diff = (left[i] ?? 0) - (right[i] ?? 0);
5116
+ if (diff !== 0) return diff > 0 ? 1 : -1;
5117
+ }
5118
+ return 0;
5119
+ }
5094
5120
  function normalizeManifestLabel(raw) {
5095
5121
  const trimmed = raw?.trim();
5096
5122
  return trimmed ? trimmed : void 0;
@@ -5187,6 +5213,39 @@ function loadPluginManifestRegistry(params) {
5187
5213
  }
5188
5214
  continue;
5189
5215
  }
5216
+ // JOHNNESS_PATCH_DEFAULTS_61: the same plugin id bundled with the harness and installed
5217
+ // under the state dir is the normal shape (mr-memory). The installed copy stays
5218
+ // authoritative (family 59) with no warning; when the bundled copy is newer by
5219
+ // package version, one info line suggests updating. Two non-bundled copies
5220
+ // still warn as before.
5221
+ const existingBundled = existing.candidate.origin === "bundled";
5222
+ const candidateBundled = candidate.origin === "bundled";
5223
+ if (existingBundled !== candidateBundled) {
5224
+ const existingRecord = records[existing.recordIndex];
5225
+ const candidateVersion = normalizeManifestLabel(manifest.version) ?? candidate.packageVersion;
5226
+ const bundledVersion = existingBundled ? existingRecord?.version : candidateVersion;
5227
+ const installedVersion = existingBundled ? candidateVersion : existingRecord?.version;
5228
+ if (existingBundled) {
5229
+ records[existing.recordIndex] = buildRecord({
5230
+ manifest,
5231
+ candidate,
5232
+ manifestPath: manifestRes.manifestPath,
5233
+ schemaCacheKey,
5234
+ configSchema
5235
+ });
5236
+ seenIds.set(manifest.id, {
5237
+ candidate,
5238
+ recordIndex: existing.recordIndex
5239
+ });
5240
+ }
5241
+ if (compareJohnnessPluginVersions(bundledVersion, installedVersion) > 0) diagnostics.push({
5242
+ level: "info",
5243
+ pluginId: manifest.id,
5244
+ source: candidate.source,
5245
+ message: `installed copy ${installedVersion ?? "?"} is older than the bundled ${bundledVersion ?? "?"}; run "johnness plugins update ${manifest.id}" to upgrade`
5246
+ });
5247
+ continue;
5248
+ }
5190
5249
  diagnostics.push({
5191
5250
  level: "warn",
5192
5251
  pluginId: manifest.id,
@@ -9576,6 +9635,7 @@ function validateConfigObjectWithPluginsBase(raw, opts) {
9576
9635
  workspaceDir: resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)) ?? void 0
9577
9636
  });
9578
9637
  for (const diag of registry.diagnostics) {
9638
+ if (diag.level === "info") continue; // JOHNNESS_PATCH_DEFAULTS_61
9579
9639
  let path = diag.pluginId ? `plugins.entries.${diag.pluginId}` : "plugins";
9580
9640
  if (!diag.pluginId && diag.message.includes("plugin path not found")) path = "plugins.load.paths";
9581
9641
  const message = `${diag.pluginId ? `plugin ${diag.pluginId}` : "plugin"}: ${diag.message}`;
@@ -4724,6 +4724,9 @@ function normalizeGoogleModelId(id) {
4724
4724
  }
4725
4725
  createSubsystemLogger("model-selection");
4726
4726
  const ANTHROPIC_MODEL_ALIASES = {
4727
+ "opus-5": "claude-opus-5", // JOHNNESS_PATCH_DEFAULTS_61
4728
+ "sonnet-5": "claude-sonnet-5",
4729
+ "fable-5.1": "claude-fable-5-1",
4727
4730
  "opus-4.6": "claude-opus-4-6",
4728
4731
  "opus-4.5": "claude-opus-4-5",
4729
4732
  "sonnet-4.6": "claude-sonnet-4-6",
@@ -4939,9 +4942,18 @@ let defaultWarnState = { warned: false };
4939
4942
  const DEFAULT_MODEL_ALIASES = {
4940
4943
  muse: "meta/muse-spark-1.3", // JOHNNESS_PATCH_MUSE_SPARK
4941
4944
  "muse-spark": "meta/muse-spark-1.3",
4942
- opus: "anthropic/claude-opus-4-6",
4943
- sonnet: "anthropic/claude-sonnet-4-6",
4944
- gpt: "openai/gpt-5.4",
4945
+ // JOHNNESS_PATCH_DEFAULTS_61: current model aliases ship with the harness; user config
4946
+ // aliases (agents.defaults.models[*].alias) still take precedence.
4947
+ opus: "anthropic/claude-opus-5",
4948
+ sonnet: "anthropic/claude-sonnet-5",
4949
+ opus46: "anthropic/claude-opus-4-6",
4950
+ sonnet46: "anthropic/claude-sonnet-4-6",
4951
+ fable: "anthropic/claude-fable-5-1",
4952
+ astra: "openai-codex/gpt-6-astra",
4953
+ sol: "openai-codex/gpt-5.6-sol",
4954
+ luna: "openai-codex/gpt-5.6-luna",
4955
+ terra: "openai-codex/gpt-5.6-terra",
4956
+ gpt: "openai-codex/gpt-5.5",
4945
4957
  "gpt-mini": "openai/gpt-5-mini",
4946
4958
  gemini: "google/gemini-3.1-pro-preview",
4947
4959
  "gemini-flash": "google/gemini-3-flash-preview",
@@ -7371,7 +7383,9 @@ function isBundledChannelEnabledByChannelConfig(cfg, pluginId) {
7371
7383
  if (!channelId) return false;
7372
7384
  const entry = cfg.channels?.[channelId];
7373
7385
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
7374
- return entry.enabled === true;
7386
+ // JOHNNESS_PATCH_DEFAULTS_61: a configured channel block implies the bundled channel
7387
+ // plugin. Only an explicit enabled:false opts out; no plugins.allow needed.
7388
+ return entry.enabled !== false;
7375
7389
  }
7376
7390
  function resolveEffectiveEnableState(params) {
7377
7391
  const base = resolveEnableState(params.id, params.origin, params.config);
@@ -8055,6 +8069,18 @@ function safeStatMtimeMs(filePath) {
8055
8069
  return null;
8056
8070
  }
8057
8071
  }
8072
+ // JOHNNESS_PATCH_DEFAULTS_61: loose semver compare for bundled-vs-installed plugin dedupe.
8073
+ function compareJohnnessPluginVersions(a, b) {
8074
+ const parse = (value) => String(value ?? "").trim().replace(/^v/i, "").split(/[-+]/)[0].split(".").map((part) => Number.parseInt(part, 10)).map((part) => Number.isFinite(part) ? part : 0);
8075
+ const left = parse(a);
8076
+ const right = parse(b);
8077
+ const len = Math.max(left.length, right.length, 1);
8078
+ for (let i = 0; i < len; i += 1) {
8079
+ const diff = (left[i] ?? 0) - (right[i] ?? 0);
8080
+ if (diff !== 0) return diff > 0 ? 1 : -1;
8081
+ }
8082
+ return 0;
8083
+ }
8058
8084
  function normalizeManifestLabel(raw) {
8059
8085
  const trimmed = raw?.trim();
8060
8086
  return trimmed ? trimmed : void 0;
@@ -8151,6 +8177,39 @@ function loadPluginManifestRegistry(params) {
8151
8177
  }
8152
8178
  continue;
8153
8179
  }
8180
+ // JOHNNESS_PATCH_DEFAULTS_61: the same plugin id bundled with the harness and installed
8181
+ // under the state dir is the normal shape (mr-memory). The installed copy stays
8182
+ // authoritative (family 59) with no warning; when the bundled copy is newer by
8183
+ // package version, one info line suggests updating. Two non-bundled copies
8184
+ // still warn as before.
8185
+ const existingBundled = existing.candidate.origin === "bundled";
8186
+ const candidateBundled = candidate.origin === "bundled";
8187
+ if (existingBundled !== candidateBundled) {
8188
+ const existingRecord = records[existing.recordIndex];
8189
+ const candidateVersion = normalizeManifestLabel(manifest.version) ?? candidate.packageVersion;
8190
+ const bundledVersion = existingBundled ? existingRecord?.version : candidateVersion;
8191
+ const installedVersion = existingBundled ? candidateVersion : existingRecord?.version;
8192
+ if (existingBundled) {
8193
+ records[existing.recordIndex] = buildRecord({
8194
+ manifest,
8195
+ candidate,
8196
+ manifestPath: manifestRes.manifestPath,
8197
+ schemaCacheKey,
8198
+ configSchema
8199
+ });
8200
+ seenIds.set(manifest.id, {
8201
+ candidate,
8202
+ recordIndex: existing.recordIndex
8203
+ });
8204
+ }
8205
+ if (compareJohnnessPluginVersions(bundledVersion, installedVersion) > 0) diagnostics.push({
8206
+ level: "info",
8207
+ pluginId: manifest.id,
8208
+ source: candidate.source,
8209
+ message: `installed copy ${installedVersion ?? "?"} is older than the bundled ${bundledVersion ?? "?"}; run "johnness plugins update ${manifest.id}" to upgrade`
8210
+ });
8211
+ continue;
8212
+ }
8154
8213
  diagnostics.push({
8155
8214
  level: "warn",
8156
8215
  pluginId: manifest.id,
@@ -12481,6 +12540,7 @@ function validateConfigObjectWithPluginsBase(raw, opts) {
12481
12540
  workspaceDir: resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)) ?? void 0
12482
12541
  });
12483
12542
  for (const diag of registry.diagnostics) {
12543
+ if (diag.level === "info") continue; // JOHNNESS_PATCH_DEFAULTS_61
12484
12544
  let path = diag.pluginId ? `plugins.entries.${diag.pluginId}` : "plugins";
12485
12545
  if (!diag.pluginId && diag.message.includes("plugin path not found")) path = "plugins.load.paths";
12486
12546
  const message = `${diag.pluginId ? `plugin ${diag.pluginId}` : "plugin"}: ${diag.message}`;
@@ -134,7 +134,9 @@ function isBundledChannelEnabledByChannelConfig(cfg, pluginId) {
134
134
  if (!channelId) return false;
135
135
  const entry = cfg.channels?.[channelId];
136
136
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
137
- return entry.enabled === true;
137
+ // JOHNNESS_PATCH_DEFAULTS_61: a configured channel block implies the bundled channel
138
+ // plugin. Only an explicit enabled:false opts out; no plugins.allow needed.
139
+ return entry.enabled !== false;
138
140
  }
139
141
  function resolveEffectiveEnableState(params) {
140
142
  const base = resolveEnableState(params.id, params.origin, params.config);
@@ -820,6 +822,18 @@ function safeStatMtimeMs(filePath) {
820
822
  return null;
821
823
  }
822
824
  }
825
+ // JOHNNESS_PATCH_DEFAULTS_61: loose semver compare for bundled-vs-installed plugin dedupe.
826
+ function compareJohnnessPluginVersions(a, b) {
827
+ const parse = (value) => String(value ?? "").trim().replace(/^v/i, "").split(/[-+]/)[0].split(".").map((part) => Number.parseInt(part, 10)).map((part) => Number.isFinite(part) ? part : 0);
828
+ const left = parse(a);
829
+ const right = parse(b);
830
+ const len = Math.max(left.length, right.length, 1);
831
+ for (let i = 0; i < len; i += 1) {
832
+ const diff = (left[i] ?? 0) - (right[i] ?? 0);
833
+ if (diff !== 0) return diff > 0 ? 1 : -1;
834
+ }
835
+ return 0;
836
+ }
823
837
  function normalizeManifestLabel(raw) {
824
838
  const trimmed = raw?.trim();
825
839
  return trimmed ? trimmed : void 0;
@@ -916,6 +930,39 @@ function loadPluginManifestRegistry(params) {
916
930
  }
917
931
  continue;
918
932
  }
933
+ // JOHNNESS_PATCH_DEFAULTS_61: the same plugin id bundled with the harness and installed
934
+ // under the state dir is the normal shape (mr-memory). The installed copy stays
935
+ // authoritative (family 59) with no warning; when the bundled copy is newer by
936
+ // package version, one info line suggests updating. Two non-bundled copies
937
+ // still warn as before.
938
+ const existingBundled = existing.candidate.origin === "bundled";
939
+ const candidateBundled = candidate.origin === "bundled";
940
+ if (existingBundled !== candidateBundled) {
941
+ const existingRecord = records[existing.recordIndex];
942
+ const candidateVersion = normalizeManifestLabel(manifest.version) ?? candidate.packageVersion;
943
+ const bundledVersion = existingBundled ? existingRecord?.version : candidateVersion;
944
+ const installedVersion = existingBundled ? candidateVersion : existingRecord?.version;
945
+ if (existingBundled) {
946
+ records[existing.recordIndex] = buildRecord({
947
+ manifest,
948
+ candidate,
949
+ manifestPath: manifestRes.manifestPath,
950
+ schemaCacheKey,
951
+ configSchema
952
+ });
953
+ seenIds.set(manifest.id, {
954
+ candidate,
955
+ recordIndex: existing.recordIndex
956
+ });
957
+ }
958
+ if (compareJohnnessPluginVersions(bundledVersion, installedVersion) > 0) diagnostics.push({
959
+ level: "info",
960
+ pluginId: manifest.id,
961
+ source: candidate.source,
962
+ message: `installed copy ${installedVersion ?? "?"} is older than the bundled ${bundledVersion ?? "?"}; run "johnness plugins update ${manifest.id}" to upgrade`
963
+ });
964
+ continue;
965
+ }
919
966
  diagnostics.push({
920
967
  level: "warn",
921
968
  pluginId: manifest.id,
@@ -134,7 +134,9 @@ function isBundledChannelEnabledByChannelConfig(cfg, pluginId) {
134
134
  if (!channelId) return false;
135
135
  const entry = cfg.channels?.[channelId];
136
136
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
137
- return entry.enabled === true;
137
+ // JOHNNESS_PATCH_DEFAULTS_61: a configured channel block implies the bundled channel
138
+ // plugin. Only an explicit enabled:false opts out; no plugins.allow needed.
139
+ return entry.enabled !== false;
138
140
  }
139
141
  function resolveEffectiveEnableState(params) {
140
142
  const base = resolveEnableState(params.id, params.origin, params.config);
@@ -820,6 +822,18 @@ function safeStatMtimeMs(filePath) {
820
822
  return null;
821
823
  }
822
824
  }
825
+ // JOHNNESS_PATCH_DEFAULTS_61: loose semver compare for bundled-vs-installed plugin dedupe.
826
+ function compareJohnnessPluginVersions(a, b) {
827
+ const parse = (value) => String(value ?? "").trim().replace(/^v/i, "").split(/[-+]/)[0].split(".").map((part) => Number.parseInt(part, 10)).map((part) => Number.isFinite(part) ? part : 0);
828
+ const left = parse(a);
829
+ const right = parse(b);
830
+ const len = Math.max(left.length, right.length, 1);
831
+ for (let i = 0; i < len; i += 1) {
832
+ const diff = (left[i] ?? 0) - (right[i] ?? 0);
833
+ if (diff !== 0) return diff > 0 ? 1 : -1;
834
+ }
835
+ return 0;
836
+ }
823
837
  function normalizeManifestLabel(raw) {
824
838
  const trimmed = raw?.trim();
825
839
  return trimmed ? trimmed : void 0;
@@ -916,6 +930,39 @@ function loadPluginManifestRegistry(params) {
916
930
  }
917
931
  continue;
918
932
  }
933
+ // JOHNNESS_PATCH_DEFAULTS_61: the same plugin id bundled with the harness and installed
934
+ // under the state dir is the normal shape (mr-memory). The installed copy stays
935
+ // authoritative (family 59) with no warning; when the bundled copy is newer by
936
+ // package version, one info line suggests updating. Two non-bundled copies
937
+ // still warn as before.
938
+ const existingBundled = existing.candidate.origin === "bundled";
939
+ const candidateBundled = candidate.origin === "bundled";
940
+ if (existingBundled !== candidateBundled) {
941
+ const existingRecord = records[existing.recordIndex];
942
+ const candidateVersion = normalizeManifestLabel(manifest.version) ?? candidate.packageVersion;
943
+ const bundledVersion = existingBundled ? existingRecord?.version : candidateVersion;
944
+ const installedVersion = existingBundled ? candidateVersion : existingRecord?.version;
945
+ if (existingBundled) {
946
+ records[existing.recordIndex] = buildRecord({
947
+ manifest,
948
+ candidate,
949
+ manifestPath: manifestRes.manifestPath,
950
+ schemaCacheKey,
951
+ configSchema
952
+ });
953
+ seenIds.set(manifest.id, {
954
+ candidate,
955
+ recordIndex: existing.recordIndex
956
+ });
957
+ }
958
+ if (compareJohnnessPluginVersions(bundledVersion, installedVersion) > 0) diagnostics.push({
959
+ level: "info",
960
+ pluginId: manifest.id,
961
+ source: candidate.source,
962
+ message: `installed copy ${installedVersion ?? "?"} is older than the bundled ${bundledVersion ?? "?"}; run "johnness plugins update ${manifest.id}" to upgrade`
963
+ });
964
+ continue;
965
+ }
919
966
  diagnostics.push({
920
967
  level: "warn",
921
968
  pluginId: manifest.id,
@@ -1648,9 +1648,18 @@ let defaultWarnState = { warned: false };
1648
1648
  const DEFAULT_MODEL_ALIASES = {
1649
1649
  muse: "meta/muse-spark-1.3", // JOHNNESS_PATCH_MUSE_SPARK
1650
1650
  "muse-spark": "meta/muse-spark-1.3",
1651
- opus: "anthropic/claude-opus-4-6",
1652
- sonnet: "anthropic/claude-sonnet-4-6",
1653
- gpt: "openai/gpt-5.4",
1651
+ // JOHNNESS_PATCH_DEFAULTS_61: current model aliases ship with the harness; user config
1652
+ // aliases (agents.defaults.models[*].alias) still take precedence.
1653
+ opus: "anthropic/claude-opus-5",
1654
+ sonnet: "anthropic/claude-sonnet-5",
1655
+ opus46: "anthropic/claude-opus-4-6",
1656
+ sonnet46: "anthropic/claude-sonnet-4-6",
1657
+ fable: "anthropic/claude-fable-5-1",
1658
+ astra: "openai-codex/gpt-6-astra",
1659
+ sol: "openai-codex/gpt-5.6-sol",
1660
+ luna: "openai-codex/gpt-5.6-luna",
1661
+ terra: "openai-codex/gpt-5.6-terra",
1662
+ gpt: "openai-codex/gpt-5.5",
1654
1663
  "gpt-mini": "openai/gpt-5-mini",
1655
1664
  gemini: "google/gemini-3.1-pro-preview",
1656
1665
  "gemini-flash": "google/gemini-3-flash-preview",
@@ -6885,7 +6894,9 @@ function isBundledChannelEnabledByChannelConfig(cfg, pluginId) {
6885
6894
  if (!channelId) return false;
6886
6895
  const entry = cfg.channels?.[channelId];
6887
6896
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return false;
6888
- return entry.enabled === true;
6897
+ // JOHNNESS_PATCH_DEFAULTS_61: a configured channel block implies the bundled channel
6898
+ // plugin. Only an explicit enabled:false opts out; no plugins.allow needed.
6899
+ return entry.enabled !== false;
6889
6900
  }
6890
6901
  function resolveEffectiveEnableState(params) {
6891
6902
  const base = resolveEnableState(params.id, params.origin, params.config);
@@ -7574,6 +7585,18 @@ function safeStatMtimeMs(filePath) {
7574
7585
  return null;
7575
7586
  }
7576
7587
  }
7588
+ // JOHNNESS_PATCH_DEFAULTS_61: loose semver compare for bundled-vs-installed plugin dedupe.
7589
+ function compareJohnnessPluginVersions(a, b) {
7590
+ const parse = (value) => String(value ?? "").trim().replace(/^v/i, "").split(/[-+]/)[0].split(".").map((part) => Number.parseInt(part, 10)).map((part) => Number.isFinite(part) ? part : 0);
7591
+ const left = parse(a);
7592
+ const right = parse(b);
7593
+ const len = Math.max(left.length, right.length, 1);
7594
+ for (let i = 0; i < len; i += 1) {
7595
+ const diff = (left[i] ?? 0) - (right[i] ?? 0);
7596
+ if (diff !== 0) return diff > 0 ? 1 : -1;
7597
+ }
7598
+ return 0;
7599
+ }
7577
7600
  function normalizeManifestLabel(raw) {
7578
7601
  const trimmed = raw?.trim();
7579
7602
  return trimmed ? trimmed : void 0;
@@ -7670,6 +7693,39 @@ function loadPluginManifestRegistry(params) {
7670
7693
  }
7671
7694
  continue;
7672
7695
  }
7696
+ // JOHNNESS_PATCH_DEFAULTS_61: the same plugin id bundled with the harness and installed
7697
+ // under the state dir is the normal shape (mr-memory). The installed copy stays
7698
+ // authoritative (family 59) with no warning; when the bundled copy is newer by
7699
+ // package version, one info line suggests updating. Two non-bundled copies
7700
+ // still warn as before.
7701
+ const existingBundled = existing.candidate.origin === "bundled";
7702
+ const candidateBundled = candidate.origin === "bundled";
7703
+ if (existingBundled !== candidateBundled) {
7704
+ const existingRecord = records[existing.recordIndex];
7705
+ const candidateVersion = normalizeManifestLabel(manifest.version) ?? candidate.packageVersion;
7706
+ const bundledVersion = existingBundled ? existingRecord?.version : candidateVersion;
7707
+ const installedVersion = existingBundled ? candidateVersion : existingRecord?.version;
7708
+ if (existingBundled) {
7709
+ records[existing.recordIndex] = buildRecord({
7710
+ manifest,
7711
+ candidate,
7712
+ manifestPath: manifestRes.manifestPath,
7713
+ schemaCacheKey,
7714
+ configSchema
7715
+ });
7716
+ seenIds.set(manifest.id, {
7717
+ candidate,
7718
+ recordIndex: existing.recordIndex
7719
+ });
7720
+ }
7721
+ if (compareJohnnessPluginVersions(bundledVersion, installedVersion) > 0) diagnostics.push({
7722
+ level: "info",
7723
+ pluginId: manifest.id,
7724
+ source: candidate.source,
7725
+ message: `installed copy ${installedVersion ?? "?"} is older than the bundled ${bundledVersion ?? "?"}; run "johnness plugins update ${manifest.id}" to upgrade`
7726
+ });
7727
+ continue;
7728
+ }
7673
7729
  diagnostics.push({
7674
7730
  level: "warn",
7675
7731
  pluginId: manifest.id,
@@ -12150,6 +12206,7 @@ function validateConfigObjectWithPluginsBase(raw, opts) {
12150
12206
  workspaceDir: resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)) ?? void 0
12151
12207
  });
12152
12208
  for (const diag of registry.diagnostics) {
12209
+ if (diag.level === "info") continue; // JOHNNESS_PATCH_DEFAULTS_61
12153
12210
  let path = diag.pluginId ? `plugins.entries.${diag.pluginId}` : "plugins";
12154
12211
  if (!diag.pluginId && diag.message.includes("plugin path not found")) path = "plugins.load.paths";
12155
12212
  const message = `${diag.pluginId ? `plugin ${diag.pluginId}` : "plugin"}: ${diag.message}`;
@@ -18275,6 +18332,9 @@ async function resolveImplicitBedrockProvider(params) {
18275
18332
  //#region src/agents/model-selection.ts
18276
18333
  const log = createSubsystemLogger("model-selection");
18277
18334
  const ANTHROPIC_MODEL_ALIASES = {
18335
+ "opus-5": "claude-opus-5", // JOHNNESS_PATCH_DEFAULTS_61
18336
+ "sonnet-5": "claude-sonnet-5",
18337
+ "fable-5.1": "claude-fable-5-1",
18278
18338
  "opus-4.6": "claude-opus-4-6",
18279
18339
  "opus-4.5": "claude-opus-4-5",
18280
18340
  "sonnet-4.6": "claude-sonnet-4-6",
@@ -18397,6 +18457,16 @@ function resolveModelRefFromString(params) {
18397
18457
  ref: aliasMatch.ref,
18398
18458
  alias: aliasMatch.alias
18399
18459
  };
18460
+ // JOHNNESS_PATCH_DEFAULTS_61: fall back to the shipped aliases (opus, sonnet, fable,
18461
+ // astra, sol, luna, terra, gpt) when the user config defines none.
18462
+ const builtinTarget = DEFAULT_MODEL_ALIASES[aliasKey];
18463
+ if (builtinTarget) {
18464
+ const builtinRef = parseModelRef(builtinTarget, params.defaultProvider);
18465
+ if (builtinRef) return {
18466
+ ref: builtinRef,
18467
+ alias: aliasKey
18468
+ };
18469
+ }
18400
18470
  }
18401
18471
  const parsed = parseModelRef(model, params.defaultProvider);
18402
18472
  if (!parsed) return null;