@mnemom/mnemom 0.17.18 → 0.17.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent-doctor.js +6 -10
- package/dist/commands/agent.d.ts +0 -3
- package/dist/commands/agent.js +4 -28
- package/dist/index.js +1 -1
- package/dist/lib/launcher-config.d.ts +2 -2
- package/dist/lib/launcher-config.js +3 -3
- package/dist/lib/login-detect.d.ts +7 -10
- package/dist/lib/login-detect.js +13 -28
- package/dist/lib/subscription-login.d.ts +22 -3
- package/dist/lib/subscription-login.js +30 -2
- package/package.json +1 -1
- package/dist/lib/console-key.d.ts +0 -40
- package/dist/lib/console-key.js +0 -77
|
@@ -14,9 +14,8 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { spawnSync } from "node:child_process";
|
|
16
16
|
import { existsSync } from "node:fs";
|
|
17
|
-
import { anthropicKeySource, checkRcCapability,
|
|
18
|
-
import {
|
|
19
|
-
import { resolveAgentAuth } from "../lib/subscription-login.js";
|
|
17
|
+
import { anthropicKeySource, checkRcCapability, resolveCliBin } from "./agent.js";
|
|
18
|
+
import { resolveAgentAuth, savedAuthIsRetiredConsole, } from "../lib/subscription-login.js";
|
|
20
19
|
import { isProdGateway, resolveAnthropicDoor, resolveGatewayHost, singleCellError, } from "../lib/agent.js";
|
|
21
20
|
import { getApiUrl, getGatewayUrl } from "../lib/config.js";
|
|
22
21
|
import { LAUNCHER_CONFIG_PATH } from "../lib/launcher-config.js";
|
|
@@ -55,17 +54,14 @@ export async function agentDoctorCommand(options = {}) {
|
|
|
55
54
|
auth = resolveAgentAuth(undefined, env);
|
|
56
55
|
}
|
|
57
56
|
catch (err) {
|
|
58
|
-
add("miss", `auth: ${err instanceof Error ? err.message : String(err)}`, "`mnemom agent config set auth api-key` (or subscription
|
|
57
|
+
add("miss", `auth: ${err instanceof Error ? err.message : String(err)}`, "`mnemom agent config set auth api-key` (or subscription)");
|
|
58
|
+
}
|
|
59
|
+
if (savedAuthIsRetiredConsole(env)) {
|
|
60
|
+
add("info", "auth: console is no longer supported — launches use an Anthropic API key", "`mnemom agent config set auth api-key` (create a key at console.anthropic.com)");
|
|
59
61
|
}
|
|
60
62
|
if (auth === "subscription") {
|
|
61
63
|
add("ok", "auth: subscription — Claude Code uses your claude.ai login (Team/Enterprise plans only); no Anthropic key needed");
|
|
62
64
|
}
|
|
63
|
-
else if (auth === "console") {
|
|
64
|
-
if (readConsoleKey(defaultConsoleKeyDeps(env)))
|
|
65
|
-
add("ok", "auth: console — using the API key your Claude Code Anthropic Console login created");
|
|
66
|
-
else
|
|
67
|
-
add("miss", "auth: console — Claude Code has no Anthropic Console login on this machine", 'run `claude`, then /login → "Anthropic Console account" — or `mnemom agent config set auth api-key`');
|
|
68
|
-
}
|
|
69
65
|
else {
|
|
70
66
|
const keySrc = anthropicKeySource(env);
|
|
71
67
|
if (keySrc === "env")
|
package/dist/commands/agent.d.ts
CHANGED
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
import { type MnemomKeyDeps } from "../lib/subscription-login.js";
|
|
29
29
|
import { type SessionRecord } from "../lib/agent-ledger.js";
|
|
30
30
|
import { type ExperimentalId } from "../lib/experimental.js";
|
|
31
|
-
import { type ConsoleKeyDeps } from "../lib/console-key.js";
|
|
32
31
|
import { type GovernanceOptIn } from "./agent-setup.js";
|
|
33
32
|
import { type ContextProfile, type LaunchShape, type SealedContractEnvelope } from "../lib/agent.js";
|
|
34
33
|
export interface AgentOptions {
|
|
@@ -228,8 +227,6 @@ export declare function recordSessionLaunch(ctx: {
|
|
|
228
227
|
}): void;
|
|
229
228
|
/** The real I/O behind a subscription launch's Mnemom key (lib/subscription-login.ts). */
|
|
230
229
|
export declare function defaultMnemomKeyDeps(storePath?: string): MnemomKeyDeps;
|
|
231
|
-
/** The real machine behind lib/console-key.ts: the macOS keychain via `security`, no shell. */
|
|
232
|
-
export declare function defaultConsoleKeyDeps(env: NodeJS.ProcessEnv): ConsoleKeyDeps;
|
|
233
230
|
/**
|
|
234
231
|
* Resolve the Anthropic key with NO 1Password dependency (built for external
|
|
235
232
|
* customer adoption), in order:
|
package/dist/commands/agent.js
CHANGED
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
import { spawn, spawnSync } from "node:child_process";
|
|
29
29
|
import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, renameSync, } from "node:fs";
|
|
30
30
|
import { randomUUID } from "node:crypto";
|
|
31
|
-
import { tmpdir, homedir, hostname
|
|
31
|
+
import { tmpdir, homedir, hostname } from "node:os";
|
|
32
32
|
import { basename, join, dirname } from "node:path";
|
|
33
33
|
import { fileURLToPath } from "node:url";
|
|
34
34
|
import { MEASURED_ENV, statuslineLaunch } from "../lib/statusline.js";
|
|
35
35
|
import { getApiUrl, getGatewayUrl, MNEMOM_DIR } from "../lib/config.js";
|
|
36
36
|
import { createApiKey } from "../lib/api.js";
|
|
37
|
-
import { MNEMOM_KEY_STORE_FIELD, resolveAgentAuth, resolveSubscriptionMnemomKey, subscriptionChildEnv, subscriptionShape, } from "../lib/subscription-login.js";
|
|
37
|
+
import { MNEMOM_KEY_STORE_FIELD, resolveAgentAuth, sayRetiredConsoleNotice, resolveSubscriptionMnemomKey, subscriptionChildEnv, subscriptionShape, } from "../lib/subscription-login.js";
|
|
38
38
|
import { LEDGER_FILE, appendSessionRecord, findResumeCandidate, readSessionRecords, resolveRetentionDays, resumedContextProfile, toLedgerContract, } from "../lib/agent-ledger.js";
|
|
39
39
|
import { isLoggedIn } from "../lib/auth.js";
|
|
40
40
|
import { loadCliConfig } from "../lib/cli-config.js";
|
|
@@ -43,7 +43,6 @@ import { experimentalNotice } from "../lib/experimental.js";
|
|
|
43
43
|
import { fmt } from "../lib/format.js";
|
|
44
44
|
import { askInput, askSelect, askYesNo, isInteractive } from "../lib/prompt.js";
|
|
45
45
|
import { authConfigured, chooseAuth, detectClaudeLogin, readClaudeLoginState, } from "../lib/login-detect.js";
|
|
46
|
-
import { requireConsoleKey, readConsoleKey } from "../lib/console-key.js";
|
|
47
46
|
import { goalAlignmentLine, resolveSessionSetup } from "./agent-session.js";
|
|
48
47
|
import { defaultAgentSlug, ensureClaimedServedAgent, ensureSessionAndBalance, isQuietPreambleExit, resolveDefaultSlug, resolvePreflightedAccount, } from "./agent-setup.js";
|
|
49
48
|
import { assembleContract, buildGoalModeHeader, buildCustomHeaders, buildHandoffMcpConfigJson, buildSessionConfig, buildSessionConfigB64, assertCompactAtCompatible, assertOffProfileCompatible, compactAtWindowWarning, describeCompactAt, launchWindow, resolveCompactAt, applyGatewayHintHeaders, resolveCompactionIntercept, resolveContextHandoff, resolveContextProfile, resolveHandoffGatewayHost, resolveUsageSavings, HANDOFF_RC_KEY_ENV_NAME, isProdGateway, launchPreferenceExplicit, launchPreflighted, remoteControlAllowed, applyToolSearchDefault, DISABLE_1M_ENV, readCcSettings, resolveWindowModel, resolveAnthropicDoor, resolveLaunchModel, resolveConversationId, resolveGatewayHost, singleCellError, resolveLaunchShape, resolveRemoteControlShape, passthroughName, sanitizeAgentName, resumeCommand, sessionDisplayName, SESSION_NAME_ENV, SESSION_CONFIG_HEADER, } from "../lib/agent.js";
|
|
@@ -141,13 +140,13 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
141
140
|
// How Claude Code authenticates: an Anthropic key (default) or the user's claude.ai
|
|
142
141
|
// subscription login (Team/Enterprise; lib/subscription-login.ts).
|
|
143
142
|
let auth = resolveAgentAuth(options.auth, env);
|
|
143
|
+
sayRetiredConsoleNotice(options.auth, env, say);
|
|
144
144
|
// Nothing configured it yet: detect Claude Code's own login and, when there is a real
|
|
145
145
|
// choice, ask once and save the answer (lib/login-detect.ts). Never on --dry-run.
|
|
146
146
|
if (!options.dryRun && !authConfigured(options.auth, env)) {
|
|
147
147
|
const loginState = readClaudeLoginState(env, homedir(), (path) => readFileSync(path, "utf8"));
|
|
148
148
|
auth = await chooseAuth({
|
|
149
149
|
login: detectClaudeLogin(loginState),
|
|
150
|
-
consoleKeyAvailable: () => readConsoleKey(defaultConsoleKeyDeps(env)) !== undefined,
|
|
151
150
|
interactive: isInteractive(),
|
|
152
151
|
select: askSelect,
|
|
153
152
|
persist: (choice) => {
|
|
@@ -309,9 +308,6 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
309
308
|
say("mnemom agent: auth = subscription — Claude Code would use your claude.ai login (Team/Enterprise plans only) with a Mnemom API key; no Anthropic key.");
|
|
310
309
|
}
|
|
311
310
|
say(`mnemom agent: the real launch first confirms the agent the gateway serves for '${agent}' is claimed — claiming it into the org the launch bills if it is not — and never runs on an unclaimed agent.`);
|
|
312
|
-
if (auth === "console") {
|
|
313
|
-
say("mnemom agent: auth = console — the launch would use the API key your Claude Code Anthropic Console login created.");
|
|
314
|
-
}
|
|
315
311
|
if (expNotice)
|
|
316
312
|
say(expNotice);
|
|
317
313
|
if (shape !== "terminal") {
|
|
@@ -354,12 +350,9 @@ export async function agentCommand(scenarioArg, options = {}) {
|
|
|
354
350
|
// AFTER the account gate above: an account Mnemom Agent is not enabled for learns that
|
|
355
351
|
// (and how to get access) before it is asked for, or refused for want of, a key.
|
|
356
352
|
// Not on a subscription launch: Claude Code then sends its own claude.ai login instead.
|
|
357
|
-
// A Console launch uses the key Claude Code's Console login created, then runs as api-key.
|
|
358
353
|
const anthropicKey = auth === "subscription"
|
|
359
354
|
? undefined
|
|
360
|
-
:
|
|
361
|
-
? requireConsoleKey(defaultConsoleKeyDeps(env))
|
|
362
|
-
: await resolveAnthropicKey(env, { allowPrompt: true, keySource: options.keySource });
|
|
355
|
+
: await resolveAnthropicKey(env, { allowPrompt: true, keySource: options.keySource });
|
|
363
356
|
// ── Remote-Control entitlement gate ─────────────────────────────────────────
|
|
364
357
|
// Remote Control (a session steerable from claude.ai / the Claude app) is
|
|
365
358
|
// internal-only. Now that we know the org's entitlement, resolve the final
|
|
@@ -837,23 +830,6 @@ export function defaultMnemomKeyDeps(storePath = CODE_STORE) {
|
|
|
837
830
|
say,
|
|
838
831
|
};
|
|
839
832
|
}
|
|
840
|
-
/** The real machine behind lib/console-key.ts: the macOS keychain via `security`, no shell. */
|
|
841
|
-
export function defaultConsoleKeyDeps(env) {
|
|
842
|
-
return {
|
|
843
|
-
platform: process.platform,
|
|
844
|
-
env,
|
|
845
|
-
username: () => userInfo().username,
|
|
846
|
-
readKeychain: (service, account) => {
|
|
847
|
-
const r = spawnSync("security", ["find-generic-password", "-a", account, "-w", "-s", service], {
|
|
848
|
-
encoding: "utf8",
|
|
849
|
-
timeout: 5_000,
|
|
850
|
-
});
|
|
851
|
-
return r.status === 0 ? r.stdout : undefined;
|
|
852
|
-
},
|
|
853
|
-
claudeJson: readClaudeLoginState(env, homedir(), (path) => readFileSync(path, "utf8"))
|
|
854
|
-
.claudeJson,
|
|
855
|
-
};
|
|
856
|
-
}
|
|
857
833
|
/**
|
|
858
834
|
* Resolve the Anthropic key with NO 1Password dependency (built for external
|
|
859
835
|
* customer adoption), in order:
|
package/dist/index.js
CHANGED
|
@@ -165,7 +165,7 @@ const agentCmd = program
|
|
|
165
165
|
// built at load, before any sign-in, so it cannot ask the entitlement; the flags still parse.
|
|
166
166
|
.addOption(new Option("--remote-control", "Interactive Remote Control session in THIS terminal (behind a local proxy)").hideHelp())
|
|
167
167
|
.addOption(new Option("--server", "Headless `claude remote-control` dispatcher (behind a local proxy)").hideHelp())
|
|
168
|
-
.option("--auth <mode>", "How Claude Code authenticates: api-key (default) | subscription (your Claude Team/Enterprise login)
|
|
168
|
+
.option("--auth <mode>", "How Claude Code authenticates: api-key (default) | subscription (your Claude Team/Enterprise login)")
|
|
169
169
|
.option("--model <alias|id>", "Model to launch (CLI alias or concrete id)")
|
|
170
170
|
.addOption(new Option("--effort <level>", "Reasoning effort").choices([
|
|
171
171
|
"low",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* resolvers in lib/code.ts keep the built-in default as the final fallback);
|
|
16
16
|
* the caller folds the plain-value settings under the CLI flags.
|
|
17
17
|
*/
|
|
18
|
-
import { type
|
|
18
|
+
import { type SavedAgentAuth } from "./subscription-login.js";
|
|
19
19
|
import { type ExperimentalId } from "./experimental.js";
|
|
20
20
|
import { type ContextProfile, type GoalModeDefault, type LaunchShape } from "./agent.js";
|
|
21
21
|
/** The human-editable settings file. Secret key lives elsewhere (launcher.json). */
|
|
@@ -31,7 +31,7 @@ export interface LauncherConfig {
|
|
|
31
31
|
cli?: string;
|
|
32
32
|
launch?: LaunchShape;
|
|
33
33
|
/** How Claude Code authenticates (lib/subscription-login.ts); api-key when unset. */
|
|
34
|
-
auth?:
|
|
34
|
+
auth?: SavedAgentAuth;
|
|
35
35
|
keySource?: KeySource;
|
|
36
36
|
/** Standing goal-alignment default when neither --goal nor --implicit is given. */
|
|
37
37
|
goalMode?: GoalModeDefault;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* resolvers in lib/code.ts keep the built-in default as the final fallback);
|
|
16
16
|
* the caller folds the plain-value settings under the CLI flags.
|
|
17
17
|
*/
|
|
18
|
-
import { AGENT_AUTH_ENV, AGENT_AUTHS, coerceAgentAuth, } from "./subscription-login.js";
|
|
18
|
+
import { AGENT_AUTH_ENV, AGENT_AUTHS, coerceAgentAuth, parseSavedAgentAuth, } from "./subscription-login.js";
|
|
19
19
|
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
20
20
|
import { dirname, join } from "node:path";
|
|
21
21
|
import { parse as parseToml, stringify as stringifyToml, TomlError } from "smol-toml";
|
|
@@ -143,7 +143,7 @@ export const CONFIG_KEYS = [
|
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
key: "auth",
|
|
146
|
-
describe: `How Claude Code authenticates (${AGENT_AUTHS.join("|")}); subscription = your Claude Team/Enterprise login
|
|
146
|
+
describe: `How Claude Code authenticates (${AGENT_AUTHS.join("|")}); subscription = your Claude Team/Enterprise login`,
|
|
147
147
|
get: (c) => c.auth,
|
|
148
148
|
set: (c, v) => {
|
|
149
149
|
c.auth = coerceAgentAuth(v);
|
|
@@ -292,7 +292,7 @@ export function parseLauncherConfig(text) {
|
|
|
292
292
|
if (raw.launch !== undefined)
|
|
293
293
|
cfg.launch = coerceLaunch(str(raw.launch) ?? "");
|
|
294
294
|
if (raw.auth !== undefined)
|
|
295
|
-
cfg.auth =
|
|
295
|
+
cfg.auth = parseSavedAgentAuth(str(raw.auth) ?? "");
|
|
296
296
|
if (raw.key_source !== undefined)
|
|
297
297
|
cfg.keySource = coerceKeySource(str(raw.key_source) ?? "");
|
|
298
298
|
if (raw.goal_mode !== undefined)
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
* Four ways Claude Code can be signed in, and what the gateway does with each today:
|
|
7
7
|
* - Claude subscription, Team or Enterprise → `auth = subscription` (supported).
|
|
8
8
|
* - Claude subscription, Pro / Max (individual) → not supported (Team/Enterprise only).
|
|
9
|
-
* - Anthropic Console login (`/login` → Console account) →
|
|
10
|
-
*
|
|
11
|
-
* `claude auth login --console` profile creates no key → not supported.
|
|
9
|
+
* - Anthropic Console login (`/login` → Console account) → not used directly: Console
|
|
10
|
+
* customers use an Anthropic API key (created in the Console).
|
|
12
11
|
* - Third-party provider (Bedrock / Vertex / Foundry) → not supported (no gateway door).
|
|
13
12
|
* An Anthropic API key always works (`auth = api-key`, the default).
|
|
14
13
|
*
|
|
@@ -48,13 +47,10 @@ export type UnsupportedLogin = Extract<ClaudeLogin, {
|
|
|
48
47
|
/** Why a detected login can't be used through the gateway. */
|
|
49
48
|
export declare function unsupportedReason(login: UnsupportedLogin): string;
|
|
50
49
|
export declare const MENU_SUBSCRIPTION = "Claude subscription \u2014 Team or Enterprise (your claude.ai login)";
|
|
51
|
-
export declare const MENU_CONSOLE = "Anthropic Console \u2014 the API key your Claude Code /login created (API billing)";
|
|
52
50
|
export declare const MENU_API_KEY = "Anthropic API key";
|
|
53
51
|
export interface ChooseAuthDeps {
|
|
54
52
|
login: ClaudeLogin;
|
|
55
53
|
interactive: boolean;
|
|
56
|
-
/** Whether Claude Code's Console-login key is readable (lib/console-key.ts); asked only for a Console login. */
|
|
57
|
-
consoleKeyAvailable(): boolean;
|
|
58
54
|
select(question: string, options: string[]): Promise<string | null>;
|
|
59
55
|
persist(auth: AgentAuth): void;
|
|
60
56
|
say(line: string): void;
|
|
@@ -62,10 +58,11 @@ export interface ChooseAuthDeps {
|
|
|
62
58
|
/**
|
|
63
59
|
* Pick `auth` when nothing configured it (no --auth, MNEMOM_AGENT_AUTH or launcher.toml).
|
|
64
60
|
* - No Claude login detected → api-key, silently, nothing saved (today's behaviour).
|
|
65
|
-
* - A login we can't use → api-key, say why once,
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* two-option menu (
|
|
61
|
+
* - A login we can't use (personal plan, Console, third-party) → api-key, say why once,
|
|
62
|
+
* save it so the note isn't repeated.
|
|
63
|
+
* - Team/Enterprise and non-interactive → api-key, nothing saved (never switch a script's
|
|
64
|
+
* auth without asking); interactive → a two-option menu (subscription or an API key),
|
|
65
|
+
* answer saved.
|
|
69
66
|
*/
|
|
70
67
|
export declare function chooseAuth(deps: ChooseAuthDeps): Promise<AgentAuth>;
|
|
71
68
|
/** True when `auth` is already decided: `--auth`, or MNEMOM_AGENT_AUTH (launcher.toml folds in). */
|
package/dist/lib/login-detect.js
CHANGED
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
* Four ways Claude Code can be signed in, and what the gateway does with each today:
|
|
7
7
|
* - Claude subscription, Team or Enterprise → `auth = subscription` (supported).
|
|
8
8
|
* - Claude subscription, Pro / Max (individual) → not supported (Team/Enterprise only).
|
|
9
|
-
* - Anthropic Console login (`/login` → Console account) →
|
|
10
|
-
*
|
|
11
|
-
* `claude auth login --console` profile creates no key → not supported.
|
|
9
|
+
* - Anthropic Console login (`/login` → Console account) → not used directly: Console
|
|
10
|
+
* customers use an Anthropic API key (created in the Console).
|
|
12
11
|
* - Third-party provider (Bedrock / Vertex / Foundry) → not supported (no gateway door).
|
|
13
12
|
* An Anthropic API key always works (`auth = api-key`, the default).
|
|
14
13
|
*
|
|
@@ -63,13 +62,12 @@ export function unsupportedReason(login) {
|
|
|
63
62
|
case "individual":
|
|
64
63
|
return `your Claude ${login.plan} plan is a personal plan — Mnemom supports subscription login on Team and Enterprise plans only`;
|
|
65
64
|
case "console":
|
|
66
|
-
return "
|
|
65
|
+
return "Claude Code is signed in with an Anthropic Console account, and Mnemom uses an Anthropic API key for Console billing (create one at console.anthropic.com)";
|
|
67
66
|
case "third-party":
|
|
68
|
-
return `Claude Code is set to use ${PROVIDER_NAMES[login.provider]}, and Mnemom supports
|
|
67
|
+
return `Claude Code is set to use ${PROVIDER_NAMES[login.provider]}, and Mnemom supports an Anthropic API key or a Claude Team or Enterprise plan`;
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
70
|
export const MENU_SUBSCRIPTION = "Claude subscription — Team or Enterprise (your claude.ai login)";
|
|
72
|
-
export const MENU_CONSOLE = "Anthropic Console — the API key your Claude Code /login created (API billing)";
|
|
73
71
|
export const MENU_API_KEY = "Anthropic API key";
|
|
74
72
|
const SAVED_HINT = `change it any time with \`mnemom agent config set auth ${AGENT_AUTHS.join("|")}\``;
|
|
75
73
|
function save(deps, auth, line) {
|
|
@@ -85,38 +83,25 @@ function save(deps, auth, line) {
|
|
|
85
83
|
/**
|
|
86
84
|
* Pick `auth` when nothing configured it (no --auth, MNEMOM_AGENT_AUTH or launcher.toml).
|
|
87
85
|
* - No Claude login detected → api-key, silently, nothing saved (today's behaviour).
|
|
88
|
-
* - A login we can't use → api-key, say why once,
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* two-option menu (
|
|
86
|
+
* - A login we can't use (personal plan, Console, third-party) → api-key, say why once,
|
|
87
|
+
* save it so the note isn't repeated.
|
|
88
|
+
* - Team/Enterprise and non-interactive → api-key, nothing saved (never switch a script's
|
|
89
|
+
* auth without asking); interactive → a two-option menu (subscription or an API key),
|
|
90
|
+
* answer saved.
|
|
92
91
|
*/
|
|
93
92
|
export async function chooseAuth(deps) {
|
|
94
93
|
const { login } = deps;
|
|
95
94
|
if (login.kind === "none")
|
|
96
95
|
return "api-key";
|
|
97
|
-
if (login.kind === "console" && deps.consoleKeyAvailable()) {
|
|
98
|
-
if (!deps.interactive)
|
|
99
|
-
return "api-key";
|
|
100
|
-
const picked = await deps.select("mnemom agent: Claude Code is signed in with an Anthropic Console account. How should it sign in through Mnemom?", [MENU_CONSOLE, MENU_API_KEY]);
|
|
101
|
-
if (picked === MENU_CONSOLE) {
|
|
102
|
-
return save(deps, "console", "mnemom agent: using your Anthropic Console login's API key.");
|
|
103
|
-
}
|
|
104
|
-
if (picked === MENU_API_KEY) {
|
|
105
|
-
return save(deps, "api-key", "mnemom agent: using an Anthropic API key.");
|
|
106
|
-
}
|
|
107
|
-
deps.say("mnemom agent: no choice made — using an Anthropic API key for this launch.");
|
|
108
|
-
return "api-key";
|
|
109
|
-
}
|
|
110
96
|
if (login.kind !== "subscription") {
|
|
111
97
|
return save(deps, "api-key", `mnemom agent: ${unsupportedReason(login)}, so this launch uses an Anthropic API key.`);
|
|
112
98
|
}
|
|
113
99
|
if (!deps.interactive)
|
|
114
100
|
return "api-key";
|
|
115
|
-
// Only options that work. The
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
// already skip this menu above with a one-line reason.
|
|
101
|
+
// Only options that work. The menu never offers a choice it can't fulfil (operator ruling
|
|
102
|
+
// 2026-10-01). Console and Bedrock/Vertex/Foundry logins skip it above with a one-line
|
|
103
|
+
// reason; the public CLI supports an Anthropic API key and a Team/Enterprise subscription
|
|
104
|
+
// only (operator ruling 2026-10-07 retired the Console-login key path).
|
|
120
105
|
const options = [MENU_SUBSCRIPTION, MENU_API_KEY];
|
|
121
106
|
const question = `mnemom agent: Claude Code is signed in with your Claude ${login.plan} plan. How should it sign in through Mnemom?`;
|
|
122
107
|
const picked = await deps.select(question, options);
|
|
@@ -17,9 +17,23 @@
|
|
|
17
17
|
* Pure apart from the injected deps, so every arm is unit-tested.
|
|
18
18
|
*/
|
|
19
19
|
import type { LaunchShape } from "./agent.js";
|
|
20
|
-
|
|
21
|
-
export type AgentAuth = "api-key" | "subscription" | "console";
|
|
20
|
+
export type AgentAuth = "api-key" | "subscription";
|
|
22
21
|
export declare const AGENT_AUTHS: readonly AgentAuth[];
|
|
22
|
+
/**
|
|
23
|
+
* The retired `console` value (it read the key Claude Code's Anthropic Console /login
|
|
24
|
+
* created). A saved `auth = console` (launcher.toml / MNEMOM_AGENT_AUTH) now runs as
|
|
25
|
+
* api-key with a one-line notice instead of failing the launch; Console customers use an
|
|
26
|
+
* Anthropic API key. An explicit `--auth console` or `config set auth console` is refused.
|
|
27
|
+
*/
|
|
28
|
+
export declare const RETIRED_CONSOLE_AUTH = "console";
|
|
29
|
+
/** What launcher.toml `auth` may hold: a live mode, or the retired `console` (kept so it folds
|
|
30
|
+
* into MNEMOM_AGENT_AUTH like any saved value — the notice and the doctor row then see it). */
|
|
31
|
+
export type SavedAgentAuth = AgentAuth | typeof RETIRED_CONSOLE_AUTH;
|
|
32
|
+
export declare const RETIRED_CONSOLE_NOTICE = "mnemom agent: auth = console is no longer supported \u2014 this launch uses an Anthropic API key (create one at console.anthropic.com). Run `mnemom agent config set auth api-key` to stop this notice.";
|
|
33
|
+
/** True when the saved setting (MNEMOM_AGENT_AUTH; launcher.toml folds in) is the retired `console`. */
|
|
34
|
+
export declare function savedAuthIsRetiredConsole(env: Record<string, string | undefined>): boolean;
|
|
35
|
+
/** Print the retired-console notice when the saved setting is `console`; a launch never fails on it. */
|
|
36
|
+
export declare function sayRetiredConsoleNotice(flag: string | undefined, env: Record<string, string | undefined>, say: (line: string) => void): void;
|
|
23
37
|
/** Env override for the setting (the launcher.toml `auth` key folds into it). */
|
|
24
38
|
export declare const AGENT_AUTH_ENV = "MNEMOM_AGENT_AUTH";
|
|
25
39
|
/** Env override for the Mnemom key a subscription launch sends. */
|
|
@@ -27,7 +41,12 @@ export declare const MNEMOM_KEY_ENV = "MNEMOM_AGENT_MNEMOM_KEY";
|
|
|
27
41
|
/** Field in ~/.mnemom/launcher.json (0600) holding the minted key. */
|
|
28
42
|
export declare const MNEMOM_KEY_STORE_FIELD = "mnemom_api_key";
|
|
29
43
|
export declare function coerceAgentAuth(raw: string): AgentAuth;
|
|
30
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* launcher.toml `auth`: the retired `console` is kept as-is (never a load error); it folds into
|
|
46
|
+
* MNEMOM_AGENT_AUTH, where resolveAgentAuth runs it as api-key and the launch says so once.
|
|
47
|
+
*/
|
|
48
|
+
export declare function parseSavedAgentAuth(raw: string): SavedAgentAuth;
|
|
49
|
+
/** `--auth` flag > MNEMOM_AGENT_AUTH (launcher.toml folds in here; a saved retired `console` → api-key) > api-key. */
|
|
31
50
|
export declare function resolveAgentAuth(flag: string | undefined, env: Record<string, string | undefined>): AgentAuth;
|
|
32
51
|
export interface MnemomKeyDeps {
|
|
33
52
|
env: Record<string, string | undefined>;
|
|
@@ -16,7 +16,24 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Pure apart from the injected deps, so every arm is unit-tested.
|
|
18
18
|
*/
|
|
19
|
-
export const AGENT_AUTHS = ["api-key", "subscription"
|
|
19
|
+
export const AGENT_AUTHS = ["api-key", "subscription"];
|
|
20
|
+
/**
|
|
21
|
+
* The retired `console` value (it read the key Claude Code's Anthropic Console /login
|
|
22
|
+
* created). A saved `auth = console` (launcher.toml / MNEMOM_AGENT_AUTH) now runs as
|
|
23
|
+
* api-key with a one-line notice instead of failing the launch; Console customers use an
|
|
24
|
+
* Anthropic API key. An explicit `--auth console` or `config set auth console` is refused.
|
|
25
|
+
*/
|
|
26
|
+
export const RETIRED_CONSOLE_AUTH = "console";
|
|
27
|
+
export const RETIRED_CONSOLE_NOTICE = "mnemom agent: auth = console is no longer supported — this launch uses an Anthropic API key (create one at console.anthropic.com). Run `mnemom agent config set auth api-key` to stop this notice.";
|
|
28
|
+
/** True when the saved setting (MNEMOM_AGENT_AUTH; launcher.toml folds in) is the retired `console`. */
|
|
29
|
+
export function savedAuthIsRetiredConsole(env) {
|
|
30
|
+
return (env[AGENT_AUTH_ENV] ?? "").trim().toLowerCase() === RETIRED_CONSOLE_AUTH;
|
|
31
|
+
}
|
|
32
|
+
/** Print the retired-console notice when the saved setting is `console`; a launch never fails on it. */
|
|
33
|
+
export function sayRetiredConsoleNotice(flag, env, say) {
|
|
34
|
+
if (!flag?.trim() && savedAuthIsRetiredConsole(env))
|
|
35
|
+
say(RETIRED_CONSOLE_NOTICE);
|
|
36
|
+
}
|
|
20
37
|
/** Env override for the setting (the launcher.toml `auth` key folds into it). */
|
|
21
38
|
export const AGENT_AUTH_ENV = "MNEMOM_AGENT_AUTH";
|
|
22
39
|
/** Env override for the Mnemom key a subscription launch sends. */
|
|
@@ -36,10 +53,21 @@ export function coerceAgentAuth(raw) {
|
|
|
36
53
|
return v;
|
|
37
54
|
throw new Error(`auth must be one of ${AGENT_AUTHS.join(", ")} (got '${raw}').`);
|
|
38
55
|
}
|
|
39
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* launcher.toml `auth`: the retired `console` is kept as-is (never a load error); it folds into
|
|
58
|
+
* MNEMOM_AGENT_AUTH, where resolveAgentAuth runs it as api-key and the launch says so once.
|
|
59
|
+
*/
|
|
60
|
+
export function parseSavedAgentAuth(raw) {
|
|
61
|
+
return raw.trim().toLowerCase() === RETIRED_CONSOLE_AUTH
|
|
62
|
+
? RETIRED_CONSOLE_AUTH
|
|
63
|
+
: coerceAgentAuth(raw);
|
|
64
|
+
}
|
|
65
|
+
/** `--auth` flag > MNEMOM_AGENT_AUTH (launcher.toml folds in here; a saved retired `console` → api-key) > api-key. */
|
|
40
66
|
export function resolveAgentAuth(flag, env) {
|
|
41
67
|
if (flag !== undefined && flag.trim())
|
|
42
68
|
return coerceAgentAuth(flag);
|
|
69
|
+
if (savedAuthIsRetiredConsole(env))
|
|
70
|
+
return "api-key";
|
|
43
71
|
const fromEnv = (env[AGENT_AUTH_ENV] ?? "").trim();
|
|
44
72
|
return fromEnv ? coerceAgentAuth(fromEnv) : "api-key";
|
|
45
73
|
}
|
package/package.json
CHANGED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `mnemom agent` with an Anthropic Console login (`auth = console`).
|
|
3
|
-
*
|
|
4
|
-
* Claude Code's `/login` → "Anthropic Console account" uses OAuth only to create a real
|
|
5
|
-
* Anthropic API key, which Claude Code stores and then sends as `x-api-key` ("/login
|
|
6
|
-
* managed key"). This module reads that key from where Claude Code keeps it, so the launch
|
|
7
|
-
* runs exactly like `auth = api-key` — same headers, same birth and claim, same identity —
|
|
8
|
-
* with no key for the user to copy. The key is read per launch and never stored by us.
|
|
9
|
-
*
|
|
10
|
-
* Where Claude Code keeps it (Claude Code 2.1.285, confirmed against the binary and a live
|
|
11
|
-
* probe on 2026-10-02):
|
|
12
|
-
* - macOS: the login keychain, service `Claude Code`, account $USER. When
|
|
13
|
-
* CLAUDE_CONFIG_DIR is set the service gains `-<first 8 hex of sha256(the raw
|
|
14
|
-
* CLAUDE_CONFIG_DIR value, NFC)>`; CLAUDE_SECURESTORAGE_CONFIG_DIR, when set, replaces
|
|
15
|
-
* that value (empty = no suffix).
|
|
16
|
-
* - everywhere (and the macOS fallback): `primaryApiKey` in Claude Code's .claude.json.
|
|
17
|
-
*
|
|
18
|
-
* A `claude auth login --console` *profile* (keyless OAuth, ~/.config/anthropic) creates no
|
|
19
|
-
* such key, so it is not read here.
|
|
20
|
-
*
|
|
21
|
-
* Pure apart from the injected deps, so every arm is unit-tested.
|
|
22
|
-
*/
|
|
23
|
-
export interface ConsoleKeyDeps {
|
|
24
|
-
platform: NodeJS.Platform;
|
|
25
|
-
env: Record<string, string | undefined>;
|
|
26
|
-
/** os.userInfo().username, for when $USER is unset. */
|
|
27
|
-
username(): string;
|
|
28
|
-
/** The keychain password for (service, account), or undefined when absent. */
|
|
29
|
-
readKeychain(service: string, account: string): string | undefined;
|
|
30
|
-
/** Parsed .claude.json (see readClaudeLoginState), or undefined. */
|
|
31
|
-
claudeJson: unknown;
|
|
32
|
-
}
|
|
33
|
-
/** The keychain service name Claude Code stores the managed key under. */
|
|
34
|
-
export declare function claudeKeychainService(env: Record<string, string | undefined>): string;
|
|
35
|
-
/** The keychain account Claude Code uses: $USER, else the OS username, else a fixed name. */
|
|
36
|
-
export declare function claudeKeychainAccount(env: Record<string, string | undefined>, username: () => string): string;
|
|
37
|
-
/** Claude Code's Console-login API key on this machine, or undefined. Never throws. */
|
|
38
|
-
export declare function readConsoleKey(deps: ConsoleKeyDeps): string | undefined;
|
|
39
|
-
/** The key for an `auth = console` launch; throws with what to do when there is none. */
|
|
40
|
-
export declare function requireConsoleKey(deps: ConsoleKeyDeps): string;
|
package/dist/lib/console-key.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `mnemom agent` with an Anthropic Console login (`auth = console`).
|
|
3
|
-
*
|
|
4
|
-
* Claude Code's `/login` → "Anthropic Console account" uses OAuth only to create a real
|
|
5
|
-
* Anthropic API key, which Claude Code stores and then sends as `x-api-key` ("/login
|
|
6
|
-
* managed key"). This module reads that key from where Claude Code keeps it, so the launch
|
|
7
|
-
* runs exactly like `auth = api-key` — same headers, same birth and claim, same identity —
|
|
8
|
-
* with no key for the user to copy. The key is read per launch and never stored by us.
|
|
9
|
-
*
|
|
10
|
-
* Where Claude Code keeps it (Claude Code 2.1.285, confirmed against the binary and a live
|
|
11
|
-
* probe on 2026-10-02):
|
|
12
|
-
* - macOS: the login keychain, service `Claude Code`, account $USER. When
|
|
13
|
-
* CLAUDE_CONFIG_DIR is set the service gains `-<first 8 hex of sha256(the raw
|
|
14
|
-
* CLAUDE_CONFIG_DIR value, NFC)>`; CLAUDE_SECURESTORAGE_CONFIG_DIR, when set, replaces
|
|
15
|
-
* that value (empty = no suffix).
|
|
16
|
-
* - everywhere (and the macOS fallback): `primaryApiKey` in Claude Code's .claude.json.
|
|
17
|
-
*
|
|
18
|
-
* A `claude auth login --console` *profile* (keyless OAuth, ~/.config/anthropic) creates no
|
|
19
|
-
* such key, so it is not read here.
|
|
20
|
-
*
|
|
21
|
-
* Pure apart from the injected deps, so every arm is unit-tested.
|
|
22
|
-
*/
|
|
23
|
-
import { createHash } from "node:crypto";
|
|
24
|
-
const ACCOUNT_RE = /^[a-zA-Z0-9._-]+$/;
|
|
25
|
-
/** The keychain service name Claude Code stores the managed key under. */
|
|
26
|
-
export function claudeKeychainService(env) {
|
|
27
|
-
const secure = env.CLAUDE_SECURESTORAGE_CONFIG_DIR;
|
|
28
|
-
const dir = secure !== undefined ? secure : (env.CLAUDE_CONFIG_DIR ?? "");
|
|
29
|
-
if (!dir)
|
|
30
|
-
return "Claude Code";
|
|
31
|
-
const hash = createHash("sha256").update(dir.normalize("NFC")).digest("hex").slice(0, 8);
|
|
32
|
-
return `Claude Code-${hash}`;
|
|
33
|
-
}
|
|
34
|
-
/** The keychain account Claude Code uses: $USER, else the OS username, else a fixed name. */
|
|
35
|
-
export function claudeKeychainAccount(env, username) {
|
|
36
|
-
let name;
|
|
37
|
-
try {
|
|
38
|
-
name = env.USER || username();
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
name = "";
|
|
42
|
-
}
|
|
43
|
-
return ACCOUNT_RE.test(name) ? name : "claude-code-user";
|
|
44
|
-
}
|
|
45
|
-
/** The key is spliced into a newline-joined header block, so CR/LF must never survive. */
|
|
46
|
-
function clean(raw) {
|
|
47
|
-
const v = (raw ?? "").replace(/[\r\n]+/g, "").trim();
|
|
48
|
-
return v || undefined;
|
|
49
|
-
}
|
|
50
|
-
/** Claude Code's Console-login API key on this machine, or undefined. Never throws. */
|
|
51
|
-
export function readConsoleKey(deps) {
|
|
52
|
-
if (deps.platform === "darwin") {
|
|
53
|
-
let fromKeychain;
|
|
54
|
-
try {
|
|
55
|
-
fromKeychain = clean(deps.readKeychain(claudeKeychainService(deps.env), claudeKeychainAccount(deps.env, deps.username)));
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
fromKeychain = undefined;
|
|
59
|
-
}
|
|
60
|
-
if (fromKeychain)
|
|
61
|
-
return fromKeychain;
|
|
62
|
-
}
|
|
63
|
-
const json = deps.claudeJson;
|
|
64
|
-
const stored = json && typeof json === "object"
|
|
65
|
-
? json.primaryApiKey
|
|
66
|
-
: undefined;
|
|
67
|
-
return typeof stored === "string" ? clean(stored) : undefined;
|
|
68
|
-
}
|
|
69
|
-
/** The key for an `auth = console` launch; throws with what to do when there is none. */
|
|
70
|
-
export function requireConsoleKey(deps) {
|
|
71
|
-
const key = readConsoleKey(deps);
|
|
72
|
-
if (key)
|
|
73
|
-
return key;
|
|
74
|
-
throw new Error("mnemom agent: auth = console, but Claude Code has no Anthropic Console login on this machine.\n" +
|
|
75
|
-
' Sign in: run `claude`, then /login → "Anthropic Console account".\n' +
|
|
76
|
-
" Or use a key instead: `mnemom agent config set auth api-key`.");
|
|
77
|
-
}
|