@remixhq/claude-plugin 0.1.8 → 0.1.10
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/.claude-plugin/plugin.json +1 -1
- package/.mcp.json +1 -1
- package/dist/{hook-post-collab.js → hook-post-collab.cjs} +191 -46
- package/dist/hook-post-collab.cjs.map +1 -0
- package/dist/{hook-pre-git.js → hook-pre-git.cjs} +41 -16
- package/dist/hook-pre-git.cjs.map +1 -0
- package/dist/{hook-stop-collab.js → hook-stop-collab.cjs} +577 -376
- package/dist/hook-stop-collab.cjs.map +1 -0
- package/dist/{hook-user-prompt.js → hook-user-prompt.cjs} +51 -28
- package/dist/hook-user-prompt.cjs.map +1 -0
- package/dist/index.js +48 -6
- package/dist/index.js.map +1 -1
- package/dist/{mcp-server.js → mcp-server.cjs} +814 -782
- package/dist/mcp-server.cjs.map +1 -0
- package/hooks/hooks.json +5 -5
- package/package.json +2 -2
- package/dist/hook-post-collab.js.map +0 -1
- package/dist/hook-pre-git.js.map +0 -1
- package/dist/hook-stop-collab.js.map +0 -1
- package/dist/hook-user-prompt.js.map +0 -1
- package/dist/mcp-server.js.map +0 -1
- /package/dist/{hook-post-collab.d.ts → hook-post-collab.d.cts} +0 -0
- /package/dist/{hook-pre-git.d.ts → hook-pre-git.d.cts} +0 -0
- /package/dist/{hook-stop-collab.d.ts → hook-stop-collab.d.cts} +0 -0
- /package/dist/{hook-user-prompt.d.ts → hook-user-prompt.d.cts} +0 -0
- /package/dist/{mcp-server.d.ts → mcp-server.d.cts} +0 -0
package/.mcp.json
CHANGED
|
@@ -1,27 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
2
25
|
|
|
3
26
|
// src/hook-state.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
27
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
28
|
+
var import_node_os = __toESM(require("os"), 1);
|
|
29
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
30
|
+
var import_node_crypto = require("crypto");
|
|
8
31
|
function stateRoot() {
|
|
9
|
-
return
|
|
32
|
+
return import_node_path.default.join(import_node_os.default.tmpdir(), "remix-claude-plugin-hooks");
|
|
10
33
|
}
|
|
11
34
|
function statePath(sessionId) {
|
|
12
|
-
return
|
|
35
|
+
return import_node_path.default.join(stateRoot(), `${sessionId}.json`);
|
|
13
36
|
}
|
|
14
37
|
function stateLockPath(sessionId) {
|
|
15
|
-
return
|
|
38
|
+
return import_node_path.default.join(stateRoot(), `${sessionId}.lock`);
|
|
16
39
|
}
|
|
17
40
|
function stateLockMetaPath(sessionId) {
|
|
18
|
-
return
|
|
41
|
+
return import_node_path.default.join(stateLockPath(sessionId), "owner.json");
|
|
19
42
|
}
|
|
20
43
|
async function writeJsonAtomic(filePath, value) {
|
|
21
|
-
await
|
|
44
|
+
await import_promises.default.mkdir(import_node_path.default.dirname(filePath), { recursive: true });
|
|
22
45
|
const tmpPath = `${filePath}.tmp-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
23
|
-
await
|
|
24
|
-
await
|
|
46
|
+
await import_promises.default.writeFile(tmpPath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
47
|
+
await import_promises.default.rename(tmpPath, filePath);
|
|
25
48
|
}
|
|
26
49
|
var STATE_LOCK_WAIT_MS = 2e3;
|
|
27
50
|
var STATE_LOCK_POLL_MS = 25;
|
|
@@ -31,7 +54,7 @@ async function sleep(ms) {
|
|
|
31
54
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
32
55
|
}
|
|
33
56
|
async function readStateLockMetadata(sessionId) {
|
|
34
|
-
const raw = await
|
|
57
|
+
const raw = await import_promises.default.readFile(stateLockMetaPath(sessionId), "utf8").catch(() => null);
|
|
35
58
|
if (!raw) return null;
|
|
36
59
|
try {
|
|
37
60
|
const parsed = JSON.parse(raw);
|
|
@@ -56,13 +79,13 @@ async function tryRemoveStaleStateLock(sessionId) {
|
|
|
56
79
|
const metadata = await readStateLockMetadata(sessionId);
|
|
57
80
|
const staleByHeartbeat = metadata && Date.now() - new Date(metadata.heartbeatAt).getTime() > STATE_LOCK_STALE_MS;
|
|
58
81
|
if (staleByHeartbeat) {
|
|
59
|
-
await
|
|
82
|
+
await import_promises.default.rm(lockPath, { recursive: true, force: true }).catch(() => void 0);
|
|
60
83
|
return true;
|
|
61
84
|
}
|
|
62
85
|
if (!metadata) {
|
|
63
|
-
const lockStat = await
|
|
86
|
+
const lockStat = await import_promises.default.stat(lockPath).catch(() => null);
|
|
64
87
|
if (lockStat && Date.now() - lockStat.mtimeMs > STATE_LOCK_STALE_MS) {
|
|
65
|
-
await
|
|
88
|
+
await import_promises.default.rm(lockPath, { recursive: true, force: true }).catch(() => void 0);
|
|
66
89
|
return true;
|
|
67
90
|
}
|
|
68
91
|
}
|
|
@@ -73,8 +96,8 @@ async function acquireStateLock(sessionId) {
|
|
|
73
96
|
const deadline = Date.now() + STATE_LOCK_WAIT_MS;
|
|
74
97
|
while (true) {
|
|
75
98
|
try {
|
|
76
|
-
await
|
|
77
|
-
const ownerId = randomUUID();
|
|
99
|
+
await import_promises.default.mkdir(lockPath);
|
|
100
|
+
const ownerId = (0, import_node_crypto.randomUUID)();
|
|
78
101
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
79
102
|
const metadata = {
|
|
80
103
|
ownerId,
|
|
@@ -98,7 +121,7 @@ async function acquireStateLock(sessionId) {
|
|
|
98
121
|
clearInterval(heartbeat);
|
|
99
122
|
const currentMetadata = await readStateLockMetadata(sessionId);
|
|
100
123
|
if (currentMetadata?.ownerId === ownerId) {
|
|
101
|
-
await
|
|
124
|
+
await import_promises.default.rm(lockPath, { recursive: true, force: true }).catch(() => void 0);
|
|
102
125
|
}
|
|
103
126
|
};
|
|
104
127
|
} catch (error) {
|
|
@@ -156,6 +179,8 @@ function normalizeTouchedRepo(value, repoRoot) {
|
|
|
156
179
|
manuallyRecorded: Boolean(parsed.manuallyRecorded),
|
|
157
180
|
manuallyRecordedAt: normalizeString(parsed.manuallyRecordedAt),
|
|
158
181
|
manuallyRecordedByTool: normalizeString(parsed.manuallyRecordedByTool),
|
|
182
|
+
manualRecordingScope: parsed.manualRecordingScope === "change_step" || parsed.manualRecordingScope === "full_turn" ? parsed.manualRecordingScope : null,
|
|
183
|
+
manualRemoteChangeRecordedAt: normalizeString(parsed.manualRemoteChangeRecordedAt),
|
|
159
184
|
stopAttempted: Boolean(parsed.stopAttempted),
|
|
160
185
|
stopRecorded: Boolean(parsed.stopRecorded),
|
|
161
186
|
stopRecordedAt: normalizeString(parsed.stopRecordedAt),
|
|
@@ -186,6 +211,8 @@ function createTouchedRepo(params) {
|
|
|
186
211
|
manuallyRecorded: false,
|
|
187
212
|
manuallyRecordedAt: null,
|
|
188
213
|
manuallyRecordedByTool: null,
|
|
214
|
+
manualRecordingScope: null,
|
|
215
|
+
manualRemoteChangeRecordedAt: null,
|
|
189
216
|
stopAttempted: false,
|
|
190
217
|
stopRecorded: false,
|
|
191
218
|
stopRecordedAt: null,
|
|
@@ -206,7 +233,7 @@ async function updatePendingTurnState(sessionId, updater) {
|
|
|
206
233
|
});
|
|
207
234
|
}
|
|
208
235
|
async function loadPendingTurnState(sessionId) {
|
|
209
|
-
const raw = await
|
|
236
|
+
const raw = await import_promises.default.readFile(statePath(sessionId), "utf8").catch(() => null);
|
|
210
237
|
if (!raw) return null;
|
|
211
238
|
try {
|
|
212
239
|
const parsed = JSON.parse(raw);
|
|
@@ -281,6 +308,10 @@ async function markTouchedRepoManuallyRecorded(sessionId, repoRoot, params) {
|
|
|
281
308
|
current.manuallyRecorded = true;
|
|
282
309
|
current.manuallyRecordedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
283
310
|
current.manuallyRecordedByTool = normalizeString(params?.toolName) ?? current.manuallyRecordedByTool;
|
|
311
|
+
current.manualRecordingScope = params?.scope ?? current.manualRecordingScope;
|
|
312
|
+
if (params?.remoteChangeRecorded) {
|
|
313
|
+
current.manualRemoteChangeRecordedAt = current.manuallyRecordedAt;
|
|
314
|
+
}
|
|
284
315
|
current.recordingFailureMessage = null;
|
|
285
316
|
current.recordingFailureHint = null;
|
|
286
317
|
current.recordingFailedAt = null;
|
|
@@ -298,18 +329,18 @@ async function markPendingTurnConsultedMemory(sessionId) {
|
|
|
298
329
|
}
|
|
299
330
|
|
|
300
331
|
// src/hook-utils.ts
|
|
301
|
-
|
|
302
|
-
|
|
332
|
+
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
333
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
303
334
|
|
|
304
335
|
// node_modules/@remixhq/core/dist/chunk-FAZUMWBS.js
|
|
305
|
-
|
|
306
|
-
|
|
336
|
+
var import_promises2 = __toESM(require("fs/promises"), 1);
|
|
337
|
+
var import_path = __toESM(require("path"), 1);
|
|
307
338
|
function getCollabBindingPath(repoRoot) {
|
|
308
|
-
return
|
|
339
|
+
return import_path.default.join(repoRoot, ".remix", "config.json");
|
|
309
340
|
}
|
|
310
341
|
async function readCollabBinding(repoRoot) {
|
|
311
342
|
try {
|
|
312
|
-
const raw = await
|
|
343
|
+
const raw = await import_promises2.default.readFile(getCollabBindingPath(repoRoot), "utf8");
|
|
313
344
|
const parsed = JSON.parse(raw);
|
|
314
345
|
if (parsed?.schemaVersion !== 1) return null;
|
|
315
346
|
if (!parsed.projectId || !parsed.currentAppId || !parsed.upstreamAppId) return null;
|
|
@@ -356,6 +387,16 @@ function extractToolResponse(payload) {
|
|
|
356
387
|
function extractToolName(payload) {
|
|
357
388
|
return extractString(payload, ["tool_name", "toolName"]);
|
|
358
389
|
}
|
|
390
|
+
function normalizeHookToolName(toolName) {
|
|
391
|
+
if (!toolName) return null;
|
|
392
|
+
const trimmed = toolName.trim();
|
|
393
|
+
if (!trimmed) return null;
|
|
394
|
+
const remixToolIndex = trimmed.toLowerCase().indexOf("remix_collab_");
|
|
395
|
+
if (remixToolIndex >= 0) {
|
|
396
|
+
return trimmed.slice(remixToolIndex);
|
|
397
|
+
}
|
|
398
|
+
return trimmed;
|
|
399
|
+
}
|
|
359
400
|
function extractString(input, keys) {
|
|
360
401
|
for (const key of keys) {
|
|
361
402
|
const value = input[key];
|
|
@@ -378,15 +419,38 @@ function extractToolCwd(payload) {
|
|
|
378
419
|
const toolInput = extractToolInput(payload);
|
|
379
420
|
return extractString(toolInput, ["cwd"]) ?? extractString(payload, ["cwd"]);
|
|
380
421
|
}
|
|
422
|
+
function extractBashCommand(payload) {
|
|
423
|
+
const toolInput = extractToolInput(payload);
|
|
424
|
+
return extractString(toolInput, ["command", "cmd", "bash_command", "bashCommand"]);
|
|
425
|
+
}
|
|
426
|
+
function extractToolErrorMessage(payload) {
|
|
427
|
+
const toolResponse = extractToolResponse(payload);
|
|
428
|
+
const toolError = getNestedRecord(toolResponse?.error) ?? getNestedRecord(payload.error);
|
|
429
|
+
return extractString(toolError ?? {}, ["message"]) ?? extractString(toolResponse ?? {}, ["errorMessage", "message"]) ?? extractString(payload, ["errorMessage"]);
|
|
430
|
+
}
|
|
431
|
+
function extractToolStatus(payload) {
|
|
432
|
+
const toolResponse = extractToolResponse(payload);
|
|
433
|
+
return extractString(toolResponse ?? {}, ["status", "state"]) ?? extractString(payload, ["status", "state"]);
|
|
434
|
+
}
|
|
381
435
|
function didToolSucceed(payload) {
|
|
382
436
|
const toolResponse = extractToolResponse(payload);
|
|
383
437
|
const explicitSuccess = toolResponse ? extractBoolean(toolResponse, ["success", "ok"]) : null;
|
|
384
438
|
if (explicitSuccess !== null) {
|
|
385
439
|
return explicitSuccess;
|
|
386
440
|
}
|
|
441
|
+
if (extractToolErrorMessage(payload)) {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
const status = extractToolStatus(payload)?.toLowerCase();
|
|
445
|
+
if (status === "error" || status === "failed" || status === "failure") {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
387
448
|
const hookEventName = extractString(payload, ["hook_event_name", "hookEventName"]);
|
|
388
449
|
return hookEventName === "PostToolUse";
|
|
389
450
|
}
|
|
451
|
+
function isRemoteChangeRecordedButLocalSyncFailed(payload) {
|
|
452
|
+
return extractToolErrorMessage(payload) === "Change step succeeded remotely, but automatic local sync failed.";
|
|
453
|
+
}
|
|
390
454
|
function collectStringPathValue(value) {
|
|
391
455
|
if (typeof value === "string" && value.trim()) return [value.trim()];
|
|
392
456
|
if (Array.isArray(value)) {
|
|
@@ -398,7 +462,7 @@ function collectPathTargetsFromObject(input, keys) {
|
|
|
398
462
|
return keys.flatMap((key) => collectStringPathValue(input[key]));
|
|
399
463
|
}
|
|
400
464
|
function resolveCandidatePath(targetPath, baseDir) {
|
|
401
|
-
return
|
|
465
|
+
return import_node_path2.default.isAbsolute(targetPath) ? import_node_path2.default.normalize(targetPath) : import_node_path2.default.resolve(baseDir, targetPath);
|
|
402
466
|
}
|
|
403
467
|
function extractToolPathTargets(payload, toolName) {
|
|
404
468
|
const name = (toolName ?? extractToolName(payload) ?? "").trim().toLowerCase();
|
|
@@ -410,16 +474,16 @@ function extractToolPathTargets(payload, toolName) {
|
|
|
410
474
|
}
|
|
411
475
|
async function findBoundRepo(startPath) {
|
|
412
476
|
if (!startPath) return null;
|
|
413
|
-
let current =
|
|
414
|
-
let stats = await
|
|
477
|
+
let current = import_node_path2.default.resolve(startPath);
|
|
478
|
+
let stats = await import_promises3.default.stat(current).catch(() => null);
|
|
415
479
|
if (stats?.isFile()) {
|
|
416
|
-
current =
|
|
480
|
+
current = import_node_path2.default.dirname(current);
|
|
417
481
|
}
|
|
418
482
|
while (true) {
|
|
419
|
-
const bindingPath =
|
|
420
|
-
const bindingStats = await
|
|
483
|
+
const bindingPath = import_node_path2.default.join(current, ".remix", "config.json");
|
|
484
|
+
const bindingStats = await import_promises3.default.stat(bindingPath).catch(() => null);
|
|
421
485
|
if (bindingStats?.isFile()) return current;
|
|
422
|
-
const parent =
|
|
486
|
+
const parent = import_node_path2.default.dirname(current);
|
|
423
487
|
if (parent === current) return null;
|
|
424
488
|
current = parent;
|
|
425
489
|
}
|
|
@@ -450,9 +514,6 @@ async function resolveBoundRepoFromToolCwd(payload) {
|
|
|
450
514
|
}
|
|
451
515
|
|
|
452
516
|
// src/hook-post-collab.ts
|
|
453
|
-
function isRecordingToolName(toolName) {
|
|
454
|
-
return /remix_collab_(add|add_change_step|record_turn|record_no_diff_turn)$/i.test(toolName);
|
|
455
|
-
}
|
|
456
517
|
function isRepoMutationToolName(toolName) {
|
|
457
518
|
return /remix_collab_(add|add_change_step|sync_apply|approve_and_sync_target|sync_upstream|reconcile_apply)$/i.test(toolName);
|
|
458
519
|
}
|
|
@@ -462,20 +523,80 @@ function isMemoryToolName(toolName) {
|
|
|
462
523
|
function isStructuredLocalWriteToolName(toolName) {
|
|
463
524
|
return /^(Edit|MultiEdit|Write|Delete|NotebookEdit)$/i.test(toolName);
|
|
464
525
|
}
|
|
526
|
+
function isStructuredLocalReadToolName(toolName) {
|
|
527
|
+
return /^Read$/i.test(toolName);
|
|
528
|
+
}
|
|
529
|
+
function isShellToolName(toolName) {
|
|
530
|
+
return /^Bash$/i.test(toolName);
|
|
531
|
+
}
|
|
532
|
+
function isRemoteChangeRecordingToolName(toolName) {
|
|
533
|
+
return /remix_collab_(add|add_change_step)$/i.test(toolName);
|
|
534
|
+
}
|
|
535
|
+
function getManualRecordingScope(toolName) {
|
|
536
|
+
if (/remix_collab_add_change_step$/i.test(toolName)) {
|
|
537
|
+
return "change_step";
|
|
538
|
+
}
|
|
539
|
+
if (/remix_collab_(add|record_turn|record_no_diff_turn)$/i.test(toolName)) {
|
|
540
|
+
return "full_turn";
|
|
541
|
+
}
|
|
542
|
+
return null;
|
|
543
|
+
}
|
|
544
|
+
function isLikelyMutatingShellCommand(command) {
|
|
545
|
+
const normalized = command.trim().toLowerCase();
|
|
546
|
+
if (!normalized) return false;
|
|
547
|
+
const readOnlyPatterns = [
|
|
548
|
+
/^pwd(?:\s|$)/,
|
|
549
|
+
/^ls(?:\s|$)/,
|
|
550
|
+
/^dir(?:\s|$)/,
|
|
551
|
+
/^tree(?:\s|$)/,
|
|
552
|
+
/^rg(?:\s|$)/,
|
|
553
|
+
/^git status(?:\s|$)/,
|
|
554
|
+
/^git diff(?:\s|$)/,
|
|
555
|
+
/^git log(?:\s|$)/,
|
|
556
|
+
/^git show(?:\s|$)/,
|
|
557
|
+
/^git branch(?:\s|$)/,
|
|
558
|
+
/^git rev-parse(?:\s|$)/,
|
|
559
|
+
/^git remote(?:\s|$)/,
|
|
560
|
+
/^git ls-files(?:\s|$)/,
|
|
561
|
+
/^cat(?:\s|$)/,
|
|
562
|
+
/^sed -n(?:\s|$)/,
|
|
563
|
+
/^head(?:\s|$)/,
|
|
564
|
+
/^tail(?:\s|$)/
|
|
565
|
+
];
|
|
566
|
+
const mutatingPatterns = [
|
|
567
|
+
/\|\s*tee(?:\s|$)/,
|
|
568
|
+
/(^|[^\w-])>>?(?=[^&]|$)/,
|
|
569
|
+
/\bgit\b(?:\s+-[^\s]+)*\s+(add|apply|checkout|cherry-pick|clean|mv|restore|revert|rm|stash|switch)\b/,
|
|
570
|
+
/\b(mv|cp|rm|mkdir|rmdir|touch|chmod|chown|ln|install)\b/,
|
|
571
|
+
/\b(sed|perl|ruby)\b.*\s-i(?:\s|$)/,
|
|
572
|
+
/\b(npm|pnpm|yarn|bun)\b\s+(install|add|remove|update|upgrade)\b/
|
|
573
|
+
];
|
|
574
|
+
const segments = normalized.split(/&&|\|\||;|\n/).map((segment) => segment.trim()).filter(Boolean);
|
|
575
|
+
if (mutatingPatterns.some((pattern) => pattern.test(normalized))) {
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
if (segments.length > 0 && segments.every((segment) => readOnlyPatterns.some((pattern) => pattern.test(segment)))) {
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
465
583
|
async function main() {
|
|
466
584
|
const payload = await readJsonStdin();
|
|
467
585
|
const sessionId = typeof payload.session_id === "string" && payload.session_id.trim() ? payload.session_id.trim() : null;
|
|
468
|
-
const toolName = extractToolName(payload);
|
|
586
|
+
const toolName = normalizeHookToolName(extractToolName(payload));
|
|
469
587
|
if (!sessionId || !toolName) {
|
|
470
588
|
return;
|
|
471
589
|
}
|
|
472
|
-
|
|
590
|
+
const toolSucceeded = didToolSucceed(payload);
|
|
591
|
+
const remoteChangeRecordedButSyncFailed = isRemoteChangeRecordingToolName(toolName) && isRemoteChangeRecordedButLocalSyncFailed(payload);
|
|
592
|
+
if (!toolSucceeded && !remoteChangeRecordedButSyncFailed) {
|
|
473
593
|
return;
|
|
474
594
|
}
|
|
475
|
-
if (isMemoryToolName(toolName)) {
|
|
595
|
+
if (toolSucceeded && isMemoryToolName(toolName)) {
|
|
476
596
|
await markPendingTurnConsultedMemory(sessionId);
|
|
477
597
|
}
|
|
478
|
-
|
|
598
|
+
const manualRecordingScope = getManualRecordingScope(toolName);
|
|
599
|
+
if (isRepoMutationToolName(toolName) || manualRecordingScope) {
|
|
479
600
|
const targetRepo = await resolveBoundRepoFromToolCwd(payload);
|
|
480
601
|
if (targetRepo) {
|
|
481
602
|
await upsertTouchedRepo(sessionId, {
|
|
@@ -486,15 +607,37 @@ async function main() {
|
|
|
486
607
|
touchedBy: toolName,
|
|
487
608
|
hasObservedWrite: isRepoMutationToolName(toolName)
|
|
488
609
|
});
|
|
489
|
-
if (isRepoMutationToolName(toolName)) {
|
|
610
|
+
if (toolSucceeded && isRepoMutationToolName(toolName)) {
|
|
490
611
|
await markTouchedRepoObservedWrite(sessionId, targetRepo.repoRoot, { toolName });
|
|
491
612
|
}
|
|
492
|
-
if (
|
|
493
|
-
await markTouchedRepoManuallyRecorded(sessionId, targetRepo.repoRoot, {
|
|
613
|
+
if (manualRecordingScope) {
|
|
614
|
+
await markTouchedRepoManuallyRecorded(sessionId, targetRepo.repoRoot, {
|
|
615
|
+
toolName,
|
|
616
|
+
scope: manualRecordingScope,
|
|
617
|
+
remoteChangeRecorded: toolSucceeded ? isRemoteChangeRecordingToolName(toolName) : remoteChangeRecordedButSyncFailed
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (toolSucceeded && isShellToolName(toolName)) {
|
|
623
|
+
const targetRepo = await resolveBoundRepoFromToolCwd(payload);
|
|
624
|
+
if (targetRepo) {
|
|
625
|
+
const bashCommand = extractBashCommand(payload);
|
|
626
|
+
const hasObservedWrite = bashCommand ? isLikelyMutatingShellCommand(bashCommand) : false;
|
|
627
|
+
await upsertTouchedRepo(sessionId, {
|
|
628
|
+
repoRoot: targetRepo.repoRoot,
|
|
629
|
+
projectId: targetRepo.projectId,
|
|
630
|
+
currentAppId: targetRepo.currentAppId,
|
|
631
|
+
upstreamAppId: targetRepo.upstreamAppId,
|
|
632
|
+
touchedBy: toolName,
|
|
633
|
+
hasObservedWrite
|
|
634
|
+
});
|
|
635
|
+
if (hasObservedWrite) {
|
|
636
|
+
await markTouchedRepoObservedWrite(sessionId, targetRepo.repoRoot, { toolName });
|
|
494
637
|
}
|
|
495
638
|
}
|
|
496
639
|
}
|
|
497
|
-
if (isStructuredLocalWriteToolName(toolName)) {
|
|
640
|
+
if (toolSucceeded && (isStructuredLocalWriteToolName(toolName) || isStructuredLocalReadToolName(toolName))) {
|
|
498
641
|
const touchedRepos = await resolveTouchedBoundReposFromPaths(extractToolPathTargets(payload, toolName));
|
|
499
642
|
for (const repo of touchedRepos) {
|
|
500
643
|
await upsertTouchedRepo(sessionId, {
|
|
@@ -503,9 +646,11 @@ async function main() {
|
|
|
503
646
|
currentAppId: repo.currentAppId,
|
|
504
647
|
upstreamAppId: repo.upstreamAppId,
|
|
505
648
|
touchedBy: toolName,
|
|
506
|
-
hasObservedWrite:
|
|
649
|
+
hasObservedWrite: isStructuredLocalWriteToolName(toolName)
|
|
507
650
|
});
|
|
508
|
-
|
|
651
|
+
if (isStructuredLocalWriteToolName(toolName)) {
|
|
652
|
+
await markTouchedRepoObservedWrite(sessionId, repo.repoRoot, { toolName });
|
|
653
|
+
}
|
|
509
654
|
}
|
|
510
655
|
}
|
|
511
656
|
}
|
|
@@ -515,4 +660,4 @@ main().catch((error) => {
|
|
|
515
660
|
`);
|
|
516
661
|
process.exitCode = 0;
|
|
517
662
|
});
|
|
518
|
-
//# sourceMappingURL=hook-post-collab.
|
|
663
|
+
//# sourceMappingURL=hook-post-collab.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hook-state.ts","../src/hook-utils.ts","../node_modules/@remixhq/core/dist/chunk-FAZUMWBS.js","../src/hook-post-collab.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\n\nimport type { TurnIntent } from \"./history-routing.js\";\n\nexport type RepoRecordMode = \"changed_turn\" | \"no_diff_turn\";\nexport type ManualRecordingScope = \"change_step\" | \"full_turn\";\n\nexport type TouchedRepoState = {\n repoRoot: string;\n projectId: string | null;\n currentAppId: string | null;\n upstreamAppId: string | null;\n firstTouchedAt: string;\n lastTouchedAt: string;\n lastObservedWriteAt: string | null;\n touchedBy: string[];\n hasObservedWrite: boolean;\n manuallyRecorded: boolean;\n manuallyRecordedAt: string | null;\n manuallyRecordedByTool: string | null;\n manualRecordingScope: ManualRecordingScope | null;\n manualRemoteChangeRecordedAt: string | null;\n stopAttempted: boolean;\n stopRecorded: boolean;\n stopRecordedAt: string | null;\n stopRecordedMode: RepoRecordMode | null;\n recordingFailureMessage: string | null;\n recordingFailureHint: string | null;\n recordingFailedAt: string | null;\n};\n\nexport type PendingTurnState = {\n sessionId: string;\n turnId: string;\n prompt: string;\n initialCwd: string | null;\n intent: TurnIntent;\n submittedAt: string;\n consultedMemory: boolean;\n touchedRepos: Record<string, TouchedRepoState>;\n turnFailureMessage: string | null;\n turnFailureHint: string | null;\n turnFailedAt: string | null;\n};\n\nfunction stateRoot(): string {\n return path.join(os.tmpdir(), \"remix-claude-plugin-hooks\");\n}\n\nfunction statePath(sessionId: string): string {\n return path.join(stateRoot(), `${sessionId}.json`);\n}\n\nfunction stateLockPath(sessionId: string): string {\n return path.join(stateRoot(), `${sessionId}.lock`);\n}\n\nfunction stateLockMetaPath(sessionId: string): string {\n return path.join(stateLockPath(sessionId), \"owner.json\");\n}\n\nasync function writeJsonAtomic(filePath: string, value: unknown): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n const tmpPath = `${filePath}.tmp-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n await fs.writeFile(tmpPath, JSON.stringify(value, null, 2) + \"\\n\", \"utf8\");\n await fs.rename(tmpPath, filePath);\n}\n\nconst STATE_LOCK_WAIT_MS = 2_000;\nconst STATE_LOCK_POLL_MS = 25;\nconst STATE_LOCK_STALE_MS = 30_000;\nconst STATE_LOCK_HEARTBEAT_MS = 5_000;\n\ntype StateLockMetadata = {\n ownerId: string;\n pid: number;\n createdAt: string;\n heartbeatAt: string;\n};\n\nasync function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function readStateLockMetadata(sessionId: string): Promise<StateLockMetadata | null> {\n const raw = await fs.readFile(stateLockMetaPath(sessionId), \"utf8\").catch(() => null);\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<StateLockMetadata>;\n if (\n typeof parsed.ownerId !== \"string\" ||\n typeof parsed.pid !== \"number\" ||\n typeof parsed.createdAt !== \"string\" ||\n typeof parsed.heartbeatAt !== \"string\"\n ) {\n return null;\n }\n return {\n ownerId: parsed.ownerId,\n pid: parsed.pid,\n createdAt: parsed.createdAt,\n heartbeatAt: parsed.heartbeatAt,\n };\n } catch {\n return null;\n }\n}\n\nasync function writeStateLockMetadata(sessionId: string, metadata: StateLockMetadata): Promise<void> {\n await writeJsonAtomic(stateLockMetaPath(sessionId), metadata);\n}\n\nasync function tryRemoveStaleStateLock(sessionId: string): Promise<boolean> {\n const lockPath = stateLockPath(sessionId);\n const metadata = await readStateLockMetadata(sessionId);\n const staleByHeartbeat =\n metadata && Date.now() - new Date(metadata.heartbeatAt).getTime() > STATE_LOCK_STALE_MS;\n if (staleByHeartbeat) {\n await fs.rm(lockPath, { recursive: true, force: true }).catch(() => undefined);\n return true;\n }\n\n if (!metadata) {\n const lockStat = await fs.stat(lockPath).catch(() => null);\n if (lockStat && Date.now() - lockStat.mtimeMs > STATE_LOCK_STALE_MS) {\n await fs.rm(lockPath, { recursive: true, force: true }).catch(() => undefined);\n return true;\n }\n }\n\n return false;\n}\n\nasync function acquireStateLock(sessionId: string): Promise<() => Promise<void>> {\n const lockPath = stateLockPath(sessionId);\n const deadline = Date.now() + STATE_LOCK_WAIT_MS;\n\n while (true) {\n try {\n await fs.mkdir(lockPath);\n const ownerId = randomUUID();\n const createdAt = new Date().toISOString();\n const metadata: StateLockMetadata = {\n ownerId,\n pid: process.pid,\n createdAt,\n heartbeatAt: createdAt,\n };\n await writeStateLockMetadata(sessionId, metadata);\n let released = false;\n const heartbeat = setInterval(() => {\n if (released) return;\n void writeStateLockMetadata(sessionId, {\n ...metadata,\n heartbeatAt: new Date().toISOString(),\n }).catch(() => undefined);\n }, STATE_LOCK_HEARTBEAT_MS);\n heartbeat.unref?.();\n\n return async () => {\n if (released) return;\n released = true;\n clearInterval(heartbeat);\n const currentMetadata = await readStateLockMetadata(sessionId);\n if (currentMetadata?.ownerId === ownerId) {\n await fs.rm(lockPath, { recursive: true, force: true }).catch(() => undefined);\n }\n };\n } catch (error) {\n const code = error && typeof error === \"object\" && \"code\" in error ? (error as { code?: unknown }).code : null;\n if (code !== \"EEXIST\") {\n throw error;\n }\n\n if (await tryRemoveStaleStateLock(sessionId)) {\n continue;\n }\n\n if (Date.now() >= deadline) {\n throw new Error(`Timed out acquiring hook state lock for session ${sessionId}.`);\n }\n await sleep(STATE_LOCK_POLL_MS);\n }\n }\n}\n\nasync function withStateLock<T>(sessionId: string, fn: () => Promise<T>): Promise<T> {\n const release = await acquireStateLock(sessionId);\n try {\n return await fn();\n } finally {\n await release();\n }\n}\n\nfunction normalizeIntent(value: unknown): TurnIntent {\n return value === \"memory_first\" || value === \"collab_state\" || value === \"git_facts\" ? value : \"neutral\";\n}\n\nfunction normalizeString(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value.trim() : null;\n}\n\nfunction normalizeStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return Array.from(\n new Set(\n value\n .filter((entry): entry is string => typeof entry === \"string\" && entry.trim().length > 0)\n .map((entry) => entry.trim()),\n ),\n );\n}\n\nfunction normalizeTouchedRepo(value: unknown, repoRoot: string): TouchedRepoState | null {\n if (!value || typeof value !== \"object\") return null;\n const parsed = value as Partial<TouchedRepoState>;\n const normalizedRepoRoot = normalizeString(parsed.repoRoot) ?? repoRoot.trim();\n if (!normalizedRepoRoot) return null;\n\n return {\n repoRoot: normalizedRepoRoot,\n projectId: normalizeString(parsed.projectId),\n currentAppId: normalizeString(parsed.currentAppId),\n upstreamAppId: normalizeString(parsed.upstreamAppId),\n firstTouchedAt: normalizeString(parsed.firstTouchedAt) ?? new Date().toISOString(),\n lastTouchedAt: normalizeString(parsed.lastTouchedAt) ?? new Date().toISOString(),\n lastObservedWriteAt: normalizeString(parsed.lastObservedWriteAt),\n touchedBy: normalizeStringArray(parsed.touchedBy),\n hasObservedWrite: Boolean(parsed.hasObservedWrite),\n manuallyRecorded: Boolean(parsed.manuallyRecorded),\n manuallyRecordedAt: normalizeString(parsed.manuallyRecordedAt),\n manuallyRecordedByTool: normalizeString(parsed.manuallyRecordedByTool),\n manualRecordingScope:\n parsed.manualRecordingScope === \"change_step\" || parsed.manualRecordingScope === \"full_turn\"\n ? parsed.manualRecordingScope\n : null,\n manualRemoteChangeRecordedAt: normalizeString(parsed.manualRemoteChangeRecordedAt),\n stopAttempted: Boolean(parsed.stopAttempted),\n stopRecorded: Boolean(parsed.stopRecorded),\n stopRecordedAt: normalizeString(parsed.stopRecordedAt),\n stopRecordedMode: parsed.stopRecordedMode === \"changed_turn\" || parsed.stopRecordedMode === \"no_diff_turn\" ? parsed.stopRecordedMode : null,\n recordingFailureMessage: normalizeString(parsed.recordingFailureMessage),\n recordingFailureHint: normalizeString(parsed.recordingFailureHint),\n recordingFailedAt: normalizeString(parsed.recordingFailedAt),\n };\n}\n\nfunction normalizeTouchedRepos(value: unknown): Record<string, TouchedRepoState> {\n if (!value || typeof value !== \"object\") return {};\n const entries = Object.entries(value as Record<string, unknown>)\n .map(([repoRoot, repo]) => normalizeTouchedRepo(repo, repoRoot))\n .filter((repo): repo is TouchedRepoState => repo !== null)\n .sort((a, b) => a.repoRoot.localeCompare(b.repoRoot));\n return Object.fromEntries(entries.map((repo) => [repo.repoRoot, repo]));\n}\n\nfunction createTouchedRepo(params: {\n repoRoot: string;\n projectId?: string | null;\n currentAppId?: string | null;\n upstreamAppId?: string | null;\n touchedBy?: string | null;\n hasObservedWrite?: boolean;\n}): TouchedRepoState {\n const now = new Date().toISOString();\n const touchedBy = params.touchedBy?.trim() ? [params.touchedBy.trim()] : [];\n return {\n repoRoot: params.repoRoot,\n projectId: normalizeString(params.projectId),\n currentAppId: normalizeString(params.currentAppId),\n upstreamAppId: normalizeString(params.upstreamAppId),\n firstTouchedAt: now,\n lastTouchedAt: now,\n lastObservedWriteAt: params.hasObservedWrite ? now : null,\n touchedBy,\n hasObservedWrite: Boolean(params.hasObservedWrite),\n manuallyRecorded: false,\n manuallyRecordedAt: null,\n manuallyRecordedByTool: null,\n manualRecordingScope: null,\n manualRemoteChangeRecordedAt: null,\n stopAttempted: false,\n stopRecorded: false,\n stopRecordedAt: null,\n stopRecordedMode: null,\n recordingFailureMessage: null,\n recordingFailureHint: null,\n recordingFailedAt: null,\n };\n}\n\nasync function updatePendingTurnState(\n sessionId: string,\n updater: (state: PendingTurnState) => void | boolean,\n): Promise<PendingTurnState | null> {\n return withStateLock(sessionId, async () => {\n const existing = await loadPendingTurnState(sessionId);\n if (!existing) return null;\n const result = updater(existing);\n if (result === false) return existing;\n await savePendingTurnState(existing);\n return existing;\n });\n}\n\nexport async function loadPendingTurnState(sessionId: string): Promise<PendingTurnState | null> {\n const raw = await fs.readFile(statePath(sessionId), \"utf8\").catch(() => null);\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<PendingTurnState>;\n if (!parsed || typeof parsed !== \"object\") return null;\n if (typeof parsed.sessionId !== \"string\" || typeof parsed.turnId !== \"string\" || typeof parsed.prompt !== \"string\") {\n return null;\n }\n return {\n sessionId: parsed.sessionId,\n turnId: parsed.turnId,\n prompt: parsed.prompt,\n initialCwd: normalizeString(parsed.initialCwd),\n intent: normalizeIntent(parsed.intent),\n submittedAt: typeof parsed.submittedAt === \"string\" ? parsed.submittedAt : new Date().toISOString(),\n consultedMemory: Boolean(parsed.consultedMemory),\n touchedRepos: normalizeTouchedRepos(parsed.touchedRepos),\n turnFailureMessage: normalizeString(parsed.turnFailureMessage),\n turnFailureHint: normalizeString(parsed.turnFailureHint),\n turnFailedAt: normalizeString(parsed.turnFailedAt),\n };\n } catch {\n return null;\n }\n}\n\nexport async function savePendingTurnState(state: PendingTurnState): Promise<void> {\n await writeJsonAtomic(statePath(state.sessionId), state);\n}\n\nexport async function createPendingTurnState(params: {\n sessionId: string;\n prompt: string;\n initialCwd?: string | null;\n intent: TurnIntent;\n}): Promise<PendingTurnState> {\n return withStateLock(params.sessionId, async () => {\n const state: PendingTurnState = {\n sessionId: params.sessionId,\n turnId: randomUUID(),\n prompt: params.prompt,\n initialCwd: params.initialCwd?.trim() || null,\n intent: params.intent,\n submittedAt: new Date().toISOString(),\n consultedMemory: false,\n touchedRepos: {},\n turnFailureMessage: null,\n turnFailureHint: null,\n turnFailedAt: null,\n };\n await savePendingTurnState(state);\n return state;\n });\n}\n\nexport async function upsertTouchedRepo(\n sessionId: string,\n params: {\n repoRoot: string;\n projectId?: string | null;\n currentAppId?: string | null;\n upstreamAppId?: string | null;\n touchedBy?: string | null;\n hasObservedWrite?: boolean;\n },\n): Promise<TouchedRepoState | null> {\n const normalizedRepoRoot = params.repoRoot.trim();\n if (!normalizedRepoRoot) return null;\n const state = await updatePendingTurnState(sessionId, (existing) => {\n const current =\n existing.touchedRepos[normalizedRepoRoot] ??\n createTouchedRepo({\n repoRoot: normalizedRepoRoot,\n projectId: params.projectId,\n currentAppId: params.currentAppId,\n upstreamAppId: params.upstreamAppId,\n touchedBy: params.touchedBy,\n hasObservedWrite: params.hasObservedWrite,\n });\n\n current.projectId = normalizeString(params.projectId) ?? current.projectId;\n current.currentAppId = normalizeString(params.currentAppId) ?? current.currentAppId;\n current.upstreamAppId = normalizeString(params.upstreamAppId) ?? current.upstreamAppId;\n current.lastTouchedAt = new Date().toISOString();\n if (params.touchedBy?.trim() && !current.touchedBy.includes(params.touchedBy.trim())) {\n current.touchedBy = [...current.touchedBy, params.touchedBy.trim()].sort((a, b) => a.localeCompare(b));\n }\n if (params.hasObservedWrite) {\n current.hasObservedWrite = true;\n current.lastObservedWriteAt = new Date().toISOString();\n }\n existing.touchedRepos[normalizedRepoRoot] = current;\n });\n return state?.touchedRepos[normalizedRepoRoot] ?? null;\n}\n\nexport async function markTouchedRepoObservedWrite(\n sessionId: string,\n repoRoot: string,\n params?: { toolName?: string | null },\n): Promise<void> {\n await upsertTouchedRepo(sessionId, {\n repoRoot,\n touchedBy: params?.toolName ?? null,\n hasObservedWrite: true,\n });\n}\n\nexport async function markTouchedRepoManuallyRecorded(\n sessionId: string,\n repoRoot: string,\n params?: { toolName?: string | null; scope?: ManualRecordingScope | null; remoteChangeRecorded?: boolean },\n): Promise<void> {\n await updatePendingTurnState(sessionId, (existing) => {\n const normalizedRepoRoot = repoRoot.trim();\n if (!normalizedRepoRoot) return false;\n const current =\n existing.touchedRepos[normalizedRepoRoot] ??\n createTouchedRepo({\n repoRoot: normalizedRepoRoot,\n touchedBy: params?.toolName ?? null,\n hasObservedWrite: false,\n });\n current.lastTouchedAt = new Date().toISOString();\n current.manuallyRecorded = true;\n current.manuallyRecordedAt = new Date().toISOString();\n current.manuallyRecordedByTool = normalizeString(params?.toolName) ?? current.manuallyRecordedByTool;\n current.manualRecordingScope = params?.scope ?? current.manualRecordingScope;\n if (params?.remoteChangeRecorded) {\n current.manualRemoteChangeRecordedAt = current.manuallyRecordedAt;\n }\n current.recordingFailureMessage = null;\n current.recordingFailureHint = null;\n current.recordingFailedAt = null;\n if (params?.toolName?.trim() && !current.touchedBy.includes(params.toolName.trim())) {\n current.touchedBy = [...current.touchedBy, params.toolName.trim()].sort((a, b) => a.localeCompare(b));\n }\n existing.touchedRepos[normalizedRepoRoot] = current;\n });\n}\n\nexport async function markPendingTurnConsultedMemory(sessionId: string): Promise<void> {\n await updatePendingTurnState(sessionId, (existing) => {\n if (existing.consultedMemory) return false;\n existing.consultedMemory = true;\n });\n}\n\nexport async function markTouchedRepoStopAttempted(sessionId: string, repoRoot: string): Promise<void> {\n await updatePendingTurnState(sessionId, (existing) => {\n const current = existing.touchedRepos[repoRoot];\n if (!current) return false;\n current.stopAttempted = true;\n current.lastTouchedAt = new Date().toISOString();\n });\n}\n\nexport async function markTouchedRepoStopRecorded(\n sessionId: string,\n repoRoot: string,\n params: {\n mode: RepoRecordMode;\n },\n): Promise<void> {\n await updatePendingTurnState(sessionId, (existing) => {\n const current = existing.touchedRepos[repoRoot];\n if (!current) return false;\n current.stopAttempted = true;\n current.stopRecorded = true;\n current.stopRecordedAt = new Date().toISOString();\n current.stopRecordedMode = params.mode;\n current.recordingFailureMessage = null;\n current.recordingFailureHint = null;\n current.recordingFailedAt = null;\n current.lastTouchedAt = new Date().toISOString();\n });\n}\n\nexport async function markTouchedRepoRecordingFailure(\n sessionId: string,\n repoRoot: string,\n params: {\n message: string;\n hint?: string | null;\n },\n): Promise<void> {\n await updatePendingTurnState(sessionId, (existing) => {\n const current = existing.touchedRepos[repoRoot];\n if (!current) return false;\n current.stopAttempted = true;\n current.recordingFailureMessage = params.message.trim();\n current.recordingFailureHint = params.hint?.trim() || null;\n current.recordingFailedAt = new Date().toISOString();\n current.lastTouchedAt = new Date().toISOString();\n });\n}\n\nexport async function markPendingTurnFailure(\n sessionId: string,\n params: {\n message: string;\n hint?: string | null;\n },\n): Promise<void> {\n await updatePendingTurnState(sessionId, (existing) => {\n existing.turnFailureMessage = params.message.trim();\n existing.turnFailureHint = params.hint?.trim() || null;\n existing.turnFailedAt = new Date().toISOString();\n });\n}\n\nexport async function listTouchedRepos(sessionId: string): Promise<TouchedRepoState[]> {\n const existing = await loadPendingTurnState(sessionId);\n if (!existing) return [];\n return Object.values(existing.touchedRepos).sort((a, b) => a.repoRoot.localeCompare(b.repoRoot));\n}\n\nexport async function clearPendingTurnState(sessionId: string): Promise<void> {\n await withStateLock(sessionId, async () => {\n await fs.rm(statePath(sessionId), { force: true }).catch(() => undefined);\n });\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { readCollabBinding } from \"@remixhq/core/binding\";\n\ntype BindingSummary = {\n repoRoot: string;\n projectId: string | null;\n currentAppId: string | null;\n upstreamAppId: string | null;\n};\n\nexport async function readJsonStdin(): Promise<Record<string, unknown>> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n const raw = Buffer.concat(chunks).toString(\"utf8\").trim();\n if (!raw) return {};\n try {\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? (parsed as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n}\n\nfunction getNestedRecord(value: unknown): Record<string, unknown> | null {\n return value && typeof value === \"object\" ? (value as Record<string, unknown>) : null;\n}\n\nexport function extractToolInput(payload: Record<string, unknown>): Record<string, unknown> {\n return getNestedRecord(payload.tool_input) ?? getNestedRecord(payload.toolInput) ?? payload;\n}\n\nexport function extractToolResponse(payload: Record<string, unknown>): Record<string, unknown> | null {\n return getNestedRecord(payload.tool_response) ?? getNestedRecord(payload.toolResponse);\n}\n\nexport function extractToolName(payload: Record<string, unknown>): string | null {\n return extractString(payload, [\"tool_name\", \"toolName\"]);\n}\n\nexport function normalizeHookToolName(toolName: string | null): string | null {\n if (!toolName) return null;\n const trimmed = toolName.trim();\n if (!trimmed) return null;\n\n const remixToolIndex = trimmed.toLowerCase().indexOf(\"remix_collab_\");\n if (remixToolIndex >= 0) {\n return trimmed.slice(remixToolIndex);\n }\n\n return trimmed;\n}\n\nexport function extractAssistantResponse(payload: Record<string, unknown>): string | null {\n const candidateKeys = [\n \"last_assistant_message\",\n \"lastAssistantMessage\",\n \"assistant_response\",\n \"assistantResponse\",\n \"assistant_message\",\n \"assistantMessage\",\n \"response\",\n \"message\",\n ];\n\n return (\n extractString(payload, candidateKeys) ??\n extractString(extractToolResponse(payload) ?? {}, candidateKeys) ??\n extractString(extractToolInput(payload), candidateKeys)\n );\n}\n\nexport function extractString(input: Record<string, unknown>, keys: string[]): string | null {\n for (const key of keys) {\n const value = input[key];\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n }\n return null;\n}\n\nexport function extractBoolean(input: Record<string, unknown>, keys: string[]): boolean | null {\n for (const key of keys) {\n const value = input[key];\n if (typeof value === \"boolean\") {\n return value;\n }\n }\n return null;\n}\n\nexport function extractToolCwd(payload: Record<string, unknown>): string | null {\n const toolInput = extractToolInput(payload);\n return extractString(toolInput, [\"cwd\"]) ?? extractString(payload, [\"cwd\"]);\n}\n\nexport function extractBashCommand(payload: Record<string, unknown>): string | null {\n const toolInput = extractToolInput(payload);\n return extractString(toolInput, [\"command\", \"cmd\", \"bash_command\", \"bashCommand\"]);\n}\n\nexport function extractToolErrorMessage(payload: Record<string, unknown>): string | null {\n const toolResponse = extractToolResponse(payload);\n const toolError = getNestedRecord(toolResponse?.error) ?? getNestedRecord(payload.error);\n return (\n extractString(toolError ?? {}, [\"message\"]) ??\n extractString(toolResponse ?? {}, [\"errorMessage\", \"message\"]) ??\n extractString(payload, [\"errorMessage\"])\n );\n}\n\nfunction extractToolStatus(payload: Record<string, unknown>): string | null {\n const toolResponse = extractToolResponse(payload);\n return (\n extractString(toolResponse ?? {}, [\"status\", \"state\"]) ??\n extractString(payload, [\"status\", \"state\"])\n );\n}\n\nexport function didToolSucceed(payload: Record<string, unknown>): boolean {\n const toolResponse = extractToolResponse(payload);\n const explicitSuccess = toolResponse ? extractBoolean(toolResponse, [\"success\", \"ok\"]) : null;\n if (explicitSuccess !== null) {\n return explicitSuccess;\n }\n\n if (extractToolErrorMessage(payload)) {\n return false;\n }\n\n const status = extractToolStatus(payload)?.toLowerCase();\n if (status === \"error\" || status === \"failed\" || status === \"failure\") {\n return false;\n }\n\n const hookEventName = extractString(payload, [\"hook_event_name\", \"hookEventName\"]);\n return hookEventName === \"PostToolUse\";\n}\n\nexport function isRemoteChangeRecordedButLocalSyncFailed(payload: Record<string, unknown>): boolean {\n return extractToolErrorMessage(payload) === \"Change step succeeded remotely, but automatic local sync failed.\";\n}\n\nfunction collectStringPathValue(value: unknown): string[] {\n if (typeof value === \"string\" && value.trim()) return [value.trim()];\n if (Array.isArray(value)) {\n return value.flatMap((entry) => collectStringPathValue(entry));\n }\n return [];\n}\n\nfunction collectPathTargetsFromObject(input: Record<string, unknown>, keys: string[]): string[] {\n return keys.flatMap((key) => collectStringPathValue(input[key]));\n}\n\nfunction resolveCandidatePath(targetPath: string, baseDir: string): string {\n return path.isAbsolute(targetPath) ? path.normalize(targetPath) : path.resolve(baseDir, targetPath);\n}\n\nexport function extractToolPathTargets(payload: Record<string, unknown>, toolName?: string | null): string[] {\n const name = (toolName ?? extractToolName(payload) ?? \"\").trim().toLowerCase();\n const toolInput = extractToolInput(payload);\n const baseDir = extractToolCwd(payload) ?? process.cwd();\n const baseKeys = [\"path\", \"paths\", \"file_path\", \"filePath\", \"target_file\", \"targetFile\", \"filename\"];\n\n const targets =\n name === \"notebookedit\"\n ? collectPathTargetsFromObject(toolInput, [\"target_notebook\", \"notebook_path\", \"notebookPath\", ...baseKeys])\n : collectPathTargetsFromObject(toolInput, baseKeys);\n\n return Array.from(new Set(targets.map((entry) => resolveCandidatePath(entry, baseDir))));\n}\n\nexport async function findBoundRepo(startPath: string | null): Promise<string | null> {\n if (!startPath) return null;\n let current = path.resolve(startPath);\n let stats = await fs.stat(current).catch(() => null);\n if (stats?.isFile()) {\n current = path.dirname(current);\n }\n\n while (true) {\n const bindingPath = path.join(current, \".remix\", \"config.json\");\n const bindingStats = await fs.stat(bindingPath).catch(() => null);\n if (bindingStats?.isFile()) return current;\n const parent = path.dirname(current);\n if (parent === current) return null;\n current = parent;\n }\n}\n\nexport async function resolveBoundRepoSummary(startPath: string | null): Promise<BindingSummary | null> {\n const repoRoot = await findBoundRepo(startPath);\n if (!repoRoot) return null;\n const binding = await readCollabBinding(repoRoot).catch(() => null);\n if (!binding) return null;\n return {\n repoRoot,\n projectId: binding.projectId,\n currentAppId: binding.currentAppId,\n upstreamAppId: binding.upstreamAppId,\n };\n}\n\nexport async function resolveTouchedBoundReposFromPaths(paths: string[]): Promise<BindingSummary[]> {\n const resolved = await Promise.all(paths.map((targetPath) => resolveBoundRepoSummary(targetPath)));\n const unique = new Map<string, BindingSummary>();\n for (const repo of resolved) {\n if (!repo) continue;\n unique.set(repo.repoRoot, repo);\n }\n return Array.from(unique.values()).sort((a, b) => a.repoRoot.localeCompare(b.repoRoot));\n}\n\nexport async function resolveBoundRepoFromToolCwd(payload: Record<string, unknown>): Promise<BindingSummary | null> {\n return resolveBoundRepoSummary(extractToolCwd(payload));\n}\n","import {\n RemixError\n} from \"./chunk-YZ34ICNN.js\";\n\n// src/infrastructure/binding/collabBindingStore.ts\nimport fs2 from \"fs/promises\";\nimport path2 from \"path\";\n\n// src/shared/fs.ts\nimport fs from \"fs/promises\";\nimport path from \"path\";\nasync function reserveDirectory(targetDir) {\n try {\n await fs.mkdir(targetDir);\n return targetDir;\n } catch (error) {\n if (error?.code === \"EEXIST\") {\n throw new RemixError(\"Output directory already exists.\", {\n exitCode: 2,\n hint: `Choose an empty destination path: ${targetDir}`\n });\n }\n throw error;\n }\n}\nasync function reserveAvailableDirPath(preferredDir) {\n const parent = path.dirname(preferredDir);\n const base = path.basename(preferredDir);\n for (let i = 1; i <= 1e3; i += 1) {\n const candidate = i === 1 ? preferredDir : path.join(parent, `${base}-${i}`);\n try {\n await fs.mkdir(candidate);\n return candidate;\n } catch (error) {\n if (error?.code === \"EEXIST\") continue;\n throw error;\n }\n }\n throw new RemixError(\"No available output directory name.\", {\n exitCode: 2,\n hint: `Tried ${base} through ${base}-1000 under ${parent}.`\n });\n}\nasync function writeJsonAtomic(filePath, value) {\n const dir = path.dirname(filePath);\n await fs.mkdir(dir, { recursive: true });\n const tmp = `${filePath}.tmp-${Date.now()}`;\n await fs.writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`, \"utf8\");\n await fs.rename(tmp, filePath);\n}\n\n// src/infrastructure/binding/collabBindingStore.ts\nfunction getCollabBindingPath(repoRoot) {\n return path2.join(repoRoot, \".remix\", \"config.json\");\n}\nasync function readCollabBinding(repoRoot) {\n try {\n const raw = await fs2.readFile(getCollabBindingPath(repoRoot), \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed?.schemaVersion !== 1) return null;\n if (!parsed.projectId || !parsed.currentAppId || !parsed.upstreamAppId) return null;\n return {\n schemaVersion: 1,\n projectId: parsed.projectId,\n currentAppId: parsed.currentAppId,\n upstreamAppId: parsed.upstreamAppId,\n threadId: parsed.threadId ?? null,\n repoFingerprint: parsed.repoFingerprint ?? null,\n remoteUrl: parsed.remoteUrl ?? null,\n defaultBranch: parsed.defaultBranch ?? null,\n preferredBranch: parsed.preferredBranch ?? parsed.defaultBranch ?? null\n };\n } catch {\n return null;\n }\n}\nasync function writeCollabBinding(repoRoot, binding) {\n const filePath = getCollabBindingPath(repoRoot);\n await writeJsonAtomic(filePath, {\n schemaVersion: 1,\n ...binding\n });\n return filePath;\n}\n\nexport {\n reserveDirectory,\n reserveAvailableDirPath,\n getCollabBindingPath,\n readCollabBinding,\n writeCollabBinding\n};\n","import {\n markPendingTurnConsultedMemory,\n markTouchedRepoManuallyRecorded,\n markTouchedRepoObservedWrite,\n upsertTouchedRepo,\n} from \"./hook-state.js\";\nimport {\n didToolSucceed,\n extractBashCommand,\n extractToolName,\n extractToolPathTargets,\n isRemoteChangeRecordedButLocalSyncFailed,\n normalizeHookToolName,\n readJsonStdin,\n resolveBoundRepoFromToolCwd,\n resolveTouchedBoundReposFromPaths,\n} from \"./hook-utils.js\";\n\nfunction isRepoMutationToolName(toolName: string): boolean {\n return /remix_collab_(add|add_change_step|sync_apply|approve_and_sync_target|sync_upstream|reconcile_apply)$/i.test(toolName);\n}\n\nfunction isMemoryToolName(toolName: string): boolean {\n return /remix_collab_memory_(summary|search|timeline|change_step_diff)$/i.test(toolName);\n}\n\nfunction isStructuredLocalWriteToolName(toolName: string): boolean {\n return /^(Edit|MultiEdit|Write|Delete|NotebookEdit)$/i.test(toolName);\n}\n\nfunction isStructuredLocalReadToolName(toolName: string): boolean {\n return /^Read$/i.test(toolName);\n}\n\nfunction isShellToolName(toolName: string): boolean {\n return /^Bash$/i.test(toolName);\n}\n\nfunction isRemoteChangeRecordingToolName(toolName: string): boolean {\n return /remix_collab_(add|add_change_step)$/i.test(toolName);\n}\n\nfunction getManualRecordingScope(toolName: string): \"change_step\" | \"full_turn\" | null {\n if (/remix_collab_add_change_step$/i.test(toolName)) {\n return \"change_step\";\n }\n if (/remix_collab_(add|record_turn|record_no_diff_turn)$/i.test(toolName)) {\n return \"full_turn\";\n }\n return null;\n}\n\nfunction isLikelyMutatingShellCommand(command: string): boolean {\n const normalized = command.trim().toLowerCase();\n if (!normalized) return false;\n\n const readOnlyPatterns = [\n /^pwd(?:\\s|$)/,\n /^ls(?:\\s|$)/,\n /^dir(?:\\s|$)/,\n /^tree(?:\\s|$)/,\n /^rg(?:\\s|$)/,\n /^git status(?:\\s|$)/,\n /^git diff(?:\\s|$)/,\n /^git log(?:\\s|$)/,\n /^git show(?:\\s|$)/,\n /^git branch(?:\\s|$)/,\n /^git rev-parse(?:\\s|$)/,\n /^git remote(?:\\s|$)/,\n /^git ls-files(?:\\s|$)/,\n /^cat(?:\\s|$)/,\n /^sed -n(?:\\s|$)/,\n /^head(?:\\s|$)/,\n /^tail(?:\\s|$)/,\n ];\n\n const mutatingPatterns = [\n /\\|\\s*tee(?:\\s|$)/,\n /(^|[^\\w-])>>?(?=[^&]|$)/,\n /\\bgit\\b(?:\\s+-[^\\s]+)*\\s+(add|apply|checkout|cherry-pick|clean|mv|restore|revert|rm|stash|switch)\\b/,\n /\\b(mv|cp|rm|mkdir|rmdir|touch|chmod|chown|ln|install)\\b/,\n /\\b(sed|perl|ruby)\\b.*\\s-i(?:\\s|$)/,\n /\\b(npm|pnpm|yarn|bun)\\b\\s+(install|add|remove|update|upgrade)\\b/,\n ];\n\n const segments = normalized\n .split(/&&|\\|\\||;|\\n/)\n .map((segment) => segment.trim())\n .filter(Boolean);\n\n if (mutatingPatterns.some((pattern) => pattern.test(normalized))) {\n return true;\n }\n\n if (segments.length > 0 && segments.every((segment) => readOnlyPatterns.some((pattern) => pattern.test(segment)))) {\n return false;\n }\n\n return false;\n}\n\nasync function main(): Promise<void> {\n const payload = await readJsonStdin();\n const sessionId = typeof payload.session_id === \"string\" && payload.session_id.trim() ? payload.session_id.trim() : null;\n const toolName = normalizeHookToolName(extractToolName(payload));\n if (!sessionId || !toolName) {\n return;\n }\n\n const toolSucceeded = didToolSucceed(payload);\n const remoteChangeRecordedButSyncFailed =\n isRemoteChangeRecordingToolName(toolName) && isRemoteChangeRecordedButLocalSyncFailed(payload);\n if (!toolSucceeded && !remoteChangeRecordedButSyncFailed) {\n return;\n }\n\n if (toolSucceeded && isMemoryToolName(toolName)) {\n await markPendingTurnConsultedMemory(sessionId);\n }\n\n const manualRecordingScope = getManualRecordingScope(toolName);\n if (isRepoMutationToolName(toolName) || manualRecordingScope) {\n const targetRepo = await resolveBoundRepoFromToolCwd(payload);\n if (targetRepo) {\n await upsertTouchedRepo(sessionId, {\n repoRoot: targetRepo.repoRoot,\n projectId: targetRepo.projectId,\n currentAppId: targetRepo.currentAppId,\n upstreamAppId: targetRepo.upstreamAppId,\n touchedBy: toolName,\n hasObservedWrite: isRepoMutationToolName(toolName),\n });\n if (toolSucceeded && isRepoMutationToolName(toolName)) {\n await markTouchedRepoObservedWrite(sessionId, targetRepo.repoRoot, { toolName });\n }\n if (manualRecordingScope) {\n await markTouchedRepoManuallyRecorded(sessionId, targetRepo.repoRoot, {\n toolName,\n scope: manualRecordingScope,\n remoteChangeRecorded: toolSucceeded\n ? isRemoteChangeRecordingToolName(toolName)\n : remoteChangeRecordedButSyncFailed,\n });\n }\n }\n }\n\n if (toolSucceeded && isShellToolName(toolName)) {\n const targetRepo = await resolveBoundRepoFromToolCwd(payload);\n if (targetRepo) {\n const bashCommand = extractBashCommand(payload);\n const hasObservedWrite = bashCommand ? isLikelyMutatingShellCommand(bashCommand) : false;\n await upsertTouchedRepo(sessionId, {\n repoRoot: targetRepo.repoRoot,\n projectId: targetRepo.projectId,\n currentAppId: targetRepo.currentAppId,\n upstreamAppId: targetRepo.upstreamAppId,\n touchedBy: toolName,\n hasObservedWrite,\n });\n if (hasObservedWrite) {\n await markTouchedRepoObservedWrite(sessionId, targetRepo.repoRoot, { toolName });\n }\n }\n }\n\n if (toolSucceeded && (isStructuredLocalWriteToolName(toolName) || isStructuredLocalReadToolName(toolName))) {\n const touchedRepos = await resolveTouchedBoundReposFromPaths(extractToolPathTargets(payload, toolName));\n for (const repo of touchedRepos) {\n await upsertTouchedRepo(sessionId, {\n repoRoot: repo.repoRoot,\n projectId: repo.projectId,\n currentAppId: repo.currentAppId,\n upstreamAppId: repo.upstreamAppId,\n touchedBy: toolName,\n hasObservedWrite: isStructuredLocalWriteToolName(toolName),\n });\n if (isStructuredLocalWriteToolName(toolName)) {\n await markTouchedRepoObservedWrite(sessionId, repo.repoRoot, { toolName });\n }\n }\n }\n}\n\nmain().catch((error) => {\n const message = error instanceof Error ? error.message : String(error);\n process.stderr.write(`${message}\\n`);\n process.exitCode = 0;\n});\n"],"mappings":"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","names":["path","os","fs","import_promises","import_node_path","import_promises","path2","fs2","path","fs"]}
|