@mnemom/mnemom 0.17.21 → 0.17.23

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/lib/agent.js CHANGED
@@ -503,16 +503,24 @@ export const CONTEXT_HEAD_RECLAIM_KEY = "CONTEXT_RUNTIME_HEAD_BREAKPOINT_RECLAIM
503
503
  export const CONTEXT_SIZE_POLICY_KEY = "CONTEXT_RUNTIME_SIZE_POLICY";
504
504
  /**
505
505
  * The two gateway env keys the `compaction_intercept` setting turns on for a single session
506
- * (payload-bound fix; both default OFF on the gateway, both read from the per-session overlay):
506
+ * (payload-bound fix; both read from the per-session overlay). The us-2 prod cell runs both on in
507
+ * its own cell env; the test and us-1 preview cells leave them at the gateway default (off). Since
508
+ * 0.17.23 the CLI asks for them on every launch — a deliberate, authorized rollout decision
509
+ * (MNE-8532, CTO 2026-10-12): every cell a `mnemom agent` session runs on then behaves like
510
+ * prod, rather than the CLI deferring to a non-prod cell's off default. The keys are TUNE-tier
511
+ * (gateway session-config allowlist, honored for any authenticated agent), so a cell without
512
+ * the companion support drops them and the session behaves as before.
507
513
  * - `GATEWAY_USAGE_REAL_SIZE` — report the size of the body the client actually sent (the
508
514
  * REAL, unfolded context) in the last `usage.iterations` entry, so Claude Code's own
509
515
  * auto-compact threshold (its 1M default, or the user's `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` /
510
516
  * `CLAUDE_CODE_AUTO_COMPACT_WINDOW` / `autoCompactWindow`) fires as it would without the fold;
511
517
  * - `GATEWAY_COMPACTION_INTERCEPT` — answer the client's compaction request at once from the
512
518
  * gateway's own fold digest (no model call), so the compaction never blocks the user.
513
- * Sent together, value `"on"`, when the `compaction_intercept` setting is on
514
- * (`resolveCompactionIntercept`) OR when `--compact-at` arms a target below 1M (below) — a
515
- * target cannot be honored without both. The `off` context profile sends both as `"off"`.
519
+ * Sent together, value `"on"`, when the `compaction_intercept` setting is on — the DEFAULT since
520
+ * 0.17.23 (`resolveCompactionIntercept`) — OR when `--compact-at` arms a target below 1M (below):
521
+ * a target cannot be honored without both. An opt-out (`--no-compaction-intercept`,
522
+ * `compaction_intercept = false`, `MNEMOM_AGENT_COMPACTION_INTERCEPT=0`) and the `off` context
523
+ * profile send both as `"off"`, so the opt-out holds on a cell whose own default is on.
516
524
  */
517
525
  export const USAGE_REAL_SIZE_KEY = "GATEWAY_USAGE_REAL_SIZE";
518
526
  export const COMPACTION_INTERCEPT_KEY = "GATEWAY_COMPACTION_INTERCEPT";
@@ -576,12 +584,12 @@ export const CONTEXT_HANDOFF_KEY = "CONTEXT_HANDOFF_ENABLED";
576
584
  // Lets an operator play with WHEN the gateway pulls this session's own client-visible
577
585
  // compaction point forward (GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS, #2251), instead of
578
586
  // leaving Claude Code to compact on its own 1M-window schedule. Unset / `1m` / `off` all
579
- // mean the SAME thing — no target — so a launch with nothing else configured sends no new
580
- // header keys at all and behaves exactly as it did before this setting existed: Claude
581
- // Code's own 1M window, no gateway-triggered compaction. A value strictly below 1,000,000
582
- // arms the compaction intercept (USAGE_REAL_SIZE_KEY + COMPACTION_INTERCEPT_KEY, above — the
583
- // same two keys `--compaction-intercept` arms, #2216, both required for the upload pull to be
584
- // honored instead of silently inert) plus the target itself. Refold (GATEWAY_COMPACTION_REFOLD)
587
+ // mean the SAME thing — no target — so no target key is sent: Claude Code's own 1M window, no
588
+ // gateway-triggered compaction. A value strictly below 1,000,000 sends the target itself and
589
+ // arms the compaction intercept (USAGE_REAL_SIZE_KEY + COMPACTION_INTERCEPT_KEY, above — on by
590
+ // default since 0.17.23; #2216: both are required for the upload pull to be honored instead of
591
+ // silently inert), even over a standing opt-out in launcher.toml or the environment; only an
592
+ // explicit --no-compaction-intercept in the same launch is refused (assertCompactAtCompatible). Refold (GATEWAY_COMPACTION_REFOLD)
585
593
  // is a SEPARATE, costlier opt-in (+9.5pts measured) — this setting never touches it. This never
