@mrrlin-dev/mcp 0.3.10 → 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.
- package/dist/bin.cjs +185 -229
- 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
|
|
20647
|
+
var import_node_path19 = __toESM(require("node:path"), 1);
|
|
20648
20648
|
var import_node_child_process8 = require("node:child_process");
|
|
20649
|
-
var
|
|
20650
|
-
var
|
|
20651
|
-
var
|
|
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
|
|
20936
|
+
var import_node_fs10 = __toESM(require("node:fs"), 1);
|
|
20937
20937
|
var import_node_http = __toESM(require("node:http"), 1);
|
|
20938
|
-
var
|
|
20939
|
-
var
|
|
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
|
|
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.
|
|
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
|
|
38998
|
-
"
|
|
38999
|
-
"
|
|
39000
|
-
"
|
|
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: () =>
|
|
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 =
|
|
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:
|
|
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
|
-
`
|
|
43839
|
-
`
|
|
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
|
|
43984
|
-
var
|
|
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,
|
|
43997
|
+
const logsDir = (0, import_node_path10.join)(stateDir, "logs");
|
|
44070
43998
|
try {
|
|
44071
|
-
(0,
|
|
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,
|
|
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,
|
|
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 =
|
|
44050
|
+
const dir = import_node_path11.default.join(stateDir, "no-checkout");
|
|
44123
44051
|
try {
|
|
44124
|
-
|
|
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.
|
|
44282
|
-
"
|
|
44283
|
-
"
|
|
44284
|
-
"
|
|
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:
|
|
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: () =>
|
|
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
|
|
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
|
|
44403
|
-
return
|
|
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:
|
|
45268
|
-
locksDir:
|
|
45269
|
-
// Wire the
|
|
45270
|
-
//
|
|
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())
|
|
45273
|
-
//
|
|
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
|
|
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
|
|
45291
|
-
//
|
|
45292
|
-
//
|
|
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
|
-
|
|
45301
|
-
|
|
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
|
|
45260
|
+
handle = await startExecutorServer({ worktree: cwd });
|
|
45305
45261
|
} catch (error51) {
|
|
45306
45262
|
try {
|
|
45307
|
-
|
|
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
|
-
|
|
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(
|
|
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:
|
|
45568
|
-
locksDir:
|
|
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 =
|
|
45736
|
+
const tokenPath = import_node_path11.default.join(stateDir, "token.txt");
|
|
45781
45737
|
try {
|
|
45782
|
-
const existing =
|
|
45738
|
+
const existing = import_node_fs10.default.readFileSync(tokenPath, "utf8").trim();
|
|
45783
45739
|
if (existing) return existing;
|
|
45784
45740
|
} catch {
|
|
45785
45741
|
}
|
|
45786
|
-
|
|
45742
|
+
import_node_fs10.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
|
|
45787
45743
|
const token = import_node_crypto5.default.randomBytes(32).toString("base64url");
|
|
45788
|
-
|
|
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
|
|
49173
|
-
var
|
|
49174
|
-
var
|
|
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
|
|
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(
|
|
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 =
|
|
49152
|
+
let current = import_node_path12.default.resolve(start);
|
|
49197
49153
|
while (true) {
|
|
49198
|
-
if (await pathExists2(
|
|
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 =
|
|
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
|
|
49166
|
+
return import_node_path12.default.resolve(input);
|
|
49211
49167
|
}
|
|
49212
49168
|
if (process.env.MRRLIN_DOCS_ROOT) {
|
|
49213
|
-
return
|
|
49169
|
+
return import_node_path12.default.resolve(process.env.MRRLIN_DOCS_ROOT);
|
|
49214
49170
|
}
|
|
49215
|
-
return
|
|
49171
|
+
return import_node_path12.default.join(await findWorkspaceRoot(), "docs");
|
|
49216
49172
|
}
|
|
49217
49173
|
async function resolveIndexPath(input) {
|
|
49218
49174
|
if (input) {
|
|
49219
|
-
return
|
|
49175
|
+
return import_node_path12.default.resolve(input);
|
|
49220
49176
|
}
|
|
49221
49177
|
if (process.env.MRRLIN_WIKI_INDEX_PATH) {
|
|
49222
|
-
return
|
|
49178
|
+
return import_node_path12.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
|
|
49223
49179
|
}
|
|
49224
49180
|
const workspaceRoot = await findWorkspaceRoot();
|
|
49225
|
-
return
|
|
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 =
|
|
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(
|
|
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
|
|
49805
|
-
var
|
|
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
|
|
49996
|
+
return import_node_path13.default.join(__dirname, "consensus", "personas");
|
|
50041
49997
|
}
|
|
50042
|
-
return
|
|
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 =
|
|
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
|
}
|
|
@@ -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 =
|
|
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 =
|
|
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 (!
|
|
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,
|
|
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 ?
|
|
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
|
|
52262
|
-
var
|
|
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
|
|
52221
|
+
var import_node_path15 = __toESM(require("node:path"), 1);
|
|
52266
52222
|
function isWorktreePath(p) {
|
|
52267
|
-
const norm =
|
|
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 ??
|
|
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) =>
|
|
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 =
|
|
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
|
|
52373
|
-
var
|
|
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
|
|
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 =
|
|
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 =
|
|
52375
|
+
const promptsDir2 = import_node_path17.default.join(codexHome, "prompts");
|
|
52420
52376
|
const out = [];
|
|
52421
52377
|
for (const name of names) {
|
|
52422
|
-
const promptPath =
|
|
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
|
|
52440
|
-
var
|
|
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
|
|
52445
|
-
return
|
|
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
|
|
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,
|
|
52709
|
-
(0,
|
|
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,
|
|
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:
|
|
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,
|
|
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,
|
|
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:
|
|
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,
|
|
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
|
|
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.
|
|
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",
|