@mnemom/mnemom 0.17.33 → 0.17.34-next.2

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 (236) hide show
  1. package/dist/base-url-proxy.mjs +18 -4
  2. package/dist/commands/agent-config.js +5 -1
  3. package/dist/commands/agent-doctor.d.ts +9 -0
  4. package/dist/commands/agent-doctor.js +4 -0
  5. package/dist/commands/agent-session.d.ts +1 -2
  6. package/dist/commands/agent-session.js +1 -2
  7. package/dist/commands/agent-setup.d.ts +6 -0
  8. package/dist/commands/agent-setup.js +12 -1
  9. package/dist/commands/agent-share-render.d.ts +1 -1
  10. package/dist/commands/agent-share-render.js +1 -1
  11. package/dist/commands/agent.d.ts +26 -0
  12. package/dist/commands/agent.js +228 -53
  13. package/dist/commands/durable-doctor.d.ts +50 -0
  14. package/dist/commands/durable-doctor.js +186 -0
  15. package/dist/commands/durable-lock.d.ts +254 -0
  16. package/dist/commands/durable-lock.js +595 -0
  17. package/dist/commands/durable-sessions.d.ts +87 -0
  18. package/dist/commands/durable-sessions.js +303 -0
  19. package/dist/commands/durable-verbs.d.ts +116 -0
  20. package/dist/commands/durable-verbs.js +393 -0
  21. package/dist/commands/protection.js +1 -1
  22. package/dist/commands/scan.d.ts +97 -0
  23. package/dist/commands/scan.js +238 -0
  24. package/dist/durable/flock.d.ts +26 -0
  25. package/dist/durable/flock.js +80 -0
  26. package/dist/durable/launch-spec.d.ts +7 -1
  27. package/dist/durable/launch-spec.js +10 -3
  28. package/dist/durable/seat-proxy-entry.d.ts +11 -0
  29. package/dist/durable/seat-proxy-entry.js +25 -0
  30. package/dist/durable/seat-proxy.d.ts +107 -0
  31. package/dist/durable/seat-proxy.js +599 -0
  32. package/dist/durable/seat-socket.d.ts +46 -0
  33. package/dist/durable/seat-socket.js +179 -0
  34. package/dist/durable/seat-spec-validator.d.ts +28 -0
  35. package/dist/durable/seat-spec-validator.js +59 -0
  36. package/dist/durable/test-mode.mjs +81 -0
  37. package/dist/durable/turn-chain.d.ts +55 -0
  38. package/dist/durable/turn-chain.js +178 -0
  39. package/dist/host/auto-continue.d.ts +67 -0
  40. package/dist/host/auto-continue.js +118 -0
  41. package/dist/host/bootid.d.ts +13 -0
  42. package/dist/host/bootid.js +41 -0
  43. package/dist/host/client.d.ts +123 -0
  44. package/dist/host/client.js +171 -0
  45. package/dist/host/commands.d.ts +2 -0
  46. package/dist/host/commands.js +122 -0
  47. package/dist/host/control.d.ts +33 -0
  48. package/dist/host/control.js +144 -0
  49. package/dist/host/daemon.d.ts +217 -0
  50. package/dist/host/daemon.js +606 -0
  51. package/dist/host/gate.d.ts +46 -0
  52. package/dist/host/gate.js +82 -0
  53. package/dist/host/grant.d.ts +24 -0
  54. package/dist/host/grant.js +24 -0
  55. package/dist/host/instance.d.ts +35 -0
  56. package/dist/host/instance.js +62 -0
  57. package/dist/host/integrity.d.ts +35 -0
  58. package/dist/host/integrity.js +115 -0
  59. package/dist/host/launchd.d.ts +16 -0
  60. package/dist/host/launchd.js +45 -0
  61. package/dist/host/lock.d.ts +20 -0
  62. package/dist/host/lock.js +63 -0
  63. package/dist/host/owner.d.ts +55 -0
  64. package/dist/host/owner.js +121 -0
  65. package/dist/host/plist.d.ts +16 -0
  66. package/dist/host/plist.js +85 -0
  67. package/dist/host/procs.d.ts +27 -0
  68. package/dist/host/procs.js +105 -0
  69. package/dist/host/run.d.ts +66 -0
  70. package/dist/host/run.js +314 -0
  71. package/dist/host/runtime.d.ts +8 -0
  72. package/dist/host/runtime.js +22 -0
  73. package/dist/host/s1-names.d.ts +22 -0
  74. package/dist/host/s1-names.js +21 -0
  75. package/dist/host/seat-credential.d.ts +27 -0
  76. package/dist/host/seat-credential.js +41 -0
  77. package/dist/host/seat-launch-main.d.ts +1 -0
  78. package/dist/host/seat-launch-main.js +59 -0
  79. package/dist/host/seat-launch.d.ts +116 -0
  80. package/dist/host/seat-launch.js +302 -0
  81. package/dist/host/seat.d.ts +48 -0
  82. package/dist/host/seat.js +149 -0
  83. package/dist/host/state.d.ts +33 -0
  84. package/dist/host/state.js +117 -0
  85. package/dist/host/status.d.ts +101 -0
  86. package/dist/host/status.js +307 -0
  87. package/dist/host/tmux.d.ts +56 -0
  88. package/dist/host/tmux.js +182 -0
  89. package/dist/host/transcript.d.ts +30 -0
  90. package/dist/host/transcript.js +130 -0
  91. package/dist/host/verbs.d.ts +50 -0
  92. package/dist/host/verbs.js +271 -0
  93. package/dist/index.d.ts +8 -6
  94. package/dist/index.js +232 -35
  95. package/dist/lib/agent.d.ts +8 -26
  96. package/dist/lib/agent.js +11 -26
  97. package/dist/lib/api.d.ts +13 -0
  98. package/dist/lib/api.js +8 -0
  99. package/dist/lib/claude-plugin.d.ts +11 -2
  100. package/dist/lib/claude-plugin.js +10 -1
  101. package/dist/lib/durable/api.d.ts +136 -0
  102. package/dist/lib/durable/api.js +220 -0
  103. package/dist/lib/durable/codes.d.ts +8 -0
  104. package/dist/lib/durable/codes.js +2 -0
  105. package/dist/lib/durable/first-turn.d.ts +50 -0
  106. package/dist/lib/durable/first-turn.js +102 -0
  107. package/dist/lib/durable/gate.d.ts +48 -0
  108. package/dist/lib/durable/gate.js +122 -0
  109. package/dist/lib/durable/handover.d.ts +101 -0
  110. package/dist/lib/durable/handover.js +175 -0
  111. package/dist/lib/durable/launch.d.ts +182 -0
  112. package/dist/lib/durable/launch.js +443 -0
  113. package/dist/lib/durable/launching.d.ts +15 -0
  114. package/dist/lib/durable/launching.js +70 -0
  115. package/dist/lib/durable/live.d.ts +194 -0
  116. package/dist/lib/durable/live.js +635 -0
  117. package/dist/lib/durable/refusal.d.ts +57 -0
  118. package/dist/lib/durable/refusal.js +78 -0
  119. package/dist/lib/durable/view.d.ts +83 -0
  120. package/dist/lib/durable/view.js +244 -0
  121. package/dist/lib/experimental.d.ts +0 -9
  122. package/dist/lib/experimental.js +18 -17
  123. package/dist/lib/launcher-config.d.ts +7 -0
  124. package/dist/lib/launcher-config.js +21 -0
  125. package/dist/lib/scan/caps.d.ts +35 -0
  126. package/dist/lib/scan/caps.js +67 -0
  127. package/dist/lib/scan/credential.d.ts +37 -0
  128. package/dist/lib/scan/credential.js +104 -0
  129. package/dist/lib/scan/failure.d.ts +10 -0
  130. package/dist/lib/scan/failure.js +43 -0
  131. package/dist/lib/scan/pr-source.d.ts +57 -0
  132. package/dist/lib/scan/pr-source.js +130 -0
  133. package/dist/lib/scan/record.d.ts +49 -0
  134. package/dist/lib/scan/record.js +85 -0
  135. package/dist/lib/scan/report-email.d.ts +92 -0
  136. package/dist/lib/scan/report-email.js +144 -0
  137. package/dist/lib/scan/report.d.ts +13 -0
  138. package/dist/lib/scan/report.js +30 -0
  139. package/dist/lib/scan/scan.d.ts +64 -0
  140. package/dist/lib/scan/scan.js +182 -0
  141. package/dist/lib/scan/share.d.ts +38 -0
  142. package/dist/lib/scan/share.js +47 -0
  143. package/dist/lib/scan/spend/ai-tool-detect.d.ts +6 -0
  144. package/dist/lib/scan/spend/ai-tool-detect.js +18 -0
  145. package/dist/lib/scan/spend/anthropic-usage.d.ts +57 -0
  146. package/dist/lib/scan/spend/anthropic-usage.js +244 -0
  147. package/dist/lib/scan/spend/cost-corpus.v1.d.ts +56 -0
  148. package/dist/lib/scan/spend/cost-corpus.v1.js +64 -0
  149. package/dist/lib/scan/spend/prices.d.ts +33 -0
  150. package/dist/lib/scan/spend/prices.js +57 -0
  151. package/dist/lib/scan/spend/spend-estimate.d.ts +30 -0
  152. package/dist/lib/scan/spend/spend-estimate.js +70 -0
  153. package/dist/lib/scan/spend/spend-tiers.d.ts +25 -0
  154. package/dist/lib/scan/spend/spend-tiers.js +42 -0
  155. package/dist/lib/scan/spend/token-rate.d.ts +30 -0
  156. package/dist/lib/scan/spend/token-rate.js +54 -0
  157. package/dist/lib/session-key.d.ts +41 -0
  158. package/dist/lib/session-key.js +124 -0
  159. package/dist/lib/subscription-login.d.ts +15 -0
  160. package/dist/lib/subscription-login.js +28 -1
  161. package/dist/rc-key-401.mjs +75 -0
  162. package/dist/rc-proxy.mjs +221 -25
  163. package/dist/vendor/durable-contract/index.js +240 -18
  164. package/dist/vendor/shared/durable-contract/admission.d.ts +240 -0
  165. package/dist/vendor/shared/durable-contract/admission.js +533 -0
  166. package/dist/vendor/shared/durable-contract/arm.d.ts +51 -0
  167. package/dist/vendor/shared/durable-contract/arm.js +133 -0
  168. package/dist/vendor/shared/durable-contract/canonical.d.ts +29 -0
  169. package/dist/vendor/shared/durable-contract/canonical.js +98 -0
  170. package/dist/vendor/shared/durable-contract/cell-id.d.ts +22 -0
  171. package/dist/vendor/shared/durable-contract/cell-id.js +38 -0
  172. package/dist/vendor/shared/durable-contract/cli-output.d.ts +342 -0
  173. package/dist/vendor/shared/durable-contract/cli-output.js +201 -0
  174. package/dist/vendor/shared/durable-contract/cli-surface.d.ts +119 -0
  175. package/dist/vendor/shared/durable-contract/cli-surface.js +270 -0
  176. package/dist/vendor/shared/durable-contract/codes.d.ts +537 -0
  177. package/dist/vendor/shared/durable-contract/codes.js +475 -0
  178. package/dist/vendor/shared/durable-contract/constants.d.ts +153 -0
  179. package/dist/vendor/shared/durable-contract/constants.js +179 -0
  180. package/dist/vendor/shared/durable-contract/doors.d.ts +119 -0
  181. package/dist/vendor/shared/durable-contract/doors.js +249 -0
  182. package/dist/vendor/shared/durable-contract/envelope.d.ts +103 -0
  183. package/dist/vendor/shared/durable-contract/envelope.js +317 -0
  184. package/dist/vendor/shared/durable-contract/events.d.ts +147 -0
  185. package/dist/vendor/shared/durable-contract/events.js +630 -0
  186. package/dist/vendor/shared/durable-contract/executor-state.d.ts +41 -0
  187. package/dist/vendor/shared/durable-contract/executor-state.js +32 -0
  188. package/dist/vendor/shared/durable-contract/fixlines.d.ts +318 -0
  189. package/dist/vendor/shared/durable-contract/fixlines.js +483 -0
  190. package/dist/vendor/shared/durable-contract/freeze-record.d.ts +787 -0
  191. package/dist/vendor/shared/durable-contract/freeze-record.js +361 -0
  192. package/dist/vendor/shared/durable-contract/index.d.ts +36 -0
  193. package/dist/vendor/shared/durable-contract/index.js +37 -0
  194. package/dist/vendor/shared/durable-contract/journal-approvals.d.ts +29 -0
  195. package/dist/vendor/shared/durable-contract/journal-approvals.js +60 -0
  196. package/dist/vendor/shared/durable-contract/keys.d.ts +24 -0
  197. package/dist/vendor/shared/durable-contract/keys.js +66 -0
  198. package/dist/vendor/shared/durable-contract/lock.d.ts +128 -0
  199. package/dist/vendor/shared/durable-contract/lock.js +151 -0
  200. package/dist/vendor/shared/durable-contract/names.d.ts +25 -0
  201. package/dist/vendor/shared/durable-contract/names.js +78 -0
  202. package/dist/vendor/shared/durable-contract/owner-verbs.d.ts +175 -0
  203. package/dist/vendor/shared/durable-contract/owner-verbs.js +403 -0
  204. package/dist/vendor/shared/durable-contract/paths.d.ts +23 -0
  205. package/dist/vendor/shared/durable-contract/paths.js +35 -0
  206. package/dist/vendor/shared/durable-contract/pure-fn.d.ts +48 -0
  207. package/dist/vendor/shared/durable-contract/pure-fn.js +89 -0
  208. package/dist/vendor/shared/durable-contract/routes.d.ts +205 -0
  209. package/dist/vendor/shared/durable-contract/routes.js +315 -0
  210. package/dist/vendor/shared/durable-contract/schema.d.ts +126 -0
  211. package/dist/vendor/shared/durable-contract/schema.js +441 -0
  212. package/dist/vendor/shared/durable-contract/seal.d.ts +54 -0
  213. package/dist/vendor/shared/durable-contract/seal.js +99 -0
  214. package/dist/vendor/shared/durable-contract/secret-scope.d.ts +28 -0
  215. package/dist/vendor/shared/durable-contract/secret-scope.js +76 -0
  216. package/dist/vendor/shared/durable-contract/session-id.d.ts +21 -0
  217. package/dist/vendor/shared/durable-contract/session-id.js +58 -0
  218. package/dist/vendor/shared/durable-contract/spec.d.ts +162 -0
  219. package/dist/vendor/shared/durable-contract/spec.js +286 -0
  220. package/dist/vendor/shared/durable-contract/states.d.ts +96 -0
  221. package/dist/vendor/shared/durable-contract/states.js +218 -0
  222. package/dist/vendor/shared/durable-contract/telemetry.d.ts +94 -0
  223. package/dist/vendor/shared/durable-contract/telemetry.js +180 -0
  224. package/dist/vendor/shared/durable-contract/test-mode.d.ts +62 -0
  225. package/dist/vendor/shared/durable-contract/test-mode.js +140 -0
  226. package/dist/vendor/shared/durable-contract/turn.d.ts +57 -0
  227. package/dist/vendor/shared/durable-contract/turn.js +81 -0
  228. package/dist/vendor/shared/durable-contract/vectors.d.ts +191 -0
  229. package/dist/vendor/shared/durable-contract/vectors.js +208 -0
  230. package/package.json +4 -3
  231. package/plugins/integrity-manifest.json +35 -0
  232. package/plugins/mnemom/hooks/hooks.json +15 -1
  233. package/plugins/mnemom/hooks/register.tsx +60 -2
  234. package/plugins/mnemom/hooks/seat-hello.mjs +116 -0
  235. package/dist/commands/agent-implicit-notice.d.ts +0 -31
  236. package/dist/commands/agent-implicit-notice.js +0 -73
