@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.
Files changed (2) hide show
  1. package/dist/bin.cjs +616 -266
  2. 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 = cache.get(memoKey);
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
- cache.set(memoKey, result);
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 cache = new LRU();
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 import_node_path31 = __toESM(require("node:path"), 1);
20647
+ var import_node_path34 = __toESM(require("node:path"), 1);
20648
20648
  var import_node_child_process18 = require("node:child_process");
20649
- var import_node_fs18 = require("node:fs");
20650
- var import_node_os15 = require("node:os");
20651
- var import_node_path32 = __toESM(require("node:path"), 1);
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 import_node_fs17 = __toESM(require("node:fs"), 1);
21557
+ var import_node_fs20 = __toESM(require("node:fs"), 1);
21558
21558
  var import_node_http = __toESM(require("node:http"), 1);
21559
- var import_node_os11 = __toESM(require("node:os"), 1);
21560
- var import_node_path24 = __toESM(require("node:path"), 1);
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 import_node_crypto10 = __toESM(require("node:crypto"), 1);
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.40";
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 import_node_path12 = require("node:path");
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 import_node_fs5 = __toESM(require("node:fs"), 1);
42981
- var import_node_path11 = __toESM(require("node:path"), 1);
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 import_node_path11.default.join(__dirname, "consensus", "personas");
44216
+ return import_node_path13.default.join(__dirname, "consensus", "personas");
44066
44217
  }
44067
- return import_node_path11.default.join(import_node_path11.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "personas");
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 = import_node_fs5.default.readFileSync(import_node_path11.default.join(getPersonasDir(), `${name}.md`), "utf8");
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, cwd, codexExecutable, extraHeadCount = 0, seat } = args;
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
- return runAgentExec(
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
- cwd,
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
- return runAgentExec(
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
- return runAgentExec(
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
- cwd,
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
- runCodexExec: runAgentExec,
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
- return runAgentExec({
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
- return runAgentExec({
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
- return runAgentExec({
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, cwd, codexExecutable, runId, seat } = args;
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
- return runAgentExec({
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
- return runAgentExec({
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
- return runAgentExec({
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, import_node_path12.join)(stateDir, "telemetry");
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, import_node_path12.join)(telemetryDir, `.processed-${projectSlug}-${day}`);
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, import_node_path12.join)(telemetryDir, file2), markerPath });
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, import_node_path12.join)(telemetryDir, `.failed-${cur.projectSlug}-${cur.day}.json`);
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 import_node_crypto6 = __toESM(require("node:crypto"), 1);
45101
- var import_node_path15 = __toESM(require("node:path"), 1);
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 import_node_crypto5 = require("node:crypto");
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, import_node_crypto5.createHash)("sha256").update(summary).digest("hex").slice(0, 10);
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 import_node_fs7 = require("node:fs");
46398
- var import_node_os6 = require("node:os");
46399
- var import_node_path14 = require("node:path");
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 import_node_fs6 = require("node:fs");
46403
- var import_node_path13 = require("node:path");
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, import_node_fs6.mkdirSync)(locksDir, { recursive: true });
46407
- const target = (0, import_node_path13.join)(locksDir, `${slug}.lock`);
46408
- if (!(0, import_node_fs6.existsSync)(target)) (0, import_node_fs6.writeFileSync)(target, "");
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, import_node_path14.join)(opts.worktreeRoot, opts.slug, opts.runId);
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, import_node_fs7.mkdirSync)(opts.worktreeRoot, { recursive: true });
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, import_node_fs7.existsSync)(worktreePath)) {
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, import_node_fs7.mkdtempSync)((0, import_node_path14.join)((0, import_node_os6.tmpdir)(), "mrrlin-push-"));
46511
- const askpass = (0, import_node_path14.join)(dir, "askpass");
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, import_node_fs7.writeFileSync)(
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, import_node_fs7.chmodSync)(askpass, 320);
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, import_node_fs7.rmSync)(dir, { recursive: true, force: true });
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, import_node_fs7.realpathSync)(opts.worktreeRoot);
46818
+ return (0, import_node_fs10.realpathSync)(opts.worktreeRoot);
46545
46819
  } catch {
46546
46820
  return opts.worktreeRoot;
46547
46821
  }
