@mnemom/mnemom 0.17.0-next.6 → 0.17.0-next.8

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 (34) hide show
  1. package/README.md +26 -0
  2. package/dist/commands/agent-config.d.ts +29 -0
  3. package/dist/commands/agent-config.js +193 -0
  4. package/dist/commands/{code-doctor.d.ts → agent-doctor.d.ts} +2 -2
  5. package/dist/commands/{code-doctor.js → agent-doctor.js} +27 -22
  6. package/dist/commands/{code-invite.d.ts → agent-invite.d.ts} +18 -18
  7. package/dist/commands/{code-invite.js → agent-invite.js} +30 -30
  8. package/dist/commands/agent-session.d.ts +68 -0
  9. package/dist/commands/agent-session.js +114 -0
  10. package/dist/commands/{code-setup.d.ts → agent-setup.d.ts} +13 -13
  11. package/dist/commands/{code-setup.js → agent-setup.js} +46 -42
  12. package/dist/commands/{code.d.ts → agent.d.ts} +50 -14
  13. package/dist/commands/{code.js → agent.js} +144 -86
  14. package/dist/commands/agents.d.ts +2 -2
  15. package/dist/commands/agents.js +5 -5
  16. package/dist/commands/onboard.js +1 -1
  17. package/dist/commands/wrap.js +1 -1
  18. package/dist/index.js +59 -51
  19. package/dist/lib/{code.d.ts → agent.d.ts} +52 -10
  20. package/dist/lib/{code.js → agent.js} +94 -15
  21. package/dist/lib/api.d.ts +4 -4
  22. package/dist/lib/api.js +9 -9
  23. package/dist/lib/auth.js +21 -1
  24. package/dist/lib/{code-config.d.ts → launcher-config.d.ts} +25 -23
  25. package/dist/lib/{code-config.js → launcher-config.js} +50 -31
  26. package/dist/lib/oauth.d.ts +26 -4
  27. package/dist/lib/oauth.js +98 -29
  28. package/dist/lib/version-gate.js +1 -1
  29. package/dist/rc-proxy.mjs +309 -136
  30. package/package.json +7 -3
  31. package/dist/commands/code-config.d.ts +0 -17
  32. package/dist/commands/code-config.js +0 -147
  33. package/dist/commands/code-session.d.ts +0 -52
  34. package/dist/commands/code-session.js +0 -78
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemom/mnemom",
3
- "version": "0.17.0-next.6",
3
+ "version": "0.17.0-next.8",
4
4
  "description": "Transparent AI agent tracing",
5
5
  "type": "module",
6
6
  "bin": {
@@ -26,10 +26,10 @@
26
26
  "devDependencies": {
27
27
  "@types/js-yaml": "^4.0.9",
28
28
  "@types/node": "^20.10.0",
29
- "@vitest/coverage-v8": "^4.1.10",
29
+ "@vitest/coverage-v8": "^4.1.11",
30
30
  "tsx": "^4.23.1",
31
31
  "typescript": "^6.0.3",
32
- "vitest": "^4.1.10"
32
+ "vitest": "^4.1.11"
33
33
  },
34
34
  "files": [
35
35
  "dist",
@@ -65,5 +65,9 @@
65
65
  },
66
66
  "engines": {
67
67
  "node": ">=18.0.0"
68
+ },
69
+ "overrides": {
70
+ "@vitest/mocker": "^4.1.11",
71
+ "nanoid": "^3.3.18"
68
72
  }
69
73
  }
