@mnemom/mnemom 0.16.2 → 0.17.0-next.0

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.
Files changed (48) hide show
  1. package/README.md +1 -0
  2. package/dist/commands/agents.d.ts +14 -0
  3. package/dist/commands/agents.js +100 -2
  4. package/dist/commands/card.d.ts +43 -0
  5. package/dist/commands/card.js +153 -102
  6. package/dist/commands/code-config.d.ts +17 -0
  7. package/dist/commands/code-config.js +147 -0
  8. package/dist/commands/code-doctor.d.ts +18 -0
  9. package/dist/commands/code-doctor.js +138 -0
  10. package/dist/commands/code-setup.d.ts +97 -0
  11. package/dist/commands/code-setup.js +330 -0
  12. package/dist/commands/code.d.ts +133 -0
  13. package/dist/commands/code.js +661 -0
  14. package/dist/commands/logs.js +11 -1
  15. package/dist/commands/onboard.d.ts +59 -0
  16. package/dist/commands/onboard.js +395 -0
  17. package/dist/commands/org.d.ts +13 -0
  18. package/dist/commands/org.js +63 -2
  19. package/dist/commands/protection.d.ts +10 -0
  20. package/dist/commands/protection.js +109 -0
  21. package/dist/commands/status.js +5 -0
  22. package/dist/commands/try-me.js +9 -0
  23. package/dist/commands/usage.d.ts +35 -0
  24. package/dist/commands/usage.js +265 -0
  25. package/dist/commands/wrap.d.ts +28 -0
  26. package/dist/commands/wrap.js +331 -0
  27. package/dist/index.js +315 -7
  28. package/dist/lib/agent-config.d.ts +27 -0
  29. package/dist/lib/agent-config.js +86 -0
  30. package/dist/lib/api.d.ts +139 -1
  31. package/dist/lib/api.js +132 -183
  32. package/dist/lib/cli-config.d.ts +33 -0
  33. package/dist/lib/cli-config.js +70 -0
  34. package/dist/lib/code-config.d.ts +78 -0
  35. package/dist/lib/code-config.js +281 -0
  36. package/dist/lib/code.d.ts +154 -0
  37. package/dist/lib/code.js +252 -0
  38. package/dist/lib/config.d.ts +10 -0
  39. package/dist/lib/config.js +39 -3
  40. package/dist/lib/keyed-identity.d.ts +35 -0
  41. package/dist/lib/keyed-identity.js +363 -0
  42. package/dist/lib/protection-drift.d.ts +117 -0
  43. package/dist/lib/protection-drift.js +180 -0
  44. package/dist/lib/skills.js +25 -12
  45. package/dist/lib/version-gate.d.ts +37 -0
  46. package/dist/lib/version-gate.js +84 -0
  47. package/dist/rc-proxy.mjs +341 -0
  48. package/package.json +9 -7
