@mnemom/mnemom 0.17.34-next.1 → 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 (195) 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.d.ts +11 -0
  10. package/dist/commands/agent.js +145 -46
  11. package/dist/commands/durable-doctor.d.ts +50 -0
  12. package/dist/commands/durable-doctor.js +186 -0
  13. package/dist/commands/durable-lock.d.ts +254 -0
  14. package/dist/commands/durable-lock.js +595 -0
  15. package/dist/commands/durable-sessions.d.ts +87 -0
  16. package/dist/commands/durable-sessions.js +303 -0
  17. package/dist/commands/durable-verbs.d.ts +116 -0
  18. package/dist/commands/durable-verbs.js +393 -0
  19. package/dist/durable/flock.d.ts +26 -0
  20. package/dist/durable/flock.js +80 -0
  21. package/dist/durable/launch-spec.d.ts +7 -1
  22. package/dist/durable/launch-spec.js +10 -3
  23. package/dist/durable/seat-proxy-entry.d.ts +11 -0
  24. package/dist/durable/seat-proxy-entry.js +25 -0
  25. package/dist/durable/seat-proxy.d.ts +107 -0
  26. package/dist/durable/seat-proxy.js +599 -0
  27. package/dist/durable/seat-socket.d.ts +46 -0
  28. package/dist/durable/seat-socket.js +179 -0
  29. package/dist/durable/seat-spec-validator.d.ts +28 -0
  30. package/dist/durable/seat-spec-validator.js +59 -0
  31. package/dist/durable/test-mode.mjs +81 -0
  32. package/dist/durable/turn-chain.d.ts +55 -0
  33. package/dist/durable/turn-chain.js +178 -0
  34. package/dist/host/auto-continue.d.ts +67 -0
  35. package/dist/host/auto-continue.js +118 -0
  36. package/dist/host/bootid.d.ts +13 -0
  37. package/dist/host/bootid.js +41 -0
  38. package/dist/host/client.d.ts +123 -0
  39. package/dist/host/client.js +171 -0
  40. package/dist/host/commands.d.ts +2 -0
  41. package/dist/host/commands.js +122 -0
  42. package/dist/host/control.d.ts +33 -0
  43. package/dist/host/control.js +144 -0
  44. package/dist/host/daemon.d.ts +217 -0
  45. package/dist/host/daemon.js +606 -0
  46. package/dist/host/gate.d.ts +46 -0
  47. package/dist/host/gate.js +82 -0
  48. package/dist/host/grant.d.ts +24 -0
  49. package/dist/host/grant.js +24 -0
  50. package/dist/host/instance.d.ts +35 -0
  51. package/dist/host/instance.js +62 -0
  52. package/dist/host/integrity.d.ts +35 -0
  53. package/dist/host/integrity.js +115 -0
  54. package/dist/host/launchd.d.ts +16 -0
  55. package/dist/host/launchd.js +45 -0
  56. package/dist/host/lock.d.ts +20 -0
  57. package/dist/host/lock.js +63 -0
  58. package/dist/host/owner.d.ts +55 -0
  59. package/dist/host/owner.js +121 -0
  60. package/dist/host/plist.d.ts +16 -0
  61. package/dist/host/plist.js +85 -0
  62. package/dist/host/procs.d.ts +27 -0
  63. package/dist/host/procs.js +105 -0
  64. package/dist/host/run.d.ts +66 -0
  65. package/dist/host/run.js +314 -0
  66. package/dist/host/runtime.d.ts +8 -0
  67. package/dist/host/runtime.js +22 -0
  68. package/dist/host/s1-names.d.ts +22 -0
  69. package/dist/host/s1-names.js +21 -0
  70. package/dist/host/seat-credential.d.ts +27 -0
  71. package/dist/host/seat-credential.js +41 -0
  72. package/dist/host/seat-launch-main.d.ts +1 -0
  73. package/dist/host/seat-launch-main.js +59 -0
  74. package/dist/host/seat-launch.d.ts +116 -0
  75. package/dist/host/seat-launch.js +302 -0
  76. package/dist/host/seat.d.ts +48 -0
  77. package/dist/host/seat.js +149 -0
  78. package/dist/host/state.d.ts +33 -0
  79. package/dist/host/state.js +117 -0
  80. package/dist/host/status.d.ts +101 -0
  81. package/dist/host/status.js +307 -0
  82. package/dist/host/tmux.d.ts +56 -0
  83. package/dist/host/tmux.js +182 -0
  84. package/dist/host/transcript.d.ts +30 -0
  85. package/dist/host/transcript.js +130 -0
  86. package/dist/host/verbs.d.ts +50 -0
  87. package/dist/host/verbs.js +271 -0
  88. package/dist/index.d.ts +8 -6
  89. package/dist/index.js +197 -35
  90. package/dist/lib/agent.d.ts +8 -26
  91. package/dist/lib/agent.js +11 -26
  92. package/dist/lib/claude-plugin.d.ts +11 -2
  93. package/dist/lib/claude-plugin.js +10 -1
  94. package/dist/lib/durable/api.d.ts +136 -0
  95. package/dist/lib/durable/api.js +220 -0
  96. package/dist/lib/durable/codes.d.ts +8 -0
  97. package/dist/lib/durable/codes.js +2 -0
  98. package/dist/lib/durable/first-turn.d.ts +50 -0
  99. package/dist/lib/durable/first-turn.js +102 -0
  100. package/dist/lib/durable/gate.d.ts +48 -0
  101. package/dist/lib/durable/gate.js +122 -0
  102. package/dist/lib/durable/handover.d.ts +101 -0
  103. package/dist/lib/durable/handover.js +175 -0
  104. package/dist/lib/durable/launch.d.ts +182 -0
  105. package/dist/lib/durable/launch.js +443 -0
  106. package/dist/lib/durable/launching.d.ts +15 -0
  107. package/dist/lib/durable/launching.js +70 -0
  108. package/dist/lib/durable/live.d.ts +194 -0
  109. package/dist/lib/durable/live.js +635 -0
  110. package/dist/lib/durable/refusal.d.ts +57 -0
  111. package/dist/lib/durable/refusal.js +78 -0
  112. package/dist/lib/durable/view.d.ts +83 -0
  113. package/dist/lib/durable/view.js +244 -0
  114. package/dist/lib/experimental.d.ts +0 -9
  115. package/dist/lib/experimental.js +18 -17
  116. package/dist/lib/launcher-config.d.ts +7 -0
  117. package/dist/lib/launcher-config.js +21 -0
  118. package/dist/lib/scan/report-email.d.ts +1 -1
  119. package/dist/lib/scan/report-email.js +9 -1
  120. package/dist/lib/subscription-login.d.ts +15 -0
  121. package/dist/lib/subscription-login.js +28 -1
  122. package/dist/vendor/durable-contract/index.js +240 -18
  123. package/dist/vendor/shared/durable-contract/admission.d.ts +240 -0
  124. package/dist/vendor/shared/durable-contract/admission.js +533 -0
  125. package/dist/vendor/shared/durable-contract/arm.d.ts +51 -0
  126. package/dist/vendor/shared/durable-contract/arm.js +133 -0
  127. package/dist/vendor/shared/durable-contract/canonical.d.ts +29 -0
  128. package/dist/vendor/shared/durable-contract/canonical.js +98 -0
  129. package/dist/vendor/shared/durable-contract/cell-id.d.ts +22 -0
  130. package/dist/vendor/shared/durable-contract/cell-id.js +38 -0
  131. package/dist/vendor/shared/durable-contract/cli-output.d.ts +342 -0
  132. package/dist/vendor/shared/durable-contract/cli-output.js +201 -0
  133. package/dist/vendor/shared/durable-contract/cli-surface.d.ts +119 -0
  134. package/dist/vendor/shared/durable-contract/cli-surface.js +270 -0
  135. package/dist/vendor/shared/durable-contract/codes.d.ts +537 -0
  136. package/dist/vendor/shared/durable-contract/codes.js +475 -0
  137. package/dist/vendor/shared/durable-contract/constants.d.ts +153 -0
  138. package/dist/vendor/shared/durable-contract/constants.js +179 -0
  139. package/dist/vendor/shared/durable-contract/doors.d.ts +119 -0
  140. package/dist/vendor/shared/durable-contract/doors.js +249 -0
  141. package/dist/vendor/shared/durable-contract/envelope.d.ts +103 -0
  142. package/dist/vendor/shared/durable-contract/envelope.js +317 -0
  143. package/dist/vendor/shared/durable-contract/events.d.ts +147 -0
  144. package/dist/vendor/shared/durable-contract/events.js +630 -0
  145. package/dist/vendor/shared/durable-contract/executor-state.d.ts +41 -0
  146. package/dist/vendor/shared/durable-contract/executor-state.js +32 -0
  147. package/dist/vendor/shared/durable-contract/fixlines.d.ts +318 -0
  148. package/dist/vendor/shared/durable-contract/fixlines.js +483 -0
  149. package/dist/vendor/shared/durable-contract/freeze-record.d.ts +787 -0
  150. package/dist/vendor/shared/durable-contract/freeze-record.js +361 -0
  151. package/dist/vendor/shared/durable-contract/index.d.ts +36 -0
  152. package/dist/vendor/shared/durable-contract/index.js +37 -0
  153. package/dist/vendor/shared/durable-contract/journal-approvals.d.ts +29 -0
  154. package/dist/vendor/shared/durable-contract/journal-approvals.js +60 -0
  155. package/dist/vendor/shared/durable-contract/keys.d.ts +24 -0
  156. package/dist/vendor/shared/durable-contract/keys.js +66 -0
  157. package/dist/vendor/shared/durable-contract/lock.d.ts +128 -0
  158. package/dist/vendor/shared/durable-contract/lock.js +151 -0
  159. package/dist/vendor/shared/durable-contract/names.d.ts +25 -0
  160. package/dist/vendor/shared/durable-contract/names.js +78 -0
  161. package/dist/vendor/shared/durable-contract/owner-verbs.d.ts +175 -0
  162. package/dist/vendor/shared/durable-contract/owner-verbs.js +403 -0
  163. package/dist/vendor/shared/durable-contract/paths.d.ts +23 -0
  164. package/dist/vendor/shared/durable-contract/paths.js +35 -0
  165. package/dist/vendor/shared/durable-contract/pure-fn.d.ts +48 -0
  166. package/dist/vendor/shared/durable-contract/pure-fn.js +89 -0
  167. package/dist/vendor/shared/durable-contract/routes.d.ts +205 -0
  168. package/dist/vendor/shared/durable-contract/routes.js +315 -0
  169. package/dist/vendor/shared/durable-contract/schema.d.ts +126 -0
  170. package/dist/vendor/shared/durable-contract/schema.js +441 -0
  171. package/dist/vendor/shared/durable-contract/seal.d.ts +54 -0
  172. package/dist/vendor/shared/durable-contract/seal.js +99 -0
  173. package/dist/vendor/shared/durable-contract/secret-scope.d.ts +28 -0
  174. package/dist/vendor/shared/durable-contract/secret-scope.js +76 -0
  175. package/dist/vendor/shared/durable-contract/session-id.d.ts +21 -0
  176. package/dist/vendor/shared/durable-contract/session-id.js +58 -0
  177. package/dist/vendor/shared/durable-contract/spec.d.ts +162 -0
  178. package/dist/vendor/shared/durable-contract/spec.js +286 -0
  179. package/dist/vendor/shared/durable-contract/states.d.ts +96 -0
  180. package/dist/vendor/shared/durable-contract/states.js +218 -0
  181. package/dist/vendor/shared/durable-contract/telemetry.d.ts +94 -0
  182. package/dist/vendor/shared/durable-contract/telemetry.js +180 -0
  183. package/dist/vendor/shared/durable-contract/test-mode.d.ts +62 -0
  184. package/dist/vendor/shared/durable-contract/test-mode.js +140 -0
  185. package/dist/vendor/shared/durable-contract/turn.d.ts +57 -0
  186. package/dist/vendor/shared/durable-contract/turn.js +81 -0
  187. package/dist/vendor/shared/durable-contract/vectors.d.ts +191 -0
  188. package/dist/vendor/shared/durable-contract/vectors.js +208 -0
  189. package/package.json +3 -2
  190. package/plugins/integrity-manifest.json +35 -0
  191. package/plugins/mnemom/hooks/hooks.json +15 -1
  192. package/plugins/mnemom/hooks/register.tsx +60 -2
  193. package/plugins/mnemom/hooks/seat-hello.mjs +116 -0
  194. package/dist/commands/agent-implicit-notice.d.ts +0 -31
  195. package/dist/commands/agent-implicit-notice.js +0 -73
