@rewind-ai/cli 0.6.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 (244) hide show
  1. package/.env.example +8 -0
  2. package/LICENSE +21 -0
  3. package/README.md +39 -0
  4. package/dist/src/action/capture.d.ts +15 -0
  5. package/dist/src/action/capture.js +215 -0
  6. package/dist/src/action/capture.js.map +1 -0
  7. package/dist/src/action/mediate.d.ts +28 -0
  8. package/dist/src/action/mediate.js +109 -0
  9. package/dist/src/action/mediate.js.map +1 -0
  10. package/dist/src/action/mutate.d.ts +11 -0
  11. package/dist/src/action/mutate.js +189 -0
  12. package/dist/src/action/mutate.js.map +1 -0
  13. package/dist/src/action/objects.d.ts +5 -0
  14. package/dist/src/action/objects.js +50 -0
  15. package/dist/src/action/objects.js.map +1 -0
  16. package/dist/src/action/store.d.ts +24 -0
  17. package/dist/src/action/store.js +149 -0
  18. package/dist/src/action/store.js.map +1 -0
  19. package/dist/src/action/types.d.ts +84 -0
  20. package/dist/src/action/types.js +3 -0
  21. package/dist/src/action/types.js.map +1 -0
  22. package/dist/src/action/undo.d.ts +11 -0
  23. package/dist/src/action/undo.js +42 -0
  24. package/dist/src/action/undo.js.map +1 -0
  25. package/dist/src/adapters/filesystem.d.ts +35 -0
  26. package/dist/src/adapters/filesystem.js +499 -0
  27. package/dist/src/adapters/filesystem.js.map +1 -0
  28. package/dist/src/adapters/index.d.ts +7 -0
  29. package/dist/src/adapters/index.js +19 -0
  30. package/dist/src/adapters/index.js.map +1 -0
  31. package/dist/src/adapters/types.d.ts +54 -0
  32. package/dist/src/adapters/types.js +7 -0
  33. package/dist/src/adapters/types.js.map +1 -0
  34. package/dist/src/api/server.d.ts +25 -0
  35. package/dist/src/api/server.js +786 -0
  36. package/dist/src/api/server.js.map +1 -0
  37. package/dist/src/approval/store.d.ts +35 -0
  38. package/dist/src/approval/store.js +113 -0
  39. package/dist/src/approval/store.js.map +1 -0
  40. package/dist/src/checkpoint.d.ts +9 -0
  41. package/dist/src/checkpoint.js +140 -0
  42. package/dist/src/checkpoint.js.map +1 -0
  43. package/dist/src/cli/v5.d.ts +15 -0
  44. package/dist/src/cli/v5.js +110 -0
  45. package/dist/src/cli/v5.js.map +1 -0
  46. package/dist/src/cli.d.ts +2 -0
  47. package/dist/src/cli.js +823 -0
  48. package/dist/src/cli.js.map +1 -0
  49. package/dist/src/clients/types.d.ts +90 -0
  50. package/dist/src/clients/types.js +239 -0
  51. package/dist/src/clients/types.js.map +1 -0
  52. package/dist/src/commercial/auth/provider.d.ts +61 -0
  53. package/dist/src/commercial/auth/provider.js +227 -0
  54. package/dist/src/commercial/auth/provider.js.map +1 -0
  55. package/dist/src/commercial/entitlement/provider.d.ts +27 -0
  56. package/dist/src/commercial/entitlement/provider.js +192 -0
  57. package/dist/src/commercial/entitlement/provider.js.map +1 -0
  58. package/dist/src/commercial/entitlement/signing.d.ts +61 -0
  59. package/dist/src/commercial/entitlement/signing.js +124 -0
  60. package/dist/src/commercial/entitlement/signing.js.map +1 -0
  61. package/dist/src/commercial/env.d.ts +10 -0
  62. package/dist/src/commercial/env.js +40 -0
  63. package/dist/src/commercial/env.js.map +1 -0
  64. package/dist/src/commercial/product.d.ts +26 -0
  65. package/dist/src/commercial/product.js +39 -0
  66. package/dist/src/commercial/product.js.map +1 -0
  67. package/dist/src/commercial/store.d.ts +46 -0
  68. package/dist/src/commercial/store.js +104 -0
  69. package/dist/src/commercial/store.js.map +1 -0
  70. package/dist/src/commercial/stripe/checkout.d.ts +104 -0
  71. package/dist/src/commercial/stripe/checkout.js +469 -0
  72. package/dist/src/commercial/stripe/checkout.js.map +1 -0
  73. package/dist/src/core/compatibility.d.ts +15 -0
  74. package/dist/src/core/compatibility.js +226 -0
  75. package/dist/src/core/compatibility.js.map +1 -0
  76. package/dist/src/core/engine.d.ts +33 -0
  77. package/dist/src/core/engine.js +432 -0
  78. package/dist/src/core/engine.js.map +1 -0
  79. package/dist/src/core/lifecycle.d.ts +17 -0
  80. package/dist/src/core/lifecycle.js +56 -0
  81. package/dist/src/core/lifecycle.js.map +1 -0
  82. package/dist/src/core/types.d.ts +140 -0
  83. package/dist/src/core/types.js +37 -0
  84. package/dist/src/core/types.js.map +1 -0
  85. package/dist/src/destroy.d.ts +21 -0
  86. package/dist/src/destroy.js +219 -0
  87. package/dist/src/destroy.js.map +1 -0
  88. package/dist/src/diff.d.ts +13 -0
  89. package/dist/src/diff.js +251 -0
  90. package/dist/src/diff.js.map +1 -0
  91. package/dist/src/enforcement/detect.d.ts +13 -0
  92. package/dist/src/enforcement/detect.js +75 -0
  93. package/dist/src/enforcement/detect.js.map +1 -0
  94. package/dist/src/enforcement/hook-policy.d.ts +38 -0
  95. package/dist/src/enforcement/hook-policy.js +111 -0
  96. package/dist/src/enforcement/hook-policy.js.map +1 -0
  97. package/dist/src/enforcement/index.d.ts +8 -0
  98. package/dist/src/enforcement/index.js +8 -0
  99. package/dist/src/enforcement/index.js.map +1 -0
  100. package/dist/src/enforcement/perf.d.ts +6 -0
  101. package/dist/src/enforcement/perf.js +18 -0
  102. package/dist/src/enforcement/perf.js.map +1 -0
  103. package/dist/src/enforcement/policy.d.ts +12 -0
  104. package/dist/src/enforcement/policy.js +84 -0
  105. package/dist/src/enforcement/policy.js.map +1 -0
  106. package/dist/src/enforcement/readonly.d.ts +17 -0
  107. package/dist/src/enforcement/readonly.js +124 -0
  108. package/dist/src/enforcement/readonly.js.map +1 -0
  109. package/dist/src/enforcement/sandbox-clone.d.ts +6 -0
  110. package/dist/src/enforcement/sandbox-clone.js +11 -0
  111. package/dist/src/enforcement/sandbox-clone.js.map +1 -0
  112. package/dist/src/enforcement/setup.d.ts +33 -0
  113. package/dist/src/enforcement/setup.js +168 -0
  114. package/dist/src/enforcement/setup.js.map +1 -0
  115. package/dist/src/enforcement/trust.d.ts +10 -0
  116. package/dist/src/enforcement/trust.js +71 -0
  117. package/dist/src/enforcement/trust.js.map +1 -0
  118. package/dist/src/enforcement/types.d.ts +40 -0
  119. package/dist/src/enforcement/types.js +3 -0
  120. package/dist/src/enforcement/types.js.map +1 -0
  121. package/dist/src/entitlement/provider.d.ts +48 -0
  122. package/dist/src/entitlement/provider.js +95 -0
  123. package/dist/src/entitlement/provider.js.map +1 -0
  124. package/dist/src/hash.d.ts +9 -0
  125. package/dist/src/hash.js +23 -0
  126. package/dist/src/hash.js.map +1 -0
  127. package/dist/src/ledger/query.d.ts +19 -0
  128. package/dist/src/ledger/query.js +158 -0
  129. package/dist/src/ledger/query.js.map +1 -0
  130. package/dist/src/manifest.d.ts +32 -0
  131. package/dist/src/manifest.js +242 -0
  132. package/dist/src/manifest.js.map +1 -0
  133. package/dist/src/mcp/server.d.ts +7 -0
  134. package/dist/src/mcp/server.js +364 -0
  135. package/dist/src/mcp/server.js.map +1 -0
  136. package/dist/src/paths.d.ts +94 -0
  137. package/dist/src/paths.js +354 -0
  138. package/dist/src/paths.js.map +1 -0
  139. package/dist/src/permission/engine.d.ts +15 -0
  140. package/dist/src/permission/engine.js +147 -0
  141. package/dist/src/permission/engine.js.map +1 -0
  142. package/dist/src/permission/types.d.ts +42 -0
  143. package/dist/src/permission/types.js +3 -0
  144. package/dist/src/permission/types.js.map +1 -0
  145. package/dist/src/product/setup.d.ts +35 -0
  146. package/dist/src/product/setup.js +300 -0
  147. package/dist/src/product/setup.js.map +1 -0
  148. package/dist/src/protect/audit.d.ts +5 -0
  149. package/dist/src/protect/audit.js +26 -0
  150. package/dist/src/protect/audit.js.map +1 -0
  151. package/dist/src/protect/capture.d.ts +7 -0
  152. package/dist/src/protect/capture.js +250 -0
  153. package/dist/src/protect/capture.js.map +1 -0
  154. package/dist/src/protect/fingerprint.d.ts +4 -0
  155. package/dist/src/protect/fingerprint.js +49 -0
  156. package/dist/src/protect/fingerprint.js.map +1 -0
  157. package/dist/src/protect/hook-cli.d.ts +2 -0
  158. package/dist/src/protect/hook-cli.js +107 -0
  159. package/dist/src/protect/hook-cli.js.map +1 -0
  160. package/dist/src/protect/index.d.ts +12 -0
  161. package/dist/src/protect/index.js +12 -0
  162. package/dist/src/protect/index.js.map +1 -0
  163. package/dist/src/protect/install.d.ts +34 -0
  164. package/dist/src/protect/install.js +293 -0
  165. package/dist/src/protect/install.js.map +1 -0
  166. package/dist/src/protect/intercept.d.ts +11 -0
  167. package/dist/src/protect/intercept.js +390 -0
  168. package/dist/src/protect/intercept.js.map +1 -0
  169. package/dist/src/protect/protect.d.ts +17 -0
  170. package/dist/src/protect/protect.js +194 -0
  171. package/dist/src/protect/protect.js.map +1 -0
  172. package/dist/src/protect/root-paths.d.ts +13 -0
  173. package/dist/src/protect/root-paths.js +140 -0
  174. package/dist/src/protect/root-paths.js.map +1 -0
  175. package/dist/src/protect/shell-policy.d.ts +17 -0
  176. package/dist/src/protect/shell-policy.js +269 -0
  177. package/dist/src/protect/shell-policy.js.map +1 -0
  178. package/dist/src/protect/status.d.ts +11 -0
  179. package/dist/src/protect/status.js +165 -0
  180. package/dist/src/protect/status.js.map +1 -0
  181. package/dist/src/protect/store.d.ts +20 -0
  182. package/dist/src/protect/store.js +170 -0
  183. package/dist/src/protect/store.js.map +1 -0
  184. package/dist/src/protect/types.d.ts +116 -0
  185. package/dist/src/protect/types.js +3 -0
  186. package/dist/src/protect/types.js.map +1 -0
  187. package/dist/src/protect/undo-session.d.ts +14 -0
  188. package/dist/src/protect/undo-session.js +182 -0
  189. package/dist/src/protect/undo-session.js.map +1 -0
  190. package/dist/src/restore.d.ts +39 -0
  191. package/dist/src/restore.js +141 -0
  192. package/dist/src/restore.js.map +1 -0
  193. package/dist/src/sandbox.d.ts +23 -0
  194. package/dist/src/sandbox.js +198 -0
  195. package/dist/src/sandbox.js.map +1 -0
  196. package/dist/src/session/ambient.d.ts +10 -0
  197. package/dist/src/session/ambient.js +53 -0
  198. package/dist/src/session/ambient.js.map +1 -0
  199. package/dist/src/session/attribution.d.ts +27 -0
  200. package/dist/src/session/attribution.js +201 -0
  201. package/dist/src/session/attribution.js.map +1 -0
  202. package/dist/src/session/index.d.ts +25 -0
  203. package/dist/src/session/index.js +472 -0
  204. package/dist/src/session/index.js.map +1 -0
  205. package/dist/src/session/process.d.ts +34 -0
  206. package/dist/src/session/process.js +234 -0
  207. package/dist/src/session/process.js.map +1 -0
  208. package/dist/src/session/store.d.ts +14 -0
  209. package/dist/src/session/store.js +125 -0
  210. package/dist/src/session/store.js.map +1 -0
  211. package/dist/src/session/types.d.ts +111 -0
  212. package/dist/src/session/types.js +3 -0
  213. package/dist/src/session/types.js.map +1 -0
  214. package/dist/src/session/watcher.d.ts +32 -0
  215. package/dist/src/session/watcher.js +186 -0
  216. package/dist/src/session/watcher.js.map +1 -0
  217. package/dist/src/timing.d.ts +7 -0
  218. package/dist/src/timing.js +19 -0
  219. package/dist/src/timing.js.map +1 -0
  220. package/dist/src/types.d.ts +101 -0
  221. package/dist/src/types.js +3 -0
  222. package/dist/src/types.js.map +1 -0
  223. package/dist/src/verify.d.ts +8 -0
  224. package/dist/src/verify.js +126 -0
  225. package/dist/src/verify.js.map +1 -0
  226. package/docs/ADAPTERS.md +37 -0
  227. package/docs/APPROVALS.md +32 -0
  228. package/docs/ARCHITECTURE.md +57 -0
  229. package/docs/ATTRIBUTION.md +179 -0
  230. package/docs/COMMERCIAL.md +51 -0
  231. package/docs/CURSOR-ENFORCEMENT.md +73 -0
  232. package/docs/ENFORCEMENT.md +134 -0
  233. package/docs/FUTURE.md +91 -0
  234. package/docs/HUMAN-SETUP.md +98 -0
  235. package/docs/IDENTITY-AUTHORITY.md +35 -0
  236. package/docs/MCP.md +107 -0
  237. package/docs/PACKAGING.md +77 -0
  238. package/docs/PERMISSIONS.md +53 -0
  239. package/docs/PRODUCT-V5.md +63 -0
  240. package/docs/PRODUCT-V6.md +69 -0
  241. package/docs/PROTECTED-SESSIONS.md +155 -0
  242. package/docs/THREAT-MODEL.md +84 -0
  243. package/docs/TRANSACTIONS.md +57 -0
  244. package/package.json +85 -0
