@mrrlin-dev/mcp 0.4.9 → 0.4.15
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 +671 -157
- package/package.json +5 -5
package/dist/bin.cjs
CHANGED
|
@@ -8166,7 +8166,7 @@ var require_graceful_fs = __commonJS({
|
|
|
8166
8166
|
function patch(fs11) {
|
|
8167
8167
|
polyfills(fs11);
|
|
8168
8168
|
fs11.gracefulify = patch;
|
|
8169
|
-
fs11.createReadStream =
|
|
8169
|
+
fs11.createReadStream = createReadStream2;
|
|
8170
8170
|
fs11.createWriteStream = createWriteStream;
|
|
8171
8171
|
var fs$readFile = fs11.readFile;
|
|
8172
8172
|
fs11.readFile = readFile9;
|
|
@@ -8376,7 +8376,7 @@ var require_graceful_fs = __commonJS({
|
|
|
8376
8376
|
}
|
|
8377
8377
|
});
|
|
8378
8378
|
}
|
|
8379
|
-
function
|
|
8379
|
+
function createReadStream2(path22, options) {
|
|
8380
8380
|
return new fs11.ReadStream(path22, options);
|
|
8381
8381
|
}
|
|
8382
8382
|
function createWriteStream(path22, options) {
|
|
@@ -20644,11 +20644,11 @@ var require_dist = __commonJS({
|
|
|
20644
20644
|
});
|
|
20645
20645
|
|
|
20646
20646
|
// src/bin.ts
|
|
20647
|
-
var
|
|
20647
|
+
var import_node_path31 = __toESM(require("node:path"), 1);
|
|
20648
20648
|
var import_node_child_process18 = require("node:child_process");
|
|
20649
|
-
var
|
|
20649
|
+
var import_node_fs18 = require("node:fs");
|
|
20650
20650
|
var import_node_os15 = require("node:os");
|
|
20651
|
-
var
|
|
20651
|
+
var import_node_path32 = __toESM(require("node:path"), 1);
|
|
20652
20652
|
|
|
20653
20653
|
// src/install-codex.ts
|
|
20654
20654
|
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
@@ -21471,10 +21471,10 @@ async function verifyProviderReadiness(provider, run3, opts = {}) {
|
|
|
21471
21471
|
}
|
|
21472
21472
|
|
|
21473
21473
|
// src/director-bridge.ts
|
|
21474
|
-
var
|
|
21474
|
+
var import_node_fs17 = __toESM(require("node:fs"), 1);
|
|
21475
21475
|
var import_node_http = __toESM(require("node:http"), 1);
|
|
21476
21476
|
var import_node_os11 = __toESM(require("node:os"), 1);
|
|
21477
|
-
var
|
|
21477
|
+
var import_node_path24 = __toESM(require("node:path"), 1);
|
|
21478
21478
|
var import_node_child_process15 = require("node:child_process");
|
|
21479
21479
|
var import_node_crypto9 = __toESM(require("node:crypto"), 1);
|
|
21480
21480
|
|
|
@@ -36828,6 +36828,8 @@ var openApiOperationIds = {
|
|
|
36828
36828
|
getArtifactFile: "getArtifactFile",
|
|
36829
36829
|
downloadArtifactFile: "downloadArtifactFile",
|
|
36830
36830
|
listArtifactFiles: "listArtifactFiles",
|
|
36831
|
+
listArtifactFileExcerpts: "listArtifactFileExcerpts",
|
|
36832
|
+
getArtifactFileContent: "getArtifactFileContent",
|
|
36831
36833
|
getOperatorSettings: "getOperatorSettings",
|
|
36832
36834
|
updateOperatorSettings: "updateOperatorSettings",
|
|
36833
36835
|
recordOperatorPresence: "recordOperatorPresence",
|
|
@@ -36842,7 +36844,8 @@ var openApiOperationIds = {
|
|
|
36842
36844
|
recordSpecConsensusReview: "recordSpecConsensusReview",
|
|
36843
36845
|
getSpecConsensusReview: "getSpecConsensusReview",
|
|
36844
36846
|
onboardingKickoffTransition: "onboardingKickoffTransition",
|
|
36845
|
-
ingestTelemetry: "ingestTelemetry"
|
|
36847
|
+
ingestTelemetry: "ingestTelemetry",
|
|
36848
|
+
getTelemetry: "getTelemetry"
|
|
36846
36849
|
};
|
|
36847
36850
|
|
|
36848
36851
|
// ../../packages/schemas/dist/session.js
|
|
@@ -37284,6 +37287,20 @@ function totalSize(items) {
|
|
|
37284
37287
|
return items.reduce((sum, i) => sum + i.size, 0);
|
|
37285
37288
|
}
|
|
37286
37289
|
|
|
37290
|
+
// ../../packages/schemas/dist/inboxProposal.js
|
|
37291
|
+
function isRunnableProposal(item) {
|
|
37292
|
+
if (item.kind !== "proposal") {
|
|
37293
|
+
return false;
|
|
37294
|
+
}
|
|
37295
|
+
if (item.actionPayload === null || item.actionPayload === void 0) {
|
|
37296
|
+
return false;
|
|
37297
|
+
}
|
|
37298
|
+
if (item.taskId === null || item.taskId === void 0 || item.taskId === "") {
|
|
37299
|
+
return false;
|
|
37300
|
+
}
|
|
37301
|
+
return true;
|
|
37302
|
+
}
|
|
37303
|
+
|
|
37287
37304
|
// ../../packages/schemas/dist/index.js
|
|
37288
37305
|
var mrrlinTaskStatusSchema = external_exports.enum([
|
|
37289
37306
|
"backlog",
|
|
@@ -38460,6 +38477,13 @@ var artifactFileCreateResponseSchema = external_exports.object({
|
|
|
38460
38477
|
})
|
|
38461
38478
|
});
|
|
38462
38479
|
var artifactFileListResponseSchema = external_exports.object({ data: external_exports.array(mrrlinArtifactFilePublicSchema) });
|
|
38480
|
+
var mrrlinArtifactFileExcerptSchema = external_exports.object({
|
|
38481
|
+
excerpt: external_exports.string(),
|
|
38482
|
+
id: external_exports.string().uuid()
|
|
38483
|
+
});
|
|
38484
|
+
var mrrlinArtifactFileExcerptsResponseSchema = external_exports.object({
|
|
38485
|
+
data: external_exports.array(mrrlinArtifactFileExcerptSchema)
|
|
38486
|
+
});
|
|
38463
38487
|
var artifactFileExpiredResponseSchema = external_exports.object({
|
|
38464
38488
|
artifact: external_exports.object({
|
|
38465
38489
|
class: mrrlinArtifactFileClassSchema,
|
|
@@ -40175,6 +40199,46 @@ function createMrrlinClient(config2) {
|
|
|
40175
40199
|
}
|
|
40176
40200
|
return response.json();
|
|
40177
40201
|
}
|
|
40202
|
+
async function requestText(path22, init) {
|
|
40203
|
+
const method = init?.method ?? "GET";
|
|
40204
|
+
const headers = new Headers(init?.headers ?? {});
|
|
40205
|
+
if (token && !headers.has("authorization")) {
|
|
40206
|
+
headers.set("authorization", `Bearer ${token}`);
|
|
40207
|
+
}
|
|
40208
|
+
const response = await customFetch(`${baseUrl}${path22}`, { ...init, headers });
|
|
40209
|
+
if (!response.ok) {
|
|
40210
|
+
const body = await response.text();
|
|
40211
|
+
let code = `HTTP_${response.status}`;
|
|
40212
|
+
let violations = null;
|
|
40213
|
+
let message = `Mrrlin API ${method} ${path22} failed: ${response.status}`;
|
|
40214
|
+
try {
|
|
40215
|
+
const parsed = JSON.parse(body);
|
|
40216
|
+
const violationsParsed = apiViolationsErrorSchema.safeParse(parsed);
|
|
40217
|
+
if (violationsParsed.success) {
|
|
40218
|
+
code = violationsParsed.data.code;
|
|
40219
|
+
violations = violationsParsed.data.violations;
|
|
40220
|
+
message = violationsParsed.data.message;
|
|
40221
|
+
} else {
|
|
40222
|
+
const errorParsed = apiErrorSchema.safeParse(parsed);
|
|
40223
|
+
if (errorParsed.success) {
|
|
40224
|
+
code = errorParsed.data.code;
|
|
40225
|
+
message = errorParsed.data.message;
|
|
40226
|
+
}
|
|
40227
|
+
}
|
|
40228
|
+
} catch {
|
|
40229
|
+
}
|
|
40230
|
+
throw new MrrlinApiError({
|
|
40231
|
+
code,
|
|
40232
|
+
method,
|
|
40233
|
+
path: path22,
|
|
40234
|
+
responseBody: body,
|
|
40235
|
+
status: response.status,
|
|
40236
|
+
violations,
|
|
40237
|
+
message
|
|
40238
|
+
});
|
|
40239
|
+
}
|
|
40240
|
+
return response.text();
|
|
40241
|
+
}
|
|
40178
40242
|
return {
|
|
40179
40243
|
async listGithubInstallations() {
|
|
40180
40244
|
const body = await request(`/github/installations`);
|
|
@@ -40894,6 +40958,14 @@ function createMrrlinClient(config2) {
|
|
|
40894
40958
|
const body = await request(`${projectPath(projectSlug)}/artifact-files${suffix}`);
|
|
40895
40959
|
return artifactFileListResponseSchema.parse(body).data;
|
|
40896
40960
|
},
|
|
40961
|
+
async listArtifactFileExcerpts(projectSlug, taskId) {
|
|
40962
|
+
const params = new URLSearchParams({ taskId });
|
|
40963
|
+
const body = await request(`${projectPath(projectSlug)}/artifact-file-excerpts?${params.toString()}`);
|
|
40964
|
+
return mrrlinArtifactFileExcerptsResponseSchema.parse(body).data;
|
|
40965
|
+
},
|
|
40966
|
+
async getArtifactFileContent(projectSlug, artifactFileId) {
|
|
40967
|
+
return requestText(`${projectPath(projectSlug)}/artifact-files/${encodeURIComponent(artifactFileId)}/content`);
|
|
40968
|
+
},
|
|
40897
40969
|
async getProjectSchedulerPolicy(projectSlug) {
|
|
40898
40970
|
const body = await request(`${projectPath(projectSlug)}/scheduler/policy`);
|
|
40899
40971
|
return projectSchedulerPolicyResponseSchema.parse(body).data;
|
|
@@ -41292,16 +41364,16 @@ function resolveBinPath(opts) {
|
|
|
41292
41364
|
return null;
|
|
41293
41365
|
}
|
|
41294
41366
|
});
|
|
41295
|
-
const
|
|
41367
|
+
const existsSync5 = opts.existsSync ?? import_node_fs2.existsSync;
|
|
41296
41368
|
const resolved = whichSync(BIN_NAME);
|
|
41297
|
-
if (resolved &&
|
|
41369
|
+
if (resolved && existsSync5(resolved)) {
|
|
41298
41370
|
return { path: resolved, source: "which" };
|
|
41299
41371
|
}
|
|
41300
41372
|
const envPath = (opts.env ?? process.env).PATH ?? "";
|
|
41301
41373
|
for (const dir of envPath.split(import_node_path5.default.delimiter)) {
|
|
41302
41374
|
if (!dir) continue;
|
|
41303
41375
|
const candidate = import_node_path5.default.join(dir, BIN_NAME);
|
|
41304
|
-
if (
|
|
41376
|
+
if (existsSync5(candidate)) {
|
|
41305
41377
|
return { path: candidate, source: "path-walk" };
|
|
41306
41378
|
}
|
|
41307
41379
|
}
|
|
@@ -41551,7 +41623,7 @@ Do NOT derail the current task - if the operator has an in-flight question, answ
|
|
|
41551
41623
|
}
|
|
41552
41624
|
|
|
41553
41625
|
// src/_generated/version.ts
|
|
41554
|
-
var PKG_VERSION = "0.4.
|
|
41626
|
+
var PKG_VERSION = "0.4.15";
|
|
41555
41627
|
|
|
41556
41628
|
// src/api-base-url-migrate.ts
|
|
41557
41629
|
var import_node_fs3 = __toESM(require("node:fs"), 1);
|
|
@@ -42114,6 +42186,9 @@ function startSchedulerTickLoop(deps) {
|
|
|
42114
42186
|
// src/retention/pruner.ts
|
|
42115
42187
|
var import_promises4 = require("node:fs/promises");
|
|
42116
42188
|
var import_node_path9 = __toESM(require("node:path"), 1);
|
|
42189
|
+
function protectedDayFloor(protectedSinceMs) {
|
|
42190
|
+
return new Date(protectedSinceMs).toISOString().slice(0, 10);
|
|
42191
|
+
}
|
|
42117
42192
|
async function prune(stateDir, bounds) {
|
|
42118
42193
|
const logsDir = import_node_path9.default.join(stateDir, "logs");
|
|
42119
42194
|
let entries;
|
|
@@ -42122,7 +42197,7 @@ async function prune(stateDir, bounds) {
|
|
|
42122
42197
|
} catch (err) {
|
|
42123
42198
|
if (err?.code === "ENOENT") {
|
|
42124
42199
|
await emitPruneLog(stateDir, [], {}, 0, null);
|
|
42125
|
-
return { daysRemoved: [], reasonByDay: {}, bytesRemoved: 0, oldestDayRemaining: null };
|
|
42200
|
+
return { daysRemoved: [], reasonByDay: {}, bytesRemoved: 0, oldestDayRemaining: null, budgetOvershootBytes: 0 };
|
|
42126
42201
|
}
|
|
42127
42202
|
throw err;
|
|
42128
42203
|
}
|
|
@@ -42166,12 +42241,15 @@ async function prune(stateDir, bounds) {
|
|
|
42166
42241
|
}
|
|
42167
42242
|
return true;
|
|
42168
42243
|
}
|
|
42244
|
+
const protectedFromDay = bounds.protectedSinceMs === void 0 ? null : protectedDayFloor(bounds.protectedSinceMs);
|
|
42245
|
+
const isProtected = (day) => protectedFromDay !== null && day >= protectedFromDay;
|
|
42169
42246
|
const budgetBytes = bounds.budgetMb * 1024 * 1024;
|
|
42170
42247
|
let totalSize2 = files.reduce((sum, f) => sum + f.size, 0);
|
|
42171
42248
|
let i = 0;
|
|
42172
42249
|
while (totalSize2 > budgetBytes && i < files.length) {
|
|
42173
42250
|
const candidate = files[i];
|
|
42174
42251
|
if (!candidate) break;
|
|
42252
|
+
if (isProtected(candidate.day)) break;
|
|
42175
42253
|
if (!await isDaySafeToDelete(candidate.day)) {
|
|
42176
42254
|
i += 1;
|
|
42177
42255
|
continue;
|
|
@@ -42189,16 +42267,18 @@ async function prune(stateDir, bounds) {
|
|
|
42189
42267
|
for (const info of files) {
|
|
42190
42268
|
const fileDate = /* @__PURE__ */ new Date(`${info.day}T00:00:00Z`);
|
|
42191
42269
|
const ageInDays = (now - fileDate.getTime()) / msPerDay;
|
|
42192
|
-
if (ageInDays > bounds.ageDays && await isDaySafeToDelete(info.day)) {
|
|
42270
|
+
if (ageInDays > bounds.ageDays && !isProtected(info.day) && await isDaySafeToDelete(info.day)) {
|
|
42193
42271
|
await (0, import_promises4.unlink)(info.fullPath);
|
|
42194
42272
|
daysRemoved.push(info.day);
|
|
42195
42273
|
reasonByDay[info.day] = "age";
|
|
42196
42274
|
bytesRemoved += info.size;
|
|
42275
|
+
totalSize2 -= info.size;
|
|
42197
42276
|
continue;
|
|
42198
42277
|
}
|
|
42199
42278
|
stillRemaining.push(info);
|
|
42200
42279
|
}
|
|
42201
42280
|
const oldestDayRemaining = stillRemaining.length > 0 ? stillRemaining[0]?.day ?? null : null;
|
|
42281
|
+
const budgetOvershootBytes = Math.max(0, totalSize2 - budgetBytes);
|
|
42202
42282
|
await emitPruneLog(stateDir, daysRemoved, reasonByDay, bytesRemoved, oldestDayRemaining);
|
|
42203
42283
|
if (daysRemoved.length > 0) {
|
|
42204
42284
|
const sessionsPath = import_node_path9.default.join(logsDir, ".sessions.json");
|
|
@@ -42220,7 +42300,7 @@ async function prune(stateDir, bounds) {
|
|
|
42220
42300
|
await (0, import_promises4.rename)(tmpPath, sessionsPath);
|
|
42221
42301
|
}
|
|
42222
42302
|
}
|
|
42223
|
-
return { daysRemoved, reasonByDay, bytesRemoved, oldestDayRemaining };
|
|
42303
|
+
return { daysRemoved, reasonByDay, bytesRemoved, oldestDayRemaining, budgetOvershootBytes };
|
|
42224
42304
|
}
|
|
42225
42305
|
async function emitPruneLog(stateDir, daysRemoved, reasonByDay, bytesRemoved, oldestDayRemaining) {
|
|
42226
42306
|
const logsDir = import_node_path9.default.join(stateDir, "logs");
|
|
@@ -44029,50 +44109,102 @@ async function uploadPendingDays(stateDir, client, bridgeHealth, gateCtx) {
|
|
|
44029
44109
|
const fullUnprocessed = pending.map((p) => ({ projectSlug: p.projectSlug, day: p.day }));
|
|
44030
44110
|
pending.sort((a, b) => a.day.localeCompare(b.day));
|
|
44031
44111
|
for (const cur of pending) {
|
|
44032
|
-
|
|
44112
|
+
const failurePath = (0, import_node_path12.join)(telemetryDir, `.failed-${cur.projectSlug}-${cur.day}.json`);
|
|
44113
|
+
let failureState = null;
|
|
44033
44114
|
try {
|
|
44034
|
-
|
|
44035
|
-
|
|
44036
|
-
|
|
44037
|
-
|
|
44038
|
-
}
|
|
44039
|
-
const rows = [];
|
|
44040
|
-
for (const line of raw.split("\n")) {
|
|
44041
|
-
if (!line.trim()) continue;
|
|
44042
|
-
try {
|
|
44043
|
-
rows.push({ ...JSON.parse(line), gateMarker: "gated" });
|
|
44044
|
-
} catch {
|
|
44045
|
-
}
|
|
44115
|
+
const data = await (0, import_promises6.readFile)(failurePath, "utf8");
|
|
44116
|
+
failureState = JSON.parse(data);
|
|
44117
|
+
} catch {
|
|
44118
|
+
failureState = null;
|
|
44046
44119
|
}
|
|
44047
|
-
const
|
|
44048
|
-
|
|
44049
|
-
bridgeVersion: PKG_VERSION,
|
|
44050
|
-
knownCrashCount,
|
|
44051
|
-
unprocessedPartitions: fullUnprocessed.filter(
|
|
44052
|
-
(p) => !(p.projectSlug === cur.projectSlug && p.day === cur.day)
|
|
44053
|
-
),
|
|
44054
|
-
rows
|
|
44055
|
-
};
|
|
44056
|
-
const gateResult = await gate(batch, [], gateCtx);
|
|
44057
|
-
const gateMarker = gateResult.gated ? "gated" : "projection-only";
|
|
44058
|
-
for (const row of gateResult.artifact.rows) row.gateMarker = gateMarker;
|
|
44059
|
-
const targetProject = cur.projectSlug === "_unattributed" ? process.env.MRRLIN_TELEMETRY_DEFAULT_PROJECT : cur.projectSlug;
|
|
44060
|
-
if (!targetProject) {
|
|
44061
|
-
console.error(`uploadPendingDays: no target project resolved for _unattributed/${cur.day}`);
|
|
44120
|
+
const now = Date.now();
|
|
44121
|
+
if (failureState && failureState.nextAttemptAt > now) {
|
|
44062
44122
|
continue;
|
|
44063
44123
|
}
|
|
44124
|
+
let success2 = false;
|
|
44064
44125
|
try {
|
|
44126
|
+
let raw;
|
|
44127
|
+
try {
|
|
44128
|
+
raw = await (0, import_promises6.readFile)(cur.rowsPath, "utf8");
|
|
44129
|
+
} catch (err) {
|
|
44130
|
+
console.error(`uploadPendingDays: failed to read ${cur.rowsPath}`, err);
|
|
44131
|
+
throw err;
|
|
44132
|
+
}
|
|
44133
|
+
const rows = [];
|
|
44134
|
+
for (const line of raw.split("\n")) {
|
|
44135
|
+
if (!line.trim()) continue;
|
|
44136
|
+
try {
|
|
44137
|
+
rows.push({ ...JSON.parse(line), gateMarker: "gated" });
|
|
44138
|
+
} catch {
|
|
44139
|
+
}
|
|
44140
|
+
}
|
|
44141
|
+
const batch = {
|
|
44142
|
+
day: cur.day,
|
|
44143
|
+
bridgeVersion: PKG_VERSION,
|
|
44144
|
+
knownCrashCount,
|
|
44145
|
+
unprocessedPartitions: fullUnprocessed.filter(
|
|
44146
|
+
(p) => !(p.projectSlug === cur.projectSlug && p.day === cur.day)
|
|
44147
|
+
),
|
|
44148
|
+
rows
|
|
44149
|
+
};
|
|
44150
|
+
const gateResult = await gate(batch, [], gateCtx);
|
|
44151
|
+
const gateMarker = gateResult.gated ? "gated" : "projection-only";
|
|
44152
|
+
for (const row of gateResult.artifact.rows) row.gateMarker = gateMarker;
|
|
44153
|
+
const targetProject = cur.projectSlug === "_unattributed" ? process.env.MRRLIN_TELEMETRY_DEFAULT_PROJECT : cur.projectSlug;
|
|
44154
|
+
if (!targetProject) {
|
|
44155
|
+
console.error(`uploadPendingDays: no target project resolved for _unattributed/${cur.day}`);
|
|
44156
|
+
continue;
|
|
44157
|
+
}
|
|
44065
44158
|
await client.postTelemetry(targetProject, gateResult.artifact);
|
|
44066
|
-
|
|
44067
|
-
|
|
44068
|
-
|
|
44159
|
+
success2 = true;
|
|
44160
|
+
} catch {
|
|
44161
|
+
success2 = false;
|
|
44069
44162
|
}
|
|
44070
|
-
|
|
44071
|
-
|
|
44072
|
-
|
|
44073
|
-
|
|
44074
|
-
|
|
44075
|
-
|
|
44163
|
+
if (success2) {
|
|
44164
|
+
const tmpMarker = `${cur.markerPath}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
44165
|
+
try {
|
|
44166
|
+
await (0, import_promises6.writeFile)(tmpMarker, "");
|
|
44167
|
+
await (0, import_promises6.rename)(tmpMarker, cur.markerPath);
|
|
44168
|
+
} catch (err) {
|
|
44169
|
+
console.error(`uploadPendingDays: failed to write marker for ${cur.projectSlug}/${cur.day}`, err);
|
|
44170
|
+
}
|
|
44171
|
+
if (failureState) {
|
|
44172
|
+
try {
|
|
44173
|
+
await (0, import_promises6.unlink)(failurePath);
|
|
44174
|
+
console.log(`uploadPendingDays: partition ${cur.projectSlug}/${cur.day} recovered after ${failureState.failureCount + 1} consecutive failures`);
|
|
44175
|
+
} catch (err) {
|
|
44176
|
+
console.error(`uploadPendingDays: failed to remove failure state for ${cur.projectSlug}/${cur.day}`, err);
|
|
44177
|
+
}
|
|
44178
|
+
}
|
|
44179
|
+
} else {
|
|
44180
|
+
let newFailureCount = 1;
|
|
44181
|
+
if (failureState) {
|
|
44182
|
+
newFailureCount = failureState.failureCount + 1;
|
|
44183
|
+
}
|
|
44184
|
+
const baseDelayMs = 36e5;
|
|
44185
|
+
const maxDelayMs = 864e5;
|
|
44186
|
+
let delayMs2 = 0;
|
|
44187
|
+
if (newFailureCount >= 2) {
|
|
44188
|
+
delayMs2 = baseDelayMs * 2 ** (newFailureCount - 2);
|
|
44189
|
+
if (delayMs2 > maxDelayMs) {
|
|
44190
|
+
delayMs2 = maxDelayMs;
|
|
44191
|
+
}
|
|
44192
|
+
}
|
|
44193
|
+
const nextAttemptAt = now + delayMs2;
|
|
44194
|
+
const newFailureState = {
|
|
44195
|
+
failureCount: newFailureCount,
|
|
44196
|
+
nextAttemptAt
|
|
44197
|
+
};
|
|
44198
|
+
const tmpFailurePath = `${failurePath}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
44199
|
+
try {
|
|
44200
|
+
await (0, import_promises6.writeFile)(tmpFailurePath, JSON.stringify(newFailureState));
|
|
44201
|
+
await (0, import_promises6.rename)(tmpFailurePath, failurePath);
|
|
44202
|
+
} catch (writeErr) {
|
|
44203
|
+
console.error(`uploadPendingDays: failed to write failure state for ${cur.projectSlug}/${cur.day}`, writeErr);
|
|
44204
|
+
}
|
|
44205
|
+
if (!failureState) {
|
|
44206
|
+
console.error(`uploadPendingDays: partition ${cur.projectSlug}/${cur.day} entering backoff after first failure`);
|
|
44207
|
+
}
|
|
44076
44208
|
}
|
|
44077
44209
|
}
|
|
44078
44210
|
}
|
|
@@ -47878,7 +48010,7 @@ function resolveBridgeLogEnabled(env = process.env) {
|
|
|
47878
48010
|
const raw = (env.MRRLIN_DIRECTOR_BRIDGE_LOG ?? "").trim().toLowerCase();
|
|
47879
48011
|
return !(raw === "0" || raw === "false");
|
|
47880
48012
|
}
|
|
47881
|
-
function resolvePromptsEnabled(env) {
|
|
48013
|
+
function resolvePromptsEnabled(env = process.env) {
|
|
47882
48014
|
const raw = (env.MRRLIN_DIRECTOR_BRIDGE_LOG_PROMPTS ?? "").trim().toLowerCase();
|
|
47883
48015
|
return !(raw === "0" || raw === "false");
|
|
47884
48016
|
}
|
|
@@ -48339,6 +48471,16 @@ function createAgentKeepalive(opts) {
|
|
|
48339
48471
|
}, opts.idleMs(providerId));
|
|
48340
48472
|
slot.idleTimer.unref?.();
|
|
48341
48473
|
},
|
|
48474
|
+
refreshNow: (providerId) => {
|
|
48475
|
+
const slot = getSlot(providerId);
|
|
48476
|
+
if (slot.holdCount > 0) return false;
|
|
48477
|
+
cancelTimer(slot);
|
|
48478
|
+
if (slot.managerHeld) {
|
|
48479
|
+
slot.managerHeld = false;
|
|
48480
|
+
opts.release(providerId);
|
|
48481
|
+
}
|
|
48482
|
+
return true;
|
|
48483
|
+
},
|
|
48342
48484
|
dropNow: () => {
|
|
48343
48485
|
for (const [providerId, slot] of slots) {
|
|
48344
48486
|
cancelTimer(slot);
|
|
@@ -52282,7 +52424,8 @@ function boundInboxItems(items) {
|
|
|
52282
52424
|
kind: it.kind,
|
|
52283
52425
|
status: it.status,
|
|
52284
52426
|
body,
|
|
52285
|
-
...it.taskId ? { taskId: it.taskId } : {}
|
|
52427
|
+
...it.taskId ? { taskId: it.taskId } : {},
|
|
52428
|
+
...it.kind === "proposal" ? { runnable: isRunnableProposal(it) } : {}
|
|
52286
52429
|
};
|
|
52287
52430
|
const size = enc2.encode(JSON.stringify(projected)).length + 1;
|
|
52288
52431
|
if (bytes3 + size > MAX_INBOX_PAYLOAD_BYTES && out.length > 0) break;
|
|
@@ -52770,19 +52913,179 @@ function extractVerificationSection(markdown) {
|
|
|
52770
52913
|
return body.length > 0 ? body : null;
|
|
52771
52914
|
}
|
|
52772
52915
|
|
|
52916
|
+
// src/director-reseed.ts
|
|
52917
|
+
var import_node_fs15 = require("node:fs");
|
|
52918
|
+
var import_node_readline = require("node:readline");
|
|
52919
|
+
var import_node_path22 = require("node:path");
|
|
52920
|
+
function estimateTokens(s) {
|
|
52921
|
+
return Buffer.byteLength(s, "utf8");
|
|
52922
|
+
}
|
|
52923
|
+
function dayFilesInWindow(now, windowMs) {
|
|
52924
|
+
const end = new Date(now.getTime());
|
|
52925
|
+
const start = new Date(now.getTime() - windowMs);
|
|
52926
|
+
const startDay = new Date(Date.UTC(
|
|
52927
|
+
start.getUTCFullYear(),
|
|
52928
|
+
start.getUTCMonth(),
|
|
52929
|
+
start.getUTCDate(),
|
|
52930
|
+
0,
|
|
52931
|
+
0,
|
|
52932
|
+
0,
|
|
52933
|
+
0
|
|
52934
|
+
));
|
|
52935
|
+
const files = [];
|
|
52936
|
+
for (let cur = new Date(startDay); cur.getTime() <= end.getTime(); cur.setUTCDate(cur.getUTCDate() + 1)) {
|
|
52937
|
+
const name = `bridge-${cur.getUTCFullYear().toString().padStart(4, "0")}-${(cur.getUTCMonth() + 1).toString().padStart(2, "0")}-${cur.getUTCDate().toString().padStart(2, "0")}.jsonl`;
|
|
52938
|
+
files.push(name);
|
|
52939
|
+
}
|
|
52940
|
+
return files;
|
|
52941
|
+
}
|
|
52942
|
+
function isRecord3(value) {
|
|
52943
|
+
return typeof value === "object" && value !== null;
|
|
52944
|
+
}
|
|
52945
|
+
function extractItems(lines2, sessionIds) {
|
|
52946
|
+
const sessionSet = new Set(sessionIds);
|
|
52947
|
+
const items = [];
|
|
52948
|
+
let skipped2 = 0;
|
|
52949
|
+
for (const raw of lines2) {
|
|
52950
|
+
if (raw.trim() === "") {
|
|
52951
|
+
continue;
|
|
52952
|
+
}
|
|
52953
|
+
let parsed;
|
|
52954
|
+
try {
|
|
52955
|
+
parsed = JSON.parse(raw);
|
|
52956
|
+
} catch {
|
|
52957
|
+
skipped2++;
|
|
52958
|
+
continue;
|
|
52959
|
+
}
|
|
52960
|
+
if (!isRecord3(parsed)) {
|
|
52961
|
+
skipped2++;
|
|
52962
|
+
continue;
|
|
52963
|
+
}
|
|
52964
|
+
const obj = parsed;
|
|
52965
|
+
if (!sessionSet.has(obj.sessionId)) continue;
|
|
52966
|
+
const ts = obj.ts;
|
|
52967
|
+
const type = obj.type;
|
|
52968
|
+
const payload = obj.payload;
|
|
52969
|
+
if (type === "turn" && isRecord3(payload) && typeof payload.message === "string") {
|
|
52970
|
+
items.push({ ts, kind: "user", text: payload.message });
|
|
52971
|
+
} else if (type === "event" && isRecord3(payload) && isRecord3(payload.event) && payload.event.type === "assistant" && typeof payload.event.content === "string") {
|
|
52972
|
+
items.push({ ts, kind: "assistant", text: payload.event.content });
|
|
52973
|
+
} else if (type === "event" && isRecord3(payload) && isRecord3(payload.event) && payload.event.type === "tool_use" && isRecord3(payload.event.tool) && typeof payload.event.tool.name === "string") {
|
|
52974
|
+
items.push({ ts, kind: "tool", text: payload.event.tool.name });
|
|
52975
|
+
}
|
|
52976
|
+
}
|
|
52977
|
+
items.sort((a, b) => a.ts < b.ts ? -1 : a.ts > b.ts ? 1 : 0);
|
|
52978
|
+
return { items, skipped: skipped2 };
|
|
52979
|
+
}
|
|
52980
|
+
function renderReseedBlock(items, opts) {
|
|
52981
|
+
const buildText = (kept2, droppedCount) => {
|
|
52982
|
+
const header = [
|
|
52983
|
+
"[bridge:reconstructed-history] The conversation below is a RECONSTRUCTION assembled",
|
|
52984
|
+
"from this bridge's own logs. It is NOT your memory: you did not run these tools in",
|
|
52985
|
+
"this thread, and nothing here is a live handle.",
|
|
52986
|
+
"- Every external session it mentions is GONE: browser tabs, logins, shell sessions,",
|
|
52987
|
+
" working directories, temporary files.",
|
|
52988
|
+
"- Tool names appear WITHOUT their arguments and WITHOUT their results, and may come",
|
|
52989
|
+
" from a different provider's tool surface than the one you have now. They are",
|
|
52990
|
+
" history, not a menu.",
|
|
52991
|
+
"- Before acting on anything described here, re-verify it against current state."
|
|
52992
|
+
].join("\n");
|
|
52993
|
+
const firstKeptTs = kept2[0]?.ts;
|
|
52994
|
+
const truncationNotice = droppedCount > 0 && firstKeptTs !== void 0 ? `- TRUNCATED: the oldest ${droppedCount} items were dropped; this reconstruction starts at ${firstKeptTs}.` : "";
|
|
52995
|
+
const roleMap = {
|
|
52996
|
+
user: "OPERATOR",
|
|
52997
|
+
assistant: "DIRECTOR",
|
|
52998
|
+
tool: "TOOL"
|
|
52999
|
+
};
|
|
53000
|
+
const itemsText = kept2.map((it) => `[${it.ts}] ${roleMap[it.kind]}: ${it.text}`).join("\n");
|
|
53001
|
+
const body = [
|
|
53002
|
+
truncationNotice,
|
|
53003
|
+
"--- reconstructed conversation begins ---",
|
|
53004
|
+
itemsText,
|
|
53005
|
+
"--- reconstructed conversation ends ---",
|
|
53006
|
+
"The operator's actual request for THIS turn is the LAST block in this message, below",
|
|
53007
|
+
"any project-context or bridge-notice blocks that follow this one."
|
|
53008
|
+
].filter((s) => s !== "").join("\n");
|
|
53009
|
+
return `${header}
|
|
53010
|
+
${body}`;
|
|
53011
|
+
};
|
|
53012
|
+
if (estimateTokens(buildText(items, 0)) <= opts.maxTokens) {
|
|
53013
|
+
return {
|
|
53014
|
+
text: buildText(items, 0),
|
|
53015
|
+
droppedCount: 0,
|
|
53016
|
+
itemCount: items.length
|
|
53017
|
+
};
|
|
53018
|
+
}
|
|
53019
|
+
const kept = [...items];
|
|
53020
|
+
let dropped = 0;
|
|
53021
|
+
const dropOne = () => {
|
|
53022
|
+
const toolIdx = kept.findIndex((it) => it.kind === "tool");
|
|
53023
|
+
kept.splice(toolIdx >= 0 ? toolIdx : 0, 1);
|
|
53024
|
+
};
|
|
53025
|
+
while (kept.length > 0) {
|
|
53026
|
+
dropOne();
|
|
53027
|
+
dropped++;
|
|
53028
|
+
if (kept.length === 0) return null;
|
|
53029
|
+
const candidateText = buildText(kept, dropped);
|
|
53030
|
+
if (estimateTokens(candidateText) <= opts.maxTokens) {
|
|
53031
|
+
const convCount = kept.filter(
|
|
53032
|
+
(it) => it.kind === "user" || it.kind === "assistant"
|
|
53033
|
+
).length;
|
|
53034
|
+
if (convCount < opts.minConversationalItems) {
|
|
53035
|
+
return null;
|
|
53036
|
+
}
|
|
53037
|
+
return {
|
|
53038
|
+
text: candidateText,
|
|
53039
|
+
droppedCount: dropped,
|
|
53040
|
+
itemCount: kept.length
|
|
53041
|
+
};
|
|
53042
|
+
}
|
|
53043
|
+
}
|
|
53044
|
+
return null;
|
|
53045
|
+
}
|
|
53046
|
+
var NO_HISTORY_BLOCK = "[bridge:no-history] No prior conversation is available for this chat \u2014 it could not be\nreconstructed. Do NOT infer what was discussed before, and do NOT assume any earlier\ntask is still in progress. If the operator's request below refers to prior context,\nsay plainly that the history is unavailable and ask them to restate what they need.";
|
|
53047
|
+
async function readSessionRows(logsDir, files, sessionIds) {
|
|
53048
|
+
const lines2 = [];
|
|
53049
|
+
let missingFiles = 0;
|
|
53050
|
+
for (const f of files) {
|
|
53051
|
+
const filePath = (0, import_node_path22.join)(logsDir, f);
|
|
53052
|
+
try {
|
|
53053
|
+
const stream = (0, import_node_fs15.createReadStream)(filePath, { encoding: "utf8" });
|
|
53054
|
+
const rl = (0, import_node_readline.createInterface)({ input: stream, crlfDelay: Infinity });
|
|
53055
|
+
try {
|
|
53056
|
+
for await (const line of rl) {
|
|
53057
|
+
if (line.trim() === "") continue;
|
|
53058
|
+
if (sessionIds && sessionIds.length > 0 && !sessionIds.some((id) => line.includes(id))) continue;
|
|
53059
|
+
lines2.push(line);
|
|
53060
|
+
}
|
|
53061
|
+
} finally {
|
|
53062
|
+
rl.close();
|
|
53063
|
+
stream.destroy();
|
|
53064
|
+
}
|
|
53065
|
+
} catch (e) {
|
|
53066
|
+
if (isRecord3(e) && e.code === "ENOENT") {
|
|
53067
|
+
missingFiles++;
|
|
53068
|
+
continue;
|
|
53069
|
+
}
|
|
53070
|
+
throw e;
|
|
53071
|
+
}
|
|
53072
|
+
}
|
|
53073
|
+
return { lines: lines2, missingFiles };
|
|
53074
|
+
}
|
|
53075
|
+
|
|
52773
53076
|
// src/external-agents-scrub.ts
|
|
52774
|
-
var
|
|
53077
|
+
var import_node_fs16 = __toESM(require("node:fs"), 1);
|
|
52775
53078
|
var import_node_os10 = __toESM(require("node:os"), 1);
|
|
52776
|
-
var
|
|
53079
|
+
var import_node_path23 = __toESM(require("node:path"), 1);
|
|
52777
53080
|
var REDACTION = "[REDACTED]";
|
|
52778
53081
|
var SHORT_VALUE_THRESHOLD = 8;
|
|
52779
|
-
var KEYS_ENV_PATH = () =>
|
|
53082
|
+
var KEYS_ENV_PATH = () => import_node_path23.default.join(import_node_os10.default.homedir(), ".local", "state", "external-agents", "keys.env");
|
|
52780
53083
|
var keysEnvCache = null;
|
|
52781
53084
|
function readKeysEnv() {
|
|
52782
53085
|
const filePath = KEYS_ENV_PATH();
|
|
52783
53086
|
let mtimeMs = 0;
|
|
52784
53087
|
try {
|
|
52785
|
-
mtimeMs =
|
|
53088
|
+
mtimeMs = import_node_fs16.default.statSync(filePath).mtimeMs;
|
|
52786
53089
|
} catch {
|
|
52787
53090
|
mtimeMs = 0;
|
|
52788
53091
|
}
|
|
@@ -52791,7 +53094,7 @@ function readKeysEnv() {
|
|
|
52791
53094
|
}
|
|
52792
53095
|
const map2 = /* @__PURE__ */ new Map();
|
|
52793
53096
|
try {
|
|
52794
|
-
const content =
|
|
53097
|
+
const content = import_node_fs16.default.readFileSync(filePath, "utf8");
|
|
52795
53098
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
52796
53099
|
const line = rawLine.trim();
|
|
52797
53100
|
if (line === "" || line.startsWith("#")) continue;
|
|
@@ -53209,7 +53512,7 @@ function addBridgeModel(target, model) {
|
|
|
53209
53512
|
}
|
|
53210
53513
|
function readTextIfExists(filePath) {
|
|
53211
53514
|
try {
|
|
53212
|
-
return
|
|
53515
|
+
return import_node_fs17.default.readFileSync(filePath, "utf8");
|
|
53213
53516
|
} catch {
|
|
53214
53517
|
return null;
|
|
53215
53518
|
}
|
|
@@ -53220,9 +53523,9 @@ function readKnownGptSlugsFromTomlFile(filePath) {
|
|
|
53220
53523
|
return Array.from(raw.matchAll(/^\s*model\s*=\s*"([^"]+)"/gm)).map((match) => match[1]?.trim() ?? "").filter(isSelectableModelSlug);
|
|
53221
53524
|
}
|
|
53222
53525
|
function readCodexFallbackModels() {
|
|
53223
|
-
const codexHome = process.env.CODEX_HOME?.trim() ||
|
|
53526
|
+
const codexHome = process.env.CODEX_HOME?.trim() || import_node_path24.default.join(import_node_os11.default.homedir(), ".codex");
|
|
53224
53527
|
const models = /* @__PURE__ */ new Map();
|
|
53225
|
-
const cachePath =
|
|
53528
|
+
const cachePath = import_node_path24.default.join(codexHome, "models_cache.json");
|
|
53226
53529
|
const cacheRaw = readTextIfExists(cachePath);
|
|
53227
53530
|
if (cacheRaw) {
|
|
53228
53531
|
try {
|
|
@@ -53272,7 +53575,7 @@ function readCodexFallbackModels() {
|
|
|
53272
53575
|
);
|
|
53273
53576
|
}
|
|
53274
53577
|
}
|
|
53275
|
-
for (const slug of readKnownGptSlugsFromTomlFile(
|
|
53578
|
+
for (const slug of readKnownGptSlugsFromTomlFile(import_node_path24.default.join(codexHome, "config.toml"))) {
|
|
53276
53579
|
addBridgeModel(
|
|
53277
53580
|
models,
|
|
53278
53581
|
mapBridgeModel({
|
|
@@ -53286,11 +53589,11 @@ function readCodexFallbackModels() {
|
|
|
53286
53589
|
})
|
|
53287
53590
|
);
|
|
53288
53591
|
}
|
|
53289
|
-
const automationsDir =
|
|
53592
|
+
const automationsDir = import_node_path24.default.join(codexHome, "automations");
|
|
53290
53593
|
try {
|
|
53291
|
-
for (const entry of
|
|
53594
|
+
for (const entry of import_node_fs17.default.readdirSync(automationsDir, { withFileTypes: true })) {
|
|
53292
53595
|
if (!entry.isDirectory()) continue;
|
|
53293
|
-
for (const slug of readKnownGptSlugsFromTomlFile(
|
|
53596
|
+
for (const slug of readKnownGptSlugsFromTomlFile(import_node_path24.default.join(automationsDir, entry.name, "automation.toml"))) {
|
|
53294
53597
|
addBridgeModel(
|
|
53295
53598
|
models,
|
|
53296
53599
|
mapBridgeModel({
|
|
@@ -53309,10 +53612,16 @@ function readCodexFallbackModels() {
|
|
|
53309
53612
|
}
|
|
53310
53613
|
return [...models.values()];
|
|
53311
53614
|
}
|
|
53615
|
+
function selfUpdateInboxItemId(offeredVersion) {
|
|
53616
|
+
if (!offeredVersion) return `II-MCPUPD-${(0, import_node_crypto9.randomUUID)()}`;
|
|
53617
|
+
if (/^[A-Za-z0-9._-]+$/.test(offeredVersion)) return `II-MCPUPD-${offeredVersion}`;
|
|
53618
|
+
const hash3 = import_node_crypto9.default.createHash("sha256").update(offeredVersion).digest("hex").slice(0, 10);
|
|
53619
|
+
return `II-MCPUPD-${offeredVersion.replace(/[^A-Za-z0-9._-]/g, "-")}-${hash3}`;
|
|
53620
|
+
}
|
|
53312
53621
|
function neutralCheckoutCwd(stateDir) {
|
|
53313
|
-
const dir =
|
|
53622
|
+
const dir = import_node_path24.default.join(stateDir, "no-checkout");
|
|
53314
53623
|
try {
|
|
53315
|
-
|
|
53624
|
+
import_node_fs17.default.mkdirSync(dir, { recursive: true });
|
|
53316
53625
|
} catch {
|
|
53317
53626
|
}
|
|
53318
53627
|
return dir;
|
|
@@ -53742,7 +54051,7 @@ async function runOrphanWorktreeSweep(client, opts) {
|
|
|
53742
54051
|
const cutoff = Date.now() - worktreeRetentionMs();
|
|
53743
54052
|
const isReapable = (worktreePath) => {
|
|
53744
54053
|
try {
|
|
53745
|
-
return
|
|
54054
|
+
return import_node_fs17.default.statSync(worktreePath).mtimeMs < cutoff;
|
|
53746
54055
|
} catch {
|
|
53747
54056
|
return false;
|
|
53748
54057
|
}
|
|
@@ -53780,8 +54089,8 @@ async function runOrphanWorktreeSweep(client, opts) {
|
|
|
53780
54089
|
}
|
|
53781
54090
|
}
|
|
53782
54091
|
function readStateDir() {
|
|
53783
|
-
if (process.env.CODEX_HOME) return
|
|
53784
|
-
return
|
|
54092
|
+
if (process.env.CODEX_HOME) return import_node_path24.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge");
|
|
54093
|
+
return import_node_path24.default.join(import_node_os11.default.homedir(), ".mrrlin", "director-bridge");
|
|
53785
54094
|
}
|
|
53786
54095
|
function readAllowedOrigins() {
|
|
53787
54096
|
const raw = (process.env.MRRLIN_DIRECTOR_BRIDGE_ALLOWED_ORIGINS ?? "").trim();
|
|
@@ -53991,7 +54300,7 @@ function describeZeroOutputLimit(signal) {
|
|
|
53991
54300
|
}
|
|
53992
54301
|
function createBridgeMessageHandler(deps) {
|
|
53993
54302
|
const tombstones = deps.tombstones ?? /* @__PURE__ */ new Map();
|
|
53994
|
-
const pendingTurnSessions = /* @__PURE__ */ new Set();
|
|
54303
|
+
const pendingTurnSessions = deps.pendingTurnSessions ?? /* @__PURE__ */ new Set();
|
|
53995
54304
|
return (socket, _request, send, logCtx) => {
|
|
53996
54305
|
const boundSessions = /* @__PURE__ */ new Set();
|
|
53997
54306
|
socket.on("close", () => {
|
|
@@ -54503,6 +54812,10 @@ function createBridgeMessageHandler(deps) {
|
|
|
54503
54812
|
sendForSpan({ type: "bootstrap", models, rateLimits, ...deps.bridgeInstanceId ? { bridgeInstanceId: deps.bridgeInstanceId } : {}, ...bootstrapError ? { error: bootstrapError } : {} });
|
|
54504
54813
|
return;
|
|
54505
54814
|
}
|
|
54815
|
+
if (msg.type === "refresh-codex") {
|
|
54816
|
+
sendForSpan({ type: "codex-refreshed", status: deps.refreshCodex?.() === false ? "busy" : "ok" });
|
|
54817
|
+
return;
|
|
54818
|
+
}
|
|
54506
54819
|
if (msg.type === "resume") {
|
|
54507
54820
|
handleResumeRequest(msg, sendForSpan);
|
|
54508
54821
|
return;
|
|
@@ -54661,6 +54974,7 @@ function createBridgeMessageHandler(deps) {
|
|
|
54661
54974
|
const desiredModel = normalizeModel(msg.model);
|
|
54662
54975
|
const desiredEffort = normalizeReasoningEffort(msg.reasoningEffort);
|
|
54663
54976
|
const resolvedProviderId = turnSeat.id;
|
|
54977
|
+
let startedFreshThread = false;
|
|
54664
54978
|
try {
|
|
54665
54979
|
const startParams = deps.buildStartParams(msg, desiredModel);
|
|
54666
54980
|
if (!thread) {
|
|
@@ -54680,6 +54994,7 @@ function createBridgeMessageHandler(deps) {
|
|
|
54680
54994
|
thread = newThread;
|
|
54681
54995
|
deps.threads.set(directorSessionId, thread);
|
|
54682
54996
|
deps.persistThreads();
|
|
54997
|
+
startedFreshThread = true;
|
|
54683
54998
|
} else {
|
|
54684
54999
|
const existingThread = thread;
|
|
54685
55000
|
const providerMismatch = existingThread.provider !== null && existingThread.provider !== resolvedProviderId;
|
|
@@ -54698,16 +55013,7 @@ function createBridgeMessageHandler(deps) {
|
|
|
54698
55013
|
}
|
|
54699
55014
|
existingThread.threadId = result.threadId;
|
|
54700
55015
|
existingThread.provider = resolvedProviderId;
|
|
54701
|
-
if (!resumed)
|
|
54702
|
-
sendForSpan({
|
|
54703
|
-
type: "event",
|
|
54704
|
-
directorSessionId,
|
|
54705
|
-
event: {
|
|
54706
|
-
type: "error",
|
|
54707
|
-
content: "Previous Director thread expired; started a fresh local thread for this chat."
|
|
54708
|
-
}
|
|
54709
|
-
});
|
|
54710
|
-
}
|
|
55016
|
+
if (!resumed) startedFreshThread = true;
|
|
54711
55017
|
existingThread.model = desiredModel;
|
|
54712
55018
|
existingThread.reasoningEffort = desiredEffort;
|
|
54713
55019
|
}
|
|
@@ -54750,6 +55056,16 @@ function createBridgeMessageHandler(deps) {
|
|
|
54750
55056
|
directorSessionId,
|
|
54751
55057
|
turnId: thread.replay.turnId
|
|
54752
55058
|
});
|
|
55059
|
+
if (startedFreshThread) {
|
|
55060
|
+
sendForSpan({
|
|
55061
|
+
type: "event",
|
|
55062
|
+
directorSessionId,
|
|
55063
|
+
event: {
|
|
55064
|
+
type: "notice",
|
|
55065
|
+
content: "This chat's previous Director thread is gone; continuing on a fresh thread. Earlier context is reconstructed from the bridge log where possible."
|
|
55066
|
+
}
|
|
55067
|
+
});
|
|
55068
|
+
}
|
|
54753
55069
|
const contextFocusTaskId = msg.context?.focusTaskId?.trim();
|
|
54754
55070
|
const contextProjectSlug = msg.context?.projectSlug?.trim();
|
|
54755
55071
|
let answeredQuestions;
|
|
@@ -54922,9 +55238,22 @@ function createBridgeMessageHandler(deps) {
|
|
|
54922
55238
|
if (updateOffer !== null && updateOfferProjectSlug && deps.fileUpdateInboxItem) {
|
|
54923
55239
|
void deps.fileUpdateInboxItem(updateOfferProjectSlug);
|
|
54924
55240
|
}
|
|
54925
|
-
|
|
54926
|
-
|
|
54927
|
-
|
|
55241
|
+
let reseedPrefix = null;
|
|
55242
|
+
if (startedFreshThread && deps.buildReseedPrefix) {
|
|
55243
|
+
const otherBytes = Buffer.byteLength(contextPrefix ?? "", "utf8") + Buffer.byteLength(updateOffer ?? "", "utf8") + Buffer.byteLength(effectiveText, "utf8");
|
|
55244
|
+
try {
|
|
55245
|
+
reseedPrefix = await deps.buildReseedPrefix({
|
|
55246
|
+
directorSessionId,
|
|
55247
|
+
// Client-supplied, so the elements are validated and not just the shape:
|
|
55248
|
+
// this array selects which sessions' log rows get replayed into a prompt.
|
|
55249
|
+
priorSessionIds: Array.isArray(msg.priorSessionIds) ? msg.priorSessionIds.filter((id) => typeof id === "string" && id.length > 0) : [],
|
|
55250
|
+
otherBytes
|
|
55251
|
+
});
|
|
55252
|
+
} catch {
|
|
55253
|
+
reseedPrefix = null;
|
|
55254
|
+
}
|
|
55255
|
+
}
|
|
55256
|
+
const composedPrefix = [reseedPrefix, contextPrefix, updateOffer].filter((part) => typeof part === "string" && part.length > 0).join("\n\n");
|
|
54928
55257
|
const composed = composedPrefix ? `${composedPrefix}
|
|
54929
55258
|
|
|
54930
55259
|
${effectiveText}` : effectiveText;
|
|
@@ -55025,6 +55354,7 @@ function sweepIdleThreads(threads, opts) {
|
|
|
55025
55354
|
const reaped = [];
|
|
55026
55355
|
for (const [directorSessionId, thread] of threads.entries()) {
|
|
55027
55356
|
if (thread.inFlight) continue;
|
|
55357
|
+
if (opts.isPending?.(directorSessionId)) continue;
|
|
55028
55358
|
if (thread.replay && !shouldGc(thread.replay, opts.now, suspendedNow)) continue;
|
|
55029
55359
|
if (thread.supersededReplay && !shouldGc(thread.supersededReplay, opts.now, suspendedNow)) continue;
|
|
55030
55360
|
if (!shouldReapIdleThread(thread, opts.now, suspendedNow, opts.idleThreadTtlMs)) continue;
|
|
@@ -55033,6 +55363,25 @@ function sweepIdleThreads(threads, opts) {
|
|
|
55033
55363
|
}
|
|
55034
55364
|
return reaped;
|
|
55035
55365
|
}
|
|
55366
|
+
function evictOverflowThreads(threads, opts) {
|
|
55367
|
+
if (threads.size <= opts.maxThreads) return [];
|
|
55368
|
+
const suspendedNow = opts.suspendedMs();
|
|
55369
|
+
const evictable = [...threads.entries()].filter(([directorSessionId, thread]) => {
|
|
55370
|
+
if (thread.inFlight) return false;
|
|
55371
|
+
if (opts.isPending?.(directorSessionId)) return false;
|
|
55372
|
+
if (thread.replay && !shouldGc(thread.replay, opts.now, suspendedNow)) return false;
|
|
55373
|
+
if (thread.supersededReplay && !shouldGc(thread.supersededReplay, opts.now, suspendedNow)) return false;
|
|
55374
|
+
return true;
|
|
55375
|
+
}).sort((a, b) => a[1].lastUsedAt - b[1].lastUsedAt);
|
|
55376
|
+
const overflow = threads.size - opts.maxThreads;
|
|
55377
|
+
const evicted = [];
|
|
55378
|
+
for (const [directorSessionId] of evictable) {
|
|
55379
|
+
if (evicted.length >= overflow) break;
|
|
55380
|
+
threads.delete(directorSessionId);
|
|
55381
|
+
evicted.push(directorSessionId);
|
|
55382
|
+
}
|
|
55383
|
+
return evicted;
|
|
55384
|
+
}
|
|
55036
55385
|
function sweepReplayBuffers(threads, tombstones, opts) {
|
|
55037
55386
|
const suspendedNow = opts.suspendedMs();
|
|
55038
55387
|
let retainedBuffers = 0;
|
|
@@ -55074,8 +55423,25 @@ function parseConfig() {
|
|
|
55074
55423
|
const token = readOrCreateBridgeToken(stateDir);
|
|
55075
55424
|
const codexCwd = process.env.MRRLIN_DIRECTOR_BRIDGE_CODEX_CWD?.trim() || void 0;
|
|
55076
55425
|
const codexExecutable = process.env.MRRLIN_DIRECTOR_BRIDGE_CODEX_BIN?.trim() || void 0;
|
|
55077
|
-
const idleThreadTtlMs = Math.max(6e4, readEnvInt("MRRLIN_DIRECTOR_BRIDGE_IDLE_TTL_SECONDS",
|
|
55078
|
-
|
|
55426
|
+
const idleThreadTtlMs = Math.max(6e4, readEnvInt("MRRLIN_DIRECTOR_BRIDGE_IDLE_TTL_SECONDS", 172800) * 1e3);
|
|
55427
|
+
const maxThreads = Math.max(1, readEnvInt("MRRLIN_DIRECTOR_BRIDGE_MAX_THREADS", 128));
|
|
55428
|
+
const reseedMaxTokens = Math.max(1e3, readEnvInt("MRRLIN_DIRECTOR_BRIDGE_RESEED_MAX_TOKENS", 48e3));
|
|
55429
|
+
const turnMaxTokens = Math.max(reseedMaxTokens, readEnvInt("MRRLIN_DIRECTOR_BRIDGE_TURN_MAX_TOKENS", 64e3));
|
|
55430
|
+
const reseedMinItems = Math.max(0, readEnvInt("MRRLIN_DIRECTOR_BRIDGE_RESEED_MIN_ITEMS", 4));
|
|
55431
|
+
return {
|
|
55432
|
+
host,
|
|
55433
|
+
port,
|
|
55434
|
+
stateDir,
|
|
55435
|
+
allowedOrigins,
|
|
55436
|
+
token,
|
|
55437
|
+
codexCwd,
|
|
55438
|
+
codexExecutable,
|
|
55439
|
+
idleThreadTtlMs,
|
|
55440
|
+
maxThreads,
|
|
55441
|
+
reseedMaxTokens,
|
|
55442
|
+
turnMaxTokens,
|
|
55443
|
+
reseedMinItems
|
|
55444
|
+
};
|
|
55079
55445
|
}
|
|
55080
55446
|
function scanForOtherBridges() {
|
|
55081
55447
|
try {
|
|
@@ -55088,11 +55454,15 @@ function scanForOtherBridges() {
|
|
|
55088
55454
|
return [];
|
|
55089
55455
|
}
|
|
55090
55456
|
}
|
|
55457
|
+
function checkTelemetryDefaultProject(env, warn) {
|
|
55458
|
+
if (env.MRRLIN_TELEMETRY_DEFAULT_PROJECT?.trim()) return;
|
|
55459
|
+
warn(
|
|
55460
|
+
"[mrrlin-mcp director-bridge] MRRLIN_TELEMETRY_DEFAULT_PROJECT is not set \u2014 telemetry for turns with no project-scoped tool call will not be uploaded. Set it in the pm2 ecosystem config to enable unattributed telemetry upload."
|
|
55461
|
+
);
|
|
55462
|
+
}
|
|
55091
55463
|
async function startDirectorBridge() {
|
|
55092
55464
|
const config2 = parseConfig();
|
|
55093
|
-
|
|
55094
|
-
throw new Error("MRRLIN_TELEMETRY_DEFAULT_PROJECT must be set (non-empty) at bridge startup.");
|
|
55095
|
-
}
|
|
55465
|
+
checkTelemetryDefaultProject(process.env, (m) => console.error(m));
|
|
55096
55466
|
const turnLock = createTurnLock();
|
|
55097
55467
|
let lastTurnEndedAt = Date.now();
|
|
55098
55468
|
const wrappedTurnLock = {
|
|
@@ -55229,8 +55599,8 @@ async function startDirectorBridge() {
|
|
|
55229
55599
|
codexCwd: config2.codexCwd,
|
|
55230
55600
|
codexExecutable: config2.codexExecutable,
|
|
55231
55601
|
checkoutRegistry,
|
|
55232
|
-
worktreeRoot:
|
|
55233
|
-
locksDir:
|
|
55602
|
+
worktreeRoot: import_node_path24.default.join(config2.stateDir, "worktrees"),
|
|
55603
|
+
locksDir: import_node_path24.default.join(config2.stateDir, "locks"),
|
|
55234
55604
|
// Wire the executor server for code-execution runs. Each run gets its own provider process
|
|
55235
55605
|
// (app-server for codex, a resident CLI child for claude) at the run worktree, running
|
|
55236
55606
|
// UNRESTRICTED from the real operator config (owner no-sandbox decision — auth + mrrlin MCP
|
|
@@ -55274,13 +55644,13 @@ async function startDirectorBridge() {
|
|
|
55274
55644
|
// egressDomains is retained in the seam signature (verification-turn.ts still computes the
|
|
55275
55645
|
// env host) but no longer constrains anything — the executor is unrestricted.
|
|
55276
55646
|
startSandbox: async (_egressDomains, providerId) => {
|
|
55277
|
-
const cwd =
|
|
55647
|
+
const cwd = import_node_fs17.default.mkdtempSync(import_node_path24.default.join(import_node_os11.default.tmpdir(), "mrrlin-verify-"));
|
|
55278
55648
|
let executor;
|
|
55279
55649
|
try {
|
|
55280
55650
|
executor = await startExecutorServer({ worktree: cwd, provider: providerId });
|
|
55281
55651
|
} catch (error51) {
|
|
55282
55652
|
try {
|
|
55283
|
-
|
|
55653
|
+
import_node_fs17.default.rmSync(cwd, { recursive: true, force: true });
|
|
55284
55654
|
} catch {
|
|
55285
55655
|
}
|
|
55286
55656
|
throw error51;
|
|
@@ -55291,7 +55661,7 @@ async function startDirectorBridge() {
|
|
|
55291
55661
|
dispose: () => {
|
|
55292
55662
|
executor.dispose();
|
|
55293
55663
|
try {
|
|
55294
|
-
|
|
55664
|
+
import_node_fs17.default.rmSync(cwd, { recursive: true, force: true });
|
|
55295
55665
|
} catch {
|
|
55296
55666
|
}
|
|
55297
55667
|
}
|
|
@@ -55436,21 +55806,98 @@ async function startDirectorBridge() {
|
|
|
55436
55806
|
);
|
|
55437
55807
|
}
|
|
55438
55808
|
};
|
|
55809
|
+
const pendingTurnSessions = /* @__PURE__ */ new Set();
|
|
55439
55810
|
const cleanupTimer = setInterval(() => {
|
|
55811
|
+
const now = Date.now();
|
|
55812
|
+
const isPending = (directorSessionId) => pendingTurnSessions.has(directorSessionId);
|
|
55440
55813
|
const reaped = sweepIdleThreads(threads, {
|
|
55441
|
-
now
|
|
55814
|
+
now,
|
|
55442
55815
|
suspendedMs: () => suspensionDetector.suspendedMs(),
|
|
55443
|
-
idleThreadTtlMs: config2.idleThreadTtlMs
|
|
55816
|
+
idleThreadTtlMs: config2.idleThreadTtlMs,
|
|
55817
|
+
isPending
|
|
55444
55818
|
});
|
|
55445
|
-
|
|
55819
|
+
const evicted = evictOverflowThreads(threads, {
|
|
55820
|
+
now,
|
|
55821
|
+
suspendedMs: () => suspensionDetector.suspendedMs(),
|
|
55822
|
+
maxThreads: config2.maxThreads,
|
|
55823
|
+
isPending
|
|
55824
|
+
});
|
|
55825
|
+
for (const sessionId of reaped) {
|
|
55826
|
+
bridgeLogger.logOut({ spanId: "gc", sessionId, type: "<thread-evicted>", payload: { sessionId, reason: "age" } });
|
|
55827
|
+
}
|
|
55828
|
+
for (const sessionId of evicted) {
|
|
55829
|
+
bridgeLogger.logOut({
|
|
55830
|
+
spanId: "gc",
|
|
55831
|
+
sessionId,
|
|
55832
|
+
type: "<thread-evicted>",
|
|
55833
|
+
payload: { sessionId, reason: "count", mapSize: threads.size, maxThreads: config2.maxThreads }
|
|
55834
|
+
});
|
|
55835
|
+
}
|
|
55836
|
+
if (reaped.length > 0 || evicted.length > 0) persistThreads();
|
|
55446
55837
|
}, 6e4);
|
|
55447
55838
|
cleanupTimer.unref?.();
|
|
55448
55839
|
let remoteRelay = null;
|
|
55449
55840
|
const relayUrl = process.env.MRRLIN_RELAY_URL?.trim();
|
|
55450
55841
|
const relayConfigured = Boolean(agentSecret && relayUrl);
|
|
55842
|
+
const buildReseedPrefix = async (args) => {
|
|
55843
|
+
const refuse = (reason) => {
|
|
55844
|
+
bridgeLogger.logOut({
|
|
55845
|
+
spanId: "reseed",
|
|
55846
|
+
sessionId: args.directorSessionId,
|
|
55847
|
+
type: "<reseed>",
|
|
55848
|
+
payload: { sessionId: args.directorSessionId, refused: reason }
|
|
55849
|
+
});
|
|
55850
|
+
return NO_HISTORY_BLOCK;
|
|
55851
|
+
};
|
|
55852
|
+
if (!resolveBridgeLogEnabled()) return refuse("log-disabled");
|
|
55853
|
+
if (!resolvePromptsEnabled()) return refuse("prompts-not-logged");
|
|
55854
|
+
const retentionWindowMs = readEnvInt("MRRLIN_LOG_RETENTION_AGE_DAYS", 30) * 864e5;
|
|
55855
|
+
const reseedWindowMs = Math.min(config2.idleThreadTtlMs, retentionWindowMs);
|
|
55856
|
+
if (reseedWindowMs < config2.idleThreadTtlMs) {
|
|
55857
|
+
bridgeLogger.logOut({
|
|
55858
|
+
spanId: "reseed",
|
|
55859
|
+
sessionId: args.directorSessionId,
|
|
55860
|
+
type: "<reseed-window-clamped>",
|
|
55861
|
+
payload: {
|
|
55862
|
+
idleThreadTtlMs: config2.idleThreadTtlMs,
|
|
55863
|
+
retentionWindowMs,
|
|
55864
|
+
effectiveWindowMs: reseedWindowMs
|
|
55865
|
+
}
|
|
55866
|
+
});
|
|
55867
|
+
}
|
|
55868
|
+
const files = dayFilesInWindow(/* @__PURE__ */ new Date(), reseedWindowMs);
|
|
55869
|
+
const sessionIds = [args.directorSessionId, ...args.priorSessionIds];
|
|
55870
|
+
const { lines: lines2, missingFiles } = await readSessionRows(import_node_path24.default.join(config2.stateDir, "logs"), files, sessionIds);
|
|
55871
|
+
const { items, skipped: skipped2 } = extractItems(lines2, sessionIds);
|
|
55872
|
+
if (items.length === 0) return refuse("no-rows");
|
|
55873
|
+
const budget = Math.max(0, Math.min(config2.reseedMaxTokens, config2.turnMaxTokens - args.otherBytes));
|
|
55874
|
+
const block = renderReseedBlock(items, {
|
|
55875
|
+
maxTokens: budget,
|
|
55876
|
+
minConversationalItems: config2.reseedMinItems
|
|
55877
|
+
});
|
|
55878
|
+
if (!block) return refuse("below-minimum-after-truncation");
|
|
55879
|
+
bridgeLogger.logOut({
|
|
55880
|
+
spanId: "reseed",
|
|
55881
|
+
sessionId: args.directorSessionId,
|
|
55882
|
+
type: "<reseed>",
|
|
55883
|
+
payload: {
|
|
55884
|
+
sessionId: args.directorSessionId,
|
|
55885
|
+
priorSessionIds: args.priorSessionIds.length,
|
|
55886
|
+
dayFiles: files.length,
|
|
55887
|
+
missingFiles,
|
|
55888
|
+
parseSkips: skipped2,
|
|
55889
|
+
itemCount: block.itemCount,
|
|
55890
|
+
droppedCount: block.droppedCount,
|
|
55891
|
+
estimatedTokens: Buffer.byteLength(block.text, "utf8"),
|
|
55892
|
+
budget
|
|
55893
|
+
}
|
|
55894
|
+
});
|
|
55895
|
+
return block.text;
|
|
55896
|
+
};
|
|
55451
55897
|
const sharedHandlerDeps = {
|
|
55452
55898
|
acquireCodex: (providerId) => agentKeepalive.acquire(providerId),
|
|
55453
55899
|
releaseCodex: (providerId) => agentKeepalive.release(providerId),
|
|
55900
|
+
refreshCodex: () => agentKeepalive.refreshNow(resolveProvider(process.env, getSelectedProvider()).id),
|
|
55454
55901
|
run: wrappedTurnLock.run,
|
|
55455
55902
|
suspendedMs: () => suspensionDetector.suspendedMs(),
|
|
55456
55903
|
buildStartParams: (msg, desiredModel) => buildThreadStartParams(msg, config2, desiredModel),
|
|
@@ -55475,7 +55922,7 @@ async function startDirectorBridge() {
|
|
|
55475
55922
|
fileUpdateInboxItem: async (projectSlug) => {
|
|
55476
55923
|
const body = selfUpdateHandle.updateInboxBody();
|
|
55477
55924
|
if (!body) return;
|
|
55478
|
-
const id =
|
|
55925
|
+
const id = selfUpdateInboxItemId(selfUpdateHandle.getLatestVersion());
|
|
55479
55926
|
try {
|
|
55480
55927
|
const row = await client.createInboxItem(projectSlug, { id, kind: "info", body });
|
|
55481
55928
|
process.stderr.write(
|
|
@@ -55517,13 +55964,21 @@ async function startDirectorBridge() {
|
|
|
55517
55964
|
const bridgeLogger = createBridgeLogger(config2.stateDir, process.env);
|
|
55518
55965
|
let bridgeBinShaShort = "unknown00000";
|
|
55519
55966
|
try {
|
|
55520
|
-
bridgeBinShaShort = import_node_crypto9.default.createHash("sha256").update(
|
|
55967
|
+
bridgeBinShaShort = import_node_crypto9.default.createHash("sha256").update(import_node_fs17.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
|
|
55521
55968
|
} catch {
|
|
55522
55969
|
}
|
|
55523
55970
|
attachBridgeWss(server, {
|
|
55524
55971
|
token: config2.token,
|
|
55525
55972
|
allowedOrigins: config2.allowedOrigins,
|
|
55526
|
-
onReady: createBridgeMessageHandler({
|
|
55973
|
+
onReady: createBridgeMessageHandler({
|
|
55974
|
+
...sharedHandlerDeps,
|
|
55975
|
+
threads,
|
|
55976
|
+
persistThreads,
|
|
55977
|
+
bridgeInstanceId,
|
|
55978
|
+
tombstones,
|
|
55979
|
+
pendingTurnSessions,
|
|
55980
|
+
buildReseedPrefix
|
|
55981
|
+
}),
|
|
55527
55982
|
logger: bridgeLogger,
|
|
55528
55983
|
onPaired: () => health.setPaired(true),
|
|
55529
55984
|
bridgeInstanceId,
|
|
@@ -55644,8 +56099,8 @@ async function startDirectorBridge() {
|
|
|
55644
56099
|
);
|
|
55645
56100
|
void runOrphanWorktreeSweep(client, {
|
|
55646
56101
|
checkoutRegistry,
|
|
55647
|
-
worktreeRoot:
|
|
55648
|
-
locksDir:
|
|
56102
|
+
worktreeRoot: import_node_path24.default.join(config2.stateDir, "worktrees"),
|
|
56103
|
+
locksDir: import_node_path24.default.join(config2.stateDir, "locks")
|
|
55649
56104
|
});
|
|
55650
56105
|
{
|
|
55651
56106
|
const { retainedBuffers, retainedBytes, tombstonesRemoved } = sweepReplayBuffers(threads, tombstones, {
|
|
@@ -55695,10 +56150,24 @@ async function startDirectorBridge() {
|
|
|
55695
56150
|
codexExecutable: config2.codexExecutable,
|
|
55696
56151
|
timeoutMs: readEnvInt("MRRLIN_TELEMETRY_GATE_TIMEOUT_SECONDS", 60) * 1e3
|
|
55697
56152
|
});
|
|
55698
|
-
await prune(config2.stateDir, {
|
|
56153
|
+
const pruneResult = await prune(config2.stateDir, {
|
|
55699
56154
|
ageDays: readEnvInt("MRRLIN_LOG_RETENTION_AGE_DAYS", 30),
|
|
55700
|
-
budgetMb: readEnvInt("MRRLIN_LOG_RETENTION_BUDGET_MB", 1024)
|
|
56155
|
+
budgetMb: readEnvInt("MRRLIN_LOG_RETENTION_BUDGET_MB", 1024),
|
|
56156
|
+
// The reconstruction window's day-files are off limits. Derived from the thread
|
|
56157
|
+
// TTL so the two numbers cannot drift apart.
|
|
56158
|
+
protectedSinceMs: Date.now() - config2.idleThreadTtlMs
|
|
55701
56159
|
});
|
|
56160
|
+
if (pruneResult.budgetOvershootBytes > 0) {
|
|
56161
|
+
bridgeLogger.logOut({
|
|
56162
|
+
spanId: "gc",
|
|
56163
|
+
sessionId: null,
|
|
56164
|
+
type: "<log-budget-overshoot>",
|
|
56165
|
+
payload: {
|
|
56166
|
+
overshootBytes: pruneResult.budgetOvershootBytes,
|
|
56167
|
+
reason: "protected re-seed window not pruned"
|
|
56168
|
+
}
|
|
56169
|
+
});
|
|
56170
|
+
}
|
|
55702
56171
|
} catch (error51) {
|
|
55703
56172
|
bridgeLogger.logOut({
|
|
55704
56173
|
spanId: "gc",
|
|
@@ -55950,15 +56419,15 @@ function readDispatchBody(req) {
|
|
|
55950
56419
|
function readOrCreateBridgeToken(stateDir) {
|
|
55951
56420
|
const explicit = (process.env.MRRLIN_DIRECTOR_BRIDGE_TOKEN ?? "").trim();
|
|
55952
56421
|
if (explicit) return explicit;
|
|
55953
|
-
const tokenPath =
|
|
56422
|
+
const tokenPath = import_node_path24.default.join(stateDir, "token.txt");
|
|
55954
56423
|
try {
|
|
55955
|
-
const existing =
|
|
56424
|
+
const existing = import_node_fs17.default.readFileSync(tokenPath, "utf8").trim();
|
|
55956
56425
|
if (existing) return existing;
|
|
55957
56426
|
} catch {
|
|
55958
56427
|
}
|
|
55959
|
-
|
|
56428
|
+
import_node_fs17.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
|
|
55960
56429
|
const token = import_node_crypto9.default.randomBytes(32).toString("base64url");
|
|
55961
|
-
|
|
56430
|
+
import_node_fs17.default.writeFileSync(tokenPath, `${token}
|
|
55962
56431
|
`, { mode: 384 });
|
|
55963
56432
|
return token;
|
|
55964
56433
|
}
|
|
@@ -59344,15 +59813,15 @@ var StdioServerTransport = class {
|
|
|
59344
59813
|
// src/tools.ts
|
|
59345
59814
|
var import_node_crypto12 = require("node:crypto");
|
|
59346
59815
|
var import_promises10 = require("node:fs/promises");
|
|
59347
|
-
var
|
|
59816
|
+
var import_node_path27 = __toESM(require("node:path"), 1);
|
|
59348
59817
|
var import_node_os12 = __toESM(require("node:os"), 1);
|
|
59349
59818
|
|
|
59350
59819
|
// ../../packages/wiki/dist/index.js
|
|
59351
59820
|
var import_promises8 = __toESM(require("node:fs/promises"), 1);
|
|
59352
|
-
var
|
|
59821
|
+
var import_node_path25 = __toESM(require("node:path"), 1);
|
|
59353
59822
|
var INCLUDED_DOC_FOLDERS = /* @__PURE__ */ new Set(["_meta", "explanation", "how-to", "reference", "sdd", "tutorials"]);
|
|
59354
59823
|
function toPosixPath(input) {
|
|
59355
|
-
return input.split(
|
|
59824
|
+
return input.split(import_node_path25.default.sep).join("/");
|
|
59356
59825
|
}
|
|
59357
59826
|
function slugifyWikiSegment(input) {
|
|
59358
59827
|
return input.trim().toLowerCase().replace(/`/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -59366,12 +59835,12 @@ async function pathExists3(input) {
|
|
|
59366
59835
|
}
|
|
59367
59836
|
}
|
|
59368
59837
|
async function findWorkspaceRoot(start = process.cwd()) {
|
|
59369
|
-
let current2 =
|
|
59838
|
+
let current2 = import_node_path25.default.resolve(start);
|
|
59370
59839
|
while (true) {
|
|
59371
|
-
if (await pathExists3(
|
|
59840
|
+
if (await pathExists3(import_node_path25.default.join(current2, "pnpm-workspace.yaml")) && await pathExists3(import_node_path25.default.join(current2, "docs"))) {
|
|
59372
59841
|
return current2;
|
|
59373
59842
|
}
|
|
59374
|
-
const parent =
|
|
59843
|
+
const parent = import_node_path25.default.dirname(current2);
|
|
59375
59844
|
if (parent === current2) {
|
|
59376
59845
|
throw new Error(`Unable to find Mrrlin workspace root from ${start}`);
|
|
59377
59846
|
}
|
|
@@ -59380,28 +59849,28 @@ async function findWorkspaceRoot(start = process.cwd()) {
|
|
|
59380
59849
|
}
|
|
59381
59850
|
async function resolveDocsRoot(input) {
|
|
59382
59851
|
if (input) {
|
|
59383
|
-
return
|
|
59852
|
+
return import_node_path25.default.resolve(input);
|
|
59384
59853
|
}
|
|
59385
59854
|
if (process.env.MRRLIN_DOCS_ROOT) {
|
|
59386
|
-
return
|
|
59855
|
+
return import_node_path25.default.resolve(process.env.MRRLIN_DOCS_ROOT);
|
|
59387
59856
|
}
|
|
59388
|
-
return
|
|
59857
|
+
return import_node_path25.default.join(await findWorkspaceRoot(), "docs");
|
|
59389
59858
|
}
|
|
59390
59859
|
async function resolveIndexPath(input) {
|
|
59391
59860
|
if (input) {
|
|
59392
|
-
return
|
|
59861
|
+
return import_node_path25.default.resolve(input);
|
|
59393
59862
|
}
|
|
59394
59863
|
if (process.env.MRRLIN_WIKI_INDEX_PATH) {
|
|
59395
|
-
return
|
|
59864
|
+
return import_node_path25.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
|
|
59396
59865
|
}
|
|
59397
59866
|
const workspaceRoot = await findWorkspaceRoot();
|
|
59398
|
-
return
|
|
59867
|
+
return import_node_path25.default.join(workspaceRoot, "apps", "web", "public", "wiki-index.json");
|
|
59399
59868
|
}
|
|
59400
59869
|
async function walkMarkdownFiles(root, dir = root) {
|
|
59401
59870
|
const entries = await import_promises8.default.readdir(dir, { withFileTypes: true });
|
|
59402
59871
|
const files = [];
|
|
59403
59872
|
for (const entry of entries) {
|
|
59404
|
-
const absolute =
|
|
59873
|
+
const absolute = import_node_path25.default.join(dir, entry.name);
|
|
59405
59874
|
if (entry.isDirectory()) {
|
|
59406
59875
|
files.push(...await walkMarkdownFiles(root, absolute));
|
|
59407
59876
|
continue;
|
|
@@ -59420,7 +59889,7 @@ function parseTitle(markdown, sourcePath) {
|
|
|
59420
59889
|
return title;
|
|
59421
59890
|
}
|
|
59422
59891
|
function documentFromFile(docsRoot, absolutePath, markdown) {
|
|
59423
|
-
const relativePath = toPosixPath(
|
|
59892
|
+
const relativePath = toPosixPath(import_node_path25.default.relative(docsRoot, absolutePath));
|
|
59424
59893
|
const [section, fileName] = relativePath.split("/");
|
|
59425
59894
|
if (!section || !fileName || !INCLUDED_DOC_FOLDERS.has(section)) {
|
|
59426
59895
|
return null;
|
|
@@ -60926,17 +61395,17 @@ var intentCheckDescriptor = createIntentCheckDescriptor();
|
|
|
60926
61395
|
|
|
60927
61396
|
// src/evidence/assembler.ts
|
|
60928
61397
|
var import_promises9 = require("node:fs/promises");
|
|
60929
|
-
var
|
|
61398
|
+
var import_node_path26 = require("node:path");
|
|
60930
61399
|
function evidenceDedupKey(sessionId, reportId) {
|
|
60931
61400
|
return `${sessionId}:${reportId}`;
|
|
60932
61401
|
}
|
|
60933
|
-
function
|
|
61402
|
+
function isRecord4(v) {
|
|
60934
61403
|
return v !== null && typeof v === "object";
|
|
60935
61404
|
}
|
|
60936
61405
|
async function readDayLines(stateDir, day, sessionId) {
|
|
60937
61406
|
let raw;
|
|
60938
61407
|
try {
|
|
60939
|
-
raw = await (0, import_promises9.readFile)((0,
|
|
61408
|
+
raw = await (0, import_promises9.readFile)((0, import_node_path26.join)(stateDir, "logs", `bridge-${day}.jsonl`), "utf8");
|
|
60940
61409
|
} catch {
|
|
60941
61410
|
return [];
|
|
60942
61411
|
}
|
|
@@ -60949,7 +61418,7 @@ async function readDayLines(stateDir, day, sessionId) {
|
|
|
60949
61418
|
} catch {
|
|
60950
61419
|
continue;
|
|
60951
61420
|
}
|
|
60952
|
-
if (!
|
|
61421
|
+
if (!isRecord4(rec) || !isRecord4(rec.payload)) continue;
|
|
60953
61422
|
if (rec.payload.directorSessionId !== sessionId) continue;
|
|
60954
61423
|
kept.push(rec);
|
|
60955
61424
|
}
|
|
@@ -61010,7 +61479,7 @@ async function assembleEvidence(stateDir, sessionId, reportId, gateCtx) {
|
|
|
61010
61479
|
}
|
|
61011
61480
|
let windowPruned = false;
|
|
61012
61481
|
try {
|
|
61013
|
-
const raw = await (0, import_promises9.readFile)((0,
|
|
61482
|
+
const raw = await (0, import_promises9.readFile)((0, import_node_path26.join)(stateDir, "logs", ".pruned.jsonl"), "utf8");
|
|
61014
61483
|
outer: for (const line of raw.split("\n")) {
|
|
61015
61484
|
if (!line.trim()) continue;
|
|
61016
61485
|
let rec;
|
|
@@ -61019,7 +61488,7 @@ async function assembleEvidence(stateDir, sessionId, reportId, gateCtx) {
|
|
|
61019
61488
|
} catch {
|
|
61020
61489
|
continue;
|
|
61021
61490
|
}
|
|
61022
|
-
if (!
|
|
61491
|
+
if (!isRecord4(rec) || !Array.isArray(rec.daysRemoved)) continue;
|
|
61023
61492
|
for (const removedDay of rec.daysRemoved) {
|
|
61024
61493
|
if (daysRead.includes(removedDay)) {
|
|
61025
61494
|
windowPruned = true;
|
|
@@ -62743,7 +63212,7 @@ function createMrrlinTools(options) {
|
|
|
62743
63212
|
"ARTIFACT_FILE_UPLOAD_FAILED",
|
|
62744
63213
|
"Unable to upload artifact file.",
|
|
62745
63214
|
async (c, { projectSlug, path: filePath, class: artifactClass, taskId, runId, description }) => {
|
|
62746
|
-
const extension2 =
|
|
63215
|
+
const extension2 = import_node_path27.default.extname(filePath).toLowerCase();
|
|
62747
63216
|
const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
|
|
62748
63217
|
if (!contentType) {
|
|
62749
63218
|
throw new McpToolCodedError(
|
|
@@ -62771,7 +63240,7 @@ function createMrrlinTools(options) {
|
|
|
62771
63240
|
"Artifact exceeds 5MB; split or summarize instead."
|
|
62772
63241
|
);
|
|
62773
63242
|
}
|
|
62774
|
-
const filename =
|
|
63243
|
+
const filename = import_node_path27.default.basename(filePath);
|
|
62775
63244
|
return uploadArtifactBytes(c, {
|
|
62776
63245
|
bytes: bytes3,
|
|
62777
63246
|
class: artifactClass,
|
|
@@ -62796,7 +63265,7 @@ function createMrrlinTools(options) {
|
|
|
62796
63265
|
`Invalid filename '${filename}'; provide a bare filename with no path separators or '..'.`
|
|
62797
63266
|
);
|
|
62798
63267
|
}
|
|
62799
|
-
const extension2 =
|
|
63268
|
+
const extension2 = import_node_path27.default.extname(filename).toLowerCase();
|
|
62800
63269
|
const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
|
|
62801
63270
|
if (!contentType) {
|
|
62802
63271
|
throw new McpToolCodedError(
|
|
@@ -62863,7 +63332,7 @@ function createMrrlinTools(options) {
|
|
|
62863
63332
|
"LOCAL_CHECKOUT_REGISTER_FAILED",
|
|
62864
63333
|
"Unable to register local checkout.",
|
|
62865
63334
|
async (_c, { projectSlug, path: checkoutPath, repo }) => {
|
|
62866
|
-
const stateDir = process.env.CODEX_HOME ?
|
|
63335
|
+
const stateDir = process.env.CODEX_HOME ? import_node_path27.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge") : import_node_path27.default.join(import_node_os12.default.homedir(), ".mrrlin", "director-bridge");
|
|
62867
63336
|
const registry3 = new CheckoutRegistry(stateDir);
|
|
62868
63337
|
const result = registerCheckout(registry3, { projectSlug, path: checkoutPath, repo }, import_node_os12.default.hostname());
|
|
62869
63338
|
if (!result.ok) {
|
|
@@ -63103,7 +63572,7 @@ function runSetCredential(args) {
|
|
|
63103
63572
|
|
|
63104
63573
|
// src/install-service.ts
|
|
63105
63574
|
var import_node_os13 = __toESM(require("node:os"), 1);
|
|
63106
|
-
var
|
|
63575
|
+
var import_node_path28 = __toESM(require("node:path"), 1);
|
|
63107
63576
|
function installService(deps) {
|
|
63108
63577
|
if (!deps.hasSecret()) {
|
|
63109
63578
|
deps.log("No agent credential found. Issue one in Settings, then run: mrrlin-mcp set-credential '<secret>'.");
|
|
@@ -63125,7 +63594,7 @@ function installService(deps) {
|
|
|
63125
63594
|
return { ok: false };
|
|
63126
63595
|
}
|
|
63127
63596
|
const resolvedBins = bins.filter((b) => b !== null);
|
|
63128
|
-
const pathEnv = Array.from(new Set(resolvedBins.map((b) =>
|
|
63597
|
+
const pathEnv = Array.from(new Set(resolvedBins.map((b) => import_node_path28.default.dirname(b)))).join(":");
|
|
63129
63598
|
const apiBaseUrl = deps.env.MRRLIN_API_BASE_URL?.trim() || void 0;
|
|
63130
63599
|
const staging = deps.env.MRRLIN_STAGING === "1" || !apiBaseUrl && bridgeUrlImpliesStaging(deps.env.MRRLIN_BRIDGE_URL);
|
|
63131
63600
|
const text = renderEcosystemConfig({
|
|
@@ -63136,7 +63605,7 @@ function installService(deps) {
|
|
|
63136
63605
|
staging,
|
|
63137
63606
|
apiBaseUrl
|
|
63138
63607
|
});
|
|
63139
|
-
const ecoPath =
|
|
63608
|
+
const ecoPath = import_node_path28.default.join(home, ".mrrlin", "ecosystem.config.cjs");
|
|
63140
63609
|
deps.writeFile(ecoPath, text);
|
|
63141
63610
|
const start = deps.runPm2(["startOrReload", ecoPath]);
|
|
63142
63611
|
if (start.code !== 0) {
|
|
@@ -63148,8 +63617,29 @@ function installService(deps) {
|
|
|
63148
63617
|
deps.log(`pm2 save failed (exit ${save.code}).`);
|
|
63149
63618
|
return { ok: false };
|
|
63150
63619
|
}
|
|
63151
|
-
deps.log(`Service installed (${ecoPath})
|
|
63620
|
+
deps.log(`Service installed (${ecoPath}).`);
|
|
63152
63621
|
deps.runPm2(["startup"]);
|
|
63622
|
+
const hook = deps.bootHookStatus?.();
|
|
63623
|
+
switch (hook?.status) {
|
|
63624
|
+
case void 0:
|
|
63625
|
+
break;
|
|
63626
|
+
case "configured":
|
|
63627
|
+
deps.log(`Boot hook registered (${hook.label}); last run clean.`);
|
|
63628
|
+
break;
|
|
63629
|
+
case "registered_failing":
|
|
63630
|
+
deps.log(
|
|
63631
|
+
`Boot hook registered (${hook.label}) but FAILING - last exit code ${hook.lastExitCode}. The bridge will NOT come back after a reboot. See docs/how-to/run-director-bridge.md.`
|
|
63632
|
+
);
|
|
63633
|
+
break;
|
|
63634
|
+
case "not_configured":
|
|
63635
|
+
deps.log(
|
|
63636
|
+
"No boot hook registered - the bridge will NOT restart after a reboot. See docs/how-to/run-director-bridge.md."
|
|
63637
|
+
);
|
|
63638
|
+
break;
|
|
63639
|
+
case "unknown":
|
|
63640
|
+
deps.log("Boot-hook status not checked on this platform.");
|
|
63641
|
+
break;
|
|
63642
|
+
}
|
|
63153
63643
|
return { ok: true };
|
|
63154
63644
|
}
|
|
63155
63645
|
function uninstallService(deps) {
|
|
@@ -63168,12 +63658,12 @@ function uninstallService(deps) {
|
|
|
63168
63658
|
// src/uninstall-codex.ts
|
|
63169
63659
|
var import_promises11 = __toESM(require("node:fs/promises"), 1);
|
|
63170
63660
|
var import_node_os14 = __toESM(require("node:os"), 1);
|
|
63171
|
-
var
|
|
63661
|
+
var import_node_path29 = __toESM(require("node:path"), 1);
|
|
63172
63662
|
var toml3 = __toESM(require_toml(), 1);
|
|
63173
63663
|
function resolveCodexHome3(options) {
|
|
63174
63664
|
if (options.codexHome) return options.codexHome;
|
|
63175
63665
|
if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
|
|
63176
|
-
return
|
|
63666
|
+
return import_node_path29.default.join(options.homeDir ?? import_node_os14.default.homedir(), ".codex");
|
|
63177
63667
|
}
|
|
63178
63668
|
async function pathExists4(target) {
|
|
63179
63669
|
try {
|
|
@@ -63186,7 +63676,7 @@ async function pathExists4(target) {
|
|
|
63186
63676
|
var MRRLIN_BLOCK_RE = /(^|\n)\[mcp_servers\.(?:mrrlin(?:-browser)?|external-agents)(?:\]|\.[^\]\n]*\])[\s\S]*?(?=\n\[|$)/g;
|
|
63187
63677
|
async function uninstallCodex(options = {}) {
|
|
63188
63678
|
const codexHome = resolveCodexHome3(options);
|
|
63189
|
-
const configPath =
|
|
63679
|
+
const configPath = import_node_path29.default.join(codexHome, "config.toml");
|
|
63190
63680
|
const removePrompts = async () => uninstallPrompts(codexHome, options.promptNames ?? []);
|
|
63191
63681
|
if (!await pathExists4(configPath)) {
|
|
63192
63682
|
return { action: "missing", configPath, prompts: await removePrompts() };
|
|
@@ -63214,10 +63704,10 @@ async function uninstallCodex(options = {}) {
|
|
|
63214
63704
|
}
|
|
63215
63705
|
async function uninstallPrompts(codexHome, names) {
|
|
63216
63706
|
if (names.length === 0) return [];
|
|
63217
|
-
const promptsDir =
|
|
63707
|
+
const promptsDir = import_node_path29.default.join(codexHome, "prompts");
|
|
63218
63708
|
const out = [];
|
|
63219
63709
|
for (const name of names) {
|
|
63220
|
-
const promptPath =
|
|
63710
|
+
const promptPath = import_node_path29.default.join(promptsDir, `${name}.md`);
|
|
63221
63711
|
try {
|
|
63222
63712
|
await import_promises11.default.unlink(promptPath);
|
|
63223
63713
|
out.push({ name, action: "removed", promptPath });
|
|
@@ -63235,7 +63725,7 @@ async function uninstallPrompts(codexHome, names) {
|
|
|
63235
63725
|
|
|
63236
63726
|
// src/extract/command.ts
|
|
63237
63727
|
var import_promises12 = require("node:fs/promises");
|
|
63238
|
-
var
|
|
63728
|
+
var import_node_path30 = require("node:path");
|
|
63239
63729
|
function parseArgs(args) {
|
|
63240
63730
|
const map2 = /* @__PURE__ */ new Map();
|
|
63241
63731
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -63251,7 +63741,7 @@ function parseArgs(args) {
|
|
|
63251
63741
|
}
|
|
63252
63742
|
return map2;
|
|
63253
63743
|
}
|
|
63254
|
-
function
|
|
63744
|
+
function isRecord5(v) {
|
|
63255
63745
|
return v !== null && typeof v === "object";
|
|
63256
63746
|
}
|
|
63257
63747
|
async function runExtract(args, deps) {
|
|
@@ -63272,7 +63762,7 @@ Missing required flag(s): ${missing.join(
|
|
|
63272
63762
|
const days = await findSessionDays(deps.stateDir, sessionId);
|
|
63273
63763
|
const matchingLines = [];
|
|
63274
63764
|
for (const day of days) {
|
|
63275
|
-
const logPath = (0,
|
|
63765
|
+
const logPath = (0, import_node_path30.join)(deps.stateDir, "logs", `bridge-${day}.jsonl`);
|
|
63276
63766
|
let raw;
|
|
63277
63767
|
try {
|
|
63278
63768
|
raw = await (0, import_promises12.readFile)(logPath, "utf8");
|
|
@@ -63288,8 +63778,8 @@ Missing required flag(s): ${missing.join(
|
|
|
63288
63778
|
} catch {
|
|
63289
63779
|
continue;
|
|
63290
63780
|
}
|
|
63291
|
-
const payload =
|
|
63292
|
-
if (
|
|
63781
|
+
const payload = isRecord5(parsed) ? parsed.payload : void 0;
|
|
63782
|
+
if (isRecord5(payload) && payload.directorSessionId === sessionId) {
|
|
63293
63783
|
matchingLines.push(line);
|
|
63294
63784
|
}
|
|
63295
63785
|
}
|
|
@@ -63368,6 +63858,29 @@ function whichBin(bin) {
|
|
|
63368
63858
|
const out = (r.stdout ?? "").trim();
|
|
63369
63859
|
return r.status === 0 && out ? out.split("\n")[0] ?? null : null;
|
|
63370
63860
|
}
|
|
63861
|
+
function bootHookStatus() {
|
|
63862
|
+
if (process.platform !== "darwin") return { status: "unknown" };
|
|
63863
|
+
const uid = process.getuid?.();
|
|
63864
|
+
if (uid === void 0 || uid === 0) return { status: "unknown" };
|
|
63865
|
+
const home = process.env.HOME ?? (0, import_node_os15.homedir)();
|
|
63866
|
+
const agents = import_node_path32.default.join(home, "Library", "LaunchAgents");
|
|
63867
|
+
const candidates = [
|
|
63868
|
+
{ label: "com.mrrlin.director-bridge", plist: import_node_path32.default.join(agents, "com.mrrlin.director-bridge.plist") },
|
|
63869
|
+
{ label: "com.PM2", plist: import_node_path32.default.join(agents, `pm2.${(0, import_node_os15.userInfo)().username}.plist`) }
|
|
63870
|
+
];
|
|
63871
|
+
for (const candidate of candidates) {
|
|
63872
|
+
const printed = (0, import_node_child_process18.spawnSync)("launchctl", ["print", `gui/${uid}/${candidate.label}`], { encoding: "utf8" });
|
|
63873
|
+
if (printed.status !== 0) continue;
|
|
63874
|
+
if (!(0, import_node_fs18.existsSync)(candidate.plist)) continue;
|
|
63875
|
+
const out = printed.stdout ?? "";
|
|
63876
|
+
const runs = /^\s*runs\s*=\s*(\d+)/m.exec(out);
|
|
63877
|
+
const exitCode = /^\s*last exit code\s*=\s*(-?\d+)/m.exec(out);
|
|
63878
|
+
if (!exitCode || runs?.[1] === "0") return { status: "configured", label: candidate.label };
|
|
63879
|
+
const code = Number(exitCode[1]);
|
|
63880
|
+
return code === 0 ? { status: "configured", label: candidate.label } : { status: "registered_failing", label: candidate.label, lastExitCode: code };
|
|
63881
|
+
}
|
|
63882
|
+
return { status: "not_configured" };
|
|
63883
|
+
}
|
|
63371
63884
|
var HELP_TEXT = `mrrlin-mcp - Mrrlin Phase 1 MCP server CLI
|
|
63372
63885
|
|
|
63373
63886
|
Usage:
|
|
@@ -63614,8 +64127,8 @@ async function main() {
|
|
|
63614
64127
|
}
|
|
63615
64128
|
}
|
|
63616
64129
|
try {
|
|
63617
|
-
const codexHome = process.env.CODEX_HOME ??
|
|
63618
|
-
(0,
|
|
64130
|
+
const codexHome = process.env.CODEX_HOME ?? import_node_path32.default.join(process.env.HOME ?? (0, import_node_os15.homedir)(), ".codex");
|
|
64131
|
+
(0, import_node_fs18.rmSync)(import_node_path32.default.join(codexHome, "prompts", "report-issue.md"), { force: true });
|
|
63619
64132
|
} catch {
|
|
63620
64133
|
}
|
|
63621
64134
|
const claudeResult = await installClaude({ binPath, force, serveEnv });
|
|
@@ -63676,12 +64189,13 @@ async function main() {
|
|
|
63676
64189
|
env: process.env,
|
|
63677
64190
|
cwd: process.cwd(),
|
|
63678
64191
|
writeFile: (p, c) => {
|
|
63679
|
-
(0,
|
|
63680
|
-
(0,
|
|
64192
|
+
(0, import_node_fs18.mkdirSync)(import_node_path32.default.dirname(p), { recursive: true, mode: 448 });
|
|
64193
|
+
(0, import_node_fs18.writeFileSync)(p, c, { mode: 384 });
|
|
63681
64194
|
},
|
|
63682
64195
|
runPm2: pm2Runner,
|
|
63683
64196
|
which: whichBin,
|
|
63684
64197
|
hasSecret: () => Boolean(readAgentSecret()),
|
|
64198
|
+
bootHookStatus,
|
|
63685
64199
|
log: (m) => process.stderr.write(`[mrrlin-mcp install-service] ${m}
|
|
63686
64200
|
`)
|
|
63687
64201
|
}).ok;
|
|
@@ -63694,14 +64208,14 @@ async function main() {
|
|
|
63694
64208
|
runPm2: (a) => ({ code: pm2Runner(a).code }),
|
|
63695
64209
|
removeFile: (p) => {
|
|
63696
64210
|
try {
|
|
63697
|
-
(0,
|
|
64211
|
+
(0, import_node_fs18.rmSync)(p, { force: true });
|
|
63698
64212
|
} catch {
|
|
63699
64213
|
}
|
|
63700
64214
|
},
|
|
63701
64215
|
purgeSecret: purge,
|
|
63702
64216
|
secretPath: agentCredentialPath(),
|
|
63703
64217
|
tokenPath: operatorTokenPath(),
|
|
63704
|
-
ecoPath:
|
|
64218
|
+
ecoPath: import_node_path32.default.join(process.env.HOME ?? (0, import_node_os15.homedir)(), ".mrrlin", "ecosystem.config.cjs"),
|
|
63705
64219
|
log: (m) => process.stderr.write(`[mrrlin-mcp uninstall-service] ${m}
|
|
63706
64220
|
`)
|
|
63707
64221
|
});
|
|
@@ -63715,14 +64229,14 @@ async function main() {
|
|
|
63715
64229
|
runPm2: (a) => ({ code: pm2Runner(a).code }),
|
|
63716
64230
|
removeFile: (p) => {
|
|
63717
64231
|
try {
|
|
63718
|
-
(0,
|
|
64232
|
+
(0, import_node_fs18.rmSync)(p, { force: true });
|
|
63719
64233
|
} catch {
|
|
63720
64234
|
}
|
|
63721
64235
|
},
|
|
63722
64236
|
purgeSecret: true,
|
|
63723
64237
|
secretPath: agentCredentialPath(),
|
|
63724
64238
|
tokenPath: operatorTokenPath(),
|
|
63725
|
-
ecoPath:
|
|
64239
|
+
ecoPath: import_node_path32.default.join(home, ".mrrlin", "ecosystem.config.cjs"),
|
|
63726
64240
|
log
|
|
63727
64241
|
});
|
|
63728
64242
|
let codexOk = true;
|
|
@@ -63742,7 +64256,7 @@ async function main() {
|
|
|
63742
64256
|
log(`codex config NOT modified: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
63743
64257
|
}
|
|
63744
64258
|
try {
|
|
63745
|
-
(0,
|
|
64259
|
+
(0, import_node_fs18.rmSync)(import_node_path32.default.join(home, ".mrrlin"), { recursive: true, force: true });
|
|
63746
64260
|
} catch {
|
|
63747
64261
|
}
|
|
63748
64262
|
log("removed ~/.mrrlin");
|
|
@@ -63783,7 +64297,7 @@ ${HELP_TEXT}`);
|
|
|
63783
64297
|
}
|
|
63784
64298
|
}
|
|
63785
64299
|
function resolveSelfBinPath() {
|
|
63786
|
-
return
|
|
64300
|
+
return import_node_path31.default.resolve(process.argv[1] ?? process.execPath);
|
|
63787
64301
|
}
|
|
63788
64302
|
main().catch((error51) => {
|
|
63789
64303
|
process.stderr.write(`mrrlin-mcp fatal error: ${error51 instanceof Error ? error51.message : String(error51)}
|