46548
- })() + import_node_path14.sep + opts.slug + import_node_path14.sep;
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-${import_node_crypto6.default.randomUUID()}`;
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-${import_node_crypto6.default.randomUUID()}`,
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-${import_node_crypto6.default.randomUUID()}`,
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-${import_node_crypto6.default.randomUUID()}`,
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 = import_node_path15.default.relative(import_node_path15.default.resolve(worktreeRoot), import_node_path15.default.resolve(run3.worktreeId));
48663
- return relative === "" || relative.length > 0 && !relative.startsWith("..") && !import_node_path15.default.isAbsolute(relative);
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-${import_node_crypto6.default.randomUUID()}`,
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 import_node_crypto8 = __toESM(require("node:crypto"), 1);
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 import_node_fs8 = require("node:fs");
48986
+ var import_node_fs11 = require("node:fs");
48713
48987
  var import_promises7 = require("node:fs/promises");
48714
- var import_node_path16 = require("node:path");
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 import_node_crypto7 = require("node:crypto");
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, import_node_crypto7.createHash)("sha256").update(status.trim().toLowerCase()).digest("hex").slice(0, 8);
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, import_node_path16.join)(stateDir, "logs");
49264
+ const logsDir = (0, import_node_path19.join)(stateDir, "logs");
48991
49265
  try {
48992
- (0, import_node_fs8.mkdirSync)(logsDir, { recursive: true });
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, import_node_path16.join)(logsDir, `bridge-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
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, import_node_path16.join)(logsDir, ".sessions.json");
49312
+ const sessionsPath = (0, import_node_path19.join)(logsDir, ".sessions.json");
49039
49313
  let sessionsObj = {};
49040
49314
  try {
49041
- const parsed = JSON.parse((0, import_node_fs8.readFileSync)(sessionsPath, "utf8"));
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, import_node_fs8.writeFileSync)(tmpPath, JSON.stringify(sessionsObj));
49052
- (0, import_node_fs8.renameSync)(tmpPath, sessionsPath);
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, import_node_fs8.appendFileSync)(fileFor(), line);
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, import_node_path16.join)(stateDir, "logs", ".sessions.json");
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-${import_node_crypto8.default.randomUUID()}`,
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 ?? import_node_crypto8.default.createHash("sha256").update(page.markdownBody).digest("hex");
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 ?? import_node_crypto8.default.createHash("sha256").update(JSON.stringify(task)).digest("hex");
49584
+ return task.updatedAt ?? import_node_crypto9.default.createHash("sha256").update(JSON.stringify(task)).digest("hex");
49311
49585
  }
49312
- return import_node_crypto8.default.createHash("sha256").update(JSON.stringify(input)).digest("hex");
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 import_node_fs9 = require("node:fs");
49591
- var import_node_os7 = __toESM(require("node:os"), 1);
49592
- var import_node_path17 = __toESM(require("node:path"), 1);
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 ? import_node_path17.default.join(process.env.CODEX_HOME, "mrrlin") : import_node_path17.default.join(import_node_os7.default.homedir(), ".mrrlin");
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 import_node_path17.default.join(operatorDir(), "operator-token");
49872
+ return import_node_path20.default.join(operatorDir(), "operator-token");
49599
49873
  }
49600
49874
  function readOperatorToken() {
49601
49875
  try {
49602
- const token = (0, import_node_fs9.readFileSync)(operatorTokenPath(), "utf8").trim();
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, import_node_fs9.mkdirSync)(dir, { recursive: true, mode: 448 });
49611
- (0, import_node_fs9.writeFileSync)(operatorTokenPath(), `${token.trim()}
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 import_node_path17.default.join(operatorDir(), "agent-credential");
49889
+ return import_node_path20.default.join(operatorDir(), "agent-credential");
49616
49890
  }