@@ -0,0 +1,186 @@
1
+ import { assertApprovedSandbox, assertSafeRelativePath, getProjectRoot, isPathInside, } from "../paths.js";
2
+ import { matchAmbientPath } from "./ambient.js";
3
+ import { randomBytes } from "node:crypto";
4
+ import path from "node:path";
5
+ import { lstat } from "node:fs/promises";
6
+ import chokidar from "chokidar";
7
+ function toRel(root, abs) {
8
+ const rel = path.relative(root, abs).split(path.sep).join("/");
9
+ if (rel === "" || rel === ".") {
10
+ throw new Error("root event");
11
+ }
12
+ return assertSafeRelativePath(rel);
13
+ }
14
+ /**
15
+ * Live sandbox watcher.
16
+ * Uses chokidar (FSEvents on macOS) with debounce/coalesce.
17
+ * Events are signals — final manifest diff remains authoritative.
18
+ */
19
+ export class SandboxWatcher {
20
+ sandboxRoot;
21
+ onEvent;
22
+ watcher = null;
23
+ pending = new Map();
24
+ closed = false;
25
+ debounceMs;
26
+ stats = {
27
+ rawSignals: 0,
28
+ emittedEvents: 0,
29
+ peakEventsPerSec: 0,
30
+ };
31
+ windowCount = 0;
32
+ windowTimer = null;
33
+ constructor(sandboxRoot, onEvent, options = {}) {
34
+ this.sandboxRoot = sandboxRoot;
35
+ this.onEvent = onEvent;
36
+ this.debounceMs = options.debounceMs ?? 75;
37
+ }
38
+ async start(projectRoot = getProjectRoot()) {
39
+ await assertApprovedSandbox(this.sandboxRoot, projectRoot);
40
+ this.windowTimer = setInterval(() => {
41
+ if (this.windowCount > this.stats.peakEventsPerSec) {
42
+ this.stats.peakEventsPerSec = this.windowCount;
43
+ }
44
+ this.windowCount = 0;
45
+ }, 1000);
46
+ this.windowTimer.unref?.();
47
+ this.watcher = chokidar.watch(this.sandboxRoot, {
48
+ ignoreInitial: true,
49
+ persistent: true,
50
+ awaitWriteFinish: {
51
+ stabilityThreshold: 50,
52
+ pollInterval: 25,
53
+ },
54
+ followSymlinks: false,
55
+ depth: 99,
56
+ });
57
+ this.watcher.on("all", (eventName, absPath) => {
58
+ void this.handleRaw(eventName, absPath);
59
+ });
60
+ this.watcher.on("error", (err) => {
61
+ // Surface as UNKNOWN modify on root marker — keep watching
62
+ console.error(`[watcher error] ${err instanceof Error ? err.message : String(err)}`);
63
+ });
64
+ // Ready wait
65
+ await new Promise((resolve) => {
66
+ this.watcher?.on("ready", () => resolve());
67
+ });
68
+ }
69
+ async handleRaw(eventName, absPath) {
70
+ if (this.closed)
71
+ return;
72
+ if (!isPathInside(this.sandboxRoot, absPath))
73
+ return;
74
+ this.stats.rawSignals++;
75
+ this.windowCount++;
76
+ const key = absPath;
77
+ const existing = this.pending.get(key);
78
+ if (existing) {
79
+ existing.types.add(eventName);
80
+ existing.rawCount++;
81
+ clearTimeout(existing.timer);
82
+ existing.timer = setTimeout(() => {
83
+ void this.flush(key);
84
+ }, this.debounceMs);
85
+ return;
86
+ }
87
+ const timer = setTimeout(() => {
88
+ void this.flush(key);
89
+ }, this.debounceMs);
90
+ this.pending.set(key, {
91
+ abs: absPath,
92
+ types: new Set([eventName]),
93
+ timer,
94
+ rawCount: 1,
95
+ });
96
+ }
97
+ async flush(key) {
98
+ const pending = this.pending.get(key);
99
+ if (!pending)
100
+ return;
101
+ this.pending.delete(key);
102
+ let rel;
103
+ try {
104
+ rel = toRel(this.sandboxRoot, pending.abs);
105
+ if (rel === ".")
106
+ return;
107
+ }
108
+ catch {
109
+ return;
110
+ }
111
+ const type = await this.classify(pending.types, pending.abs);
112
+ const ambient = matchAmbientPath(rel);
113
+ const evidence = [
114
+ {
115
+ kind: "watcher_signal",
116
+ detail: `chokidar/FSEvents signals: ${[...pending.types].join(",")}`,
117
+ observedAt: new Date().toISOString(),
118
+ },
119
+ ];
120
+ if (ambient.ambient) {
121
+ evidence.push({
122
+ kind: "ambient_filename_pattern",
123
+ detail: ambient.evidence,
124
+ observedAt: new Date().toISOString(),
125
+ });
126
+ }
127
+ const event = {
128
+ id: `ev-${Date.now().toString(36)}-${randomBytes(2).toString("hex")}`,
129
+ at: new Date().toISOString(),
130
+ type,
131
+ path: rel,
132
+ rawCount: pending.rawCount,
133
+ // Honest default: watcher does not know the actor
134
+ actor: ambient.ambient ? "SYSTEM" : "UNKNOWN",
135
+ confidence: ambient.ambient ? "MEDIUM" : "NONE",
136
+ evidence,
137
+ ambientSuspect: ambient.ambient,
138
+ };
139
+ this.stats.emittedEvents++;
140
+ this.onEvent(event);
141
+ }
142
+ async classify(types, abs) {
143
+ const has = (t) => types.has(t);
144
+ let isDir = false;
145
+ try {
146
+ const st = await lstat(abs);
147
+ isDir = st.isDirectory();
148
+ }
149
+ catch {
150
+ // deleted
151
+ if (has("unlinkDir") || has("rmdir"))
152
+ return "DIRECTORY_DELETE";
153
+ if (has("unlink") || has("delete"))
154
+ return "DELETE";
155
+ return "DELETE";
156
+ }
157
+ if (has("addDir") || (has("add") && isDir))
158
+ return "DIRECTORY_CREATE";
159
+ if (has("unlinkDir"))
160
+ return "DIRECTORY_DELETE";
161
+ if (has("add") && !isDir)
162
+ return "CREATE";
163
+ if (has("change") || has("modify"))
164
+ return "MODIFY";
165
+ if (has("unlink"))
166
+ return "DELETE";
167
+ return "UNKNOWN";
168
+ }
169
+ async stop() {
170
+ this.closed = true;
171
+ for (const p of this.pending.values())
172
+ clearTimeout(p.timer);
173
+ // Flush remaining
174
+ const keys = [...this.pending.keys()];
175
+ for (const k of keys)
176
+ await this.flush(k);
177
+ if (this.windowTimer)
178
+ clearInterval(this.windowTimer);
179
+ if (this.watcher) {
180
+ await this.watcher.close();
181
+ this.watcher = null;
182
+ }
183
+ return { ...this.stats };
184
+ }
185
+ }
186
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/session/watcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /** Simple timing helpers. */
2
+ export declare class Timer {
3
+ private readonly start;
4
+ constructor();
5
+ elapsedMs(): number;
6
+ }
7
+ export declare function formatMs(ms: number): string;
@@ -0,0 +1,19 @@
1
+ /** Simple timing helpers. */
2
+ export class Timer {
3
+ start;
4
+ constructor() {
5
+ this.start = process.hrtime.bigint();
6
+ }
7
+ elapsedMs() {
8
+ const ns = process.hrtime.bigint() - this.start;
9
+ return Number(ns) / 1e6;
10
+ }
11
+ }
12
+ export function formatMs(ms) {
13
+ if (ms < 1)
14
+ return `${ms.toFixed(2)}ms`;
15
+ if (ms < 1000)
16
+ return `${ms.toFixed(1)}ms`;
17
+ return `${(ms / 1000).toFixed(2)}s`;
18
+ }
19
+ //# sourceMappingURL=timing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.js","sourceRoot":"","sources":["../../src/timing.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAE7B,MAAM,OAAO,KAAK;IACC,KAAK,CAAS;IAE/B;QACE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;IACvC,CAAC;IAED,SAAS;QACP,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAChD,OAAO,MAAM,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;IAC1B,CAAC;CACF;AAED,MAAM,UAAU,QAAQ,CAAC,EAAU;IACjC,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IACxC,IAAI,EAAE,GAAG,IAAI;QAAE,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3C,OAAO,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AACtC,CAAC"}
@@ -0,0 +1,101 @@
1
+ /** Core domain types for REWIND V0. */
2
+ export type ChangeType = "CREATED" | "MODIFIED" | "DELETED" | "RENAMED" | "MOVED";
3
+ export type Reversibility = "REVERSIBLE" | "COMPENSABLE" | "IRREVERSIBLE";
4
+ export type EntryKind = "file" | "directory" | "symlink";
5
+ export interface ManifestEntry {
6
+ /** Relative path from sandbox root, POSIX-style, no leading slash. */
7
+ path: string;
8
+ kind: EntryKind;
9
+ /** SHA-256 of file contents; null for directories; symlink target hashed for symlinks. */
10
+ hash: string | null;
11
+ size: number;
12
+ /** Octal permission bits as number (e.g. 0o644). */
13
+ mode: number;
14
+ /** Symlink target if kind === "symlink". */
15
+ linkTarget: string | null;
16
+ }
17
+ export interface Manifest {
18
+ version: 1;
19
+ createdAt: string;
20
+ rootLabel: string;
21
+ entries: ManifestEntry[];
22
+ /** SHA-256 of canonical serialized entries. */
23
+ fingerprint: string;
24
+ }
25
+ export interface CheckpointMeta {
26
+ id: string;
27
+ createdAt: string;
28
+ targetPath: string;
29
+ fingerprint: string;
30
+ fileCount: number;
31
+ directoryCount: number;
32
+ symlinkCount: number;
33
+ timingsMs: {
34
+ manifest: number;
35
+ contentStore: number;
36
+ total: number;
37
+ };
38
+ }
39
+ export interface Checkpoint {
40
+ meta: CheckpointMeta;
41
+ manifest: Manifest;
42
+ /** Absolute path to checkpoint directory under .rewind/checkpoints/<id> */
43
+ directory: string;
44
+ }
45
+ export interface Change {
46
+ type: ChangeType;
47
+ pathBefore: string | null;
48
+ pathAfter: string | null;
49
+ hashBefore: string | null;
50
+ hashAfter: string | null;
51
+ sizeBefore: number | null;
52
+ sizeAfter: number | null;
53
+ reversibility: Reversibility;
54
+ }
55
+ export type TransactionStatus = "open" | "recorded" | "rewound" | "verified" | "failed";
56
+ export interface Transaction {
57
+ id: string;
58
+ startedAt: string;
59
+ completedAt: string | null;
60
+ checkpointId: string;
61
+ targetPath: string;
62
+ changes: Change[];
63
+ status: TransactionStatus;
64
+ summary: TransactionSummary;
65
+ timingsMs: {
66
+ diff: number;
67
+ };
68
+ }
69
+ export interface TransactionSummary {
70
+ total: number;
71
+ modified: number;
72
+ created: number;
73
+ deleted: number;
74
+ renamed: number;
75
+ moved: number;
76
+ reversible: number;
77
+ compensable: number;
78
+ irreversible: number;
79
+ }
80
+ export interface VerificationResult {
81
+ ok: boolean;
82
+ filesChecked: number;
83
+ expectedFingerprint: string;
84
+ actualFingerprint: string;
85
+ mismatches: VerificationMismatch[];
86
+ timingsMs: {
87
+ manifest: number;
88
+ compare: number;
89
+ total: number;
90
+ };
91
+ }
92
+ export interface VerificationMismatch {
93
+ path: string;
94
+ reason: string;
95
+ expected?: string;
96
+ actual?: string;
97
+ }
98
+ export interface TimingRecord {
99
+ label: string;
100
+ ms: number;
101
+ }
@@ -0,0 +1,3 @@
1
+ /** Core domain types for REWIND V0. */
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,uCAAuC"}
@@ -0,0 +1,8 @@
1
+ import type { Checkpoint, VerificationResult } from "./types.js";
2
+ /**
3
+ * Compare restored sandbox against a checkpoint manifest.
4
+ * Fail closed: any mismatch → ok: false.
5
+ */
6
+ export declare function verifyAgainstCheckpoint(checkpoint: Checkpoint, projectRoot?: string): Promise<VerificationResult>;
7
+ export declare function verifyLatest(projectRoot?: string): Promise<VerificationResult>;
8
+ export declare function printVerification(result: VerificationResult): void;
@@ -0,0 +1,126 @@
1
+ import { getProjectRoot, getSandboxPath, assertApprovedSandbox, } from "./paths.js";
2
+ import { loadCheckpoint } from "./checkpoint.js";
3
+ import { buildManifest, fingerprintManifestEntries, } from "./manifest.js";
4
+ import { Timer } from "./timing.js";
5
+ function entryKey(e) {
6
+ return [
7
+ e.path,
8
+ e.kind,
9
+ e.hash ?? "",
10
+ String(e.size),
11
+ String(e.mode),
12
+ e.linkTarget ?? "",
13
+ ].join("|");
14
+ }
15
+ /**
16
+ * Compare restored sandbox against a checkpoint manifest.
17
+ * Fail closed: any mismatch → ok: false.
18
+ */
19
+ export async function verifyAgainstCheckpoint(checkpoint, projectRoot = getProjectRoot()) {
20
+ const totalTimer = new Timer();
21
+ const sandbox = getSandboxPath(projectRoot);
22
+ await assertApprovedSandbox(sandbox, projectRoot);
23
+ const manifestTimer = new Timer();
24
+ const actual = await buildManifest(sandbox, "sandbox-test-project");
25
+ const manifestMs = manifestTimer.elapsedMs();
26
+ const compareTimer = new Timer();
27
+ const mismatches = [];
28
+ const expectedMap = new Map(checkpoint.manifest.entries.map((e) => [e.path, e]));
29
+ const actualMap = new Map(actual.entries.map((e) => [e.path, e]));
30
+ for (const [p, exp] of expectedMap) {
31
+ const act = actualMap.get(p);
32
+ if (!act) {
33
+ mismatches.push({
34
+ path: p,
35
+ reason: "missing in restored tree",
36
+ expected: entryKey(exp),
37
+ });
38
+ continue;
39
+ }
40
+ if (entryKey(exp) !== entryKey(act)) {
41
+ const reasons = [];
42
+ if (exp.kind !== act.kind)
43
+ reasons.push(`kind ${exp.kind}→${act.kind}`);
44
+ if (exp.hash !== act.hash)
45
+ reasons.push("hash mismatch");
46
+ if (exp.size !== act.size)
47
+ reasons.push(`size ${exp.size}→${act.size}`);
48
+ if (exp.mode !== act.mode)
49
+ reasons.push(`mode ${exp.mode}→${act.mode}`);
50
+ if (exp.linkTarget !== act.linkTarget)
51
+ reasons.push("linkTarget mismatch");
52
+ mismatches.push({
53
+ path: p,
54
+ reason: reasons.join(", ") || "entry mismatch",
55
+ expected: entryKey(exp),
56
+ actual: entryKey(act),
57
+ });
58
+ }
59
+ }
60
+ for (const [p, act] of actualMap) {
61
+ if (!expectedMap.has(p)) {
62
+ mismatches.push({
63
+ path: p,
64
+ reason: "unexpected path after restore",
65
+ actual: entryKey(act),
66
+ });
67
+ }
68
+ }
69
+ // Fingerprint compare (authoritative whole-tree check)
70
+ const expectedFingerprint = checkpoint.manifest.fingerprint;
71
+ const actualFingerprint = fingerprintManifestEntries(actual.entries);
72
+ if (expectedFingerprint !== actualFingerprint && mismatches.length === 0) {
73
+ mismatches.push({
74
+ path: "(fingerprint)",
75
+ reason: "fingerprint mismatch without per-entry diffs (canonicalization bug?)",
76
+ expected: expectedFingerprint,
77
+ actual: actualFingerprint,
78
+ });
79
+ }
80
+ const compareMs = compareTimer.elapsedMs();
81
+ const filesChecked = checkpoint.manifest.entries.length;
82
+ return {
83
+ ok: mismatches.length === 0 && expectedFingerprint === actualFingerprint,
84
+ filesChecked,
85
+ expectedFingerprint,
86
+ actualFingerprint,
87
+ mismatches,
88
+ timingsMs: {
89
+ manifest: manifestMs,
90
+ compare: compareMs,
91
+ total: totalTimer.elapsedMs(),
92
+ },
93
+ };
94
+ }
95
+ export async function verifyLatest(projectRoot = getProjectRoot()) {
96
+ const checkpoint = await loadCheckpoint("latest", projectRoot);
97
+ return verifyAgainstCheckpoint(checkpoint, projectRoot);
98
+ }
99
+ export function printVerification(result) {
100
+ console.log("REWIND VERIFICATION");
101
+ console.log("");
102
+ console.log(`Files checked: ${result.filesChecked}`);
103
+ console.log("");
104
+ console.log("Expected manifest hash:");
105
+ console.log(result.expectedFingerprint);
106
+ console.log("");
107
+ console.log("Actual manifest hash:");
108
+ console.log(result.actualFingerprint);
109
+ console.log("");
110
+ console.log("RESULT:");
111
+ console.log("");
112
+ if (result.ok) {
113
+ console.log("EXACT MATCH");
114
+ }
115
+ else {
116
+ console.log("RESTORE FAILED");
117
+ console.log("");
118
+ for (const m of result.mismatches.slice(0, 50)) {
119
+ console.log(`- ${m.path}: ${m.reason}`);
120
+ }
121
+ if (result.mismatches.length > 50) {
122
+ console.log(`… and ${result.mismatches.length - 50} more`);
123
+ }
124
+ }
125
+ }
126
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,cAAc,EACd,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,aAAa,EACb,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AAOvB,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,SAAS,QAAQ,CAAC,CAAgB;IAChC,OAAO;QACL,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,IAAI,IAAI,EAAE;QACZ,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACd,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACd,CAAC,CAAC,UAAU,IAAI,EAAE;KACnB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,UAAsB,EACtB,WAAW,GAAG,cAAc,EAAE;IAE9B,MAAM,UAAU,GAAG,IAAI,KAAK,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,qBAAqB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAElD,MAAM,aAAa,GAAG,IAAI,KAAK,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,EAAE,CAAC;IAE7C,MAAM,YAAY,GAAG,IAAI,KAAK,EAAE,CAAC;IACjC,MAAM,UAAU,GAA2B,EAAE,CAAC;IAE9C,MAAM,WAAW,GAAG,IAAI,GAAG,CACzB,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CACpD,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAElE,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,WAAW,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,UAAU,CAAC,IAAI,CAAC;gBACd,IAAI,EAAE,CAAC;gBACP,MAAM,EAAE,0BAA0B;gBAClC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC;aACxB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,OAAO,GAAa,EAAE,CAAC;YAC7B,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACxE,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACzD,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACxE,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI;gBAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;YACxE,IAAI,GAAG,CAAC,UAAU,KAAK,GAAG,CAAC,UAAU;gBAAE,OAAO,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC3E,UAAU,CAAC,IAAI,CAAC;gBACd,IAAI,EAAE,CAAC;gBACP,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,gBAAgB;gBAC9C,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC;gBACvB,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC;aACtB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACxB,UAAU,CAAC,IAAI,CAAC;gBACd,IAAI,EAAE,CAAC;gBACP,MAAM,EAAE,+BAA+B;gBACvC,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC;aACtB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,MAAM,mBAAmB,GAAG,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC5D,MAAM,iBAAiB,GAAG,0BAA0B,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrE,IAAI,mBAAmB,KAAK,iBAAiB,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzE,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,eAAe;YACrB,MAAM,EAAE,sEAAsE;YAC9E,QAAQ,EAAE,mBAAmB;YAC7B,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,EAAE,CAAC;IAC3C,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;IAExD,OAAO;QACL,EAAE,EAAE,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,mBAAmB,KAAK,iBAAiB;QACxE,YAAY;QACZ,mBAAmB;QACnB,iBAAiB;QACjB,UAAU;QACV,SAAS,EAAE;YACT,QAAQ,EAAE,UAAU;YACpB,OAAO,EAAE,SAAS;YAClB,KAAK,EAAE,UAAU,CAAC,SAAS,EAAE;SAC9B;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,WAAW,GAAG,cAAc,EAAE;IAE9B,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC/D,OAAO,uBAAuB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAA0B;IAC1D,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,37 @@
1
+ # Adapters (V5)
2
+
3
+ ## EXISTS
4
+
5
+ ### Interface (`RewindAdapter`)
6
+
7
+ - `identifyTarget` / `validateOperation`
8
+ - `inspectCurrent` / `captureBefore`
9
+ - `execute` / `captureAfter`
10
+ - `compareExpectedCurrent` / `reverse`
11
+ - `describe`
12
+
13
+ ### FilesystemAdapter
14
+
15
+ **Shipped.** Wraps proven V2 primitives:
16
+
17
+ - create / write / delete / move
18
+ - create_directory / delete_directory (subtree capture)
19
+ - CAS objects under `.rewind/objects`
20
+ - conflict-aware reverse via snapshot restore
21
+
22
+ MCP tools and `mediate*` functions call the transaction engine, which calls this adapter. There is one authoritative mediated FS path.
23
+
24
+ ### Registry
25
+
26
+ `getAdapter("filesystem")` — only registered adapter in V5.
27
+
28
+ ## PLANNED (not implemented)
29
+
30
+ | Adapter | Notes |
31
+ |---------|--------|
32
+ | shell | Command capture + cwd/env; often COMPENSATABLE/IRREVERSIBLE |
33
+ | database | Txn-aware reverse or compensating SQL |
34
+ | http/api | Idempotency keys + compensation |
35
+ | browser | DOM/navigation actions |
36
+
37
+ Do not treat these as available APIs.
@@ -0,0 +1,32 @@
1
+ # Approvals (V5)
2
+
3
+ ## EXISTS
4
+
5
+ When permission returns **ASK**:
6
+
7
+ 1. Capture validated intent + before state
8
+ 2. Fingerprint current target state
9
+ 3. Persist `.rewind/approvals/appr_….json`
10
+ 4. Transaction status = `AWAITING_APPROVAL`
11
+ 5. **No mutation yet**
12
+
13
+ Human may:
14
+
15
+ - `rewind approvals`
16
+ - `rewind approve <appr_…>` — revalidate fingerprint + operation, then execute
17
+ - `rewind deny <appr_…>` — mark DENIED, never execute
18
+
19
+ ### TOCTOU
20
+
21
+ If target state changes while waiting, approve **refuses** and does not apply the stale intent.
22
+
23
+ ### UI / API
24
+
25
+ Local API: `GET /v1/approvals`, `POST /v1/approvals/:id/approve|deny`
26
+ Minimal control app shows Approve/Deny on real pending rows.
27
+
28
+ ## PLANNED
29
+
30
+ - Rich desktop approval UX
31
+ - Push notifications
32
+ - Multi-approver / quorum (not designed yet)
@@ -0,0 +1,57 @@
1
+ # Architecture (V5)
2
+
3
+ ## EXISTS
4
+
5
+ ```
6
+ MCP / CLI / Local API
7
+
8
+
9
+ ┌───────────────────┐
10
+ │ Transaction Engine │ prepare → permission → adapter → mutate
11
+ └─────────┬─────────┘
12
+
13
+ ┌──────┴──────┐
14
+ ▼ ▼
15
+ Permission Adapter Registry
16
+ Engine │
17
+
18
+ FilesystemAdapter ← wraps action/capture|mutate|objects
19
+
20
+
21
+ .rewind/actions (v2 JSON, append index)
22
+ .rewind/transactions (v5 overlays)
23
+ .rewind/objects (CAS)
24
+ .rewind/approvals
25
+ .rewind/policy/permissions.json
26
+ ```
27
+
28
+ ### Layers
29
+
30
+ | Layer | Path | Role |
31
+ |-------|------|------|
32
+ | Core types | `src/core/types.ts` | Transaction, Actor, Authority, reversibility |
33
+ | Lifecycle | `src/core/lifecycle.ts` | Validated status transitions |
34
+ | Engine | `src/core/engine.ts` | Single mediated execution + undo + approval |
35
+ | Compatibility | `src/core/compatibility.ts` | ActionRecord v2 ↔ Transaction v5 |
36
+ | Adapters | `src/adapters/*` | RewindAdapter + FilesystemAdapter |
37
+ | Permission | `src/permission/*` | ALLOW / ASK / DENY policies |
38
+ | Approval | `src/approval/*` | Pending intents + TOCTOU fingerprint |
39
+ | Ledger query | `src/ledger/query.ts` | History / formatting |
40
+ | Entitlement | `src/entitlement/provider.ts` | Pluggable license boundary |
41
+ | Local API | `src/api/server.ts` | Loopback control API + minimal UI |
42
+ | MCP | `src/mcp/server.ts` | Tools → mediate* → engine |
43
+ | V0–V4 | `src/sandbox`, `session`, `enforcement`, `protect` | Unchanged proofs |
44
+
45
+ ## PLANNED
46
+
47
+ - Additional adapters (shell, database, HTTP, browser)
48
+ - Stronger OS-level enforcement so bypass is hard
49
+ - Delegated authority with real principals
50
+ - Paid `EntitlementProvider` implementation (not in core)
51
+
52
+ ## Design rules
53
+
54
+ - Do not duplicate FS mutation paths — adapter calls existing `action/mutate`.
55
+ - Do not claim COMPENSATABLE unless an adapter implements compensation.
56
+ - Do not fabricate human principals; authority may be UNKNOWN.
57
+ - Crash recovery marks PREPARED/EXECUTING/UNDOING as FAILED; never wipes AWAITING_APPROVAL.