@mnemom/mnemom 0.17.2-next.0 → 0.17.2-next.1

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.
@@ -13,7 +13,7 @@
13
13
  * local sha is never printed as "the sealed hash" and no mismatch is flagged —
14
14
  * only the server's hash is shown, labelled "sealed hash".
15
15
  */
16
- import { type SessionRecord } from "../lib/agent-ledger.js";
16
+ import { type GoalMode, type SessionRecord } from "../lib/agent-ledger.js";
17
17
  import { type AgentSessionResponse } from "../lib/api.js";
18
18
  export interface SessionCommandDeps {
19
19
  /** The ledger, newest first. */
@@ -47,8 +47,19 @@ export interface SessionRefAmbiguous {
47
47
  * - nothing matches (or the ledger is empty) → null.
48
48
  */
49
49
  export declare function resolveSessionRef(records: SessionRecord[], ref?: string): SessionRefMatch | SessionRefAmbiguous | null;
50
- /** Goal alignment as the ledger recorded it: a contract at launch ⇒ on. */
51
- export declare function localGoalFlag(record: SessionRecord): "on" | "off";
50
+ /**
51
+ * Goal-alignment mode as the ledger recorded it. Prefers the explicit
52
+ * `goal_mode` (which alone distinguishes `implicit` from `off`); records
53
+ * written before that field existed fall back to `contract ? "on" : "off"`.
54
+ */
55
+ export declare function localGoalFlag(record: SessionRecord): GoalMode;
56
+ /**
57
+ * Goal-alignment mode for the `show` view: the live gateway state wins when it
58
+ * is present (a sealed contract ⇒ `on`), otherwise the locally recorded mode.
59
+ * A gateway with no sealed contract can still be an `implicit` session, so the
60
+ * local `goal_mode` fills that in.
61
+ */
62
+ export declare function resolveGoalMode(local: SessionRecord, remote: AgentSessionResponse | null): GoalMode;
52
63
  /**
53
64
  * Render the ledger as a table, newest first — the newest
54
65
  * `DEFAULT_SESSIONS_LIMIT` rows unless `all`, with a footer naming the rest.
@@ -69,7 +80,7 @@ export interface ShowJson {
69
80
  session: SessionRecord & {
70
81
  source: "local";
71
82
  };
72
- goal_alignment: "on" | "off";
83
+ goal_alignment: GoalMode;
73
84
  live: {
74
85
  source: "gateway";
75
86
  available: true;
@@ -55,15 +55,46 @@ export function resolveSessionRef(records, ref) {
55
55
  return null;
56
56
  }
57
57
  // ─── sessions table ───────────────────────────────────────────────────────────
58
- const COL = { session: 26, started: 16, agent: 22, goal: 6, conv: 8 };
58
+ const COL = { session: 26, started: 16, agent: 22, goal: 10, conv: 8 };
59
59
  function cell(text, width) {
60
60
  const max = width - 2;
61
61
  const shown = text.length > max ? `${text.slice(0, max - 1)}…` : text;
62
62
  return shown.padEnd(width);
63
63
  }
64
- /** Goal alignment as the ledger recorded it: a contract at launch ⇒ on. */
64
+ /**
65
+ * Goal-alignment mode as the ledger recorded it. Prefers the explicit
66
+ * `goal_mode` (which alone distinguishes `implicit` from `off`); records
67
+ * written before that field existed fall back to `contract ? "on" : "off"`.
68
+ */
65
69
  export function localGoalFlag(record) {
66
- return record.contract ? "on" : "off";
70
+ return record.goal_mode ?? (record.contract ? "on" : "off");
71
+ }
72
+ /**
73
+ * Goal-alignment mode for the `show` view: the live gateway state wins when it
74
+ * is present (a sealed contract ⇒ `on`), otherwise the locally recorded mode.
75
+ * A gateway with no sealed contract can still be an `implicit` session, so the
76
+ * local `goal_mode` fills that in.
77
+ */
78
+ export function resolveGoalMode(local, remote) {
79
+ if (remote) {
80
+ // Live truth wins: a sealed contract ⇒ on. When the gateway has NO sealed
81
+ // contract, the session is either implicit or off — and only the local
82
+ // `goal_mode` distinguishes those. A stale local "on" (a contract that has
83
+ // since cleared/expired/been revoked on the gateway) must NOT resurrect an
84
+ // "on" the live state contradicts, so only "implicit" is recovered here.
85
+ if (remote.sealed !== null)
86
+ return "on";
87
+ return local.goal_mode === "implicit" ? "implicit" : "off";
88
+ }
89
+ return localGoalFlag(local);
90
+ }
91
+ /** The badge for a goal mode: on → green, implicit → cyan, off → yellow. */
92
+ function goalBadge(mode) {
93
+ if (mode === "on")
94
+ return fmt.badge("ON", "green");
95
+ if (mode === "implicit")
96
+ return fmt.badge("IMPLICIT", "cyan");
97
+ return fmt.badge("OFF", "yellow");
67
98
  }
68
99
  /**
69
100
  * Render the ledger as a table, newest first — the newest
@@ -123,8 +154,8 @@ export function buildShowView(local, remote, reason) {
123
154
  launchBits.push(`effort ${local.effort}`);
124
155
  L.push(fmt.label("launch: ", launchBits.join(" · ")));
125
156
  L.push(fmt.label("conversation: ", local.conversation_id));
126
- const goalOn = remote ? remote.sealed !== null : local.contract !== null;
127
- L.push(fmt.label("goal alignment:", goalOn ? fmt.badge("ON", "green") : fmt.badge("OFF", "yellow")));
157
+ const goalMode = resolveGoalMode(local, remote);
158
+ L.push(fmt.label("goal alignment:", goalBadge(goalMode)));
128
159
  if (local.contract) {
129
160
  L.push(fmt.label("goal (at launch):", local.contract.statement));
130
161
  }
@@ -176,10 +207,9 @@ export function buildShowView(local, remote, reason) {
176
207
  return L;
177
208
  }
178
209
  export function buildShowJson(local, remote, reason) {
179
- const goalOn = remote ? remote.sealed !== null : local.contract !== null;
180
210
  return {
181
211
  session: { ...local, source: "local" },
182
- goal_alignment: goalOn ? "on" : "off",
212
+ goal_alignment: resolveGoalMode(local, remote),
183
213
  live: remote
184
214
  ? {
185
215
  source: "gateway",
@@ -91,6 +91,7 @@ export declare function recordSessionLaunch(ctx: {
91
91
  options: AgentOptions;
92
92
  cli: ResolvedCli;
93
93
  envelope: SealedContractEnvelope | null;
94
+ goalMode: string | null;
94
95
  }): Promise<void>;
95
96
  /**
96
97
  * Resolve the Anthropic key with NO 1Password dependency (built for external
@@ -231,6 +231,7 @@ export async function agentCommand(scenarioArg, options = {}) {
231
231
  options,
232
232
  cli,
233
233
  envelope,
234
+ goalMode,
234
235
  });
235
236
  logLaunch({ shape, door, agent, conversationId, cellNote, envelope, goalMode, cli });
236
237
  say(goalAlignmentLine(goalAlignmentMode(envelope, goalMode)));
@@ -292,6 +293,7 @@ export async function recordSessionLaunch(ctx) {
292
293
  effort: ctx.options.effort?.trim() || null,
293
294
  cli: ctx.cli.name,
294
295
  contract: toLedgerContract(ctx.envelope?.contract ?? null),
296
+ goal_mode: goalAlignmentMode(ctx.envelope, ctx.goalMode),
295
297
  }, { dir: MNEMOM_DIR, now: () => new Date(), pid: process.pid });
296
298
  if (!result.ok) {
297
299
  say(fmt.warn(`mnemom agent: could not record this session in ~/.mnemom/${LEDGER_FILE} (${result.error}) — launching anyway.`));
@@ -46,7 +46,18 @@ export interface SessionRecord {
46
46
  /** The coding-agent CLI's basename, e.g. "claude". */
47
47
  cli: string;
48
48
  contract: SessionRecordContract | null;
49
+ /**
50
+ * The goal-alignment mode the launch ran under: `"on"` (a sealed contract),
51
+ * `"implicit"` (`--implicit` — the gateway infers the goal, no sealed
52
+ * contract), or `"off"`. Optional: records written before this field existed
53
+ * omit it, and readers fall back to `contract ? "on" : "off"` (an old
54
+ * `--implicit` launch is indistinguishable from `off` — its mode was never
55
+ * captured).
56
+ */
57
+ goal_mode?: GoalMode;
49
58
  }
59
+ /** Goal-alignment mode as recorded at launch. */
60
+ export type GoalMode = "off" | "on" | "implicit";
50
61
  /** What the call site supplies — the ledger stamps `v` and `started_at`. */
51
62
  export type SessionRecordInput = Omit<SessionRecord, "v" | "started_at">;
52
63
  /** The injected environment of the ledger. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemom/mnemom",
3
- "version": "0.17.2-next.0",
3
+ "version": "0.17.2-next.1",
4
4
  "description": "Transparent AI agent tracing",
5
5
  "type": "module",
6
6
  "bin": {