@mrrlin-dev/mcp 0.3.9 → 0.3.11

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 +187 -231
  2. package/package.json +2 -2
package/dist/bin.cjs CHANGED
@@ -20644,11 +20644,11 @@ var require_dist = __commonJS({
20644
20644
  });
20645
20645
 
20646
20646
  // src/bin.ts
20647
- var import_node_path20 = __toESM(require("node:path"), 1);
20647
+ var import_node_path19 = __toESM(require("node:path"), 1);
20648
20648
  var import_node_child_process8 = require("node:child_process");
20649
- var import_node_fs15 = require("node:fs");
20650
- var import_node_os12 = require("node:os");
20651
- var import_node_path21 = __toESM(require("node:path"), 1);
20649
+ var import_node_fs14 = require("node:fs");
20650
+ var import_node_os11 = require("node:os");
20651
+ var import_node_path20 = __toESM(require("node:path"), 1);
20652
20652
 
20653
20653
  // src/install-codex.ts
20654
20654
  var import_promises = __toESM(require("node:fs/promises"), 1);
@@ -20933,10 +20933,10 @@ ${block}`;
20933
20933
  }
20934
20934
 
20935
20935
  // src/director-bridge.ts
20936
- var import_node_fs11 = __toESM(require("node:fs"), 1);
20936
+ var import_node_fs10 = __toESM(require("node:fs"), 1);
20937
20937
  var import_node_http = __toESM(require("node:http"), 1);
20938
- var import_node_os8 = __toESM(require("node:os"), 1);
20939
- var import_node_path12 = __toESM(require("node:path"), 1);
20938
+ var import_node_os7 = __toESM(require("node:os"), 1);
20939
+ var import_node_path11 = __toESM(require("node:path"), 1);
20940
20940
  var import_node_child_process4 = require("node:child_process");
20941
20941
  var import_node_crypto5 = __toESM(require("node:crypto"), 1);
20942
20942
 
@@ -21326,6 +21326,8 @@ var CodexServerManager = class {
21326
21326
  rpcClient.onServerRequest((id, method) => {
21327
21327
  if (method === "requestApproval") {
21328
21328
  rpcClient.respond(id, { decision: "accept" });
21329
+ } else if (method === "mcpServer/elicitation/request") {
21330
+ rpcClient.respond(id, { action: "accept" });
21329
21331
  }
21330
21332
  });
21331
21333
  const notificationHandlers = /* @__PURE__ */ new Set();
@@ -21398,6 +21400,8 @@ var CodexBridgeEventMapper = class {
21398
21400
  return this.handleOutputDelta(notification);
21399
21401
  case "codex/event/error":
21400
21402
  return this.handleServerError(notification);
21403
+ case "error":
21404
+ return this.handleStreamError(notification);
21401
21405
  default:
21402
21406
  return [];
21403
21407
  }
@@ -21490,9 +21494,10 @@ var CodexBridgeEventMapper = class {
21490
21494
  }
21491
21495
  handleTurnCompleted(notification) {
21492
21496
  const events = this.flushPendingText();
21493
- const status = notification.params?.status ?? "completed";
21497
+ const turn = notification.params?.turn;
21498
+ const status = (typeof turn?.status === "string" ? turn.status : void 0) ?? notification.params?.status ?? "completed";
21494
21499
  if (status === "failed") {
21495
- const error51 = notification.params?.error;
21500
+ const error51 = turn?.error ?? notification.params?.error;
21496
21501
  const content = typeof error51 === "string" ? error51 : typeof error51?.message === "string" ? String(error51.message) : "Unknown error";
21497
21502
  events.push({ type: "error", content });
21498
21503
  return events;
@@ -21504,6 +21509,18 @@ var CodexBridgeEventMapper = class {
21504
21509
  events.push({ type: "result", subtype: "success" });
21505
21510
  return events;
21506
21511
  }
21512
+ /** Bare `error` notifications carry model-stream failures ({ error: { message }, willRetry }).
21513
+ * Retryable ones (willRetry=true) are transport noise — codex is still driving the turn — so
21514
+ * only terminal failures surface as error events. */
21515
+ handleStreamError(notification) {
21516
+ if (notification.params?.willRetry === true)
21517
+ return [];
21518
+ const events = this.flushPendingText();
21519
+ const error51 = notification.params?.error;
21520
+ const content = (typeof error51?.message === "string" ? error51.message : void 0) ?? (typeof error51?.additionalDetails === "string" ? error51.additionalDetails : void 0) ?? "Unknown Codex error";
21521
+ events.push({ type: "error", content });
21522
+ return events;
21523
+ }
21507
21524
  handleServerError(notification) {
21508
21525
  const events = this.flushPendingText();
21509
21526
  const msg = notification.params?.msg;
@@ -37244,7 +37261,9 @@ var executionRunListFiltersSchema = external_exports.object({
37244
37261
  return value;
37245
37262
  }, external_exports.array(mrrlinExecutionRunStatusSchema)).optional()
37246
37263
  });
37264
+ var mrrlinAutoSpecApprovalSchema = external_exports.enum(["manual", "after_consensus"]);
37247
37265
  var mrrlinProjectSchedulerPolicySchema = external_exports.object({
37266
+ autoSpecApproval: mrrlinAutoSpecApprovalSchema,
37248
37267
  cadenceSeconds: external_exports.number().int().positive().nullable(),
37249
37268
  createdAt: external_exports.string().datetime(),
37250
37269
  eligibleAutonomyLevels: external_exports.array(mrrlinAutonomyLevelSchema).min(1),
@@ -37253,6 +37272,7 @@ var mrrlinProjectSchedulerPolicySchema = external_exports.object({
37253
37272
  wakeFloor: external_exports.string().datetime().nullable()
37254
37273
  });
37255
37274
  var mrrlinProjectSchedulerPolicyUpsertSchema = external_exports.object({
37275
+ autoSpecApproval: mrrlinAutoSpecApprovalSchema.optional(),
37256
37276
  cadenceSeconds: external_exports.number().int().positive().nullable().optional(),
37257
37277
  eligibleAutonomyLevels: external_exports.array(mrrlinAutonomyLevelSchema).min(1).optional(),
37258
37278
  wakeFloor: external_exports.string().datetime().nullable().optional()
@@ -38514,7 +38534,7 @@ Do NOT derail the current task \u2014 if the operator has an in-flight question,
38514
38534
  }
38515
38535
 
38516
38536
  // src/_generated/version.ts
38517
- var PKG_VERSION = "0.3.9";
38537
+ var PKG_VERSION = "0.3.11";
38518
38538
 
38519
38539
  // src/api-base-url.ts
38520
38540
  var DEFAULT_API_BASE_URL = "http://127.0.0.1:8787";
@@ -38994,10 +39014,12 @@ var CONSUMER_BASE_INSTRUCTIONS = [
38994
39014
  ].join("\n");
38995
39015
  var EXECUTOR_BASE_INSTRUCTIONS = [
38996
39016
  ...BASE_INSTRUCTIONS_PREFIX,
38997
- "You run inside an isolated, write-authorized git worktree: you MAY create, edit, and",
38998
- "delete files and run git commands within this worktree to make progress. Writes outside",
38999
- "the worktree and reads of operator secrets are blocked by the sandbox. Be concise. When",
39000
- "you have made the next increment of progress, stop the turn."
39017
+ "You run inside a git worktree dedicated to this run, with full read/write/network access to",
39018
+ "the host (there is NO filesystem sandbox). Do your work by creating, editing, and deleting",
39019
+ "files and running git/build/test commands WITHIN this worktree. Keep all changes inside the",
39020
+ "worktree and do not read the operator's personal secrets or files outside it \u2014 this is a rule",
39021
+ "you must follow, not something the environment enforces. Be concise. When you have made the",
39022
+ "next increment of progress, stop the turn."
39001
39023
  ].join("\n");
39002
39024
  function artifactKindForEvent(event) {
39003
39025
  switch (event.type) {
@@ -39117,12 +39139,25 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
39117
39139
  };
39118
39140
  return deps.runExclusive(async () => {
39119
39141
  const pending = [];
39142
+ let resolveTurnEnded = null;
39143
+ const turnEnded = new Promise((resolve) => {
39144
+ resolveTurnEnded = resolve;
39145
+ });
39146
+ let acceptedTurnId = null;
39120
39147
  const unsub = codex.onNotification((method, params) => {
39121
39148
  const events = mapper.mapNotification(
39122
39149
  { method, params },
39123
39150
  threadId
39124
39151
  );
39125
39152
  for (const event of events) pending.push(persist(event));
39153
+ if (method === "turn/completed") {
39154
+ const p = params;
39155
+ const notifThreadId = p?.threadId;
39156
+ const notifTurnId = p?.turn?.id;
39157
+ const threadMatches = !notifThreadId || notifThreadId === threadId;
39158
+ const turnMatches = !acceptedTurnId || !notifTurnId || notifTurnId === acceptedTurnId;
39159
+ if (threadMatches && turnMatches) resolveTurnEnded?.();
39160
+ }
39126
39161
  });
39127
39162
  const touchTimer = setInterval(() => {
39128
39163
  void deps.client.touchExecutionRun(projectSlug, runId, leaseId).catch(() => {
@@ -39132,7 +39167,14 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
39132
39167
  try {
39133
39168
  const timeoutMs = execTurnTimeoutMs();
39134
39169
  await awaitTurnWithDeadline({
39135
- run: () => codex.turn.start({ threadId, input: [{ type: "text", text: inputText }] }),
39170
+ run: async () => {
39171
+ const accepted = await codex.turn.start({
39172
+ threadId,
39173
+ input: [{ type: "text", text: inputText }]
39174
+ });
39175
+ acceptedTurnId = accepted?.turn?.id ?? null;
39176
+ await turnEnded;
39177
+ },
39136
39178
  interrupt: () => codex.turn.interrupt({ threadId }),
39137
39179
  timeoutMs,
39138
39180
  timeoutMessage: `Execution turn did not complete within ${timeoutMs}ms.`,
@@ -39203,7 +39245,7 @@ async function driveRun(deps, projectSlug, runId) {
39203
39245
  defaultBranch: await getDefaultBranch(projectSlug)
39204
39246
  });
39205
39247
  await deps.client.updateExecutionRun(projectSlug, runId, { worktreeId: worktreePath });
39206
- sandbox = null;
39248
+ sandbox = "danger-full-access";
39207
39249
  turnCwd = worktreePath;
39208
39250
  useExecutor = true;
39209
39251
  if (deps.acquireExecutorCodex) {
@@ -43687,127 +43729,13 @@ var CheckoutRegistry = class {
43687
43729
  };
43688
43730
 
43689
43731
  // src/executor-server.ts
43690
- var import_node_fs9 = require("node:fs");
43691
- var import_node_os7 = require("node:os");
43692
- var import_node_path10 = require("node:path");
43693
- var DENY_READ_GLOBS = [
43694
- "**/.ssh/**",
43695
- "**/.aws/**",
43696
- "**/.config/gh/**",
43697
- "**/.netrc",
43698
- "**/.npmrc",
43699
- "**/.env*",
43700
- "**/.gnupg/**"
43701
- ];
43702
- var ENV_ALLOWLIST = ["PATH", "LANG", "LC_ALL", "TERM", "TMPDIR", "GIT_SSH_COMMAND"];
43703
- var DEFAULT_EGRESS_DOMAINS = [
43704
- "registry.npmjs.org",
43705
- "github.com",
43706
- "api.github.com",
43707
- "codeload.github.com"
43708
- ];
43709
- function buildExecutorConfig(opts) {
43710
- const env = { HOME: opts.scratchHome };
43711
- for (const k of ENV_ALLOWLIST) {
43712
- if (process.env[k]) env[k] = process.env[k];
43713
- }
43714
- return {
43715
- cwd: opts.worktree,
43716
- env,
43717
- denyReadGlobs: DENY_READ_GLOBS,
43718
- denyReadResolvesSymlinks: true,
43719
- network: { allowedDomains: opts.egressDomains },
43720
- trustWorktreeConfig: false
43721
- };
43722
- }
43723
- function operatorSecretPaths(realHome = (0, import_node_os7.homedir)()) {
43724
- return [
43725
- (0, import_node_path10.join)(realHome, ".ssh"),
43726
- (0, import_node_path10.join)(realHome, ".aws"),
43727
- (0, import_node_path10.join)(realHome, ".config", "gh"),
43728
- (0, import_node_path10.join)(realHome, ".npmrc"),
43729
- (0, import_node_path10.join)(realHome, ".netrc"),
43730
- (0, import_node_path10.join)(realHome, ".gnupg"),
43731
- (0, import_node_path10.join)(realHome, ".kube"),
43732
- (0, import_node_path10.join)(realHome, ".docker", "config.json"),
43733
- (0, import_node_path10.join)(realHome, ".config", "gcloud")
43734
- ];
43735
- }
43736
- var SECRET_DIRECTORY_BASENAMES = /* @__PURE__ */ new Set([".ssh", ".aws", "gh", ".gnupg", ".kube", "gcloud"]);
43737
- function isSecretDirectoryPath(p) {
43738
- const base = p.split(/[/\\]/).filter(Boolean).pop() ?? "";
43739
- return SECRET_DIRECTORY_BASENAMES.has(base);
43740
- }
43741
- function writeExecutorCodexHome(scratchDir, opts) {
43742
- const codexHome = (0, import_node_path10.join)(scratchDir, ".codex");
43743
- (0, import_node_fs9.mkdirSync)(codexHome, { recursive: true });
43744
- const hasEgress = opts.egressDomains.length > 0;
43745
- const networkSection = hasEgress ? [
43746
- "[permissions.executor.network]",
43747
- "enabled = true",
43748
- 'mode = "limited"',
43749
- "",
43750
- "[permissions.executor.network.domains]",
43751
- ...opts.egressDomains.map((d) => `"${d}" = "allow"`)
43752
- ].join("\n") : [
43753
- "[permissions.executor.network]",
43754
- "enabled = false"
43755
- ].join("\n");
43756
- const absoluteDenyLines = opts.denySecretPaths.flatMap(
43757
- (p) => isSecretDirectoryPath(p) ? [`"${p}" = "deny"`, `"${p}/**" = "deny"`] : [`"${p}" = "deny"`]
43758
- ).join("\n");
43759
- const workspaceRootsDenyLines = [
43760
- '[permissions.executor.filesystem.":workspace_roots"]',
43761
- '"**/.env*" = "deny"'
43762
- ].join("\n");
43763
- const toml3 = [
43764
- 'default_permissions = "executor"',
43765
- "",
43766
- "[permissions.executor]",
43767
- 'extends = ":workspace"',
43768
- "",
43769
- "[permissions.executor.filesystem]",
43770
- "glob_scan_max_depth = 8",
43771
- absoluteDenyLines,
43772
- "",
43773
- workspaceRootsDenyLines,
43774
- "",
43775
- networkSection,
43776
- ""
43777
- ].join("\n");
43778
- (0, import_node_fs9.writeFileSync)((0, import_node_path10.join)(codexHome, "config.toml"), toml3, "utf8");
43779
- return codexHome;
43780
- }
43781
43732
  async function startExecutorServer(opts) {
43782
- const egressDomains = opts.egressDomains ?? DEFAULT_EGRESS_DOMAINS;
43783
- const realHome = (0, import_node_os7.homedir)();
43784
- const denySecretPaths = operatorSecretPaths(realHome);
43785
- const scratchDir = (0, import_node_fs9.mkdtempSync)((0, import_node_path10.join)((0, import_node_os7.tmpdir)(), "mrrlin-executor-"));
43786
- const scratchHome = scratchDir;
43787
- let scratchCleaned = false;
43788
- const cleanScratch = () => {
43789
- if (scratchCleaned) return;
43790
- scratchCleaned = true;
43791
- try {
43792
- (0, import_node_fs9.rmSync)(scratchDir, { recursive: true, force: true });
43793
- } catch {
43794
- }
43795
- };
43796
43733
  const manager = new CodexServerManager();
43797
43734
  try {
43798
- const codexHome = writeExecutorCodexHome(scratchDir, {
43799
- worktree: opts.worktree,
43800
- egressDomains,
43801
- denySecretPaths
43802
- });
43803
- const cfg = buildExecutorConfig({ worktree: opts.worktree, scratchHome, egressDomains });
43804
- const env = { ...cfg.env, CODEX_HOME: codexHome };
43805
43735
  const client = await manager.acquire({
43806
- cwd: cfg.cwd,
43807
- env,
43736
+ cwd: opts.worktree,
43808
43737
  approvalPolicy: "never",
43809
- ...opts.spawn ? { spawn: opts.spawn } : {},
43810
- ...opts.sandbox != null ? { sandbox: opts.sandbox } : {}
43738
+ ...opts.spawn ? { spawn: opts.spawn } : {}
43811
43739
  });
43812
43740
  let disposed = false;
43813
43741
  const dispose = () => {
@@ -43817,7 +43745,6 @@ async function startExecutorServer(opts) {
43817
43745
  manager.shutdown();
43818
43746
  } catch {
43819
43747
  }
43820
- cleanScratch();
43821
43748
  };
43822
43749
  return { client, dispose };
43823
43750
  } catch (error51) {
@@ -43825,7 +43752,6 @@ async function startExecutorServer(opts) {
43825
43752
  manager.shutdown();
43826
43753
  } catch {
43827
43754
  }
43828
- cleanScratch();
43829
43755
  throw error51;
43830
43756
  }
43831
43757
  }
@@ -43835,8 +43761,10 @@ function buildVerificationPrompt(input) {
43835
43761
  return [
43836
43762
  `You are verifying a deployment. The application is live at: ${input.environmentUrl}`,
43837
43763
  `Run ONLY read-only HTTP checks against that URL to evaluate the verification steps below.`,
43838
- `You have NO repository, filesystem, or credential access and you must not attempt to mutate`,
43839
- `anything \u2014 only observe the deployed app over HTTP.`,
43764
+ `Behave as if you had no repository, filesystem, or credential access: do not read or write`,
43765
+ `files, do not use any credentials, do not contact any other host, and do not attempt to`,
43766
+ `mutate anything \u2014 only observe the deployed app over HTTP. (This is a rule you must follow,`,
43767
+ `not something the environment enforces.)`,
43840
43768
  ``,
43841
43769
  `Verification steps for environment "${input.env}":`,
43842
43770
  input.verificationSection,
@@ -43980,8 +43908,8 @@ function extractVerificationSection(markdown) {
43980
43908
  }
43981
43909
 
43982
43910
  // src/bridge-log.ts
43983
- var import_node_fs10 = require("node:fs");
43984
- var import_node_path11 = require("node:path");
43911
+ var import_node_fs9 = require("node:fs");
43912
+ var import_node_path10 = require("node:path");
43985
43913
 
43986
43914
  // src/redact.ts
43987
43915
  var REDACTED = "[REDACTED]";
@@ -44066,14 +43994,14 @@ function resolvePromptsEnabled(env) {
44066
43994
  }
44067
43995
  function createBridgeLogger(stateDir, env = process.env) {
44068
43996
  if (!resolveBridgeLogEnabled(env)) return NOOP_LOGGER;
44069
- const logsDir = (0, import_node_path11.join)(stateDir, "logs");
43997
+ const logsDir = (0, import_node_path10.join)(stateDir, "logs");
44070
43998
  try {
44071
- (0, import_node_fs10.mkdirSync)(logsDir, { recursive: true });
43999
+ (0, import_node_fs9.mkdirSync)(logsDir, { recursive: true });
44072
44000
  } catch {
44073
44001
  return NOOP_LOGGER;
44074
44002
  }
44075
44003
  const includePrompts = resolvePromptsEnabled(env);
44076
- const fileFor = () => (0, import_node_path11.join)(logsDir, `bridge-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
44004
+ const fileFor = () => (0, import_node_path10.join)(logsDir, `bridge-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
44077
44005
  const write = (dir, rec) => {
44078
44006
  try {
44079
44007
  const line = JSON.stringify({
@@ -44085,7 +44013,7 @@ function createBridgeLogger(stateDir, env = process.env) {
44085
44013
  ...rec.ms !== void 0 ? { ms: rec.ms } : {},
44086
44014
  payload: redactMessage(rec.payload, { includePrompts })
44087
44015
  }) + "\n";
44088
- (0, import_node_fs10.appendFileSync)(fileFor(), line);
44016
+ (0, import_node_fs9.appendFileSync)(fileFor(), line);
44089
44017
  } catch {
44090
44018
  }
44091
44019
  };
@@ -44119,9 +44047,9 @@ function normalizeModel(value) {
44119
44047
  return trimmed ? trimmed : null;
44120
44048
  }
44121
44049
  function neutralCheckoutCwd(stateDir) {
44122
- const dir = import_node_path12.default.join(stateDir, "no-checkout");
44050
+ const dir = import_node_path11.default.join(stateDir, "no-checkout");
44123
44051
  try {
44124
- import_node_fs11.default.mkdirSync(dir, { recursive: true });
44052
+ import_node_fs10.default.mkdirSync(dir, { recursive: true });
44125
44053
  } catch {
44126
44054
  }
44127
44055
  return dir;
@@ -44278,10 +44206,11 @@ function tokenRefreshIntervalMs() {
44278
44206
  var COLLECTED_TURN_TIMEOUT_MS = 3e5;
44279
44207
  var DEFAULT_IMAGE_ONLY_PROMPT = "Look at the attached image.";
44280
44208
  var VERIFICATION_BASE_INSTRUCTIONS = [
44281
- "You are a deployment verification agent. You may ONLY make read-only HTTP requests to the",
44282
- "single allowlisted environment URL to confirm a deploy succeeded. You have NO repository,",
44283
- "filesystem, or credential access and must not attempt to modify anything. Follow the",
44284
- "verification steps and end with a single VERDICT line exactly as instructed."
44209
+ "You are a deployment verification agent. Make ONLY read-only HTTP requests to the single",
44210
+ "environment URL given in the prompt to confirm a deploy succeeded. Do not read or write any",
44211
+ "files, do not use repository or credential access, do not contact any other host, and do not",
44212
+ "modify anything \u2014 these are rules you must follow, not limits the environment enforces. Follow",
44213
+ "the verification steps and end with a single VERDICT line exactly as instructed."
44285
44214
  ].join("\n");
44286
44215
  var SELF_REVIEW_BASE_INSTRUCTIONS = [
44287
44216
  "You are a code self-review agent. You MAY run read-only git/shell commands (e.g. `git log`,",
@@ -44292,11 +44221,14 @@ var SELF_REVIEW_BASE_INSTRUCTIONS = [
44292
44221
  async function runCollectedCodexTurn(client, prompt, cwd, baseInstructions) {
44293
44222
  const { threadId } = await acquireThread(client, {
44294
44223
  threadId: null,
44224
+ // danger-full-access: collected turns (self-review reads the worktree diff; deploy
44225
+ // verification hits the deployed env URL over the network) run unrestricted, matching
44226
+ // the owner decision that the executor is not sandboxed. The turn's base instructions
44227
+ // (review-only / observe-only) bound what it actually does.
44295
44228
  startParams: {
44296
44229
  cwd,
44297
44230
  approvalPolicy: "never",
44298
- sandbox: null,
44299
- // the executor permissions profile governs; an override would discard it
44231
+ sandbox: "danger-full-access",
44300
44232
  model: null,
44301
44233
  baseInstructions,
44302
44234
  developerInstructions: null,
@@ -44308,14 +44240,34 @@ async function runCollectedCodexTurn(client, prompt, cwd, baseInstructions) {
44308
44240
  const mapper = new CodexBridgeEventMapper();
44309
44241
  mapper.reset();
44310
44242
  const chunks = [];
44243
+ let acceptedTurnId = null;
44244
+ let turnError = null;
44245
+ let resolveTurnEnded = null;
44246
+ const turnEnded = new Promise((resolve) => {
44247
+ resolveTurnEnded = resolve;
44248
+ });
44311
44249
  const unsub = client.onNotification((method, params) => {
44312
44250
  for (const ev of mapper.mapNotification({ method, params }, threadId)) {
44313
44251
  if (ev.type === "assistant") chunks.push(ev.content);
44252
+ else if (ev.type === "error") turnError = ev.content;
44253
+ }
44254
+ if (method === "turn/completed") {
44255
+ const p = params;
44256
+ const threadMatches = !p?.threadId || p.threadId === threadId;
44257
+ const turnMatches = !acceptedTurnId || !p?.turn?.id || p.turn.id === acceptedTurnId;
44258
+ if (threadMatches && turnMatches) resolveTurnEnded?.();
44314
44259
  }
44315
44260
  });
44316
44261
  try {
44317
44262
  await awaitTurnWithDeadline({
44318
- run: () => client.turn.start({ threadId, input: [{ type: "text", text: prompt }] }),
44263
+ run: async () => {
44264
+ const accepted = await client.turn.start({
44265
+ threadId,
44266
+ input: [{ type: "text", text: prompt }]
44267
+ });
44268
+ acceptedTurnId = accepted?.turn?.id ?? null;
44269
+ await turnEnded;
44270
+ },
44319
44271
  interrupt: () => client.turn.interrupt({ threadId }),
44320
44272
  timeoutMs: COLLECTED_TURN_TIMEOUT_MS,
44321
44273
  timeoutMessage: `Collected turn did not complete within ${COLLECTED_TURN_TIMEOUT_MS}ms.`
@@ -44324,6 +44276,7 @@ async function runCollectedCodexTurn(client, prompt, cwd, baseInstructions) {
44324
44276
  } finally {
44325
44277
  unsub();
44326
44278
  }
44279
+ if (turnError) throw new Error(`Collected turn failed: ${turnError}`);
44327
44280
  return chunks.join("");
44328
44281
  }
44329
44282
  function resolveDefaultBranch(checkoutPath) {
@@ -44362,7 +44315,7 @@ async function runOrphanWorktreeSweep(client, opts) {
44362
44315
  const cutoff = Date.now() - worktreeRetentionMs();
44363
44316
  const isReapable = (worktreePath) => {
44364
44317
  try {
44365
- return import_node_fs11.default.statSync(worktreePath).mtimeMs < cutoff;
44318
+ return import_node_fs10.default.statSync(worktreePath).mtimeMs < cutoff;
44366
44319
  } catch {
44367
44320
  return false;
44368
44321
  }
@@ -44399,8 +44352,8 @@ async function runOrphanWorktreeSweep(client, opts) {
44399
44352
  }
44400
44353
  }
44401
44354
  function readStateDir() {
44402
- if (process.env.CODEX_HOME) return import_node_path12.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge");
44403
- return import_node_path12.default.join(import_node_os8.default.homedir(), ".mrrlin", "director-bridge");
44355
+ if (process.env.CODEX_HOME) return import_node_path11.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge");
44356
+ return import_node_path11.default.join(import_node_os7.default.homedir(), ".mrrlin", "director-bridge");
44404
44357
  }
44405
44358
  function readAllowedOrigins() {
44406
44359
  const raw = (process.env.MRRLIN_DIRECTOR_BRIDGE_ALLOWED_ORIGINS ?? "").trim();
@@ -45264,13 +45217,14 @@ async function startDirectorBridge() {
45264
45217
  codexCwd: config2.codexCwd,
45265
45218
  codexExecutable: config2.codexExecutable,
45266
45219
  checkoutRegistry,
45267
- worktreeRoot: import_node_path12.default.join(config2.stateDir, "worktrees"),
45268
- locksDir: import_node_path12.default.join(config2.stateDir, "locks"),
45269
- // Wire the profile-enforced executor server for code-execution runs. Each run gets its own
45270
- // sandboxed Codex instance (scrubbed env, scratch CODEX_HOME, deny-read, egress allowlist).
45220
+ worktreeRoot: import_node_path11.default.join(config2.stateDir, "worktrees"),
45221
+ locksDir: import_node_path11.default.join(config2.stateDir, "locks"),
45222
+ // Wire the executor server for code-execution runs. Each run gets its own app-server
45223
+ // process at the run worktree, running UNRESTRICTED from the real ~/.codex (owner
45224
+ // no-sandbox decision — auth + mrrlin MCP come from the operator config).
45271
45225
  // The returned handle's dispose() shuts down the spawned app-server CHILD (manager.shutdown(),
45272
- // not the JSON-RPC-only client.close()) and removes the scratch dir releasing the executor
45273
- // therefore kills the process and cleans up. driveRun owns this dispose per-run (Fix A + G).
45226
+ // not the JSON-RPC-only client.close()) releasing the executor therefore kills the process.
45227
+ // driveRun owns this dispose per-run (Fix A + G).
45274
45228
  acquireExecutorCodex: async (worktreePath) => {
45275
45229
  const handle = await startExecutorServer({ worktree: worktreePath });
45276
45230
  return { client: handle.client, dispose: handle.dispose };
@@ -45281,15 +45235,15 @@ async function startDirectorBridge() {
45281
45235
  // fail. If the resolved branch does not exist on origin, createRunWorktree surfaces a
45282
45236
  // `default_branch_unresolved` error which the consumer routes to a clean operator handoff.
45283
45237
  getDefaultBranch: (projectSlug) => Promise.resolve(resolveDefaultBranch(checkoutRegistry.get(projectSlug)?.path ?? null)),
45284
- // ADR 0007 self-review: critique the committed diff on the executor's own sandbox before
45238
+ // ADR 0007 self-review: critique the committed diff on the executor's own client before
45285
45239
  // push/PR. Reuses the verification turn-runner (acquireThread + collect assistant text).
45286
45240
  selfReviewTurn: createSelfReviewTurn({
45287
45241
  runTurn: (codexClient, cwd, prompt) => runCollectedCodexTurn(codexClient, prompt, cwd, SELF_REVIEW_BASE_INSTRUCTIONS)
45288
45242
  }),
45289
45243
  // ADR 0015 deploy gate: after a pushed run reaches dev_deploy/prod_deploy, the backstop sweep
45290
- // dispatches the deploy + polls + runs a DEDICATED sandboxed verification turn against the
45291
- // deployed env URL. The verification sandbox is network-only (egress allowlisted to ONLY the
45292
- // env host) with a fresh empty scratch cwd no repo/worktree/secret access.
45244
+ // dispatches the deploy + polls + runs a verification turn against the deployed env URL in a
45245
+ // throwaway cwd. Per the owner no-sandbox decision the verification turn runs from the real
45246
+ // ~/.codex like every other executor turn; its observe-only base instructions bound behaviour.
45293
45247
  deployGate: {
45294
45248
  loadVerificationSection: async (projectSlug, task) => {
45295
45249
  if (!task.specWikiPageId) return null;
@@ -45297,14 +45251,16 @@ async function startDirectorBridge() {
45297
45251
  return page?.markdownBody ? extractVerificationSection(page.markdownBody) : null;
45298
45252
  },
45299
45253
  runVerificationTurn: createRunVerificationTurn({
45300
- startSandbox: async (egressDomains) => {
45301
- const cwd = import_node_fs11.default.mkdtempSync(import_node_path12.default.join(import_node_os8.default.tmpdir(), "mrrlin-verify-"));
45254
+ // egressDomains is retained in the seam signature (verification-turn.ts still computes the
45255
+ // env host) but no longer constrains anything — the executor is unrestricted.
45256
+ startSandbox: async (_egressDomains) => {
45257
+ const cwd = import_node_fs10.default.mkdtempSync(import_node_path11.default.join(import_node_os7.default.tmpdir(), "mrrlin-verify-"));
45302
45258
  let handle;
45303
45259
  try {
45304
- handle = await startExecutorServer({ worktree: cwd, egressDomains });
45260
+ handle = await startExecutorServer({ worktree: cwd });
45305
45261
  } catch (error51) {
45306
45262
  try {
45307
- import_node_fs11.default.rmSync(cwd, { recursive: true, force: true });
45263
+ import_node_fs10.default.rmSync(cwd, { recursive: true, force: true });
45308
45264
  } catch {
45309
45265
  }
45310
45266
  throw error51;
@@ -45315,7 +45271,7 @@ async function startDirectorBridge() {
45315
45271
  dispose: () => {
45316
45272
  handle.dispose();
45317
45273
  try {
45318
- import_node_fs11.default.rmSync(cwd, { recursive: true, force: true });
45274
+ import_node_fs10.default.rmSync(cwd, { recursive: true, force: true });
45319
45275
  } catch {
45320
45276
  }
45321
45277
  }
@@ -45455,7 +45411,7 @@ async function startDirectorBridge() {
45455
45411
  const bridgeLogger = createBridgeLogger(config2.stateDir, process.env);
45456
45412
  let bridgeBinShaShort = "unknown00000";
45457
45413
  try {
45458
- bridgeBinShaShort = import_node_crypto5.default.createHash("sha256").update(import_node_fs11.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
45414
+ bridgeBinShaShort = import_node_crypto5.default.createHash("sha256").update(import_node_fs10.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
45459
45415
  } catch {
45460
45416
  }
45461
45417
  attachBridgeWss(server, {
@@ -45564,8 +45520,8 @@ async function startDirectorBridge() {
45564
45520
  enqueueRun(
45565
45521
  () => runOrphanWorktreeSweep(client, {
45566
45522
  checkoutRegistry,
45567
- worktreeRoot: import_node_path12.default.join(config2.stateDir, "worktrees"),
45568
- locksDir: import_node_path12.default.join(config2.stateDir, "locks")
45523
+ worktreeRoot: import_node_path11.default.join(config2.stateDir, "worktrees"),
45524
+ locksDir: import_node_path11.default.join(config2.stateDir, "locks")
45569
45525
  })
45570
45526
  );
45571
45527
  enqueueRun(async () => {
@@ -45777,15 +45733,15 @@ function readDispatchBody(req) {
45777
45733
  function readOrCreateBridgeToken(stateDir) {
45778
45734
  const explicit = (process.env.MRRLIN_DIRECTOR_BRIDGE_TOKEN ?? "").trim();
45779
45735
  if (explicit) return explicit;
45780
- const tokenPath = import_node_path12.default.join(stateDir, "token.txt");
45736
+ const tokenPath = import_node_path11.default.join(stateDir, "token.txt");
45781
45737
  try {
45782
- const existing = import_node_fs11.default.readFileSync(tokenPath, "utf8").trim();
45738
+ const existing = import_node_fs10.default.readFileSync(tokenPath, "utf8").trim();
45783
45739
  if (existing) return existing;
45784
45740
  } catch {
45785
45741
  }
45786
- import_node_fs11.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
45742
+ import_node_fs10.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
45787
45743
  const token = import_node_crypto5.default.randomBytes(32).toString("base64url");
45788
- import_node_fs11.default.writeFileSync(tokenPath, `${token}
45744
+ import_node_fs10.default.writeFileSync(tokenPath, `${token}
45789
45745
  `, { mode: 384 });
45790
45746
  return token;
45791
45747
  }
