@mrrlin-dev/mcp 0.3.4 → 0.3.7
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/dist/bin.cjs
CHANGED
|
@@ -4273,7 +4273,7 @@ var require_websocket = __commonJS({
|
|
|
4273
4273
|
var http2 = require("http");
|
|
4274
4274
|
var net = require("net");
|
|
4275
4275
|
var tls = require("tls");
|
|
4276
|
-
var { randomBytes:
|
|
4276
|
+
var { randomBytes: randomBytes4, createHash: createHash3 } = require("crypto");
|
|
4277
4277
|
var { Duplex, Readable } = require("stream");
|
|
4278
4278
|
var { URL: URL2 } = require("url");
|
|
4279
4279
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -4811,7 +4811,7 @@ var require_websocket = __commonJS({
|
|
|
4811
4811
|
}
|
|
4812
4812
|
}
|
|
4813
4813
|
const defaultPort = isSecure ? 443 : 80;
|
|
4814
|
-
const key =
|
|
4814
|
+
const key = randomBytes4(16).toString("base64");
|
|
4815
4815
|
const request = isSecure ? https.request : http2.request;
|
|
4816
4816
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
4817
4817
|
let perMessageDeflate;
|
|
@@ -4941,7 +4941,7 @@ var require_websocket = __commonJS({
|
|
|
4941
4941
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
4942
4942
|
return;
|
|
4943
4943
|
}
|
|
4944
|
-
const digest =
|
|
4944
|
+
const digest = createHash3("sha1").update(key + GUID).digest("base64");
|
|
4945
4945
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
4946
4946
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
4947
4947
|
return;
|
|
@@ -5310,7 +5310,7 @@ var require_websocket_server = __commonJS({
|
|
|
5310
5310
|
var EventEmitter3 = require("events");
|
|
5311
5311
|
var http2 = require("http");
|
|
5312
5312
|
var { Duplex } = require("stream");
|
|
5313
|
-
var { createHash:
|
|
5313
|
+
var { createHash: createHash3 } = require("crypto");
|
|
5314
5314
|
var extension2 = require_extension();
|
|
5315
5315
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
5316
5316
|
var subprotocol2 = require_subprotocol();
|
|
@@ -5617,7 +5617,7 @@ var require_websocket_server = __commonJS({
|
|
|
5617
5617
|
);
|
|
5618
5618
|
}
|
|
5619
5619
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
5620
|
-
const digest =
|
|
5620
|
+
const digest = createHash3("sha1").update(key + GUID).digest("base64");
|
|
5621
5621
|
const headers = [
|
|
5622
5622
|
"HTTP/1.1 101 Switching Protocols",
|
|
5623
5623
|
"Upgrade: websocket",
|
|
@@ -7683,7 +7683,7 @@ var require_polyfills = __commonJS({
|
|
|
7683
7683
|
var constants = require("constants");
|
|
7684
7684
|
var origCwd = process.cwd;
|
|
7685
7685
|
var cwd = null;
|
|
7686
|
-
var
|
|
7686
|
+
var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform;
|
|
7687
7687
|
process.cwd = function() {
|
|
7688
7688
|
if (!cwd)
|
|
7689
7689
|
cwd = origCwd.call(process);
|
|
@@ -7729,20 +7729,20 @@ var require_polyfills = __commonJS({
|
|
|
7729
7729
|
fs7.fstatSync = statFixSync(fs7.fstatSync);
|
|
7730
7730
|
fs7.lstatSync = statFixSync(fs7.lstatSync);
|
|
7731
7731
|
if (fs7.chmod && !fs7.lchmod) {
|
|
7732
|
-
fs7.lchmod = function(
|
|
7732
|
+
fs7.lchmod = function(path15, mode, cb) {
|
|
7733
7733
|
if (cb) process.nextTick(cb);
|
|
7734
7734
|
};
|
|
7735
7735
|
fs7.lchmodSync = function() {
|
|
7736
7736
|
};
|
|
7737
7737
|
}
|
|
7738
7738
|
if (fs7.chown && !fs7.lchown) {
|
|
7739
|
-
fs7.lchown = function(
|
|
7739
|
+
fs7.lchown = function(path15, uid, gid, cb) {
|
|
7740
7740
|
if (cb) process.nextTick(cb);
|
|
7741
7741
|
};
|
|
7742
7742
|
fs7.lchownSync = function() {
|
|
7743
7743
|
};
|
|
7744
7744
|
}
|
|
7745
|
-
if (
|
|
7745
|
+
if (platform === "win32") {
|
|
7746
7746
|
fs7.rename = typeof fs7.rename !== "function" ? fs7.rename : function(fs$rename) {
|
|
7747
7747
|
function rename(from, to, cb) {
|
|
7748
7748
|
var start = Date.now();
|
|
@@ -7803,9 +7803,9 @@ var require_polyfills = __commonJS({
|
|
|
7803
7803
|
};
|
|
7804
7804
|
}(fs7.readSync);
|
|
7805
7805
|
function patchLchmod(fs8) {
|
|
7806
|
-
fs8.lchmod = function(
|
|
7806
|
+
fs8.lchmod = function(path15, mode, callback) {
|
|
7807
7807
|
fs8.open(
|
|
7808
|
-
|
|
7808
|
+
path15,
|
|
7809
7809
|
constants.O_WRONLY | constants.O_SYMLINK,
|
|
7810
7810
|
mode,
|
|
7811
7811
|
function(err, fd) {
|
|
@@ -7821,8 +7821,8 @@ var require_polyfills = __commonJS({
|
|
|
7821
7821
|
}
|
|
7822
7822
|
);
|
|
7823
7823
|
};
|
|
7824
|
-
fs8.lchmodSync = function(
|
|
7825
|
-
var fd = fs8.openSync(
|
|
7824
|
+
fs8.lchmodSync = function(path15, mode) {
|
|
7825
|
+
var fd = fs8.openSync(path15, constants.O_WRONLY | constants.O_SYMLINK, mode);
|
|
7826
7826
|
var threw = true;
|
|
7827
7827
|
var ret;
|
|
7828
7828
|
try {
|
|
@@ -7843,8 +7843,8 @@ var require_polyfills = __commonJS({
|
|
|
7843
7843
|
}
|
|
7844
7844
|
function patchLutimes(fs8) {
|
|
7845
7845
|
if (constants.hasOwnProperty("O_SYMLINK") && fs8.futimes) {
|
|
7846
|
-
fs8.lutimes = function(
|
|
7847
|
-
fs8.open(
|
|
7846
|
+
fs8.lutimes = function(path15, at, mt, cb) {
|
|
7847
|
+
fs8.open(path15, constants.O_SYMLINK, function(er, fd) {
|
|
7848
7848
|
if (er) {
|
|
7849
7849
|
if (cb) cb(er);
|
|
7850
7850
|
return;
|
|
@@ -7856,8 +7856,8 @@ var require_polyfills = __commonJS({
|
|
|
7856
7856
|
});
|
|
7857
7857
|
});
|
|
7858
7858
|
};
|
|
7859
|
-
fs8.lutimesSync = function(
|
|
7860
|
-
var fd = fs8.openSync(
|
|
7859
|
+
fs8.lutimesSync = function(path15, at, mt) {
|
|
7860
|
+
var fd = fs8.openSync(path15, constants.O_SYMLINK);
|
|
7861
7861
|
var ret;
|
|
7862
7862
|
var threw = true;
|
|
7863
7863
|
try {
|
|
@@ -7975,11 +7975,11 @@ var require_legacy_streams = __commonJS({
|
|
|
7975
7975
|
ReadStream,
|
|
7976
7976
|
WriteStream
|
|
7977
7977
|
};
|
|
7978
|
-
function ReadStream(
|
|
7979
|
-
if (!(this instanceof ReadStream)) return new ReadStream(
|
|
7978
|
+
function ReadStream(path15, options) {
|
|
7979
|
+
if (!(this instanceof ReadStream)) return new ReadStream(path15, options);
|
|
7980
7980
|
Stream.call(this);
|
|
7981
7981
|
var self = this;
|
|
7982
|
-
this.path =
|
|
7982
|
+
this.path = path15;
|
|
7983
7983
|
this.fd = null;
|
|
7984
7984
|
this.readable = true;
|
|
7985
7985
|
this.paused = false;
|
|
@@ -8024,10 +8024,10 @@ var require_legacy_streams = __commonJS({
|
|
|
8024
8024
|
self._read();
|
|
8025
8025
|
});
|
|
8026
8026
|
}
|
|
8027
|
-
function WriteStream(
|
|
8028
|
-
if (!(this instanceof WriteStream)) return new WriteStream(
|
|
8027
|
+
function WriteStream(path15, options) {
|
|
8028
|
+
if (!(this instanceof WriteStream)) return new WriteStream(path15, options);
|
|
8029
8029
|
Stream.call(this);
|
|
8030
|
-
this.path =
|
|
8030
|
+
this.path = path15;
|
|
8031
8031
|
this.fd = null;
|
|
8032
8032
|
this.writable = true;
|
|
8033
8033
|
this.flags = "w";
|
|
@@ -8170,14 +8170,14 @@ var require_graceful_fs = __commonJS({
|
|
|
8170
8170
|
fs8.createWriteStream = createWriteStream;
|
|
8171
8171
|
var fs$readFile = fs8.readFile;
|
|
8172
8172
|
fs8.readFile = readFile2;
|
|
8173
|
-
function readFile2(
|
|
8173
|
+
function readFile2(path15, options, cb) {
|
|
8174
8174
|
if (typeof options === "function")
|
|
8175
8175
|
cb = options, options = null;
|
|
8176
|
-
return go$readFile(
|
|
8177
|
-
function go$readFile(
|
|
8178
|
-
return fs$readFile(
|
|
8176
|
+
return go$readFile(path15, options, cb);
|
|
8177
|
+
function go$readFile(path16, options2, cb2, startTime) {
|
|
8178
|
+
return fs$readFile(path16, options2, function(err) {
|
|
8179
8179
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
8180
|
-
enqueue([go$readFile, [
|
|
8180
|
+
enqueue([go$readFile, [path16, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
8181
8181
|
else {
|
|
8182
8182
|
if (typeof cb2 === "function")
|
|
8183
8183
|
cb2.apply(this, arguments);
|
|
@@ -8187,14 +8187,14 @@ var require_graceful_fs = __commonJS({
|
|
|
8187
8187
|
}
|
|
8188
8188
|
var fs$writeFile = fs8.writeFile;
|
|
8189
8189
|
fs8.writeFile = writeFile;
|
|
8190
|
-
function writeFile(
|
|
8190
|
+
function writeFile(path15, data, options, cb) {
|
|
8191
8191
|
if (typeof options === "function")
|
|
8192
8192
|
cb = options, options = null;
|
|
8193
|
-
return go$writeFile(
|
|
8194
|
-
function go$writeFile(
|
|
8195
|
-
return fs$writeFile(
|
|
8193
|
+
return go$writeFile(path15, data, options, cb);
|
|
8194
|
+
function go$writeFile(path16, data2, options2, cb2, startTime) {
|
|
8195
|
+
return fs$writeFile(path16, data2, options2, function(err) {
|
|
8196
8196
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
8197
|
-
enqueue([go$writeFile, [
|
|
8197
|
+
enqueue([go$writeFile, [path16, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
8198
8198
|
else {
|
|
8199
8199
|
if (typeof cb2 === "function")
|
|
8200
8200
|
cb2.apply(this, arguments);
|
|
@@ -8205,14 +8205,14 @@ var require_graceful_fs = __commonJS({
|
|
|
8205
8205
|
var fs$appendFile = fs8.appendFile;
|
|
8206
8206
|
if (fs$appendFile)
|
|
8207
8207
|
fs8.appendFile = appendFile;
|
|
8208
|
-
function appendFile(
|
|
8208
|
+
function appendFile(path15, data, options, cb) {
|
|
8209
8209
|
if (typeof options === "function")
|
|
8210
8210
|
cb = options, options = null;
|
|
8211
|
-
return go$appendFile(
|
|
8212
|
-
function go$appendFile(
|
|
8213
|
-
return fs$appendFile(
|
|
8211
|
+
return go$appendFile(path15, data, options, cb);
|
|
8212
|
+
function go$appendFile(path16, data2, options2, cb2, startTime) {
|
|
8213
|
+
return fs$appendFile(path16, data2, options2, function(err) {
|
|
8214
8214
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
8215
|
-
enqueue([go$appendFile, [
|
|
8215
|
+
enqueue([go$appendFile, [path16, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
8216
8216
|
else {
|
|
8217
8217
|
if (typeof cb2 === "function")
|
|
8218
8218
|
cb2.apply(this, arguments);
|
|
@@ -8243,31 +8243,31 @@ var require_graceful_fs = __commonJS({
|
|
|
8243
8243
|
var fs$readdir = fs8.readdir;
|
|
8244
8244
|
fs8.readdir = readdir2;
|
|
8245
8245
|
var noReaddirOptionVersions = /^v[0-5]\./;
|
|
8246
|
-
function readdir2(
|
|
8246
|
+
function readdir2(path15, options, cb) {
|
|
8247
8247
|
if (typeof options === "function")
|
|
8248
8248
|
cb = options, options = null;
|
|
8249
|
-
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(
|
|
8250
|
-
return fs$readdir(
|
|
8251
|
-
|
|
8249
|
+
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path16, options2, cb2, startTime) {
|
|
8250
|
+
return fs$readdir(path16, fs$readdirCallback(
|
|
8251
|
+
path16,
|
|
8252
8252
|
options2,
|
|
8253
8253
|
cb2,
|
|
8254
8254
|
startTime
|
|
8255
8255
|
));
|
|
8256
|
-
} : function go$readdir2(
|
|
8257
|
-
return fs$readdir(
|
|
8258
|
-
|
|
8256
|
+
} : function go$readdir2(path16, options2, cb2, startTime) {
|
|
8257
|
+
return fs$readdir(path16, options2, fs$readdirCallback(
|
|
8258
|
+
path16,
|
|
8259
8259
|
options2,
|
|
8260
8260
|
cb2,
|
|
8261
8261
|
startTime
|
|
8262
8262
|
));
|
|
8263
8263
|
};
|
|
8264
|
-
return go$readdir(
|
|
8265
|
-
function fs$readdirCallback(
|
|
8264
|
+
return go$readdir(path15, options, cb);
|
|
8265
|
+
function fs$readdirCallback(path16, options2, cb2, startTime) {
|
|
8266
8266
|
return function(err, files) {
|
|
8267
8267
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
8268
8268
|
enqueue([
|
|
8269
8269
|
go$readdir,
|
|
8270
|
-
[
|
|
8270
|
+
[path16, options2, cb2],
|
|
8271
8271
|
err,
|
|
8272
8272
|
startTime || Date.now(),
|
|
8273
8273
|
Date.now()
|
|
@@ -8338,7 +8338,7 @@ var require_graceful_fs = __commonJS({
|
|
|
8338
8338
|
enumerable: true,
|
|
8339
8339
|
configurable: true
|
|
8340
8340
|
});
|
|
8341
|
-
function ReadStream(
|
|
8341
|
+
function ReadStream(path15, options) {
|
|
8342
8342
|
if (this instanceof ReadStream)
|
|
8343
8343
|
return fs$ReadStream.apply(this, arguments), this;
|
|
8344
8344
|
else
|
|
@@ -8358,7 +8358,7 @@ var require_graceful_fs = __commonJS({
|
|
|
8358
8358
|
}
|
|
8359
8359
|
});
|
|
8360
8360
|
}
|
|
8361
|
-
function WriteStream(
|
|
8361
|
+
function WriteStream(path15, options) {
|
|
8362
8362
|
if (this instanceof WriteStream)
|
|
8363
8363
|
return fs$WriteStream.apply(this, arguments), this;
|
|
8364
8364
|
else
|
|
@@ -8376,22 +8376,22 @@ var require_graceful_fs = __commonJS({
|
|
|
8376
8376
|
}
|
|
8377
8377
|
});
|
|
8378
8378
|
}
|
|
8379
|
-
function createReadStream(
|
|
8380
|
-
return new fs8.ReadStream(
|
|
8379
|
+
function createReadStream(path15, options) {
|
|
8380
|
+
return new fs8.ReadStream(path15, options);
|
|
8381
8381
|
}
|
|
8382
|
-
function createWriteStream(
|
|
8383
|
-
return new fs8.WriteStream(
|
|
8382
|
+
function createWriteStream(path15, options) {
|
|
8383
|
+
return new fs8.WriteStream(path15, options);
|
|
8384
8384
|
}
|
|
8385
8385
|
var fs$open = fs8.open;
|
|
8386
8386
|
fs8.open = open;
|
|
8387
|
-
function open(
|
|
8387
|
+
function open(path15, flags, mode, cb) {
|
|
8388
8388
|
if (typeof mode === "function")
|
|
8389
8389
|
cb = mode, mode = null;
|
|
8390
|
-
return go$open(
|
|
8391
|
-
function go$open(
|
|
8392
|
-
return fs$open(
|
|
8390
|
+
return go$open(path15, flags, mode, cb);
|
|
8391
|
+
function go$open(path16, flags2, mode2, cb2, startTime) {
|
|
8392
|
+
return fs$open(path16, flags2, mode2, function(err, fd) {
|
|
8393
8393
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
8394
|
-
enqueue([go$open, [
|
|
8394
|
+
enqueue([go$open, [path16, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
8395
8395
|
else {
|
|
8396
8396
|
if (typeof cb2 === "function")
|
|
8397
8397
|
cb2.apply(this, arguments);
|
|
@@ -8920,7 +8920,7 @@ var require_mtime_precision = __commonJS({
|
|
|
8920
8920
|
var require_lockfile = __commonJS({
|
|
8921
8921
|
"../../node_modules/.pnpm/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/lockfile.js"(exports2, module2) {
|
|
8922
8922
|
"use strict";
|
|
8923
|
-
var
|
|
8923
|
+
var path15 = require("path");
|
|
8924
8924
|
var fs7 = require_graceful_fs();
|
|
8925
8925
|
var retry = require_retry2();
|
|
8926
8926
|
var onExit = require_signal_exit();
|
|
@@ -8931,7 +8931,7 @@ var require_lockfile = __commonJS({
|
|
|
8931
8931
|
}
|
|
8932
8932
|
function resolveCanonicalPath(file2, options, callback) {
|
|
8933
8933
|
if (!options.realpath) {
|
|
8934
|
-
return callback(null,
|
|
8934
|
+
return callback(null, path15.resolve(file2));
|
|
8935
8935
|
}
|
|
8936
8936
|
options.fs.realpath(file2, callback);
|
|
8937
8937
|
}
|
|
@@ -10795,10 +10795,10 @@ var require_segments = __commonJS({
|
|
|
10795
10795
|
const segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled());
|
|
10796
10796
|
const nodes = buildNodes(segs);
|
|
10797
10797
|
const graph = buildGraph(nodes, version2);
|
|
10798
|
-
const
|
|
10798
|
+
const path15 = dijkstra.find_path(graph.map, "start", "end");
|
|
10799
10799
|
const optimizedSegs = [];
|
|
10800
|
-
for (let i = 1; i <
|
|
10801
|
-
optimizedSegs.push(graph.table[
|
|
10800
|
+
for (let i = 1; i < path15.length - 1; i++) {
|
|
10801
|
+
optimizedSegs.push(graph.table[path15[i]].node);
|
|
10802
10802
|
}
|
|
10803
10803
|
return exports2.fromArray(mergeSegments(optimizedSegs));
|
|
10804
10804
|
};
|
|
@@ -13275,7 +13275,7 @@ var require_png2 = __commonJS({
|
|
|
13275
13275
|
});
|
|
13276
13276
|
png.pack();
|
|
13277
13277
|
};
|
|
13278
|
-
exports2.renderToFile = function renderToFile(
|
|
13278
|
+
exports2.renderToFile = function renderToFile(path15, qrData, options, cb) {
|
|
13279
13279
|
if (typeof cb === "undefined") {
|
|
13280
13280
|
cb = options;
|
|
13281
13281
|
options = void 0;
|
|
@@ -13286,7 +13286,7 @@ var require_png2 = __commonJS({
|
|
|
13286
13286
|
called = true;
|
|
13287
13287
|
cb.apply(null, args);
|
|
13288
13288
|
};
|
|
13289
|
-
const stream = fs7.createWriteStream(
|
|
13289
|
+
const stream = fs7.createWriteStream(path15);
|
|
13290
13290
|
stream.on("error", done);
|
|
13291
13291
|
stream.on("close", done);
|
|
13292
13292
|
exports2.renderToFileStream(stream, qrData, options);
|
|
@@ -13348,14 +13348,14 @@ var require_utf8 = __commonJS({
|
|
|
13348
13348
|
}
|
|
13349
13349
|
return output3;
|
|
13350
13350
|
};
|
|
13351
|
-
exports2.renderToFile = function renderToFile(
|
|
13351
|
+
exports2.renderToFile = function renderToFile(path15, qrData, options, cb) {
|
|
13352
13352
|
if (typeof cb === "undefined") {
|
|
13353
13353
|
cb = options;
|
|
13354
13354
|
options = void 0;
|
|
13355
13355
|
}
|
|
13356
13356
|
const fs7 = require("fs");
|
|
13357
13357
|
const utf8 = exports2.render(qrData, options);
|
|
13358
|
-
fs7.writeFile(
|
|
13358
|
+
fs7.writeFile(path15, utf8, cb);
|
|
13359
13359
|
};
|
|
13360
13360
|
}
|
|
13361
13361
|
});
|
|
@@ -13476,7 +13476,7 @@ var require_svg_tag = __commonJS({
|
|
|
13476
13476
|
return str;
|
|
13477
13477
|
}
|
|
13478
13478
|
function qrToPath(data, size, margin) {
|
|
13479
|
-
let
|
|
13479
|
+
let path15 = "";
|
|
13480
13480
|
let moveBy = 0;
|
|
13481
13481
|
let newRow = false;
|
|
13482
13482
|
let lineLength = 0;
|
|
@@ -13487,19 +13487,19 @@ var require_svg_tag = __commonJS({
|
|
|
13487
13487
|
if (data[i]) {
|
|
13488
13488
|
lineLength++;
|
|
13489
13489
|
if (!(i > 0 && col > 0 && data[i - 1])) {
|
|
13490
|
-
|
|
13490
|
+
path15 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
|
|
13491
13491
|
moveBy = 0;
|
|
13492
13492
|
newRow = false;
|
|
13493
13493
|
}
|
|
13494
13494
|
if (!(col + 1 < size && data[i + 1])) {
|
|
13495
|
-
|
|
13495
|
+
path15 += svgCmd("h", lineLength);
|
|
13496
13496
|
lineLength = 0;
|
|
13497
13497
|
}
|
|
13498
13498
|
} else {
|
|
13499
13499
|
moveBy++;
|
|
13500
13500
|
}
|
|
13501
13501
|
}
|
|
13502
|
-
return
|
|
13502
|
+
return path15;
|
|
13503
13503
|
}
|
|
13504
13504
|
exports2.render = function render(qrData, options, cb) {
|
|
13505
13505
|
const opts = Utils.getOptions(options);
|
|
@@ -13507,10 +13507,10 @@ var require_svg_tag = __commonJS({
|
|
|
13507
13507
|
const data = qrData.modules.data;
|
|
13508
13508
|
const qrcodesize = size + opts.margin * 2;
|
|
13509
13509
|
const bg = !opts.color.light.a ? "" : "<path " + getColorAttrib(opts.color.light, "fill") + ' d="M0 0h' + qrcodesize + "v" + qrcodesize + 'H0z"/>';
|
|
13510
|
-
const
|
|
13510
|
+
const path15 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
|
|
13511
13511
|
const viewBox = 'viewBox="0 0 ' + qrcodesize + " " + qrcodesize + '"';
|
|
13512
13512
|
const width = !opts.width ? "" : 'width="' + opts.width + '" height="' + opts.width + '" ';
|
|
13513
|
-
const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg +
|
|
13513
|
+
const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path15 + "</svg>\n";
|
|
13514
13514
|
if (typeof cb === "function") {
|
|
13515
13515
|
cb(null, svgTag);
|
|
13516
13516
|
}
|
|
@@ -13524,7 +13524,7 @@ var require_svg = __commonJS({
|
|
|
13524
13524
|
"../../node_modules/.pnpm/qrcode@1.5.4/node_modules/qrcode/lib/renderer/svg.js"(exports2) {
|
|
13525
13525
|
var svgTagRenderer = require_svg_tag();
|
|
13526
13526
|
exports2.render = svgTagRenderer.render;
|
|
13527
|
-
exports2.renderToFile = function renderToFile(
|
|
13527
|
+
exports2.renderToFile = function renderToFile(path15, qrData, options, cb) {
|
|
13528
13528
|
if (typeof cb === "undefined") {
|
|
13529
13529
|
cb = options;
|
|
13530
13530
|
options = void 0;
|
|
@@ -13532,7 +13532,7 @@ var require_svg = __commonJS({
|
|
|
13532
13532
|
const fs7 = require("fs");
|
|
13533
13533
|
const svgTag = exports2.render(qrData, options);
|
|
13534
13534
|
const xmlStr = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + svgTag;
|
|
13535
|
-
fs7.writeFile(
|
|
13535
|
+
fs7.writeFile(path15, xmlStr, cb);
|
|
13536
13536
|
};
|
|
13537
13537
|
}
|
|
13538
13538
|
});
|
|
@@ -13690,8 +13690,8 @@ var require_server = __commonJS({
|
|
|
13690
13690
|
cb
|
|
13691
13691
|
};
|
|
13692
13692
|
}
|
|
13693
|
-
function getTypeFromFilename(
|
|
13694
|
-
return
|
|
13693
|
+
function getTypeFromFilename(path15) {
|
|
13694
|
+
return path15.slice((path15.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
|
|
13695
13695
|
}
|
|
13696
13696
|
function getRendererFromType(type) {
|
|
13697
13697
|
switch (type) {
|
|
@@ -13755,17 +13755,17 @@ var require_server = __commonJS({
|
|
|
13755
13755
|
const renderer = getRendererFromType(params.opts.type);
|
|
13756
13756
|
return render(renderer.renderToBuffer, text, params);
|
|
13757
13757
|
};
|
|
13758
|
-
exports2.toFile = function toFile(
|
|
13759
|
-
if (typeof
|
|
13758
|
+
exports2.toFile = function toFile(path15, text, opts, cb) {
|
|
13759
|
+
if (typeof path15 !== "string" || !(typeof text === "string" || typeof text === "object")) {
|
|
13760
13760
|
throw new Error("Invalid argument");
|
|
13761
13761
|
}
|
|
13762
13762
|
if (arguments.length < 3 && !canPromise()) {
|
|
13763
13763
|
throw new Error("Too few arguments provided");
|
|
13764
13764
|
}
|
|
13765
13765
|
const params = checkParams(text, opts, cb);
|
|
13766
|
-
const type = params.opts.type || getTypeFromFilename(
|
|
13766
|
+
const type = params.opts.type || getTypeFromFilename(path15);
|
|
13767
13767
|
const renderer = getRendererFromType(type);
|
|
13768
|
-
const renderToFile = renderer.renderToFile.bind(null,
|
|
13768
|
+
const renderToFile = renderer.renderToFile.bind(null, path15);
|
|
13769
13769
|
return render(renderToFile, text, params);
|
|
13770
13770
|
};
|
|
13771
13771
|
exports2.toFileStream = function toFileStream(stream, text, opts) {
|
|
@@ -16983,8 +16983,8 @@ var require_utils3 = __commonJS({
|
|
|
16983
16983
|
}
|
|
16984
16984
|
return ind;
|
|
16985
16985
|
}
|
|
16986
|
-
function removeDotSegments(
|
|
16987
|
-
let input =
|
|
16986
|
+
function removeDotSegments(path15) {
|
|
16987
|
+
let input = path15;
|
|
16988
16988
|
const output3 = [];
|
|
16989
16989
|
let nextSlash = -1;
|
|
16990
16990
|
let len = 0;
|
|
@@ -17236,8 +17236,8 @@ var require_schemes = __commonJS({
|
|
|
17236
17236
|
wsComponent.secure = void 0;
|
|
17237
17237
|
}
|
|
17238
17238
|
if (wsComponent.resourceName) {
|
|
17239
|
-
const [
|
|
17240
|
-
wsComponent.path =
|
|
17239
|
+
const [path15, query] = wsComponent.resourceName.split("?");
|
|
17240
|
+
wsComponent.path = path15 && path15 !== "/" ? path15 : void 0;
|
|
17241
17241
|
wsComponent.query = query;
|
|
17242
17242
|
wsComponent.resourceName = void 0;
|
|
17243
17243
|
}
|
|
@@ -20644,11 +20644,11 @@ var require_dist = __commonJS({
|
|
|
20644
20644
|
});
|
|
20645
20645
|
|
|
20646
20646
|
// src/bin.ts
|
|
20647
|
+
var import_node_path20 = __toESM(require("node:path"), 1);
|
|
20648
|
+
var import_node_child_process8 = require("node:child_process");
|
|
20649
|
+
var import_node_fs15 = require("node:fs");
|
|
20650
|
+
var import_node_os12 = require("node:os");
|
|
20647
20651
|
var import_node_path21 = __toESM(require("node:path"), 1);
|
|
20648
|
-
var import_node_child_process9 = require("node:child_process");
|
|
20649
|
-
var import_node_fs16 = require("node:fs");
|
|
20650
|
-
var import_node_os13 = require("node:os");
|
|
20651
|
-
var import_node_path22 = __toESM(require("node:path"), 1);
|
|
20652
20652
|
|
|
20653
20653
|
// src/install-codex.ts
|
|
20654
20654
|
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
@@ -20915,11 +20915,11 @@ ${block}`;
|
|
|
20915
20915
|
}
|
|
20916
20916
|
|
|
20917
20917
|
// src/director-bridge.ts
|
|
20918
|
-
var
|
|
20918
|
+
var import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
20919
20919
|
var import_node_http = __toESM(require("node:http"), 1);
|
|
20920
|
-
var
|
|
20921
|
-
var
|
|
20922
|
-
var
|
|
20920
|
+
var import_node_os8 = __toESM(require("node:os"), 1);
|
|
20921
|
+
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
20922
|
+
var import_node_child_process4 = require("node:child_process");
|
|
20923
20923
|
var import_node_crypto5 = __toESM(require("node:crypto"), 1);
|
|
20924
20924
|
|
|
20925
20925
|
// src/turn-replay-buffer.ts
|
|
@@ -22421,10 +22421,10 @@ function mergeDefs(...defs) {
|
|
|
22421
22421
|
function cloneDef(schema) {
|
|
22422
22422
|
return mergeDefs(schema._zod.def);
|
|
22423
22423
|
}
|
|
22424
|
-
function getElementAtPath(obj,
|
|
22425
|
-
if (!
|
|
22424
|
+
function getElementAtPath(obj, path15) {
|
|
22425
|
+
if (!path15)
|
|
22426
22426
|
return obj;
|
|
22427
|
-
return
|
|
22427
|
+
return path15.reduce((acc, key) => acc?.[key], obj);
|
|
22428
22428
|
}
|
|
22429
22429
|
function promiseAllObject(promisesObj) {
|
|
22430
22430
|
const keys = Object.keys(promisesObj);
|
|
@@ -22833,11 +22833,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
22833
22833
|
}
|
|
22834
22834
|
return false;
|
|
22835
22835
|
}
|
|
22836
|
-
function prefixIssues(
|
|
22836
|
+
function prefixIssues(path15, issues) {
|
|
22837
22837
|
return issues.map((iss) => {
|
|
22838
22838
|
var _a3;
|
|
22839
22839
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
22840
|
-
iss.path.unshift(
|
|
22840
|
+
iss.path.unshift(path15);
|
|
22841
22841
|
return iss;
|
|
22842
22842
|
});
|
|
22843
22843
|
}
|
|
@@ -22984,16 +22984,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
22984
22984
|
}
|
|
22985
22985
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
22986
22986
|
const fieldErrors = { _errors: [] };
|
|
22987
|
-
const processError = (error52,
|
|
22987
|
+
const processError = (error52, path15 = []) => {
|
|
22988
22988
|
for (const issue2 of error52.issues) {
|
|
22989
22989
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
22990
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
22990
|
+
issue2.errors.map((issues) => processError({ issues }, [...path15, ...issue2.path]));
|
|
22991
22991
|
} else if (issue2.code === "invalid_key") {
|
|
22992
|
-
processError({ issues: issue2.issues }, [...
|
|
22992
|
+
processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
|
|
22993
22993
|
} else if (issue2.code === "invalid_element") {
|
|
22994
|
-
processError({ issues: issue2.issues }, [...
|
|
22994
|
+
processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
|
|
22995
22995
|
} else {
|
|
22996
|
-
const fullpath = [...
|
|
22996
|
+
const fullpath = [...path15, ...issue2.path];
|
|
22997
22997
|
if (fullpath.length === 0) {
|
|
22998
22998
|
fieldErrors._errors.push(mapper(issue2));
|
|
22999
22999
|
} else {
|
|
@@ -23020,17 +23020,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
23020
23020
|
}
|
|
23021
23021
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
23022
23022
|
const result = { errors: [] };
|
|
23023
|
-
const processError = (error52,
|
|
23023
|
+
const processError = (error52, path15 = []) => {
|
|
23024
23024
|
var _a3, _b;
|
|
23025
23025
|
for (const issue2 of error52.issues) {
|
|
23026
23026
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
23027
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
23027
|
+
issue2.errors.map((issues) => processError({ issues }, [...path15, ...issue2.path]));
|
|
23028
23028
|
} else if (issue2.code === "invalid_key") {
|
|
23029
|
-
processError({ issues: issue2.issues }, [...
|
|
23029
|
+
processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
|
|
23030
23030
|
} else if (issue2.code === "invalid_element") {
|
|
23031
|
-
processError({ issues: issue2.issues }, [...
|
|
23031
|
+
processError({ issues: issue2.issues }, [...path15, ...issue2.path]);
|
|
23032
23032
|
} else {
|
|
23033
|
-
const fullpath = [...
|
|
23033
|
+
const fullpath = [...path15, ...issue2.path];
|
|
23034
23034
|
if (fullpath.length === 0) {
|
|
23035
23035
|
result.errors.push(mapper(issue2));
|
|
23036
23036
|
continue;
|
|
@@ -23062,8 +23062,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
23062
23062
|
}
|
|
23063
23063
|
function toDotPath(_path) {
|
|
23064
23064
|
const segs = [];
|
|
23065
|
-
const
|
|
23066
|
-
for (const seg of
|
|
23065
|
+
const path15 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
23066
|
+
for (const seg of path15) {
|
|
23067
23067
|
if (typeof seg === "number")
|
|
23068
23068
|
segs.push(`[${seg}]`);
|
|
23069
23069
|
else if (typeof seg === "symbol")
|
|
@@ -35755,13 +35755,13 @@ function resolveRef(ref, ctx) {
|
|
|
35755
35755
|
if (!ref.startsWith("#")) {
|
|
35756
35756
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
35757
35757
|
}
|
|
35758
|
-
const
|
|
35759
|
-
if (
|
|
35758
|
+
const path15 = ref.slice(1).split("/").filter(Boolean);
|
|
35759
|
+
if (path15.length === 0) {
|
|
35760
35760
|
return ctx.rootSchema;
|
|
35761
35761
|
}
|
|
35762
35762
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
35763
|
-
if (
|
|
35764
|
-
const key =
|
|
35763
|
+
if (path15[0] === defsKey) {
|
|
35764
|
+
const key = path15[1];
|
|
35765
35765
|
if (!key || !ctx.defs[key]) {
|
|
35766
35766
|
throw new Error(`Reference not found: ${ref}`);
|
|
35767
35767
|
}
|
|
@@ -36264,7 +36264,8 @@ var openApiOperationIds = {
|
|
|
36264
36264
|
updateWikiPageCas: "updateWikiPageCas",
|
|
36265
36265
|
promoteSpecReadyCas: "promoteSpecReadyCas",
|
|
36266
36266
|
recordSpecConsensusReview: "recordSpecConsensusReview",
|
|
36267
|
-
getSpecConsensusReview: "getSpecConsensusReview"
|
|
36267
|
+
getSpecConsensusReview: "getSpecConsensusReview",
|
|
36268
|
+
onboardingKickoffTransition: "onboardingKickoffTransition"
|
|
36268
36269
|
};
|
|
36269
36270
|
|
|
36270
36271
|
// ../../packages/schemas/dist/session.js
|
|
@@ -36275,7 +36276,7 @@ var operatorSessionSchema = external_exports.object({
|
|
|
36275
36276
|
issuedAt: external_exports.number().int().positive(),
|
|
36276
36277
|
kind: external_exports.enum(["web", "agent"]).default("web"),
|
|
36277
36278
|
login: external_exports.string().min(1),
|
|
36278
|
-
projectSlug: external_exports.string().min(1),
|
|
36279
|
+
projectSlug: external_exports.string().min(1).optional(),
|
|
36279
36280
|
provider: external_exports.literal("github"),
|
|
36280
36281
|
repo: external_exports.string().min(1).nullable(),
|
|
36281
36282
|
// ADR 0016: `scope` distinguishes project-pinned agent tokens (legacy, default) from
|
|
@@ -36284,7 +36285,7 @@ var operatorSessionSchema = external_exports.object({
|
|
|
36284
36285
|
// cleanly into the project branch of the middleware (which mirrors today's behavior).
|
|
36285
36286
|
scope: external_exports.enum(["project", "operator"]).default("project")
|
|
36286
36287
|
});
|
|
36287
|
-
var AGENT_SESSION_TTL_MS = 1e3 * 60 *
|
|
36288
|
+
var AGENT_SESSION_TTL_MS = 1e3 * 60 * 15;
|
|
36288
36289
|
|
|
36289
36290
|
// ../../packages/schemas/dist/github-state.js
|
|
36290
36291
|
var TTL_MS = 10 * 6e4;
|
|
@@ -36402,6 +36403,7 @@ var mrrlinTaskTypeSchema = external_exports.enum(["task", "bug"]);
|
|
|
36402
36403
|
var mrrlinTaskImpactSchema = external_exports.enum(["low", "medium", "high"]);
|
|
36403
36404
|
var mrrlinAutonomyLevelSchema = external_exports.enum(["auto", "minimal_human", "human_only"]);
|
|
36404
36405
|
var mrrlinAutoDeploySchema = external_exports.enum(["off", "dev", "prod"]);
|
|
36406
|
+
var mrrlinSpecApprovedSchema = external_exports.enum(["pending", "approved", "skipped", "skipped_legacy"]);
|
|
36405
36407
|
var mrrlinTaskSourceSchema = external_exports.enum(["fixture-import", "api"]);
|
|
36406
36408
|
var mrrlinPlanStatusSchema = external_exports.enum(["active", "paused", "done", "archived"]);
|
|
36407
36409
|
var mrrlinTaskEventTypeSchema = external_exports.enum(["autonomy_set", "director_thread_reset", "note"]);
|
|
@@ -36458,6 +36460,7 @@ var mrrlinExecutionArtifactKindSchema = external_exports.enum([
|
|
|
36458
36460
|
"handoff_judgement",
|
|
36459
36461
|
"file",
|
|
36460
36462
|
"verification",
|
|
36463
|
+
"produced_url",
|
|
36461
36464
|
"resume_spec"
|
|
36462
36465
|
]);
|
|
36463
36466
|
var mrrlinDeployAttemptPayloadSchema = external_exports.object({
|
|
@@ -36473,6 +36476,11 @@ var mrrlinVerificationPayloadSchema = external_exports.object({
|
|
|
36473
36476
|
checks: external_exports.array(external_exports.unknown()).optional(),
|
|
36474
36477
|
turnRef: external_exports.string().nullable()
|
|
36475
36478
|
});
|
|
36479
|
+
var producedUrlSafeString = external_exports.string().regex(/^[^\x00-\x1F\x7F]+$/, "control chars are not allowed");
|
|
36480
|
+
var mrrlinProducedUrlPayloadSchema = external_exports.object({
|
|
36481
|
+
url: producedUrlSafeString.min(1).max(2048).refine((v) => v.startsWith("/") || /^https?:\/\//.test(v), "must be an absolute http(s) URL or a path starting with /"),
|
|
36482
|
+
label: producedUrlSafeString.min(1).max(40).optional()
|
|
36483
|
+
});
|
|
36476
36484
|
var taxonomyCategorySchema = external_exports.string().min(1).regex(/^[a-z][a-z0-9-]*$/);
|
|
36477
36485
|
var taxonomySubcategorySchema = external_exports.string().min(1).regex(/^[a-z][a-z0-9-]*$/);
|
|
36478
36486
|
var mrrlinTaskAssigneeSchema = external_exports.union([external_exports.string().regex(/^@/), external_exports.string().email()]).nullable();
|
|
@@ -36492,7 +36500,13 @@ var mrrlinTaskSchema = external_exports.object({
|
|
|
36492
36500
|
latestJudgementAt: external_exports.string().datetime().nullable().default(null),
|
|
36493
36501
|
latestJudgementKind: external_exports.enum(["autonomy", "handoff"]).nullable().default(null),
|
|
36494
36502
|
notes: external_exports.string().nullable().default(null),
|
|
36503
|
+
// Raw operator request captured at task creation (operator-authored ONLY, never Director-generated).
|
|
36504
|
+
// The intent-aware spec gate judges the spec against this; null/absent ⇒ the gate fail-closes.
|
|
36505
|
+
// Output-optional (not .default) so existing task fixtures need no churn; DB rows always resolve it
|
|
36506
|
+
// to `string | null` via taskRowToTask.
|
|
36507
|
+
operatorSeedRequest: external_exports.string().max(8e3).nullable().optional(),
|
|
36495
36508
|
planId: mrrlinPlanIdSchema.nullable(),
|
|
36509
|
+
specApproved: mrrlinSpecApprovedSchema.optional(),
|
|
36496
36510
|
specWikiPageId: mrrlinWikiPageIdSchema.nullable(),
|
|
36497
36511
|
status: mrrlinTaskStatusSchema,
|
|
36498
36512
|
subcategory: taxonomySubcategorySchema,
|
|
@@ -36508,6 +36522,7 @@ var mrrlinPlanSchema = external_exports.object({
|
|
|
36508
36522
|
id: mrrlinPlanIdSchema,
|
|
36509
36523
|
name: external_exports.string().min(1),
|
|
36510
36524
|
progress: external_exports.number().min(0).max(1),
|
|
36525
|
+
specWikiPageId: external_exports.string().nullable().default(null),
|
|
36511
36526
|
status: mrrlinPlanStatusSchema,
|
|
36512
36527
|
taskCount: external_exports.number().int().nonnegative()
|
|
36513
36528
|
});
|
|
@@ -36588,14 +36603,28 @@ var mrrlinProjectSummarySchema = external_exports.object({
|
|
|
36588
36603
|
displayName: external_exports.string().min(1),
|
|
36589
36604
|
emoji: mrrlinProjectEmojiSchema,
|
|
36590
36605
|
github: mrrlinGithubBindingSchema,
|
|
36606
|
+
onboardingKickoffState: external_exports.enum(["pending", "sent"]).nullable().optional(),
|
|
36591
36607
|
slug: mrrlinProjectSlugSchema
|
|
36592
36608
|
});
|
|
36593
36609
|
var mrrlinProjectUpsertSchema = mrrlinProjectSummarySchema.omit({
|
|
36610
|
+
onboardingKickoffState: true,
|
|
36594
36611
|
slug: true
|
|
36595
36612
|
});
|
|
36596
36613
|
var mrrlinProjectRenameSchema = external_exports.object({
|
|
36597
36614
|
displayName: external_exports.string().trim().min(1).max(120)
|
|
36598
36615
|
});
|
|
36616
|
+
var ONBOARDING_KICKOFF_TRANSITIONS = [
|
|
36617
|
+
{ from: null, to: "pending" },
|
|
36618
|
+
{ from: "pending", to: "sent" },
|
|
36619
|
+
{ from: "sent", to: "pending" }
|
|
36620
|
+
];
|
|
36621
|
+
var mrrlinOnboardingKickoffTransitionSchema = external_exports.object({
|
|
36622
|
+
from: external_exports.enum(["pending", "sent"]).nullable(),
|
|
36623
|
+
to: external_exports.enum(["pending", "sent"])
|
|
36624
|
+
}).refine((value) => ONBOARDING_KICKOFF_TRANSITIONS.some((t) => t.from === value.from && t.to === value.to), { message: "Unsupported onboarding kickoff transition" });
|
|
36625
|
+
var mrrlinOnboardingKickoffTransitionResponseSchema = external_exports.object({
|
|
36626
|
+
data: external_exports.object({ applied: external_exports.boolean() })
|
|
36627
|
+
});
|
|
36599
36628
|
var mrrlinProjectMemberSchema = external_exports.object({
|
|
36600
36629
|
email: external_exports.string().email(),
|
|
36601
36630
|
githubLogin: external_exports.string().nullable(),
|
|
@@ -36632,6 +36661,7 @@ var mrrlinTaskCreateSchema = external_exports.object({
|
|
|
36632
36661
|
id: mrrlinTaskIdSchema,
|
|
36633
36662
|
impact: mrrlinTaskImpactSchema.default("medium"),
|
|
36634
36663
|
notes: external_exports.string().nullable().optional(),
|
|
36664
|
+
operatorSeedRequest: external_exports.string().max(8e3).nullable().optional(),
|
|
36635
36665
|
planId: mrrlinPlanIdSchema.nullable().optional(),
|
|
36636
36666
|
specWikiPageId: mrrlinWikiPageIdSchema.nullable().optional(),
|
|
36637
36667
|
tags: mrrlinTaskTagsSchema.optional(),
|
|
@@ -36655,6 +36685,7 @@ var mrrlinTaskUpdateSchema = external_exports.object({
|
|
|
36655
36685
|
impact: mrrlinTaskImpactSchema.optional(),
|
|
36656
36686
|
notes: external_exports.string().nullable().optional(),
|
|
36657
36687
|
planId: mrrlinPlanIdSchema.nullable().optional(),
|
|
36688
|
+
specApproved: mrrlinSpecApprovedSchema.optional(),
|
|
36658
36689
|
specWikiPageId: mrrlinWikiPageIdSchema.nullable().optional(),
|
|
36659
36690
|
status: mrrlinTaskStatusSchema.optional(),
|
|
36660
36691
|
subcategory: taxonomySubcategorySchema.optional(),
|
|
@@ -36662,7 +36693,7 @@ var mrrlinTaskUpdateSchema = external_exports.object({
|
|
|
36662
36693
|
type: mrrlinTaskTypeSchema.optional(),
|
|
36663
36694
|
followUpAt: external_exports.string().datetime().nullable().optional(),
|
|
36664
36695
|
verificationDueAt: external_exports.string().datetime().nullable().optional()
|
|
36665
|
-
}).refine((value) => value.assignee !== void 0 || value.autoDeploy !== void 0 || value.autonomyLevel !== void 0 || value.autonomyReason !== void 0 || value.category !== void 0 || value.directorThreadId !== void 0 || value.dueDate !== void 0 || value.followUpAt !== void 0 || value.impact !== void 0 || value.notes !== void 0 || value.planId !== void 0 || value.specWikiPageId !== void 0 || value.status !== void 0 || value.subcategory !== void 0 || value.tags !== void 0 || value.type !== void 0 || value.verificationDueAt !== void 0, { message: "TaskUpdate requires at least one field" }).superRefine((value, context) => {
|
|
36696
|
+
}).refine((value) => value.assignee !== void 0 || value.autoDeploy !== void 0 || value.autonomyLevel !== void 0 || value.autonomyReason !== void 0 || value.category !== void 0 || value.directorThreadId !== void 0 || value.dueDate !== void 0 || value.followUpAt !== void 0 || value.impact !== void 0 || value.notes !== void 0 || value.planId !== void 0 || value.specApproved !== void 0 || value.specWikiPageId !== void 0 || value.status !== void 0 || value.subcategory !== void 0 || value.tags !== void 0 || value.type !== void 0 || value.verificationDueAt !== void 0, { message: "TaskUpdate requires at least one field" }).superRefine((value, context) => {
|
|
36666
36697
|
if (value.autonomyLevel !== void 0 && value.autonomyReason === void 0) {
|
|
36667
36698
|
context.addIssue({
|
|
36668
36699
|
code: external_exports.ZodIssueCode.custom,
|
|
@@ -36703,12 +36734,14 @@ var mrrlinPlanCreateSchema = external_exports.object({
|
|
|
36703
36734
|
goal: external_exports.string().min(1),
|
|
36704
36735
|
id: mrrlinPlanIdSchema,
|
|
36705
36736
|
name: external_exports.string().min(1),
|
|
36737
|
+
specWikiPageId: external_exports.string().nullable().optional(),
|
|
36706
36738
|
status: mrrlinPlanStatusSchema.default("active")
|
|
36707
36739
|
});
|
|
36708
36740
|
var mrrlinPlanUpdateSchema = external_exports.object({
|
|
36709
36741
|
dueDate: external_exports.string().date().nullable().optional(),
|
|
36710
36742
|
goal: external_exports.string().min(1).optional(),
|
|
36711
36743
|
name: external_exports.string().min(1).optional(),
|
|
36744
|
+
specWikiPageId: external_exports.string().nullable().optional(),
|
|
36712
36745
|
status: mrrlinPlanStatusSchema.optional()
|
|
36713
36746
|
}).refine((value) => Object.keys(value).length > 0, { message: "PlanUpdate requires at least one field" });
|
|
36714
36747
|
var mrrlinTaxonomyCreateSchema = mrrlinTaxonomyEntrySchema;
|
|
@@ -37103,7 +37136,9 @@ var exchangeAgentTokenRequestSchema = external_exports.object({
|
|
|
37103
37136
|
var exchangeAgentTokenResponseSchema = external_exports.object({
|
|
37104
37137
|
token: external_exports.string().min(1),
|
|
37105
37138
|
expiresAt: external_exports.string().datetime(),
|
|
37106
|
-
|
|
37139
|
+
// ADR 0016 §T7 amendment: operator-scope exchanges return no projectSlug (the token is
|
|
37140
|
+
// operator-wide); project-scope exchanges still return the pinned slug.
|
|
37141
|
+
projectSlug: external_exports.string().min(1).optional(),
|
|
37107
37142
|
login: external_exports.string().min(1)
|
|
37108
37143
|
});
|
|
37109
37144
|
var MRRLIN_ARTIFACT_FILE_MAX_BYTES = 5 * 1024 * 1024;
|
|
@@ -37271,6 +37306,8 @@ var mrrlinInboxItemSchema = external_exports.object({
|
|
|
37271
37306
|
directorSessionId: external_exports.string().min(1).nullable(),
|
|
37272
37307
|
id: mrrlinInboxItemIdSchema,
|
|
37273
37308
|
kind: mrrlinInboxItemKindSchema,
|
|
37309
|
+
origin: external_exports.string().nullable().optional(),
|
|
37310
|
+
planId: mrrlinPlanIdSchema.nullable().default(null),
|
|
37274
37311
|
projectSlug: mrrlinProjectSlugSchema,
|
|
37275
37312
|
readAt: external_exports.string().datetime().nullable(),
|
|
37276
37313
|
status: mrrlinInboxItemStatusSchema,
|
|
@@ -37282,6 +37319,8 @@ var mrrlinInboxItemCreateSchema = external_exports.object({
|
|
|
37282
37319
|
directorSessionId: external_exports.string().min(1).optional(),
|
|
37283
37320
|
id: mrrlinInboxItemIdSchema,
|
|
37284
37321
|
kind: mrrlinInboxItemKindSchema,
|
|
37322
|
+
origin: external_exports.string().min(1).optional(),
|
|
37323
|
+
planId: mrrlinPlanIdSchema.nullable().optional(),
|
|
37285
37324
|
taskId: mrrlinTaskIdSchema.nullable().optional()
|
|
37286
37325
|
});
|
|
37287
37326
|
var mrrlinInboxItemDecideSchema = external_exports.object({
|
|
@@ -37412,18 +37451,18 @@ function createMrrlinClient(config2) {
|
|
|
37412
37451
|
const customFetch = config2.fetch ?? globalThis.fetch;
|
|
37413
37452
|
const baseUrl = config2.baseUrl.replace(/\/$/, "");
|
|
37414
37453
|
const token = config2.token;
|
|
37415
|
-
async function request(
|
|
37454
|
+
async function request(path15, init) {
|
|
37416
37455
|
const method = init?.method ?? "GET";
|
|
37417
37456
|
const headers = new Headers(init?.headers ?? {});
|
|
37418
37457
|
if (token && !headers.has("authorization")) {
|
|
37419
37458
|
headers.set("authorization", `Bearer ${token}`);
|
|
37420
37459
|
}
|
|
37421
|
-
const response = await customFetch(`${baseUrl}${
|
|
37460
|
+
const response = await customFetch(`${baseUrl}${path15}`, { ...init, headers });
|
|
37422
37461
|
if (!response.ok) {
|
|
37423
37462
|
const body = await response.text();
|
|
37424
37463
|
let code = `HTTP_${response.status}`;
|
|
37425
37464
|
let violations = null;
|
|
37426
|
-
let message = `Mrrlin API ${method} ${
|
|
37465
|
+
let message = `Mrrlin API ${method} ${path15} failed: ${response.status}`;
|
|
37427
37466
|
try {
|
|
37428
37467
|
const parsed = JSON.parse(body);
|
|
37429
37468
|
const violationsParsed = apiViolationsErrorSchema.safeParse(parsed);
|
|
@@ -37443,7 +37482,7 @@ function createMrrlinClient(config2) {
|
|
|
37443
37482
|
throw new MrrlinApiError({
|
|
37444
37483
|
code,
|
|
37445
37484
|
method,
|
|
37446
|
-
path:
|
|
37485
|
+
path: path15,
|
|
37447
37486
|
responseBody: body,
|
|
37448
37487
|
status: response.status,
|
|
37449
37488
|
violations,
|
|
@@ -37531,6 +37570,14 @@ function createMrrlinClient(config2) {
|
|
|
37531
37570
|
});
|
|
37532
37571
|
return projectSummaryResponseSchema.parse(body).data;
|
|
37533
37572
|
},
|
|
37573
|
+
async transitionOnboardingKickoff(projectSlug, input) {
|
|
37574
|
+
const body = await request(`${projectPath(projectSlug)}/onboarding-kickoff`, {
|
|
37575
|
+
body: JSON.stringify(mrrlinOnboardingKickoffTransitionSchema.parse(input)),
|
|
37576
|
+
headers: { "content-type": "application/json" },
|
|
37577
|
+
method: "PATCH"
|
|
37578
|
+
});
|
|
37579
|
+
return mrrlinOnboardingKickoffTransitionResponseSchema.parse(body).data.applied;
|
|
37580
|
+
},
|
|
37534
37581
|
async createTaskDependency(projectSlug, input) {
|
|
37535
37582
|
const body = await request(`${projectPath(projectSlug)}/task-dependencies`, {
|
|
37536
37583
|
body: JSON.stringify(input),
|
|
@@ -37690,7 +37737,7 @@ function createMrrlinClient(config2) {
|
|
|
37690
37737
|
return taskEventListResponseSchema.parse(body).data;
|
|
37691
37738
|
},
|
|
37692
37739
|
async listTasks(projectSlug, filters = {}) {
|
|
37693
|
-
const
|
|
37740
|
+
const path15 = appendQuery(`${projectPath(projectSlug)}/tasks`, {
|
|
37694
37741
|
assignee: filters.assignee,
|
|
37695
37742
|
autonomyLevel: filters.autonomyLevel,
|
|
37696
37743
|
blockedBy: filters.blockedBy,
|
|
@@ -37702,7 +37749,7 @@ function createMrrlinClient(config2) {
|
|
|
37702
37749
|
subcategory: filters.subcategory,
|
|
37703
37750
|
type: filters.type
|
|
37704
37751
|
});
|
|
37705
|
-
const body = await request(
|
|
37752
|
+
const body = await request(path15);
|
|
37706
37753
|
return taskListResponseSchema.parse(body).data;
|
|
37707
37754
|
},
|
|
37708
37755
|
async listTaxonomy(projectSlug) {
|
|
@@ -37710,22 +37757,22 @@ function createMrrlinClient(config2) {
|
|
|
37710
37757
|
return taxonomyListResponseSchema.parse(body).data;
|
|
37711
37758
|
},
|
|
37712
37759
|
async listWikiPages(projectSlug, filters = {}) {
|
|
37713
|
-
const
|
|
37760
|
+
const path15 = appendQuery(`${projectPath(projectSlug)}/wiki`, {
|
|
37714
37761
|
folder: filters.folder,
|
|
37715
37762
|
q: filters.q,
|
|
37716
37763
|
taskId: filters.taskId
|
|
37717
37764
|
});
|
|
37718
|
-
const body = await request(
|
|
37765
|
+
const body = await request(path15);
|
|
37719
37766
|
return wikiPageListResponseSchema.parse(body).data;
|
|
37720
37767
|
},
|
|
37721
37768
|
async searchWikiPages(projectSlug, query) {
|
|
37722
|
-
const
|
|
37769
|
+
const path15 = appendQuery(`${projectPath(projectSlug)}/wiki/search`, {
|
|
37723
37770
|
folder: query.folder,
|
|
37724
37771
|
limit: query.limit === void 0 ? void 0 : String(query.limit),
|
|
37725
37772
|
pathPrefix: query.pathPrefix,
|
|
37726
37773
|
q: query.q
|
|
37727
37774
|
});
|
|
37728
|
-
const body = await request(
|
|
37775
|
+
const body = await request(path15);
|
|
37729
37776
|
return wikiPageSearchResponseSchema.parse(body).data;
|
|
37730
37777
|
},
|
|
37731
37778
|
async updatePlan(projectSlug, planId, patch) {
|
|
@@ -38442,7 +38489,7 @@ Do NOT derail the current task \u2014 if the operator has an in-flight question,
|
|
|
38442
38489
|
}
|
|
38443
38490
|
|
|
38444
38491
|
// src/_generated/version.ts
|
|
38445
|
-
var PKG_VERSION = "0.3.
|
|
38492
|
+
var PKG_VERSION = "0.3.7";
|
|
38446
38493
|
|
|
38447
38494
|
// src/api-base-url.ts
|
|
38448
38495
|
var DEFAULT_API_BASE_URL = "http://127.0.0.1:8787";
|
|
@@ -38826,6 +38873,41 @@ async function sweepOrphanWorktrees(opts) {
|
|
|
38826
38873
|
return reaped;
|
|
38827
38874
|
}
|
|
38828
38875
|
|
|
38876
|
+
// src/pr-body.ts
|
|
38877
|
+
function isSafeAbsoluteUrl(url2) {
|
|
38878
|
+
try {
|
|
38879
|
+
const protocol = new URL(url2).protocol;
|
|
38880
|
+
return protocol === "http:" || protocol === "https:";
|
|
38881
|
+
} catch {
|
|
38882
|
+
return false;
|
|
38883
|
+
}
|
|
38884
|
+
}
|
|
38885
|
+
function escapeMarkdown(text) {
|
|
38886
|
+
return text.replace(/([\\`[\]])/g, "\\$1");
|
|
38887
|
+
}
|
|
38888
|
+
function buildPullRequestBody(input) {
|
|
38889
|
+
const plain = `Automated change for run \`${input.runId}\` (task ${input.taskId}).`;
|
|
38890
|
+
const seen = /* @__PURE__ */ new Set();
|
|
38891
|
+
const lines2 = [];
|
|
38892
|
+
for (const { url: url2, label } of input.producedUrls) {
|
|
38893
|
+
if (seen.has(url2)) continue;
|
|
38894
|
+
seen.add(url2);
|
|
38895
|
+
if (url2.startsWith("/")) {
|
|
38896
|
+
const note = label ? `${escapeMarkdown(label)} \u2014 ` : "";
|
|
38897
|
+
lines2.push(`- ${note}\`${escapeMarkdown(url2)}\` (deploy-relative)`);
|
|
38898
|
+
continue;
|
|
38899
|
+
}
|
|
38900
|
+
if (!isSafeAbsoluteUrl(url2)) continue;
|
|
38901
|
+
const text = escapeMarkdown(label ?? "Page");
|
|
38902
|
+
lines2.push(`- [${text}](${url2})`);
|
|
38903
|
+
}
|
|
38904
|
+
if (lines2.length === 0) return plain;
|
|
38905
|
+
return `${plain}
|
|
38906
|
+
|
|
38907
|
+
## Produced pages
|
|
38908
|
+
${lines2.join("\n")}`;
|
|
38909
|
+
}
|
|
38910
|
+
|
|
38829
38911
|
// src/execution-consumer.ts
|
|
38830
38912
|
var DEFAULT_STALE_SECONDS = 300;
|
|
38831
38913
|
var DEFAULT_TOUCH_INTERVAL_MS = 6e4;
|
|
@@ -38868,6 +38950,16 @@ var BASE_INSTRUCTIONS_PREFIX = [
|
|
|
38868
38950
|
" or evidence page will reference (180 days). Always pass taskId/runId when known.",
|
|
38869
38951
|
"- Anything user-facing delivered as a file MUST be uploaded. Files are capped at 5MB \u2014",
|
|
38870
38952
|
" split or summarize larger outputs.",
|
|
38953
|
+
"",
|
|
38954
|
+
"Browser tools (when the run needs to drive a browser):",
|
|
38955
|
+
"- Use tools from the `mrrlin-browser` MCP server ONLY \u2014 browser_navigate, browser_click,",
|
|
38956
|
+
" browser_snapshot, browser_type, etc. Never invoke the same-named tools from any other",
|
|
38957
|
+
" browser MCP (`playwright`, `chrome-devtools`, `puppeteer`, ...) that may also be connected.",
|
|
38958
|
+
"- Only `mrrlin-browser` uses this project's dedicated, version-pinned Chromium + persistent",
|
|
38959
|
+
" operator profile (`~/.mrrlin/browser/profile`). Others share the default Playwright profile",
|
|
38960
|
+
" and lose login/cookie state across runs.",
|
|
38961
|
+
"- If tool listings show duplicate names across servers, prefer the `mrrlin-browser` one",
|
|
38962
|
+
" unconditionally. Do not switch mid-run.",
|
|
38871
38963
|
""
|
|
38872
38964
|
];
|
|
38873
38965
|
var CONSUMER_BASE_INSTRUCTIONS = [
|
|
@@ -39200,8 +39292,19 @@ Continue executing task ${task.id}. Make the next concrete increment of progress
|
|
|
39200
39292
|
}
|
|
39201
39293
|
return m;
|
|
39202
39294
|
});
|
|
39295
|
+
const producedUrls = await (async () => {
|
|
39296
|
+
try {
|
|
39297
|
+
const artifacts = await deps.client.listExecutionArtifacts(projectSlug, runId);
|
|
39298
|
+
return artifacts.filter((a) => a.kind === "produced_url").flatMap((a) => {
|
|
39299
|
+
const parsed = mrrlinProducedUrlPayloadSchema.safeParse(a.payload);
|
|
39300
|
+
return parsed.success ? [parsed.data] : [];
|
|
39301
|
+
});
|
|
39302
|
+
} catch {
|
|
39303
|
+
return [];
|
|
39304
|
+
}
|
|
39305
|
+
})();
|
|
39203
39306
|
const pr = await deps.client.createGithubPullRequest(projectSlug, {
|
|
39204
|
-
body:
|
|
39307
|
+
body: buildPullRequestBody({ runId, taskId: readiness.task.id, producedUrls }),
|
|
39205
39308
|
draft: true,
|
|
39206
39309
|
headBranch: minted.branch,
|
|
39207
39310
|
title: `[mrrlin] ${readiness.task.title}`
|
|
@@ -41014,7 +41117,7 @@ function validateOpts(curve) {
|
|
|
41014
41117
|
}
|
|
41015
41118
|
function twistedEdwards(curveDef) {
|
|
41016
41119
|
const CURVE = validateOpts(curveDef);
|
|
41017
|
-
const { Fp: Fp2, n: CURVE_ORDER, prehash, hash: cHash, randomBytes:
|
|
41120
|
+
const { Fp: Fp2, n: CURVE_ORDER, prehash, hash: cHash, randomBytes: randomBytes4, nByteLength, h: cofactor } = CURVE;
|
|
41018
41121
|
const MASK = _2n3 << BigInt(nByteLength * 8) - _1n4;
|
|
41019
41122
|
const modP = Fp2.create;
|
|
41020
41123
|
const uvRatio2 = CURVE.uvRatio || ((u, v) => {
|
|
@@ -41353,7 +41456,7 @@ function twistedEdwards(curveDef) {
|
|
|
41353
41456
|
const utils = {
|
|
41354
41457
|
getExtendedPublicKey,
|
|
41355
41458
|
// ed25519 private keys are uniform 32b. No need to check for modulo bias, like in secp256k1.
|
|
41356
|
-
randomPrivateKey: () =>
|
|
41459
|
+
randomPrivateKey: () => randomBytes4(Fp2.BYTES),
|
|
41357
41460
|
/**
|
|
41358
41461
|
* We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
|
|
41359
41462
|
* values. This slows down first getPublicKey() by milliseconds (see Speed section),
|
|
@@ -42520,7 +42623,10 @@ function parseFrame(bytes3) {
|
|
|
42520
42623
|
};
|
|
42521
42624
|
}
|
|
42522
42625
|
case "inbox_read":
|
|
42523
|
-
return {
|
|
42626
|
+
return {
|
|
42627
|
+
type: "inbox_read",
|
|
42628
|
+
...isString(f.projectSlug) ? { projectSlug: f.projectSlug } : {}
|
|
42629
|
+
};
|
|
42524
42630
|
case "inbox_decide":
|
|
42525
42631
|
if (!isString(f.itemId) || !isString(f.idempotencyKey))
|
|
42526
42632
|
throw new Error("frame inbox_decide: itemId + idempotencyKey required");
|
|
@@ -42533,7 +42639,8 @@ function parseFrame(bytes3) {
|
|
|
42533
42639
|
itemId: f.itemId,
|
|
42534
42640
|
decision: f.decision,
|
|
42535
42641
|
idempotencyKey: f.idempotencyKey,
|
|
42536
|
-
...f.reason === void 0 ? {} : { reason: f.reason }
|
|
42642
|
+
...f.reason === void 0 ? {} : { reason: f.reason },
|
|
42643
|
+
...isString(f.projectSlug) ? { projectSlug: f.projectSlug } : {}
|
|
42537
42644
|
};
|
|
42538
42645
|
case "ack":
|
|
42539
42646
|
if (!isString(f.refId))
|
|
@@ -43279,12 +43386,12 @@ var DirectorRelay = class {
|
|
|
43279
43386
|
this.sendFrame(channelId, { type: "ack", refId: frame.idempotencyKey });
|
|
43280
43387
|
return;
|
|
43281
43388
|
}
|
|
43282
|
-
await this.deps.onInboxDecide?.(frame.itemId, frame.decision, frame.idempotencyKey, frame.reason);
|
|
43389
|
+
await this.deps.onInboxDecide?.(frame.itemId, frame.decision, frame.idempotencyKey, frame.reason, frame.projectSlug);
|
|
43283
43390
|
this.seenDecideKeys.add(frame.idempotencyKey);
|
|
43284
43391
|
this.sendFrame(channelId, { type: "ack", refId: frame.idempotencyKey });
|
|
43285
43392
|
return;
|
|
43286
43393
|
case "inbox_read": {
|
|
43287
|
-
const items = await this.deps.onInboxRead?.();
|
|
43394
|
+
const items = await this.deps.onInboxRead?.(frame.projectSlug);
|
|
43288
43395
|
if (items !== void 0) this.sendDirectorEvent(channelId, { type: "inbox_items", items });
|
|
43289
43396
|
this.sendFrame(channelId, { type: "ack", refId: "inbox_read" });
|
|
43290
43397
|
return;
|
|
@@ -43312,9 +43419,9 @@ var DirectorRelay = class {
|
|
|
43312
43419
|
|
|
43313
43420
|
// src/remote-phone-relay.ts
|
|
43314
43421
|
function loadOrCreateAgentDeviceKey() {
|
|
43315
|
-
const
|
|
43422
|
+
const path15 = (0, import_node_path8.join)((0, import_node_os6.homedir)(), ".mrrlin", "agent-device-key");
|
|
43316
43423
|
try {
|
|
43317
|
-
const raw = JSON.parse((0, import_node_fs7.readFileSync)(
|
|
43424
|
+
const raw = JSON.parse((0, import_node_fs7.readFileSync)(path15, "utf8"));
|
|
43318
43425
|
if (typeof raw.priv === "string" && typeof raw.pub === "string") {
|
|
43319
43426
|
return { privateKey: fromBase64Url(raw.priv), publicKey: fromBase64Url(raw.pub) };
|
|
43320
43427
|
}
|
|
@@ -43324,7 +43431,7 @@ function loadOrCreateAgentDeviceKey() {
|
|
|
43324
43431
|
try {
|
|
43325
43432
|
(0, import_node_fs7.mkdirSync)((0, import_node_path8.join)((0, import_node_os6.homedir)(), ".mrrlin"), { recursive: true });
|
|
43326
43433
|
(0, import_node_fs7.writeFileSync)(
|
|
43327
|
-
|
|
43434
|
+
path15,
|
|
43328
43435
|
JSON.stringify({ priv: toBase64Url(kp.privateKey), pub: toBase64Url(kp.publicKey) }),
|
|
43329
43436
|
{ mode: 384 }
|
|
43330
43437
|
);
|
|
@@ -43429,30 +43536,38 @@ function decisionToVerdict(decision) {
|
|
|
43429
43536
|
throw new Error(`remote-relay: unknown inbox decision "${decision}"`);
|
|
43430
43537
|
}
|
|
43431
43538
|
}
|
|
43432
|
-
function
|
|
43433
|
-
const
|
|
43434
|
-
`));
|
|
43435
|
-
const provider = createAgentTokenProvider({ secret: deps.agentSecret, baseUrl: deps.apiBaseUrl });
|
|
43436
|
-
const authed = async () => {
|
|
43539
|
+
function _makeRelayInboxCallbacks(provider, apiBaseUrl) {
|
|
43540
|
+
const authed = async (frameSlug) => {
|
|
43437
43541
|
const session = await provider.getSession();
|
|
43542
|
+
const slug = frameSlug ?? session.projectSlug;
|
|
43543
|
+
if (!slug) {
|
|
43544
|
+
throw new Error("[mrrlin-mcp remote-relay] missing project context for inbox action");
|
|
43545
|
+
}
|
|
43438
43546
|
return {
|
|
43439
|
-
client: createMrrlinClient({ baseUrl:
|
|
43440
|
-
slug
|
|
43547
|
+
client: createMrrlinClient({ baseUrl: apiBaseUrl, token: session.token }),
|
|
43548
|
+
slug,
|
|
43441
43549
|
login: session.login
|
|
43442
43550
|
};
|
|
43443
43551
|
};
|
|
43444
|
-
const onInboxRead = async () => {
|
|
43445
|
-
const { client, slug } = await authed();
|
|
43552
|
+
const onInboxRead = async (projectSlug) => {
|
|
43553
|
+
const { client, slug } = await authed(projectSlug);
|
|
43446
43554
|
return boundInboxItems(await client.listInboxItems(slug, { status: "pending" }));
|
|
43447
43555
|
};
|
|
43448
|
-
const onInboxDecide = async (itemId, decision, _key, reason) => {
|
|
43449
|
-
const { client, slug, login } = await authed();
|
|
43556
|
+
const onInboxDecide = async (itemId, decision, _key, reason, projectSlug) => {
|
|
43557
|
+
const { client, slug, login } = await authed(projectSlug);
|
|
43450
43558
|
await client.decideInboxItem(slug, itemId, {
|
|
43451
43559
|
verdict: decisionToVerdict(decision),
|
|
43452
43560
|
decidedBy: login,
|
|
43453
43561
|
...reason ? { reason } : {}
|
|
43454
43562
|
});
|
|
43455
43563
|
};
|
|
43564
|
+
return { onInboxRead, onInboxDecide };
|
|
43565
|
+
}
|
|
43566
|
+
function startRemotePhoneRelay(deps) {
|
|
43567
|
+
const log = deps.log ?? ((m) => process.stderr.write(`[mrrlin-mcp remote-relay] ${m}
|
|
43568
|
+
`));
|
|
43569
|
+
const provider = createAgentTokenProvider({ secret: deps.agentSecret, baseUrl: deps.apiBaseUrl });
|
|
43570
|
+
const { onInboxRead, onInboxDecide } = _makeRelayInboxCallbacks(provider, deps.apiBaseUrl);
|
|
43456
43571
|
const relayClient = new RelayClient({
|
|
43457
43572
|
relayUrl: deps.relayUrl,
|
|
43458
43573
|
now: () => Date.now(),
|
|
@@ -43539,9 +43654,9 @@ var CheckoutRegistry = class {
|
|
|
43539
43654
|
get(slug) {
|
|
43540
43655
|
return this.read()[slug] ?? null;
|
|
43541
43656
|
}
|
|
43542
|
-
confirm(slug,
|
|
43657
|
+
confirm(slug, path15, now) {
|
|
43543
43658
|
const all = this.read();
|
|
43544
|
-
all[slug] = { path:
|
|
43659
|
+
all[slug] = { path: path15, confirmedAt: now };
|
|
43545
43660
|
(0, import_node_fs8.writeFileSync)(this.file, JSON.stringify(all, null, 2));
|
|
43546
43661
|
}
|
|
43547
43662
|
};
|
|
@@ -43957,336 +44072,6 @@ function createBridgeLogger(stateDir, env = process.env) {
|
|
|
43957
44072
|
};
|
|
43958
44073
|
}
|
|
43959
44074
|
|
|
43960
|
-
// src/issue-report.ts
|
|
43961
|
-
var import_node_fs11 = require("node:fs");
|
|
43962
|
-
var import_node_os8 = require("node:os");
|
|
43963
|
-
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
43964
|
-
var import_node_child_process4 = require("node:child_process");
|
|
43965
|
-
var TELEGRAM_BOT_TOKEN = "8506614214:AAGyhO1phWb7ah2aN6_gAX2Co7OXNN3zb0A";
|
|
43966
|
-
var TELEGRAM_CHAT_ID = "-5373779177";
|
|
43967
|
-
function summarizeTranscript(entries = []) {
|
|
43968
|
-
const normalized = entries.map((entry) => ({
|
|
43969
|
-
kind: entry.kind,
|
|
43970
|
-
content: squashWhitespace(entry.content)
|
|
43971
|
-
})).filter((entry) => entry.content.length > 0);
|
|
43972
|
-
if (normalized.length <= 20) return normalized;
|
|
43973
|
-
return normalized.slice(normalized.length - 20);
|
|
43974
|
-
}
|
|
43975
|
-
function squashWhitespace(value) {
|
|
43976
|
-
return value.replace(/\s+/g, " ").trim();
|
|
43977
|
-
}
|
|
43978
|
-
function clip(value, maxChars) {
|
|
43979
|
-
if (value.length <= maxChars) return value;
|
|
43980
|
-
return `${value.slice(0, Math.max(0, maxChars - 1))}\u2026`;
|
|
43981
|
-
}
|
|
43982
|
-
function firstSentence(value) {
|
|
43983
|
-
const trimmed = squashWhitespace(value);
|
|
43984
|
-
if (!trimmed) return "";
|
|
43985
|
-
const match = trimmed.match(/^(.{1,120}?[.!?])(?:\s|$)/);
|
|
43986
|
-
return match?.[1] ? squashWhitespace(match[1]) : clip(trimmed, 120);
|
|
43987
|
-
}
|
|
43988
|
-
function describePayload(payload) {
|
|
43989
|
-
if (typeof payload === "string") return payload;
|
|
43990
|
-
try {
|
|
43991
|
-
return JSON.stringify(payload);
|
|
43992
|
-
} catch {
|
|
43993
|
-
return String(payload);
|
|
43994
|
-
}
|
|
43995
|
-
}
|
|
43996
|
-
function resolveLogDir() {
|
|
43997
|
-
const codexHome = process.env.CODEX_HOME?.trim();
|
|
43998
|
-
if (codexHome) {
|
|
43999
|
-
const candidate = import_node_path12.default.join(codexHome, "mrrlin", "director-bridge", "logs");
|
|
44000
|
-
if (existsDir(candidate)) return candidate;
|
|
44001
|
-
}
|
|
44002
|
-
const fallback = import_node_path12.default.join((0, import_node_os8.homedir)(), ".mrrlin", "director-bridge", "logs");
|
|
44003
|
-
return fallback;
|
|
44004
|
-
}
|
|
44005
|
-
function existsDir(candidate) {
|
|
44006
|
-
try {
|
|
44007
|
-
return (0, import_node_fs11.statSync)(candidate).isDirectory();
|
|
44008
|
-
} catch {
|
|
44009
|
-
return false;
|
|
44010
|
-
}
|
|
44011
|
-
}
|
|
44012
|
-
function listRecentLogFiles(logDir) {
|
|
44013
|
-
if (!existsDir(logDir)) return [];
|
|
44014
|
-
return (0, import_node_fs11.readdirSync)(logDir).filter((name) => /^bridge-\d{4}-\d{2}-\d{2}\.jsonl$/.test(name)).sort((a, b) => b.localeCompare(a)).slice(0, 3).map((name) => import_node_path12.default.join(logDir, name));
|
|
44015
|
-
}
|
|
44016
|
-
function parseLogFile(file2) {
|
|
44017
|
-
const lines2 = (0, import_node_fs11.readFileSync)(file2, "utf8").split(/\r?\n/).filter(Boolean);
|
|
44018
|
-
const parsed = [];
|
|
44019
|
-
for (const rawLine of lines2) {
|
|
44020
|
-
try {
|
|
44021
|
-
const raw = JSON.parse(rawLine);
|
|
44022
|
-
if (typeof raw.ts !== "string" || typeof raw.type !== "string" || typeof raw.spanId !== "string") continue;
|
|
44023
|
-
parsed.push({
|
|
44024
|
-
ts: raw.ts,
|
|
44025
|
-
dir: raw.dir === "in" ? "in" : "out",
|
|
44026
|
-
spanId: raw.spanId,
|
|
44027
|
-
sessionId: typeof raw.sessionId === "string" ? raw.sessionId : null,
|
|
44028
|
-
type: raw.type,
|
|
44029
|
-
ms: typeof raw.ms === "number" ? raw.ms : void 0,
|
|
44030
|
-
payload: raw.payload,
|
|
44031
|
-
rawLine,
|
|
44032
|
-
file: file2
|
|
44033
|
-
});
|
|
44034
|
-
} catch {
|
|
44035
|
-
}
|
|
44036
|
-
}
|
|
44037
|
-
return parsed;
|
|
44038
|
-
}
|
|
44039
|
-
function looksLikeError(record2) {
|
|
44040
|
-
if (record2.type === "error" || record2.type === "<parse-error>") return true;
|
|
44041
|
-
const text = `${record2.type} ${describePayload(record2.payload)}`.toLowerCase();
|
|
44042
|
-
return /(^|[^a-z])(error|failed|failure|timed out|timeout|unauthorized|forbidden|invalid|closed before returning a reply)([^a-z]|$)/.test(
|
|
44043
|
-
text
|
|
44044
|
-
);
|
|
44045
|
-
}
|
|
44046
|
-
function buildKeywordSet(input) {
|
|
44047
|
-
return Array.from(
|
|
44048
|
-
new Set(
|
|
44049
|
-
input.toLowerCase().split(/[^a-z0-9_:-]+/).map((part) => part.trim()).filter((part) => part.length >= 4)
|
|
44050
|
-
)
|
|
44051
|
-
).slice(0, 8);
|
|
44052
|
-
}
|
|
44053
|
-
function pickCluster(records, index) {
|
|
44054
|
-
const from = Math.max(0, index - 10);
|
|
44055
|
-
const to = Math.min(records.length, index + 31);
|
|
44056
|
-
return records.slice(from, to);
|
|
44057
|
-
}
|
|
44058
|
-
function findRelevantLogWindow(request, opts = {}) {
|
|
44059
|
-
const logDir = opts.logDir ?? resolveLogDir();
|
|
44060
|
-
const files = listRecentLogFiles(logDir);
|
|
44061
|
-
if (files.length === 0) {
|
|
44062
|
-
return { strategy: "no-log", matchedOn: "(log directory missing or empty)", records: [], file: null };
|
|
44063
|
-
}
|
|
44064
|
-
const allRecords = files.flatMap((file2) => parseLogFile(file2));
|
|
44065
|
-
if (allRecords.length === 0) {
|
|
44066
|
-
return { strategy: "no-log", matchedOn: "(no readable JSONL records)", records: [], file: files[0] ?? null };
|
|
44067
|
-
}
|
|
44068
|
-
const directorSessionId = request.directorSessionId?.trim() || "";
|
|
44069
|
-
if (directorSessionId) {
|
|
44070
|
-
const sessionRecords = allRecords.filter((record2) => record2.sessionId === directorSessionId);
|
|
44071
|
-
if (sessionRecords.length > 0) {
|
|
44072
|
-
for (let index = sessionRecords.length - 1; index >= 0; index -= 1) {
|
|
44073
|
-
const record2 = sessionRecords[index];
|
|
44074
|
-
if (!record2 || !looksLikeError(record2)) continue;
|
|
44075
|
-
const cluster = pickCluster(sessionRecords, index);
|
|
44076
|
-
return {
|
|
44077
|
-
strategy: "session-error-cluster",
|
|
44078
|
-
matchedOn: clip(record2.rawLine, 160),
|
|
44079
|
-
records: cluster,
|
|
44080
|
-
file: record2.file
|
|
44081
|
-
};
|
|
44082
|
-
}
|
|
44083
|
-
return {
|
|
44084
|
-
strategy: "session-tail",
|
|
44085
|
-
matchedOn: `directorSessionId=${directorSessionId}`,
|
|
44086
|
-
records: sessionRecords.slice(Math.max(0, sessionRecords.length - 30)),
|
|
44087
|
-
file: sessionRecords.at(-1)?.file ?? null
|
|
44088
|
-
};
|
|
44089
|
-
}
|
|
44090
|
-
}
|
|
44091
|
-
const description = request.customerDescription.trim();
|
|
44092
|
-
const keywords = buildKeywordSet(description);
|
|
44093
|
-
if (keywords.length > 0) {
|
|
44094
|
-
for (let index = allRecords.length - 1; index >= 0; index -= 1) {
|
|
44095
|
-
const record2 = allRecords[index];
|
|
44096
|
-
if (!record2) continue;
|
|
44097
|
-
const haystack = `${record2.type} ${describePayload(record2.payload)}`.toLowerCase();
|
|
44098
|
-
if (!keywords.some((keyword) => haystack.includes(keyword))) continue;
|
|
44099
|
-
return {
|
|
44100
|
-
strategy: "hint-cluster",
|
|
44101
|
-
matchedOn: clip(record2.rawLine, 160),
|
|
44102
|
-
records: pickCluster(allRecords, index),
|
|
44103
|
-
file: record2.file
|
|
44104
|
-
};
|
|
44105
|
-
}
|
|
44106
|
-
}
|
|
44107
|
-
for (let index = allRecords.length - 1; index >= 0; index -= 1) {
|
|
44108
|
-
const record2 = allRecords[index];
|
|
44109
|
-
if (!record2 || !looksLikeError(record2)) continue;
|
|
44110
|
-
return {
|
|
44111
|
-
strategy: "global-error-tail",
|
|
44112
|
-
matchedOn: clip(record2.rawLine, 160),
|
|
44113
|
-
records: pickCluster(allRecords, index),
|
|
44114
|
-
file: record2.file
|
|
44115
|
-
};
|
|
44116
|
-
}
|
|
44117
|
-
const tail2 = allRecords.slice(Math.max(0, allRecords.length - 30));
|
|
44118
|
-
return {
|
|
44119
|
-
strategy: "global-error-tail",
|
|
44120
|
-
matchedOn: "(no error cluster; using global tail)",
|
|
44121
|
-
records: tail2,
|
|
44122
|
-
file: tail2.at(-1)?.file ?? null
|
|
44123
|
-
};
|
|
44124
|
-
}
|
|
44125
|
-
function formatTranscript(entries) {
|
|
44126
|
-
if (entries.length === 0) return "(no transcript context)";
|
|
44127
|
-
return entries.map((entry) => `- ${entry.kind}: ${clip(redact(entry.content), 400)}`).join("\n");
|
|
44128
|
-
}
|
|
44129
|
-
function formatLogWindow(window) {
|
|
44130
|
-
if (window.records.length === 0) return "(no relevant bridge log lines found)";
|
|
44131
|
-
const preferred = window.records.filter((record2) => looksLikeError(record2)).concat(window.records.filter((record2) => !looksLikeError(record2)));
|
|
44132
|
-
const unique = preferred.filter((record2, index, array2) => array2.findIndex((item) => item.rawLine === record2.rawLine) === index);
|
|
44133
|
-
return clip(
|
|
44134
|
-
unique.map((record2) => {
|
|
44135
|
-
const payload = clip(redact(describePayload(record2.payload)), 360);
|
|
44136
|
-
return `${record2.ts} ${record2.dir} ${record2.type} span=${record2.spanId}${record2.sessionId ? ` session=${record2.sessionId}` : ""} ${payload}`;
|
|
44137
|
-
}).join("\n"),
|
|
44138
|
-
5e3
|
|
44139
|
-
);
|
|
44140
|
-
}
|
|
44141
|
-
function titlePrefix(source) {
|
|
44142
|
-
return source === "shell-menu" ? "[Web]" : "[Director]";
|
|
44143
|
-
}
|
|
44144
|
-
function plainTitle(title) {
|
|
44145
|
-
return title.replace(/^\[[^\]]+\]\s*/, "").trim();
|
|
44146
|
-
}
|
|
44147
|
-
function buildIssueDraft(request, logWindow) {
|
|
44148
|
-
const customerDescription = clip(redact(request.customerDescription.trim() || "(not provided)"), 4e3);
|
|
44149
|
-
const titleStem = firstSentence(customerDescription) || firstSentence(logWindow.records.find((record2) => looksLikeError(record2))?.rawLine ?? "") || "Issue report";
|
|
44150
|
-
const title = clip(`${titlePrefix(request.source)} ${titleStem}`, 96);
|
|
44151
|
-
const transcript = summarizeTranscript(request.transcript ?? []);
|
|
44152
|
-
const screenshotLines = request.screenshots && request.screenshots.length > 0 ? request.screenshots.map((shot) => `- [${shot.filename}](${shot.url})`).join("\n") : "(no screenshots)";
|
|
44153
|
-
const environment = [
|
|
44154
|
-
`- Created at (UTC): ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
44155
|
-
`- Source: ${request.source}`,
|
|
44156
|
-
`- Project: ${request.projectSlug?.trim() || "(unknown)"}`,
|
|
44157
|
-
`- Route: ${request.urlPath?.trim() || "(unknown)"}`,
|
|
44158
|
-
`- Director session: ${request.directorSessionId?.trim() || "(none)"}`,
|
|
44159
|
-
`- @mrrlin-dev/mcp: ${PKG_VERSION}`,
|
|
44160
|
-
`- OS: ${(0, import_node_os8.platform)()}`,
|
|
44161
|
-
`- Node: ${process.version}`
|
|
44162
|
-
].join("\n");
|
|
44163
|
-
const logLabel = logWindow.file ? import_node_path12.default.basename(logWindow.file) : "(none)";
|
|
44164
|
-
const body = [
|
|
44165
|
-
"## Summary",
|
|
44166
|
-
`${titlePrefix(request.source)} issue report generated from local Mrrlin evidence.`,
|
|
44167
|
-
"",
|
|
44168
|
-
"## Customer report",
|
|
44169
|
-
customerDescription,
|
|
44170
|
-
"",
|
|
44171
|
-
"## Observed behavior",
|
|
44172
|
-
`- Log search strategy: ${logWindow.strategy}`,
|
|
44173
|
-
`- Matched on: ${redact(logWindow.matchedOn)}`,
|
|
44174
|
-
"",
|
|
44175
|
-
"## Director / shell context",
|
|
44176
|
-
environment,
|
|
44177
|
-
"",
|
|
44178
|
-
`## Bridge log excerpt (${logLabel})`,
|
|
44179
|
-
"```text",
|
|
44180
|
-
formatLogWindow(logWindow),
|
|
44181
|
-
"```",
|
|
44182
|
-
"",
|
|
44183
|
-
"## Transcript excerpt",
|
|
44184
|
-
"```text",
|
|
44185
|
-
formatTranscript(transcript),
|
|
44186
|
-
"```",
|
|
44187
|
-
"",
|
|
44188
|
-
"## Screenshots",
|
|
44189
|
-
screenshotLines
|
|
44190
|
-
].join("\n");
|
|
44191
|
-
return { title, body, labels: ["bug"] };
|
|
44192
|
-
}
|
|
44193
|
-
function buildTelegramAnnouncement(request, draft, issueUrl) {
|
|
44194
|
-
const summary = firstSentence(redact(request.customerDescription.trim())) || firstSentence(plainTitle(draft.title)) || "\u043D\u0435\u0432\u0456\u0434\u0442\u0432\u043E\u0440\u0435\u043D\u0430 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0430";
|
|
44195
|
-
return `\u0437\u0430\u0440\u0435\u043F\u043E\u0440\u0447\u0435\u043D\u043E \u043D\u043E\u0432\u0438\u0439 \u0431\u0430\u0433, \u043A\u043E\u0440\u043E\u0442\u043A\u043E: ${clip(summary, 280)}
|
|
44196
|
-
${issueUrl}`;
|
|
44197
|
-
}
|
|
44198
|
-
function ensureGhReady() {
|
|
44199
|
-
const auth = (0, import_node_child_process4.spawnSync)("gh", ["auth", "status", "-h", "github.com"], { encoding: "utf8" });
|
|
44200
|
-
if (auth.status !== 0) {
|
|
44201
|
-
const detail = (auth.stderr || auth.stdout || "gh auth status failed").trim();
|
|
44202
|
-
throw new Error(`GitHub CLI is not ready: ${detail}`);
|
|
44203
|
-
}
|
|
44204
|
-
}
|
|
44205
|
-
function createGithubIssue(draft) {
|
|
44206
|
-
ensureGhReady();
|
|
44207
|
-
const tmpDir = (0, import_node_fs11.mkdtempSync)(import_node_path12.default.join((0, import_node_os8.tmpdir)(), "mrrlin-issue-"));
|
|
44208
|
-
const bodyFile = import_node_path12.default.join(tmpDir, "issue-body.md");
|
|
44209
|
-
try {
|
|
44210
|
-
(0, import_node_fs11.writeFileSync)(bodyFile, draft.body, "utf8");
|
|
44211
|
-
const args = ["issue", "create", "--repo", "fnnzzz/mrrlin", "--title", draft.title, "--body-file", bodyFile];
|
|
44212
|
-
for (const label of draft.labels) args.push("--label", label);
|
|
44213
|
-
const result = (0, import_node_child_process4.spawnSync)("gh", args, { encoding: "utf8" });
|
|
44214
|
-
if (result.status !== 0) {
|
|
44215
|
-
const detail = (result.stderr || result.stdout || "gh issue create failed").trim();
|
|
44216
|
-
throw new Error(detail);
|
|
44217
|
-
}
|
|
44218
|
-
const url2 = (result.stdout || "").trim().split(/\s+/).at(-1) ?? "";
|
|
44219
|
-
if (!/^https?:\/\//.test(url2)) {
|
|
44220
|
-
throw new Error(`Issue created but URL could not be parsed from gh output: ${result.stdout.trim()}`);
|
|
44221
|
-
}
|
|
44222
|
-
const numberMatch = url2.match(/\/issues\/(\d+)$/);
|
|
44223
|
-
return { issueNumber: numberMatch ? Number(numberMatch[1]) : null, url: url2 };
|
|
44224
|
-
} finally {
|
|
44225
|
-
(0, import_node_fs11.rmSync)(tmpDir, { recursive: true, force: true });
|
|
44226
|
-
}
|
|
44227
|
-
}
|
|
44228
|
-
function sendTelegramAnnouncement(text) {
|
|
44229
|
-
const tmpDir = (0, import_node_fs11.mkdtempSync)(import_node_path12.default.join((0, import_node_os8.tmpdir)(), "mrrlin-issue-telegram-"));
|
|
44230
|
-
const bodyFile = import_node_path12.default.join(tmpDir, "telegram-body.json");
|
|
44231
|
-
try {
|
|
44232
|
-
(0, import_node_fs11.writeFileSync)(
|
|
44233
|
-
bodyFile,
|
|
44234
|
-
JSON.stringify({
|
|
44235
|
-
chat_id: TELEGRAM_CHAT_ID,
|
|
44236
|
-
text,
|
|
44237
|
-
disable_web_page_preview: true
|
|
44238
|
-
}),
|
|
44239
|
-
"utf8"
|
|
44240
|
-
);
|
|
44241
|
-
const result = (0, import_node_child_process4.spawnSync)(
|
|
44242
|
-
"curl",
|
|
44243
|
-
[
|
|
44244
|
-
"-sS",
|
|
44245
|
-
"-X",
|
|
44246
|
-
"POST",
|
|
44247
|
-
`https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`,
|
|
44248
|
-
"-H",
|
|
44249
|
-
"Content-Type: application/json",
|
|
44250
|
-
"--data-binary",
|
|
44251
|
-
`@${bodyFile}`
|
|
44252
|
-
],
|
|
44253
|
-
{ encoding: "utf8" }
|
|
44254
|
-
);
|
|
44255
|
-
if (result.error) {
|
|
44256
|
-
return `Telegram announce failed: ${result.error.message}`;
|
|
44257
|
-
}
|
|
44258
|
-
if (result.status !== 0) {
|
|
44259
|
-
const detail = (result.stderr || result.stdout || "curl failed").trim();
|
|
44260
|
-
return `Telegram announce failed: ${detail}`;
|
|
44261
|
-
}
|
|
44262
|
-
let parsed = null;
|
|
44263
|
-
try {
|
|
44264
|
-
parsed = JSON.parse(result.stdout || "{}");
|
|
44265
|
-
} catch {
|
|
44266
|
-
return `Telegram announce failed: could not parse response: ${result.stdout.trim()}`;
|
|
44267
|
-
}
|
|
44268
|
-
if (!parsed?.ok) {
|
|
44269
|
-
return `Telegram announce failed: ${parsed?.description || "unknown Telegram error"}`;
|
|
44270
|
-
}
|
|
44271
|
-
return null;
|
|
44272
|
-
} finally {
|
|
44273
|
-
(0, import_node_fs11.rmSync)(tmpDir, { recursive: true, force: true });
|
|
44274
|
-
}
|
|
44275
|
-
}
|
|
44276
|
-
function fileIssueReport(request, opts = {}) {
|
|
44277
|
-
const logWindow = findRelevantLogWindow(request, opts);
|
|
44278
|
-
const draft = buildIssueDraft(request, logWindow);
|
|
44279
|
-
const created = createGithubIssue(draft);
|
|
44280
|
-
const telegramWarning = sendTelegramAnnouncement(buildTelegramAnnouncement(request, draft, created.url));
|
|
44281
|
-
return {
|
|
44282
|
-
issueNumber: created.issueNumber,
|
|
44283
|
-
title: draft.title,
|
|
44284
|
-
url: created.url,
|
|
44285
|
-
telegramDelivered: telegramWarning === null,
|
|
44286
|
-
telegramWarning
|
|
44287
|
-
};
|
|
44288
|
-
}
|
|
44289
|
-
|
|
44290
44075
|
// src/director-bridge.ts
|
|
44291
44076
|
var DEFAULT_DIRECTOR_BRIDGE_ALLOWED_ORIGINS = [
|
|
44292
44077
|
"http://localhost:*",
|
|
@@ -44308,46 +44093,10 @@ function normalizeModel(value) {
|
|
|
44308
44093
|
const trimmed = value.trim();
|
|
44309
44094
|
return trimmed ? trimmed : null;
|
|
44310
44095
|
}
|
|
44311
|
-
function normalizeIssueTranscript(value) {
|
|
44312
|
-
if (value === void 0 || value === null) return [];
|
|
44313
|
-
if (!Array.isArray(value)) return { error: "transcript must be an array." };
|
|
44314
|
-
const transcript = [];
|
|
44315
|
-
for (const entry of value.slice(0, 20)) {
|
|
44316
|
-
if (!entry || typeof entry !== "object") return { error: "transcript entries must be objects." };
|
|
44317
|
-
const kind = entry.kind;
|
|
44318
|
-
const content = entry.content;
|
|
44319
|
-
if (kind !== "user" && kind !== "assistant" && kind !== "error" && kind !== "tool") {
|
|
44320
|
-
return { error: "transcript entry kind is invalid." };
|
|
44321
|
-
}
|
|
44322
|
-
if (typeof content !== "string") return { error: "transcript entry content must be a string." };
|
|
44323
|
-
const trimmed = content.trim();
|
|
44324
|
-
if (!trimmed) continue;
|
|
44325
|
-
transcript.push({ kind, content: trimmed });
|
|
44326
|
-
}
|
|
44327
|
-
return transcript;
|
|
44328
|
-
}
|
|
44329
|
-
function normalizeIssueScreenshots(value) {
|
|
44330
|
-
if (value === void 0 || value === null) return [];
|
|
44331
|
-
if (!Array.isArray(value)) return { error: "screenshots must be an array." };
|
|
44332
|
-
const screenshots = [];
|
|
44333
|
-
for (const entry of value.slice(0, 3)) {
|
|
44334
|
-
if (!entry || typeof entry !== "object") return { error: "screenshots entries must be objects." };
|
|
44335
|
-
const filename = entry.filename;
|
|
44336
|
-
const url2 = entry.url;
|
|
44337
|
-
if (typeof filename !== "string" || !filename.trim()) {
|
|
44338
|
-
return { error: "screenshot filename is required." };
|
|
44339
|
-
}
|
|
44340
|
-
if (typeof url2 !== "string" || !/^https?:\/\//.test(url2)) {
|
|
44341
|
-
return { error: "screenshot url must be an absolute http(s) URL." };
|
|
44342
|
-
}
|
|
44343
|
-
screenshots.push({ filename: filename.trim(), url: url2.trim() });
|
|
44344
|
-
}
|
|
44345
|
-
return screenshots;
|
|
44346
|
-
}
|
|
44347
44096
|
function neutralCheckoutCwd(stateDir) {
|
|
44348
|
-
const dir =
|
|
44097
|
+
const dir = import_node_path12.default.join(stateDir, "no-checkout");
|
|
44349
44098
|
try {
|
|
44350
|
-
|
|
44099
|
+
import_node_fs11.default.mkdirSync(dir, { recursive: true });
|
|
44351
44100
|
} catch {
|
|
44352
44101
|
}
|
|
44353
44102
|
return dir;
|
|
@@ -44356,12 +44105,19 @@ function buildThreadStartParams(msg, config2, desiredModel) {
|
|
|
44356
44105
|
const baseInstructions = [
|
|
44357
44106
|
"You are the Mrrlin Director assistant.",
|
|
44358
44107
|
"You can call MCP tools to read and write project state.",
|
|
44359
|
-
"Prefer calling tools over guessing. Be concise.
|
|
44108
|
+
"Prefer calling tools over guessing. Be concise.",
|
|
44109
|
+
"Autonomy level is NOT a reason to skip clarification. `auto` means only that no human gate is",
|
|
44110
|
+
"required before the result LANDS (merge/deploy); it does not authorize building on unvalidated",
|
|
44111
|
+
"assumptions. Judge clarification on requirement clarity, independently of autonomy_level.",
|
|
44360
44112
|
"Never announce or pre-narrate that you are about to use tools, and never name the toolset in",
|
|
44361
44113
|
`prose. Do NOT write openers like "I'll use the Mrrlin tools to\u2026", "\u0412\u0438\u043A\u043E\u0440\u0438\u0441\u0442\u0430\u044E Mrrlin tools\u2026",`,
|
|
44362
44114
|
'or "let me call the \u2026 tool" in ANY language. The operator already sees tool calls in the',
|
|
44363
44115
|
"transcript. Just call the tools and reply with the outcome \u2014 start your reply with the result.",
|
|
44364
44116
|
"When creating or updating tasks, always provide `autonomyLevel` and `autonomyReason`.",
|
|
44117
|
+
"When you create a task out of an operator request, set `operatorSeedRequest` to the operator's",
|
|
44118
|
+
"VERBATIM words (their request as they wrote it \u2014 NOT your paraphrase or synthesized notes). It is",
|
|
44119
|
+
"the spec gate's independent record of intent; omit it only when there is genuinely no operator",
|
|
44120
|
+
"request behind the task (pure system bookkeeping) \u2014 note that omitting it makes the gate fail-closed.",
|
|
44365
44121
|
"",
|
|
44366
44122
|
"Spec authoring contract \u2014 when creating or updating a `Specs/{id}` wiki page:",
|
|
44367
44123
|
"- In `## Specification`, write each requirement as `### Requirement: <name>` followed by one",
|
|
@@ -44372,6 +44128,7 @@ function buildThreadStartParams(msg, config2, desiredModel) {
|
|
|
44372
44128
|
"- Apply this format ONLY to Specs/{id} pages; do not retro-fit it onto other wiki page types.",
|
|
44373
44129
|
"- Spec consensus runs ASYNCHRONOUSLY. Call `run_spec_consensus` for a `Specs/{id}` page; it returns IMMEDIATELY. On `already_converged`, the spec is already marked ready \u2014 proceed straight to `create_execution_run`; do NOT call `mark_spec_ready` and do NOT re-run consensus. On `queued` or `already_running`, tell the user it was launched and END your turn \u2014 do NOT poll or call it again; the result arrives in the inbox (an `info` item on CONVERGED, a `handoff` item if it was blocked/failed). When a consensus `info` item says CONVERGED, proceed to `create_execution_run`. When a `handoff` says it was blocked, address the recorded issues in the spec (any edit re-arms the gate) and call `run_spec_consensus` once more.",
|
|
44374
44130
|
'- When a task needs a browser (login flows, UI verification/clicks, scraping), pass `prerequisites:[{mcp:"mrrlin-browser",reason:"..."}]` to `create_execution_run`. If that run later fails into a handoff, the operator gets a one-click "Launch browser & resume" that brings up the dedicated browser as the turn starts.',
|
|
44131
|
+
"- When you actually drive a browser (calling `browser_navigate`, `browser_click`, `browser_snapshot`, `browser_type`, etc.), invoke those tools from the **`mrrlin-browser`** MCP server ONLY. Do NOT use tools from any other browser MCP (`playwright`, `chrome-devtools`, `puppeteer`, etc.) even if they are also connected on this operator's box \u2014 those use a shared/default Playwright profile that is fragile across runs. Only `mrrlin-browser` uses this project's dedicated Chromium + persistent operator profile (`~/.mrrlin/browser/profile`). If your host exposes multiple browser MCPs with overlapping tool names, prefer the `mrrlin-browser` server unconditionally.",
|
|
44375
44132
|
"",
|
|
44376
44133
|
'Research playbook \u2014 when the user asks about a topic, an area, or "what do we have on X":',
|
|
44377
44134
|
"- Tasks are the source of truth. Start with `list_tasks` using `q=<keyword>`; the filter is a",
|
|
@@ -44433,12 +44190,20 @@ function buildThreadStartParams(msg, config2, desiredModel) {
|
|
|
44433
44190
|
" call `list_inbox_items` (kind=question), fold any relevant `acknowledged` TASKLESS answer",
|
|
44434
44191
|
" into the new task's Specs/{id} Clarifications, and `reject` (with a reason) any taskless",
|
|
44435
44192
|
" question the new task makes moot \u2014 so taskless answers never linger unconsumed.",
|
|
44436
|
-
"-
|
|
44437
|
-
"
|
|
44193
|
+
"- Gate-origin questions (origin='gate', filed by the spec consensus gate) are auto-folded",
|
|
44194
|
+
" into the spec and re-gated by the system when the operator answers them in the inbox.",
|
|
44195
|
+
" Do NOT fold or `decide_inbox_item` them yourself \u2014 your fold-contract above applies only",
|
|
44196
|
+
" to YOUR OWN discretionary questions.",
|
|
44197
|
+
"- When resuming a task, call `list_inbox_items` (kind=question) and fold any `acknowledged`",
|
|
44198
|
+
" answer from YOUR questions (origin is null/absent) not yet reflected into the spec's",
|
|
44199
|
+
" Clarifications section \u2014 THEN re-run `run_spec_consensus` on the updated spec. Skip",
|
|
44200
|
+
" gate-origin items (origin='gate') as those are handled automatically.",
|
|
44438
44201
|
"- If a question becomes moot (task cancelled, superseded, or no longer relevant), close it",
|
|
44439
44202
|
' with `decide_inbox_item` `verdict="rejected"` + a `reason`; never leave it pending.',
|
|
44440
|
-
"-
|
|
44441
|
-
" runs; use the handoff contract above when there is no live operator.",
|
|
44203
|
+
"- YOUR discretionary questions are a chat-only mechanism: do not create question items yourself",
|
|
44204
|
+
" from non-interactive runs; use the handoff contract above when there is no live operator.",
|
|
44205
|
+
" The spec consensus GATE, however, may file its own clarification questions on non-interactive",
|
|
44206
|
+
" runs (that is gate-driven, not your discretion) \u2014 resume them via the rule above when answered.",
|
|
44442
44207
|
"",
|
|
44443
44208
|
"Onboarding contract \u2014 seed project context when there is none:",
|
|
44444
44209
|
`- A project is un-onboarded when it has no \`${PROJECT_CONSTITUTION_PAGE.path}\` wiki page.`,
|
|
@@ -44540,7 +44305,7 @@ function resolveDefaultBranch(checkoutPath) {
|
|
|
44540
44305
|
if (!checkoutPath) return "main";
|
|
44541
44306
|
const runGit = (args) => {
|
|
44542
44307
|
try {
|
|
44543
|
-
return (0,
|
|
44308
|
+
return (0, import_node_child_process4.execFileSync)("git", ["-C", checkoutPath, ...args], {
|
|
44544
44309
|
encoding: "utf8",
|
|
44545
44310
|
stdio: ["ignore", "pipe", "ignore"],
|
|
44546
44311
|
timeout: 15e3,
|
|
@@ -44572,7 +44337,7 @@ async function runOrphanWorktreeSweep(client, opts) {
|
|
|
44572
44337
|
const cutoff = Date.now() - worktreeRetentionMs();
|
|
44573
44338
|
const isReapable = (worktreePath) => {
|
|
44574
44339
|
try {
|
|
44575
|
-
return
|
|
44340
|
+
return import_node_fs11.default.statSync(worktreePath).mtimeMs < cutoff;
|
|
44576
44341
|
} catch {
|
|
44577
44342
|
return false;
|
|
44578
44343
|
}
|
|
@@ -44609,8 +44374,8 @@ async function runOrphanWorktreeSweep(client, opts) {
|
|
|
44609
44374
|
}
|
|
44610
44375
|
}
|
|
44611
44376
|
function readStateDir() {
|
|
44612
|
-
if (process.env.CODEX_HOME) return
|
|
44613
|
-
return
|
|
44377
|
+
if (process.env.CODEX_HOME) return import_node_path12.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge");
|
|
44378
|
+
return import_node_path12.default.join(import_node_os8.default.homedir(), ".mrrlin", "director-bridge");
|
|
44614
44379
|
}
|
|
44615
44380
|
function readAllowedOrigins() {
|
|
44616
44381
|
const raw = (process.env.MRRLIN_DIRECTOR_BRIDGE_ALLOWED_ORIGINS ?? "").trim();
|
|
@@ -44959,54 +44724,6 @@ function createBridgeMessageHandler(deps) {
|
|
|
44959
44724
|
handleResumeRequest(msg, sendForSpan);
|
|
44960
44725
|
return;
|
|
44961
44726
|
}
|
|
44962
|
-
if (msg.type === "report_issue") {
|
|
44963
|
-
if (msg.source !== "director-chat" && msg.source !== "director-panel" && msg.source !== "shell-menu") {
|
|
44964
|
-
sendForSpan({ type: "report-issue-result", status: "error", error: "report source is invalid." });
|
|
44965
|
-
return;
|
|
44966
|
-
}
|
|
44967
|
-
const customerDescription = typeof msg.customerDescription === "string" ? msg.customerDescription.trim() : "";
|
|
44968
|
-
if (!customerDescription) {
|
|
44969
|
-
sendForSpan({ type: "report-issue-result", status: "error", error: "customerDescription is required." });
|
|
44970
|
-
return;
|
|
44971
|
-
}
|
|
44972
|
-
const transcript = normalizeIssueTranscript(msg.transcript);
|
|
44973
|
-
if ("error" in transcript) {
|
|
44974
|
-
sendForSpan({ type: "report-issue-result", status: "error", error: transcript.error });
|
|
44975
|
-
return;
|
|
44976
|
-
}
|
|
44977
|
-
const screenshots = normalizeIssueScreenshots(msg.screenshots);
|
|
44978
|
-
if ("error" in screenshots) {
|
|
44979
|
-
sendForSpan({ type: "report-issue-result", status: "error", error: screenshots.error });
|
|
44980
|
-
return;
|
|
44981
|
-
}
|
|
44982
|
-
try {
|
|
44983
|
-
const result = fileIssueReport({
|
|
44984
|
-
source: msg.source,
|
|
44985
|
-
customerDescription,
|
|
44986
|
-
directorSessionId: typeof msg.directorSessionId === "string" ? msg.directorSessionId.trim() || null : null,
|
|
44987
|
-
projectSlug: typeof msg.projectSlug === "string" ? msg.projectSlug.trim() || null : null,
|
|
44988
|
-
urlPath: typeof msg.urlPath === "string" ? msg.urlPath.trim() || null : null,
|
|
44989
|
-
transcript,
|
|
44990
|
-
screenshots
|
|
44991
|
-
});
|
|
44992
|
-
sendForSpan({
|
|
44993
|
-
type: "report-issue-result",
|
|
44994
|
-
status: "ok",
|
|
44995
|
-
issueNumber: result.issueNumber,
|
|
44996
|
-
title: result.title,
|
|
44997
|
-
url: result.url,
|
|
44998
|
-
telegramDelivered: result.telegramDelivered,
|
|
44999
|
-
telegramWarning: result.telegramWarning
|
|
45000
|
-
});
|
|
45001
|
-
} catch (error51) {
|
|
45002
|
-
sendForSpan({
|
|
45003
|
-
type: "report-issue-result",
|
|
45004
|
-
status: "error",
|
|
45005
|
-
error: error51 instanceof Error ? error51.message : String(error51)
|
|
45006
|
-
});
|
|
45007
|
-
}
|
|
45008
|
-
return;
|
|
45009
|
-
}
|
|
45010
44727
|
if (msg.type === "interrupt") {
|
|
45011
44728
|
const directorSessionId2 = (msg.directorSessionId ?? "").trim();
|
|
45012
44729
|
const existing = directorSessionId2 ? deps.threads.get(directorSessionId2) : void 0;
|
|
@@ -45390,7 +45107,7 @@ function parseConfig() {
|
|
|
45390
45107
|
}
|
|
45391
45108
|
function scanForOtherBridges() {
|
|
45392
45109
|
try {
|
|
45393
|
-
const result = (0,
|
|
45110
|
+
const result = (0, import_node_child_process4.spawnSync)("pgrep", ["-f", "mrrlin-mcp director-bridge"], {
|
|
45394
45111
|
encoding: "utf8"
|
|
45395
45112
|
});
|
|
45396
45113
|
if (result.status !== 0) return [];
|
|
@@ -45522,8 +45239,8 @@ async function startDirectorBridge() {
|
|
|
45522
45239
|
codexCwd: config2.codexCwd,
|
|
45523
45240
|
codexExecutable: config2.codexExecutable,
|
|
45524
45241
|
checkoutRegistry,
|
|
45525
|
-
worktreeRoot:
|
|
45526
|
-
locksDir:
|
|
45242
|
+
worktreeRoot: import_node_path12.default.join(config2.stateDir, "worktrees"),
|
|
45243
|
+
locksDir: import_node_path12.default.join(config2.stateDir, "locks"),
|
|
45527
45244
|
// Wire the profile-enforced executor server for code-execution runs. Each run gets its own
|
|
45528
45245
|
// sandboxed Codex instance (scrubbed env, scratch CODEX_HOME, deny-read, egress allowlist).
|
|
45529
45246
|
// The returned handle's dispose() shuts down the spawned app-server CHILD (manager.shutdown(),
|
|
@@ -45556,13 +45273,13 @@ async function startDirectorBridge() {
|
|
|
45556
45273
|
},
|
|
45557
45274
|
runVerificationTurn: createRunVerificationTurn({
|
|
45558
45275
|
startSandbox: async (egressDomains) => {
|
|
45559
|
-
const cwd =
|
|
45276
|
+
const cwd = import_node_fs11.default.mkdtempSync(import_node_path12.default.join(import_node_os8.default.tmpdir(), "mrrlin-verify-"));
|
|
45560
45277
|
let handle;
|
|
45561
45278
|
try {
|
|
45562
45279
|
handle = await startExecutorServer({ worktree: cwd, egressDomains });
|
|
45563
45280
|
} catch (error51) {
|
|
45564
45281
|
try {
|
|
45565
|
-
|
|
45282
|
+
import_node_fs11.default.rmSync(cwd, { recursive: true, force: true });
|
|
45566
45283
|
} catch {
|
|
45567
45284
|
}
|
|
45568
45285
|
throw error51;
|
|
@@ -45573,7 +45290,7 @@ async function startDirectorBridge() {
|
|
|
45573
45290
|
dispose: () => {
|
|
45574
45291
|
handle.dispose();
|
|
45575
45292
|
try {
|
|
45576
|
-
|
|
45293
|
+
import_node_fs11.default.rmSync(cwd, { recursive: true, force: true });
|
|
45577
45294
|
} catch {
|
|
45578
45295
|
}
|
|
45579
45296
|
}
|
|
@@ -45713,7 +45430,7 @@ async function startDirectorBridge() {
|
|
|
45713
45430
|
const bridgeLogger = createBridgeLogger(config2.stateDir, process.env);
|
|
45714
45431
|
let bridgeBinShaShort = "unknown00000";
|
|
45715
45432
|
try {
|
|
45716
|
-
bridgeBinShaShort = import_node_crypto5.default.createHash("sha256").update(
|
|
45433
|
+
bridgeBinShaShort = import_node_crypto5.default.createHash("sha256").update(import_node_fs11.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
|
|
45717
45434
|
} catch {
|
|
45718
45435
|
}
|
|
45719
45436
|
attachBridgeWss(server, {
|
|
@@ -45822,8 +45539,8 @@ async function startDirectorBridge() {
|
|
|
45822
45539
|
enqueueRun(
|
|
45823
45540
|
() => runOrphanWorktreeSweep(client, {
|
|
45824
45541
|
checkoutRegistry,
|
|
45825
|
-
worktreeRoot:
|
|
45826
|
-
locksDir:
|
|
45542
|
+
worktreeRoot: import_node_path12.default.join(config2.stateDir, "worktrees"),
|
|
45543
|
+
locksDir: import_node_path12.default.join(config2.stateDir, "locks")
|
|
45827
45544
|
})
|
|
45828
45545
|
);
|
|
45829
45546
|
enqueueRun(async () => {
|
|
@@ -46035,15 +45752,15 @@ function readDispatchBody(req) {
|
|
|
46035
45752
|
function readOrCreateBridgeToken(stateDir) {
|
|
46036
45753
|
const explicit = (process.env.MRRLIN_DIRECTOR_BRIDGE_TOKEN ?? "").trim();
|
|
46037
45754
|
if (explicit) return explicit;
|
|
46038
|
-
const tokenPath =
|
|
45755
|
+
const tokenPath = import_node_path12.default.join(stateDir, "token.txt");
|
|
46039
45756
|
try {
|
|
46040
|
-
const existing =
|
|
45757
|
+
const existing = import_node_fs11.default.readFileSync(tokenPath, "utf8").trim();
|
|
46041
45758
|
if (existing) return existing;
|
|
46042
45759
|
} catch {
|
|
46043
45760
|
}
|
|
46044
|
-
|
|
45761
|
+
import_node_fs11.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
|
|
46045
45762
|
const token = import_node_crypto5.default.randomBytes(32).toString("base64url");
|
|
46046
|
-
|
|
45763
|
+
import_node_fs11.default.writeFileSync(tokenPath, `${token}
|
|
46047
45764
|
`, { mode: 384 });
|
|
46048
45765
|
return token;
|
|
46049
45766
|
}
|
|
@@ -49425,18 +49142,19 @@ var StdioServerTransport = class {
|
|
|
49425
49142
|
};
|
|
49426
49143
|
|
|
49427
49144
|
// src/tools.ts
|
|
49145
|
+
var import_node_crypto8 = require("node:crypto");
|
|
49428
49146
|
var import_promises3 = require("node:fs/promises");
|
|
49429
|
-
var
|
|
49430
|
-
var
|
|
49431
|
-
var
|
|
49432
|
-
var
|
|
49147
|
+
var import_node_fs13 = require("node:fs");
|
|
49148
|
+
var import_node_path15 = __toESM(require("node:path"), 1);
|
|
49149
|
+
var import_node_os9 = __toESM(require("node:os"), 1);
|
|
49150
|
+
var import_node_child_process7 = require("node:child_process");
|
|
49433
49151
|
|
|
49434
49152
|
// ../../packages/wiki/dist/index.js
|
|
49435
49153
|
var import_promises2 = __toESM(require("node:fs/promises"), 1);
|
|
49436
|
-
var
|
|
49154
|
+
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
49437
49155
|
var INCLUDED_DOC_FOLDERS = /* @__PURE__ */ new Set(["_meta", "explanation", "how-to", "reference", "sdd", "tutorials"]);
|
|
49438
49156
|
function toPosixPath(input) {
|
|
49439
|
-
return input.split(
|
|
49157
|
+
return input.split(import_node_path13.default.sep).join("/");
|
|
49440
49158
|
}
|
|
49441
49159
|
function slugifyWikiSegment(input) {
|
|
49442
49160
|
return input.trim().toLowerCase().replace(/`/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -49450,12 +49168,12 @@ async function pathExists2(input) {
|
|
|
49450
49168
|
}
|
|
49451
49169
|
}
|
|
49452
49170
|
async function findWorkspaceRoot(start = process.cwd()) {
|
|
49453
|
-
let current =
|
|
49171
|
+
let current = import_node_path13.default.resolve(start);
|
|
49454
49172
|
while (true) {
|
|
49455
|
-
if (await pathExists2(
|
|
49173
|
+
if (await pathExists2(import_node_path13.default.join(current, "pnpm-workspace.yaml")) && await pathExists2(import_node_path13.default.join(current, "docs"))) {
|
|
49456
49174
|
return current;
|
|
49457
49175
|
}
|
|
49458
|
-
const parent =
|
|
49176
|
+
const parent = import_node_path13.default.dirname(current);
|
|
49459
49177
|
if (parent === current) {
|
|
49460
49178
|
throw new Error(`Unable to find Mrrlin workspace root from ${start}`);
|
|
49461
49179
|
}
|
|
@@ -49464,28 +49182,28 @@ async function findWorkspaceRoot(start = process.cwd()) {
|
|
|
49464
49182
|
}
|
|
49465
49183
|
async function resolveDocsRoot(input) {
|
|
49466
49184
|
if (input) {
|
|
49467
|
-
return
|
|
49185
|
+
return import_node_path13.default.resolve(input);
|
|
49468
49186
|
}
|
|
49469
49187
|
if (process.env.MRRLIN_DOCS_ROOT) {
|
|
49470
|
-
return
|
|
49188
|
+
return import_node_path13.default.resolve(process.env.MRRLIN_DOCS_ROOT);
|
|
49471
49189
|
}
|
|
49472
|
-
return
|
|
49190
|
+
return import_node_path13.default.join(await findWorkspaceRoot(), "docs");
|
|
49473
49191
|
}
|
|
49474
49192
|
async function resolveIndexPath(input) {
|
|
49475
49193
|
if (input) {
|
|
49476
|
-
return
|
|
49194
|
+
return import_node_path13.default.resolve(input);
|
|
49477
49195
|
}
|
|
49478
49196
|
if (process.env.MRRLIN_WIKI_INDEX_PATH) {
|
|
49479
|
-
return
|
|
49197
|
+
return import_node_path13.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
|
|
49480
49198
|
}
|
|
49481
49199
|
const workspaceRoot = await findWorkspaceRoot();
|
|
49482
|
-
return
|
|
49200
|
+
return import_node_path13.default.join(workspaceRoot, "apps", "web", "public", "wiki-index.json");
|
|
49483
49201
|
}
|
|
49484
49202
|
async function walkMarkdownFiles(root, dir = root) {
|
|
49485
49203
|
const entries = await import_promises2.default.readdir(dir, { withFileTypes: true });
|
|
49486
49204
|
const files = [];
|
|
49487
49205
|
for (const entry of entries) {
|
|
49488
|
-
const absolute =
|
|
49206
|
+
const absolute = import_node_path13.default.join(dir, entry.name);
|
|
49489
49207
|
if (entry.isDirectory()) {
|
|
49490
49208
|
files.push(...await walkMarkdownFiles(root, absolute));
|
|
49491
49209
|
continue;
|
|
@@ -49504,7 +49222,7 @@ function parseTitle(markdown, sourcePath) {
|
|
|
49504
49222
|
return title;
|
|
49505
49223
|
}
|
|
49506
49224
|
function documentFromFile(docsRoot, absolutePath, markdown) {
|
|
49507
|
-
const relativePath = toPosixPath(
|
|
49225
|
+
const relativePath = toPosixPath(import_node_path13.default.relative(docsRoot, absolutePath));
|
|
49508
49226
|
const [section, fileName] = relativePath.split("/");
|
|
49509
49227
|
if (!section || !fileName || !INCLUDED_DOC_FOLDERS.has(section)) {
|
|
49510
49228
|
return null;
|
|
@@ -49802,6 +49520,19 @@ ${dismissedFwd.slice(-20).join("\n")}` : "";
|
|
|
49802
49520
|
var SPEC_HEADS = ["plan-reviewer", "architect", "security-analyst", "scope-analyst"];
|
|
49803
49521
|
async function runSpecGate(_target, deps, opts) {
|
|
49804
49522
|
if (!await deps.consensusEnabled()) return { outcome: "SKIPPED" };
|
|
49523
|
+
const intent = await deps.readIntent();
|
|
49524
|
+
if (intent.taskId !== null && (intent.seed === null || intent.seed.trim() === "")) {
|
|
49525
|
+
return {
|
|
49526
|
+
outcome: "CONSENSUS_BLOCKED",
|
|
49527
|
+
clarifications: [
|
|
49528
|
+
{
|
|
49529
|
+
question: "What are the requirements for this task? There is no operator request on record, so the spec cannot be validated against your intent \u2014 please state what this task must do.",
|
|
49530
|
+
whyBlocking: "operator_seed_request is empty",
|
|
49531
|
+
category: "scope"
|
|
49532
|
+
}
|
|
49533
|
+
]
|
|
49534
|
+
};
|
|
49535
|
+
}
|
|
49805
49536
|
const extraHeads = opts?.extraHeads ?? [];
|
|
49806
49537
|
const heads = [...SPEC_HEADS, ...extraHeads.filter((h) => !SPEC_HEADS.includes(h))];
|
|
49807
49538
|
const spec = await deps.readSpec();
|
|
@@ -49843,6 +49574,15 @@ async function runSpecGate(_target, deps, opts) {
|
|
|
49843
49574
|
await deps.promoteSpecReady(currentHash);
|
|
49844
49575
|
return { outcome: "CONVERGED" };
|
|
49845
49576
|
}
|
|
49577
|
+
if (result.outcome === "CONSENSUS_BLOCKED") {
|
|
49578
|
+
const accepted = result.history.at(-1)?.accepted ?? [];
|
|
49579
|
+
const clarifications = accepted.filter((issue2) => issue2.category === "ambiguity" || issue2.category === "scope").map((issue2) => ({
|
|
49580
|
+
question: issue2.text,
|
|
49581
|
+
whyBlocking: `reviewer raised a ${issue2.category} issue`,
|
|
49582
|
+
category: issue2.category
|
|
49583
|
+
}));
|
|
49584
|
+
return clarifications.length > 0 ? { outcome: "CONSENSUS_BLOCKED", clarifications } : { outcome: "CONSENSUS_BLOCKED" };
|
|
49585
|
+
}
|
|
49846
49586
|
return { outcome: result.outcome };
|
|
49847
49587
|
}
|
|
49848
49588
|
|
|
@@ -49919,7 +49659,7 @@ async function runCodeGate(_target, deps) {
|
|
|
49919
49659
|
}
|
|
49920
49660
|
|
|
49921
49661
|
// src/consensus/codex-exec.ts
|
|
49922
|
-
var
|
|
49662
|
+
var import_node_child_process5 = require("node:child_process");
|
|
49923
49663
|
function extractFinalMessage(stdout) {
|
|
49924
49664
|
let last = null;
|
|
49925
49665
|
for (const rawLine of stdout.split(/\r?\n/)) {
|
|
@@ -49964,7 +49704,7 @@ function firstString(...values) {
|
|
|
49964
49704
|
return null;
|
|
49965
49705
|
}
|
|
49966
49706
|
function runCodexExec(input, deps) {
|
|
49967
|
-
const spawn2 = deps?.spawn ??
|
|
49707
|
+
const spawn2 = deps?.spawn ?? import_node_child_process5.spawn;
|
|
49968
49708
|
const executable = input.codexExecutable ?? "codex";
|
|
49969
49709
|
const sandbox = input.sandbox ?? "read-only";
|
|
49970
49710
|
const fullPrompt = input.developerInstructions.trim() ? `${input.developerInstructions.trim()}
|
|
@@ -50036,12 +49776,12 @@ function errMessage(err) {
|
|
|
50036
49776
|
}
|
|
50037
49777
|
|
|
50038
49778
|
// src/consensus/wiring.ts
|
|
50039
|
-
var
|
|
50040
|
-
var
|
|
49779
|
+
var import_node_fs12 = __toESM(require("node:fs"), 1);
|
|
49780
|
+
var import_node_path14 = __toESM(require("node:path"), 1);
|
|
50041
49781
|
var import_node_url2 = require("node:url");
|
|
50042
49782
|
|
|
50043
49783
|
// src/consensus/code-gate-git.ts
|
|
50044
|
-
var
|
|
49784
|
+
var import_node_child_process6 = require("node:child_process");
|
|
50045
49785
|
var DIFF_MAX_BYTES = 2e5;
|
|
50046
49786
|
var FASTGATE_OUTPUT_MAX_BYTES = 16e3;
|
|
50047
49787
|
var GIT_TIMEOUT_MS = 6e4;
|
|
@@ -50057,7 +49797,7 @@ var defaultRunCmd = (cmd, args, opts) => new Promise((resolve) => {
|
|
|
50057
49797
|
};
|
|
50058
49798
|
let child;
|
|
50059
49799
|
try {
|
|
50060
|
-
child = (0,
|
|
49800
|
+
child = (0, import_node_child_process6.spawn)(cmd, args, {
|
|
50061
49801
|
cwd: opts.cwd,
|
|
50062
49802
|
env: process.env,
|
|
50063
49803
|
shell: false,
|
|
@@ -50272,15 +50012,15 @@ ${res.stdout}${res.stderr}`);
|
|
|
50272
50012
|
var import_meta2 = {};
|
|
50273
50013
|
function getPersonasDir() {
|
|
50274
50014
|
if (typeof __dirname !== "undefined") {
|
|
50275
|
-
return
|
|
50015
|
+
return import_node_path14.default.join(__dirname, "consensus", "personas");
|
|
50276
50016
|
}
|
|
50277
|
-
return
|
|
50017
|
+
return import_node_path14.default.join(import_node_path14.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "personas");
|
|
50278
50018
|
}
|
|
50279
50019
|
var personaCache = /* @__PURE__ */ new Map();
|
|
50280
50020
|
function loadPersona(name) {
|
|
50281
50021
|
const cached2 = personaCache.get(name);
|
|
50282
50022
|
if (cached2 !== void 0) return cached2;
|
|
50283
|
-
const content =
|
|
50023
|
+
const content = import_node_fs12.default.readFileSync(import_node_path14.default.join(getPersonasDir(), `${name}.md`), "utf8");
|
|
50284
50024
|
personaCache.set(name, content);
|
|
50285
50025
|
return content;
|
|
50286
50026
|
}
|
|
@@ -50289,6 +50029,19 @@ function buildSpecGateDeps(args) {
|
|
|
50289
50029
|
const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 3);
|
|
50290
50030
|
const maxHeadCalls = rounds * (4 + extraHeadCount + 1);
|
|
50291
50031
|
const timeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
|
|
50032
|
+
let intentPromise = null;
|
|
50033
|
+
function loadIntent() {
|
|
50034
|
+
if (!intentPromise) {
|
|
50035
|
+
intentPromise = (async () => {
|
|
50036
|
+
const page = await client.getWikiPage(projectSlug, specPageId);
|
|
50037
|
+
const taskId = page?.taskId ?? null;
|
|
50038
|
+
if (taskId === null) return { taskId: null, seed: null };
|
|
50039
|
+
const task = await client.getTask(projectSlug, taskId);
|
|
50040
|
+
return { taskId, seed: task?.operatorSeedRequest ?? null };
|
|
50041
|
+
})();
|
|
50042
|
+
}
|
|
50043
|
+
return intentPromise;
|
|
50044
|
+
}
|
|
50292
50045
|
return {
|
|
50293
50046
|
rounds,
|
|
50294
50047
|
maxHeadCalls,
|
|
@@ -50304,15 +50057,23 @@ function buildSpecGateDeps(args) {
|
|
|
50304
50057
|
contentHash: page.contentHash
|
|
50305
50058
|
};
|
|
50306
50059
|
},
|
|
50060
|
+
readIntent() {
|
|
50061
|
+
return loadIntent();
|
|
50062
|
+
},
|
|
50307
50063
|
async runHead(personaName, artifact, dismissed) {
|
|
50308
50064
|
const persona = loadPersona(personaName);
|
|
50065
|
+
const { seed } = await loadIntent();
|
|
50066
|
+
const intentBlock = seed ? `--- OPERATOR INTENT (the operator's own words \u2014 judge the spec against THIS) ---
|
|
50067
|
+
${seed}
|
|
50068
|
+
|
|
50069
|
+
` : "";
|
|
50309
50070
|
return runCodexExec(
|
|
50310
50071
|
{
|
|
50311
|
-
prompt: `Review this spec.
|
|
50072
|
+
prompt: `Review this spec against the operator's intent.
|
|
50312
50073
|
|
|
50313
50074
|
${dismissed}
|
|
50314
50075
|
|
|
50315
|
-
--- SPEC ---
|
|
50076
|
+
${intentBlock}--- SPEC ---
|
|
50316
50077
|
${artifact}`,
|
|
50317
50078
|
developerInstructions: persona,
|
|
50318
50079
|
cwd,
|
|
@@ -50488,6 +50249,7 @@ ${artifact}`,
|
|
|
50488
50249
|
}
|
|
50489
50250
|
|
|
50490
50251
|
// src/async-tools/consensus.ts
|
|
50252
|
+
var import_node_crypto6 = require("node:crypto");
|
|
50491
50253
|
async function cachedResult(client, input) {
|
|
50492
50254
|
const page = await client.getWikiPage(input.projectSlug, input.pageId);
|
|
50493
50255
|
if (!page) return null;
|
|
@@ -50514,16 +50276,58 @@ async function run(ctx, input) {
|
|
|
50514
50276
|
deps,
|
|
50515
50277
|
input.extraHeads && input.extraHeads.length > 0 ? { extraHeads: input.extraHeads } : void 0
|
|
50516
50278
|
);
|
|
50279
|
+
if (result.outcome === "CONSENSUS_BLOCKED") {
|
|
50280
|
+
const clarifications = result.clarifications ?? [];
|
|
50281
|
+
if (clarifications.length > 0) {
|
|
50282
|
+
const page = await ctx.client.getWikiPage(input.projectSlug, input.pageId);
|
|
50283
|
+
const taskId = page?.taskId ?? null;
|
|
50284
|
+
let planId = null;
|
|
50285
|
+
if (!taskId) {
|
|
50286
|
+
const plans = await ctx.client.listPlans(input.projectSlug);
|
|
50287
|
+
planId = plans.find((p) => p.specWikiPageId === input.pageId)?.id ?? null;
|
|
50288
|
+
}
|
|
50289
|
+
if (taskId) {
|
|
50290
|
+
for (const clarification of clarifications) {
|
|
50291
|
+
const scopeId = taskId;
|
|
50292
|
+
const id = `II-${scopeId}-gate-${(0, import_node_crypto6.createHash)("sha256").update(clarification.question).digest("hex").slice(0, 10)}`;
|
|
50293
|
+
try {
|
|
50294
|
+
await ctx.client.createInboxItem(input.projectSlug, {
|
|
50295
|
+
id,
|
|
50296
|
+
kind: "question",
|
|
50297
|
+
taskId: scopeId,
|
|
50298
|
+
body: clarification.question,
|
|
50299
|
+
origin: "gate"
|
|
50300
|
+
});
|
|
50301
|
+
} catch {
|
|
50302
|
+
}
|
|
50303
|
+
}
|
|
50304
|
+
} else if (planId) {
|
|
50305
|
+
for (const clarification of clarifications) {
|
|
50306
|
+
const scopeId = planId;
|
|
50307
|
+
const id = `II-${scopeId}-gate-${(0, import_node_crypto6.createHash)("sha256").update(clarification.question).digest("hex").slice(0, 10)}`;
|
|
50308
|
+
try {
|
|
50309
|
+
await ctx.client.createInboxItem(input.projectSlug, {
|
|
50310
|
+
id,
|
|
50311
|
+
kind: "question",
|
|
50312
|
+
planId: scopeId,
|
|
50313
|
+
body: clarification.question,
|
|
50314
|
+
origin: "gate"
|
|
50315
|
+
});
|
|
50316
|
+
} catch {
|
|
50317
|
+
}
|
|
50318
|
+
}
|
|
50319
|
+
}
|
|
50320
|
+
}
|
|
50321
|
+
return {
|
|
50322
|
+
kind: "failed",
|
|
50323
|
+
failureReason: "consensus_blocked",
|
|
50324
|
+
error: clarifications.length > 0 ? `Consensus blocked on ${clarifications.length} clarification(s); filed as operator question(s).` : "Consensus blocked: reviewers did not converge within budget."
|
|
50325
|
+
};
|
|
50326
|
+
}
|
|
50517
50327
|
switch (result.outcome) {
|
|
50518
50328
|
case "CONVERGED":
|
|
50519
50329
|
case "SKIPPED":
|
|
50520
50330
|
return { kind: "done", resultJson: JSON.stringify(result), finalReviewedHash: null };
|
|
50521
|
-
case "CONSENSUS_BLOCKED":
|
|
50522
|
-
return {
|
|
50523
|
-
kind: "failed",
|
|
50524
|
-
failureReason: "consensus_blocked",
|
|
50525
|
-
error: "Consensus blocked: reviewers did not converge within budget."
|
|
50526
|
-
};
|
|
50527
50331
|
case "CONSENSUS_UNAVAILABLE":
|
|
50528
50332
|
return { kind: "retry", failureReason: "provider_unavailable", error: "Consensus unavailable (provider/quota)." };
|
|
50529
50333
|
case "SPEC_CHANGED_DURING_REVIEW":
|
|
@@ -50538,6 +50342,17 @@ async function run(ctx, input) {
|
|
|
50538
50342
|
}
|
|
50539
50343
|
function onComplete(outcome, input) {
|
|
50540
50344
|
if (outcome.kind === "done") {
|
|
50345
|
+
let specOutcome = "CONVERGED";
|
|
50346
|
+
try {
|
|
50347
|
+
specOutcome = JSON.parse(outcome.resultJson).outcome ?? "CONVERGED";
|
|
50348
|
+
} catch {
|
|
50349
|
+
}
|
|
50350
|
+
if (specOutcome === "SKIPPED") {
|
|
50351
|
+
return {
|
|
50352
|
+
kind: "info",
|
|
50353
|
+
body: `Consensus is disabled for this project; Specs/${input.pageId} was not gated and spec_ready is unchanged.`
|
|
50354
|
+
};
|
|
50355
|
+
}
|
|
50541
50356
|
return {
|
|
50542
50357
|
kind: "info",
|
|
50543
50358
|
body: `Consensus CONVERGED for Specs/${input.pageId}; spec_ready set. Ready to create an execution run.`
|
|
@@ -50558,7 +50373,7 @@ var consensusDescriptor = {
|
|
|
50558
50373
|
};
|
|
50559
50374
|
|
|
50560
50375
|
// src/async-tools/enqueue.ts
|
|
50561
|
-
var
|
|
50376
|
+
var import_node_crypto7 = __toESM(require("node:crypto"), 1);
|
|
50562
50377
|
async function enqueueAsyncTool(client, descriptor2, input) {
|
|
50563
50378
|
if (descriptor2.cachedResult) {
|
|
50564
50379
|
const cached2 = await descriptor2.cachedResult(client, input);
|
|
@@ -50571,7 +50386,7 @@ async function enqueueAsyncTool(client, descriptor2, input) {
|
|
|
50571
50386
|
if (active) {
|
|
50572
50387
|
return { status: "already_running", jobId: active.id, message: "Already running; will notify in inbox." };
|
|
50573
50388
|
}
|
|
50574
|
-
const jobId = `AJ-${
|
|
50389
|
+
const jobId = `AJ-${import_node_crypto7.default.randomUUID()}`;
|
|
50575
50390
|
try {
|
|
50576
50391
|
await client.createAsyncJob(input.projectSlug, {
|
|
50577
50392
|
id: jobId,
|
|
@@ -50669,6 +50484,7 @@ var mcpToolNames = {
|
|
|
50669
50484
|
uploadArtifact: "upload_artifact",
|
|
50670
50485
|
listArtifactFiles: "list_artifact_files",
|
|
50671
50486
|
resolveHandoff: "resolve_handoff",
|
|
50487
|
+
recordProducedUrl: "record_produced_url",
|
|
50672
50488
|
registerLocalCheckout: "register_local_checkout",
|
|
50673
50489
|
/** Compact-context retrieval: rehydrate a mrrlin:// handle into the canonical full record. */
|
|
50674
50490
|
retrieveContext: "retrieve_context"
|
|
@@ -51230,6 +51046,7 @@ var getExecutionRunInputSchema = runScopedSchema;
|
|
|
51230
51046
|
var updateExecutionRunInputSchema = runScopedSchema.merge(mrrlinExecutionRunUpdateSchema);
|
|
51231
51047
|
var listExecutionArtifactsInputSchema = runScopedSchema;
|
|
51232
51048
|
var appendExecutionArtifactInputSchema = runScopedSchema.merge(mrrlinExecutionArtifactCreateSchema);
|
|
51049
|
+
var recordProducedUrlInputSchema = runScopedSchema.merge(mrrlinProducedUrlPayloadSchema);
|
|
51233
51050
|
var getProjectSchedulerPolicyInputSchema = projectScopedSchema;
|
|
51234
51051
|
var upsertProjectSchedulerPolicyInputSchema = projectScopedSchema.merge(mrrlinProjectSchedulerPolicyUpsertSchema);
|
|
51235
51052
|
var getSchedulerPendingTasksInputSchema = projectScopedSchema;
|
|
@@ -51327,6 +51144,7 @@ var mcpToolInputSchemas = {
|
|
|
51327
51144
|
[mcpToolNames.uploadArtifact]: uploadArtifactInputSchema,
|
|
51328
51145
|
[mcpToolNames.listArtifactFiles]: listArtifactFilesInputSchema,
|
|
51329
51146
|
[mcpToolNames.resolveHandoff]: resolveHandoffInputSchema,
|
|
51147
|
+
[mcpToolNames.recordProducedUrl]: recordProducedUrlInputSchema,
|
|
51330
51148
|
[mcpToolNames.registerLocalCheckout]: registerLocalCheckoutInputSchema,
|
|
51331
51149
|
[mcpToolNames.retrieveContext]: retrieveContextInputSchema
|
|
51332
51150
|
};
|
|
@@ -51430,7 +51248,8 @@ var mcpToolDescriptions = {
|
|
|
51430
51248
|
[mcpToolNames.runSpecConsensus]: 'Enqueue the consensus review gate over a Specs/{id} page. Returns IMMEDIATELY with one of: already_converged (a CONVERGED review already exists for the current content \u2014 proceed straight to create_execution_run, do NOT call mark_spec_ready, it is already set), already_reviewed (a terminal CONSENSUS_BLOCKED for this content), already_running (a consensus job is in flight), or queued (a new job was launched). The review runs in the background; its result/blocker arrives in the inbox (info on CONVERGED, handoff on failure) and is surfaced into the open chat. Do NOT call again for the same spec and do NOT poll. On queued/already_running, tell the user it was launched and end the turn. Pass extraHeads: ["researcher"] for specs referencing external libraries/APIs, or ["debugger"] for root-cause/investigation specs to add opt-in specialist reviewers on top of the fixed four.',
|
|
51431
51249
|
[mcpToolNames.runCodeReviewerGate]: `Review the current branch's code diff (vs baseRef) with a Code Reviewer gate \u2014 independent reviewers iterate review\u2192fix\u2192re-check (checkpoint, scope-limited reviser edits, typecheck/build fast-gate, rollback) until the diff converges or is blocked. Run before opening a PR. Pass extraHeads: ["security-analyst"] for sensitive diffs (auth, secrets, input handling, new endpoints).`,
|
|
51432
51250
|
[mcpToolNames.appendExecutionArtifact]: "Append a durable artifact (plan, checkpoint, command output, test result, diff summary, self-review, error, deploy attempt, or handoff judgement) to an execution run.",
|
|
51433
|
-
[mcpToolNames.
|
|
51251
|
+
[mcpToolNames.recordProducedUrl]: 'Call this after publishing each web page produced by the task, so the UI link opens the page itself instead of the deployed site root. Pass the page\'s full https URL (for external pages, e.g. "https://dev.to/<slug>") OR a path starting with "/" for the deploy environment (e.g. "/blog/<slug>") \u2014 paths are resolved against the run\'s deployed env URL at render time. Optional `label` (\u226440 chars) is shown next to the link; omit and the UI defaults to the page title. Call once per page; multiple calls dedupe by resolved URL in the UI.',
|
|
51252
|
+
[mcpToolNames.createExecutionRun]: 'Create a durable Director execution run for a task. Persists status, branch/SHA, workflow ids, and checkpoint cursor outside the chat transcript. For tasks that require a browser (login flows, UI verification, scraping), set prerequisites:[{mcp:"mrrlin-browser",reason:"<why a browser is needed>"}] so any resulting handoff offers a one-click "Launch browser & resume". When actually driving the browser inside the run, invoke tools from the `mrrlin-browser` MCP server ONLY (browser_navigate/browser_click/browser_snapshot/browser_type/etc.) \u2014 never from `playwright`, `chrome-devtools`, `puppeteer`, or any other browser MCP that may also be connected on the operator\'s box. Only `mrrlin-browser` uses the dedicated Chromium + persistent operator profile.',
|
|
51434
51253
|
[mcpToolNames.getExecutionRun]: "Fetch a single execution run by id.",
|
|
51435
51254
|
[mcpToolNames.listExecutionArtifacts]: "List artifacts captured during an execution run, in chronological order.",
|
|
51436
51255
|
[mcpToolNames.listExecutionRuns]: "List execution runs for a project. Optional filters: taskId, status.",
|
|
@@ -51874,7 +51693,10 @@ function createMrrlinTools(options) {
|
|
|
51874
51693
|
if (ready !== true) return await c.markSpecReady({ projectSlug, pageId, ready });
|
|
51875
51694
|
const settings = await c.getOperatorSettings();
|
|
51876
51695
|
if (!settings.consensusEnabled) {
|
|
51877
|
-
|
|
51696
|
+
throw new McpToolCodedError(
|
|
51697
|
+
"SPEC_CONSENSUS_REQUIRED",
|
|
51698
|
+
`Spec ${pageId} cannot be marked ready by the Director while consensus is disabled for this project \u2014 an operator must approve it (web wiki / markSpecReady route). Autonomy is a landing gate, not a license to self-promote.`
|
|
51699
|
+
);
|
|
51878
51700
|
}
|
|
51879
51701
|
const page = await c.getWikiPage(projectSlug, pageId);
|
|
51880
51702
|
if (!page || page.folder !== "Specs") {
|
|
@@ -51985,6 +51807,21 @@ function createMrrlinTools(options) {
|
|
|
51985
51807
|
"Unable to append execution artifact.",
|
|
51986
51808
|
async (c, { projectSlug, runId, ...input }) => await c.appendExecutionArtifact(projectSlug, runId, input)
|
|
51987
51809
|
),
|
|
51810
|
+
[mcpToolNames.recordProducedUrl]: makeTool(
|
|
51811
|
+
client,
|
|
51812
|
+
mcpToolNames.recordProducedUrl,
|
|
51813
|
+
"PRODUCED_URL_RECORD_FAILED",
|
|
51814
|
+
"Unable to record produced URL.",
|
|
51815
|
+
async (c, { projectSlug, runId, url: url2, label }) => {
|
|
51816
|
+
const id = `EA-pu-${(0, import_node_crypto8.randomBytes)(4).toString("hex")}`;
|
|
51817
|
+
const payload = label ? { url: url2, label } : { url: url2 };
|
|
51818
|
+
return await c.appendExecutionArtifact(projectSlug, runId, {
|
|
51819
|
+
id,
|
|
51820
|
+
kind: "produced_url",
|
|
51821
|
+
payload
|
|
51822
|
+
});
|
|
51823
|
+
}
|
|
51824
|
+
),
|
|
51988
51825
|
[mcpToolNames.getProjectSchedulerPolicy]: makeTool(
|
|
51989
51826
|
client,
|
|
51990
51827
|
mcpToolNames.getProjectSchedulerPolicy,
|
|
@@ -52043,7 +51880,7 @@ function createMrrlinTools(options) {
|
|
|
52043
51880
|
"ARTIFACT_FILE_UPLOAD_FAILED",
|
|
52044
51881
|
"Unable to upload artifact file.",
|
|
52045
51882
|
async (c, { projectSlug, path: filePath, class: artifactClass, taskId, runId, description }) => {
|
|
52046
|
-
const extension2 =
|
|
51883
|
+
const extension2 = import_node_path15.default.extname(filePath).toLowerCase();
|
|
52047
51884
|
const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
|
|
52048
51885
|
if (!contentType) {
|
|
52049
51886
|
throw new McpToolCodedError(
|
|
@@ -52071,7 +51908,7 @@ function createMrrlinTools(options) {
|
|
|
52071
51908
|
"Artifact exceeds 5MB; split or summarize instead."
|
|
52072
51909
|
);
|
|
52073
51910
|
}
|
|
52074
|
-
const filename =
|
|
51911
|
+
const filename = import_node_path15.default.basename(filePath);
|
|
52075
51912
|
const created = await c.createArtifactFile(projectSlug, {
|
|
52076
51913
|
class: artifactClass,
|
|
52077
51914
|
contentType,
|
|
@@ -52154,7 +51991,7 @@ function createMrrlinTools(options) {
|
|
|
52154
51991
|
"Unable to register local checkout.",
|
|
52155
51992
|
async (_c, { projectSlug, path: checkoutPath, repo }) => {
|
|
52156
51993
|
const trimmedPath = checkoutPath.trim();
|
|
52157
|
-
if (!
|
|
51994
|
+
if (!import_node_path15.default.isAbsolute(trimmedPath)) {
|
|
52158
51995
|
throw new McpToolCodedError(
|
|
52159
51996
|
"LOCAL_CHECKOUT_PATH_NOT_ABSOLUTE",
|
|
52160
51997
|
`Path must be absolute, got: ${trimmedPath}`
|
|
@@ -52162,7 +51999,7 @@ function createMrrlinTools(options) {
|
|
|
52162
51999
|
}
|
|
52163
52000
|
let resolvedPath;
|
|
52164
52001
|
try {
|
|
52165
|
-
resolvedPath = (0,
|
|
52002
|
+
resolvedPath = (0, import_node_fs13.realpathSync)(trimmedPath);
|
|
52166
52003
|
} catch {
|
|
52167
52004
|
throw new McpToolCodedError(
|
|
52168
52005
|
"LOCAL_CHECKOUT_PATH_NOT_FOUND",
|
|
@@ -52171,7 +52008,7 @@ function createMrrlinTools(options) {
|
|
|
52171
52008
|
}
|
|
52172
52009
|
let remoteUrl;
|
|
52173
52010
|
try {
|
|
52174
|
-
remoteUrl = (0,
|
|
52011
|
+
remoteUrl = (0, import_node_child_process7.execFileSync)("git", ["-C", resolvedPath, "remote", "get-url", "origin"], {
|
|
52175
52012
|
encoding: "utf8",
|
|
52176
52013
|
stdio: ["ignore", "pipe", "ignore"],
|
|
52177
52014
|
timeout: 15e3,
|
|
@@ -52189,7 +52026,7 @@ function createMrrlinTools(options) {
|
|
|
52189
52026
|
`Origin remote ${remoteUrl} does not match repo ${repo}.`
|
|
52190
52027
|
);
|
|
52191
52028
|
}
|
|
52192
|
-
const stateDir = process.env.CODEX_HOME ?
|
|
52029
|
+
const stateDir = process.env.CODEX_HOME ? import_node_path15.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge") : import_node_path15.default.join(import_node_os9.default.homedir(), ".mrrlin", "director-bridge");
|
|
52193
52030
|
const registry3 = new CheckoutRegistry(stateDir);
|
|
52194
52031
|
const confirmedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
52195
52032
|
registry3.confirm(projectSlug, resolvedPath, confirmedAt);
|
|
@@ -52396,13 +52233,13 @@ function runSetCredential(args) {
|
|
|
52396
52233
|
}
|
|
52397
52234
|
|
|
52398
52235
|
// src/install-service.ts
|
|
52399
|
-
var
|
|
52400
|
-
var
|
|
52236
|
+
var import_node_os10 = __toESM(require("node:os"), 1);
|
|
52237
|
+
var import_node_path17 = __toESM(require("node:path"), 1);
|
|
52401
52238
|
|
|
52402
52239
|
// src/service-paths.ts
|
|
52403
|
-
var
|
|
52240
|
+
var import_node_path16 = __toESM(require("node:path"), 1);
|
|
52404
52241
|
function isWorktreePath(p) {
|
|
52405
|
-
const norm =
|
|
52242
|
+
const norm = import_node_path16.default.normalize(p).split(import_node_path16.default.sep).join("/");
|
|
52406
52243
|
return norm.includes("/.claude/worktrees/");
|
|
52407
52244
|
}
|
|
52408
52245
|
function resolveServiceCwd(opts) {
|
|
@@ -52456,7 +52293,7 @@ function installService(deps) {
|
|
|
52456
52293
|
deps.log(resolved.reason);
|
|
52457
52294
|
return { ok: false };
|
|
52458
52295
|
}
|
|
52459
|
-
const home = deps.env.HOME ??
|
|
52296
|
+
const home = deps.env.HOME ?? import_node_os10.default.homedir();
|
|
52460
52297
|
const bins = ["node", "codex", "mrrlin-mcp"].map((b) => deps.which(b));
|
|
52461
52298
|
if (bins.some((b) => !b)) {
|
|
52462
52299
|
deps.log("Could not resolve absolute paths for node/codex/mrrlin-mcp on PATH. Install them or fix PATH.");
|
|
@@ -52467,7 +52304,7 @@ function installService(deps) {
|
|
|
52467
52304
|
return { ok: false };
|
|
52468
52305
|
}
|
|
52469
52306
|
const resolvedBins = bins.filter((b) => b !== null);
|
|
52470
|
-
const pathEnv = Array.from(new Set(resolvedBins.map((b) =>
|
|
52307
|
+
const pathEnv = Array.from(new Set(resolvedBins.map((b) => import_node_path17.default.dirname(b)))).join(":");
|
|
52471
52308
|
const text = renderEcosystemConfig({
|
|
52472
52309
|
cwd: resolved.cwd,
|
|
52473
52310
|
home,
|
|
@@ -52476,7 +52313,7 @@ function installService(deps) {
|
|
|
52476
52313
|
staging: deps.env.MRRLIN_STAGING === "1",
|
|
52477
52314
|
apiBaseUrl: deps.env.MRRLIN_API_BASE_URL?.trim() || void 0
|
|
52478
52315
|
});
|
|
52479
|
-
const ecoPath =
|
|
52316
|
+
const ecoPath = import_node_path17.default.join(home, ".mrrlin", "ecosystem.config.cjs");
|
|
52480
52317
|
deps.writeFile(ecoPath, text);
|
|
52481
52318
|
const start = deps.runPm2(["startOrReload", ecoPath]);
|
|
52482
52319
|
if (start.code !== 0) {
|
|
@@ -52507,13 +52344,13 @@ function uninstallService(deps) {
|
|
|
52507
52344
|
|
|
52508
52345
|
// src/uninstall-codex.ts
|
|
52509
52346
|
var import_promises4 = __toESM(require("node:fs/promises"), 1);
|
|
52510
|
-
var
|
|
52511
|
-
var
|
|
52347
|
+
var import_node_os11 = __toESM(require("node:os"), 1);
|
|
52348
|
+
var import_node_path18 = __toESM(require("node:path"), 1);
|
|
52512
52349
|
var toml2 = __toESM(require_toml(), 1);
|
|
52513
52350
|
function resolveCodexHome2(options) {
|
|
52514
52351
|
if (options.codexHome) return options.codexHome;
|
|
52515
52352
|
if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
|
|
52516
|
-
return
|
|
52353
|
+
return import_node_path18.default.join(options.homeDir ?? import_node_os11.default.homedir(), ".codex");
|
|
52517
52354
|
}
|
|
52518
52355
|
async function pathExists3(target) {
|
|
52519
52356
|
try {
|
|
@@ -52526,7 +52363,7 @@ async function pathExists3(target) {
|
|
|
52526
52363
|
var MRRLIN_BLOCK_RE = /(^|\n)\[mcp_servers\.mrrlin(?:-browser)?(?:\]|\.[^\]\n]*\])[\s\S]*?(?=\n\[|$)/g;
|
|
52527
52364
|
async function uninstallCodex(options = {}) {
|
|
52528
52365
|
const codexHome = resolveCodexHome2(options);
|
|
52529
|
-
const configPath =
|
|
52366
|
+
const configPath = import_node_path18.default.join(codexHome, "config.toml");
|
|
52530
52367
|
const removePrompts = async () => uninstallPrompts(codexHome, options.promptNames ?? []);
|
|
52531
52368
|
if (!await pathExists3(configPath)) {
|
|
52532
52369
|
return { action: "missing", configPath, prompts: await removePrompts() };
|
|
@@ -52554,10 +52391,10 @@ async function uninstallCodex(options = {}) {
|
|
|
52554
52391
|
}
|
|
52555
52392
|
async function uninstallPrompts(codexHome, names) {
|
|
52556
52393
|
if (names.length === 0) return [];
|
|
52557
|
-
const promptsDir2 =
|
|
52394
|
+
const promptsDir2 = import_node_path18.default.join(codexHome, "prompts");
|
|
52558
52395
|
const out = [];
|
|
52559
52396
|
for (const name of names) {
|
|
52560
|
-
const promptPath =
|
|
52397
|
+
const promptPath = import_node_path18.default.join(promptsDir2, `${name}.md`);
|
|
52561
52398
|
try {
|
|
52562
52399
|
await import_promises4.default.unlink(promptPath);
|
|
52563
52400
|
out.push({ name, action: "removed", promptPath });
|
|
@@ -52574,27 +52411,27 @@ async function uninstallPrompts(codexHome, names) {
|
|
|
52574
52411
|
}
|
|
52575
52412
|
|
|
52576
52413
|
// src/report-issue-prompt.ts
|
|
52577
|
-
var
|
|
52578
|
-
var
|
|
52414
|
+
var import_node_fs14 = __toESM(require("node:fs"), 1);
|
|
52415
|
+
var import_node_path19 = __toESM(require("node:path"), 1);
|
|
52579
52416
|
var import_node_url3 = require("node:url");
|
|
52580
52417
|
var import_meta3 = {};
|
|
52581
52418
|
function promptsDir() {
|
|
52582
|
-
if (typeof __dirname !== "undefined") return
|
|
52583
|
-
return
|
|
52419
|
+
if (typeof __dirname !== "undefined") return import_node_path19.default.join(__dirname, "prompts");
|
|
52420
|
+
return import_node_path19.default.join(import_node_path19.default.dirname((0, import_node_url3.fileURLToPath)(import_meta3.url)), "prompts");
|
|
52584
52421
|
}
|
|
52585
52422
|
function readReportIssuePrompt() {
|
|
52586
|
-
return
|
|
52423
|
+
return import_node_fs14.default.readFileSync(import_node_path19.default.join(promptsDir(), "report-issue.md"), "utf8");
|
|
52587
52424
|
}
|
|
52588
52425
|
|
|
52589
52426
|
// src/bin.ts
|
|
52590
52427
|
function pm2Runner(args) {
|
|
52591
|
-
const r = (0,
|
|
52428
|
+
const r = (0, import_node_child_process8.spawnSync)("pm2", args, { encoding: "utf8" });
|
|
52592
52429
|
process.stderr.write(r.stdout ?? "");
|
|
52593
52430
|
process.stderr.write(r.stderr ?? "");
|
|
52594
52431
|
return { code: r.status ?? 1, stdout: r.stdout ?? "" };
|
|
52595
52432
|
}
|
|
52596
52433
|
function whichBin(bin) {
|
|
52597
|
-
const r = (0,
|
|
52434
|
+
const r = (0, import_node_child_process8.spawnSync)("which", [bin], { encoding: "utf8" });
|
|
52598
52435
|
const out = (r.stdout ?? "").trim();
|
|
52599
52436
|
return r.status === 0 && out ? out.split("\n")[0] ?? null : null;
|
|
52600
52437
|
}
|
|
@@ -52760,7 +52597,7 @@ async function main() {
|
|
|
52760
52597
|
}
|
|
52761
52598
|
case "browser-serve": {
|
|
52762
52599
|
const { command: command2, args, env } = browserServeArgs();
|
|
52763
|
-
const r = (0,
|
|
52600
|
+
const r = (0, import_node_child_process8.spawnSync)(command2, args, { stdio: "inherit", env: { ...process.env, ...env } });
|
|
52764
52601
|
process.exitCode = r.status ?? 1;
|
|
52765
52602
|
return;
|
|
52766
52603
|
}
|
|
@@ -52828,8 +52665,8 @@ async function main() {
|
|
|
52828
52665
|
env: process.env,
|
|
52829
52666
|
cwd: process.cwd(),
|
|
52830
52667
|
writeFile: (p, c) => {
|
|
52831
|
-
(0,
|
|
52832
|
-
(0,
|
|
52668
|
+
(0, import_node_fs15.mkdirSync)(import_node_path21.default.dirname(p), { recursive: true, mode: 448 });
|
|
52669
|
+
(0, import_node_fs15.writeFileSync)(p, c, { mode: 384 });
|
|
52833
52670
|
},
|
|
52834
52671
|
runPm2: pm2Runner,
|
|
52835
52672
|
which: whichBin,
|
|
@@ -52846,35 +52683,35 @@ async function main() {
|
|
|
52846
52683
|
runPm2: (a) => ({ code: pm2Runner(a).code }),
|
|
52847
52684
|
removeFile: (p) => {
|
|
52848
52685
|
try {
|
|
52849
|
-
(0,
|
|
52686
|
+
(0, import_node_fs15.rmSync)(p, { force: true });
|
|
52850
52687
|
} catch {
|
|
52851
52688
|
}
|
|
52852
52689
|
},
|
|
52853
52690
|
purgeSecret: purge,
|
|
52854
52691
|
secretPath: agentCredentialPath(),
|
|
52855
52692
|
tokenPath: operatorTokenPath(),
|
|
52856
|
-
ecoPath:
|
|
52693
|
+
ecoPath: import_node_path21.default.join(process.env.HOME ?? (0, import_node_os12.homedir)(), ".mrrlin", "ecosystem.config.cjs"),
|
|
52857
52694
|
log: (m) => process.stderr.write(`[mrrlin-mcp uninstall-service] ${m}
|
|
52858
52695
|
`)
|
|
52859
52696
|
});
|
|
52860
52697
|
return;
|
|
52861
52698
|
}
|
|
52862
52699
|
case "uninstall": {
|
|
52863
|
-
const home = process.env.HOME ?? (0,
|
|
52700
|
+
const home = process.env.HOME ?? (0, import_node_os12.homedir)();
|
|
52864
52701
|
const log = (m) => process.stderr.write(`[mrrlin-mcp uninstall] ${m}
|
|
52865
52702
|
`);
|
|
52866
52703
|
uninstallService({
|
|
52867
52704
|
runPm2: (a) => ({ code: pm2Runner(a).code }),
|
|
52868
52705
|
removeFile: (p) => {
|
|
52869
52706
|
try {
|
|
52870
|
-
(0,
|
|
52707
|
+
(0, import_node_fs15.rmSync)(p, { force: true });
|
|
52871
52708
|
} catch {
|
|
52872
52709
|
}
|
|
52873
52710
|
},
|
|
52874
52711
|
purgeSecret: true,
|
|
52875
52712
|
secretPath: agentCredentialPath(),
|
|
52876
52713
|
tokenPath: operatorTokenPath(),
|
|
52877
|
-
ecoPath:
|
|
52714
|
+
ecoPath: import_node_path21.default.join(home, ".mrrlin", "ecosystem.config.cjs"),
|
|
52878
52715
|
log
|
|
52879
52716
|
});
|
|
52880
52717
|
let codexOk = true;
|
|
@@ -52894,7 +52731,7 @@ async function main() {
|
|
|
52894
52731
|
log(`codex config NOT modified: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
52895
52732
|
}
|
|
52896
52733
|
try {
|
|
52897
|
-
(0,
|
|
52734
|
+
(0, import_node_fs15.rmSync)(import_node_path21.default.join(home, ".mrrlin"), { recursive: true, force: true });
|
|
52898
52735
|
} catch {
|
|
52899
52736
|
}
|
|
52900
52737
|
log("removed ~/.mrrlin");
|
|
@@ -52935,7 +52772,7 @@ ${HELP_TEXT}`);
|
|
|
52935
52772
|
}
|
|
52936
52773
|
}
|
|
52937
52774
|
function resolveSelfBinPath() {
|
|
52938
|
-
return
|
|
52775
|
+
return import_node_path20.default.resolve(process.argv[1] ?? process.execPath);
|
|
52939
52776
|
}
|
|
52940
52777
|
main().catch((error51) => {
|
|
52941
52778
|
process.stderr.write(`mrrlin-mcp fatal error: ${error51 instanceof Error ? error51.message : String(error51)}
|