@mnemom/mnemom 0.17.0-next.6 → 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} +13 -13
- package/dist/commands/{code-setup.js → agent-setup.js} +46 -42
- package/dist/commands/{code.d.ts → agent.d.ts} +14 -14
- package/dist/commands/{code.js → agent.js} +76 -76
- 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 +4 -4
- package/dist/lib/api.js +9 -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, resolveDefaultSlug, } 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
|
|
@@ -150,7 +150,7 @@ export async function codeCommand(scenarioArg, options = {}) {
|
|
|
150
150
|
}
|
|
151
151
|
// Now that a session exists, a defaulted slug uses the real login handle from
|
|
152
152
|
// /v1/auth/me (the stored token has no email, so the pre-sign-in value was the
|
|
153
|
-
// "
|
|
153
|
+
// "agent-user" fallback). Only when the caller didn't name an agent.
|
|
154
154
|
if (!options.agent?.trim()) {
|
|
155
155
|
const refreshed = sanitizeAgentName(await resolveDefaultSlug());
|
|
156
156
|
if (refreshed)
|
|
@@ -172,7 +172,7 @@ export async function codeCommand(scenarioArg, options = {}) {
|
|
|
172
172
|
}
|
|
173
173
|
catch (err) {
|
|
174
174
|
const msg = err instanceof Error ? err.message : String(err);
|
|
175
|
-
say(fmt.warn(`mnemom
|
|
175
|
+
say(fmt.warn(`mnemom agent: agent setup did not complete (${msg}) — launching with the unclaimed identity.`));
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
logLaunch({ shape, door, agent, conversationId, cellNote, envelope, cli });
|
|
@@ -210,8 +210,8 @@ export async function codeCommand(scenarioArg, options = {}) {
|
|
|
210
210
|
/**
|
|
211
211
|
* Resolve the Anthropic key with NO 1Password dependency (built for external
|
|
212
212
|
* customer adoption), in order:
|
|
213
|
-
* 1. env:
|
|
214
|
-
* 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`)
|
|
215
215
|
* 3. interactive prompt (masked), offering to save it to the store
|
|
216
216
|
* Never logged / printed. Throws with guidance when nothing resolves — we refuse
|
|
217
217
|
* to launch un-routed.
|
|
@@ -220,13 +220,13 @@ export async function resolveAnthropicKey(env, opts) {
|
|
|
220
220
|
const source = opts.keySource;
|
|
221
221
|
// "prompt" forces the interactive prompt (skips env + store).
|
|
222
222
|
if (source !== "prompt") {
|
|
223
|
-
const fromEnv = (env.
|
|
223
|
+
const fromEnv = (env.MNEMOM_AGENT_ANTHROPIC_KEY || env.ANTHROPIC_API_KEY || "").trim();
|
|
224
224
|
if (fromEnv)
|
|
225
225
|
return fromEnv;
|
|
226
226
|
// "env" restricts to env only — no store, no prompt.
|
|
227
227
|
if (source === "env") {
|
|
228
|
-
throw new Error("mnemom
|
|
229
|
-
" 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)");
|
|
230
230
|
}
|
|
231
231
|
const stored = readStoredKey();
|
|
232
232
|
if (stored)
|
|
@@ -234,28 +234,28 @@ export async function resolveAnthropicKey(env, opts) {
|
|
|
234
234
|
}
|
|
235
235
|
// (source can only be "store", "prompt", or undefined here — "env" threw above.)
|
|
236
236
|
if (opts.allowPrompt && isInteractive()) {
|
|
237
|
-
say("mnemom
|
|
237
|
+
say("mnemom agent: no Anthropic key in env (MNEMOM_AGENT_ANTHROPIC_KEY / ANTHROPIC_API_KEY) or ~/.mnemom/launcher.json.");
|
|
238
238
|
const entered = (await askInput("Enter your Anthropic API key (sk-ant-…):", true)).trim();
|
|
239
239
|
if (entered) {
|
|
240
|
-
if (await askYesNo("Save it to ~/.mnemom/
|
|
240
|
+
if (await askYesNo("Save it to ~/.mnemom/launcher.json (0600) for next time?", true)) {
|
|
241
241
|
storeKey(entered);
|
|
242
|
-
say("mnemom
|
|
242
|
+
say("mnemom agent: saved to ~/.mnemom/launcher.json.");
|
|
243
243
|
}
|
|
244
244
|
return entered;
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
|
-
throw new Error("mnemom
|
|
248
|
-
" Set one: export
|
|
249
|
-
" Or save it: run `mnemom
|
|
250
|
-
" (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).");
|
|
251
251
|
}
|
|
252
252
|
/**
|
|
253
253
|
* Where an Anthropic key would resolve from RIGHT NOW, without reading its value:
|
|
254
|
-
* "env" (
|
|
255
|
-
* 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`.
|
|
256
256
|
*/
|
|
257
257
|
export function anthropicKeySource(env = process.env) {
|
|
258
|
-
if ((env.
|
|
258
|
+
if ((env.MNEMOM_AGENT_ANTHROPIC_KEY || env.ANTHROPIC_API_KEY || "").trim())
|
|
259
259
|
return "env";
|
|
260
260
|
if (readStoredKey())
|
|
261
261
|
return "store";
|
|
@@ -272,7 +272,7 @@ function readStoredKey() {
|
|
|
272
272
|
return undefined;
|
|
273
273
|
}
|
|
274
274
|
}
|
|
275
|
-
/** Persist the provider key to ~/.mnemom/
|
|
275
|
+
/** Persist the provider key to ~/.mnemom/launcher.json at 0600 (atomic). Best-effort. */
|
|
276
276
|
function storeKey(key) {
|
|
277
277
|
try {
|
|
278
278
|
mkdirSync(MNEMOM_DIR, { recursive: true });
|
|
@@ -285,7 +285,7 @@ function storeKey(key) {
|
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
287
|
/**
|
|
288
|
-
* Resolve which coding-agent CLI to launch. `--cli` (or
|
|
288
|
+
* Resolve which coding-agent CLI to launch. `--cli` (or MNEMOM_AGENT_CLI) is a
|
|
289
289
|
* name or a full path; default "claude". A value with a path separator is used
|
|
290
290
|
* verbatim (must exist); a bare name is resolved on PATH, then — for claude — the
|
|
291
291
|
* fnm/nvm/asdf install dirs (a version-manager shim / shell function is absent in
|
|
@@ -293,12 +293,12 @@ function storeKey(key) {
|
|
|
293
293
|
* a non-claude executable is launched through it with a warning.
|
|
294
294
|
*/
|
|
295
295
|
export function resolveCliBin(cliOpt, env) {
|
|
296
|
-
const requested = (cliOpt || env.
|
|
296
|
+
const requested = (cliOpt || env.MNEMOM_AGENT_CLI || "claude").trim();
|
|
297
297
|
const name = basename(requested);
|
|
298
298
|
if (requested.includes("/")) {
|
|
299
299
|
if (existsSync(requested))
|
|
300
300
|
return { bin: requested, name };
|
|
301
|
-
throw new Error(`mnemom
|
|
301
|
+
throw new Error(`mnemom agent: --cli path '${requested}' not found.`);
|
|
302
302
|
}
|
|
303
303
|
for (const dir of (env.PATH || "").split(":")) {
|
|
304
304
|
// Skip ephemeral cmux CLI shims: they only work inside a cmux session and,
|
|
@@ -334,10 +334,10 @@ export function resolveCliBin(cliOpt, env) {
|
|
|
334
334
|
}
|
|
335
335
|
}
|
|
336
336
|
}
|
|
337
|
-
throw new Error(`mnemom
|
|
337
|
+
throw new Error(`mnemom agent: coding-agent CLI '${requested}' not found.\n` +
|
|
338
338
|
" Looked on $PATH" +
|
|
339
339
|
(name === "claude" ? " and in the fnm/nvm/asdf node dirs" : "") +
|
|
340
|
-
".\n Pass --cli <name|/full/path> or set
|
|
340
|
+
".\n Pass --cli <name|/full/path> or set MNEMOM_AGENT_CLI.");
|
|
341
341
|
}
|
|
342
342
|
export /**
|
|
343
343
|
* Recover when the coding-agent CLI can't be found — a good experience beats a
|
|
@@ -346,11 +346,11 @@ export /**
|
|
|
346
346
|
* so they never retype it). A non-interactive session re-throws the clear,
|
|
347
347
|
* actionable error rather than hanging on a prompt.
|
|
348
348
|
*/ async function promptForCliPath(cliOpt, env, origErr) {
|
|
349
|
-
const requested = (cliOpt || env.
|
|
349
|
+
const requested = (cliOpt || env.MNEMOM_AGENT_CLI || "claude").trim();
|
|
350
350
|
if (!isInteractive()) {
|
|
351
|
-
throw origErr ?? new Error(`mnemom
|
|
351
|
+
throw origErr ?? new Error(`mnemom agent: coding-agent CLI '${requested}' not found.`);
|
|
352
352
|
}
|
|
353
|
-
say(`mnemom
|
|
353
|
+
say(`mnemom agent: couldn't find the '${requested}' CLI on your PATH.`);
|
|
354
354
|
if (requested === "claude") {
|
|
355
355
|
say(" If Claude Code is installed, paste its full path (find it with: which claude).");
|
|
356
356
|
say(" Not installed yet? Get it at https://claude.com/claude-code, then re-run.");
|
|
@@ -361,9 +361,9 @@ export /**
|
|
|
361
361
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
362
362
|
const entered = (await askInput("Path to your coding-agent CLI (Enter to cancel):")).trim();
|
|
363
363
|
if (!entered) {
|
|
364
|
-
throw new Error("mnemom
|
|
364
|
+
throw new Error("mnemom agent: no coding-agent CLI available.\n" +
|
|
365
365
|
" Install Claude Code (https://claude.com/claude-code), or pass --cli <path> " +
|
|
366
|
-
"(or save it: mnemom
|
|
366
|
+
"(or save it: mnemom agent config set cli <path>).");
|
|
367
367
|
}
|
|
368
368
|
if (!existsSync(entered)) {
|
|
369
369
|
say(` '${entered}' doesn't exist — try again.`);
|
|
@@ -371,9 +371,9 @@ export /**
|
|
|
371
371
|
}
|
|
372
372
|
if (await askYesNo("Save this as your default CLI so you don't retype it?", true)) {
|
|
373
373
|
try {
|
|
374
|
-
const cfg =
|
|
374
|
+
const cfg = loadLauncherConfig();
|
|
375
375
|
configKeySpec("cli").set(cfg, entered);
|
|
376
|
-
|
|
376
|
+
writeLauncherConfig(cfg);
|
|
377
377
|
say(" Saved — future launches will use it.");
|
|
378
378
|
}
|
|
379
379
|
catch {
|
|
@@ -382,7 +382,7 @@ export /**
|
|
|
382
382
|
}
|
|
383
383
|
return { bin: entered, name: basename(entered) };
|
|
384
384
|
}
|
|
385
|
-
throw new Error("mnemom
|
|
385
|
+
throw new Error("mnemom agent: couldn't resolve a coding-agent CLI path — pass --cli <path>.");
|
|
386
386
|
}
|
|
387
387
|
function commandExists(cmd) {
|
|
388
388
|
const res = spawnSync("sh", ["-c", `command -v "$1" >/dev/null 2>&1`, "sh", cmd], {
|
|
@@ -408,7 +408,7 @@ export function cliSupportsRemoteControl(bin) {
|
|
|
408
408
|
/**
|
|
409
409
|
* Can we launch the DEFAULT Remote-Control-in-terminal shape on this machine?
|
|
410
410
|
* Needs node + openssl (the local proxy mints an ephemeral CA) and a claude
|
|
411
|
-
* adapter that advertises `--remote-control`. Used both by `mnemom
|
|
411
|
+
* adapter that advertises `--remote-control`. Used both by `mnemom agent doctor`
|
|
412
412
|
* and by the auto-default selection (a bare launch prefers RC when capable).
|
|
413
413
|
*/
|
|
414
414
|
export function checkRcCapability(cli) {
|
|
@@ -429,7 +429,7 @@ export function checkRcCapability(cli) {
|
|
|
429
429
|
/** Warn once when a non-claude executable rides the v1 Claude Code adapter. */
|
|
430
430
|
function warnAdapter(cli) {
|
|
431
431
|
if (cli.name !== "claude") {
|
|
432
|
-
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.`);
|
|
433
433
|
}
|
|
434
434
|
}
|
|
435
435
|
// ───────────────────────────────────────────────────────────────────────────
|
|
@@ -459,7 +459,7 @@ function launchTerminal(ctx) {
|
|
|
459
459
|
}
|
|
460
460
|
const child = spawn(ctx.cli.bin, args, { stdio: "inherit", env: childEnv });
|
|
461
461
|
child.on("error", (err) => {
|
|
462
|
-
say(`mnemom
|
|
462
|
+
say(`mnemom agent: failed to launch ${ctx.cli.name}: ${err.message}`);
|
|
463
463
|
process.exit(1);
|
|
464
464
|
});
|
|
465
465
|
child.on("exit", (code, signal) => {
|
|
@@ -476,21 +476,21 @@ function launchRemoteControl(ctx) {
|
|
|
476
476
|
warnAdapter(ctx.cli);
|
|
477
477
|
for (const tool of ["node", "openssl"]) {
|
|
478
478
|
if (!commandExists(tool)) {
|
|
479
|
-
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).`);
|
|
480
480
|
}
|
|
481
481
|
}
|
|
482
482
|
const proxyScript = resolveProxyScript();
|
|
483
483
|
const rcDir = mkdtempSync(join(tmpdir(), "mnemom-code-rc."));
|
|
484
|
-
const proxyLog = process.env.
|
|
484
|
+
const proxyLog = process.env.MNEMOM_AGENT_RC_PROXY_LOG || join(rcDir, "proxy.log");
|
|
485
485
|
const proxy = spawn("node", [proxyScript], {
|
|
486
486
|
env: {
|
|
487
487
|
...process.env,
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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),
|
|
494
494
|
},
|
|
495
495
|
stdio: ["pipe", "pipe", "inherit"],
|
|
496
496
|
});
|
|
@@ -526,7 +526,7 @@ function launchRemoteControl(ctx) {
|
|
|
526
526
|
const port = m[1];
|
|
527
527
|
const ca = m[2].trim();
|
|
528
528
|
if (!existsSync(ca)) {
|
|
529
|
-
say("mnemom
|
|
529
|
+
say("mnemom agent: malformed READY line from the Remote Control proxy.");
|
|
530
530
|
onExit();
|
|
531
531
|
process.exit(1);
|
|
532
532
|
}
|
|
@@ -534,13 +534,13 @@ function launchRemoteControl(ctx) {
|
|
|
534
534
|
return;
|
|
535
535
|
}
|
|
536
536
|
if (proxy.exitCode !== null) {
|
|
537
|
-
say("mnemom
|
|
537
|
+
say("mnemom agent: the Remote Control proxy exited before it was ready — refusing to launch un-routed.");
|
|
538
538
|
redactedProxyLog(proxyLog);
|
|
539
539
|
onExit();
|
|
540
540
|
process.exit(1);
|
|
541
541
|
}
|
|
542
542
|
if (Date.now() - start > 15_000) {
|
|
543
|
-
say("mnemom
|
|
543
|
+
say("mnemom agent: the Remote Control proxy did not report READY within 15s.");
|
|
544
544
|
onExit();
|
|
545
545
|
process.exit(1);
|
|
546
546
|
}
|
|
@@ -550,7 +550,7 @@ function launchRemoteControl(ctx) {
|
|
|
550
550
|
stdoutBuf += chunk.toString("utf8");
|
|
551
551
|
});
|
|
552
552
|
proxy.on("error", (err) => {
|
|
553
|
-
say(`mnemom
|
|
553
|
+
say(`mnemom agent: failed to launch the Remote Control proxy: ${err.message}`);
|
|
554
554
|
onExit();
|
|
555
555
|
process.exit(1);
|
|
556
556
|
});
|
|
@@ -602,7 +602,7 @@ function spawnRcCli(ctx) {
|
|
|
602
602
|
if (ctx.options.model)
|
|
603
603
|
childEnv.ANTHROPIC_MODEL = ctx.options.model;
|
|
604
604
|
args = ["remote-control", "--name", rcName, ...passthrough];
|
|
605
|
-
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.`);
|
|
606
606
|
}
|
|
607
607
|
else {
|
|
608
608
|
// Interactive RC in THIS terminal: the CLI's own `--remote-control <name>`
|
|
@@ -610,11 +610,11 @@ function spawnRcCli(ctx) {
|
|
|
610
610
|
// buildCliArgs already includes the (name-stripped) passthrough.
|
|
611
611
|
const flagArgs = buildCliArgs(scopedOptions, { yolo: ctx.yolo, allowCliFlags: true });
|
|
612
612
|
args = ["--remote-control", rcName, ...flagArgs];
|
|
613
|
-
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.`);
|
|
614
614
|
}
|
|
615
615
|
const child = spawn(ctx.cli.bin, args, { stdio: "inherit", env: childEnv });
|
|
616
616
|
child.on("error", (err) => {
|
|
617
|
-
say(`mnemom
|
|
617
|
+
say(`mnemom agent: failed to launch ${ctx.cli.name} under Remote Control: ${err.message}`);
|
|
618
618
|
ctx.onExit();
|
|
619
619
|
process.exit(1);
|
|
620
620
|
});
|
|
@@ -628,20 +628,20 @@ function spawnRcCli(ctx) {
|
|
|
628
628
|
}
|
|
629
629
|
function warnServerDrops(options, yolo) {
|
|
630
630
|
if (options.effort) {
|
|
631
|
-
say("mnemom
|
|
631
|
+
say("mnemom agent: --effort is not applied under --server (set it from the session instead).");
|
|
632
632
|
}
|
|
633
633
|
if (options.trimMcp) {
|
|
634
|
-
say("mnemom
|
|
634
|
+
say("mnemom agent: --trim-mcp is not applied under --server (sessions load the full MCP set).");
|
|
635
635
|
}
|
|
636
636
|
if (yolo) {
|
|
637
|
-
say("mnemom
|
|
637
|
+
say("mnemom agent: yolo (--dangerously-skip-permissions) is not applied under --server; set permissions from the driven sessions.");
|
|
638
638
|
}
|
|
639
639
|
}
|
|
640
640
|
function resolveProxyScript() {
|
|
641
641
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
642
642
|
const cand = join(here, "..", "rc-proxy.mjs");
|
|
643
643
|
if (!existsSync(cand)) {
|
|
644
|
-
throw new Error(`mnemom
|
|
644
|
+
throw new Error(`mnemom agent: the Remote Control proxy is missing (expected ${cand}). Reinstall the CLI.`);
|
|
645
645
|
}
|
|
646
646
|
return cand;
|
|
647
647
|
}
|
|
@@ -721,15 +721,15 @@ function seedContextHintFlag(childEnv) {
|
|
|
721
721
|
// Human-facing logging (never prints the key)
|
|
722
722
|
// ───────────────────────────────────────────────────────────────────────────
|
|
723
723
|
function logLaunch(ctx) {
|
|
724
|
-
say(`mnemom
|
|
724
|
+
say(`mnemom agent: routing ${ctx.cli.name} through ${ctx.door} [${ctx.cellNote}] as '${ctx.agent}' (conversation ${ctx.conversationId}).`);
|
|
725
725
|
if (ctx.envelope) {
|
|
726
|
-
say(`mnemom
|
|
727
|
-
say(`mnemom
|
|
726
|
+
say(`mnemom agent: contract statement: ${ctx.envelope.contract.statement}`);
|
|
727
|
+
say(`mnemom agent: contract sha256[0:16]: ${ctx.envelope.sha}`);
|
|
728
728
|
}
|
|
729
729
|
}
|
|
730
730
|
function printPlan(ctx) {
|
|
731
731
|
const L = [];
|
|
732
|
-
L.push("mnemom
|
|
732
|
+
L.push("mnemom agent — launch plan (dry run)");
|
|
733
733
|
L.push(` scenario: ${ctx.scenario}`);
|
|
734
734
|
L.push(` cli: ${ctx.cli.name} (${ctx.cli.bin})`);
|
|
735
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
|
];
|