johns-harness 2026.9.11 → 2026.9.12
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 +3 -1
- 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 +1 -0
- 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 +1 -0
- package/dist/pi-embedded-DoQsYfIY.js +1 -0
- 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/dispatch-BP0viZiL.js +1 -0
- package/dist/plugin-sdk/dispatch-CQsjmw7g.js +1 -0
- package/dist/plugin-sdk/dispatch-Cerq29sy.js +1 -0
- package/dist/plugin-sdk/dispatch-Cndjtt0g.js +1 -0
- package/dist/plugin-sdk/dispatch-UogiJYul.js +1 -0
- package/dist/plugin-sdk/mattermost.js +1 -0
- package/dist/plugin-sdk/reply-DbZnH8-h.js +1 -0
- package/dist/reply-C5LKjXcC.js +1 -0
- package/docs/PATCHES.md +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,9 +45,11 @@ 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
|
|
|
@@ -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";
|
package/dist/models-CxHdes0w.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { runDeviceLoginCli } from "./codex-oauth-device.js";
|
|
3
4
|
import { t as __exportAll } from "./rolldown-runtime-DUslC3ob.js";
|
|
4
5
|
import { d as colorize, f as isRich$1, p as theme } from "./globals-Bv4ZcVWM.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { runDeviceLoginCli } from "./codex-oauth-device.js";
|
|
3
4
|
import { t as CONFIG_PATH } from "./paths-BJV7vkaX.js";
|
|
4
5
|
import { d as colorize, f as isRich$1, p as theme } from "./globals-BM8hKFm0.js";
|
|
@@ -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
|
// JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
|
|
4
5
|
import { _ as normalizeStringEntries, a as resolveAgentDir, b as resolveAgentModelPrimaryValue, c as resolveAgentWorkspaceDir, d as resolveRunModelFallbacksOverride, f as resolveSessionAgentId, g as normalizeHyphenSlug, h as normalizeAtHashSlug, i as resolveAgentConfig, l as resolveDefaultAgentId, n as hasConfiguredModelFallbacks, p as resolveSessionAgentIds, r as listAgentIds, s as resolveAgentSkillsFilter, t as runTasksWithConcurrency, u as resolveEffectiveModelFallbacks, v as normalizeStringEntriesLower, x as toAgentModelListLike, y as resolveAgentModelFallbackValues } from "./run-with-concurrency-Cuc1THN9.js";
|
|
@@ -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
|
// JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
|
|
4
5
|
import { $ as isValidAgentId, C as filterBootstrapFilesForSession, D as runCommandWithTimeout, G as normalizeStringEntries, J as DEFAULT_MAIN_KEY, K as normalizeStringEntriesLower, M as openBoundaryFileSync, O as runExec, Q as classifySessionKeyShape, S as ensureAgentWorkspace, T as resolveJohnnessPackageRoot, U as normalizeAtHashSlug, V as normalizeWindowsPathForComparison, W as normalizeHyphenSlug, X as buildAgentPeerSessionKey, Y as buildAgentMainSessionKey, _t as resolveAgentModelFallbackValues, a as resolveAgentDir, at as scopedHeartbeatWakeOptions, c as resolveAgentWorkspaceDir, ct as normalizeOptionalAccountId, d as resolveRunModelFallbacksOverride, dt as getSubagentDepth, et as normalizeAgentId, f as resolveSessionAgentId, ft as isAcpSessionKey, gt as resolveThreadParentSessionKey, h as DEFAULT_AGENT_WORKSPACE_DIR, ht as parseAgentSessionKey, i as resolveAgentConfig, it as sanitizeAgentId, j as openBoundaryFile, k as spawnWithFallback, l as resolveDefaultAgentId, lt as isBlockedObjectKey, mt as isSubagentSessionKey, n as hasConfiguredModelFallbacks, nt as resolveAgentIdFromSessionKey, ot as DEFAULT_ACCOUNT_ID, p as resolveSessionAgentIds, pt as isCronSessionKey, q as DEFAULT_AGENT_ID, r as listAgentIds, rt as resolveThreadSessionKeys, s as resolveAgentSkillsFilter, st as normalizeAccountId$2, t as runTasksWithConcurrency, tt as normalizeMainKey, u as resolveEffectiveModelFallbacks, ut as deriveSessionChatType, v as DEFAULT_IDENTITY_FILENAME, vt as resolveAgentModelPrimaryValue, w as loadWorkspaceBootstrapFiles, yt as toAgentModelListLike } from "./run-with-concurrency-BXSUl5Nj.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { It as getActivePluginRegistry, Nr as DEFAULT_MODEL, Pr as DEFAULT_PROVIDER, or as resolveConfiguredModelRef } from "./model-auth-Ciehz0x5.js";
|
|
3
4
|
import { D as isPlainObject, u as escapeRegExp } from "./logger-Cxu-Klb_.js";
|
|
4
5
|
import { f as listChannelDocks, r as listThinkingLevels } from "./thinking-WQ4Zq8Nl.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-3VRkTvTU.js";
|
|
3
4
|
import { f as listChannelDocks, r as listThinkingLevels } from "./thinking-B-rIrY_n.js";
|
|
4
5
|
import { Dn as resolveConfiguredModelRef, Xn as DEFAULT_PROVIDER, Yn as DEFAULT_MODEL, mr as getActivePluginRegistry } from "./model-auth-CX9cPHdC.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { Ir as DEFAULT_MODEL, Lr as DEFAULT_PROVIDER, Rt as getActivePluginRegistry, cr as resolveConfiguredModelRef } from "./model-auth-DVyo6JSX.js";
|
|
3
4
|
import { D as isPlainObject, u as escapeRegExp } from "./logger-By5InJr-.js";
|
|
4
5
|
import { f as listChannelDocks, r as listThinkingLevels } from "./thinking-WXqkGljb.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { C as isPlainObject, o as escapeRegExp } from "./utils-B0IyLNx9.js";
|
|
3
4
|
import { r as normalizeChannelId } from "./plugins-BQilE2mk.js";
|
|
4
5
|
import { Ar as DEFAULT_MODEL, Mt as getActivePluginRegistry, jr as DEFAULT_PROVIDER, nr as resolveConfiguredModelRef } from "./model-auth-kiHYHGrs.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { Dt as getActivePluginRegistry, Rn as resolveConfiguredModelRef, ii as DEFAULT_PROVIDER, ri as DEFAULT_MODEL } from "./config-4Fgm-yEH.js";
|
|
3
4
|
import { F as isPlainObject, v as escapeRegExp } from "./logger-U3s76KST.js";
|
|
4
5
|
import { f as listChannelDocks, r as listThinkingLevels } from "./thinking-pTdxk2dr.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { Kt as resolveConfiguredModelRef, Xn as DEFAULT_MODEL, Zn as DEFAULT_PROVIDER, yr as getActivePluginRegistry } from "./config-Di-lyCdh.js";
|
|
3
4
|
import { D as isPlainObject, u as escapeRegExp } from "./logger-Blr-bUxJ.js";
|
|
4
5
|
import { r as normalizeChannelId } from "./plugins-Bv1h7dAV.js";
|
|
@@ -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
|
// JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
|
|
4
5
|
import { $ as buildAgentPeerSessionKey, C as filterBootstrapFilesForSession, D as runCommandWithTimeout, G as normalizeStringEntries, J as resolveAgentModelPrimaryValue, K as normalizeStringEntriesLower, M as openBoundaryFileSync, O as runExec, Q as buildAgentMainSessionKey, S as ensureAgentWorkspace, T as resolveJohnnessPackageRoot, U as normalizeAtHashSlug, V as normalizeWindowsPathForComparison, W as normalizeHyphenSlug, X as DEFAULT_AGENT_ID, Y as toAgentModelListLike, Z as DEFAULT_MAIN_KEY, _t as isSubagentSessionKey, a as resolveAgentDir, at as resolveAgentIdFromSessionKey, c as resolveAgentWorkspaceDir, ct as scopedHeartbeatWakeOptions, d as resolveRunModelFallbacksOverride, dt as normalizeOptionalAccountId, f as resolveSessionAgentId, ft as isBlockedObjectKey, gt as isCronSessionKey, h as DEFAULT_AGENT_WORKSPACE_DIR, ht as isAcpSessionKey, i as resolveAgentConfig, it as normalizeMainKey, j as openBoundaryFile, k as spawnWithFallback, l as resolveDefaultAgentId, lt as DEFAULT_ACCOUNT_ID, mt as getSubagentDepth, n as hasConfiguredModelFallbacks, nt as isValidAgentId, ot as resolveThreadSessionKeys, p as resolveSessionAgentIds, pt as deriveSessionChatType, q as resolveAgentModelFallbackValues, r as listAgentIds, rt as normalizeAgentId, s as resolveAgentSkillsFilter, st as sanitizeAgentId, t as runTasksWithConcurrency, tt as classifySessionKeyShape, u as resolveEffectiveModelFallbacks, ut as normalizeAccountId$2, v as DEFAULT_IDENTITY_FILENAME, vt as parseAgentSessionKey, w as loadWorkspaceBootstrapFiles, yt as resolveThreadParentSessionKey } from "./run-with-concurrency-XmKq-xNS.js";
|
|
@@ -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
|
// JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
|
|
4
5
|
import { A as mediaKindFromMime, C as imageMimeFromFormat, E as kindFromMime, O as MAX_IMAGE_BYTES, T as isGifMedia, a as isMarkdownCapableMessageChannel, b as detectMime, c as resolveGatewayMessageChannel, d as GATEWAY_CLIENT_MODES, f as GATEWAY_CLIENT_NAMES, g as getImageMetadata, i as isInternalMessageChannel, l as resolveMessageChannel, n as isDeliverableMessageChannel, o as listDeliverableMessageChannels, r as isGatewayMessageChannel, s as normalizeMessageChannel, t as INTERNAL_MESSAGE_CHANNEL, u as GATEWAY_CLIENT_IDS, w as isAudioFileName, x as extensionForMime, y as resizeToJpeg } from "./message-channel-DfmYEnql.js";
|
|
@@ -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
|
// JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
|
|
4
5
|
import { $ as buildAgentPeerSessionKey, C as filterBootstrapFilesForSession, D as runCommandWithTimeout, G as normalizeStringEntries, J as resolveAgentModelPrimaryValue, K as normalizeStringEntriesLower, M as openBoundaryFileSync, O as runExec, Q as buildAgentMainSessionKey, S as ensureAgentWorkspace, T as resolveJohnnessPackageRoot, U as normalizeAtHashSlug, V as normalizeWindowsPathForComparison, W as normalizeHyphenSlug, X as DEFAULT_AGENT_ID, Y as toAgentModelListLike, Z as DEFAULT_MAIN_KEY, _t as isSubagentSessionKey, a as resolveAgentDir, at as resolveAgentIdFromSessionKey, c as resolveAgentWorkspaceDir, ct as scopedHeartbeatWakeOptions, d as resolveRunModelFallbacksOverride, dt as normalizeOptionalAccountId, f as resolveSessionAgentId, ft as isBlockedObjectKey, gt as isCronSessionKey, h as DEFAULT_AGENT_WORKSPACE_DIR, ht as isAcpSessionKey, i as resolveAgentConfig, it as normalizeMainKey, j as openBoundaryFile, k as spawnWithFallback, l as resolveDefaultAgentId, lt as DEFAULT_ACCOUNT_ID, mt as getSubagentDepth, n as hasConfiguredModelFallbacks, nt as isValidAgentId, ot as resolveThreadSessionKeys, p as resolveSessionAgentIds, pt as deriveSessionChatType, q as resolveAgentModelFallbackValues, r as listAgentIds, rt as normalizeAgentId, s as resolveAgentSkillsFilter, st as sanitizeAgentId, t as runTasksWithConcurrency, tt as classifySessionKeyShape, u as resolveEffectiveModelFallbacks, ut as normalizeAccountId$2, v as DEFAULT_IDENTITY_FILENAME, vt as parseAgentSessionKey, w as loadWorkspaceBootstrapFiles, yt as resolveThreadParentSessionKey } from "./run-with-concurrency-BMh-rgTO.js";
|
|
@@ -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
|
// JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
|
|
4
5
|
import { $ as isValidAgentId, C as filterBootstrapFilesForSession, D as runCommandWithTimeout, G as normalizeStringEntries, J as DEFAULT_MAIN_KEY, K as normalizeStringEntriesLower, M as openBoundaryFileSync, O as runExec, Q as classifySessionKeyShape, S as ensureAgentWorkspace, T as resolveJohnnessPackageRoot, U as normalizeAtHashSlug, V as normalizeWindowsPathForComparison, W as normalizeHyphenSlug, X as buildAgentPeerSessionKey, Y as buildAgentMainSessionKey, _t as resolveAgentModelFallbackValues, a as resolveAgentDir, at as scopedHeartbeatWakeOptions, c as resolveAgentWorkspaceDir, ct as normalizeOptionalAccountId, d as resolveRunModelFallbacksOverride, dt as getSubagentDepth, et as normalizeAgentId, f as resolveSessionAgentId, ft as isAcpSessionKey, gt as resolveThreadParentSessionKey, h as DEFAULT_AGENT_WORKSPACE_DIR, ht as parseAgentSessionKey, i as resolveAgentConfig, it as sanitizeAgentId, j as openBoundaryFile, k as spawnWithFallback, l as resolveDefaultAgentId, lt as isBlockedObjectKey, mt as isSubagentSessionKey, n as hasConfiguredModelFallbacks, nt as resolveAgentIdFromSessionKey, ot as DEFAULT_ACCOUNT_ID, p as resolveSessionAgentIds, pt as isCronSessionKey, q as DEFAULT_AGENT_ID, r as listAgentIds, rt as resolveThreadSessionKeys, s as resolveAgentSkillsFilter, st as normalizeAccountId$2, t as runTasksWithConcurrency, tt as normalizeMainKey, u as resolveEffectiveModelFallbacks, ut as deriveSessionChatType, v as DEFAULT_IDENTITY_FILENAME, vt as resolveAgentModelPrimaryValue, w as loadWorkspaceBootstrapFiles, yt as toAgentModelListLike } from "./run-with-concurrency-DCb27DCP.js";
|
|
@@ -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
|
// JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
|
|
4
5
|
import { $ as stripUndefinedFields, A as unpinMessageDiscord, At as resolveAllowlistProviderRuntimeGroupPolicy, B as listScheduledEventsDiscord, C as editMessageDiscord, Ct as hasAnyGuildPermissionDiscord, D as pinMessageDiscord, Dt as evaluateGroupRouteAccessForPolicy, E as listThreadsDiscord, Et as chunkDiscordTextWithMode, F as fetchMemberInfoDiscord, Ft as buildChannelKeyCandidates, G as uploadStickerDiscord, H as timeoutMemberDiscord, I as fetchRoleInfoDiscord, It as normalizeChannelSlug, J as editChannelDiscord, K as createChannelDiscord, L as fetchVoiceStatusDiscord, Lt as resolveChannelEntryMatchWithFallback, M as banMemberDiscord, Mt as resolveOpenProviderRuntimeGroupPolicy, N as createScheduledEventDiscord, Nt as warnMissingProviderGroupPolicyFallbackOnce, O as readMessagesDiscord, Ot as evaluateMatchedGroupAccessForPolicy, P as fetchChannelInfoDiscord, Pt as applyChannelMatchMeta, Q as sendDiscordText, R as kickMemberDiscord, S as deleteMessageDiscord, St as fetchChannelPermissionsDiscord, T as listPinsDiscord, Tt as createDiscordRestClient, U as listGuildEmojisDiscord, V as removeRoleDiscord, W as uploadEmojiDiscord, X as removeChannelPermissionDiscord, Y as moveChannelDiscord, Z as setChannelPermissionDiscord, _ as sendStickerDiscord, _t as formatDiscordUserTag, a as sendDiscordComponentMessage, at as normalizeDiscordAllowList, b as formatMention, bt as DiscordApiError, c as parseDiscordComponentCustomId, ct as resolveDiscordChannelConfigWithFallback, d as parseDiscordModalCustomIdForCarbon, dt as resolveDiscordOwnerAccess, et as parseDiscordTarget, f as readDiscordComponentSpec, ft as resolveDiscordOwnerAllowFrom, g as sendPollDiscord, gt as formatDiscordReactionEmoji, h as sendMessageDiscord, ht as shouldEmitDiscordReactionNotification, i as removeReactionDiscord, it as isDiscordGroupAllowedByPolicy, j as addRoleDiscord, jt as resolveDefaultGroupPolicy, k as searchMessagesDiscord, kt as GROUP_POLICY_BLOCKED_LABEL, l as parseDiscordComponentCustomIdForCarbon, lt as resolveDiscordGuildEntry, m as resolveDiscordModalEntry, mt as resolveGroupDmAllow, n as reactMessageDiscord, nt as listDiscordDirectoryGroupsLive, o as createDiscordFormModal, ot as normalizeDiscordSlug, p as resolveDiscordComponentEntry, pt as resolveDiscordShouldRequireMention, q as deleteChannelDiscord, r as removeOwnReactionsDiscord, rt as listDiscordDirectoryPeersLive, s as formatDiscordComponentEventText, st as resolveDiscordAllowListMatch, t as fetchReactionsDiscord, tt as resolveDiscordChannelId, u as parseDiscordModalCustomId, ut as resolveDiscordMemberAccessState, v as sendVoiceMessageDiscord, vt as resolveDiscordSystemLocation, w as fetchMessageDiscord, wt as createDiscordClient, x as createThreadDiscord, xt as fetchDiscord, y as sendWebhookMessageDiscord, yt as resolveTimestampMs, z as listGuildChannelsDiscord } from "./send-Dy8sRjb5.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// JOHNNESS_PATCH_DEVICE_LOGIN_60
|
|
2
|
+
// JOHNNESS_PATCH_DEVICE_LOGIN_60B
|
|
2
3
|
import { $ as findOverlappingPluginHttpRoute, A as parseCanonicalIpAddress, B as resolveMemorySlotDecision, Bt as resolvePreferredJohnnessTmpDir, C as isBlockedSpecialUseIpv6Address, Ct as normalizeStringEntries, D as isLegacyIpv4Literal, Dt as normalizeE164, E as isIpv4Address, Et as isRecord, F as resolveProcessScopedMap, Ft as normalizeOptionalAccountId, G as normalizeChatChannelId, Gt as resolveRequiredHomeDir, H as MANIFEST_KEY, Ht as resolveOAuthDir, I as isPathInsideWithRealpath, It as resolveThreadParentSessionKey, J as isValidFileSecretRefId, K as isTruthyEnvValue, L as loadPluginManifestRegistry, Lt as createSubsystemLogger, M as applyConfigEnvVars, Mt as resolveThreadSessionKeys, Nt as DEFAULT_ACCOUNT_ID, O as isLoopbackIpAddress, Ot as resolveUserPath, P as resolveJohnnessAgentDir, Pt as normalizeAccountId, Q as requireActivePluginRegistry, R as normalizePluginsConfig, Rt as logVerbose, S as isBlockedSpecialUseIpv4Address, St as normalizeHyphenSlug, T as isIpInCidr, Tt as escapeRegExp, U as CHAT_CHANNEL_ORDER, Ut as resolveStateDir, V as LEGACY_MANIFEST_KEYS, Vt as consumeRootOptionToken, W as getChatChannelMeta, Wt as expandHomePrefix, X as getActivePluginRegistry, Y as resolveDefaultSecretProviderAlias, Z as getActivePluginRegistryVersion, _ as DmPolicySchema, _t as isNotFoundPathError, a as resolveModelRefFromString, at as normalizeResolvedSecretInputString, b as requireOpenAllowFrom, bt as normalizeSkillFilter, c as resolveImplicitCopilotProvider, ct as resolveAgentConfig, d as resolveSecretRefString, dt as resolveDefaultAgentId, et as normalizePluginHttpPath, f as encodeJsonPointerToken, ft as resolveJohnnessPackageRootSync, g as BlockStreamingCoalesceSchema, gt as hasNodeErrorCode, h as loadConfig, ht as sameFileIdentity, i as resolveDefaultModelForAgent, it as isValidEnvSecretRefId, j as parseLooseIpAddress, jt as normalizeAgentId, k as normalizeIpAddress, kt as safeParseJson, l as resolveImplicitProviders, lt as resolveAgentSkillsFilter, m as getRuntimeConfigSourceSnapshot, mt as logWarn, n as buildModelAliasIndex, nt as coerceSecretRef, o as normalizeProviders, ot as normalizeSecretInputString, p as getRuntimeConfigSnapshot, pt as runExec, q as parseBooleanValue, r as normalizeProviderId, rt as hasConfiguredSecretInput, s as resolveImplicitBedrockProvider, st as listAgentIds, t as buildAllowedModelSet, tt as formatCliCommand, u as isNonSecretApiKeyMarker, ut as resolveAgentWorkspaceDir, v as GroupPolicySchema, vt as isPathInside, w as isCanonicalDottedDecimalIPv4, wt as CONFIG_DIR, x as extractEmbeddedIpv4FromIpv6, xt as normalizeAtHashSlug, y as MarkdownConfigSchema, yt as isSymlinkOpenError, z as resolveEffectiveEnableState, zt as shouldLogVerbose } from "./model-selection-Dbj4jDYM.js";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import fs, { constants } from "node:fs";
|
|
@@ -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
|
// JOHNNESS_PATCH_NATIVE_STATE_MIGRATION_59
|
|
4
5
|
import { $ as buildAgentPeerSessionKey, C as filterBootstrapFilesForSession, D as runCommandWithTimeout, G as toAgentModelListLike, J as normalizeStringEntries, K as normalizeAtHashSlug, M as openBoundaryFileSync, O as runExec, Q as buildAgentMainSessionKey, S as ensureAgentWorkspace, T as resolveJohnnessPackageRoot, U as resolveAgentModelFallbackValues, V as normalizeWindowsPathForComparison, W as resolveAgentModelPrimaryValue, X as DEFAULT_AGENT_ID, Y as normalizeStringEntriesLower, Z as DEFAULT_MAIN_KEY, _t as isSubagentSessionKey, a as resolveAgentDir, at as resolveAgentIdFromSessionKey, c as resolveAgentWorkspaceDir, ct as scopedHeartbeatWakeOptions, d as resolveRunModelFallbacksOverride, dt as normalizeOptionalAccountId, f as resolveSessionAgentId, ft as isBlockedObjectKey, gt as isCronSessionKey, h as DEFAULT_AGENT_WORKSPACE_DIR, ht as isAcpSessionKey, i as resolveAgentConfig, it as normalizeMainKey, j as openBoundaryFile, k as spawnWithFallback, l as resolveDefaultAgentId, lt as DEFAULT_ACCOUNT_ID, mt as getSubagentDepth, n as hasConfiguredModelFallbacks, nt as isValidAgentId, ot as resolveThreadSessionKeys, p as resolveSessionAgentIds, pt as deriveSessionChatType, q as normalizeHyphenSlug, r as listAgentIds, rt as normalizeAgentId, s as resolveAgentSkillsFilter, st as sanitizeAgentId, t as runTasksWithConcurrency, tt as classifySessionKeyShape, u as resolveEffectiveModelFallbacks, ut as normalizeAccountId$2, v as DEFAULT_IDENTITY_FILENAME, vt as parseAgentSessionKey, w as loadWorkspaceBootstrapFiles, yt as resolveThreadParentSessionKey } from "./run-with-concurrency-8rEOAFIb.js";
|
package/dist/reply-C5LKjXcC.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 { g as resolveStateDir, r as STATE_DIR, u as resolveGatewayPort, y as resolveRequiredHomeDir } from "./paths-BJV7vkaX.js";
|
|
4
5
|
import { E as normalizeLogLevel, R as consumeRootOptionToken, a as logVerbose, c as shouldLogVerbose, k as resolvePreferredJohnnessTmpDir, m as getChildLogger, p as theme, t as danger, u as warn } from "./globals-BM8hKFm0.js";
|
package/docs/PATCHES.md
CHANGED
|
@@ -2348,7 +2348,7 @@ Confirm its in-flight request has finished before handoff, archive its plist/scr
|
|
|
2348
2348
|
**Patch:** `patches/60-codex-oauth-device.patch`; `scripts/patch-codex-oauth-device.py` validates all anchors before writing and supports an alternate package root.
|
|
2349
2349
|
**Runtime:** `dist/codex-oauth-device.js`, `dist/codex-oauth-nudge.js`, the shared Family 58 owner, ten command dispatch bundles, eleven command registries, two CLI action copies and two CLI registrations (three distinct CLI files). Total: 27 runtime files; one `JOHNNESS_PATCH_DEVICE_LOGIN_60` marker per file.
|
|
2350
2350
|
|
|
2351
|
-
**What it does:** `/login` and `/relogin` run before model-backed work, use the existing config-changing-command sender authorization, return a device URL/code in the originating channel, and poll without holding its command lane. Duplicate requests share the public prompt and one poller across bundle copies, inherited main-agent profiles, and CLI/gateway processes. A separate ownership-checked device lock spans the human authorization window. Public prompt/status metadata is kept in the canonical auth store; the device-auth id and PKCE verifier are memory-only. Success says "Signed in. I'm back."; expiry says "That code expired. Send /login
|
|
2351
|
+
**What it does:** `/login` and `/relogin` run before model-backed work, use the existing config-changing-command sender authorization, return a device URL/code in the originating channel, and poll without holding its command lane. Duplicate requests share the public prompt and one poller across bundle copies, inherited main-agent profiles, and CLI/gateway processes. A separate ownership-checked device lock spans the human authorization window. Public prompt/status metadata is kept in the canonical auth store; the device-auth id and PKCE verifier are memory-only. Success says "Signed in. I'm back."; expiry says "That code expired (they last 15 minutes). Send /login and I'll give you a fresh one." Native slash registries advertise `/login`; `/relogin` is a text alias. Natural-language phrases are not added to the slash matcher.
|
|
2352
2352
|
|
|
2353
2353
|
`johnness models auth login --device` defaults to `openai-codex`, needs no TTY, and prints the prompt followed by a redacted identity. `--provider openai-codex --device` is equivalent. Without `--device`, the browser/callback flow is unchanged.
|
|
2354
2354
|
|
|
@@ -2359,3 +2359,6 @@ Confirm its in-flight request has finished before handoff, archive its plist/scr
|
|
|
2359
2359
|
**Recovery notice:** The shared owner (already reached by all ten refresh adapters) recognizes refresh-token reuse, invalid grant/expired refresh chains, and expired credentials with no refresh token. A fresh-store transaction reserves one notice per profile per six hours in `codexLoginNudges` before sending to a concrete configured owner on an enabled channel. Wildcard/group targets are not used. Unresolved owners or delivery failures get a token-free log notice instead; the reservation prevents storms across process restarts. Existing auth failures nudge when next inspected by the owner, not via an extra periodic job.
|
|
2360
2360
|
|
|
2361
2361
|
**Tests:** `tests/codex-oauth-device.test.mjs` covers exact fake endpoints, pending/success, expiry/denial, rate limits, sanitized failures, canonical handoff, explicit account changes, inherited ownership, authorization, duplicate prompts, background routing, CLI identity redaction, nudge debounce, all ten real dispatcher adapters, and exact/idempotent/atomic patch replay. Historical Family 51/54 replay tests now replay Family 60 before exact byte comparison; the Family 59 header fixture excludes only the independent Family 60 import/comment. Verifier checks every runtime copy plus exact read-only replay. Live end-to-end account authorization still requires the human to complete OpenAI's device page.
|
|
2362
|
+
|
|
2363
|
+
<!-- JOHNNESS_PATCH_DEVICE_LOGIN_60B -->
|
|
2364
|
+
**Amendment 60B (2026.9.12): first-try instructions.** Additive patch: `patches/60b-device-login-instructions.patch`. Chat and CLI now give four numbered steps: open the device page, sign in first if asked, enter the code on that same page, then tap Approve. Telegram's code is on its own line in inline-code formatting, with a tap-to-copy instruction. A redacted known account (or "the same account as before") helps choose the right sign-in. The prompt explains the one-time chatgpt.com > Settings > Security > "Device code authorization for Codex" setting and asks for a fresh code after enabling it. CLI startup unavailability or an explicit disabled-setting HTTP 403 prints that same fix without echoing the response body. Bare polling 403/404 semantics are unchanged. Expiry, declined-sign-in and dead-chain notices now explain the next action. All 27 runtime surfaces carry the 60B sub-marker and are checked by exact replay; tests cover walkthrough content, copyable Telegram code, sanitized startup errors, and unchanged pending behavior.
|