@mrrlin-dev/mcp 0.4.41 → 0.4.43

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 +957 -282
  2. package/package.json +1 -1
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_fs19 = 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;
@@ -36816,6 +36816,17 @@ var ARTIFACT_CHECKS = {
36816
36816
  structured_data: null,
36817
36817
  message: { verifier: "status" }
36818
36818
  };
36819
+ var ARTIFACT_DESTINATIONS = {
36820
+ document: "wiki",
36821
+ page: "git",
36822
+ file_set: null,
36823
+ code_change: "git",
36824
+ structured_data: null,
36825
+ message: null
36826
+ };
36827
+ function resolveKindCapability(kind) {
36828
+ return ARTIFACT_DESTINATIONS[kind];
36829
+ }
36819
36830
 
36820
36831
  // ../../packages/schemas/dist/operationIds.js
36821
36832
  var openApiOperationIds = {
@@ -36957,7 +36968,11 @@ var openApiOperationIds = {
36957
36968
  upsertCapabilityRoute: "upsertCapabilityRoute",
36958
36969
  resolveCapabilityRoute: "resolveCapabilityRoute",
36959
36970
  overrideCapabilityToolClass: "overrideCapabilityToolClass",
36960
- listCapabilityUses: "listCapabilityUses"
36971
+ listCapabilityUses: "listCapabilityUses",
36972
+ confirmFirstWrite: "confirmFirstWrite",
36973
+ resolveArtifactKindRoute: "resolveArtifactKindRoute",
36974
+ resolveDeliveryForArtifactKind: "resolveDeliveryForArtifactKind",
36975
+ recordCapabilityUse: "recordCapabilityUse"
36961
36976
  };
36962
36977
 
36963
36978
  // ../../packages/schemas/dist/session.js
@@ -37206,7 +37221,7 @@ var mrrlinAsyncJobRequeueSchema = external_exports.object({
37206
37221
  });
37207
37222
 
37208
37223
  // ../../packages/schemas/dist/telemetry.js
37209
- var LOG_PROJECTION_KINDS = ["tool_use", "tool_result", "turn_lifecycle", "plumbing"];
37224
+ var LOG_PROJECTION_KINDS = ["tool_use", "tool_result", "turn_lifecycle", "plumbing", "gate_call"];
37210
37225
  var PLUMBING_KINDS = [
37211
37226
  "socket_close",
37212
37227
  "ready",
@@ -37272,14 +37287,60 @@ var telemetryRowSchema = external_exports.object({
37272
37287
  projectionFailures: external_exports.number(),
37273
37288
  gateMarker: external_exports.enum(GATE_MARKERS)
37274
37289
  });
37290
+ var GATE_KINDS = ["spec", "code", "deliverable"];
37291
+ var GATE_CALL_ROLES = ["head", "arbiter", "reviser", "findings"];
37292
+ var gateCallRecordSchema = external_exports.object({
37293
+ day: external_exports.string(),
37294
+ gate: external_exports.enum(GATE_KINDS),
37295
+ /**
37296
+ * The gate's own round, 1-based. Zero is legal and means "outside the loop": spec-gate.ts makes
37297
+ * one reviser call BEFORE runConsensus is ever entered, and labelling it round 1 would put a
37298
+ * pre-loop call inside a round that had not started.
37299
+ */
37300
+ round: external_exports.number(),
37301
+ role: external_exports.enum(GATE_CALL_ROLES),
37302
+ /** The persona file driving the call, or null for a role that loads none (the revisers). */
37303
+ persona: external_exports.string().nullable(),
37304
+ /** Null where the call site minted no seat and therefore genuinely does not know — a guessed
37305
+ * provider on a cost record is worse than an absent one. */
37306
+ provider: external_exports.string().nullable(),
37307
+ agentId: external_exports.string().nullable(),
37308
+ inputTokens: external_exports.number().nullable(),
37309
+ cachedInputTokens: external_exports.number().nullable(),
37310
+ cacheWriteInputTokens: external_exports.number().nullable(),
37311
+ outputTokens: external_exports.number().nullable(),
37312
+ durationMs: external_exports.number()
37313
+ });
37275
37314
  var telemetryBatchSchema = external_exports.object({
37276
37315
  day: external_exports.string(),
37277
37316
  bridgeVersion: external_exports.string(),
37317
+ /**
37318
+ * Which installation produced this batch. OPTIONAL on the wire on purpose: a bridge that has not
37319
+ * restarted after deploy still posts batches, and rejecting them would turn a rollout window into
37320
+ * data loss. The API resolves a missing value to the literal installation `legacy`, which is
37321
+ * exactly today's behaviour — one shared slot — so nothing regresses while everything that does
37322
+ * send an id gains its own.
37323
+ */
37324
+ installationId: external_exports.string().optional(),
37278
37325
  knownCrashCount: external_exports.number(),
37279
37326
  // pairs still lacking .processed-* after this run completes; a project that never uploads at
37280
37327
  // all cannot report its own gap this way — silence is not coverage.
37281
37328
  unprocessedPartitions: external_exports.array(external_exports.object({ projectSlug: external_exports.string(), day: external_exports.string() })),
37282
- rows: external_exports.array(telemetryRowSchema)
37329
+ rows: external_exports.array(telemetryRowSchema),
37330
+ /**
37331
+ * Consensus-gate provider calls for this day. Optional, exactly like `installationId` above and
37332
+ * for the same reason: a bridge that makes no gate call, and every uploader built before this
37333
+ * field existed, must keep producing a valid batch — a rollout window is not allowed to become
37334
+ * data loss.
37335
+ *
37336
+ * `.optional()` rather than `.default([])`, which was tried first. A Zod default splits the
37337
+ * schema's input type from its output type, so the parsed batch would carry a REQUIRED
37338
+ * `gateCalls` while producers do not — and every construction site (the uploader, the store
37339
+ * tests, the ingest tests) would then have to name a field it has no opinion about. An absent
37340
+ * array and an empty one mean the same thing to every reader here, so the split buys nothing and
37341
+ * costs a trap.
37342
+ */
37343
+ gateCalls: external_exports.array(gateCallRecordSchema).optional()
37283
37344
  });
37284
37345
  var evidenceStepSchema = external_exports.object({
37285
37346
  toolName: external_exports.string(),
@@ -37487,6 +37548,18 @@ var mrrlinDeclaredOutcomeSchema = mrrlinDeclaredOutcomeShapeSchema.superRefine((
37487
37548
  message: `requires spans more than one verifier, so no receipt can ever satisfy it (${spread}). Declare the outcome rather than the steps that produced it; if two things must genuinely exist and neither is a means to the other, split them into linked tasks.`
37488
37549
  });
37489
37550
  }
37551
+ const distinctCapabilities = new Set(value.requires.map((kind) => resolveKindCapability(kind)).filter((capability) => capability !== null));
37552
+ if (distinctCapabilities.size > 1) {
37553
+ const spread = value.requires.map((kind) => {
37554
+ const capability = resolveKindCapability(kind);
37555
+ return capability === null ? `${kind} has no destination` : `${kind} routes to ${capability}`;
37556
+ }).join(", ");
37557
+ ctx.addIssue({
37558
+ code: external_exports.ZodIssueCode.custom,
37559
+ path: ["requires"],
37560
+ message: `requires spans more than one capability, so no single delivery can satisfy it (${spread}). Split into linked tasks, one per destination.`
37561
+ });
37562
+ }
37490
37563
  const hasVerifiableKind = value.requires.some((kind) => ARTIFACT_CHECKS[kind] !== null);
37491
37564
  const hasUnverifiableKind = value.requires.some((kind) => ARTIFACT_CHECKS[kind] === null);
37492
37565
  if (value.verification === "human_tap" && hasVerifiableKind) {
@@ -37614,6 +37687,13 @@ var mrrlinRunBlockingReasonCodeSchema = external_exports.enum([
37614
37687
  // with a task-content block; before it existed such a failure fell through to `unknown` and was
37615
37688
  // handed off to the operator as though the Director had judged the task.
37616
37689
  "provider_limit_exhausted",
37690
+ // Крок 3, task 8.1: the dispatch pre-flight's own refusal — the task's declared outcome requires
37691
+ // an artifact kind with no capability route at all (client-side, resolveKindCapability) or no
37692
+ // configured route in this project (server-side, resolveArtifactKindRoute). Distinct from
37693
+ // `task_blocked` (which is about blocker TASKS, not this run's own delivery destination): a task
37694
+ // whose blockers clear can start; a task whose required kind cannot route needs an operator to
37695
+ // configure the missing route before any retry would succeed.
37696
+ "capability_not_routed",
37617
37697
  "unknown"
37618
37698
  ]);
37619
37699
  var mrrlinExecutionArtifactKindSchema = external_exports.enum([
@@ -37694,6 +37774,13 @@ var mrrlinStopReasonSchema = external_exports.enum([
37694
37774
  "consensus_disabled_spec_not_ready",
37695
37775
  "spec_approval_pending",
37696
37776
  "awaiting_handoff",
37777
+ // Крок 3 (delivery-as-capability-call), task 3.1: the parked reason for an open capability
37778
+ // question (origin: "capability"), the same shape as awaiting_clarification's own open gate
37779
+ // question (origin: "gate") one line above -- caught by the whole-change gate (task 9.3), not
37780
+ // task 3.1 itself: this schema and mrrlinSchedulerParkedReasonSchema are siblings apps/web's
37781
+ // autopilotQueue.ts assumes stay in lockstep (every parked reason not explicitly remapped is
37782
+ // used as a stop reason directly), and no per-package typecheck in this change ever ran apps/web.
37783
+ "awaiting_capability_decision",
37697
37784
  "assigned_to_other",
37698
37785
  "backlog",
37699
37786
  "attempts_exhausted",
@@ -38877,7 +38964,11 @@ var mrrlinSchedulerParkedReasonSchema = external_exports.enum([
38877
38964
  "awaiting_handoff",
38878
38965
  "awaiting_clarification",
38879
38966
  "spec_awaiting_approval",
38880
- "blocked_by_active"
38967
+ "blocked_by_active",
38968
+ // Derived, not stored (design.md, "Parking is derived"): an open `question` inbox item with
38969
+ // `origin === "capability"` yields this reason, exactly as an `origin === "gate"` one already
38970
+ // yields `awaiting_clarification`. No column, and nobody but the derivation may set it.
38971
+ "awaiting_capability_decision"
38881
38972
  ]);
38882
38973
  var mrrlinSchedulerParkedTaskSchema = external_exports.object({
38883
38974
  task: mrrlinTaskSchema,
@@ -39216,6 +39307,16 @@ var capabilityRouteResponseSchema = external_exports.object({ data: CapabilityRo
39216
39307
  var capabilityRouteListResponseSchema = external_exports.object({ data: external_exports.array(CapabilityRouteSchema) });
39217
39308
  var capabilityToolClassResponseSchema = external_exports.object({ data: CapabilityToolClassSchema });
39218
39309
  var capabilityUseListResponseSchema = external_exports.object({ data: external_exports.array(CapabilityUseSchema) });
39310
+ var capabilityUseResponseSchema = external_exports.object({ data: CapabilityUseSchema.nullable() });
39311
+ var capabilityUseCreateSchema = external_exports.object({
39312
+ serverId: capabilityServerIdSchema,
39313
+ toolName: capabilityToolNameSchema,
39314
+ taskId: mrrlinTaskIdSchema.nullable(),
39315
+ outcome: capabilityUseOutcomeSchema
39316
+ });
39317
+ var deliveryResolutionResponseSchema = external_exports.object({
39318
+ data: external_exports.object({ route: CapabilityRouteSchema, verdict: CapabilityGateVerdictSchema })
39319
+ });
39219
39320
 
39220
39321
  // ../../packages/agent-client/dist/providers/codex/render-context-bundle.js
39221
39322
  var DEFAULT_SPEC_BUDGET_CHARS = 6e3;
@@ -40044,6 +40145,68 @@ function resolveProvider(env, persisted) {
40044
40145
 
40045
40146
  // ../../packages/agent-client/dist/providers/codex/exec.js
40046
40147
  var import_node_child_process5 = require("node:child_process");
40148
+
40149
+ // ../../packages/agent-client/dist/exec-usage.js
40150
+ function readCount2(source, ...keys) {
40151
+ for (const key of keys) {
40152
+ const value = source[key];
40153
+ if (typeof value === "number" && Number.isFinite(value))
40154
+ return value;
40155
+ }
40156
+ return null;
40157
+ }
40158
+ function fromBlock(block) {
40159
+ const usage = {
40160
+ inputTokens: readCount2(block, "input_tokens", "inputTokens"),
40161
+ cachedInputTokens: readCount2(block, "cached_input_tokens", "cache_read_input_tokens", "cachedInputTokens"),
40162
+ cacheWriteInputTokens: readCount2(block, "cache_write_input_tokens", "cache_creation_input_tokens", "cacheWriteInputTokens"),
40163
+ outputTokens: readCount2(block, "output_tokens", "outputTokens")
40164
+ };
40165
+ const measuredNothing = usage.inputTokens === null && usage.cachedInputTokens === null && usage.cacheWriteInputTokens === null && usage.outputTokens === null;
40166
+ return measuredNothing ? null : usage;
40167
+ }
40168
+ function extractCodexExecUsage(stdout) {
40169
+ let last = null;
40170
+ for (const rawLine of stdout.split(/\r?\n/)) {
40171
+ const line = rawLine.trim();
40172
+ if (!line || line[0] !== "{")
40173
+ continue;
40174
+ let event;
40175
+ try {
40176
+ event = JSON.parse(line);
40177
+ } catch {
40178
+ continue;
40179
+ }
40180
+ if (typeof event !== "object" || event === null)
40181
+ continue;
40182
+ const usage = event.usage;
40183
+ if (typeof usage !== "object" || usage === null)
40184
+ continue;
40185
+ const parsed = fromBlock(usage);
40186
+ if (parsed !== null)
40187
+ last = parsed;
40188
+ }
40189
+ return last;
40190
+ }
40191
+ function extractClaudeExecUsage(parsed) {
40192
+ if (!Array.isArray(parsed))
40193
+ return null;
40194
+ for (let i = parsed.length - 1; i >= 0; i -= 1) {
40195
+ const element = parsed[i];
40196
+ if (typeof element !== "object" || element === null)
40197
+ continue;
40198
+ const record2 = element;
40199
+ if (record2.type !== "result")
40200
+ continue;
40201
+ const usage = record2.usage;
40202
+ if (typeof usage !== "object" || usage === null)
40203
+ return null;
40204
+ return fromBlock(usage);
40205
+ }
40206
+ return null;
40207
+ }
40208
+
40209
+ // ../../packages/agent-client/dist/providers/codex/exec.js
40047
40210
  function extractFinalMessage(stdout) {
40048
40211
  let last = null;
40049
40212
  for (const rawLine of stdout.split(/\r?\n/)) {
@@ -40164,7 +40327,7 @@ ${input.prompt}` : input.prompt;
40164
40327
  finish({ ok: false, error: "codex exec produced no parseable assistant message" });
40165
40328
  return;
40166
40329
  }
40167
- finish({ ok: true, text });
40330
+ finish({ ok: true, text, usage: extractCodexExecUsage(stdout) });
40168
40331
  });
40169
40332
  });
40170
40333
  }
@@ -40269,7 +40432,7 @@ function extractOneShotResult(stdout) {
40269
40432
  if (typeof resultEvent.result !== "string") {
40270
40433
  return { ok: false, error: "claude exec's 'result' event had no string result field" };
40271
40434
  }
40272
- return { ok: true, text: resultEvent.result };
40435
+ return { ok: true, text: resultEvent.result, usage: extractClaudeExecUsage(parsed) };
40273
40436
  }
40274
40437
  function errMessage2(err) {
40275
40438
  return err instanceof Error ? err.message : String(err);
@@ -40443,6 +40606,12 @@ function createAgentTokenProvider(opts) {
40443
40606
  }
40444
40607
 
40445
40608
  // ../../packages/client/dist/index.js
40609
+ var CAPABILITY_ROUTE_RESOLUTION_REASON_BY_CODE = {
40610
+ NO_ROUTE: "no_route",
40611
+ NO_GRANT: "no_grant",
40612
+ PROJECT_MISMATCH: "project_mismatch",
40613
+ AMBIGUOUS_ROUTE: "ambiguous_route"
40614
+ };
40446
40615
  function appendQuery(url2, params) {
40447
40616
  const search = new URLSearchParams();
40448
40617
  for (const [key, value] of Object.entries(params)) {
@@ -41072,6 +41241,52 @@ function createMrrlinClient(config2) {
41072
41241
  const body = await request(`${projectPath(projectSlug)}/capability-grants/${encodeURIComponent(serverId)}`, { method: "DELETE" });
41073
41242
  return capabilityGrantResponseSchema.parse(body).data;
41074
41243
  },
41244
+ async confirmFirstWrite(projectSlug, serverId) {
41245
+ try {
41246
+ const body = await request(`${projectPath(projectSlug)}/capability-grants/${encodeURIComponent(serverId)}/first-write-confirmation`, { method: "POST" });
41247
+ return capabilityGrantResponseSchema.parse(body).data;
41248
+ } catch (error51) {
41249
+ if (error51 instanceof MrrlinApiError && error51.code === "NO_GRANT")
41250
+ return null;
41251
+ throw error51;
41252
+ }
41253
+ },
41254
+ async resolveArtifactKindRoute(projectSlug, artifactKind, taskProjectSlug) {
41255
+ try {
41256
+ const body = await request(`${projectPath(projectSlug)}/artifact-kinds/${encodeURIComponent(artifactKind)}/resolution?taskProjectSlug=${encodeURIComponent(taskProjectSlug)}`, { method: "POST" });
41257
+ return { ok: true, route: capabilityRouteResponseSchema.parse(body).data };
41258
+ } catch (error51) {
41259
+ if (error51 instanceof MrrlinApiError) {
41260
+ const reason = CAPABILITY_ROUTE_RESOLUTION_REASON_BY_CODE[error51.code];
41261
+ if (reason)
41262
+ return { ok: false, reason, message: error51.message };
41263
+ }
41264
+ throw error51;
41265
+ }
41266
+ },
41267
+ async resolveDeliveryForArtifactKind(projectSlug, artifactKind, taskProjectSlug, taskId) {
41268
+ try {
41269
+ const url2 = appendQuery(`${projectPath(projectSlug)}/artifact-kinds/${encodeURIComponent(artifactKind)}/delivery-resolution`, { taskProjectSlug, taskId });
41270
+ const body = await request(url2, { method: "POST" });
41271
+ const { route, verdict } = deliveryResolutionResponseSchema.parse(body).data;
41272
+ return { ok: true, route, verdict };
41273
+ } catch (error51) {
41274
+ if (error51 instanceof MrrlinApiError) {
41275
+ const reason = CAPABILITY_ROUTE_RESOLUTION_REASON_BY_CODE[error51.code];
41276
+ if (reason)
41277
+ return { ok: false, reason, message: error51.message };
41278
+ }
41279
+ throw error51;
41280
+ }
41281
+ },
41282
+ async recordCapabilityUse(projectSlug, input) {
41283
+ const body = await request(`${projectPath(projectSlug)}/capability-uses`, {
41284
+ body: JSON.stringify(input),
41285
+ headers: { "content-type": "application/json" },
41286
+ method: "POST"
41287
+ });
41288
+ return capabilityUseResponseSchema.parse(body).data;
41289
+ },
41075
41290
  async listInboxItems(projectSlug, filters = {}) {
41076
41291
  const url2 = appendQuery(`${projectPath(projectSlug)}/inbox`, {
41077
41292
  groupId: filters.groupId,
@@ -42080,7 +42295,7 @@ Do NOT derail the current task - if the operator has an in-flight question, answ
42080
42295
  }
42081
42296
 
42082
42297
  // src/_generated/version.ts
42083
- var PKG_VERSION = "0.4.41";
42298
+ var PKG_VERSION = "0.4.43";
42084
42299
 
42085
42300
  // src/api-base-url-migrate.ts
42086
42301
  var import_node_fs3 = __toESM(require("node:fs"), 1);
@@ -42983,14 +43198,37 @@ async function foldClosedDays(stateDir, today) {
42983
43198
 
42984
43199
  // src/telemetry/daily-uploader.ts
42985
43200
  var import_promises6 = require("node:fs/promises");
42986
- var import_node_path12 = require("node:path");
43201
+ var import_node_path15 = require("node:path");
42987
43202
 
42988
43203
  // src/consensus/wiring.ts
42989
43204
  var import_node_crypto4 = __toESM(require("node:crypto"), 1);
42990
- var import_node_fs5 = __toESM(require("node:fs"), 1);
42991
- var import_node_path11 = __toESM(require("node:path"), 1);
43205
+ var import_node_fs7 = __toESM(require("node:fs"), 1);
43206
+ var import_node_path13 = __toESM(require("node:path"), 1);
42992
43207
  var import_node_url2 = require("node:url");
42993
43208
 
43209
+ // src/consensus/gate-usage-log.ts
43210
+ var import_node_fs5 = require("node:fs");
43211
+ var import_node_path11 = require("node:path");
43212
+ function recordGateCall(stateDir, projectSlug, record2) {
43213
+ try {
43214
+ const dir = (0, import_node_path11.join)(stateDir, "telemetry");
43215
+ (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
43216
+ (0, import_node_fs5.appendFileSync)((0, import_node_path11.join)(dir, gateFileName(projectSlug, record2.day)), `${JSON.stringify(record2)}
43217
+ `, "utf8");
43218
+ } catch {
43219
+ }
43220
+ }
43221
+ var SAFE_SLUG = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
43222
+ function gateFileName(projectSlug, day) {
43223
+ if (!SAFE_SLUG.test(projectSlug)) {
43224
+ throw new Error(`refusing to build a telemetry partition name from an unsafe project slug: ${JSON.stringify(projectSlug)}`);
43225
+ }
43226
+ return `gate-${projectSlug}-${day}.jsonl`;
43227
+ }
43228
+ function telemetryDay(now = /* @__PURE__ */ new Date()) {
43229
+ return now.toISOString().slice(0, 10);
43230
+ }
43231
+
42994
43232
  // src/consensus/verdict.ts
42995
43233
  var CATEGORIES = [
42996
43234
  "correctness",
@@ -43840,6 +44078,16 @@ ${issuesBlock}`,
43840
44078
  }
43841
44079
  }
43842
44080
 
44081
+ // src/consensus/sterile-cwd.ts
44082
+ var import_node_fs6 = require("node:fs");
44083
+ var import_node_os6 = require("node:os");
44084
+ var import_node_path12 = require("node:path");
44085
+ var sterileDir = null;
44086
+ function sterileCwd() {
44087
+ sterileDir ??= (0, import_node_fs6.mkdtempSync)((0, import_node_path12.join)((0, import_node_os6.tmpdir)(), "mrrlin-gate-"));
44088
+ return sterileDir;
44089
+ }
44090
+
43843
44091
  // src/consensus/code-gate-git.ts
43844
44092
  var import_node_child_process8 = require("node:child_process");
43845
44093
  var DIFF_MAX_BYTES = 2e5;
@@ -44072,15 +44320,15 @@ ${res.stdout}${res.stderr}`);
44072
44320
  var import_meta2 = {};
44073
44321
  function getPersonasDir() {
44074
44322
  if (typeof __dirname !== "undefined") {
44075
- return import_node_path11.default.join(__dirname, "consensus", "personas");
44323
+ return import_node_path13.default.join(__dirname, "consensus", "personas");
44076
44324
  }
44077
- return import_node_path11.default.join(import_node_path11.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "personas");
44325
+ return import_node_path13.default.join(import_node_path13.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "personas");
44078
44326
  }
44079
44327
  var personaCache = /* @__PURE__ */ new Map();
44080
44328
  function loadPersona(name) {
44081
44329
  const cached2 = personaCache.get(name);
44082
44330
  if (cached2 !== void 0) return cached2;
44083
- const content = import_node_fs5.default.readFileSync(import_node_path11.default.join(getPersonasDir(), `${name}.md`), "utf8");
44331
+ const content = import_node_fs7.default.readFileSync(import_node_path13.default.join(getPersonasDir(), `${name}.md`), "utf8");
44084
44332
  personaCache.set(name, content);
44085
44333
  return content;
44086
44334
  }
@@ -44118,8 +44366,36 @@ function reviserIdentityInstructions(taskId, title) {
44118
44366
  ` : "";
44119
44367
  return `${lock}You revise a spec to address accepted issues. Return ONLY the full revised markdown, no commentary.`;
44120
44368
  }
44369
+ function gateCallRecorder(args) {
44370
+ let round = 0;
44371
+ let headSinceArbiter = false;
44372
+ return function record2(role, persona, agentId, startedAt, result) {
44373
+ if (role === "head" && !headSinceArbiter) {
44374
+ round += 1;
44375
+ headSinceArbiter = true;
44376
+ }
44377
+ if (role === "arbiter") headSinceArbiter = false;
44378
+ if (args.stateDir === void 0) return;
44379
+ const usage = "usage" in result ? result.usage : null;
44380
+ recordGateCall(args.stateDir, args.projectSlug, {
44381
+ day: telemetryDay(),
44382
+ gate: args.gate,
44383
+ round,
44384
+ role,
44385
+ persona,
44386
+ agentId,
44387
+ provider: args.provider,
44388
+ inputTokens: usage?.inputTokens ?? null,
44389
+ cachedInputTokens: usage?.cachedInputTokens ?? null,
44390
+ cacheWriteInputTokens: usage?.cacheWriteInputTokens ?? null,
44391
+ outputTokens: usage?.outputTokens ?? null,
44392
+ durationMs: Date.now() - startedAt
44393
+ });
44394
+ };
44395
+ }
44121
44396
  function buildSpecGateDeps(args) {
44122
- const { client, projectSlug, specPageId, cwd, codexExecutable, extraHeadCount = 0, seat } = args;
44397
+ const { client, projectSlug, specPageId, codexExecutable, extraHeadCount = 0, seat, stateDir } = args;
44398
+ const recordCost = gateCallRecorder({ stateDir, projectSlug, gate: "spec", provider: seat?.id ?? null });
44123
44399
  const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
44124
44400
  const maxHeadCalls = 2 * rounds * (MAX_DOMAIN_HEADS + extraHeadCount + 2);
44125
44401
  const timeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
@@ -44194,7 +44470,8 @@ function buildSpecGateDeps(args) {
44194
44470
  const persona = loadPersona(personaName);
44195
44471
  const { taskId, title, seed, impact, adjudicated } = await loadIntent();
44196
44472
  const intentBlock = specHeadIntentBlock(taskId, title, seed, impact, adjudicated);
44197
- return runAgentExec(
44473
+ const startedAt = Date.now();
44474
+ const result = await runAgentExec(
44198
44475
  {
44199
44476
  prompt: `Review this spec against the operator's intent.
44200
44477
 
@@ -44203,19 +44480,26 @@ ${dismissed}
44203
44480
  ${intentBlock}--- SPEC ---
44204
44481
  ${artifact}`,
44205
44482
  developerInstructions: persona,
44206
- cwd,
44483
+ // Every provider call in this factory runs from the empty per-process directory rather
44484
+ // than the caller's repository — see sterile-cwd.ts for the measurement and the accepted
44485
+ // risk. Nothing in a spec review reads the repository: the artifact and the operator
44486
+ // intent are both in the prompt above.
44487
+ cwd: sterileCwd(),
44207
44488
  timeoutMs,
44208
44489
  sandbox: "read-only",
44209
44490
  codexExecutable
44210
44491
  }
44211
44492
  );
44493
+ recordCost("head", personaName, null, startedAt, result);
44494
+ return result;
44212
44495
  },
44213
44496
  async runArbiter(prompt) {
44214
- return runAgentExec(
44497
+ const startedAt = Date.now();
44498
+ const result = await runAgentExec(
44215
44499
  {
44216
44500
  prompt,
44217
44501
  developerInstructions: loadPersona("arbiter"),
44218
- cwd,
44502
+ cwd: sterileCwd(),
44219
44503
  timeoutMs,
44220
44504
  sandbox: "read-only",
44221
44505
  codexExecutable,
@@ -44224,11 +44508,14 @@ ${artifact}`,
44224
44508
  model: seat?.models.strong
44225
44509
  }
44226
44510
  );
44511
+ recordCost("arbiter", "arbiter", seat?.models.strong ?? null, startedAt, result);
44512
+ return result;
44227
44513
  },
44228
44514
  async runReviser(artifact, accepted) {
44229
44515
  const acceptedList = accepted.map((a) => `- (${a.category}) ${a.text}`).join("\n");
44230
44516
  const { taskId, title } = await loadIntent();
44231
- return runAgentExec(
44517
+ const startedAt = Date.now();
44518
+ const result = await runAgentExec(
44232
44519
  {
44233
44520
  prompt: `Accepted issues:
44234
44521
  ${acceptedList}
@@ -44236,12 +44523,16 @@ ${acceptedList}
44236
44523
  --- SPEC ---
44237
44524
  ${artifact}`,
44238
44525
  developerInstructions: reviserIdentityInstructions(taskId, title),
44239
- cwd,
44526
+ // Sterile like the rest of this factory: the spec reviser rewrites the markdown it is
44527
+ // handed and returns it, so unlike the CODE gate's reviser it never touches a worktree.
44528
+ cwd: sterileCwd(),
44240
44529
  timeoutMs,
44241
44530
  sandbox: "read-only",
44242
44531
  codexExecutable
44243
44532
  }
44244
44533
  );
44534
+ recordCost("reviser", null, null, startedAt, result);
44535
+ return result;
44245
44536
  },
44246
44537
  async casUpdateSpec(markdownBody, expectedHash) {
44247
44538
  try {
@@ -44288,9 +44579,17 @@ ${artifact}`,
44288
44579
  const rounds2 = r["rounds"];
44289
44580
  const history = r["history"];
44290
44581
  const highlights = await curateFindings(Array.isArray(history) ? history : [], {
44291
- runCodexExec: runAgentExec,
44582
+ // Wrapped, not passed raw: this is the one gate provider call that does NOT go through a
44583
+ // `deps.run*` function, so without this the post-gate findings pass would be the single
44584
+ // call the cost record silently omits.
44585
+ runCodexExec: async (input) => {
44586
+ const startedAt = Date.now();
44587
+ const result = await runAgentExec(input);
44588
+ recordCost("findings", "findings-writer", null, startedAt, result);
44589
+ return result;
44590
+ },
44292
44591
  loadPersona,
44293
- cwd,
44592
+ cwd: sterileCwd(),
44294
44593
  timeoutMs,
44295
44594
  codexExecutable
44296
44595
  });
@@ -44313,7 +44612,8 @@ ${artifact}`,
44313
44612
  };
44314
44613
  }
44315
44614
  function buildCodeGateDeps(args) {
44316
- const { client, projectSlug, baseRef, cwd, codexExecutable, extraHeads, seat } = args;
44615
+ const { client, projectSlug, baseRef, cwd, codexExecutable, extraHeads, seat, stateDir } = args;
44616
+ const recordCost = gateCallRecorder({ stateDir, projectSlug, gate: "code", provider: seat?.id ?? null });
44317
44617
  const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
44318
44618
  const heads = ["code-reviewer", ...extraHeads ?? []];
44319
44619
  const maxHeadCalls = 2 * rounds * (heads.length + 2);
@@ -44336,7 +44636,8 @@ function buildCodeGateDeps(args) {
44336
44636
  },
44337
44637
  async runHead(personaName, artifact, dismissed) {
44338
44638
  const persona = loadPersona(personaName);
44339
- return runAgentExec({
44639
+ const startedAt = Date.now();
44640
+ const result = await runAgentExec({
44340
44641
  prompt: `Review this code diff.
44341
44642
 
44342
44643
  ${dismissed}
@@ -44344,17 +44645,23 @@ ${dismissed}
44344
44645
  --- DIFF ---
44345
44646
  ${artifact}`,
44346
44647
  developerInstructions: persona,
44347
- cwd,
44648
+ // Read-only review of a diff that is entirely in the prompt — sterile, per sterile-cwd.ts.
44649
+ // This factory is the ONE that stays mixed: runReviser below keeps the real `cwd` because
44650
+ // it edits the branch, and the git helpers keep it because they are not provider calls.
44651
+ cwd: sterileCwd(),
44348
44652
  timeoutMs: headTimeoutMs,
44349
44653
  sandbox: "read-only",
44350
44654
  codexExecutable
44351
44655
  });
44656
+ recordCost("head", personaName, null, startedAt, result);
44657
+ return result;
44352
44658
  },
44353
44659
  async runArbiter(prompt) {
44354
- return runAgentExec({
44660
+ const startedAt = Date.now();
44661
+ const result = await runAgentExec({
44355
44662
  prompt,
44356
44663
  developerInstructions: loadPersona("arbiter"),
44357
- cwd,
44664
+ cwd: sterileCwd(),
44358
44665
  timeoutMs: headTimeoutMs,
44359
44666
  sandbox: "read-only",
44360
44667
  codexExecutable,
@@ -44362,21 +44669,30 @@ ${artifact}`,
44362
44669
  // strongest model.
44363
44670
  model: seat?.models.strong
44364
44671
  });
44672
+ recordCost("arbiter", "arbiter", seat?.models.strong ?? null, startedAt, result);
44673
+ return result;
44365
44674
  },
44366
44675
  async runReviser(artifact, accepted) {
44367
44676
  const acceptedList = accepted.map((a) => `- (${a.category}) ${a.text}`).join("\n");
44368
- return runAgentExec({
44677
+ const startedAt = Date.now();
44678
+ const result = await runAgentExec({
44369
44679
  prompt: `Accepted issues to fix:
44370
44680
  ${acceptedList}
44371
44681
 
44372
44682
  --- DIFF ---
44373
44683
  ${artifact}`,
44374
44684
  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.",
44685
+ // The real repository root, NOT sterileCwd(): this is the one gate call that runs
44686
+ // `workspace-write` and edits the branch, so a sterile cwd would point the sandbox at an
44687
+ // empty directory and the revision would silently apply to nothing — the gate would keep
44688
+ // reporting rounds while fixing no code at all.
44375
44689
  cwd,
44376
44690
  timeoutMs: reviserTimeoutMs,
44377
44691
  sandbox: "workspace-write",
44378
44692
  codexExecutable
44379
44693
  });
44694
+ recordCost("reviser", null, null, startedAt, result);
44695
+ return result;
44380
44696
  },
44381
44697
  checkpoint() {
44382
44698
  return checkpoint(gitArgs);
@@ -44397,7 +44713,8 @@ function renderCriteriaBlock(criteria) {
44397
44713
  return criteria.map((c, i) => `${i + 1}. [ ] ${c}`).join("\n");
44398
44714
  }
44399
44715
  async function buildDeliverableGateDeps(args) {
44400
- const { client, projectSlug, deliverablePageId, attemptOutcome, cwd, codexExecutable, runId, seat } = args;
44716
+ const { client, projectSlug, deliverablePageId, attemptOutcome, codexExecutable, runId, seat, stateDir } = args;
44717
+ const recordCost = gateCallRecorder({ stateDir, projectSlug, gate: "deliverable", provider: seat?.id ?? null });
44401
44718
  const rounds = Number(process.env["MRRLIN_CONSENSUS_ROUNDS"] ?? 5);
44402
44719
  const timeoutMs = Number(process.env["MRRLIN_CONSENSUS_HEAD_TIMEOUT_MS"] ?? 15e4);
44403
44720
  const page = await client.getWikiPage(projectSlug, deliverablePageId);
@@ -44443,7 +44760,8 @@ async function buildDeliverableGateDeps(args) {
44443
44760
  },
44444
44761
  async runHead(personaName, artifact, dismissed) {
44445
44762
  const persona = loadPersona(personaName);
44446
- return runAgentExec({
44763
+ const startedAt = Date.now();
44764
+ const result = await runAgentExec({
44447
44765
  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.
44448
44766
 
44449
44767
  ${dismissed}
@@ -44458,17 +44776,23 @@ ${artifact}`,
44458
44776
  developerInstructions: `${DELIVERABLE_ANTIINJECTION_INSTRUCTION}
44459
44777
 
44460
44778
  ${persona}`,
44461
- cwd,
44779
+ // Sterile, like every other provider call in this factory — see sterile-cwd.ts. It also
44780
+ // narrows the anti-injection surface: a deliverable that tries to talk the head into
44781
+ // reading files now has no repository under it to read.
44782
+ cwd: sterileCwd(),
44462
44783
  timeoutMs,
44463
44784
  sandbox: "read-only",
44464
44785
  codexExecutable
44465
44786
  });
44787
+ recordCost("head", personaName, null, startedAt, result);
44788
+ return result;
44466
44789
  },
44467
44790
  async runArbiter(prompt) {
44468
- return runAgentExec({
44791
+ const startedAt = Date.now();
44792
+ const result = await runAgentExec({
44469
44793
  prompt,
44470
44794
  developerInstructions: loadPersona("arbiter"),
44471
- cwd,
44795
+ cwd: sterileCwd(),
44472
44796
  timeoutMs,
44473
44797
  sandbox: "read-only",
44474
44798
  codexExecutable,
@@ -44476,10 +44800,13 @@ ${persona}`,
44476
44800
  // strongest model.
44477
44801
  model: seat?.models.strong
44478
44802
  });
44803
+ recordCost("arbiter", "arbiter", seat?.models.strong ?? null, startedAt, result);
44804
+ return result;
44479
44805
  },
44480
44806
  async runReviser(artifact, accepted) {
44481
44807
  const acceptedList = accepted.map((a) => `- (${a.category}) ${a.text}`).join("\n");
44482
- return runAgentExec({
44808
+ const startedAt = Date.now();
44809
+ const result = await runAgentExec({
44483
44810
  prompt: `Accepted issues to fix (each maps to an unmet acceptance criterion):
44484
44811
  ${acceptedList}
44485
44812
 
@@ -44491,11 +44818,13 @@ ${artifact}`,
44491
44818
  developerInstructions: `${DELIVERABLE_ANTIINJECTION_INSTRUCTION}
44492
44819
 
44493
44820
  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.`,
44494
- cwd,
44821
+ cwd: sterileCwd(),
44495
44822
  timeoutMs,
44496
44823
  sandbox: "read-only",
44497
44824
  codexExecutable
44498
44825
  });
44826
+ recordCost("reviser", null, null, startedAt, result);
44827
+ return result;
44499
44828
  },
44500
44829
  async casUpdateDeliverable(markdownBody, expectedHash) {
44501
44830
  try {
@@ -44526,7 +44855,7 @@ You revise a deliverable to address the accepted issues so it satisfies the acce
44526
44855
  const highlights = await curateFindings(Array.isArray(history) ? history : [], {
44527
44856
  runCodexExec: runAgentExec,
44528
44857
  loadPersona,
44529
- cwd,
44858
+ cwd: sterileCwd(),
44530
44859
  timeoutMs,
44531
44860
  codexExecutable
44532
44861
  });
@@ -44649,10 +44978,35 @@ async function gate(artifact, prose, ctx) {
44649
44978
  return { ok: true, gated: false, artifact: maskedClone };
44650
44979
  }
44651
44980
 
44981
+ // src/telemetry/installation-id.ts
44982
+ var import_node_crypto5 = require("node:crypto");
44983
+ var import_node_fs8 = require("node:fs");
44984
+ var import_node_path14 = require("node:path");
44985
+ var FILE_NAME = "installation-id";
44986
+ var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
44987
+ var cache = /* @__PURE__ */ new Map();
44988
+ function resolveInstallationId(stateDir) {
44989
+ const cached2 = cache.get(stateDir);
44990
+ if (cached2 !== void 0) return cached2;
44991
+ const path22 = (0, import_node_path14.join)(stateDir, FILE_NAME);
44992
+ let id;
44993
+ try {
44994
+ id = (0, import_node_fs8.readFileSync)(path22, "utf8").trim();
44995
+ if (!UUID.test(id)) throw new Error("unusable");
44996
+ } catch {
44997
+ id = (0, import_node_crypto5.randomUUID)();
44998
+ (0, import_node_fs8.mkdirSync)((0, import_node_path14.dirname)(path22), { recursive: true });
44999
+ (0, import_node_fs8.writeFileSync)(path22, `${id}
45000
+ `, "utf8");
45001
+ }
45002
+ cache.set(stateDir, id);
45003
+ return id;
45004
+ }
45005
+
44652
45006
  // src/telemetry/daily-uploader.ts
44653
45007
  var ROWS_FILE_RE = /^rows-(.+)-(\d{4}-\d{2}-\d{2})\.jsonl$/;
44654
45008
  async function uploadPendingDays(stateDir, client, bridgeHealth, gateCtx) {
44655
- const telemetryDir = (0, import_node_path12.join)(stateDir, "telemetry");
45009
+ const telemetryDir = (0, import_node_path15.join)(stateDir, "telemetry");
44656
45010
  let files;
44657
45011
  try {
44658
45012
  files = await (0, import_promises6.readdir)(telemetryDir);
@@ -44665,11 +45019,11 @@ async function uploadPendingDays(stateDir, client, bridgeHealth, gateCtx) {
44665
45019
  const match = ROWS_FILE_RE.exec(file2);
44666
45020
  if (!match) continue;
44667
45021
  const [, projectSlug, day] = match;
44668
- const markerPath = (0, import_node_path12.join)(telemetryDir, `.processed-${projectSlug}-${day}`);
45022
+ const markerPath = (0, import_node_path15.join)(telemetryDir, `.processed-${projectSlug}-${day}`);
44669
45023
  try {
44670
45024
  await (0, import_promises6.access)(markerPath);
44671
45025
  } catch {
44672
- pending.push({ projectSlug, day, rowsPath: (0, import_node_path12.join)(telemetryDir, file2), markerPath });
45026
+ pending.push({ projectSlug, day, rowsPath: (0, import_node_path15.join)(telemetryDir, file2), markerPath });
44673
45027
  }
44674
45028
  }
44675
45029
  if (pending.length === 0) return;
@@ -44677,7 +45031,7 @@ async function uploadPendingDays(stateDir, client, bridgeHealth, gateCtx) {
44677
45031
  const fullUnprocessed = pending.map((p) => ({ projectSlug: p.projectSlug, day: p.day }));
44678
45032
  pending.sort((a, b) => a.day.localeCompare(b.day));
44679
45033
  for (const cur of pending) {
44680
- const failurePath = (0, import_node_path12.join)(telemetryDir, `.failed-${cur.projectSlug}-${cur.day}.json`);
45034
+ const failurePath = (0, import_node_path15.join)(telemetryDir, `.failed-${cur.projectSlug}-${cur.day}.json`);
44681
45035
  let failureState = null;
44682
45036
  try {
44683
45037
  const data = await (0, import_promises6.readFile)(failurePath, "utf8");
@@ -44706,14 +45060,31 @@ async function uploadPendingDays(stateDir, client, bridgeHealth, gateCtx) {
44706
45060
  } catch {
44707
45061
  }
44708
45062
  }
45063
+ const gateCalls = [];
45064
+ try {
45065
+ const rawGate = await (0, import_promises6.readFile)((0, import_node_path15.join)(telemetryDir, gateFileName(cur.projectSlug, cur.day)), "utf8");
45066
+ for (const line of rawGate.split("\n")) {
45067
+ if (!line.trim()) continue;
45068
+ try {
45069
+ gateCalls.push(JSON.parse(line));
45070
+ } catch {
45071
+ }
45072
+ }
45073
+ } catch {
45074
+ }
44709
45075
  const batch = {
44710
45076
  day: cur.day,
44711
45077
  bridgeVersion: PKG_VERSION,
45078
+ installationId: resolveInstallationId(stateDir),
44712
45079
  knownCrashCount,
44713
45080
  unprocessedPartitions: fullUnprocessed.filter(
44714
45081
  (p) => !(p.projectSlug === cur.projectSlug && p.day === cur.day)
44715
45082
  ),
44716
- rows
45083
+ rows,
45084
+ // Omitted entirely when empty: an absent array and an empty one mean the same thing to
45085
+ // every reader, and not sending the key keeps a gate-free day's batch byte-identical to
45086
+ // what every uploader before this change produced.
45087
+ ...gateCalls.length > 0 ? { gateCalls } : {}
44717
45088
  };
44718
45089
  const gateResult = await gate(batch, [], gateCtx);
44719
45090
  const gateMarker = gateResult.gated ? "gated" : "projection-only";
@@ -45107,8 +45478,8 @@ function setSelectedProvider(value) {
45107
45478
 
45108
45479
  // src/execution-consumer.ts
45109
45480
  var import_node_child_process12 = require("node:child_process");
45110
- var import_node_crypto6 = __toESM(require("node:crypto"), 1);
45111
- var import_node_path15 = __toESM(require("node:path"), 1);
45481
+ var import_node_crypto7 = __toESM(require("node:crypto"), 1);
45482
+ var import_node_path18 = __toESM(require("node:path"), 1);
45112
45483
  var import_node_util = require("node:util");
45113
45484
 
45114
45485
  // src/consensus/deliverable-gate-outcome.ts
@@ -45178,7 +45549,7 @@ function mapDeliverableGateResult(result) {
45178
45549
  }
45179
45550
 
45180
45551
  // src/async-tools/draft-spec.ts
45181
- var import_node_crypto5 = require("node:crypto");
45552
+ var import_node_crypto6 = require("node:crypto");
45182
45553
  var DRAFT_SPEC_TOOL_NAME = "draft_task_spec";
45183
45554
  var SPECS_FOLDER = "Specs";
45184
45555
  var DRAFT_SPEC_TLDR_MAX_CHARS = 300;
@@ -45673,7 +46044,7 @@ function onComplete(outcome, input) {
45673
46044
  };
45674
46045
  }
45675
46046
  const summary = outcome.error;
45676
- const hash3 = (0, import_node_crypto5.createHash)("sha256").update(summary).digest("hex").slice(0, 10);
46047
+ const hash3 = (0, import_node_crypto6.createHash)("sha256").update(summary).digest("hex").slice(0, 10);
45677
46048
  return {
45678
46049
  kind: "info",
45679
46050
  id: `II-sched-draft-failed-${input.taskId}-${hash3}`,
@@ -46404,18 +46775,18 @@ async function awaitTurnWithDeadline(opts) {
46404
46775
 
46405
46776
  // src/worktree.ts
46406
46777
  var import_node_child_process11 = require("node:child_process");
46407
- var import_node_fs7 = require("node:fs");
46408
- var import_node_os6 = require("node:os");
46409
- var import_node_path14 = require("node:path");
46778
+ var import_node_fs10 = require("node:fs");
46779
+ var import_node_os7 = require("node:os");
46780
+ var import_node_path17 = require("node:path");
46410
46781
 
46411
46782
  // src/checkout-lock.ts
46412
- var import_node_fs6 = require("node:fs");
46413
- var import_node_path13 = require("node:path");
46783
+ var import_node_fs9 = require("node:fs");
46784
+ var import_node_path16 = require("node:path");
46414
46785
  var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
46415
46786
  async function withCheckoutLock(locksDir, slug, fn) {
46416
- (0, import_node_fs6.mkdirSync)(locksDir, { recursive: true });
46417
- const target = (0, import_node_path13.join)(locksDir, `${slug}.lock`);
46418
- if (!(0, import_node_fs6.existsSync)(target)) (0, import_node_fs6.writeFileSync)(target, "");
46787
+ (0, import_node_fs9.mkdirSync)(locksDir, { recursive: true });
46788
+ const target = (0, import_node_path16.join)(locksDir, `${slug}.lock`);
46789
+ if (!(0, import_node_fs9.existsSync)(target)) (0, import_node_fs9.writeFileSync)(target, "");
46419
46790
  const release = await import_proper_lockfile.default.lock(target, {
46420
46791
  retries: { retries: 600, factor: 1, minTimeout: 100, maxTimeout: 100 },
46421
46792
  stale: 5 * 6e4
@@ -46440,12 +46811,12 @@ function git(checkout, args) {
46440
46811
  });
46441
46812
  }
46442
46813
  async function createRunWorktree(opts) {
46443
- const worktreePath = (0, import_node_path14.join)(opts.worktreeRoot, opts.slug, opts.runId);
46814
+ const worktreePath = (0, import_node_path17.join)(opts.worktreeRoot, opts.slug, opts.runId);
46444
46815
  await withCheckoutLock(opts.locksDir, opts.slug, async () => {
46445
- (0, import_node_fs7.mkdirSync)(opts.worktreeRoot, { recursive: true });
46816
+ (0, import_node_fs10.mkdirSync)(opts.worktreeRoot, { recursive: true });
46446
46817
  try {
46447
46818
  git(opts.checkout, ["fetch", "origin", opts.defaultBranch]);
46448
- if (!(0, import_node_fs7.existsSync)(worktreePath)) {
46819
+ if (!(0, import_node_fs10.existsSync)(worktreePath)) {
46449
46820
  git(opts.checkout, [
46450
46821
  "worktree",
46451
46822
  "add",
@@ -46517,15 +46888,15 @@ async function doPushRunBranch(opts, execGit) {
46517
46888
  if (localConfig.trim()) {
46518
46889
  throw new Error(`push aborted: agent-controlled git config present in worktree: ${localConfig.trim().split("\n")[0]}`);
46519
46890
  }
46520
- const dir = (0, import_node_fs7.mkdtempSync)((0, import_node_path14.join)((0, import_node_os6.tmpdir)(), "mrrlin-push-"));
46521
- const askpass = (0, import_node_path14.join)(dir, "askpass");
46891
+ const dir = (0, import_node_fs10.mkdtempSync)((0, import_node_path17.join)((0, import_node_os7.tmpdir)(), "mrrlin-push-"));
46892
+ const askpass = (0, import_node_path17.join)(dir, "askpass");
46522
46893
  try {
46523
- (0, import_node_fs7.writeFileSync)(
46894
+ (0, import_node_fs10.writeFileSync)(
46524
46895
  askpass,
46525
46896
  '#!/bin/sh\ncase "$1" in *[Uu]sername*) printf %s "x-access-token" ;; *) printf %s "$MRRLIN_PUSH_TOKEN" ;; esac\n',
46526
46897
  { mode: 320 }
46527
46898
  );
46528
- (0, import_node_fs7.chmodSync)(askpass, 320);
46899
+ (0, import_node_fs10.chmodSync)(askpass, 320);
46529
46900
  execGit(
46530
46901
  [
46531
46902
  "-C",
@@ -46544,18 +46915,18 @@ async function doPushRunBranch(opts, execGit) {
46544
46915
  );
46545
46916
  return { pushedSha: localSha };
46546
46917
  } finally {
46547
- (0, import_node_fs7.rmSync)(dir, { recursive: true, force: true });
46918
+ (0, import_node_fs10.rmSync)(dir, { recursive: true, force: true });
46548
46919
  }
46549
46920
  }
46550
46921
  async function sweepOrphanWorktrees(opts) {
46551
46922
  const reaped = [];
46552
46923
  const ownedPrefix = (() => {
46553
46924
  try {
46554
- return (0, import_node_fs7.realpathSync)(opts.worktreeRoot);
46925
+ return (0, import_node_fs10.realpathSync)(opts.worktreeRoot);
46555
46926
  } catch {
46556
46927
  return opts.worktreeRoot;
46557
46928
  }
46558
- })() + import_node_path14.sep + opts.slug + import_node_path14.sep;
46929
+ })() + import_node_path17.sep + opts.slug + import_node_path17.sep;
46559
46930
  await withCheckoutLock(opts.locksDir, opts.slug, async () => {
46560
46931
  const listing = git(opts.checkout, ["worktree", "list", "--porcelain"]);
46561
46932
  for (const block of listing.split("\n\n")) {
@@ -47075,7 +47446,7 @@ function isBridgeGeneratedArtifact(artifact) {
47075
47446
  return typeof payload === "object" && payload !== null && "event" in payload;
47076
47447
  }
47077
47448
  function newArtifactId() {
47078
- return `EA-${import_node_crypto6.default.randomUUID()}`;
47449
+ return `EA-${import_node_crypto7.default.randomUUID()}`;
47079
47450
  }
47080
47451
  var BLAST_RADIUS_FLOOR_PATTERNS = [/^supabase\/migrations\//, /^packages\/db\/src\/schema\.ts$/];
47081
47452
  function isBlastRadiusFloorPath(path22) {
@@ -47317,7 +47688,7 @@ async function driveRun(deps, projectSlug, runId) {
47317
47688
  if (!claimed) return;
47318
47689
  if (!claimed.leaseId) {
47319
47690
  await deps.client.createInboxItem(projectSlug, {
47320
- id: `II-${import_node_crypto6.default.randomUUID()}`,
47691
+ id: `II-${import_node_crypto7.default.randomUUID()}`,
47321
47692
  kind: "handoff",
47322
47693
  taskId: claimed.taskId,
47323
47694
  body: `Execution run ${runId} was claimed but returned no leaseId. This indicates DB/API corruption and requires operator attention.`
@@ -47334,6 +47705,35 @@ async function driveRun(deps, projectSlug, runId) {
47334
47705
  return legacy != null ? Math.min(legacy, remaining) : remaining;
47335
47706
  };
47336
47707
  const task = await deps.client.getTask(projectSlug, claimed.taskId);
47708
+ if (task.declaredOutcome != null) {
47709
+ for (const kind of task.declaredOutcome.requires) {
47710
+ if (resolveKindCapability(kind) === null) {
47711
+ await failRun(
47712
+ deps,
47713
+ projectSlug,
47714
+ task,
47715
+ runId,
47716
+ leaseId,
47717
+ `capability_not_routed: run ${runId} targets ${task.id}, which requires artifact kind "${kind}" -- that kind has no capability at all`,
47718
+ "capability_not_routed"
47719
+ );
47720
+ return;
47721
+ }
47722
+ const routeResolution = await deps.client.resolveArtifactKindRoute(projectSlug, kind, projectSlug);
47723
+ if (!routeResolution.ok) {
47724
+ await failRun(
47725
+ deps,
47726
+ projectSlug,
47727
+ task,
47728
+ runId,
47729
+ leaseId,
47730
+ `capability_not_routed: run ${runId} targets ${task.id}, which requires artifact kind "${kind}" -- no route (${routeResolution.reason})`,
47731
+ "capability_not_routed"
47732
+ );
47733
+ return;
47734
+ }
47735
+ }
47736
+ }
47337
47737
  const blockerTasks = task.blockedBy.length ? await Promise.all(task.blockedBy.map((blockerTaskId) => deps.client.getTask(projectSlug, blockerTaskId))) : [];
47338
47738
  const missingBlockers = task.blockedBy.filter((_, index) => !blockerTasks[index]);
47339
47739
  if (missingBlockers.length > 0) {
@@ -48494,7 +48894,7 @@ async function reconcileTaskAwaitingMerge(deps, projectSlug, task, runId, reason
48494
48894
  }
48495
48895
  try {
48496
48896
  await deps.client.createInboxItem(projectSlug, {
48497
- id: `II-${import_node_crypto6.default.randomUUID()}`,
48897
+ id: `II-${import_node_crypto7.default.randomUUID()}`,
48498
48898
  kind: "handoff",
48499
48899
  taskId: task.id,
48500
48900
  body: `Task ${task.id} (${task.title}) still needs operator follow-up: ${reason}. Mrrlin could not move the task back to Handoff needed automatically.`
@@ -48529,7 +48929,7 @@ async function notifyOperatorHandoff(deps, projectSlug, task, runId, reason) {
48529
48929
  }
48530
48930
  try {
48531
48931
  await deps.client.createInboxItem(projectSlug, {
48532
- id: `II-${import_node_crypto6.default.randomUUID()}`,
48932
+ id: `II-${import_node_crypto7.default.randomUUID()}`,
48533
48933
  kind: "handoff",
48534
48934
  taskId: task.id,
48535
48935
  body: `Execution run ${runId} for task ${task.id} (${task.title}) needs operator attention: ${reason}`
@@ -48669,8 +49069,8 @@ async function runBackstopSweep(deps, drive = (slug, id) => driveRun(deps, slug,
48669
49069
  function isRunRecoverableByThisBridge(run3, worktreeRoot) {
48670
49070
  if (!worktreeRoot) return true;
48671
49071
  if (!run3.worktreeId) return false;
48672
- const relative = import_node_path15.default.relative(import_node_path15.default.resolve(worktreeRoot), import_node_path15.default.resolve(run3.worktreeId));
48673
- return relative === "" || relative.length > 0 && !relative.startsWith("..") && !import_node_path15.default.isAbsolute(relative);
49072
+ const relative = import_node_path18.default.relative(import_node_path18.default.resolve(worktreeRoot), import_node_path18.default.resolve(run3.worktreeId));
49073
+ return relative === "" || relative.length > 0 && !relative.startsWith("..") && !import_node_path18.default.isAbsolute(relative);
48674
49074
  }
48675
49075
  async function deployGateHandoff(deps, projectSlug, task, runId, reason, leaseId) {
48676
49076
  await deps.client.updateExecutionRun(projectSlug, runId, { status: "failed", finishedAt: (/* @__PURE__ */ new Date()).toISOString(), leaseId: leaseId ?? void 0 }).catch(() => {
@@ -48688,7 +49088,7 @@ async function deployGateHandoff(deps, projectSlug, task, runId, reason, leaseId
48688
49088
  }).catch(() => {
48689
49089
  });
48690
49090
  await deps.client.createInboxItem(projectSlug, {
48691
- id: `II-${import_node_crypto6.default.randomUUID()}`,
49091
+ id: `II-${import_node_crypto7.default.randomUUID()}`,
48692
49092
  kind: "handoff",
48693
49093
  taskId: task.id,
48694
49094
  body: `Deploy gate for run ${runId} (task ${task.id} \u2014 ${task.title}) needs operator attention: ${reason}`
@@ -48707,7 +49107,7 @@ function maxLeaseReclaims() {
48707
49107
  }
48708
49108
 
48709
49109
  // src/async-job-consumer.ts
48710
- var import_node_crypto8 = __toESM(require("node:crypto"), 1);
49110
+ var import_node_crypto9 = __toESM(require("node:crypto"), 1);
48711
49111
 
48712
49112
  // src/async-tools/registry.ts
48713
49113
  var registry2 = /* @__PURE__ */ new Map();
@@ -48719,9 +49119,9 @@ function getAsyncToolDescriptor(toolName) {
48719
49119
  }
48720
49120
 
48721
49121
  // src/bridge-log.ts
48722
- var import_node_fs8 = require("node:fs");
49122
+ var import_node_fs11 = require("node:fs");
48723
49123
  var import_promises7 = require("node:fs/promises");
48724
- var import_node_path16 = require("node:path");
49124
+ var import_node_path19 = require("node:path");
48725
49125
 
48726
49126
  // src/redact.ts
48727
49127
  var REDACTED = "[REDACTED]";
@@ -48746,7 +49146,7 @@ function redact(input) {
48746
49146
  }
48747
49147
 
48748
49148
  // src/telemetry/projector.ts
48749
- var import_node_crypto7 = require("node:crypto");
49149
+ var import_node_crypto8 = require("node:crypto");
48750
49150
  function isRecord2(x) {
48751
49151
  return typeof x === "object" && x !== null;
48752
49152
  }
@@ -48787,7 +49187,7 @@ function buildProjection(payload, type, ms, telemetry) {
48787
49187
  if (typeof exitCode === "number") proj.exitCode = exitCode;
48788
49188
  const status = tool.status;
48789
49189
  if (typeof status === "string" && status.trim() !== "") {
48790
- proj.statusHash = (0, import_node_crypto7.createHash)("sha256").update(status.trim().toLowerCase()).digest("hex").slice(0, 8);
49190
+ proj.statusHash = (0, import_node_crypto8.createHash)("sha256").update(status.trim().toLowerCase()).digest("hex").slice(0, 8);
48791
49191
  }
48792
49192
  return proj;
48793
49193
  }
@@ -48997,14 +49397,14 @@ function resolvePromptsEnabled(env = process.env) {
48997
49397
  }
48998
49398
  function createBridgeLogger(stateDir, env = process.env) {
48999
49399
  if (!resolveBridgeLogEnabled(env)) return NOOP_LOGGER;
49000
- const logsDir = (0, import_node_path16.join)(stateDir, "logs");
49400
+ const logsDir = (0, import_node_path19.join)(stateDir, "logs");
49001
49401
  try {
49002
- (0, import_node_fs8.mkdirSync)(logsDir, { recursive: true });
49402
+ (0, import_node_fs11.mkdirSync)(logsDir, { recursive: true });
49003
49403
  } catch {
49004
49404
  return NOOP_LOGGER;
49005
49405
  }
49006
49406
  const includePrompts = resolvePromptsEnabled(env);
49007
- const fileFor = () => (0, import_node_path16.join)(logsDir, `bridge-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
49407
+ const fileFor = () => (0, import_node_path19.join)(logsDir, `bridge-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
49008
49408
  const MAX_TRACKED_SESSIONS = 64;
49009
49409
  const contextSlugBySession = /* @__PURE__ */ new Map();
49010
49410
  const rememberContextSlug = (sessionId, payload) => {
@@ -49045,10 +49445,10 @@ function createBridgeLogger(stateDir, env = process.env) {
49045
49445
  return { isGap, isNewTurn };
49046
49446
  };
49047
49447
  const gainDay = (sessionId) => {
49048
- const sessionsPath = (0, import_node_path16.join)(logsDir, ".sessions.json");
49448
+ const sessionsPath = (0, import_node_path19.join)(logsDir, ".sessions.json");
49049
49449
  let sessionsObj = {};
49050
49450
  try {
49051
- const parsed = JSON.parse((0, import_node_fs8.readFileSync)(sessionsPath, "utf8"));
49451
+ const parsed = JSON.parse((0, import_node_fs11.readFileSync)(sessionsPath, "utf8"));
49052
49452
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) sessionsObj = parsed;
49053
49453
  } catch {
49054
49454
  sessionsObj = {};
@@ -49058,8 +49458,8 @@ function createBridgeLogger(stateDir, env = process.env) {
49058
49458
  if (idsToday.includes(sessionId)) return;
49059
49459
  sessionsObj[day] = [...idsToday, sessionId];
49060
49460
  const tmpPath = `${sessionsPath}.tmp`;
49061
- (0, import_node_fs8.writeFileSync)(tmpPath, JSON.stringify(sessionsObj));
49062
- (0, import_node_fs8.renameSync)(tmpPath, sessionsPath);
49461
+ (0, import_node_fs11.writeFileSync)(tmpPath, JSON.stringify(sessionsObj));
49462
+ (0, import_node_fs11.renameSync)(tmpPath, sessionsPath);
49063
49463
  };
49064
49464
  const write = (dir, rec) => {
49065
49465
  try {
@@ -49150,7 +49550,7 @@ function createBridgeLogger(stateDir, env = process.env) {
49150
49550
  ...recordingObligationUnresolved ? { recordingObligationUnresolved } : {},
49151
49551
  ...recordingObligationMultiResolve ? { recordingObligationMultiResolve } : {}
49152
49552
  }) + "\n";
49153
- (0, import_node_fs8.appendFileSync)(fileFor(), line);
49553
+ (0, import_node_fs11.appendFileSync)(fileFor(), line);
49154
49554
  if (rec.sessionId !== null) gainDay(rec.sessionId);
49155
49555
  } catch {
49156
49556
  }
@@ -49163,7 +49563,7 @@ function createBridgeLogger(stateDir, env = process.env) {
49163
49563
  };
49164
49564
  }
49165
49565
  async function findSessionDays(stateDir, sessionId) {
49166
- const sessionsPath = (0, import_node_path16.join)(stateDir, "logs", ".sessions.json");
49566
+ const sessionsPath = (0, import_node_path19.join)(stateDir, "logs", ".sessions.json");
49167
49567
  let sessionsObj;
49168
49568
  try {
49169
49569
  const parsed = JSON.parse(await (0, import_promises7.readFile)(sessionsPath, "utf8"));
@@ -49295,7 +49695,7 @@ async function driveAsyncJob(deps, projectSlug, jobId) {
49295
49695
  const delivery = descriptor2.onComplete(outcome, input);
49296
49696
  if (!delivery.suppressInbox) {
49297
49697
  await deps.client.createInboxItem(projectSlug, {
49298
- id: delivery.id ?? `II-${import_node_crypto8.default.randomUUID()}`,
49698
+ id: delivery.id ?? `II-${import_node_crypto9.default.randomUUID()}`,
49299
49699
  kind: delivery.kind,
49300
49700
  body: delivery.body,
49301
49701
  ...delivery.taskId ? { taskId: delivery.taskId } : {},
@@ -49313,13 +49713,13 @@ async function deriveRequestedHash(client, toolName, input) {
49313
49713
  if (input.requestedHash) return input.requestedHash;
49314
49714
  if (toolName === "run_spec_consensus" && input.pageId) {
49315
49715
  const page = await client.getWikiPage(input.projectSlug, input.pageId);
49316
- return page.contentHash ?? import_node_crypto8.default.createHash("sha256").update(page.markdownBody).digest("hex");
49716
+ return page.contentHash ?? import_node_crypto9.default.createHash("sha256").update(page.markdownBody).digest("hex");
49317
49717
  }
49318
49718
  if (toolName === "draft_task_spec" && input.taskId) {
49319
49719
  const task = await client.getTask(input.projectSlug, input.taskId);
49320
- return task.updatedAt ?? import_node_crypto8.default.createHash("sha256").update(JSON.stringify(task)).digest("hex");
49720
+ return task.updatedAt ?? import_node_crypto9.default.createHash("sha256").update(JSON.stringify(task)).digest("hex");
49321
49721
  }
49322
- return import_node_crypto8.default.createHash("sha256").update(JSON.stringify(input)).digest("hex");
49722
+ return import_node_crypto9.default.createHash("sha256").update(JSON.stringify(input)).digest("hex");
49323
49723
  }
49324
49724
  async function runAsyncBackstopSweep(deps, drive = (slug, jobId) => driveAsyncJob(deps, slug, jobId)) {
49325
49725
  const projects = await deps.client.listProjects();
@@ -49597,19 +49997,19 @@ function agentIdleMs(provider) {
49597
49997
  }
49598
49998
 
49599
49999
  // src/operator-token.ts
49600
- var import_node_fs9 = require("node:fs");
49601
- var import_node_os7 = __toESM(require("node:os"), 1);
49602
- var import_node_path17 = __toESM(require("node:path"), 1);
50000
+ var import_node_fs12 = require("node:fs");
50001
+ var import_node_os8 = __toESM(require("node:os"), 1);
50002
+ var import_node_path20 = __toESM(require("node:path"), 1);
49603
50003
  function operatorDir() {
49604
- 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");
50004
+ 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");
49605
50005
  return base;
49606
50006
  }
49607
50007
  function operatorTokenPath() {
49608
- return import_node_path17.default.join(operatorDir(), "operator-token");
50008
+ return import_node_path20.default.join(operatorDir(), "operator-token");
49609
50009
  }
49610
50010
  function readOperatorToken() {
49611
50011
  try {
49612
- const token = (0, import_node_fs9.readFileSync)(operatorTokenPath(), "utf8").trim();
50012
+ const token = (0, import_node_fs12.readFileSync)(operatorTokenPath(), "utf8").trim();
49613
50013
  return token.length > 0 ? token : null;
49614
50014
  } catch {
49615
50015
  return null;
@@ -49617,24 +50017,24 @@ function readOperatorToken() {
49617
50017
  }
49618
50018
  function persistOperatorToken(token) {
49619
50019
  const dir = operatorDir();
49620
- (0, import_node_fs9.mkdirSync)(dir, { recursive: true, mode: 448 });
49621
- (0, import_node_fs9.writeFileSync)(operatorTokenPath(), `${token.trim()}
50020
+ (0, import_node_fs12.mkdirSync)(dir, { recursive: true, mode: 448 });
50021
+ (0, import_node_fs12.writeFileSync)(operatorTokenPath(), `${token.trim()}
49622
50022
  `, { encoding: "utf8", mode: 384 });
49623
50023
  }
49624
50024
  function agentCredentialPath() {
49625
- return import_node_path17.default.join(operatorDir(), "agent-credential");
50025
+ return import_node_path20.default.join(operatorDir(), "agent-credential");
49626
50026
  }
49627
50027
  function persistAgentSecret(secret) {
49628
50028
  const dir = operatorDir();
49629
- (0, import_node_fs9.mkdirSync)(dir, { recursive: true, mode: 448 });
49630
- (0, import_node_fs9.writeFileSync)(agentCredentialPath(), `${secret.trim()}
50029
+ (0, import_node_fs12.mkdirSync)(dir, { recursive: true, mode: 448 });
50030
+ (0, import_node_fs12.writeFileSync)(agentCredentialPath(), `${secret.trim()}
49631
50031
  `, { encoding: "utf8", mode: 384 });
49632
50032
  }
49633
50033
  function readAgentSecret() {
49634
50034
  const fromEnv = process.env.MRRLIN_AGENT_SECRET?.trim();
49635
50035
  if (fromEnv) return fromEnv;
49636
50036
  try {
49637
- const raw = (0, import_node_fs9.readFileSync)(agentCredentialPath(), "utf8").trim();
50037
+ const raw = (0, import_node_fs12.readFileSync)(agentCredentialPath(), "utf8").trim();
49638
50038
  return raw || void 0;
49639
50039
  } catch {
49640
50040
  return void 0;
@@ -49642,16 +50042,16 @@ function readAgentSecret() {
49642
50042
  }
49643
50043
 
49644
50044
  // src/thread-index.ts
49645
- var import_node_fs10 = require("node:fs");
49646
- var import_node_path18 = __toESM(require("node:path"), 1);
50045
+ var import_node_fs13 = require("node:fs");
50046
+ var import_node_path21 = __toESM(require("node:path"), 1);
49647
50047
  function threadIndexPath(stateDir) {
49648
- return import_node_path18.default.join(stateDir, "threads.json");
50048
+ return import_node_path21.default.join(stateDir, "threads.json");
49649
50049
  }
49650
50050
  function loadThreadIndex(stateDir, ttlMs, now) {
49651
50051
  const result = /* @__PURE__ */ new Map();
49652
50052
  let parsed;
49653
50053
  try {
49654
- parsed = JSON.parse((0, import_node_fs10.readFileSync)(threadIndexPath(stateDir), "utf8"));
50054
+ parsed = JSON.parse((0, import_node_fs13.readFileSync)(threadIndexPath(stateDir), "utf8"));
49655
50055
  } catch {
49656
50056
  return result;
49657
50057
  }
@@ -49674,8 +50074,8 @@ function loadThreadIndex(stateDir, ttlMs, now) {
49674
50074
  return result;
49675
50075
  }
49676
50076
  function saveThreadIndex(stateDir, entries) {
49677
- (0, import_node_fs10.mkdirSync)(stateDir, { recursive: true, mode: 448 });
49678
- (0, import_node_fs10.writeFileSync)(threadIndexPath(stateDir), `${JSON.stringify(Object.fromEntries(entries), null, 2)}
50077
+ (0, import_node_fs13.mkdirSync)(stateDir, { recursive: true, mode: 448 });
50078
+ (0, import_node_fs13.writeFileSync)(threadIndexPath(stateDir), `${JSON.stringify(Object.fromEntries(entries), null, 2)}
49679
50079
  `, {
49680
50080
  encoding: "utf8",
49681
50081
  mode: 384
@@ -49810,10 +50210,10 @@ function createToolBusyClock(opts) {
49810
50210
  }
49811
50211
 
49812
50212
  // src/worker-token.ts
49813
- var import_node_crypto9 = require("node:crypto");
49814
- var import_node_fs11 = require("node:fs");
49815
- var import_node_os8 = __toESM(require("node:os"), 1);
49816
- var import_node_path19 = __toESM(require("node:path"), 1);
50213
+ var import_node_crypto10 = require("node:crypto");
50214
+ var import_node_fs14 = require("node:fs");
50215
+ var import_node_os9 = __toESM(require("node:os"), 1);
50216
+ var import_node_path22 = __toESM(require("node:path"), 1);
49817
50217
  var DEFAULT_WORKER_PORT = 8792;
49818
50218
  function workerPort() {
49819
50219
  const raw = process.env.MRRLIN_WORKER_PORT;
@@ -49822,15 +50222,15 @@ function workerPort() {
49822
50222
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_WORKER_PORT;
49823
50223
  }
49824
50224
  function workerDir() {
49825
- 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");
49826
- return import_node_path19.default.join(base, "worker");
50225
+ 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");
50226
+ return import_node_path22.default.join(base, "worker");
49827
50227
  }
49828
50228
  function workerTokenPath() {
49829
- return import_node_path19.default.join(workerDir(), "token");
50229
+ return import_node_path22.default.join(workerDir(), "token");
49830
50230
  }
49831
50231
  function readWorkerToken() {
49832
50232
  try {
49833
- const token = (0, import_node_fs11.readFileSync)(workerTokenPath(), "utf8").trim();
50233
+ const token = (0, import_node_fs14.readFileSync)(workerTokenPath(), "utf8").trim();
49834
50234
  return token.length > 0 ? token : null;
49835
50235
  } catch {
49836
50236
  return null;
@@ -49840,18 +50240,18 @@ function readOrCreateWorkerToken() {
49840
50240
  const existing = readWorkerToken();
49841
50241
  if (existing) return existing;
49842
50242
  const dir = workerDir();
49843
- (0, import_node_fs11.mkdirSync)(dir, { recursive: true, mode: 448 });
49844
- const token = (0, import_node_crypto9.randomBytes)(32).toString("hex");
49845
- (0, import_node_fs11.writeFileSync)(workerTokenPath(), `${token}
50243
+ (0, import_node_fs14.mkdirSync)(dir, { recursive: true, mode: 448 });
50244
+ const token = (0, import_node_crypto10.randomBytes)(32).toString("hex");
50245
+ (0, import_node_fs14.writeFileSync)(workerTokenPath(), `${token}
49846
50246
  `, { encoding: "utf8", mode: 384 });
49847
50247
  return token;
49848
50248
  }
49849
50249
 
49850
50250
  // src/remote-phone-relay.ts
49851
50251
  var import_node_events2 = require("node:events");
49852
- var import_node_fs12 = require("node:fs");
49853
- var import_node_os9 = require("node:os");
49854
- var import_node_path20 = require("node:path");
50252
+ var import_node_fs15 = require("node:fs");
50253
+ var import_node_os10 = require("node:os");
50254
+ var import_node_path23 = require("node:path");
49855
50255
 
49856
50256
  // ../../node_modules/.pnpm/@noble+hashes@1.3.3/node_modules/@noble/hashes/esm/cryptoNode.js
49857
50257
  var nc = __toESM(require("node:crypto"), 1);
@@ -53422,9 +53822,9 @@ var DirectorRelay = class {
53422
53822
 
53423
53823
  // src/remote-phone-relay.ts
53424
53824
  function loadOrCreateAgentDeviceKey() {
53425
- const path22 = (0, import_node_path20.join)((0, import_node_os9.homedir)(), ".mrrlin", "agent-device-key");
53825
+ const path22 = (0, import_node_path23.join)((0, import_node_os10.homedir)(), ".mrrlin", "agent-device-key");
53426
53826
  try {
53427
- const raw = JSON.parse((0, import_node_fs12.readFileSync)(path22, "utf8"));
53827
+ const raw = JSON.parse((0, import_node_fs15.readFileSync)(path22, "utf8"));
53428
53828
  if (typeof raw.priv === "string" && typeof raw.pub === "string") {
53429
53829
  return { privateKey: fromBase64Url(raw.priv), publicKey: fromBase64Url(raw.pub) };
53430
53830
  }
@@ -53432,8 +53832,8 @@ function loadOrCreateAgentDeviceKey() {
53432
53832
  }
53433
53833
  const kp = generateIdentityKeyPair();
53434
53834
  try {
53435
- (0, import_node_fs12.mkdirSync)((0, import_node_path20.join)((0, import_node_os9.homedir)(), ".mrrlin"), { recursive: true });
53436
- (0, import_node_fs12.writeFileSync)(
53835
+ (0, import_node_fs15.mkdirSync)((0, import_node_path23.join)((0, import_node_os10.homedir)(), ".mrrlin"), { recursive: true });
53836
+ (0, import_node_fs15.writeFileSync)(
53437
53837
  path22,
53438
53838
  JSON.stringify({ priv: toBase64Url(kp.privateKey), pub: toBase64Url(kp.publicKey) }),
53439
53839
  { mode: 384 }
@@ -53442,10 +53842,10 @@ function loadOrCreateAgentDeviceKey() {
53442
53842
  }
53443
53843
  return kp;
53444
53844
  }
53445
- var AGENT_PAIRING_PATH = (0, import_node_path20.join)((0, import_node_os9.homedir)(), ".mrrlin", "agent-pairing.json");
53845
+ var AGENT_PAIRING_PATH = (0, import_node_path23.join)((0, import_node_os10.homedir)(), ".mrrlin", "agent-pairing.json");
53446
53846
  function loadAgentPairing() {
53447
53847
  try {
53448
- const raw = JSON.parse((0, import_node_fs12.readFileSync)(AGENT_PAIRING_PATH, "utf8"));
53848
+ const raw = JSON.parse((0, import_node_fs15.readFileSync)(AGENT_PAIRING_PATH, "utf8"));
53449
53849
  if (typeof raw.channelId === "string" && typeof raw.agentControlSecret === "string" && typeof raw.relayAuth === "string" && typeof raw.peerIdentityKey === "string") {
53450
53850
  return {
53451
53851
  channelId: raw.channelId,
@@ -53460,8 +53860,8 @@ function loadAgentPairing() {
53460
53860
  }
53461
53861
  function saveAgentPairing(record2) {
53462
53862
  try {
53463
- (0, import_node_fs12.mkdirSync)((0, import_node_path20.join)((0, import_node_os9.homedir)(), ".mrrlin"), { recursive: true });
53464
- (0, import_node_fs12.writeFileSync)(AGENT_PAIRING_PATH, JSON.stringify(record2), { mode: 384 });
53863
+ (0, import_node_fs15.mkdirSync)((0, import_node_path23.join)((0, import_node_os10.homedir)(), ".mrrlin"), { recursive: true });
53864
+ (0, import_node_fs15.writeFileSync)(AGENT_PAIRING_PATH, JSON.stringify(record2), { mode: 384 });
53465
53865
  } catch {
53466
53866
  }
53467
53867
  }
@@ -53639,18 +54039,18 @@ async function renderPairingQrSvg(payload) {
53639
54039
  }
53640
54040
 
53641
54041
  // src/checkout-registry.ts
53642
- var import_node_fs13 = require("node:fs");
53643
- var import_node_path21 = require("node:path");
54042
+ var import_node_fs16 = require("node:fs");
54043
+ var import_node_path24 = require("node:path");
53644
54044
  var CheckoutRegistry = class {
53645
54045
  file;
53646
54046
  constructor(stateDir) {
53647
- this.file = (0, import_node_path21.join)(stateDir, "checkouts.json");
53648
- (0, import_node_fs13.mkdirSync)(stateDir, { recursive: true });
54047
+ this.file = (0, import_node_path24.join)(stateDir, "checkouts.json");
54048
+ (0, import_node_fs16.mkdirSync)(stateDir, { recursive: true });
53649
54049
  }
53650
54050
  read() {
53651
- if (!(0, import_node_fs13.existsSync)(this.file)) return {};
54051
+ if (!(0, import_node_fs16.existsSync)(this.file)) return {};
53652
54052
  try {
53653
- return JSON.parse((0, import_node_fs13.readFileSync)(this.file, "utf8"));
54053
+ return JSON.parse((0, import_node_fs16.readFileSync)(this.file, "utf8"));
53654
54054
  } catch {
53655
54055
  return {};
53656
54056
  }
@@ -53661,13 +54061,13 @@ var CheckoutRegistry = class {
53661
54061
  confirm(slug, path22, now) {
53662
54062
  const all = this.read();
53663
54063
  all[slug] = { path: path22, confirmedAt: now };
53664
- (0, import_node_fs13.writeFileSync)(this.file, JSON.stringify(all, null, 2));
54064
+ (0, import_node_fs16.writeFileSync)(this.file, JSON.stringify(all, null, 2));
53665
54065
  }
53666
54066
  };
53667
54067
 
53668
54068
  // src/checkout-handlers.ts
53669
54069
  var import_node_child_process13 = require("node:child_process");
53670
- var import_node_fs14 = require("node:fs");
54070
+ var import_node_fs17 = require("node:fs");
53671
54071
 
53672
54072
  // src/git-remote-match.ts
53673
54073
  function normalizeRemote(url2) {
@@ -53702,7 +54102,7 @@ function validateCheckoutPath(checkoutPath, repo) {
53702
54102
  }
53703
54103
  let resolvedPath;
53704
54104
  try {
53705
- resolvedPath = (0, import_node_fs14.realpathSync)(trimmedPath);
54105
+ resolvedPath = (0, import_node_fs17.realpathSync)(trimmedPath);
53706
54106
  } catch {
53707
54107
  return {
53708
54108
  ok: false,
@@ -54008,9 +54408,9 @@ function extractVerificationSection(markdown) {
54008
54408
  }
54009
54409
 
54010
54410
  // src/director-reseed.ts
54011
- var import_node_fs15 = require("node:fs");
54411
+ var import_node_fs18 = require("node:fs");
54012
54412
  var import_node_readline = require("node:readline");
54013
- var import_node_path22 = require("node:path");
54413
+ var import_node_path25 = require("node:path");
54014
54414
  function estimateTokens(s) {
54015
54415
  return Buffer.byteLength(s, "utf8");
54016
54416
  }
@@ -54142,9 +54542,9 @@ async function readSessionRows(logsDir, files, sessionIds) {
54142
54542
  const lines2 = [];
54143
54543
  let missingFiles = 0;
54144
54544
  for (const f of files) {
54145
- const filePath = (0, import_node_path22.join)(logsDir, f);
54545
+ const filePath = (0, import_node_path25.join)(logsDir, f);
54146
54546
  try {
54147
- const stream = (0, import_node_fs15.createReadStream)(filePath, { encoding: "utf8" });
54547
+ const stream = (0, import_node_fs18.createReadStream)(filePath, { encoding: "utf8" });
54148
54548
  const rl = (0, import_node_readline.createInterface)({ input: stream, crlfDelay: Infinity });
54149
54549
  try {
54150
54550
  for await (const line of rl) {
@@ -54168,18 +54568,18 @@ async function readSessionRows(logsDir, files, sessionIds) {
54168
54568
  }
54169
54569
 
54170
54570
  // src/external-agents-scrub.ts
54171
- var import_node_fs16 = __toESM(require("node:fs"), 1);
54172
- var import_node_os10 = __toESM(require("node:os"), 1);
54173
- var import_node_path23 = __toESM(require("node:path"), 1);
54571
+ var import_node_fs19 = __toESM(require("node:fs"), 1);
54572
+ var import_node_os11 = __toESM(require("node:os"), 1);
54573
+ var import_node_path26 = __toESM(require("node:path"), 1);
54174
54574
  var REDACTION = "[REDACTED]";
54175
54575
  var SHORT_VALUE_THRESHOLD = 8;
54176
- var KEYS_ENV_PATH = () => import_node_path23.default.join(import_node_os10.default.homedir(), ".local", "state", "external-agents", "keys.env");
54576
+ var KEYS_ENV_PATH = () => import_node_path26.default.join(import_node_os11.default.homedir(), ".local", "state", "external-agents", "keys.env");
54177
54577
  var keysEnvCache = null;
54178
54578
  function readKeysEnv() {
54179
54579
  const filePath = KEYS_ENV_PATH();
54180
54580
  let mtimeMs = 0;
54181
54581
  try {
54182
- mtimeMs = import_node_fs16.default.statSync(filePath).mtimeMs;
54582
+ mtimeMs = import_node_fs19.default.statSync(filePath).mtimeMs;
54183
54583
  } catch {
54184
54584
  mtimeMs = 0;
54185
54585
  }
@@ -54188,7 +54588,7 @@ function readKeysEnv() {
54188
54588
  }
54189
54589
  const map2 = /* @__PURE__ */ new Map();
54190
54590
  try {
54191
- const content = import_node_fs16.default.readFileSync(filePath, "utf8");
54591
+ const content = import_node_fs19.default.readFileSync(filePath, "utf8");
54192
54592
  for (const rawLine of content.split(/\r?\n/)) {
54193
54593
  const line = rawLine.trim();
54194
54594
  if (line === "" || line.startsWith("#")) continue;
@@ -54606,7 +55006,7 @@ function addBridgeModel(target, model) {
54606
55006
  }
54607
55007
  function readTextIfExists(filePath) {
54608
55008
  try {
54609
- return import_node_fs17.default.readFileSync(filePath, "utf8");
55009
+ return import_node_fs20.default.readFileSync(filePath, "utf8");
54610
55010
  } catch {
54611
55011
  return null;
54612
55012
  }
@@ -54617,9 +55017,9 @@ function readKnownGptSlugsFromTomlFile(filePath) {
54617
55017
  return Array.from(raw.matchAll(/^\s*model\s*=\s*"([^"]+)"/gm)).map((match) => match[1]?.trim() ?? "").filter(isSelectableModelSlug);
54618
55018
  }
54619
55019
  function readCodexFallbackModels() {
54620
- const codexHome = process.env.CODEX_HOME?.trim() || import_node_path24.default.join(import_node_os11.default.homedir(), ".codex");
55020
+ const codexHome = process.env.CODEX_HOME?.trim() || import_node_path27.default.join(import_node_os12.default.homedir(), ".codex");
54621
55021
  const models = /* @__PURE__ */ new Map();
54622
- const cachePath = import_node_path24.default.join(codexHome, "models_cache.json");
55022
+ const cachePath = import_node_path27.default.join(codexHome, "models_cache.json");
54623
55023
  const cacheRaw = readTextIfExists(cachePath);
54624
55024
  if (cacheRaw) {
54625
55025
  try {
@@ -54669,7 +55069,7 @@ function readCodexFallbackModels() {
54669
55069
  );
54670
55070
  }
54671
55071
  }
54672
- for (const slug of readKnownGptSlugsFromTomlFile(import_node_path24.default.join(codexHome, "config.toml"))) {
55072
+ for (const slug of readKnownGptSlugsFromTomlFile(import_node_path27.default.join(codexHome, "config.toml"))) {
54673
55073
  addBridgeModel(
54674
55074
  models,
54675
55075
  mapBridgeModel({
@@ -54683,11 +55083,11 @@ function readCodexFallbackModels() {
54683
55083
  })
54684
55084
  );
54685
55085
  }
54686
- const automationsDir = import_node_path24.default.join(codexHome, "automations");
55086
+ const automationsDir = import_node_path27.default.join(codexHome, "automations");
54687
55087
  try {
54688
- for (const entry of import_node_fs17.default.readdirSync(automationsDir, { withFileTypes: true })) {
55088
+ for (const entry of import_node_fs20.default.readdirSync(automationsDir, { withFileTypes: true })) {
54689
55089
  if (!entry.isDirectory()) continue;
54690
- for (const slug of readKnownGptSlugsFromTomlFile(import_node_path24.default.join(automationsDir, entry.name, "automation.toml"))) {
55090
+ for (const slug of readKnownGptSlugsFromTomlFile(import_node_path27.default.join(automationsDir, entry.name, "automation.toml"))) {
54691
55091
  addBridgeModel(
54692
55092
  models,
54693
55093
  mapBridgeModel({
@@ -54707,15 +55107,15 @@ function readCodexFallbackModels() {
54707
55107
  return [...models.values()];
54708
55108
  }
54709
55109
  function selfUpdateInboxItemId(offeredVersion) {
54710
- if (!offeredVersion) return `II-MCPUPD-${(0, import_node_crypto10.randomUUID)()}`;
55110
+ if (!offeredVersion) return `II-MCPUPD-${(0, import_node_crypto11.randomUUID)()}`;
54711
55111
  if (/^[A-Za-z0-9._-]+$/.test(offeredVersion)) return `II-MCPUPD-${offeredVersion}`;
54712
- const hash3 = import_node_crypto10.default.createHash("sha256").update(offeredVersion).digest("hex").slice(0, 10);
55112
+ const hash3 = import_node_crypto11.default.createHash("sha256").update(offeredVersion).digest("hex").slice(0, 10);
54713
55113
  return `II-MCPUPD-${offeredVersion.replace(/[^A-Za-z0-9._-]/g, "-")}-${hash3}`;
54714
55114
  }
54715
55115
  function neutralCheckoutCwd(stateDir) {
54716
- const dir = import_node_path24.default.join(stateDir, "no-checkout");
55116
+ const dir = import_node_path27.default.join(stateDir, "no-checkout");
54717
55117
  try {
54718
- import_node_fs17.default.mkdirSync(dir, { recursive: true });
55118
+ import_node_fs20.default.mkdirSync(dir, { recursive: true });
54719
55119
  } catch {
54720
55120
  }
54721
55121
  return dir;
@@ -55225,7 +55625,7 @@ async function runOrphanWorktreeSweep(client, opts) {
55225
55625
  const cutoff = Date.now() - worktreeRetentionMs();
55226
55626
  const isReapable = (worktreePath) => {
55227
55627
  try {
55228
- return import_node_fs17.default.statSync(worktreePath).mtimeMs < cutoff;
55628
+ return import_node_fs20.default.statSync(worktreePath).mtimeMs < cutoff;
55229
55629
  } catch {
55230
55630
  return false;
55231
55631
  }
@@ -55263,8 +55663,8 @@ async function runOrphanWorktreeSweep(client, opts) {
55263
55663
  }
55264
55664
  }
55265
55665
  function readStateDir() {
55266
- if (process.env.CODEX_HOME) return import_node_path24.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge");
55267
- return import_node_path24.default.join(import_node_os11.default.homedir(), ".mrrlin", "director-bridge");
55666
+ if (process.env.CODEX_HOME) return import_node_path27.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge");
55667
+ return import_node_path27.default.join(import_node_os12.default.homedir(), ".mrrlin", "director-bridge");
55268
55668
  }
55269
55669
  function readAllowedOrigins() {
55270
55670
  const raw = (process.env.MRRLIN_DIRECTOR_BRIDGE_ALLOWED_ORIGINS ?? "").trim();
@@ -55339,7 +55739,7 @@ function createBridgeRequestListener(opts) {
55339
55739
  res.end(JSON.stringify({ ok: false, error: "Origin not allowed." }));
55340
55740
  return;
55341
55741
  }
55342
- const nonce = import_node_crypto10.default.randomBytes(16).toString("base64url");
55742
+ const nonce = import_node_crypto11.default.randomBytes(16).toString("base64url");
55343
55743
  res.writeHead(200, { "content-type": "application/json" });
55344
55744
  res.end(JSON.stringify({ ok: true, wsUrl: `ws://${host}:${port}/ws`, token, nonce }));
55345
55745
  return;
@@ -55638,7 +56038,7 @@ function createBridgeMessageHandler(deps) {
55638
56038
  }
55639
56039
  }
55640
56040
  socket.on("message", async (data) => {
55641
- const spanId = import_node_crypto10.default.randomUUID();
56041
+ const spanId = import_node_crypto11.default.randomUUID();
55642
56042
  if (logCtx) {
55643
56043
  logCtx.span.id = spanId;
55644
56044
  logCtx.span.at = Date.now();
@@ -55700,7 +56100,7 @@ function createBridgeMessageHandler(deps) {
55700
56100
  sendForSpan({ type: "checkout-state", ok: false, error: { code: "invalid_input", fields: { projectSlug: "required" } } });
55701
56101
  return;
55702
56102
  }
55703
- const state = readCheckoutState(deps.checkoutRegistry, projectSlug, import_node_os11.default.hostname());
56103
+ const state = readCheckoutState(deps.checkoutRegistry, projectSlug, import_node_os12.default.hostname());
55704
56104
  if (!state) {
55705
56105
  sendForSpan({ type: "checkout-state", ok: false, error: { code: "checkout_missing" } });
55706
56106
  return;
@@ -55732,7 +56132,7 @@ function createBridgeMessageHandler(deps) {
55732
56132
  const result = registerCheckout(
55733
56133
  deps.checkoutRegistry,
55734
56134
  { projectSlug, path: typeof msg.path === "string" ? msg.path : "", repo },
55735
- import_node_os11.default.hostname()
56135
+ import_node_os12.default.hostname()
55736
56136
  );
55737
56137
  if (!result.ok) {
55738
56138
  sendForSpan({ type: "checkout-register", ok: false, error: { code: result.code, detail: result.detail } });
@@ -56218,7 +56618,7 @@ function createBridgeMessageHandler(deps) {
56218
56618
  thread.inFlight = true;
56219
56619
  pendingTurnSessions.delete(directorSessionId);
56220
56620
  thread.replay = createReplayBuffer({
56221
- turnId: (0, import_node_crypto10.randomUUID)(),
56621
+ turnId: (0, import_node_crypto11.randomUUID)(),
56222
56622
  spanId,
56223
56623
  ...deps.retentionMs !== void 0 ? { retentionMs: deps.retentionMs } : {},
56224
56624
  ...deps.ackLingerMs !== void 0 ? { ackLingerMs: deps.ackLingerMs } : {}
@@ -56799,8 +57199,8 @@ async function startDirectorBridge() {
56799
57199
  codexCwd: config2.codexCwd,
56800
57200
  codexExecutable: config2.codexExecutable,
56801
57201
  checkoutRegistry,
56802
- worktreeRoot: import_node_path24.default.join(config2.stateDir, "worktrees"),
56803
- locksDir: import_node_path24.default.join(config2.stateDir, "locks"),
57202
+ worktreeRoot: import_node_path27.default.join(config2.stateDir, "worktrees"),
57203
+ locksDir: import_node_path27.default.join(config2.stateDir, "locks"),
56804
57204
  // Wire the executor server for code-execution runs. Each run gets its own provider process
56805
57205
  // (app-server for codex, a resident CLI child for claude) at the run worktree, running
56806
57206
  // UNRESTRICTED from the real operator config (owner no-sandbox decision — auth + mrrlin MCP
@@ -56844,13 +57244,13 @@ async function startDirectorBridge() {
56844
57244
  // egressDomains is retained in the seam signature (verification-turn.ts still computes the
56845
57245
  // env host) but no longer constrains anything — the executor is unrestricted.
56846
57246
  startSandbox: async (_egressDomains, providerId) => {
56847
- const cwd = import_node_fs17.default.mkdtempSync(import_node_path24.default.join(import_node_os11.default.tmpdir(), "mrrlin-verify-"));
57247
+ const cwd = import_node_fs20.default.mkdtempSync(import_node_path27.default.join(import_node_os12.default.tmpdir(), "mrrlin-verify-"));
56848
57248
  let executor;
56849
57249
  try {
56850
57250
  executor = await startExecutorServer({ worktree: cwd, provider: providerId });
56851
57251
  } catch (error51) {
56852
57252
  try {
56853
- import_node_fs17.default.rmSync(cwd, { recursive: true, force: true });
57253
+ import_node_fs20.default.rmSync(cwd, { recursive: true, force: true });
56854
57254
  } catch {
56855
57255
  }
56856
57256
  throw error51;
@@ -56861,7 +57261,7 @@ async function startDirectorBridge() {
56861
57261
  dispose: () => {
56862
57262
  executor.dispose();
56863
57263
  try {
56864
- import_node_fs17.default.rmSync(cwd, { recursive: true, force: true });
57264
+ import_node_fs20.default.rmSync(cwd, { recursive: true, force: true });
56865
57265
  } catch {
56866
57266
  }
56867
57267
  }
@@ -56890,7 +57290,7 @@ async function startDirectorBridge() {
56890
57290
  };
56891
57291
  const sessionSinks = createSessionSinkRegistry();
56892
57292
  const tombstones = /* @__PURE__ */ new Map();
56893
- const bridgeInstanceId = (0, import_node_crypto10.randomUUID)();
57293
+ const bridgeInstanceId = (0, import_node_crypto11.randomUUID)();
56894
57294
  const asyncConsumerDeps = {
56895
57295
  client,
56896
57296
  run: wrappedTurnLock.run,
@@ -57041,7 +57441,7 @@ async function startDirectorBridge() {
57041
57441
  const relayUrl = process.env.MRRLIN_RELAY_URL?.trim();
57042
57442
  const relayConfigured = Boolean(agentSecret && relayUrl);
57043
57443
  const buildReseedPrefix = async (args) => {
57044
- const refuse = (reason) => {
57444
+ const refuse2 = (reason) => {
57045
57445
  bridgeLogger.logOut({
57046
57446
  spanId: "reseed",
57047
57447
  sessionId: args.directorSessionId,
@@ -57050,8 +57450,8 @@ async function startDirectorBridge() {
57050
57450
  });
57051
57451
  return NO_HISTORY_BLOCK;
57052
57452
  };
57053
- if (!resolveBridgeLogEnabled()) return refuse("log-disabled");
57054
- if (!resolvePromptsEnabled()) return refuse("prompts-not-logged");
57453
+ if (!resolveBridgeLogEnabled()) return refuse2("log-disabled");
57454
+ if (!resolvePromptsEnabled()) return refuse2("prompts-not-logged");
57055
57455
  const retentionWindowMs = readEnvInt("MRRLIN_LOG_RETENTION_AGE_DAYS", 30) * 864e5;
57056
57456
  const reseedWindowMs = Math.min(config2.idleThreadTtlMs, retentionWindowMs);
57057
57457
  if (reseedWindowMs < config2.idleThreadTtlMs) {
@@ -57068,15 +57468,15 @@ async function startDirectorBridge() {
57068
57468
  }
57069
57469
  const files = dayFilesInWindow(/* @__PURE__ */ new Date(), reseedWindowMs);
57070
57470
  const sessionIds = [args.directorSessionId, ...args.priorSessionIds];
57071
- const { lines: lines2, missingFiles } = await readSessionRows(import_node_path24.default.join(config2.stateDir, "logs"), files, sessionIds);
57471
+ const { lines: lines2, missingFiles } = await readSessionRows(import_node_path27.default.join(config2.stateDir, "logs"), files, sessionIds);
57072
57472
  const { items, skipped: skipped2 } = extractItems(lines2, sessionIds);
57073
- if (items.length === 0) return refuse("no-rows");
57473
+ if (items.length === 0) return refuse2("no-rows");
57074
57474
  const budget = Math.max(0, Math.min(config2.reseedMaxTokens, config2.turnMaxTokens - args.otherBytes));
57075
57475
  const block = renderReseedBlock(items, {
57076
57476
  maxTokens: budget,
57077
57477
  minConversationalItems: config2.reseedMinItems
57078
57478
  });
57079
- if (!block) return refuse("below-minimum-after-truncation");
57479
+ if (!block) return refuse2("below-minimum-after-truncation");
57080
57480
  bridgeLogger.logOut({
57081
57481
  spanId: "reseed",
57082
57482
  sessionId: args.directorSessionId,
@@ -57165,7 +57565,7 @@ async function startDirectorBridge() {
57165
57565
  const bridgeLogger = createBridgeLogger(config2.stateDir, process.env);
57166
57566
  let bridgeBinShaShort = "unknown00000";
57167
57567
  try {
57168
- bridgeBinShaShort = import_node_crypto10.default.createHash("sha256").update(import_node_fs17.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
57568
+ bridgeBinShaShort = import_node_crypto11.default.createHash("sha256").update(import_node_fs20.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
57169
57569
  } catch {
57170
57570
  }
57171
57571
  attachBridgeWss(server, {
@@ -57301,8 +57701,8 @@ async function startDirectorBridge() {
57301
57701
  );
57302
57702
  void runOrphanWorktreeSweep(client, {
57303
57703
  checkoutRegistry,
57304
- worktreeRoot: import_node_path24.default.join(config2.stateDir, "worktrees"),
57305
- locksDir: import_node_path24.default.join(config2.stateDir, "locks")
57704
+ worktreeRoot: import_node_path27.default.join(config2.stateDir, "worktrees"),
57705
+ locksDir: import_node_path27.default.join(config2.stateDir, "locks")
57306
57706
  });
57307
57707
  {
57308
57708
  const { retainedBuffers, retainedBytes, tombstonesRemoved } = sweepReplayBuffers(threads, tombstones, {
@@ -57610,7 +58010,7 @@ function timingSafeTokenEqual(provided, expected) {
57610
58010
  const a = Buffer.from(provided);
57611
58011
  const b = Buffer.from(expected);
57612
58012
  if (a.length !== b.length) return false;
57613
- return import_node_crypto10.default.timingSafeEqual(a, b);
58013
+ return import_node_crypto11.default.timingSafeEqual(a, b);
57614
58014
  }
57615
58015
  function readDispatchBody(req) {
57616
58016
  return new Promise((resolve, reject) => {
@@ -57632,15 +58032,15 @@ function readDispatchBody(req) {
57632
58032
  function readOrCreateBridgeToken(stateDir) {
57633
58033
  const explicit = (process.env.MRRLIN_DIRECTOR_BRIDGE_TOKEN ?? "").trim();
57634
58034
  if (explicit) return explicit;
57635
- const tokenPath = import_node_path24.default.join(stateDir, "token.txt");
58035
+ const tokenPath = import_node_path27.default.join(stateDir, "token.txt");
57636
58036
  try {
57637
- const existing = import_node_fs17.default.readFileSync(tokenPath, "utf8").trim();
58037
+ const existing = import_node_fs20.default.readFileSync(tokenPath, "utf8").trim();
57638
58038
  if (existing) return existing;
57639
58039
  } catch {
57640
58040
  }
57641
- import_node_fs17.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
57642
- const token = import_node_crypto10.default.randomBytes(32).toString("base64url");
57643
- import_node_fs17.default.writeFileSync(tokenPath, `${token}
58041
+ import_node_fs20.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
58042
+ const token = import_node_crypto11.default.randomBytes(32).toString("base64url");
58043
+ import_node_fs20.default.writeFileSync(tokenPath, `${token}
57644
58044
  `, { mode: 384 });
57645
58045
  return token;
57646
58046
  }
@@ -61028,17 +61428,17 @@ var StdioServerTransport = class {
61028
61428
  };
61029
61429
 
61030
61430
  // src/tools.ts
61031
- var import_node_crypto13 = require("node:crypto");
61431
+ var import_node_crypto14 = require("node:crypto");
61032
61432
  var import_promises10 = require("node:fs/promises");
61033
- var import_node_path27 = __toESM(require("node:path"), 1);
61034
- var import_node_os12 = __toESM(require("node:os"), 1);
61433
+ var import_node_path30 = __toESM(require("node:path"), 1);
61434
+ var import_node_os13 = __toESM(require("node:os"), 1);
61035
61435
 
61036
61436
  // ../../packages/wiki/dist/index.js
61037
61437
  var import_promises8 = __toESM(require("node:fs/promises"), 1);
61038
- var import_node_path25 = __toESM(require("node:path"), 1);
61438
+ var import_node_path28 = __toESM(require("node:path"), 1);
61039
61439
  var INCLUDED_DOC_FOLDERS = /* @__PURE__ */ new Set(["_meta", "explanation", "how-to", "reference", "sdd", "tutorials"]);
61040
61440
  function toPosixPath(input) {
61041
- return input.split(import_node_path25.default.sep).join("/");
61441
+ return input.split(import_node_path28.default.sep).join("/");
61042
61442
  }
61043
61443
  function slugifyWikiSegment(input) {
61044
61444
  return input.trim().toLowerCase().replace(/`/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -61052,12 +61452,12 @@ async function pathExists3(input) {
61052
61452
  }
61053
61453
  }
61054
61454
  async function findWorkspaceRoot(start = process.cwd()) {
61055
- let current2 = import_node_path25.default.resolve(start);
61455
+ let current2 = import_node_path28.default.resolve(start);
61056
61456
  while (true) {
61057
- if (await pathExists3(import_node_path25.default.join(current2, "pnpm-workspace.yaml")) && await pathExists3(import_node_path25.default.join(current2, "docs"))) {
61457
+ if (await pathExists3(import_node_path28.default.join(current2, "pnpm-workspace.yaml")) && await pathExists3(import_node_path28.default.join(current2, "docs"))) {
61058
61458
  return current2;
61059
61459
  }
61060
- const parent = import_node_path25.default.dirname(current2);
61460
+ const parent = import_node_path28.default.dirname(current2);
61061
61461
  if (parent === current2) {
61062
61462
  throw new Error(`Unable to find Mrrlin workspace root from ${start}`);
61063
61463
  }
@@ -61066,28 +61466,28 @@ async function findWorkspaceRoot(start = process.cwd()) {
61066
61466
  }
61067
61467
  async function resolveDocsRoot(input) {
61068
61468
  if (input) {
61069
- return import_node_path25.default.resolve(input);
61469
+ return import_node_path28.default.resolve(input);
61070
61470
  }
61071
61471
  if (process.env.MRRLIN_DOCS_ROOT) {
61072
- return import_node_path25.default.resolve(process.env.MRRLIN_DOCS_ROOT);
61472
+ return import_node_path28.default.resolve(process.env.MRRLIN_DOCS_ROOT);
61073
61473
  }
61074
- return import_node_path25.default.join(await findWorkspaceRoot(), "docs");
61474
+ return import_node_path28.default.join(await findWorkspaceRoot(), "docs");
61075
61475
  }
61076
61476
  async function resolveIndexPath(input) {
61077
61477
  if (input) {
61078
- return import_node_path25.default.resolve(input);
61478
+ return import_node_path28.default.resolve(input);
61079
61479
  }
61080
61480
  if (process.env.MRRLIN_WIKI_INDEX_PATH) {
61081
- return import_node_path25.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
61481
+ return import_node_path28.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
61082
61482
  }
61083
61483
  const workspaceRoot = await findWorkspaceRoot();
61084
- return import_node_path25.default.join(workspaceRoot, "apps", "web", "public", "wiki-index.json");
61484
+ return import_node_path28.default.join(workspaceRoot, "apps", "web", "public", "wiki-index.json");
61085
61485
  }
61086
61486
  async function walkMarkdownFiles(root, dir = root) {
61087
61487
  const entries = await import_promises8.default.readdir(dir, { withFileTypes: true });
61088
61488
  const files = [];
61089
61489
  for (const entry of entries) {
61090
- const absolute = import_node_path25.default.join(dir, entry.name);
61490
+ const absolute = import_node_path28.default.join(dir, entry.name);
61091
61491
  if (entry.isDirectory()) {
61092
61492
  files.push(...await walkMarkdownFiles(root, absolute));
61093
61493
  continue;
@@ -61106,7 +61506,7 @@ function parseTitle(markdown, sourcePath) {
61106
61506
  return title;
61107
61507
  }
61108
61508
  function documentFromFile(docsRoot, absolutePath, markdown) {
61109
- const relativePath = toPosixPath(import_node_path25.default.relative(docsRoot, absolutePath));
61509
+ const relativePath = toPosixPath(import_node_path28.default.relative(docsRoot, absolutePath));
61110
61510
  const [section, fileName] = relativePath.split("/");
61111
61511
  if (!section || !fileName || !INCLUDED_DOC_FOLDERS.has(section)) {
61112
61512
  return null;
@@ -61457,15 +61857,17 @@ async function pickPanel(input, deps) {
61457
61857
  const agents = r.stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
61458
61858
  return { ok: true, agents };
61459
61859
  }
61460
- async function dispatchHead(agentId, prompt, timeoutMs, deps) {
61461
- const spawn4 = deps?.spawn ?? import_node_child_process17.spawn;
61462
- const { command, prefixArgs } = resolveExternalAgentsCliInvocation(deps?.externalAgentsBin);
61463
- const args = ["dispatch", agentId, "--json", prompt];
61464
- const r = await runExternalAgents(command, [...prefixArgs, ...args], "dispatch", timeoutMs, spawn4);
61465
- if (r.error) return { ok: false, error: r.error };
61466
- const lines2 = r.stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
61860
+ function dispatchUsage(parsed) {
61861
+ const readCount3 = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
61862
+ const inputTokens = readCount3(parsed.tokens_in);
61863
+ const outputTokens = readCount3(parsed.tokens_out);
61864
+ if (inputTokens === null && outputTokens === null) return null;
61865
+ return { inputTokens, cachedInputTokens: null, cacheWriteInputTokens: null, outputTokens };
61866
+ }
61867
+ function parseDispatch(agentId, stdout, exitCode) {
61868
+ const lines2 = stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
61467
61869
  const jsonLine = [...lines2].reverse().find((l) => l[0] === "{");
61468
- if (!jsonLine) return { ok: false, error: `dispatch ${agentId}: no JSON on stdout (exit ${r.code})` };
61870
+ if (!jsonLine) return { ok: false, error: `dispatch ${agentId}: no JSON on stdout (exit ${exitCode})` };
61469
61871
  let parsed;
61470
61872
  try {
61471
61873
  parsed = JSON.parse(jsonLine);
@@ -61478,7 +61880,16 @@ async function dispatchHead(agentId, prompt, timeoutMs, deps) {
61478
61880
  if (typeof parsed.text !== "string" || parsed.text.trim() === "") {
61479
61881
  return { ok: false, error: `dispatch ${agentId}: empty text on success` };
61480
61882
  }
61481
- return { ok: true, text: parsed.text };
61883
+ const usage = dispatchUsage(parsed);
61884
+ return { ok: true, text: parsed.text, usage };
61885
+ }
61886
+ async function dispatchHead(agentId, prompt, timeoutMs, deps) {
61887
+ const spawn4 = deps?.spawn ?? import_node_child_process17.spawn;
61888
+ const { command, prefixArgs } = resolveExternalAgentsCliInvocation(deps?.externalAgentsBin);
61889
+ const args = ["dispatch", agentId, "--json", prompt];
61890
+ const r = await runExternalAgents(command, [...prefixArgs, ...args], "dispatch", timeoutMs, spawn4);
61891
+ if (r.error) return { ok: false, error: r.error };
61892
+ return parseDispatch(agentId, r.stdout, r.code);
61482
61893
  }
61483
61894
  async function buildMultiHeadRunner(input, deps) {
61484
61895
  const pickOnce = () => pickPanel(
@@ -61722,6 +62133,245 @@ async function resolveActivePanel(input, deps) {
61722
62133
  }
61723
62134
  }
61724
62135
 
62136
+ // src/delivery/wiki.ts
62137
+ async function deliverToWiki(client, projectSlug, payload) {
62138
+ if (payload.operation === "create") return client.createWikiPage(projectSlug, payload.page);
62139
+ return client.updateWikiPage(projectSlug, payload.pageId, payload.patch);
62140
+ }
62141
+
62142
+ // src/delivery/git.ts
62143
+ async function deliverToGit(client, projectSlug, payload) {
62144
+ if (payload.operation === "branch") {
62145
+ return client.createGithubBranch(projectSlug, { baseBranch: payload.baseBranch, branchName: payload.branchName });
62146
+ }
62147
+ return client.createGithubPullRequest(projectSlug, {
62148
+ baseBranch: payload.baseBranch,
62149
+ body: payload.body,
62150
+ draft: payload.draft,
62151
+ headBranch: payload.headBranch,
62152
+ title: payload.title
62153
+ });
62154
+ }
62155
+
62156
+ // src/delivery/index.ts
62157
+ async function deliverThroughCapability(client, input) {
62158
+ if (resolveKindCapability(input.artifactKind) === null) {
62159
+ return { ok: false, reason: "blocked_kind" };
62160
+ }
62161
+ let resolution;
62162
+ try {
62163
+ resolution = await client.resolveDeliveryForArtifactKind(
62164
+ input.projectSlug,
62165
+ input.artifactKind,
62166
+ input.taskProjectSlug,
62167
+ input.taskId ?? void 0
62168
+ );
62169
+ } catch {
62170
+ return { ok: false, reason: "transport_error" };
62171
+ }
62172
+ if (!resolution.ok) {
62173
+ return { ok: false, reason: resolution.reason };
62174
+ }
62175
+ const { route, verdict } = resolution;
62176
+ if (verdict === "silent") {
62177
+ return proceedToDestination(client, route, input);
62178
+ }
62179
+ if (verdict === "ask_once") {
62180
+ return handleAskOnce(client, route, input);
62181
+ }
62182
+ if (verdict === "window") {
62183
+ return handleWindow(client, route, input);
62184
+ }
62185
+ if (verdict === "approval") {
62186
+ return handleApproval(client, route, input);
62187
+ }
62188
+ await recordUse(client, route, input, "refused");
62189
+ return { ok: false, reason: "gate_refused" };
62190
+ }
62191
+ async function proceedToDestination(client, route, input) {
62192
+ try {
62193
+ const result = await callDestination(client, input.taskProjectSlug, route.capability, input.payload);
62194
+ const recorded = await recordUse(client, route, input, "ok");
62195
+ return { ok: true, use: recorded, result };
62196
+ } catch {
62197
+ await recordUse(client, route, input, "error");
62198
+ return { ok: false, reason: "delivery_failed" };
62199
+ }
62200
+ }
62201
+ async function refuse(client, route, input) {
62202
+ await recordUse(client, route, input, "refused");
62203
+ return { ok: false, reason: "gate_refused" };
62204
+ }
62205
+ async function handleAskOnce(client, route, input) {
62206
+ const groupId = `capability:ask-once:${input.taskProjectSlug}:${route.serverId}`;
62207
+ try {
62208
+ await client.createInboxItem(input.taskProjectSlug, {
62209
+ id: `II-capability-ask-once-${input.taskProjectSlug}-${route.serverId}`,
62210
+ kind: "question",
62211
+ origin: "capability",
62212
+ groupId,
62213
+ body: `The first write to ${route.serverId} (via ${route.toolName}) needs a one-time confirmation before it can proceed.`,
62214
+ taskId: input.taskId
62215
+ });
62216
+ } catch {
62217
+ }
62218
+ return refuse(client, route, input);
62219
+ }
62220
+ async function alreadyConsumed(client, route, input, after) {
62221
+ let uses;
62222
+ try {
62223
+ uses = await client.listCapabilityUses(input.taskProjectSlug);
62224
+ } catch {
62225
+ return true;
62226
+ }
62227
+ const afterMs = Date.parse(after);
62228
+ if (!Number.isFinite(afterMs)) return true;
62229
+ return uses.some((use) => {
62230
+ if (use.serverId !== route.serverId || use.toolName !== route.toolName || use.taskId !== input.taskId || use.outcome !== "ok") {
62231
+ return false;
62232
+ }
62233
+ const useAtMs = Date.parse(use.at);
62234
+ if (!Number.isFinite(useAtMs)) return true;
62235
+ return useAtMs > afterMs;
62236
+ });
62237
+ }
62238
+ async function handleApproval(client, route, input) {
62239
+ const scopeId = input.runId ?? input.taskId;
62240
+ if (scopeId === null) {
62241
+ return refuse(client, route, input);
62242
+ }
62243
+ const groupId = `capability:approval:${scopeId}:${route.serverId}:${route.toolName}`;
62244
+ const id = `II-capability-approval-${scopeId}-${route.serverId}-${route.toolName}`;
62245
+ let items;
62246
+ try {
62247
+ items = await client.listInboxItems(input.taskProjectSlug, { groupId });
62248
+ } catch {
62249
+ return refuse(client, route, input);
62250
+ }
62251
+ const existing = items[0];
62252
+ if (!existing) {
62253
+ try {
62254
+ await client.createInboxItem(input.taskProjectSlug, {
62255
+ id,
62256
+ kind: "question",
62257
+ origin: "capability",
62258
+ groupId,
62259
+ body: `Approve ${route.toolName} on ${route.serverId}?`,
62260
+ taskId: input.taskId
62261
+ });
62262
+ } catch {
62263
+ }
62264
+ return refuse(client, route, input);
62265
+ }
62266
+ if (existing.status !== "approved") {
62267
+ return refuse(client, route, input);
62268
+ }
62269
+ if (existing.decidedAt === null) {
62270
+ return refuse(client, route, input);
62271
+ }
62272
+ if (await alreadyConsumed(client, route, input, existing.decidedAt)) {
62273
+ return refuse(client, route, input);
62274
+ }
62275
+ return proceedToDestination(client, route, input);
62276
+ }
62277
+ async function handleWindow(client, route, input) {
62278
+ if (input.taskId === null) {
62279
+ return refuse(client, route, input);
62280
+ }
62281
+ const taskId = input.taskId;
62282
+ const scopeId = input.runId ?? taskId;
62283
+ const groupId = `capability:window:${scopeId}:${route.serverId}:${route.toolName}`;
62284
+ const id = `II-capability-window-${scopeId}-${route.serverId}-${route.toolName}`;
62285
+ let items;
62286
+ try {
62287
+ items = await client.listInboxItems(input.taskProjectSlug, { groupId });
62288
+ } catch {
62289
+ return refuse(client, route, input);
62290
+ }
62291
+ const existing = items[0];
62292
+ if (!existing) {
62293
+ try {
62294
+ await client.createInboxItem(input.taskProjectSlug, {
62295
+ id,
62296
+ kind: "question",
62297
+ origin: "capability",
62298
+ groupId,
62299
+ body: `Waiting for the ${route.toolName} window on ${route.serverId} to elapse.`,
62300
+ taskId
62301
+ });
62302
+ } catch {
62303
+ }
62304
+ await extendFollowUpAt(client, input.taskProjectSlug, taskId);
62305
+ return refuse(client, route, input);
62306
+ }
62307
+ if (existing.status === "rejected") {
62308
+ return refuse(client, route, input);
62309
+ }
62310
+ let task;
62311
+ try {
62312
+ task = await client.getTask(input.taskProjectSlug, taskId);
62313
+ } catch {
62314
+ return refuse(client, route, input);
62315
+ }
62316
+ const elapsed = task.followUpAt !== null && Date.parse(task.followUpAt) <= Date.now();
62317
+ if (!elapsed) {
62318
+ return refuse(client, route, input);
62319
+ }
62320
+ if (await alreadyConsumed(client, route, input, existing.createdAt)) {
62321
+ return refuse(client, route, input);
62322
+ }
62323
+ const result = await proceedToDestination(client, route, input);
62324
+ if (result.ok) {
62325
+ try {
62326
+ await client.decideInboxItem(input.taskProjectSlug, existing.id, { verdict: "acknowledged", decidedBy: "system" });
62327
+ } catch {
62328
+ }
62329
+ }
62330
+ return result;
62331
+ }
62332
+ async function extendFollowUpAt(client, taskProjectSlug, taskId) {
62333
+ try {
62334
+ const task = await client.getTask(taskProjectSlug, taskId);
62335
+ const existingMs = task.followUpAt !== null ? Date.parse(task.followUpAt) : -Infinity;
62336
+ const candidateMs = Date.now() + 5 * 60 * 1e3;
62337
+ if (candidateMs > existingMs) {
62338
+ await client.updateTask(taskProjectSlug, taskId, { followUpAt: new Date(candidateMs).toISOString() });
62339
+ }
62340
+ } catch {
62341
+ }
62342
+ }
62343
+ async function recordUse(client, route, input, outcome) {
62344
+ try {
62345
+ return await client.recordCapabilityUse(input.taskProjectSlug, {
62346
+ serverId: route.serverId,
62347
+ toolName: route.toolName,
62348
+ taskId: input.taskId,
62349
+ outcome
62350
+ });
62351
+ } catch {
62352
+ return null;
62353
+ }
62354
+ }
62355
+ async function callDestination(client, projectSlug, capability, payload) {
62356
+ const operation = isRecord4(payload) ? payload.operation : void 0;
62357
+ if (capability === "wiki") {
62358
+ if (operation !== "create" && operation !== "update") {
62359
+ throw new Error(`callDestination: payload.operation "${String(operation)}" is not valid for wiki`);
62360
+ }
62361
+ return deliverToWiki(client, projectSlug, payload);
62362
+ }
62363
+ if (capability === "git") {
62364
+ if (operation !== "branch" && operation !== "pull_request") {
62365
+ throw new Error(`callDestination: payload.operation "${String(operation)}" is not valid for git`);
62366
+ }
62367
+ return deliverToGit(client, projectSlug, payload);
62368
+ }
62369
+ throw new Error(`callDestination: no destination wired for capability "${capability}"`);
62370
+ }
62371
+ function isRecord4(value) {
62372
+ return typeof value === "object" && value !== null;
62373
+ }
62374
+
61725
62375
  // src/decision-consensus.ts
61726
62376
  var ANCHOR_TIMEOUT_MS = Number(process.env["MRRLIN_DECISION_TIMEOUT_MS"] ?? 9e4);
61727
62377
  var PICK_TIMEOUT_MS3 = 15e3;
@@ -61863,7 +62513,7 @@ async function runDecisionConsensus(input, deps) {
61863
62513
  }
61864
62514
 
61865
62515
  // src/async-tools/consensus.ts
61866
- var import_node_crypto11 = require("node:crypto");
62516
+ var import_node_crypto12 = require("node:crypto");
61867
62517
 
61868
62518
  // src/consensus/question-similarity.ts
61869
62519
  var SUPPRESSION_SIMILARITY_THRESHOLD = 0.6;
@@ -62059,6 +62709,10 @@ async function runNativeSpecGate(ctx, input, builders = defaultNativeSpecGateBui
62059
62709
  specPageId: input.pageId,
62060
62710
  cwd: ctx.cwd,
62061
62711
  codexExecutable: ctx.codexExecutable,
62712
+ // Where the gate records what each of its provider calls cost. This is the only one of the
62713
+ // four gate-deps call sites that holds a stateDir today; without it the recorder is a no-op,
62714
+ // so the spec gate is the one whose cost is actually observable.
62715
+ stateDir: ctx.stateDir,
62062
62716
  extraHeadCount: input.extraHeads?.length ?? 0,
62063
62717
  // model-tier-planning-and-arbiter task 1.21: the seat minted at the async-job claim.
62064
62718
  seat: ctx.seat
@@ -62139,9 +62793,9 @@ async function handleConsensusBlocked(result, ctx, input, resolvedTaskId) {
62139
62793
  }
62140
62794
  if (taskId) {
62141
62795
  const scopeId = taskId;
62142
- 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;
62796
+ 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;
62143
62797
  for (const clarification of toFile) {
62144
- const id = `II-${scopeId}-gate-${(0, import_node_crypto11.createHash)("sha256").update(clarification.rawQuestion).digest("hex").slice(0, 10)}`;
62798
+ const id = `II-${scopeId}-gate-${(0, import_node_crypto12.createHash)("sha256").update(clarification.rawQuestion).digest("hex").slice(0, 10)}`;
62145
62799
  try {
62146
62800
  const questionOptions = buildGateQuestionOptions(clarification.rawQuestion, clarification.category);
62147
62801
  await ctx.client.createInboxItem(input.projectSlug, {
@@ -62159,9 +62813,9 @@ async function handleConsensusBlocked(result, ctx, input, resolvedTaskId) {
62159
62813
  filedQuestionCount = toFile.length;
62160
62814
  } else if (planId) {
62161
62815
  const scopeId = planId;
62162
- 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;
62816
+ 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;
62163
62817
  for (const clarification of toFile) {
62164
- const id = `II-${scopeId}-gate-${(0, import_node_crypto11.createHash)("sha256").update(clarification.rawQuestion).digest("hex").slice(0, 10)}`;
62818
+ const id = `II-${scopeId}-gate-${(0, import_node_crypto12.createHash)("sha256").update(clarification.rawQuestion).digest("hex").slice(0, 10)}`;
62165
62819
  try {
62166
62820
  const questionOptions = buildGateQuestionOptions(clarification.rawQuestion, clarification.category);
62167
62821
  await ctx.client.createInboxItem(input.projectSlug, {
@@ -62185,7 +62839,7 @@ async function handleConsensusBlocked(result, ctx, input, resolvedTaskId) {
62185
62839
  taskId: page.taskId ?? null
62186
62840
  });
62187
62841
  const reviewHash = domainScopedReviewHash2(page.contentHash, domain2);
62188
- const baseBlockItemId = `II-${taskId}-gateblock-${(0, import_node_crypto11.createHash)("sha256").update(reviewHash).digest("hex").slice(0, 10)}`;
62842
+ const baseBlockItemId = `II-${taskId}-gateblock-${(0, import_node_crypto12.createHash)("sha256").update(reviewHash).digest("hex").slice(0, 10)}`;
62189
62843
  const reviewAgainAvailable = !taskInboxItems.some(
62190
62844
  (item) => item.id === baseBlockItemId && item.status !== "pending" && item.answer === REVIEW_AGAIN_ANSWER
62191
62845
  );
@@ -62757,17 +63411,17 @@ var intentCheckDescriptor = createIntentCheckDescriptor();
62757
63411
 
62758
63412
  // src/evidence/assembler.ts
62759
63413
  var import_promises9 = require("node:fs/promises");
62760
- var import_node_path26 = require("node:path");
63414
+ var import_node_path29 = require("node:path");
62761
63415
  function evidenceDedupKey(sessionId, reportId) {
62762
63416
  return `${sessionId}:${reportId}`;
62763
63417
  }
62764
- function isRecord4(v) {
63418
+ function isRecord5(v) {
62765
63419
  return v !== null && typeof v === "object";
62766
63420
  }
62767
63421
  async function readDayLines(stateDir, day, sessionId) {
62768
63422
  let raw;
62769
63423
  try {
62770
- raw = await (0, import_promises9.readFile)((0, import_node_path26.join)(stateDir, "logs", `bridge-${day}.jsonl`), "utf8");
63424
+ raw = await (0, import_promises9.readFile)((0, import_node_path29.join)(stateDir, "logs", `bridge-${day}.jsonl`), "utf8");
62771
63425
  } catch {
62772
63426
  return [];
62773
63427
  }
@@ -62780,7 +63434,7 @@ async function readDayLines(stateDir, day, sessionId) {
62780
63434
  } catch {
62781
63435
  continue;
62782
63436
  }
62783
- if (!isRecord4(rec) || !isRecord4(rec.payload)) continue;
63437
+ if (!isRecord5(rec) || !isRecord5(rec.payload)) continue;
62784
63438
  if (rec.payload.directorSessionId !== sessionId) continue;
62785
63439
  kept.push(rec);
62786
63440
  }
@@ -62841,7 +63495,7 @@ async function assembleEvidence(stateDir, sessionId, reportId, gateCtx) {
62841
63495
  }
62842
63496
  let windowPruned = false;
62843
63497
  try {
62844
- const raw = await (0, import_promises9.readFile)((0, import_node_path26.join)(stateDir, "logs", ".pruned.jsonl"), "utf8");
63498
+ const raw = await (0, import_promises9.readFile)((0, import_node_path29.join)(stateDir, "logs", ".pruned.jsonl"), "utf8");
62845
63499
  outer: for (const line of raw.split("\n")) {
62846
63500
  if (!line.trim()) continue;
62847
63501
  let rec;
@@ -62850,7 +63504,7 @@ async function assembleEvidence(stateDir, sessionId, reportId, gateCtx) {
62850
63504
  } catch {
62851
63505
  continue;
62852
63506
  }
62853
- if (!isRecord4(rec) || !Array.isArray(rec.daysRemoved)) continue;
63507
+ if (!isRecord5(rec) || !Array.isArray(rec.daysRemoved)) continue;
62854
63508
  for (const removedDay of rec.daysRemoved) {
62855
63509
  if (daysRead.includes(removedDay)) {
62856
63510
  windowPruned = true;
@@ -62907,7 +63561,7 @@ function createReportEvidenceDescriptor() {
62907
63561
  var reportEvidenceDescriptor = createReportEvidenceDescriptor();
62908
63562
 
62909
63563
  // src/async-tools/enqueue.ts
62910
- var import_node_crypto12 = __toESM(require("node:crypto"), 1);
63564
+ var import_node_crypto13 = __toESM(require("node:crypto"), 1);
62911
63565
  async function enqueueAsyncTool(client, descriptor2, input) {
62912
63566
  if (descriptor2.cachedResult) {
62913
63567
  const cached2 = await descriptor2.cachedResult(client, input);
@@ -62920,7 +63574,7 @@ async function enqueueAsyncTool(client, descriptor2, input) {
62920
63574
  if (active) {
62921
63575
  return { status: "already_running", jobId: active.id, message: "Already running; will notify in inbox." };
62922
63576
  }
62923
- const jobId = `AJ-${import_node_crypto12.default.randomUUID()}`;
63577
+ const jobId = `AJ-${import_node_crypto13.default.randomUUID()}`;
62924
63578
  try {
62925
63579
  await client.createAsyncJob(input.projectSlug, {
62926
63580
  id: jobId,
@@ -63952,6 +64606,20 @@ function pingAsyncWorkerDispatch(projectSlug, jobId) {
63952
64606
  }).catch(() => {
63953
64607
  });
63954
64608
  }
64609
+ async function deliverBuiltIn(client, projectSlug, artifactKind, payload) {
64610
+ const result = await deliverThroughCapability(client, {
64611
+ projectSlug,
64612
+ taskProjectSlug: projectSlug,
64613
+ artifactKind,
64614
+ taskId: null,
64615
+ runId: null,
64616
+ payload
64617
+ });
64618
+ if (!result.ok) {
64619
+ throw new McpToolCodedError(`CAPABILITY_${result.reason.toUpperCase()}`, `Delivery refused: ${result.reason}`);
64620
+ }
64621
+ return result.result;
64622
+ }
63955
64623
  function makeTool(client, name, fallbackCode, fallbackMessage, handler) {
63956
64624
  return {
63957
64625
  description: mcpToolDescriptions[name],
@@ -64121,19 +64789,24 @@ function createMrrlinTools(options) {
64121
64789
  "Unable to bind project repository.",
64122
64790
  async (c, { projectSlug, ...input }) => await c.bindProjectGithubRepo(projectSlug, input)
64123
64791
  ),
64792
+ // Task 8.2: routed through deliverBuiltIn, not c.createGithubBranch directly. artifactKind
64793
+ // "code_change" (not "page"): this tool is a generic git operation, not specifically about
64794
+ // publishing a website page (design.md, "`page` routes to git, not the wiki") -- there is no
64795
+ // dedicated page-publishing tool in this change's scope, so a task requiring "page" has no path
64796
+ // through these generic tools today, an accepted limitation of the current scope.
64124
64797
  [mcpToolNames.createGithubBranch]: makeTool(
64125
64798
  client,
64126
64799
  mcpToolNames.createGithubBranch,
64127
64800
  "GITHUB_BRANCH_CREATE_FAILED",
64128
64801
  "Unable to create GitHub branch.",
64129
- async (c, { projectSlug, ...input }) => await c.createGithubBranch(projectSlug, input)
64802
+ async (c, { projectSlug, ...input }) => await deliverBuiltIn(c, projectSlug, "code_change", { operation: "branch", ...input })
64130
64803
  ),
64131
64804
  [mcpToolNames.createGithubPullRequest]: makeTool(
64132
64805
  client,
64133
64806
  mcpToolNames.createGithubPullRequest,
64134
64807
  "GITHUB_PULL_REQUEST_CREATE_FAILED",
64135
64808
  "Unable to create GitHub pull request.",
64136
- async (c, { projectSlug, ...input }) => await c.createGithubPullRequest(projectSlug, input)
64809
+ async (c, { projectSlug, ...input }) => await deliverBuiltIn(c, projectSlug, "code_change", { operation: "pull_request", ...input })
64137
64810
  ),
64138
64811
  [mcpToolNames.createPlan]: makeTool(
64139
64812
  client,
@@ -64198,12 +64871,13 @@ function createMrrlinTools(options) {
64198
64871
  "Unable to append task event.",
64199
64872
  async (c, { projectSlug, taskId, ...input }) => await c.appendTaskEvent(projectSlug, taskId, input)
64200
64873
  ),
64874
+ // Task 8.2: routed through deliverBuiltIn, not c.createWikiPage directly.
64201
64875
  [mcpToolNames.createWikiPage]: makeTool(
64202
64876
  client,
64203
64877
  mcpToolNames.createWikiPage,
64204
64878
  "WIKI_PAGE_CREATE_FAILED",
64205
64879
  "Unable to create wiki page.",
64206
- async (c, { projectSlug, ...input }) => await c.createWikiPage(projectSlug, input)
64880
+ async (c, { projectSlug, ...input }) => await deliverBuiltIn(c, projectSlug, "document", { operation: "create", page: input })
64207
64881
  ),
64208
64882
  [mcpToolNames.deleteTaskDependency]: makeTool(
64209
64883
  client,
@@ -64386,12 +65060,13 @@ function createMrrlinTools(options) {
64386
65060
  "Unable to close task as won't-do.",
64387
65061
  async (c, { projectSlug, taskId, reason }) => await c.closeTaskAsWontDo(projectSlug, taskId, reason)
64388
65062
  ),
65063
+ // Task 8.2: routed through deliverBuiltIn, not c.updateWikiPage directly.
64389
65064
  [mcpToolNames.updateWikiPage]: makeTool(
64390
65065
  client,
64391
65066
  mcpToolNames.updateWikiPage,
64392
65067
  "WIKI_PAGE_UPDATE_FAILED",
64393
65068
  "Unable to update wiki page.",
64394
- async (c, { projectSlug, pageId, ...patch }) => await c.updateWikiPage(projectSlug, pageId, patch)
65069
+ async (c, { projectSlug, pageId, ...patch }) => await deliverBuiltIn(c, projectSlug, "document", { operation: "update", pageId, patch })
64395
65070
  ),
64396
65071
  [mcpToolNames.markSpecReady]: makeTool(
64397
65072
  client,
@@ -64580,7 +65255,7 @@ function createMrrlinTools(options) {
64580
65255
  "PRODUCED_URL_RECORD_FAILED",
64581
65256
  "Unable to record produced URL.",
64582
65257
  async (c, { projectSlug, runId, url: url2, label }) => {
64583
- const id = `EA-pu-${(0, import_node_crypto13.randomBytes)(4).toString("hex")}`;
65258
+ const id = `EA-pu-${(0, import_node_crypto14.randomBytes)(4).toString("hex")}`;
64584
65259
  const payload = label ? { url: url2, label } : { url: url2 };
64585
65260
  return await c.appendExecutionArtifact(projectSlug, runId, {
64586
65261
  id,
@@ -64654,7 +65329,7 @@ function createMrrlinTools(options) {
64654
65329
  "ARTIFACT_FILE_UPLOAD_FAILED",
64655
65330
  "Unable to upload artifact file.",
64656
65331
  async (c, { projectSlug, path: filePath, class: artifactClass, taskId, runId, description }) => {
64657
- const extension2 = import_node_path27.default.extname(filePath).toLowerCase();
65332
+ const extension2 = import_node_path30.default.extname(filePath).toLowerCase();
64658
65333
  const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
64659
65334
  if (!contentType) {
64660
65335
  throw new McpToolCodedError(
@@ -64682,7 +65357,7 @@ function createMrrlinTools(options) {
64682
65357
  "Artifact exceeds 5MB; split or summarize instead."
64683
65358
  );
64684
65359
  }
64685
- const filename = import_node_path27.default.basename(filePath);
65360
+ const filename = import_node_path30.default.basename(filePath);
64686
65361
  return uploadArtifactBytes(c, {
64687
65362
  bytes: bytes3,
64688
65363
  class: artifactClass,
@@ -64707,7 +65382,7 @@ function createMrrlinTools(options) {
64707
65382
  `Invalid filename '${filename}'; provide a bare filename with no path separators or '..'.`
64708
65383
  );
64709
65384
  }
64710
- const extension2 = import_node_path27.default.extname(filename).toLowerCase();
65385
+ const extension2 = import_node_path30.default.extname(filename).toLowerCase();
64711
65386
  const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
64712
65387
  if (!contentType) {
64713
65388
  throw new McpToolCodedError(
@@ -64781,9 +65456,9 @@ function createMrrlinTools(options) {
64781
65456
  "LOCAL_CHECKOUT_REGISTER_FAILED",
64782
65457
  "Unable to register local checkout.",
64783
65458
  async (_c, { projectSlug, path: checkoutPath, repo }) => {
64784
- 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");
65459
+ 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");
64785
65460
  const registry3 = new CheckoutRegistry(stateDir);
64786
- const result = registerCheckout(registry3, { projectSlug, path: checkoutPath, repo }, import_node_os12.default.hostname());
65461
+ const result = registerCheckout(registry3, { projectSlug, path: checkoutPath, repo }, import_node_os13.default.hostname());
64787
65462
  if (!result.ok) {
64788
65463
  const codeMap = {
64789
65464
  not_absolute: "LOCAL_CHECKOUT_PATH_NOT_ABSOLUTE",
@@ -65020,13 +65695,13 @@ function runSetCredential(args) {
65020
65695
  }
65021
65696
 
65022
65697
  // src/install-service.ts
65023
- var import_node_os13 = __toESM(require("node:os"), 1);
65024
- var import_node_fs18 = require("node:fs");
65025
- var import_node_path28 = __toESM(require("node:path"), 1);
65698
+ var import_node_os14 = __toESM(require("node:os"), 1);
65699
+ var import_node_fs21 = require("node:fs");
65700
+ var import_node_path31 = __toESM(require("node:path"), 1);
65026
65701
  var SYSTEM_PATH_DIRS = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"];
65027
65702
  function defaultHomeOwnerUid(home) {
65028
65703
  try {
65029
- return (0, import_node_fs18.statSync)(home).uid;
65704
+ return (0, import_node_fs21.statSync)(home).uid;
65030
65705
  } catch {
65031
65706
  return null;
65032
65707
  }
@@ -65067,11 +65742,11 @@ function installService(deps) {
65067
65742
  deps.log(resolved.reason);
65068
65743
  return { ok: false };
65069
65744
  }
65070
- const home = deps.env.HOME ?? import_node_os13.default.homedir();
65745
+ const home = deps.env.HOME ?? import_node_os14.default.homedir();
65071
65746
  const user = resolveBridgeUser({
65072
65747
  env: deps.env,
65073
65748
  home,
65074
- userInfo: deps.userInfo ?? (() => import_node_os13.default.userInfo()),
65749
+ userInfo: deps.userInfo ?? (() => import_node_os14.default.userInfo()),
65075
65750
  homeOwnerUid: deps.homeOwnerUid ?? defaultHomeOwnerUid,
65076
65751
  log: deps.log
65077
65752
  });
@@ -65087,7 +65762,7 @@ function installService(deps) {
65087
65762
  const claudeBin = deps.which("claude");
65088
65763
  const resolvedBins = [...bins, claudeBin].filter((b) => b !== null);
65089
65764
  const pathEnv = Array.from(
65090
- /* @__PURE__ */ new Set([...resolvedBins.map((b) => import_node_path28.default.dirname(b)), ...SYSTEM_PATH_DIRS])
65765
+ /* @__PURE__ */ new Set([...resolvedBins.map((b) => import_node_path31.default.dirname(b)), ...SYSTEM_PATH_DIRS])
65091
65766
  ).join(":");
65092
65767
  const apiBaseUrl = deps.env.MRRLIN_API_BASE_URL?.trim() || void 0;
65093
65768
  const staging = deps.env.MRRLIN_STAGING === "1" || !apiBaseUrl && bridgeUrlImpliesStaging(deps.env.MRRLIN_BRIDGE_URL);
@@ -65100,7 +65775,7 @@ function installService(deps) {
65100
65775
  staging,
65101
65776
  apiBaseUrl
65102
65777
  });
65103
- const ecoPath = import_node_path28.default.join(home, ".mrrlin", "ecosystem.config.cjs");
65778
+ const ecoPath = import_node_path31.default.join(home, ".mrrlin", "ecosystem.config.cjs");
65104
65779
  deps.writeFile(ecoPath, text);
65105
65780
  const start = deps.runPm2(["startOrReload", ecoPath]);
65106
65781
  if (start.code !== 0) {
@@ -65152,13 +65827,13 @@ function uninstallService(deps) {
65152
65827
 
65153
65828
  // src/uninstall-codex.ts
65154
65829
  var import_promises11 = __toESM(require("node:fs/promises"), 1);
65155
- var import_node_os14 = __toESM(require("node:os"), 1);
65156
- var import_node_path29 = __toESM(require("node:path"), 1);
65830
+ var import_node_os15 = __toESM(require("node:os"), 1);
65831
+ var import_node_path32 = __toESM(require("node:path"), 1);
65157
65832
  var toml3 = __toESM(require_toml(), 1);
65158
65833
  function resolveCodexHome3(options) {
65159
65834
  if (options.codexHome) return options.codexHome;
65160
65835
  if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
65161
- return import_node_path29.default.join(options.homeDir ?? import_node_os14.default.homedir(), ".codex");
65836
+ return import_node_path32.default.join(options.homeDir ?? import_node_os15.default.homedir(), ".codex");
65162
65837
  }
65163
65838
  async function pathExists4(target) {
65164
65839
  try {
@@ -65171,7 +65846,7 @@ async function pathExists4(target) {
65171
65846
  var MRRLIN_BLOCK_RE = /(^|\n)\[mcp_servers\.(?:mrrlin(?:-browser)?|external-agents)(?:\]|\.[^\]\n]*\])[\s\S]*?(?=\n\[|$)/g;
65172
65847
  async function uninstallCodex(options = {}) {
65173
65848
  const codexHome = resolveCodexHome3(options);
65174
- const configPath = import_node_path29.default.join(codexHome, "config.toml");
65849
+ const configPath = import_node_path32.default.join(codexHome, "config.toml");
65175
65850
  const removePrompts = async () => uninstallPrompts(codexHome, options.promptNames ?? []);
65176
65851
  if (!await pathExists4(configPath)) {
65177
65852
  return { action: "missing", configPath, prompts: await removePrompts() };
@@ -65199,10 +65874,10 @@ async function uninstallCodex(options = {}) {
65199
65874
  }
65200
65875
  async function uninstallPrompts(codexHome, names) {
65201
65876
  if (names.length === 0) return [];
65202
- const promptsDir = import_node_path29.default.join(codexHome, "prompts");
65877
+ const promptsDir = import_node_path32.default.join(codexHome, "prompts");
65203
65878
  const out = [];
65204
65879
  for (const name of names) {
65205
- const promptPath = import_node_path29.default.join(promptsDir, `${name}.md`);
65880
+ const promptPath = import_node_path32.default.join(promptsDir, `${name}.md`);
65206
65881
  try {
65207
65882
  await import_promises11.default.unlink(promptPath);
65208
65883
  out.push({ name, action: "removed", promptPath });
@@ -65220,7 +65895,7 @@ async function uninstallPrompts(codexHome, names) {
65220
65895
 
65221
65896
  // src/extract/command.ts
65222
65897
  var import_promises12 = require("node:fs/promises");
65223
- var import_node_path30 = require("node:path");
65898
+ var import_node_path33 = require("node:path");
65224
65899
  function parseArgs(args) {
65225
65900
  const map2 = /* @__PURE__ */ new Map();
65226
65901
  for (let i = 0; i < args.length; i++) {
@@ -65236,7 +65911,7 @@ function parseArgs(args) {
65236
65911
  }
65237
65912
  return map2;
65238
65913
  }
65239
- function isRecord5(v) {
65914
+ function isRecord6(v) {
65240
65915
  return v !== null && typeof v === "object";
65241
65916
  }
65242
65917
  async function runExtract(args, deps) {
@@ -65257,7 +65932,7 @@ Missing required flag(s): ${missing.join(
65257
65932
  const days = await findSessionDays(deps.stateDir, sessionId);
65258
65933
  const matchingLines = [];
65259
65934
  for (const day of days) {
65260
- const logPath = (0, import_node_path30.join)(deps.stateDir, "logs", `bridge-${day}.jsonl`);
65935
+ const logPath = (0, import_node_path33.join)(deps.stateDir, "logs", `bridge-${day}.jsonl`);
65261
65936
  let raw;
65262
65937
  try {
65263
65938
  raw = await (0, import_promises12.readFile)(logPath, "utf8");
@@ -65273,8 +65948,8 @@ Missing required flag(s): ${missing.join(
65273
65948
  } catch {
65274
65949
  continue;
65275
65950
  }
65276
- const payload = isRecord5(parsed) ? parsed.payload : void 0;
65277
- if (isRecord5(payload) && payload.directorSessionId === sessionId) {
65951
+ const payload = isRecord6(parsed) ? parsed.payload : void 0;
65952
+ if (isRecord6(payload) && payload.directorSessionId === sessionId) {
65278
65953
  matchingLines.push(line);
65279
65954
  }
65280
65955
  }
@@ -65357,16 +66032,16 @@ function bootHookStatus() {
65357
66032
  if (process.platform !== "darwin") return { status: "unknown" };
65358
66033
  const uid = process.getuid?.();
65359
66034
  if (uid === void 0 || uid === 0) return { status: "unknown" };
65360
- const home = process.env.HOME ?? (0, import_node_os15.homedir)();
65361
- const agents = import_node_path32.default.join(home, "Library", "LaunchAgents");
66035
+ const home = process.env.HOME ?? (0, import_node_os16.homedir)();
66036
+ const agents = import_node_path35.default.join(home, "Library", "LaunchAgents");
65362
66037
  const candidates = [
65363
- { label: "com.mrrlin.director-bridge", plist: import_node_path32.default.join(agents, "com.mrrlin.director-bridge.plist") },
65364
- { label: "com.PM2", plist: import_node_path32.default.join(agents, `pm2.${(0, import_node_os15.userInfo)().username}.plist`) }
66038
+ { label: "com.mrrlin.director-bridge", plist: import_node_path35.default.join(agents, "com.mrrlin.director-bridge.plist") },
66039
+ { label: "com.PM2", plist: import_node_path35.default.join(agents, `pm2.${(0, import_node_os16.userInfo)().username}.plist`) }
65365
66040
  ];
65366
66041
  for (const candidate of candidates) {
65367
66042
  const printed = (0, import_node_child_process18.spawnSync)("launchctl", ["print", `gui/${uid}/${candidate.label}`], { encoding: "utf8" });
65368
66043
  if (printed.status !== 0) continue;
65369
- if (!(0, import_node_fs19.existsSync)(candidate.plist)) continue;
66044
+ if (!(0, import_node_fs22.existsSync)(candidate.plist)) continue;
65370
66045
  const out = printed.stdout ?? "";
65371
66046
  const runs = /^\s*runs\s*=\s*(\d+)/m.exec(out);
65372
66047
  const exitCode = /^\s*last exit code\s*=\s*(-?\d+)/m.exec(out);
@@ -65649,8 +66324,8 @@ async function main() {
65649
66324
  }
65650
66325
  }
65651
66326
  try {
65652
- const codexHome = process.env.CODEX_HOME ?? import_node_path32.default.join(process.env.HOME ?? (0, import_node_os15.homedir)(), ".codex");
65653
- (0, import_node_fs19.rmSync)(import_node_path32.default.join(codexHome, "prompts", "report-issue.md"), { force: true });
66327
+ const codexHome = process.env.CODEX_HOME ?? import_node_path35.default.join(process.env.HOME ?? (0, import_node_os16.homedir)(), ".codex");
66328
+ (0, import_node_fs22.rmSync)(import_node_path35.default.join(codexHome, "prompts", "report-issue.md"), { force: true });
65654
66329
  } catch {
65655
66330
  }
65656
66331
  const claudeResult = await installClaude({ binPath, force, serveEnv });
@@ -65711,8 +66386,8 @@ async function main() {
65711
66386
  env: process.env,
65712
66387
  cwd: process.cwd(),
65713
66388
  writeFile: (p, c) => {
65714
- (0, import_node_fs19.mkdirSync)(import_node_path32.default.dirname(p), { recursive: true, mode: 448 });
65715
- (0, import_node_fs19.writeFileSync)(p, c, { mode: 384 });
66389
+ (0, import_node_fs22.mkdirSync)(import_node_path35.default.dirname(p), { recursive: true, mode: 448 });
66390
+ (0, import_node_fs22.writeFileSync)(p, c, { mode: 384 });
65716
66391
  },
65717
66392
  runPm2: pm2Runner,
65718
66393
  which: whichBin,
@@ -65730,35 +66405,35 @@ async function main() {
65730
66405
  runPm2: (a) => ({ code: pm2Runner(a).code }),
65731
66406
  removeFile: (p) => {
65732
66407
  try {
65733
- (0, import_node_fs19.rmSync)(p, { force: true });
66408
+ (0, import_node_fs22.rmSync)(p, { force: true });
65734
66409
  } catch {
65735
66410
  }
65736
66411
  },
65737
66412
  purgeSecret: purge,
65738
66413
  secretPath: agentCredentialPath(),
65739
66414
  tokenPath: operatorTokenPath(),
65740
- ecoPath: import_node_path32.default.join(process.env.HOME ?? (0, import_node_os15.homedir)(), ".mrrlin", "ecosystem.config.cjs"),
66415
+ ecoPath: import_node_path35.default.join(process.env.HOME ?? (0, import_node_os16.homedir)(), ".mrrlin", "ecosystem.config.cjs"),
65741
66416
  log: (m) => process.stderr.write(`[mrrlin-mcp uninstall-service] ${m}
65742
66417
  `)
65743
66418
  });
65744
66419
  return;
65745
66420
  }
65746
66421
  case "uninstall": {
65747
- const home = process.env.HOME ?? (0, import_node_os15.homedir)();
66422
+ const home = process.env.HOME ?? (0, import_node_os16.homedir)();
65748
66423
  const log = (m) => process.stderr.write(`[mrrlin-mcp uninstall] ${m}
65749
66424
  `);
65750
66425
  uninstallService({
65751
66426
  runPm2: (a) => ({ code: pm2Runner(a).code }),
65752
66427
  removeFile: (p) => {
65753
66428
  try {
65754
- (0, import_node_fs19.rmSync)(p, { force: true });
66429
+ (0, import_node_fs22.rmSync)(p, { force: true });
65755
66430
  } catch {
65756
66431
  }
65757
66432
  },
65758
66433
  purgeSecret: true,
65759
66434
  secretPath: agentCredentialPath(),
65760
66435
  tokenPath: operatorTokenPath(),
65761
- ecoPath: import_node_path32.default.join(home, ".mrrlin", "ecosystem.config.cjs"),
66436
+ ecoPath: import_node_path35.default.join(home, ".mrrlin", "ecosystem.config.cjs"),
65762
66437
  log
65763
66438
  });
65764
66439
  let codexOk = true;
@@ -65778,7 +66453,7 @@ async function main() {
65778
66453
  log(`codex config NOT modified: ${error51 instanceof Error ? error51.message : String(error51)}`);
65779
66454
  }
65780
66455
  try {
65781
- (0, import_node_fs19.rmSync)(import_node_path32.default.join(home, ".mrrlin"), { recursive: true, force: true });
66456
+ (0, import_node_fs22.rmSync)(import_node_path35.default.join(home, ".mrrlin"), { recursive: true, force: true });
65782
66457
  } catch {
65783
66458
  }
65784
66459
  log("removed ~/.mrrlin");
@@ -65819,7 +66494,7 @@ ${HELP_TEXT}`);
65819
66494
  }
65820
66495
  }
65821
66496
  function resolveSelfBinPath() {
65822
- return import_node_path31.default.resolve(process.argv[1] ?? process.execPath);
66497
+ return import_node_path34.default.resolve(process.argv[1] ?? process.execPath);
65823
66498
  }
65824
66499
  main().catch((error51) => {
65825
66500
  process.stderr.write(`mrrlin-mcp fatal error: ${error51 instanceof Error ? error51.message : String(error51)}