@@ -49169,17 +49125,17 @@ var StdioServerTransport = class {
49169
49125
  // src/tools.ts
49170
49126
  var import_node_crypto8 = require("node:crypto");
49171
49127
  var import_promises3 = require("node:fs/promises");
49172
- var import_node_fs13 = require("node:fs");
49173
- var import_node_path15 = __toESM(require("node:path"), 1);
49174
- var import_node_os9 = __toESM(require("node:os"), 1);
49128
+ var import_node_fs12 = require("node:fs");
49129
+ var import_node_path14 = __toESM(require("node:path"), 1);
49130
+ var import_node_os8 = __toESM(require("node:os"), 1);
49175
49131
  var import_node_child_process7 = require("node:child_process");
49176
49132
 
49177
49133
  // ../../packages/wiki/dist/index.js
49178
49134
  var import_promises2 = __toESM(require("node:fs/promises"), 1);
49179
- var import_node_path13 = __toESM(require("node:path"), 1);
49135
+ var import_node_path12 = __toESM(require("node:path"), 1);
49180
49136
  var INCLUDED_DOC_FOLDERS = /* @__PURE__ */ new Set(["_meta", "explanation", "how-to", "reference", "sdd", "tutorials"]);
49181
49137
  function toPosixPath(input) {
49182
- return input.split(import_node_path13.default.sep).join("/");
49138
+ return input.split(import_node_path12.default.sep).join("/");
49183
49139
  }
49184
49140
  function slugifyWikiSegment(input) {
49185
49141
  return input.trim().toLowerCase().replace(/`/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -49193,12 +49149,12 @@ async function pathExists2(input) {
49193
49149
  }
49194
49150
  }
49195
49151
  async function findWorkspaceRoot(start = process.cwd()) {
49196
- let current = import_node_path13.default.resolve(start);
49152
+ let current = import_node_path12.default.resolve(start);
49197
49153
  while (true) {
49198
- if (await pathExists2(import_node_path13.default.join(current, "pnpm-workspace.yaml")) && await pathExists2(import_node_path13.default.join(current, "docs"))) {
49154
+ if (await pathExists2(import_node_path12.default.join(current, "pnpm-workspace.yaml")) && await pathExists2(import_node_path12.default.join(current, "docs"))) {
49199
49155
  return current;
49200
49156
  }
49201
- const parent = import_node_path13.default.dirname(current);
49157
+ const parent = import_node_path12.default.dirname(current);
49202
49158
  if (parent === current) {
49203
49159
  throw new Error(`Unable to find Mrrlin workspace root from ${start}`);
49204
49160
  }
@@ -49207,28 +49163,28 @@ async function findWorkspaceRoot(start = process.cwd()) {
49207
49163
  }
49208
49164
  async function resolveDocsRoot(input) {
49209
49165
  if (input) {
49210
- return import_node_path13.default.resolve(input);
49166
+ return import_node_path12.default.resolve(input);
49211
49167
  }
49212
49168
  if (process.env.MRRLIN_DOCS_ROOT) {
49213
- return import_node_path13.default.resolve(process.env.MRRLIN_DOCS_ROOT);
49169
+ return import_node_path12.default.resolve(process.env.MRRLIN_DOCS_ROOT);
49214
49170
  }
49215
- return import_node_path13.default.join(await findWorkspaceRoot(), "docs");
49171
+ return import_node_path12.default.join(await findWorkspaceRoot(), "docs");
49216
49172
  }
49217
49173
  async function resolveIndexPath(input) {
49218
49174
  if (input) {
49219
- return import_node_path13.default.resolve(input);
49175
+ return import_node_path12.default.resolve(input);
49220
49176
  }
49221
49177
  if (process.env.MRRLIN_WIKI_INDEX_PATH) {
49222
- return import_node_path13.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
49178
+ return import_node_path12.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
49223
49179
  }
49224
49180
  const workspaceRoot = await findWorkspaceRoot();
49225
- return import_node_path13.default.join(workspaceRoot, "apps", "web", "public", "wiki-index.json");
49181
+ return import_node_path12.default.join(workspaceRoot, "apps", "web", "public", "wiki-index.json");
49226
49182
  }
49227
49183
  async function walkMarkdownFiles(root, dir = root) {
49228
49184
  const entries = await import_promises2.default.readdir(dir, { withFileTypes: true });
49229
49185
  const files = [];
49230
49186
  for (const entry of entries) {
49231
- const absolute = import_node_path13.default.join(dir, entry.name);
49187
+ const absolute = import_node_path12.default.join(dir, entry.name);
49232
49188
  if (entry.isDirectory()) {
49233
49189
  files.push(...await walkMarkdownFiles(root, absolute));
49234
49190
  continue;
@@ -49247,7 +49203,7 @@ function parseTitle(markdown, sourcePath) {
49247
49203
  return title;
49248
49204
  }
49249
49205
  function documentFromFile(docsRoot, absolutePath, markdown) {
49250
- const relativePath = toPosixPath(import_node_path13.default.relative(docsRoot, absolutePath));
49206
+ const relativePath = toPosixPath(import_node_path12.default.relative(docsRoot, absolutePath));
49251
49207
  const [section, fileName] = relativePath.split("/");
49252
49208
  if (!section || !fileName || !INCLUDED_DOC_FOLDERS.has(section)) {
49253
49209
  return null;
@@ -49801,8 +49757,8 @@ function errMessage(err) {
49801
49757
  }
49802
49758
 
49803
49759
  // src/consensus/wiring.ts
49804
- var import_node_fs12 = __toESM(require("node:fs"), 1);
49805
- var import_node_path14 = __toESM(require("node:path"), 1);
49760
+ var import_node_fs11 = __toESM(require("node:fs"), 1);
49761
+ var import_node_path13 = __toESM(require("node:path"), 1);
49806
49762
  var import_node_url2 = require("node:url");
49807
49763
 
49808
49764
  // src/consensus/code-gate-git.ts
@@ -50037,15 +49993,15 @@ ${res.stdout}${res.stderr}`);
50037
49993
  var import_meta2 = {};
50038
49994
  function getPersonasDir() {
50039
49995
  if (typeof __dirname !== "undefined") {
50040
- return import_node_path14.default.join(__dirname, "consensus", "personas");
49996
+ return import_node_path13.default.join(__dirname, "consensus", "personas");
50041
49997
  }
50042
- return import_node_path14.default.join(import_node_path14.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "personas");
49998
+ return import_node_path13.default.join(import_node_path13.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "personas");
50043
49999
  }
50044
50000
  var personaCache = /* @__PURE__ */ new Map();
50045
50001
  function loadPersona(name) {
50046
50002
  const cached2 = personaCache.get(name);
50047
50003
  if (cached2 !== void 0) return cached2;
50048
- const content = import_node_fs12.default.readFileSync(import_node_path14.default.join(getPersonasDir(), `${name}.md`), "utf8");
50004
+ const content = import_node_fs11.default.readFileSync(import_node_path13.default.join(getPersonasDir(), `${name}.md`), "utf8");
50049
50005
  personaCache.set(name, content);
50050
50006
  return content;
50051
50007
  }
@@ -51716,8 +51672,8 @@ function createMrrlinTools(options) {
51716
51672
  // follow-up (see Task D2d notes).
51717
51673
  async (c, { projectSlug, pageId, ready }) => {
51718
51674
  if (ready !== true) return await c.markSpecReady({ projectSlug, pageId, ready });
51719
- const settings = await c.getOperatorSettings();
51720
- if (!settings.consensusEnabled) {
51675
+ const config2 = await c.getConsensusConfig(projectSlug);
51676
+ if (!config2.consensusEnabled) {
51721
51677
  throw new McpToolCodedError(
51722
51678
  "SPEC_CONSENSUS_REQUIRED",
51723
51679
  `Spec ${pageId} cannot be marked ready by the Director while consensus is disabled for this project \u2014 an operator must approve it (web wiki / markSpecReady route). Autonomy is a landing gate, not a license to self-promote.`
@@ -51905,7 +51861,7 @@ function createMrrlinTools(options) {
51905
51861
  "ARTIFACT_FILE_UPLOAD_FAILED",
51906
51862
  "Unable to upload artifact file.",
51907
51863
  async (c, { projectSlug, path: filePath, class: artifactClass, taskId, runId, description }) => {
51908
- const extension2 = import_node_path15.default.extname(filePath).toLowerCase();
51864
+ const extension2 = import_node_path14.default.extname(filePath).toLowerCase();
51909
51865
  const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
51910
51866
  if (!contentType) {
51911
51867
  throw new McpToolCodedError(
@@ -51933,7 +51889,7 @@ function createMrrlinTools(options) {
51933
51889
  "Artifact exceeds 5MB; split or summarize instead."
51934
51890
  );
51935
51891
  }
51936
- const filename = import_node_path15.default.basename(filePath);
51892
+ const filename = import_node_path14.default.basename(filePath);
51937
51893
  const created = await c.createArtifactFile(projectSlug, {
51938
51894
  class: artifactClass,
51939
51895
  contentType,
@@ -52016,7 +51972,7 @@ function createMrrlinTools(options) {
52016
51972
  "Unable to register local checkout.",
52017
51973
  async (_c, { projectSlug, path: checkoutPath, repo }) => {
52018
51974
  const trimmedPath = checkoutPath.trim();
52019
- if (!import_node_path15.default.isAbsolute(trimmedPath)) {
51975
+ if (!import_node_path14.default.isAbsolute(trimmedPath)) {
52020
51976
  throw new McpToolCodedError(
52021
51977
  "LOCAL_CHECKOUT_PATH_NOT_ABSOLUTE",
52022
51978
  `Path must be absolute, got: ${trimmedPath}`
@@ -52024,7 +51980,7 @@ function createMrrlinTools(options) {
52024
51980
  }
52025
51981
  let resolvedPath;
52026
51982
  try {
52027
- resolvedPath = (0, import_node_fs13.realpathSync)(trimmedPath);
51983
+ resolvedPath = (0, import_node_fs12.realpathSync)(trimmedPath);
52028
51984
  } catch {
52029
51985
  throw new McpToolCodedError(
52030
51986
  "LOCAL_CHECKOUT_PATH_NOT_FOUND",
@@ -52051,7 +52007,7 @@ function createMrrlinTools(options) {
52051
52007
  `Origin remote ${remoteUrl} does not match repo ${repo}.`
52052
52008
  );
52053
52009
  }
52054
- const stateDir = process.env.CODEX_HOME ? import_node_path15.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge") : import_node_path15.default.join(import_node_os9.default.homedir(), ".mrrlin", "director-bridge");
52010
+ const stateDir = process.env.CODEX_HOME ? import_node_path14.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge") : import_node_path14.default.join(import_node_os8.default.homedir(), ".mrrlin", "director-bridge");
52055
52011
  const registry3 = new CheckoutRegistry(stateDir);
52056
52012
  const confirmedAt = (/* @__PURE__ */ new Date()).toISOString();
52057
52013
  registry3.confirm(projectSlug, resolvedPath, confirmedAt);
@@ -52258,13 +52214,13 @@ function runSetCredential(args) {
52258
52214
  }
52259
52215
 
52260
52216
  // src/install-service.ts
52261
- var import_node_os10 = __toESM(require("node:os"), 1);
52262
- var import_node_path17 = __toESM(require("node:path"), 1);
52217
+ var import_node_os9 = __toESM(require("node:os"), 1);
52218
+ var import_node_path16 = __toESM(require("node:path"), 1);
52263
52219
 
52264
52220
  // src/service-paths.ts
52265
- var import_node_path16 = __toESM(require("node:path"), 1);
52221
+ var import_node_path15 = __toESM(require("node:path"), 1);
52266
52222
  function isWorktreePath(p) {
52267
- const norm = import_node_path16.default.normalize(p).split(import_node_path16.default.sep).join("/");
52223
+ const norm = import_node_path15.default.normalize(p).split(import_node_path15.default.sep).join("/");
52268
52224
  return norm.includes("/.claude/worktrees/");
52269
52225
  }
52270
52226
  function resolveServiceCwd(opts) {
@@ -52318,7 +52274,7 @@ function installService(deps) {
52318
52274
  deps.log(resolved.reason);
52319
52275
  return { ok: false };
52320
52276
  }
52321
- const home = deps.env.HOME ?? import_node_os10.default.homedir();
52277
+ const home = deps.env.HOME ?? import_node_os9.default.homedir();
52322
52278
  const bins = ["node", "codex", "mrrlin-mcp"].map((b) => deps.which(b));
52323
52279
  if (bins.some((b) => !b)) {
52324
52280
  deps.log("Could not resolve absolute paths for node/codex/mrrlin-mcp on PATH. Install them or fix PATH.");
@@ -52329,7 +52285,7 @@ function installService(deps) {
52329
52285
  return { ok: false };
52330
52286
  }
52331
52287
  const resolvedBins = bins.filter((b) => b !== null);
52332
- const pathEnv = Array.from(new Set(resolvedBins.map((b) => import_node_path17.default.dirname(b)))).join(":");
52288
+ const pathEnv = Array.from(new Set(resolvedBins.map((b) => import_node_path16.default.dirname(b)))).join(":");
52333
52289
  const text = renderEcosystemConfig({
52334
52290
  cwd: resolved.cwd,
52335
52291
  home,
@@ -52338,7 +52294,7 @@ function installService(deps) {
52338
52294
  staging: deps.env.MRRLIN_STAGING === "1",
52339
52295
  apiBaseUrl: deps.env.MRRLIN_API_BASE_URL?.trim() || void 0
52340
52296
  });
52341
- const ecoPath = import_node_path17.default.join(home, ".mrrlin", "ecosystem.config.cjs");
52297
+ const ecoPath = import_node_path16.default.join(home, ".mrrlin", "ecosystem.config.cjs");
52342
52298
  deps.writeFile(ecoPath, text);
52343
52299
  const start = deps.runPm2(["startOrReload", ecoPath]);
52344
52300
  if (start.code !== 0) {
@@ -52369,13 +52325,13 @@ function uninstallService(deps) {
52369
52325
 
52370
52326
  // src/uninstall-codex.ts
52371
52327
  var import_promises4 = __toESM(require("node:fs/promises"), 1);
52372
- var import_node_os11 = __toESM(require("node:os"), 1);
52373
- var import_node_path18 = __toESM(require("node:path"), 1);
52328
+ var import_node_os10 = __toESM(require("node:os"), 1);
52329
+ var import_node_path17 = __toESM(require("node:path"), 1);
52374
52330
  var toml2 = __toESM(require_toml(), 1);
52375
52331
  function resolveCodexHome2(options) {
52376
52332
  if (options.codexHome) return options.codexHome;
52377
52333
  if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
52378
- return import_node_path18.default.join(options.homeDir ?? import_node_os11.default.homedir(), ".codex");
52334
+ return import_node_path17.default.join(options.homeDir ?? import_node_os10.default.homedir(), ".codex");
52379
52335
  }
52380
52336
  async function pathExists3(target) {
52381
52337
  try {
@@ -52388,7 +52344,7 @@ async function pathExists3(target) {
52388
52344
  var MRRLIN_BLOCK_RE = /(^|\n)\[mcp_servers\.mrrlin(?:-browser)?(?:\]|\.[^\]\n]*\])[\s\S]*?(?=\n\[|$)/g;
52389
52345
  async function uninstallCodex(options = {}) {
52390
52346
  const codexHome = resolveCodexHome2(options);
52391
- const configPath = import_node_path18.default.join(codexHome, "config.toml");
52347
+ const configPath = import_node_path17.default.join(codexHome, "config.toml");
52392
52348
  const removePrompts = async () => uninstallPrompts(codexHome, options.promptNames ?? []);
52393
52349
  if (!await pathExists3(configPath)) {
52394
52350
  return { action: "missing", configPath, prompts: await removePrompts() };
@@ -52416,10 +52372,10 @@ async function uninstallCodex(options = {}) {
52416
52372
  }
52417
52373
  async function uninstallPrompts(codexHome, names) {
52418
52374
  if (names.length === 0) return [];
52419
- const promptsDir2 = import_node_path18.default.join(codexHome, "prompts");
52375
+ const promptsDir2 = import_node_path17.default.join(codexHome, "prompts");
52420
52376
  const out = [];
52421
52377
  for (const name of names) {
52422
- const promptPath = import_node_path18.default.join(promptsDir2, `${name}.md`);
52378
+ const promptPath = import_node_path17.default.join(promptsDir2, `${name}.md`);
52423
52379
  try {
52424
52380
  await import_promises4.default.unlink(promptPath);
52425
52381
  out.push({ name, action: "removed", promptPath });
@@ -52436,16 +52392,16 @@ async function uninstallPrompts(codexHome, names) {
52436
52392
  }
52437
52393
 
52438
52394
  // src/report-issue-prompt.ts
52439
- var import_node_fs14 = __toESM(require("node:fs"), 1);
52440
- var import_node_path19 = __toESM(require("node:path"), 1);
52395
+ var import_node_fs13 = __toESM(require("node:fs"), 1);
52396
+ var import_node_path18 = __toESM(require("node:path"), 1);
52441
52397
  var import_node_url3 = require("node:url");
52442
52398
  var import_meta3 = {};
52443
52399
  function promptsDir() {
52444
- if (typeof __dirname !== "undefined") return import_node_path19.default.join(__dirname, "prompts");
52445
- return import_node_path19.default.join(import_node_path19.default.dirname((0, import_node_url3.fileURLToPath)(import_meta3.url)), "prompts");
52400
+ if (typeof __dirname !== "undefined") return import_node_path18.default.join(__dirname, "prompts");
52401
+ return import_node_path18.default.join(import_node_path18.default.dirname((0, import_node_url3.fileURLToPath)(import_meta3.url)), "prompts");
52446
52402
  }
52447
52403
  function readReportIssuePrompt() {
52448
- return import_node_fs14.default.readFileSync(import_node_path19.default.join(promptsDir(), "report-issue.md"), "utf8");
52404
+ return import_node_fs13.default.readFileSync(import_node_path18.default.join(promptsDir(), "report-issue.md"), "utf8");
52449
52405
  }
52450
52406
 
52451
52407
  // src/bin.ts
@@ -52705,8 +52661,8 @@ async function main() {
52705
52661
  env: process.env,
52706
52662
  cwd: process.cwd(),
52707
52663
  writeFile: (p, c) => {
52708
- (0, import_node_fs15.mkdirSync)(import_node_path21.default.dirname(p), { recursive: true, mode: 448 });
52709
- (0, import_node_fs15.writeFileSync)(p, c, { mode: 384 });
52664
+ (0, import_node_fs14.mkdirSync)(import_node_path20.default.dirname(p), { recursive: true, mode: 448 });
52665
+ (0, import_node_fs14.writeFileSync)(p, c, { mode: 384 });
52710
52666
  },
52711
52667
  runPm2: pm2Runner,
52712
52668
  which: whichBin,
@@ -52723,35 +52679,35 @@ async function main() {
52723
52679
  runPm2: (a) => ({ code: pm2Runner(a).code }),
52724
52680
  removeFile: (p) => {
52725
52681
  try {
52726
- (0, import_node_fs15.rmSync)(p, { force: true });
52682
+ (0, import_node_fs14.rmSync)(p, { force: true });
52727
52683
  } catch {
52728
52684
  }
52729
52685
  },
52730
52686
  purgeSecret: purge,
52731
52687
  secretPath: agentCredentialPath(),
52732
52688
  tokenPath: operatorTokenPath(),
52733
- ecoPath: import_node_path21.default.join(process.env.HOME ?? (0, import_node_os12.homedir)(), ".mrrlin", "ecosystem.config.cjs"),
52689
+ ecoPath: import_node_path20.default.join(process.env.HOME ?? (0, import_node_os11.homedir)(), ".mrrlin", "ecosystem.config.cjs"),
52734
52690
  log: (m) => process.stderr.write(`[mrrlin-mcp uninstall-service] ${m}
52735
52691
  `)
52736
52692
  });
52737
52693
  return;
52738
52694
  }
52739
52695
  case "uninstall": {
52740
- const home = process.env.HOME ?? (0, import_node_os12.homedir)();
52696
+ const home = process.env.HOME ?? (0, import_node_os11.homedir)();
52741
52697
  const log = (m) => process.stderr.write(`[mrrlin-mcp uninstall] ${m}
52742
52698
  `);
52743
52699
  uninstallService({
52744
52700
  runPm2: (a) => ({ code: pm2Runner(a).code }),
52745
52701
  removeFile: (p) => {
52746
52702
  try {
52747
- (0, import_node_fs15.rmSync)(p, { force: true });
52703
+ (0, import_node_fs14.rmSync)(p, { force: true });
52748
52704
  } catch {
52749
52705
  }
52750
52706
  },
52751
52707
  purgeSecret: true,
52752
52708
  secretPath: agentCredentialPath(),
52753
52709
  tokenPath: operatorTokenPath(),
52754
- ecoPath: import_node_path21.default.join(home, ".mrrlin", "ecosystem.config.cjs"),
52710
+ ecoPath: import_node_path20.default.join(home, ".mrrlin", "ecosystem.config.cjs"),
52755
52711
  log
52756
52712
  });
52757
52713
  let codexOk = true;
@@ -52771,7 +52727,7 @@ async function main() {
52771
52727
  log(`codex config NOT modified: ${error51 instanceof Error ? error51.message : String(error51)}`);
52772
52728
  }
52773
52729
  try {
52774
- (0, import_node_fs15.rmSync)(import_node_path21.default.join(home, ".mrrlin"), { recursive: true, force: true });
52730
+ (0, import_node_fs14.rmSync)(import_node_path20.default.join(home, ".mrrlin"), { recursive: true, force: true });
52775
52731
  } catch {
52776
52732
  }
52777
52733
  log("removed ~/.mrrlin");
@@ -52812,7 +52768,7 @@ ${HELP_TEXT}`);
52812
52768
  }
52813
52769
  }
52814
52770
  function resolveSelfBinPath() {
52815
- return import_node_path20.default.resolve(process.argv[1] ?? process.execPath);
52771
+ return import_node_path19.default.resolve(process.argv[1] ?? process.execPath);
52816
52772
  }
52817
52773
  main().catch((error51) => {
52818
52774
  process.stderr.write(`mrrlin-mcp fatal error: ${error51 instanceof Error ? error51.message : String(error51)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrrlin-dev/mcp",
3
- "version": "0.3.9",
3
+ "version": "0.3.11",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mrrlin-mcp": "dist/bin.cjs"
@@ -22,8 +22,8 @@
22
22
  "@types/ws": "^8.18.1",
23
23
  "esbuild": "^0.24.0",
24
24
  "tsx": "^4.22.3",
25
- "@mrrlin/client": "0.0.0",
26
25
  "@mrrlin/codex-client": "0.0.0",
26
+ "@mrrlin/client": "0.0.0",
27
27
  "@mrrlin/director-e2e": "0.0.0",
28
28
  "@mrrlin/schemas": "0.0.0",
29
29
  "@mrrlin/tsconfig": "0.0.0",