49617
49891
  function persistAgentSecret(secret) {
49618
49892
  const dir = operatorDir();
49619
- (0, import_node_fs9.mkdirSync)(dir, { recursive: true, mode: 448 });
49620
- (0, import_node_fs9.writeFileSync)(agentCredentialPath(), `${secret.trim()}
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, import_node_fs9.readFileSync)(agentCredentialPath(), "utf8").trim();
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 import_node_fs10 = require("node:fs");
49636
- var import_node_path18 = __toESM(require("node:path"), 1);
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 import_node_path18.default.join(stateDir, "threads.json");
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, import_node_fs10.readFileSync)(threadIndexPath(stateDir), "utf8"));
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, import_node_fs10.mkdirSync)(stateDir, { recursive: true, mode: 448 });
49668
- (0, import_node_fs10.writeFileSync)(threadIndexPath(stateDir), `${JSON.stringify(Object.fromEntries(entries), null, 2)}
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 import_node_crypto9 = require("node:crypto");
49804
- var import_node_fs11 = require("node:fs");
49805
- var import_node_os8 = __toESM(require("node:os"), 1);
49806
- var import_node_path19 = __toESM(require("node:path"), 1);
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 ? import_node_path19.default.join(process.env.CODEX_HOME, "mrrlin") : import_node_path19.default.join(import_node_os8.default.homedir(), ".mrrlin");
49816
- return import_node_path19.default.join(base, "worker");
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 import_node_path19.default.join(workerDir(), "token");
50093
+ return import_node_path22.default.join(workerDir(), "token");
49820
50094
  }
49821
50095
  function readWorkerToken() {
49822
50096
  try {
49823
- const token = (0, import_node_fs11.readFileSync)(workerTokenPath(), "utf8").trim();
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, import_node_fs11.mkdirSync)(dir, { recursive: true, mode: 448 });
49834
- const token = (0, import_node_crypto9.randomBytes)(32).toString("hex");
49835
- (0, import_node_fs11.writeFileSync)(workerTokenPath(), `${token}
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 import_node_fs12 = require("node:fs");
49843
- var import_node_os9 = require("node:os");
49844
- var import_node_path20 = require("node:path");
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, import_node_path20.join)((0, import_node_os9.homedir)(), ".mrrlin", "agent-device-key");
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, import_node_fs12.readFileSync)(path22, "utf8"));
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, import_node_fs12.mkdirSync)((0, import_node_path20.join)((0, import_node_os9.homedir)(), ".mrrlin"), { recursive: true });
53426
- (0, import_node_fs12.writeFileSync)(
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, import_node_path20.join)((0, import_node_os9.homedir)(), ".mrrlin", "agent-pairing.json");
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, import_node_fs12.readFileSync)(AGENT_PAIRING_PATH, "utf8"));
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, import_node_fs12.mkdirSync)((0, import_node_path20.join)((0, import_node_os9.homedir)(), ".mrrlin"), { recursive: true });
53454
- (0, import_node_fs12.writeFileSync)(AGENT_PAIRING_PATH, JSON.stringify(record2), { mode: 384 });
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 import_node_fs13 = require("node:fs");
53633
- var import_node_path21 = require("node:path");
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, import_node_path21.join)(stateDir, "checkouts.json");
53638
- (0, import_node_fs13.mkdirSync)(stateDir, { recursive: true });
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, import_node_fs13.existsSync)(this.file)) return {};
53915
+ if (!(0, import_node_fs16.existsSync)(this.file)) return {};
53642
53916
  try {
53643
- return JSON.parse((0, import_node_fs13.readFileSync)(this.file, "utf8"));
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, import_node_fs13.writeFileSync)(this.file, JSON.stringify(all, null, 2));
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 import_node_fs14 = require("node:fs");
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, import_node_fs14.realpathSync)(trimmedPath);
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 import_node_fs15 = require("node:fs");
54275
+ var import_node_fs18 = require("node:fs");
54002
54276
  var import_node_readline = require("node:readline");
54003
- var import_node_path22 = require("node:path");
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, import_node_path22.join)(logsDir, f);
54409
+ const filePath = (0, import_node_path25.join)(logsDir, f);
54136
54410
  try {
54137
- const stream = (0, import_node_fs15.createReadStream)(filePath, { encoding: "utf8" });
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 import_node_fs16 = __toESM(require("node:fs"), 1);
54162
- var import_node_os10 = __toESM(require("node:os"), 1);
54163
- var import_node_path23 = __toESM(require("node:path"), 1);
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 = () => import_node_path23.default.join(import_node_os10.default.homedir(), ".local", "state", "external-agents", "keys.env");
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 = import_node_fs16.default.statSync(filePath).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 = import_node_fs16.default.readFileSync(filePath, "utf8");
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 import_node_fs17.default.readFileSync(filePath, "utf8");
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() || import_node_path24.default.join(import_node_os11.default.homedir(), ".codex");
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 = import_node_path24.default.join(codexHome, "models_cache.json");
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(import_node_path24.default.join(codexHome, "config.toml"))) {
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 = import_node_path24.default.join(codexHome, "automations");
54950
+ const automationsDir = import_node_path27.default.join(codexHome, "automations");
54677
54951
  try {
54678
- for (const entry of import_node_fs17.default.readdirSync(automationsDir, { withFileTypes: true })) {
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(import_node_path24.default.join(automationsDir, entry.name, "automation.toml"))) {
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, import_node_crypto10.randomUUID)()}`;
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 = import_node_crypto10.default.createHash("sha256").update(offeredVersion).digest("hex").slice(0, 10);
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 = import_node_path24.default.join(stateDir, "no-checkout");
54980
+ const dir = import_node_path27.default.join(stateDir, "no-checkout");
54707
54981
  try {
54708
- import_node_fs17.default.mkdirSync(dir, { recursive: true });
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 import_node_fs17.default.statSync(worktreePath).mtimeMs < cutoff;
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 import_node_path24.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge");
55257
- return import_node_path24.default.join(import_node_os11.default.homedir(), ".mrrlin", "director-bridge");
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 = import_node_crypto10.default.randomBytes(16).toString("base64url");
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 = import_node_crypto10.default.randomUUID();
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, import_node_os11.default.hostname());
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
- import_node_os11.default.hostname()
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, import_node_crypto10.randomUUID)(),
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: import_node_path24.default.join(config2.stateDir, "worktrees"),
56776
- locksDir: import_node_path24.default.join(config2.stateDir, "locks"),
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 = import_node_fs17.default.mkdtempSync(import_node_path24.default.join(import_node_os11.default.tmpdir(), "mrrlin-verify-"));
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
- import_node_fs17.default.rmSync(cwd, { recursive: true, force: true });
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
- import_node_fs17.default.rmSync(cwd, { recursive: true, force: true });
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, import_node_crypto10.randomUUID)();
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(import_node_path24.default.join(config2.stateDir, "logs"), files, sessionIds);
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 = import_node_crypto10.default.createHash("sha256").update(import_node_fs17.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
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: import_node_path24.default.join(config2.stateDir, "worktrees"),
57278
- locksDir: import_node_path24.default.join(config2.stateDir, "locks")
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
- client.getOperatorSettings().then((settings) => setSelectedProvider(settings.agentProvider)).catch(() => {
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 import_node_crypto10.default.timingSafeEqual(a, b);
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 = import_node_path24.default.join(stateDir, "token.txt");
57899
+ const tokenPath = import_node_path27.default.join(stateDir, "token.txt");
57607
57900
  try {
57608
- const existing = import_node_fs17.default.readFileSync(tokenPath, "utf8").trim();
57901
+ const existing = import_node_fs20.default.readFileSync(tokenPath, "utf8").trim();
57609
57902
  if (existing) return existing;
57610
57903
  } catch {
57611
57904
  }
57612
- import_node_fs17.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
57613
- const token = import_node_crypto10.default.randomBytes(32).toString("base64url");
57614
- import_node_fs17.default.writeFileSync(tokenPath, `${token}
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 import_node_crypto13 = require("node:crypto");
61295
+ var import_node_crypto14 = require("node:crypto");
61003
61296
  var import_promises10 = require("node:fs/promises");
61004
- var import_node_path27 = __toESM(require("node:path"), 1);
61005
- var import_node_os12 = __toESM(require("node:os"), 1);
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 import_node_path25 = __toESM(require("node:path"), 1);
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(import_node_path25.default.sep).join("/");
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 = import_node_path25.default.resolve(start);
61319
+ let current2 = import_node_path28.default.resolve(start);
61027
61320
  while (true) {
61028
- if (await pathExists3(import_node_path25.default.join(current2, "pnpm-workspace.yaml")) && await pathExists3(import_node_path25.default.join(current2, "docs"))) {
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 = import_node_path25.default.dirname(current2);
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 import_node_path25.default.resolve(input);
61333
+ return import_node_path28.default.resolve(input);
61041
61334
  }
61042
61335
  if (process.env.MRRLIN_DOCS_ROOT) {
61043
- return import_node_path25.default.resolve(process.env.MRRLIN_DOCS_ROOT);
61336
+ return import_node_path28.default.resolve(process.env.MRRLIN_DOCS_ROOT);
61044
61337
  }
61045
- return import_node_path25.default.join(await findWorkspaceRoot(), "docs");
61338
+ return import_node_path28.default.join(await findWorkspaceRoot(), "docs");
61046
61339
  }
61047
61340
  async function resolveIndexPath(input) {
61048
61341
  if (input) {
61049
- return import_node_path25.default.resolve(input);
61342
+ return import_node_path28.default.resolve(input);
61050
61343
  }
61051
61344
  if (process.env.MRRLIN_WIKI_INDEX_PATH) {
61052
- return import_node_path25.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
61345
+ return import_node_path28.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
61053
61346
  }
61054
61347
  const workspaceRoot = await findWorkspaceRoot();
61055
- return import_node_path25.default.join(workspaceRoot, "apps", "web", "public", "wiki-index.json");
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 = import_node_path25.default.join(dir, entry.name);
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(import_node_path25.default.relative(docsRoot, absolutePath));
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
- async function dispatchHead(agentId, prompt, timeoutMs, deps) {
61432
- const spawn4 = deps?.spawn ?? import_node_child_process17.spawn;
61433
- const { command, prefixArgs } = resolveExternalAgentsCliInvocation(deps?.externalAgentsBin);
61434
- const args = ["dispatch", agentId, "--json", prompt];
61435
- const r = await runExternalAgents(command, [...prefixArgs, ...args], "dispatch", timeoutMs, spawn4);
61436
- if (r.error) return { ok: false, error: r.error };
61437
- const lines2 = r.stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
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 ${r.code})` };
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
- return { ok: true, text: parsed.text };
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 import_node_crypto11 = require("node:crypto");
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, import_node_crypto11.createHash)("sha256").update(toFile.map((c) => c.rawQuestion).sort().join("\n")).digest("hex").slice(0, 10)}` : void 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, import_node_crypto11.createHash)("sha256").update(clarification.rawQuestion).digest("hex").slice(0, 10)}`;
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, import_node_crypto11.createHash)("sha256").update(toFile.map((c) => c.rawQuestion).sort().join("\n")).digest("hex").slice(0, 10)}` : void 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, import_node_crypto11.createHash)("sha256").update(clarification.rawQuestion).digest("hex").slice(0, 10)}`;
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, import_node_crypto11.createHash)("sha256").update(reviewHash).digest("hex").slice(0, 10)}`;
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 import_node_path26 = require("node:path");
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, import_node_path26.join)(stateDir, "logs", `bridge-${day}.jsonl`), "utf8");
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, import_node_path26.join)(stateDir, "logs", ".pruned.jsonl"), "utf8");
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 import_node_crypto12 = __toESM(require("node:crypto"), 1);
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-${import_node_crypto12.default.randomUUID()}`;
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, import_node_crypto13.randomBytes)(4).toString("hex")}`;
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 = import_node_path27.default.extname(filePath).toLowerCase();
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 = import_node_path27.default.basename(filePath);
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 = import_node_path27.default.extname(filename).toLowerCase();
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 ? import_node_path27.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge") : import_node_path27.default.join(import_node_os12.default.homedir(), ".mrrlin", "director-bridge");
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 }, import_node_os12.default.hostname());
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 import_node_os13 = __toESM(require("node:os"), 1);
64995
- var import_node_path28 = __toESM(require("node:path"), 1);
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 ?? import_node_os13.default.homedir();
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) => import_node_path28.default.dirname(b)), ...SYSTEM_PATH_DIRS])
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 = import_node_path28.default.join(home, ".mrrlin", "ecosystem.config.cjs");
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 import_node_os14 = __toESM(require("node:os"), 1);
65085
- var import_node_path29 = __toESM(require("node:path"), 1);
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 import_node_path29.default.join(options.homeDir ?? import_node_os14.default.homedir(), ".codex");
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 = import_node_path29.default.join(codexHome, "config.toml");
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 = import_node_path29.default.join(codexHome, "prompts");
65481
+ const promptsDir = import_node_path32.default.join(codexHome, "prompts");
65132
65482
  const out = [];
65133
65483
  for (const name of names) {
65134
- const promptPath = import_node_path29.default.join(promptsDir, `${name}.md`);
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 import_node_path30 = require("node:path");
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, import_node_path30.join)(deps.stateDir, "logs", `bridge-${day}.jsonl`);
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, import_node_os15.homedir)();
65290
- const agents = import_node_path32.default.join(home, "Library", "LaunchAgents");
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: import_node_path32.default.join(agents, "com.mrrlin.director-bridge.plist") },
65293
- { label: "com.PM2", plist: import_node_path32.default.join(agents, `pm2.${(0, import_node_os15.userInfo)().username}.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, import_node_fs18.existsSync)(candidate.plist)) continue;
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 ?? import_node_path32.default.join(process.env.HOME ?? (0, import_node_os15.homedir)(), ".codex");
65582
- (0, import_node_fs18.rmSync)(import_node_path32.default.join(codexHome, "prompts", "report-issue.md"), { force: true });
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, import_node_fs18.mkdirSync)(import_node_path32.default.dirname(p), { recursive: true, mode: 448 });
65644
- (0, import_node_fs18.writeFileSync)(p, c, { mode: 384 });
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, import_node_fs18.rmSync)(p, { force: true });
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: import_node_path32.default.join(process.env.HOME ?? (0, import_node_os15.homedir)(), ".mrrlin", "ecosystem.config.cjs"),
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, import_node_os15.homedir)();
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, import_node_fs18.rmSync)(p, { force: true });
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: import_node_path32.default.join(home, ".mrrlin", "ecosystem.config.cjs"),
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, import_node_fs18.rmSync)(import_node_path32.default.join(home, ".mrrlin"), { recursive: true, force: true });
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 import_node_path31.default.resolve(process.argv[1] ?? process.execPath);
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)}