johns-harness 2026.9.11 → 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.
- package/README.md +7 -1
- package/dist/auth-profiles-5CHn7vq1.js +26 -3
- package/dist/codex-oauth-device.js +39 -9
- package/dist/codex-oauth-nudge.js +3 -2
- package/dist/codex-oauth-owner.js +1 -0
- package/dist/commands-registry-C78-tPS3.js +1 -0
- package/dist/commands-registry-D0Jkz-Sn.js +1 -0
- package/dist/commands-registry-DJWLO-6B.js +1 -0
- package/dist/commands-registry-l51VuG0m.js +1 -0
- package/dist/compact-B247y5Qt.js +10 -1
- package/dist/config-koj5M_EO.js +64 -4
- package/dist/daemon-cli.js +64 -4
- package/dist/manifest-registry-BMEqbkWA.js +48 -1
- package/dist/manifest-registry-Ba187z7Z.js +48 -1
- package/dist/model-selection-BGlGpPgM.js +74 -4
- package/dist/model-selection-BU6wl1le.js +74 -4
- package/dist/model-selection-L7RMwsG-.js +26 -3
- package/dist/models-CxHdes0w.js +1 -0
- package/dist/models-cli-DZnoM8Ln.js +1 -0
- package/dist/models-cli-U89juIRK.js +1 -0
- package/dist/pi-embedded-C6ITuRXf.js +10 -1
- package/dist/pi-embedded-DoQsYfIY.js +10 -1
- package/dist/plugin-sdk/commands-registry-B4ZP4Y1B.js +1 -0
- package/dist/plugin-sdk/commands-registry-B8Og-fWU.js +1 -0
- package/dist/plugin-sdk/commands-registry-BoAXxFpH.js +1 -0
- package/dist/plugin-sdk/commands-registry-Ca1h6XvV.js +1 -0
- package/dist/plugin-sdk/commands-registry-Do-Y2EhN.js +1 -0
- package/dist/plugin-sdk/commands-registry-DpRs-E_M.js +1 -0
- package/dist/plugin-sdk/config-4Fgm-yEH.js +74 -4
- package/dist/plugin-sdk/config-Di-lyCdh.js +74 -4
- package/dist/plugin-sdk/discord.js +64 -4
- package/dist/plugin-sdk/dispatch-BP0viZiL.js +10 -1
- package/dist/plugin-sdk/dispatch-CQsjmw7g.js +10 -1
- package/dist/plugin-sdk/dispatch-Cerq29sy.js +10 -1
- package/dist/plugin-sdk/dispatch-Cndjtt0g.js +10 -1
- package/dist/plugin-sdk/dispatch-UogiJYul.js +10 -1
- package/dist/plugin-sdk/mattermost.js +1 -0
- package/dist/plugin-sdk/model-auth-CX9cPHdC.js +74 -4
- package/dist/plugin-sdk/model-auth-Ciehz0x5.js +74 -4
- package/dist/plugin-sdk/model-auth-DVyo6JSX.js +74 -4
- package/dist/plugin-sdk/model-auth-kiHYHGrs.js +74 -4
- package/dist/plugin-sdk/model-selection-Dbj4jDYM.js +74 -4
- package/dist/plugin-sdk/reply-DbZnH8-h.js +10 -1
- package/dist/reply-C5LKjXcC.js +10 -1
- package/docs/PATCHES.md +21 -1
- package/extensions/mr-memory/johnness.plugin.json +1 -0
- package/package.json +1 -1
- package/vendor/patched-deps/@mariozechner/pi-ai/dist/models.generated.js +242 -0
- package/vendor/patched-deps/@mariozechner/pi-ai/dist/models.js +5 -0
package/README.md
CHANGED
|
@@ -45,12 +45,18 @@ The wizard sets up credentials, workspace, gateway, and channels. It asks for yo
|
|
|
45
45
|
| Connect | `johnness channels add --channel telegram --token "<bot token>"` | Connects a chat channel. Discord, Slack, WhatsApp, Signal, iMessage, Matrix, and more are supported. |
|
|
46
46
|
| Check | `johnness doctor` | Health checks and quick fixes for the gateway and channels. |
|
|
47
47
|
|
|
48
|
+
<!-- JOHNNESS_PATCH_DEVICE_LOGIN_60B -->
|
|
48
49
|
### Signing in from chat
|
|
49
50
|
Owners and allowlisted senders can send `/login` (or `/relogin`) in Telegram, Discord, or another chat channel.
|
|
50
|
-
Open the link, enter the device code
|
|
51
|
+
Open the link, sign in to ChatGPT if asked, then enter the device code on the same page and tap Approve. In Telegram, tap the code to copy it.
|
|
52
|
+
Enable "Device code authorization for Codex" once in chatgpt.com > Settings > Security; if it was disabled, send `/login` again for a fresh code.
|
|
51
53
|
For headless installs, run `johnness models auth login --device`; no browser or localhost callback needed.
|
|
52
54
|
Expired ChatGPT credentials trigger an owner notice with the `/login` recovery command.
|
|
53
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
|
+
|
|
54
60
|
### From source
|
|
55
61
|
|
|
56
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
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
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}`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
// Native OpenAI device flow, verified against Codex 0.154.0 device_code_auth.rs.
|
|
3
4
|
// OpenAI uses deviceauth + an authorization-code/PKCE exchange, NOT RFC 8628.
|
|
4
5
|
import path from 'node:path';
|
|
@@ -23,6 +24,23 @@ export function redactLoginEmail(email) {
|
|
|
23
24
|
const [local, domain] = email.split('@');
|
|
24
25
|
return `${local.slice(0, 1)}***@${domain.slice(0, 1)}***`;
|
|
25
26
|
}
|
|
27
|
+
export const DEVICE_LOGIN_SECURITY_FIX = "Go to chatgpt.com > Settings > Security, turn on 'Device code authorization for Codex'";
|
|
28
|
+
export function formatDeviceLoginInstructions(login, { email, chat = false } = {}) {
|
|
29
|
+
const account = typeof email === 'string' && email.includes('@') ? redactLoginEmail(email) : 'the same account as before';
|
|
30
|
+
const code = chat ? `\`${login.userCode}\`` : login.userCode;
|
|
31
|
+
const retry = chat ? 'send /login again' : 'run johnness models auth login --device again';
|
|
32
|
+
const minutes = Math.max(1, Math.ceil((login.expiresAt - Date.now()) / 60000));
|
|
33
|
+
return `Let's sign you back into ChatGPT.
|
|
34
|
+
1. Open ${login.verificationUri} on your phone or computer.
|
|
35
|
+
2. Sign in with your ChatGPT account (${account}) if asked.
|
|
36
|
+
3. On the same page, enter this code${chat ? ' (tap the code to copy it)' : ''}:
|
|
37
|
+
${code}
|
|
38
|
+
4. Tap Approve.
|
|
39
|
+
Code is good for ${minutes} minute${minutes === 1 ? '' : 's'}. If you see 'Device code authorization is disabled', ${DEVICE_LOGIN_SECURITY_FIX.charAt(0).toLowerCase() + DEVICE_LOGIN_SECURITY_FIX.slice(1)}, then ${retry} for a fresh code.`;
|
|
40
|
+
}
|
|
41
|
+
function hasDeviceLoginSecurityFix(error) {
|
|
42
|
+
return ['device_login_unavailable', 'device_code_authorization_disabled'].includes(error?.reason);
|
|
43
|
+
}
|
|
26
44
|
export async function startDeviceLogin({ provider = PROVIDER, fetch: fetchImpl = globalThis.fetch, now = Date.now, sleep: pause = sleep, signal } = {}) {
|
|
27
45
|
if (provider !== PROVIDER) fail('unsupported_provider');
|
|
28
46
|
async function request(url, body, form = false, remaining = 30000) {
|
|
@@ -36,7 +54,12 @@ export async function startDeviceLogin({ provider = PROVIDER, fetch: fetchImpl =
|
|
|
36
54
|
}
|
|
37
55
|
const started = now();
|
|
38
56
|
const { response, data } = await request(`${ISSUER}/api/accounts/deviceauth/usercode`, { client_id: CLIENT_ID });
|
|
39
|
-
if (!response.ok)
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
// Only classify the initial request, never reinterpret polling's bare 403/404.
|
|
59
|
+
const messages = [data?.message, data?.error_description, data?.error?.message, data?.error];
|
|
60
|
+
if (response.status === 403 && messages.some(message => typeof message === 'string' && /device code authorization is disabled|security settings do not allow device code authorization for codex/i.test(message))) fail('device_code_authorization_disabled', response.status);
|
|
61
|
+
fail(response.status === 404 ? 'device_login_unavailable' : 'request_failed', response.status);
|
|
62
|
+
}
|
|
40
63
|
const userCode = data.user_code ?? data.usercode;
|
|
41
64
|
if (typeof data.device_auth_id !== 'string' || !data.device_auth_id || typeof userCode !== 'string' || !/^[A-Za-z0-9-]{4,32}$/.test(userCode)) fail('invalid_response');
|
|
42
65
|
const expiresAt = started + TTL;
|
|
@@ -166,11 +189,16 @@ export async function getOrStartDeviceLogin(params = {}) {
|
|
|
166
189
|
}
|
|
167
190
|
export async function runDeviceLoginCli(opts, runtime, params = {}) {
|
|
168
191
|
if (opts.provider && opts.provider !== PROVIDER) fail('unsupported_provider');
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
192
|
+
try {
|
|
193
|
+
const login = await getOrStartDeviceLogin(params);
|
|
194
|
+
runtime.log(formatDeviceLoginInstructions(login, { email: selectDeviceLoginProfile(params).previous?.email }));
|
|
195
|
+
const result = await login.complete();
|
|
196
|
+
runtime.log(`Signed in as ${redactLoginEmail(result.credential.email)}`);
|
|
197
|
+
return result;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
if (hasDeviceLoginSecurityFix(error)) runtime.log(`${DEVICE_LOGIN_SECURITY_FIX}, then run johnness models auth login --device again for a fresh code.`);
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
174
202
|
}
|
|
175
203
|
export async function handleDeviceLoginCommand(params, allowTextCommands, { routeReply, callGateway, log = console.info, ...options } = {}) {
|
|
176
204
|
if (!allowTextCommands || !/^\/(login|relogin)(?:\s|$)/i.test(params.command.commandBodyNormalized)) return null;
|
|
@@ -185,7 +213,7 @@ export async function handleDeviceLoginCommand(params, allowTextCommands, { rout
|
|
|
185
213
|
if (!login.notifiedRoutes.has(routeKey)) {
|
|
186
214
|
login.notifiedRoutes.add(routeKey);
|
|
187
215
|
// Never keep the command lane occupied for the 15-minute authorization window.
|
|
188
|
-
void login.complete().then(() => 'Signed in. I\'m back.', error => error.reason === 'expired' ?
|
|
216
|
+
void login.complete().then(() => 'Signed in. I\'m back.', error => error.reason === 'expired' ? "That code expired (they last 15 minutes). Send /login and I'll give you a fresh one." : error.reason === 'denied' ? 'That sign-in was declined. Send /login to try again.' : 'Login failed. Send /login to try again.').then(async text => {
|
|
189
217
|
const result = ["webchat", "internal"].includes(route.channel) && callGateway
|
|
190
218
|
? await callGateway({ method: "chat.inject", params: { sessionKey: route.sessionKey, message: text } })
|
|
191
219
|
: await routeReply({ ...route, payload: { text } });
|
|
@@ -194,6 +222,8 @@ export async function handleDeviceLoginCommand(params, allowTextCommands, { rout
|
|
|
194
222
|
}).catch(() => log('[codex-device-login] completion delivery failed; send /login again.'));
|
|
195
223
|
}
|
|
196
224
|
log('[codex-device-login] /login recognized; code issued (code and identity redacted)');
|
|
197
|
-
return reply(
|
|
198
|
-
} catch
|
|
225
|
+
return reply(formatDeviceLoginInstructions(login, { email: selectDeviceLoginProfile({ ...options, agentDir: params.agentDir }).previous?.email, chat: true }));
|
|
226
|
+
} catch (error) {
|
|
227
|
+
return reply(hasDeviceLoginSecurityFix(error) ? `${DEVICE_LOGIN_SECURITY_FIX}, then send /login again for a fresh code.` : 'Could not start ChatGPT login. Send /login to try again.');
|
|
228
|
+
}
|
|
199
229
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import fs from 'node:fs';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import { transactAuthStore, sameCredential } from './auth-store-transactions.js';
|
|
5
|
-
export const LOGIN_NUDGE_TEXT =
|
|
6
|
+
export const LOGIN_NUDGE_TEXT = "My ChatGPT login expired. Send /login and I'll walk you through signing back in (takes about a minute).";
|
|
6
7
|
const DEAD = new Set(['refresh_token_reused', 'invalid_grant', 'refresh_token_expired', 'refresh_token_invalidated', 'expired_no_refresh']);
|
|
7
8
|
export function resolveLoginOwnerRoute(cfg = {}) {
|
|
8
9
|
const owners = cfg.commands?.ownerAllowFrom ?? [];
|
|
@@ -48,7 +49,7 @@ export async function notifyDeadCodexChain(params = {}) {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
const route = resolveLoginOwnerRoute(cfg);
|
|
51
|
-
if (!route) { log(
|
|
52
|
+
if (!route) { log(`[codex-device-login] ${LOGIN_NUDGE_TEXT} (No owner route resolved.)`); return true; }
|
|
52
53
|
if (params.send) await params.send({ ...route, text: LOGIN_NUDGE_TEXT, cfg });
|
|
53
54
|
else {
|
|
54
55
|
const { deliverOutboundPayloads } = await import('./deliver-runtime-JZdz0coW.js');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { l as escapeRegExp } from "./utils-DC4zYvW0.js";
|
|
3
4
|
import { i as listThinkingLevels } from "./thinking-BYwvlJ3S.js";
|
|
4
5
|
import { Gi as DEFAULT_PROVIDER, Wi as DEFAULT_MODEL, h as resolveConfiguredModelRef } from "./model-selection-L7RMwsG-.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { D as isPlainObject, u as escapeRegExp } from "./logger-Bj0Xl6pn.js";
|
|
3
4
|
import { Fr as DEFAULT_MODEL, Ir as DEFAULT_PROVIDER, l as resolveConfiguredModelRef, nn as getActivePluginRegistry } from "./model-selection-BGlGpPgM.js";
|
|
4
5
|
import { f as listChannelDocks, r as listThinkingLevels } from "./thinking-CAzdgmNV.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { D as isPlainObject, u as escapeRegExp } from "./logger-BW8uLq6f.js";
|
|
3
4
|
import { Mr as DEFAULT_PROVIDER, jr as DEFAULT_MODEL, tn as getActivePluginRegistry, u as resolveConfiguredModelRef } from "./model-selection-BU6wl1le.js";
|
|
4
5
|
import { f as listChannelDocks, r as listThinkingLevels } from "./thinking-B5B36ffe.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { Bi as DEFAULT_PROVIDER, Or as resolveConfiguredModelRef, zi as DEFAULT_MODEL } from "./auth-profiles-5CHn7vq1.js";
|
|
3
4
|
import { c as escapeRegExp } from "./utils-C5WN6czr.js";
|
|
4
5
|
import { u as getActivePluginRegistry } from "./registry-DoLLbW4m.js";
|
package/dist/compact-B247y5Qt.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { handleDeviceLoginCommand } from "./codex-oauth-device.js";
|
|
3
4
|
import { E as normalizeLogLevel, a as logVerbose, c as shouldLogVerbose, k as resolvePreferredJohnnessTmpDir, m as getChildLogger, p as theme, t as danger, u as warn } from "./globals-Bv4ZcVWM.js";
|
|
4
5
|
import { g as resolveStateDir, r as STATE_DIR, u as resolveGatewayPort, y as resolveRequiredHomeDir } from "./paths-BfR2LXbA.js";
|
|
@@ -92631,7 +92632,10 @@ function isTrackedByProvenance(params) {
|
|
|
92631
92632
|
function warnWhenAllowlistIsOpen(params) {
|
|
92632
92633
|
if (!params.pluginsEnabled) return;
|
|
92633
92634
|
if (params.allow.length > 0) return;
|
|
92634
|
-
|
|
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));
|
|
92635
92639
|
if (nonBundled.length === 0) return;
|
|
92636
92640
|
const preview = nonBundled.slice(0, 6).map((entry) => `${entry.id} (${entry.source})`).join(", ");
|
|
92637
92641
|
const extra = nonBundled.length > 6 ? ` (+${nonBundled.length - 6} more)` : "";
|
|
@@ -92729,6 +92733,11 @@ function loadJohnnessPlugins(options = {}) {
|
|
|
92729
92733
|
logger,
|
|
92730
92734
|
pluginsEnabled: normalized.enabled,
|
|
92731
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
|
|
92732
92741
|
discoverablePlugins: manifestRegistry.plugins.map((plugin) => ({
|
|
92733
92742
|
id: plugin.id,
|
|
92734
92743
|
source: plugin.source,
|
package/dist/config-koj5M_EO.js
CHANGED
|
@@ -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
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
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
|
-
|
|
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}`;
|
package/dist/daemon-cli.js
CHANGED
|
@@ -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
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|