@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.
- package/.env.example +8 -0
- package/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/src/action/capture.d.ts +15 -0
- package/dist/src/action/capture.js +215 -0
- package/dist/src/action/capture.js.map +1 -0
- package/dist/src/action/mediate.d.ts +28 -0
- package/dist/src/action/mediate.js +109 -0
- package/dist/src/action/mediate.js.map +1 -0
- package/dist/src/action/mutate.d.ts +11 -0
- package/dist/src/action/mutate.js +189 -0
- package/dist/src/action/mutate.js.map +1 -0
- package/dist/src/action/objects.d.ts +5 -0
- package/dist/src/action/objects.js +50 -0
- package/dist/src/action/objects.js.map +1 -0
- package/dist/src/action/store.d.ts +24 -0
- package/dist/src/action/store.js +149 -0
- package/dist/src/action/store.js.map +1 -0
- package/dist/src/action/types.d.ts +84 -0
- package/dist/src/action/types.js +3 -0
- package/dist/src/action/types.js.map +1 -0
- package/dist/src/action/undo.d.ts +11 -0
- package/dist/src/action/undo.js +42 -0
- package/dist/src/action/undo.js.map +1 -0
- package/dist/src/adapters/filesystem.d.ts +35 -0
- package/dist/src/adapters/filesystem.js +499 -0
- package/dist/src/adapters/filesystem.js.map +1 -0
- package/dist/src/adapters/index.d.ts +7 -0
- package/dist/src/adapters/index.js +19 -0
- package/dist/src/adapters/index.js.map +1 -0
- package/dist/src/adapters/types.d.ts +54 -0
- package/dist/src/adapters/types.js +7 -0
- package/dist/src/adapters/types.js.map +1 -0
- package/dist/src/api/server.d.ts +25 -0
- package/dist/src/api/server.js +786 -0
- package/dist/src/api/server.js.map +1 -0
- package/dist/src/approval/store.d.ts +35 -0
- package/dist/src/approval/store.js +113 -0
- package/dist/src/approval/store.js.map +1 -0
- package/dist/src/checkpoint.d.ts +9 -0
- package/dist/src/checkpoint.js +140 -0
- package/dist/src/checkpoint.js.map +1 -0
- package/dist/src/cli/v5.d.ts +15 -0
- package/dist/src/cli/v5.js +110 -0
- package/dist/src/cli/v5.js.map +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +823 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/clients/types.d.ts +90 -0
- package/dist/src/clients/types.js +239 -0
- package/dist/src/clients/types.js.map +1 -0
- package/dist/src/commercial/auth/provider.d.ts +61 -0
- package/dist/src/commercial/auth/provider.js +227 -0
- package/dist/src/commercial/auth/provider.js.map +1 -0
- package/dist/src/commercial/entitlement/provider.d.ts +27 -0
- package/dist/src/commercial/entitlement/provider.js +192 -0
- package/dist/src/commercial/entitlement/provider.js.map +1 -0
- package/dist/src/commercial/entitlement/signing.d.ts +61 -0
- package/dist/src/commercial/entitlement/signing.js +124 -0
- package/dist/src/commercial/entitlement/signing.js.map +1 -0
- package/dist/src/commercial/env.d.ts +10 -0
- package/dist/src/commercial/env.js +40 -0
- package/dist/src/commercial/env.js.map +1 -0
- package/dist/src/commercial/product.d.ts +26 -0
- package/dist/src/commercial/product.js +39 -0
- package/dist/src/commercial/product.js.map +1 -0
- package/dist/src/commercial/store.d.ts +46 -0
- package/dist/src/commercial/store.js +104 -0
- package/dist/src/commercial/store.js.map +1 -0
- package/dist/src/commercial/stripe/checkout.d.ts +104 -0
- package/dist/src/commercial/stripe/checkout.js +469 -0
- package/dist/src/commercial/stripe/checkout.js.map +1 -0
- package/dist/src/core/compatibility.d.ts +15 -0
- package/dist/src/core/compatibility.js +226 -0
- package/dist/src/core/compatibility.js.map +1 -0
- package/dist/src/core/engine.d.ts +33 -0
- package/dist/src/core/engine.js +432 -0
- package/dist/src/core/engine.js.map +1 -0
- package/dist/src/core/lifecycle.d.ts +17 -0
- package/dist/src/core/lifecycle.js +56 -0
- package/dist/src/core/lifecycle.js.map +1 -0
- package/dist/src/core/types.d.ts +140 -0
- package/dist/src/core/types.js +37 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/destroy.d.ts +21 -0
- package/dist/src/destroy.js +219 -0
- package/dist/src/destroy.js.map +1 -0
- package/dist/src/diff.d.ts +13 -0
- package/dist/src/diff.js +251 -0
- package/dist/src/diff.js.map +1 -0
- package/dist/src/enforcement/detect.d.ts +13 -0
- package/dist/src/enforcement/detect.js +75 -0
- package/dist/src/enforcement/detect.js.map +1 -0
- package/dist/src/enforcement/hook-policy.d.ts +38 -0
- package/dist/src/enforcement/hook-policy.js +111 -0
- package/dist/src/enforcement/hook-policy.js.map +1 -0
- package/dist/src/enforcement/index.d.ts +8 -0
- package/dist/src/enforcement/index.js +8 -0
- package/dist/src/enforcement/index.js.map +1 -0
- package/dist/src/enforcement/perf.d.ts +6 -0
- package/dist/src/enforcement/perf.js +18 -0
- package/dist/src/enforcement/perf.js.map +1 -0
- package/dist/src/enforcement/policy.d.ts +12 -0
- package/dist/src/enforcement/policy.js +84 -0
- package/dist/src/enforcement/policy.js.map +1 -0
- package/dist/src/enforcement/readonly.d.ts +17 -0
- package/dist/src/enforcement/readonly.js +124 -0
- package/dist/src/enforcement/readonly.js.map +1 -0
- package/dist/src/enforcement/sandbox-clone.d.ts +6 -0
- package/dist/src/enforcement/sandbox-clone.js +11 -0
- package/dist/src/enforcement/sandbox-clone.js.map +1 -0
- package/dist/src/enforcement/setup.d.ts +33 -0
- package/dist/src/enforcement/setup.js +168 -0
- package/dist/src/enforcement/setup.js.map +1 -0
- package/dist/src/enforcement/trust.d.ts +10 -0
- package/dist/src/enforcement/trust.js +71 -0
- package/dist/src/enforcement/trust.js.map +1 -0
- package/dist/src/enforcement/types.d.ts +40 -0
- package/dist/src/enforcement/types.js +3 -0
- package/dist/src/enforcement/types.js.map +1 -0
- package/dist/src/entitlement/provider.d.ts +48 -0
- package/dist/src/entitlement/provider.js +95 -0
- package/dist/src/entitlement/provider.js.map +1 -0
- package/dist/src/hash.d.ts +9 -0
- package/dist/src/hash.js +23 -0
- package/dist/src/hash.js.map +1 -0
- package/dist/src/ledger/query.d.ts +19 -0
- package/dist/src/ledger/query.js +158 -0
- package/dist/src/ledger/query.js.map +1 -0
- package/dist/src/manifest.d.ts +32 -0
- package/dist/src/manifest.js +242 -0
- package/dist/src/manifest.js.map +1 -0
- package/dist/src/mcp/server.d.ts +7 -0
- package/dist/src/mcp/server.js +364 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/paths.d.ts +94 -0
- package/dist/src/paths.js +354 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/permission/engine.d.ts +15 -0
- package/dist/src/permission/engine.js +147 -0
- package/dist/src/permission/engine.js.map +1 -0
- package/dist/src/permission/types.d.ts +42 -0
- package/dist/src/permission/types.js +3 -0
- package/dist/src/permission/types.js.map +1 -0
- package/dist/src/product/setup.d.ts +35 -0
- package/dist/src/product/setup.js +300 -0
- package/dist/src/product/setup.js.map +1 -0
- package/dist/src/protect/audit.d.ts +5 -0
- package/dist/src/protect/audit.js +26 -0
- package/dist/src/protect/audit.js.map +1 -0
- package/dist/src/protect/capture.d.ts +7 -0
- package/dist/src/protect/capture.js +250 -0
- package/dist/src/protect/capture.js.map +1 -0
- package/dist/src/protect/fingerprint.d.ts +4 -0
- package/dist/src/protect/fingerprint.js +49 -0
- package/dist/src/protect/fingerprint.js.map +1 -0
- package/dist/src/protect/hook-cli.d.ts +2 -0
- package/dist/src/protect/hook-cli.js +107 -0
- package/dist/src/protect/hook-cli.js.map +1 -0
- package/dist/src/protect/index.d.ts +12 -0
- package/dist/src/protect/index.js +12 -0
- package/dist/src/protect/index.js.map +1 -0
- package/dist/src/protect/install.d.ts +34 -0
- package/dist/src/protect/install.js +293 -0
- package/dist/src/protect/install.js.map +1 -0
- package/dist/src/protect/intercept.d.ts +11 -0
- package/dist/src/protect/intercept.js +390 -0
- package/dist/src/protect/intercept.js.map +1 -0
- package/dist/src/protect/protect.d.ts +17 -0
- package/dist/src/protect/protect.js +194 -0
- package/dist/src/protect/protect.js.map +1 -0
- package/dist/src/protect/root-paths.d.ts +13 -0
- package/dist/src/protect/root-paths.js +140 -0
- package/dist/src/protect/root-paths.js.map +1 -0
- package/dist/src/protect/shell-policy.d.ts +17 -0
- package/dist/src/protect/shell-policy.js +269 -0
- package/dist/src/protect/shell-policy.js.map +1 -0
- package/dist/src/protect/status.d.ts +11 -0
- package/dist/src/protect/status.js +165 -0
- package/dist/src/protect/status.js.map +1 -0
- package/dist/src/protect/store.d.ts +20 -0
- package/dist/src/protect/store.js +170 -0
- package/dist/src/protect/store.js.map +1 -0
- package/dist/src/protect/types.d.ts +116 -0
- package/dist/src/protect/types.js +3 -0
- package/dist/src/protect/types.js.map +1 -0
- package/dist/src/protect/undo-session.d.ts +14 -0
- package/dist/src/protect/undo-session.js +182 -0
- package/dist/src/protect/undo-session.js.map +1 -0
- package/dist/src/restore.d.ts +39 -0
- package/dist/src/restore.js +141 -0
- package/dist/src/restore.js.map +1 -0
- package/dist/src/sandbox.d.ts +23 -0
- package/dist/src/sandbox.js +198 -0
- package/dist/src/sandbox.js.map +1 -0
- package/dist/src/session/ambient.d.ts +10 -0
- package/dist/src/session/ambient.js +53 -0
- package/dist/src/session/ambient.js.map +1 -0
- package/dist/src/session/attribution.d.ts +27 -0
- package/dist/src/session/attribution.js +201 -0
- package/dist/src/session/attribution.js.map +1 -0
- package/dist/src/session/index.d.ts +25 -0
- package/dist/src/session/index.js +472 -0
- package/dist/src/session/index.js.map +1 -0
- package/dist/src/session/process.d.ts +34 -0
- package/dist/src/session/process.js +234 -0
- package/dist/src/session/process.js.map +1 -0
- package/dist/src/session/store.d.ts +14 -0
- package/dist/src/session/store.js +125 -0
- package/dist/src/session/store.js.map +1 -0
- package/dist/src/session/types.d.ts +111 -0
- package/dist/src/session/types.js +3 -0
- package/dist/src/session/types.js.map +1 -0
- package/dist/src/session/watcher.d.ts +32 -0
- package/dist/src/session/watcher.js +186 -0
- package/dist/src/session/watcher.js.map +1 -0
- package/dist/src/timing.d.ts +7 -0
- package/dist/src/timing.js +19 -0
- package/dist/src/timing.js.map +1 -0
- package/dist/src/types.d.ts +101 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/verify.d.ts +8 -0
- package/dist/src/verify.js +126 -0
- package/dist/src/verify.js.map +1 -0
- package/docs/ADAPTERS.md +37 -0
- package/docs/APPROVALS.md +32 -0
- package/docs/ARCHITECTURE.md +57 -0
- package/docs/ATTRIBUTION.md +179 -0
- package/docs/COMMERCIAL.md +51 -0
- package/docs/CURSOR-ENFORCEMENT.md +73 -0
- package/docs/ENFORCEMENT.md +134 -0
- package/docs/FUTURE.md +91 -0
- package/docs/HUMAN-SETUP.md +98 -0
- package/docs/IDENTITY-AUTHORITY.md +35 -0
- package/docs/MCP.md +107 -0
- package/docs/PACKAGING.md +77 -0
- package/docs/PERMISSIONS.md +53 -0
- package/docs/PRODUCT-V5.md +63 -0
- package/docs/PRODUCT-V6.md +69 -0
- package/docs/PROTECTED-SESSIONS.md +155 -0
- package/docs/THREAT-MODEL.md +84 -0
- package/docs/TRANSACTIONS.md +57 -0
- package/package.json +85 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { PathSafetyError } from "../paths.js";
|
|
2
|
+
import { appendAuditEvent } from "./audit.js";
|
|
3
|
+
import { captureProtectedEntry, snapshotIdentityHash, } from "./capture.js";
|
|
4
|
+
import { resolveProtectedRelative } from "./root-paths.js";
|
|
5
|
+
import { decideProtectedShell } from "./shell-policy.js";
|
|
6
|
+
import { loadActiveSession, loadProtectAction, listIncompleteProtectActions, markIncompleteProtectFailed, newProtectActionId, saveProtectAction, saveSession, } from "./store.js";
|
|
7
|
+
const MUTATING_TOOLS = new Set([
|
|
8
|
+
"Write",
|
|
9
|
+
"Delete",
|
|
10
|
+
"StrReplace",
|
|
11
|
+
"EditNotebook",
|
|
12
|
+
"DeleteNotebookCell",
|
|
13
|
+
]);
|
|
14
|
+
function emptyAbsent() {
|
|
15
|
+
return {
|
|
16
|
+
exists: false,
|
|
17
|
+
kind: "absent",
|
|
18
|
+
hash: null,
|
|
19
|
+
size: 0,
|
|
20
|
+
mode: null,
|
|
21
|
+
linkTarget: null,
|
|
22
|
+
objectId: null,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function mapTool(name) {
|
|
26
|
+
switch (name) {
|
|
27
|
+
case "Write":
|
|
28
|
+
return "cursor_Write";
|
|
29
|
+
case "Delete":
|
|
30
|
+
return "cursor_Delete";
|
|
31
|
+
case "StrReplace":
|
|
32
|
+
return "cursor_StrReplace";
|
|
33
|
+
case "EditNotebook":
|
|
34
|
+
case "DeleteNotebookCell":
|
|
35
|
+
return "cursor_EditNotebook";
|
|
36
|
+
default:
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function extractPaths(toolInput, payload) {
|
|
41
|
+
const out = [];
|
|
42
|
+
if (typeof payload.file_path === "string")
|
|
43
|
+
out.push(payload.file_path);
|
|
44
|
+
if (!toolInput || typeof toolInput !== "object")
|
|
45
|
+
return out;
|
|
46
|
+
const o = toolInput;
|
|
47
|
+
for (const k of ["path", "file_path", "target_notebook", "from", "to"]) {
|
|
48
|
+
if (typeof o[k] === "string")
|
|
49
|
+
out.push(o[k]);
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(o.paths)) {
|
|
52
|
+
for (const p of o.paths) {
|
|
53
|
+
if (typeof p === "string")
|
|
54
|
+
out.push(p);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return [...new Set(out)];
|
|
58
|
+
}
|
|
59
|
+
function cursorFromPayload(payload) {
|
|
60
|
+
const binding = {};
|
|
61
|
+
if (typeof payload.conversation_id === "string") {
|
|
62
|
+
binding.conversationId = payload.conversation_id;
|
|
63
|
+
}
|
|
64
|
+
if (typeof payload.session_id === "string") {
|
|
65
|
+
binding.sessionId = payload.session_id;
|
|
66
|
+
}
|
|
67
|
+
if (typeof payload.generation_id === "string") {
|
|
68
|
+
binding.generationId = payload.generation_id;
|
|
69
|
+
}
|
|
70
|
+
if (typeof payload.cursor_version === "string") {
|
|
71
|
+
binding.cursorVersion = payload.cursor_version;
|
|
72
|
+
}
|
|
73
|
+
if (typeof payload.model === "string") {
|
|
74
|
+
binding.model = payload.model;
|
|
75
|
+
}
|
|
76
|
+
return binding;
|
|
77
|
+
}
|
|
78
|
+
function toolCallIdOf(payload) {
|
|
79
|
+
for (const k of ["tool_call_id", "toolCallId", "call_id"]) {
|
|
80
|
+
if (typeof payload[k] === "string")
|
|
81
|
+
return payload[k];
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
async function ensureSession(projectRoot, cursor) {
|
|
86
|
+
const session = await loadActiveSession(projectRoot);
|
|
87
|
+
if (!session || session.status !== "ACTIVE") {
|
|
88
|
+
throw new PathSafetyError("No ACTIVE protected session — run: rewind protect <path>");
|
|
89
|
+
}
|
|
90
|
+
// Bind cursor child-session ids when first seen
|
|
91
|
+
let dirty = false;
|
|
92
|
+
if (cursor.conversationId && !session.cursor.conversationId) {
|
|
93
|
+
session.cursor.conversationId = cursor.conversationId;
|
|
94
|
+
dirty = true;
|
|
95
|
+
}
|
|
96
|
+
if (cursor.sessionId && session.cursor.sessionId !== cursor.sessionId) {
|
|
97
|
+
if (!session.cursor.sessionId) {
|
|
98
|
+
session.cursor.sessionId = cursor.sessionId;
|
|
99
|
+
dirty = true;
|
|
100
|
+
await appendAuditEvent({
|
|
101
|
+
type: "CURSOR_SESSION_STARTED",
|
|
102
|
+
sessionId: session.id,
|
|
103
|
+
detail: cursor.sessionId,
|
|
104
|
+
}, projectRoot);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (cursor.cursorVersion && !session.cursor.cursorVersion) {
|
|
108
|
+
session.cursor.cursorVersion = cursor.cursorVersion;
|
|
109
|
+
dirty = true;
|
|
110
|
+
}
|
|
111
|
+
if (cursor.model && !session.cursor.model) {
|
|
112
|
+
session.cursor.model = cursor.model;
|
|
113
|
+
dirty = true;
|
|
114
|
+
}
|
|
115
|
+
if (dirty)
|
|
116
|
+
await saveSession(session, projectRoot);
|
|
117
|
+
return session;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Handle preToolUse / beforeShellExecution / beforeMCPExecution.
|
|
121
|
+
*/
|
|
122
|
+
export async function handlePreHook(payload, projectRoot) {
|
|
123
|
+
const event = String(payload.hook_event_name ?? "");
|
|
124
|
+
const toolName = String(payload.tool_name ?? "");
|
|
125
|
+
const cursor = cursorFromPayload(payload);
|
|
126
|
+
// Shell gate
|
|
127
|
+
if (event === "beforeShellExecution" || toolName === "Shell") {
|
|
128
|
+
const command = String(payload.command ??
|
|
129
|
+
payload.tool_input?.command ??
|
|
130
|
+
"");
|
|
131
|
+
const decision = decideProtectedShell(command);
|
|
132
|
+
const session = await loadActiveSession(projectRoot);
|
|
133
|
+
if (decision.permission === "deny") {
|
|
134
|
+
if (session) {
|
|
135
|
+
session.blockedShellCount += 1;
|
|
136
|
+
await saveSession(session, projectRoot);
|
|
137
|
+
}
|
|
138
|
+
await appendAuditEvent({
|
|
139
|
+
type: "SHELL_BLOCKED",
|
|
140
|
+
sessionId: session?.id,
|
|
141
|
+
tool: "Shell",
|
|
142
|
+
detail: decision.reason,
|
|
143
|
+
}, projectRoot);
|
|
144
|
+
return {
|
|
145
|
+
permission: "deny",
|
|
146
|
+
user_message: `REWIND: shell blocked (${decision.reason})`,
|
|
147
|
+
agent_message: `POLICY: Shell command denied during protected session. ` +
|
|
148
|
+
`Reason: ${decision.reason}. ` +
|
|
149
|
+
`Use native Write/StrReplace/Delete tools for file changes (REWIND will ledger them), ` +
|
|
150
|
+
`or use only allowlisted read-only shell commands (ls, cat, grep, git status, …).`,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
await appendAuditEvent({
|
|
154
|
+
type: "SHELL_ALLOWED",
|
|
155
|
+
sessionId: session?.id,
|
|
156
|
+
tool: "Shell",
|
|
157
|
+
detail: decision.reason,
|
|
158
|
+
}, projectRoot);
|
|
159
|
+
return { permission: "allow" };
|
|
160
|
+
}
|
|
161
|
+
// MCP: allow REWIND tools; allow others (optional gate)
|
|
162
|
+
if (event === "beforeMCPExecution" || toolName.startsWith("MCP:")) {
|
|
163
|
+
return { permission: "allow" };
|
|
164
|
+
}
|
|
165
|
+
if (!MUTATING_TOOLS.has(toolName)) {
|
|
166
|
+
return { permission: "allow" };
|
|
167
|
+
}
|
|
168
|
+
const session = await ensureSession(projectRoot, cursor);
|
|
169
|
+
const paths = extractPaths(payload.tool_input, payload);
|
|
170
|
+
if (paths.length === 0) {
|
|
171
|
+
await appendAuditEvent({
|
|
172
|
+
type: "HOOK_DENY",
|
|
173
|
+
sessionId: session.id,
|
|
174
|
+
tool: toolName,
|
|
175
|
+
detail: "mutating tool with no identifiable path",
|
|
176
|
+
}, projectRoot);
|
|
177
|
+
return {
|
|
178
|
+
permission: "deny",
|
|
179
|
+
user_message: "REWIND: cannot protect mutation without a target path",
|
|
180
|
+
agent_message: "POLICY: Native mutation blocked — no path in tool input for BEFORE capture.",
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const mapped = mapTool(toolName);
|
|
184
|
+
if (!mapped) {
|
|
185
|
+
return {
|
|
186
|
+
permission: "deny",
|
|
187
|
+
agent_message: `POLICY: Unsupported mutating tool ${toolName}`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// Capture BEFORE for primary path (multi-path: prepare one action per path)
|
|
191
|
+
const preparedIds = [];
|
|
192
|
+
for (const rawPath of paths) {
|
|
193
|
+
let rel;
|
|
194
|
+
try {
|
|
195
|
+
rel = resolveProtectedRelative(rawPath, projectRoot);
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
await appendAuditEvent({
|
|
199
|
+
type: "HOOK_DENY",
|
|
200
|
+
sessionId: session.id,
|
|
201
|
+
tool: toolName,
|
|
202
|
+
path: rawPath,
|
|
203
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
204
|
+
}, projectRoot);
|
|
205
|
+
return {
|
|
206
|
+
permission: "deny",
|
|
207
|
+
user_message: `REWIND: path outside protected project (${rawPath})`,
|
|
208
|
+
agent_message: "POLICY: Path escapes protected root. Stay inside the project.",
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
await appendAuditEvent({
|
|
212
|
+
type: "TOOL_REQUESTED",
|
|
213
|
+
sessionId: session.id,
|
|
214
|
+
tool: toolName,
|
|
215
|
+
path: rel,
|
|
216
|
+
}, projectRoot);
|
|
217
|
+
const before = await captureProtectedEntry(rel, projectRoot, {
|
|
218
|
+
storeContent: true,
|
|
219
|
+
});
|
|
220
|
+
const sequence = session.actionIds.length + 1;
|
|
221
|
+
const action = {
|
|
222
|
+
id: newProtectActionId(),
|
|
223
|
+
version: 4,
|
|
224
|
+
protectedSessionId: session.id,
|
|
225
|
+
sequence,
|
|
226
|
+
source: "CURSOR_HOOK",
|
|
227
|
+
tool: mapped,
|
|
228
|
+
provenance: "cursor_agent_tool_request",
|
|
229
|
+
requestedAt: new Date().toISOString(),
|
|
230
|
+
completedAt: null,
|
|
231
|
+
target: rel,
|
|
232
|
+
targets: [rel],
|
|
233
|
+
targetSecondary: null,
|
|
234
|
+
before,
|
|
235
|
+
after: emptyAbsent(),
|
|
236
|
+
beforeSecondary: null,
|
|
237
|
+
afterSecondary: null,
|
|
238
|
+
reversibility: "REVERSIBLE",
|
|
239
|
+
status: "PREPARED",
|
|
240
|
+
client: {
|
|
241
|
+
name: "Cursor",
|
|
242
|
+
version: cursor.cursorVersion ?? "unknown",
|
|
243
|
+
},
|
|
244
|
+
cursor,
|
|
245
|
+
toolCallId: toolCallIdOf(payload),
|
|
246
|
+
error: null,
|
|
247
|
+
undoneAt: null,
|
|
248
|
+
undoVerification: null,
|
|
249
|
+
conflict: null,
|
|
250
|
+
};
|
|
251
|
+
action.status = "EXECUTING";
|
|
252
|
+
await saveProtectAction(action, projectRoot);
|
|
253
|
+
session.actionIds.push(action.id);
|
|
254
|
+
preparedIds.push(action.id);
|
|
255
|
+
await appendAuditEvent({
|
|
256
|
+
type: "ACTION_PREPARED",
|
|
257
|
+
sessionId: session.id,
|
|
258
|
+
actionId: action.id,
|
|
259
|
+
tool: mapped,
|
|
260
|
+
path: rel,
|
|
261
|
+
}, projectRoot);
|
|
262
|
+
}
|
|
263
|
+
await saveSession(session, projectRoot);
|
|
264
|
+
return {
|
|
265
|
+
permission: "allow",
|
|
266
|
+
// Keep agent_message minimal — user should not need to babysit REWIND
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Handle postToolUse / afterFileEdit — complete PREPARED/EXECUTING actions.
|
|
271
|
+
*/
|
|
272
|
+
export async function handlePostHook(payload, projectRoot) {
|
|
273
|
+
const event = String(payload.hook_event_name ?? "");
|
|
274
|
+
const toolName = String(payload.tool_name ?? "");
|
|
275
|
+
const session = await loadActiveSession(projectRoot);
|
|
276
|
+
if (!session) {
|
|
277
|
+
return { permission: "allow" };
|
|
278
|
+
}
|
|
279
|
+
const paths = extractPaths(payload.tool_input, payload);
|
|
280
|
+
if (event === "afterFileEdit" && typeof payload.file_path === "string") {
|
|
281
|
+
paths.push(payload.file_path);
|
|
282
|
+
}
|
|
283
|
+
const unique = [...new Set(paths)];
|
|
284
|
+
if (unique.length === 0 && MUTATING_TOOLS.has(toolName)) {
|
|
285
|
+
// Cannot complete without path — leave EXECUTING for crash recovery
|
|
286
|
+
return { permission: "allow" };
|
|
287
|
+
}
|
|
288
|
+
const incomplete = await listIncompleteProtectActions(projectRoot);
|
|
289
|
+
const callId = toolCallIdOf(payload);
|
|
290
|
+
for (const raw of unique) {
|
|
291
|
+
let rel;
|
|
292
|
+
try {
|
|
293
|
+
rel = resolveProtectedRelative(raw, projectRoot);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
// Prefer matching toolCallId, then newest EXECUTING/PREPARED for path
|
|
299
|
+
let action = incomplete.find((a) => a.protectedSessionId === session.id &&
|
|
300
|
+
a.target === rel &&
|
|
301
|
+
callId &&
|
|
302
|
+
a.toolCallId === callId) ??
|
|
303
|
+
[...incomplete]
|
|
304
|
+
.reverse()
|
|
305
|
+
.find((a) => a.protectedSessionId === session.id && a.target === rel);
|
|
306
|
+
if (!action) {
|
|
307
|
+
// afterFileEdit without pre — do NOT invent provenance
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
// Reload latest
|
|
311
|
+
action = await loadProtectAction(action.id, projectRoot);
|
|
312
|
+
if (action.status !== "PREPARED" && action.status !== "EXECUTING") {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
const after = await captureProtectedEntry(rel, projectRoot, {
|
|
317
|
+
storeContent: true,
|
|
318
|
+
});
|
|
319
|
+
action.after = after;
|
|
320
|
+
action.status = "COMPLETED";
|
|
321
|
+
action.completedAt = new Date().toISOString();
|
|
322
|
+
await saveProtectAction(action, projectRoot);
|
|
323
|
+
await appendAuditEvent({
|
|
324
|
+
type: "ACTION_COMPLETED",
|
|
325
|
+
sessionId: session.id,
|
|
326
|
+
actionId: action.id,
|
|
327
|
+
tool: action.tool,
|
|
328
|
+
path: rel,
|
|
329
|
+
detail: `after=${snapshotIdentityHash(after)}`,
|
|
330
|
+
}, projectRoot);
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
action.status = "FAILED";
|
|
334
|
+
action.error = err instanceof Error ? err.message : String(err);
|
|
335
|
+
action.completedAt = new Date().toISOString();
|
|
336
|
+
await saveProtectAction(action, projectRoot);
|
|
337
|
+
await appendAuditEvent({
|
|
338
|
+
type: "ACTION_FAILED",
|
|
339
|
+
sessionId: session.id,
|
|
340
|
+
actionId: action.id,
|
|
341
|
+
path: rel,
|
|
342
|
+
detail: action.error,
|
|
343
|
+
}, projectRoot);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return { permission: "allow" };
|
|
347
|
+
}
|
|
348
|
+
export async function handlePostFailure(payload, projectRoot) {
|
|
349
|
+
const session = await loadActiveSession(projectRoot);
|
|
350
|
+
const paths = extractPaths(payload.tool_input, payload);
|
|
351
|
+
const incomplete = await listIncompleteProtectActions(projectRoot);
|
|
352
|
+
for (const raw of paths) {
|
|
353
|
+
let rel;
|
|
354
|
+
try {
|
|
355
|
+
rel = resolveProtectedRelative(raw, projectRoot);
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const action = [...incomplete]
|
|
361
|
+
.reverse()
|
|
362
|
+
.find((a) => a.target === rel);
|
|
363
|
+
if (!action)
|
|
364
|
+
continue;
|
|
365
|
+
const a = await loadProtectAction(action.id, projectRoot);
|
|
366
|
+
a.status = "FAILED";
|
|
367
|
+
a.error = String(payload.error ?? "tool failure");
|
|
368
|
+
a.completedAt = new Date().toISOString();
|
|
369
|
+
await saveProtectAction(a, projectRoot);
|
|
370
|
+
await appendAuditEvent({
|
|
371
|
+
type: "ACTION_FAILED",
|
|
372
|
+
sessionId: session?.id,
|
|
373
|
+
actionId: a.id,
|
|
374
|
+
path: rel,
|
|
375
|
+
detail: a.error,
|
|
376
|
+
}, projectRoot);
|
|
377
|
+
}
|
|
378
|
+
return { permission: "allow" };
|
|
379
|
+
}
|
|
380
|
+
export async function recoverCrashState(projectRoot) {
|
|
381
|
+
const n = await markIncompleteProtectFailed(projectRoot);
|
|
382
|
+
if (n > 0) {
|
|
383
|
+
await appendAuditEvent({
|
|
384
|
+
type: "CRASH_RECOVERY",
|
|
385
|
+
detail: `Marked ${n} incomplete action(s) FAILED`,
|
|
386
|
+
}, projectRoot);
|
|
387
|
+
}
|
|
388
|
+
return n;
|
|
389
|
+
}
|
|
390
|
+
//# sourceMappingURL=intercept.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intercept.js","sourceRoot":"","sources":["../../../src/protect/intercept.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ProtectState, ProtectedSession } from "./types.js";
|
|
2
|
+
export declare function resolveProtectTarget(pathArg: string | undefined): string;
|
|
3
|
+
/**
|
|
4
|
+
* Enable protected Cursor session for a project directory.
|
|
5
|
+
* Idempotent: re-running refreshes hooks and ensures an ACTIVE session.
|
|
6
|
+
*/
|
|
7
|
+
export declare function protectProject(pathArg: string | undefined, options?: {
|
|
8
|
+
rewindPackageRoot?: string;
|
|
9
|
+
}): Promise<{
|
|
10
|
+
state: ProtectState;
|
|
11
|
+
session: ProtectedSession;
|
|
12
|
+
summary: string;
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Remove REWIND-managed hooks/MCP entries. Keeps .rewind history.
|
|
16
|
+
*/
|
|
17
|
+
export declare function unprotectProject(pathArg: string | undefined): Promise<string>;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { mkdir } from "node:fs/promises";
|
|
3
|
+
import { getPackageRoot, PathSafetyError, normalizeAbsolute } from "../paths.js";
|
|
4
|
+
import { appendAuditEvent } from "./audit.js";
|
|
5
|
+
import { fingerprintProject } from "./fingerprint.js";
|
|
6
|
+
import { installProtectArtifacts, uninstallProtectArtifacts, } from "./install.js";
|
|
7
|
+
import { recoverCrashState } from "./intercept.js";
|
|
8
|
+
import { assertSafeProtectRoot, getProtectDir } from "./root-paths.js";
|
|
9
|
+
import { loadActiveSession, loadProtectState, newProtectedSessionId, saveProtectConfig, saveProtectState, saveSession, } from "./store.js";
|
|
10
|
+
export function resolveProtectTarget(pathArg) {
|
|
11
|
+
if (pathArg)
|
|
12
|
+
return normalizeAbsolute(pathArg);
|
|
13
|
+
return normalizeAbsolute(process.cwd());
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Enable protected Cursor session for a project directory.
|
|
17
|
+
* Idempotent: re-running refreshes hooks and ensures an ACTIVE session.
|
|
18
|
+
*/
|
|
19
|
+
export async function protectProject(pathArg, options = {}) {
|
|
20
|
+
const rewindPackageRoot = options.rewindPackageRoot ?? getPackageRoot();
|
|
21
|
+
const projectRoot = await assertSafeProtectRoot(resolveProtectTarget(pathArg), rewindPackageRoot);
|
|
22
|
+
// Refuse protecting the REWIND monorepo root itself for destructive demos —
|
|
23
|
+
// allow only if basename looks like a sandbox/demo project OR is not the package root.
|
|
24
|
+
if (projectRoot === path.resolve(rewindPackageRoot)) {
|
|
25
|
+
throw new PathSafetyError("Refusing to protect the REWIND package root. Protect a project subdirectory (e.g. sandbox-v4-project).");
|
|
26
|
+
}
|
|
27
|
+
await mkdir(getProtectDir(projectRoot), { recursive: true });
|
|
28
|
+
await mkdir(path.join(projectRoot, ".rewind", "actions"), { recursive: true });
|
|
29
|
+
await mkdir(path.join(projectRoot, ".rewind", "sessions"), { recursive: true });
|
|
30
|
+
await mkdir(path.join(projectRoot, ".rewind", "objects"), { recursive: true });
|
|
31
|
+
await mkdir(path.join(projectRoot, ".rewind", "audit"), { recursive: true });
|
|
32
|
+
const recovered = await recoverCrashState(projectRoot);
|
|
33
|
+
const installed = await installProtectArtifacts(projectRoot, {
|
|
34
|
+
rewindPackageRoot,
|
|
35
|
+
});
|
|
36
|
+
await saveProtectConfig({
|
|
37
|
+
version: 4,
|
|
38
|
+
projectRoot,
|
|
39
|
+
rewindPackageRoot,
|
|
40
|
+
hookModule: installed.hookModule,
|
|
41
|
+
architecture: "MODEL_A_INTERCEPT",
|
|
42
|
+
}, projectRoot);
|
|
43
|
+
const baselineFingerprint = await fingerprintProject(projectRoot);
|
|
44
|
+
const now = new Date().toISOString();
|
|
45
|
+
let session = await loadActiveSession(projectRoot);
|
|
46
|
+
if (!session || session.status !== "ACTIVE") {
|
|
47
|
+
session = {
|
|
48
|
+
id: newProtectedSessionId(),
|
|
49
|
+
version: 4,
|
|
50
|
+
projectRoot,
|
|
51
|
+
startedAt: now,
|
|
52
|
+
endedAt: null,
|
|
53
|
+
status: "ACTIVE",
|
|
54
|
+
client: "Cursor",
|
|
55
|
+
cursor: {},
|
|
56
|
+
actionIds: [],
|
|
57
|
+
policyEventIds: [],
|
|
58
|
+
blockedShellCount: 0,
|
|
59
|
+
baselineFingerprint,
|
|
60
|
+
finalFingerprint: null,
|
|
61
|
+
trust: "AUTHORITATIVE",
|
|
62
|
+
architecture: "MODEL_A_INTERCEPT",
|
|
63
|
+
};
|
|
64
|
+
await saveSession(session, projectRoot);
|
|
65
|
+
await appendAuditEvent({
|
|
66
|
+
type: "PROTECTED_SESSION_STARTED",
|
|
67
|
+
sessionId: session.id,
|
|
68
|
+
detail: `baseline=${baselineFingerprint}`,
|
|
69
|
+
}, projectRoot);
|
|
70
|
+
}
|
|
71
|
+
const prev = await loadProtectState(projectRoot);
|
|
72
|
+
const state = {
|
|
73
|
+
version: 4,
|
|
74
|
+
protected: true,
|
|
75
|
+
projectRoot,
|
|
76
|
+
activeSessionId: session.id,
|
|
77
|
+
rewindPackageRoot,
|
|
78
|
+
hooksInstalled: true,
|
|
79
|
+
failClosed: true,
|
|
80
|
+
installedAt: prev?.installedAt ?? now,
|
|
81
|
+
updatedAt: now,
|
|
82
|
+
managedHookEvents: installed.managedEvents,
|
|
83
|
+
managedMcpServerName: installed.mcpServerName,
|
|
84
|
+
};
|
|
85
|
+
await saveProtectState(state, projectRoot);
|
|
86
|
+
await appendAuditEvent({
|
|
87
|
+
type: "PROTECT_ENABLED",
|
|
88
|
+
sessionId: session.id,
|
|
89
|
+
detail: recovered ? `recoveredIncomplete=${recovered}` : "ok",
|
|
90
|
+
}, projectRoot);
|
|
91
|
+
// Self-test: in-process policy + real wrapper spawn for pwd allow
|
|
92
|
+
await selfTestHook(projectRoot);
|
|
93
|
+
const summary = [
|
|
94
|
+
"REWIND PROTECTED SESSION",
|
|
95
|
+
"",
|
|
96
|
+
`Project: ${projectRoot}`,
|
|
97
|
+
`Agent: Cursor`,
|
|
98
|
+
`Session: ${session.id}`,
|
|
99
|
+
"",
|
|
100
|
+
"✓ agent filesystem mutations protected",
|
|
101
|
+
"✓ shell mutations guarded",
|
|
102
|
+
"✓ action ledger active",
|
|
103
|
+
"✓ undo available",
|
|
104
|
+
"✓ hooks fail closed",
|
|
105
|
+
"",
|
|
106
|
+
"Architecture: Model A (intercept + transactionalise)",
|
|
107
|
+
"Open this project in Cursor and use the agent normally.",
|
|
108
|
+
"You do NOT need to mention REWIND MCP in prompts.",
|
|
109
|
+
].join("\n");
|
|
110
|
+
return { state, session, summary };
|
|
111
|
+
}
|
|
112
|
+
async function selfTestHook(projectRoot) {
|
|
113
|
+
// Prefer compiled hook module for speed; fall back to direct in-process check
|
|
114
|
+
// plus a lightweight wrapper spawn when the module is TypeScript (tsx).
|
|
115
|
+
const { decideProtectedShell } = await import("./shell-policy.js");
|
|
116
|
+
if (decideProtectedShell("pwd").permission !== "allow") {
|
|
117
|
+
throw new PathSafetyError("Protect self-test: pwd should be allow");
|
|
118
|
+
}
|
|
119
|
+
if (decideProtectedShell("echo x > f").permission !== "deny") {
|
|
120
|
+
throw new PathSafetyError("Protect self-test: redirect should be deny");
|
|
121
|
+
}
|
|
122
|
+
const cfg = await import("./store.js").then((m) => m.loadProtectConfig(projectRoot));
|
|
123
|
+
if (!cfg?.hookModule) {
|
|
124
|
+
throw new PathSafetyError("Protect self-test: missing hook module");
|
|
125
|
+
}
|
|
126
|
+
// When hook module is .js, exercise the real wrapper end-to-end.
|
|
127
|
+
if (cfg.hookModule.endsWith(".js")) {
|
|
128
|
+
const { spawnSync } = await import("node:child_process");
|
|
129
|
+
const result = spawnSync("node", [".cursor/hooks/rewind-protect.mjs"], {
|
|
130
|
+
cwd: projectRoot,
|
|
131
|
+
input: JSON.stringify({
|
|
132
|
+
hook_event_name: "beforeShellExecution",
|
|
133
|
+
command: "pwd",
|
|
134
|
+
}),
|
|
135
|
+
encoding: "utf8",
|
|
136
|
+
timeout: 10000,
|
|
137
|
+
env: { ...process.env, REWIND_PROTECT_ROOT: projectRoot },
|
|
138
|
+
});
|
|
139
|
+
if (result.status !== 0) {
|
|
140
|
+
throw new PathSafetyError(`Protect self-test failed (hook exit ${result.status}): ${result.stderr || result.stdout}`);
|
|
141
|
+
}
|
|
142
|
+
let parsed;
|
|
143
|
+
try {
|
|
144
|
+
parsed = JSON.parse(result.stdout || "{}");
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
throw new PathSafetyError("Protect self-test: invalid hook JSON");
|
|
148
|
+
}
|
|
149
|
+
if (parsed.permission !== "allow") {
|
|
150
|
+
throw new PathSafetyError(`Protect self-test: expected allow for pwd, got ${parsed.permission}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Remove REWIND-managed hooks/MCP entries. Keeps .rewind history.
|
|
156
|
+
*/
|
|
157
|
+
export async function unprotectProject(pathArg) {
|
|
158
|
+
const projectRoot = resolveProtectTarget(pathArg);
|
|
159
|
+
const state = await loadProtectState(projectRoot);
|
|
160
|
+
if (!state?.protected) {
|
|
161
|
+
return "REWIND: project is not protected (nothing to remove).";
|
|
162
|
+
}
|
|
163
|
+
const session = await loadActiveSession(projectRoot);
|
|
164
|
+
if (session && session.status === "ACTIVE") {
|
|
165
|
+
session.status = "COMPLETED";
|
|
166
|
+
session.endedAt = new Date().toISOString();
|
|
167
|
+
session.finalFingerprint = await fingerprintProject(projectRoot);
|
|
168
|
+
await saveSession(session, projectRoot);
|
|
169
|
+
await appendAuditEvent({
|
|
170
|
+
type: "PROTECTED_SESSION_ENDED",
|
|
171
|
+
sessionId: session.id,
|
|
172
|
+
detail: "unprotect",
|
|
173
|
+
}, projectRoot);
|
|
174
|
+
}
|
|
175
|
+
await uninstallProtectArtifacts(projectRoot, state.managedMcpServerName ?? "rewind");
|
|
176
|
+
const now = new Date().toISOString();
|
|
177
|
+
await saveProtectState({
|
|
178
|
+
...state,
|
|
179
|
+
protected: false,
|
|
180
|
+
hooksInstalled: false,
|
|
181
|
+
activeSessionId: null,
|
|
182
|
+
updatedAt: now,
|
|
183
|
+
}, projectRoot);
|
|
184
|
+
await appendAuditEvent({ type: "PROTECT_DISABLED" }, projectRoot);
|
|
185
|
+
return [
|
|
186
|
+
"REWIND UNPROTECTED",
|
|
187
|
+
"",
|
|
188
|
+
`Project: ${projectRoot}`,
|
|
189
|
+
"REWIND-managed hooks/MCP entries removed.",
|
|
190
|
+
"History under .rewind/ preserved.",
|
|
191
|
+
"Unrelated Cursor config preserved.",
|
|
192
|
+
].join("\n");
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=protect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protect.js","sourceRoot":"","sources":["../../../src/protect/protect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function getProtectDir(projectRoot: string): string;
|
|
2
|
+
export declare function getProtectSessionsDir(projectRoot: string): string;
|
|
3
|
+
export declare function getProtectAuditDir(projectRoot: string): string;
|
|
4
|
+
export declare function getProtectActionsDir(projectRoot: string): string;
|
|
5
|
+
export declare function getProtectObjectsDir(projectRoot: string): string;
|
|
6
|
+
/** Refuse protecting home, Desktop, system roots, or the REWIND package itself by accident. */
|
|
7
|
+
export declare function assertSafeProtectRoot(target: string, rewindPackageRoot: string): Promise<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a tool-supplied path to a POSIX relative path inside the protected root.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveProtectedRelative(input: string, projectRoot: string): string;
|
|
12
|
+
export declare function protectedAbs(rel: string, projectRoot: string): string;
|
|
13
|
+
export declare function assertProtectedNoSymlinkEscape(absolutePath: string, projectRoot: string): Promise<void>;
|