@remixhq/claude-plugin 0.1.23 → 0.1.25
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/dist/hook-post-collab.cjs +3 -3
- package/dist/hook-post-collab.cjs.map +1 -1
- package/dist/hook-stop-collab.cjs +261 -183
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-user-prompt.cjs +310 -228
- package/dist/hook-user-prompt.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +209 -73
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +3 -3
- package/skills/submit-change-step/SKILL.md +1 -1
|
@@ -38,7 +38,7 @@ var require_windows = __commonJS({
|
|
|
38
38
|
module2.exports = isexe;
|
|
39
39
|
isexe.sync = sync;
|
|
40
40
|
var fs13 = require("fs");
|
|
41
|
-
function checkPathExt(
|
|
41
|
+
function checkPathExt(path17, options) {
|
|
42
42
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
43
43
|
if (!pathext) {
|
|
44
44
|
return true;
|
|
@@ -49,25 +49,25 @@ var require_windows = __commonJS({
|
|
|
49
49
|
}
|
|
50
50
|
for (var i2 = 0; i2 < pathext.length; i2++) {
|
|
51
51
|
var p = pathext[i2].toLowerCase();
|
|
52
|
-
if (p &&
|
|
52
|
+
if (p && path17.substr(-p.length).toLowerCase() === p) {
|
|
53
53
|
return true;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
return false;
|
|
57
57
|
}
|
|
58
|
-
function checkStat(stat,
|
|
58
|
+
function checkStat(stat, path17, options) {
|
|
59
59
|
if (!stat.isSymbolicLink() && !stat.isFile()) {
|
|
60
60
|
return false;
|
|
61
61
|
}
|
|
62
|
-
return checkPathExt(
|
|
62
|
+
return checkPathExt(path17, options);
|
|
63
63
|
}
|
|
64
|
-
function isexe(
|
|
65
|
-
fs13.stat(
|
|
66
|
-
cb(er, er ? false : checkStat(stat,
|
|
64
|
+
function isexe(path17, options, cb) {
|
|
65
|
+
fs13.stat(path17, function(er, stat) {
|
|
66
|
+
cb(er, er ? false : checkStat(stat, path17, options));
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
|
-
function sync(
|
|
70
|
-
return checkStat(fs13.statSync(
|
|
69
|
+
function sync(path17, options) {
|
|
70
|
+
return checkStat(fs13.statSync(path17), path17, options);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
});
|
|
@@ -79,13 +79,13 @@ var require_mode = __commonJS({
|
|
|
79
79
|
module2.exports = isexe;
|
|
80
80
|
isexe.sync = sync;
|
|
81
81
|
var fs13 = require("fs");
|
|
82
|
-
function isexe(
|
|
83
|
-
fs13.stat(
|
|
82
|
+
function isexe(path17, options, cb) {
|
|
83
|
+
fs13.stat(path17, function(er, stat) {
|
|
84
84
|
cb(er, er ? false : checkStat(stat, options));
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
function sync(
|
|
88
|
-
return checkStat(fs13.statSync(
|
|
87
|
+
function sync(path17, options) {
|
|
88
|
+
return checkStat(fs13.statSync(path17), options);
|
|
89
89
|
}
|
|
90
90
|
function checkStat(stat, options) {
|
|
91
91
|
return stat.isFile() && checkMode(stat, options);
|
|
@@ -119,7 +119,7 @@ var require_isexe = __commonJS({
|
|
|
119
119
|
}
|
|
120
120
|
module2.exports = isexe;
|
|
121
121
|
isexe.sync = sync;
|
|
122
|
-
function isexe(
|
|
122
|
+
function isexe(path17, options, cb) {
|
|
123
123
|
if (typeof options === "function") {
|
|
124
124
|
cb = options;
|
|
125
125
|
options = {};
|
|
@@ -129,7 +129,7 @@ var require_isexe = __commonJS({
|
|
|
129
129
|
throw new TypeError("callback not provided");
|
|
130
130
|
}
|
|
131
131
|
return new Promise(function(resolve, reject) {
|
|
132
|
-
isexe(
|
|
132
|
+
isexe(path17, options || {}, function(er, is) {
|
|
133
133
|
if (er) {
|
|
134
134
|
reject(er);
|
|
135
135
|
} else {
|
|
@@ -138,7 +138,7 @@ var require_isexe = __commonJS({
|
|
|
138
138
|
});
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
|
-
core(
|
|
141
|
+
core(path17, options || {}, function(er, is) {
|
|
142
142
|
if (er) {
|
|
143
143
|
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
144
144
|
er = null;
|
|
@@ -148,9 +148,9 @@ var require_isexe = __commonJS({
|
|
|
148
148
|
cb(er, is);
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
|
-
function sync(
|
|
151
|
+
function sync(path17, options) {
|
|
152
152
|
try {
|
|
153
|
-
return core.sync(
|
|
153
|
+
return core.sync(path17, options || {});
|
|
154
154
|
} catch (er) {
|
|
155
155
|
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
156
156
|
return false;
|
|
@@ -167,7 +167,7 @@ var require_which = __commonJS({
|
|
|
167
167
|
"node_modules/which/which.js"(exports2, module2) {
|
|
168
168
|
"use strict";
|
|
169
169
|
var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
170
|
-
var
|
|
170
|
+
var path17 = require("path");
|
|
171
171
|
var COLON = isWindows ? ";" : ":";
|
|
172
172
|
var isexe = require_isexe();
|
|
173
173
|
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
@@ -205,7 +205,7 @@ var require_which = __commonJS({
|
|
|
205
205
|
return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
|
|
206
206
|
const ppRaw = pathEnv[i2];
|
|
207
207
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
208
|
-
const pCmd =
|
|
208
|
+
const pCmd = path17.join(pathPart, cmd);
|
|
209
209
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
210
210
|
resolve(subStep(p, i2, 0));
|
|
211
211
|
});
|
|
@@ -232,7 +232,7 @@ var require_which = __commonJS({
|
|
|
232
232
|
for (let i2 = 0; i2 < pathEnv.length; i2++) {
|
|
233
233
|
const ppRaw = pathEnv[i2];
|
|
234
234
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
235
|
-
const pCmd =
|
|
235
|
+
const pCmd = path17.join(pathPart, cmd);
|
|
236
236
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
237
237
|
for (let j = 0; j < pathExt.length; j++) {
|
|
238
238
|
const cur = p + pathExt[j];
|
|
@@ -280,7 +280,7 @@ var require_path_key = __commonJS({
|
|
|
280
280
|
var require_resolveCommand = __commonJS({
|
|
281
281
|
"node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) {
|
|
282
282
|
"use strict";
|
|
283
|
-
var
|
|
283
|
+
var path17 = require("path");
|
|
284
284
|
var which = require_which();
|
|
285
285
|
var getPathKey = require_path_key();
|
|
286
286
|
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
@@ -298,7 +298,7 @@ var require_resolveCommand = __commonJS({
|
|
|
298
298
|
try {
|
|
299
299
|
resolved = which.sync(parsed.command, {
|
|
300
300
|
path: env[getPathKey({ env })],
|
|
301
|
-
pathExt: withoutPathExt ?
|
|
301
|
+
pathExt: withoutPathExt ? path17.delimiter : void 0
|
|
302
302
|
});
|
|
303
303
|
} catch (e) {
|
|
304
304
|
} finally {
|
|
@@ -307,7 +307,7 @@ var require_resolveCommand = __commonJS({
|
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
if (resolved) {
|
|
310
|
-
resolved =
|
|
310
|
+
resolved = path17.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
311
311
|
}
|
|
312
312
|
return resolved;
|
|
313
313
|
}
|
|
@@ -361,8 +361,8 @@ var require_shebang_command = __commonJS({
|
|
|
361
361
|
if (!match) {
|
|
362
362
|
return null;
|
|
363
363
|
}
|
|
364
|
-
const [
|
|
365
|
-
const binary =
|
|
364
|
+
const [path17, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
365
|
+
const binary = path17.split("/").pop();
|
|
366
366
|
if (binary === "env") {
|
|
367
367
|
return argument;
|
|
368
368
|
}
|
|
@@ -397,7 +397,7 @@ var require_readShebang = __commonJS({
|
|
|
397
397
|
var require_parse = __commonJS({
|
|
398
398
|
"node_modules/cross-spawn/lib/parse.js"(exports2, module2) {
|
|
399
399
|
"use strict";
|
|
400
|
-
var
|
|
400
|
+
var path17 = require("path");
|
|
401
401
|
var resolveCommand = require_resolveCommand();
|
|
402
402
|
var escape = require_escape();
|
|
403
403
|
var readShebang = require_readShebang();
|
|
@@ -422,7 +422,7 @@ var require_parse = __commonJS({
|
|
|
422
422
|
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
423
423
|
if (parsed.options.forceShell || needsShell) {
|
|
424
424
|
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
425
|
-
parsed.command =
|
|
425
|
+
parsed.command = path17.normalize(parsed.command);
|
|
426
426
|
parsed.command = escape.command(parsed.command);
|
|
427
427
|
parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
|
|
428
428
|
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
@@ -4941,13 +4941,13 @@ var logOutputSync = ({ serializedResult, fdNumber, state, verboseInfo, encoding,
|
|
|
4941
4941
|
}
|
|
4942
4942
|
};
|
|
4943
4943
|
var writeToFiles = (serializedResult, stdioItems, outputFiles) => {
|
|
4944
|
-
for (const { path:
|
|
4945
|
-
const pathString = typeof
|
|
4944
|
+
for (const { path: path17, append } of stdioItems.filter(({ type }) => FILE_TYPES.has(type))) {
|
|
4945
|
+
const pathString = typeof path17 === "string" ? path17 : path17.toString();
|
|
4946
4946
|
if (append || outputFiles.has(pathString)) {
|
|
4947
|
-
(0, import_node_fs4.appendFileSync)(
|
|
4947
|
+
(0, import_node_fs4.appendFileSync)(path17, serializedResult);
|
|
4948
4948
|
} else {
|
|
4949
4949
|
outputFiles.add(pathString);
|
|
4950
|
-
(0, import_node_fs4.writeFileSync)(
|
|
4950
|
+
(0, import_node_fs4.writeFileSync)(path17, serializedResult);
|
|
4951
4951
|
}
|
|
4952
4952
|
}
|
|
4953
4953
|
};
|
|
@@ -8578,6 +8578,15 @@ function shouldRequireRemoteLaneForCurrentBranch(params) {
|
|
|
8578
8578
|
if (params.currentBranch === defaultBranch) return false;
|
|
8579
8579
|
return !params.binding.laneId || params.binding.currentAppId === params.binding.upstreamAppId;
|
|
8580
8580
|
}
|
|
8581
|
+
function resolveLaneLookupProjectId(params) {
|
|
8582
|
+
const currentBranch = normalizeBranchName2(params.currentBranch);
|
|
8583
|
+
const defaultBranch = normalizeBranchName2(params.defaultBranch);
|
|
8584
|
+
const localProjectId = params.localBinding.projectId ?? null;
|
|
8585
|
+
if (currentBranch && currentBranch !== defaultBranch && localProjectId) {
|
|
8586
|
+
return localProjectId;
|
|
8587
|
+
}
|
|
8588
|
+
return params.explicitRootProjectId ?? (params.requireRemoteLane ? void 0 : localProjectId ?? params.fallbackProjectId ?? void 0);
|
|
8589
|
+
}
|
|
8581
8590
|
async function persistResolvedLane(repoRoot, binding) {
|
|
8582
8591
|
await writeCollabBinding(repoRoot, {
|
|
8583
8592
|
projectId: binding.projectId,
|
|
@@ -8656,7 +8665,14 @@ async function resolveActiveLaneBindingUncached(params, state) {
|
|
|
8656
8665
|
};
|
|
8657
8666
|
}
|
|
8658
8667
|
const laneResp2 = await params.api.resolveProjectLaneBinding({
|
|
8659
|
-
projectId:
|
|
8668
|
+
projectId: resolveLaneLookupProjectId({
|
|
8669
|
+
explicitRootProjectId: state.explicitRootBinding?.projectId,
|
|
8670
|
+
localBinding,
|
|
8671
|
+
currentBranch,
|
|
8672
|
+
defaultBranch: state.defaultBranch,
|
|
8673
|
+
requireRemoteLane,
|
|
8674
|
+
fallbackProjectId: state.projectId
|
|
8675
|
+
}),
|
|
8660
8676
|
repoFingerprint: state.repoFingerprint ?? void 0,
|
|
8661
8677
|
remoteUrl: state.remoteUrl ?? void 0,
|
|
8662
8678
|
defaultBranch: state.defaultBranch ?? void 0,
|
|
@@ -9507,6 +9523,59 @@ function buildWorkspaceMetadata(params) {
|
|
|
9507
9523
|
}
|
|
9508
9524
|
return metadata;
|
|
9509
9525
|
}
|
|
9526
|
+
async function findExistingChangeStepByIdempotency(params) {
|
|
9527
|
+
const idempotencyKey = params.idempotencyKey?.trim();
|
|
9528
|
+
if (!idempotencyKey) return null;
|
|
9529
|
+
const resp = await params.api.listChangeSteps(params.appId, { limit: 1, idempotencyKey });
|
|
9530
|
+
const responseObject = unwrapResponseObject(
|
|
9531
|
+
resp,
|
|
9532
|
+
"change step list"
|
|
9533
|
+
);
|
|
9534
|
+
const steps = Array.isArray(responseObject) ? responseObject : Array.isArray(responseObject.items) ? responseObject.items : [];
|
|
9535
|
+
return steps.find((step) => step.idempotencyKey === idempotencyKey) ?? null;
|
|
9536
|
+
}
|
|
9537
|
+
async function writeBaselineFromSucceededChangeStep(params) {
|
|
9538
|
+
const nextServerHeadHash = typeof params.changeStep.headCommitHash === "string" ? params.changeStep.headCommitHash.trim() : "";
|
|
9539
|
+
if (!nextServerHeadHash) {
|
|
9540
|
+
throw buildFinalizeCliError({
|
|
9541
|
+
message: "Backend returned a succeeded change step without a head commit hash.",
|
|
9542
|
+
exitCode: 1,
|
|
9543
|
+
hint: "This is a backend invariant violation; retry will not help. Run `remix collab status` before trying again.",
|
|
9544
|
+
disposition: "terminal",
|
|
9545
|
+
reason: "missing_head_commit_hash"
|
|
9546
|
+
});
|
|
9547
|
+
}
|
|
9548
|
+
let nextServerRevisionId = typeof params.changeStep.resultRevisionId === "string" ? params.changeStep.resultRevisionId.trim() : "";
|
|
9549
|
+
let nextServerTreeHash = null;
|
|
9550
|
+
if (!nextServerRevisionId) {
|
|
9551
|
+
const freshHeadResp = await params.api.getAppHead(params.job.currentAppId);
|
|
9552
|
+
const freshHead = unwrapResponseObject(freshHeadResp, "app head");
|
|
9553
|
+
if (freshHead.headCommitHash !== nextServerHeadHash || !freshHead.headRevisionId) {
|
|
9554
|
+
throw buildFinalizeCliError({
|
|
9555
|
+
message: "Backend returned a succeeded change step without a matching result revision.",
|
|
9556
|
+
exitCode: 1,
|
|
9557
|
+
hint: "The local baseline was not advanced because the post-step revision could not be verified. Restart the backend/CLI and retry after checking `remix collab status`.",
|
|
9558
|
+
disposition: "terminal",
|
|
9559
|
+
reason: "missing_result_revision_id"
|
|
9560
|
+
});
|
|
9561
|
+
}
|
|
9562
|
+
nextServerRevisionId = freshHead.headRevisionId;
|
|
9563
|
+
nextServerTreeHash = freshHead.treeHash ?? null;
|
|
9564
|
+
}
|
|
9565
|
+
await writeLocalBaseline({
|
|
9566
|
+
repoRoot: params.job.repoRoot,
|
|
9567
|
+
repoFingerprint: params.job.repoFingerprint,
|
|
9568
|
+
laneId: params.job.laneId,
|
|
9569
|
+
currentAppId: params.job.currentAppId,
|
|
9570
|
+
branchName: params.job.branchName,
|
|
9571
|
+
lastSnapshotId: params.snapshot.id,
|
|
9572
|
+
lastSnapshotHash: params.snapshot.snapshotHash,
|
|
9573
|
+
lastServerRevisionId: nextServerRevisionId,
|
|
9574
|
+
lastServerTreeHash: nextServerTreeHash,
|
|
9575
|
+
lastServerHeadHash: nextServerHeadHash,
|
|
9576
|
+
lastSeenLocalCommitHash: params.snapshot.localCommitHash
|
|
9577
|
+
});
|
|
9578
|
+
}
|
|
9510
9579
|
async function harvestPreTurnEvents(repoRoot, fromCommit, toCommit) {
|
|
9511
9580
|
if (!toCommit) return null;
|
|
9512
9581
|
try {
|
|
@@ -9692,6 +9761,34 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
9692
9761
|
});
|
|
9693
9762
|
}
|
|
9694
9763
|
const replayNeeded = appHead.headCommitHash !== submissionBaseHeadHash || baselineDrifted;
|
|
9764
|
+
if (replayNeeded) {
|
|
9765
|
+
const existingChangeStep = await findExistingChangeStepByIdempotency({
|
|
9766
|
+
api: params.api,
|
|
9767
|
+
appId: job.currentAppId,
|
|
9768
|
+
idempotencyKey: job.idempotencyKey
|
|
9769
|
+
});
|
|
9770
|
+
if (existingChangeStep) {
|
|
9771
|
+
const changeStep2 = existingChangeStep.status === "succeeded" ? existingChangeStep : await pollChangeStep(params.api, job.currentAppId, existingChangeStep.id);
|
|
9772
|
+
invalidateAppHeadCache(job.currentAppId);
|
|
9773
|
+
invalidateAppDeltaCacheForApp(job.currentAppId);
|
|
9774
|
+
await writeBaselineFromSucceededChangeStep({ api: params.api, job, snapshot, changeStep: changeStep2 });
|
|
9775
|
+
await updatePendingFinalizeJob(job.id, {
|
|
9776
|
+
status: "completed",
|
|
9777
|
+
metadata: { changeStepId: String(changeStep2.id ?? "") }
|
|
9778
|
+
});
|
|
9779
|
+
return {
|
|
9780
|
+
mode: "changed_turn",
|
|
9781
|
+
idempotencyKey: job.idempotencyKey ?? "",
|
|
9782
|
+
queued: false,
|
|
9783
|
+
jobId: job.id,
|
|
9784
|
+
repoState,
|
|
9785
|
+
changeStep: changeStep2,
|
|
9786
|
+
collabTurn: null,
|
|
9787
|
+
autoSync: null,
|
|
9788
|
+
warnings: []
|
|
9789
|
+
};
|
|
9790
|
+
}
|
|
9791
|
+
}
|
|
9695
9792
|
if (replayNeeded) {
|
|
9696
9793
|
try {
|
|
9697
9794
|
const replayResp = await params.api.startChangeStepReplay(job.currentAppId, {
|
|
@@ -9789,46 +9886,7 @@ async function processClaimedPendingFinalizeJobInner(params) {
|
|
|
9789
9886
|
const changeStep = await pollChangeStep(params.api, job.currentAppId, String(createdStep.id));
|
|
9790
9887
|
invalidateAppHeadCache(job.currentAppId);
|
|
9791
9888
|
invalidateAppDeltaCacheForApp(job.currentAppId);
|
|
9792
|
-
|
|
9793
|
-
if (!nextServerHeadHash) {
|
|
9794
|
-
throw buildFinalizeCliError({
|
|
9795
|
-
message: "Backend returned a succeeded change step without a head commit hash.",
|
|
9796
|
-
exitCode: 1,
|
|
9797
|
-
hint: "This is a backend invariant violation; retry will not help. Run `remix collab status` before trying again.",
|
|
9798
|
-
disposition: "terminal",
|
|
9799
|
-
reason: "missing_head_commit_hash"
|
|
9800
|
-
});
|
|
9801
|
-
}
|
|
9802
|
-
let nextServerRevisionId = typeof changeStep.resultRevisionId === "string" ? changeStep.resultRevisionId.trim() : "";
|
|
9803
|
-
let nextServerTreeHash = null;
|
|
9804
|
-
if (!nextServerRevisionId) {
|
|
9805
|
-
const freshHeadResp = await params.api.getAppHead(job.currentAppId);
|
|
9806
|
-
const freshHead = unwrapResponseObject(freshHeadResp, "app head");
|
|
9807
|
-
if (freshHead.headCommitHash !== nextServerHeadHash || !freshHead.headRevisionId) {
|
|
9808
|
-
throw buildFinalizeCliError({
|
|
9809
|
-
message: "Backend returned a succeeded change step without a matching result revision.",
|
|
9810
|
-
exitCode: 1,
|
|
9811
|
-
hint: "The local baseline was not advanced because the post-step revision could not be verified. Restart the backend/CLI and retry after checking `remix collab status`.",
|
|
9812
|
-
disposition: "terminal",
|
|
9813
|
-
reason: "missing_result_revision_id"
|
|
9814
|
-
});
|
|
9815
|
-
}
|
|
9816
|
-
nextServerRevisionId = freshHead.headRevisionId;
|
|
9817
|
-
nextServerTreeHash = freshHead.treeHash ?? null;
|
|
9818
|
-
}
|
|
9819
|
-
await writeLocalBaseline({
|
|
9820
|
-
repoRoot: job.repoRoot,
|
|
9821
|
-
repoFingerprint: job.repoFingerprint,
|
|
9822
|
-
laneId: job.laneId,
|
|
9823
|
-
currentAppId: job.currentAppId,
|
|
9824
|
-
branchName: job.branchName,
|
|
9825
|
-
lastSnapshotId: snapshot.id,
|
|
9826
|
-
lastSnapshotHash: snapshot.snapshotHash,
|
|
9827
|
-
lastServerRevisionId: nextServerRevisionId,
|
|
9828
|
-
lastServerTreeHash: nextServerTreeHash,
|
|
9829
|
-
lastServerHeadHash: nextServerHeadHash,
|
|
9830
|
-
lastSeenLocalCommitHash: snapshot.localCommitHash
|
|
9831
|
-
});
|
|
9889
|
+
await writeBaselineFromSucceededChangeStep({ api: params.api, job, snapshot, changeStep });
|
|
9832
9890
|
await updatePendingFinalizeJob(job.id, {
|
|
9833
9891
|
status: "completed",
|
|
9834
9892
|
metadata: { changeStepId: String(changeStep.id ?? "") }
|
|
@@ -10113,8 +10171,10 @@ function isFinalizePreflightFailureCode(value) {
|
|
|
10113
10171
|
|
|
10114
10172
|
// src/auto-fix-dispatcher.ts
|
|
10115
10173
|
var import_node_child_process6 = require("child_process");
|
|
10174
|
+
var import_node_crypto4 = require("crypto");
|
|
10116
10175
|
var import_node_fs6 = require("fs");
|
|
10117
|
-
var
|
|
10176
|
+
var import_node_os7 = __toESM(require("os"), 1);
|
|
10177
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
10118
10178
|
|
|
10119
10179
|
// src/finalize-failure-marker.ts
|
|
10120
10180
|
var import_promises18 = __toESM(require("fs/promises"), 1);
|
|
@@ -10153,32 +10213,47 @@ function buildFreshFailureMarker(params) {
|
|
|
10153
10213
|
};
|
|
10154
10214
|
}
|
|
10155
10215
|
|
|
10216
|
+
// src/collab-init-spawn-lock.ts
|
|
10217
|
+
var import_node_crypto = require("crypto");
|
|
10218
|
+
var import_node_os4 = __toESM(require("os"), 1);
|
|
10219
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
10220
|
+
function stateRoot() {
|
|
10221
|
+
const configured = process.env.REMIX_CLAUDE_PLUGIN_HOOK_STATE_ROOT?.trim();
|
|
10222
|
+
return configured || import_node_path7.default.join(import_node_os4.default.tmpdir(), "remix-claude-plugin-hooks");
|
|
10223
|
+
}
|
|
10224
|
+
function sha256Hex3(value) {
|
|
10225
|
+
return (0, import_node_crypto.createHash)("sha256").update(value).digest("hex");
|
|
10226
|
+
}
|
|
10227
|
+
function collabInitSpawnLockPath(repoRoot) {
|
|
10228
|
+
return import_node_path7.default.join(stateRoot(), "collab-init-spawn-locks", `${sha256Hex3(repoRoot)}.json`);
|
|
10229
|
+
}
|
|
10230
|
+
|
|
10156
10231
|
// src/hook-diagnostics.ts
|
|
10157
|
-
var
|
|
10232
|
+
var import_node_crypto3 = require("crypto");
|
|
10158
10233
|
var import_promises20 = __toESM(require("fs/promises"), 1);
|
|
10159
|
-
var
|
|
10160
|
-
var
|
|
10234
|
+
var import_node_os6 = __toESM(require("os"), 1);
|
|
10235
|
+
var import_node_path9 = __toESM(require("path"), 1);
|
|
10161
10236
|
|
|
10162
10237
|
// src/hook-state.ts
|
|
10163
10238
|
var import_promises19 = __toESM(require("fs/promises"), 1);
|
|
10164
|
-
var
|
|
10165
|
-
var
|
|
10166
|
-
var
|
|
10167
|
-
function
|
|
10239
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
10240
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
10241
|
+
var import_node_crypto2 = require("crypto");
|
|
10242
|
+
function stateRoot2() {
|
|
10168
10243
|
const configured = process.env.REMIX_CLAUDE_PLUGIN_HOOK_STATE_ROOT?.trim();
|
|
10169
|
-
return configured ||
|
|
10244
|
+
return configured || import_node_path8.default.join(import_node_os5.default.tmpdir(), "remix-claude-plugin-hooks");
|
|
10170
10245
|
}
|
|
10171
10246
|
function statePath(sessionId) {
|
|
10172
|
-
return
|
|
10247
|
+
return import_node_path8.default.join(stateRoot2(), `${sessionId}.json`);
|
|
10173
10248
|
}
|
|
10174
10249
|
function stateLockPath(sessionId) {
|
|
10175
|
-
return
|
|
10250
|
+
return import_node_path8.default.join(stateRoot2(), `${sessionId}.lock`);
|
|
10176
10251
|
}
|
|
10177
10252
|
function stateLockMetaPath(sessionId) {
|
|
10178
|
-
return
|
|
10253
|
+
return import_node_path8.default.join(stateLockPath(sessionId), "owner.json");
|
|
10179
10254
|
}
|
|
10180
10255
|
async function writeJsonAtomic2(filePath, value) {
|
|
10181
|
-
await import_promises19.default.mkdir(
|
|
10256
|
+
await import_promises19.default.mkdir(import_node_path8.default.dirname(filePath), { recursive: true });
|
|
10182
10257
|
const tmpPath = `${filePath}.tmp-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
10183
10258
|
await import_promises19.default.writeFile(tmpPath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
10184
10259
|
await import_promises19.default.rename(tmpPath, filePath);
|
|
@@ -10231,11 +10306,11 @@ async function tryRemoveStaleStateLock(sessionId) {
|
|
|
10231
10306
|
async function acquireStateLock(sessionId) {
|
|
10232
10307
|
const lockPath = stateLockPath(sessionId);
|
|
10233
10308
|
const deadline = Date.now() + STATE_LOCK_WAIT_MS;
|
|
10234
|
-
await import_promises19.default.mkdir(
|
|
10309
|
+
await import_promises19.default.mkdir(stateRoot2(), { recursive: true });
|
|
10235
10310
|
while (true) {
|
|
10236
10311
|
try {
|
|
10237
10312
|
await import_promises19.default.mkdir(lockPath);
|
|
10238
|
-
const ownerId = (0,
|
|
10313
|
+
const ownerId = (0, import_node_crypto2.randomUUID)();
|
|
10239
10314
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10240
10315
|
const metadata = {
|
|
10241
10316
|
ownerId,
|
|
@@ -10466,7 +10541,7 @@ async function markTouchedRepoRecordingFailure(sessionId, repoRoot, params) {
|
|
|
10466
10541
|
});
|
|
10467
10542
|
}
|
|
10468
10543
|
function lastFinalizedPath(sessionId) {
|
|
10469
|
-
return
|
|
10544
|
+
return import_node_path8.default.join(stateRoot2(), `${sessionId}.last-finalized.json`);
|
|
10470
10545
|
}
|
|
10471
10546
|
async function markLastFinalizedTurn(sessionId, turnId, prompt) {
|
|
10472
10547
|
const record = {
|
|
@@ -10516,7 +10591,7 @@ async function clearPendingTurnState(sessionId) {
|
|
|
10516
10591
|
// package.json
|
|
10517
10592
|
var package_default = {
|
|
10518
10593
|
name: "@remixhq/claude-plugin",
|
|
10519
|
-
version: "0.1.
|
|
10594
|
+
version: "0.1.25",
|
|
10520
10595
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
10521
10596
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
10522
10597
|
license: "MIT",
|
|
@@ -10554,8 +10629,8 @@ var package_default = {
|
|
|
10554
10629
|
prepack: "npm run build"
|
|
10555
10630
|
},
|
|
10556
10631
|
dependencies: {
|
|
10557
|
-
"@remixhq/core": "^0.1.
|
|
10558
|
-
"@remixhq/mcp": "^0.1.
|
|
10632
|
+
"@remixhq/core": "^0.1.20",
|
|
10633
|
+
"@remixhq/mcp": "^0.1.20"
|
|
10559
10634
|
},
|
|
10560
10635
|
devDependencies: {
|
|
10561
10636
|
"@types/node": "^25.4.0",
|
|
@@ -10578,17 +10653,17 @@ var pluginMetadata = {
|
|
|
10578
10653
|
var MAX_LOG_BYTES = 512 * 1024;
|
|
10579
10654
|
function resolveClaudeRoot() {
|
|
10580
10655
|
const configured = process.env.CLAUDE_CONFIG_DIR?.trim();
|
|
10581
|
-
return configured ||
|
|
10656
|
+
return configured || import_node_path9.default.join(import_node_os6.default.homedir(), ".claude");
|
|
10582
10657
|
}
|
|
10583
10658
|
function resolvePluginDataDirName() {
|
|
10584
10659
|
return `${pluginMetadata.pluginId}-${pluginMetadata.pluginId}`;
|
|
10585
10660
|
}
|
|
10586
10661
|
function getHookDiagnosticsDirPath() {
|
|
10587
10662
|
const configured = process.env.REMIX_CLAUDE_PLUGIN_HOOK_DIAGNOSTICS_DIR?.trim();
|
|
10588
|
-
return configured ||
|
|
10663
|
+
return configured || import_node_path9.default.join(resolveClaudeRoot(), "plugins", "data", resolvePluginDataDirName());
|
|
10589
10664
|
}
|
|
10590
10665
|
function getHookDiagnosticsLogPath() {
|
|
10591
|
-
return
|
|
10666
|
+
return import_node_path9.default.join(getHookDiagnosticsDirPath(), "hooks.ndjson");
|
|
10592
10667
|
}
|
|
10593
10668
|
function toFieldValue(value) {
|
|
10594
10669
|
if (value === null) return null;
|
|
@@ -10626,13 +10701,13 @@ function summarizeText(value) {
|
|
|
10626
10701
|
return {
|
|
10627
10702
|
present: true,
|
|
10628
10703
|
length: trimmed.length,
|
|
10629
|
-
sha256Prefix: (0,
|
|
10704
|
+
sha256Prefix: (0, import_node_crypto3.createHash)("sha256").update(trimmed).digest("hex").slice(0, 12)
|
|
10630
10705
|
};
|
|
10631
10706
|
}
|
|
10632
10707
|
async function appendHookDiagnosticsEvent(params) {
|
|
10633
10708
|
try {
|
|
10634
10709
|
const logPath = getHookDiagnosticsLogPath();
|
|
10635
|
-
await import_promises20.default.mkdir(
|
|
10710
|
+
await import_promises20.default.mkdir(import_node_path9.default.dirname(logPath), { recursive: true });
|
|
10636
10711
|
await rotateLogIfNeeded(logPath);
|
|
10637
10712
|
const event = {
|
|
10638
10713
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10682,18 +10757,27 @@ var RECOMMENDED_USER_COMMAND = {
|
|
|
10682
10757
|
pull_required: "remix collab sync",
|
|
10683
10758
|
baseline_missing: "remix collab init"
|
|
10684
10759
|
};
|
|
10685
|
-
var SPAWN_LOCK_REL = (cmdSlug) => import_node_path9.default.join(".remix", `.${cmdSlug}-spawning`);
|
|
10686
|
-
var SPAWN_LOG_REL = (cmdSlug) => import_node_path9.default.join(".remix", `${cmdSlug}.log`);
|
|
10687
10760
|
var SPAWN_THROTTLE_MS = 5 * 60 * 1e3;
|
|
10688
10761
|
function commandSlug(args) {
|
|
10689
10762
|
return args.join("-").replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
10690
10763
|
}
|
|
10764
|
+
function stateRoot3() {
|
|
10765
|
+
const configured = process.env.REMIX_CLAUDE_PLUGIN_HOOK_STATE_ROOT?.trim();
|
|
10766
|
+
return configured || import_node_path10.default.join(import_node_os7.default.tmpdir(), "remix-claude-plugin-hooks");
|
|
10767
|
+
}
|
|
10768
|
+
function sha256Hex4(value) {
|
|
10769
|
+
return (0, import_node_crypto4.createHash)("sha256").update(value).digest("hex");
|
|
10770
|
+
}
|
|
10771
|
+
function spawnLockPath(repoRoot, cmdSlug) {
|
|
10772
|
+
if (cmdSlug === "collab-init") {
|
|
10773
|
+
return collabInitSpawnLockPath(repoRoot);
|
|
10774
|
+
}
|
|
10775
|
+
return import_node_path10.default.join(stateRoot3(), "auto-fix-spawn-locks", sha256Hex4(repoRoot), `${cmdSlug}.lock`);
|
|
10776
|
+
}
|
|
10691
10777
|
function spawnFixDetached(repoRoot, args) {
|
|
10692
10778
|
const slug = commandSlug(args);
|
|
10693
10779
|
const command = `remix ${args.join(" ")}`;
|
|
10694
|
-
const
|
|
10695
|
-
const lockPath = import_node_path9.default.join(repoRoot, SPAWN_LOCK_REL(slug));
|
|
10696
|
-
const logPath = import_node_path9.default.join(repoRoot, SPAWN_LOG_REL(slug));
|
|
10780
|
+
const lockPath = spawnLockPath(repoRoot, slug);
|
|
10697
10781
|
try {
|
|
10698
10782
|
if ((0, import_node_fs6.existsSync)(lockPath)) {
|
|
10699
10783
|
const ageMs = Date.now() - (0, import_node_fs6.statSync)(lockPath).mtimeMs;
|
|
@@ -10704,27 +10788,14 @@ function spawnFixDetached(repoRoot, args) {
|
|
|
10704
10788
|
} catch {
|
|
10705
10789
|
}
|
|
10706
10790
|
try {
|
|
10707
|
-
(0, import_node_fs6.mkdirSync)(
|
|
10791
|
+
(0, import_node_fs6.mkdirSync)(import_node_path10.default.dirname(lockPath), { recursive: true });
|
|
10708
10792
|
} catch {
|
|
10709
10793
|
}
|
|
10710
|
-
let out;
|
|
10711
|
-
let err;
|
|
10712
|
-
try {
|
|
10713
|
-
out = (0, import_node_fs6.openSync)(logPath, "a");
|
|
10714
|
-
err = (0, import_node_fs6.openSync)(logPath, "a");
|
|
10715
|
-
} catch (logErr) {
|
|
10716
|
-
return {
|
|
10717
|
-
kind: "spawn_failed",
|
|
10718
|
-
command,
|
|
10719
|
-
reason: "log_open_failed",
|
|
10720
|
-
message: logErr instanceof Error ? logErr.message : String(logErr)
|
|
10721
|
-
};
|
|
10722
|
-
}
|
|
10723
10794
|
try {
|
|
10724
10795
|
const child = (0, import_node_child_process6.spawn)("remix", [...args], {
|
|
10725
10796
|
cwd: repoRoot,
|
|
10726
10797
|
detached: true,
|
|
10727
|
-
stdio:
|
|
10798
|
+
stdio: "ignore",
|
|
10728
10799
|
env: { ...process.env, REMIX_AUTO_FIX_SPAWN: "1" }
|
|
10729
10800
|
});
|
|
10730
10801
|
child.unref();
|
|
@@ -10733,7 +10804,7 @@ function spawnFixDetached(repoRoot, args) {
|
|
|
10733
10804
|
(0, import_node_fs6.utimesSync)(lockPath, /* @__PURE__ */ new Date(), /* @__PURE__ */ new Date());
|
|
10734
10805
|
} catch {
|
|
10735
10806
|
}
|
|
10736
|
-
return { kind: "spawned", command, pid: child.pid
|
|
10807
|
+
return { kind: "spawned", command, pid: child.pid };
|
|
10737
10808
|
} catch (spawnErr) {
|
|
10738
10809
|
return {
|
|
10739
10810
|
kind: "spawn_failed",
|
|
@@ -10789,7 +10860,6 @@ async function dispatchFinalizeFailure(input) {
|
|
|
10789
10860
|
preflightCode: input.preflightCode,
|
|
10790
10861
|
command: "command" in outcome ? outcome.command : null,
|
|
10791
10862
|
pid: outcome.kind === "spawned" ? outcome.pid ?? null : null,
|
|
10792
|
-
logPath: outcome.kind === "spawned" ? outcome.logPath : null,
|
|
10793
10863
|
recommendedCommand
|
|
10794
10864
|
},
|
|
10795
10865
|
message: outcome.kind === "spawn_failed" ? outcome.message : null
|
|
@@ -10802,7 +10872,7 @@ function mergeOutcomeIntoMarker(existing, outcome) {
|
|
|
10802
10872
|
status: "in_progress",
|
|
10803
10873
|
command: outcome.command,
|
|
10804
10874
|
pid: outcome.pid ?? null,
|
|
10805
|
-
logPath:
|
|
10875
|
+
logPath: null,
|
|
10806
10876
|
attemptedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10807
10877
|
failureMessage: null
|
|
10808
10878
|
};
|
|
@@ -10832,25 +10902,25 @@ function mergeOutcomeIntoMarker(existing, outcome) {
|
|
|
10832
10902
|
|
|
10833
10903
|
// src/deferred-turn-queue.ts
|
|
10834
10904
|
var import_promises21 = __toESM(require("fs/promises"), 1);
|
|
10835
|
-
var
|
|
10836
|
-
var
|
|
10905
|
+
var import_node_os8 = __toESM(require("os"), 1);
|
|
10906
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
10837
10907
|
var DEFERRED_TURN_SCHEMA_VERSION = 1;
|
|
10838
10908
|
var DEFERRED_TURN_MAX_ATTEMPTS = 10;
|
|
10839
10909
|
var DEFERRED_TURN_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
10840
10910
|
var DEFERRED_TURN_DIR = "deferred-turns";
|
|
10841
|
-
function
|
|
10911
|
+
function stateRoot4() {
|
|
10842
10912
|
const configured = process.env.REMIX_CLAUDE_PLUGIN_HOOK_STATE_ROOT?.trim();
|
|
10843
|
-
return configured ||
|
|
10913
|
+
return configured || import_node_path11.default.join(import_node_os8.default.tmpdir(), "remix-claude-plugin-hooks");
|
|
10844
10914
|
}
|
|
10845
10915
|
function getDeferredTurnDirPath() {
|
|
10846
|
-
return
|
|
10916
|
+
return import_node_path11.default.join(stateRoot4(), DEFERRED_TURN_DIR);
|
|
10847
10917
|
}
|
|
10848
10918
|
function deferredTurnFileName(sessionId, turnId) {
|
|
10849
10919
|
const safe = (s) => s.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
10850
10920
|
return `${safe(sessionId)}-${safe(turnId)}.json`;
|
|
10851
10921
|
}
|
|
10852
10922
|
function getDeferredTurnFilePath(sessionId, turnId) {
|
|
10853
|
-
return
|
|
10923
|
+
return import_node_path11.default.join(getDeferredTurnDirPath(), deferredTurnFileName(sessionId, turnId));
|
|
10854
10924
|
}
|
|
10855
10925
|
async function writeDeferredTurn(record) {
|
|
10856
10926
|
if (record.schemaVersion !== DEFERRED_TURN_SCHEMA_VERSION) {
|
|
@@ -10911,7 +10981,7 @@ async function listDeferredTurnsForRepo(repoRoot) {
|
|
|
10911
10981
|
const entries = [];
|
|
10912
10982
|
for (const entry of dirEntries) {
|
|
10913
10983
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
10914
|
-
const filePath =
|
|
10984
|
+
const filePath = import_node_path11.default.join(dir, entry.name);
|
|
10915
10985
|
const record = await readDeferredTurnFile(filePath);
|
|
10916
10986
|
if (!record) continue;
|
|
10917
10987
|
if (record.repoRoot !== repoRoot) continue;
|
|
@@ -10935,7 +11005,7 @@ async function pruneStaleDeferredTurns(maxAgeMs = DEFERRED_TURN_TTL_MS) {
|
|
|
10935
11005
|
const now = Date.now();
|
|
10936
11006
|
for (const entry of dirEntries) {
|
|
10937
11007
|
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
10938
|
-
const filePath =
|
|
11008
|
+
const filePath = import_node_path11.default.join(dir, entry.name);
|
|
10939
11009
|
const record = await readDeferredTurnFile(filePath);
|
|
10940
11010
|
if (!record) {
|
|
10941
11011
|
const stat = await import_promises21.default.stat(filePath).catch(() => null);
|
|
@@ -10990,10 +11060,10 @@ async function recordDeferredTurnFailedAttempt(filePath) {
|
|
|
10990
11060
|
|
|
10991
11061
|
// src/deferred-turn-drainer.ts
|
|
10992
11062
|
var import_promises23 = __toESM(require("fs/promises"), 1);
|
|
10993
|
-
var
|
|
10994
|
-
var
|
|
11063
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
11064
|
+
var import_node_crypto5 = require("crypto");
|
|
10995
11065
|
|
|
10996
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
11066
|
+
// node_modules/@remixhq/core/dist/chunk-C2FOZ3O7.js
|
|
10997
11067
|
async function readJsonSafe(res) {
|
|
10998
11068
|
const ct = res.headers.get("content-type") ?? "";
|
|
10999
11069
|
if (!ct.toLowerCase().includes("application/json")) return null;
|
|
@@ -11012,7 +11082,7 @@ function createApiClient(config, opts) {
|
|
|
11012
11082
|
const ms = typeof timeoutMs === "number" && timeoutMs > 0 ? timeoutMs : defaultTimeoutMs;
|
|
11013
11083
|
return ms != null ? AbortSignal.timeout(ms) : void 0;
|
|
11014
11084
|
}
|
|
11015
|
-
async function request(
|
|
11085
|
+
async function request(path17, init, opts2) {
|
|
11016
11086
|
if (!tokenProvider) {
|
|
11017
11087
|
throw new RemixError("API client is missing a token provider.", {
|
|
11018
11088
|
exitCode: 1,
|
|
@@ -11020,7 +11090,7 @@ function createApiClient(config, opts) {
|
|
|
11020
11090
|
});
|
|
11021
11091
|
}
|
|
11022
11092
|
const auth = await tokenProvider();
|
|
11023
|
-
const url = new URL(
|
|
11093
|
+
const url = new URL(path17, config.apiUrl).toString();
|
|
11024
11094
|
const doFetch = async (bearer) => fetch(url, {
|
|
11025
11095
|
...init,
|
|
11026
11096
|
signal: makeTimeoutSignal(opts2?.timeoutMs),
|
|
@@ -11049,7 +11119,7 @@ function createApiClient(config, opts) {
|
|
|
11049
11119
|
const json = await readJsonSafe(res);
|
|
11050
11120
|
return json ?? null;
|
|
11051
11121
|
}
|
|
11052
|
-
async function requestBinary(
|
|
11122
|
+
async function requestBinary(path17, init, opts2) {
|
|
11053
11123
|
if (!tokenProvider) {
|
|
11054
11124
|
throw new RemixError("API client is missing a token provider.", {
|
|
11055
11125
|
exitCode: 1,
|
|
@@ -11057,7 +11127,7 @@ function createApiClient(config, opts) {
|
|
|
11057
11127
|
});
|
|
11058
11128
|
}
|
|
11059
11129
|
const auth = await tokenProvider();
|
|
11060
|
-
const url = new URL(
|
|
11130
|
+
const url = new URL(path17, config.apiUrl).toString();
|
|
11061
11131
|
const doFetch = async (bearer) => fetch(url, {
|
|
11062
11132
|
...init,
|
|
11063
11133
|
signal: makeTimeoutSignal(opts2?.timeoutMs),
|
|
@@ -11187,6 +11257,14 @@ function createApiClient(config, opts) {
|
|
|
11187
11257
|
method: "POST",
|
|
11188
11258
|
body: JSON.stringify(payload)
|
|
11189
11259
|
}),
|
|
11260
|
+
listChangeSteps: (appId, params) => {
|
|
11261
|
+
const qs = new URLSearchParams();
|
|
11262
|
+
if (params?.limit !== void 0) qs.set("limit", String(params.limit));
|
|
11263
|
+
if (params?.offset !== void 0) qs.set("offset", String(params.offset));
|
|
11264
|
+
if (params?.idempotencyKey) qs.set("idempotencyKey", params.idempotencyKey);
|
|
11265
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
11266
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/change-steps${suffix}`, { method: "GET" });
|
|
11267
|
+
},
|
|
11190
11268
|
createCollabTurn: (appId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/collab-turns`, {
|
|
11191
11269
|
method: "POST",
|
|
11192
11270
|
body: JSON.stringify(payload)
|
|
@@ -11912,8 +11990,8 @@ function getErrorMap() {
|
|
|
11912
11990
|
|
|
11913
11991
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
11914
11992
|
var makeIssue = (params) => {
|
|
11915
|
-
const { data, path:
|
|
11916
|
-
const fullPath = [...
|
|
11993
|
+
const { data, path: path17, errorMaps, issueData } = params;
|
|
11994
|
+
const fullPath = [...path17, ...issueData.path || []];
|
|
11917
11995
|
const fullIssue = {
|
|
11918
11996
|
...issueData,
|
|
11919
11997
|
path: fullPath
|
|
@@ -12029,11 +12107,11 @@ var errorUtil;
|
|
|
12029
12107
|
|
|
12030
12108
|
// node_modules/zod/v3/types.js
|
|
12031
12109
|
var ParseInputLazyPath = class {
|
|
12032
|
-
constructor(parent, value,
|
|
12110
|
+
constructor(parent, value, path17, key) {
|
|
12033
12111
|
this._cachedPath = [];
|
|
12034
12112
|
this.parent = parent;
|
|
12035
12113
|
this.data = value;
|
|
12036
|
-
this._path =
|
|
12114
|
+
this._path = path17;
|
|
12037
12115
|
this._key = key;
|
|
12038
12116
|
}
|
|
12039
12117
|
get path() {
|
|
@@ -24581,8 +24659,8 @@ var IcebergError = class extends Error {
|
|
|
24581
24659
|
return this.status === 419;
|
|
24582
24660
|
}
|
|
24583
24661
|
};
|
|
24584
|
-
function buildUrl(baseUrl,
|
|
24585
|
-
const url = new URL(
|
|
24662
|
+
function buildUrl(baseUrl, path17, query) {
|
|
24663
|
+
const url = new URL(path17, baseUrl);
|
|
24586
24664
|
if (query) {
|
|
24587
24665
|
for (const [key, value] of Object.entries(query)) {
|
|
24588
24666
|
if (value !== void 0) {
|
|
@@ -24612,12 +24690,12 @@ function createFetchClient(options) {
|
|
|
24612
24690
|
return {
|
|
24613
24691
|
async request({
|
|
24614
24692
|
method,
|
|
24615
|
-
path:
|
|
24693
|
+
path: path17,
|
|
24616
24694
|
query,
|
|
24617
24695
|
body,
|
|
24618
24696
|
headers
|
|
24619
24697
|
}) {
|
|
24620
|
-
const url = buildUrl(options.baseUrl,
|
|
24698
|
+
const url = buildUrl(options.baseUrl, path17, query);
|
|
24621
24699
|
const authHeaders = await buildAuthHeaders(options.auth);
|
|
24622
24700
|
const res = await fetchFn(url, {
|
|
24623
24701
|
method,
|
|
@@ -25455,7 +25533,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
25455
25533
|
* @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.
|
|
25456
25534
|
* @param fileBody The body of the file to be stored in the bucket.
|
|
25457
25535
|
*/
|
|
25458
|
-
async uploadOrUpdate(method,
|
|
25536
|
+
async uploadOrUpdate(method, path17, fileBody, fileOptions) {
|
|
25459
25537
|
var _this = this;
|
|
25460
25538
|
return _this.handleOperation(async () => {
|
|
25461
25539
|
let body;
|
|
@@ -25479,7 +25557,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
25479
25557
|
if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
|
|
25480
25558
|
}
|
|
25481
25559
|
if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) for (const [key, value] of Object.entries(fileOptions.headers)) headers = setHeader(headers, key, value);
|
|
25482
|
-
const cleanPath = _this._removeEmptyFolders(
|
|
25560
|
+
const cleanPath = _this._removeEmptyFolders(path17);
|
|
25483
25561
|
const _path = _this._getFinalPath(cleanPath);
|
|
25484
25562
|
const data = await (method == "PUT" ? put : post)(_this.fetch, `${_this.url}/object/${_path}`, body, _objectSpread22({ headers }, (options === null || options === void 0 ? void 0 : options.duplex) ? { duplex: options.duplex } : {}));
|
|
25485
25563
|
return {
|
|
@@ -25540,8 +25618,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
25540
25618
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
25541
25619
|
* - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Upload file using `ArrayBuffer` from base64 file data instead, see example below.
|
|
25542
25620
|
*/
|
|
25543
|
-
async upload(
|
|
25544
|
-
return this.uploadOrUpdate("POST",
|
|
25621
|
+
async upload(path17, fileBody, fileOptions) {
|
|
25622
|
+
return this.uploadOrUpdate("POST", path17, fileBody, fileOptions);
|
|
25545
25623
|
}
|
|
25546
25624
|
/**
|
|
25547
25625
|
* Upload a file with a token generated from `createSignedUploadUrl`.
|
|
@@ -25580,9 +25658,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
25580
25658
|
* - `objects` table permissions: none
|
|
25581
25659
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
25582
25660
|
*/
|
|
25583
|
-
async uploadToSignedUrl(
|
|
25661
|
+
async uploadToSignedUrl(path17, token, fileBody, fileOptions) {
|
|
25584
25662
|
var _this3 = this;
|
|
25585
|
-
const cleanPath = _this3._removeEmptyFolders(
|
|
25663
|
+
const cleanPath = _this3._removeEmptyFolders(path17);
|
|
25586
25664
|
const _path = _this3._getFinalPath(cleanPath);
|
|
25587
25665
|
const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
|
|
25588
25666
|
url.searchParams.set("token", token);
|
|
@@ -25644,10 +25722,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
25644
25722
|
* - `objects` table permissions: `insert`
|
|
25645
25723
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
25646
25724
|
*/
|
|
25647
|
-
async createSignedUploadUrl(
|
|
25725
|
+
async createSignedUploadUrl(path17, options) {
|
|
25648
25726
|
var _this4 = this;
|
|
25649
25727
|
return _this4.handleOperation(async () => {
|
|
25650
|
-
let _path = _this4._getFinalPath(
|
|
25728
|
+
let _path = _this4._getFinalPath(path17);
|
|
25651
25729
|
const headers = _objectSpread22({}, _this4.headers);
|
|
25652
25730
|
if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
|
|
25653
25731
|
const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
|
|
@@ -25656,7 +25734,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
25656
25734
|
if (!token) throw new StorageError("No token returned by API");
|
|
25657
25735
|
return {
|
|
25658
25736
|
signedUrl: url.toString(),
|
|
25659
|
-
path:
|
|
25737
|
+
path: path17,
|
|
25660
25738
|
token
|
|
25661
25739
|
};
|
|
25662
25740
|
});
|
|
@@ -25712,8 +25790,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
25712
25790
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
25713
25791
|
* - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Update file using `ArrayBuffer` from base64 file data instead, see example below.
|
|
25714
25792
|
*/
|
|
25715
|
-
async update(
|
|
25716
|
-
return this.uploadOrUpdate("PUT",
|
|
25793
|
+
async update(path17, fileBody, fileOptions) {
|
|
25794
|
+
return this.uploadOrUpdate("PUT", path17, fileBody, fileOptions);
|
|
25717
25795
|
}
|
|
25718
25796
|
/**
|
|
25719
25797
|
* Moves an existing file to a new path in the same bucket.
|
|
@@ -25861,10 +25939,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
25861
25939
|
* - `objects` table permissions: `select`
|
|
25862
25940
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
25863
25941
|
*/
|
|
25864
|
-
async createSignedUrl(
|
|
25942
|
+
async createSignedUrl(path17, expiresIn, options) {
|
|
25865
25943
|
var _this8 = this;
|
|
25866
25944
|
return _this8.handleOperation(async () => {
|
|
25867
|
-
let _path = _this8._getFinalPath(
|
|
25945
|
+
let _path = _this8._getFinalPath(path17);
|
|
25868
25946
|
const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
|
|
25869
25947
|
let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
|
|
25870
25948
|
const query = new URLSearchParams();
|
|
@@ -25998,13 +26076,13 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
25998
26076
|
* - `objects` table permissions: `select`
|
|
25999
26077
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
26000
26078
|
*/
|
|
26001
|
-
download(
|
|
26079
|
+
download(path17, options, parameters) {
|
|
26002
26080
|
const renderPath = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0 ? "render/image/authenticated" : "object";
|
|
26003
26081
|
const query = new URLSearchParams();
|
|
26004
26082
|
if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
|
|
26005
26083
|
if ((options === null || options === void 0 ? void 0 : options.cacheNonce) != null) query.set("cacheNonce", String(options.cacheNonce));
|
|
26006
26084
|
const queryString = query.toString();
|
|
26007
|
-
const _path = this._getFinalPath(
|
|
26085
|
+
const _path = this._getFinalPath(path17);
|
|
26008
26086
|
const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ""}`, {
|
|
26009
26087
|
headers: this.headers,
|
|
26010
26088
|
noResolveJson: true
|
|
@@ -26034,9 +26112,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
26034
26112
|
* }
|
|
26035
26113
|
* ```
|
|
26036
26114
|
*/
|
|
26037
|
-
async info(
|
|
26115
|
+
async info(path17) {
|
|
26038
26116
|
var _this10 = this;
|
|
26039
|
-
const _path = _this10._getFinalPath(
|
|
26117
|
+
const _path = _this10._getFinalPath(path17);
|
|
26040
26118
|
return _this10.handleOperation(async () => {
|
|
26041
26119
|
return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
|
|
26042
26120
|
});
|
|
@@ -26056,9 +26134,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
26056
26134
|
* .exists('folder/avatar1.png')
|
|
26057
26135
|
* ```
|
|
26058
26136
|
*/
|
|
26059
|
-
async exists(
|
|
26137
|
+
async exists(path17) {
|
|
26060
26138
|
var _this11 = this;
|
|
26061
|
-
const _path = _this11._getFinalPath(
|
|
26139
|
+
const _path = _this11._getFinalPath(path17);
|
|
26062
26140
|
try {
|
|
26063
26141
|
await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
|
|
26064
26142
|
return {
|
|
@@ -26136,8 +26214,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
26136
26214
|
* - `objects` table permissions: none
|
|
26137
26215
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
26138
26216
|
*/
|
|
26139
|
-
getPublicUrl(
|
|
26140
|
-
const _path = this._getFinalPath(
|
|
26217
|
+
getPublicUrl(path17, options) {
|
|
26218
|
+
const _path = this._getFinalPath(path17);
|
|
26141
26219
|
const query = new URLSearchParams();
|
|
26142
26220
|
if (options === null || options === void 0 ? void 0 : options.download) query.set("download", options.download === true ? "" : options.download);
|
|
26143
26221
|
if (options === null || options === void 0 ? void 0 : options.transform) this.applyTransformOptsToQuery(query, options.transform);
|
|
@@ -26274,10 +26352,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
26274
26352
|
* - `objects` table permissions: `select`
|
|
26275
26353
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
26276
26354
|
*/
|
|
26277
|
-
async list(
|
|
26355
|
+
async list(path17, options, parameters) {
|
|
26278
26356
|
var _this13 = this;
|
|
26279
26357
|
return _this13.handleOperation(async () => {
|
|
26280
|
-
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix:
|
|
26358
|
+
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path17 || "" });
|
|
26281
26359
|
return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
|
|
26282
26360
|
});
|
|
26283
26361
|
}
|
|
@@ -26341,11 +26419,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
26341
26419
|
if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
|
|
26342
26420
|
return btoa(data);
|
|
26343
26421
|
}
|
|
26344
|
-
_getFinalPath(
|
|
26345
|
-
return `${this.bucketId}/${
|
|
26422
|
+
_getFinalPath(path17) {
|
|
26423
|
+
return `${this.bucketId}/${path17.replace(/^\/+/, "")}`;
|
|
26346
26424
|
}
|
|
26347
|
-
_removeEmptyFolders(
|
|
26348
|
-
return
|
|
26425
|
+
_removeEmptyFolders(path17) {
|
|
26426
|
+
return path17.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
|
|
26349
26427
|
}
|
|
26350
26428
|
/** Modifies the `query`, appending values the from `transform` */
|
|
26351
26429
|
applyTransformOptsToQuery(query, transform) {
|
|
@@ -35723,11 +35801,11 @@ function isPidAlive(pid) {
|
|
|
35723
35801
|
}
|
|
35724
35802
|
}
|
|
35725
35803
|
function repoLockFileName(repoRoot) {
|
|
35726
|
-
const hash = (0,
|
|
35804
|
+
const hash = (0, import_node_crypto5.createHash)("sha256").update(repoRoot).digest("hex").slice(0, 16);
|
|
35727
35805
|
return `.drainer-${hash}.lock`;
|
|
35728
35806
|
}
|
|
35729
35807
|
function repoLockPath(repoRoot) {
|
|
35730
|
-
return
|
|
35808
|
+
return import_node_path12.default.join(getDeferredTurnDirPath(), repoLockFileName(repoRoot));
|
|
35731
35809
|
}
|
|
35732
35810
|
async function readDrainLockMetadata(lockPath) {
|
|
35733
35811
|
const raw = await import_promises23.default.readFile(lockPath, "utf8").catch(() => null);
|
|
@@ -35749,7 +35827,7 @@ async function writeDrainLockMetadata(lockPath, metadata) {
|
|
|
35749
35827
|
}
|
|
35750
35828
|
async function tryAcquireDrainLock(repoRoot) {
|
|
35751
35829
|
const lockPath = repoLockPath(repoRoot);
|
|
35752
|
-
await import_promises23.default.mkdir(
|
|
35830
|
+
await import_promises23.default.mkdir(import_node_path12.default.dirname(lockPath), { recursive: true });
|
|
35753
35831
|
const existingMeta = await readDrainLockMetadata(lockPath);
|
|
35754
35832
|
if (existingMeta) {
|
|
35755
35833
|
const lockStat = await import_promises23.default.stat(lockPath).catch(() => null);
|
|
@@ -36608,8 +36686,8 @@ function harvestClaudeCodeUsage(input) {
|
|
|
36608
36686
|
// src/usage/claudeCodeSession.ts
|
|
36609
36687
|
var import_node_child_process8 = require("child_process");
|
|
36610
36688
|
var import_node_fs7 = require("fs");
|
|
36611
|
-
var
|
|
36612
|
-
var
|
|
36689
|
+
var import_node_os9 = require("os");
|
|
36690
|
+
var import_node_path13 = require("path");
|
|
36613
36691
|
var CACHE_SCHEMA_VERSION = 1;
|
|
36614
36692
|
var SUCCESS_TTL_MS = 60 * 60 * 1e3;
|
|
36615
36693
|
var FAILURE_TTL_MS = 5 * 60 * 1e3;
|
|
@@ -36638,10 +36716,10 @@ function defaultSpawnClaudeAuthStatus(timeoutMs) {
|
|
|
36638
36716
|
}
|
|
36639
36717
|
function getCollabStateRoot2() {
|
|
36640
36718
|
const configured = process.env.REMIX_COLLAB_STATE_ROOT?.trim();
|
|
36641
|
-
return configured || (0,
|
|
36719
|
+
return configured || (0, import_node_path13.join)((0, import_node_os9.homedir)(), ".remix", "collab-state");
|
|
36642
36720
|
}
|
|
36643
36721
|
function getAuthCachePath() {
|
|
36644
|
-
return (0,
|
|
36722
|
+
return (0, import_node_path13.join)(getCollabStateRoot2(), "claude-auth-cache.json");
|
|
36645
36723
|
}
|
|
36646
36724
|
function getSpawnTimeoutMs() {
|
|
36647
36725
|
const raw = process.env.REMIX_CLAUDE_AUTH_TIMEOUT_MS?.trim();
|
|
@@ -36682,7 +36760,7 @@ function isCacheFresh(record) {
|
|
|
36682
36760
|
function writeAuthCache(record) {
|
|
36683
36761
|
const cachePath = getAuthCachePath();
|
|
36684
36762
|
try {
|
|
36685
|
-
(0, import_node_fs7.mkdirSync)((0,
|
|
36763
|
+
(0, import_node_fs7.mkdirSync)((0, import_node_path13.dirname)(cachePath), { recursive: true });
|
|
36686
36764
|
const tmpPath = `${cachePath}.${process.pid}.${Date.now()}.tmp`;
|
|
36687
36765
|
(0, import_node_fs7.writeFileSync)(tmpPath, JSON.stringify(record), "utf8");
|
|
36688
36766
|
(0, import_node_fs7.renameSync)(tmpPath, cachePath);
|
|
@@ -36740,7 +36818,7 @@ function resolveClaudeCodeSession(hookPayload) {
|
|
|
36740
36818
|
|
|
36741
36819
|
// src/hook-utils.ts
|
|
36742
36820
|
var import_promises25 = __toESM(require("fs/promises"), 1);
|
|
36743
|
-
var
|
|
36821
|
+
var import_node_path14 = __toESM(require("path"), 1);
|
|
36744
36822
|
async function readJsonStdin() {
|
|
36745
36823
|
const chunks = [];
|
|
36746
36824
|
for await (const chunk of process.stdin) {
|
|
@@ -36802,16 +36880,16 @@ function extractBoolean(input, keys) {
|
|
|
36802
36880
|
}
|
|
36803
36881
|
async function findBoundRepo(startPath) {
|
|
36804
36882
|
if (!startPath) return null;
|
|
36805
|
-
let current =
|
|
36883
|
+
let current = import_node_path14.default.resolve(startPath);
|
|
36806
36884
|
let stats = await import_promises25.default.stat(current).catch(() => null);
|
|
36807
36885
|
if (stats?.isFile()) {
|
|
36808
|
-
current =
|
|
36886
|
+
current = import_node_path14.default.dirname(current);
|
|
36809
36887
|
}
|
|
36810
36888
|
while (true) {
|
|
36811
|
-
const bindingPath =
|
|
36889
|
+
const bindingPath = import_node_path14.default.join(current, ".remix", "config.json");
|
|
36812
36890
|
const bindingStats = await import_promises25.default.stat(bindingPath).catch(() => null);
|
|
36813
36891
|
if (bindingStats?.isFile()) return current;
|
|
36814
|
-
const parent =
|
|
36892
|
+
const parent = import_node_path14.default.dirname(current);
|
|
36815
36893
|
if (parent === current) return null;
|
|
36816
36894
|
current = parent;
|
|
36817
36895
|
}
|