@mrrlin-dev/mcp 0.3.10 → 0.3.12
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 +203 -233
- package/package.json +1 -1
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;
|
|
@@ -37108,6 +37125,10 @@ var mrrlinExecutionArtifactCreateSchema = external_exports.object({
|
|
|
37108
37125
|
kind: mrrlinExecutionArtifactKindSchema,
|
|
37109
37126
|
payload: external_exports.record(external_exports.string(), external_exports.unknown()).default({})
|
|
37110
37127
|
});
|
|
37128
|
+
var executionArtifactListFiltersSchema = external_exports.object({
|
|
37129
|
+
limit: external_exports.coerce.number().int().min(1).max(100).optional(),
|
|
37130
|
+
order: external_exports.enum(["asc", "desc"]).optional()
|
|
37131
|
+
});
|
|
37111
37132
|
var executionRunResponseSchema = external_exports.object({
|
|
37112
37133
|
data: mrrlinExecutionRunSchema
|
|
37113
37134
|
});
|
|
@@ -37244,7 +37265,9 @@ var executionRunListFiltersSchema = external_exports.object({
|
|
|
37244
37265
|
return value;
|
|
37245
37266
|
}, external_exports.array(mrrlinExecutionRunStatusSchema)).optional()
|
|
37246
37267
|
});
|
|
37268
|
+
var mrrlinAutoSpecApprovalSchema = external_exports.enum(["manual", "after_consensus"]);
|
|
37247
37269
|
var mrrlinProjectSchedulerPolicySchema = external_exports.object({
|
|
37270
|
+
autoSpecApproval: mrrlinAutoSpecApprovalSchema,
|
|
37248
37271
|
cadenceSeconds: external_exports.number().int().positive().nullable(),
|
|
37249
37272
|
createdAt: external_exports.string().datetime(),
|
|
37250
37273
|
eligibleAutonomyLevels: external_exports.array(mrrlinAutonomyLevelSchema).min(1),
|
|
@@ -37253,6 +37276,7 @@ var mrrlinProjectSchedulerPolicySchema = external_exports.object({
|
|
|
37253
37276
|
wakeFloor: external_exports.string().datetime().nullable()
|
|
37254
37277
|
});
|
|
37255
37278
|
var mrrlinProjectSchedulerPolicyUpsertSchema = external_exports.object({
|
|
37279
|
+
autoSpecApproval: mrrlinAutoSpecApprovalSchema.optional(),
|
|
37256
37280
|
cadenceSeconds: external_exports.number().int().positive().nullable().optional(),
|
|
37257
37281
|
eligibleAutonomyLevels: external_exports.array(mrrlinAutonomyLevelSchema).min(1).optional(),
|
|
37258
37282
|
wakeFloor: external_exports.string().datetime().nullable().optional()
|
|
@@ -37313,7 +37337,10 @@ var mrrlinInboxItemIdSchema = external_exports.string().regex(/^II-[A-Za-z0-9._-
|
|
|
37313
37337
|
var mrrlinInboxItemActionPayloadSchema = external_exports.object({
|
|
37314
37338
|
actor: external_exports.string().min(1),
|
|
37315
37339
|
provider: external_exports.string().min(1),
|
|
37316
|
-
runId: mrrlinExecutionRunIdSchema
|
|
37340
|
+
runId: mrrlinExecutionRunIdSchema,
|
|
37341
|
+
// Optional (additive): when true, approving the proposal creates a full code-execution run
|
|
37342
|
+
// (worktree + push/PR path). Scheduler proposals set it; legacy payloads omit it.
|
|
37343
|
+
codeExecution: external_exports.boolean().optional()
|
|
37317
37344
|
});
|
|
37318
37345
|
var mrrlinInboxItemSchema = external_exports.object({
|
|
37319
37346
|
actionPayload: mrrlinInboxItemActionPayloadSchema.nullable(),
|
|
@@ -38067,8 +38094,12 @@ function createMrrlinClient(config2) {
|
|
|
38067
38094
|
});
|
|
38068
38095
|
return executionRunResponseSchema.parse(body).data;
|
|
38069
38096
|
},
|
|
38070
|
-
async listExecutionArtifacts(projectSlug, runId) {
|
|
38071
|
-
const
|
|
38097
|
+
async listExecutionArtifacts(projectSlug, runId, filters = {}) {
|
|
38098
|
+
const url2 = appendQuery(`${projectPath(projectSlug)}/execution-runs/${encodeURIComponent(runId)}/artifacts`, {
|
|
38099
|
+
limit: filters.limit !== void 0 ? String(filters.limit) : void 0,
|
|
38100
|
+
order: filters.order === "desc" ? "desc" : void 0
|
|
38101
|
+
});
|
|
38102
|
+
const body = await request(url2);
|
|
38072
38103
|
return executionArtifactListResponseSchema.parse(body).data;
|
|
38073
38104
|
},
|
|
38074
38105
|
async appendExecutionArtifact(projectSlug, runId, input) {
|
|
@@ -38514,7 +38545,7 @@ Do NOT derail the current task \u2014 if the operator has an in-flight question,
|
|
|
38514
38545
|
}
|
|
38515
38546
|
|
|
38516
38547
|
// src/_generated/version.ts
|
|
38517
|
-
var PKG_VERSION = "0.3.
|
|
38548
|
+
var PKG_VERSION = "0.3.12";
|
|
38518
38549
|
|
|
38519
38550
|
// src/api-base-url.ts
|
|
38520
38551
|
var DEFAULT_API_BASE_URL = "http://127.0.0.1:8787";
|
|
@@ -38994,10 +39025,12 @@ var CONSUMER_BASE_INSTRUCTIONS = [
|
|
|
38994
39025
|
].join("\n");
|
|
38995
39026
|
var EXECUTOR_BASE_INSTRUCTIONS = [
|
|
38996
39027
|
...BASE_INSTRUCTIONS_PREFIX,
|
|
38997
|
-
"You run inside
|
|
38998
|
-
"
|
|
38999
|
-
"
|
|
39000
|
-
"
|
|
39028
|
+
"You run inside a git worktree dedicated to this run, with full read/write/network access to",
|
|
39029
|
+
"the host (there is NO filesystem sandbox). Do your work by creating, editing, and deleting",
|
|
39030
|
+
"files and running git/build/test commands WITHIN this worktree. Keep all changes inside the",
|
|
39031
|
+
"worktree and do not read the operator's personal secrets or files outside it \u2014 this is a rule",
|
|
39032
|
+
"you must follow, not something the environment enforces. Be concise. When you have made the",
|
|
39033
|
+
"next increment of progress, stop the turn."
|
|
39001
39034
|
].join("\n");
|
|
39002
39035
|
function artifactKindForEvent(event) {
|
|
39003
39036
|
switch (event.type) {
|
|
@@ -39117,12 +39150,25 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
39117
39150
|
};
|
|
39118
39151
|
return deps.runExclusive(async () => {
|
|
39119
39152
|
const pending = [];
|
|
39153
|
+
let resolveTurnEnded = null;
|
|
39154
|
+
const turnEnded = new Promise((resolve) => {
|
|
39155
|
+
resolveTurnEnded = resolve;
|
|
39156
|
+
});
|
|
39157
|
+
let acceptedTurnId = null;
|
|
39120
39158
|
const unsub = codex.onNotification((method, params) => {
|
|
39121
39159
|
const events = mapper.mapNotification(
|
|
39122
39160
|
{ method, params },
|
|
39123
39161
|
threadId
|
|
39124
39162
|
);
|
|
39125
39163
|
for (const event of events) pending.push(persist(event));
|
|
39164
|
+
if (method === "turn/completed") {
|
|
39165
|
+
const p = params;
|
|
39166
|
+
const notifThreadId = p?.threadId;
|
|
39167
|
+
const notifTurnId = p?.turn?.id;
|
|
39168
|
+
const threadMatches = !notifThreadId || notifThreadId === threadId;
|
|
39169
|
+
const turnMatches = !acceptedTurnId || !notifTurnId || notifTurnId === acceptedTurnId;
|
|
39170
|
+
if (threadMatches && turnMatches) resolveTurnEnded?.();
|
|
39171
|
+
}
|
|
39126
39172
|
});
|
|
39127
39173
|
const touchTimer = setInterval(() => {
|
|
39128
39174
|
void deps.client.touchExecutionRun(projectSlug, runId, leaseId).catch(() => {
|
|
@@ -39132,7 +39178,14 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
39132
39178
|
try {
|
|
39133
39179
|
const timeoutMs = execTurnTimeoutMs();
|
|
39134
39180
|
await awaitTurnWithDeadline({
|
|
39135
|
-
run: () =>
|
|
39181
|
+
run: async () => {
|
|
39182
|
+
const accepted = await codex.turn.start({
|
|
39183
|
+
threadId,
|
|
39184
|
+
input: [{ type: "text", text: inputText }]
|
|
39185
|
+
});
|
|
39186
|
+
acceptedTurnId = accepted?.turn?.id ?? null;
|
|
39187
|
+
await turnEnded;
|
|
39188
|
+
},
|
|
39136
39189
|
interrupt: () => codex.turn.interrupt({ threadId }),
|
|
39137
39190
|
timeoutMs,
|
|
39138
39191
|
timeoutMessage: `Execution turn did not complete within ${timeoutMs}ms.`,
|
|
@@ -39202,8 +39255,11 @@ async function driveRun(deps, projectSlug, runId) {
|
|
|
39202
39255
|
runId,
|
|
39203
39256
|
defaultBranch: await getDefaultBranch(projectSlug)
|
|
39204
39257
|
});
|
|
39205
|
-
await deps.client.updateExecutionRun(projectSlug, runId, {
|
|
39206
|
-
|
|
39258
|
+
await deps.client.updateExecutionRun(projectSlug, runId, {
|
|
39259
|
+
worktreeId: worktreePath,
|
|
39260
|
+
branch: worktreeBranch(runId)
|
|
39261
|
+
});
|
|
39262
|
+
sandbox = "danger-full-access";
|
|
39207
39263
|
turnCwd = worktreePath;
|
|
39208
39264
|
useExecutor = true;
|
|
39209
39265
|
if (deps.acquireExecutorCodex) {
|
|
@@ -43687,127 +43743,13 @@ var CheckoutRegistry = class {
|
|
|
43687
43743
|
};
|
|
43688
43744
|
|
|
43689
43745
|
// 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
43746
|
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
43747
|
const manager = new CodexServerManager();
|
|
43797
43748
|
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
43749
|
const client = await manager.acquire({
|
|
43806
|
-
cwd:
|
|
43807
|
-
env,
|
|
43750
|
+
cwd: opts.worktree,
|
|
43808
43751
|
approvalPolicy: "never",
|
|
43809
|
-
...opts.spawn ? { spawn: opts.spawn } : {}
|
|
43810
|
-
...opts.sandbox != null ? { sandbox: opts.sandbox } : {}
|
|
43752
|
+
...opts.spawn ? { spawn: opts.spawn } : {}
|
|
43811
43753
|
});
|
|
43812
43754
|
let disposed = false;
|
|
43813
43755
|
const dispose = () => {
|
|
@@ -43817,7 +43759,6 @@ async function startExecutorServer(opts) {
|
|
|
43817
43759
|
manager.shutdown();
|
|
43818
43760
|
} catch {
|
|
43819
43761
|
}
|
|
43820
|
-
cleanScratch();
|
|
43821
43762
|
};
|
|
43822
43763
|
return { client, dispose };
|
|
43823
43764
|
} catch (error51) {
|
|
@@ -43825,7 +43766,6 @@ async function startExecutorServer(opts) {
|
|
|
43825
43766
|
manager.shutdown();
|
|
43826
43767
|
} catch {
|
|
43827
43768
|
}
|
|
43828
|
-
cleanScratch();
|
|
43829
43769
|
throw error51;
|
|
43830
43770
|
}
|
|
43831
43771
|
}
|
|
@@ -43835,8 +43775,10 @@ function buildVerificationPrompt(input) {
|
|
|
43835
43775
|
return [
|
|
43836
43776
|
`You are verifying a deployment. The application is live at: ${input.environmentUrl}`,
|
|
43837
43777
|
`Run ONLY read-only HTTP checks against that URL to evaluate the verification steps below.`,
|
|
43838
|
-
`
|
|
43839
|
-
`
|
|
43778
|
+
`Behave as if you had no repository, filesystem, or credential access: do not read or write`,
|
|
43779
|
+
`files, do not use any credentials, do not contact any other host, and do not attempt to`,
|
|
43780
|
+
`mutate anything \u2014 only observe the deployed app over HTTP. (This is a rule you must follow,`,
|
|
43781
|
+
`not something the environment enforces.)`,
|
|
43840
43782
|
``,
|
|
43841
43783
|
`Verification steps for environment "${input.env}":`,
|
|
43842
43784
|
input.verificationSection,
|
|
@@ -43980,8 +43922,8 @@ function extractVerificationSection(markdown) {
|
|
|
43980
43922
|
}
|
|
43981
43923
|
|
|
43982
43924
|
// src/bridge-log.ts
|
|
43983
|
-
var
|
|
43984
|
-
var
|
|
43925
|
+
var import_node_fs9 = require("node:fs");
|
|
43926
|
+
var import_node_path10 = require("node:path");
|
|
43985
43927
|
|
|
43986
43928
|
// src/redact.ts
|
|
43987
43929
|
var REDACTED = "[REDACTED]";
|
|
@@ -44066,14 +44008,14 @@ function resolvePromptsEnabled(env) {
|
|
|
44066
44008
|
}
|
|
44067
44009
|
function createBridgeLogger(stateDir, env = process.env) {
|
|
44068
44010
|
if (!resolveBridgeLogEnabled(env)) return NOOP_LOGGER;
|
|
44069
|
-
const logsDir = (0,
|
|
44011
|
+
const logsDir = (0, import_node_path10.join)(stateDir, "logs");
|
|
44070
44012
|
try {
|
|
44071
|
-
(0,
|
|
44013
|
+
(0, import_node_fs9.mkdirSync)(logsDir, { recursive: true });
|
|
44072
44014
|
} catch {
|
|
44073
44015
|
return NOOP_LOGGER;
|
|
44074
44016
|
}
|
|
44075
44017
|
const includePrompts = resolvePromptsEnabled(env);
|
|
44076
|
-
const fileFor = () => (0,
|
|
44018
|
+
const fileFor = () => (0, import_node_path10.join)(logsDir, `bridge-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
|
|
44077
44019
|
const write = (dir, rec) => {
|
|
44078
44020
|
try {
|
|
44079
44021
|
const line = JSON.stringify({
|
|
@@ -44085,7 +44027,7 @@ function createBridgeLogger(stateDir, env = process.env) {
|
|
|
44085
44027
|
...rec.ms !== void 0 ? { ms: rec.ms } : {},
|
|
44086
44028
|
payload: redactMessage(rec.payload, { includePrompts })
|
|
44087
44029
|
}) + "\n";
|
|
44088
|
-
(0,
|
|
44030
|
+
(0, import_node_fs9.appendFileSync)(fileFor(), line);
|
|
44089
44031
|
} catch {
|
|
44090
44032
|
}
|
|
44091
44033
|
};
|
|
@@ -44119,9 +44061,9 @@ function normalizeModel(value) {
|
|
|
44119
44061
|
return trimmed ? trimmed : null;
|
|
44120
44062
|
}
|
|
44121
44063
|
function neutralCheckoutCwd(stateDir) {
|
|
44122
|
-
const dir =
|
|
44064
|
+
const dir = import_node_path11.default.join(stateDir, "no-checkout");
|
|
44123
44065
|
try {
|
|
44124
|
-
|
|
44066
|
+
import_node_fs10.default.mkdirSync(dir, { recursive: true });
|
|
44125
44067
|
} catch {
|
|
44126
44068
|
}
|
|
44127
44069
|
return dir;
|
|
@@ -44278,10 +44220,11 @@ function tokenRefreshIntervalMs() {
|
|
|
44278
44220
|
var COLLECTED_TURN_TIMEOUT_MS = 3e5;
|
|
44279
44221
|
var DEFAULT_IMAGE_ONLY_PROMPT = "Look at the attached image.";
|
|
44280
44222
|
var VERIFICATION_BASE_INSTRUCTIONS = [
|
|
44281
|
-
"You are a deployment verification agent.
|
|
44282
|
-
"
|
|
44283
|
-
"
|
|
44284
|
-
"
|
|
44223
|
+
"You are a deployment verification agent. Make ONLY read-only HTTP requests to the single",
|
|
44224
|
+
"environment URL given in the prompt to confirm a deploy succeeded. Do not read or write any",
|
|
44225
|
+
"files, do not use repository or credential access, do not contact any other host, and do not",
|
|
44226
|
+
"modify anything \u2014 these are rules you must follow, not limits the environment enforces. Follow",
|
|
44227
|
+
"the verification steps and end with a single VERDICT line exactly as instructed."
|
|
44285
44228
|
].join("\n");
|
|
44286
44229
|
var SELF_REVIEW_BASE_INSTRUCTIONS = [
|
|
44287
44230
|
"You are a code self-review agent. You MAY run read-only git/shell commands (e.g. `git log`,",
|
|
@@ -44292,11 +44235,14 @@ var SELF_REVIEW_BASE_INSTRUCTIONS = [
|
|
|
44292
44235
|
async function runCollectedCodexTurn(client, prompt, cwd, baseInstructions) {
|
|
44293
44236
|
const { threadId } = await acquireThread(client, {
|
|
44294
44237
|
threadId: null,
|
|
44238
|
+
// danger-full-access: collected turns (self-review reads the worktree diff; deploy
|
|
44239
|
+
// verification hits the deployed env URL over the network) run unrestricted, matching
|
|
44240
|
+
// the owner decision that the executor is not sandboxed. The turn's base instructions
|
|
44241
|
+
// (review-only / observe-only) bound what it actually does.
|
|
44295
44242
|
startParams: {
|
|
44296
44243
|
cwd,
|
|
44297
44244
|
approvalPolicy: "never",
|
|
44298
|
-
sandbox:
|
|
44299
|
-
// the executor permissions profile governs; an override would discard it
|
|
44245
|
+
sandbox: "danger-full-access",
|
|
44300
44246
|
model: null,
|
|
44301
44247
|
baseInstructions,
|
|
44302
44248
|
developerInstructions: null,
|
|
@@ -44308,14 +44254,34 @@ async function runCollectedCodexTurn(client, prompt, cwd, baseInstructions) {
|
|
|
44308
44254
|
const mapper = new CodexBridgeEventMapper();
|
|
44309
44255
|
mapper.reset();
|
|
44310
44256
|
const chunks = [];
|
|
44257
|
+
let acceptedTurnId = null;
|
|
44258
|
+
let turnError = null;
|
|
44259
|
+
let resolveTurnEnded = null;
|
|
44260
|
+
const turnEnded = new Promise((resolve) => {
|
|
44261
|
+
resolveTurnEnded = resolve;
|
|
44262
|
+
});
|
|
44311
44263
|
const unsub = client.onNotification((method, params) => {
|
|
44312
44264
|
for (const ev of mapper.mapNotification({ method, params }, threadId)) {
|
|
44313
44265
|
if (ev.type === "assistant") chunks.push(ev.content);
|
|
44266
|
+
else if (ev.type === "error") turnError = ev.content;
|
|
44267
|
+
}
|
|
44268
|
+
if (method === "turn/completed") {
|
|
44269
|
+
const p = params;
|
|
44270
|
+
const threadMatches = !p?.threadId || p.threadId === threadId;
|
|
44271
|
+
const turnMatches = !acceptedTurnId || !p?.turn?.id || p.turn.id === acceptedTurnId;
|
|
44272
|
+
if (threadMatches && turnMatches) resolveTurnEnded?.();
|
|
44314
44273
|
}
|
|
44315
44274
|
});
|
|
44316
44275
|
try {
|
|
44317
44276
|
await awaitTurnWithDeadline({
|
|
44318
|
-
run: () =>
|
|
44277
|
+
run: async () => {
|
|
44278
|
+
const accepted = await client.turn.start({
|
|
44279
|
+
threadId,
|
|
44280
|
+
input: [{ type: "text", text: prompt }]
|
|
44281
|
+
});
|
|
44282
|
+
acceptedTurnId = accepted?.turn?.id ?? null;
|
|
44283
|
+
await turnEnded;
|
|
44284
|
+
},
|
|
44319
44285
|
interrupt: () => client.turn.interrupt({ threadId }),
|
|
44320
44286
|
timeoutMs: COLLECTED_TURN_TIMEOUT_MS,
|
|
44321
44287
|
timeoutMessage: `Collected turn did not complete within ${COLLECTED_TURN_TIMEOUT_MS}ms.`
|
|
@@ -44324,6 +44290,7 @@ async function runCollectedCodexTurn(client, prompt, cwd, baseInstructions) {
|
|
|
44324
44290
|
} finally {
|
|
44325
44291
|
unsub();
|
|
44326
44292
|
}
|
|
44293
|
+
if (turnError) throw new Error(`Collected turn failed: ${turnError}`);
|
|
44327
44294
|
return chunks.join("");
|
|
44328
44295
|
}
|
|
44329
44296
|
function resolveDefaultBranch(checkoutPath) {
|
|
@@ -44362,7 +44329,7 @@ async function runOrphanWorktreeSweep(client, opts) {
|
|
|
44362
44329
|
const cutoff = Date.now() - worktreeRetentionMs();
|
|
44363
44330
|
const isReapable = (worktreePath) => {
|
|
44364
44331
|
try {
|
|
44365
|
-
return
|
|
44332
|
+
return import_node_fs10.default.statSync(worktreePath).mtimeMs < cutoff;
|
|
44366
44333
|
} catch {
|
|
44367
44334
|
return false;
|
|
44368
44335
|
}
|
|
@@ -44399,8 +44366,8 @@ async function runOrphanWorktreeSweep(client, opts) {
|
|
|
44399
44366
|
}
|
|
44400
44367
|
}
|
|
44401
44368
|
function readStateDir() {
|
|
44402
|
-
if (process.env.CODEX_HOME) return
|
|
44403
|
-
return
|
|
44369
|
+
if (process.env.CODEX_HOME) return import_node_path11.default.join(process.env.CODEX_HOME, "mrrlin", "director-bridge");
|
|
44370
|
+
return import_node_path11.default.join(import_node_os7.default.homedir(), ".mrrlin", "director-bridge");
|
|
44404
44371
|
}
|
|
44405
44372
|
function readAllowedOrigins() {
|
|
44406
44373
|
const raw = (process.env.MRRLIN_DIRECTOR_BRIDGE_ALLOWED_ORIGINS ?? "").trim();
|
|
@@ -45264,13 +45231,14 @@ async function startDirectorBridge() {
|
|
|
45264
45231
|
codexCwd: config2.codexCwd,
|
|
45265
45232
|
codexExecutable: config2.codexExecutable,
|
|
45266
45233
|
checkoutRegistry,
|
|
45267
|
-
worktreeRoot:
|
|
45268
|
-
locksDir:
|
|
45269
|
-
// Wire the
|
|
45270
|
-
//
|
|
45234
|
+
worktreeRoot: import_node_path11.default.join(config2.stateDir, "worktrees"),
|
|
45235
|
+
locksDir: import_node_path11.default.join(config2.stateDir, "locks"),
|
|
45236
|
+
// Wire the executor server for code-execution runs. Each run gets its own app-server
|
|
45237
|
+
// process at the run worktree, running UNRESTRICTED from the real ~/.codex (owner
|
|
45238
|
+
// no-sandbox decision — auth + mrrlin MCP come from the operator config).
|
|
45271
45239
|
// The returned handle's dispose() shuts down the spawned app-server CHILD (manager.shutdown(),
|
|
45272
|
-
// not the JSON-RPC-only client.close())
|
|
45273
|
-
//
|
|
45240
|
+
// not the JSON-RPC-only client.close()) — releasing the executor therefore kills the process.
|
|
45241
|
+
// driveRun owns this dispose per-run (Fix A + G).
|
|
45274
45242
|
acquireExecutorCodex: async (worktreePath) => {
|
|
45275
45243
|
const handle = await startExecutorServer({ worktree: worktreePath });
|
|
45276
45244
|
return { client: handle.client, dispose: handle.dispose };
|
|
@@ -45281,15 +45249,15 @@ async function startDirectorBridge() {
|
|
|
45281
45249
|
// fail. If the resolved branch does not exist on origin, createRunWorktree surfaces a
|
|
45282
45250
|
// `default_branch_unresolved` error which the consumer routes to a clean operator handoff.
|
|
45283
45251
|
getDefaultBranch: (projectSlug) => Promise.resolve(resolveDefaultBranch(checkoutRegistry.get(projectSlug)?.path ?? null)),
|
|
45284
|
-
// ADR 0007 self-review: critique the committed diff on the executor's own
|
|
45252
|
+
// ADR 0007 self-review: critique the committed diff on the executor's own client before
|
|
45285
45253
|
// push/PR. Reuses the verification turn-runner (acquireThread + collect assistant text).
|
|
45286
45254
|
selfReviewTurn: createSelfReviewTurn({
|
|
45287
45255
|
runTurn: (codexClient, cwd, prompt) => runCollectedCodexTurn(codexClient, prompt, cwd, SELF_REVIEW_BASE_INSTRUCTIONS)
|
|
45288
45256
|
}),
|
|
45289
45257
|
// 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
|
-
//
|
|
45258
|
+
// dispatches the deploy + polls + runs a verification turn against the deployed env URL in a
|
|
45259
|
+
// throwaway cwd. Per the owner no-sandbox decision the verification turn runs from the real
|
|
45260
|
+
// ~/.codex like every other executor turn; its observe-only base instructions bound behaviour.
|
|
45293
45261
|
deployGate: {
|
|
45294
45262
|
loadVerificationSection: async (projectSlug, task) => {
|
|
45295
45263
|
if (!task.specWikiPageId) return null;
|
|
@@ -45297,14 +45265,16 @@ async function startDirectorBridge() {
|
|
|
45297
45265
|
return page?.markdownBody ? extractVerificationSection(page.markdownBody) : null;
|
|
45298
45266
|
},
|
|
45299
45267
|
runVerificationTurn: createRunVerificationTurn({
|
|
45300
|
-
|
|
45301
|
-
|
|
45268
|
+
// egressDomains is retained in the seam signature (verification-turn.ts still computes the
|
|
45269
|
+
// env host) but no longer constrains anything — the executor is unrestricted.
|
|
45270
|
+
startSandbox: async (_egressDomains) => {
|
|
45271
|
+
const cwd = import_node_fs10.default.mkdtempSync(import_node_path11.default.join(import_node_os7.default.tmpdir(), "mrrlin-verify-"));
|
|
45302
45272
|
let handle;
|
|
45303
45273
|
try {
|
|
45304
|
-
handle = await startExecutorServer({ worktree: cwd
|
|
45274
|
+
handle = await startExecutorServer({ worktree: cwd });
|
|
45305
45275
|
} catch (error51) {
|
|
45306
45276
|
try {
|
|
45307
|
-
|
|
45277
|
+
import_node_fs10.default.rmSync(cwd, { recursive: true, force: true });
|
|
45308
45278
|
} catch {
|
|
45309
45279
|
}
|
|
45310
45280
|
throw error51;
|
|
@@ -45315,7 +45285,7 @@ async function startDirectorBridge() {
|
|
|
45315
45285
|
dispose: () => {
|
|
45316
45286
|
handle.dispose();
|
|
45317
45287
|
try {
|
|
45318
|
-
|
|
45288
|
+
import_node_fs10.default.rmSync(cwd, { recursive: true, force: true });
|
|
45319
45289
|
} catch {
|
|
45320
45290
|
}
|
|
45321
45291
|
}
|
|
@@ -45455,7 +45425,7 @@ async function startDirectorBridge() {
|
|
|
45455
45425
|
const bridgeLogger = createBridgeLogger(config2.stateDir, process.env);
|
|
45456
45426
|
let bridgeBinShaShort = "unknown00000";
|
|
45457
45427
|
try {
|
|
45458
|
-
bridgeBinShaShort = import_node_crypto5.default.createHash("sha256").update(
|
|
45428
|
+
bridgeBinShaShort = import_node_crypto5.default.createHash("sha256").update(import_node_fs10.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
|
|
45459
45429
|
} catch {
|
|
45460
45430
|
}
|
|
45461
45431
|
attachBridgeWss(server, {
|
|
@@ -45564,8 +45534,8 @@ async function startDirectorBridge() {
|
|
|
45564
45534
|
enqueueRun(
|
|
45565
45535
|
() => runOrphanWorktreeSweep(client, {
|
|
45566
45536
|
checkoutRegistry,
|
|
45567
|
-
worktreeRoot:
|
|
45568
|
-
locksDir:
|
|
45537
|
+
worktreeRoot: import_node_path11.default.join(config2.stateDir, "worktrees"),
|
|
45538
|
+
locksDir: import_node_path11.default.join(config2.stateDir, "locks")
|
|
45569
45539
|
})
|
|
45570
45540
|
);
|
|
45571
45541
|
enqueueRun(async () => {
|
|
@@ -45777,15 +45747,15 @@ function readDispatchBody(req) {
|
|
|
45777
45747
|
function readOrCreateBridgeToken(stateDir) {
|
|
45778
45748
|
const explicit = (process.env.MRRLIN_DIRECTOR_BRIDGE_TOKEN ?? "").trim();
|
|
45779
45749
|
if (explicit) return explicit;
|
|
45780
|
-
const tokenPath =
|
|
45750
|
+
const tokenPath = import_node_path11.default.join(stateDir, "token.txt");
|
|
45781
45751
|
try {
|
|
45782
|
-
const existing =
|
|
45752
|
+
const existing = import_node_fs10.default.readFileSync(tokenPath, "utf8").trim();
|
|
45783
45753
|
if (existing) return existing;
|
|
45784
45754
|
} catch {
|
|
45785
45755
|
}
|
|
45786
|
-
|
|
45756
|
+
import_node_fs10.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
|
|
45787
45757
|
const token = import_node_crypto5.default.randomBytes(32).toString("base64url");
|
|
45788
|
-
|
|
45758
|
+
import_node_fs10.default.writeFileSync(tokenPath, `${token}
|
|
45789
45759
|
`, { mode: 384 });
|
|
45790
45760
|
return token;
|
|
45791
45761
|
}
|
|
@@ -49169,17 +49139,17 @@ var StdioServerTransport = class {
|
|
|
49169
49139
|
// src/tools.ts
|
|
49170
49140
|
var import_node_crypto8 = require("node:crypto");
|
|
49171
49141
|
var import_promises3 = require("node:fs/promises");
|
|
49172
|
-
var
|
|
49173
|
-
var
|
|
49174
|
-
var
|
|
49142
|
+
var import_node_fs12 = require("node:fs");
|
|
49143
|
+
var import_node_path14 = __toESM(require("node:path"), 1);
|
|
49144
|
+
var import_node_os8 = __toESM(require("node:os"), 1);
|
|
49175
49145
|
var import_node_child_process7 = require("node:child_process");
|
|
49176
49146
|
|
|
49177
49147
|
// ../../packages/wiki/dist/index.js
|
|
49178
49148
|
var import_promises2 = __toESM(require("node:fs/promises"), 1);
|
|
49179
|
-
var
|
|
49149
|
+
var import_node_path12 = __toESM(require("node:path"), 1);
|
|
49180
49150
|
var INCLUDED_DOC_FOLDERS = /* @__PURE__ */ new Set(["_meta", "explanation", "how-to", "reference", "sdd", "tutorials"]);
|
|
49181
49151
|
function toPosixPath(input) {
|
|
49182
|
-
return input.split(
|
|
49152
|
+
return input.split(import_node_path12.default.sep).join("/");
|
|
49183
49153
|
}
|
|
49184
49154
|
function slugifyWikiSegment(input) {
|
|
49185
49155
|
return input.trim().toLowerCase().replace(/`/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -49193,12 +49163,12 @@ async function pathExists2(input) {
|
|
|
49193
49163
|
}
|
|
49194
49164
|
}
|
|
49195
49165
|
async function findWorkspaceRoot(start = process.cwd()) {
|
|
49196
|
-
let current =
|
|
49166
|
+
let current = import_node_path12.default.resolve(start);
|
|
49197
49167
|
while (true) {
|
|
49198
|
-
if (await pathExists2(
|
|
49168
|
+
if (await pathExists2(import_node_path12.default.join(current, "pnpm-workspace.yaml")) && await pathExists2(import_node_path12.default.join(current, "docs"))) {
|
|
49199
49169
|
return current;
|
|
49200
49170
|
}
|
|
49201
|
-
const parent =
|
|
49171
|
+
const parent = import_node_path12.default.dirname(current);
|
|
49202
49172
|
if (parent === current) {
|
|
49203
49173
|
throw new Error(`Unable to find Mrrlin workspace root from ${start}`);
|
|
49204
49174
|
}
|
|
@@ -49207,28 +49177,28 @@ async function findWorkspaceRoot(start = process.cwd()) {
|
|
|
49207
49177
|
}
|
|
49208
49178
|
async function resolveDocsRoot(input) {
|
|
49209
49179
|
if (input) {
|
|
49210
|
-
return
|
|
49180
|
+
return import_node_path12.default.resolve(input);
|
|
49211
49181
|
}
|
|
49212
49182
|
if (process.env.MRRLIN_DOCS_ROOT) {
|
|
49213
|
-
return
|
|
49183
|
+
return import_node_path12.default.resolve(process.env.MRRLIN_DOCS_ROOT);
|
|
49214
49184
|
}
|
|
49215
|
-
return
|
|
49185
|
+
return import_node_path12.default.join(await findWorkspaceRoot(), "docs");
|
|
49216
49186
|
}
|
|
49217
49187
|
async function resolveIndexPath(input) {
|
|
49218
49188
|
if (input) {
|
|
49219
|
-
return
|
|
49189
|
+
return import_node_path12.default.resolve(input);
|
|
49220
49190
|
}
|
|
49221
49191
|
if (process.env.MRRLIN_WIKI_INDEX_PATH) {
|
|
49222
|
-
return
|
|
49192
|
+
return import_node_path12.default.resolve(process.env.MRRLIN_WIKI_INDEX_PATH);
|
|
49223
49193
|
}
|
|
49224
49194
|
const workspaceRoot = await findWorkspaceRoot();
|
|
49225
|
-
return
|
|
49195
|
+
return import_node_path12.default.join(workspaceRoot, "apps", "web", "public", "wiki-index.json");
|
|
49226
49196
|
}
|
|
49227
49197
|
async function walkMarkdownFiles(root, dir = root) {
|
|
49228
49198
|
const entries = await import_promises2.default.readdir(dir, { withFileTypes: true });
|
|
49229
49199
|
const files = [];
|
|
49230
49200
|
for (const entry of entries) {
|
|
49231
|
-
const absolute =
|
|
49201
|
+
const absolute = import_node_path12.default.join(dir, entry.name);
|
|
49232
49202
|
if (entry.isDirectory()) {
|
|
49233
49203
|
files.push(...await walkMarkdownFiles(root, absolute));
|
|
49234
49204
|
continue;
|
|
@@ -49247,7 +49217,7 @@ function parseTitle(markdown, sourcePath) {
|
|
|
49247
49217
|
return title;
|
|
49248
49218
|
}
|
|
49249
49219
|
function documentFromFile(docsRoot, absolutePath, markdown) {
|
|
49250
|
-
const relativePath = toPosixPath(
|
|
49220
|
+
const relativePath = toPosixPath(import_node_path12.default.relative(docsRoot, absolutePath));
|
|
49251
49221
|
const [section, fileName] = relativePath.split("/");
|
|
49252
49222
|
if (!section || !fileName || !INCLUDED_DOC_FOLDERS.has(section)) {
|
|
49253
49223
|
return null;
|
|
@@ -49801,8 +49771,8 @@ function errMessage(err) {
|
|
|
49801
49771
|
}
|
|
49802
49772
|
|
|
49803
49773
|
// src/consensus/wiring.ts
|
|
49804
|
-
var
|
|
49805
|
-
var
|
|
49774
|
+
var import_node_fs11 = __toESM(require("node:fs"), 1);
|
|
49775
|
+
var import_node_path13 = __toESM(require("node:path"), 1);
|
|
49806
49776
|
var import_node_url2 = require("node:url");
|
|
49807
49777
|
|
|
49808
49778
|
// src/consensus/code-gate-git.ts
|
|
@@ -50037,15 +50007,15 @@ ${res.stdout}${res.stderr}`);
|
|
|
50037
50007
|
var import_meta2 = {};
|
|
50038
50008
|
function getPersonasDir() {
|
|
50039
50009
|
if (typeof __dirname !== "undefined") {
|
|
50040
|
-
return
|
|
50010
|
+
return import_node_path13.default.join(__dirname, "consensus", "personas");
|
|
50041
50011
|
}
|
|
50042
|
-
return
|
|
50012
|
+
return import_node_path13.default.join(import_node_path13.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "personas");
|
|
50043
50013
|
}
|
|
50044
50014
|
var personaCache = /* @__PURE__ */ new Map();
|
|
50045
50015
|
function loadPersona(name) {
|
|
50046
50016
|
const cached2 = personaCache.get(name);
|
|
50047
50017
|
if (cached2 !== void 0) return cached2;
|
|
50048
|
-
const content =
|
|
50018
|
+
const content = import_node_fs11.default.readFileSync(import_node_path13.default.join(getPersonasDir(), `${name}.md`), "utf8");
|
|
50049
50019
|
personaCache.set(name, content);
|
|
50050
50020
|
return content;
|
|
50051
50021
|
}
|
|
@@ -51905,7 +51875,7 @@ function createMrrlinTools(options) {
|
|
|
51905
51875
|
"ARTIFACT_FILE_UPLOAD_FAILED",
|
|
51906
51876
|
"Unable to upload artifact file.",
|
|
51907
51877
|
async (c, { projectSlug, path: filePath, class: artifactClass, taskId, runId, description }) => {
|
|
51908
|
-
const extension2 =
|
|
51878
|
+
const extension2 = import_node_path14.default.extname(filePath).toLowerCase();
|
|
51909
51879
|
const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
|
|
51910
51880
|
if (!contentType) {
|
|
51911
51881
|
throw new McpToolCodedError(
|
|
@@ -51933,7 +51903,7 @@ function createMrrlinTools(options) {
|
|
|
51933
51903
|
"Artifact exceeds 5MB; split or summarize instead."
|
|
51934
51904
|
);
|
|
51935
51905
|
}
|
|
51936
|
-
const filename =
|
|
51906
|
+
const filename = import_node_path14.default.basename(filePath);
|
|
51937
51907
|
const created = await c.createArtifactFile(projectSlug, {
|
|
51938
51908
|
class: artifactClass,
|
|
51939
51909
|
contentType,
|
|
@@ -52016,7 +51986,7 @@ function createMrrlinTools(options) {
|
|
|
52016
51986
|
"Unable to register local checkout.",
|
|
52017
51987
|
async (_c, { projectSlug, path: checkoutPath, repo }) => {
|
|
52018
51988
|
const trimmedPath = checkoutPath.trim();
|
|
52019
|
-
if (!
|
|
51989
|
+
if (!import_node_path14.default.isAbsolute(trimmedPath)) {
|
|
52020
51990
|
throw new McpToolCodedError(
|
|
52021
51991
|
"LOCAL_CHECKOUT_PATH_NOT_ABSOLUTE",
|
|
52022
51992
|
`Path must be absolute, got: ${trimmedPath}`
|
|
@@ -52024,7 +51994,7 @@ function createMrrlinTools(options) {
|
|
|
52024
51994
|
}
|
|
52025
51995
|
let resolvedPath;
|
|
52026
51996
|
try {
|
|
52027
|
-
resolvedPath = (0,
|
|
51997
|
+
resolvedPath = (0, import_node_fs12.realpathSync)(trimmedPath);
|
|
52028
51998
|
} catch {
|
|
52029
51999
|
throw new McpToolCodedError(
|
|
52030
52000
|
"LOCAL_CHECKOUT_PATH_NOT_FOUND",
|
|
@@ -52051,7 +52021,7 @@ function createMrrlinTools(options) {
|
|
|
52051
52021
|
`Origin remote ${remoteUrl} does not match repo ${repo}.`
|
|
52052
52022
|
);
|
|
52053
52023
|
}
|
|
52054
|
-
const stateDir = process.env.CODEX_HOME ?
|
|
52024
|
+
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
52025
|
const registry3 = new CheckoutRegistry(stateDir);
|
|
52056
52026
|
const confirmedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
52057
52027
|
registry3.confirm(projectSlug, resolvedPath, confirmedAt);
|
|
@@ -52258,13 +52228,13 @@ function runSetCredential(args) {
|
|
|
52258
52228
|
}
|
|
52259
52229
|
|
|
52260
52230
|
// src/install-service.ts
|
|
52261
|
-
var
|
|
52262
|
-
var
|
|
52231
|
+
var import_node_os9 = __toESM(require("node:os"), 1);
|
|
52232
|
+
var import_node_path16 = __toESM(require("node:path"), 1);
|
|
52263
52233
|
|
|
52264
52234
|
// src/service-paths.ts
|
|
52265
|
-
var
|
|
52235
|
+
var import_node_path15 = __toESM(require("node:path"), 1);
|
|
52266
52236
|
function isWorktreePath(p) {
|
|
52267
|
-
const norm =
|
|
52237
|
+
const norm = import_node_path15.default.normalize(p).split(import_node_path15.default.sep).join("/");
|
|
52268
52238
|
return norm.includes("/.claude/worktrees/");
|
|
52269
52239
|
}
|
|
52270
52240
|
function resolveServiceCwd(opts) {
|
|
@@ -52318,7 +52288,7 @@ function installService(deps) {
|
|
|
52318
52288
|
deps.log(resolved.reason);
|
|
52319
52289
|
return { ok: false };
|
|
52320
52290
|
}
|
|
52321
|
-
const home = deps.env.HOME ??
|
|
52291
|
+
const home = deps.env.HOME ?? import_node_os9.default.homedir();
|
|
52322
52292
|
const bins = ["node", "codex", "mrrlin-mcp"].map((b) => deps.which(b));
|
|
52323
52293
|
if (bins.some((b) => !b)) {
|
|
52324
52294
|
deps.log("Could not resolve absolute paths for node/codex/mrrlin-mcp on PATH. Install them or fix PATH.");
|
|
@@ -52329,7 +52299,7 @@ function installService(deps) {
|
|
|
52329
52299
|
return { ok: false };
|
|
52330
52300
|
}
|
|
52331
52301
|
const resolvedBins = bins.filter((b) => b !== null);
|
|
52332
|
-
const pathEnv = Array.from(new Set(resolvedBins.map((b) =>
|
|
52302
|
+
const pathEnv = Array.from(new Set(resolvedBins.map((b) => import_node_path16.default.dirname(b)))).join(":");
|
|
52333
52303
|
const text = renderEcosystemConfig({
|
|
52334
52304
|
cwd: resolved.cwd,
|
|
52335
52305
|
home,
|
|
@@ -52338,7 +52308,7 @@ function installService(deps) {
|
|
|
52338
52308
|
staging: deps.env.MRRLIN_STAGING === "1",
|
|
52339
52309
|
apiBaseUrl: deps.env.MRRLIN_API_BASE_URL?.trim() || void 0
|
|
52340
52310
|
});
|
|
52341
|
-
const ecoPath =
|
|
52311
|
+
const ecoPath = import_node_path16.default.join(home, ".mrrlin", "ecosystem.config.cjs");
|
|
52342
52312
|
deps.writeFile(ecoPath, text);
|
|
52343
52313
|
const start = deps.runPm2(["startOrReload", ecoPath]);
|
|
52344
52314
|
if (start.code !== 0) {
|
|
@@ -52369,13 +52339,13 @@ function uninstallService(deps) {
|
|
|
52369
52339
|
|
|
52370
52340
|
// src/uninstall-codex.ts
|
|
52371
52341
|
var import_promises4 = __toESM(require("node:fs/promises"), 1);
|
|
52372
|
-
var
|
|
52373
|
-
var
|
|
52342
|
+
var import_node_os10 = __toESM(require("node:os"), 1);
|
|
52343
|
+
var import_node_path17 = __toESM(require("node:path"), 1);
|
|
52374
52344
|
var toml2 = __toESM(require_toml(), 1);
|
|
52375
52345
|
function resolveCodexHome2(options) {
|
|
52376
52346
|
if (options.codexHome) return options.codexHome;
|
|
52377
52347
|
if (process.env.CODEX_HOME) return process.env.CODEX_HOME;
|
|
52378
|
-
return
|
|
52348
|
+
return import_node_path17.default.join(options.homeDir ?? import_node_os10.default.homedir(), ".codex");
|
|
52379
52349
|
}
|
|
52380
52350
|
async function pathExists3(target) {
|
|
52381
52351
|
try {
|
|
@@ -52388,7 +52358,7 @@ async function pathExists3(target) {
|
|
|
52388
52358
|
var MRRLIN_BLOCK_RE = /(^|\n)\[mcp_servers\.mrrlin(?:-browser)?(?:\]|\.[^\]\n]*\])[\s\S]*?(?=\n\[|$)/g;
|
|
52389
52359
|
async function uninstallCodex(options = {}) {
|
|
52390
52360
|
const codexHome = resolveCodexHome2(options);
|
|
52391
|
-
const configPath =
|
|
52361
|
+
const configPath = import_node_path17.default.join(codexHome, "config.toml");
|
|
52392
52362
|
const removePrompts = async () => uninstallPrompts(codexHome, options.promptNames ?? []);
|
|
52393
52363
|
if (!await pathExists3(configPath)) {
|
|
52394
52364
|
return { action: "missing", configPath, prompts: await removePrompts() };
|
|
@@ -52416,10 +52386,10 @@ async function uninstallCodex(options = {}) {
|
|
|
52416
52386
|
}
|
|
52417
52387
|
async function uninstallPrompts(codexHome, names) {
|
|
52418
52388
|
if (names.length === 0) return [];
|
|
52419
|
-
const promptsDir2 =
|
|
52389
|
+
const promptsDir2 = import_node_path17.default.join(codexHome, "prompts");
|
|
52420
52390
|
const out = [];
|
|
52421
52391
|
for (const name of names) {
|
|
52422
|
-
const promptPath =
|
|
52392
|
+
const promptPath = import_node_path17.default.join(promptsDir2, `${name}.md`);
|
|
52423
52393
|
try {
|
|
52424
52394
|
await import_promises4.default.unlink(promptPath);
|
|
52425
52395
|
out.push({ name, action: "removed", promptPath });
|
|
@@ -52436,16 +52406,16 @@ async function uninstallPrompts(codexHome, names) {
|
|
|
52436
52406
|
}
|
|
52437
52407
|
|
|
52438
52408
|
// src/report-issue-prompt.ts
|
|
52439
|
-
var
|
|
52440
|
-
var
|
|
52409
|
+
var import_node_fs13 = __toESM(require("node:fs"), 1);
|
|
52410
|
+
var import_node_path18 = __toESM(require("node:path"), 1);
|
|
52441
52411
|
var import_node_url3 = require("node:url");
|
|
52442
52412
|
var import_meta3 = {};
|
|
52443
52413
|
function promptsDir() {
|
|
52444
|
-
if (typeof __dirname !== "undefined") return
|
|
52445
|
-
return
|
|
52414
|
+
if (typeof __dirname !== "undefined") return import_node_path18.default.join(__dirname, "prompts");
|
|
52415
|
+
return import_node_path18.default.join(import_node_path18.default.dirname((0, import_node_url3.fileURLToPath)(import_meta3.url)), "prompts");
|
|
52446
52416
|
}
|
|
52447
52417
|
function readReportIssuePrompt() {
|
|
52448
|
-
return
|
|
52418
|
+
return import_node_fs13.default.readFileSync(import_node_path18.default.join(promptsDir(), "report-issue.md"), "utf8");
|
|
52449
52419
|
}
|
|
52450
52420
|
|
|
52451
52421
|
// src/bin.ts
|
|
@@ -52705,8 +52675,8 @@ async function main() {
|
|
|
52705
52675
|
env: process.env,
|
|
52706
52676
|
cwd: process.cwd(),
|
|
52707
52677
|
writeFile: (p, c) => {
|
|
52708
|
-
(0,
|
|
52709
|
-
(0,
|
|
52678
|
+
(0, import_node_fs14.mkdirSync)(import_node_path20.default.dirname(p), { recursive: true, mode: 448 });
|
|
52679
|
+
(0, import_node_fs14.writeFileSync)(p, c, { mode: 384 });
|
|
52710
52680
|
},
|
|
52711
52681
|
runPm2: pm2Runner,
|
|
52712
52682
|
which: whichBin,
|
|
@@ -52723,35 +52693,35 @@ async function main() {
|
|
|
52723
52693
|
runPm2: (a) => ({ code: pm2Runner(a).code }),
|
|
52724
52694
|
removeFile: (p) => {
|
|
52725
52695
|
try {
|
|
52726
|
-
(0,
|
|
52696
|
+
(0, import_node_fs14.rmSync)(p, { force: true });
|
|
52727
52697
|
} catch {
|
|
52728
52698
|
}
|
|
52729
52699
|
},
|
|
52730
52700
|
purgeSecret: purge,
|
|
52731
52701
|
secretPath: agentCredentialPath(),
|
|
52732
52702
|
tokenPath: operatorTokenPath(),
|
|
52733
|
-
ecoPath:
|
|
52703
|
+
ecoPath: import_node_path20.default.join(process.env.HOME ?? (0, import_node_os11.homedir)(), ".mrrlin", "ecosystem.config.cjs"),
|
|
52734
52704
|
log: (m) => process.stderr.write(`[mrrlin-mcp uninstall-service] ${m}
|
|
52735
52705
|
`)
|
|
52736
52706
|
});
|
|
52737
52707
|
return;
|
|
52738
52708
|
}
|
|
52739
52709
|
case "uninstall": {
|
|
52740
|
-
const home = process.env.HOME ?? (0,
|
|
52710
|
+
const home = process.env.HOME ?? (0, import_node_os11.homedir)();
|
|
52741
52711
|
const log = (m) => process.stderr.write(`[mrrlin-mcp uninstall] ${m}
|
|
52742
52712
|
`);
|
|
52743
52713
|
uninstallService({
|
|
52744
52714
|
runPm2: (a) => ({ code: pm2Runner(a).code }),
|
|
52745
52715
|
removeFile: (p) => {
|
|
52746
52716
|
try {
|
|
52747
|
-
(0,
|
|
52717
|
+
(0, import_node_fs14.rmSync)(p, { force: true });
|
|
52748
52718
|
} catch {
|
|
52749
52719
|
}
|
|
52750
52720
|
},
|
|
52751
52721
|
purgeSecret: true,
|
|
52752
52722
|
secretPath: agentCredentialPath(),
|
|
52753
52723
|
tokenPath: operatorTokenPath(),
|
|
52754
|
-
ecoPath:
|
|
52724
|
+
ecoPath: import_node_path20.default.join(home, ".mrrlin", "ecosystem.config.cjs"),
|
|
52755
52725
|
log
|
|
52756
52726
|
});
|
|
52757
52727
|
let codexOk = true;
|
|
@@ -52771,7 +52741,7 @@ async function main() {
|
|
|
52771
52741
|
log(`codex config NOT modified: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
52772
52742
|
}
|
|
52773
52743
|
try {
|
|
52774
|
-
(0,
|
|
52744
|
+
(0, import_node_fs14.rmSync)(import_node_path20.default.join(home, ".mrrlin"), { recursive: true, force: true });
|
|
52775
52745
|
} catch {
|
|
52776
52746
|
}
|
|
52777
52747
|
log("removed ~/.mrrlin");
|
|
@@ -52812,7 +52782,7 @@ ${HELP_TEXT}`);
|
|
|
52812
52782
|
}
|
|
52813
52783
|
}
|
|
52814
52784
|
function resolveSelfBinPath() {
|
|
52815
|
-
return
|
|
52785
|
+
return import_node_path19.default.resolve(process.argv[1] ?? process.execPath);
|
|
52816
52786
|
}
|
|
52817
52787
|
main().catch((error51) => {
|
|
52818
52788
|
process.stderr.write(`mrrlin-mcp fatal error: ${error51 instanceof Error ? error51.message : String(error51)}
|