@mrrlin-dev/mcp 0.4.40 → 0.4.42
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 +616 -266
- package/package.json +4 -4
package/dist/bin.cjs
CHANGED
|
@@ -3008,7 +3008,7 @@ var require_range = __commonJS({
|
|
|
3008
3008
|
parseRange(range) {
|
|
3009
3009
|
const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
|
|
3010
3010
|
const memoKey = memoOpts + ":" + range;
|
|
3011
|
-
const cached2 =
|
|
3011
|
+
const cached2 = cache2.get(memoKey);
|
|
3012
3012
|
if (cached2) {
|
|
3013
3013
|
return cached2;
|
|
3014
3014
|
}
|
|
@@ -3042,7 +3042,7 @@ var require_range = __commonJS({
|
|
|
3042
3042
|
rangeMap.delete("");
|
|
3043
3043
|
}
|
|
3044
3044
|
const result = [...rangeMap.values()];
|
|
3045
|
-
|
|
3045
|
+
cache2.set(memoKey, result);
|
|
3046
3046
|
return result;
|
|
3047
3047
|
}
|
|
3048
3048
|
intersects(range, options) {
|
|
@@ -3081,7 +3081,7 @@ var require_range = __commonJS({
|
|
|
3081
3081
|
};
|
|
3082
3082
|
module2.exports = Range;
|
|
3083
3083
|
var LRU = require_lrucache();
|
|
3084
|
-
var
|
|
3084
|
+
var cache2 = new LRU();
|
|
3085
3085
|
var parseOptions = require_parse_options();
|
|
3086
3086
|
var Comparator = require_comparator();
|
|
3087
3087
|
var debug = require_debug();
|
|
@@ -20644,11 +20644,11 @@ var require_dist = __commonJS({
|
|
|
20644
20644
|
});
|
|
20645
20645
|
|
|
20646
20646
|
// src/bin.ts
|
|
20647
|
-
var
|
|
20647
|
+
var import_node_path34 = __toESM(require("node:path"), 1);
|
|
20648
20648
|
var import_node_child_process18 = require("node:child_process");
|
|
20649
|
-
var
|
|
20650
|
-
var
|
|
20651
|
-
var
|
|
20649
|
+
var import_node_fs22 = require("node:fs");
|
|
20650
|
+
var import_node_os16 = require("node:os");
|
|
20651
|
+
var import_node_path35 = __toESM(require("node:path"), 1);
|
|
20652
20652
|
|
|
20653
20653
|
// src/install-codex.ts
|
|
20654
20654
|
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
@@ -21554,12 +21554,12 @@ async function verifyProviderReadiness(provider, run3, opts = {}) {
|
|
|
21554
21554
|
}
|
|
21555
21555
|
|
|
21556
21556
|
// src/director-bridge.ts
|
|
21557
|
-
var
|
|
21557
|
+
var import_node_fs20 = __toESM(require("node:fs"), 1);
|
|
21558
21558
|
var import_node_http = __toESM(require("node:http"), 1);
|
|
21559
|
-
var
|
|
21560
|
-
var
|
|
21559
|
+
var import_node_os12 = __toESM(require("node:os"), 1);
|
|
21560
|
+
var import_node_path27 = __toESM(require("node:path"), 1);
|
|
21561
21561
|
var import_node_child_process15 = require("node:child_process");
|
|
21562
|
-
var
|
|
21562
|
+
var import_node_crypto11 = __toESM(require("node:crypto"), 1);
|
|
21563
21563
|
|
|
21564
21564
|
// src/turn-replay-buffer.ts
|
|
21565
21565
|
var DEFAULT_MAX_EVENTS = 2e3;
|
|
@@ -36942,6 +36942,7 @@ var openApiOperationIds = {
|
|
|
36942
36942
|
getProviderReadiness: "getProviderReadiness",
|
|
36943
36943
|
putProviderReadiness: "putProviderReadiness",
|
|
36944
36944
|
getConsensusConfig: "getConsensusConfig",
|
|
36945
|
+
getAgentProviderConfig: "getAgentProviderConfig",
|
|
36945
36946
|
updateWikiPageCas: "updateWikiPageCas",
|
|
36946
36947
|
promoteSpecReadyCas: "promoteSpecReadyCas",
|
|
36947
36948
|
recordSpecConsensusReview: "recordSpecConsensusReview",
|
|
@@ -37027,6 +37028,10 @@ var operatorPresenceResponseSchema = external_exports.object({ data: external_ex
|
|
|
37027
37028
|
var operatorPresenceRequestSchema = external_exports.object({ projectSlug: external_exports.string().min(1).optional() }).strict().optional();
|
|
37028
37029
|
var mrrlinConsensusConfigSchema = external_exports.object({ consensusEnabled: external_exports.boolean() });
|
|
37029
37030
|
var consensusConfigResponseSchema = external_exports.object({ data: mrrlinConsensusConfigSchema });
|
|
37031
|
+
var mrrlinAgentProviderConfigSchema = external_exports.object({
|
|
37032
|
+
agentProvider: external_exports.enum(["codex", "claude"])
|
|
37033
|
+
});
|
|
37034
|
+
var agentProviderConfigResponseSchema = external_exports.object({ data: mrrlinAgentProviderConfigSchema });
|
|
37030
37035
|
var agentPoolSnapshotSchema = external_exports.object({
|
|
37031
37036
|
collected_at: external_exports.string(),
|
|
37032
37037
|
status: external_exports.enum(["ok", "unavailable"]),
|
|
@@ -37201,7 +37206,7 @@ var mrrlinAsyncJobRequeueSchema = external_exports.object({
|
|
|
37201
37206
|
});
|
|
37202
37207
|
|
|
37203
37208
|
// ../../packages/schemas/dist/telemetry.js
|
|
37204
|
-
var LOG_PROJECTION_KINDS = ["tool_use", "tool_result", "turn_lifecycle", "plumbing"];
|
|
37209
|
+
var LOG_PROJECTION_KINDS = ["tool_use", "tool_result", "turn_lifecycle", "plumbing", "gate_call"];
|
|
37205
37210
|
var PLUMBING_KINDS = [
|
|
37206
37211
|
"socket_close",
|
|
37207
37212
|
"ready",
|
|
@@ -37267,14 +37272,60 @@ var telemetryRowSchema = external_exports.object({
|
|
|
37267
37272
|
projectionFailures: external_exports.number(),
|
|
37268
37273
|
gateMarker: external_exports.enum(GATE_MARKERS)
|
|
37269
37274
|
});
|
|
37275
|
+
var GATE_KINDS = ["spec", "code", "deliverable"];
|
|
37276
|
+
var GATE_CALL_ROLES = ["head", "arbiter", "reviser", "findings"];
|
|
37277
|
+
var gateCallRecordSchema = external_exports.object({
|
|
37278
|
+
day: external_exports.string(),
|
|
37279
|
+
gate: external_exports.enum(GATE_KINDS),
|
|
37280
|
+
/**
|
|
37281
|
+
* The gate's own round, 1-based. Zero is legal and means "outside the loop": spec-gate.ts makes
|
|
37282
|
+
* one reviser call BEFORE runConsensus is ever entered, and labelling it round 1 would put a
|
|
37283
|
+
* pre-loop call inside a round that had not started.
|
|
37284
|
+
*/
|
|
37285
|
+
round: external_exports.number(),
|
|
37286
|
+
role: external_exports.enum(GATE_CALL_ROLES),
|
|
37287
|
+
/** The persona file driving the call, or null for a role that loads none (the revisers). */
|
|
37288
|
+
persona: external_exports.string().nullable(),
|
|
37289
|
+
/** Null where the call site minted no seat and therefore genuinely does not know — a guessed
|
|
37290
|
+
* provider on a cost record is worse than an absent one. */
|
|
37291
|
+
provider: external_exports.string().nullable(),
|
|
37292
|
+
agentId: external_exports.string().nullable(),
|
|
37293
|
+
inputTokens: external_exports.number().nullable(),
|
|
37294
|
+
cachedInputTokens: external_exports.number().nullable(),
|
|
37295
|
+
cacheWriteInputTokens: external_exports.number().nullable(),
|
|
37296
|
+
outputTokens: external_exports.number().nullable(),
|
|
37297
|
+
durationMs: external_exports.number()
|
|
37298
|
+
});
|
|
37270
37299
|
var telemetryBatchSchema = external_exports.object({
|
|
37271
37300
|
day: external_exports.string(),
|
|
37272
37301
|
bridgeVersion: external_exports.string(),
|
|
37302
|
+
/**
|
|
37303
|
+
* Which installation produced this batch. OPTIONAL on the wire on purpose: a bridge that has not
|
|
37304
|
+
* restarted after deploy still posts batches, and rejecting them would turn a rollout window into
|
|
37305
|
+
* data loss. The API resolves a missing value to the literal installation `legacy`, which is
|
|
37306
|
+
* exactly today's behaviour — one shared slot — so nothing regresses while everything that does
|
|
37307
|
+
* send an id gains its own.
|
|
37308
|
+
*/
|
|
37309
|
+
installationId: external_exports.string().optional(),
|
|
37273
37310
|
knownCrashCount: external_exports.number(),
|
|
37274
37311
|
// pairs still lacking .processed-* after this run completes; a project that never uploads at
|
|
37275
37312
|
// all cannot report its own gap this way — silence is not coverage.
|
|
37276
37313
|
unprocessedPartitions: external_exports.array(external_exports.object({ projectSlug: external_exports.string(), day: external_exports.string() })),
|
|
37277
|
-
rows: external_exports.array(telemetryRowSchema)
|
|
37314
|
+
rows: external_exports.array(telemetryRowSchema),
|
|
37315
|
+
/**
|
|
37316
|
+
* Consensus-gate provider calls for this day. Optional, exactly like `installationId` above and
|
|
37317
|
+
* for the same reason: a bridge that makes no gate call, and every uploader built before this
|
|
37318
|
+
* field existed, must keep producing a valid batch — a rollout window is not allowed to become
|
|
37319
|
+
* data loss.
|
|
37320
|
+
*
|
|
37321
|
+
* `.optional()` rather than `.default([])`, which was tried first. A Zod default splits the
|
|
37322
|
+
* schema's input type from its output type, so the parsed batch would carry a REQUIRED
|
|
37323
|
+
* `gateCalls` while producers do not — and every construction site (the uploader, the store
|
|
37324
|
+
* tests, the ingest tests) would then have to name a field it has no opinion about. An absent
|
|
37325
|
+
* array and an empty one mean the same thing to every reader here, so the split buys nothing and
|
|
37326
|
+
* costs a trap.
|
|
37327
|
+
*/
|
|
37328
|
+
gateCalls: external_exports.array(gateCallRecordSchema).optional()
|
|
37278
37329
|
});
|
|
37279
37330
|
var evidenceStepSchema = external_exports.object({
|
|
37280
37331
|
toolName: external_exports.string(),
|
|
@@ -40039,6 +40090,68 @@ function resolveProvider(env, persisted) {
|
|
|
40039
40090
|
|
|
40040
40091
|
// ../../packages/agent-client/dist/providers/codex/exec.js
|
|
40041
40092
|
var import_node_child_process5 = require("node:child_process");
|
|
40093
|
+
|
|
40094
|
+
// ../../packages/agent-client/dist/exec-usage.js
|
|
40095
|
+
function readCount2(source, ...keys) {
|
|
40096
|
+
for (const key of keys) {
|
|
40097
|
+
const value = source[key];
|
|
40098
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
40099
|
+
return value;
|
|
40100
|
+
}
|
|
40101
|
+
return null;
|
|
40102
|
+
}
|
|
40103
|
+
function fromBlock(block) {
|
|
40104
|
+
const usage = {
|
|
40105
|
+
inputTokens: readCount2(block, "input_tokens", "inputTokens"),
|
|
40106
|
+
cachedInputTokens: readCount2(block, "cached_input_tokens", "cache_read_input_tokens", "cachedInputTokens"),
|
|
40107
|
+
cacheWriteInputTokens: readCount2(block, "cache_write_input_tokens", "cache_creation_input_tokens", "cacheWriteInputTokens"),
|
|
40108
|
+
outputTokens: readCount2(block, "output_tokens", "outputTokens")
|
|
40109
|
+
};
|
|
40110
|
+
const measuredNothing = usage.inputTokens === null && usage.cachedInputTokens === null && usage.cacheWriteInputTokens === null && usage.outputTokens === null;
|
|
40111
|
+
return measuredNothing ? null : usage;
|
|
40112
|
+
}
|
|
40113
|
+
function extractCodexExecUsage(stdout) {
|
|
40114
|
+
let last = null;
|
|
40115
|
+
for (const rawLine of stdout.split(/\r?\n/)) {
|
|
40116
|
+
const line = rawLine.trim();
|
|
40117
|
+
if (!line || line[0] !== "{")
|
|
40118
|
+
continue;
|
|
40119
|
+
let event;
|
|
40120
|
+
try {
|
|
40121
|
+
event = JSON.parse(line);
|
|
40122
|
+
} catch {
|
|
40123
|
+
continue;
|
|
40124
|
+
}
|
|
40125
|
+
if (typeof event !== "object" || event === null)
|
|
40126
|
+
continue;
|
|
40127
|
+
const usage = event.usage;
|
|
40128
|
+
if (typeof usage !== "object" || usage === null)
|
|
40129
|
+
continue;
|
|
40130
|
+
const parsed = fromBlock(usage);
|
|
40131
|
+
if (parsed !== null)
|
|
40132
|
+
last = parsed;
|
|
40133
|
+
}
|
|
40134
|
+
return last;
|
|
40135
|
+
}
|
|
40136
|
+
function extractClaudeExecUsage(parsed) {
|
|
40137
|
+
if (!Array.isArray(parsed))
|
|
40138
|
+
return null;
|
|
40139
|
+
for (let i = parsed.length - 1; i >= 0; i -= 1) {
|
|
40140
|
+
const element = parsed[i];
|
|
40141
|
+
if (typeof element !== "object" || element === null)
|
|
40142
|
+
continue;
|
|
40143
|
+
const record2 = element;
|
|
40144
|
+
if (record2.type !== "result")
|
|
40145
|
+
continue;
|
|
40146
|
+
const usage = record2.usage;
|
|
40147
|
+
if (typeof usage !== "object" || usage === null)
|
|
40148
|
+
return null;
|
|
40149
|
+
return fromBlock(usage);
|
|
40150
|
+
}
|
|
40151
|
+
return null;
|
|
40152
|
+
}
|
|
40153
|
+
|
|
40154
|
+
// ../../packages/agent-client/dist/providers/codex/exec.js
|
|
40042
40155
|
function extractFinalMessage(stdout) {
|
|
40043
40156
|
let last = null;
|
|
40044
40157
|
for (const rawLine of stdout.split(/\r?\n/)) {
|
|
@@ -40159,7 +40272,7 @@ ${input.prompt}` : input.prompt;
|
|
|
40159
40272
|
finish({ ok: false, error: "codex exec produced no parseable assistant message" });
|
|
40160
40273
|
return;
|
|
40161
40274
|
}
|
|
40162
|
-
finish({ ok: true, text });
|
|
40275
|
+
finish({ ok: true, text, usage: extractCodexExecUsage(stdout) });
|
|
40163
40276
|
});
|
|
40164
40277
|
});
|
|
40165
40278
|
}
|
|
@@ -40264,7 +40377,7 @@ function extractOneShotResult(stdout) {
|
|
|
40264
40377
|
if (typeof resultEvent.result !== "string") {
|
|
40265
40378
|
return { ok: false, error: "claude exec's 'result' event had no string result field" };
|
|
40266
40379
|
}
|
|
40267
|
-
return { ok: true, text: resultEvent.result };
|
|
40380
|
+
return { ok: true, text: resultEvent.result, usage: extractClaudeExecUsage(parsed) };
|
|
40268
40381
|
}
|
|
40269
40382
|
function errMessage2(err) {
|
|
40270
40383
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -41397,6 +41510,10 @@ function createMrrlinClient(config2) {
|
|
|
41397
41510
|
const body = await request(`/operator/settings`);
|
|
41398
41511
|
return operatorSettingsGetResponseSchema.parse(body).data;
|
|
41399
41512
|
},
|
|
41513
|
+
async getAgentProviderConfig() {
|
|
41514
|
+
const body = await request(`/operator/agent-provider`);
|
|
41515
|
+
return agentProviderConfigResponseSchema.parse(body).data;
|
|
41516
|
+
},
|
|
41400
41517
|
async updateOperatorSettings(input) {
|
|
41401
41518
|
const body = await request(`/operator/settings`, {
|
|
41402
41519
|
body: JSON.stringify(input),
|
|
@@ -42071,7 +42188,7 @@ Do NOT derail the current task - if the operator has an in-flight question, answ
|
|
|
42071
42188
|
}
|
|
42072
42189
|
|
|
42073
42190
|
// src/_generated/version.ts
|
|
42074
|
-
var PKG_VERSION = "0.4.
|
|
42191
|
+
var PKG_VERSION = "0.4.42";
|
|
42075
42192
|
|
|
42076
42193
|
// src/api-base-url-migrate.ts
|
|
42077
42194
|
var import_node_fs3 = __toESM(require("node:fs"), 1);
|
|
@@ -42101,6 +42218,7 @@ function renderEcosystemConfig(opts) {
|
|
|
42101
42218
|
PATH: opts.pathEnv,
|
|
42102
42219
|
MRRLIN_DIRECTOR_BRIDGE_LOG: "1"
|
|
42103
42220
|
};
|
|
42221
|
+
if (opts.user) env.USER = opts.user;
|
|
42104
42222
|
if (opts.codexHome) env.CODEX_HOME = opts.codexHome;
|
|
42105
42223
|
const retargeted = opts.apiBaseUrl ? retargetRetiredApiBaseUrl(opts.apiBaseUrl).baseUrl : void 0;
|
|
42106
42224
|
if (opts.staging || retargeted && isStagingApiBaseUrl(retargeted)) env.MRRLIN_STAGING = "1";
|
|
@@ -42973,14 +43091,37 @@ async function foldClosedDays(stateDir, today) {
|
|
|
42973
43091
|
|
|
42974
43092
|
// src/telemetry/daily-uploader.ts
|
|
42975
43093
|
var import_promises6 = require("node:fs/promises");
|
|
42976
|
-
var
|
|
43094
|
+
var import_node_path15 = require("node:path");
|
|
42977
43095
|
|
|
42978
43096
|
// src/consensus/wiring.ts
|
|
42979
43097
|
var import_node_crypto4 = __toESM(require("node:crypto"), 1);
|
|
42980
|
-
var
|
|
42981
|
-
var
|
|
43098
|
+
var import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
43099
|
+
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
42982
43100
|
var import_node_url2 = require("node:url");
|
|
42983
43101
|
|
|
43102
|
+
// src/consensus/gate-usage-log.ts
|
|
43103
|
+
var import_node_fs5 = require("node:fs");
|
|
43104
|
+
var import_node_path11 = require("node:path");
|
|
43105
|
+
function recordGateCall(stateDir, projectSlug, record2) {
|
|
43106
|
+
try {
|
|
43107
|
+
const dir = (0, import_node_path11.join)(stateDir, "telemetry");
|
|
43108
|
+
(0, import_node_fs5.mkdirSync)(dir, { recursive: true });
|
|
43109
|
+
(0, import_node_fs5.appendFileSync)((0, import_node_path11.join)(dir, gateFileName(projectSlug, record2.day)), `${JSON.stringify(record2)}
|
|
43110
|
+
`, "utf8");
|
|
43111
|
+
} catch {
|
|
43112
|
+
}
|
|
43113
|
+
}
|
|
43114
|
+
var SAFE_SLUG = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
43115
|
+
function gateFileName(projectSlug, day) {
|
|
43116
|
+
if (!SAFE_SLUG.test(projectSlug)) {
|
|
43117
|
+
throw new Error(`refusing to build a telemetry partition name from an unsafe project slug: ${JSON.stringify(projectSlug)}`);
|
|
43118
|
+
}
|
|
43119
|
+
return `gate-${projectSlug}-${day}.jsonl`;
|
|
43120
|
+
}
|
|
43121
|
+
function telemetryDay(now = /* @__PURE__ */ new Date()) {
|
|
43122
|
+
return now.toISOString().slice(0, 10);
|
|
43123
|
+
}
|
|
43124
|
+
|
|
42984
43125
|
// src/consensus/verdict.ts
|
|
42985
43126
|
var CATEGORIES = [
|
|
42986
43127
|
"correctness",
|
|
@@ -43830,6 +43971,16 @@ ${issuesBlock}`,
|
|
|
43830
43971
|
}
|
|
43831
43972
|
}
|
|
43832
43973
|
|
|
43974
|
+
// src/consensus/sterile-cwd.ts
|
|
43975
|
+
var import_node_fs6 = require("node:fs");
|
|
43976
|
+
var import_node_os6 = require("node:os");
|
|
43977
|
+
var import_node_path12 = require("node:path");
|
|
43978
|
+
var sterileDir = null;
|
|
43979
|
+
function sterileCwd() {
|
|
43980
|
+
sterileDir ??= (0, import_node_fs6.mkdtempSync)((0, import_node_path12.join)((0, import_node_os6.tmpdir)(), "mrrlin-gate-"));
|
|
43981
|
+
return sterileDir;
|
|
43982
|
+
}
|
|
43983
|
+
|
|
43833
43984
|
// src/consensus/code-gate-git.ts
|
|
43834
43985
|
var import_node_child_process8 = require("node:child_process");
|
|
43835
43986
|
var DIFF_MAX_BYTES = 2e5;
|
|
@@ -44062,15 +44213,15 @@ ${res.stdout}${res.stderr}`);
|
|
|
44062
44213
|
var import_meta2 = {};
|
|
44063
44214
|
function getPersonasDir() {
|
|
44064
44215
|
if (typeof __dirname !== "undefined") {
|
|
44065
|
-
return
|
|
44216
|
+
return import_node_path13.default.join(__dirname, "consensus", "personas");
|
|
44066
44217
|
}
|
|
44067
|
-
return
|
|
44218
|
+
return import_node_path13.default.join(import_node_path13.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "personas");
|
|
44068
44219
|
}
|
|
44069
44220
|
var personaCache = /* @__PURE__ */ new Map();
|
|
44070
44221
|
function loadPersona(name) {
|
|
44071
44222
|
const cached2 = personaCache.get(name);
|
|
44072
44223
|
if (cached2 !== void 0) return cached2;
|
|
44073
|
-
const content =
|
|
44224
|
+
const content = import_node_fs7.default.readFileSync(import_node_path13.default.join(getPersonasDir(), `${name}.md`), "utf8");
|
|
44074
44225
|
personaCache.set(name, content);
|
|
44075
44226
|
return content;
|
|
44076
44227
|
}
|
|
@@ -44108,8 +44259,36 @@ function reviserIdentityInstructions(taskId, title) {
|
|
|
44108
44259
|
` : "";
|
|
44109
44260
|
return `${lock}You revise a spec to address accepted issues. Return ONLY the full revised markdown, no commentary.`;
|
|
44110
44261
|
}
|
|
44262
|
+
function gateCallRecorder(args) {
|
|
44263
|
+
let round = 0;
|
|
44264
|
+
let headSinceArbiter = false;
|
|
44265
|
+
return function record2(role, persona, agentId, startedAt, result) {
|
|
44266
|
+
if (role === "head" && !headSinceArbiter) {
|
|
44267
|
+
round += 1;
|
|
44268
|
+
headSinceArbiter = true;
|
|
44269
|
+
}
|
|
44270
|
+
if (role === "arbiter") headSinceArbiter = false;
|
|
44271
|
+
if (args.stateDir === void 0) return;
|
|
44272
|
+
const usage = "usage" in result ? result.usage : null;
|
|
44273
|
+
recordGateCall(args.stateDir, args.projectSlug, {
|
|
44274
|
+
day: telemetryDay(),
|
|
44275
|
+
gate: args.gate,
|
|
44276
|
+
round,
|
|
44277
|
+
role,
|
|
44278
|
+
persona,
|
|
44279
|
+
agentId,
|
|
44280
|
+
provider: args.provider,
|
|
44281
|
+
inputTokens: usage?.inputTokens ?? null,
|
|
44282
|
+
cachedInputTokens: usage?.cachedInputTokens ?? null,
|
|
44283
|
+
cacheWriteInputTokens: usage?.cacheWriteInputTokens ?? null,
|
|
44284
|
+
outputTokens: usage?.outputTokens ?? null,
|
|
44285
|
+
durationMs: Date.now() - startedAt
|
|
44286
|
+
});
|
|
44287
|
+
};
|
|
44288
|
+
}
|
|
44111
44289
|
function buildSpecGateDeps(args) {
|
|
44112
|
-
const { client, projectSlug, specPageId,
|
|
44290
|
+
const { client, projectSlug, specPageId, codexExecutable, extraHeadCount = 0, seat, stateDir } = args;
|
|
44291
|
+
const recordCost = gateCallRecorder({ stateDir, projectSlug, gate: "spec", provider: seat?.id ?? null });
|
|
44113
44292
|
const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
|
|
44114
44293
|
const maxHeadCalls = 2 * rounds * (MAX_DOMAIN_HEADS + extraHeadCount + 2);
|
|
44115
44294
|
const timeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
|
|
@@ -44184,7 +44363,8 @@ function buildSpecGateDeps(args) {
|
|
|
44184
44363
|
const persona = loadPersona(personaName);
|
|
44185
44364
|
const { taskId, title, seed, impact, adjudicated } = await loadIntent();
|
|
44186
44365
|
const intentBlock = specHeadIntentBlock(taskId, title, seed, impact, adjudicated);
|
|
44187
|
-
|
|
44366
|
+
const startedAt = Date.now();
|
|
44367
|
+
const result = await runAgentExec(
|
|
44188
44368
|
{
|
|
44189
44369
|
prompt: `Review this spec against the operator's intent.
|
|
44190
44370
|
|
|
@@ -44193,19 +44373,26 @@ ${dismissed}
|
|
|
44193
44373
|
${intentBlock}--- SPEC ---
|
|
44194
44374
|
${artifact}`,
|
|
44195
44375
|
developerInstructions: persona,
|
|
44196
|
-
|
|
44376
|
+
// Every provider call in this factory runs from the empty per-process directory rather
|
|
44377
|
+
// than the caller's repository — see sterile-cwd.ts for the measurement and the accepted
|
|
44378
|
+
// risk. Nothing in a spec review reads the repository: the artifact and the operator
|
|
44379
|
+
// intent are both in the prompt above.
|
|
44380
|
+
cwd: sterileCwd(),
|
|
44197
44381
|
timeoutMs,
|
|
44198
44382
|
sandbox: "read-only",
|
|
44199
44383
|
codexExecutable
|
|
44200
44384
|
}
|
|
44201
44385
|
);
|
|
44386
|
+
recordCost("head", personaName, null, startedAt, result);
|
|
44387
|
+
return result;
|
|
44202
44388
|
},
|
|
44203
44389
|
async runArbiter(prompt) {
|
|
44204
|
-
|
|
44390
|
+
const startedAt = Date.now();
|
|
44391
|
+
const result = await runAgentExec(
|
|
44205
44392
|
{
|
|
44206
44393
|
prompt,
|
|
44207
44394
|
developerInstructions: loadPersona("arbiter"),
|
|
44208
|
-
cwd,
|
|
44395
|
+
cwd: sterileCwd(),
|
|
44209
44396
|
timeoutMs,
|
|
44210
44397
|
sandbox: "read-only",
|
|
44211
44398
|
codexExecutable,
|
|
@@ -44214,11 +44401,14 @@ ${artifact}`,
|
|
|
44214
44401
|
model: seat?.models.strong
|
|
44215
44402
|
}
|
|
44216
44403
|
);
|
|
44404
|
+
recordCost("arbiter", "arbiter", seat?.models.strong ?? null, startedAt, result);
|
|
44405
|
+
return result;
|
|
44217
44406
|
},
|
|
44218
44407
|
async runReviser(artifact, accepted) {
|
|
44219
44408
|
const acceptedList = accepted.map((a) => `- (${a.category}) ${a.text}`).join("\n");
|
|
44220
44409
|
const { taskId, title } = await loadIntent();
|
|
44221
|
-
|
|
44410
|
+
const startedAt = Date.now();
|
|
44411
|
+
const result = await runAgentExec(
|
|
44222
44412
|
{
|
|
44223
44413
|
prompt: `Accepted issues:
|
|
44224
44414
|
${acceptedList}
|
|
@@ -44226,12 +44416,16 @@ ${acceptedList}
|
|
|
44226
44416
|
--- SPEC ---
|
|
44227
44417
|
${artifact}`,
|
|
44228
44418
|
developerInstructions: reviserIdentityInstructions(taskId, title),
|
|
44229
|
-
|
|
44419
|
+
// Sterile like the rest of this factory: the spec reviser rewrites the markdown it is
|
|
44420
|
+
// handed and returns it, so unlike the CODE gate's reviser it never touches a worktree.
|
|
44421
|
+
cwd: sterileCwd(),
|
|
44230
44422
|
timeoutMs,
|
|
44231
44423
|
sandbox: "read-only",
|
|
44232
44424
|
codexExecutable
|
|
44233
44425
|
}
|
|
44234
44426
|
);
|
|
44427
|
+
recordCost("reviser", null, null, startedAt, result);
|
|
44428
|
+
return result;
|
|
44235
44429
|
},
|
|
44236
44430
|
async casUpdateSpec(markdownBody, expectedHash) {
|
|
44237
44431
|
try {
|
|
@@ -44278,9 +44472,17 @@ ${artifact}`,
|
|
|
44278
44472
|
const rounds2 = r["rounds"];
|
|
44279
44473
|
const history = r["history"];
|
|
44280
44474
|
const highlights = await curateFindings(Array.isArray(history) ? history : [], {
|
|
44281
|
-
|
|
44475
|
+
// Wrapped, not passed raw: this is the one gate provider call that does NOT go through a
|
|
44476
|
+
// `deps.run*` function, so without this the post-gate findings pass would be the single
|
|
44477
|
+
// call the cost record silently omits.
|
|
44478
|
+
runCodexExec: async (input) => {
|
|
44479
|
+
const startedAt = Date.now();
|
|
44480
|
+
const result = await runAgentExec(input);
|
|
44481
|
+
recordCost("findings", "findings-writer", null, startedAt, result);
|
|
44482
|
+
return result;
|
|
44483
|
+
},
|
|
44282
44484
|
loadPersona,
|
|
44283
|
-
cwd,
|
|
44485
|
+
cwd: sterileCwd(),
|
|
44284
44486
|
timeoutMs,
|
|
44285
44487
|
codexExecutable
|
|
44286
44488
|
});
|
|
@@ -44303,7 +44505,8 @@ ${artifact}`,
|
|
|
44303
44505
|
};
|
|
44304
44506
|
}
|
|
44305
44507
|
function buildCodeGateDeps(args) {
|
|
44306
|
-
const { client, projectSlug, baseRef, cwd, codexExecutable, extraHeads, seat } = args;
|
|
44508
|
+
const { client, projectSlug, baseRef, cwd, codexExecutable, extraHeads, seat, stateDir } = args;
|
|
44509
|
+
const recordCost = gateCallRecorder({ stateDir, projectSlug, gate: "code", provider: seat?.id ?? null });
|
|
44307
44510
|
const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
|
|
44308
44511
|
const heads = ["code-reviewer", ...extraHeads ?? []];
|
|
44309
44512
|
const maxHeadCalls = 2 * rounds * (heads.length + 2);
|
|
@@ -44326,7 +44529,8 @@ function buildCodeGateDeps(args) {
|
|
|
44326
44529
|
},
|
|
44327
44530
|
async runHead(personaName, artifact, dismissed) {
|
|
44328
44531
|
const persona = loadPersona(personaName);
|
|
44329
|
-
|
|
44532
|
+
const startedAt = Date.now();
|
|
44533
|
+
const result = await runAgentExec({
|
|
44330
44534
|
prompt: `Review this code diff.
|
|
44331
44535
|
|
|
44332
44536
|
${dismissed}
|
|
@@ -44334,17 +44538,23 @@ ${dismissed}
|
|
|
44334
44538
|
--- DIFF ---
|
|
44335
44539
|
${artifact}`,
|
|
44336
44540
|
developerInstructions: persona,
|
|
44337
|
-
cwd
|
|
44541
|
+
// Read-only review of a diff that is entirely in the prompt — sterile, per sterile-cwd.ts.
|
|
44542
|
+
// This factory is the ONE that stays mixed: runReviser below keeps the real `cwd` because
|
|
44543
|
+
// it edits the branch, and the git helpers keep it because they are not provider calls.
|
|
44544
|
+
cwd: sterileCwd(),
|
|
44338
44545
|
timeoutMs: headTimeoutMs,
|
|
44339
44546
|
sandbox: "read-only",
|
|
44340
44547
|
codexExecutable
|
|
44341
44548
|
});
|
|
44549
|
+
recordCost("head", personaName, null, startedAt, result);
|
|
44550
|
+
return result;
|
|
44342
44551
|
},
|
|
44343
44552
|
async runArbiter(prompt) {
|
|
44344
|
-
|
|
44553
|
+
const startedAt = Date.now();
|
|
44554
|
+
const result = await runAgentExec({
|
|
44345
44555
|
prompt,
|
|
44346
44556
|
developerInstructions: loadPersona("arbiter"),
|
|
44347
|
-
cwd,
|
|
44557
|
+
cwd: sterileCwd(),
|
|
44348
44558
|
timeoutMs: headTimeoutMs,
|
|
44349
44559
|
sandbox: "read-only",
|
|
44350
44560
|
codexExecutable,
|
|
@@ -44352,21 +44562,30 @@ ${artifact}`,
|
|
|
44352
44562
|
// strongest model.
|
|
44353
44563
|
model: seat?.models.strong
|
|
44354
44564
|
});
|
|
44565
|
+
recordCost("arbiter", "arbiter", seat?.models.strong ?? null, startedAt, result);
|
|
44566
|
+
return result;
|
|
44355
44567
|
},
|
|
44356
44568
|
async runReviser(artifact, accepted) {
|
|
44357
44569
|
const acceptedList = accepted.map((a) => `- (${a.category}) ${a.text}`).join("\n");
|
|
44358
|
-
|
|
44570
|
+
const startedAt = Date.now();
|
|
44571
|
+
const result = await runAgentExec({
|
|
44359
44572
|
prompt: `Accepted issues to fix:
|
|
44360
44573
|
${acceptedList}
|
|
44361
44574
|
|
|
44362
44575
|
--- DIFF ---
|
|
44363
44576
|
${artifact}`,
|
|
44364
44577
|
developerInstructions: "You are fixing code review issues. Edit ONLY files already changed in this branch's diff; make the minimal change to resolve each accepted issue. Do not refactor unrelated code. Do not edit files outside the diff.",
|
|
44578
|
+
// The real repository root, NOT sterileCwd(): this is the one gate call that runs
|
|
44579
|
+
// `workspace-write` and edits the branch, so a sterile cwd would point the sandbox at an
|
|
44580
|
+
// empty directory and the revision would silently apply to nothing — the gate would keep
|
|
44581
|
+
// reporting rounds while fixing no code at all.
|
|
44365
44582
|
cwd,
|
|
44366
44583
|
timeoutMs: reviserTimeoutMs,
|
|
44367
44584
|
sandbox: "workspace-write",
|
|
44368
44585
|
codexExecutable
|
|
44369
44586
|
});
|
|
44587
|
+
recordCost("reviser", null, null, startedAt, result);
|
|
44588
|
+
return result;
|
|
44370
44589
|
},
|
|
44371
44590
|
checkpoint() {
|
|
44372
44591
|
return checkpoint(gitArgs);
|
|
@@ -44387,7 +44606,8 @@ function renderCriteriaBlock(criteria) {
|
|
|
44387
44606
|
return criteria.map((c, i) => `${i + 1}. [ ] ${c}`).join("\n");
|
|
44388
44607
|
}
|
|
44389
44608
|
async function buildDeliverableGateDeps(args) {
|
|
44390
|
-
const { client, projectSlug, deliverablePageId, attemptOutcome,
|
|
44609
|
+
const { client, projectSlug, deliverablePageId, attemptOutcome, codexExecutable, runId, seat, stateDir } = args;
|
|
44610
|
+
const recordCost = gateCallRecorder({ stateDir, projectSlug, gate: "deliverable", provider: seat?.id ?? null });
|
|
44391
44611
|
const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
|
|
44392
44612
|
const timeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
|
|
44393
44613
|
const page = await client.getWikiPage(projectSlug, deliverablePageId);
|
|
@@ -44433,7 +44653,8 @@ async function buildDeliverableGateDeps(args) {
|
|
|
44433
44653
|
},
|
|
44434
44654
|
async runHead(personaName, artifact, dismissed) {
|
|
44435
44655
|
const persona = loadPersona(personaName);
|
|
44436
|
-
|
|
44656
|
+
const startedAt = Date.now();
|
|
44657
|
+
const result = await runAgentExec({
|
|
44437
44658
|
prompt: `Score this deliverable ITEM BY ITEM against the acceptance criteria below. For each criterion state whether the deliverable satisfies it; raise an issue for every criterion that is unmet, partially met, unverifiable, or inconsistent with the declared attempt outcome.
|
|
44438
44659
|
|
|
44439
44660
|
${dismissed}
|
|
@@ -44448,17 +44669,23 @@ ${artifact}`,
|
|
|
44448
44669
|
developerInstructions: `${DELIVERABLE_ANTIINJECTION_INSTRUCTION}
|
|
44449
44670
|
|
|
44450
44671
|
${persona}`,
|
|
44451
|
-
cwd
|
|
44672
|
+
// Sterile, like every other provider call in this factory — see sterile-cwd.ts. It also
|
|
44673
|
+
// narrows the anti-injection surface: a deliverable that tries to talk the head into
|
|
44674
|
+
// reading files now has no repository under it to read.
|
|
44675
|
+
cwd: sterileCwd(),
|
|
44452
44676
|
timeoutMs,
|
|
44453
44677
|
sandbox: "read-only",
|
|
44454
44678
|
codexExecutable
|
|
44455
44679
|
});
|
|
44680
|
+
recordCost("head", personaName, null, startedAt, result);
|
|
44681
|
+
return result;
|
|
44456
44682
|
},
|
|
44457
44683
|
async runArbiter(prompt) {
|
|
44458
|
-
|
|
44684
|
+
const startedAt = Date.now();
|
|
44685
|
+
const result = await runAgentExec({
|
|
44459
44686
|
prompt,
|
|
44460
44687
|
developerInstructions: loadPersona("arbiter"),
|
|
44461
|
-
cwd,
|
|
44688
|
+
cwd: sterileCwd(),
|
|
44462
44689
|
timeoutMs,
|
|
44463
44690
|
sandbox: "read-only",
|
|
44464
44691
|
codexExecutable,
|
|
@@ -44466,10 +44693,13 @@ ${persona}`,
|
|
|
44466
44693
|
// strongest model.
|
|
44467
44694
|
model: seat?.models.strong
|
|
44468
44695
|
});
|
|
44696
|
+
recordCost("arbiter", "arbiter", seat?.models.strong ?? null, startedAt, result);
|
|
44697
|
+
return result;
|
|
44469
44698
|
},
|
|
44470
44699
|
async runReviser(artifact, accepted) {
|
|
44471
44700
|
const acceptedList = accepted.map((a) => `- (${a.category}) ${a.text}`).join("\n");
|
|
44472
|
-
|
|
44701
|
+
const startedAt = Date.now();
|
|
44702
|
+
const result = await runAgentExec({
|
|
44473
44703
|
prompt: `Accepted issues to fix (each maps to an unmet acceptance criterion):
|
|
44474
44704
|
${acceptedList}
|
|
44475
44705
|
|
|
@@ -44481,11 +44711,13 @@ ${artifact}`,
|
|
|
44481
44711
|
developerInstructions: `${DELIVERABLE_ANTIINJECTION_INSTRUCTION}
|
|
44482
44712
|
|
|
44483
44713
|
You revise a deliverable to address the accepted issues so it satisfies the acceptance criteria and stays consistent with the declared outcome${attemptOutcome ? ` (${attemptOutcome})` : ""}. Return ONLY the full revised markdown, no commentary. Do not invent facts; keep the deliverable's format and do not change the declared outcome.`,
|
|
44484
|
-
cwd,
|
|
44714
|
+
cwd: sterileCwd(),
|
|
44485
44715
|
timeoutMs,
|
|
44486
44716
|
sandbox: "read-only",
|
|
44487
44717
|
codexExecutable
|
|
44488
44718
|
});
|
|
44719
|
+
recordCost("reviser", null, null, startedAt, result);
|
|
44720
|
+
return result;
|
|
44489
44721
|
},
|
|
44490
44722
|
async casUpdateDeliverable(markdownBody, expectedHash) {
|
|
44491
44723
|
try {
|
|
@@ -44516,7 +44748,7 @@ You revise a deliverable to address the accepted issues so it satisfies the acce
|
|
|
44516
44748
|
const highlights = await curateFindings(Array.isArray(history) ? history : [], {
|
|
44517
44749
|
runCodexExec: runAgentExec,
|
|
44518
44750
|
loadPersona,
|
|
44519
|
-
cwd,
|
|
44751
|
+
cwd: sterileCwd(),
|
|
44520
44752
|
timeoutMs,
|
|
44521
44753
|
codexExecutable
|
|
44522
44754
|
});
|
|
@@ -44639,10 +44871,35 @@ async function gate(artifact, prose, ctx) {
|
|
|
44639
44871
|
return { ok: true, gated: false, artifact: maskedClone };
|
|
44640
44872
|
}
|
|
44641
44873
|
|
|
44874
|
+
// src/telemetry/installation-id.ts
|
|
44875
|
+
var import_node_crypto5 = require("node:crypto");
|
|
44876
|
+
var import_node_fs8 = require("node:fs");
|
|
44877
|
+
var import_node_path14 = require("node:path");
|
|
44878
|
+
var FILE_NAME = "installation-id";
|
|
44879
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
44880
|
+
var cache = /* @__PURE__ */ new Map();
|
|
44881
|
+
function resolveInstallationId(stateDir) {
|
|
44882
|
+
const cached2 = cache.get(stateDir);
|
|
44883
|
+
if (cached2 !== void 0) return cached2;
|
|
44884
|
+
const path22 = (0, import_node_path14.join)(stateDir, FILE_NAME);
|
|
44885
|
+
let id;
|
|
44886
|
+
try {
|
|
44887
|
+
id = (0, import_node_fs8.readFileSync)(path22, "utf8").trim();
|
|
44888
|
+
if (!UUID.test(id)) throw new Error("unusable");
|
|
44889
|
+
} catch {
|
|
44890
|
+
id = (0, import_node_crypto5.randomUUID)();
|
|
44891
|
+
(0, import_node_fs8.mkdirSync)((0, import_node_path14.dirname)(path22), { recursive: true });
|
|
44892
|
+
(0, import_node_fs8.writeFileSync)(path22, `${id}
|
|
44893
|
+
`, "utf8");
|
|
44894
|
+
}
|
|
44895
|
+
cache.set(stateDir, id);
|
|
44896
|
+
return id;
|
|
44897
|
+
}
|
|
44898
|
+
|
|
44642
44899
|
// src/telemetry/daily-uploader.ts
|
|
44643
44900
|
var ROWS_FILE_RE = /^rows-(.+)-(\d{4}-\d{2}-\d{2})\.jsonl$/;
|
|
44644
44901
|
async function uploadPendingDays(stateDir, client, bridgeHealth, gateCtx) {
|
|
44645
|
-
const telemetryDir = (0,
|
|
44902
|
+
const telemetryDir = (0, import_node_path15.join)(stateDir, "telemetry");
|
|
44646
44903
|
let files;
|
|
44647
44904
|
try {
|
|
44648
44905
|
files = await (0, import_promises6.readdir)(telemetryDir);
|
|
@@ -44655,11 +44912,11 @@ async function uploadPendingDays(stateDir, client, bridgeHealth, gateCtx) {
|
|
|
44655
44912
|
const match = ROWS_FILE_RE.exec(file2);
|
|
44656
44913
|
if (!match) continue;
|
|
44657
44914
|
const [, projectSlug, day] = match;
|
|
44658
|
-
const markerPath = (0,
|
|
44915
|
+
const markerPath = (0, import_node_path15.join)(telemetryDir, `.processed-${projectSlug}-${day}`);
|
|
44659
44916
|
try {
|
|
44660
44917
|
await (0, import_promises6.access)(markerPath);
|
|
44661
44918
|
} catch {
|
|
44662
|
-
pending.push({ projectSlug, day, rowsPath: (0,
|
|
44919
|
+
pending.push({ projectSlug, day, rowsPath: (0, import_node_path15.join)(telemetryDir, file2), markerPath });
|
|
44663
44920
|
}
|
|
44664
44921
|
}
|
|
44665
44922
|
if (pending.length === 0) return;
|
|
@@ -44667,7 +44924,7 @@ async function uploadPendingDays(stateDir, client, bridgeHealth, gateCtx) {
|
|
|
44667
44924
|
const fullUnprocessed = pending.map((p) => ({ projectSlug: p.projectSlug, day: p.day }));
|
|
44668
44925
|
pending.sort((a, b) => a.day.localeCompare(b.day));
|
|
44669
44926
|
for (const cur of pending) {
|
|
44670
|
-
const failurePath = (0,
|
|
44927
|
+
const failurePath = (0, import_node_path15.join)(telemetryDir, `.failed-${cur.projectSlug}-${cur.day}.json`);
|
|
44671
44928
|
let failureState = null;
|
|
44672
44929
|
try {
|
|
44673
44930
|
const data = await (0, import_promises6.readFile)(failurePath, "utf8");
|
|
@@ -44696,14 +44953,31 @@ async function uploadPendingDays(stateDir, client, bridgeHealth, gateCtx) {
|
|
|
44696
44953
|
} catch {
|
|
44697
44954
|
}
|
|
44698
44955
|
}
|
|
44956
|
+
const gateCalls = [];
|
|
44957
|
+
try {
|
|
44958
|
+
const rawGate = await (0, import_promises6.readFile)((0, import_node_path15.join)(telemetryDir, gateFileName(cur.projectSlug, cur.day)), "utf8");
|
|
44959
|
+
for (const line of rawGate.split("\n")) {
|
|
44960
|
+
if (!line.trim()) continue;
|
|
44961
|
+
try {
|
|
44962
|
+
gateCalls.push(JSON.parse(line));
|
|
44963
|
+
} catch {
|
|
44964
|
+
}
|
|
44965
|
+
}
|
|
44966
|
+
} catch {
|
|
44967
|
+
}
|
|
44699
44968
|
const batch = {
|
|
44700
44969
|
day: cur.day,
|
|
44701
44970
|
bridgeVersion: PKG_VERSION,
|
|
44971
|
+
installationId: resolveInstallationId(stateDir),
|
|
44702
44972
|
knownCrashCount,
|
|
44703
44973
|
unprocessedPartitions: fullUnprocessed.filter(
|
|
44704
44974
|
(p) => !(p.projectSlug === cur.projectSlug && p.day === cur.day)
|
|
44705
44975
|
),
|
|
44706
|
-
rows
|
|
44976
|
+
rows,
|
|
44977
|
+
// Omitted entirely when empty: an absent array and an empty one mean the same thing to
|
|
44978
|
+
// every reader, and not sending the key keeps a gate-free day's batch byte-identical to
|
|
44979
|
+
// what every uploader before this change produced.
|
|
44980
|
+
...gateCalls.length > 0 ? { gateCalls } : {}
|
|
44707
44981
|
};
|
|
44708
44982
|
const gateResult = await gate(batch, [], gateCtx);
|
|
44709
44983
|
const gateMarker = gateResult.gated ? "gated" : "projection-only";
|
|
@@ -45097,8 +45371,8 @@ function setSelectedProvider(value) {
|
|
|
45097
45371
|
|
|
45098
45372
|
// src/execution-consumer.ts
|
|
45099
45373
|
var import_node_child_process12 = require("node:child_process");
|
|
45100
|
-
var
|
|
45101
|
-
var
|
|
45374
|
+
var import_node_crypto7 = __toESM(require("node:crypto"), 1);
|
|
45375
|
+
var import_node_path18 = __toESM(require("node:path"), 1);
|
|
45102
45376
|
var import_node_util = require("node:util");
|
|
45103
45377
|
|
|
45104
45378
|
// src/consensus/deliverable-gate-outcome.ts
|
|
@@ -45168,7 +45442,7 @@ function mapDeliverableGateResult(result) {
|
|
|
45168
45442
|
}
|
|
45169
45443
|
|
|
45170
45444
|
// src/async-tools/draft-spec.ts
|
|
45171
|
-
var
|
|
45445
|
+
var import_node_crypto6 = require("node:crypto");
|
|
45172
45446
|
var DRAFT_SPEC_TOOL_NAME = "draft_task_spec";
|
|
45173
45447
|
var SPECS_FOLDER = "Specs";
|
|
45174
45448
|
var DRAFT_SPEC_TLDR_MAX_CHARS = 300;
|
|
@@ -45663,7 +45937,7 @@ function onComplete(outcome, input) {
|
|
|
45663
45937
|
};
|
|
45664
45938
|
}
|
|
45665
45939
|
const summary = outcome.error;
|
|
45666
|
-
const hash3 = (0,
|
|
45940
|
+
const hash3 = (0, import_node_crypto6.createHash)("sha256").update(summary).digest("hex").slice(0, 10);
|
|
45667
45941
|
return {
|
|
45668
45942
|
kind: "info",
|
|
45669
45943
|
id: `II-sched-draft-failed-${input.taskId}-${hash3}`,
|
|
@@ -46394,18 +46668,18 @@ async function awaitTurnWithDeadline(opts) {
|
|
|
46394
46668
|
|
|
46395
46669
|
// src/worktree.ts
|
|
46396
46670
|
var import_node_child_process11 = require("node:child_process");
|
|
46397
|
-
var
|
|
46398
|
-
var
|
|
46399
|
-
var
|
|
46671
|
+
var import_node_fs10 = require("node:fs");
|
|
46672
|
+
var import_node_os7 = require("node:os");
|
|
46673
|
+
var import_node_path17 = require("node:path");
|
|
46400
46674
|
|
|
46401
46675
|
// src/checkout-lock.ts
|
|
46402
|
-
var
|
|
46403
|
-
var
|
|
46676
|
+
var import_node_fs9 = require("node:fs");
|
|
46677
|
+
var import_node_path16 = require("node:path");
|
|
46404
46678
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
46405
46679
|
async function withCheckoutLock(locksDir, slug, fn) {
|
|
46406
|
-
(0,
|
|
46407
|
-
const target = (0,
|
|
46408
|
-
if (!(0,
|
|
46680
|
+
(0, import_node_fs9.mkdirSync)(locksDir, { recursive: true });
|
|
46681
|
+
const target = (0, import_node_path16.join)(locksDir, `${slug}.lock`);
|
|
46682
|
+
if (!(0, import_node_fs9.existsSync)(target)) (0, import_node_fs9.writeFileSync)(target, "");
|
|
46409
46683
|
const release = await import_proper_lockfile.default.lock(target, {
|
|
46410
46684
|
retries: { retries: 600, factor: 1, minTimeout: 100, maxTimeout: 100 },
|
|
46411
46685
|
stale: 5 * 6e4
|
|
@@ -46430,12 +46704,12 @@ function git(checkout, args) {
|
|
|
46430
46704
|
});
|
|
46431
46705
|
}
|
|
46432
46706
|
async function createRunWorktree(opts) {
|
|
46433
|
-
const worktreePath = (0,
|
|
46707
|
+
const worktreePath = (0, import_node_path17.join)(opts.worktreeRoot, opts.slug, opts.runId);
|
|
46434
46708
|
await withCheckoutLock(opts.locksDir, opts.slug, async () => {
|
|
46435
|
-
(0,
|
|
46709
|
+
(0, import_node_fs10.mkdirSync)(opts.worktreeRoot, { recursive: true });
|
|
46436
46710
|
try {
|
|
46437
46711
|
git(opts.checkout, ["fetch", "origin", opts.defaultBranch]);
|
|
46438
|
-
if (!(0,
|
|
46712
|
+
if (!(0, import_node_fs10.existsSync)(worktreePath)) {
|
|
46439
46713
|
git(opts.checkout, [
|
|
46440
46714
|
"worktree",
|
|
46441
46715
|
"add",
|
|
@@ -46507,15 +46781,15 @@ async function doPushRunBranch(opts, execGit) {
|
|
|
46507
46781
|
if (localConfig.trim()) {
|
|
46508
46782
|
throw new Error(`push aborted: agent-controlled git config present in worktree: ${localConfig.trim().split("\n")[0]}`);
|
|
46509
46783
|
}
|
|
46510
|
-
const dir = (0,
|
|
46511
|
-
const askpass = (0,
|
|
46784
|
+
const dir = (0, import_node_fs10.mkdtempSync)((0, import_node_path17.join)((0, import_node_os7.tmpdir)(), "mrrlin-push-"));
|
|
46785
|
+
const askpass = (0, import_node_path17.join)(dir, "askpass");
|
|
46512
46786
|
try {
|
|
46513
|
-
(0,
|
|
46787
|
+
(0, import_node_fs10.writeFileSync)(
|
|
46514
46788
|
askpass,
|
|
46515
46789
|
'#!/bin/sh\ncase "$1" in *[Uu]sername*) printf %s "x-access-token" ;; *) printf %s "$MRRLIN_PUSH_TOKEN" ;; esac\n',
|
|
46516
46790
|
{ mode: 320 }
|
|
46517
46791
|
);
|
|
46518
|
-
(0,
|
|
46792
|
+
(0, import_node_fs10.chmodSync)(askpass, 320);
|
|
46519
46793
|
execGit(
|
|
46520
46794
|
[
|
|
46521
46795
|
"-C",
|
|
@@ -46534,18 +46808,18 @@ async function doPushRunBranch(opts, execGit) {
|
|
|
46534
46808
|
);
|
|
46535
46809
|
return { pushedSha: localSha };
|
|
46536
46810
|
} finally {
|
|
46537
|
-
(0,
|
|
46811
|
+
(0, import_node_fs10.rmSync)(dir, { recursive: true, force: true });
|
|
46538
46812
|
}
|
|
46539
46813
|
}
|
|
46540
46814
|
async function sweepOrphanWorktrees(opts) {
|
|
46541
46815
|
const reaped = [];
|
|
46542
46816
|
const ownedPrefix = (() => {
|
|
46543
46817
|
try {
|
|
46544
|
-
return (0,
|
|
46818
|
+
return (0, import_node_fs10.realpathSync)(opts.worktreeRoot);
|
|
46545
46819
|
} catch {
|
|
46546
46820
|
return opts.worktreeRoot;
|
|
46547
46821
|
}
|
|
46548
|
-
})() +
|
|
46822
|
+
})() + import_node_path17.sep + opts.slug + import_node_path17.sep;
|
|
46549
46823
|
await withCheckoutLock(opts.locksDir, opts.slug, async () => {
|
|
46550
46824
|
const listing = git(opts.checkout, ["worktree", "list", "--porcelain"]);
|
|
46551
46825
|
for (const block of listing.split("\n\n")) {
|
|
@@ -47065,7 +47339,7 @@ function isBridgeGeneratedArtifact(artifact) {
|
|
|
47065
47339
|
return typeof payload === "object" && payload !== null && "event" in payload;
|
|
47066
47340
|
}
|
|
47067
47341
|
function newArtifactId() {
|
|
47068
|
-
return `EA-${
|
|
47342
|
+
return `EA-${import_node_crypto7.default.randomUUID()}`;
|
|
47069
47343
|
}
|
|
47070
47344
|
var BLAST_RADIUS_FLOOR_PATTERNS = [/^supabase\/migrations\//, /^packages\/db\/src\/schema\.ts$/];
|
|
47071
47345
|
function isBlastRadiusFloorPath(path22) {
|
|
@@ -47307,7 +47581,7 @@ async function driveRun(deps, projectSlug, runId) {
|
|
|
47307
47581
|
if (!claimed) return;
|
|
47308
47582
|
if (!claimed.leaseId) {
|
|
47309
47583
|
await deps.client.createInboxItem(projectSlug, {
|
|
47310
|
-
id: `II-${
|
|
47584
|
+
id: `II-${import_node_crypto7.default.randomUUID()}`,
|
|
47311
47585
|
kind: "handoff",
|
|
47312
47586
|
taskId: claimed.taskId,
|
|
47313
47587
|
body: `Execution run ${runId} was claimed but returned no leaseId. This indicates DB/API corruption and requires operator attention.`
|
|
@@ -48484,7 +48758,7 @@ async function reconcileTaskAwaitingMerge(deps, projectSlug, task, runId, reason
|
|
|
48484
48758
|
}
|
|
48485
48759
|
try {
|
|
48486
48760
|
await deps.client.createInboxItem(projectSlug, {
|
|
48487
|
-
id: `II-${
|
|
48761
|
+
id: `II-${import_node_crypto7.default.randomUUID()}`,
|
|
48488
48762
|
kind: "handoff",
|
|
48489
48763
|
taskId: task.id,
|
|
48490
48764
|
body: `Task ${task.id} (${task.title}) still needs operator follow-up: ${reason}. Mrrlin could not move the task back to Handoff needed automatically.`
|
|
@@ -48519,7 +48793,7 @@ async function notifyOperatorHandoff(deps, projectSlug, task, runId, reason) {
|
|
|
48519
48793
|
}
|
|
48520
48794
|
try {
|
|
48521
48795
|
await deps.client.createInboxItem(projectSlug, {
|
|
48522
|
-
id: `II-${
|
|
48796
|
+
id: `II-${import_node_crypto7.default.randomUUID()}`,
|
|
48523
48797
|
kind: "handoff",
|
|
48524
48798
|
taskId: task.id,
|
|
48525
48799
|
body: `Execution run ${runId} for task ${task.id} (${task.title}) needs operator attention: ${reason}`
|
|
@@ -48659,8 +48933,8 @@ async function runBackstopSweep(deps, drive = (slug, id) => driveRun(deps, slug,
|
|
|
48659
48933
|
function isRunRecoverableByThisBridge(run3, worktreeRoot) {
|
|
48660
48934
|
if (!worktreeRoot) return true;
|
|
48661
48935
|
if (!run3.worktreeId) return false;
|
|
48662
|
-
const relative =
|
|
48663
|
-
return relative === "" || relative.length > 0 && !relative.startsWith("..") && !
|
|
48936
|
+
const relative = import_node_path18.default.relative(import_node_path18.default.resolve(worktreeRoot), import_node_path18.default.resolve(run3.worktreeId));
|
|
48937
|
+
return relative === "" || relative.length > 0 && !relative.startsWith("..") && !import_node_path18.default.isAbsolute(relative);
|
|
48664
48938
|
}
|
|
48665
48939
|
async function deployGateHandoff(deps, projectSlug, task, runId, reason, leaseId) {
|
|
48666
48940
|
await deps.client.updateExecutionRun(projectSlug, runId, { status: "failed", finishedAt: (/* @__PURE__ */ new Date()).toISOString(), leaseId: leaseId ?? void 0 }).catch(() => {
|
|
@@ -48678,7 +48952,7 @@ async function deployGateHandoff(deps, projectSlug, task, runId, reason, leaseId
|
|
|
48678
48952
|
}).catch(() => {
|
|
48679
48953
|
});
|
|
48680
48954
|
await deps.client.createInboxItem(projectSlug, {
|
|
48681
|
-
id: `II-${
|
|
48955
|
+
id: `II-${import_node_crypto7.default.randomUUID()}`,
|
|
48682
48956
|
kind: "handoff",
|
|
48683
48957
|
taskId: task.id,
|
|
48684
48958
|
body: `Deploy gate for run ${runId} (task ${task.id} \u2014 ${task.title}) needs operator attention: ${reason}`
|
|
@@ -48697,7 +48971,7 @@ function maxLeaseReclaims() {
|
|
|
48697
48971
|
}
|
|
48698
48972
|
|
|
48699
48973
|
// src/async-job-consumer.ts
|
|
48700
|
-
var
|
|
48974
|
+
var import_node_crypto9 = __toESM(require("node:crypto"), 1);
|
|
48701
48975
|
|
|
48702
48976
|
// src/async-tools/registry.ts
|
|
48703
48977
|
var registry2 = /* @__PURE__ */ new Map();
|
|
@@ -48709,9 +48983,9 @@ function getAsyncToolDescriptor(toolName) {
|
|
|
48709
48983
|
}
|
|
48710
48984
|
|
|
48711
48985
|
// src/bridge-log.ts
|
|
48712
|
-
var
|
|
48986
|
+
var import_node_fs11 = require("node:fs");
|
|
48713
48987
|
var import_promises7 = require("node:fs/promises");
|
|
48714
|
-
var
|
|
48988
|
+
var import_node_path19 = require("node:path");
|
|
48715
48989
|
|
|
48716
48990
|
// src/redact.ts
|
|
48717
48991
|
var REDACTED = "[REDACTED]";
|
|
@@ -48736,7 +49010,7 @@ function redact(input) {
|
|
|
48736
49010
|
}
|
|
48737
49011
|
|
|
48738
49012
|
// src/telemetry/projector.ts
|
|
48739
|
-
var
|
|
49013
|
+
var import_node_crypto8 = require("node:crypto");
|
|
48740
49014
|
function isRecord2(x) {
|
|
48741
49015
|
return typeof x === "object" && x !== null;
|
|
48742
49016
|
}
|
|
@@ -48777,7 +49051,7 @@ function buildProjection(payload, type, ms, telemetry) {
|
|
|
48777
49051
|
if (typeof exitCode === "number") proj.exitCode = exitCode;
|
|
48778
49052
|
const status = tool.status;
|
|
48779
49053
|
if (typeof status === "string" && status.trim() !== "") {
|
|
48780
|
-
proj.statusHash = (0,
|
|
49054
|
+
proj.statusHash = (0, import_node_crypto8.createHash)("sha256").update(status.trim().toLowerCase()).digest("hex").slice(0, 8);
|
|
48781
49055
|
}
|
|
48782
49056
|
return proj;
|
|
48783
49057
|
}
|
|
@@ -48987,14 +49261,14 @@ function resolvePromptsEnabled(env = process.env) {
|
|
|
48987
49261
|
}
|
|
48988
49262
|
function createBridgeLogger(stateDir, env = process.env) {
|
|
48989
49263
|
if (!resolveBridgeLogEnabled(env)) return NOOP_LOGGER;
|
|
48990
|
-
const logsDir = (0,
|
|
49264
|
+
const logsDir = (0, import_node_path19.join)(stateDir, "logs");
|
|
48991
49265
|
try {
|
|
48992
|
-
(0,
|
|
49266
|
+
(0, import_node_fs11.mkdirSync)(logsDir, { recursive: true });
|
|
48993
49267
|
} catch {
|
|
48994
49268
|
return NOOP_LOGGER;
|
|
48995
49269
|
}
|
|
48996
49270
|
const includePrompts = resolvePromptsEnabled(env);
|
|
48997
|
-
const fileFor = () => (0,
|
|
49271
|
+
const fileFor = () => (0, import_node_path19.join)(logsDir, `bridge-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
|
|
48998
49272
|
const MAX_TRACKED_SESSIONS = 64;
|
|
48999
49273
|
const contextSlugBySession = /* @__PURE__ */ new Map();
|
|
49000
49274
|
const rememberContextSlug = (sessionId, payload) => {
|
|
@@ -49035,10 +49309,10 @@ function createBridgeLogger(stateDir, env = process.env) {
|
|
|
49035
49309
|
return { isGap, isNewTurn };
|
|
49036
49310
|
};
|
|
49037
49311
|
const gainDay = (sessionId) => {
|
|
49038
|
-
const sessionsPath = (0,
|
|
49312
|
+
const sessionsPath = (0, import_node_path19.join)(logsDir, ".sessions.json");
|
|
49039
49313
|
let sessionsObj = {};
|
|
49040
49314
|
try {
|
|
49041
|
-
const parsed = JSON.parse((0,
|
|
49315
|
+
const parsed = JSON.parse((0, import_node_fs11.readFileSync)(sessionsPath, "utf8"));
|
|
49042
49316
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) sessionsObj = parsed;
|
|
49043
49317
|
} catch {
|
|
49044
49318
|
sessionsObj = {};
|
|
@@ -49048,8 +49322,8 @@ function createBridgeLogger(stateDir, env = process.env) {
|
|
|
49048
49322
|
if (idsToday.includes(sessionId)) return;
|
|
49049
49323
|
sessionsObj[day] = [...idsToday, sessionId];
|
|
49050
49324
|
const tmpPath = `${sessionsPath}.tmp`;
|
|
49051
|
-
(0,
|
|
49052
|
-
(0,
|
|
49325
|
+
(0, import_node_fs11.writeFileSync)(tmpPath, JSON.stringify(sessionsObj));
|
|
49326
|
+
(0, import_node_fs11.renameSync)(tmpPath, sessionsPath);
|
|
49053
49327
|
};
|
|
49054
49328
|
const write = (dir, rec) => {
|
|
49055
49329
|
try {
|
|
@@ -49140,7 +49414,7 @@ function createBridgeLogger(stateDir, env = process.env) {
|
|
|
49140
49414
|
...recordingObligationUnresolved ? { recordingObligationUnresolved } : {},
|
|
49141
49415
|
...recordingObligationMultiResolve ? { recordingObligationMultiResolve } : {}
|
|
49142
49416
|
}) + "\n";
|
|
49143
|
-
(0,
|
|
49417
|
+
(0, import_node_fs11.appendFileSync)(fileFor(), line);
|
|
49144
49418
|
if (rec.sessionId !== null) gainDay(rec.sessionId);
|
|
49145
49419
|
} catch {
|
|
49146
49420
|
}
|
|
@@ -49153,7 +49427,7 @@ function createBridgeLogger(stateDir, env = process.env) {
|
|
|
49153
49427
|
};
|
|
49154
49428
|
}
|
|
49155
49429
|
async function findSessionDays(stateDir, sessionId) {
|
|
49156
|
-
const sessionsPath = (0,
|
|
49430
|
+
const sessionsPath = (0, import_node_path19.join)(stateDir, "logs", ".sessions.json");
|
|
49157
49431
|
let sessionsObj;
|
|
49158
49432
|
try {
|
|
49159
49433
|
const parsed = JSON.parse(await (0, import_promises7.readFile)(sessionsPath, "utf8"));
|
|
@@ -49285,7 +49559,7 @@ async function driveAsyncJob(deps, projectSlug, jobId) {
|
|
|
49285
49559
|
const delivery = descriptor2.onComplete(outcome, input);
|
|
49286
49560
|
if (!delivery.suppressInbox) {
|
|
49287
49561
|
await deps.client.createInboxItem(projectSlug, {
|
|
49288
|
-
id: delivery.id ?? `II-${
|
|
49562
|
+
id: delivery.id ?? `II-${import_node_crypto9.default.randomUUID()}`,
|
|
49289
49563
|
kind: delivery.kind,
|
|
49290
49564
|
body: delivery.body,
|
|
49291
49565
|
...delivery.taskId ? { taskId: delivery.taskId } : {},
|
|
@@ -49303,13 +49577,13 @@ async function deriveRequestedHash(client, toolName, input) {
|
|
|
49303
49577
|
if (input.requestedHash) return input.requestedHash;
|
|
49304
49578
|
if (toolName === "run_spec_consensus" && input.pageId) {
|
|
49305
49579
|
const page = await client.getWikiPage(input.projectSlug, input.pageId);
|
|
49306
|
-
return page.contentHash ??
|
|
49580
|
+
return page.contentHash ?? import_node_crypto9.default.createHash("sha256").update(page.markdownBody).digest("hex");
|
|
49307
49581
|
}
|
|
49308
49582
|
if (toolName === "draft_task_spec" && input.taskId) {
|
|
49309
49583
|
const task = await client.getTask(input.projectSlug, input.taskId);
|
|
49310
|
-
return task.updatedAt ??
|
|
49584
|
+
return task.updatedAt ?? import_node_crypto9.default.createHash("sha256").update(JSON.stringify(task)).digest("hex");
|
|
49311
49585
|
}
|
|
49312
|
-
return
|
|
49586
|
+
return import_node_crypto9.default.createHash("sha256").update(JSON.stringify(input)).digest("hex");
|
|
49313
49587
|
}
|
|
49314
49588
|
async function runAsyncBackstopSweep(deps, drive = (slug, jobId) => driveAsyncJob(deps, slug, jobId)) {
|
|
49315
49589
|
const projects = await deps.client.listProjects();
|
|
@@ -49587,19 +49861,19 @@ function agentIdleMs(provider) {
|
|
|
49587
49861
|
}
|
|
49588
49862
|
|
|
49589
49863
|
// src/operator-token.ts
|
|
49590
|
-
var
|
|
49591
|
-
var
|
|
49592
|
-
var
|
|
49864
|
+
var import_node_fs12 = require("node:fs");
|
|
49865
|
+
var import_node_os8 = __toESM(require("node:os"), 1);
|
|
49866
|
+
var import_node_path20 = __toESM(require("node:path"), 1);
|
|
49593
49867
|
function operatorDir() {
|
|
49594
|
-
const base = process.env.CODEX_HOME ?
|
|
49868
|
+
const base = process.env.CODEX_HOME ? import_node_path20.default.join(process.env.CODEX_HOME, "mrrlin") : import_node_path20.default.join(import_node_os8.default.homedir(), ".mrrlin");
|
|
49595
49869
|
return base;
|
|
49596
49870
|
}
|
|
49597
49871
|
function operatorTokenPath() {
|
|
49598
|
-
return
|
|
49872
|
+
return import_node_path20.default.join(operatorDir(), "operator-token");
|
|
49599
49873
|
}
|
|
49600
49874
|
function readOperatorToken() {
|
|
49601
49875
|
try {
|
|
49602
|
-
const token = (0,
|
|
49876
|
+
const token = (0, import_node_fs12.readFileSync)(operatorTokenPath(), "utf8").trim();
|
|
49603
49877
|
return token.length > 0 ? token : null;
|
|
49604
49878
|
} catch {
|
|
49605
49879
|
return null;
|
|
@@ -49607,24 +49881,24 @@ function readOperatorToken() {
|
|
|
49607
49881
|
}
|
|
49608
49882
|
function persistOperatorToken(token) {
|
|
49609
49883
|
const dir = operatorDir();
|
|
49610
|
-
(0,
|
|
49611
|
-
(0,
|
|
49884
|
+
(0, import_node_fs12.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
49885
|
+
(0, import_node_fs12.writeFileSync)(operatorTokenPath(), `${token.trim()}
|
|
49612
49886
|
`, { encoding: "utf8", mode: 384 });
|
|
49613
49887
|
}
|
|
49614
49888
|
function agentCredentialPath() {
|
|
49615
|
-
return
|
|
49889
|
+
return import_node_path20.default.join(operatorDir(), "agent-credential");
|
|
49616
49890
|
}
|
|
49617
49891
|
function persistAgentSecret(secret) {
|
|
49618
49892
|
const dir = operatorDir();
|
|
49619
|
-
(0,
|
|
49620
|
-
(0,
|
|
49893
|
+
(0, import_node_fs12.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
49894
|
+
(0, import_node_fs12.writeFileSync)(agentCredentialPath(), `${secret.trim()}
|
|
49621
49895
|
`, { encoding: "utf8", mode: 384 });
|
|
49622
49896
|
}
|
|
49623
49897
|
function readAgentSecret() {
|
|
49624
49898
|
const fromEnv = process.env.MRRLIN_AGENT_SECRET?.trim();
|
|
49625
49899
|
if (fromEnv) return fromEnv;
|
|
49626
49900
|
try {
|
|
49627
|
-
const raw = (0,
|
|
49901
|
+
const raw = (0, import_node_fs12.readFileSync)(agentCredentialPath(), "utf8").trim();
|
|
49628
49902
|
return raw || void 0;
|
|
49629
49903
|
} catch {
|
|
49630
49904
|
return void 0;
|
|
@@ -49632,16 +49906,16 @@ function readAgentSecret() {
|
|
|
49632
49906
|
}
|
|
49633
49907
|
|
|
49634
49908
|
// src/thread-index.ts
|
|
49635
|
-
var
|
|
49636
|
-
var
|
|
49909
|
+
var import_node_fs13 = require("node:fs");
|
|
49910
|
+
var import_node_path21 = __toESM(require("node:path"), 1);
|
|
49637
49911
|
function threadIndexPath(stateDir) {
|
|
49638
|
-
return
|
|
49912
|
+
return import_node_path21.default.join(stateDir, "threads.json");
|
|
49639
49913
|
}
|
|
49640
49914
|
function loadThreadIndex(stateDir, ttlMs, now) {
|
|
49641
49915
|
const result = /* @__PURE__ */ new Map();
|
|
49642
49916
|
let parsed;
|
|
49643
49917
|
try {
|
|
49644
|
-
parsed = JSON.parse((0,
|
|
49918
|
+
parsed = JSON.parse((0, import_node_fs13.readFileSync)(threadIndexPath(stateDir), "utf8"));
|
|
49645
49919
|
} catch {
|
|
49646
49920
|
return result;
|
|
49647
49921
|
}
|
|
@@ -49664,8 +49938,8 @@ function loadThreadIndex(stateDir, ttlMs, now) {
|
|
|
49664
49938
|
return result;
|
|
49665
49939
|
}
|
|
49666
49940
|
function saveThreadIndex(stateDir, entries) {
|
|
49667
|
-
(0,
|
|
49668
|
-
(0,
|
|
49941
|
+
(0, import_node_fs13.mkdirSync)(stateDir, { recursive: true, mode: 448 });
|
|
49942
|
+
(0, import_node_fs13.writeFileSync)(threadIndexPath(stateDir), `${JSON.stringify(Object.fromEntries(entries), null, 2)}
|
|
49669
49943
|
`, {
|
|
49670
49944
|
encoding: "utf8",
|
|
49671
49945
|
mode: 384
|
|
@@ -49800,10 +50074,10 @@ function createToolBusyClock(opts) {
|
|
|
49800
50074
|
}
|
|
49801
50075
|
|
|
49802
50076
|
// src/worker-token.ts
|
|
49803
|
-
var
|
|
49804
|
-
var
|
|
49805
|
-
var
|
|
49806
|
-
var
|
|
50077
|
+
var import_node_crypto10 = require("node:crypto");
|
|
50078
|
+
var import_node_fs14 = require("node:fs");
|
|
50079
|
+
var import_node_os9 = __toESM(require("node:os"), 1);
|
|
50080
|
+
var import_node_path22 = __toESM(require("node:path"), 1);
|
|
49807
50081
|
var DEFAULT_WORKER_PORT = 8792;
|
|
49808
50082
|
function workerPort() {
|
|
49809
50083
|
const raw = process.env.MRRLIN_WORKER_PORT;
|
|
@@ -49812,15 +50086,15 @@ function workerPort() {
|
|
|
49812
50086
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_WORKER_PORT;
|
|
49813
50087
|
}
|
|
49814
50088
|
function workerDir() {
|
|
49815
|
-
const base = process.env.CODEX_HOME ?
|
|
49816
|
-
return
|
|
50089
|
+
const base = process.env.CODEX_HOME ? import_node_path22.default.join(process.env.CODEX_HOME, "mrrlin") : import_node_path22.default.join(import_node_os9.default.homedir(), ".mrrlin");
|
|
50090
|
+
return import_node_path22.default.join(base, "worker");
|
|
49817
50091
|
}
|
|
49818
50092
|
function workerTokenPath() {
|
|
49819
|
-
return
|
|
50093
|
+
return import_node_path22.default.join(workerDir(), "token");
|
|
49820
50094
|
}
|
|
49821
50095
|
function readWorkerToken() {
|
|
49822
50096
|
try {
|
|
49823
|
-
const token = (0,
|
|
50097
|
+
const token = (0, import_node_fs14.readFileSync)(workerTokenPath(), "utf8").trim();
|
|
49824
50098
|
return token.length > 0 ? token : null;
|
|
49825
50099
|
} catch {
|
|
49826
50100
|
return null;
|
|
@@ -49830,18 +50104,18 @@ function readOrCreateWorkerToken() {
|
|
|
49830
50104
|
const existing = readWorkerToken();
|
|
49831
50105
|
if (existing) return existing;
|
|
49832
50106
|
const dir = workerDir();
|
|
49833
|
-
(0,
|
|
49834
|
-
const token = (0,
|
|
49835
|
-
(0,
|
|
50107
|
+
(0, import_node_fs14.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
50108
|
+
const token = (0, import_node_crypto10.randomBytes)(32).toString("hex");
|
|
50109
|
+
(0, import_node_fs14.writeFileSync)(workerTokenPath(), `${token}
|
|
49836
50110
|
`, { encoding: "utf8", mode: 384 });
|
|
49837
50111
|
return token;
|
|
49838
50112
|
}
|
|
49839
50113
|
|
|
49840
50114
|
// src/remote-phone-relay.ts
|
|
49841
50115
|
var import_node_events2 = require("node:events");
|
|
49842
|
-
var
|
|
49843
|
-
var
|
|
49844
|
-
var
|
|
50116
|
+
var import_node_fs15 = require("node:fs");
|
|
50117
|
+
var import_node_os10 = require("node:os");
|
|
50118
|
+
var import_node_path23 = require("node:path");
|
|
49845
50119
|
|
|
49846
50120
|
// ../../node_modules/.pnpm/@noble+hashes@1.3.3/node_modules/@noble/hashes/esm/cryptoNode.js
|
|
49847
50121
|
var nc = __toESM(require("node:crypto"), 1);
|
|
@@ -53412,9 +53686,9 @@ var DirectorRelay = class {
|
|
|
53412
53686
|
|
|
53413
53687
|
// src/remote-phone-relay.ts
|
|
53414
53688
|
function loadOrCreateAgentDeviceKey() {
|
|
53415
|
-
const path22 = (0,
|
|
53689
|
+
const path22 = (0, import_node_path23.join)((0, import_node_os10.homedir)(), ".mrrlin", "agent-device-key");
|
|
53416
53690
|
try {
|
|
53417
|
-
const raw = JSON.parse((0,
|
|
53691
|
+
const raw = JSON.parse((0, import_node_fs15.readFileSync)(path22, "utf8"));
|
|
53418
53692
|
if (typeof raw.priv === "string" && typeof raw.pub === "string") {
|
|
53419
53693
|
return { privateKey: fromBase64Url(raw.priv), publicKey: fromBase64Url(raw.pub) };
|
|
53420
53694
|
}
|
|
@@ -53422,8 +53696,8 @@ function loadOrCreateAgentDeviceKey() {
|
|
|
53422
53696
|
}
|
|
53423
53697
|
const kp = generateIdentityKeyPair();
|
|
53424
53698
|
try {
|
|
53425
|
-
(0,
|
|
53426
|
-
(0,
|
|
53699
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path23.join)((0, import_node_os10.homedir)(), ".mrrlin"), { recursive: true });
|
|
53700
|
+
(0, import_node_fs15.writeFileSync)(
|
|
53427
53701
|
path22,
|
|
53428
53702
|
JSON.stringify({ priv: toBase64Url(kp.privateKey), pub: toBase64Url(kp.publicKey) }),
|
|
53429
53703
|
{ mode: 384 }
|
|
@@ -53432,10 +53706,10 @@ function loadOrCreateAgentDeviceKey() {
|
|
|
53432
53706
|
}
|
|
53433
53707
|
return kp;
|
|
53434
53708
|
}
|
|
53435
|
-
var AGENT_PAIRING_PATH = (0,
|
|
53709
|
+
var AGENT_PAIRING_PATH = (0, import_node_path23.join)((0, import_node_os10.homedir)(), ".mrrlin", "agent-pairing.json");
|
|
53436
53710
|
function loadAgentPairing() {
|
|
53437
53711
|
try {
|
|
53438
|
-
const raw = JSON.parse((0,
|
|
53712
|
+
const raw = JSON.parse((0, import_node_fs15.readFileSync)(AGENT_PAIRING_PATH, "utf8"));
|
|
53439
53713
|
if (typeof raw.channelId === "string" && typeof raw.agentControlSecret === "string" && typeof raw.relayAuth === "string" && typeof raw.peerIdentityKey === "string") {
|
|
53440
53714
|
return {
|
|
53441
53715
|
channelId: raw.channelId,
|
|
@@ -53450,8 +53724,8 @@ function loadAgentPairing() {
|
|
|
53450
53724
|
}
|
|
53451
53725
|
function saveAgentPairing(record2) {
|
|
53452
53726
|
try {
|
|
53453
|
-
(0,
|
|
53454
|
-
(0,
|
|
53727
|
+
(0, import_node_fs15.mkdirSync)((0, import_node_path23.join)((0, import_node_os10.homedir)(), ".mrrlin"), { recursive: true });
|
|
53728
|
+
(0, import_node_fs15.writeFileSync)(AGENT_PAIRING_PATH, JSON.stringify(record2), { mode: 384 });
|
|
53455
53729
|
} catch {
|
|
53456
53730
|
}
|
|
53457
53731
|
}
|
|
@@ -53629,18 +53903,18 @@ async function renderPairingQrSvg(payload) {
|
|
|
53629
53903
|
}
|
|
53630
53904
|
|
|
53631
53905
|
// src/checkout-registry.ts
|
|
53632
|
-
var
|
|
53633
|
-
var
|
|
53906
|
+
var import_node_fs16 = require("node:fs");
|
|
53907
|
+
var import_node_path24 = require("node:path");
|
|
53634
53908
|
var CheckoutRegistry = class {
|
|
53635
53909
|
file;
|
|
53636
53910
|
constructor(stateDir) {
|
|
53637
|
-
this.file = (0,
|
|
53638
|
-
(0,
|
|
53911
|
+
this.file = (0, import_node_path24.join)(stateDir, "checkouts.json");
|
|
53912
|
+
(0, import_node_fs16.mkdirSync)(stateDir, { recursive: true });
|
|
53639
53913
|
}
|
|
53640
53914
|
read() {
|
|
53641
|
-
if (!(0,
|
|
53915
|
+
if (!(0, import_node_fs16.existsSync)(this.file)) return {};
|
|
53642
53916
|
try {
|
|
53643
|
-
return JSON.parse((0,
|
|
53917
|
+
return JSON.parse((0, import_node_fs16.readFileSync)(this.file, "utf8"));
|
|
53644
53918
|
} catch {
|
|
53645
53919
|
return {};
|
|
53646
53920
|
}
|
|
@@ -53651,13 +53925,13 @@ var CheckoutRegistry = class {
|
|
|
53651
53925
|
confirm(slug, path22, now) {
|
|
53652
53926
|
const all = this.read();
|
|
53653
53927
|
all[slug] = { path: path22, confirmedAt: now };
|
|
53654
|
-
(0,
|
|
53928
|
+
(0, import_node_fs16.writeFileSync)(this.file, JSON.stringify(all, null, 2));
|
|
53655
53929
|
}
|
|
53656
53930
|
};
|
|
53657
53931
|
|
|
53658
53932
|
// src/checkout-handlers.ts
|
|
53659
53933
|
var import_node_child_process13 = require("node:child_process");
|
|
53660
|
-
var
|
|
53934
|
+
var import_node_fs17 = require("node:fs");
|
|
53661
53935
|
|
|
53662
53936
|
// src/git-remote-match.ts
|
|
53663
53937
|
function normalizeRemote(url2) {
|
|
@@ -53692,7 +53966,7 @@ function validateCheckoutPath(checkoutPath, repo) {
|
|
|
53692
53966
|
}
|
|
53693
53967
|
let resolvedPath;
|
|
53694
53968
|
try {
|
|
53695
|
-
resolvedPath = (0,
|
|
53969
|
+
resolvedPath = (0, import_node_fs17.realpathSync)(trimmedPath);
|
|
53696
53970
|
} catch {
|
|
53697
53971
|
return {
|
|
53698
53972
|
ok: false,
|
|
@@ -53998,9 +54272,9 @@ function extractVerificationSection(markdown) {
|
|
|
53998
54272
|
}
|
|
53999
54273
|
|
|
54000
54274
|
// src/director-reseed.ts
|
|
54001
|
-
var
|
|
54275
|
+
var import_node_fs18 = require("node:fs");
|
|
54002
54276
|
var import_node_readline = require("node:readline");
|
|
54003
|
-
var
|
|
54277
|
+
var import_node_path25 = require("node:path");
|
|
54004
54278
|
function estimateTokens(s) {
|
|
54005
54279
|
return Buffer.byteLength(s, "utf8");
|
|
54006
54280
|
}
|
|
@@ -54132,9 +54406,9 @@ async function readSessionRows(logsDir, files, sessionIds) {
|
|
|
54132
54406
|
const lines2 = [];
|
|
54133
54407
|
let missingFiles = 0;
|
|
54134
54408
|
for (const f of files) {
|
|
54135
|
-
const filePath = (0,
|
|
54409
|
+
const filePath = (0, import_node_path25.join)(logsDir, f);
|
|
54136
54410
|
try {
|
|
54137
|
-
const stream = (0,
|
|
54411
|
+
const stream = (0, import_node_fs18.createReadStream)(filePath, { encoding: "utf8" });
|
|
54138
54412
|
const rl = (0, import_node_readline.createInterface)({ input: stream, crlfDelay: Infinity });
|
|
54139
54413
|
try {
|
|
54140
54414
|
for await (const line of rl) {
|
|
@@ -54158,18 +54432,18 @@ async function readSessionRows(logsDir, files, sessionIds) {
|
|
|
54158
54432
|
}
|
|
54159
54433
|
|
|
54160
54434
|
// src/external-agents-scrub.ts
|
|
54161
|
-
var
|
|
54162
|
-
var
|
|
54163
|
-
var
|
|
54435
|
+
var import_node_fs19 = __toESM(require("node:fs"), 1);
|
|
54436
|
+
var import_node_os11 = __toESM(require("node:os"), 1);
|
|
54437
|
+
var import_node_path26 = __toESM(require("node:path"), 1);
|
|
54164
54438
|
var REDACTION = "[REDACTED]";
|
|
54165
54439
|
var SHORT_VALUE_THRESHOLD = 8;
|
|
54166
|
-
var KEYS_ENV_PATH = () =>
|
|
54440
|
+
var KEYS_ENV_PATH = () => import_node_path26.default.join(import_node_os11.default.homedir(), ".local", "state", "external-agents", "keys.env");
|
|
54167
54441
|
var keysEnvCache = null;
|
|
54168
54442
|
function readKeysEnv() {
|
|
54169
54443
|
const filePath = KEYS_ENV_PATH();
|
|
54170
54444
|
let mtimeMs = 0;
|
|
54171
54445
|
try {
|
|
54172
|
-
mtimeMs =
|
|
54446
|
+
mtimeMs = import_node_fs19.default.statSync(filePath).mtimeMs;
|
|
54173
54447
|
} catch {
|
|
54174
54448
|
mtimeMs = 0;
|
|
54175
54449
|
}
|
|
@@ -54178,7 +54452,7 @@ function readKeysEnv() {
|
|
|
54178
54452
|
}
|
|
54179
54453
|
const map2 = /* @__PURE__ */ new Map();
|
|
54180
54454
|
try {
|
|
54181
|
-
const content =
|
|
54455
|
+
const content = import_node_fs19.default.readFileSync(filePath, "utf8");
|
|
54182
54456
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
54183
54457
|
const line = rawLine.trim();
|
|
54184
54458
|
if (line === "" || line.startsWith("#")) continue;
|
|
@@ -54596,7 +54870,7 @@ function addBridgeModel(target, model) {
|
|
|
54596
54870
|
}
|
|
54597
54871
|
function readTextIfExists(filePath) {
|
|
54598
54872
|
try {
|
|
54599
|
-
return
|
|
54873
|
+
return import_node_fs20.default.readFileSync(filePath, "utf8");
|
|
54600
54874
|
} catch {
|
|
54601
54875
|
return null;
|
|
54602
54876
|
}
|
|
@@ -54607,9 +54881,9 @@ function readKnownGptSlugsFromTomlFile(filePath) {
|
|
|
54607
54881
|
return Array.from(raw.matchAll(/^\s*model\s*=\s*"([^"]+)"/gm)).map((match) => match[1]?.trim() ?? "").filter(isSelectableModelSlug);
|
|
54608
54882
|
}
|
|
54609
54883
|
function readCodexFallbackModels() {
|
|
54610
|
-
const codexHome = process.env.CODEX_HOME?.trim() ||
|
|
54884
|
+
const codexHome = process.env.CODEX_HOME?.trim() || import_node_path27.default.join(import_node_os12.default.homedir(), ".codex");
|
|
54611
54885
|
const models = /* @__PURE__ */ new Map();
|
|
54612
|
-
const cachePath =
|
|
54886
|
+
const cachePath = import_node_path27.default.join(codexHome, "models_cache.json");
|
|
54613
54887
|
const cacheRaw = readTextIfExists(cachePath);
|
|
54614
54888
|
if (cacheRaw) {
|
|
54615
54889
|
try {
|
|
@@ -54659,7 +54933,7 @@ function readCodexFallbackModels() {
|
|
|
54659
54933
|
);
|
|
54660
54934
|
}
|
|
54661
54935
|
}
|
|
54662
|
-
for (const slug of readKnownGptSlugsFromTomlFile(
|
|
54936
|
+
for (const slug of readKnownGptSlugsFromTomlFile(import_node_path27.default.join(codexHome, "config.toml"))) {
|
|
54663
54937
|
addBridgeModel(
|
|
54664
54938
|
models,
|
|
54665
54939
|
mapBridgeModel({
|
|
@@ -54673,11 +54947,11 @@ function readCodexFallbackModels() {
|
|
|
54673
54947
|
})
|
|
54674
54948
|
);
|
|
54675
54949
|
}
|
|
54676
|
-
const automationsDir =
|
|
54950
|
+
const automationsDir = import_node_path27.default.join(codexHome, "automations");
|
|
54677
54951
|
try {
|
|
54678
|
-
for (const entry of
|
|
54952
|
+
for (const entry of import_node_fs20.default.readdirSync(automationsDir, { withFileTypes: true })) {
|
|
54679
54953
|
if (!entry.isDirectory()) continue;
|
|
54680
|
-
for (const slug of readKnownGptSlugsFromTomlFile(
|
|
54954
|
+
for (const slug of readKnownGptSlugsFromTomlFile(import_node_path27.default.join(automationsDir, entry.name, "automation.toml"))) {
|
|
54681
54955
|
addBridgeModel(
|
|
54682
54956
|
models,
|
|
54683
54957
|
mapBridgeModel({
|
|
@@ -54697,15 +54971,15 @@ function readCodexFallbackModels() {
|
|
|
54697
54971
|
return [...models.values()];
|
|
54698
54972
|
}
|
|
54699
54973
|
function selfUpdateInboxItemId(offeredVersion) {
|
|
54700
|
-
if (!offeredVersion) return `II-MCPUPD-${(0,
|
|
54974
|
+
if (!offeredVersion) return `II-MCPUPD-${(0, import_node_crypto11.randomUUID)()}`;
|
|
54701
54975
|
if (/^[A-Za-z0-9._-]+$/.test(offeredVersion)) return `II-MCPUPD-${offeredVersion}`;
|
|
54702
|
-
const hash3 =
|
|
54976
|
+
const hash3 = import_node_crypto11.default.createHash("sha256").update(offeredVersion).digest("hex").slice(0, 10);
|
|
54703
54977
|
return `II-MCPUPD-${offeredVersion.replace(/[^A-Za-z0-9._-]/g, "-")}-${hash3}`;
|
|
54704
54978
|
}
|
|
54705
54979
|
function neutralCheckoutCwd(stateDir) {
|
|
54706
|
-
const dir =
|
|
54980
|
+
const dir = import_node_path27.default.join(stateDir, "no-checkout");
|
|
54707
54981
|
try {
|
|
54708
|
-
|
|
54982
|
+
import_node_fs20.default.mkdirSync(dir, { recursive: true });
|
|
54709
54983
|
} catch {
|
|
54710
54984
|
}
|
|
54711
54985
|
return dir;
|
|
@@ -55215,7 +55489,7 @@ async function runOrphanWorktreeSweep(client, opts) {
|
|
|
55215
55489
|
const cutoff = Date.now() - worktreeRetentionMs();
|
|
55216
55490
|
const isReapable = (worktreePath) => {
|
|
55217
55491
|
try {
|
|
55218
|
-
return
|
|
55492
|
+
return import_node_fs20.default.statSync(worktreePath).mtimeMs < cutoff;
|
|
55219
55493
|
} catch {
|
|
55220
55494
|
return false;
|
|
55221
55495
|
}
|
|
@@ -55253,8 +55527,8 @@ async function runOrphanWorktreeSweep(client, opts) {
|
|
|
55253
55527
|
}
|
|
55254
55528
|
}
|
|
55255
55529
|
function readStateDir() {
|
|
55256
|
-
if (process.env.CODEX_HOME) return
|
|
55257
|
-
return
|
|
55530
|
+
if (process.env.CODEX_HOME) return import_node_path27.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge");
|
|
55531
|
+
return import_node_path27.default.join(import_node_os12.default.homedir(), ".mrrlin", "director-bridge");
|
|
55258
55532
|
}
|
|
55259
55533
|
function readAllowedOrigins() {
|
|
55260
55534
|
const raw = (process.env.MRRLIN_DIRECTOR_BRIDGE_ALLOWED_ORIGINS ?? "").trim();
|
|
@@ -55329,7 +55603,7 @@ function createBridgeRequestListener(opts) {
|
|
|
55329
55603
|
res.end(JSON.stringify({ ok: false, error: "Origin not allowed." }));
|
|
55330
55604
|
return;
|
|
55331
55605
|
}
|
|
55332
|
-
const nonce =
|
|
55606
|
+
const nonce = import_node_crypto11.default.randomBytes(16).toString("base64url");
|
|
55333
55607
|
res.writeHead(200, { "content-type": "application/json" });
|
|
55334
55608
|
res.end(JSON.stringify({ ok: true, wsUrl: `ws://${host}:${port}/ws`, token, nonce }));
|
|
55335
55609
|
return;
|
|
@@ -55628,7 +55902,7 @@ function createBridgeMessageHandler(deps) {
|
|
|
55628
55902
|
}
|
|
55629
55903
|
}
|
|
55630
55904
|
socket.on("message", async (data) => {
|
|
55631
|
-
const spanId =
|
|
55905
|
+
const spanId = import_node_crypto11.default.randomUUID();
|
|
55632
55906
|
if (logCtx) {
|
|
55633
55907
|
logCtx.span.id = spanId;
|
|
55634
55908
|
logCtx.span.at = Date.now();
|
|
@@ -55690,7 +55964,7 @@ function createBridgeMessageHandler(deps) {
|
|
|
55690
55964
|
sendForSpan({ type: "checkout-state", ok: false, error: { code: "invalid_input", fields: { projectSlug: "required" } } });
|
|
55691
55965
|
return;
|
|
55692
55966
|
}
|
|
55693
|
-
const state = readCheckoutState(deps.checkoutRegistry, projectSlug,
|
|
55967
|
+
const state = readCheckoutState(deps.checkoutRegistry, projectSlug, import_node_os12.default.hostname());
|
|
55694
55968
|
if (!state) {
|
|
55695
55969
|
sendForSpan({ type: "checkout-state", ok: false, error: { code: "checkout_missing" } });
|
|
55696
55970
|
return;
|
|
@@ -55722,7 +55996,7 @@ function createBridgeMessageHandler(deps) {
|
|
|
55722
55996
|
const result = registerCheckout(
|
|
55723
55997
|
deps.checkoutRegistry,
|
|
55724
55998
|
{ projectSlug, path: typeof msg.path === "string" ? msg.path : "", repo },
|
|
55725
|
-
|
|
55999
|
+
import_node_os12.default.hostname()
|
|
55726
56000
|
);
|
|
55727
56001
|
if (!result.ok) {
|
|
55728
56002
|
sendForSpan({ type: "checkout-register", ok: false, error: { code: result.code, detail: result.detail } });
|
|
@@ -56208,7 +56482,7 @@ function createBridgeMessageHandler(deps) {
|
|
|
56208
56482
|
thread.inFlight = true;
|
|
56209
56483
|
pendingTurnSessions.delete(directorSessionId);
|
|
56210
56484
|
thread.replay = createReplayBuffer({
|
|
56211
|
-
turnId: (0,
|
|
56485
|
+
turnId: (0, import_node_crypto11.randomUUID)(),
|
|
56212
56486
|
spanId,
|
|
56213
56487
|
...deps.retentionMs !== void 0 ? { retentionMs: deps.retentionMs } : {},
|
|
56214
56488
|
...deps.ackLingerMs !== void 0 ? { ackLingerMs: deps.ackLingerMs } : {}
|
|
@@ -56626,6 +56900,23 @@ function checkTelemetryDefaultProject(env, warn) {
|
|
|
56626
56900
|
"[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."
|
|
56627
56901
|
);
|
|
56628
56902
|
}
|
|
56903
|
+
function createSelectedProviderRefresher(deps) {
|
|
56904
|
+
let lastError = null;
|
|
56905
|
+
return () => {
|
|
56906
|
+
deps.read().then((config2) => {
|
|
56907
|
+
lastError = null;
|
|
56908
|
+
deps.apply(config2.agentProvider);
|
|
56909
|
+
}).catch((error51) => {
|
|
56910
|
+
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
56911
|
+
if (message !== lastError) {
|
|
56912
|
+
lastError = message;
|
|
56913
|
+
deps.warn(
|
|
56914
|
+
`[mrrlin-mcp director-bridge] agent-provider refresh failed; keeping the held seat: ${message}`
|
|
56915
|
+
);
|
|
56916
|
+
}
|
|
56917
|
+
});
|
|
56918
|
+
};
|
|
56919
|
+
}
|
|
56629
56920
|
async function startDirectorBridge() {
|
|
56630
56921
|
const config2 = parseConfig();
|
|
56631
56922
|
const failureLog = createFailureLog();
|
|
@@ -56772,8 +57063,8 @@ async function startDirectorBridge() {
|
|
|
56772
57063
|
codexCwd: config2.codexCwd,
|
|
56773
57064
|
codexExecutable: config2.codexExecutable,
|
|
56774
57065
|
checkoutRegistry,
|
|
56775
|
-
worktreeRoot:
|
|
56776
|
-
locksDir:
|
|
57066
|
+
worktreeRoot: import_node_path27.default.join(config2.stateDir, "worktrees"),
|
|
57067
|
+
locksDir: import_node_path27.default.join(config2.stateDir, "locks"),
|
|
56777
57068
|
// Wire the executor server for code-execution runs. Each run gets its own provider process
|
|
56778
57069
|
// (app-server for codex, a resident CLI child for claude) at the run worktree, running
|
|
56779
57070
|
// UNRESTRICTED from the real operator config (owner no-sandbox decision — auth + mrrlin MCP
|
|
@@ -56817,13 +57108,13 @@ async function startDirectorBridge() {
|
|
|
56817
57108
|
// egressDomains is retained in the seam signature (verification-turn.ts still computes the
|
|
56818
57109
|
// env host) but no longer constrains anything — the executor is unrestricted.
|
|
56819
57110
|
startSandbox: async (_egressDomains, providerId) => {
|
|
56820
|
-
const cwd =
|
|
57111
|
+
const cwd = import_node_fs20.default.mkdtempSync(import_node_path27.default.join(import_node_os12.default.tmpdir(), "mrrlin-verify-"));
|
|
56821
57112
|
let executor;
|
|
56822
57113
|
try {
|
|
56823
57114
|
executor = await startExecutorServer({ worktree: cwd, provider: providerId });
|
|
56824
57115
|
} catch (error51) {
|
|
56825
57116
|
try {
|
|
56826
|
-
|
|
57117
|
+
import_node_fs20.default.rmSync(cwd, { recursive: true, force: true });
|
|
56827
57118
|
} catch {
|
|
56828
57119
|
}
|
|
56829
57120
|
throw error51;
|
|
@@ -56834,7 +57125,7 @@ async function startDirectorBridge() {
|
|
|
56834
57125
|
dispose: () => {
|
|
56835
57126
|
executor.dispose();
|
|
56836
57127
|
try {
|
|
56837
|
-
|
|
57128
|
+
import_node_fs20.default.rmSync(cwd, { recursive: true, force: true });
|
|
56838
57129
|
} catch {
|
|
56839
57130
|
}
|
|
56840
57131
|
}
|
|
@@ -56863,7 +57154,7 @@ async function startDirectorBridge() {
|
|
|
56863
57154
|
};
|
|
56864
57155
|
const sessionSinks = createSessionSinkRegistry();
|
|
56865
57156
|
const tombstones = /* @__PURE__ */ new Map();
|
|
56866
|
-
const bridgeInstanceId = (0,
|
|
57157
|
+
const bridgeInstanceId = (0, import_node_crypto11.randomUUID)();
|
|
56867
57158
|
const asyncConsumerDeps = {
|
|
56868
57159
|
client,
|
|
56869
57160
|
run: wrappedTurnLock.run,
|
|
@@ -57041,7 +57332,7 @@ async function startDirectorBridge() {
|
|
|
57041
57332
|
}
|
|
57042
57333
|
const files = dayFilesInWindow(/* @__PURE__ */ new Date(), reseedWindowMs);
|
|
57043
57334
|
const sessionIds = [args.directorSessionId, ...args.priorSessionIds];
|
|
57044
|
-
const { lines: lines2, missingFiles } = await readSessionRows(
|
|
57335
|
+
const { lines: lines2, missingFiles } = await readSessionRows(import_node_path27.default.join(config2.stateDir, "logs"), files, sessionIds);
|
|
57045
57336
|
const { items, skipped: skipped2 } = extractItems(lines2, sessionIds);
|
|
57046
57337
|
if (items.length === 0) return refuse("no-rows");
|
|
57047
57338
|
const budget = Math.max(0, Math.min(config2.reseedMaxTokens, config2.turnMaxTokens - args.otherBytes));
|
|
@@ -57138,7 +57429,7 @@ async function startDirectorBridge() {
|
|
|
57138
57429
|
const bridgeLogger = createBridgeLogger(config2.stateDir, process.env);
|
|
57139
57430
|
let bridgeBinShaShort = "unknown00000";
|
|
57140
57431
|
try {
|
|
57141
|
-
bridgeBinShaShort =
|
|
57432
|
+
bridgeBinShaShort = import_node_crypto11.default.createHash("sha256").update(import_node_fs20.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
|
|
57142
57433
|
} catch {
|
|
57143
57434
|
}
|
|
57144
57435
|
attachBridgeWss(server, {
|
|
@@ -57274,8 +57565,8 @@ async function startDirectorBridge() {
|
|
|
57274
57565
|
);
|
|
57275
57566
|
void runOrphanWorktreeSweep(client, {
|
|
57276
57567
|
checkoutRegistry,
|
|
57277
|
-
worktreeRoot:
|
|
57278
|
-
locksDir:
|
|
57568
|
+
worktreeRoot: import_node_path27.default.join(config2.stateDir, "worktrees"),
|
|
57569
|
+
locksDir: import_node_path27.default.join(config2.stateDir, "locks")
|
|
57279
57570
|
});
|
|
57280
57571
|
{
|
|
57281
57572
|
const { retainedBuffers, retainedBytes, tombstonesRemoved } = sweepReplayBuffers(threads, tombstones, {
|
|
@@ -57399,10 +57690,12 @@ async function startDirectorBridge() {
|
|
|
57399
57690
|
}
|
|
57400
57691
|
let selectedProviderTimer = null;
|
|
57401
57692
|
if (tokenProvider) {
|
|
57402
|
-
const refreshSelectedProvider = (
|
|
57403
|
-
|
|
57404
|
-
|
|
57405
|
-
|
|
57693
|
+
const refreshSelectedProvider = createSelectedProviderRefresher({
|
|
57694
|
+
read: () => client.getAgentProviderConfig(),
|
|
57695
|
+
apply: setSelectedProvider,
|
|
57696
|
+
warn: (m) => process.stderr.write(`${m}
|
|
57697
|
+
`)
|
|
57698
|
+
});
|
|
57406
57699
|
refreshSelectedProvider();
|
|
57407
57700
|
selectedProviderTimer = setInterval(refreshSelectedProvider, 6e4);
|
|
57408
57701
|
selectedProviderTimer.unref?.();
|
|
@@ -57581,7 +57874,7 @@ function timingSafeTokenEqual(provided, expected) {
|
|
|
57581
57874
|
const a = Buffer.from(provided);
|
|
57582
57875
|
const b = Buffer.from(expected);
|
|
57583
57876
|
if (a.length !== b.length) return false;
|
|
57584
|
-
return
|
|
57877
|
+
return import_node_crypto11.default.timingSafeEqual(a, b);
|
|
57585
57878
|
}
|
|
57586
57879
|
function readDispatchBody(req) {
|
|
57587
57880
|
return new Promise((resolve, reject) => {
|
|
@@ -57603,15 +57896,15 @@ function readDispatchBody(req) {
|
|
|
57603
57896
|
function readOrCreateBridgeToken(stateDir) {
|
|
57604
57897
|
const explicit = (process.env.MRRLIN_DIRECTOR_BRIDGE_TOKEN ?? "").trim();
|
|
57605
57898
|
if (explicit) return explicit;
|
|
57606
|
-
const tokenPath =
|
|
57899
|
+
const tokenPath = import_node_path27.default.join(stateDir, "token.txt");
|
|
57607
57900
|
try {
|
|
57608
|
-
const existing =
|
|
57901
|
+
const existing = import_node_fs20.default.readFileSync(tokenPath, "utf8").trim();
|
|
57609
57902
|
if (existing) return existing;
|
|
57610
57903
|
} catch {
|
|
57611
57904
|
}
|
|
57612
|
-
|
|
57613
|
-
const token =
|
|
57614
|
-
|
|
57905
|
+
import_node_fs20.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
|
|
57906
|
+
const token = import_node_crypto11.default.randomBytes(32).toString("base64url");
|
|
57907
|
+
import_node_fs20.default.writeFileSync(tokenPath, `${token}
|
|
57615
57908
|
`, { mode: 384 });
|
|
57616
57909
|
return token;
|
|
57617
57910
|
}
|
|
@@ -60999,17 +61292,17 @@ var StdioServerTransport = class {
|
|
|
60999
61292
|
};
|
|
61000
61293
|
|
|
61001
61294
|
// src/tools.ts
|
|
61002
|
-
var
|
|
61295
|
+
var import_node_crypto14 = require("node:crypto");
|
|
61003
61296
|
var import_promises10 = require("node:fs/promises");
|
|
61004
|
-
var
|
|
61005
|
-
var
|
|
61297
|
+
var import_node_path30 = __toESM(require("node:path"), 1);
|
|
61298
|
+
var import_node_os13 = __toESM(require("node:os"), 1);
|
|
61006
61299
|
|
|
61007
61300
|
// ../../packages/wiki/dist/index.js
|
|
61008
61301
|
var import_promises8 = __toESM(require("node:fs/promises"), 1);
|
|
61009
|
-
var
|
|
61302
|
+
var import_node_path28 = __toESM(require("node:path"), 1);
|
|
61010
61303
|
var INCLUDED_DOC_FOLDERS = /* @__PURE__ */ new Set(["_meta", "explanation", "how-to", "reference", "sdd", "tutorials"]);
|
|
61011
61304
|
function toPosixPath(input) {
|
|
61012
|
-
return input.split(
|
|
61305
|
+
return input.split(import_node_path28.default.sep).join("/");
|
|
61013
61306
|
}
|
|
61014
61307
|
function slugifyWikiSegment(input) {
|
|
61015
61308
|
return input.trim().toLowerCase().replace(/`/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -61023,12 +61316,12 @@ async function pathExists3(input) {
|
|
|
61023
61316
|
}
|
|
61024
61317
|
}
|
|
61025
61318
|
async function findWorkspaceRoot(start = process.cwd()) {
|
|
61026
|
-
let current2 =
|
|
61319
|
+
let current2 = import_node_path28.default.resolve(start);
|
|
61027
61320
|
while (true) {
|
|
61028
|
-
if (await pathExists3(
|
|
61321
|
+
if (await pathExists3(import_node_path28.default.join(current2, "pnpm-workspace.yaml")) && await pathExists3(import_node_path28.default.join(current2, "docs"))) {
|
|
61029
61322
|
return current2;
|
|
61030
61323
|
}
|
|
61031
|
-
const parent =
|
|
61324
|
+
const parent = import_node_path28.default.dirname(current2);
|
|
61032
61325
|
if (parent === current2) {
|
|
61033
61326
|
throw new Error(`Unable to find Mrrlin workspace root from ${start}`);
|
|
61034
61327
|
}
|
|
@@ -61037,28 +61330,28 @@ async function findWorkspaceRoot(start = process.cwd()) {
|
|
|
61037
61330
|
}
|
|
61038
61331
|
async function resolveDocsRoot(input) {
|
|
61039
61332
|
if (input) {
|
|
61040
|
-
return
|
|
61333
|
+
return import_node_path28.default.resolve(input);
|
|
61041
61334
|
}
|
|
61042
61335
|
if (process.env.MRRLIN_DOCS_ROOT) {
|
|
61043
|
-
return
|
|
61336
|
+
return import_node_path28.default.resolve(process.env.MRRLIN_DOCS_ROOT);
|
|
61044
61337
|
}
|
|
61045
|
-
return
|
|
61338
|
+
return import_node_path28.default.join(await findWorkspaceRoot(), "docs");
|
|
61046
61339
|
}
|
|
61047
61340
|
async function resolveIndexPath(input) {
|
|
61048
61341
|
if (input) {
|
|
61049
|
-
return
|
|
61342
|
+
return import_node_path28.default.resolve(input);
|
|
61050
61343
|
}
|
|
61051
61344
|
if (process.env.MRRLIN_WIKI_INDEX_PATH) {
|
|
61052
|
-
return
|
|
61345
|
+
return import_node_path28.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
|
|
61053
61346
|
}
|
|
61054
61347
|
const workspaceRoot = await findWorkspaceRoot();
|
|
61055
|
-
return
|
|
61348
|
+
return import_node_path28.default.join(workspaceRoot, "apps", "web", "public", "wiki-index.json");
|
|
61056
61349
|
}
|
|
61057
61350
|
async function walkMarkdownFiles(root, dir = root) {
|
|
61058
61351
|
const entries = await import_promises8.default.readdir(dir, { withFileTypes: true });
|
|
61059
61352
|
const files = [];
|
|
61060
61353
|
for (const entry of entries) {
|
|
61061
|
-
const absolute =
|
|
61354
|
+
const absolute = import_node_path28.default.join(dir, entry.name);
|
|
61062
61355
|
if (entry.isDirectory()) {
|
|
61063
61356
|
files.push(...await walkMarkdownFiles(root, absolute));
|
|
61064
61357
|
continue;
|
|
@@ -61077,7 +61370,7 @@ function parseTitle(markdown, sourcePath) {
|
|
|
61077
61370
|
return title;
|
|
61078
61371
|
}
|
|
61079
61372
|
function documentFromFile(docsRoot, absolutePath, markdown) {
|
|
61080
|
-
const relativePath = toPosixPath(
|
|
61373
|
+
const relativePath = toPosixPath(import_node_path28.default.relative(docsRoot, absolutePath));
|
|
61081
61374
|
const [section, fileName] = relativePath.split("/");
|
|
61082
61375
|
if (!section || !fileName || !INCLUDED_DOC_FOLDERS.has(section)) {
|
|
61083
61376
|
return null;
|
|
@@ -61428,15 +61721,17 @@ async function pickPanel(input, deps) {
|
|
|
61428
61721
|
const agents = r.stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
61429
61722
|
return { ok: true, agents };
|
|
61430
61723
|
}
|
|
61431
|
-
|
|
61432
|
-
const
|
|
61433
|
-
const
|
|
61434
|
-
const
|
|
61435
|
-
|
|
61436
|
-
|
|
61437
|
-
|
|
61724
|
+
function dispatchUsage(parsed) {
|
|
61725
|
+
const readCount3 = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
61726
|
+
const inputTokens = readCount3(parsed.tokens_in);
|
|
61727
|
+
const outputTokens = readCount3(parsed.tokens_out);
|
|
61728
|
+
if (inputTokens === null && outputTokens === null) return null;
|
|
61729
|
+
return { inputTokens, cachedInputTokens: null, cacheWriteInputTokens: null, outputTokens };
|
|
61730
|
+
}
|
|
61731
|
+
function parseDispatch(agentId, stdout, exitCode) {
|
|
61732
|
+
const lines2 = stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
61438
61733
|
const jsonLine = [...lines2].reverse().find((l) => l[0] === "{");
|
|
61439
|
-
if (!jsonLine) return { ok: false, error: `dispatch ${agentId}: no JSON on stdout (exit ${
|
|
61734
|
+
if (!jsonLine) return { ok: false, error: `dispatch ${agentId}: no JSON on stdout (exit ${exitCode})` };
|
|
61440
61735
|
let parsed;
|
|
61441
61736
|
try {
|
|
61442
61737
|
parsed = JSON.parse(jsonLine);
|
|
@@ -61449,7 +61744,16 @@ async function dispatchHead(agentId, prompt, timeoutMs, deps) {
|
|
|
61449
61744
|
if (typeof parsed.text !== "string" || parsed.text.trim() === "") {
|
|
61450
61745
|
return { ok: false, error: `dispatch ${agentId}: empty text on success` };
|
|
61451
61746
|
}
|
|
61452
|
-
|
|
61747
|
+
const usage = dispatchUsage(parsed);
|
|
61748
|
+
return { ok: true, text: parsed.text, usage };
|
|
61749
|
+
}
|
|
61750
|
+
async function dispatchHead(agentId, prompt, timeoutMs, deps) {
|
|
61751
|
+
const spawn4 = deps?.spawn ?? import_node_child_process17.spawn;
|
|
61752
|
+
const { command, prefixArgs } = resolveExternalAgentsCliInvocation(deps?.externalAgentsBin);
|
|
61753
|
+
const args = ["dispatch", agentId, "--json", prompt];
|
|
61754
|
+
const r = await runExternalAgents(command, [...prefixArgs, ...args], "dispatch", timeoutMs, spawn4);
|
|
61755
|
+
if (r.error) return { ok: false, error: r.error };
|
|
61756
|
+
return parseDispatch(agentId, r.stdout, r.code);
|
|
61453
61757
|
}
|
|
61454
61758
|
async function buildMultiHeadRunner(input, deps) {
|
|
61455
61759
|
const pickOnce = () => pickPanel(
|
|
@@ -61834,7 +62138,7 @@ async function runDecisionConsensus(input, deps) {
|
|
|
61834
62138
|
}
|
|
61835
62139
|
|
|
61836
62140
|
// src/async-tools/consensus.ts
|
|
61837
|
-
var
|
|
62141
|
+
var import_node_crypto12 = require("node:crypto");
|
|
61838
62142
|
|
|
61839
62143
|
// src/consensus/question-similarity.ts
|
|
61840
62144
|
var SUPPRESSION_SIMILARITY_THRESHOLD = 0.6;
|
|
@@ -62030,6 +62334,10 @@ async function runNativeSpecGate(ctx, input, builders = defaultNativeSpecGateBui
|
|
|
62030
62334
|
specPageId: input.pageId,
|
|
62031
62335
|
cwd: ctx.cwd,
|
|
62032
62336
|
codexExecutable: ctx.codexExecutable,
|
|
62337
|
+
// Where the gate records what each of its provider calls cost. This is the only one of the
|
|
62338
|
+
// four gate-deps call sites that holds a stateDir today; without it the recorder is a no-op,
|
|
62339
|
+
// so the spec gate is the one whose cost is actually observable.
|
|
62340
|
+
stateDir: ctx.stateDir,
|
|
62033
62341
|
extraHeadCount: input.extraHeads?.length ?? 0,
|
|
62034
62342
|
// model-tier-planning-and-arbiter task 1.21: the seat minted at the async-job claim.
|
|
62035
62343
|
seat: ctx.seat
|
|
@@ -62110,9 +62418,9 @@ async function handleConsensusBlocked(result, ctx, input, resolvedTaskId) {
|
|
|
62110
62418
|
}
|
|
62111
62419
|
if (taskId) {
|
|
62112
62420
|
const scopeId = taskId;
|
|
62113
|
-
const groupId = toFile.length > 1 ? `II-${scopeId}-gate-group-${(0,
|
|
62421
|
+
const groupId = toFile.length > 1 ? `II-${scopeId}-gate-group-${(0, import_node_crypto12.createHash)("sha256").update(toFile.map((c) => c.rawQuestion).sort().join("\n")).digest("hex").slice(0, 10)}` : void 0;
|
|
62114
62422
|
for (const clarification of toFile) {
|
|
62115
|
-
const id = `II-${scopeId}-gate-${(0,
|
|
62423
|
+
const id = `II-${scopeId}-gate-${(0, import_node_crypto12.createHash)("sha256").update(clarification.rawQuestion).digest("hex").slice(0, 10)}`;
|
|
62116
62424
|
try {
|
|
62117
62425
|
const questionOptions = buildGateQuestionOptions(clarification.rawQuestion, clarification.category);
|
|
62118
62426
|
await ctx.client.createInboxItem(input.projectSlug, {
|
|
@@ -62130,9 +62438,9 @@ async function handleConsensusBlocked(result, ctx, input, resolvedTaskId) {
|
|
|
62130
62438
|
filedQuestionCount = toFile.length;
|
|
62131
62439
|
} else if (planId) {
|
|
62132
62440
|
const scopeId = planId;
|
|
62133
|
-
const groupId = toFile.length > 1 ? `II-${scopeId}-gate-group-${(0,
|
|
62441
|
+
const groupId = toFile.length > 1 ? `II-${scopeId}-gate-group-${(0, import_node_crypto12.createHash)("sha256").update(toFile.map((c) => c.rawQuestion).sort().join("\n")).digest("hex").slice(0, 10)}` : void 0;
|
|
62134
62442
|
for (const clarification of toFile) {
|
|
62135
|
-
const id = `II-${scopeId}-gate-${(0,
|
|
62443
|
+
const id = `II-${scopeId}-gate-${(0, import_node_crypto12.createHash)("sha256").update(clarification.rawQuestion).digest("hex").slice(0, 10)}`;
|
|
62136
62444
|
try {
|
|
62137
62445
|
const questionOptions = buildGateQuestionOptions(clarification.rawQuestion, clarification.category);
|
|
62138
62446
|
await ctx.client.createInboxItem(input.projectSlug, {
|
|
@@ -62156,7 +62464,7 @@ async function handleConsensusBlocked(result, ctx, input, resolvedTaskId) {
|
|
|
62156
62464
|
taskId: page.taskId ?? null
|
|
62157
62465
|
});
|
|
62158
62466
|
const reviewHash = domainScopedReviewHash2(page.contentHash, domain2);
|
|
62159
|
-
const baseBlockItemId = `II-${taskId}-gateblock-${(0,
|
|
62467
|
+
const baseBlockItemId = `II-${taskId}-gateblock-${(0, import_node_crypto12.createHash)("sha256").update(reviewHash).digest("hex").slice(0, 10)}`;
|
|
62160
62468
|
const reviewAgainAvailable = !taskInboxItems.some(
|
|
62161
62469
|
(item) => item.id === baseBlockItemId && item.status !== "pending" && item.answer === REVIEW_AGAIN_ANSWER
|
|
62162
62470
|
);
|
|
@@ -62728,7 +63036,7 @@ var intentCheckDescriptor = createIntentCheckDescriptor();
|
|
|
62728
63036
|
|
|
62729
63037
|
// src/evidence/assembler.ts
|
|
62730
63038
|
var import_promises9 = require("node:fs/promises");
|
|
62731
|
-
var
|
|
63039
|
+
var import_node_path29 = require("node:path");
|
|
62732
63040
|
function evidenceDedupKey(sessionId, reportId) {
|
|
62733
63041
|
return `${sessionId}:${reportId}`;
|
|
62734
63042
|
}
|
|
@@ -62738,7 +63046,7 @@ function isRecord4(v) {
|
|
|
62738
63046
|
async function readDayLines(stateDir, day, sessionId) {
|
|
62739
63047
|
let raw;
|
|
62740
63048
|
try {
|
|
62741
|
-
raw = await (0, import_promises9.readFile)((0,
|
|
63049
|
+
raw = await (0, import_promises9.readFile)((0, import_node_path29.join)(stateDir, "logs", `bridge-${day}.jsonl`), "utf8");
|
|
62742
63050
|
} catch {
|
|
62743
63051
|
return [];
|
|
62744
63052
|
}
|
|
@@ -62812,7 +63120,7 @@ async function assembleEvidence(stateDir, sessionId, reportId, gateCtx) {
|
|
|
62812
63120
|
}
|
|
62813
63121
|
let windowPruned = false;
|
|
62814
63122
|
try {
|
|
62815
|
-
const raw = await (0, import_promises9.readFile)((0,
|
|
63123
|
+
const raw = await (0, import_promises9.readFile)((0, import_node_path29.join)(stateDir, "logs", ".pruned.jsonl"), "utf8");
|
|
62816
63124
|
outer: for (const line of raw.split("\n")) {
|
|
62817
63125
|
if (!line.trim()) continue;
|
|
62818
63126
|
let rec;
|
|
@@ -62878,7 +63186,7 @@ function createReportEvidenceDescriptor() {
|
|
|
62878
63186
|
var reportEvidenceDescriptor = createReportEvidenceDescriptor();
|
|
62879
63187
|
|
|
62880
63188
|
// src/async-tools/enqueue.ts
|
|
62881
|
-
var
|
|
63189
|
+
var import_node_crypto13 = __toESM(require("node:crypto"), 1);
|
|
62882
63190
|
async function enqueueAsyncTool(client, descriptor2, input) {
|
|
62883
63191
|
if (descriptor2.cachedResult) {
|
|
62884
63192
|
const cached2 = await descriptor2.cachedResult(client, input);
|
|
@@ -62891,7 +63199,7 @@ async function enqueueAsyncTool(client, descriptor2, input) {
|
|
|
62891
63199
|
if (active) {
|
|
62892
63200
|
return { status: "already_running", jobId: active.id, message: "Already running; will notify in inbox." };
|
|
62893
63201
|
}
|
|
62894
|
-
const jobId = `AJ-${
|
|
63202
|
+
const jobId = `AJ-${import_node_crypto13.default.randomUUID()}`;
|
|
62895
63203
|
try {
|
|
62896
63204
|
await client.createAsyncJob(input.projectSlug, {
|
|
62897
63205
|
id: jobId,
|
|
@@ -64551,7 +64859,7 @@ function createMrrlinTools(options) {
|
|
|
64551
64859
|
"PRODUCED_URL_RECORD_FAILED",
|
|
64552
64860
|
"Unable to record produced URL.",
|
|
64553
64861
|
async (c, { projectSlug, runId, url: url2, label }) => {
|
|
64554
|
-
const id = `EA-pu-${(0,
|
|
64862
|
+
const id = `EA-pu-${(0, import_node_crypto14.randomBytes)(4).toString("hex")}`;
|
|
64555
64863
|
const payload = label ? { url: url2, label } : { url: url2 };
|
|
64556
64864
|
return await c.appendExecutionArtifact(projectSlug, runId, {
|
|
64557
64865
|
id,
|
|
@@ -64625,7 +64933,7 @@ function createMrrlinTools(options) {
|
|
|
64625
64933
|
"ARTIFACT_FILE_UPLOAD_FAILED",
|
|
64626
64934
|
"Unable to upload artifact file.",
|
|
64627
64935
|
async (c, { projectSlug, path: filePath, class: artifactClass, taskId, runId, description }) => {
|
|
64628
|
-
const extension2 =
|
|
64936
|
+
const extension2 = import_node_path30.default.extname(filePath).toLowerCase();
|
|
64629
64937
|
const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
|
|
64630
64938
|
if (!contentType) {
|
|
64631
64939
|
throw new McpToolCodedError(
|
|
@@ -64653,7 +64961,7 @@ function createMrrlinTools(options) {
|
|
|
64653
64961
|
"Artifact exceeds 5MB; split or summarize instead."
|
|
64654
64962
|
);
|
|
64655
64963
|
}
|
|
64656
|
-
const filename =
|
|
64964
|
+
const filename = import_node_path30.default.basename(filePath);
|
|
64657
64965
|
return uploadArtifactBytes(c, {
|
|
64658
64966
|
bytes: bytes3,
|
|
64659
64967
|
class: artifactClass,
|
|
@@ -64678,7 +64986,7 @@ function createMrrlinTools(options) {
|
|
|
64678
64986
|
`Invalid filename '${filename}'; provide a bare filename with no path separators or '..'.`
|
|
64679
64987
|
);
|
|
64680
64988
|
}
|
|
64681
|
-
const extension2 =
|
|
64989
|
+
const extension2 = import_node_path30.default.extname(filename).toLowerCase();
|
|
64682
64990
|
const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
|
|
64683
64991
|
if (!contentType) {
|
|
64684
64992
|
throw new McpToolCodedError(
|
|
@@ -64752,9 +65060,9 @@ function createMrrlinTools(options) {
|
|
|
64752
65060
|
"LOCAL_CHECKOUT_REGISTER_FAILED",
|
|
64753
65061
|
"Unable to register local checkout.",
|
|
64754
65062
|
async (_c, { projectSlug, path: checkoutPath, repo }) => {
|
|
64755
|
-
const stateDir = process.env.CODEX_HOME ?
|
|
65063
|
+
const stateDir = process.env.CODEX_HOME ? import_node_path30.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge") : import_node_path30.default.join(import_node_os13.default.homedir(), ".mrrlin", "director-bridge");
|
|
64756
65064
|
const registry3 = new CheckoutRegistry(stateDir);
|
|
64757
|
-
const result = registerCheckout(registry3, { projectSlug, path: checkoutPath, repo },
|
|
65065
|
+
const result = registerCheckout(registry3, { projectSlug, path: checkoutPath, repo }, import_node_os13.default.hostname());
|
|
64758
65066
|
if (!result.ok) {
|
|
64759
65067
|
const codeMap = {
|
|
64760
65068
|
not_absolute: "LOCAL_CHECKOUT_PATH_NOT_ABSOLUTE",
|
|
@@ -64991,9 +65299,43 @@ function runSetCredential(args) {
|
|
|
64991
65299
|
}
|
|
64992
65300
|
|
|
64993
65301
|
// src/install-service.ts
|
|
64994
|
-
var
|
|
64995
|
-
var
|
|
65302
|
+
var import_node_os14 = __toESM(require("node:os"), 1);
|
|
65303
|
+
var import_node_fs21 = require("node:fs");
|
|
65304
|
+
var import_node_path31 = __toESM(require("node:path"), 1);
|
|
64996
65305
|
var SYSTEM_PATH_DIRS = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"];
|
|
65306
|
+
function defaultHomeOwnerUid(home) {
|
|
65307
|
+
try {
|
|
65308
|
+
return (0, import_node_fs21.statSync)(home).uid;
|
|
65309
|
+
} catch {
|
|
65310
|
+
return null;
|
|
65311
|
+
}
|
|
65312
|
+
}
|
|
65313
|
+
function resolveBridgeUser(deps) {
|
|
65314
|
+
if (deps.env.SUDO_USER?.trim()) {
|
|
65315
|
+
deps.log(
|
|
65316
|
+
"Running under sudo, so USER is left out of the service config: HOME, the pm2 daemon and the resolved user would all be root's, and Claude reads its credentials from a user's own keychain. Re-run install-service WITHOUT sudo unless you really mean to run as root."
|
|
65317
|
+
);
|
|
65318
|
+
return void 0;
|
|
65319
|
+
}
|
|
65320
|
+
let info;
|
|
65321
|
+
try {
|
|
65322
|
+
info = deps.userInfo();
|
|
65323
|
+
} catch {
|
|
65324
|
+
deps.log(
|
|
65325
|
+
"Could not resolve the OS user, so USER is left out of the service config. If the Claude CLI reports 'Not logged in' despite a real login, this is why."
|
|
65326
|
+
);
|
|
65327
|
+
return void 0;
|
|
65328
|
+
}
|
|
65329
|
+
const ownerUid = deps.homeOwnerUid(deps.home);
|
|
65330
|
+
const uidsAreMeaningful = info.uid >= 0 && ownerUid !== null && ownerUid >= 0;
|
|
65331
|
+
if (uidsAreMeaningful && ownerUid !== info.uid) {
|
|
65332
|
+
deps.log(
|
|
65333
|
+
`USER is left out of the service config: this process runs as '${info.username}' (uid ${info.uid}) but HOME ${deps.home} is owned by uid ${ownerUid}. Install as the user who owns that home directory, whose keychain Claude will read.`
|
|
65334
|
+
);
|
|
65335
|
+
return void 0;
|
|
65336
|
+
}
|
|
65337
|
+
return info.username;
|
|
65338
|
+
}
|
|
64997
65339
|
function installService(deps) {
|
|
64998
65340
|
if (!deps.hasSecret()) {
|
|
64999
65341
|
deps.log("No agent credential found. Issue one in Settings, then run: mrrlin-mcp set-credential '<secret>'.");
|
|
@@ -65004,7 +65346,14 @@ function installService(deps) {
|
|
|
65004
65346
|
deps.log(resolved.reason);
|
|
65005
65347
|
return { ok: false };
|
|
65006
65348
|
}
|
|
65007
|
-
const home = deps.env.HOME ??
|
|
65349
|
+
const home = deps.env.HOME ?? import_node_os14.default.homedir();
|
|
65350
|
+
const user = resolveBridgeUser({
|
|
65351
|
+
env: deps.env,
|
|
65352
|
+
home,
|
|
65353
|
+
userInfo: deps.userInfo ?? (() => import_node_os14.default.userInfo()),
|
|
65354
|
+
homeOwnerUid: deps.homeOwnerUid ?? defaultHomeOwnerUid,
|
|
65355
|
+
log: deps.log
|
|
65356
|
+
});
|
|
65008
65357
|
const bins = ["node", "codex", "mrrlin-mcp"].map((b) => deps.which(b));
|
|
65009
65358
|
if (bins.some((b) => !b)) {
|
|
65010
65359
|
deps.log("Could not resolve absolute paths for node/codex/mrrlin-mcp on PATH. Install them or fix PATH.");
|
|
@@ -65017,19 +65366,20 @@ function installService(deps) {
|
|
|
65017
65366
|
const claudeBin = deps.which("claude");
|
|
65018
65367
|
const resolvedBins = [...bins, claudeBin].filter((b) => b !== null);
|
|
65019
65368
|
const pathEnv = Array.from(
|
|
65020
|
-
/* @__PURE__ */ new Set([...resolvedBins.map((b) =>
|
|
65369
|
+
/* @__PURE__ */ new Set([...resolvedBins.map((b) => import_node_path31.default.dirname(b)), ...SYSTEM_PATH_DIRS])
|
|
65021
65370
|
).join(":");
|
|
65022
65371
|
const apiBaseUrl = deps.env.MRRLIN_API_BASE_URL?.trim() || void 0;
|
|
65023
65372
|
const staging = deps.env.MRRLIN_STAGING === "1" || !apiBaseUrl && bridgeUrlImpliesStaging(deps.env.MRRLIN_BRIDGE_URL);
|
|
65024
65373
|
const text = renderEcosystemConfig({
|
|
65025
65374
|
cwd: resolved.cwd,
|
|
65026
65375
|
home,
|
|
65376
|
+
user,
|
|
65027
65377
|
codexHome: deps.env.CODEX_HOME?.trim() || void 0,
|
|
65028
65378
|
pathEnv,
|
|
65029
65379
|
staging,
|
|
65030
65380
|
apiBaseUrl
|
|
65031
65381
|
});
|
|
65032
|
-
const ecoPath =
|
|
65382
|
+
const ecoPath = import_node_path31.default.join(home, ".mrrlin", "ecosystem.config.cjs");
|
|
65033
65383
|
deps.writeFile(ecoPath, text);
|
|
65034
65384
|
const start = deps.runPm2(["startOrReload", ecoPath]);
|
|
65035
65385
|
if (start.code !== 0) {
|
|
@@ -65081,13 +65431,13 @@ function uninstallService(deps) {
|
|
|
65081
65431
|
|
|
65082
65432
|
// src/uninstall-codex.ts
|
|
65083
65433
|
var import_promises11 = __toESM(require("node:fs/promises"), 1);
|
|
65084
|
-
var
|
|
65085
|
-
var
|
|
65434
|
+
var import_node_os15 = __toESM(require("node:os"), 1);
|
|
65435
|
+
var import_node_path32 = __toESM(require("node:path"), 1);
|
|
65086
65436
|
var toml3 = __toESM(require_toml(), 1);
|
|
65087
65437
|
function resolveCodexHome3(options) {
|
|
65088
65438
|
if (options.codexHome) return options.codexHome;
|
|
65089
65439
|
if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
|
|
65090
|
-
return
|
|
65440
|
+
return import_node_path32.default.join(options.homeDir ?? import_node_os15.default.homedir(), ".codex");
|
|
65091
65441
|
}
|
|
65092
65442
|
async function pathExists4(target) {
|
|
65093
65443
|
try {
|
|
@@ -65100,7 +65450,7 @@ async function pathExists4(target) {
|
|
|
65100
65450
|
var MRRLIN_BLOCK_RE = /(^|\n)\[mcp_servers\.(?:mrrlin(?:-browser)?|external-agents)(?:\]|\.[^\]\n]*\])[\s\S]*?(?=\n\[|$)/g;
|
|
65101
65451
|
async function uninstallCodex(options = {}) {
|
|
65102
65452
|
const codexHome = resolveCodexHome3(options);
|
|
65103
|
-
const configPath =
|
|
65453
|
+
const configPath = import_node_path32.default.join(codexHome, "config.toml");
|
|
65104
65454
|
const removePrompts = async () => uninstallPrompts(codexHome, options.promptNames ?? []);
|
|
65105
65455
|
if (!await pathExists4(configPath)) {
|
|
65106
65456
|
return { action: "missing", configPath, prompts: await removePrompts() };
|
|
@@ -65128,10 +65478,10 @@ async function uninstallCodex(options = {}) {
|
|
|
65128
65478
|
}
|
|
65129
65479
|
async function uninstallPrompts(codexHome, names) {
|
|
65130
65480
|
if (names.length === 0) return [];
|
|
65131
|
-
const promptsDir =
|
|
65481
|
+
const promptsDir = import_node_path32.default.join(codexHome, "prompts");
|
|
65132
65482
|
const out = [];
|
|
65133
65483
|
for (const name of names) {
|
|
65134
|
-
const promptPath =
|
|
65484
|
+
const promptPath = import_node_path32.default.join(promptsDir, `${name}.md`);
|
|
65135
65485
|
try {
|
|
65136
65486
|
await import_promises11.default.unlink(promptPath);
|
|
65137
65487
|
out.push({ name, action: "removed", promptPath });
|
|
@@ -65149,7 +65499,7 @@ async function uninstallPrompts(codexHome, names) {
|
|
|
65149
65499
|
|
|
65150
65500
|
// src/extract/command.ts
|
|
65151
65501
|
var import_promises12 = require("node:fs/promises");
|
|
65152
|
-
var
|
|
65502
|
+
var import_node_path33 = require("node:path");
|
|
65153
65503
|
function parseArgs(args) {
|
|
65154
65504
|
const map2 = /* @__PURE__ */ new Map();
|
|
65155
65505
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -65186,7 +65536,7 @@ Missing required flag(s): ${missing.join(
|
|
|
65186
65536
|
const days = await findSessionDays(deps.stateDir, sessionId);
|
|
65187
65537
|
const matchingLines = [];
|
|
65188
65538
|
for (const day of days) {
|
|
65189
|
-
const logPath = (0,
|
|
65539
|
+
const logPath = (0, import_node_path33.join)(deps.stateDir, "logs", `bridge-${day}.jsonl`);
|
|
65190
65540
|
let raw;
|
|
65191
65541
|
try {
|
|
65192
65542
|
raw = await (0, import_promises12.readFile)(logPath, "utf8");
|
|
@@ -65286,16 +65636,16 @@ function bootHookStatus() {
|
|
|
65286
65636
|
if (process.platform !== "darwin") return { status: "unknown" };
|
|
65287
65637
|
const uid = process.getuid?.();
|
|
65288
65638
|
if (uid === void 0 || uid === 0) return { status: "unknown" };
|
|
65289
|
-
const home = process.env.HOME ?? (0,
|
|
65290
|
-
const agents =
|
|
65639
|
+
const home = process.env.HOME ?? (0, import_node_os16.homedir)();
|
|
65640
|
+
const agents = import_node_path35.default.join(home, "Library", "LaunchAgents");
|
|
65291
65641
|
const candidates = [
|
|
65292
|
-
{ label: "com.mrrlin.director-bridge", plist:
|
|
65293
|
-
{ label: "com.PM2", plist:
|
|
65642
|
+
{ label: "com.mrrlin.director-bridge", plist: import_node_path35.default.join(agents, "com.mrrlin.director-bridge.plist") },
|
|
65643
|
+
{ label: "com.PM2", plist: import_node_path35.default.join(agents, `pm2.${(0, import_node_os16.userInfo)().username}.plist`) }
|
|
65294
65644
|
];
|
|
65295
65645
|
for (const candidate of candidates) {
|
|
65296
65646
|
const printed = (0, import_node_child_process18.spawnSync)("launchctl", ["print", `gui/${uid}/${candidate.label}`], { encoding: "utf8" });
|
|
65297
65647
|
if (printed.status !== 0) continue;
|
|
65298
|
-
if (!(0,
|
|
65648
|
+
if (!(0, import_node_fs22.existsSync)(candidate.plist)) continue;
|
|
65299
65649
|
const out = printed.stdout ?? "";
|
|
65300
65650
|
const runs = /^\s*runs\s*=\s*(\d+)/m.exec(out);
|
|
65301
65651
|
const exitCode = /^\s*last exit code\s*=\s*(-?\d+)/m.exec(out);
|
|
@@ -65578,8 +65928,8 @@ async function main() {
|
|
|
65578
65928
|
}
|
|
65579
65929
|
}
|
|
65580
65930
|
try {
|
|
65581
|
-
const codexHome = process.env.CODEX_HOME ??
|
|
65582
|
-
(0,
|
|
65931
|
+
const codexHome = process.env.CODEX_HOME ?? import_node_path35.default.join(process.env.HOME ?? (0, import_node_os16.homedir)(), ".codex");
|
|
65932
|
+
(0, import_node_fs22.rmSync)(import_node_path35.default.join(codexHome, "prompts", "report-issue.md"), { force: true });
|
|
65583
65933
|
} catch {
|
|
65584
65934
|
}
|
|
65585
65935
|
const claudeResult = await installClaude({ binPath, force, serveEnv });
|
|
@@ -65640,8 +65990,8 @@ async function main() {
|
|
|
65640
65990
|
env: process.env,
|
|
65641
65991
|
cwd: process.cwd(),
|
|
65642
65992
|
writeFile: (p, c) => {
|
|
65643
|
-
(0,
|
|
65644
|
-
(0,
|
|
65993
|
+
(0, import_node_fs22.mkdirSync)(import_node_path35.default.dirname(p), { recursive: true, mode: 448 });
|
|
65994
|
+
(0, import_node_fs22.writeFileSync)(p, c, { mode: 384 });
|
|
65645
65995
|
},
|
|
65646
65996
|
runPm2: pm2Runner,
|
|
65647
65997
|
which: whichBin,
|
|
@@ -65659,35 +66009,35 @@ async function main() {
|
|
|
65659
66009
|
runPm2: (a) => ({ code: pm2Runner(a).code }),
|
|
65660
66010
|
removeFile: (p) => {
|
|
65661
66011
|
try {
|
|
65662
|
-
(0,
|
|
66012
|
+
(0, import_node_fs22.rmSync)(p, { force: true });
|
|
65663
66013
|
} catch {
|
|
65664
66014
|
}
|
|
65665
66015
|
},
|
|
65666
66016
|
purgeSecret: purge,
|
|
65667
66017
|
secretPath: agentCredentialPath(),
|
|
65668
66018
|
tokenPath: operatorTokenPath(),
|
|
65669
|
-
ecoPath:
|
|
66019
|
+
ecoPath: import_node_path35.default.join(process.env.HOME ?? (0, import_node_os16.homedir)(), ".mrrlin", "ecosystem.config.cjs"),
|
|
65670
66020
|
log: (m) => process.stderr.write(`[mrrlin-mcp uninstall-service] ${m}
|
|
65671
66021
|
`)
|
|
65672
66022
|
});
|
|
65673
66023
|
return;
|
|
65674
66024
|
}
|
|
65675
66025
|
case "uninstall": {
|
|
65676
|
-
const home = process.env.HOME ?? (0,
|
|
66026
|
+
const home = process.env.HOME ?? (0, import_node_os16.homedir)();
|
|
65677
66027
|
const log = (m) => process.stderr.write(`[mrrlin-mcp uninstall] ${m}
|
|
65678
66028
|
`);
|
|
65679
66029
|
uninstallService({
|
|
65680
66030
|
runPm2: (a) => ({ code: pm2Runner(a).code }),
|
|
65681
66031
|
removeFile: (p) => {
|
|
65682
66032
|
try {
|
|
65683
|
-
(0,
|
|
66033
|
+
(0, import_node_fs22.rmSync)(p, { force: true });
|
|
65684
66034
|
} catch {
|
|
65685
66035
|
}
|
|
65686
66036
|
},
|
|
65687
66037
|
purgeSecret: true,
|
|
65688
66038
|
secretPath: agentCredentialPath(),
|
|
65689
66039
|
tokenPath: operatorTokenPath(),
|
|
65690
|
-
ecoPath:
|
|
66040
|
+
ecoPath: import_node_path35.default.join(home, ".mrrlin", "ecosystem.config.cjs"),
|
|
65691
66041
|
log
|
|
65692
66042
|
});
|
|
65693
66043
|
let codexOk = true;
|
|
@@ -65707,7 +66057,7 @@ async function main() {
|
|
|
65707
66057
|
log(`codex config NOT modified: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
65708
66058
|
}
|
|
65709
66059
|
try {
|
|
65710
|
-
(0,
|
|
66060
|
+
(0, import_node_fs22.rmSync)(import_node_path35.default.join(home, ".mrrlin"), { recursive: true, force: true });
|
|
65711
66061
|
} catch {
|
|
65712
66062
|
}
|
|
65713
66063
|
log("removed ~/.mrrlin");
|
|
@@ -65748,7 +66098,7 @@ ${HELP_TEXT}`);
|
|
|
65748
66098
|
}
|
|
65749
66099
|
}
|
|
65750
66100
|
function resolveSelfBinPath() {
|
|
65751
|
-
return
|
|
66101
|
+
return import_node_path34.default.resolve(process.argv[1] ?? process.execPath);
|
|
65752
66102
|
}
|
|
65753
66103
|
main().catch((error51) => {
|
|
65754
66104
|
process.stderr.write(`mrrlin-mcp fatal error: ${error51 instanceof Error ? error51.message : String(error51)}
|