@@ -0,0 +1,201 @@
1
+ // GENERATED from shared/durable-contract/src/cli-output.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
2
+ /**
3
+ * `mnemom agent <verb> --json` on a refused durable verb (wave-0 fix ruling 19). stdout carries
4
+ * exactly one JSON document, the ruling-14 error envelope: an API or gateway refusal body is passed
5
+ * through unchanged; a refusal the CLI decides itself (S1 codes with status null, such as
6
+ * session_homed_elsewhere or durable_cwd_not_root) is built here in the same shape, with the code's
7
+ * closed fields and the rendered fix line in details.fix. stderr is the same with or without
8
+ * --json (refusal line, fix line, machine code), and nothing reaches stdout on a refusal without it.
9
+ */
10
+ import { HEX64_RE, sha256Hex, UUID_RE } from "./canonical.js";
11
+ import { CLAIM_UNAVAILABLE_CAUSES, durableErrorBody, } from "./codes.js";
12
+ import { TRANSCRIPT_GUARD_MODES } from "./paths.js";
13
+ import { SESSION_STATES } from "./states.js";
14
+ /** Exit status of every refused or failed `mnemom agent` verb, with or without --json. */
15
+ export const CLI_REFUSAL_EXIT = 1;
16
+ /** Exit status of a usage error and of the experimental gate (C04-R01, ruling 9); never a refusal. */
17
+ export const CLI_USAGE_EXIT = 2;
18
+ /**
19
+ * The --json stdout document for a CLI-side refusal: durableErrorBody with details always present
20
+ * and carrying the rendered fix line. Throws on a missing or empty fix, and on a field outside `fix`
21
+ * and the code's closed fields.
22
+ */
23
+ export function cliRefusalJson(code, message, details) {
24
+ if (typeof details.fix !== "string" || details.fix === "")
25
+ throw new Error(`${code}: a CLI refusal carries its rendered fix line in details.fix`);
26
+ return durableErrorBody(code, message, details);
27
+ }
28
+ /** Hex characters a fingerprint keeps: the sha256 prefix host status prints (ruling 26; C12-R23). */
29
+ export const FINGERPRINT_HEX_CHARS = 12;
30
+ /** A secret's fingerprint: the first FINGERPRINT_HEX_CHARS lowercase hex characters of its sha256. */
31
+ export async function fingerprint(value) {
32
+ return (await sha256Hex(value)).slice(0, FINGERPRINT_HEX_CHARS);
33
+ }
34
+ const f = (spec) => Object.freeze(spec);
35
+ /**
36
+ * One seat row (rulings 26, 26.1; C12-R23): pid is the pane pid; state is the session's stored state
37
+ * (the DB probe); spec_path is the local launch-spec file the daemon spawned the seat from. Every
38
+ * field describes the seat at call time, so a value that does not exist yet (mid-spawn) or any more
39
+ * (claude exited) is null: proxy_pid until the seat proxy runs, proxy_port until it listens,
40
+ * socket_path until the socket exists, claude_pid while claude is not running. A non-null
41
+ * proxy_port implies a non-null proxy_pid.
42
+ */
43
+ export const HOST_STATUS_SEAT = Object.freeze({
44
+ session_id: f({ type: "uuid", nullable: false }),
45
+ epoch: f({ type: "integer", nullable: false }),
46
+ spawn_id: f({ type: "uuid", nullable: false }),
47
+ state: f({ type: "enum", nullable: false, values: SESSION_STATES }),
48
+ pid: f({ type: "pid", nullable: false }),
49
+ proxy_pid: f({ type: "pid", nullable: true }),
50
+ claude_pid: f({ type: "pid", nullable: true }),
51
+ proxy_port: f({ type: "port", nullable: true }),
52
+ socket_path: f({ type: "string", nullable: true }),
53
+ spec_path: f({ type: "string", nullable: false }),
54
+ spec_sha256: f({ type: "hex64", nullable: false }),
55
+ });
56
+ /**
57
+ * One session entry (ruling 24.12, Wassim option 1; C12-R31): claim_unavailable is the last
58
+ * durable_claim_unavailable cause and the count of consecutive unavailable claims, or null when the
59
+ * session's last claim was not unavailable.
60
+ */
61
+ export const HOST_STATUS_SESSION = Object.freeze({
62
+ session_id: f({ type: "uuid", nullable: false }),
63
+ claim_unavailable: f({
64
+ type: "object",
65
+ nullable: true,
66
+ fields: Object.freeze({
67
+ cause: f({ type: "enum", nullable: false, values: CLAIM_UNAVAILABLE_CAUSES }),
68
+ consecutive: f({ type: "positive_integer", nullable: false }),
69
+ }),
70
+ }),
71
+ });
72
+ /**
73
+ * `mnemom agent host status --json` (ruling 26, Wassim option 1; C12-R04, R23, R31): one closed
74
+ * document, key order as frozen. The nonce and key appear only as fingerprints, never raw.
75
+ */
76
+ export const HOST_STATUS_JSON = Object.freeze({
77
+ installed: f({ type: "boolean", nullable: false }),
78
+ loaded: f({ type: "boolean", nullable: false }),
79
+ /** The host instance name (launchd label and tmux socket name), from config/env (C12-R04). */
80
+ instance: f({ type: "string", nullable: false }),
81
+ daemon_pid: f({ type: "pid", nullable: true }),
82
+ lock_holder_pid: f({ type: "pid", nullable: true }),
83
+ lock_path: f({ type: "string", nullable: false }),
84
+ transcript_guard: f({ type: "enum", nullable: false, values: TRANSCRIPT_GUARD_MODES }),
85
+ /** The stored boot-bound nonce's fingerprint; null with no state file or no nonce yet (26.1). */
86
+ nonce_fingerprint: f({ type: "fingerprint", nullable: true }),
87
+ /** The executor key's fingerprint; null with no readable state file, whatever installed says (26.1). */
88
+ key_fingerprint: f({ type: "fingerprint", nullable: true }),
89
+ seats: f({ type: "array", nullable: false, item: HOST_STATUS_SEAT }),
90
+ sessions: f({ type: "array", nullable: false, item: HOST_STATUS_SESSION }),
91
+ });
92
+ const FINGERPRINT_RE = new RegExp(`^[0-9a-f]{${FINGERPRINT_HEX_CHARS}}$`);
93
+ const isRecord = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
94
+ const isInt = (v, min, max = Number.MAX_SAFE_INTEGER) => Number.isSafeInteger(v) && v >= min && v <= max;
95
+ function fieldValueOk(spec, v) {
96
+ if (v === null)
97
+ return spec.nullable;
98
+ switch (spec.type) {
99
+ case "boolean":
100
+ return typeof v === "boolean";
101
+ case "string":
102
+ return typeof v === "string" && v.length > 0;
103
+ case "uuid":
104
+ return typeof v === "string" && UUID_RE.test(v);
105
+ case "integer":
106
+ return isInt(v, 0);
107
+ case "positive_integer":
108
+ case "pid":
109
+ return isInt(v, 1);
110
+ case "port":
111
+ return isInt(v, 1, 65535);
112
+ case "hex64":
113
+ return typeof v === "string" && HEX64_RE.test(v);
114
+ case "fingerprint":
115
+ return typeof v === "string" && FINGERPRINT_RE.test(v);
116
+ case "enum":
117
+ return typeof v === "string" && spec.values.includes(v);
118
+ case "array":
119
+ return Array.isArray(v) && v.every((x) => closedOk(spec.item, x));
120
+ case "object":
121
+ return closedOk(spec.fields, v);
122
+ }
123
+ }
124
+ /** Every key present and well formed, no other key. */
125
+ function closedOk(schema, v) {
126
+ if (!isRecord(v))
127
+ return false;
128
+ const keys = Object.keys(schema);
129
+ if (Object.keys(v).some((k) => !keys.includes(k)))
130
+ return false;
131
+ return keys.every((k) => k in v && fieldValueOk(schema[k], v[k]));
132
+ }
133
+ function stringsIn(v) {
134
+ if (typeof v === "string")
135
+ return [v];
136
+ if (Array.isArray(v))
137
+ return v.flatMap(stringsIn);
138
+ if (isRecord(v))
139
+ return Object.entries(v).flatMap(([k, x]) => [k, ...stringsIn(x)]);
140
+ return [];
141
+ }
142
+ const VECTOR_DOC = {
143
+ installed: true,
144
+ loaded: true,
145
+ instance: "ai.mnemom.agent-host.default",
146
+ daemon_pid: 4000,
147
+ lock_holder_pid: 4000,
148
+ lock_path: "/Users/dev/.mnemom/durable/host.lock",
149
+ transcript_guard: "link",
150
+ seats: [],
151
+ sessions: [],
152
+ };
153
+ /**
154
+ * Host status documents for the three enrollment states ruling 26.1 names. The fingerprints are of
155
+ * "vector-executor-key" (4b27142c3a90) and "vector-nonce" (55ccea8c7f0d).
156
+ */
157
+ export const HOST_STATUS_JSON_VECTORS = Object.freeze({
158
+ /** Not enrolled: no state file, so neither fingerprint exists. */
159
+ no_state_file: Object.freeze({
160
+ ...VECTOR_DOC,
161
+ installed: false,
162
+ loaded: false,
163
+ daemon_pid: null,
164
+ lock_holder_pid: null,
165
+ nonce_fingerprint: null,
166
+ key_fingerprint: null,
167
+ }),
168
+ /** Enrolled and running, before the daemon has written its first nonce. */
169
+ enrolled_no_nonce: Object.freeze({
170
+ ...VECTOR_DOC,
171
+ nonce_fingerprint: null,
172
+ key_fingerprint: "4b27142c3a90",
173
+ }),
174
+ /** Uninstalled: the state file and enrollment stay (C12 F6-05, R24). */
175
+ not_installed_with_state_file: Object.freeze({
176
+ ...VECTOR_DOC,
177
+ installed: false,
178
+ loaded: false,
179
+ daemon_pid: null,
180
+ lock_holder_pid: null,
181
+ nonce_fingerprint: "55ccea8c7f0d",
182
+ key_fingerprint: "4b27142c3a90",
183
+ }),
184
+ });
185
+ /**
186
+ * True for exactly the frozen document: HOST_STATUS_JSON closed at every level. Given the raw
187
+ * `secrets`, also false when either appears in any key or string value (only fingerprints may).
188
+ */
189
+ export function hostStatusJsonOk(v, secrets) {
190
+ if (secrets && (secrets.nonce === "" || secrets.key === ""))
191
+ throw new RangeError("hostStatusJsonOk: secrets must be non-empty strings");
192
+ if (!closedOk(HOST_STATUS_JSON, v))
193
+ return false;
194
+ // ruling 26.1: a listening port needs the proxy process it belongs to
195
+ const seats = v.seats;
196
+ if (seats.some((seat) => seat.proxy_port !== null && seat.proxy_pid === null))
197
+ return false;
198
+ if (!secrets)
199
+ return true;
200
+ return !stringsIn(v).some((s) => s.includes(secrets.nonce) || s.includes(secrets.key));
201
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Every command path and long option M1 adds to the CLI (ruling 32.01). E4's report-only D1
3
+ * detector tags a non-PASS row `product_missing` when a CLI step's argv (before a literal `--`)
4
+ * names an entry here that the build's cli/command-tree.json lacks; nothing here changes a verdict.
5
+ *
6
+ * Sources, in order (a later amendment wins): design-v3 section 7 (P0a-A rows 6 and 7), the
7
+ * BACKBONE CLI pieces C1-C4 and their amendments, rulings 19, 20, 24.12, 26, 32.31 and 32.33. An entry is a new
8
+ * path, or a pre-M1 path with only the options M1 adds to it; nothing the pre-M1 CLI already has
9
+ * (cli/command-tree.json at merge-base(int, origin/main)) is listed. Sorted by path, then closed.
10
+ *
11
+ * Deliberately absent: `agent sessions` / `agent show` and their --json (pre-M1); `agent config`
12
+ * and `agent doctor` (pre-M1 launcher scenarios, not commander paths); `experimental enable
13
+ * durable` (a value, not a path); `--local` and `host breakglass` (BACKBONE cut list: P0a-B);
14
+ * `amend --goal` (design section 7 row 12: P0a-B). Ruling 32.31: a spelling exists only if a binding
15
+ * source names it, so dataset-only spellings (a top-level agent adopt, agent contract, amend
16
+ * --model, lock --also-lock, options on bare `agent sessions` such as --own-agent/--dry-run,
17
+ * launcher --durable/--direct/--door, host enroll --json) are not listed; contract and amend are API
18
+ * verbs (BACKBONE A2). Ruling 32.33 corrects 32.31: the `agent sessions adopt` and `agent sessions
19
+ * unlock` subcommands are M1 paths and are listed. C1 builds every M1 verb as a commander command,
20
+ * so each entry appears in cli/command-tree.json once it lands.
21
+ */
22
+ export interface CliSurfaceEntry {
23
+ readonly path: readonly string[];
24
+ /** Long options M1 adds on this path, sorted. */
25
+ readonly options: readonly string[];
26
+ }
27
+ export declare const M1_CLI_SURFACE: readonly CliSurfaceEntry[];
28
+ /**
29
+ * Which M1 piece builds each entry (ruling 32.31; an internal S1 tag, not part of the frozen
30
+ * {path, options} shape): C1 the launcher and owner verbs (BACKBONE line 122), C2 the host daemon
31
+ * verbs (line 131; `agent host` is the shared parent, so it is C2's), C3 the credential proxy's
32
+ * hidden seat-proxy (line 145), C4 the launch spec and adopt (line 146; ruling 32.33). `agent
33
+ * sessions unlock` is C1 (BACKBONE C1 flat verbs; the unlock owner_mutation device step, A4). R1 is
34
+ * the Doors thin runner, `agent run` (ruling 34.12; Doors lane W-L13). Every entry has exactly one
35
+ * tag.
36
+ */
37
+ export declare const M1_CLI_SURFACE_BUILDERS: Readonly<{
38
+ readonly C1: readonly string[];
39
+ readonly C2: readonly string[];
40
+ readonly C3: readonly string[];
41
+ readonly C4: readonly string[];
42
+ readonly R1: readonly string[];
43
+ }>;
44
+ export type M1CliBuilder = keyof typeof M1_CLI_SURFACE_BUILDERS;
45
+ /** A command tree's surface: "a b" path strings and "a b --opt" option strings. */
46
+ export interface CliTreeSurface {
47
+ readonly paths: ReadonlySet<string>;
48
+ readonly options: ReadonlySet<string>;
49
+ }
50
+ /**
51
+ * One builder group against a candidate tree (ruling 32.31). Its items are its paths absent from
52
+ * the pre-M1 `baseline` and every option of its entries. The group has landed once any item is in
53
+ * the candidate; then every item must be (`missing` empty). Before that, `present` is empty.
54
+ */
55
+ export declare function m1CliGroupCheck(group: M1CliBuilder, candidate: CliTreeSurface, baseline: CliTreeSurface): {
56
+ landed: boolean;
57
+ present: string[];
58
+ missing: string[];
59
+ };
60
+ /**
61
+ * Pre-M1 launcher sub-verbs (ruling 32.35): words `mnemom agent` reads from its `session`
62
+ * positional and dispatches itself, so gen-command-tree never lists them. b37bfbf1
63
+ * cli/src/index.ts: `scenario === "help"` (493), "config" (523), "slack" (530), "doctor" (577),
64
+ * "setup" (587). Accepted only as the first word after `agent`; the words after it are its
65
+ * arguments and are not checked.
66
+ */
67
+ export declare const PRE_M1_LAUNCHER_SUBVERBS: readonly ["config", "doctor", "help", "setup", "slack"];
68
+ /** The parts of cli/command-tree.json the resolver reads. */
69
+ export interface CliTreeOption {
70
+ readonly long?: string;
71
+ readonly required?: boolean;
72
+ readonly optional?: boolean;
73
+ }
74
+ export interface CliTreeNode {
75
+ readonly name: string;
76
+ readonly arguments?: readonly {
77
+ readonly variadic?: boolean;
78
+ }[];
79
+ readonly options?: readonly CliTreeOption[];
80
+ readonly commands?: readonly CliTreeNode[];
81
+ }
82
+ export interface CliTree {
83
+ readonly globalOptions?: readonly CliTreeOption[];
84
+ readonly commands: readonly CliTreeNode[];
85
+ }
86
+ export interface CliResolution {
87
+ ok: boolean;
88
+ /** The command path the argv resolves to (a launcher sub-verb is ["agent", <sub-verb>]). */
89
+ path: string[];
90
+ /** Each unknown command word or option, in argv order; absent when ok. */
91
+ unknown?: string[];
92
+ }
93
+ /**
94
+ * One argv (binary name excluded) against the pre-M1 tree and M1_CLI_SURFACE (rulings 32.31,
95
+ * 32.33, 32.35; CASE-DSL rule 29). Read as commander does: a word is a subcommand when the
96
+ * current path has it and no positional has been taken there, else the path's positional (a
97
+ * pre-M1 path's declared arguments; an M1-only path without subcommands takes any number), else
98
+ * unknown, and the walk stops (commander stops at an unknown command). A word that names a
99
+ * command anywhere in the tree, the surface or the sub-verb list never fills a positional, so a
100
+ * misplaced verb (`agent adopt <name>`, `agent lock doctor`) is unknown. A launcher sub-verb is
101
+ * accepted only as the first word after `agent`, and its arguments are not checked. An option
102
+ * counts on its own path or as a global option, never on an ancestor; a pre-M1 option that takes
103
+ * a value consumes the next token, and M1 options are read as flags (each M1 path that adds one
104
+ * takes positionals, so a value is a positional there). `--name=value` is read as `--name`.
105
+ * Short options, `--help`, `$` references and everything after a literal `--` are not checked.
106
+ */
107
+ export declare function resolveCliArgv(argv: readonly string[], preM1Tree: CliTree, surface?: readonly CliSurfaceEntry[]): CliResolution;
108
+ /** An argv slot the resolver fills from the named environment variable. */
109
+ export interface EnvArg {
110
+ readonly env: string;
111
+ }
112
+ /**
113
+ * The CLI call the bundled plugin's /mnemom lock makes: the M1 `agent lock` path with the session
114
+ * name as its one positional, read from MNEMOM_AGENT_SESSION_NAME (the launcher sets it in the
115
+ * claude it starts). No option, no cwd argument: the child inherits the original's process cwd.
116
+ */
117
+ export declare const PLUGIN_LOCK_ARGV: readonly (string | EnvArg)[];
118
+ /** PLUGIN_LOCK_ARGV resolved against `env`; null when MNEMOM_AGENT_SESSION_NAME is unset or empty (the plugin then runs no CLI call). */
119
+ export declare function pluginLockArgv(env: Readonly<Record<string, string | undefined>>): string[] | null;
@@ -0,0 +1,270 @@
1
+ // GENERATED from shared/durable-contract/src/cli-surface.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
2
+ /**
3
+ * Every command path and long option M1 adds to the CLI (ruling 32.01). E4's report-only D1
4
+ * detector tags a non-PASS row `product_missing` when a CLI step's argv (before a literal `--`)
5
+ * names an entry here that the build's cli/command-tree.json lacks; nothing here changes a verdict.
6
+ *
7
+ * Sources, in order (a later amendment wins): design-v3 section 7 (P0a-A rows 6 and 7), the
8
+ * BACKBONE CLI pieces C1-C4 and their amendments, rulings 19, 20, 24.12, 26, 32.31 and 32.33. An entry is a new
9
+ * path, or a pre-M1 path with only the options M1 adds to it; nothing the pre-M1 CLI already has
10
+ * (cli/command-tree.json at merge-base(int, origin/main)) is listed. Sorted by path, then closed.
11
+ *
12
+ * Deliberately absent: `agent sessions` / `agent show` and their --json (pre-M1); `agent config`
13
+ * and `agent doctor` (pre-M1 launcher scenarios, not commander paths); `experimental enable
14
+ * durable` (a value, not a path); `--local` and `host breakglass` (BACKBONE cut list: P0a-B);
15
+ * `amend --goal` (design section 7 row 12: P0a-B). Ruling 32.31: a spelling exists only if a binding
16
+ * source names it, so dataset-only spellings (a top-level agent adopt, agent contract, amend
17
+ * --model, lock --also-lock, options on bare `agent sessions` such as --own-agent/--dry-run,
18
+ * launcher --durable/--direct/--door, host enroll --json) are not listed; contract and amend are API
19
+ * verbs (BACKBONE A2). Ruling 32.33 corrects 32.31: the `agent sessions adopt` and `agent sessions
20
+ * unlock` subcommands are M1 paths and are listed. C1 builds every M1 verb as a commander command,
21
+ * so each entry appears in cli/command-tree.json once it lands.
22
+ */
23
+ const entry = (path, options = []) => Object.freeze({ path: Object.freeze(path), options: Object.freeze(options) });
24
+ export const M1_CLI_SURFACE = Object.freeze([
25
+ // BACKBONE C1 "--new"; design-v3 CLI table ("`--new` starts fresh", marked New).
26
+ entry(["agent"], ["--new"]),
27
+ // BACKBONE C1 amend (lowering + budget raise) and the amend line (`amend <name> --budget <n>`);
28
+ // ruling 19 (--json on the durable verbs); --turns: BACKBONE C1 (amend lowers; a turns raise is
29
+ // refused) and C08 (a `--turns` raise stays refused), ruling 32.31.
30
+ entry(["agent", "amend"], ["--budget", "--json", "--turns"]),
31
+ // BACKBONE C1 `mnemom agent containment pause|resume <agent>`; amendment 26.
32
+ entry(["agent", "containment"]),
33
+ entry(["agent", "containment", "pause"]),
34
+ entry(["agent", "containment", "resume"]),
35
+ // BACKBONE C1 flat verbs; ruling 19.
36
+ entry(["agent", "done"], ["--json"]),
37
+ // BACKBONE C2 (`mnemom agent host` replaces `mnemom host`, amendment 2; design-v3 row 7).
38
+ entry(["agent", "host"]),
39
+ // BACKBONE C2 enroll (device step).
40
+ entry(["agent", "host", "enroll"]),
41
+ // BACKBONE C2 install/status/uninstall; --json: C04 (`mnemom agent host install --json`),
42
+ // ruling 32.31.
43
+ entry(["agent", "host", "install"], ["--json"]),
44
+ // BACKBONE C2 renew; amendment 15; --json: C04 (`mnemom agent host renew --json`), ruling 32.31.
45
+ entry(["agent", "host", "renew"], ["--json"]),
46
+ // BACKBONE C2 hidden `run` for launchd; amendment 49.
47
+ entry(["agent", "host", "run"]),
48
+ // BACKBONE C3 hidden `mnemom agent host seat-proxy`; amendment 49; options: C13 test_hooks
49
+ // (`seat-proxy --conversation <cid> --agent-id <uuid> --door <url> --cwd <dir>`), ruling 32.31.
50
+ entry(["agent", "host", "seat-proxy"], ["--agent-id", "--conversation", "--cwd", "--door"]),
51
+ // BACKBONE C2 host status `--json` (line 139); rulings 24.12 and 26.
52
+ entry(["agent", "host", "status"], ["--json"]),
53
+ entry(["agent", "host", "uninstall"]),
54
+ // BACKBONE C1 flat verbs; ruling 19.
55
+ entry(["agent", "kill"], ["--json"]),
56
+ // BACKBONE C1 lock; design-v3 `mnemom agent lock <name> [--own-agent]` (row 6); ruling 16
57
+ // lock_agent_shared fix; rulings 19 and 20 (C02-LOCK-SUBDIR-JSON-215, lock --json).
58
+ entry(["agent", "lock"], ["--json", "--own-agent"]),
59
+ // BACKBONE C1 flat verbs; ruling 19.
60
+ entry(["agent", "pause"], ["--json"]),
61
+ entry(["agent", "resume"], ["--json"]),
62
+ // Doors thin runner (W-L13), ruling 34.12 (1): --watch or --once, --fail-mode, --json, --oidc.
63
+ entry(["agent", "run"], ["--fail-mode", "--json", "--oidc", "--once", "--watch"]),
64
+ // BACKBONE C4 (line 147: buildDurableLaunchSpec serves 'sessions adopt'); options: C14 spec
65
+ // (`sessions adopt --dry-run --json`, `sessions adopt --own-agent`); ruling 32.33.
66
+ entry(["agent", "sessions", "adopt"], ["--dry-run", "--json", "--own-agent"]),
67
+ // fixlines.ts launch_spec_change_sole_unlock (`mnemom agent sessions unlock <name>`); C11, C16 and
68
+ // C17 specs; no source names an option; ruling 32.33.
69
+ entry(["agent", "sessions", "unlock"]),
70
+ ]);
71
+ /**
72
+ * Which M1 piece builds each entry (ruling 32.31; an internal S1 tag, not part of the frozen
73
+ * {path, options} shape): C1 the launcher and owner verbs (BACKBONE line 122), C2 the host daemon
74
+ * verbs (line 131; `agent host` is the shared parent, so it is C2's), C3 the credential proxy's
75
+ * hidden seat-proxy (line 145), C4 the launch spec and adopt (line 146; ruling 32.33). `agent
76
+ * sessions unlock` is C1 (BACKBONE C1 flat verbs; the unlock owner_mutation device step, A4). R1 is
77
+ * the Doors thin runner, `agent run` (ruling 34.12; Doors lane W-L13). Every entry has exactly one
78
+ * tag.
79
+ */
80
+ export const M1_CLI_SURFACE_BUILDERS = Object.freeze({
81
+ C1: Object.freeze([
82
+ "agent",
83
+ "agent amend",
84
+ "agent containment",
85
+ "agent containment pause",
86
+ "agent containment resume",
87
+ "agent done",
88
+ "agent kill",
89
+ "agent lock",
90
+ "agent pause",
91
+ "agent resume",
92
+ "agent sessions unlock",
93
+ ]),
94
+ C2: Object.freeze([
95
+ "agent host",
96
+ "agent host enroll",
97
+ "agent host install",
98
+ "agent host renew",
99
+ "agent host run",
100
+ "agent host status",
101
+ "agent host uninstall",
102
+ ]),
103
+ C3: Object.freeze(["agent host seat-proxy"]),
104
+ C4: Object.freeze(["agent sessions adopt"]),
105
+ R1: Object.freeze(["agent run"]),
106
+ });
107
+ /**
108
+ * One builder group against a candidate tree (ruling 32.31). Its items are its paths absent from
109
+ * the pre-M1 `baseline` and every option of its entries. The group has landed once any item is in
110
+ * the candidate; then every item must be (`missing` empty). Before that, `present` is empty.
111
+ */
112
+ export function m1CliGroupCheck(group, candidate, baseline) {
113
+ const paths = M1_CLI_SURFACE_BUILDERS[group];
114
+ const present = [];
115
+ const missing = [];
116
+ for (const e of M1_CLI_SURFACE) {
117
+ const p = e.path.join(" ");
118
+ if (!paths.includes(p))
119
+ continue;
120
+ if (!baseline.paths.has(p))
121
+ (candidate.paths.has(p) ? present : missing).push(p);
122
+ for (const o of e.options)
123
+ (candidate.options.has(`${p} ${o}`) ? present : missing).push(`${p} ${o}`);
124
+ }
125
+ return { landed: present.length > 0, present, missing };
126
+ }
127
+ /**
128
+ * Pre-M1 launcher sub-verbs (ruling 32.35): words `mnemom agent` reads from its `session`
129
+ * positional and dispatches itself, so gen-command-tree never lists them. b37bfbf1
130
+ * cli/src/index.ts: `scenario === "help"` (493), "config" (523), "slack" (530), "doctor" (577),
131
+ * "setup" (587). Accepted only as the first word after `agent`; the words after it are its
132
+ * arguments and are not checked.
133
+ */
134
+ export const PRE_M1_LAUNCHER_SUBVERBS = Object.freeze([
135
+ "config",
136
+ "doctor",
137
+ "help",
138
+ "setup",
139
+ "slack",
140
+ ]);
141
+ const takesValue = (o) => o.required === true || o.optional === true;
142
+ /**
143
+ * One argv (binary name excluded) against the pre-M1 tree and M1_CLI_SURFACE (rulings 32.31,
144
+ * 32.33, 32.35; CASE-DSL rule 29). Read as commander does: a word is a subcommand when the
145
+ * current path has it and no positional has been taken there, else the path's positional (a
146
+ * pre-M1 path's declared arguments; an M1-only path without subcommands takes any number), else
147
+ * unknown, and the walk stops (commander stops at an unknown command). A word that names a
148
+ * command anywhere in the tree, the surface or the sub-verb list never fills a positional, so a
149
+ * misplaced verb (`agent adopt <name>`, `agent lock doctor`) is unknown. A launcher sub-verb is
150
+ * accepted only as the first word after `agent`, and its arguments are not checked. An option
151
+ * counts on its own path or as a global option, never on an ancestor; a pre-M1 option that takes
152
+ * a value consumes the next token, and M1 options are read as flags (each M1 path that adds one
153
+ * takes positionals, so a value is a positional there). `--name=value` is read as `--name`.
154
+ * Short options, `--help`, `$` references and everything after a literal `--` are not checked.
155
+ */
156
+ export function resolveCliArgv(argv, preM1Tree, surface = M1_CLI_SURFACE) {
157
+ const info = new Map();
158
+ const get = (p) => {
159
+ let i = info.get(p);
160
+ if (!i)
161
+ info.set(p, (i = { children: new Set(), slots: -1, options: new Map() }));
162
+ return i;
163
+ };
164
+ const verbs = new Set(PRE_M1_LAUNCHER_SUBVERBS);
165
+ const walk = (n, parent) => {
166
+ const p = [...parent, n.name];
167
+ const i = get(p.join(" "));
168
+ verbs.add(n.name);
169
+ if (parent.length > 0)
170
+ get(parent.join(" ")).children.add(n.name);
171
+ const args = n.arguments ?? [];
172
+ i.slots = args.some((a) => a.variadic) ? Infinity : args.length;
173
+ for (const o of n.options ?? [])
174
+ if (o.long)
175
+ i.options.set(o.long, takesValue(o));
176
+ for (const c of n.commands ?? [])
177
+ walk(c, p);
178
+ };
179
+ for (const c of preM1Tree.commands)
180
+ walk(c, []);
181
+ const top = get("");
182
+ for (const c of preM1Tree.commands)
183
+ top.children.add(c.name);
184
+ for (const e of surface) {
185
+ for (let k = 1; k <= e.path.length; k++) {
186
+ get(e.path.slice(0, k - 1).join(" ")).children.add(e.path[k - 1]);
187
+ verbs.add(e.path[k - 1]);
188
+ }
189
+ const i = get(e.path.join(" "));
190
+ for (const o of e.options)
191
+ if (!i.options.has(o))
192
+ i.options.set(o, false);
193
+ }
194
+ // An M1-only path (not in the tree) takes positionals unless it has subcommands.
195
+ for (const i of info.values())
196
+ if (i.slots < 0)
197
+ i.slots = i.children.size > 0 ? 0 : Infinity;
198
+ top.slots = 0;
199
+ const global = new Map();
200
+ for (const o of preM1Tree.globalOptions ?? [])
201
+ if (o.long)
202
+ global.set(o.long, takesValue(o));
203
+ const path = [];
204
+ const unknown = [];
205
+ let taken = 0;
206
+ for (let k = 0; k < argv.length; k++) {
207
+ const t = argv[k];
208
+ if (t === "--")
209
+ break;
210
+ if (t.startsWith("--")) {
211
+ const name = t.split("=")[0];
212
+ if (name === "--help")
213
+ continue;
214
+ const here = get(path.join(" ")).options;
215
+ const value = here.has(name) ? here.get(name) : global.get(name);
216
+ if (value === undefined)
217
+ unknown.push(name);
218
+ else if (value && !t.includes("="))
219
+ k++;
220
+ continue;
221
+ }
222
+ if (t.startsWith("-") || t.startsWith("$"))
223
+ continue;
224
+ if (path.length === 1 &&
225
+ path[0] === "agent" &&
226
+ taken === 0 &&
227
+ PRE_M1_LAUNCHER_SUBVERBS.includes(t))
228
+ return finish([...path, t]);
229
+ const here = get(path.join(" "));
230
+ if (taken === 0 && here.children.has(t)) {
231
+ path.push(t);
232
+ continue;
233
+ }
234
+ if (!verbs.has(t) && taken < here.slots) {
235
+ taken++;
236
+ continue;
237
+ }
238
+ unknown.push(t);
239
+ break;
240
+ }
241
+ return finish(path);
242
+ function finish(p) {
243
+ return unknown.length === 0 ? { ok: true, path: p } : { ok: false, path: p, unknown };
244
+ }
245
+ }
246
+ /**
247
+ * The CLI call the bundled plugin's /mnemom lock makes: the M1 `agent lock` path with the session
248
+ * name as its one positional, read from MNEMOM_AGENT_SESSION_NAME (the launcher sets it in the
249
+ * claude it starts). No option, no cwd argument: the child inherits the original's process cwd.
250
+ */
251
+ export const PLUGIN_LOCK_ARGV = Object.freeze([
252
+ "agent",
253
+ "lock",
254
+ Object.freeze({ env: "MNEMOM_AGENT_SESSION_NAME" }),
255
+ ]);
256
+ /** PLUGIN_LOCK_ARGV resolved against `env`; null when MNEMOM_AGENT_SESSION_NAME is unset or empty (the plugin then runs no CLI call). */
257
+ export function pluginLockArgv(env) {
258
+ const out = [];
259
+ for (const a of PLUGIN_LOCK_ARGV) {
260
+ if (typeof a === "string") {
261
+ out.push(a);
262
+ continue;
263
+ }
264
+ const v = env[a.env];
265
+ if (v === undefined || v === "")
266
+ return null;
267
+ out.push(v);
268
+ }
269
+ return out;
270
+ }