@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,403 @@
1
+ // GENERATED from shared/durable-contract/src/owner-verbs.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
2
+ /**
3
+ * The owner-verb table (BACKBONE amendments 35, 45; C11-R04..R11, R17, R23, R26, R34, R36;
4
+ * rulings r3 U04, I03; final F04, F06). One total pure function, first match wins:
5
+ *
6
+ * 1 machine principal -> 403 machine_principal_refused
7
+ * 2 unknown session or another org -> 404 agent_not_found (the existing answer)
8
+ * 3 caller is not the owner -> 403 durable_not_owner {owner}
9
+ * 4 effective terminal (expired included) -> 410 durable_session_ended {state, state_reason}, every verb
10
+ * 5 resume of paused(agent_contained) while the agent is still paused -> 409 durable_agent_contained
11
+ * 6 pause on suspended(identity_mismatch) -> 409 durable_invalid_transition (done then --new)
12
+ * 7 no-op repeats -> 200 {changed:false}
13
+ * 8 anything else not in the §3.4 table -> 409 durable_invalid_transition {from_state, state_reason, verb}
14
+ *
15
+ * Applied rows bump the epoch FIRST in the same transaction where they fence (pause, complete,
16
+ * kill); resume to parked does not bump (the home executor's next claim does). Device-step verbs
17
+ * (unlock, budget_raise, and resume of paused(agent_contained) once the agent is active) answer
18
+ * 202 and change nothing until the approval is consumed; with an API-key-only credential they are
19
+ * refused before any approval row (F06).
20
+ */
21
+ import { budgetFixKey, stoppedFixKey } from "./fixlines.js";
22
+ import { endedBody, isEffectiveStateConsistent, } from "./states.js";
23
+ import { PER_SESSION_BUDGET_LIMIT_USD } from "./constants.js";
24
+ /**
25
+ * The owner verbs BACKBONE names for this table: pause, resume, complete, kill, amend. The first
26
+ * four are decided by `ownerVerbDecision`; `amend` is decided by `amendDecision`, which runs the
27
+ * same precedence rows 1-6 and then splits by direction (C07-R07, C16-R04): a budget raise goes to
28
+ * the device-step verb `budget_raise`, any other raise or loosening (goal text edits included, and
29
+ * a budget raise mixed with one) is 409 durable_amend_raise_refused {field}, and a lowering applies
30
+ * with journal `charter.amended {change:'lowering'}` and no state transition.
31
+ */
32
+ export const OWNER_VERBS = ["pause", "resume", "complete", "kill", "amend"];
33
+ /**
34
+ * The verbs `ownerVerbDecision` takes: the four table verbs plus the two device-step verbs that
35
+ * run the same precedence (`unlock`, and `budget_raise`, which is amend's raise leg).
36
+ */
37
+ export const OWNER_TABLE_VERBS = [
38
+ "pause",
39
+ "resume",
40
+ "complete",
41
+ "kill",
42
+ "unlock",
43
+ "budget_raise",
44
+ ];
45
+ /** Verbs that run the owner_mutation device step (and so need a signed-in owner, F06). */
46
+ export const DEVICE_STEP_VERBS = [
47
+ "unlock",
48
+ "budget_raise",
49
+ ];
50
+ export const CALLER_CREDENTIALS = ["jwt", "owner_api_key", "machine"];
51
+ /**
52
+ * The catalogue fix for a bare row-8 refusal (wave-0 fix ruling 4). Locked rows key on the
53
+ * EFFECTIVE state through STOPPED_FIX (so a lapsed grant over any stored state gets grant_expired)
54
+ * and are never null: budget_raise on paused(owner) gets budget_while_paused, every other locked
55
+ * row-8 the stopped line for its state. A locked row 8 only arises on a stopped effective state;
56
+ * any other state, or an effective state the stored row cannot derive, throws. Tracked rows keep
57
+ * their tracked lines.
58
+ */
59
+ export function invalidTransitionFix(state, reason, effective, durableMode, verb, committedBudgetUsd = 0) {
60
+ if (durableMode === "tracked") {
61
+ if (verb === "pause")
62
+ return "tracked_pause";
63
+ if (verb === "resume")
64
+ return "tracked_resume";
65
+ if (verb === "budget_raise")
66
+ return "tracked_budget";
67
+ return null;
68
+ }
69
+ if (!isEffectiveStateConsistent(state, reason, effective))
70
+ throw new RangeError(`effective ${effective} does not derive from ${state}(${String(reason)})`);
71
+ if (verb === "budget_raise" && effective === "paused" && reason === "owner")
72
+ return "budget_while_paused";
73
+ return stoppedFixKey(effective, reason, { committedBudgetUsd });
74
+ }
75
+ /** The (from_state, state_reason) a row-8 body reports: the effective pair for a lapsed grant. */
76
+ export function row8FromPair(state, reason, effective) {
77
+ return effective === "suspended_grant_expired"
78
+ ? { from_state: "suspended", state_reason: "grant_expired" }
79
+ : { from_state: state, state_reason: reason };
80
+ }
81
+ const NOOP_RESUME_STATES = ["running", "resuming", "parked", "detached"];
82
+ const BUDGET_IN_PLACE = ["running", "resuming", "detached", "parked"];
83
+ export function ownerVerbDecision(i) {
84
+ const row8 = () => ({
85
+ kind: "refuse",
86
+ row: 8,
87
+ status: 409,
88
+ code: "durable_invalid_transition",
89
+ fix: invalidTransitionFix(i.state, i.state_reason, i.effective_state, i.durable_mode, i.verb, i.committedBudgetUsd ?? 0),
90
+ body: i.durable_mode === "tracked"
91
+ ? { from_state: "tracked", state_reason: null, verb: i.verb }
92
+ : { ...row8FromPair(i.state, i.state_reason, i.effective_state), verb: i.verb },
93
+ });
94
+ const common = precedenceRows1to4(i, i.verb);
95
+ if (common !== null)
96
+ return common;
97
+ const contained = i.state === "paused" && i.state_reason === "agent_contained";
98
+ // 5
99
+ if (i.verb === "resume" && contained && i.agentContainment === "paused") {
100
+ return {
101
+ kind: "refuse",
102
+ row: 5,
103
+ status: 409,
104
+ code: "durable_agent_contained",
105
+ fix: "agent_contained",
106
+ body: { status: "paused" },
107
+ };
108
+ }
109
+ // 6
110
+ if (i.verb === "pause" && i.state === "suspended" && i.state_reason === "identity_mismatch") {
111
+ return {
112
+ kind: "refuse",
113
+ row: 6,
114
+ status: 409,
115
+ code: "durable_invalid_transition",
116
+ fix: "identity_mismatch",
117
+ body: { from_state: i.state, state_reason: i.state_reason, verb: i.verb },
118
+ };
119
+ }
120
+ const locked = i.durable_mode === "locked";
121
+ // 7
122
+ if (locked && i.verb === "pause" && i.state === "paused")
123
+ return { kind: "noop", row: 7, status: 200, fix: null };
124
+ if (locked && i.verb === "resume" && NOOP_RESUME_STATES.includes(i.effective_state)) {
125
+ return { kind: "noop", row: 7, status: 200, fix: "resume_live" };
126
+ }
127
+ // Applied rows and device steps.
128
+ switch (i.verb) {
129
+ case "complete":
130
+ return {
131
+ kind: "apply",
132
+ status: 200,
133
+ to: { state: "completed", state_reason: null },
134
+ event: "session.completed",
135
+ epochBump: true,
136
+ clearsLease: true,
137
+ resetsResumeFailures: false,
138
+ };
139
+ case "kill":
140
+ return {
141
+ kind: "apply",
142
+ status: 200,
143
+ to: { state: "killed", state_reason: null },
144
+ event: "session.killed",
145
+ epochBump: true,
146
+ clearsLease: true,
147
+ resetsResumeFailures: false,
148
+ };
149
+ case "pause":
150
+ if (!locked)
151
+ return row8();
152
+ return {
153
+ kind: "apply",
154
+ status: 200,
155
+ to: { state: "paused", state_reason: "owner" },
156
+ event: "session.paused",
157
+ epochBump: true,
158
+ clearsLease: true,
159
+ resetsResumeFailures: false,
160
+ };
161
+ case "resume":
162
+ if (!locked)
163
+ return row8();
164
+ if (contained)
165
+ return deviceStepOr(i, "unpause_contained");
166
+ if ((i.state === "paused" && i.state_reason === "owner") ||
167
+ (i.state === "suspended" &&
168
+ (i.state_reason === "respawn_failed" ||
169
+ i.state_reason === "attestation_failed" ||
170
+ i.state_reason === "approval_expired" ||
171
+ i.state_reason === "approval_denied"))) {
172
+ return {
173
+ kind: "apply",
174
+ status: 200,
175
+ to: { state: "parked", state_reason: null },
176
+ event: "session.unpaused",
177
+ epochBump: false,
178
+ clearsLease: false,
179
+ resetsResumeFailures: i.state === "suspended",
180
+ };
181
+ }
182
+ return row8();
183
+ case "unlock":
184
+ if (!locked)
185
+ return { kind: "noop", row: 7, status: 200, fix: null };
186
+ return deviceStepOr(i, "unlock");
187
+ case "budget_raise": {
188
+ if (!locked)
189
+ return row8();
190
+ const committed = i.committedBudgetUsd;
191
+ const requested = i.requestedBudgetUsd;
192
+ if (committed === undefined || requested === undefined || !(requested > committed)) {
193
+ throw new RangeError("budget_raise needs requested > committed; lowering is amend's path");
194
+ }
195
+ const raisable = BUDGET_IN_PLACE.includes(i.effective_state) ||
196
+ (i.state === "suspended" && i.state_reason === "budget_reached") ||
197
+ i.effective_state === "suspended_grant_expired";
198
+ if (!raisable)
199
+ return row8();
200
+ if (requested > PER_SESSION_BUDGET_LIMIT_USD) {
201
+ return {
202
+ kind: "refuse",
203
+ row: 8,
204
+ status: 422,
205
+ code: "durable_unsupported",
206
+ fix: budgetFixKey(committed, PER_SESSION_BUDGET_LIMIT_USD, "raise"),
207
+ body: { feature: "above_limit_raise" },
208
+ };
209
+ }
210
+ return deviceStepOr(i, "budget_raise");
211
+ }
212
+ }
213
+ }
214
+ /**
215
+ * The old contract route (POST /v1/agent/sessions/{cid}/contract) and MCP update_contract on a
216
+ * LOCKED session (C07-R08; wave-0 fix ruling 1.20, Wassim option 1): a lowering is applied as a
217
+ * chained charter amend, exactly `amendDecision` (charter.amended {change:'lowering'}); every raise
218
+ * or loosening is 409 durable_amend_raise_refused {field}. The gateway picks the new charter up
219
+ * lazily, on the next request (C07-R06); nothing is pushed. Constants only here; the route
220
+ * behaviour lands in Wave 1.
221
+ */
222
+ export const OLD_ROUTE_BRANCH = "amend";
223
+ export const OLD_ROUTE_REFRESH = "lazy";
224
+ /** The charter field an amend raises budget through; every other field can only be lowered. */
225
+ export const AMEND_BUDGET_FIELD = "budget";
226
+ /**
227
+ * The owner `amend` verb (BACKBONE owner-verb table; C07-R07, C16-R04, C11 final F04). First match:
228
+ *
229
+ * rows 1-4 as for every verb (rows 5 and 6 are resume- and pause-only, so never match amend)
230
+ * row 7 every change is "equal" (the new value is the current one) -> 200 {changed:false},
231
+ * nothing journaled, in either mode; "equal" changes beside others are ignored
232
+ * raise-refused any non-budget raise or loosening, alone or mixed with a budget raise
233
+ * -> 409 durable_amend_raise_refused {field} (the first such field); refused whole
234
+ * budget raise -> exactly the budget_raise row (tracked line, raisable states, 422, device step)
235
+ * tracked a lowering on a tracked session -> 409 durable_invalid_transition with the tracked budget line
236
+ * lowering -> 200 applied in place: charter.amended {change:'lowering'}, no state, epoch or lease change
237
+ */
238
+ export function amendDecision(i) {
239
+ if (i.changes.length === 0)
240
+ throw new RangeError("amend needs at least one change");
241
+ const common = precedenceRows1to4(i, "amend");
242
+ if (common !== null)
243
+ return common;
244
+ // 7
245
+ const changes = i.changes.filter((c) => c.direction !== "equal");
246
+ if (changes.length === 0)
247
+ return { kind: "noop", row: 7, status: 200, fix: null };
248
+ const refused = changes.find((c) => c.direction === "loosen" || (c.direction === "raise" && c.field !== AMEND_BUDGET_FIELD));
249
+ if (refused !== undefined) {
250
+ return {
251
+ kind: "refuse",
252
+ row: 8,
253
+ status: 409,
254
+ code: "durable_amend_raise_refused",
255
+ fix: null,
256
+ body: { field: refused.field },
257
+ };
258
+ }
259
+ if (changes.some((c) => c.direction === "raise")) {
260
+ const { changes: _changes, ...rest } = i;
261
+ return ownerVerbDecision({ ...rest, verb: "budget_raise" });
262
+ }
263
+ if (i.durable_mode === "tracked") {
264
+ return {
265
+ kind: "refuse",
266
+ row: 8,
267
+ status: 409,
268
+ code: "durable_invalid_transition",
269
+ fix: "tracked_budget",
270
+ body: { from_state: "tracked", state_reason: null, verb: "amend" },
271
+ };
272
+ }
273
+ return {
274
+ kind: "apply",
275
+ status: 200,
276
+ to: "unchanged",
277
+ event: "charter.amended",
278
+ epochBump: false,
279
+ clearsLease: false,
280
+ resetsResumeFailures: false,
281
+ change: "lowering",
282
+ };
283
+ }
284
+ /** Rows 1-4, shared by every owner verb (amend included). Null when none matches. */
285
+ function precedenceRows1to4(i, verb) {
286
+ // 1-3
287
+ if (i.credential === "machine")
288
+ return { kind: "refuse", row: 1, status: 403, code: "machine_principal_refused", fix: null };
289
+ if (!i.visible)
290
+ return { kind: "refuse", row: 2, status: 404, code: "agent_not_found", fix: null };
291
+ if (!i.isOwner) {
292
+ const admin = i.callerIsAdmin && (verb === "pause" || verb === "kill");
293
+ return {
294
+ kind: "refuse",
295
+ row: 3,
296
+ status: 403,
297
+ code: "durable_not_owner",
298
+ fix: admin ? "not_owner_admin" : "not_owner_info",
299
+ };
300
+ }
301
+ // 4
302
+ const ended = endedBody(i.effective_state, i.state_reason);
303
+ if (ended !== null) {
304
+ return {
305
+ kind: "refuse",
306
+ row: 4,
307
+ status: 410,
308
+ code: "durable_session_ended",
309
+ fix: ended.state_reason === "agent_killed" ? "agent_killed" : "session_ended",
310
+ body: { ...ended },
311
+ };
312
+ }
313
+ return null;
314
+ }
315
+ /** A device step needs a signed-in owner (F06): an API-key-only owner gets the login line and nothing changes. */
316
+ function deviceStepOr(i, subject) {
317
+ if (i.credential === "owner_api_key") {
318
+ return {
319
+ kind: "refuse",
320
+ row: 8,
321
+ status: 403,
322
+ code: "durable_session_login_required",
323
+ fix: "device_step_login",
324
+ };
325
+ }
326
+ return { kind: "device_step", status: 202, subject };
327
+ }
328
+ /**
329
+ * What an applied owner_mutation does on consume (C11-R07, R17, R36; C16-R29). budget_raise from
330
+ * suspended(budget_reached) parks; elsewhere it raises the ceiling in place.
331
+ */
332
+ export function applyDeviceStep(subject, state, reason) {
333
+ switch (subject) {
334
+ case "unlock":
335
+ return {
336
+ kind: "apply",
337
+ status: 200,
338
+ to: { state: "tracked", state_reason: null },
339
+ event: "session.unlocked",
340
+ epochBump: true,
341
+ clearsLease: true,
342
+ resetsResumeFailures: false,
343
+ };
344
+ case "unpause_contained":
345
+ return {
346
+ kind: "apply",
347
+ status: 200,
348
+ to: { state: "parked", state_reason: null },
349
+ event: "session.unpaused",
350
+ epochBump: false,
351
+ clearsLease: false,
352
+ resetsResumeFailures: false,
353
+ };
354
+ case "budget_raise":
355
+ return state === "suspended" && reason === "budget_reached"
356
+ ? {
357
+ kind: "apply",
358
+ status: 200,
359
+ to: { state: "parked", state_reason: null },
360
+ event: "charter.amended",
361
+ epochBump: false,
362
+ clearsLease: false,
363
+ resetsResumeFailures: false,
364
+ change: "budget_raise",
365
+ }
366
+ : {
367
+ kind: "apply",
368
+ status: 200,
369
+ to: "unchanged",
370
+ event: "charter.amended",
371
+ epochBump: false,
372
+ clearsLease: false,
373
+ resetsResumeFailures: false,
374
+ change: "budget_raise",
375
+ };
376
+ }
377
+ }
378
+ /**
379
+ * Revocation table for pre-bump keys (rulings I03, r2 I01): which transitions REVOKE (revoked_at
380
+ * set, a pre-bump key then answers 401 durable_key_revoked) versus only fence (revoked_at stays
381
+ * NULL; the key answers 410 durable_session_ended or 409 durable_lease_fenced). Exactly four
382
+ * transitions revoke, each in the same transaction as its epoch bump (a fault between the bump
383
+ * and the revoke rolls back both). The M1 sweep never writes revoked_at.
384
+ */
385
+ export const KEY_EFFECT_OF_TRANSITION = {
386
+ pause: "fence",
387
+ complete: "fence",
388
+ kill: "fence",
389
+ expire: "fence",
390
+ fail: "fence",
391
+ containment: "fence",
392
+ unlock: "revoke",
393
+ claim_supersede: "revoke",
394
+ executor_revoke: "revoke",
395
+ respawn_failed_suspend: "revoke",
396
+ };
397
+ /** The four revoking transitions, in ruling order (I03). */
398
+ export const REVOKING_TRANSITIONS = [
399
+ "claim_supersede",
400
+ "executor_revoke",
401
+ "unlock",
402
+ "respawn_failed_suspend",
403
+ ];
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Host paths (BACKBONE C2, C3; amendment 51). Pure functions of the HOME directory and the ids.
3
+ * Ids are validated so a path never escapes its directory.
4
+ */
5
+ /** A session or conversation id safe to use as a path segment (the gateway cid rule). */
6
+ export declare const ID_RE: RegExp;
7
+ export declare const DURABLE_DIR = ".mnemom/durable";
8
+ /** The per-conversation proxy lock (flock LOCK_EX|LOCK_NB), a pure function of the conversation id. */
9
+ export declare function proxyLockPath(home: string, conversationId: string): string;
10
+ /** The transcript guard copy or link for a session (C2). */
11
+ export declare function transcriptGuardPath(home: string, sessionId: string): string;
12
+ export declare const TRANSCRIPT_GUARD_MODES: readonly ["link", "copy"];
13
+ /**
14
+ * The executor state directory and file, HOME-relative (wave-0 fix ruling 1.07; design section 4;
15
+ * amendment 51). The state file is the ONLY place the executor key may be stored (SECRET_SCOPE
16
+ * allowance). Directory mode 0700, file mode 0600.
17
+ */
18
+ export declare const EXECUTOR_STATE_DIR = ".mnemom/durable";
19
+ export declare const EXECUTOR_STATE_FILE = ".mnemom/durable/executor-state.json";
20
+ export declare const EXECUTOR_STATE_DIR_MODE = 448;
21
+ export declare const EXECUTOR_STATE_FILE_MODE = 384;
22
+ /** The absolute executor state file path under `home`. */
23
+ export declare function executorStatePath(home: string): string;
@@ -0,0 +1,35 @@
1
+ // GENERATED from shared/durable-contract/src/paths.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
2
+ /**
3
+ * Host paths (BACKBONE C2, C3; amendment 51). Pure functions of the HOME directory and the ids.
4
+ * Ids are validated so a path never escapes its directory.
5
+ */
6
+ /** A session or conversation id safe to use as a path segment (the gateway cid rule). */
7
+ export const ID_RE = /^[A-Za-z0-9-]{1,64}$/;
8
+ function checkId(id) {
9
+ if (!ID_RE.test(id))
10
+ throw new RangeError(`not a safe id: ${id}`);
11
+ return id;
12
+ }
13
+ export const DURABLE_DIR = ".mnemom/durable";
14
+ /** The per-conversation proxy lock (flock LOCK_EX|LOCK_NB), a pure function of the conversation id. */
15
+ export function proxyLockPath(home, conversationId) {
16
+ return `${home}/${DURABLE_DIR}/locks/${checkId(conversationId)}.lock`;
17
+ }
18
+ /** The transcript guard copy or link for a session (C2). */
19
+ export function transcriptGuardPath(home, sessionId) {
20
+ return `${home}/${DURABLE_DIR}/transcripts/${checkId(sessionId)}.jsonl`;
21
+ }
22
+ export const TRANSCRIPT_GUARD_MODES = ["link", "copy"];
23
+ /**
24
+ * The executor state directory and file, HOME-relative (wave-0 fix ruling 1.07; design section 4;
25
+ * amendment 51). The state file is the ONLY place the executor key may be stored (SECRET_SCOPE
26
+ * allowance). Directory mode 0700, file mode 0600.
27
+ */
28
+ export const EXECUTOR_STATE_DIR = DURABLE_DIR;
29
+ export const EXECUTOR_STATE_FILE = `${DURABLE_DIR}/executor-state.json`;
30
+ export const EXECUTOR_STATE_DIR_MODE = 0o700;
31
+ export const EXECUTOR_STATE_FILE_MODE = 0o600;
32
+ /** The absolute executor state file path under `home`. */
33
+ export function executorStatePath(home) {
34
+ return `${home}/${EXECUTOR_STATE_FILE}`;
35
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The pure exports a case's pure_fn step may call (ruling 32.34; CASE-DSL rule 30). Closed: a
3
+ * pure_fn step's (module, export) must be listed here, and its input must fit the arity.
4
+ *
5
+ * `module` is the specifier cases pass. S1 entries use 'shared/durable-contract'; their `source` is
6
+ * the S1 file and they carry no sha, because S1 is the freeze. Pre-M1 product entries are pinned at
7
+ * the merge-base b37bfbf1 by the git blob sha of the file. M1-built product exports join only once
8
+ * their builder lands them on int and a ruling or spec names them; none is listed today.
9
+ *
10
+ * Input contract: arity 1 passes `input` as the single argument. Arity n > 1 requires `input` to be
11
+ * an array of length n, spread as the positional arguments (pureFnArgs).
12
+ *
13
+ * Sorted by (module, export), unique, closed.
14
+ */
15
+ export interface PureFnExport {
16
+ readonly module: string;
17
+ readonly export: string;
18
+ readonly async: boolean;
19
+ readonly arity: number;
20
+ readonly source: string;
21
+ /** Git blob sha of the product file at the merge-base; absent on S1 entries. */
22
+ readonly sha?: string;
23
+ }
24
+ export declare const PURE_FN_S1_MODULE = "shared/durable-contract";
25
+ /** The merge-base product entries are pinned at (ruling 32.34). */
26
+ export declare const PURE_FN_PRODUCT_BASE = "b37bfbf14a41a4d8adeed38f89d2dedb01f1bc76";
27
+ export declare const PURE_FN_EXPORTS: readonly PureFnExport[];
28
+ /** A pending M1 export: the PureFnExport shape without sha (ruling 33.01). */
29
+ export type PureFnPending = Omit<PureFnExport, "sha">;
30
+ /**
31
+ * M1 product exports a pure_fn step may name before their builder lands them (ruling 33.01; rule 30
32
+ * accepts them, E4 detector D4 tags a row product_missing while the module is absent). When an
33
+ * entry lands on int it moves to PURE_FN_EXPORTS with its int blob sha. Sorted, unique, closed,
34
+ * disjoint from PURE_FN_EXPORTS.
35
+ *
36
+ * validateSeatSpec (BACKBONE line 153: the daemon RC refusal as a spec-validator unit test):
37
+ * input {raw_spec: object (the spec exactly as the daemon received it, which may carry fields
38
+ * outside the closed schema), name: string, launcher_key: 'off' | 'ask' | 'always'}
39
+ * output {seat_spec_built: boolean, spawn_requested: boolean,
40
+ * refusal: null | {code: 'durable_unsupported', feature: 'remote_control', names: string[],
41
+ * fix: string}}
42
+ * It calls hasRemoteControl on raw_spec before parseLaunchSpec (BACKBONE line 84 order). fix is the
43
+ * launch_spec_change render for name, with flags = the spec's model/effort flags (remote control
44
+ * removed) and the launcher suffix for launcher_key.
45
+ */
46
+ export declare const PURE_FN_M1_PENDING: readonly PureFnPending[];
47
+ /** The positional arguments for a pure_fn call (a PURE_FN_EXPORTS or PURE_FN_M1_PENDING entry) under the input contract; throws on a misfit. */
48
+ export declare function pureFnArgs(arity: number, input: unknown): unknown[];
@@ -0,0 +1,89 @@
1
+ // GENERATED from shared/durable-contract/src/pure-fn.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
2
+ /**
3
+ * The pure exports a case's pure_fn step may call (ruling 32.34; CASE-DSL rule 30). Closed: a
4
+ * pure_fn step's (module, export) must be listed here, and its input must fit the arity.
5
+ *
6
+ * `module` is the specifier cases pass. S1 entries use 'shared/durable-contract'; their `source` is
7
+ * the S1 file and they carry no sha, because S1 is the freeze. Pre-M1 product entries are pinned at
8
+ * the merge-base b37bfbf1 by the git blob sha of the file. M1-built product exports join only once
9
+ * their builder lands them on int and a ruling or spec names them; none is listed today.
10
+ *
11
+ * Input contract: arity 1 passes `input` as the single argument. Arity n > 1 requires `input` to be
12
+ * an array of length n, spread as the positional arguments (pureFnArgs).
13
+ *
14
+ * Sorted by (module, export), unique, closed.
15
+ */
16
+ export const PURE_FN_S1_MODULE = "shared/durable-contract";
17
+ /** The merge-base product entries are pinned at (ruling 32.34). */
18
+ export const PURE_FN_PRODUCT_BASE = "b37bfbf14a41a4d8adeed38f89d2dedb01f1bc76";
19
+ const s1 = (name, arity, isAsync, file) => Object.freeze({
20
+ module: PURE_FN_S1_MODULE,
21
+ export: name,
22
+ async: isAsync,
23
+ arity,
24
+ source: `shared/durable-contract/src/${file}`,
25
+ });
26
+ export const PURE_FN_EXPORTS = Object.freeze([
27
+ // Pre-M1 product, pinned at b37bfbf1. buildTurnHeader (int cli/src/turn-origin.mjs:139; arity 1,
28
+ // its second parameter has a default) applies entryOrigin to transcript entries (ruling 33.02).
29
+ Object.freeze({
30
+ module: "cli/src/turn-origin.mjs",
31
+ export: "buildTurnHeader",
32
+ async: false,
33
+ arity: 1,
34
+ source: "cli/src/turn-origin.mjs@b37bfbf1",
35
+ sha: "980d4401feb44069aa1fd0bc4ebeeffe0a9c58ab",
36
+ }),
37
+ // int cli/src/turn-origin.mjs:316.
38
+ Object.freeze({
39
+ module: "cli/src/turn-origin.mjs",
40
+ export: "turnHeaderFor",
41
+ async: true,
42
+ arity: 2,
43
+ source: "cli/src/turn-origin.mjs@b37bfbf1",
44
+ sha: "980d4401feb44069aa1fd0bc4ebeeffe0a9c58ab",
45
+ }),
46
+ s1("admitSweepDigest", 1, true, "admission.ts"),
47
+ s1("canonicalJson", 1, false, "canonical.ts"),
48
+ s1("eventHash", 1, true, "events.ts"),
49
+ s1("formatArm", 1, false, "arm.ts"),
50
+ s1("isLeaseKey", 1, false, "keys.ts"),
51
+ s1("normalizeCellId", 1, false, "cell-id.ts"),
52
+ s1("parseArm", 1, false, "arm.ts"),
53
+ s1("pluginLockArgv", 1, false, "cli-surface.ts"),
54
+ ]);
55
+ /**
56
+ * M1 product exports a pure_fn step may name before their builder lands them (ruling 33.01; rule 30
57
+ * accepts them, E4 detector D4 tags a row product_missing while the module is absent). When an
58
+ * entry lands on int it moves to PURE_FN_EXPORTS with its int blob sha. Sorted, unique, closed,
59
+ * disjoint from PURE_FN_EXPORTS.
60
+ *
61
+ * validateSeatSpec (BACKBONE line 153: the daemon RC refusal as a spec-validator unit test):
62
+ * input {raw_spec: object (the spec exactly as the daemon received it, which may carry fields
63
+ * outside the closed schema), name: string, launcher_key: 'off' | 'ask' | 'always'}
64
+ * output {seat_spec_built: boolean, spawn_requested: boolean,
65
+ * refusal: null | {code: 'durable_unsupported', feature: 'remote_control', names: string[],
66
+ * fix: string}}
67
+ * It calls hasRemoteControl on raw_spec before parseLaunchSpec (BACKBONE line 84 order). fix is the
68
+ * launch_spec_change render for name, with flags = the spec's model/effort flags (remote control
69
+ * removed) and the launcher suffix for launcher_key.
70
+ */
71
+ export const PURE_FN_M1_PENDING = Object.freeze([
72
+ Object.freeze({
73
+ module: "cli/src/durable/seat-spec-validator",
74
+ export: "validateSeatSpec",
75
+ async: false,
76
+ arity: 1,
77
+ source: "BACKBONE line 153; ruling 33.01",
78
+ }),
79
+ ]);
80
+ /** The positional arguments for a pure_fn call (a PURE_FN_EXPORTS or PURE_FN_M1_PENDING entry) under the input contract; throws on a misfit. */
81
+ export function pureFnArgs(arity, input) {
82
+ if (!Number.isInteger(arity) || arity < 1)
83
+ throw new RangeError(`bad arity: ${arity}`);
84
+ if (arity === 1)
85
+ return [input];
86
+ if (!Array.isArray(input) || input.length !== arity)
87
+ throw new RangeError(`arity ${arity} needs an input array of length ${arity}`);
88
+ return [...input];
89
+ }