586
594
  // sets a Claude Code autocompact env/window: Claude Code's own compaction math is untouched;
587
595
  // only what the GATEWAY reports back changes.
@@ -704,15 +712,13 @@ export function resolveCompactAt(opts) {
704
712
  * (either silently re-arming the intercept the user just turned off, or silently sending an
705
713
  * inert upload-target the gateway can never act on). `compactionIntercept` here is the raw,
706
714
  * pre-`resolveCompactionIntercept` flag value: `false` only when `--no-compaction-intercept`
707
- * was explicitly passed (or the experimental gate forced it, which `compactAt` cannot reach
708
- * past either — see index.ts's `assertEnabled`), never the mere absence of `--compaction-intercept`.
715
+ * was explicitly passed, never the mere absence of `--compaction-intercept`.
709
716
  */
710
717
  export function assertCompactAtCompatible(opts) {
711
718
  if (opts.compactionIntercept === false && opts.compactAt !== null) {
712
- throw new Error("mnemom agent: --compact-at needs the compaction intercept to arm, but it is off for " +
713
- "this launch (--no-compaction-intercept, or the compaction-intercept experimental " +
714
- "feature is disabled). Drop --no-compaction-intercept (and run `mnemom experimental " +
715
- "enable compaction-intercept`), or pass --compact-at off.");
719
+ throw new Error("mnemom agent: --compact-at needs the compaction intercept to arm, but " +
720
+ "--no-compaction-intercept turns it off for this launch. Drop --no-compaction-intercept, " +
721
+ "or pass --compact-at off.");
716
722
  }
717
723
  }
718
724
  /**
@@ -1039,13 +1045,14 @@ export function resolveContextProfile(opts) {
1039
1045
  * no profile was chosen), then `CONTEXT_HANDOFF_ENABLED: "true"` when context handoff is ON, then
1040
1046
  * `GATEWAY_USAGE_SAVINGS: "on"` when measured savings is ON (under every profile), then
1041
1047
  * `GATEWAY_USAGE_REAL_SIZE: "on"` + `GATEWAY_COMPACTION_INTERCEPT: "on"` when EITHER the
1042
- * `compaction_intercept` setting is ON OR `--compact-at` arms a target below 1M (the target
1043
- * cannot be honored without the intercept), then `GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS: "<N>"`
1044
- * when a target is set. The `off` profile wins over the intercept and the target: a session with
1048
+ * `compaction_intercept` setting is ON (the default) OR `--compact-at` arms a target below 1M (the
1049
+ * target cannot be honored without the intercept) — or both as `"off"` when the setting is
1050
+ * explicitly `false` (an opt-out) and no target is armed, so the opt-out holds on a cell whose own
1051
+ * env turns them on — then `GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS: "<N>"` when a target is set. The `off` profile wins over the intercept and the target: a session with
1045
1052
  * no fold never has its compaction intercepted (`assertOffProfileCompatible` refuses the explicit
1046
1053
  * flag pair; a standing intercept or target from the environment or launcher.toml is dropped).
1047
- * Empty with no profile chosen and everything off — the common case, where
1048
- * no header is sent at all. Exported so `--dry-run` can list exactly what the header carries.
1054
+ * Empty with no profile chosen, everything else off and `compactionIntercept` absent (callers
1055
+ * that do not resolve it) — then no header is sent at all. Exported so `--dry-run` can list exactly what the header carries.
1049
1056
  */
1050
1057
  export function buildSessionConfig(opts) {
1051
1058
  const config = {};
@@ -1068,6 +1075,12 @@ export function buildSessionConfig(opts) {
1068
1075
  config[USAGE_REAL_SIZE_KEY] = "on";
1069
1076
  config[COMPACTION_INTERCEPT_KEY] = "on";
1070
1077
  }
1078
+ else if (opts.compactionIntercept === false) {
1079
+ // An opt-out says "off" by name: sending nothing would leave a cell whose own env turns the
1080
+ // intercept on (us-2) intercepting anyway.
1081
+ config[USAGE_REAL_SIZE_KEY] = "off";
1082
+ config[COMPACTION_INTERCEPT_KEY] = "off";
1083
+ }
1071
1084
  if (hasCompactionTarget) {
1072
1085
  config[GATEWAY_COMPACTION_UPLOAD_TARGET_KEY] = String(opts.compactAt);
1073
1086
  }
@@ -1095,8 +1108,8 @@ export function buildSessionConfigPayload(opts) {
1095
1108
  * `aggressive` → the three fold-tuning keys + `CONTEXT_RUNTIME_SIZE_POLICY: "off"`,
1096
1109
  * `balanced` → `CONTEXT_RUNTIME_SIZE_POLICY: "off"`, `adaptive` →
1097
1110
  * `CONTEXT_RUNTIME_SIZE_POLICY: "banded"`, none chosen → nothing;
1098
- * - `compactionIntercept: true` → `GATEWAY_USAGE_REAL_SIZE` + `GATEWAY_COMPACTION_INTERCEPT`
1099
- * `"on"` (the `compaction_intercept` setting);
1111
+ * - `compactionIntercept: true` (the default) → `GATEWAY_USAGE_REAL_SIZE` +
1112
+ * `GATEWAY_COMPACTION_INTERCEPT` `"on"`; `false` (an opt-out) → both `"off"`;
1100
1113
  * - `compactAt: <N>` (`--compact-at`, below 1M) → the SAME two intercept keys plus
1101
1114
  * `GATEWAY_COMPACTION_UPLOAD_TARGET_TOKENS: "<N>"`; unset, `1m` or `off` → nothing beyond
1102
1115
  * what `compactionIntercept` already sent (Claude Code's own 1M window, untouched);
@@ -1131,18 +1144,17 @@ export function resolveContextHandoff(opts) {
1131
1144
  }
1132
1145
  /**
1133
1146
  * Is the compaction intercept (`GATEWAY_USAGE_REAL_SIZE` + `GATEWAY_COMPACTION_INTERCEPT` in the
1134
- * session-config header) ON for this launch? OFF by default, same shape as
1135
- * `resolveContextHandoff`: an explicit `--compaction-intercept` / `--no-compaction-intercept`
1136
- * wins, else `MNEMOM_AGENT_COMPACTION_INTERCEPT` (which `applyConfigToEnv` sets from the
1137
- * `compaction_intercept` config key), else OFF.
1147
+ * session-config header) ON for this launch? ON by default since 0.17.23 (it graduated from the
1148
+ * `compaction-intercept` experimental feature). An explicit `--compaction-intercept` /
1149
+ * `--no-compaction-intercept` wins, else `MNEMOM_AGENT_COMPACTION_INTERCEPT` (which
1150
+ * `applyConfigToEnv` sets from the `compaction_intercept` config key: `0`/`false`/`off`/`no`
1151
+ * opt out), else ON.
1138
1152
  */
1139
1153
  export function resolveCompactionIntercept(opts) {
1140
1154
  if (opts.compactionIntercept !== undefined)
1141
1155
  return opts.compactionIntercept;
1142
1156
  const raw = (opts.env?.MNEMOM_AGENT_COMPACTION_INTERCEPT ?? "").trim().toLowerCase();
1143
- if (raw === "")
1144
- return false;
1145
- return raw === "1" || raw === "true" || raw === "on" || raw === "yes";
1157
+ return !(raw === "0" || raw === "false" || raw === "off" || raw === "no");
1146
1158
  }
1147
1159
  /**
1148
1160
  * Does the gateway measure this launch's saving (`GATEWAY_USAGE_SAVINGS` in the header, and the
package/dist/lib/api.d.ts CHANGED
@@ -371,6 +371,18 @@ export interface MoveAgentResult {
371
371
  export declare function moveAgent(agentId: string, destOrgId: string, opts?: {
372
372
  idempotencyKey?: string;
373
373
  }): Promise<MoveAgentResult>;
374
+ /**
375
+ * GET /v1/agents/:id/compliance-export — the agent's full record (JSON or CSV).
376
+ *
377
+ * Returns the raw body bytes (written to disk verbatim so the checksum the CLI
378
+ * prints matches what the server sent) plus the response headers (CSV carries
379
+ * its per-section counts in `X-Mnemom-Export-Counts`). `query` is the full
380
+ * `?format=…&from=…&to=…` string (see lib/agent-export.ts buildExportQuery).
381
+ */
382
+ export declare function getComplianceExport(agentId: string, query: string): Promise<{
383
+ body: Uint8Array;
384
+ headers: Headers;
385
+ }>;
374
386
  /**
375
387
  * GET /v1/auth/me/personal-org — accessor for the user's personal org.
376
388
  * Idempotent: lazily provisions for legacy accounts that pre-date the
package/dist/lib/api.js CHANGED
@@ -367,6 +367,23 @@ export async function moveAgent(agentId, destOrgId, opts = {}) {
367
367
  to_org_id: data.to_org_id ?? null,
368
368
  };
369
369
  }
370
+ /**
371
+ * GET /v1/agents/:id/compliance-export — the agent's full record (JSON or CSV).
372
+ *
373
+ * Returns the raw body bytes (written to disk verbatim so the checksum the CLI
374
+ * prints matches what the server sent) plus the response headers (CSV carries
375
+ * its per-section counts in `X-Mnemom-Export-Counts`). `query` is the full
376
+ * `?format=…&from=…&to=…` string (see lib/agent-export.ts buildExportQuery).
377
+ */
378
+ export async function getComplianceExport(agentId, query) {
379
+ const url = validateUrl(`${API_BASE}/v1/agents/${encodeURIComponent(agentId)}/compliance-export${query}`);
380
+ const response = await fetchWithAuthRetry(url, async () => ({
381
+ headers: { ...(await authHeaders()), Accept: "application/json, text/csv" },
382
+ }));
383
+ if (!response.ok)
384
+ throw await readApiError(response, "Failed to export the agent record");
385
+ return { body: new Uint8Array(await response.arrayBuffer()), headers: response.headers };
386
+ }
370
387
  /**
371
388
  * GET /v1/auth/me/personal-org — accessor for the user's personal org.
372
389
  * Idempotent: lazily provisions for legacy accounts that pre-date the
@@ -12,16 +12,20 @@
12
12
  * Everything here is pure or dependency-injected; index.ts and the command
13
13
  * modules are the thin drivers.
14
14
  */
15
- export type ExperimentalId = "context-handoff" | "slack" | "implicit" | "compaction-intercept" | "measured-savings";
15
+ export type ExperimentalId = "context-handoff" | "slack" | "implicit" | "measured-savings";
16
16
  /**
17
- * Is a `compact_at` / `MNEMOM_COMPACT_AT` value (trimmed, case-insensitive) an ARMED gateway
18
- * target, as opposed to "no target" (`""`, `"1m"`, `"off"`)? Deliberately duplicates
19
- * `parseCompactAt`'s no-target spellings rather than importing it, to keep this registry
20
- * dependency-free (see the module doc); an unparseable value (bad k/m suffix, out of range)
21
- * is treated as armed so the gate errs toward requiring the opt-in rather than toward silently
22
- * admitting a value the real parser would reject anyway.
17
+ * Features that used to be experimental and are now on by default for everyone. Their ids are
18
+ * no longer in the registry, but `mnemom experimental enable|disable <id>` still accepts them
19
+ * as a no-op (with a one-line note naming the release and the real opt-out) instead of failing
20
+ * on an id a user, a script or an old README still names. Value: the release that graduated it
21
+ * and how to turn it off now.
23
22
  */
24
- export declare function compactAtArmed(raw: string | undefined): boolean;
23
+ export declare const GRADUATED_FEATURES: Readonly<Record<string, {
24
+ since: string;
25
+ optOut: string;
26
+ }>>;
27
+ /** The one-line note for `mnemom experimental enable|disable <graduated id>`; null otherwise. */
28
+ export declare function graduatedNote(id: string): string | null;
25
29
  export interface ExperimentalFeature {
26
30
  id: ExperimentalId;
27
31
  summary: string;
@@ -82,8 +86,7 @@ export declare function assertEnabled(uses: ReadonlyArray<{
82
86
  export declare function experimentalIdForConfigKey(key: string, value: string): ExperimentalId | undefined;
83
87
  /**
84
88
  * The stderr lines for experimental settings a launch ignores because their feature
85
- * is off: launcher.toml keys (`entries` as `[key, value]`), MNEMOM_AGENT_CONTEXT_HANDOFF,
86
- * MNEMOM_AGENT_COMPACTION_INTERCEPT and MNEMOM_COMPACT_AT (an armed target only).
89
+ * is off: launcher.toml keys (`entries` as `[key, value]`) and MNEMOM_AGENT_CONTEXT_HANDOFF.
87
90
  */
88
91
  export declare function ignoredSettingLines(opts: {
89
92
  entries: ReadonlyArray<[string, string]>;
@@ -13,16 +13,24 @@
13
13
  * modules are the thin drivers.
14
14
  */
15
15
  /**
16
- * Is a `compact_at` / `MNEMOM_COMPACT_AT` value (trimmed, case-insensitive) an ARMED gateway
17
- * target, as opposed to "no target" (`""`, `"1m"`, `"off"`)? Deliberately duplicates
18
- * `parseCompactAt`'s no-target spellings rather than importing it, to keep this registry
19
- * dependency-free (see the module doc); an unparseable value (bad k/m suffix, out of range)
20
- * is treated as armed so the gate errs toward requiring the opt-in rather than toward silently
21
- * admitting a value the real parser would reject anyway.
16
+ * Features that used to be experimental and are now on by default for everyone. Their ids are
17
+ * no longer in the registry, but `mnemom experimental enable|disable <id>` still accepts them
18
+ * as a no-op (with a one-line note naming the release and the real opt-out) instead of failing
19
+ * on an id a user, a script or an old README still names. Value: the release that graduated it
20
+ * and how to turn it off now.
22
21
  */
23
- export function compactAtArmed(raw) {
24
- const v = (raw ?? "").trim().toLowerCase();
25
- return v !== "" && v !== "1m" && v !== "off";
22
+ export const GRADUATED_FEATURES = {
23
+ "compaction-intercept": {
24
+ since: "0.17.23",
25
+ optOut: "--no-compaction-intercept, `compaction_intercept = false` in launcher.toml, or MNEMOM_AGENT_COMPACTION_INTERCEPT=0",
26
+ },
27
+ };
28
+ /** The one-line note for `mnemom experimental enable|disable <graduated id>`; null otherwise. */
29
+ export function graduatedNote(id) {
30
+ const g = GRADUATED_FEATURES[id];
31
+ if (!g)
32
+ return null;
33
+ return `${id} is no longer experimental: it is on by default since ${g.since}, so this changes nothing. To turn it off: ${g.optOut}.`;
26
34
  }
27
35
  export const EXPERIMENTAL_FEATURES = [
28
36
  {
@@ -58,17 +66,6 @@ export const EXPERIMENTAL_FEATURES = [
58
66
  env: [],
59
67
  },
60
68
  },
61
- {
62
- id: "compaction-intercept",
63
- summary: "Have the gateway report the real context size (so Claude Code compacts at its own threshold) and answer the compaction at once from its fold",
64
- since: "0.17.4",
65
- gates: {
66
- flags: ["--compaction-intercept"],
67
- configKeys: ["compaction_intercept"],
68
- commands: [],
69
- env: ["MNEMOM_AGENT_COMPACTION_INTERCEPT"],
70
- },
71
- },
72
69
  {
73
70
  // No flag, launcher.toml key or env of its own: `mnemom experimental enable` is the switch.
74
71
  id: "measured-savings",
@@ -162,25 +159,19 @@ export function experimentalIdForConfigKey(key, value) {
162
159
  return value === "true" ? "slack" : undefined;
163
160
  case "context_handoff":
164
161
  return value === "true" ? "context-handoff" : undefined;
165
- case "compaction_intercept":
166
- return value === "true" ? "compaction-intercept" : undefined;
167
- case "compact_at":
168
- // Arms the SAME gateway keys compaction_intercept does — same gate.
169
- return compactAtArmed(value) ? "compaction-intercept" : undefined;
170
162
  case "goal_mode":
171
163
  return value === "implicit" ? "implicit" : undefined;
172
164
  default:
173
165
  return undefined;
174
166
  }
175
167
  }
176
- /** Is an env value one of the truthy spellings resolveContextHandoff / resolveCompactionIntercept accept? */
168
+ /** Is an env value one of the truthy spellings resolveContextHandoff accepts? */
177
169
  function truthy(raw) {
178
170
  return ["1", "true", "on", "yes"].includes((raw ?? "").trim().toLowerCase());
179
171
  }
180
172
  /**
181
173
  * The stderr lines for experimental settings a launch ignores because their feature
182
- * is off: launcher.toml keys (`entries` as `[key, value]`), MNEMOM_AGENT_CONTEXT_HANDOFF,
183
- * MNEMOM_AGENT_COMPACTION_INTERCEPT and MNEMOM_COMPACT_AT (an armed target only).
174
+ * is off: launcher.toml keys (`entries` as `[key, value]`) and MNEMOM_AGENT_CONTEXT_HANDOFF.
184
175
  */
185
176
  export function ignoredSettingLines(opts) {
186
177
  const lines = [];
@@ -193,14 +184,6 @@ export function ignoredSettingLines(opts) {
193
184
  if (truthy(opts.env.MNEMOM_AGENT_CONTEXT_HANDOFF) && !opts.enabled.includes("context-handoff")) {
194
185
  lines.push(`mnemom agent: ignoring ${gatedMessage("MNEMOM_AGENT_CONTEXT_HANDOFF", "context-handoff")}`);
195
186
  }
196
- if (truthy(opts.env.MNEMOM_AGENT_COMPACTION_INTERCEPT) &&
197
- !opts.enabled.includes("compaction-intercept")) {
198
- lines.push(`mnemom agent: ignoring ${gatedMessage("MNEMOM_AGENT_COMPACTION_INTERCEPT", "compaction-intercept")}`);
199
- }
200
- if (compactAtArmed(opts.env.MNEMOM_COMPACT_AT) &&
201
- !opts.enabled.includes("compaction-intercept")) {
202
- lines.push(`mnemom agent: ignoring ${gatedMessage("MNEMOM_COMPACT_AT", "compaction-intercept")}`);
203
- }
204
187
  return lines;
205
188
  }
206
189
  /** The features an existing launcher.toml already uses (the one-time migration). */
@@ -250,8 +233,6 @@ export function configKeyFeature(key) {
250
233
  return "slack";
251
234
  if (key === "context_handoff")
252
235
  return "context-handoff";
253
- if (key === "compaction_intercept")
254
- return "compaction-intercept";
255
236
  if (key === "goal_mode")
256
237
  return "implicit";
257
238
  return undefined;
@@ -50,9 +50,9 @@ export interface LauncherConfig {
50
50
  */
51
51
  contextHandoff?: boolean;
52
52
  /**
53
- * Compaction-intercept default (EXPERIMENTAL, off when unset): `true` sends
53
+ * Compaction-intercept default (ON when unset, since 0.17.23): `true` sends
54
54
  * `GATEWAY_USAGE_REAL_SIZE: "on"` + `GATEWAY_COMPACTION_INTERCEPT: "on"` in the per-session
55
- * config header for every launch. Off means no header key at all.
55
+ * config header for every launch; `false` opts out and sends both as `"off"`.
56
56
  */
57
57
  compactionIntercept?: boolean;
58
58
  /**
@@ -121,9 +121,8 @@ export declare function launcherEntries(cfg: LauncherConfig): Array<[string, str
121
121
  /**
122
122
  * `cfg` without the settings of experimental features that are off (a copy; `cfg` is
123
123
  * untouched): `slack_*` while `slack` is off, `context_handoff` while `context-handoff` is
124
- * off, `compaction_intercept` (and an ARMED `compact_at` — it arms the same two gateway keys,
125
- * so it needs the same opt-in; `compact_at = "off"`/`"1m"` carries no gated behaviour and is
126
- * kept) while `compaction-intercept` is off, and `goal_mode = implicit` while `implicit` is
127
- * off (`goal_mode = off` is kept).
124
+ * off, and `goal_mode = implicit` while `implicit` is off (`goal_mode = off` is kept).
125
+ * `compaction_intercept` / `compact_at` are not experimental (on by default since 0.17.23) and
126
+ * always pass through.
128
127
  */
129
128
  export declare function withoutDisabledExperimental(cfg: LauncherConfig, enabled: readonly ExperimentalId[]): LauncherConfig;
@@ -20,7 +20,6 @@ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "
20
20
  import { dirname, join } from "node:path";
21
21
  import { parse as parseToml, stringify as stringifyToml, TomlError } from "smol-toml";
22
22
  import { MNEMOM_DIR } from "./config.js";
23
- import { compactAtArmed } from "./experimental.js";
24
23
  import { CONTEXT_PROFILES, isPositiveInt, isPositiveNumber, parseCompactAt, parseContextProfile, } from "./agent.js";
25
24
  /** The human-editable settings file. Secret key lives elsewhere (launcher.json). */
26
25
  export const LAUNCHER_CONFIG_PATH = join(MNEMOM_DIR, "launcher.toml");
@@ -207,7 +206,7 @@ export const CONFIG_KEYS = [
207
206
  },
208
207
  {
209
208
  key: "compaction_intercept",
210
- describe: "EXPERIMENTAL: tell the gateway GATEWAY_USAGE_REAL_SIZE=on + GATEWAY_COMPACTION_INTERCEPT=on (off by default)",
209
+ describe: "Compaction intercept: the gateway reports the real context size and answers Claude Code's compaction from its fold (GATEWAY_USAGE_REAL_SIZE + GATEWAY_COMPACTION_INTERCEPT; on by default, false opts out)",
211
210
  get: (c) => c.compactionIntercept,
212
211
  set: (c, v) => {
213
212
  c.compactionIntercept = coerceBool("compaction_intercept", v);
@@ -467,10 +466,9 @@ export function launcherEntries(cfg) {
467
466
  /**
468
467
  * `cfg` without the settings of experimental features that are off (a copy; `cfg` is
469
468
  * untouched): `slack_*` while `slack` is off, `context_handoff` while `context-handoff` is
470
- * off, `compaction_intercept` (and an ARMED `compact_at` — it arms the same two gateway keys,
471
- * so it needs the same opt-in; `compact_at = "off"`/`"1m"` carries no gated behaviour and is
472
- * kept) while `compaction-intercept` is off, and `goal_mode = implicit` while `implicit` is
473
- * off (`goal_mode = off` is kept).
469
+ * off, and `goal_mode = implicit` while `implicit` is off (`goal_mode = off` is kept).
470
+ * `compaction_intercept` / `compact_at` are not experimental (on by default since 0.17.23) and
471
+ * always pass through.
474
472
  */
475
473
  export function withoutDisabledExperimental(cfg, enabled) {
476
474
  const out = { ...cfg };
@@ -481,11 +479,6 @@ export function withoutDisabledExperimental(cfg, enabled) {
481
479
  }
482
480
  if (!enabled.includes("context-handoff"))
483
481
  delete out.contextHandoff;
484
- if (!enabled.includes("compaction-intercept")) {
485
- delete out.compactionIntercept;
486
- if (compactAtArmed(out.compactAt))
487
- delete out.compactAt;
488
- }
489
482
  if (!enabled.includes("implicit") && out.goalMode === "implicit")
490
483
  delete out.goalMode;
491
484
  return out;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemom/mnemom",
3
- "version": "0.17.21",
3
+ "version": "0.17.23",
4
4
  "description": "Transparent AI agent tracing",
5
5
  "type": "module",
6
6
  "bin": {