@mnemom/mnemom 0.17.0-next.5 → 0.17.0-next.7
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-config.d.ts +17 -0
- package/dist/commands/agent-config.js +173 -0
- package/dist/commands/{code-doctor.d.ts → agent-doctor.d.ts} +2 -2
- package/dist/commands/{code-doctor.js → agent-doctor.js} +27 -22
- package/dist/commands/{code-invite.d.ts → agent-invite.d.ts} +18 -18
- package/dist/commands/{code-invite.js → agent-invite.js} +30 -30
- package/dist/commands/{code-session.d.ts → agent-session.d.ts} +2 -2
- package/dist/commands/{code-session.js → agent-session.js} +8 -8
- package/dist/commands/{code-setup.d.ts → agent-setup.d.ts} +19 -11
- package/dist/commands/{code-setup.js → agent-setup.js} +63 -39
- package/dist/commands/{code.d.ts → agent.d.ts} +14 -14
- package/dist/commands/{code.js → agent.js} +79 -78
- package/dist/commands/agents.d.ts +2 -2
- package/dist/commands/agents.js +5 -5
- package/dist/commands/onboard.js +1 -1
- package/dist/commands/wrap.js +1 -1
- package/dist/index.js +42 -47
- package/dist/lib/{code.d.ts → agent.d.ts} +9 -9
- package/dist/lib/{code.js → agent.js} +14 -14
- package/dist/lib/api.d.ts +15 -3
- package/dist/lib/api.js +12 -9
- package/dist/lib/{code-config.d.ts → launcher-config.d.ts} +23 -23
- package/dist/lib/{code-config.js → launcher-config.js} +31 -31
- package/dist/lib/version-gate.js +1 -1
- package/dist/rc-proxy.mjs +297 -134
- package/package.json +1 -1
- package/dist/commands/code-config.d.ts +0 -17
- package/dist/commands/code-config.js +0 -147
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `mnemom
|
|
2
|
+
* `mnemom agent <scenario>` — the CLI's first-class governed-coding-agent launcher.
|
|
3
3
|
*
|
|
4
4
|
* Launches your coding-agent CLI (Claude Code in v1) with its dev-time model
|
|
5
5
|
* traffic routed through the Mnemom gateway's /anthropic door for observability +
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* no router door / Mnemom key). `--cli` selects the executable to run (name or
|
|
12
12
|
* full path) so codex/cursor/github adapters can be added later.
|
|
13
13
|
* - The us-2/PROD gateway is the DEFAULT door (https://gateway.mnemom.ai); an
|
|
14
|
-
* explicit
|
|
14
|
+
* explicit MNEMOM_AGENT_GATEWAY / --gateway still wins, never silently prod.
|
|
15
15
|
* - Three launch shapes: `terminal` (DEFAULT), `remote-control` (interactive RC
|
|
16
16
|
* in this terminal), `server` (headless RC dispatcher). RC runs the CLI
|
|
17
17
|
* UNTOUCHED behind a bundled local TLS proxy (rc-proxy.mjs) — Claude Code
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* - yolo (`--dangerously-skip-permissions`) is ON by default; `--no-yolo` opts out.
|
|
21
21
|
*
|
|
22
22
|
* The Anthropic key is resolved from a credential source with ZERO 1Password
|
|
23
|
-
* dependency (env → the CLI's own ~/.mnemom/
|
|
23
|
+
* dependency (env → the CLI's own ~/.mnemom/launcher.json store → interactive
|
|
24
24
|
* prompt) and placed ONLY in the launched process (an `ANTHROPIC_CUSTOM_HEADERS`
|
|
25
25
|
* line, or the proxy's stdin under RC). It is never logged, printed, or passed as
|
|
26
26
|
* an argv value.
|
|
@@ -31,31 +31,31 @@ import { tmpdir, homedir } from "node:os";
|
|
|
31
31
|
import { basename, join, dirname } from "node:path";
|
|
32
32
|
import { fileURLToPath } from "node:url";
|
|
33
33
|
import { MNEMOM_DIR } from "../lib/config.js";
|
|
34
|
-
import { configKeySpec,
|
|
34
|
+
import { configKeySpec, loadLauncherConfig, writeLauncherConfig } from "../lib/launcher-config.js";
|
|
35
35
|
import { fmt } from "../lib/format.js";
|
|
36
36
|
import { askInput, askYesNo, isInteractive } from "../lib/prompt.js";
|
|
37
|
-
import { goalAlignmentLine, resolveSessionSetup } from "./
|
|
38
|
-
import { defaultAgentSlug, ensureGovernedAgent, ensureSessionAndBalance, isQuietPreambleExit, } from "./
|
|
39
|
-
import { assembleContract, buildCustomHeaders, isProdGateway, launchPreferenceExplicit, resolveAnthropicDoor, resolveConversationId, resolveGatewayHost, resolveLaunchShape, sanitizeAgentName, } from "../lib/
|
|
40
|
-
/** The CLI's own provider-key store (zero 1Password): ~/.mnemom/
|
|
41
|
-
const CODE_STORE = join(MNEMOM_DIR, "
|
|
37
|
+
import { goalAlignmentLine, resolveSessionSetup } from "./agent-session.js";
|
|
38
|
+
import { defaultAgentSlug, ensureGovernedAgent, ensureSessionAndBalance, isQuietPreambleExit, resolveDefaultSlug, } from "./agent-setup.js";
|
|
39
|
+
import { assembleContract, buildCustomHeaders, isProdGateway, launchPreferenceExplicit, resolveAnthropicDoor, resolveConversationId, resolveGatewayHost, resolveLaunchShape, sanitizeAgentName, } from "../lib/agent.js";
|
|
40
|
+
/** The CLI's own provider-key store (zero 1Password): ~/.mnemom/launcher.json, 0600. */
|
|
41
|
+
const CODE_STORE = join(MNEMOM_DIR, "launcher.json");
|
|
42
42
|
const say = (line = "") => console.error(line);
|
|
43
|
-
/** Entry point for `mnemom
|
|
44
|
-
export async function
|
|
45
|
-
// ── session name + goal ── (a bare `mnemom
|
|
43
|
+
/** Entry point for `mnemom agent [scenario]`. Throws on fatal misconfig. */
|
|
44
|
+
export async function agentCommand(scenarioArg, options = {}) {
|
|
45
|
+
// ── session name + goal ── (a bare `mnemom agent` in a terminal asks for both,
|
|
46
46
|
// explaining goal alignment; no goal ⇒ no contract header ⇒ goal alignment off)
|
|
47
47
|
const session = await resolveSessionSetup({ scenario: scenarioArg, goal: options.goal, interactive: isInteractive() }, { askInput: (q) => askInput(q), askYesNo: (q, d) => askYesNo(q, d) });
|
|
48
48
|
const scenario = session.scenario;
|
|
49
49
|
const env = process.env;
|
|
50
50
|
let shape = resolveLaunchShape({ remoteControl: options.remoteControl, server: options.server }, env);
|
|
51
51
|
const shapeExplicit = launchPreferenceExplicit({ remoteControl: options.remoteControl, server: options.server }, env);
|
|
52
|
-
// ── governed identity ── (default: per-customer `
|
|
52
|
+
// ── governed identity ── (default: per-customer `agent-<handle>`, not a shared
|
|
53
53
|
// "code-agent" — see defaultAgentSlug; provisioning claims exactly this slug.
|
|
54
54
|
// `let` because a brand-new user who signs in during the pre-launch gate below
|
|
55
55
|
// gets their real handle re-derived once the session exists.)
|
|
56
56
|
let agent = sanitizeAgentName(options.agent?.trim() || defaultAgentSlug());
|
|
57
57
|
if (!agent) {
|
|
58
|
-
throw new Error("mnemom
|
|
58
|
+
throw new Error("mnemom agent: --agent sanitised to an empty string — pick a value with at least one letter or digit.");
|
|
59
59
|
}
|
|
60
60
|
const conversationId = resolveConversationId(options.conversationId);
|
|
61
61
|
// ── contract (built only if a contract flag was given; --goal then required) ──
|
|
@@ -98,16 +98,16 @@ export async function codeCommand(scenarioArg, options = {}) {
|
|
|
98
98
|
shape = "remote-control";
|
|
99
99
|
}
|
|
100
100
|
else {
|
|
101
|
-
say(`mnemom
|
|
102
|
-
say("mnemom
|
|
101
|
+
say(`mnemom agent: launching terminal-only (Remote Control unavailable: ${rc.missing.join("; ")}).`);
|
|
102
|
+
say("mnemom agent: once those are in place, `mnemom agent <scenario> --remote-control` (or `config set launch remote-control`) gives you a session steerable from claude.ai and the Claude app too.");
|
|
103
103
|
}
|
|
104
104
|
};
|
|
105
105
|
if (cli)
|
|
106
106
|
applyAutoShape(cli);
|
|
107
107
|
if (options.dryRun) {
|
|
108
108
|
const planCli = cli ?? {
|
|
109
|
-
bin: "(not found — pass --cli <path> or `mnemom
|
|
110
|
-
name: basename((options.cli || env.
|
|
109
|
+
bin: "(not found — pass --cli <path> or `mnemom agent config set cli <path>`)",
|
|
110
|
+
name: basename((options.cli || env.MNEMOM_AGENT_CLI || "claude").trim()),
|
|
111
111
|
};
|
|
112
112
|
printPlan({
|
|
113
113
|
scenario,
|
|
@@ -135,7 +135,7 @@ export async function codeCommand(scenarioArg, options = {}) {
|
|
|
135
135
|
keySource: options.keySource,
|
|
136
136
|
});
|
|
137
137
|
// ── account + µ-balance gate (no free tier) ─────────────────────────────────
|
|
138
|
-
// mnemom
|
|
138
|
+
// mnemom agent runs governed and on µ, so before we seal a contract or launch we
|
|
139
139
|
// (1) ensure a Mnemom session — offering the try-me-style sign-in / sign-up when
|
|
140
140
|
// there isn't one — and (2) enforce a positive µ balance on the org the agent
|
|
141
141
|
// lives in (default: the user's personal org). No µ ⇒ blocked with a
|
|
@@ -148,10 +148,11 @@ export async function codeCommand(scenarioArg, options = {}) {
|
|
|
148
148
|
process.exit(1); // guidance already printed
|
|
149
149
|
throw err;
|
|
150
150
|
}
|
|
151
|
-
// Now that a session exists, a defaulted slug
|
|
152
|
-
// (
|
|
151
|
+
// Now that a session exists, a defaulted slug uses the real login handle from
|
|
152
|
+
// /v1/auth/me (the stored token has no email, so the pre-sign-in value was the
|
|
153
|
+
// "agent-user" fallback). Only when the caller didn't name an agent.
|
|
153
154
|
if (!options.agent?.trim()) {
|
|
154
|
-
const refreshed = sanitizeAgentName(
|
|
155
|
+
const refreshed = sanitizeAgentName(await resolveDefaultSlug());
|
|
155
156
|
if (refreshed)
|
|
156
157
|
agent = refreshed;
|
|
157
158
|
}
|
|
@@ -171,7 +172,7 @@ export async function codeCommand(scenarioArg, options = {}) {
|
|
|
171
172
|
}
|
|
172
173
|
catch (err) {
|
|
173
174
|
const msg = err instanceof Error ? err.message : String(err);
|
|
174
|
-
say(fmt.warn(`mnemom
|
|
175
|
+
say(fmt.warn(`mnemom agent: agent setup did not complete (${msg}) — launching with the unclaimed identity.`));
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
178
|
logLaunch({ shape, door, agent, conversationId, cellNote, envelope, cli });
|
|
@@ -209,8 +210,8 @@ export async function codeCommand(scenarioArg, options = {}) {
|
|
|
209
210
|
/**
|
|
210
211
|
* Resolve the Anthropic key with NO 1Password dependency (built for external
|
|
211
212
|
* customer adoption), in order:
|
|
212
|
-
* 1. env:
|
|
213
|
-
* 2. the CLI's own store: ~/.mnemom/
|
|
213
|
+
* 1. env: MNEMOM_AGENT_ANTHROPIC_KEY, else ANTHROPIC_API_KEY
|
|
214
|
+
* 2. the CLI's own store: ~/.mnemom/launcher.json (`anthropic_key`)
|
|
214
215
|
* 3. interactive prompt (masked), offering to save it to the store
|
|
215
216
|
* Never logged / printed. Throws with guidance when nothing resolves — we refuse
|
|
216
217
|
* to launch un-routed.
|
|
@@ -219,13 +220,13 @@ export async function resolveAnthropicKey(env, opts) {
|
|
|
219
220
|
const source = opts.keySource;
|
|
220
221
|
// "prompt" forces the interactive prompt (skips env + store).
|
|
221
222
|
if (source !== "prompt") {
|
|
222
|
-
const fromEnv = (env.
|
|
223
|
+
const fromEnv = (env.MNEMOM_AGENT_ANTHROPIC_KEY || env.ANTHROPIC_API_KEY || "").trim();
|
|
223
224
|
if (fromEnv)
|
|
224
225
|
return fromEnv;
|
|
225
226
|
// "env" restricts to env only — no store, no prompt.
|
|
226
227
|
if (source === "env") {
|
|
227
|
-
throw new Error("mnemom
|
|
228
|
-
" Set one: export
|
|
228
|
+
throw new Error("mnemom agent: key_source is 'env' but no Anthropic key is set.\n" +
|
|
229
|
+
" Set one: export MNEMOM_AGENT_ANTHROPIC_KEY=sk-ant-... (or ANTHROPIC_API_KEY)");
|
|
229
230
|
}
|
|
230
231
|
const stored = readStoredKey();
|
|
231
232
|
if (stored)
|
|
@@ -233,28 +234,28 @@ export async function resolveAnthropicKey(env, opts) {
|
|
|
233
234
|
}
|
|
234
235
|
// (source can only be "store", "prompt", or undefined here — "env" threw above.)
|
|
235
236
|
if (opts.allowPrompt && isInteractive()) {
|
|
236
|
-
say("mnemom
|
|
237
|
+
say("mnemom agent: no Anthropic key in env (MNEMOM_AGENT_ANTHROPIC_KEY / ANTHROPIC_API_KEY) or ~/.mnemom/launcher.json.");
|
|
237
238
|
const entered = (await askInput("Enter your Anthropic API key (sk-ant-…):", true)).trim();
|
|
238
239
|
if (entered) {
|
|
239
|
-
if (await askYesNo("Save it to ~/.mnemom/
|
|
240
|
+
if (await askYesNo("Save it to ~/.mnemom/launcher.json (0600) for next time?", true)) {
|
|
240
241
|
storeKey(entered);
|
|
241
|
-
say("mnemom
|
|
242
|
+
say("mnemom agent: saved to ~/.mnemom/launcher.json.");
|
|
242
243
|
}
|
|
243
244
|
return entered;
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
|
-
throw new Error("mnemom
|
|
247
|
-
" Set one: export
|
|
248
|
-
" Or save it: run `mnemom
|
|
249
|
-
" (stored 0600 at ~/.mnemom/
|
|
247
|
+
throw new Error("mnemom agent: no Anthropic key found — refusing to launch un-routed.\n" +
|
|
248
|
+
" Set one: export MNEMOM_AGENT_ANTHROPIC_KEY=sk-ant-... (or ANTHROPIC_API_KEY)\n" +
|
|
249
|
+
" Or save it: run `mnemom agent` interactively and accept the save prompt\n" +
|
|
250
|
+
" (stored 0600 at ~/.mnemom/launcher.json).");
|
|
250
251
|
}
|
|
251
252
|
/**
|
|
252
253
|
* Where an Anthropic key would resolve from RIGHT NOW, without reading its value:
|
|
253
|
-
* "env" (
|
|
254
|
-
* or null (would fall to the interactive prompt). For `mnemom
|
|
254
|
+
* "env" (MNEMOM_AGENT_ANTHROPIC_KEY / ANTHROPIC_API_KEY), "store" (~/.mnemom/launcher.json),
|
|
255
|
+
* or null (would fall to the interactive prompt). For `mnemom agent doctor`.
|
|
255
256
|
*/
|
|
256
257
|
export function anthropicKeySource(env = process.env) {
|
|
257
|
-
if ((env.
|
|
258
|
+
if ((env.MNEMOM_AGENT_ANTHROPIC_KEY || env.ANTHROPIC_API_KEY || "").trim())
|
|
258
259
|
return "env";
|
|
259
260
|
if (readStoredKey())
|
|
260
261
|
return "store";
|
|
@@ -271,7 +272,7 @@ function readStoredKey() {
|
|
|
271
272
|
return undefined;
|
|
272
273
|
}
|
|
273
274
|
}
|
|
274
|
-
/** Persist the provider key to ~/.mnemom/
|
|
275
|
+
/** Persist the provider key to ~/.mnemom/launcher.json at 0600 (atomic). Best-effort. */
|
|
275
276
|
function storeKey(key) {
|
|
276
277
|
try {
|
|
277
278
|
mkdirSync(MNEMOM_DIR, { recursive: true });
|
|
@@ -284,7 +285,7 @@ function storeKey(key) {
|
|
|
284
285
|
}
|
|
285
286
|
}
|
|
286
287
|
/**
|
|
287
|
-
* Resolve which coding-agent CLI to launch. `--cli` (or
|
|
288
|
+
* Resolve which coding-agent CLI to launch. `--cli` (or MNEMOM_AGENT_CLI) is a
|
|
288
289
|
* name or a full path; default "claude". A value with a path separator is used
|
|
289
290
|
* verbatim (must exist); a bare name is resolved on PATH, then — for claude — the
|
|
290
291
|
* fnm/nvm/asdf install dirs (a version-manager shim / shell function is absent in
|
|
@@ -292,12 +293,12 @@ function storeKey(key) {
|
|
|
292
293
|
* a non-claude executable is launched through it with a warning.
|
|
293
294
|
*/
|
|
294
295
|
export function resolveCliBin(cliOpt, env) {
|
|
295
|
-
const requested = (cliOpt || env.
|
|
296
|
+
const requested = (cliOpt || env.MNEMOM_AGENT_CLI || "claude").trim();
|
|
296
297
|
const name = basename(requested);
|
|
297
298
|
if (requested.includes("/")) {
|
|
298
299
|
if (existsSync(requested))
|
|
299
300
|
return { bin: requested, name };
|
|
300
|
-
throw new Error(`mnemom
|
|
301
|
+
throw new Error(`mnemom agent: --cli path '${requested}' not found.`);
|
|
301
302
|
}
|
|
302
303
|
for (const dir of (env.PATH || "").split(":")) {
|
|
303
304
|
// Skip ephemeral cmux CLI shims: they only work inside a cmux session and,
|
|
@@ -333,10 +334,10 @@ export function resolveCliBin(cliOpt, env) {
|
|
|
333
334
|
}
|
|
334
335
|
}
|
|
335
336
|
}
|
|
336
|
-
throw new Error(`mnemom
|
|
337
|
+
throw new Error(`mnemom agent: coding-agent CLI '${requested}' not found.\n` +
|
|
337
338
|
" Looked on $PATH" +
|
|
338
339
|
(name === "claude" ? " and in the fnm/nvm/asdf node dirs" : "") +
|
|
339
|
-
".\n Pass --cli <name|/full/path> or set
|
|
340
|
+
".\n Pass --cli <name|/full/path> or set MNEMOM_AGENT_CLI.");
|
|
340
341
|
}
|
|
341
342
|
export /**
|
|
342
343
|
* Recover when the coding-agent CLI can't be found — a good experience beats a
|
|
@@ -345,11 +346,11 @@ export /**
|
|
|
345
346
|
* so they never retype it). A non-interactive session re-throws the clear,
|
|
346
347
|
* actionable error rather than hanging on a prompt.
|
|
347
348
|
*/ async function promptForCliPath(cliOpt, env, origErr) {
|
|
348
|
-
const requested = (cliOpt || env.
|
|
349
|
+
const requested = (cliOpt || env.MNEMOM_AGENT_CLI || "claude").trim();
|
|
349
350
|
if (!isInteractive()) {
|
|
350
|
-
throw origErr ?? new Error(`mnemom
|
|
351
|
+
throw origErr ?? new Error(`mnemom agent: coding-agent CLI '${requested}' not found.`);
|
|
351
352
|
}
|
|
352
|
-
say(`mnemom
|
|
353
|
+
say(`mnemom agent: couldn't find the '${requested}' CLI on your PATH.`);
|
|
353
354
|
if (requested === "claude") {
|
|
354
355
|
say(" If Claude Code is installed, paste its full path (find it with: which claude).");
|
|
355
356
|
say(" Not installed yet? Get it at https://claude.com/claude-code, then re-run.");
|
|
@@ -360,9 +361,9 @@ export /**
|
|
|
360
361
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
361
362
|
const entered = (await askInput("Path to your coding-agent CLI (Enter to cancel):")).trim();
|
|
362
363
|
if (!entered) {
|
|
363
|
-
throw new Error("mnemom
|
|
364
|
+
throw new Error("mnemom agent: no coding-agent CLI available.\n" +
|
|
364
365
|
" Install Claude Code (https://claude.com/claude-code), or pass --cli <path> " +
|
|
365
|
-
"(or save it: mnemom
|
|
366
|
+
"(or save it: mnemom agent config set cli <path>).");
|
|
366
367
|
}
|
|
367
368
|
if (!existsSync(entered)) {
|
|
368
369
|
say(` '${entered}' doesn't exist — try again.`);
|
|
@@ -370,9 +371,9 @@ export /**
|
|
|
370
371
|
}
|
|
371
372
|
if (await askYesNo("Save this as your default CLI so you don't retype it?", true)) {
|
|
372
373
|
try {
|
|
373
|
-
const cfg =
|
|
374
|
+
const cfg = loadLauncherConfig();
|
|
374
375
|
configKeySpec("cli").set(cfg, entered);
|
|
375
|
-
|
|
376
|
+
writeLauncherConfig(cfg);
|
|
376
377
|
say(" Saved — future launches will use it.");
|
|
377
378
|
}
|
|
378
379
|
catch {
|
|
@@ -381,7 +382,7 @@ export /**
|
|
|
381
382
|
}
|
|
382
383
|
return { bin: entered, name: basename(entered) };
|
|
383
384
|
}
|
|
384
|
-
throw new Error("mnemom
|
|
385
|
+
throw new Error("mnemom agent: couldn't resolve a coding-agent CLI path — pass --cli <path>.");
|
|
385
386
|
}
|
|
386
387
|
function commandExists(cmd) {
|
|
387
388
|
const res = spawnSync("sh", ["-c", `command -v "$1" >/dev/null 2>&1`, "sh", cmd], {
|
|
@@ -407,7 +408,7 @@ export function cliSupportsRemoteControl(bin) {
|
|
|
407
408
|
/**
|
|
408
409
|
* Can we launch the DEFAULT Remote-Control-in-terminal shape on this machine?
|
|
409
410
|
* Needs node + openssl (the local proxy mints an ephemeral CA) and a claude
|
|
410
|
-
* adapter that advertises `--remote-control`. Used both by `mnemom
|
|
411
|
+
* adapter that advertises `--remote-control`. Used both by `mnemom agent doctor`
|
|
411
412
|
* and by the auto-default selection (a bare launch prefers RC when capable).
|
|
412
413
|
*/
|
|
413
414
|
export function checkRcCapability(cli) {
|
|
@@ -428,7 +429,7 @@ export function checkRcCapability(cli) {
|
|
|
428
429
|
/** Warn once when a non-claude executable rides the v1 Claude Code adapter. */
|
|
429
430
|
function warnAdapter(cli) {
|
|
430
431
|
if (cli.name !== "claude") {
|
|
431
|
-
say(`mnemom
|
|
432
|
+
say(`mnemom agent: only the Claude Code adapter is wired in v1 — launching '${cli.name}' with the Anthropic gateway env. codex/cursor/github adapters are coming.`);
|
|
432
433
|
}
|
|
433
434
|
}
|
|
434
435
|
// ───────────────────────────────────────────────────────────────────────────
|
|
@@ -458,7 +459,7 @@ function launchTerminal(ctx) {
|
|
|
458
459
|
}
|
|
459
460
|
const child = spawn(ctx.cli.bin, args, { stdio: "inherit", env: childEnv });
|
|
460
461
|
child.on("error", (err) => {
|
|
461
|
-
say(`mnemom
|
|
462
|
+
say(`mnemom agent: failed to launch ${ctx.cli.name}: ${err.message}`);
|
|
462
463
|
process.exit(1);
|
|
463
464
|
});
|
|
464
465
|
child.on("exit", (code, signal) => {
|
|
@@ -475,21 +476,21 @@ function launchRemoteControl(ctx) {
|
|
|
475
476
|
warnAdapter(ctx.cli);
|
|
476
477
|
for (const tool of ["node", "openssl"]) {
|
|
477
478
|
if (!commandExists(tool)) {
|
|
478
|
-
throw new Error(`mnemom
|
|
479
|
+
throw new Error(`mnemom agent: --remote-control needs '${tool}' on PATH (the local proxy is a Node script that mints an ephemeral CA with openssl).`);
|
|
479
480
|
}
|
|
480
481
|
}
|
|
481
482
|
const proxyScript = resolveProxyScript();
|
|
482
483
|
const rcDir = mkdtempSync(join(tmpdir(), "mnemom-code-rc."));
|
|
483
|
-
const proxyLog = process.env.
|
|
484
|
+
const proxyLog = process.env.MNEMOM_AGENT_RC_PROXY_LOG || join(rcDir, "proxy.log");
|
|
484
485
|
const proxy = spawn("node", [proxyScript], {
|
|
485
486
|
env: {
|
|
486
487
|
...process.env,
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
488
|
+
MNEMOM_AGENT_RC_DOOR: ctx.door,
|
|
489
|
+
MNEMOM_AGENT_RC_AGENT: ctx.agent,
|
|
490
|
+
MNEMOM_AGENT_RC_CONVERSATION_ID: ctx.conversationId,
|
|
491
|
+
MNEMOM_AGENT_RC_CONTRACT_B64: ctx.envelope?.base64 ?? "",
|
|
492
|
+
MNEMOM_AGENT_RC_PROXY_LOG: proxyLog,
|
|
493
|
+
MNEMOM_AGENT_RC_PARENT_PID: String(process.pid),
|
|
493
494
|
},
|
|
494
495
|
stdio: ["pipe", "pipe", "inherit"],
|
|
495
496
|
});
|
|
@@ -525,7 +526,7 @@ function launchRemoteControl(ctx) {
|
|
|
525
526
|
const port = m[1];
|
|
526
527
|
const ca = m[2].trim();
|
|
527
528
|
if (!existsSync(ca)) {
|
|
528
|
-
say("mnemom
|
|
529
|
+
say("mnemom agent: malformed READY line from the Remote Control proxy.");
|
|
529
530
|
onExit();
|
|
530
531
|
process.exit(1);
|
|
531
532
|
}
|
|
@@ -533,13 +534,13 @@ function launchRemoteControl(ctx) {
|
|
|
533
534
|
return;
|
|
534
535
|
}
|
|
535
536
|
if (proxy.exitCode !== null) {
|
|
536
|
-
say("mnemom
|
|
537
|
+
say("mnemom agent: the Remote Control proxy exited before it was ready — refusing to launch un-routed.");
|
|
537
538
|
redactedProxyLog(proxyLog);
|
|
538
539
|
onExit();
|
|
539
540
|
process.exit(1);
|
|
540
541
|
}
|
|
541
542
|
if (Date.now() - start > 15_000) {
|
|
542
|
-
say("mnemom
|
|
543
|
+
say("mnemom agent: the Remote Control proxy did not report READY within 15s.");
|
|
543
544
|
onExit();
|
|
544
545
|
process.exit(1);
|
|
545
546
|
}
|
|
@@ -549,7 +550,7 @@ function launchRemoteControl(ctx) {
|
|
|
549
550
|
stdoutBuf += chunk.toString("utf8");
|
|
550
551
|
});
|
|
551
552
|
proxy.on("error", (err) => {
|
|
552
|
-
say(`mnemom
|
|
553
|
+
say(`mnemom agent: failed to launch the Remote Control proxy: ${err.message}`);
|
|
553
554
|
onExit();
|
|
554
555
|
process.exit(1);
|
|
555
556
|
});
|
|
@@ -601,7 +602,7 @@ function spawnRcCli(ctx) {
|
|
|
601
602
|
if (ctx.options.model)
|
|
602
603
|
childEnv.ANTHROPIC_MODEL = ctx.options.model;
|
|
603
604
|
args = ["remote-control", "--name", rcName, ...passthrough];
|
|
604
|
-
say(`mnemom
|
|
605
|
+
say(`mnemom agent: remote-control: headless server (session name '${rcName}'); drive the sessions it spawns from claude.ai/code or the Claude app. Stop this command to stop the server.`);
|
|
605
606
|
}
|
|
606
607
|
else {
|
|
607
608
|
// Interactive RC in THIS terminal: the CLI's own `--remote-control <name>`
|
|
@@ -609,11 +610,11 @@ function spawnRcCli(ctx) {
|
|
|
609
610
|
// buildCliArgs already includes the (name-stripped) passthrough.
|
|
610
611
|
const flagArgs = buildCliArgs(scopedOptions, { yolo: ctx.yolo, allowCliFlags: true });
|
|
611
612
|
args = ["--remote-control", rcName, ...flagArgs];
|
|
612
|
-
say(`mnemom
|
|
613
|
+
say(`mnemom agent: remote-control: interactive session in THIS terminal with Remote Control on (session name '${rcName}'); it also appears under Remote Control at claude.ai/code and in the Claude app. Exit the CLI to stop everything.`);
|
|
613
614
|
}
|
|
614
615
|
const child = spawn(ctx.cli.bin, args, { stdio: "inherit", env: childEnv });
|
|
615
616
|
child.on("error", (err) => {
|
|
616
|
-
say(`mnemom
|
|
617
|
+
say(`mnemom agent: failed to launch ${ctx.cli.name} under Remote Control: ${err.message}`);
|
|
617
618
|
ctx.onExit();
|
|
618
619
|
process.exit(1);
|
|
619
620
|
});
|
|
@@ -627,20 +628,20 @@ function spawnRcCli(ctx) {
|
|
|
627
628
|
}
|
|
628
629
|
function warnServerDrops(options, yolo) {
|
|
629
630
|
if (options.effort) {
|
|
630
|
-
say("mnemom
|
|
631
|
+
say("mnemom agent: --effort is not applied under --server (set it from the session instead).");
|
|
631
632
|
}
|
|
632
633
|
if (options.trimMcp) {
|
|
633
|
-
say("mnemom
|
|
634
|
+
say("mnemom agent: --trim-mcp is not applied under --server (sessions load the full MCP set).");
|
|
634
635
|
}
|
|
635
636
|
if (yolo) {
|
|
636
|
-
say("mnemom
|
|
637
|
+
say("mnemom agent: yolo (--dangerously-skip-permissions) is not applied under --server; set permissions from the driven sessions.");
|
|
637
638
|
}
|
|
638
639
|
}
|
|
639
640
|
function resolveProxyScript() {
|
|
640
641
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
641
642
|
const cand = join(here, "..", "rc-proxy.mjs");
|
|
642
643
|
if (!existsSync(cand)) {
|
|
643
|
-
throw new Error(`mnemom
|
|
644
|
+
throw new Error(`mnemom agent: the Remote Control proxy is missing (expected ${cand}). Reinstall the CLI.`);
|
|
644
645
|
}
|
|
645
646
|
return cand;
|
|
646
647
|
}
|
|
@@ -720,15 +721,15 @@ function seedContextHintFlag(childEnv) {
|
|
|
720
721
|
// Human-facing logging (never prints the key)
|
|
721
722
|
// ───────────────────────────────────────────────────────────────────────────
|
|
722
723
|
function logLaunch(ctx) {
|
|
723
|
-
say(`mnemom
|
|
724
|
+
say(`mnemom agent: routing ${ctx.cli.name} through ${ctx.door} [${ctx.cellNote}] as '${ctx.agent}' (conversation ${ctx.conversationId}).`);
|
|
724
725
|
if (ctx.envelope) {
|
|
725
|
-
say(`mnemom
|
|
726
|
-
say(`mnemom
|
|
726
|
+
say(`mnemom agent: contract statement: ${ctx.envelope.contract.statement}`);
|
|
727
|
+
say(`mnemom agent: contract sha256[0:16]: ${ctx.envelope.sha}`);
|
|
727
728
|
}
|
|
728
729
|
}
|
|
729
730
|
function printPlan(ctx) {
|
|
730
731
|
const L = [];
|
|
731
|
-
L.push("mnemom
|
|
732
|
+
L.push("mnemom agent — launch plan (dry run)");
|
|
732
733
|
L.push(` scenario: ${ctx.scenario}`);
|
|
733
734
|
L.push(` cli: ${ctx.cli.name} (${ctx.cli.bin})`);
|
|
734
735
|
L.push(` shape: ${ctx.shape}`);
|
|
@@ -26,7 +26,7 @@ export interface AgentsClaimOptions {
|
|
|
26
26
|
*/
|
|
27
27
|
export declare function deriveHashProof(apiKey: string, agentName?: string): string;
|
|
28
28
|
/**
|
|
29
|
-
* `mnemom
|
|
29
|
+
* `mnemom agent claim <id-or-name> [--org <slug>] (--key <k> | --hash-proof <h>)`
|
|
30
30
|
*
|
|
31
31
|
* Claims an agent into an org (ADR-062). Possession of the agent's key (via
|
|
32
32
|
* `--key`, from which the CLI derives the proof) or a pre-computed
|
|
@@ -42,7 +42,7 @@ export interface AgentsMoveOptions {
|
|
|
42
42
|
json?: boolean;
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
* `mnemom
|
|
45
|
+
* `mnemom agent move <id-or-name> --to <slug|id>`
|
|
46
46
|
*
|
|
47
47
|
* Role-based relocation between orgs (the counterpart to re-claim, which is
|
|
48
48
|
* possession-based). The server requires the caller to be an owner/admin of
|
package/dist/commands/agents.js
CHANGED
|
@@ -121,7 +121,7 @@ function extractClaimableOrgs(details) {
|
|
|
121
121
|
return list.filter((o) => !!o && typeof o === "object" && typeof o.org_id === "string");
|
|
122
122
|
}
|
|
123
123
|
/**
|
|
124
|
-
* `mnemom
|
|
124
|
+
* `mnemom agent claim <id-or-name> [--org <slug>] (--key <k> | --hash-proof <h>)`
|
|
125
125
|
*
|
|
126
126
|
* Claims an agent into an org (ADR-062). Possession of the agent's key (via
|
|
127
127
|
* `--key`, from which the CLI derives the proof) or a pre-computed
|
|
@@ -148,7 +148,7 @@ export async function agentsClaimCommand(idOrName, options = {}) {
|
|
|
148
148
|
// The arg names an agent we can't see yet (unclaimed agents aren't in
|
|
149
149
|
// your fleet), so we have no id to address the claim — guide to the id.
|
|
150
150
|
console.log(fmt.error(`Could not resolve '${idOrName}' to an agent id you can see yet — unclaimed agents are not in your fleet.`));
|
|
151
|
-
console.log(fmt.dim(` Pass the agent id directly: mnemom
|
|
151
|
+
console.log(fmt.dim(` Pass the agent id directly: mnemom agent claim mnm-... --key <key> [--name ${idOrName}]`) + "\n");
|
|
152
152
|
process.exit(1);
|
|
153
153
|
return;
|
|
154
154
|
}
|
|
@@ -286,7 +286,7 @@ export async function agentsClaimCommand(idOrName, options = {}) {
|
|
|
286
286
|
console.log(fmt.error("Failed to claim agent: the --key (and agent name) didn't match the agent's stored proof (invalid hash proof)."));
|
|
287
287
|
console.log(fmt.dim(` Confirm --key is the exact provider key the agent runs with.\n` +
|
|
288
288
|
` If the name couldn't be auto-resolved from the id, pass it explicitly:\n` +
|
|
289
|
-
` mnemom
|
|
289
|
+
` mnemom agent claim ${agentId} --key <key> --name <provisioned-name>`) + "\n");
|
|
290
290
|
process.exit(1);
|
|
291
291
|
return;
|
|
292
292
|
}
|
|
@@ -335,7 +335,7 @@ export async function agentsClaimCommand(idOrName, options = {}) {
|
|
|
335
335
|
console.log();
|
|
336
336
|
}
|
|
337
337
|
/**
|
|
338
|
-
* `mnemom
|
|
338
|
+
* `mnemom agent move <id-or-name> --to <slug|id>`
|
|
339
339
|
*
|
|
340
340
|
* Role-based relocation between orgs (the counterpart to re-claim, which is
|
|
341
341
|
* possession-based). The server requires the caller to be an owner/admin of
|
|
@@ -400,7 +400,7 @@ export async function agentsMoveCommand(idOrName, options = {}) {
|
|
|
400
400
|
catch (err) {
|
|
401
401
|
if (err instanceof MnemomApiError && err.effectiveStatus === 403) {
|
|
402
402
|
console.log(fmt.error("Move denied: you must be an owner/admin of BOTH the agent's current org and the destination org.") + "\n");
|
|
403
|
-
console.log(fmt.dim(" Check your roles with `mnemom org list`. If you hold the agent's key instead, re-claim can move it: mnemom
|
|
403
|
+
console.log(fmt.dim(" Check your roles with `mnemom org list`. If you hold the agent's key instead, re-claim can move it: mnemom agent claim <id> --org <slug> --key <key>.") + "\n");
|
|
404
404
|
process.exit(1);
|
|
405
405
|
return;
|
|
406
406
|
}
|
package/dist/commands/onboard.js
CHANGED
|
@@ -262,7 +262,7 @@ async function claimIdentity(agentId, scannedName, options, result, json, steps,
|
|
|
262
262
|
if (status === 403 &&
|
|
263
263
|
(err.code === "invalid_hash_proof" || /hash[ _]?proof/i.test(err.message))) {
|
|
264
264
|
throw teachingClaimError(agentId, "the --key (and agent name) didn't match the agent's stored proof (invalid hash proof).", "Confirm --key is the exact provider key the agent runs with. If the name couldn't be " +
|
|
265
|
-
`auto-resolved, pass it via \`mnemom
|
|
265
|
+
`auto-resolved, pass it via \`mnemom agent claim ${agentId} --key <key> --name <name>\`.`, json, result, steps);
|
|
266
266
|
}
|
|
267
267
|
if (status === 403 && err.code === "agent_cross_tenant") {
|
|
268
268
|
throw teachingClaimError(agentId, "this agent is already claimed by a different owner.", "Onboard an agent you own, or provision a fresh one with `mnemom wrap`.", json, result, steps);
|
package/dist/commands/wrap.js
CHANGED
|
@@ -323,7 +323,7 @@ function renderClaimInstructions(agentId) {
|
|
|
323
323
|
"",
|
|
324
324
|
fmt.dim(" Claim this agent so you own its identity on the platform:"),
|
|
325
325
|
"",
|
|
326
|
-
` mnemom
|
|
326
|
+
` mnemom agent claim ${agentId}`,
|
|
327
327
|
"",
|
|
328
328
|
fmt.dim(" After claiming, traces appear in `mnemom logs`."),
|
|
329
329
|
];
|