@mrrlin-dev/mcp 0.4.139 → 0.4.142
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 +132 -40
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -43704,7 +43704,8 @@ var CodexServerManager = class {
|
|
|
43704
43704
|
thread: {
|
|
43705
43705
|
start: (params) => rpcClient.request("thread/start", params),
|
|
43706
43706
|
resume: (params) => rpcClient.request("thread/resume", params),
|
|
43707
|
-
read: (params) => rpcClient.request("thread/read", params)
|
|
43707
|
+
read: (params) => rpcClient.request("thread/read", params),
|
|
43708
|
+
loadedList: (params) => rpcClient.request("thread/loaded/list", params)
|
|
43708
43709
|
},
|
|
43709
43710
|
turn: {
|
|
43710
43711
|
start: (params) => rpcClient.request("turn/start", params),
|
|
@@ -43771,6 +43772,28 @@ function addTurnTokenUsage(total, turn) {
|
|
|
43771
43772
|
outputTokens: add2(total.outputTokens, turn.outputTokens)
|
|
43772
43773
|
};
|
|
43773
43774
|
}
|
|
43775
|
+
var CONTEXT_WINDOW_TOKENS = 2e5;
|
|
43776
|
+
function extractContextWindow(method, params) {
|
|
43777
|
+
if (method !== TOKEN_USAGE_NOTIFICATION_METHOD)
|
|
43778
|
+
return null;
|
|
43779
|
+
if (params === null || typeof params !== "object")
|
|
43780
|
+
return null;
|
|
43781
|
+
const usage = params.tokenUsage;
|
|
43782
|
+
if (usage === null || typeof usage !== "object")
|
|
43783
|
+
return null;
|
|
43784
|
+
const window = readCount(usage, "modelContextWindow");
|
|
43785
|
+
return window !== null && window > 0 ? window : null;
|
|
43786
|
+
}
|
|
43787
|
+
function isNearContextLimit(usage, contextWindow) {
|
|
43788
|
+
if (!usage)
|
|
43789
|
+
return false;
|
|
43790
|
+
const contextTokens = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
|
|
43791
|
+
if (contextTokens <= 0)
|
|
43792
|
+
return false;
|
|
43793
|
+
const window = contextWindow && contextWindow > 0 ? contextWindow : CONTEXT_WINDOW_TOKENS;
|
|
43794
|
+
const remainingTokens = window - contextTokens;
|
|
43795
|
+
return remainingTokens / window < 0.03 || remainingTokens < 4e3;
|
|
43796
|
+
}
|
|
43774
43797
|
|
|
43775
43798
|
// ../../packages/agent-client/dist/providers/codex/event-mapper.js
|
|
43776
43799
|
var CodexBridgeEventMapper = class {
|
|
@@ -43937,7 +43960,8 @@ var CodexBridgeEventMapper = class {
|
|
|
43937
43960
|
const usage = extractTurnTokenUsage(TOKEN_USAGE_NOTIFICATION_METHOD, notification.params);
|
|
43938
43961
|
if (!usage)
|
|
43939
43962
|
return [];
|
|
43940
|
-
|
|
43963
|
+
const contextWindow = extractContextWindow(TOKEN_USAGE_NOTIFICATION_METHOD, notification.params);
|
|
43964
|
+
return [contextWindow === null ? { type: "token_usage", usage } : { type: "token_usage", usage, contextWindow }];
|
|
43941
43965
|
}
|
|
43942
43966
|
/** Bare `error` notifications carry model-stream failures ({ error: { message }, willRetry }).
|
|
43943
43967
|
* Retryable ones (willRetry=true) are transport noise — codex is still driving the turn — so
|
|
@@ -44339,12 +44363,57 @@ var CodexProviderAdapter = class {
|
|
|
44339
44363
|
function createCodexAgentHandle(client) {
|
|
44340
44364
|
return new CodexAgentHandle(client);
|
|
44341
44365
|
}
|
|
44366
|
+
var MRRLIN_MCP_SERVER = "mrrlin";
|
|
44367
|
+
function codexThreadConfig(env) {
|
|
44368
|
+
if (!env)
|
|
44369
|
+
return null;
|
|
44370
|
+
const config2 = {};
|
|
44371
|
+
for (const [key, value] of Object.entries(env)) {
|
|
44372
|
+
if (!ENV_NAME.test(key))
|
|
44373
|
+
continue;
|
|
44374
|
+
config2[`mcp_servers.${MRRLIN_MCP_SERVER}.env.${key}`] = value ?? "";
|
|
44375
|
+
}
|
|
44376
|
+
return Object.keys(config2).length > 0 ? config2 : null;
|
|
44377
|
+
}
|
|
44378
|
+
var ENV_NAME = /^[A-Z_][A-Z0-9_]*$/;
|
|
44379
|
+
var loadedThreadConfig = /* @__PURE__ */ new WeakMap();
|
|
44380
|
+
function threadConfigsOf(client) {
|
|
44381
|
+
let configs = loadedThreadConfig.get(client);
|
|
44382
|
+
if (!configs) {
|
|
44383
|
+
configs = /* @__PURE__ */ new Map();
|
|
44384
|
+
loadedThreadConfig.set(client, configs);
|
|
44385
|
+
}
|
|
44386
|
+
return configs;
|
|
44387
|
+
}
|
|
44388
|
+
function configSignature(config2) {
|
|
44389
|
+
return JSON.stringify(Object.entries(config2 ?? {}).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
|
|
44390
|
+
}
|
|
44391
|
+
var resumeQueues = /* @__PURE__ */ new WeakMap();
|
|
44392
|
+
function serializePerThread(client, threadId, work) {
|
|
44393
|
+
let queues = resumeQueues.get(client);
|
|
44394
|
+
if (!queues) {
|
|
44395
|
+
queues = /* @__PURE__ */ new Map();
|
|
44396
|
+
resumeQueues.set(client, queues);
|
|
44397
|
+
}
|
|
44398
|
+
const previous = queues.get(threadId) ?? Promise.resolve();
|
|
44399
|
+
const run3 = previous.then(work, work);
|
|
44400
|
+
const settled = run3.then(() => {
|
|
44401
|
+
}, () => {
|
|
44402
|
+
});
|
|
44403
|
+
queues.set(threadId, settled);
|
|
44404
|
+
void settled.then(() => {
|
|
44405
|
+
if (queues.get(threadId) === settled)
|
|
44406
|
+
queues.delete(threadId);
|
|
44407
|
+
});
|
|
44408
|
+
return run3;
|
|
44409
|
+
}
|
|
44342
44410
|
var CodexAgentHandle = class {
|
|
44343
44411
|
client;
|
|
44344
44412
|
constructor(client) {
|
|
44345
44413
|
this.client = client;
|
|
44346
44414
|
}
|
|
44347
44415
|
async startThread(params) {
|
|
44416
|
+
const config2 = codexThreadConfig(params.env);
|
|
44348
44417
|
const started = await this.client.thread.start({
|
|
44349
44418
|
model: params.model ?? null,
|
|
44350
44419
|
cwd: params.cwd ?? null,
|
|
@@ -44353,21 +44422,59 @@ var CodexAgentHandle = class {
|
|
|
44353
44422
|
baseInstructions: params.baseInstructions ?? null,
|
|
44354
44423
|
developerInstructions: params.developerInstructions ?? null,
|
|
44355
44424
|
ephemeral: params.ephemeral ?? null,
|
|
44356
|
-
mcpConfig: params.mcpConfig ?? null
|
|
44425
|
+
mcpConfig: params.mcpConfig ?? null,
|
|
44426
|
+
config: config2
|
|
44357
44427
|
});
|
|
44428
|
+
threadConfigsOf(this.client).set(started.thread.id, configSignature(config2));
|
|
44358
44429
|
return { threadId: started.thread.id };
|
|
44359
44430
|
}
|
|
44360
|
-
|
|
44431
|
+
resumeThread(threadId, params) {
|
|
44432
|
+
return serializePerThread(this.client, threadId, () => this.resumeNow(threadId, params));
|
|
44433
|
+
}
|
|
44434
|
+
async resumeNow(threadId, params) {
|
|
44435
|
+
const config2 = codexThreadConfig(params.env);
|
|
44436
|
+
const signature = configSignature(config2);
|
|
44437
|
+
const configs = threadConfigsOf(this.client);
|
|
44438
|
+
const loadedWith = configs.get(threadId);
|
|
44439
|
+
if (loadedWith !== void 0 && loadedWith !== signature) {
|
|
44440
|
+
configs.delete(threadId);
|
|
44441
|
+
throw new Error("codex: thread binding changed; start a fresh thread");
|
|
44442
|
+
}
|
|
44443
|
+
if (loadedWith === void 0 && await this.isLoaded(threadId)) {
|
|
44444
|
+
throw new Error("codex: thread is loaded with an unknown binding; start a fresh thread");
|
|
44445
|
+
}
|
|
44361
44446
|
const resumed = await this.client.thread.resume({
|
|
44362
44447
|
threadId,
|
|
44363
44448
|
model: params.model ?? null,
|
|
44364
44449
|
cwd: params.cwd ?? null,
|
|
44365
44450
|
approvalPolicy: params.approvalPolicy ?? null,
|
|
44366
44451
|
sandbox: params.sandbox ?? null,
|
|
44367
|
-
mcpConfig: params.mcpConfig ?? null
|
|
44452
|
+
mcpConfig: params.mcpConfig ?? null,
|
|
44453
|
+
config: config2
|
|
44368
44454
|
});
|
|
44455
|
+
configs.set(resumed.thread.id, signature);
|
|
44369
44456
|
return { threadId: resumed.thread.id };
|
|
44370
44457
|
}
|
|
44458
|
+
/** Whether this app-server currently holds the thread. A query that fails counts as loaded, so
|
|
44459
|
+
* the caller gets a fresh thread rather than a possibly stale one. A client without the query
|
|
44460
|
+
* (a wrapper or test double; the app-server client always has it) can only hold the threads this
|
|
44461
|
+
* adapter recorded, so for it an unrecorded thread is not loaded. */
|
|
44462
|
+
async isLoaded(threadId) {
|
|
44463
|
+
if (!this.client.thread.loadedList)
|
|
44464
|
+
return false;
|
|
44465
|
+
try {
|
|
44466
|
+
let cursor = null;
|
|
44467
|
+
do {
|
|
44468
|
+
const page = await this.client.thread.loadedList(cursor ? { cursor } : {});
|
|
44469
|
+
if (page.data?.includes(threadId))
|
|
44470
|
+
return true;
|
|
44471
|
+
cursor = page.nextCursor ?? null;
|
|
44472
|
+
} while (cursor);
|
|
44473
|
+
return false;
|
|
44474
|
+
} catch {
|
|
44475
|
+
return true;
|
|
44476
|
+
}
|
|
44477
|
+
}
|
|
44371
44478
|
async startTurn(threadId, input, effort) {
|
|
44372
44479
|
const accepted = await this.client.turn.start({ threadId, input, ...effort ? { effort } : {} });
|
|
44373
44480
|
return { turnId: accepted?.turn?.id };
|
|
@@ -59211,22 +59318,22 @@ function isBridgeRunWorktree(worktreePath, checkout, worktreeRoot) {
|
|
|
59211
59318
|
return false;
|
|
59212
59319
|
}
|
|
59213
59320
|
}
|
|
59214
|
-
var short = (sha) => (sha ?? "").slice(0, 7);
|
|
59215
59321
|
function localLandingNote(outcome, ctx) {
|
|
59216
59322
|
const { taskId, title, defaultBranch: d, detail } = ctx;
|
|
59323
|
+
const prefix = `${taskId} (${title})`;
|
|
59217
59324
|
const bodies = {
|
|
59218
|
-
applied: `${
|
|
59219
|
-
already_applied: `${
|
|
59220
|
-
uncommitted_changes: `${
|
|
59221
|
-
would_overwrite_files: `${
|
|
59222
|
-
default_branch_moved: `${
|
|
59223
|
-
conflict: `${
|
|
59224
|
-
build_failed: `${
|
|
59225
|
-
ff_failed: `${
|
|
59226
|
-
run_reclaimed: `${
|
|
59227
|
-
landing_partial: `${
|
|
59228
|
-
run_branch_changed: `${
|
|
59229
|
-
delivery_ref_mismatch: `${
|
|
59325
|
+
applied: `${prefix} \u2014 Applied and merged to ${d}. Restart your dev server if running to pick up changes.`,
|
|
59326
|
+
already_applied: `${prefix} \u2014 Already applied to ${d}. No changes needed.`,
|
|
59327
|
+
uncommitted_changes: `${prefix} \u2014 Can't apply: you have uncommitted changes in your project folder. Commit or stash them, then ask the Director to apply ${taskId} again.`,
|
|
59328
|
+
would_overwrite_files: `${prefix} \u2014 Can't apply: local files (${detail}) would be overwritten. Move them aside, then ask the Director to apply ${taskId} again.`,
|
|
59329
|
+
default_branch_moved: `${prefix} \u2014 Can't apply: ${d} received new commits while building. Ask the Director to apply ${taskId} again; it will be merged with the newest version and re-tested first.`,
|
|
59330
|
+
conflict: `${prefix} \u2014 Merge conflicts in ${detail}. Ask the Director to create a follow-up task that reconciles ${taskId} with ${d}.`,
|
|
59331
|
+
build_failed: `${prefix} \u2014 Merged with ${d}, but the build or tests failed (${detail}). Ask the Director to create a follow-up task to fix it.`,
|
|
59332
|
+
ff_failed: `${prefix} \u2014 Could not update ${d} branch: git refused the update (${detail}). Ask the Director to apply ${taskId} again.`,
|
|
59333
|
+
run_reclaimed: `${prefix} \u2014 Run ${ctx.runId} was taken over by another bridge instance. Ask the Director to apply ${taskId} again.`,
|
|
59334
|
+
landing_partial: `${prefix} \u2014 Partially applied (${detail}). Your work is saved. Please do not change the project folder yet: ask the Director to inspect.`,
|
|
59335
|
+
run_branch_changed: `${prefix} \u2014 Not applied: run branch mrrlin/run-${ctx.runId} received new commits. Ask the Director to restart the run if those commits belong in it.`,
|
|
59336
|
+
delivery_ref_mismatch: `${prefix} \u2014 Delivery ref mismatch (${detail}). Nothing was changed. Ask the Director to look into run ${ctx.runId}.`
|
|
59230
59337
|
};
|
|
59231
59338
|
return { id: `II-local-apply-${ctx.runId}-${outcome}`, body: bodies[outcome] };
|
|
59232
59339
|
}
|
|
@@ -63710,7 +63817,7 @@ Do NOT derail the current task - if the operator has an in-flight question, answ
|
|
|
63710
63817
|
}
|
|
63711
63818
|
|
|
63712
63819
|
// src/_generated/version.ts
|
|
63713
|
-
var PKG_VERSION = "0.4.
|
|
63820
|
+
var PKG_VERSION = "0.4.142";
|
|
63714
63821
|
|
|
63715
63822
|
// src/bridge-allowed-origins.ts
|
|
63716
63823
|
var DEFAULT_DIRECTOR_BRIDGE_ALLOWED_ORIGINS = [
|
|
@@ -67799,6 +67906,7 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
67799
67906
|
let touch = () => {
|
|
67800
67907
|
};
|
|
67801
67908
|
let turnUsage = null;
|
|
67909
|
+
let turnContextWindow = null;
|
|
67802
67910
|
const promptBytes = Buffer.byteLength(inputText, "utf8");
|
|
67803
67911
|
const turnStartedAt = Date.now();
|
|
67804
67912
|
let lastActivityAt = turnStartedAt;
|
|
@@ -67830,6 +67938,7 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
67830
67938
|
pending.push(persist(event));
|
|
67831
67939
|
if (event.type === "token_usage") {
|
|
67832
67940
|
turnUsage = event.usage;
|
|
67941
|
+
turnContextWindow = event.contextWindow ?? turnContextWindow;
|
|
67833
67942
|
} else if (event.type === "rate_limits") {
|
|
67834
67943
|
const signal = detectExhaustedProviderLimit(event.snapshot, Date.now());
|
|
67835
67944
|
if (signal) {
|
|
@@ -67891,7 +68000,7 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
67891
68000
|
clearInterval(touchTimer);
|
|
67892
68001
|
unsub();
|
|
67893
68002
|
}
|
|
67894
|
-
const telemetry = { promptBytes, usage: turnUsage };
|
|
68003
|
+
const telemetry = { promptBytes, usage: turnUsage, contextWindow: turnContextWindow };
|
|
67895
68004
|
return turnError ? { ok: false, error: turnError, interruptFailed, telemetry } : { ok: true, telemetry };
|
|
67896
68005
|
});
|
|
67897
68006
|
}
|
|
@@ -68154,14 +68263,6 @@ async function driveRun(deps, projectSlug, runId) {
|
|
|
68154
68263
|
runTelemetry.usage = addTurnTokenUsage(runTelemetry.usage, outcome.telemetry.usage);
|
|
68155
68264
|
return outcome;
|
|
68156
68265
|
};
|
|
68157
|
-
const isContextBudgetExhausted = (usage) => {
|
|
68158
|
-
if (!usage) return false;
|
|
68159
|
-
const contextTokens = (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
|
|
68160
|
-
if (contextTokens <= 0) return false;
|
|
68161
|
-
const maxTokens = 2e5;
|
|
68162
|
-
const remainingTokens = maxTokens - contextTokens;
|
|
68163
|
-
return remainingTokens / maxTokens < 0.03 || remainingTokens < 4e3;
|
|
68164
|
-
};
|
|
68165
68266
|
const effortDecision = deriveEffort({
|
|
68166
68267
|
impact: task.impact,
|
|
68167
68268
|
type: task.type,
|
|
@@ -68505,7 +68606,7 @@ Continue executing task ${task.id}. Make the next concrete increment of progress
|
|
|
68505
68606
|
await failRun(deps, projectSlug, task, runId, leaseId, outcome.error);
|
|
68506
68607
|
return;
|
|
68507
68608
|
}
|
|
68508
|
-
if (
|
|
68609
|
+
if (isNearContextLimit(outcome.telemetry.usage, outcome.telemetry.contextWindow)) {
|
|
68509
68610
|
console.warn(
|
|
68510
68611
|
JSON.stringify({
|
|
68511
68612
|
event: "context_budget_gate_triggered",
|
|
@@ -78719,18 +78820,9 @@ function createBridgeMessageHandler(deps) {
|
|
|
78719
78820
|
return;
|
|
78720
78821
|
}
|
|
78721
78822
|
if (event.type === "token_usage") {
|
|
78722
|
-
const usage = event
|
|
78823
|
+
const { usage, contextWindow } = event;
|
|
78723
78824
|
turnTokenUsage = addTurnTokenUsage(turnTokenUsage, usage);
|
|
78724
|
-
if (
|
|
78725
|
-
const totalTokens = (turnTokenUsage.inputTokens ?? 0) + (turnTokenUsage.outputTokens ?? 0);
|
|
78726
|
-
if (totalTokens > 0) {
|
|
78727
|
-
const maxTokens = 2e5;
|
|
78728
|
-
const remainingTokens = maxTokens - totalTokens;
|
|
78729
|
-
if (remainingTokens / maxTokens < 0.03 || remainingTokens < 4e3) {
|
|
78730
|
-
contextBudgetGateTriggered = true;
|
|
78731
|
-
}
|
|
78732
|
-
}
|
|
78733
|
-
}
|
|
78825
|
+
if (isNearContextLimit(usage, contextWindow)) contextBudgetGateTriggered = true;
|
|
78734
78826
|
return;
|
|
78735
78827
|
}
|
|
78736
78828
|
if (event.type === "turn_completed" || event.type === "rate_limits") {
|