@remixhq/claude-plugin 0.1.11 → 0.1.14
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/agents/remix-collab.md +5 -6
- package/dist/hook-post-collab.cjs +339 -23
- package/dist/hook-post-collab.cjs.map +1 -1
- package/dist/hook-post-collab.d.cts +2 -1
- package/dist/hook-pre-git.cjs +3 -2
- package/dist/hook-pre-git.cjs.map +1 -1
- package/dist/hook-stop-collab.cjs +595 -119
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-stop-collab.d.cts +2 -1
- package/dist/hook-user-prompt.cjs +305 -17
- package/dist/hook-user-prompt.cjs.map +1 -1
- package/dist/hook-user-prompt.d.cts +2 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +12228 -10077
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +3 -3
- package/skills/access-troubleshooting/SKILL.md +35 -0
- package/skills/app-ops-triage/SKILL.md +32 -0
- package/skills/historical-memory-routing/SKILL.md +2 -0
- package/skills/identity-and-scope-routing/SKILL.md +31 -0
- package/skills/init-or-remix/SKILL.md +1 -1
- package/skills/review-merge-request/SKILL.md +1 -1
- package/skills/safe-collab-workflow/SKILL.md +15 -21
- package/skills/submit-change-step/SKILL.md +11 -19
- package/skills/sync-and-reconcile/SKILL.md +3 -1
|
@@ -29,6 +29,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
29
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
30
30
|
mod
|
|
31
31
|
));
|
|
32
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
33
|
|
|
33
34
|
// node_modules/isexe/windows.js
|
|
34
35
|
var require_windows = __commonJS({
|
|
@@ -36,8 +37,8 @@ var require_windows = __commonJS({
|
|
|
36
37
|
"use strict";
|
|
37
38
|
module2.exports = isexe;
|
|
38
39
|
isexe.sync = sync;
|
|
39
|
-
var
|
|
40
|
-
function checkPathExt(
|
|
40
|
+
var fs9 = require("fs");
|
|
41
|
+
function checkPathExt(path13, options) {
|
|
41
42
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
42
43
|
if (!pathext) {
|
|
43
44
|
return true;
|
|
@@ -48,25 +49,25 @@ var require_windows = __commonJS({
|
|
|
48
49
|
}
|
|
49
50
|
for (var i2 = 0; i2 < pathext.length; i2++) {
|
|
50
51
|
var p = pathext[i2].toLowerCase();
|
|
51
|
-
if (p &&
|
|
52
|
+
if (p && path13.substr(-p.length).toLowerCase() === p) {
|
|
52
53
|
return true;
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
return false;
|
|
56
57
|
}
|
|
57
|
-
function checkStat(stat,
|
|
58
|
+
function checkStat(stat, path13, options) {
|
|
58
59
|
if (!stat.isSymbolicLink() && !stat.isFile()) {
|
|
59
60
|
return false;
|
|
60
61
|
}
|
|
61
|
-
return checkPathExt(
|
|
62
|
+
return checkPathExt(path13, options);
|
|
62
63
|
}
|
|
63
|
-
function isexe(
|
|
64
|
-
|
|
65
|
-
cb(er, er ? false : checkStat(stat,
|
|
64
|
+
function isexe(path13, options, cb) {
|
|
65
|
+
fs9.stat(path13, function(er, stat) {
|
|
66
|
+
cb(er, er ? false : checkStat(stat, path13, options));
|
|
66
67
|
});
|
|
67
68
|
}
|
|
68
|
-
function sync(
|
|
69
|
-
return checkStat(
|
|
69
|
+
function sync(path13, options) {
|
|
70
|
+
return checkStat(fs9.statSync(path13), path13, options);
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
});
|
|
@@ -77,14 +78,14 @@ var require_mode = __commonJS({
|
|
|
77
78
|
"use strict";
|
|
78
79
|
module2.exports = isexe;
|
|
79
80
|
isexe.sync = sync;
|
|
80
|
-
var
|
|
81
|
-
function isexe(
|
|
82
|
-
|
|
81
|
+
var fs9 = require("fs");
|
|
82
|
+
function isexe(path13, options, cb) {
|
|
83
|
+
fs9.stat(path13, function(er, stat) {
|
|
83
84
|
cb(er, er ? false : checkStat(stat, options));
|
|
84
85
|
});
|
|
85
86
|
}
|
|
86
|
-
function sync(
|
|
87
|
-
return checkStat(
|
|
87
|
+
function sync(path13, options) {
|
|
88
|
+
return checkStat(fs9.statSync(path13), options);
|
|
88
89
|
}
|
|
89
90
|
function checkStat(stat, options) {
|
|
90
91
|
return stat.isFile() && checkMode(stat, options);
|
|
@@ -109,7 +110,7 @@ var require_mode = __commonJS({
|
|
|
109
110
|
var require_isexe = __commonJS({
|
|
110
111
|
"node_modules/isexe/index.js"(exports2, module2) {
|
|
111
112
|
"use strict";
|
|
112
|
-
var
|
|
113
|
+
var fs9 = require("fs");
|
|
113
114
|
var core;
|
|
114
115
|
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
115
116
|
core = require_windows();
|
|
@@ -118,7 +119,7 @@ var require_isexe = __commonJS({
|
|
|
118
119
|
}
|
|
119
120
|
module2.exports = isexe;
|
|
120
121
|
isexe.sync = sync;
|
|
121
|
-
function isexe(
|
|
122
|
+
function isexe(path13, options, cb) {
|
|
122
123
|
if (typeof options === "function") {
|
|
123
124
|
cb = options;
|
|
124
125
|
options = {};
|
|
@@ -128,7 +129,7 @@ var require_isexe = __commonJS({
|
|
|
128
129
|
throw new TypeError("callback not provided");
|
|
129
130
|
}
|
|
130
131
|
return new Promise(function(resolve, reject) {
|
|
131
|
-
isexe(
|
|
132
|
+
isexe(path13, options || {}, function(er, is) {
|
|
132
133
|
if (er) {
|
|
133
134
|
reject(er);
|
|
134
135
|
} else {
|
|
@@ -137,7 +138,7 @@ var require_isexe = __commonJS({
|
|
|
137
138
|
});
|
|
138
139
|
});
|
|
139
140
|
}
|
|
140
|
-
core(
|
|
141
|
+
core(path13, options || {}, function(er, is) {
|
|
141
142
|
if (er) {
|
|
142
143
|
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
143
144
|
er = null;
|
|
@@ -147,9 +148,9 @@ var require_isexe = __commonJS({
|
|
|
147
148
|
cb(er, is);
|
|
148
149
|
});
|
|
149
150
|
}
|
|
150
|
-
function sync(
|
|
151
|
+
function sync(path13, options) {
|
|
151
152
|
try {
|
|
152
|
-
return core.sync(
|
|
153
|
+
return core.sync(path13, options || {});
|
|
153
154
|
} catch (er) {
|
|
154
155
|
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
155
156
|
return false;
|
|
@@ -166,7 +167,7 @@ var require_which = __commonJS({
|
|
|
166
167
|
"node_modules/which/which.js"(exports2, module2) {
|
|
167
168
|
"use strict";
|
|
168
169
|
var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
169
|
-
var
|
|
170
|
+
var path13 = require("path");
|
|
170
171
|
var COLON = isWindows ? ";" : ":";
|
|
171
172
|
var isexe = require_isexe();
|
|
172
173
|
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
@@ -204,7 +205,7 @@ var require_which = __commonJS({
|
|
|
204
205
|
return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
|
|
205
206
|
const ppRaw = pathEnv[i2];
|
|
206
207
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
207
|
-
const pCmd =
|
|
208
|
+
const pCmd = path13.join(pathPart, cmd);
|
|
208
209
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
209
210
|
resolve(subStep(p, i2, 0));
|
|
210
211
|
});
|
|
@@ -231,7 +232,7 @@ var require_which = __commonJS({
|
|
|
231
232
|
for (let i2 = 0; i2 < pathEnv.length; i2++) {
|
|
232
233
|
const ppRaw = pathEnv[i2];
|
|
233
234
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
234
|
-
const pCmd =
|
|
235
|
+
const pCmd = path13.join(pathPart, cmd);
|
|
235
236
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
236
237
|
for (let j = 0; j < pathExt.length; j++) {
|
|
237
238
|
const cur = p + pathExt[j];
|
|
@@ -279,7 +280,7 @@ var require_path_key = __commonJS({
|
|
|
279
280
|
var require_resolveCommand = __commonJS({
|
|
280
281
|
"node_modules/cross-spawn/lib/util/resolveCommand.js"(exports2, module2) {
|
|
281
282
|
"use strict";
|
|
282
|
-
var
|
|
283
|
+
var path13 = require("path");
|
|
283
284
|
var which = require_which();
|
|
284
285
|
var getPathKey = require_path_key();
|
|
285
286
|
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
@@ -297,7 +298,7 @@ var require_resolveCommand = __commonJS({
|
|
|
297
298
|
try {
|
|
298
299
|
resolved = which.sync(parsed.command, {
|
|
299
300
|
path: env[getPathKey({ env })],
|
|
300
|
-
pathExt: withoutPathExt ?
|
|
301
|
+
pathExt: withoutPathExt ? path13.delimiter : void 0
|
|
301
302
|
});
|
|
302
303
|
} catch (e) {
|
|
303
304
|
} finally {
|
|
@@ -306,7 +307,7 @@ var require_resolveCommand = __commonJS({
|
|
|
306
307
|
}
|
|
307
308
|
}
|
|
308
309
|
if (resolved) {
|
|
309
|
-
resolved =
|
|
310
|
+
resolved = path13.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
310
311
|
}
|
|
311
312
|
return resolved;
|
|
312
313
|
}
|
|
@@ -360,8 +361,8 @@ var require_shebang_command = __commonJS({
|
|
|
360
361
|
if (!match) {
|
|
361
362
|
return null;
|
|
362
363
|
}
|
|
363
|
-
const [
|
|
364
|
-
const binary =
|
|
364
|
+
const [path13, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
365
|
+
const binary = path13.split("/").pop();
|
|
365
366
|
if (binary === "env") {
|
|
366
367
|
return argument;
|
|
367
368
|
}
|
|
@@ -374,16 +375,16 @@ var require_shebang_command = __commonJS({
|
|
|
374
375
|
var require_readShebang = __commonJS({
|
|
375
376
|
"node_modules/cross-spawn/lib/util/readShebang.js"(exports2, module2) {
|
|
376
377
|
"use strict";
|
|
377
|
-
var
|
|
378
|
+
var fs9 = require("fs");
|
|
378
379
|
var shebangCommand = require_shebang_command();
|
|
379
380
|
function readShebang(command) {
|
|
380
381
|
const size = 150;
|
|
381
382
|
const buffer = Buffer.alloc(size);
|
|
382
383
|
let fd;
|
|
383
384
|
try {
|
|
384
|
-
fd =
|
|
385
|
-
|
|
386
|
-
|
|
385
|
+
fd = fs9.openSync(command, "r");
|
|
386
|
+
fs9.readSync(fd, buffer, 0, size, 0);
|
|
387
|
+
fs9.closeSync(fd);
|
|
387
388
|
} catch (e) {
|
|
388
389
|
}
|
|
389
390
|
return shebangCommand(buffer.toString());
|
|
@@ -396,7 +397,7 @@ var require_readShebang = __commonJS({
|
|
|
396
397
|
var require_parse = __commonJS({
|
|
397
398
|
"node_modules/cross-spawn/lib/parse.js"(exports2, module2) {
|
|
398
399
|
"use strict";
|
|
399
|
-
var
|
|
400
|
+
var path13 = require("path");
|
|
400
401
|
var resolveCommand = require_resolveCommand();
|
|
401
402
|
var escape = require_escape();
|
|
402
403
|
var readShebang = require_readShebang();
|
|
@@ -421,7 +422,7 @@ var require_parse = __commonJS({
|
|
|
421
422
|
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
422
423
|
if (parsed.options.forceShell || needsShell) {
|
|
423
424
|
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
424
|
-
parsed.command =
|
|
425
|
+
parsed.command = path13.normalize(parsed.command);
|
|
425
426
|
parsed.command = escape.command(parsed.command);
|
|
426
427
|
parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
|
|
427
428
|
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
@@ -531,6 +532,13 @@ var require_cross_spawn = __commonJS({
|
|
|
531
532
|
}
|
|
532
533
|
});
|
|
533
534
|
|
|
535
|
+
// src/hook-stop-collab.ts
|
|
536
|
+
var hook_stop_collab_exports = {};
|
|
537
|
+
__export(hook_stop_collab_exports, {
|
|
538
|
+
runHookStopCollab: () => runHookStopCollab
|
|
539
|
+
});
|
|
540
|
+
module.exports = __toCommonJS(hook_stop_collab_exports);
|
|
541
|
+
|
|
534
542
|
// node_modules/@remixhq/core/dist/chunk-YZ34ICNN.js
|
|
535
543
|
var RemixError = class extends Error {
|
|
536
544
|
code;
|
|
@@ -545,7 +553,7 @@ var RemixError = class extends Error {
|
|
|
545
553
|
}
|
|
546
554
|
};
|
|
547
555
|
|
|
548
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
556
|
+
// node_modules/@remixhq/core/dist/chunk-GEHSFPCD.js
|
|
549
557
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
550
558
|
var import_path = __toESM(require("path"), 1);
|
|
551
559
|
function getCollabBindingPath(repoRoot) {
|
|
@@ -582,7 +590,7 @@ var REMIX_ERROR_CODES = {
|
|
|
582
590
|
PREFERRED_BRANCH_MISMATCH: "PREFERRED_BRANCH_MISMATCH"
|
|
583
591
|
};
|
|
584
592
|
|
|
585
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
593
|
+
// node_modules/@remixhq/core/dist/chunk-J3J4PBQ7.js
|
|
586
594
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
587
595
|
var import_crypto = require("crypto");
|
|
588
596
|
var import_os = __toESM(require("os"), 1);
|
|
@@ -4969,13 +4977,13 @@ var logOutputSync = ({ serializedResult, fdNumber, state, verboseInfo, encoding,
|
|
|
4969
4977
|
}
|
|
4970
4978
|
};
|
|
4971
4979
|
var writeToFiles = (serializedResult, stdioItems, outputFiles) => {
|
|
4972
|
-
for (const { path:
|
|
4973
|
-
const pathString = typeof
|
|
4980
|
+
for (const { path: path13, append } of stdioItems.filter(({ type }) => FILE_TYPES.has(type))) {
|
|
4981
|
+
const pathString = typeof path13 === "string" ? path13 : path13.toString();
|
|
4974
4982
|
if (append || outputFiles.has(pathString)) {
|
|
4975
|
-
(0, import_node_fs4.appendFileSync)(
|
|
4983
|
+
(0, import_node_fs4.appendFileSync)(path13, serializedResult);
|
|
4976
4984
|
} else {
|
|
4977
4985
|
outputFiles.add(pathString);
|
|
4978
|
-
(0, import_node_fs4.writeFileSync)(
|
|
4986
|
+
(0, import_node_fs4.writeFileSync)(path13, serializedResult);
|
|
4979
4987
|
}
|
|
4980
4988
|
}
|
|
4981
4989
|
};
|
|
@@ -7363,7 +7371,7 @@ var {
|
|
|
7363
7371
|
getCancelSignal: getCancelSignal2
|
|
7364
7372
|
} = getIpcExport();
|
|
7365
7373
|
|
|
7366
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
7374
|
+
// node_modules/@remixhq/core/dist/chunk-J3J4PBQ7.js
|
|
7367
7375
|
async function runGit(args, cwd) {
|
|
7368
7376
|
const res = await execa("git", args, { cwd, stderr: "ignore" });
|
|
7369
7377
|
return String(res.stdout || "").trim();
|
|
@@ -7879,6 +7887,25 @@ function formatCliErrorDetail(err) {
|
|
|
7879
7887
|
}
|
|
7880
7888
|
return typeof err === "string" && err.trim() ? err.trim() : null;
|
|
7881
7889
|
}
|
|
7890
|
+
async function pollAppReady(api, appId) {
|
|
7891
|
+
const started = Date.now();
|
|
7892
|
+
let delay = 2e3;
|
|
7893
|
+
while (Date.now() - started < 20 * 60 * 1e3) {
|
|
7894
|
+
const appResp = await api.getApp(appId);
|
|
7895
|
+
const app = unwrapResponseObject(appResp, "app");
|
|
7896
|
+
const status = typeof app.status === "string" ? app.status : "";
|
|
7897
|
+
if (status === "ready") return app;
|
|
7898
|
+
if (status === "error") {
|
|
7899
|
+
throw new RemixError("App is in error state.", {
|
|
7900
|
+
exitCode: 1,
|
|
7901
|
+
hint: typeof app.statusError === "string" ? app.statusError : null
|
|
7902
|
+
});
|
|
7903
|
+
}
|
|
7904
|
+
await sleep(delay);
|
|
7905
|
+
delay = Math.min(1e4, Math.floor(delay * 1.4));
|
|
7906
|
+
}
|
|
7907
|
+
throw new RemixError("Timed out waiting for app to become ready.", { exitCode: 1 });
|
|
7908
|
+
}
|
|
7882
7909
|
async function pollChangeStep(api, appId, changeStepId) {
|
|
7883
7910
|
const started = Date.now();
|
|
7884
7911
|
let delay = 1500;
|
|
@@ -8700,6 +8727,7 @@ async function collabAdd(params) {
|
|
|
8700
8727
|
}
|
|
8701
8728
|
const { backupPath } = await writeTempUnifiedDiffBackup(diff, "remix-add");
|
|
8702
8729
|
try {
|
|
8730
|
+
await pollAppReady(params.api, binding.currentAppId);
|
|
8703
8731
|
if (submissionSnapshot) {
|
|
8704
8732
|
await assertRepoSnapshotUnchanged(repoRoot, submissionSnapshot, {
|
|
8705
8733
|
operation: "`remix collab add` auto-sync",
|
|
@@ -8845,7 +8873,7 @@ async function collabRecordTurn(params) {
|
|
|
8845
8873
|
return unwrapResponseObject(resp, "collab turn");
|
|
8846
8874
|
}
|
|
8847
8875
|
|
|
8848
|
-
// node_modules/@remixhq/core/dist/chunk-
|
|
8876
|
+
// node_modules/@remixhq/core/dist/chunk-XC2FV57P.js
|
|
8849
8877
|
async function readJsonSafe(res) {
|
|
8850
8878
|
const ct = res.headers.get("content-type") ?? "";
|
|
8851
8879
|
if (!ct.toLowerCase().includes("application/json")) return null;
|
|
@@ -8859,7 +8887,7 @@ function createApiClient(config, opts) {
|
|
|
8859
8887
|
const apiKey = (opts?.apiKey ?? "").trim();
|
|
8860
8888
|
const tokenProvider = opts?.tokenProvider;
|
|
8861
8889
|
const CLIENT_KEY_HEADER = "x-comerge-api-key";
|
|
8862
|
-
async function request(
|
|
8890
|
+
async function request(path13, init) {
|
|
8863
8891
|
if (!tokenProvider) {
|
|
8864
8892
|
throw new RemixError("API client is missing a token provider.", {
|
|
8865
8893
|
exitCode: 1,
|
|
@@ -8867,7 +8895,7 @@ function createApiClient(config, opts) {
|
|
|
8867
8895
|
});
|
|
8868
8896
|
}
|
|
8869
8897
|
const auth = await tokenProvider();
|
|
8870
|
-
const url = new URL(
|
|
8898
|
+
const url = new URL(path13, config.apiUrl).toString();
|
|
8871
8899
|
const doFetch = async (bearer) => fetch(url, {
|
|
8872
8900
|
...init,
|
|
8873
8901
|
headers: {
|
|
@@ -8891,7 +8919,7 @@ function createApiClient(config, opts) {
|
|
|
8891
8919
|
const json = await readJsonSafe(res);
|
|
8892
8920
|
return json ?? null;
|
|
8893
8921
|
}
|
|
8894
|
-
async function requestBinary(
|
|
8922
|
+
async function requestBinary(path13, init) {
|
|
8895
8923
|
if (!tokenProvider) {
|
|
8896
8924
|
throw new RemixError("API client is missing a token provider.", {
|
|
8897
8925
|
exitCode: 1,
|
|
@@ -8899,7 +8927,7 @@ function createApiClient(config, opts) {
|
|
|
8899
8927
|
});
|
|
8900
8928
|
}
|
|
8901
8929
|
const auth = await tokenProvider();
|
|
8902
|
-
const url = new URL(
|
|
8930
|
+
const url = new URL(path13, config.apiUrl).toString();
|
|
8903
8931
|
const doFetch = async (bearer) => fetch(url, {
|
|
8904
8932
|
...init,
|
|
8905
8933
|
headers: {
|
|
@@ -8960,10 +8988,29 @@ function createApiClient(config, opts) {
|
|
|
8960
8988
|
if (params?.projectId) qs.set("projectId", params.projectId);
|
|
8961
8989
|
if (params?.organizationId) qs.set("organizationId", params.organizationId);
|
|
8962
8990
|
if (params?.forked) qs.set("forked", params.forked);
|
|
8991
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
8992
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
8963
8993
|
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
8964
8994
|
return request(`/v1/apps${suffix}`, { method: "GET" });
|
|
8965
8995
|
},
|
|
8966
8996
|
getApp: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}`, { method: "GET" }),
|
|
8997
|
+
getAppContext: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/context`, { method: "GET" }),
|
|
8998
|
+
getAppOverview: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/overview`, { method: "GET" }),
|
|
8999
|
+
listAppTimeline: (appId, params) => {
|
|
9000
|
+
const qs = new URLSearchParams();
|
|
9001
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9002
|
+
if (params?.cursor) qs.set("cursor", params.cursor);
|
|
9003
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9004
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/timeline${suffix}`, { method: "GET" });
|
|
9005
|
+
},
|
|
9006
|
+
getAppTimelineEvent: (appId, eventId) => request(`/v1/apps/${encodeURIComponent(appId)}/timeline/${encodeURIComponent(eventId)}`, { method: "GET" }),
|
|
9007
|
+
listAppEditQueue: (appId, params) => {
|
|
9008
|
+
const qs = new URLSearchParams();
|
|
9009
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9010
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9011
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9012
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/edit-queue${suffix}`, { method: "GET" });
|
|
9013
|
+
},
|
|
8967
9014
|
getMergeRequest: (mrId) => request(`/v1/merge-requests/${encodeURIComponent(mrId)}`, { method: "GET" }),
|
|
8968
9015
|
presignImportUpload: (payload) => request("/v1/apps/import/upload/presign", { method: "POST", body: JSON.stringify(payload) }),
|
|
8969
9016
|
importFromUpload: (payload) => request("/v1/apps/import/upload", { method: "POST", body: JSON.stringify(payload) }),
|
|
@@ -9045,6 +9092,8 @@ function createApiClient(config, opts) {
|
|
|
9045
9092
|
qs.set("status", params.status);
|
|
9046
9093
|
}
|
|
9047
9094
|
if (params?.kind) qs.set("kind", params.kind);
|
|
9095
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9096
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9048
9097
|
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9049
9098
|
return request(`/v1/merge-requests${suffix}`, { method: "GET" });
|
|
9050
9099
|
},
|
|
@@ -9063,24 +9112,60 @@ function createApiClient(config, opts) {
|
|
|
9063
9112
|
method: "POST",
|
|
9064
9113
|
body: JSON.stringify(payload)
|
|
9065
9114
|
}),
|
|
9066
|
-
listOrganizationMembers: (orgId) =>
|
|
9115
|
+
listOrganizationMembers: (orgId, params) => {
|
|
9116
|
+
const qs = new URLSearchParams();
|
|
9117
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9118
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9119
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9120
|
+
return request(`/v1/organizations/${encodeURIComponent(orgId)}/members${suffix}`, { method: "GET" });
|
|
9121
|
+
},
|
|
9067
9122
|
updateOrganizationMember: (orgId, userId, payload) => request(`/v1/organizations/${encodeURIComponent(orgId)}/members/${encodeURIComponent(userId)}`, {
|
|
9068
9123
|
method: "PATCH",
|
|
9069
9124
|
body: JSON.stringify(payload)
|
|
9070
9125
|
}),
|
|
9071
|
-
listProjectMembers: (projectId) =>
|
|
9126
|
+
listProjectMembers: (projectId, params) => {
|
|
9127
|
+
const qs = new URLSearchParams();
|
|
9128
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9129
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9130
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9131
|
+
return request(`/v1/projects/${encodeURIComponent(projectId)}/members${suffix}`, { method: "GET" });
|
|
9132
|
+
},
|
|
9072
9133
|
updateProjectMember: (projectId, userId, payload) => request(`/v1/projects/${encodeURIComponent(projectId)}/members/${encodeURIComponent(userId)}`, {
|
|
9073
9134
|
method: "PATCH",
|
|
9074
9135
|
body: JSON.stringify(payload)
|
|
9075
9136
|
}),
|
|
9076
|
-
listAppMembers: (appId) =>
|
|
9137
|
+
listAppMembers: (appId, params) => {
|
|
9138
|
+
const qs = new URLSearchParams();
|
|
9139
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9140
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9141
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9142
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/members${suffix}`, { method: "GET" });
|
|
9143
|
+
},
|
|
9077
9144
|
updateAppMember: (appId, userId, payload) => request(`/v1/apps/${encodeURIComponent(appId)}/members/${encodeURIComponent(userId)}`, {
|
|
9078
9145
|
method: "PATCH",
|
|
9079
9146
|
body: JSON.stringify(payload)
|
|
9080
9147
|
}),
|
|
9081
|
-
listOrganizationInvites: (orgId) =>
|
|
9082
|
-
|
|
9083
|
-
|
|
9148
|
+
listOrganizationInvites: (orgId, params) => {
|
|
9149
|
+
const qs = new URLSearchParams();
|
|
9150
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9151
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9152
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9153
|
+
return request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations${suffix}`, { method: "GET" });
|
|
9154
|
+
},
|
|
9155
|
+
listProjectInvites: (projectId, params) => {
|
|
9156
|
+
const qs = new URLSearchParams();
|
|
9157
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9158
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9159
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9160
|
+
return request(`/v1/projects/${encodeURIComponent(projectId)}/invitations${suffix}`, { method: "GET" });
|
|
9161
|
+
},
|
|
9162
|
+
listAppInvites: (appId, params) => {
|
|
9163
|
+
const qs = new URLSearchParams();
|
|
9164
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9165
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9166
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9167
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/invitations${suffix}`, { method: "GET" });
|
|
9168
|
+
},
|
|
9084
9169
|
resendOrganizationInvite: (orgId, inviteId, payload) => request(`/v1/organizations/${encodeURIComponent(orgId)}/invitations/${encodeURIComponent(inviteId)}/resend`, {
|
|
9085
9170
|
method: "POST",
|
|
9086
9171
|
body: JSON.stringify(payload ?? {})
|
|
@@ -9102,6 +9187,7 @@ function createApiClient(config, opts) {
|
|
|
9102
9187
|
revokeAppInvite: (appId, inviteId) => request(`/v1/apps/${encodeURIComponent(appId)}/invitations/${encodeURIComponent(inviteId)}`, {
|
|
9103
9188
|
method: "DELETE"
|
|
9104
9189
|
}),
|
|
9190
|
+
acceptInvitation: (payload) => request("/v1/invitations/accept", { method: "POST", body: JSON.stringify(payload) }),
|
|
9105
9191
|
syncUpstreamApp: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/sync-upstream`, {
|
|
9106
9192
|
method: "POST",
|
|
9107
9193
|
body: JSON.stringify({})
|
|
@@ -9137,7 +9223,31 @@ function createApiClient(config, opts) {
|
|
|
9137
9223
|
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/assets/download?${qs.toString()}`,
|
|
9138
9224
|
{ method: "GET" }
|
|
9139
9225
|
);
|
|
9140
|
-
}
|
|
9226
|
+
},
|
|
9227
|
+
listAgentRuns: (appId, params) => {
|
|
9228
|
+
const qs = new URLSearchParams();
|
|
9229
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9230
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9231
|
+
if (params?.status) qs.set("status", params.status);
|
|
9232
|
+
if (params?.currentPhase) qs.set("currentPhase", params.currentPhase);
|
|
9233
|
+
if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
|
|
9234
|
+
if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
|
|
9235
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9236
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/agent-runs${suffix}`, { method: "GET" });
|
|
9237
|
+
},
|
|
9238
|
+
getAgentRun: (appId, runId) => request(`/v1/apps/${encodeURIComponent(appId)}/agent-runs/${encodeURIComponent(runId)}`, { method: "GET" }),
|
|
9239
|
+
listAgentRunEvents: (appId, runId, params) => {
|
|
9240
|
+
const qs = new URLSearchParams();
|
|
9241
|
+
if (typeof params?.limit === "number") qs.set("limit", String(params.limit));
|
|
9242
|
+
if (typeof params?.offset === "number") qs.set("offset", String(params.offset));
|
|
9243
|
+
if (params?.createdAfter) qs.set("createdAfter", params.createdAfter);
|
|
9244
|
+
if (params?.createdBefore) qs.set("createdBefore", params.createdBefore);
|
|
9245
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
9246
|
+
return request(`/v1/apps/${encodeURIComponent(appId)}/agent-runs/${encodeURIComponent(runId)}/events${suffix}`, {
|
|
9247
|
+
method: "GET"
|
|
9248
|
+
});
|
|
9249
|
+
},
|
|
9250
|
+
getSandboxStatus: (appId) => request(`/v1/apps/${encodeURIComponent(appId)}/sandbox/status`, { method: "GET" })
|
|
9141
9251
|
};
|
|
9142
9252
|
}
|
|
9143
9253
|
|
|
@@ -9619,8 +9729,8 @@ function getErrorMap() {
|
|
|
9619
9729
|
|
|
9620
9730
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
9621
9731
|
var makeIssue = (params) => {
|
|
9622
|
-
const { data, path:
|
|
9623
|
-
const fullPath = [...
|
|
9732
|
+
const { data, path: path13, errorMaps, issueData } = params;
|
|
9733
|
+
const fullPath = [...path13, ...issueData.path || []];
|
|
9624
9734
|
const fullIssue = {
|
|
9625
9735
|
...issueData,
|
|
9626
9736
|
path: fullPath
|
|
@@ -9736,11 +9846,11 @@ var errorUtil;
|
|
|
9736
9846
|
|
|
9737
9847
|
// node_modules/zod/v3/types.js
|
|
9738
9848
|
var ParseInputLazyPath = class {
|
|
9739
|
-
constructor(parent, value,
|
|
9849
|
+
constructor(parent, value, path13, key) {
|
|
9740
9850
|
this._cachedPath = [];
|
|
9741
9851
|
this.parent = parent;
|
|
9742
9852
|
this.data = value;
|
|
9743
|
-
this._path =
|
|
9853
|
+
this._path = path13;
|
|
9744
9854
|
this._key = key;
|
|
9745
9855
|
}
|
|
9746
9856
|
get path() {
|
|
@@ -22073,8 +22183,8 @@ var IcebergError = class extends Error {
|
|
|
22073
22183
|
return this.status === 419;
|
|
22074
22184
|
}
|
|
22075
22185
|
};
|
|
22076
|
-
function buildUrl(baseUrl,
|
|
22077
|
-
const url = new URL(
|
|
22186
|
+
function buildUrl(baseUrl, path13, query) {
|
|
22187
|
+
const url = new URL(path13, baseUrl);
|
|
22078
22188
|
if (query) {
|
|
22079
22189
|
for (const [key, value] of Object.entries(query)) {
|
|
22080
22190
|
if (value !== void 0) {
|
|
@@ -22104,12 +22214,12 @@ function createFetchClient(options) {
|
|
|
22104
22214
|
return {
|
|
22105
22215
|
async request({
|
|
22106
22216
|
method,
|
|
22107
|
-
path:
|
|
22217
|
+
path: path13,
|
|
22108
22218
|
query,
|
|
22109
22219
|
body,
|
|
22110
22220
|
headers
|
|
22111
22221
|
}) {
|
|
22112
|
-
const url = buildUrl(options.baseUrl,
|
|
22222
|
+
const url = buildUrl(options.baseUrl, path13, query);
|
|
22113
22223
|
const authHeaders = await buildAuthHeaders(options.auth);
|
|
22114
22224
|
const res = await fetchFn(url, {
|
|
22115
22225
|
method,
|
|
@@ -22928,7 +23038,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
22928
23038
|
* @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.
|
|
22929
23039
|
* @param fileBody The body of the file to be stored in the bucket.
|
|
22930
23040
|
*/
|
|
22931
|
-
async uploadOrUpdate(method,
|
|
23041
|
+
async uploadOrUpdate(method, path13, fileBody, fileOptions) {
|
|
22932
23042
|
var _this = this;
|
|
22933
23043
|
return _this.handleOperation(async () => {
|
|
22934
23044
|
let body;
|
|
@@ -22952,7 +23062,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
22952
23062
|
if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
|
|
22953
23063
|
}
|
|
22954
23064
|
if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) headers = _objectSpread22(_objectSpread22({}, headers), fileOptions.headers);
|
|
22955
|
-
const cleanPath = _this._removeEmptyFolders(
|
|
23065
|
+
const cleanPath = _this._removeEmptyFolders(path13);
|
|
22956
23066
|
const _path = _this._getFinalPath(cleanPath);
|
|
22957
23067
|
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 } : {}));
|
|
22958
23068
|
return {
|
|
@@ -23013,8 +23123,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23013
23123
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23014
23124
|
* - 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.
|
|
23015
23125
|
*/
|
|
23016
|
-
async upload(
|
|
23017
|
-
return this.uploadOrUpdate("POST",
|
|
23126
|
+
async upload(path13, fileBody, fileOptions) {
|
|
23127
|
+
return this.uploadOrUpdate("POST", path13, fileBody, fileOptions);
|
|
23018
23128
|
}
|
|
23019
23129
|
/**
|
|
23020
23130
|
* Upload a file with a token generated from `createSignedUploadUrl`.
|
|
@@ -23053,9 +23163,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23053
23163
|
* - `objects` table permissions: none
|
|
23054
23164
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23055
23165
|
*/
|
|
23056
|
-
async uploadToSignedUrl(
|
|
23166
|
+
async uploadToSignedUrl(path13, token, fileBody, fileOptions) {
|
|
23057
23167
|
var _this3 = this;
|
|
23058
|
-
const cleanPath = _this3._removeEmptyFolders(
|
|
23168
|
+
const cleanPath = _this3._removeEmptyFolders(path13);
|
|
23059
23169
|
const _path = _this3._getFinalPath(cleanPath);
|
|
23060
23170
|
const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
|
|
23061
23171
|
url.searchParams.set("token", token);
|
|
@@ -23117,10 +23227,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23117
23227
|
* - `objects` table permissions: `insert`
|
|
23118
23228
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23119
23229
|
*/
|
|
23120
|
-
async createSignedUploadUrl(
|
|
23230
|
+
async createSignedUploadUrl(path13, options) {
|
|
23121
23231
|
var _this4 = this;
|
|
23122
23232
|
return _this4.handleOperation(async () => {
|
|
23123
|
-
let _path = _this4._getFinalPath(
|
|
23233
|
+
let _path = _this4._getFinalPath(path13);
|
|
23124
23234
|
const headers = _objectSpread22({}, _this4.headers);
|
|
23125
23235
|
if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
|
|
23126
23236
|
const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
|
|
@@ -23129,7 +23239,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23129
23239
|
if (!token) throw new StorageError("No token returned by API");
|
|
23130
23240
|
return {
|
|
23131
23241
|
signedUrl: url.toString(),
|
|
23132
|
-
path:
|
|
23242
|
+
path: path13,
|
|
23133
23243
|
token
|
|
23134
23244
|
};
|
|
23135
23245
|
});
|
|
@@ -23185,8 +23295,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23185
23295
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23186
23296
|
* - 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.
|
|
23187
23297
|
*/
|
|
23188
|
-
async update(
|
|
23189
|
-
return this.uploadOrUpdate("PUT",
|
|
23298
|
+
async update(path13, fileBody, fileOptions) {
|
|
23299
|
+
return this.uploadOrUpdate("PUT", path13, fileBody, fileOptions);
|
|
23190
23300
|
}
|
|
23191
23301
|
/**
|
|
23192
23302
|
* Moves an existing file to a new path in the same bucket.
|
|
@@ -23333,10 +23443,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23333
23443
|
* - `objects` table permissions: `select`
|
|
23334
23444
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23335
23445
|
*/
|
|
23336
|
-
async createSignedUrl(
|
|
23446
|
+
async createSignedUrl(path13, expiresIn, options) {
|
|
23337
23447
|
var _this8 = this;
|
|
23338
23448
|
return _this8.handleOperation(async () => {
|
|
23339
|
-
let _path = _this8._getFinalPath(
|
|
23449
|
+
let _path = _this8._getFinalPath(path13);
|
|
23340
23450
|
const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
|
|
23341
23451
|
let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
|
|
23342
23452
|
const downloadQueryParam = (options === null || options === void 0 ? void 0 : options.download) ? `&download=${options.download === true ? "" : options.download}` : "";
|
|
@@ -23463,11 +23573,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23463
23573
|
* - `objects` table permissions: `select`
|
|
23464
23574
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23465
23575
|
*/
|
|
23466
|
-
download(
|
|
23576
|
+
download(path13, options, parameters) {
|
|
23467
23577
|
const renderPath = typeof (options === null || options === void 0 ? void 0 : options.transform) !== "undefined" ? "render/image/authenticated" : "object";
|
|
23468
23578
|
const transformationQuery = this.transformOptsToQueryString((options === null || options === void 0 ? void 0 : options.transform) || {});
|
|
23469
23579
|
const queryString = transformationQuery ? `?${transformationQuery}` : "";
|
|
23470
|
-
const _path = this._getFinalPath(
|
|
23580
|
+
const _path = this._getFinalPath(path13);
|
|
23471
23581
|
const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString}`, {
|
|
23472
23582
|
headers: this.headers,
|
|
23473
23583
|
noResolveJson: true
|
|
@@ -23497,9 +23607,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23497
23607
|
* }
|
|
23498
23608
|
* ```
|
|
23499
23609
|
*/
|
|
23500
|
-
async info(
|
|
23610
|
+
async info(path13) {
|
|
23501
23611
|
var _this10 = this;
|
|
23502
|
-
const _path = _this10._getFinalPath(
|
|
23612
|
+
const _path = _this10._getFinalPath(path13);
|
|
23503
23613
|
return _this10.handleOperation(async () => {
|
|
23504
23614
|
return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
|
|
23505
23615
|
});
|
|
@@ -23519,9 +23629,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23519
23629
|
* .exists('folder/avatar1.png')
|
|
23520
23630
|
* ```
|
|
23521
23631
|
*/
|
|
23522
|
-
async exists(
|
|
23632
|
+
async exists(path13) {
|
|
23523
23633
|
var _this11 = this;
|
|
23524
|
-
const _path = _this11._getFinalPath(
|
|
23634
|
+
const _path = _this11._getFinalPath(path13);
|
|
23525
23635
|
try {
|
|
23526
23636
|
await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
|
|
23527
23637
|
return {
|
|
@@ -23598,8 +23708,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23598
23708
|
* - `objects` table permissions: none
|
|
23599
23709
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23600
23710
|
*/
|
|
23601
|
-
getPublicUrl(
|
|
23602
|
-
const _path = this._getFinalPath(
|
|
23711
|
+
getPublicUrl(path13, options) {
|
|
23712
|
+
const _path = this._getFinalPath(path13);
|
|
23603
23713
|
const _queryString = [];
|
|
23604
23714
|
const downloadQueryParam = (options === null || options === void 0 ? void 0 : options.download) ? `download=${options.download === true ? "" : options.download}` : "";
|
|
23605
23715
|
if (downloadQueryParam !== "") _queryString.push(downloadQueryParam);
|
|
@@ -23738,10 +23848,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23738
23848
|
* - `objects` table permissions: `select`
|
|
23739
23849
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23740
23850
|
*/
|
|
23741
|
-
async list(
|
|
23851
|
+
async list(path13, options, parameters) {
|
|
23742
23852
|
var _this13 = this;
|
|
23743
23853
|
return _this13.handleOperation(async () => {
|
|
23744
|
-
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix:
|
|
23854
|
+
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path13 || "" });
|
|
23745
23855
|
return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
|
|
23746
23856
|
});
|
|
23747
23857
|
}
|
|
@@ -23805,11 +23915,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23805
23915
|
if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
|
|
23806
23916
|
return btoa(data);
|
|
23807
23917
|
}
|
|
23808
|
-
_getFinalPath(
|
|
23809
|
-
return `${this.bucketId}/${
|
|
23918
|
+
_getFinalPath(path13) {
|
|
23919
|
+
return `${this.bucketId}/${path13.replace(/^\/+/, "")}`;
|
|
23810
23920
|
}
|
|
23811
|
-
_removeEmptyFolders(
|
|
23812
|
-
return
|
|
23921
|
+
_removeEmptyFolders(path13) {
|
|
23922
|
+
return path13.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
|
|
23813
23923
|
}
|
|
23814
23924
|
transformOptsToQueryString(transform) {
|
|
23815
23925
|
const params = [];
|
|
@@ -33085,13 +33195,20 @@ async function createHookCollabApiClient() {
|
|
|
33085
33195
|
});
|
|
33086
33196
|
}
|
|
33087
33197
|
|
|
33198
|
+
// src/hook-diagnostics.ts
|
|
33199
|
+
var import_node_crypto2 = require("crypto");
|
|
33200
|
+
var import_promises19 = __toESM(require("fs/promises"), 1);
|
|
33201
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
33202
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
33203
|
+
|
|
33088
33204
|
// src/hook-state.ts
|
|
33089
33205
|
var import_promises18 = __toESM(require("fs/promises"), 1);
|
|
33090
33206
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
33091
33207
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
33092
33208
|
var import_node_crypto = require("crypto");
|
|
33093
33209
|
function stateRoot() {
|
|
33094
|
-
|
|
33210
|
+
const configured = process.env.REMIX_CLAUDE_PLUGIN_HOOK_STATE_ROOT?.trim();
|
|
33211
|
+
return configured || import_node_path6.default.join(import_node_os4.default.tmpdir(), "remix-claude-plugin-hooks");
|
|
33095
33212
|
}
|
|
33096
33213
|
function statePath(sessionId) {
|
|
33097
33214
|
return import_node_path6.default.join(stateRoot(), `${sessionId}.json`);
|
|
@@ -33156,6 +33273,7 @@ async function tryRemoveStaleStateLock(sessionId) {
|
|
|
33156
33273
|
async function acquireStateLock(sessionId) {
|
|
33157
33274
|
const lockPath = stateLockPath(sessionId);
|
|
33158
33275
|
const deadline = Date.now() + STATE_LOCK_WAIT_MS;
|
|
33276
|
+
await import_promises18.default.mkdir(stateRoot(), { recursive: true });
|
|
33159
33277
|
while (true) {
|
|
33160
33278
|
try {
|
|
33161
33279
|
await import_promises18.default.mkdir(lockPath);
|
|
@@ -33404,7 +33522,7 @@ async function clearPendingTurnState(sessionId) {
|
|
|
33404
33522
|
// package.json
|
|
33405
33523
|
var package_default = {
|
|
33406
33524
|
name: "@remixhq/claude-plugin",
|
|
33407
|
-
version: "0.1.
|
|
33525
|
+
version: "0.1.14",
|
|
33408
33526
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
33409
33527
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
33410
33528
|
license: "MIT",
|
|
@@ -33435,8 +33553,8 @@ var package_default = {
|
|
|
33435
33553
|
prepack: "npm run build"
|
|
33436
33554
|
},
|
|
33437
33555
|
dependencies: {
|
|
33438
|
-
"@remixhq/core": "^0.1.
|
|
33439
|
-
"@remixhq/mcp": "^0.1.
|
|
33556
|
+
"@remixhq/core": "^0.1.9",
|
|
33557
|
+
"@remixhq/mcp": "^0.1.9"
|
|
33440
33558
|
},
|
|
33441
33559
|
devDependencies: {
|
|
33442
33560
|
"@types/node": "^25.4.0",
|
|
@@ -33455,9 +33573,90 @@ var pluginMetadata = {
|
|
|
33455
33573
|
agentName: "remix-collab"
|
|
33456
33574
|
};
|
|
33457
33575
|
|
|
33576
|
+
// src/hook-diagnostics.ts
|
|
33577
|
+
var MAX_LOG_BYTES = 512 * 1024;
|
|
33578
|
+
function resolveClaudeRoot() {
|
|
33579
|
+
const configured = process.env.CLAUDE_CONFIG_DIR?.trim();
|
|
33580
|
+
return configured || import_node_path7.default.join(import_node_os5.default.homedir(), ".claude");
|
|
33581
|
+
}
|
|
33582
|
+
function resolvePluginDataDirName() {
|
|
33583
|
+
return `${pluginMetadata.pluginId}-${pluginMetadata.pluginId}`;
|
|
33584
|
+
}
|
|
33585
|
+
function getHookDiagnosticsDirPath() {
|
|
33586
|
+
const configured = process.env.REMIX_CLAUDE_PLUGIN_HOOK_DIAGNOSTICS_DIR?.trim();
|
|
33587
|
+
return configured || import_node_path7.default.join(resolveClaudeRoot(), "plugins", "data", resolvePluginDataDirName());
|
|
33588
|
+
}
|
|
33589
|
+
function getHookDiagnosticsLogPath() {
|
|
33590
|
+
return import_node_path7.default.join(getHookDiagnosticsDirPath(), "hooks.ndjson");
|
|
33591
|
+
}
|
|
33592
|
+
function toFieldValue(value) {
|
|
33593
|
+
if (value === null) return null;
|
|
33594
|
+
if (typeof value === "string") return value;
|
|
33595
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
33596
|
+
if (typeof value === "boolean") return value;
|
|
33597
|
+
return void 0;
|
|
33598
|
+
}
|
|
33599
|
+
function normalizeFields(fields) {
|
|
33600
|
+
if (!fields) return {};
|
|
33601
|
+
const normalizedEntries = Object.entries(fields).map(([key, value]) => {
|
|
33602
|
+
const normalized = toFieldValue(value);
|
|
33603
|
+
return normalized === void 0 ? null : [key, normalized];
|
|
33604
|
+
}).filter((entry) => entry !== null);
|
|
33605
|
+
return Object.fromEntries(normalizedEntries);
|
|
33606
|
+
}
|
|
33607
|
+
async function rotateLogIfNeeded(logPath) {
|
|
33608
|
+
const stat = await import_promises19.default.stat(logPath).catch(() => null);
|
|
33609
|
+
if (!stat || stat.size < MAX_LOG_BYTES) {
|
|
33610
|
+
return;
|
|
33611
|
+
}
|
|
33612
|
+
const rotatedPath = `${logPath}.1`;
|
|
33613
|
+
await import_promises19.default.rm(rotatedPath, { force: true }).catch(() => void 0);
|
|
33614
|
+
await import_promises19.default.rename(logPath, rotatedPath).catch(() => void 0);
|
|
33615
|
+
}
|
|
33616
|
+
function summarizeText(value) {
|
|
33617
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
33618
|
+
return {
|
|
33619
|
+
present: false,
|
|
33620
|
+
length: 0,
|
|
33621
|
+
sha256Prefix: null
|
|
33622
|
+
};
|
|
33623
|
+
}
|
|
33624
|
+
const trimmed = value.trim();
|
|
33625
|
+
return {
|
|
33626
|
+
present: true,
|
|
33627
|
+
length: trimmed.length,
|
|
33628
|
+
sha256Prefix: (0, import_node_crypto2.createHash)("sha256").update(trimmed).digest("hex").slice(0, 12)
|
|
33629
|
+
};
|
|
33630
|
+
}
|
|
33631
|
+
async function appendHookDiagnosticsEvent(params) {
|
|
33632
|
+
try {
|
|
33633
|
+
const logPath = getHookDiagnosticsLogPath();
|
|
33634
|
+
await import_promises19.default.mkdir(import_node_path7.default.dirname(logPath), { recursive: true });
|
|
33635
|
+
await rotateLogIfNeeded(logPath);
|
|
33636
|
+
const event = {
|
|
33637
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
33638
|
+
hook: params.hook,
|
|
33639
|
+
pluginVersion: pluginMetadata.version,
|
|
33640
|
+
pid: process.pid,
|
|
33641
|
+
sessionId: params.sessionId?.trim() || null,
|
|
33642
|
+
turnId: params.turnId?.trim() || null,
|
|
33643
|
+
stage: params.stage.trim(),
|
|
33644
|
+
result: params.result,
|
|
33645
|
+
reason: params.reason?.trim() || null,
|
|
33646
|
+
toolName: params.toolName?.trim() || null,
|
|
33647
|
+
repoRoot: params.repoRoot?.trim() || null,
|
|
33648
|
+
message: params.message?.trim() || null,
|
|
33649
|
+
fields: normalizeFields(params.fields)
|
|
33650
|
+
};
|
|
33651
|
+
await import_promises19.default.appendFile(logPath, `${JSON.stringify(event)}
|
|
33652
|
+
`, "utf8");
|
|
33653
|
+
} catch {
|
|
33654
|
+
}
|
|
33655
|
+
}
|
|
33656
|
+
|
|
33458
33657
|
// src/hook-utils.ts
|
|
33459
|
-
var
|
|
33460
|
-
var
|
|
33658
|
+
var import_promises20 = __toESM(require("fs/promises"), 1);
|
|
33659
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
33461
33660
|
async function readJsonStdin() {
|
|
33462
33661
|
const chunks = [];
|
|
33463
33662
|
for await (const chunk of process.stdin) {
|
|
@@ -33481,6 +33680,11 @@ function extractToolInput(payload) {
|
|
|
33481
33680
|
function extractToolResponse(payload) {
|
|
33482
33681
|
return getNestedRecord(payload.tool_response) ?? getNestedRecord(payload.toolResponse);
|
|
33483
33682
|
}
|
|
33683
|
+
function extractToolStructuredData(payload) {
|
|
33684
|
+
const toolResponse = extractToolResponse(payload);
|
|
33685
|
+
const structuredContent = getNestedRecord(toolResponse?.structuredContent) ?? getNestedRecord(payload.structuredContent);
|
|
33686
|
+
return getNestedRecord(toolResponse?.data) ?? getNestedRecord(structuredContent?.data) ?? structuredContent;
|
|
33687
|
+
}
|
|
33484
33688
|
function extractAssistantResponse(payload) {
|
|
33485
33689
|
const candidateKeys = [
|
|
33486
33690
|
"last_assistant_message",
|
|
@@ -33492,7 +33696,7 @@ function extractAssistantResponse(payload) {
|
|
|
33492
33696
|
"response",
|
|
33493
33697
|
"message"
|
|
33494
33698
|
];
|
|
33495
|
-
return extractString(payload, candidateKeys) ?? extractString(extractToolResponse(payload) ?? {}, candidateKeys) ?? extractString(extractToolInput(payload), candidateKeys);
|
|
33699
|
+
return extractString(payload, candidateKeys) ?? extractString(extractToolResponse(payload) ?? {}, candidateKeys) ?? extractString(extractToolStructuredData(payload) ?? {}, candidateKeys) ?? extractString(extractToolInput(payload), candidateKeys);
|
|
33496
33700
|
}
|
|
33497
33701
|
function extractString(input, keys) {
|
|
33498
33702
|
for (const key of keys) {
|
|
@@ -33514,16 +33718,16 @@ function extractBoolean(input, keys) {
|
|
|
33514
33718
|
}
|
|
33515
33719
|
async function findBoundRepo(startPath) {
|
|
33516
33720
|
if (!startPath) return null;
|
|
33517
|
-
let current =
|
|
33518
|
-
let stats = await
|
|
33721
|
+
let current = import_node_path8.default.resolve(startPath);
|
|
33722
|
+
let stats = await import_promises20.default.stat(current).catch(() => null);
|
|
33519
33723
|
if (stats?.isFile()) {
|
|
33520
|
-
current =
|
|
33724
|
+
current = import_node_path8.default.dirname(current);
|
|
33521
33725
|
}
|
|
33522
33726
|
while (true) {
|
|
33523
|
-
const bindingPath =
|
|
33524
|
-
const bindingStats = await
|
|
33727
|
+
const bindingPath = import_node_path8.default.join(current, ".remix", "config.json");
|
|
33728
|
+
const bindingStats = await import_promises20.default.stat(bindingPath).catch(() => null);
|
|
33525
33729
|
if (bindingStats?.isFile()) return current;
|
|
33526
|
-
const parent =
|
|
33730
|
+
const parent = import_node_path8.default.dirname(current);
|
|
33527
33731
|
if (parent === current) return null;
|
|
33528
33732
|
current = parent;
|
|
33529
33733
|
}
|
|
@@ -33552,52 +33756,52 @@ function getErrorDetails(error) {
|
|
|
33552
33756
|
if (error instanceof Error) {
|
|
33553
33757
|
const hint = typeof error.hint === "string" ? String(error.hint) : null;
|
|
33554
33758
|
return {
|
|
33555
|
-
message: error.message || "
|
|
33759
|
+
message: error.message || "Fallback Remix turn recording failed.",
|
|
33556
33760
|
hint
|
|
33557
33761
|
};
|
|
33558
33762
|
}
|
|
33559
|
-
const message = typeof error === "string" && error.trim() ? error.trim() : "
|
|
33763
|
+
const message = typeof error === "string" && error.trim() ? error.trim() : "Fallback Remix turn recording failed.";
|
|
33560
33764
|
return { message, hint: null };
|
|
33561
33765
|
}
|
|
33562
33766
|
function getRecordingBlockedMessage(status, repoRoot) {
|
|
33563
33767
|
switch (status.status) {
|
|
33564
33768
|
case "not_git_repo":
|
|
33565
33769
|
return {
|
|
33566
|
-
message: "
|
|
33770
|
+
message: "Fallback Remix turn recording failed because the repository is no longer inside a git repository.",
|
|
33567
33771
|
hint: status.hint || `Repo root: ${repoRoot}`
|
|
33568
33772
|
};
|
|
33569
33773
|
case "not_bound":
|
|
33570
33774
|
return {
|
|
33571
|
-
message: "
|
|
33775
|
+
message: "Fallback Remix turn recording failed because the repository is no longer bound to Remix.",
|
|
33572
33776
|
hint: status.hint || `Repo root: ${repoRoot}`
|
|
33573
33777
|
};
|
|
33574
33778
|
case "missing_head":
|
|
33575
33779
|
return {
|
|
33576
|
-
message: "
|
|
33780
|
+
message: "Fallback Remix turn recording failed because the repository HEAD could not be resolved.",
|
|
33577
33781
|
hint: status.hint || `Repo root: ${repoRoot}`
|
|
33578
33782
|
};
|
|
33579
33783
|
case "branch_mismatch":
|
|
33580
33784
|
return {
|
|
33581
|
-
message: "
|
|
33785
|
+
message: "Fallback Remix turn recording was blocked by the checkout's preferred-branch policy.",
|
|
33582
33786
|
hint: status.hint || `Repo root: ${repoRoot}`
|
|
33583
33787
|
};
|
|
33584
33788
|
case "metadata_conflict":
|
|
33585
33789
|
return {
|
|
33586
|
-
message: "
|
|
33790
|
+
message: "Fallback Remix turn recording was blocked because local repository metadata conflicts with the bound Remix app.",
|
|
33587
33791
|
hint: status.hint || `Repo root: ${repoRoot}`
|
|
33588
33792
|
};
|
|
33589
33793
|
case "reconcile_required":
|
|
33590
33794
|
return {
|
|
33591
|
-
message: "
|
|
33795
|
+
message: "Fallback Remix turn recording was blocked because the repository must be reconciled before recording can continue safely.",
|
|
33592
33796
|
hint: status.hint || `Repo root: ${repoRoot}`
|
|
33593
33797
|
};
|
|
33594
33798
|
default:
|
|
33595
33799
|
return null;
|
|
33596
33800
|
}
|
|
33597
33801
|
}
|
|
33598
|
-
function buildRepoIdempotencyKey(turnId, repo
|
|
33802
|
+
function buildRepoIdempotencyKey(turnId, repo) {
|
|
33599
33803
|
const repoToken = repo.currentAppId?.trim() || repo.repoRoot;
|
|
33600
|
-
return `${turnId}:${repoToken}
|
|
33804
|
+
return `${turnId}:${repoToken}:finalize_turn`;
|
|
33601
33805
|
}
|
|
33602
33806
|
function shouldSkipStopRecording(repo) {
|
|
33603
33807
|
if (repo.stopRecorded) {
|
|
@@ -33650,21 +33854,64 @@ function createFallbackTouchedRepo(params) {
|
|
|
33650
33854
|
};
|
|
33651
33855
|
}
|
|
33652
33856
|
async function recordTouchedRepo(params) {
|
|
33653
|
-
const { sessionId, turnId, repo, prompt, assistantResponse, api } = params;
|
|
33857
|
+
const { hook, sessionId, turnId, repo, prompt, assistantResponse, api } = params;
|
|
33654
33858
|
await markTouchedRepoStopAttempted(sessionId, repo.repoRoot);
|
|
33859
|
+
await appendHookDiagnosticsEvent({
|
|
33860
|
+
hook,
|
|
33861
|
+
sessionId,
|
|
33862
|
+
turnId,
|
|
33863
|
+
stage: "recording_started",
|
|
33864
|
+
result: "info",
|
|
33865
|
+
repoRoot: repo.repoRoot,
|
|
33866
|
+
fields: {
|
|
33867
|
+
hasObservedWrite: repo.hasObservedWrite,
|
|
33868
|
+
manuallyRecorded: repo.manuallyRecorded,
|
|
33869
|
+
stopAttempted: true
|
|
33870
|
+
}
|
|
33871
|
+
});
|
|
33655
33872
|
try {
|
|
33656
33873
|
const binding = await readCollabBinding(repo.repoRoot).catch(() => null);
|
|
33657
33874
|
if (!binding) {
|
|
33658
33875
|
await markTouchedRepoRecordingFailure(sessionId, repo.repoRoot, {
|
|
33659
|
-
message: "
|
|
33876
|
+
message: "Fallback Remix turn recording failed because the repository is no longer bound to Remix.",
|
|
33660
33877
|
hint: `Repo root: ${repo.repoRoot}`
|
|
33661
33878
|
});
|
|
33879
|
+
await appendHookDiagnosticsEvent({
|
|
33880
|
+
hook,
|
|
33881
|
+
sessionId,
|
|
33882
|
+
turnId,
|
|
33883
|
+
stage: "binding_lookup",
|
|
33884
|
+
result: "error",
|
|
33885
|
+
reason: "repo_not_bound",
|
|
33886
|
+
repoRoot: repo.repoRoot
|
|
33887
|
+
});
|
|
33662
33888
|
return false;
|
|
33663
33889
|
}
|
|
33664
33890
|
const workspaceDiff = await getWorkspaceDiff(repo.repoRoot);
|
|
33665
33891
|
if (workspaceDiff.diff.trim()) {
|
|
33892
|
+
await appendHookDiagnosticsEvent({
|
|
33893
|
+
hook,
|
|
33894
|
+
sessionId,
|
|
33895
|
+
turnId,
|
|
33896
|
+
stage: "workspace_diff_checked",
|
|
33897
|
+
result: "info",
|
|
33898
|
+
repoRoot: repo.repoRoot,
|
|
33899
|
+
fields: {
|
|
33900
|
+
hasWorkspaceDiff: true,
|
|
33901
|
+
diffLength: workspaceDiff.diff.length
|
|
33902
|
+
}
|
|
33903
|
+
});
|
|
33666
33904
|
if (repo.manualRemoteChangeRecordedAt && !hasNewObservedWriteSince(repo.manualRemoteChangeRecordedAt, repo)) {
|
|
33667
33905
|
await markTouchedRepoStopRecorded(sessionId, repo.repoRoot, { mode: "changed_turn" });
|
|
33906
|
+
await appendHookDiagnosticsEvent({
|
|
33907
|
+
hook,
|
|
33908
|
+
sessionId,
|
|
33909
|
+
turnId,
|
|
33910
|
+
stage: "recording_skipped",
|
|
33911
|
+
result: "success",
|
|
33912
|
+
reason: "manual_recording_already_covers_diff",
|
|
33913
|
+
repoRoot: repo.repoRoot
|
|
33914
|
+
});
|
|
33668
33915
|
return true;
|
|
33669
33916
|
}
|
|
33670
33917
|
const recordingPreflight2 = await collabRecordingPreflight({
|
|
@@ -33674,6 +33921,19 @@ async function recordTouchedRepo(params) {
|
|
|
33674
33921
|
const blocked2 = getRecordingBlockedMessage(recordingPreflight2, repo.repoRoot);
|
|
33675
33922
|
if (blocked2) {
|
|
33676
33923
|
await markTouchedRepoRecordingFailure(sessionId, repo.repoRoot, blocked2);
|
|
33924
|
+
await appendHookDiagnosticsEvent({
|
|
33925
|
+
hook,
|
|
33926
|
+
sessionId,
|
|
33927
|
+
turnId,
|
|
33928
|
+
stage: "recording_preflight",
|
|
33929
|
+
result: "error",
|
|
33930
|
+
reason: recordingPreflight2.status,
|
|
33931
|
+
repoRoot: repo.repoRoot,
|
|
33932
|
+
message: blocked2.message,
|
|
33933
|
+
fields: {
|
|
33934
|
+
hint: blocked2.hint
|
|
33935
|
+
}
|
|
33936
|
+
});
|
|
33677
33937
|
return false;
|
|
33678
33938
|
}
|
|
33679
33939
|
await collabAdd({
|
|
@@ -33682,12 +33942,33 @@ async function recordTouchedRepo(params) {
|
|
|
33682
33942
|
prompt,
|
|
33683
33943
|
assistantResponse,
|
|
33684
33944
|
diffSource: "worktree",
|
|
33685
|
-
idempotencyKey: buildRepoIdempotencyKey(turnId, repo
|
|
33945
|
+
idempotencyKey: buildRepoIdempotencyKey(turnId, repo),
|
|
33686
33946
|
actor: HOOK_ACTOR
|
|
33687
33947
|
});
|
|
33688
33948
|
await markTouchedRepoStopRecorded(sessionId, repo.repoRoot, { mode: "changed_turn" });
|
|
33949
|
+
await appendHookDiagnosticsEvent({
|
|
33950
|
+
hook,
|
|
33951
|
+
sessionId,
|
|
33952
|
+
turnId,
|
|
33953
|
+
stage: "recording_completed",
|
|
33954
|
+
result: "success",
|
|
33955
|
+
reason: "changed_turn_recorded",
|
|
33956
|
+
repoRoot: repo.repoRoot
|
|
33957
|
+
});
|
|
33689
33958
|
return true;
|
|
33690
33959
|
}
|
|
33960
|
+
await appendHookDiagnosticsEvent({
|
|
33961
|
+
hook,
|
|
33962
|
+
sessionId,
|
|
33963
|
+
turnId,
|
|
33964
|
+
stage: "workspace_diff_checked",
|
|
33965
|
+
result: "info",
|
|
33966
|
+
repoRoot: repo.repoRoot,
|
|
33967
|
+
fields: {
|
|
33968
|
+
hasWorkspaceDiff: false,
|
|
33969
|
+
diffLength: 0
|
|
33970
|
+
}
|
|
33971
|
+
});
|
|
33691
33972
|
const recordingPreflight = await collabRecordingPreflight({
|
|
33692
33973
|
api,
|
|
33693
33974
|
cwd: repo.repoRoot
|
|
@@ -33695,6 +33976,19 @@ async function recordTouchedRepo(params) {
|
|
|
33695
33976
|
const blocked = getRecordingBlockedMessage(recordingPreflight, repo.repoRoot);
|
|
33696
33977
|
if (blocked) {
|
|
33697
33978
|
await markTouchedRepoRecordingFailure(sessionId, repo.repoRoot, blocked);
|
|
33979
|
+
await appendHookDiagnosticsEvent({
|
|
33980
|
+
hook,
|
|
33981
|
+
sessionId,
|
|
33982
|
+
turnId,
|
|
33983
|
+
stage: "recording_preflight",
|
|
33984
|
+
result: "error",
|
|
33985
|
+
reason: recordingPreflight.status,
|
|
33986
|
+
repoRoot: repo.repoRoot,
|
|
33987
|
+
message: blocked.message,
|
|
33988
|
+
fields: {
|
|
33989
|
+
hint: blocked.hint
|
|
33990
|
+
}
|
|
33991
|
+
});
|
|
33698
33992
|
return false;
|
|
33699
33993
|
}
|
|
33700
33994
|
await collabRecordTurn({
|
|
@@ -33702,36 +33996,116 @@ async function recordTouchedRepo(params) {
|
|
|
33702
33996
|
cwd: repo.repoRoot,
|
|
33703
33997
|
prompt,
|
|
33704
33998
|
assistantResponse,
|
|
33705
|
-
idempotencyKey: buildRepoIdempotencyKey(turnId, repo
|
|
33999
|
+
idempotencyKey: buildRepoIdempotencyKey(turnId, repo),
|
|
33706
34000
|
actor: HOOK_ACTOR
|
|
33707
34001
|
});
|
|
33708
34002
|
await markTouchedRepoStopRecorded(sessionId, repo.repoRoot, { mode: "no_diff_turn" });
|
|
34003
|
+
await appendHookDiagnosticsEvent({
|
|
34004
|
+
hook,
|
|
34005
|
+
sessionId,
|
|
34006
|
+
turnId,
|
|
34007
|
+
stage: "recording_completed",
|
|
34008
|
+
result: "success",
|
|
34009
|
+
reason: "no_diff_turn_recorded",
|
|
34010
|
+
repoRoot: repo.repoRoot
|
|
34011
|
+
});
|
|
33709
34012
|
return true;
|
|
33710
34013
|
} catch (error) {
|
|
33711
34014
|
const details = getErrorDetails(error);
|
|
33712
34015
|
await markTouchedRepoRecordingFailure(sessionId, repo.repoRoot, details);
|
|
34016
|
+
await appendHookDiagnosticsEvent({
|
|
34017
|
+
hook,
|
|
34018
|
+
sessionId,
|
|
34019
|
+
turnId,
|
|
34020
|
+
stage: "recording_failed",
|
|
34021
|
+
result: "error",
|
|
34022
|
+
reason: "exception",
|
|
34023
|
+
repoRoot: repo.repoRoot,
|
|
34024
|
+
message: details.message,
|
|
34025
|
+
fields: {
|
|
34026
|
+
hint: details.hint
|
|
34027
|
+
}
|
|
34028
|
+
});
|
|
33713
34029
|
return false;
|
|
33714
34030
|
}
|
|
33715
34031
|
}
|
|
33716
|
-
async function
|
|
33717
|
-
const
|
|
34032
|
+
async function runHookStopCollab(payload) {
|
|
34033
|
+
const hook = "Stop";
|
|
33718
34034
|
if (extractBoolean(payload, ["stop_hook_active"])) {
|
|
34035
|
+
await appendHookDiagnosticsEvent({
|
|
34036
|
+
hook,
|
|
34037
|
+
stage: "reentrancy_guard",
|
|
34038
|
+
result: "skip",
|
|
34039
|
+
reason: "stop_hook_active"
|
|
34040
|
+
});
|
|
33719
34041
|
return;
|
|
33720
34042
|
}
|
|
33721
34043
|
const sessionId = extractString(payload, ["session_id"]);
|
|
34044
|
+
await appendHookDiagnosticsEvent({
|
|
34045
|
+
hook,
|
|
34046
|
+
sessionId,
|
|
34047
|
+
stage: "payload_received",
|
|
34048
|
+
result: "start",
|
|
34049
|
+
fields: {
|
|
34050
|
+
hasSessionId: Boolean(sessionId),
|
|
34051
|
+
hasStopHookActive: Boolean(extractBoolean(payload, ["stop_hook_active"])),
|
|
34052
|
+
hasAssistantResponse: summarizeText(extractAssistantResponse(payload)).present
|
|
34053
|
+
}
|
|
34054
|
+
});
|
|
33722
34055
|
if (!sessionId) {
|
|
34056
|
+
await appendHookDiagnosticsEvent({
|
|
34057
|
+
hook,
|
|
34058
|
+
stage: "payload_validation",
|
|
34059
|
+
result: "skip",
|
|
34060
|
+
reason: "missing_session_id"
|
|
34061
|
+
});
|
|
33723
34062
|
return;
|
|
33724
34063
|
}
|
|
33725
34064
|
const state = await loadPendingTurnState(sessionId);
|
|
33726
34065
|
if (!state) {
|
|
34066
|
+
await appendHookDiagnosticsEvent({
|
|
34067
|
+
hook,
|
|
34068
|
+
sessionId,
|
|
34069
|
+
stage: "state_lookup",
|
|
34070
|
+
result: "skip",
|
|
34071
|
+
reason: "pending_state_not_found"
|
|
34072
|
+
});
|
|
33727
34073
|
return;
|
|
33728
34074
|
}
|
|
34075
|
+
await appendHookDiagnosticsEvent({
|
|
34076
|
+
hook,
|
|
34077
|
+
sessionId,
|
|
34078
|
+
turnId: state.turnId,
|
|
34079
|
+
stage: "state_loaded",
|
|
34080
|
+
result: "info",
|
|
34081
|
+
fields: {
|
|
34082
|
+
consultedMemory: state.consultedMemory,
|
|
34083
|
+
touchedRepoCount: Object.keys(state.touchedRepos).length,
|
|
34084
|
+
hasTurnFailure: Boolean(state.turnFailureMessage)
|
|
34085
|
+
}
|
|
34086
|
+
});
|
|
33729
34087
|
try {
|
|
33730
34088
|
let touchedRepos = await listTouchedRepos(sessionId);
|
|
33731
34089
|
if (touchedRepos.length === 0) {
|
|
33732
34090
|
const fallbackRepo = await resolveBoundRepoSummary(state.initialCwd);
|
|
33733
34091
|
if (!fallbackRepo) {
|
|
33734
34092
|
await clearPendingTurnState(sessionId);
|
|
34093
|
+
await appendHookDiagnosticsEvent({
|
|
34094
|
+
hook,
|
|
34095
|
+
sessionId,
|
|
34096
|
+
turnId: state.turnId,
|
|
34097
|
+
stage: "fallback_repo_lookup",
|
|
34098
|
+
result: "skip",
|
|
34099
|
+
reason: "no_bound_repo_for_fallback"
|
|
34100
|
+
});
|
|
34101
|
+
await appendHookDiagnosticsEvent({
|
|
34102
|
+
hook,
|
|
34103
|
+
sessionId,
|
|
34104
|
+
turnId: state.turnId,
|
|
34105
|
+
stage: "state_cleanup",
|
|
34106
|
+
result: "success",
|
|
34107
|
+
reason: "cleared_without_bound_repo"
|
|
34108
|
+
});
|
|
33735
34109
|
return;
|
|
33736
34110
|
}
|
|
33737
34111
|
await upsertTouchedRepo(sessionId, {
|
|
@@ -33746,22 +34120,80 @@ async function main() {
|
|
|
33746
34120
|
if (touchedRepos.length === 0) {
|
|
33747
34121
|
touchedRepos = [createFallbackTouchedRepo(fallbackRepo)];
|
|
33748
34122
|
}
|
|
34123
|
+
await appendHookDiagnosticsEvent({
|
|
34124
|
+
hook,
|
|
34125
|
+
sessionId,
|
|
34126
|
+
turnId: state.turnId,
|
|
34127
|
+
stage: "fallback_repo_lookup",
|
|
34128
|
+
result: "info",
|
|
34129
|
+
repoRoot: fallbackRepo.repoRoot,
|
|
34130
|
+
fields: {
|
|
34131
|
+
touchedRepoCount: touchedRepos.length
|
|
34132
|
+
}
|
|
34133
|
+
});
|
|
33749
34134
|
}
|
|
33750
34135
|
const prompt = state.prompt.trim();
|
|
33751
34136
|
const assistantResponse = (extractAssistantResponse(payload) || "").trim();
|
|
34137
|
+
const promptSummary = summarizeText(prompt);
|
|
34138
|
+
const assistantResponseSummary = summarizeText(assistantResponse);
|
|
34139
|
+
await appendHookDiagnosticsEvent({
|
|
34140
|
+
hook,
|
|
34141
|
+
sessionId,
|
|
34142
|
+
turnId: state.turnId,
|
|
34143
|
+
stage: "response_summary",
|
|
34144
|
+
result: "info",
|
|
34145
|
+
fields: {
|
|
34146
|
+
promptLength: promptSummary.length,
|
|
34147
|
+
promptHash: promptSummary.sha256Prefix,
|
|
34148
|
+
assistantResponseLength: assistantResponseSummary.length,
|
|
34149
|
+
assistantResponseHash: assistantResponseSummary.sha256Prefix
|
|
34150
|
+
}
|
|
34151
|
+
});
|
|
33752
34152
|
if (!prompt || !assistantResponse) {
|
|
33753
34153
|
await markPendingTurnFailure(sessionId, {
|
|
33754
|
-
message: "
|
|
34154
|
+
message: "Fallback Remix turn recording failed because the prompt or assistant response was missing."
|
|
34155
|
+
});
|
|
34156
|
+
await appendHookDiagnosticsEvent({
|
|
34157
|
+
hook,
|
|
34158
|
+
sessionId,
|
|
34159
|
+
turnId: state.turnId,
|
|
34160
|
+
stage: "response_validation",
|
|
34161
|
+
result: "error",
|
|
34162
|
+
reason: !prompt ? "missing_prompt" : "missing_assistant_response"
|
|
33755
34163
|
});
|
|
33756
34164
|
return;
|
|
33757
34165
|
}
|
|
33758
34166
|
const api = await createHookCollabApiClient();
|
|
34167
|
+
await appendHookDiagnosticsEvent({
|
|
34168
|
+
hook,
|
|
34169
|
+
sessionId,
|
|
34170
|
+
turnId: state.turnId,
|
|
34171
|
+
stage: "api_client_created",
|
|
34172
|
+
result: "success",
|
|
34173
|
+
fields: {
|
|
34174
|
+
touchedRepoCount: touchedRepos.length
|
|
34175
|
+
}
|
|
34176
|
+
});
|
|
33759
34177
|
let hadFailure = false;
|
|
33760
34178
|
for (const repo of touchedRepos) {
|
|
33761
34179
|
if (shouldSkipStopRecording(repo)) {
|
|
34180
|
+
await appendHookDiagnosticsEvent({
|
|
34181
|
+
hook,
|
|
34182
|
+
sessionId,
|
|
34183
|
+
turnId: state.turnId,
|
|
34184
|
+
stage: "recording_skipped",
|
|
34185
|
+
result: "info",
|
|
34186
|
+
reason: "skip_stop_recording",
|
|
34187
|
+
repoRoot: repo.repoRoot,
|
|
34188
|
+
fields: {
|
|
34189
|
+
manuallyRecorded: repo.manuallyRecorded,
|
|
34190
|
+
stopRecorded: repo.stopRecorded
|
|
34191
|
+
}
|
|
34192
|
+
});
|
|
33762
34193
|
continue;
|
|
33763
34194
|
}
|
|
33764
34195
|
const recorded = await recordTouchedRepo({
|
|
34196
|
+
hook,
|
|
33765
34197
|
sessionId,
|
|
33766
34198
|
turnId: state.turnId,
|
|
33767
34199
|
repo,
|
|
@@ -33775,16 +34207,60 @@ async function main() {
|
|
|
33775
34207
|
}
|
|
33776
34208
|
if (!hadFailure) {
|
|
33777
34209
|
await clearPendingTurnState(sessionId);
|
|
34210
|
+
await appendHookDiagnosticsEvent({
|
|
34211
|
+
hook,
|
|
34212
|
+
sessionId,
|
|
34213
|
+
turnId: state.turnId,
|
|
34214
|
+
stage: "state_cleanup",
|
|
34215
|
+
result: "success",
|
|
34216
|
+
reason: "cleared_after_success"
|
|
34217
|
+
});
|
|
34218
|
+
return;
|
|
33778
34219
|
}
|
|
34220
|
+
await appendHookDiagnosticsEvent({
|
|
34221
|
+
hook,
|
|
34222
|
+
sessionId,
|
|
34223
|
+
turnId: state.turnId,
|
|
34224
|
+
stage: "state_cleanup",
|
|
34225
|
+
result: "info",
|
|
34226
|
+
reason: "retained_after_failure"
|
|
34227
|
+
});
|
|
33779
34228
|
} catch (error) {
|
|
33780
34229
|
const details = getErrorDetails(error);
|
|
33781
34230
|
await markPendingTurnFailure(sessionId, details);
|
|
34231
|
+
await appendHookDiagnosticsEvent({
|
|
34232
|
+
hook,
|
|
34233
|
+
sessionId,
|
|
34234
|
+
turnId: state.turnId,
|
|
34235
|
+
stage: "turn_failed",
|
|
34236
|
+
result: "error",
|
|
34237
|
+
reason: "exception",
|
|
34238
|
+
message: details.message,
|
|
34239
|
+
fields: {
|
|
34240
|
+
hint: details.hint
|
|
34241
|
+
}
|
|
34242
|
+
});
|
|
33782
34243
|
}
|
|
33783
34244
|
}
|
|
34245
|
+
async function main() {
|
|
34246
|
+
const payload = await readJsonStdin();
|
|
34247
|
+
await runHookStopCollab(payload);
|
|
34248
|
+
}
|
|
33784
34249
|
main().catch((error) => {
|
|
33785
34250
|
const message = error instanceof Error ? error.message : String(error);
|
|
34251
|
+
void appendHookDiagnosticsEvent({
|
|
34252
|
+
hook: "Stop",
|
|
34253
|
+
stage: "unhandled_error",
|
|
34254
|
+
result: "error",
|
|
34255
|
+
reason: "exception",
|
|
34256
|
+
message
|
|
34257
|
+
});
|
|
33786
34258
|
process.stderr.write(`${message}
|
|
33787
34259
|
`);
|
|
33788
34260
|
process.exitCode = 0;
|
|
33789
34261
|
});
|
|
34262
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
34263
|
+
0 && (module.exports = {
|
|
34264
|
+
runHookStopCollab
|
|
34265
|
+
});
|
|
33790
34266
|
//# sourceMappingURL=hook-stop-collab.cjs.map
|