@@ -0,0 +1,330 @@
1
+ /**
2
+ * `mnemom code setup` + the zero-friction provisioning behind a bare
3
+ * `mnemom code <scenario>`.
4
+ *
5
+ * If a customer names no agent, `mnemom code` launches under a per-customer
6
+ * governed identity `code-<handle>`. This module makes that identity REAL in
7
+ * their Mnemom org: it births the agent through the gateway, claims it (so the
8
+ * customer owns it), and publishes a sane default coding posture — nudge/nudge:
9
+ * - alignment card: autonomy_mode + integrity_mode = nudge,
10
+ * principal.relationship = delegated_authority, coding bounded/forbidden
11
+ * actions, escalate-on-irreversible;
12
+ * - protection card: mode = nudge, thresholds 0.60/0.80/0.95, all four
13
+ * screen_surfaces on.
14
+ *
15
+ * All account writes are gated: interactive runs show the plan and confirm;
16
+ * non-interactive runs provision only with an explicit `--setup`, and otherwise
17
+ * launch under the unclaimed (fail-open) identity with a clear warning. A
18
+ * provisioning failure never blocks the launch. Reuses the existing machinery —
19
+ * birthThroughGateway (wrap.ts), deriveHashProof (agents.ts), claimAgent +
20
+ * putAlignmentCard/putProtectionCard (lib/api.ts) — rather than reinventing it.
21
+ */
22
+ import { claimAgent, getAgentByName, getMuBalance, getMyPersonalOrg, MnemomApiError, putAlignmentCard, putProtectionCard, } from "../lib/api.js";
23
+ import { getAuthInfo, isLoggedIn, loginWithBrowser, loginWithDeviceFlow, resolveAuth, } from "../lib/auth.js";
24
+ import { getActiveOrg } from "../lib/cli-config.js";
25
+ import { getWebsiteUrl } from "../lib/config.js";
26
+ import { fmt } from "../lib/format.js";
27
+ import { askYesNo, isInteractive } from "../lib/prompt.js";
28
+ import { resolveGatewayHost, sanitizeAgentName } from "../lib/code.js";
29
+ import { configKeySpec, loadCodeConfig, writeCodeConfig } from "../lib/code-config.js";
30
+ import { deriveHashProof } from "./agents.js";
31
+ import { birthThroughGateway } from "./wrap.js";
32
+ import { resolveAnthropicKey } from "./code.js";
33
+ const say = (line = "") => console.error(line);
34
+ /**
35
+ * The default governed-agent slug for the current customer: `code-<handle>`,
36
+ * where <handle> is the local-part of their mnemom login email (sanitised), or
37
+ * "user" when no email is available (API-key auth / opaque OAuth token).
38
+ */
39
+ export function defaultAgentSlug() {
40
+ const email = getAuthInfo()?.email ?? "";
41
+ const local = email.split("@")[0] ?? "";
42
+ const handle = sanitizeAgentName(local) || "user";
43
+ return `code-${handle}`;
44
+ }
45
+ /**
46
+ * Ensure `slug` is a usable governed agent in the customer's org. Returns
47
+ * {provisioned:false} when it is already usable, when provisioning is not
48
+ * allowed here (non-interactive without --setup, or not logged in), or when the
49
+ * customer declines the confirm — in all those cases the launch continues under
50
+ * the given slug. THROWS only on an actual provisioning failure (birth/claim/
51
+ * card write) so the caller can decide whether that is fatal (`mnemom code
52
+ * setup`) or a warn-and-continue (a bare launch).
53
+ */
54
+ export async function ensureGovernedAgent(opts) {
55
+ const slug = opts.slug;
56
+ const interactive = opts.interactive ?? isInteractive();
57
+ // 1. Already usable? A named agent in the caller's fleet is claimed by them.
58
+ const loggedIn = await isLoggedIn();
59
+ if (loggedIn) {
60
+ const existing = await getAgentByName(slug).catch(() => null);
61
+ if (existing)
62
+ return { slug, provisioned: false };
63
+ }
64
+ // 2. Are we allowed to provision here?
65
+ const canProvision = opts.setup === true || (opts.setup !== false && interactive);
66
+ if (!canProvision) {
67
+ warnUnclaimed(slug);
68
+ return { slug, provisioned: false };
69
+ }
70
+ // 3. Writing to the org needs a mnemom session.
71
+ if (!loggedIn) {
72
+ if (opts.setup === true && !interactive) {
73
+ throw new Error("not authenticated — run `mnemom login` (or set MNEMOM_API_KEY) first.");
74
+ }
75
+ say(fmt.warn(`mnemom code: not logged in — can't provision '${slug}'.`));
76
+ say(fmt.dim(" Run `mnemom login`, then `mnemom code setup`. Launching with the unclaimed identity for now."));
77
+ return { slug, provisioned: false };
78
+ }
79
+ // 4. Confirm the plan (interactive runs; --setup non-interactive proceeds).
80
+ const org = getActiveOrg();
81
+ const orgLabel = org ? `${org.name} (${org.slug})` : "your personal org";
82
+ if (interactive) {
83
+ say(fmt.section("Set up a governed coding agent"));
84
+ say(fmt.label(" Agent:", slug));
85
+ say(fmt.label(" Org:", orgLabel));
86
+ say(fmt.label(" Posture:", "nudge / nudge (alignment: autonomy + integrity nudge; protection: all surfaces screened)"));
87
+ say(fmt.dim(" Births the agent through the gateway, claims it to your org, and publishes its cards."));
88
+ if (!(await askYesNo("Provision and claim this agent now?", true))) {
89
+ say(fmt.dim(" Skipped — launching under the unclaimed identity. Run `mnemom code setup` anytime."));
90
+ return { slug, provisioned: false };
91
+ }
92
+ }
93
+ // 5. Birth → claim → publish nudge/nudge cards. (Key never logged.)
94
+ const gatewayUrl = opts.gatewayHost.replace(/\/+$/, "");
95
+ const agentId = await birthThroughGateway(gatewayUrl, "anthropic", slug, opts.anthropicKey);
96
+ const hashProof = deriveHashProof(opts.anthropicKey, slug);
97
+ await claimAgent(agentId, { hashProof, orgId: org?.org_id });
98
+ await putAlignmentCard(agentId, JSON.stringify(buildCodeAlignmentCard(agentId)), "application/json");
99
+ await putProtectionCard(agentId, JSON.stringify(buildCodeProtectionCard(agentId)), "application/json");
100
+ say(fmt.success(`mnemom code: provisioned + claimed '${slug}' (${agentId}) in ${orgLabel} — nudge/nudge posture published.`));
101
+ // 6. Remember the slug so future launches skip straight to usable.
102
+ persistAgentSlug(slug);
103
+ return { slug, provisioned: true };
104
+ }
105
+ /** `mnemom code setup [--agent <slug>]` — the explicit provisioning entry point. */
106
+ export async function codeSetupCommand(opts = {}) {
107
+ const gatewayHost = resolveGatewayHost(process.env);
108
+ // Sign in (offer sign-up) and enforce the MU balance before any account write.
109
+ try {
110
+ await ensureSessionAndBalance({});
111
+ }
112
+ catch (err) {
113
+ if (err instanceof MuInsufficientError)
114
+ process.exit(1);
115
+ throw err;
116
+ }
117
+ const anthropicKey = await resolveAnthropicKey(process.env, { allowPrompt: true });
118
+ const slug = opts.agent?.trim() ? sanitizeAgentName(opts.agent.trim()) : defaultAgentSlug();
119
+ if (!slug)
120
+ throw new Error("mnemom code setup: agent slug sanitised to empty — pass --agent <slug>.");
121
+ const result = await ensureGovernedAgent({ slug, anthropicKey, setup: true, gatewayHost });
122
+ if (!result.provisioned) {
123
+ say(fmt.dim(` '${slug}' is ready (already claimed) or setup was skipped.`));
124
+ }
125
+ }
126
+ function warnUnclaimed(slug) {
127
+ say(fmt.warn(`mnemom code: agent '${slug}' is not set up in your org — launching with an UNCLAIMED identity (governance is advisory/fail-open).`));
128
+ say(fmt.dim(" Provision it (creates + claims the agent, publishes nudge/nudge cards): mnemom code setup"));
129
+ }
130
+ function persistAgentSlug(slug) {
131
+ try {
132
+ const cfg = loadCodeConfig();
133
+ if (!cfg.agent) {
134
+ configKeySpec("agent").set(cfg, slug);
135
+ writeCodeConfig(cfg);
136
+ }
137
+ }
138
+ catch {
139
+ // best effort — provisioning already succeeded either way
140
+ }
141
+ }
142
+ // ── Session (login/sign-up, the try-me flow) + MU balance gate ──────────────
143
+ /** Thrown when the agent's org has no spendable MU balance. The user-facing
144
+ * top-up guidance is already printed when this is thrown — callers exit quietly. */
145
+ export class MuInsufficientError extends Error {
146
+ orgLabel;
147
+ constructor(orgLabel) {
148
+ super("insufficient MU balance");
149
+ this.orgLabel = orgLabel;
150
+ this.name = "MuInsufficientError";
151
+ }
152
+ }
153
+ /** Best-effort detection of a headless/SSH box where a browser can't open. */
154
+ function headlessEnv() {
155
+ const e = process.env;
156
+ if (e.SSH_CONNECTION || e.SSH_TTY)
157
+ return true;
158
+ if (process.platform === "linux" && !e.DISPLAY && !e.WAYLAND_DISPLAY)
159
+ return true;
160
+ return false;
161
+ }
162
+ /**
163
+ * Ensure the customer has a Mnemom session, the way `mnemom try-me` does: if
164
+ * they are not signed in, offer a one-click browser sign-in (device-flow
165
+ * fallback for headless/SSH boxes), mentioning that a free account can be
166
+ * created in the same flow. Returns true if a session exists (or was just
167
+ * created), false if the customer declined or the run is non-interactive.
168
+ * Idempotent — a no-op when already authenticated.
169
+ */
170
+ export async function ensureMnemomSession(opts = {}) {
171
+ const cred = await resolveAuth();
172
+ if (cred.type !== "none")
173
+ return true; // already a jwt or api-key session
174
+ const interactive = opts.interactive ?? isInteractive();
175
+ if (!interactive)
176
+ return false;
177
+ say(fmt.section("Sign in to Mnemom"));
178
+ say(fmt.dim(" mnemom code runs your coding session governed and under your Mnemom account,"));
179
+ say(fmt.dim(" so it shows up in your traces and bills to your org's Mnemom Units."));
180
+ say(fmt.dim(` New to Mnemom? You can create a free account in the same flow (or at ${getWebsiteUrl()}/signup).`));
181
+ if (!(await askYesNo("Sign in or create your account now?", true)))
182
+ return false;
183
+ const device = headlessEnv();
184
+ try {
185
+ if (device)
186
+ await loginWithDeviceFlow();
187
+ else
188
+ await loginWithBrowser();
189
+ }
190
+ catch (err) {
191
+ if (!device) {
192
+ say(fmt.dim(" Browser sign-in didn't work here — falling back to a device code…"));
193
+ await loginWithDeviceFlow();
194
+ }
195
+ else {
196
+ throw err;
197
+ }
198
+ }
199
+ say(fmt.success("Signed in to Mnemom."));
200
+ return true;
201
+ }
202
+ /**
203
+ * Enforce a positive Mnemom Units balance on the org the agent lives in.
204
+ * `mnemom code` has NO free tier — a determined zero/negative balance (or an org
205
+ * with no billing account) is BLOCKED with a portal-style top-up message.
206
+ * Fails OPEN on an inconclusive error (transient 5xx / network / 403), since the
207
+ * gateway is the real enforcement and this is a friendly pre-check; hard-blocks
208
+ * only on a determined depletion. Requires a session (caller ensures one first).
209
+ */
210
+ export async function assertMuBalance(orgId, orgLabel) {
211
+ let bal;
212
+ try {
213
+ bal = await getMuBalance(orgId);
214
+ }
215
+ catch (err) {
216
+ if (err instanceof MnemomApiError && err.status === 409) {
217
+ // Org has no billing account ⇒ no MUs. Block.
218
+ printTopUp(orgLabel, "0");
219
+ throw new MuInsufficientError(orgLabel);
220
+ }
221
+ // Inconclusive — don't lock out a paying customer on a transient failure.
222
+ say(fmt.dim(` (Could not verify your MU balance — ${err instanceof Error ? err.message : String(err)}. Continuing.)`));
223
+ return;
224
+ }
225
+ const available = safeBigInt(bal.balanceMmu) - safeBigInt(bal.activeHoldsMmu);
226
+ if (available <= 0n) {
227
+ printTopUp(orgLabel, bal.balanceMu ?? "0");
228
+ throw new MuInsufficientError(orgLabel);
229
+ }
230
+ }
231
+ function safeBigInt(v) {
232
+ try {
233
+ return BigInt(String(v ?? "0").trim().split(".")[0] || "0");
234
+ }
235
+ catch {
236
+ return 0n;
237
+ }
238
+ }
239
+ /**
240
+ * The "you need Mnemom Units" message (no free tier). Voiced like the portal's
241
+ * enforcement-paused banner — safety features can't run without µ — but never
242
+ * says "exhausted" (that assumes a prior balance; a new org may simply have none).
243
+ */
244
+ function printTopUp(orgLabel, balanceMu) {
245
+ say();
246
+ say(fmt.warn(`No Mnemom Units — ${orgLabel} has a balance of ${balanceMu} µ.`));
247
+ say(fmt.dim(" mnemom code runs on Mnemom Units (µ), and there's no free tier. Without µ,"));
248
+ say(fmt.dim(" Mnemom's safety features can't run, so the launch is blocked. Top up to launch"));
249
+ say(fmt.dim(" a governed session:"));
250
+ say();
251
+ say(` Top up µ: ${getWebsiteUrl()}/settings/billing`);
252
+ say(fmt.dim(" If you don't manage billing for this org, ask an admin to top up."));
253
+ say();
254
+ say(fmt.dim(" Your balance updates the moment a top-up completes — then re-run `mnemom code`."));
255
+ }
256
+ /**
257
+ * The shared pre-launch preamble for `mnemom code` (and `mnemom code setup`):
258
+ * ensure a Mnemom session (login/sign-up), then enforce the MU balance on the
259
+ * org the agent lives in (default: the user's personal org). Returns the
260
+ * resolved org so the caller can reuse it. Throws with clear guidance when there
261
+ * is no session, or MuInsufficientError (message already printed) on zero MUs.
262
+ */
263
+ export async function ensureSessionAndBalance(opts) {
264
+ const interactive = opts.interactive ?? isInteractive();
265
+ const haveSession = await ensureMnemomSession({ interactive });
266
+ if (!haveSession) {
267
+ throw new Error("mnemom code needs a Mnemom account — it runs your coding session governed and on Mnemom Units.\n" +
268
+ " Sign in: mnemom login (or set MNEMOM_API_KEY)\n" +
269
+ ` New here? create a free account, then add MUs: ${getWebsiteUrl()}/settings/billing`);
270
+ }
271
+ const active = getActiveOrg();
272
+ const orgId = active?.org_id ?? (await getMyPersonalOrg()).org_id;
273
+ const orgLabel = active ? `${active.name} (${active.slug})` : "your personal org";
274
+ await assertMuBalance(orgId, orgLabel);
275
+ return { orgId, orgLabel };
276
+ }
277
+ // ── The default coding posture (nudge/nudge) ────────────────────────────────
278
+ function buildCodeAlignmentCard(agentId) {
279
+ return {
280
+ card_version: "unified/2026-04-26",
281
+ agent_id: agentId,
282
+ autonomy_mode: "nudge",
283
+ integrity_mode: "nudge",
284
+ principal: { type: "agent", identifier: agentId, relationship: "delegated_authority" },
285
+ values: {
286
+ declared: ["transparency", "safety", "honesty", "user_control", "harm_prevention"],
287
+ },
288
+ autonomy: {
289
+ bounded_actions: [
290
+ "read_files",
291
+ "search_code",
292
+ "edit_files",
293
+ "run_commands",
294
+ "fetch_web_content",
295
+ "use_developer_tools",
296
+ ],
297
+ forbidden_actions: [
298
+ "push_to_main",
299
+ "force_push",
300
+ "delete_remote_branches",
301
+ "trigger_production_deploy",
302
+ "exfiltrate_credentials",
303
+ "modify_ci_secrets",
304
+ ],
305
+ escalation_triggers: [
306
+ {
307
+ condition: "an irreversible or destructive operation is requested",
308
+ action: "escalate",
309
+ reason: "a human should confirm before irreversible changes",
310
+ },
311
+ ],
312
+ },
313
+ audit: { retention_days: 30, queryable: false, trace_format: "otel" },
314
+ };
315
+ }
316
+ function buildCodeProtectionCard(agentId) {
317
+ return {
318
+ card_version: "protection/2026-04-26",
319
+ agent_id: agentId,
320
+ mode: "nudge",
321
+ thresholds: { warn: 0.6, quarantine: 0.8, block: 0.95 },
322
+ screen_surfaces: {
323
+ incoming: true,
324
+ outgoing: true,
325
+ tool_calls: true,
326
+ tool_responses: true,
327
+ },
328
+ trusted_sources: { domains: [], agent_ids: [], ip_ranges: [] },
329
+ };
330
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * `mnemom code <scenario>` — the CLI's first-class governed-coding-agent launcher.
3
+ *
4
+ * Launches your coding-agent CLI (Claude Code in v1) with its dev-time model
5
+ * traffic routed through the Mnemom gateway's /anthropic door for observability +
6
+ * governance, under a governed agent identity and an optional per-conversation
7
+ * CONTRACT the gateway seals on the first turn.
8
+ *
9
+ * v1 scope:
10
+ * - The Claude Code launch adapter (Anthropic /anthropic door; Anthropic-only,
11
+ * no router door / Mnemom key). `--cli` selects the executable to run (name or
12
+ * full path) so codex/cursor/github adapters can be added later.
13
+ * - The us-2/PROD gateway is the DEFAULT door (https://gateway.mnemom.ai); an
14
+ * explicit MNEMOM_CODE_GATEWAY / --gateway still wins, never silently prod.
15
+ * - Three launch shapes: `terminal` (DEFAULT), `remote-control` (interactive RC
16
+ * in this terminal), `server` (headless RC dispatcher). RC runs the CLI
17
+ * UNTOUCHED behind a bundled local TLS proxy (rc-proxy.mjs) — Claude Code
18
+ * gates RC on a first-party claude.ai-OAuth setup, so the gateway door cannot
19
+ * be wired via env there.
20
+ * - yolo (`--dangerously-skip-permissions`) is ON by default; `--no-yolo` opts out.
21
+ *
22
+ * The Anthropic key is resolved from a credential source with ZERO 1Password
23
+ * dependency (env → the CLI's own ~/.mnemom/code.json store → interactive
24
+ * prompt) and placed ONLY in the launched process (an `ANTHROPIC_CUSTOM_HEADERS`
25
+ * line, or the proxy's stdin under RC). It is never logged, printed, or passed as
26
+ * an argv value.
27
+ */
28
+ export interface CodeOptions {
29
+ goal?: string;
30
+ requirement?: string[];
31
+ allow?: string[];
32
+ forbid?: string[];
33
+ goalId?: string;
34
+ budget?: string;
35
+ maxTurns?: string;
36
+ stall?: string;
37
+ /** x-mnemom-agent value (defaults to "code-agent"). */
38
+ agent?: string;
39
+ conversationId?: string;
40
+ cli?: string;
41
+ remoteControl?: boolean;
42
+ server?: boolean;
43
+ model?: string;
44
+ effort?: string;
45
+ trimMcp?: boolean;
46
+ /** yolo default: commander `--no-yolo` sets this false. */
47
+ yolo?: boolean;
48
+ /** context-hint seed default: commander `--no-context-hint` sets this false. */
49
+ contextHint?: boolean;
50
+ /**
51
+ * Governed-agent provisioning: undefined = AUTO (provision-with-confirm when
52
+ * interactive, warn-and-continue otherwise), true = force (`--setup`), false =
53
+ * skip entirely (`--no-setup`).
54
+ */
55
+ setup?: boolean;
56
+ /**
57
+ * Where to source the Anthropic key (from ~/.mnemom/code.toml `key_source`).
58
+ * Restricts the default env → store → prompt search: "env" uses env only,
59
+ * "store" uses env → store (no prompt), "prompt" forces the interactive prompt.
60
+ * Undefined = the full default order.
61
+ */
62
+ keySource?: "env" | "store" | "prompt";
63
+ passthrough?: string[];
64
+ /** Print the resolved launch plan and exit — no key read, no spawn. */
65
+ dryRun?: boolean;
66
+ }
67
+ /** Entry point for `mnemom code <scenario>`. Throws on fatal misconfig. */
68
+ export declare function codeCommand(scenario: string, options?: CodeOptions): Promise<void>;
69
+ /**
70
+ * Resolve the Anthropic key with NO 1Password dependency (built for external
71
+ * customer adoption), in order:
72
+ * 1. env: MNEMOM_CODE_ANTHROPIC_KEY, else ANTHROPIC_API_KEY
73
+ * 2. the CLI's own store: ~/.mnemom/code.json (`anthropic_key`)
74
+ * 3. interactive prompt (masked), offering to save it to the store
75
+ * Never logged / printed. Throws with guidance when nothing resolves — we refuse
76
+ * to launch un-routed.
77
+ */
78
+ export declare function resolveAnthropicKey(env: NodeJS.ProcessEnv, opts: {
79
+ allowPrompt: boolean;
80
+ keySource?: "env" | "store" | "prompt";
81
+ }): Promise<string>;
82
+ /**
83
+ * Where an Anthropic key would resolve from RIGHT NOW, without reading its value:
84
+ * "env" (MNEMOM_CODE_ANTHROPIC_KEY / ANTHROPIC_API_KEY), "store" (~/.mnemom/code.json),
85
+ * or null (would fall to the interactive prompt). For `mnemom code doctor`.
86
+ */
87
+ export declare function anthropicKeySource(env?: NodeJS.ProcessEnv): "env" | "store" | null;
88
+ export interface ResolvedCli {
89
+ /** The executable to spawn (a resolved path, or a bare name on PATH). */
90
+ bin: string;
91
+ /** The basename, e.g. "claude" — selects the launch adapter. */
92
+ name: string;
93
+ }
94
+ /**
95
+ * Resolve which coding-agent CLI to launch. `--cli` (or MNEMOM_CODE_CLI) is a
96
+ * name or a full path; default "claude". A value with a path separator is used
97
+ * verbatim (must exist); a bare name is resolved on PATH, then — for claude — the
98
+ * fnm/nvm/asdf install dirs (a version-manager shim / shell function is absent in
99
+ * the fresh shell that runs the launch). v1 wires only the Claude Code adapter;
100
+ * a non-claude executable is launched through it with a warning.
101
+ */
102
+ export declare function resolveCliBin(cliOpt: string | undefined, env: NodeJS.ProcessEnv): ResolvedCli;
103
+ export declare function commandExists(cmd: string): boolean;
104
+ /**
105
+ * Does the resolved coding-agent CLI advertise the `--remote-control` startup
106
+ * flag (Claude Code >= 2.1.269)? Determined by scanning its `--help`. Best-effort:
107
+ * a spawn failure or timeout reads as "no". Only the claude adapter wires RC.
108
+ */
109
+ export declare function cliSupportsRemoteControl(bin: string): boolean;
110
+ /** The result of checking whether Remote Control can run here. */
111
+ export interface RcCapability {
112
+ ok: boolean;
113
+ /** Human reasons RC is unavailable (empty when ok). */
114
+ missing: string[];
115
+ }
116
+ /**
117
+ * Can we launch the DEFAULT Remote-Control-in-terminal shape on this machine?
118
+ * Needs node + openssl (the local proxy mints an ephemeral CA) and a claude
119
+ * adapter that advertises `--remote-control`. Used both by `mnemom code doctor`
120
+ * and by the auto-default selection (a bare launch prefers RC when capable).
121
+ */
122
+ export declare function checkRcCapability(cli: ResolvedCli): RcCapability;
123
+ /**
124
+ * Build the coding-agent CLI args from the model/effort/trim-mcp/yolo knobs plus
125
+ * the caller's passthrough. `--model`/`--effort` are injected only when given (no
126
+ * silent default). yolo appends `--dangerously-skip-permissions`. `--trim-mcp`
127
+ * appends `--strict-mcp-config --mcp-config {}` LAST so it wins over any
128
+ * caller-supplied --mcp-config.
129
+ */
130
+ export declare function buildCliArgs(options: CodeOptions, ctx: {
131
+ yolo: boolean;
132
+ allowCliFlags: boolean;
133
+ }): string[];