@remixhq/claude-plugin 0.1.11 → 0.1.12
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 +293 -15
- package/dist/hook-post-collab.cjs.map +1 -1
- package/dist/hook-post-collab.d.cts +2 -1
- package/dist/hook-pre-git.cjs +2 -1
- package/dist/hook-pre-git.cjs.map +1 -1
- package/dist/hook-stop-collab.cjs +460 -91
- package/dist/hook-stop-collab.cjs.map +1 -1
- package/dist/hook-stop-collab.d.cts +2 -1
- package/dist/hook-user-prompt.cjs +274 -14
- package/dist/hook-user-prompt.cjs.map +1 -1
- package/dist/hook-user-prompt.d.cts +2 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +9639 -9337
- package/dist/mcp-server.cjs.map +1 -1
- package/package.json +1 -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;
|
|
@@ -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
|
};
|
|
@@ -8859,7 +8867,7 @@ function createApiClient(config, opts) {
|
|
|
8859
8867
|
const apiKey = (opts?.apiKey ?? "").trim();
|
|
8860
8868
|
const tokenProvider = opts?.tokenProvider;
|
|
8861
8869
|
const CLIENT_KEY_HEADER = "x-comerge-api-key";
|
|
8862
|
-
async function request(
|
|
8870
|
+
async function request(path13, init) {
|
|
8863
8871
|
if (!tokenProvider) {
|
|
8864
8872
|
throw new RemixError("API client is missing a token provider.", {
|
|
8865
8873
|
exitCode: 1,
|
|
@@ -8867,7 +8875,7 @@ function createApiClient(config, opts) {
|
|
|
8867
8875
|
});
|
|
8868
8876
|
}
|
|
8869
8877
|
const auth = await tokenProvider();
|
|
8870
|
-
const url = new URL(
|
|
8878
|
+
const url = new URL(path13, config.apiUrl).toString();
|
|
8871
8879
|
const doFetch = async (bearer) => fetch(url, {
|
|
8872
8880
|
...init,
|
|
8873
8881
|
headers: {
|
|
@@ -8891,7 +8899,7 @@ function createApiClient(config, opts) {
|
|
|
8891
8899
|
const json = await readJsonSafe(res);
|
|
8892
8900
|
return json ?? null;
|
|
8893
8901
|
}
|
|
8894
|
-
async function requestBinary(
|
|
8902
|
+
async function requestBinary(path13, init) {
|
|
8895
8903
|
if (!tokenProvider) {
|
|
8896
8904
|
throw new RemixError("API client is missing a token provider.", {
|
|
8897
8905
|
exitCode: 1,
|
|
@@ -8899,7 +8907,7 @@ function createApiClient(config, opts) {
|
|
|
8899
8907
|
});
|
|
8900
8908
|
}
|
|
8901
8909
|
const auth = await tokenProvider();
|
|
8902
|
-
const url = new URL(
|
|
8910
|
+
const url = new URL(path13, config.apiUrl).toString();
|
|
8903
8911
|
const doFetch = async (bearer) => fetch(url, {
|
|
8904
8912
|
...init,
|
|
8905
8913
|
headers: {
|
|
@@ -9619,8 +9627,8 @@ function getErrorMap() {
|
|
|
9619
9627
|
|
|
9620
9628
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
9621
9629
|
var makeIssue = (params) => {
|
|
9622
|
-
const { data, path:
|
|
9623
|
-
const fullPath = [...
|
|
9630
|
+
const { data, path: path13, errorMaps, issueData } = params;
|
|
9631
|
+
const fullPath = [...path13, ...issueData.path || []];
|
|
9624
9632
|
const fullIssue = {
|
|
9625
9633
|
...issueData,
|
|
9626
9634
|
path: fullPath
|
|
@@ -9736,11 +9744,11 @@ var errorUtil;
|
|
|
9736
9744
|
|
|
9737
9745
|
// node_modules/zod/v3/types.js
|
|
9738
9746
|
var ParseInputLazyPath = class {
|
|
9739
|
-
constructor(parent, value,
|
|
9747
|
+
constructor(parent, value, path13, key) {
|
|
9740
9748
|
this._cachedPath = [];
|
|
9741
9749
|
this.parent = parent;
|
|
9742
9750
|
this.data = value;
|
|
9743
|
-
this._path =
|
|
9751
|
+
this._path = path13;
|
|
9744
9752
|
this._key = key;
|
|
9745
9753
|
}
|
|
9746
9754
|
get path() {
|
|
@@ -22073,8 +22081,8 @@ var IcebergError = class extends Error {
|
|
|
22073
22081
|
return this.status === 419;
|
|
22074
22082
|
}
|
|
22075
22083
|
};
|
|
22076
|
-
function buildUrl(baseUrl,
|
|
22077
|
-
const url = new URL(
|
|
22084
|
+
function buildUrl(baseUrl, path13, query) {
|
|
22085
|
+
const url = new URL(path13, baseUrl);
|
|
22078
22086
|
if (query) {
|
|
22079
22087
|
for (const [key, value] of Object.entries(query)) {
|
|
22080
22088
|
if (value !== void 0) {
|
|
@@ -22104,12 +22112,12 @@ function createFetchClient(options) {
|
|
|
22104
22112
|
return {
|
|
22105
22113
|
async request({
|
|
22106
22114
|
method,
|
|
22107
|
-
path:
|
|
22115
|
+
path: path13,
|
|
22108
22116
|
query,
|
|
22109
22117
|
body,
|
|
22110
22118
|
headers
|
|
22111
22119
|
}) {
|
|
22112
|
-
const url = buildUrl(options.baseUrl,
|
|
22120
|
+
const url = buildUrl(options.baseUrl, path13, query);
|
|
22113
22121
|
const authHeaders = await buildAuthHeaders(options.auth);
|
|
22114
22122
|
const res = await fetchFn(url, {
|
|
22115
22123
|
method,
|
|
@@ -22928,7 +22936,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
22928
22936
|
* @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
22937
|
* @param fileBody The body of the file to be stored in the bucket.
|
|
22930
22938
|
*/
|
|
22931
|
-
async uploadOrUpdate(method,
|
|
22939
|
+
async uploadOrUpdate(method, path13, fileBody, fileOptions) {
|
|
22932
22940
|
var _this = this;
|
|
22933
22941
|
return _this.handleOperation(async () => {
|
|
22934
22942
|
let body;
|
|
@@ -22952,7 +22960,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
22952
22960
|
if ((typeof ReadableStream !== "undefined" && body instanceof ReadableStream || body && typeof body === "object" && "pipe" in body && typeof body.pipe === "function") && !options.duplex) options.duplex = "half";
|
|
22953
22961
|
}
|
|
22954
22962
|
if (fileOptions === null || fileOptions === void 0 ? void 0 : fileOptions.headers) headers = _objectSpread22(_objectSpread22({}, headers), fileOptions.headers);
|
|
22955
|
-
const cleanPath = _this._removeEmptyFolders(
|
|
22963
|
+
const cleanPath = _this._removeEmptyFolders(path13);
|
|
22956
22964
|
const _path = _this._getFinalPath(cleanPath);
|
|
22957
22965
|
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
22966
|
return {
|
|
@@ -23013,8 +23021,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23013
23021
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23014
23022
|
* - 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
23023
|
*/
|
|
23016
|
-
async upload(
|
|
23017
|
-
return this.uploadOrUpdate("POST",
|
|
23024
|
+
async upload(path13, fileBody, fileOptions) {
|
|
23025
|
+
return this.uploadOrUpdate("POST", path13, fileBody, fileOptions);
|
|
23018
23026
|
}
|
|
23019
23027
|
/**
|
|
23020
23028
|
* Upload a file with a token generated from `createSignedUploadUrl`.
|
|
@@ -23053,9 +23061,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23053
23061
|
* - `objects` table permissions: none
|
|
23054
23062
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23055
23063
|
*/
|
|
23056
|
-
async uploadToSignedUrl(
|
|
23064
|
+
async uploadToSignedUrl(path13, token, fileBody, fileOptions) {
|
|
23057
23065
|
var _this3 = this;
|
|
23058
|
-
const cleanPath = _this3._removeEmptyFolders(
|
|
23066
|
+
const cleanPath = _this3._removeEmptyFolders(path13);
|
|
23059
23067
|
const _path = _this3._getFinalPath(cleanPath);
|
|
23060
23068
|
const url = new URL(_this3.url + `/object/upload/sign/${_path}`);
|
|
23061
23069
|
url.searchParams.set("token", token);
|
|
@@ -23117,10 +23125,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23117
23125
|
* - `objects` table permissions: `insert`
|
|
23118
23126
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23119
23127
|
*/
|
|
23120
|
-
async createSignedUploadUrl(
|
|
23128
|
+
async createSignedUploadUrl(path13, options) {
|
|
23121
23129
|
var _this4 = this;
|
|
23122
23130
|
return _this4.handleOperation(async () => {
|
|
23123
|
-
let _path = _this4._getFinalPath(
|
|
23131
|
+
let _path = _this4._getFinalPath(path13);
|
|
23124
23132
|
const headers = _objectSpread22({}, _this4.headers);
|
|
23125
23133
|
if (options === null || options === void 0 ? void 0 : options.upsert) headers["x-upsert"] = "true";
|
|
23126
23134
|
const data = await post(_this4.fetch, `${_this4.url}/object/upload/sign/${_path}`, {}, { headers });
|
|
@@ -23129,7 +23137,7 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23129
23137
|
if (!token) throw new StorageError("No token returned by API");
|
|
23130
23138
|
return {
|
|
23131
23139
|
signedUrl: url.toString(),
|
|
23132
|
-
path:
|
|
23140
|
+
path: path13,
|
|
23133
23141
|
token
|
|
23134
23142
|
};
|
|
23135
23143
|
});
|
|
@@ -23185,8 +23193,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23185
23193
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23186
23194
|
* - 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
23195
|
*/
|
|
23188
|
-
async update(
|
|
23189
|
-
return this.uploadOrUpdate("PUT",
|
|
23196
|
+
async update(path13, fileBody, fileOptions) {
|
|
23197
|
+
return this.uploadOrUpdate("PUT", path13, fileBody, fileOptions);
|
|
23190
23198
|
}
|
|
23191
23199
|
/**
|
|
23192
23200
|
* Moves an existing file to a new path in the same bucket.
|
|
@@ -23333,10 +23341,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23333
23341
|
* - `objects` table permissions: `select`
|
|
23334
23342
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23335
23343
|
*/
|
|
23336
|
-
async createSignedUrl(
|
|
23344
|
+
async createSignedUrl(path13, expiresIn, options) {
|
|
23337
23345
|
var _this8 = this;
|
|
23338
23346
|
return _this8.handleOperation(async () => {
|
|
23339
|
-
let _path = _this8._getFinalPath(
|
|
23347
|
+
let _path = _this8._getFinalPath(path13);
|
|
23340
23348
|
const hasTransform = typeof (options === null || options === void 0 ? void 0 : options.transform) === "object" && options.transform !== null && Object.keys(options.transform).length > 0;
|
|
23341
23349
|
let data = await post(_this8.fetch, `${_this8.url}/object/sign/${_path}`, _objectSpread22({ expiresIn }, hasTransform ? { transform: options.transform } : {}), { headers: _this8.headers });
|
|
23342
23350
|
const downloadQueryParam = (options === null || options === void 0 ? void 0 : options.download) ? `&download=${options.download === true ? "" : options.download}` : "";
|
|
@@ -23463,11 +23471,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23463
23471
|
* - `objects` table permissions: `select`
|
|
23464
23472
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23465
23473
|
*/
|
|
23466
|
-
download(
|
|
23474
|
+
download(path13, options, parameters) {
|
|
23467
23475
|
const renderPath = typeof (options === null || options === void 0 ? void 0 : options.transform) !== "undefined" ? "render/image/authenticated" : "object";
|
|
23468
23476
|
const transformationQuery = this.transformOptsToQueryString((options === null || options === void 0 ? void 0 : options.transform) || {});
|
|
23469
23477
|
const queryString = transformationQuery ? `?${transformationQuery}` : "";
|
|
23470
|
-
const _path = this._getFinalPath(
|
|
23478
|
+
const _path = this._getFinalPath(path13);
|
|
23471
23479
|
const downloadFn = () => get(this.fetch, `${this.url}/${renderPath}/${_path}${queryString}`, {
|
|
23472
23480
|
headers: this.headers,
|
|
23473
23481
|
noResolveJson: true
|
|
@@ -23497,9 +23505,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23497
23505
|
* }
|
|
23498
23506
|
* ```
|
|
23499
23507
|
*/
|
|
23500
|
-
async info(
|
|
23508
|
+
async info(path13) {
|
|
23501
23509
|
var _this10 = this;
|
|
23502
|
-
const _path = _this10._getFinalPath(
|
|
23510
|
+
const _path = _this10._getFinalPath(path13);
|
|
23503
23511
|
return _this10.handleOperation(async () => {
|
|
23504
23512
|
return recursiveToCamel(await get(_this10.fetch, `${_this10.url}/object/info/${_path}`, { headers: _this10.headers }));
|
|
23505
23513
|
});
|
|
@@ -23519,9 +23527,9 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23519
23527
|
* .exists('folder/avatar1.png')
|
|
23520
23528
|
* ```
|
|
23521
23529
|
*/
|
|
23522
|
-
async exists(
|
|
23530
|
+
async exists(path13) {
|
|
23523
23531
|
var _this11 = this;
|
|
23524
|
-
const _path = _this11._getFinalPath(
|
|
23532
|
+
const _path = _this11._getFinalPath(path13);
|
|
23525
23533
|
try {
|
|
23526
23534
|
await head(_this11.fetch, `${_this11.url}/object/${_path}`, { headers: _this11.headers });
|
|
23527
23535
|
return {
|
|
@@ -23598,8 +23606,8 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23598
23606
|
* - `objects` table permissions: none
|
|
23599
23607
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23600
23608
|
*/
|
|
23601
|
-
getPublicUrl(
|
|
23602
|
-
const _path = this._getFinalPath(
|
|
23609
|
+
getPublicUrl(path13, options) {
|
|
23610
|
+
const _path = this._getFinalPath(path13);
|
|
23603
23611
|
const _queryString = [];
|
|
23604
23612
|
const downloadQueryParam = (options === null || options === void 0 ? void 0 : options.download) ? `download=${options.download === true ? "" : options.download}` : "";
|
|
23605
23613
|
if (downloadQueryParam !== "") _queryString.push(downloadQueryParam);
|
|
@@ -23738,10 +23746,10 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23738
23746
|
* - `objects` table permissions: `select`
|
|
23739
23747
|
* - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works
|
|
23740
23748
|
*/
|
|
23741
|
-
async list(
|
|
23749
|
+
async list(path13, options, parameters) {
|
|
23742
23750
|
var _this13 = this;
|
|
23743
23751
|
return _this13.handleOperation(async () => {
|
|
23744
|
-
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix:
|
|
23752
|
+
const body = _objectSpread22(_objectSpread22(_objectSpread22({}, DEFAULT_SEARCH_OPTIONS), options), {}, { prefix: path13 || "" });
|
|
23745
23753
|
return await post(_this13.fetch, `${_this13.url}/object/list/${_this13.bucketId}`, body, { headers: _this13.headers }, parameters);
|
|
23746
23754
|
});
|
|
23747
23755
|
}
|
|
@@ -23805,11 +23813,11 @@ var StorageFileApi = class extends BaseApiClient {
|
|
|
23805
23813
|
if (typeof Buffer !== "undefined") return Buffer.from(data).toString("base64");
|
|
23806
23814
|
return btoa(data);
|
|
23807
23815
|
}
|
|
23808
|
-
_getFinalPath(
|
|
23809
|
-
return `${this.bucketId}/${
|
|
23816
|
+
_getFinalPath(path13) {
|
|
23817
|
+
return `${this.bucketId}/${path13.replace(/^\/+/, "")}`;
|
|
23810
23818
|
}
|
|
23811
|
-
_removeEmptyFolders(
|
|
23812
|
-
return
|
|
23819
|
+
_removeEmptyFolders(path13) {
|
|
23820
|
+
return path13.replace(/^\/|\/$/g, "").replace(/\/+/g, "/");
|
|
23813
23821
|
}
|
|
23814
23822
|
transformOptsToQueryString(transform) {
|
|
23815
23823
|
const params = [];
|
|
@@ -33085,13 +33093,20 @@ async function createHookCollabApiClient() {
|
|
|
33085
33093
|
});
|
|
33086
33094
|
}
|
|
33087
33095
|
|
|
33096
|
+
// src/hook-diagnostics.ts
|
|
33097
|
+
var import_node_crypto2 = require("crypto");
|
|
33098
|
+
var import_promises19 = __toESM(require("fs/promises"), 1);
|
|
33099
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
33100
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
33101
|
+
|
|
33088
33102
|
// src/hook-state.ts
|
|
33089
33103
|
var import_promises18 = __toESM(require("fs/promises"), 1);
|
|
33090
33104
|
var import_node_os4 = __toESM(require("os"), 1);
|
|
33091
33105
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
33092
33106
|
var import_node_crypto = require("crypto");
|
|
33093
33107
|
function stateRoot() {
|
|
33094
|
-
|
|
33108
|
+
const configured = process.env.REMIX_CLAUDE_PLUGIN_HOOK_STATE_ROOT?.trim();
|
|
33109
|
+
return configured || import_node_path6.default.join(import_node_os4.default.tmpdir(), "remix-claude-plugin-hooks");
|
|
33095
33110
|
}
|
|
33096
33111
|
function statePath(sessionId) {
|
|
33097
33112
|
return import_node_path6.default.join(stateRoot(), `${sessionId}.json`);
|
|
@@ -33156,6 +33171,7 @@ async function tryRemoveStaleStateLock(sessionId) {
|
|
|
33156
33171
|
async function acquireStateLock(sessionId) {
|
|
33157
33172
|
const lockPath = stateLockPath(sessionId);
|
|
33158
33173
|
const deadline = Date.now() + STATE_LOCK_WAIT_MS;
|
|
33174
|
+
await import_promises18.default.mkdir(stateRoot(), { recursive: true });
|
|
33159
33175
|
while (true) {
|
|
33160
33176
|
try {
|
|
33161
33177
|
await import_promises18.default.mkdir(lockPath);
|
|
@@ -33404,7 +33420,7 @@ async function clearPendingTurnState(sessionId) {
|
|
|
33404
33420
|
// package.json
|
|
33405
33421
|
var package_default = {
|
|
33406
33422
|
name: "@remixhq/claude-plugin",
|
|
33407
|
-
version: "0.1.
|
|
33423
|
+
version: "0.1.12",
|
|
33408
33424
|
description: "Claude Code plugin for Remix collaboration workflows",
|
|
33409
33425
|
homepage: "https://github.com/RemixDotOne/remix-claude-plugin",
|
|
33410
33426
|
license: "MIT",
|
|
@@ -33455,9 +33471,90 @@ var pluginMetadata = {
|
|
|
33455
33471
|
agentName: "remix-collab"
|
|
33456
33472
|
};
|
|
33457
33473
|
|
|
33474
|
+
// src/hook-diagnostics.ts
|
|
33475
|
+
var MAX_LOG_BYTES = 512 * 1024;
|
|
33476
|
+
function resolveClaudeRoot() {
|
|
33477
|
+
const configured = process.env.CLAUDE_CONFIG_DIR?.trim();
|
|
33478
|
+
return configured || import_node_path7.default.join(import_node_os5.default.homedir(), ".claude");
|
|
33479
|
+
}
|
|
33480
|
+
function resolvePluginDataDirName() {
|
|
33481
|
+
return `${pluginMetadata.pluginId}-${pluginMetadata.pluginId}`;
|
|
33482
|
+
}
|
|
33483
|
+
function getHookDiagnosticsDirPath() {
|
|
33484
|
+
const configured = process.env.REMIX_CLAUDE_PLUGIN_HOOK_DIAGNOSTICS_DIR?.trim();
|
|
33485
|
+
return configured || import_node_path7.default.join(resolveClaudeRoot(), "plugins", "data", resolvePluginDataDirName());
|
|
33486
|
+
}
|
|
33487
|
+
function getHookDiagnosticsLogPath() {
|
|
33488
|
+
return import_node_path7.default.join(getHookDiagnosticsDirPath(), "hooks.ndjson");
|
|
33489
|
+
}
|
|
33490
|
+
function toFieldValue(value) {
|
|
33491
|
+
if (value === null) return null;
|
|
33492
|
+
if (typeof value === "string") return value;
|
|
33493
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
33494
|
+
if (typeof value === "boolean") return value;
|
|
33495
|
+
return void 0;
|
|
33496
|
+
}
|
|
33497
|
+
function normalizeFields(fields) {
|
|
33498
|
+
if (!fields) return {};
|
|
33499
|
+
const normalizedEntries = Object.entries(fields).map(([key, value]) => {
|
|
33500
|
+
const normalized = toFieldValue(value);
|
|
33501
|
+
return normalized === void 0 ? null : [key, normalized];
|
|
33502
|
+
}).filter((entry) => entry !== null);
|
|
33503
|
+
return Object.fromEntries(normalizedEntries);
|
|
33504
|
+
}
|
|
33505
|
+
async function rotateLogIfNeeded(logPath) {
|
|
33506
|
+
const stat = await import_promises19.default.stat(logPath).catch(() => null);
|
|
33507
|
+
if (!stat || stat.size < MAX_LOG_BYTES) {
|
|
33508
|
+
return;
|
|
33509
|
+
}
|
|
33510
|
+
const rotatedPath = `${logPath}.1`;
|
|
33511
|
+
await import_promises19.default.rm(rotatedPath, { force: true }).catch(() => void 0);
|
|
33512
|
+
await import_promises19.default.rename(logPath, rotatedPath).catch(() => void 0);
|
|
33513
|
+
}
|
|
33514
|
+
function summarizeText(value) {
|
|
33515
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
33516
|
+
return {
|
|
33517
|
+
present: false,
|
|
33518
|
+
length: 0,
|
|
33519
|
+
sha256Prefix: null
|
|
33520
|
+
};
|
|
33521
|
+
}
|
|
33522
|
+
const trimmed = value.trim();
|
|
33523
|
+
return {
|
|
33524
|
+
present: true,
|
|
33525
|
+
length: trimmed.length,
|
|
33526
|
+
sha256Prefix: (0, import_node_crypto2.createHash)("sha256").update(trimmed).digest("hex").slice(0, 12)
|
|
33527
|
+
};
|
|
33528
|
+
}
|
|
33529
|
+
async function appendHookDiagnosticsEvent(params) {
|
|
33530
|
+
try {
|
|
33531
|
+
const logPath = getHookDiagnosticsLogPath();
|
|
33532
|
+
await import_promises19.default.mkdir(import_node_path7.default.dirname(logPath), { recursive: true });
|
|
33533
|
+
await rotateLogIfNeeded(logPath);
|
|
33534
|
+
const event = {
|
|
33535
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
33536
|
+
hook: params.hook,
|
|
33537
|
+
pluginVersion: pluginMetadata.version,
|
|
33538
|
+
pid: process.pid,
|
|
33539
|
+
sessionId: params.sessionId?.trim() || null,
|
|
33540
|
+
turnId: params.turnId?.trim() || null,
|
|
33541
|
+
stage: params.stage.trim(),
|
|
33542
|
+
result: params.result,
|
|
33543
|
+
reason: params.reason?.trim() || null,
|
|
33544
|
+
toolName: params.toolName?.trim() || null,
|
|
33545
|
+
repoRoot: params.repoRoot?.trim() || null,
|
|
33546
|
+
message: params.message?.trim() || null,
|
|
33547
|
+
fields: normalizeFields(params.fields)
|
|
33548
|
+
};
|
|
33549
|
+
await import_promises19.default.appendFile(logPath, `${JSON.stringify(event)}
|
|
33550
|
+
`, "utf8");
|
|
33551
|
+
} catch {
|
|
33552
|
+
}
|
|
33553
|
+
}
|
|
33554
|
+
|
|
33458
33555
|
// src/hook-utils.ts
|
|
33459
|
-
var
|
|
33460
|
-
var
|
|
33556
|
+
var import_promises20 = __toESM(require("fs/promises"), 1);
|
|
33557
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
33461
33558
|
async function readJsonStdin() {
|
|
33462
33559
|
const chunks = [];
|
|
33463
33560
|
for await (const chunk of process.stdin) {
|
|
@@ -33514,16 +33611,16 @@ function extractBoolean(input, keys) {
|
|
|
33514
33611
|
}
|
|
33515
33612
|
async function findBoundRepo(startPath) {
|
|
33516
33613
|
if (!startPath) return null;
|
|
33517
|
-
let current =
|
|
33518
|
-
let stats = await
|
|
33614
|
+
let current = import_node_path8.default.resolve(startPath);
|
|
33615
|
+
let stats = await import_promises20.default.stat(current).catch(() => null);
|
|
33519
33616
|
if (stats?.isFile()) {
|
|
33520
|
-
current =
|
|
33617
|
+
current = import_node_path8.default.dirname(current);
|
|
33521
33618
|
}
|
|
33522
33619
|
while (true) {
|
|
33523
|
-
const bindingPath =
|
|
33524
|
-
const bindingStats = await
|
|
33620
|
+
const bindingPath = import_node_path8.default.join(current, ".remix", "config.json");
|
|
33621
|
+
const bindingStats = await import_promises20.default.stat(bindingPath).catch(() => null);
|
|
33525
33622
|
if (bindingStats?.isFile()) return current;
|
|
33526
|
-
const parent =
|
|
33623
|
+
const parent = import_node_path8.default.dirname(current);
|
|
33527
33624
|
if (parent === current) return null;
|
|
33528
33625
|
current = parent;
|
|
33529
33626
|
}
|
|
@@ -33650,8 +33747,21 @@ function createFallbackTouchedRepo(params) {
|
|
|
33650
33747
|
};
|
|
33651
33748
|
}
|
|
33652
33749
|
async function recordTouchedRepo(params) {
|
|
33653
|
-
const { sessionId, turnId, repo, prompt, assistantResponse, api } = params;
|
|
33750
|
+
const { hook, sessionId, turnId, repo, prompt, assistantResponse, api } = params;
|
|
33654
33751
|
await markTouchedRepoStopAttempted(sessionId, repo.repoRoot);
|
|
33752
|
+
await appendHookDiagnosticsEvent({
|
|
33753
|
+
hook,
|
|
33754
|
+
sessionId,
|
|
33755
|
+
turnId,
|
|
33756
|
+
stage: "recording_started",
|
|
33757
|
+
result: "info",
|
|
33758
|
+
repoRoot: repo.repoRoot,
|
|
33759
|
+
fields: {
|
|
33760
|
+
hasObservedWrite: repo.hasObservedWrite,
|
|
33761
|
+
manuallyRecorded: repo.manuallyRecorded,
|
|
33762
|
+
stopAttempted: true
|
|
33763
|
+
}
|
|
33764
|
+
});
|
|
33655
33765
|
try {
|
|
33656
33766
|
const binding = await readCollabBinding(repo.repoRoot).catch(() => null);
|
|
33657
33767
|
if (!binding) {
|
|
@@ -33659,12 +33769,42 @@ async function recordTouchedRepo(params) {
|
|
|
33659
33769
|
message: "Automatic Remix turn recording failed because the repository is no longer bound to Remix.",
|
|
33660
33770
|
hint: `Repo root: ${repo.repoRoot}`
|
|
33661
33771
|
});
|
|
33772
|
+
await appendHookDiagnosticsEvent({
|
|
33773
|
+
hook,
|
|
33774
|
+
sessionId,
|
|
33775
|
+
turnId,
|
|
33776
|
+
stage: "binding_lookup",
|
|
33777
|
+
result: "error",
|
|
33778
|
+
reason: "repo_not_bound",
|
|
33779
|
+
repoRoot: repo.repoRoot
|
|
33780
|
+
});
|
|
33662
33781
|
return false;
|
|
33663
33782
|
}
|
|
33664
33783
|
const workspaceDiff = await getWorkspaceDiff(repo.repoRoot);
|
|
33665
33784
|
if (workspaceDiff.diff.trim()) {
|
|
33785
|
+
await appendHookDiagnosticsEvent({
|
|
33786
|
+
hook,
|
|
33787
|
+
sessionId,
|
|
33788
|
+
turnId,
|
|
33789
|
+
stage: "workspace_diff_checked",
|
|
33790
|
+
result: "info",
|
|
33791
|
+
repoRoot: repo.repoRoot,
|
|
33792
|
+
fields: {
|
|
33793
|
+
hasWorkspaceDiff: true,
|
|
33794
|
+
diffLength: workspaceDiff.diff.length
|
|
33795
|
+
}
|
|
33796
|
+
});
|
|
33666
33797
|
if (repo.manualRemoteChangeRecordedAt && !hasNewObservedWriteSince(repo.manualRemoteChangeRecordedAt, repo)) {
|
|
33667
33798
|
await markTouchedRepoStopRecorded(sessionId, repo.repoRoot, { mode: "changed_turn" });
|
|
33799
|
+
await appendHookDiagnosticsEvent({
|
|
33800
|
+
hook,
|
|
33801
|
+
sessionId,
|
|
33802
|
+
turnId,
|
|
33803
|
+
stage: "recording_skipped",
|
|
33804
|
+
result: "success",
|
|
33805
|
+
reason: "manual_recording_already_covers_diff",
|
|
33806
|
+
repoRoot: repo.repoRoot
|
|
33807
|
+
});
|
|
33668
33808
|
return true;
|
|
33669
33809
|
}
|
|
33670
33810
|
const recordingPreflight2 = await collabRecordingPreflight({
|
|
@@ -33674,6 +33814,19 @@ async function recordTouchedRepo(params) {
|
|
|
33674
33814
|
const blocked2 = getRecordingBlockedMessage(recordingPreflight2, repo.repoRoot);
|
|
33675
33815
|
if (blocked2) {
|
|
33676
33816
|
await markTouchedRepoRecordingFailure(sessionId, repo.repoRoot, blocked2);
|
|
33817
|
+
await appendHookDiagnosticsEvent({
|
|
33818
|
+
hook,
|
|
33819
|
+
sessionId,
|
|
33820
|
+
turnId,
|
|
33821
|
+
stage: "recording_preflight",
|
|
33822
|
+
result: "error",
|
|
33823
|
+
reason: recordingPreflight2.status,
|
|
33824
|
+
repoRoot: repo.repoRoot,
|
|
33825
|
+
message: blocked2.message,
|
|
33826
|
+
fields: {
|
|
33827
|
+
hint: blocked2.hint
|
|
33828
|
+
}
|
|
33829
|
+
});
|
|
33677
33830
|
return false;
|
|
33678
33831
|
}
|
|
33679
33832
|
await collabAdd({
|
|
@@ -33686,8 +33839,29 @@ async function recordTouchedRepo(params) {
|
|
|
33686
33839
|
actor: HOOK_ACTOR
|
|
33687
33840
|
});
|
|
33688
33841
|
await markTouchedRepoStopRecorded(sessionId, repo.repoRoot, { mode: "changed_turn" });
|
|
33842
|
+
await appendHookDiagnosticsEvent({
|
|
33843
|
+
hook,
|
|
33844
|
+
sessionId,
|
|
33845
|
+
turnId,
|
|
33846
|
+
stage: "recording_completed",
|
|
33847
|
+
result: "success",
|
|
33848
|
+
reason: "changed_turn_recorded",
|
|
33849
|
+
repoRoot: repo.repoRoot
|
|
33850
|
+
});
|
|
33689
33851
|
return true;
|
|
33690
33852
|
}
|
|
33853
|
+
await appendHookDiagnosticsEvent({
|
|
33854
|
+
hook,
|
|
33855
|
+
sessionId,
|
|
33856
|
+
turnId,
|
|
33857
|
+
stage: "workspace_diff_checked",
|
|
33858
|
+
result: "info",
|
|
33859
|
+
repoRoot: repo.repoRoot,
|
|
33860
|
+
fields: {
|
|
33861
|
+
hasWorkspaceDiff: false,
|
|
33862
|
+
diffLength: 0
|
|
33863
|
+
}
|
|
33864
|
+
});
|
|
33691
33865
|
const recordingPreflight = await collabRecordingPreflight({
|
|
33692
33866
|
api,
|
|
33693
33867
|
cwd: repo.repoRoot
|
|
@@ -33695,6 +33869,19 @@ async function recordTouchedRepo(params) {
|
|
|
33695
33869
|
const blocked = getRecordingBlockedMessage(recordingPreflight, repo.repoRoot);
|
|
33696
33870
|
if (blocked) {
|
|
33697
33871
|
await markTouchedRepoRecordingFailure(sessionId, repo.repoRoot, blocked);
|
|
33872
|
+
await appendHookDiagnosticsEvent({
|
|
33873
|
+
hook,
|
|
33874
|
+
sessionId,
|
|
33875
|
+
turnId,
|
|
33876
|
+
stage: "recording_preflight",
|
|
33877
|
+
result: "error",
|
|
33878
|
+
reason: recordingPreflight.status,
|
|
33879
|
+
repoRoot: repo.repoRoot,
|
|
33880
|
+
message: blocked.message,
|
|
33881
|
+
fields: {
|
|
33882
|
+
hint: blocked.hint
|
|
33883
|
+
}
|
|
33884
|
+
});
|
|
33698
33885
|
return false;
|
|
33699
33886
|
}
|
|
33700
33887
|
await collabRecordTurn({
|
|
@@ -33706,32 +33893,112 @@ async function recordTouchedRepo(params) {
|
|
|
33706
33893
|
actor: HOOK_ACTOR
|
|
33707
33894
|
});
|
|
33708
33895
|
await markTouchedRepoStopRecorded(sessionId, repo.repoRoot, { mode: "no_diff_turn" });
|
|
33896
|
+
await appendHookDiagnosticsEvent({
|
|
33897
|
+
hook,
|
|
33898
|
+
sessionId,
|
|
33899
|
+
turnId,
|
|
33900
|
+
stage: "recording_completed",
|
|
33901
|
+
result: "success",
|
|
33902
|
+
reason: "no_diff_turn_recorded",
|
|
33903
|
+
repoRoot: repo.repoRoot
|
|
33904
|
+
});
|
|
33709
33905
|
return true;
|
|
33710
33906
|
} catch (error) {
|
|
33711
33907
|
const details = getErrorDetails(error);
|
|
33712
33908
|
await markTouchedRepoRecordingFailure(sessionId, repo.repoRoot, details);
|
|
33909
|
+
await appendHookDiagnosticsEvent({
|
|
33910
|
+
hook,
|
|
33911
|
+
sessionId,
|
|
33912
|
+
turnId,
|
|
33913
|
+
stage: "recording_failed",
|
|
33914
|
+
result: "error",
|
|
33915
|
+
reason: "exception",
|
|
33916
|
+
repoRoot: repo.repoRoot,
|
|
33917
|
+
message: details.message,
|
|
33918
|
+
fields: {
|
|
33919
|
+
hint: details.hint
|
|
33920
|
+
}
|
|
33921
|
+
});
|
|
33713
33922
|
return false;
|
|
33714
33923
|
}
|
|
33715
33924
|
}
|
|
33716
|
-
async function
|
|
33717
|
-
const
|
|
33925
|
+
async function runHookStopCollab(payload) {
|
|
33926
|
+
const hook = "Stop";
|
|
33718
33927
|
if (extractBoolean(payload, ["stop_hook_active"])) {
|
|
33928
|
+
await appendHookDiagnosticsEvent({
|
|
33929
|
+
hook,
|
|
33930
|
+
stage: "reentrancy_guard",
|
|
33931
|
+
result: "skip",
|
|
33932
|
+
reason: "stop_hook_active"
|
|
33933
|
+
});
|
|
33719
33934
|
return;
|
|
33720
33935
|
}
|
|
33721
33936
|
const sessionId = extractString(payload, ["session_id"]);
|
|
33937
|
+
await appendHookDiagnosticsEvent({
|
|
33938
|
+
hook,
|
|
33939
|
+
sessionId,
|
|
33940
|
+
stage: "payload_received",
|
|
33941
|
+
result: "start",
|
|
33942
|
+
fields: {
|
|
33943
|
+
hasSessionId: Boolean(sessionId),
|
|
33944
|
+
hasStopHookActive: Boolean(extractBoolean(payload, ["stop_hook_active"])),
|
|
33945
|
+
hasAssistantResponse: summarizeText(extractAssistantResponse(payload)).present
|
|
33946
|
+
}
|
|
33947
|
+
});
|
|
33722
33948
|
if (!sessionId) {
|
|
33949
|
+
await appendHookDiagnosticsEvent({
|
|
33950
|
+
hook,
|
|
33951
|
+
stage: "payload_validation",
|
|
33952
|
+
result: "skip",
|
|
33953
|
+
reason: "missing_session_id"
|
|
33954
|
+
});
|
|
33723
33955
|
return;
|
|
33724
33956
|
}
|
|
33725
33957
|
const state = await loadPendingTurnState(sessionId);
|
|
33726
33958
|
if (!state) {
|
|
33959
|
+
await appendHookDiagnosticsEvent({
|
|
33960
|
+
hook,
|
|
33961
|
+
sessionId,
|
|
33962
|
+
stage: "state_lookup",
|
|
33963
|
+
result: "skip",
|
|
33964
|
+
reason: "pending_state_not_found"
|
|
33965
|
+
});
|
|
33727
33966
|
return;
|
|
33728
33967
|
}
|
|
33968
|
+
await appendHookDiagnosticsEvent({
|
|
33969
|
+
hook,
|
|
33970
|
+
sessionId,
|
|
33971
|
+
turnId: state.turnId,
|
|
33972
|
+
stage: "state_loaded",
|
|
33973
|
+
result: "info",
|
|
33974
|
+
fields: {
|
|
33975
|
+
consultedMemory: state.consultedMemory,
|
|
33976
|
+
touchedRepoCount: Object.keys(state.touchedRepos).length,
|
|
33977
|
+
hasTurnFailure: Boolean(state.turnFailureMessage)
|
|
33978
|
+
}
|
|
33979
|
+
});
|
|
33729
33980
|
try {
|
|
33730
33981
|
let touchedRepos = await listTouchedRepos(sessionId);
|
|
33731
33982
|
if (touchedRepos.length === 0) {
|
|
33732
33983
|
const fallbackRepo = await resolveBoundRepoSummary(state.initialCwd);
|
|
33733
33984
|
if (!fallbackRepo) {
|
|
33734
33985
|
await clearPendingTurnState(sessionId);
|
|
33986
|
+
await appendHookDiagnosticsEvent({
|
|
33987
|
+
hook,
|
|
33988
|
+
sessionId,
|
|
33989
|
+
turnId: state.turnId,
|
|
33990
|
+
stage: "fallback_repo_lookup",
|
|
33991
|
+
result: "skip",
|
|
33992
|
+
reason: "no_bound_repo_for_fallback"
|
|
33993
|
+
});
|
|
33994
|
+
await appendHookDiagnosticsEvent({
|
|
33995
|
+
hook,
|
|
33996
|
+
sessionId,
|
|
33997
|
+
turnId: state.turnId,
|
|
33998
|
+
stage: "state_cleanup",
|
|
33999
|
+
result: "success",
|
|
34000
|
+
reason: "cleared_without_bound_repo"
|
|
34001
|
+
});
|
|
33735
34002
|
return;
|
|
33736
34003
|
}
|
|
33737
34004
|
await upsertTouchedRepo(sessionId, {
|
|
@@ -33746,22 +34013,80 @@ async function main() {
|
|
|
33746
34013
|
if (touchedRepos.length === 0) {
|
|
33747
34014
|
touchedRepos = [createFallbackTouchedRepo(fallbackRepo)];
|
|
33748
34015
|
}
|
|
34016
|
+
await appendHookDiagnosticsEvent({
|
|
34017
|
+
hook,
|
|
34018
|
+
sessionId,
|
|
34019
|
+
turnId: state.turnId,
|
|
34020
|
+
stage: "fallback_repo_lookup",
|
|
34021
|
+
result: "info",
|
|
34022
|
+
repoRoot: fallbackRepo.repoRoot,
|
|
34023
|
+
fields: {
|
|
34024
|
+
touchedRepoCount: touchedRepos.length
|
|
34025
|
+
}
|
|
34026
|
+
});
|
|
33749
34027
|
}
|
|
33750
34028
|
const prompt = state.prompt.trim();
|
|
33751
34029
|
const assistantResponse = (extractAssistantResponse(payload) || "").trim();
|
|
34030
|
+
const promptSummary = summarizeText(prompt);
|
|
34031
|
+
const assistantResponseSummary = summarizeText(assistantResponse);
|
|
34032
|
+
await appendHookDiagnosticsEvent({
|
|
34033
|
+
hook,
|
|
34034
|
+
sessionId,
|
|
34035
|
+
turnId: state.turnId,
|
|
34036
|
+
stage: "response_summary",
|
|
34037
|
+
result: "info",
|
|
34038
|
+
fields: {
|
|
34039
|
+
promptLength: promptSummary.length,
|
|
34040
|
+
promptHash: promptSummary.sha256Prefix,
|
|
34041
|
+
assistantResponseLength: assistantResponseSummary.length,
|
|
34042
|
+
assistantResponseHash: assistantResponseSummary.sha256Prefix
|
|
34043
|
+
}
|
|
34044
|
+
});
|
|
33752
34045
|
if (!prompt || !assistantResponse) {
|
|
33753
34046
|
await markPendingTurnFailure(sessionId, {
|
|
33754
34047
|
message: "Automatic Remix turn recording failed because the prompt or assistant response was missing."
|
|
33755
34048
|
});
|
|
34049
|
+
await appendHookDiagnosticsEvent({
|
|
34050
|
+
hook,
|
|
34051
|
+
sessionId,
|
|
34052
|
+
turnId: state.turnId,
|
|
34053
|
+
stage: "response_validation",
|
|
34054
|
+
result: "error",
|
|
34055
|
+
reason: !prompt ? "missing_prompt" : "missing_assistant_response"
|
|
34056
|
+
});
|
|
33756
34057
|
return;
|
|
33757
34058
|
}
|
|
33758
34059
|
const api = await createHookCollabApiClient();
|
|
34060
|
+
await appendHookDiagnosticsEvent({
|
|
34061
|
+
hook,
|
|
34062
|
+
sessionId,
|
|
34063
|
+
turnId: state.turnId,
|
|
34064
|
+
stage: "api_client_created",
|
|
34065
|
+
result: "success",
|
|
34066
|
+
fields: {
|
|
34067
|
+
touchedRepoCount: touchedRepos.length
|
|
34068
|
+
}
|
|
34069
|
+
});
|
|
33759
34070
|
let hadFailure = false;
|
|
33760
34071
|
for (const repo of touchedRepos) {
|
|
33761
34072
|
if (shouldSkipStopRecording(repo)) {
|
|
34073
|
+
await appendHookDiagnosticsEvent({
|
|
34074
|
+
hook,
|
|
34075
|
+
sessionId,
|
|
34076
|
+
turnId: state.turnId,
|
|
34077
|
+
stage: "recording_skipped",
|
|
34078
|
+
result: "info",
|
|
34079
|
+
reason: "skip_stop_recording",
|
|
34080
|
+
repoRoot: repo.repoRoot,
|
|
34081
|
+
fields: {
|
|
34082
|
+
manuallyRecorded: repo.manuallyRecorded,
|
|
34083
|
+
stopRecorded: repo.stopRecorded
|
|
34084
|
+
}
|
|
34085
|
+
});
|
|
33762
34086
|
continue;
|
|
33763
34087
|
}
|
|
33764
34088
|
const recorded = await recordTouchedRepo({
|
|
34089
|
+
hook,
|
|
33765
34090
|
sessionId,
|
|
33766
34091
|
turnId: state.turnId,
|
|
33767
34092
|
repo,
|
|
@@ -33775,16 +34100,60 @@ async function main() {
|
|
|
33775
34100
|
}
|
|
33776
34101
|
if (!hadFailure) {
|
|
33777
34102
|
await clearPendingTurnState(sessionId);
|
|
34103
|
+
await appendHookDiagnosticsEvent({
|
|
34104
|
+
hook,
|
|
34105
|
+
sessionId,
|
|
34106
|
+
turnId: state.turnId,
|
|
34107
|
+
stage: "state_cleanup",
|
|
34108
|
+
result: "success",
|
|
34109
|
+
reason: "cleared_after_success"
|
|
34110
|
+
});
|
|
34111
|
+
return;
|
|
33778
34112
|
}
|
|
34113
|
+
await appendHookDiagnosticsEvent({
|
|
34114
|
+
hook,
|
|
34115
|
+
sessionId,
|
|
34116
|
+
turnId: state.turnId,
|
|
34117
|
+
stage: "state_cleanup",
|
|
34118
|
+
result: "info",
|
|
34119
|
+
reason: "retained_after_failure"
|
|
34120
|
+
});
|
|
33779
34121
|
} catch (error) {
|
|
33780
34122
|
const details = getErrorDetails(error);
|
|
33781
34123
|
await markPendingTurnFailure(sessionId, details);
|
|
34124
|
+
await appendHookDiagnosticsEvent({
|
|
34125
|
+
hook,
|
|
34126
|
+
sessionId,
|
|
34127
|
+
turnId: state.turnId,
|
|
34128
|
+
stage: "turn_failed",
|
|
34129
|
+
result: "error",
|
|
34130
|
+
reason: "exception",
|
|
34131
|
+
message: details.message,
|
|
34132
|
+
fields: {
|
|
34133
|
+
hint: details.hint
|
|
34134
|
+
}
|
|
34135
|
+
});
|
|
33782
34136
|
}
|
|
33783
34137
|
}
|
|
34138
|
+
async function main() {
|
|
34139
|
+
const payload = await readJsonStdin();
|
|
34140
|
+
await runHookStopCollab(payload);
|
|
34141
|
+
}
|
|
33784
34142
|
main().catch((error) => {
|
|
33785
34143
|
const message = error instanceof Error ? error.message : String(error);
|
|
34144
|
+
void appendHookDiagnosticsEvent({
|
|
34145
|
+
hook: "Stop",
|
|
34146
|
+
stage: "unhandled_error",
|
|
34147
|
+
result: "error",
|
|
34148
|
+
reason: "exception",
|
|
34149
|
+
message
|
|
34150
|
+
});
|
|
33786
34151
|
process.stderr.write(`${message}
|
|
33787
34152
|
`);
|
|
33788
34153
|
process.exitCode = 0;
|
|
33789
34154
|
});
|
|
34155
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
34156
|
+
0 && (module.exports = {
|
|
34157
|
+
runHookStopCollab
|
|
34158
|
+
});
|
|
33790
34159
|
//# sourceMappingURL=hook-stop-collab.cjs.map
|