@@ -1,17 +0,0 @@
1
- /**
2
- * `mnemom code config …` — read and write the persistent per-customer settings
3
- * for `mnemom code` (see lib/code-config.ts). A sub-verb of `mnemom code`, so a
4
- * customer configures the launcher once and never retypes their flags:
5
- *
6
- * mnemom code config list # show the current settings
7
- * mnemom code config get <key> # print one value
8
- * mnemom code config set <key> <value> # validate + persist one value
9
- * mnemom code config unset <key> # remove one value
10
- * mnemom code config edit # open ~/.mnemom/code.toml in $EDITOR
11
- * mnemom code config path # print the settings file path
12
- *
13
- * Settable keys are the single source of truth in lib/code-config.ts CONFIG_KEYS.
14
- * The secret Anthropic key is NOT a config key — it lives in ~/.mnemom/code.json.
15
- */
16
- /** Entry point for `mnemom code config <verb> [args...]`. Throws on misuse. */
17
- export declare function codeConfigCommand(argv: string[]): Promise<void>;
@@ -1,147 +0,0 @@
1
- /**
2
- * `mnemom code config …` — read and write the persistent per-customer settings
3
- * for `mnemom code` (see lib/code-config.ts). A sub-verb of `mnemom code`, so a
4
- * customer configures the launcher once and never retypes their flags:
5
- *
6
- * mnemom code config list # show the current settings
7
- * mnemom code config get <key> # print one value
8
- * mnemom code config set <key> <value> # validate + persist one value
9
- * mnemom code config unset <key> # remove one value
10
- * mnemom code config edit # open ~/.mnemom/code.toml in $EDITOR
11
- * mnemom code config path # print the settings file path
12
- *
13
- * Settable keys are the single source of truth in lib/code-config.ts CONFIG_KEYS.
14
- * The secret Anthropic key is NOT a config key — it lives in ~/.mnemom/code.json.
15
- */
16
- import { spawnSync } from "node:child_process";
17
- import { existsSync } from "node:fs";
18
- import { CODE_CONFIG_PATH, CONFIG_KEYS, configKeySpec, loadCodeConfig, writeCodeConfig, } from "../lib/code-config.js";
19
- const out = (line = "") => console.log(line);
20
- const err = (line = "") => console.error(line);
21
- /** Entry point for `mnemom code config <verb> [args...]`. Throws on misuse. */
22
- export async function codeConfigCommand(argv) {
23
- const [verb, ...rest] = argv;
24
- switch (verb) {
25
- case undefined:
26
- case "list":
27
- return listConfig();
28
- case "path":
29
- out(CODE_CONFIG_PATH);
30
- return;
31
- case "get":
32
- return getConfig(rest[0]);
33
- case "set":
34
- return setConfig(rest[0], rest[1]);
35
- case "unset":
36
- return unsetConfig(rest[0]);
37
- case "edit":
38
- return editConfig();
39
- default:
40
- throw new Error(`mnemom code config: unknown verb '${verb}'. Use list | get | set | unset | edit | path.`);
41
- }
42
- }
43
- function listConfig() {
44
- const cfg = loadCodeConfig();
45
- const rows = [];
46
- for (const spec of CONFIG_KEYS) {
47
- const v = spec.get(cfg);
48
- if (v !== undefined)
49
- rows.push([spec.key, String(v)]);
50
- }
51
- if (!rows.length) {
52
- out(`No settings yet at ${CODE_CONFIG_PATH}.`);
53
- out("Set one with: mnemom code config set <key> <value>");
54
- out("");
55
- out("Settable keys:");
56
- for (const spec of CONFIG_KEYS)
57
- out(` ${spec.key.padEnd(22)} ${spec.describe}`);
58
- return;
59
- }
60
- const width = Math.max(...rows.map(([k]) => k.length));
61
- out(`# ${CODE_CONFIG_PATH}`);
62
- for (const [k, v] of rows)
63
- out(`${k.padEnd(width)} ${v}`);
64
- }
65
- function getConfig(key) {
66
- if (!key)
67
- throw new Error("mnemom code config get: a <key> is required.");
68
- const spec = requireSpec(key);
69
- const value = spec.get(loadCodeConfig());
70
- if (value === undefined) {
71
- err(`mnemom code config: '${key}' is not set.`);
72
- process.exitCode = 1;
73
- return;
74
- }
75
- out(String(value));
76
- }
77
- function setConfig(key, value) {
78
- if (!key)
79
- throw new Error("mnemom code config set: a <key> is required.");
80
- if (value === undefined)
81
- throw new Error(`mnemom code config set: a value for '${key}' is required.`);
82
- const spec = requireSpec(key);
83
- const cfg = loadCodeConfig();
84
- spec.set(cfg, value); // validates + coerces; throws on invalid
85
- writeCodeConfig(cfg);
86
- out(`${key} = ${String(spec.get(cfg))} (saved to ${CODE_CONFIG_PATH})`);
87
- }
88
- function unsetConfig(key) {
89
- if (!key)
90
- throw new Error("mnemom code config unset: a <key> is required.");
91
- requireSpec(key);
92
- const cfg = loadCodeConfig();
93
- deleteKey(cfg, key);
94
- writeCodeConfig(cfg);
95
- out(`unset ${key} (saved to ${CODE_CONFIG_PATH})`);
96
- }
97
- function editConfig() {
98
- // Seed a header-only file so $EDITOR opens something with guidance, not a blank.
99
- if (!existsSync(CODE_CONFIG_PATH))
100
- writeCodeConfig(loadCodeConfig());
101
- const editor = process.env.VISUAL || process.env.EDITOR || fallbackEditor();
102
- const res = spawnSync(editor, [CODE_CONFIG_PATH], { stdio: "inherit" });
103
- if (res.error) {
104
- throw new Error(`mnemom code config edit: could not launch editor '${editor}': ${res.error.message}\n` +
105
- ` Set $EDITOR, or edit ${CODE_CONFIG_PATH} directly.`);
106
- }
107
- // Re-parse so a typo surfaces now, not at the next launch.
108
- loadCodeConfig();
109
- out(`Saved ${CODE_CONFIG_PATH}.`);
110
- }
111
- function fallbackEditor() {
112
- for (const cand of ["nano", "vim", "vi"]) {
113
- const r = spawnSync("sh", ["-c", `command -v "$1" >/dev/null 2>&1`, "sh", cand], {
114
- stdio: "ignore",
115
- });
116
- if (r.status === 0)
117
- return cand;
118
- }
119
- return "vi";
120
- }
121
- function requireSpec(key) {
122
- const spec = configKeySpec(key);
123
- if (!spec) {
124
- throw new Error(`mnemom code config: unknown key '${key}'.\n Known keys: ${CONFIG_KEYS.map((k) => k.key).join(", ")}`);
125
- }
126
- return spec;
127
- }
128
- /** Remove a (possibly dotted) key from a config object, pruning an emptied table. */
129
- function deleteKey(cfg, key) {
130
- if (key.startsWith("guardrails.")) {
131
- const g = cfg.guardrails;
132
- if (!g)
133
- return;
134
- const field = key.slice("guardrails.".length);
135
- if (field === "max_turns")
136
- delete g.maxTurns;
137
- if (field === "budget_usd")
138
- delete g.budgetUsd;
139
- if (field === "stall_turns")
140
- delete g.stallTurns;
141
- if (g.maxTurns === undefined && g.budgetUsd === undefined && g.stallTurns === undefined) {
142
- delete cfg.guardrails;
143
- }
144
- return;
145
- }
146
- delete cfg[key === "key_source" ? "keySource" : key];
147
- }
@@ -1,52 +0,0 @@
1
- /**
2
- * `mnemom code` with no session name — the interactive first-run setup.
3
- *
4
- * The daily command is just `mnemom code` (the Claude Code pattern: install
5
- * once, then the bare command). When the positional session name is omitted in
6
- * a terminal we ask two things, explaining each in a sentence:
7
- *
8
- * 1. a SESSION NAME — labels the session in traces and the claude.ai session
9
- * list (defaults to the current folder's name);
10
- * 2. an optional GOAL — one line. With a goal, Mnemom seals a goal contract
11
- * for the session and the judge nudges the agent back when it drifts (a
12
- * little µ per turn). Without one, the session runs governed but with goal
13
- * alignment OFF: no contract header is sent, so the gateway's goal hook is
14
- * simply not engaged for the conversation.
15
- *
16
- * Non-interactive runs (pipes, CI) never prompt — they get a clear error asking
17
- * for a name. `--goal` on the command line always wins over the prompt. Pure
18
- * apart from the injected `ask` functions, so every arm is unit-tested.
19
- */
20
- export interface SessionAsk {
21
- askInput(question: string): Promise<string>;
22
- askYesNo(question: string, defaultYes: boolean): Promise<boolean>;
23
- }
24
- export interface SessionSetupInput {
25
- /** The positional `[scenario]` (session name), if given. */
26
- scenario?: string;
27
- /** `--goal <statement>`, if given — skips the goal prompt. */
28
- goal?: string;
29
- interactive: boolean;
30
- /** For the default session name (tests inject one). */
31
- cwd?: string;
32
- /** Narration sink (stderr by default; tests capture). */
33
- say?: (line?: string) => void;
34
- }
35
- export interface SessionSetup {
36
- scenario: string;
37
- /** The goal statement to seal, or undefined = goal alignment off. */
38
- goal?: string;
39
- goalAlignment: "on" | "off";
40
- /** True when the terminal prompts ran. */
41
- prompted: boolean;
42
- }
43
- export declare const NO_SESSION_NAME_MESSAGE: string;
44
- /** Current folder name, sanitised like an agent slug; "session" when that is empty. */
45
- export declare function defaultSessionName(cwd?: string): string;
46
- /** The one-line status printed at launch so the customer always knows the mode. */
47
- export declare function goalAlignmentLine(on: boolean): string;
48
- /**
49
- * Resolve the session name + goal for this launch. See the module doc for the
50
- * rules. Throws NO_SESSION_NAME_MESSAGE when no name was given and we cannot ask.
51
- */
52
- export declare function resolveSessionSetup(input: SessionSetupInput, ask: SessionAsk): Promise<SessionSetup>;
@@ -1,78 +0,0 @@
1
- /**
2
- * `mnemom code` with no session name — the interactive first-run setup.
3
- *
4
- * The daily command is just `mnemom code` (the Claude Code pattern: install
5
- * once, then the bare command). When the positional session name is omitted in
6
- * a terminal we ask two things, explaining each in a sentence:
7
- *
8
- * 1. a SESSION NAME — labels the session in traces and the claude.ai session
9
- * list (defaults to the current folder's name);
10
- * 2. an optional GOAL — one line. With a goal, Mnemom seals a goal contract
11
- * for the session and the judge nudges the agent back when it drifts (a
12
- * little µ per turn). Without one, the session runs governed but with goal
13
- * alignment OFF: no contract header is sent, so the gateway's goal hook is
14
- * simply not engaged for the conversation.
15
- *
16
- * Non-interactive runs (pipes, CI) never prompt — they get a clear error asking
17
- * for a name. `--goal` on the command line always wins over the prompt. Pure
18
- * apart from the injected `ask` functions, so every arm is unit-tested.
19
- */
20
- import { basename } from "node:path";
21
- import { sanitizeAgentName } from "../lib/code.js";
22
- export const NO_SESSION_NAME_MESSAGE = "mnemom code: a session name is required here (e.g. `mnemom code onboarding`). " +
23
- "In a terminal, plain `mnemom code` asks for one.";
24
- /** Current folder name, sanitised like an agent slug; "session" when that is empty. */
25
- export function defaultSessionName(cwd = process.cwd()) {
26
- return sanitizeAgentName(basename(cwd)) || "session";
27
- }
28
- /** The one-line status printed at launch so the customer always knows the mode. */
29
- export function goalAlignmentLine(on) {
30
- return on
31
- ? "mnemom code: goal alignment: on (the judge nudges the agent back when it drifts from your goal)"
32
- : "mnemom code: goal alignment: off (no goal set — pass --goal or set one when prompted)";
33
- }
34
- const defaultSay = (line = "") => console.error(line);
35
- /**
36
- * Resolve the session name + goal for this launch. See the module doc for the
37
- * rules. Throws NO_SESSION_NAME_MESSAGE when no name was given and we cannot ask.
38
- */
39
- export async function resolveSessionSetup(input, ask) {
40
- const say = input.say ?? defaultSay;
41
- const flagGoal = (input.goal ?? "").trim();
42
- const given = (input.scenario ?? "").trim();
43
- if (given) {
44
- return {
45
- scenario: given,
46
- goal: flagGoal || undefined,
47
- goalAlignment: flagGoal ? "on" : "off",
48
- prompted: false,
49
- };
50
- }
51
- if (!input.interactive)
52
- throw new Error(NO_SESSION_NAME_MESSAGE);
53
- // ── 1. session name ──
54
- const fallback = defaultSessionName(input.cwd);
55
- say();
56
- say("Session name — labels this session in your traces and the claude.ai session list.");
57
- say(` (Next time you can pass it directly: mnemom code <name>.)`);
58
- const typed = await ask.askInput(`Session name [${fallback}]:`);
59
- const scenario = sanitizeAgentName(typed.trim()) || fallback;
60
- // ── 2. goal (skipped when --goal was given) ──
61
- if (flagGoal) {
62
- return { scenario, goal: flagGoal, goalAlignment: "on", prompted: true };
63
- }
64
- say();
65
- say("Goal alignment — an optional one-line goal for this session.");
66
- say(" With a goal, Mnemom's judge watches each turn and nudges the agent back when it drifts");
67
- say(" (a little µ per turn). Without one, the session runs governed with goal alignment off.");
68
- const wantsGoal = await ask.askYesNo("Set a goal for this session?", true);
69
- if (!wantsGoal) {
70
- return { scenario, goalAlignment: "off", prompted: true };
71
- }
72
- const goal = (await ask.askInput("Goal (one line):")).trim();
73
- if (!goal) {
74
- say(" No goal entered — continuing with goal alignment off.");
75
- return { scenario, goalAlignment: "off", prompted: true };
76
- }
77
- return { scenario, goal, goalAlignment: "on", prompted: true };
78
- }