@@ -0,0 +1,483 @@
1
+ // GENERATED from shared/durable-contract/src/fixlines.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
2
+ /**
3
+ * The fix-line catalogue, the fix-line rule and the catalogue lint (BACKBONE "Fix-line catalogue",
4
+ * "Fix-line rule"; C01-R16, C02-R05/R26, C11-R09/R27, C14-R11, C16-R29, final F04/F06/F11/F14).
5
+ *
6
+ * Every line is quoted ONCE here and rendered by `renderFixLine`; no other module restates one.
7
+ * An entry is `lead + [done clause] + body + [suffix]`:
8
+ * - `ruled` entries (their body contains `mnemom agent <name> --new`) obey the fix-line rule:
9
+ * (a) DONE_CLAUSE is inserted before the body whenever a non-terminal row holds the name
10
+ * (the caller says so: `nameHeld`); (b) LAUNCHER_SUFFIX is appended whenever the launcher
11
+ * key is not `always`.
12
+ * - every other entry renders lead + body verbatim.
13
+ * Placeholders are `<name>`-style; `renderFixLine` refuses a missing or unknown one.
14
+ *
15
+ * Text decisions recorded here (S1 owns them):
16
+ * - Every done clause is "`mnemom agent done <name>`, then " WITH the comma (the rule's own
17
+ * wording). Two backbone quotations of the `budget_at_limit` and `guard` lines omit the comma;
18
+ * the rule governs, so the catalogue carries the comma everywhere.
19
+ * - The unattended line puts the command in backticks like every other line (C08-R14 wording;
20
+ * the C06-R14 quotation without backticks is the same line).
21
+ */
22
+ import { ATTESTATION_CHECKS_M1 } from "./codes.js";
23
+ import { PER_SESSION_BUDGET_LIMIT_USD, RESPAWN_FAILURES_SUSPEND_AT, RISK_LINE_VERSION, } from "./constants.js";
24
+ export const LAUNCHER_KEYS = ["off", "ask", "always"];
25
+ export const DONE_CLAUSE = "`mnemom agent done <name>`, then ";
26
+ export const LAUNCHER_SUFFIX = " (set `mnemom agent config set durable always` first)";
27
+ export const NEW_TOKEN = "mnemom agent <name> --new";
28
+ const e = (kind, body, lead = "") => ({ kind, lead, body });
29
+ export const FIX_LINES = {
30
+ // ---- budget (C08-R24, C11-R09, C16-R29) ----
31
+ budget_reached: e("command", "budget reached: `mnemom agent amend <name> --budget <n>` (up to <limit>)"),
32
+ above_limit_raise: e("command", "raise up to <limit>: `mnemom agent amend <name> --budget <limit>`"),
33
+ budget_at_limit: e("command", "`mnemom agent <name> --new`", "budget is at the per-session limit (<limit>): "),
34
+ // ---- ended and killed ----
35
+ agent_killed: e("command", "the agent was killed; start this work with another agent: `mnemom agent <name> --agent <another-agent>`"),
36
+ session_ended: e("command", "`mnemom agent <name> --new`", "this session has ended; start fresh: "),
37
+ session_transcript_missing: e("command", "`mnemom agent <name> --new`"),
38
+ // ---- stopped reasons (C01-R16 d-i, C11-R09) ----
39
+ paused_owner: e("command", "`mnemom agent resume <name>`"),
40
+ agent_contained: e("command", "an org admin resumes the agent: `mnemom agent containment resume <agent>`"),
41
+ respawn_failed: e("command", "`mnemom agent resume <name>`"),
42
+ attestation_failed: e("command", "`mnemom agent resume <name>`"),
43
+ /** suspended(approval_expired|approval_denied) (ruling 34.22): the wait was left; the owner resumes by hand. */
44
+ approval_expired: e("command", "`mnemom agent resume <name>`", "the approval expired and this session needs you to resume it: "),
45
+ approval_denied: e("command", "`mnemom agent resume <name>`", "the approval was denied and this session needs you to resume it: "),
46
+ attestation_cwd_missing: e("command", "`cd <toplevel> && mnemom agent <name> --new`", "restore <cwd> (e.g. `git worktree add <cwd> <branch>`), then `mnemom agent resume <name>`; or "),
47
+ attestation_cwd_not_toplevel: e("command", "`cd <checkout> && mnemom agent <name> --new`"),
48
+ grant_expired: e("command", "`mnemom agent host renew`"),
49
+ grant_warning: e("command", "grant ends in <days> days: `mnemom agent host renew`"),
50
+ identity_mismatch: e("command", "`mnemom agent <name> --new`"),
51
+ /**
52
+ * Stopped reasons M1 has no remedy for (wave-0 fix ruling 4): suspended(card_drift,
53
+ * enforce_refused, charter_breach, owner_departed), paused(breakglass) and the fixture-only
54
+ * paused(null). done-then-new is the only exit that works in M1.
55
+ */
56
+ stopped_no_m1_remedy: e("command", "`mnemom agent <name> --new`", "this session cannot be resumed in this release: "),
57
+ /** suspended(account_balance) (wave-0 fix ruling 4). */
58
+ account_balance: e("command", "`mnemom agent <name> --new`", "the Mnemom account is out of credit; add credit, then "),
59
+ /** budget_raise (or amend --budget) on paused(owner) (wave-0 fix ruling 4). */
60
+ budget_while_paused: e("command", "resume it first: `mnemom agent resume <name>`, then `mnemom agent amend <name> --budget <n>`"),
61
+ // ---- claim unavailable surfaced by host status (C08-R16, C12-R30) ----
62
+ guard: e("command", "`mnemom agent <name> --new`"),
63
+ // ---- home and daemon (C01-R16 b, c, k; C01-R28; C12-R39) ----
64
+ seat_wait_timeout: e("command", "`mnemom agent host status`"),
65
+ daemon_not_running: e("command", "the host daemon is not running here: `mnemom agent host install`"),
66
+ daemon_idle: e("command", "`mnemom experimental enable durable`", "daemon: idle (durable disabled in config): "),
67
+ unreachable_home: e("command", "`mnemom agent <name> --new`"),
68
+ session_homed_elsewhere: e("command", "run `mnemom agent <name>` on <machine>"),
69
+ session_homed_elsewhere_stale: e("command", "`mnemom agent <name> --new`", "run `mnemom agent <name>` on <machine>; if <machine> is gone for good: "),
70
+ resume_live: e("command", "`mnemom agent <name>` attaches"),
71
+ // ---- lock (C02-R05, R22, R26, R27) ----
72
+ lock_not_entitled: e("action", "durable sessions are not enabled for this org yet: ask support@mnemom.ai"),
73
+ lock_mfa_required: e("action", "enrol a passkey or TOTP factor, then check with `mnemom agent doctor`"),
74
+ lock_branch_unprotected: e("action", "add a ruleset or branch protection to <repo>, then rerun"),
75
+ lock_agent_shared: e("command", "`mnemom agent lock <name> --own-agent`"),
76
+ no_executor: e("command", "`mnemom agent host install`"),
77
+ tool_classes: e("action", "declare every tool input_dependent (or omit tool_classes) and lock again"),
78
+ remote_control: e("command", "`mnemom agent lock <name>` (the CLI drops --remote-control)"),
79
+ cwd_subdirectory: e("command", "start it at the repo root: `cd <toplevel> && mnemom agent <name> --new`"),
80
+ cwd_not_git: e("command", "start it in a git checkout: `cd <checkout> && mnemom agent <name> --new`"),
81
+ cwd_symlink_transcript: e("command", "`cd <realpath> && mnemom agent <name> --new`"),
82
+ launch_spec_change: e("command", "`mnemom agent <name> --new <flags>`"),
83
+ /** C14-R11: offered beside launch_spec_change only when this is the agent's sole locked session. */
84
+ launch_spec_change_sole_unlock: e("command", "`mnemom agent sessions unlock <name>`, relaunch, `mnemom agent lock <name>`"),
85
+ // ---- durable-only (C02-R24, final F11): the trailing config clause is added by renderDurableOnly ----
86
+ // ruling 21: `<another-agent>` is printed literally (never filled in); the hyphen keeps it outside
87
+ // PLACEHOLDER_RE, so no caller supplies a value for it.
88
+ durable_only_agent: e("command", "`mnemom agent <name> --agent <another-agent>`, or <precondition>"),
89
+ // The api's create refusal while another session is locked on the agent (dogfood walk5): the
90
+ // reader finishes or reuses the holder, or starts <name> on another agent. <holder> is the
91
+ // locked session's name; `<another-agent>` stays literal (ruling 21).
92
+ durable_only_held: e("command", "<holder> is locked on this agent: finish it with `mnemom agent done <holder>`, carry on in it with `mnemom agent <holder>`, or start <name> on another agent with `mnemom agent <name> --agent <another-agent>`"),
93
+ // ---- owner verbs (owner-verb table step 3; final F04, F06) ----
94
+ not_owner_admin: e("command", "an org admin can stop the agent: `mnemom agent containment pause <agent>`"),
95
+ not_owner_info: e("informational", "this session belongs to <owner>"),
96
+ tracked_pause: e("command", "pause applies to locked sessions: `mnemom agent lock <name>`, then `mnemom agent pause <name>`"),
97
+ tracked_resume: e("command", "this session is not paused; continue it: `mnemom agent <name>`"),
98
+ tracked_budget: e("command", "budgets apply to locked sessions: `mnemom agent lock <name>`"),
99
+ device_step_login: e("command", "this change needs a signed-in owner: `mnemom login`, then rerun"),
100
+ containment_login: e("command", "org containment needs a signed-in admin: `mnemom login`, then rerun"),
101
+ // ---- plugin integrity before claim (ruling 25; RULINGS-evals U13; C12-R36, C14-R28) ----
102
+ integrity: e("command", "installed CLI fails its integrity check: `npm i -g @mnemom/mnemom@<cli_version>`"),
103
+ // ---- gateway unattended (C06-R14, C08-R14) ----
104
+ unattended: e("command", "unattended work starts in a later release; type in the seat (`mnemom agent <name>`)"),
105
+ };
106
+ /** The clause renderDurableOnly appends for launcher keys off and ask (C02-R24). */
107
+ export const DURABLE_ONLY_CONFIG_CLAUSE = ", or `mnemom agent config set durable always` and rerun";
108
+ export function isRuled(entry) {
109
+ return entry.body.includes(NEW_TOKEN);
110
+ }
111
+ const PLACEHOLDER_RE = /<([a-z_]+)>/g;
112
+ function substitute(template, params) {
113
+ return template.replace(PLACEHOLDER_RE, (_, p) => {
114
+ const v = params[p];
115
+ if (v === undefined)
116
+ throw new RangeError(`fix line placeholder <${p}> has no value`);
117
+ return v;
118
+ });
119
+ }
120
+ /** The placeholders an entry needs (lead, done clause when ruled, body). */
121
+ export function placeholdersOf(key) {
122
+ const entry = FIX_LINES[key];
123
+ const text = entry.lead + (isRuled(entry) ? DONE_CLAUSE : "") + entry.body;
124
+ return [...new Set([...text.matchAll(PLACEHOLDER_RE)].map((m) => m[1]))];
125
+ }
126
+ /** Render one catalogue entry under the fix-line rule. Throws on an unknown or missing placeholder. */
127
+ export function renderFixLine(key, ctx) {
128
+ const entry = FIX_LINES[key];
129
+ if (!isRuled(entry))
130
+ return substitute(entry.lead + entry.body, ctx.params);
131
+ const done = ctx.nameHeld ? DONE_CLAUSE : "";
132
+ const suffix = ctx.launcherKey === "always" ? "" : LAUNCHER_SUFFIX;
133
+ return substitute(entry.lead + done + entry.body, ctx.params) + suffix;
134
+ }
135
+ /** The durable_only_agent entry's trailing precondition clause (C02-R24, wave-0 fix ruling 16.1). */
136
+ export const DURABLE_ONLY_PRECONDITION_CLAUSE = ", or <precondition>";
137
+ /**
138
+ * The frozen <precondition> clause of each lock fix entry (wave-0 fix ruling 16.1), worded by the
139
+ * kind of fix so a whole fix entry is never wrapped in 'fix ... and rerun': a setup command run
140
+ * before relaunching ('run `<cmd>` and rerun'); a command that is itself the relaunch (the cwd
141
+ * entries: no rerun); an action, then a retry ('<action>, then rerun', rerun once); nothing the
142
+ * user can fix alone (not entitled: who can, no rerun). Every clause starts lowercase after ', or '.
143
+ */
144
+ export const DURABLE_ONLY_PRECONDITION = Object.freeze({
145
+ lock_not_entitled: "ask support@mnemom.ai to enable durable sessions for this org",
146
+ lock_mfa_required: "enrol a passkey or TOTP factor (check with `mnemom agent doctor`), then rerun",
147
+ lock_branch_unprotected: "add a ruleset or branch protection to <repo>, then rerun",
148
+ lock_agent_shared: "run `mnemom agent lock <name> --own-agent` and rerun",
149
+ no_executor: "run `mnemom agent host install` and rerun",
150
+ cwd_subdirectory: "start it at the repo root: `cd <toplevel> && mnemom agent <name> --new`",
151
+ cwd_not_git: "start it in a git checkout: `cd <checkout> && mnemom agent <name> --new`",
152
+ cwd_symlink_transcript: "start it from the real path: `cd <realpath> && mnemom agent <name> --new`",
153
+ });
154
+ /**
155
+ * The fix entry of each lock refusal code (wave-0 fix ruling 16): what fills durable_only_agent's
156
+ * <precondition>. durable_cwd_not_root picks its entry by cwd_kind; durable_precondition_unavailable
157
+ * is null: it means retry, so the durable-only line carries no precondition clause for it.
158
+ */
159
+ export const LOCK_REFUSAL_FIX = Object.freeze({
160
+ durable_lock_not_entitled: "lock_not_entitled",
161
+ durable_lock_mfa_required: "lock_mfa_required",
162
+ durable_lock_branch_unprotected: "lock_branch_unprotected",
163
+ durable_lock_agent_shared: "lock_agent_shared",
164
+ durable_no_executor: "no_executor",
165
+ durable_cwd_not_root: Object.freeze({
166
+ subdirectory: "cwd_subdirectory",
167
+ not_git: "cwd_not_git",
168
+ symlink_transcript: "cwd_symlink_transcript",
169
+ }),
170
+ durable_precondition_unavailable: null,
171
+ });
172
+ /** The fix entry a lock refusal fills <precondition> with, or null (no clause). Throws when durable_cwd_not_root has no cwd_kind. */
173
+ export function lockRefusalFixKey(refusal) {
174
+ const v = LOCK_REFUSAL_FIX[refusal.code];
175
+ if (v === null || typeof v === "string")
176
+ return v;
177
+ if (refusal.cwd_kind === undefined)
178
+ throw new RangeError(`${refusal.code} needs a cwd_kind to pick its fix entry`);
179
+ return v[refusal.cwd_kind];
180
+ }
181
+ /**
182
+ * The durable_only_agent entry (final F11; wave-0 fix rulings 6, Wassim option 1, and 16). The
183
+ * precondition clause appears only when a lock precondition really refused (`refusal` non-null and
184
+ * not durable_precondition_unavailable); its <precondition> is the clause DURABLE_ONLY_PRECONDITION
185
+ * holds for the refusing code's fix entry (LOCK_REFUSAL_FIX; ruling 16.1), rendered with `name`
186
+ * plus `fixParams` (<repo>, <toplevel>, <checkout>, <realpath>). The config clause appears only
187
+ * for launcher keys off and ask; never an unlock offer. So off, ask answered N and non-TTY ask (no
188
+ * lock attempted) print the other-agent and config options; always with a lock refusal prints the other-agent and precondition options; ask
189
+ * answered Y with a lock refusal prints all three, in that order.
190
+ */
191
+ export function renderDurableOnly(launcherKey, params) {
192
+ return renderDurableOnlyWith(DURABLE_ONLY_PRECONDITION, launcherKey, params);
193
+ }
194
+ function renderDurableOnlyWith(clauses, launcherKey, params) {
195
+ const body = FIX_LINES.durable_only_agent.body;
196
+ const otherOnly = body.slice(0, body.length - DURABLE_ONLY_PRECONDITION_CLAUSE.length);
197
+ const { name, refusal } = params;
198
+ const key = refusal === null ? null : lockRefusalFixKey(refusal);
199
+ const base = key === null
200
+ ? substitute(otherOnly, { name })
201
+ : substitute(body, {
202
+ name,
203
+ precondition: substitute(clauses[key], { ...params.fixParams, name }),
204
+ });
205
+ return launcherKey === "always" ? base : base + DURABLE_ONLY_CONFIG_CLAUSE;
206
+ }
207
+ /**
208
+ * The api's durable_only_agent answer to a create while another session (<holder>) is locked on the
209
+ * agent: the durable_only_held entry. Distinct from renderDurableOnly, which is the launcher's own
210
+ * line when THIS launch would not end locked.
211
+ */
212
+ export function renderDurableOnlyHeld(params) {
213
+ return substitute(FIX_LINES.durable_only_held.body, { name: params.name, holder: params.holder });
214
+ }
215
+ // ---- Stopped-state fixes (wave-0 fix ruling 4) ------------------------------------------------
216
+ /** The stopped effective states: the ones a row-8 owner-verb refusal and the CLI stopped line cover. */
217
+ export const STOPPED_EFFECTIVE_STATES = ["paused", "suspended", "suspended_grant_expired"];
218
+ /** The key STOPPED_FIX uses for a NULL state_reason, and for "any reason" under suspended_grant_expired. */
219
+ export const STOPPED_FIX_NULL_REASON = "null";
220
+ export const STOPPED_FIX_ANY_REASON = "*";
221
+ /**
222
+ * One map for owner-verb row-8 refusals and the CLI's stopped-state line, so they cannot diverge:
223
+ * effective state -> state_reason -> fix key. Total over every stopped (state, reason) pair in
224
+ * STATE_REASONS; suspended_grant_expired takes grant_expired over any stored reason. Two entries
225
+ * are refined by stoppedFixKey: budget_reached becomes budget_at_limit at or above the per-session
226
+ * limit, and attestation_failed with a cwd cause takes its attestation_cwd_* line.
227
+ */
228
+ export const STOPPED_FIX = Object.freeze({
229
+ paused: Object.freeze({
230
+ [STOPPED_FIX_NULL_REASON]: "stopped_no_m1_remedy",
231
+ owner: "paused_owner",
232
+ agent_contained: "agent_contained",
233
+ breakglass: "stopped_no_m1_remedy",
234
+ }),
235
+ suspended: Object.freeze({
236
+ budget_reached: "budget_reached",
237
+ enforce_refused: "stopped_no_m1_remedy",
238
+ charter_breach: "stopped_no_m1_remedy",
239
+ account_balance: "account_balance",
240
+ identity_mismatch: "identity_mismatch",
241
+ grant_expired: "grant_expired",
242
+ card_drift: "stopped_no_m1_remedy",
243
+ attestation_failed: "attestation_failed",
244
+ owner_departed: "stopped_no_m1_remedy",
245
+ respawn_failed: "respawn_failed",
246
+ approval_expired: "approval_expired",
247
+ approval_denied: "approval_denied",
248
+ }),
249
+ suspended_grant_expired: Object.freeze({ [STOPPED_FIX_ANY_REASON]: "grant_expired" }),
250
+ });
251
+ /** The STOPPED_FIX entry for an effective state and its stored reason. Throws on a non-stopped state or a reason the state cannot carry. */
252
+ export function stoppedFixKey(effective, reason, opts = {}) {
253
+ if (effective === "suspended_grant_expired")
254
+ return STOPPED_FIX.suspended_grant_expired["*"];
255
+ if (effective !== "paused" && effective !== "suspended")
256
+ throw new RangeError(`not a stopped state: ${effective}`);
257
+ const table = STOPPED_FIX[effective];
258
+ const k = reason === null ? STOPPED_FIX_NULL_REASON : reason;
259
+ const key = Object.prototype.hasOwnProperty.call(table, k) ? table[k] : undefined;
260
+ if (key === undefined)
261
+ throw new RangeError(`${effective} cannot carry reason ${String(reason)}`);
262
+ if (key === "budget_reached")
263
+ return budgetFixKey(opts.committedBudgetUsd ?? 0, PER_SESSION_BUDGET_LIMIT_USD, "reached");
264
+ if (key === "attestation_failed" && opts.cwdCause === "missing")
265
+ return "attestation_cwd_missing";
266
+ if (key === "attestation_failed" && opts.cwdCause === "not_toplevel")
267
+ return "attestation_cwd_not_toplevel";
268
+ return key;
269
+ }
270
+ /**
271
+ * The check-specific sentence `mnemom agent <name>` prints next to the `mnemom agent resume <name>`
272
+ * fix for these two stopped reasons (wave-0 fix ruling 1.22; RULINGS-evals C11 U05 note). <n> is
273
+ * RESPAWN_FAILURES_SUSPEND_AT; <check> is the check of the session's last attestation.failed.
274
+ */
275
+ export const STOPPED_REASON_TEXT = Object.freeze({
276
+ respawn_failed: "the seat failed to start <n> times in a row",
277
+ attestation_failed: "the claim check <check> failed",
278
+ });
279
+ export function renderStoppedReasonText(reason, check) {
280
+ if (reason === "respawn_failed")
281
+ return substitute(STOPPED_REASON_TEXT.respawn_failed, {
282
+ n: String(RESPAWN_FAILURES_SUSPEND_AT),
283
+ });
284
+ if (check === undefined || !ATTESTATION_CHECKS_M1.includes(check))
285
+ throw new RangeError(`not an M1 attestation check: ${String(check)}`);
286
+ return substitute(STOPPED_REASON_TEXT.attestation_failed, { check });
287
+ }
288
+ /**
289
+ * The attestation check the C01 stopped-line fixtures seed in their last attestation.failed
290
+ * (check 12, branch protection: reachable in M1). The dataset seeds `$S1.U05_FIXTURE_CHECK`.
291
+ */
292
+ export const U05_FIXTURE_CHECK = "12";
293
+ /** The rendered texts the C01-X-055/056 fixtures assert (n = 3; check = U05_FIXTURE_CHECK). */
294
+ export const U05_CHECK_TEXT_RESPAWN_FAILED = renderStoppedReasonText("respawn_failed");
295
+ export const U05_CHECK_TEXT_ATTESTATION_FAILED = renderStoppedReasonText("attestation_failed", U05_FIXTURE_CHECK);
296
+ /** The budget refusal fix (429, 422 and stopped): amend while below the limit, budget_at_limit at or above it. */
297
+ export function budgetFixKey(committedBudgetUsd, limitUsd, surface) {
298
+ if (committedBudgetUsd >= limitUsd)
299
+ return "budget_at_limit";
300
+ return surface === "reached" ? "budget_reached" : "above_limit_raise";
301
+ }
302
+ // ---- Lint (C11-R27 static half: the eval executes the lines; this checks their shape) ----------
303
+ /** Commands that exist in M1. A backticked command must start with one of these. */
304
+ export const M1_COMMAND_PREFIXES = [
305
+ "mnemom agent ",
306
+ "mnemom login",
307
+ "mnemom experimental enable durable",
308
+ "cd <",
309
+ "git worktree add ",
310
+ /** The CLI reinstall the integrity line names (ruling 25; U13). Only this package, never npm at large. */
311
+ "npm i -g @mnemom/mnemom@",
312
+ ];
313
+ /** Tokens no fix line may contain (U12; C01-R16). */
314
+ export const FORBIDDEN_FIX_TOKENS = ["--local", "host breakglass"];
315
+ /** Shape lint over a catalogue (defaults to FIX_LINES). Empty result = clean. */
316
+ export function lintFixCatalogue(catalogue = FIX_LINES) {
317
+ const out = [];
318
+ for (const [key, entry] of Object.entries(catalogue)) {
319
+ const text = entry.lead + entry.body;
320
+ for (const tok of FORBIDDEN_FIX_TOKENS) {
321
+ if (text.includes(tok))
322
+ out.push({ key, problem: `forbidden token ${tok}` });
323
+ }
324
+ if (entry.lead.includes(NEW_TOKEN))
325
+ out.push({ key, problem: "--new in the lead escapes the rule" });
326
+ if (text.includes("mnemom agent done <name>"))
327
+ out.push({ key, problem: "done clause restated; the rule adds it" });
328
+ if (text.includes("config set durable always") && key !== "durable_only_agent") {
329
+ out.push({ key, problem: "launcher suffix restated; the rule adds it" });
330
+ }
331
+ const commands = [...text.matchAll(/`([^`]+)`/g)].map((m) => m[1]);
332
+ if (entry.kind === "command" && commands.length === 0)
333
+ out.push({ key, problem: "command entry has no command" });
334
+ if (entry.kind === "informational" && commands.length > 0)
335
+ out.push({ key, problem: "informational entry names a command" });
336
+ for (const c of commands) {
337
+ if (!M1_COMMAND_PREFIXES.some((p) => c.startsWith(p)))
338
+ out.push({ key, problem: `not an M1 command: ${c}` });
339
+ }
340
+ }
341
+ return out;
342
+ }
343
+ /** Wordings no rendered durable_only line may contain (wave-0 fix ruling 16.1). */
344
+ export const DURABLE_ONLY_FORBIDDEN = ["rerun and rerun", ", then rerun, then", "or fix "];
345
+ /**
346
+ * Lint every durable_only line: each lock refusal (each cwd_kind) under each launcher key, rendered
347
+ * with sample params. Flags a forbidden wording, 'rerun' twice in one clause, and a clause that does
348
+ * not start lowercase.
349
+ */
350
+ export function lintDurableOnly(clauses = DURABLE_ONLY_PRECONDITION) {
351
+ const out = [];
352
+ for (const [key, clause] of Object.entries(clauses)) {
353
+ if (!/^[a-z]/.test(clause))
354
+ out.push({ key, problem: "clause does not start lowercase" });
355
+ if ((clause.match(/\brerun\b/g) ?? []).length > 1)
356
+ out.push({ key, problem: "clause says rerun more than once" });
357
+ }
358
+ const fixParams = {
359
+ repo: "acme/web",
360
+ toplevel: "/wt/web",
361
+ checkout: "/src/web",
362
+ realpath: "/real/web",
363
+ };
364
+ const refusals = [null];
365
+ for (const [code, v] of Object.entries(LOCK_REFUSAL_FIX)) {
366
+ if (v !== null && typeof v === "object")
367
+ for (const cwd_kind of Object.keys(v))
368
+ refusals.push({ code, cwd_kind });
369
+ else
370
+ refusals.push({ code });
371
+ }
372
+ for (const refusal of refusals) {
373
+ for (const lk of ["always", "ask", "off"]) {
374
+ const line = renderDurableOnlyWith(clauses, lk, {
375
+ name: "web",
376
+ refusal,
377
+ fixParams,
378
+ });
379
+ const key = `${refusal?.code ?? "none"}${refusal?.cwd_kind ? `/${refusal.cwd_kind}` : ""}/${lk}`;
380
+ for (const bad of DURABLE_ONLY_FORBIDDEN)
381
+ if (line.includes(bad))
382
+ out.push({ key, problem: `contains '${bad}'` });
383
+ }
384
+ }
385
+ return out;
386
+ }
387
+ // ---- Fixed CLI texts and templates (C01-R16 non-TTY, C01-R24 show, C01-R25 spend, C14-R12) ----
388
+ export const NON_TTY_LOCKED_TEMPLATE = "`<name>` is locked; the host daemon runs it. Attach: `mnemom agent <name>`";
389
+ /** The single non-TTY stdout line (owner Q4, final F03), with the builder's dropped flags if any. */
390
+ export function renderNonTtyLocked(name, droppedFlags) {
391
+ const line = substitute(NON_TTY_LOCKED_TEMPLATE, { name });
392
+ return droppedFlags.length === 0 ? line : `${line} (flags dropped: ${droppedFlags.join(", ")})`;
393
+ }
394
+ /** The adopt Note grammar (C14-R12): '<with-you text>; flags dropped: <list>'. */
395
+ export const ADOPT_WITH_YOU_TEXT = "approvals with you";
396
+ export function renderAdoptNote(droppedFlags) {
397
+ return droppedFlags.length === 0
398
+ ? ADOPT_WITH_YOU_TEXT
399
+ : `${ADOPT_WITH_YOU_TEXT}; flags dropped: ${droppedFlags.join(", ")}`;
400
+ }
401
+ /** `mnemom agent show` sections, in order; the --json keys are the same strings in the same order. */
402
+ export const SHOW_KEYS = [
403
+ "state",
404
+ "machine",
405
+ "sharing",
406
+ "goal",
407
+ "rules",
408
+ "pins",
409
+ "limits",
410
+ "approvals",
411
+ "outage",
412
+ "storage",
413
+ "seat",
414
+ "journal",
415
+ ];
416
+ /** show keys that do not apply to a tracked session. */
417
+ export const SHOW_KEYS_LOCKED_ONLY = [
418
+ "machine",
419
+ "pins",
420
+ "limits",
421
+ "approvals",
422
+ "outage",
423
+ "seat",
424
+ ];
425
+ /** The not-applicable value: human output prints NA_TEXT, --json carries null. */
426
+ export const NA_TEXT = "-";
427
+ export const APPROVALS_TEXT_M1 = "with you";
428
+ export const OUTAGE_TEXT_M1 = "if Mnemom is unavailable this session's model calls stop until it is back; nothing runs on its own in this release";
429
+ export const STORAGE_TEXT_M1 = "goal text: encrypted, erasable, purged 30 days after the session ends; charter, journal and session row: content-free; transcript: on this machine only";
430
+ export const SEAT_TEXT_M1 = "leave without stopping it: tmux detach (ctrl-b d); `/exit` restarts the seat";
431
+ export const JOURNAL_TAIL_N = 10;
432
+ /**
433
+ * The laptop risk line, version RISK_LINE_VERSION (constants.ts). Printed at host install, in the
434
+ * adopt summary and on lock, never recorded as seen (C02-R17). It is the design §2.2 sentence
435
+ * minus what M1 lacks (no Slack approvals, no org-limit raises in M1).
436
+ */
437
+ export const RISK_LINE_TEXT = "Here the session acts with your account's access on this machine. Never-rules and holds are tripwires, not walls; a container is the recommended home for work on its own.";
438
+ /**
439
+ * The device verification page's harness markers (C04-R08; wave-0 fix 3d): HTML attributes, values
440
+ * from server state only (never from the submitted form). The visible text is RISK_LINE_TEXT.
441
+ * data-subject-kind the stored kind ('host' in M1)
442
+ * data-subject-runtime the stored runtime string
443
+ * data-runtime-self-declared 'true' | 'false'
444
+ * data-risk-sentence-id RISK_SENTENCE_ID_HOST for kind host
445
+ * data-risk-line-version String(RISK_LINE_VERSION)
446
+ */
447
+ export const DEVICE_PAGE_MARKERS = [
448
+ "data-subject-kind",
449
+ "data-subject-runtime",
450
+ "data-runtime-self-declared",
451
+ "data-risk-sentence-id",
452
+ "data-risk-line-version",
453
+ ];
454
+ export const RISK_SENTENCE_ID_HOST = "laptop";
455
+ /** The marker values for one enrollment subject, from its stored row. M1 knows kind 'host' only. */
456
+ export function devicePageMarkerValues(subject) {
457
+ if (subject.kind !== "host")
458
+ throw new RangeError(`no risk sentence for kind ${subject.kind}`);
459
+ return {
460
+ "data-subject-kind": subject.kind,
461
+ "data-subject-runtime": subject.runtime,
462
+ "data-runtime-self-declared": subject.runtimeSelfDeclared ? "true" : "false",
463
+ "data-risk-sentence-id": RISK_SENTENCE_ID_HOST,
464
+ "data-risk-line-version": String(RISK_LINE_VERSION),
465
+ };
466
+ }
467
+ /** Spend column (C01-R25): guard_state.spend_usd to cents, two decimals, no currency sign; tracked rows print NA_TEXT. */
468
+ export function formatSpendCents(spendUsd) {
469
+ if (spendUsd === null)
470
+ return NA_TEXT;
471
+ if (!Number.isFinite(spendUsd) || spendUsd < 0)
472
+ throw new RangeError(`spend out of range: ${spendUsd}`);
473
+ return (Math.round((spendUsd + Number.EPSILON) * 100) / 100).toFixed(2);
474
+ }
475
+ /**
476
+ * Days shown in the grant warning: ceil(remaining / 1 day), so "6 days" at six days left and
477
+ * "1 days" in the last day. null (no warning) above GRANT_WARNING_S or when already expired.
478
+ */
479
+ export function grantWarningDays(remainingSeconds, warningWindowSeconds) {
480
+ if (!(remainingSeconds > 0) || remainingSeconds > warningWindowSeconds)
481
+ return null;
482
+ return Math.ceil(remainingSeconds / 86400);
483
+ }