@mrrlin-dev/mcp 0.3.68 → 0.4.1
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 +406 -119
- package/package.json +6 -6
package/dist/bin.cjs
CHANGED
|
@@ -20700,6 +20700,18 @@ function retargetRetiredApiBaseUrl(input) {
|
|
|
20700
20700
|
function retiredApiHostnames() {
|
|
20701
20701
|
return Object.keys(RETIRED_API_BASE_URLS);
|
|
20702
20702
|
}
|
|
20703
|
+
function bridgeUrlImpliesStaging(input) {
|
|
20704
|
+
const raw = input?.trim();
|
|
20705
|
+
if (!raw) return false;
|
|
20706
|
+
if (isLoopbackUrl(raw)) return true;
|
|
20707
|
+
let hostname3;
|
|
20708
|
+
try {
|
|
20709
|
+
hostname3 = new URL(raw).hostname.toLowerCase();
|
|
20710
|
+
} catch {
|
|
20711
|
+
return false;
|
|
20712
|
+
}
|
|
20713
|
+
return hostname3 === "staging.mrrlin.com";
|
|
20714
|
+
}
|
|
20703
20715
|
function isLoopbackUrl(input) {
|
|
20704
20716
|
try {
|
|
20705
20717
|
const url2 = new URL(input);
|
|
@@ -20846,11 +20858,12 @@ async function installBrowser(opts = {}) {
|
|
|
20846
20858
|
function deriveServeEnvFromProcessEnv(env) {
|
|
20847
20859
|
const out = {};
|
|
20848
20860
|
const rawApiUrl = env.MRRLIN_API_BASE_URL?.trim();
|
|
20861
|
+
const bridgeWantsStaging = bridgeUrlImpliesStaging(env.MRRLIN_BRIDGE_URL);
|
|
20849
20862
|
const apiUrl = rawApiUrl ? retargetRetiredApiBaseUrl(rawApiUrl).baseUrl : void 0;
|
|
20850
20863
|
if (apiUrl && !isStagingApiBaseUrl(apiUrl)) {
|
|
20851
20864
|
out.MRRLIN_API_BASE_URL = apiUrl;
|
|
20852
20865
|
if (env.MRRLIN_API_ALLOW_REMOTE === "1") out.MRRLIN_API_ALLOW_REMOTE = "1";
|
|
20853
|
-
} else if (apiUrl || env.MRRLIN_STAGING === "1") {
|
|
20866
|
+
} else if (apiUrl || env.MRRLIN_STAGING === "1" || bridgeWantsStaging) {
|
|
20854
20867
|
out.MRRLIN_STAGING = "1";
|
|
20855
20868
|
}
|
|
20856
20869
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
@@ -21009,7 +21022,7 @@ function blockEnvHasRetiredApiUrl(actual) {
|
|
|
21009
21022
|
}
|
|
21010
21023
|
function renderEnvPreservedNotice(blockId, envKeys) {
|
|
21011
21024
|
const keys = [...envKeys].sort().join(", ");
|
|
21012
|
-
return `[mrrlin-mcp
|
|
21025
|
+
return `[mrrlin-mcp configure bridge] kept your existing [mcp_servers.${blockId}] env keys (${keys}) so your API target is preserved. Re-run with --force to replace or remove it.`;
|
|
21013
21026
|
}
|
|
21014
21027
|
async function pathExists(target) {
|
|
21015
21028
|
try {
|
|
@@ -36401,6 +36414,8 @@ var openApiOperationIds = {
|
|
|
36401
36414
|
getTask: "getTask",
|
|
36402
36415
|
archiveTask: "archiveTask",
|
|
36403
36416
|
unarchiveTask: "unarchiveTask",
|
|
36417
|
+
takeOverTask: "takeOverTask",
|
|
36418
|
+
closeTaskAsWontDo: "closeTaskAsWontDo",
|
|
36404
36419
|
getWikiPage: "getWikiPage",
|
|
36405
36420
|
handleGithubInstallCallback: "handleGithubInstallCallback",
|
|
36406
36421
|
listExecutionArtifacts: "listExecutionArtifacts",
|
|
@@ -36461,6 +36476,7 @@ var openApiOperationIds = {
|
|
|
36461
36476
|
getOperatorSettings: "getOperatorSettings",
|
|
36462
36477
|
updateOperatorSettings: "updateOperatorSettings",
|
|
36463
36478
|
recordOperatorPresence: "recordOperatorPresence",
|
|
36479
|
+
pauseAutopilotForLimit: "pauseAutopilotForLimit",
|
|
36464
36480
|
getAgentPool: "getAgentPool",
|
|
36465
36481
|
putAgentPool: "putAgentPool",
|
|
36466
36482
|
getConsensusConfig: "getConsensusConfig",
|
|
@@ -36507,6 +36523,13 @@ var mrrlinOperatorSettingsSchema = external_exports.object({
|
|
|
36507
36523
|
activeProjectSlug: external_exports.string().min(1).nullable(),
|
|
36508
36524
|
// The last time an authenticated BROWSER operator session was observed. Null means never seen.
|
|
36509
36525
|
lastPresenceAt: external_exports.string().datetime().nullable(),
|
|
36526
|
+
// autopilot-limit-pause: READ-ONLY status for an automatic provider-limit pause. These are never
|
|
36527
|
+
// writable via mrrlinOperatorSettingsUpdateSchema (an explicit operator write clears them
|
|
36528
|
+
// server-side). Non-null autoPauseSource => the current pause is machine-owned; autoPauseResetAt
|
|
36529
|
+
// is the absolute reset time (null = indefinite, manual resume required).
|
|
36530
|
+
autoPauseSource: external_exports.string().min(1).nullable(),
|
|
36531
|
+
autoPauseReason: external_exports.string().min(1).nullable(),
|
|
36532
|
+
autoPauseResetAt: external_exports.string().datetime().nullable(),
|
|
36510
36533
|
createdAt: external_exports.string().datetime(),
|
|
36511
36534
|
updatedAt: external_exports.string().datetime()
|
|
36512
36535
|
});
|
|
@@ -36518,6 +36541,11 @@ var mrrlinOperatorSettingsUpdateSchema = external_exports.object({
|
|
|
36518
36541
|
message: "OperatorSettingsUpdate requires at least one field"
|
|
36519
36542
|
});
|
|
36520
36543
|
var operatorSettingsResponseSchema = external_exports.object({ data: mrrlinOperatorSettingsSchema });
|
|
36544
|
+
var autopilotLimitPauseRequestSchema = external_exports.object({
|
|
36545
|
+
source: external_exports.string().min(1).default("provider_limit"),
|
|
36546
|
+
reason: external_exports.string().min(1).max(500),
|
|
36547
|
+
resetAt: external_exports.string().datetime().nullable().default(null)
|
|
36548
|
+
}).strict();
|
|
36521
36549
|
var operatorPresenceResponseSchema = external_exports.object({ data: external_exports.object({ lastPresenceAt: external_exports.string().datetime() }) });
|
|
36522
36550
|
var operatorPresenceRequestSchema = external_exports.object({ projectSlug: external_exports.string().min(1).optional() }).strict().optional();
|
|
36523
36551
|
var mrrlinConsensusConfigSchema = external_exports.object({ consensusEnabled: external_exports.boolean() });
|
|
@@ -36889,6 +36917,32 @@ var SUPPORTED_EXECUTION_DOMAINS = Object.keys(SUPPORTED_EXECUTION_POLICY_BY_DOMA
|
|
|
36889
36917
|
var taxonomyCategorySchema = external_exports.string().min(1).regex(/^[a-z][a-z0-9-]*$/);
|
|
36890
36918
|
var taxonomySubcategorySchema = external_exports.string().min(1).regex(/^[a-z][a-z0-9-]*$/);
|
|
36891
36919
|
var mrrlinTaskAssigneeSchema = external_exports.union([external_exports.string().regex(/^@/), external_exports.string().email()]).nullable();
|
|
36920
|
+
var mrrlinStopReasonSchema = external_exports.enum([
|
|
36921
|
+
"task_terminal",
|
|
36922
|
+
"active_run_exists",
|
|
36923
|
+
"draft_running",
|
|
36924
|
+
"consensus_running",
|
|
36925
|
+
"spec_changed_during_advance",
|
|
36926
|
+
"run_limit_reached",
|
|
36927
|
+
"backoff_pending",
|
|
36928
|
+
"blocked_by_active",
|
|
36929
|
+
"spec_missing",
|
|
36930
|
+
"spec_draft_failed",
|
|
36931
|
+
"spec_not_specs_folder",
|
|
36932
|
+
"awaiting_clarification",
|
|
36933
|
+
"consensus_blocked",
|
|
36934
|
+
"consensus_run_failed",
|
|
36935
|
+
"consensus_disabled_spec_not_ready",
|
|
36936
|
+
"spec_approval_pending",
|
|
36937
|
+
"awaiting_handoff",
|
|
36938
|
+
"assigned_to_other",
|
|
36939
|
+
"attempts_exhausted",
|
|
36940
|
+
"daily_job_budget_exhausted",
|
|
36941
|
+
"taken_over",
|
|
36942
|
+
"operator_absent",
|
|
36943
|
+
"autonomy_paused",
|
|
36944
|
+
"unknown"
|
|
36945
|
+
]);
|
|
36892
36946
|
var mrrlinTaskSchema = external_exports.object({
|
|
36893
36947
|
// Output-optional (not defaulted-required) so existing task fixtures/mocks across the
|
|
36894
36948
|
// codebase need no churn; DB rows always resolve it to `string | null` via taskRowToTask.
|
|
@@ -36903,6 +36957,9 @@ var mrrlinTaskSchema = external_exports.object({
|
|
|
36903
36957
|
autonomyReason: external_exports.string().min(1).max(240),
|
|
36904
36958
|
blockedBy: external_exports.array(mrrlinTaskIdSchema),
|
|
36905
36959
|
category: taxonomyCategorySchema,
|
|
36960
|
+
// Slice 3 (task-stall-visibility): why a task was closed as won't-do -- populated only by
|
|
36961
|
+
// closeTaskAsWontDo. Output-optional so existing task fixtures need no churn.
|
|
36962
|
+
closeReason: external_exports.string().nullable().optional(),
|
|
36906
36963
|
directorThreadId: external_exports.string().nullable().default(null),
|
|
36907
36964
|
dueDate: external_exports.string().date().nullable(),
|
|
36908
36965
|
followUpAt: external_exports.string().datetime().nullable(),
|
|
@@ -36911,6 +36968,9 @@ var mrrlinTaskSchema = external_exports.object({
|
|
|
36911
36968
|
latestJudgement: external_exports.string().nullable().default(null),
|
|
36912
36969
|
latestJudgementAt: external_exports.string().datetime().nullable().default(null),
|
|
36913
36970
|
latestJudgementKind: external_exports.enum(["autonomy", "handoff"]).nullable().default(null),
|
|
36971
|
+
// Slice 3: the retry-backoff timer for exactly spec_draft_failed/consensus_run_failed -- a task
|
|
36972
|
+
// whose next_attempt_at is in the future is skipped from admission (backoff_pending).
|
|
36973
|
+
nextAttemptAt: external_exports.string().datetime().nullable().optional(),
|
|
36914
36974
|
notes: external_exports.string().nullable().default(null),
|
|
36915
36975
|
// Raw operator request captured at task creation (operator-authored ONLY, never Director-generated).
|
|
36916
36976
|
// The intent-aware spec gate judges the spec against this; null/absent ⇒ the gate fail-closes.
|
|
@@ -36920,6 +36980,14 @@ var mrrlinTaskSchema = external_exports.object({
|
|
|
36920
36980
|
planId: mrrlinPlanIdSchema.nullable(),
|
|
36921
36981
|
specApproved: mrrlinSpecApprovedSchema.optional(),
|
|
36922
36982
|
specWikiPageId: mrrlinWikiPageIdSchema.nullable(),
|
|
36983
|
+
// Slice 3: episode bookkeeping alongside the async_jobs-derived countEpisodeAttempts --
|
|
36984
|
+
// stallAttemptCount backs the exponential-backoff formula, stallRearmed guards against
|
|
36985
|
+
// re-arming the same episode's ceiling more than once.
|
|
36986
|
+
stallAttemptCount: external_exports.number().int().nonnegative().optional(),
|
|
36987
|
+
stallRearmed: external_exports.boolean().optional(),
|
|
36988
|
+
stallNextAction: external_exports.string().nullable().optional(),
|
|
36989
|
+
stallReason: mrrlinStopReasonSchema.nullable().optional(),
|
|
36990
|
+
stallSince: external_exports.string().datetime().nullable().optional(),
|
|
36923
36991
|
status: mrrlinTaskStatusSchema,
|
|
36924
36992
|
subcategory: taxonomySubcategorySchema,
|
|
36925
36993
|
tags: mrrlinTaskTagsSchema,
|
|
@@ -36982,6 +37050,12 @@ var mrrlinWikiPageSchema = external_exports.object({
|
|
|
36982
37050
|
var mrrlinMarkSpecReadyRequestSchema = external_exports.object({
|
|
36983
37051
|
ready: external_exports.boolean()
|
|
36984
37052
|
});
|
|
37053
|
+
var mrrlinTakeOverTaskRequestSchema = external_exports.object({
|
|
37054
|
+
assignee: external_exports.string().min(1)
|
|
37055
|
+
});
|
|
37056
|
+
var mrrlinCloseTaskAsWontDoRequestSchema = external_exports.object({
|
|
37057
|
+
reason: external_exports.string().min(1)
|
|
37058
|
+
});
|
|
36985
37059
|
var mrrlinGithubBindingSchema = external_exports.object({
|
|
36986
37060
|
appInstallationState: external_exports.enum(["installed", "missing"]),
|
|
36987
37061
|
installationId: external_exports.number().int().positive().nullable().default(null),
|
|
@@ -37997,7 +38071,8 @@ var mrrlinInFlightSchedulerEntrySchema = external_exports.discriminatedUnion("ki
|
|
|
37997
38071
|
]);
|
|
37998
38072
|
var mrrlinIneligibleTaskSchema = external_exports.object({
|
|
37999
38073
|
task: mrrlinTaskSchema,
|
|
38000
|
-
autonomyLevel: mrrlinAutonomyLevelSchema
|
|
38074
|
+
autonomyLevel: mrrlinAutonomyLevelSchema,
|
|
38075
|
+
reason: external_exports.string().nullable().optional()
|
|
38001
38076
|
});
|
|
38002
38077
|
var schedulerPendingTasksResponseSchema = external_exports.object({
|
|
38003
38078
|
data: external_exports.object({
|
|
@@ -38021,6 +38096,12 @@ var schedulerPendingTasksResponseSchema = external_exports.object({
|
|
|
38021
38096
|
// person actually running the project) is visible as a large number instead of the autopilot
|
|
38022
38097
|
// silently doing nothing.
|
|
38023
38098
|
excludedByOwnershipCount: external_exports.number().int().min(0),
|
|
38099
|
+
// Additive: the same ownership exclusion grouped by assignee. This reveals who the
|
|
38100
|
+
// autopilot is waiting for without returning task ids or titles in this endpoint.
|
|
38101
|
+
ownershipExcludedAssignees: external_exports.array(external_exports.object({
|
|
38102
|
+
assignee: external_exports.string(),
|
|
38103
|
+
count: external_exports.number().int().min(1)
|
|
38104
|
+
})),
|
|
38024
38105
|
// Additive: true when the operator-web-presence gate is the reason nothing new is starting
|
|
38025
38106
|
// (autonomyPaused takes precedence when both apply). Computed by the same shared helper the
|
|
38026
38107
|
// tick uses, so this page can never claim a task is starting when the tick would decline it.
|
|
@@ -38055,7 +38136,7 @@ var wakeDirectorResponseSchema = external_exports.object({
|
|
|
38055
38136
|
}))
|
|
38056
38137
|
})
|
|
38057
38138
|
});
|
|
38058
|
-
var mrrlinInboxItemKindSchema = external_exports.enum(["proposal", "check_in", "question", "handoff", "info"]);
|
|
38139
|
+
var mrrlinInboxItemKindSchema = external_exports.enum(["proposal", "check_in", "question", "handoff", "info", "completed"]);
|
|
38059
38140
|
var mrrlinInboxItemStatusSchema = external_exports.enum(["pending", "approved", "rejected", "acknowledged"]);
|
|
38060
38141
|
var mrrlinInboxItemIdSchema = external_exports.string().regex(/^II-[A-Za-z0-9._-]+$/);
|
|
38061
38142
|
var mrrlinInboxItemActionPayloadSchema = external_exports.object({
|
|
@@ -38124,6 +38205,7 @@ var mrrlinInboxItemSchema = external_exports.object({
|
|
|
38124
38205
|
projectSlug: mrrlinProjectSlugSchema,
|
|
38125
38206
|
questionOptions: mrrlinInboxQuestionOptionsSchema.nullable().default(null),
|
|
38126
38207
|
readAt: external_exports.string().datetime().nullable(),
|
|
38208
|
+
reason: external_exports.string().nullable().optional(),
|
|
38127
38209
|
status: mrrlinInboxItemStatusSchema,
|
|
38128
38210
|
taskId: mrrlinTaskIdSchema.nullable()
|
|
38129
38211
|
}).superRefine((value, context) => {
|
|
@@ -38514,6 +38596,36 @@ function addTurnTokenUsage(total, turn) {
|
|
|
38514
38596
|
};
|
|
38515
38597
|
}
|
|
38516
38598
|
|
|
38599
|
+
// ../../packages/codex-client/dist/rate-limit.js
|
|
38600
|
+
var EXHAUSTION_USED_PERCENT = 100;
|
|
38601
|
+
function windowExhausted(window) {
|
|
38602
|
+
if (!window)
|
|
38603
|
+
return false;
|
|
38604
|
+
return typeof window.usedPercent === "number" && Number.isFinite(window.usedPercent) && window.usedPercent >= EXHAUSTION_USED_PERCENT;
|
|
38605
|
+
}
|
|
38606
|
+
function normalizeResetEpochSeconds(resetsAt, nowMs) {
|
|
38607
|
+
if (typeof resetsAt !== "number" || !Number.isFinite(resetsAt))
|
|
38608
|
+
return null;
|
|
38609
|
+
const resetMs = resetsAt * 1e3;
|
|
38610
|
+
if (resetMs <= nowMs)
|
|
38611
|
+
return null;
|
|
38612
|
+
return new Date(resetMs).toISOString();
|
|
38613
|
+
}
|
|
38614
|
+
function detectExhaustedProviderLimit(snapshot, nowMs) {
|
|
38615
|
+
if (!snapshot)
|
|
38616
|
+
return null;
|
|
38617
|
+
const reachedType = typeof snapshot.rateLimitReachedType === "string" ? snapshot.rateLimitReachedType.trim() : "";
|
|
38618
|
+
const exhausted = reachedType.length > 0 || windowExhausted(snapshot.primary) || windowExhausted(snapshot.secondary);
|
|
38619
|
+
if (!exhausted)
|
|
38620
|
+
return null;
|
|
38621
|
+
const candidates = [
|
|
38622
|
+
normalizeResetEpochSeconds(snapshot.primary?.resetsAt, nowMs),
|
|
38623
|
+
normalizeResetEpochSeconds(snapshot.secondary?.resetsAt, nowMs)
|
|
38624
|
+
].filter((value) => value !== null);
|
|
38625
|
+
const resetAt = candidates.length > 0 ? candidates.reduce((a, b) => a > b ? a : b) : null;
|
|
38626
|
+
return { exhausted: true, resetAt };
|
|
38627
|
+
}
|
|
38628
|
+
|
|
38517
38629
|
// ../../packages/client/dist/agent-token-provider.js
|
|
38518
38630
|
var AgentTokenProviderError = class extends Error {
|
|
38519
38631
|
code;
|
|
@@ -38970,6 +39082,22 @@ function createMrrlinClient(config2) {
|
|
|
38970
39082
|
});
|
|
38971
39083
|
return taskResponseSchema.parse(body).data;
|
|
38972
39084
|
},
|
|
39085
|
+
async takeOverTask(projectSlug, taskId, assignee) {
|
|
39086
|
+
const body = await request(`${projectPath(projectSlug)}/tasks/${encodeURIComponent(taskId)}/take-over`, {
|
|
39087
|
+
method: "POST",
|
|
39088
|
+
headers: { "content-type": "application/json" },
|
|
39089
|
+
body: JSON.stringify({ assignee })
|
|
39090
|
+
});
|
|
39091
|
+
return taskResponseSchema.parse(body).data;
|
|
39092
|
+
},
|
|
39093
|
+
async closeTaskAsWontDo(projectSlug, taskId, reason) {
|
|
39094
|
+
const body = await request(`${projectPath(projectSlug)}/tasks/${encodeURIComponent(taskId)}/wont-do`, {
|
|
39095
|
+
method: "POST",
|
|
39096
|
+
headers: { "content-type": "application/json" },
|
|
39097
|
+
body: JSON.stringify({ reason })
|
|
39098
|
+
});
|
|
39099
|
+
return taskResponseSchema.parse(body).data;
|
|
39100
|
+
},
|
|
38973
39101
|
async updateWikiPage(projectSlug, pageId, patch) {
|
|
38974
39102
|
const body = await request(`${projectPath(projectSlug)}/wiki/${encodeURIComponent(pageId)}`, {
|
|
38975
39103
|
body: JSON.stringify(patch),
|
|
@@ -39408,6 +39536,15 @@ function createMrrlinClient(config2) {
|
|
|
39408
39536
|
});
|
|
39409
39537
|
return operatorSettingsResponseSchema.parse(body).data;
|
|
39410
39538
|
},
|
|
39539
|
+
async pauseAutopilotForLimit(input) {
|
|
39540
|
+
const parsed = autopilotLimitPauseRequestSchema.parse(input);
|
|
39541
|
+
const body = await request(`/operator/autopilot/limit-pause`, {
|
|
39542
|
+
body: JSON.stringify(parsed),
|
|
39543
|
+
headers: { "content-type": "application/json" },
|
|
39544
|
+
method: "POST"
|
|
39545
|
+
});
|
|
39546
|
+
return operatorSettingsResponseSchema.parse(body).data;
|
|
39547
|
+
},
|
|
39411
39548
|
async recordOperatorPresence(input) {
|
|
39412
39549
|
const projectSlug = input?.projectSlug;
|
|
39413
39550
|
const body = await request(`/operator/presence`, {
|
|
@@ -40050,7 +40187,7 @@ function startCodexProbe(deps = {}) {
|
|
|
40050
40187
|
}
|
|
40051
40188
|
|
|
40052
40189
|
// src/_generated/version.ts
|
|
40053
|
-
var PKG_VERSION = "0.
|
|
40190
|
+
var PKG_VERSION = "0.4.1";
|
|
40054
40191
|
|
|
40055
40192
|
// src/api-base-url-migrate.ts
|
|
40056
40193
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
|
@@ -42861,7 +42998,7 @@ function onComplete(outcome, input) {
|
|
|
42861
42998
|
}
|
|
42862
42999
|
const taskRef = parsed.taskTitle ? `${input.taskId} \u2014 ${parsed.taskTitle}` : input.taskId;
|
|
42863
43000
|
return {
|
|
42864
|
-
kind: "
|
|
43001
|
+
kind: "completed",
|
|
42865
43002
|
taskId: input.taskId,
|
|
42866
43003
|
body: `Spec drafted automatically for ${taskRef} \u2014 page ${parsed.pageId ?? "?"} in Specs/. The next scheduler tick will run the consensus review.`
|
|
42867
43004
|
};
|
|
@@ -43921,6 +44058,10 @@ function executionTurnBudgetMessage(budgetMs) {
|
|
|
43921
44058
|
function isExecutionTurnTimeoutReason(reason) {
|
|
43922
44059
|
return reason.startsWith(EXECUTION_TURN_TIMEOUT_PREFIX) || reason.startsWith(EXECUTION_TURN_STALL_PREFIX);
|
|
43923
44060
|
}
|
|
44061
|
+
function reportAutopilotLimitPause(client, reason, resetAt) {
|
|
44062
|
+
void client.pauseAutopilotForLimit({ source: "provider_limit", reason, resetAt }).catch(() => {
|
|
44063
|
+
});
|
|
44064
|
+
}
|
|
43924
44065
|
function isDeliverableGateRetryableReason(reason) {
|
|
43925
44066
|
return DELIVERABLE_GATE_RETRYABLE_REASON_PREFIXES.some((prefix) => reason.startsWith(prefix));
|
|
43926
44067
|
}
|
|
@@ -43992,20 +44133,24 @@ var BASE_INSTRUCTIONS_PREFIX = [
|
|
|
43992
44133
|
" if you are blocked and a human must decide before the work can continue, leave it at `handoff_needed`.",
|
|
43993
44134
|
"",
|
|
43994
44135
|
"File artifacts:",
|
|
43995
|
-
"- Decide BEFORE writing your result
|
|
43996
|
-
"
|
|
43997
|
-
"
|
|
43998
|
-
"-
|
|
43999
|
-
"
|
|
44000
|
-
"
|
|
44136
|
+
"- Decide BEFORE writing your result, by PROVENANCE: output assembled from data you RETRIEVED",
|
|
44137
|
+
" this run (API, browser, analytics, database, a search over project records) that comes out as",
|
|
44138
|
+
" a multi-record or multi-dimension result is a FILE, not inline text.",
|
|
44139
|
+
"- Your own synthesis or comparison stays inline however structured it looks, and so does a",
|
|
44140
|
+
" retrieval yielding one value. Both conditions must hold before it becomes a file. When it",
|
|
44141
|
+
" qualifies, produce the file; never merely offer one.",
|
|
44142
|
+
"- Mixed output counts as retrieved: if any material part came from a retrieval, treat the whole",
|
|
44143
|
+
" result as retrieved rather than splitting it between inline text and a file.",
|
|
44144
|
+
"- When your output is a file (markdown report, HTML), call `deliver_file`: pass the body inline",
|
|
44145
|
+
" as `content` and embed the returned markdown link. It needs no writable path, so it is the",
|
|
44146
|
+
" default even when this run path cannot write files \u2014 never inline large blobs into chat,",
|
|
44147
|
+
" spec, or note text.",
|
|
44001
44148
|
"- class=temp for one-off operator hand-offs (48h); class=durable for anything a spec",
|
|
44002
44149
|
" or evidence page will reference (180 days). Always pass taskId/runId when known.",
|
|
44003
|
-
"- Anything user-facing delivered as a file MUST
|
|
44004
|
-
" split or summarize larger outputs.",
|
|
44005
|
-
"- `upload_artifact`
|
|
44006
|
-
"
|
|
44007
|
-
" cannot write, do NOT attempt the file: put the summary in your result text and state what a",
|
|
44008
|
-
" file would have held. Never fake a path you did not write.",
|
|
44150
|
+
"- Anything user-facing delivered as a file MUST go through `deliver_file`. Files are capped at",
|
|
44151
|
+
" 5MB \u2014 split or summarize larger outputs.",
|
|
44152
|
+
"- Use `upload_artifact` only for a file already on disk (e.g. a screenshot the browser wrote);",
|
|
44153
|
+
" it needs a real local path, so never fake a path you did not write.",
|
|
44009
44154
|
"",
|
|
44010
44155
|
"Produced URLs \u2014 the operator's per-page links come only from you:",
|
|
44011
44156
|
"- Call `record_produced_url` after publishing EACH web page this task produced, so the task UI",
|
|
@@ -44335,6 +44480,17 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
|
|
|
44335
44480
|
}
|
|
44336
44481
|
const usage = !notifThreadId || notifThreadId === threadId ? extractTurnTokenUsage(method, params) : null;
|
|
44337
44482
|
if (usage) turnUsage = usage;
|
|
44483
|
+
if (method === "account/rateLimits/updated") {
|
|
44484
|
+
const snapshot = params?.rateLimits ?? null;
|
|
44485
|
+
const signal = detectExhaustedProviderLimit(snapshot, Date.now());
|
|
44486
|
+
if (signal) {
|
|
44487
|
+
reportAutopilotLimitPause(
|
|
44488
|
+
deps.client,
|
|
44489
|
+
"Codex provider limit exhausted during an autonomous execution run.",
|
|
44490
|
+
signal.resetAt
|
|
44491
|
+
);
|
|
44492
|
+
}
|
|
44493
|
+
}
|
|
44338
44494
|
const events = mapper.mapNotification(
|
|
44339
44495
|
{ method, params },
|
|
44340
44496
|
threadId
|
|
@@ -50959,13 +51115,22 @@ function buildThreadStartParams(msg, config2, desiredModel) {
|
|
|
50959
51115
|
" is not measurable, re-set `verificationDueAt` to a new date with a reason.",
|
|
50960
51116
|
"",
|
|
50961
51117
|
"File artifacts contract \u2014 decide the delivery medium BEFORE you compose the reply:",
|
|
50962
|
-
"-
|
|
50963
|
-
"
|
|
50964
|
-
"
|
|
50965
|
-
"-
|
|
50966
|
-
"
|
|
50967
|
-
"
|
|
50968
|
-
"
|
|
51118
|
+
"- Decide by PROVENANCE, not by predicting what the operator will do later. If this answer is",
|
|
51119
|
+
" assembled from data you RETRIEVED this turn (an HTTP/API call, the browser, analytics, a",
|
|
51120
|
+
" database, a search over project records) AND it comes out as a multi-record or",
|
|
51121
|
+
" multi-dimension result rather than one fact or a few values, it belongs in a FILE.",
|
|
51122
|
+
"- Your own synthesis, comparison, or judgement belongs in chat, however structured it looks.",
|
|
51123
|
+
" A retrieval that yields one number or one line also belongs in chat. Both conditions must",
|
|
51124
|
+
" hold before it becomes a file.",
|
|
51125
|
+
"- Mixed answers count as retrieved: if any material part of the result came from a retrieval,",
|
|
51126
|
+
" treat the whole answer as retrieved rather than splitting it between chat and a file.",
|
|
51127
|
+
'- When it qualifies, PRODUCE the file. Offering one ("I can give you this as CSV/JSON") is the',
|
|
51128
|
+
" failure, not the courtesy.",
|
|
51129
|
+
"- When it is a file: choose the format (`.md` for linear prose, `.html` when structure or",
|
|
51130
|
+
" layout carries meaning), then call `deliver_file` \u2014 pass the body inline as `content` and it",
|
|
51131
|
+
" needs no local file (class=temp for one-off downloads, class=durable when a spec/evidence",
|
|
51132
|
+
" page references it; pass taskId when known), and paste the returned markdown link into your",
|
|
51133
|
+
" reply. Use `upload_artifact` only for a file that already exists on disk (e.g. a screenshot).",
|
|
50969
51134
|
"- The chat reply must still stand alone as a complete answer even if the file is never opened:",
|
|
50970
51135
|
" the headline finding, the few points that matter, then the link. Never reduce it to",
|
|
50971
51136
|
' "see attached" or "details in the report".',
|
|
@@ -51202,6 +51367,10 @@ var DEFAULT_WORKTREE_RETENTION_HOURS = 48;
|
|
|
51202
51367
|
function worktreeRetentionMs() {
|
|
51203
51368
|
return readEnvInt("MRRLIN_DIRECTOR_WORKTREE_RETENTION_HOURS", DEFAULT_WORKTREE_RETENTION_HOURS) * 36e5;
|
|
51204
51369
|
}
|
|
51370
|
+
function reportAutopilotLimitPause2(client, reason, resetAt) {
|
|
51371
|
+
void client.pauseAutopilotForLimit({ source: "provider_limit", reason, resetAt }).catch(() => {
|
|
51372
|
+
});
|
|
51373
|
+
}
|
|
51205
51374
|
async function runOrphanWorktreeSweep(client, opts) {
|
|
51206
51375
|
const cutoff = Date.now() - worktreeRetentionMs();
|
|
51207
51376
|
const isReapable = (worktreePath) => {
|
|
@@ -52133,7 +52302,18 @@ function createBridgeMessageHandler(deps) {
|
|
|
52133
52302
|
});
|
|
52134
52303
|
const mapper = thread.mapper;
|
|
52135
52304
|
mapper.reset();
|
|
52136
|
-
const
|
|
52305
|
+
const contextFocusTaskId = msg.context?.focusTaskId?.trim();
|
|
52306
|
+
const contextProjectSlug = msg.context?.projectSlug?.trim();
|
|
52307
|
+
let answeredQuestions;
|
|
52308
|
+
if (deps.listAnsweredQuestions && contextFocusTaskId && contextProjectSlug) {
|
|
52309
|
+
try {
|
|
52310
|
+
const acknowledged = await deps.listAnsweredQuestions(contextProjectSlug, contextFocusTaskId);
|
|
52311
|
+
const withAnswers = acknowledged.filter((item) => Boolean(item.answer)).map((item) => ({ answer: item.answer, question: item.body }));
|
|
52312
|
+
answeredQuestions = withAnswers.length ? withAnswers : void 0;
|
|
52313
|
+
} catch {
|
|
52314
|
+
}
|
|
52315
|
+
}
|
|
52316
|
+
const contextPrefix = renderContextPrefix({ ...msg.context, answeredQuestions, directorSessionId });
|
|
52137
52317
|
const sendInTurn = (msg2) => {
|
|
52138
52318
|
const buf = thread.replay;
|
|
52139
52319
|
if (!buf) {
|
|
@@ -52201,7 +52381,13 @@ function createBridgeMessageHandler(deps) {
|
|
|
52201
52381
|
pokeActivity();
|
|
52202
52382
|
if (method === "account/rateLimits/updated") {
|
|
52203
52383
|
const snapshot = params?.rateLimits ?? null;
|
|
52204
|
-
if (snapshot)
|
|
52384
|
+
if (snapshot) {
|
|
52385
|
+
sendInTurn({ type: "rateLimits", directorSessionId, rateLimits: snapshot });
|
|
52386
|
+
const signal = detectExhaustedProviderLimit(snapshot, Date.now());
|
|
52387
|
+
if (signal) {
|
|
52388
|
+
deps.reportLimitPause?.("Codex provider limit exhausted during a Director turn.", signal.resetAt);
|
|
52389
|
+
}
|
|
52390
|
+
}
|
|
52205
52391
|
}
|
|
52206
52392
|
const events = mapper.mapNotification({ method, params }, threadId);
|
|
52207
52393
|
for (const event of events) {
|
|
@@ -52303,6 +52489,10 @@ ${effectiveText}` : effectiveText;
|
|
|
52303
52489
|
forward(event);
|
|
52304
52490
|
}
|
|
52305
52491
|
if (outputEvents === 0) {
|
|
52492
|
+
deps.reportLimitPause?.(
|
|
52493
|
+
"Director turn completed without output; Codex likely hit its usage or credits limit.",
|
|
52494
|
+
null
|
|
52495
|
+
);
|
|
52306
52496
|
sendInTurn({
|
|
52307
52497
|
type: "error",
|
|
52308
52498
|
directorSessionId,
|
|
@@ -52800,6 +52990,7 @@ async function startDirectorBridge() {
|
|
|
52800
52990
|
turnInactivity: () => ({ idleMs: chatTurnIdleMs(), maxMs: chatTurnMaxMs() }),
|
|
52801
52991
|
checkoutRegistry,
|
|
52802
52992
|
setCodexAuth: (s) => health.setCodexAuth(s),
|
|
52993
|
+
reportLimitPause: (reason, resetAt) => reportAutopilotLimitPause2(client, reason, resetAt),
|
|
52803
52994
|
getPairingQr: async () => {
|
|
52804
52995
|
if (!relayConfigured || !remoteRelay) return { status: "not-configured" };
|
|
52805
52996
|
const payload = remoteRelay.qrPayload;
|
|
@@ -52819,7 +53010,7 @@ async function startDirectorBridge() {
|
|
|
52819
53010
|
if (!body) return;
|
|
52820
53011
|
const id = `II-MCPUPD-${(0, import_node_crypto8.randomUUID)()}`;
|
|
52821
53012
|
try {
|
|
52822
|
-
const row = await client.createInboxItem(projectSlug, { id, kind: "
|
|
53013
|
+
const row = await client.createInboxItem(projectSlug, { id, kind: "info", body });
|
|
52823
53014
|
process.stderr.write(
|
|
52824
53015
|
`[mrrlin-mcp director-bridge] info bridge.self_update.inbox_filed ${JSON.stringify({
|
|
52825
53016
|
projectSlug,
|
|
@@ -52839,6 +53030,7 @@ async function startDirectorBridge() {
|
|
|
52839
53030
|
);
|
|
52840
53031
|
}
|
|
52841
53032
|
},
|
|
53033
|
+
listAnsweredQuestions: (projectSlug, taskId) => client.listInboxItems(projectSlug, { status: "acknowledged", kind: "question", taskId }),
|
|
52842
53034
|
// External-agents control plane: the real spawn runner, with the EXTERNAL_AGENTS_CLI operator
|
|
52843
53035
|
// escape hatch bound here (the handlers stay spawn-free and this is the only production seam).
|
|
52844
53036
|
runExternalAgentsCli: (args, opts) => runExternalAgentsCli(args, { ...opts, envCliPath: process.env["EXTERNAL_AGENTS_CLI"] })
|
|
@@ -53253,11 +53445,13 @@ function renderContextPrefix(context) {
|
|
|
53253
53445
|
const urlPath = context?.urlPath?.trim() ? context.urlPath.trim() : void 0;
|
|
53254
53446
|
const focusTaskId = context?.focusTaskId?.trim() ? context.focusTaskId.trim() : void 0;
|
|
53255
53447
|
const directorSessionId = context?.directorSessionId?.trim() ? context.directorSessionId.trim() : void 0;
|
|
53448
|
+
const answeredQuestions = context?.answeredQuestions?.length ? context.answeredQuestions : void 0;
|
|
53256
53449
|
const payload = {};
|
|
53257
53450
|
if (projectSlug) payload.projectSlug = projectSlug;
|
|
53258
53451
|
if (urlPath) payload.urlPath = urlPath;
|
|
53259
53452
|
if (focusTaskId) payload.focusTaskId = focusTaskId;
|
|
53260
53453
|
if (directorSessionId) payload.directorSessionId = directorSessionId;
|
|
53454
|
+
if (answeredQuestions) payload.answeredQuestions = answeredQuestions;
|
|
53261
53455
|
const keys = Object.keys(payload);
|
|
53262
53456
|
if (keys.length === 0) return "";
|
|
53263
53457
|
return `Context (JSON): ${JSON.stringify(payload)}`;
|
|
@@ -57271,30 +57465,9 @@ var HUMANIZE_TEMPLATE_BY_KIND = {
|
|
|
57271
57465
|
missing_requirement: "A required part of the task is still missing from the spec. What should it say?",
|
|
57272
57466
|
acceptance_criteria_detail: "The direction is clear, but the spec still needs a sharper success check. What should count as done?"
|
|
57273
57467
|
};
|
|
57274
|
-
var HUMANIZE_CONTEXT_CAP = 200;
|
|
57275
|
-
function truncateToSentenceBoundary(text, cap) {
|
|
57276
|
-
if (text.length <= cap) return text;
|
|
57277
|
-
const sentences = text.match(/.+?[.!?](?=\s|$)/g);
|
|
57278
|
-
if (sentences) {
|
|
57279
|
-
let kept = "";
|
|
57280
|
-
let keptCount = 0;
|
|
57281
|
-
for (const sentence of sentences) {
|
|
57282
|
-
const candidate = kept ? `${kept} ${sentence.trim()}` : sentence.trim();
|
|
57283
|
-
if (candidate.length > cap) break;
|
|
57284
|
-
kept = candidate;
|
|
57285
|
-
keptCount++;
|
|
57286
|
-
}
|
|
57287
|
-
if (kept) return keptCount < sentences.length ? `${kept} \u2026` : kept;
|
|
57288
|
-
}
|
|
57289
|
-
const cutIdx = text.lastIndexOf(" ", cap);
|
|
57290
|
-
return text.slice(0, cutIdx > 0 ? cutIdx : cap).trim() + "\u2026";
|
|
57291
|
-
}
|
|
57292
57468
|
function humanizeClarificationBody(clarification) {
|
|
57293
57469
|
const prefix = HUMANIZE_TEMPLATE_BY_KIND[clarification.kind];
|
|
57294
|
-
const context =
|
|
57295
|
-
clarification.rawQuestion.replace(/\b(?:parseable|SPEC_IDENTITY_MISMATCH|machine-usable)\b/gi, "").replace(/\s+/g, " ").trim(),
|
|
57296
|
-
HUMANIZE_CONTEXT_CAP
|
|
57297
|
-
);
|
|
57470
|
+
const context = clarification.rawQuestion.replace(/\b(?:parseable|SPEC_IDENTITY_MISMATCH|machine-usable)\b/gi, "").replace(/\s+/g, " ").trim();
|
|
57298
57471
|
return context ? `${prefix} ${context}` : prefix;
|
|
57299
57472
|
}
|
|
57300
57473
|
var defaultNativeSpecGateBuilders = { buildSpecGateDeps, runSpecGate };
|
|
@@ -57589,7 +57762,7 @@ function onComplete2(outcome, input) {
|
|
|
57589
57762
|
};
|
|
57590
57763
|
}
|
|
57591
57764
|
return {
|
|
57592
|
-
kind: "
|
|
57765
|
+
kind: "completed",
|
|
57593
57766
|
...taskId ? { taskId } : {},
|
|
57594
57767
|
body: taskRef ? `Consensus CONVERGED for ${taskRef} (spec Specs/${input.pageId}); spec_ready set. Ready to create an execution run.` : `Consensus CONVERGED for Specs/${input.pageId}; spec_ready set. Ready to create an execution run.`
|
|
57595
57768
|
};
|
|
@@ -57720,7 +57893,7 @@ function onComplete3(outcome, input) {
|
|
|
57720
57893
|
};
|
|
57721
57894
|
}
|
|
57722
57895
|
return {
|
|
57723
|
-
kind: "
|
|
57896
|
+
kind: "completed",
|
|
57724
57897
|
...taskId ? { taskId } : {},
|
|
57725
57898
|
body: taskRef ? `Deliverable consensus CONVERGED for ${taskRef} (Deliverables/${input.pageId}); it meets the acceptance criteria.` : `Deliverable consensus CONVERGED for Deliverables/${input.pageId}; it meets the acceptance criteria.`
|
|
57726
57899
|
};
|
|
@@ -57836,11 +58009,14 @@ var mcpToolNames = {
|
|
|
57836
58009
|
resetDirectorThread: "reset_director_thread",
|
|
57837
58010
|
archiveTask: "archive_task",
|
|
57838
58011
|
unarchiveTask: "unarchive_task",
|
|
58012
|
+
takeOverTask: "take_over_task",
|
|
58013
|
+
closeTaskAsWontDo: "close_task_as_wont_do",
|
|
57839
58014
|
updateWikiPage: "update_wiki_page",
|
|
57840
58015
|
markSpecReady: "mark_spec_ready",
|
|
57841
58016
|
runSpecConsensus: "run_spec_consensus",
|
|
57842
58017
|
runCodeReviewerGate: "run_code_reviewer_gate",
|
|
57843
58018
|
uploadArtifact: "upload_artifact",
|
|
58019
|
+
deliverFile: "deliver_file",
|
|
57844
58020
|
listArtifactFiles: "list_artifact_files",
|
|
57845
58021
|
reclaimExecutionRunLease: "reclaim_execution_run_lease",
|
|
57846
58022
|
restartExecutionRun: "restart_execution_run",
|
|
@@ -58342,6 +58518,8 @@ var updateTaskInputSchema = taskScopedSchema.merge(mrrlinTaskUpdateSchema);
|
|
|
58342
58518
|
var resetDirectorThreadInputSchema = taskScopedSchema;
|
|
58343
58519
|
var archiveTaskInputSchema = taskScopedSchema;
|
|
58344
58520
|
var unarchiveTaskInputSchema = taskScopedSchema;
|
|
58521
|
+
var takeOverTaskInputSchema = taskScopedSchema.merge(mrrlinTakeOverTaskRequestSchema);
|
|
58522
|
+
var closeTaskAsWontDoInputSchema = taskScopedSchema.merge(mrrlinCloseTaskAsWontDoRequestSchema);
|
|
58345
58523
|
var listPlansInputSchema = projectScopedSchema;
|
|
58346
58524
|
var createPlanInputSchema = projectScopedSchema.merge(mrrlinPlanCreateSchema);
|
|
58347
58525
|
var updatePlanInputSchema = planScopedSchema.merge(mrrlinPlanUpdateSchema);
|
|
@@ -58424,6 +58602,20 @@ var uploadArtifactInputSchema = projectScopedSchema.merge(
|
|
|
58424
58602
|
description: external_exports.string().optional().describe("Shown in the run's artifact history; ignored when runId is not provided.")
|
|
58425
58603
|
})
|
|
58426
58604
|
);
|
|
58605
|
+
var deliverFileInputSchema = projectScopedSchema.merge(
|
|
58606
|
+
external_exports.object({
|
|
58607
|
+
filename: external_exports.string().min(1).describe(
|
|
58608
|
+
"Bare filename with extension (e.g. 'notes.md'). No path separators or '..' allowed."
|
|
58609
|
+
),
|
|
58610
|
+
content: external_exports.string().describe("UTF-8 text content of the file."),
|
|
58611
|
+
class: mrrlinArtifactFileClassSchema.describe(
|
|
58612
|
+
"temp = 48h one-off hand-off; durable = 180d, for spec/evidence references."
|
|
58613
|
+
),
|
|
58614
|
+
taskId: mrrlinTaskIdSchema.optional(),
|
|
58615
|
+
runId: mrrlinExecutionRunIdSchema.optional(),
|
|
58616
|
+
description: external_exports.string().optional().describe("Shown in the run's artifact history; ignored when runId is not provided.")
|
|
58617
|
+
})
|
|
58618
|
+
);
|
|
58427
58619
|
var listArtifactFilesInputSchema = projectScopedSchema.merge(
|
|
58428
58620
|
external_exports.object({
|
|
58429
58621
|
taskId: mrrlinTaskIdSchema.optional(),
|
|
@@ -58499,6 +58691,8 @@ var mcpToolInputSchemas = {
|
|
|
58499
58691
|
[mcpToolNames.resetDirectorThread]: resetDirectorThreadInputSchema,
|
|
58500
58692
|
[mcpToolNames.archiveTask]: archiveTaskInputSchema,
|
|
58501
58693
|
[mcpToolNames.unarchiveTask]: unarchiveTaskInputSchema,
|
|
58694
|
+
[mcpToolNames.takeOverTask]: takeOverTaskInputSchema,
|
|
58695
|
+
[mcpToolNames.closeTaskAsWontDo]: closeTaskAsWontDoInputSchema,
|
|
58502
58696
|
[mcpToolNames.updateWikiPage]: updateWikiPageInputSchema,
|
|
58503
58697
|
[mcpToolNames.markSpecReady]: markSpecReadyInputSchema,
|
|
58504
58698
|
[mcpToolNames.runSpecConsensus]: runSpecConsensusInputSchema,
|
|
@@ -58507,6 +58701,7 @@ var mcpToolInputSchemas = {
|
|
|
58507
58701
|
[mcpToolNames.createInboxItem]: createInboxItemInputSchema,
|
|
58508
58702
|
[mcpToolNames.decideInboxItem]: decideInboxItemInputSchema,
|
|
58509
58703
|
[mcpToolNames.uploadArtifact]: uploadArtifactInputSchema,
|
|
58704
|
+
[mcpToolNames.deliverFile]: deliverFileInputSchema,
|
|
58510
58705
|
[mcpToolNames.listArtifactFiles]: listArtifactFilesInputSchema,
|
|
58511
58706
|
[mcpToolNames.reclaimExecutionRunLease]: reclaimExecutionRunLeaseInputSchema,
|
|
58512
58707
|
[mcpToolNames.restartExecutionRun]: restartExecutionRunInputSchema,
|
|
@@ -58568,6 +58763,8 @@ var mcpToolOperationIds = {
|
|
|
58568
58763
|
[mcpToolNames.resetDirectorThread]: openApiOperationIds.resetDirectorThread,
|
|
58569
58764
|
[mcpToolNames.archiveTask]: openApiOperationIds.archiveTask,
|
|
58570
58765
|
[mcpToolNames.unarchiveTask]: openApiOperationIds.unarchiveTask,
|
|
58766
|
+
[mcpToolNames.takeOverTask]: openApiOperationIds.takeOverTask,
|
|
58767
|
+
[mcpToolNames.closeTaskAsWontDo]: openApiOperationIds.closeTaskAsWontDo,
|
|
58571
58768
|
[mcpToolNames.updateWikiPage]: openApiOperationIds.updateWikiPage,
|
|
58572
58769
|
[mcpToolNames.markSpecReady]: openApiOperationIds.markSpecReady,
|
|
58573
58770
|
[mcpToolNames.listInboxItems]: openApiOperationIds.listInboxItems,
|
|
@@ -58619,6 +58816,8 @@ var mcpToolDescriptions = {
|
|
|
58619
58816
|
[mcpToolNames.resetDirectorThread]: "Clear a task's persisted Director execution thread handle so the next execution run starts a fresh provider thread. Records a director_thread_reset task event.",
|
|
58620
58817
|
[mcpToolNames.archiveTask]: "Archive a task: hides it from default reads, removes it from plan progress and scheduler consideration, cancels its non-terminal execution runs, and closes its open inbox items. Reversible \u2014 the project owner can restore it with unarchive_task. Records an 'archived' task event.",
|
|
58621
58818
|
[mcpToolNames.unarchiveTask]: "Restore an archived task to its original status and visibility. Owner-only \u2014 refused with NOT_PROJECT_OWNER for any other caller. Does not resurrect the execution runs or inbox items that were cancelled/closed when the task was archived. Records a 'restored' task event.",
|
|
58819
|
+
[mcpToolNames.takeOverTask]: "Take ownership of a task by assigning it to the provided assignee through the dedicated take-over route.",
|
|
58820
|
+
[mcpToolNames.closeTaskAsWontDo]: "Close a task as won't-do with a required human-readable reason recorded on the task.",
|
|
58622
58821
|
[mcpToolNames.updateWikiPage]: "Update a markdown Wiki page.",
|
|
58623
58822
|
[mcpToolNames.markSpecReady]: "Mark a wiki page (folder=Specs) as ready (or not) for execution-run gating. The Director sets this true after validating the spec; any edit to the page's markdown auto-resets it to false.",
|
|
58624
58823
|
[mcpToolNames.runSpecConsensus]: 'Enqueue the consensus review gate over a Specs/{id} page. Returns IMMEDIATELY with one of: already_converged (a CONVERGED review already exists for the current content \u2014 proceed straight to create_execution_run, do NOT call mark_spec_ready, it is already set), already_reviewed (a terminal CONSENSUS_BLOCKED for this content), already_running (a consensus job is in flight), or queued (a new job was launched). The review runs in the background; its result/blocker arrives in the inbox (info on CONVERGED, handoff on failure) and is surfaced into the open chat. Do NOT call again for the same spec and do NOT poll. On queued/already_running, tell the user it was launched and end the turn. Pass extraHeads: ["researcher"] for specs referencing external libraries/APIs, or ["debugger"] for root-cause/investigation specs to add opt-in specialist reviewers on top of the fixed four. For a NON-code task (domain seo/marketing/content, ADR 0020): the low-risk lanes `seo`, `marketing`, and `content` proceed to `create_execution_run` after consensus, using the same flow as code tasks. Report the spec\'s review outcome to the operator.',
|
|
@@ -58640,6 +58839,7 @@ var mcpToolDescriptions = {
|
|
|
58640
58839
|
[mcpToolNames.createInboxItem]: "Create an operator-inbox item (proposal, check_in, question, handoff, or info) for a project.",
|
|
58641
58840
|
[mcpToolNames.decideInboxItem]: "Approve, reject, or acknowledge an operator-inbox item. Rejection requires a reason.",
|
|
58642
58841
|
[mcpToolNames.uploadArtifact]: "Upload a local file (md/txt/html/csv/json/pdf/png/jpg/webp/gif, <=5MB) as a project artifact. Returns a stable markdown link to embed in chat/spec/handoff text. Use class=temp for one-off hand-offs, class=durable for anything referenced by specs or evidence. Pass runId to record the file in that run's artifact history; pass taskId to surface it on the task's Artifacts list.",
|
|
58842
|
+
[mcpToolNames.deliverFile]: "This is the DEFAULT way to deliver a file the agent just composed; it takes the body inline as UTF-8 `content` in one call and needs no local file or writable path; `upload_artifact` is for a file that already exists on disk; use class=temp / class=durable and taskId/runId semantics with a 5MB cap.",
|
|
58643
58843
|
[mcpToolNames.listArtifactFiles]: "List uploaded artifact files for the project (optionally filtered by taskId/runId), newest first.",
|
|
58644
58844
|
[mcpToolNames.reclaimExecutionRunLease]: "Clear a stale pending execution-run lease when the lease has aged past staleSeconds. Returns the reclaimed run on success, null when the lease is not stale yet, and surfaces a structured conflict when reclaim retries are exhausted.",
|
|
58645
58845
|
[mcpToolNames.restartExecutionRun]: "Restart a parked execution run (handoff_requested or handoff_queued) back to pending so the queue can resume it.",
|
|
@@ -58786,6 +58986,68 @@ function makeReadTool(client, name, fallbackCode, fallbackMessage, handler, proj
|
|
|
58786
58986
|
}
|
|
58787
58987
|
function createMrrlinTools(options) {
|
|
58788
58988
|
const client = createMrrlinClient(withAuth(options));
|
|
58989
|
+
async function uploadArtifactBytes(c, args) {
|
|
58990
|
+
const { bytes: bytes3, class: artifactClass, contentType, description, filename, projectSlug, runId, taskId } = args;
|
|
58991
|
+
const created = await c.createArtifactFile(projectSlug, {
|
|
58992
|
+
class: artifactClass,
|
|
58993
|
+
contentType,
|
|
58994
|
+
filename,
|
|
58995
|
+
runId,
|
|
58996
|
+
sizeBytes: bytes3.byteLength,
|
|
58997
|
+
taskId
|
|
58998
|
+
});
|
|
58999
|
+
let stage = "upload";
|
|
59000
|
+
try {
|
|
59001
|
+
if (created.upload.kind === "presigned-post") {
|
|
59002
|
+
const form = new FormData();
|
|
59003
|
+
for (const [field, value] of Object.entries(created.upload.fields)) {
|
|
59004
|
+
form.append(field, value);
|
|
59005
|
+
}
|
|
59006
|
+
form.append("file", new Blob([bytes3], { type: contentType }), filename);
|
|
59007
|
+
const bareFetch = options.fetch ?? globalThis.fetch;
|
|
59008
|
+
const uploadResponse = await bareFetch(created.upload.url, { body: form, method: "POST" });
|
|
59009
|
+
if (!uploadResponse.ok) {
|
|
59010
|
+
throw new Error(
|
|
59011
|
+
`Presigned upload failed: ${uploadResponse.status} ${await uploadResponse.text()}`
|
|
59012
|
+
);
|
|
59013
|
+
}
|
|
59014
|
+
} else {
|
|
59015
|
+
await c.uploadArtifactFileContent(projectSlug, created.artifact.id, bytes3, contentType);
|
|
59016
|
+
}
|
|
59017
|
+
stage = "complete";
|
|
59018
|
+
const completed = await c.completeArtifactFile(projectSlug, created.artifact.id);
|
|
59019
|
+
if (completed.runId) {
|
|
59020
|
+
stage = "append-run-artifact";
|
|
59021
|
+
await c.appendExecutionArtifact(projectSlug, completed.runId, {
|
|
59022
|
+
id: `EA-${completed.id}`,
|
|
59023
|
+
kind: "file",
|
|
59024
|
+
payload: {
|
|
59025
|
+
artifactFileId: completed.id,
|
|
59026
|
+
class: completed.class,
|
|
59027
|
+
contentType: completed.contentType,
|
|
59028
|
+
description: description ?? null,
|
|
59029
|
+
filename: completed.filename,
|
|
59030
|
+
sizeBytes: completed.sizeBytes,
|
|
59031
|
+
stableUrl: created.stableUrl
|
|
59032
|
+
}
|
|
59033
|
+
});
|
|
59034
|
+
}
|
|
59035
|
+
const markdown = contentType.startsWith("image/") ? `` : `[${completed.filename}](${created.stableUrl})`;
|
|
59036
|
+
return {
|
|
59037
|
+
artifactFile: completed,
|
|
59038
|
+
markdown,
|
|
59039
|
+
stableUrl: created.stableUrl
|
|
59040
|
+
};
|
|
59041
|
+
} catch (error51) {
|
|
59042
|
+
const original = error51 instanceof MrrlinApiError ? error51.code : error51 instanceof McpToolCodedError ? error51.code : "ARTIFACT_FILE_UPLOAD_FAILED";
|
|
59043
|
+
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
59044
|
+
const note = stage === "append-run-artifact" ? "file uploaded and completed successfully; only the run-history append failed \u2014 do NOT re-upload, reference the stableUrl directly" : "a pending row may remain; it is reaped automatically after 1h";
|
|
59045
|
+
throw new McpToolCodedError(
|
|
59046
|
+
original,
|
|
59047
|
+
`artifactFileId=${created.artifact.id} stableUrl=${created.stableUrl} (failed at ${stage}; ${note}): ${message}`
|
|
59048
|
+
);
|
|
59049
|
+
}
|
|
59050
|
+
}
|
|
58789
59051
|
return {
|
|
58790
59052
|
[mcpToolNames.archivePlan]: makeTool(
|
|
58791
59053
|
client,
|
|
@@ -59066,6 +59328,20 @@ function createMrrlinTools(options) {
|
|
|
59066
59328
|
"Unable to unarchive task.",
|
|
59067
59329
|
async (c, { projectSlug, taskId }) => await c.unarchiveTask(projectSlug, taskId)
|
|
59068
59330
|
),
|
|
59331
|
+
[mcpToolNames.takeOverTask]: makeTool(
|
|
59332
|
+
client,
|
|
59333
|
+
mcpToolNames.takeOverTask,
|
|
59334
|
+
"TASK_TAKE_OVER_FAILED",
|
|
59335
|
+
"Unable to take over task.",
|
|
59336
|
+
async (c, { projectSlug, taskId, assignee }) => await c.takeOverTask(projectSlug, taskId, assignee)
|
|
59337
|
+
),
|
|
59338
|
+
[mcpToolNames.closeTaskAsWontDo]: makeTool(
|
|
59339
|
+
client,
|
|
59340
|
+
mcpToolNames.closeTaskAsWontDo,
|
|
59341
|
+
"TASK_CLOSE_AS_WONT_DO_FAILED",
|
|
59342
|
+
"Unable to close task as won't-do.",
|
|
59343
|
+
async (c, { projectSlug, taskId, reason }) => await c.closeTaskAsWontDo(projectSlug, taskId, reason)
|
|
59344
|
+
),
|
|
59069
59345
|
[mcpToolNames.updateWikiPage]: makeTool(
|
|
59070
59346
|
client,
|
|
59071
59347
|
mcpToolNames.updateWikiPage,
|
|
@@ -59339,65 +59615,61 @@ function createMrrlinTools(options) {
|
|
|
59339
59615
|
);
|
|
59340
59616
|
}
|
|
59341
59617
|
const filename = import_node_path20.default.basename(filePath);
|
|
59342
|
-
|
|
59618
|
+
return uploadArtifactBytes(c, {
|
|
59619
|
+
bytes: bytes3,
|
|
59343
59620
|
class: artifactClass,
|
|
59344
59621
|
contentType,
|
|
59622
|
+
description,
|
|
59345
59623
|
filename,
|
|
59624
|
+
projectSlug,
|
|
59346
59625
|
runId,
|
|
59347
|
-
sizeBytes: bytes3.byteLength,
|
|
59348
59626
|
taskId
|
|
59349
59627
|
});
|
|
59350
|
-
|
|
59351
|
-
|
|
59352
|
-
|
|
59353
|
-
|
|
59354
|
-
|
|
59355
|
-
|
|
59356
|
-
|
|
59357
|
-
|
|
59358
|
-
|
|
59359
|
-
|
|
59360
|
-
|
|
59361
|
-
|
|
59362
|
-
|
|
59363
|
-
|
|
59364
|
-
|
|
59365
|
-
|
|
59366
|
-
|
|
59367
|
-
|
|
59368
|
-
|
|
59369
|
-
|
|
59370
|
-
|
|
59371
|
-
|
|
59372
|
-
|
|
59373
|
-
|
|
59374
|
-
|
|
59375
|
-
|
|
59376
|
-
|
|
59377
|
-
|
|
59378
|
-
|
|
59379
|
-
|
|
59380
|
-
filename: completed.filename,
|
|
59381
|
-
sizeBytes: completed.sizeBytes,
|
|
59382
|
-
stableUrl: created.stableUrl
|
|
59383
|
-
}
|
|
59384
|
-
});
|
|
59385
|
-
}
|
|
59386
|
-
const markdown = contentType.startsWith("image/") ? `` : `[${completed.filename}](${created.stableUrl})`;
|
|
59387
|
-
return {
|
|
59388
|
-
artifactFile: completed,
|
|
59389
|
-
markdown,
|
|
59390
|
-
stableUrl: created.stableUrl
|
|
59391
|
-
};
|
|
59392
|
-
} catch (error51) {
|
|
59393
|
-
const original = error51 instanceof MrrlinApiError ? error51.code : error51 instanceof McpToolCodedError ? error51.code : "ARTIFACT_FILE_UPLOAD_FAILED";
|
|
59394
|
-
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
59395
|
-
const note = stage === "append-run-artifact" ? "file uploaded and completed successfully; only the run-history append failed \u2014 do NOT re-upload, reference the stableUrl directly" : "a pending row may remain; it is reaped automatically after 1h";
|
|
59628
|
+
}
|
|
59629
|
+
),
|
|
59630
|
+
[mcpToolNames.deliverFile]: makeTool(
|
|
59631
|
+
client,
|
|
59632
|
+
mcpToolNames.deliverFile,
|
|
59633
|
+
"ARTIFACT_FILE_UPLOAD_FAILED",
|
|
59634
|
+
"Unable to deliver artifact file.",
|
|
59635
|
+
async (c, { projectSlug, filename, content, class: artifactClass, taskId, runId, description }) => {
|
|
59636
|
+
if (filename.includes("/") || filename.includes("\\") || filename.includes("..")) {
|
|
59637
|
+
throw new McpToolCodedError(
|
|
59638
|
+
"ARTIFACT_FILE_NAME_INVALID",
|
|
59639
|
+
`Invalid filename '${filename}'; provide a bare filename with no path separators or '..'.`
|
|
59640
|
+
);
|
|
59641
|
+
}
|
|
59642
|
+
const extension2 = import_node_path20.default.extname(filename).toLowerCase();
|
|
59643
|
+
const contentType = ARTIFACT_EXTENSION_TYPES[extension2];
|
|
59644
|
+
if (!contentType) {
|
|
59645
|
+
throw new McpToolCodedError(
|
|
59646
|
+
"ARTIFACT_FILE_TYPE_UNSUPPORTED",
|
|
59647
|
+
`Unsupported artifact extension '${extension2}'. Allowed: ${Object.keys(ARTIFACT_EXTENSION_TYPES).join(", ")}.`
|
|
59648
|
+
);
|
|
59649
|
+
}
|
|
59650
|
+
const bytes3 = new Uint8Array(Buffer.from(content, "utf8"));
|
|
59651
|
+
if (bytes3.byteLength === 0) {
|
|
59652
|
+
throw new McpToolCodedError(
|
|
59653
|
+
"ARTIFACT_FILE_EMPTY",
|
|
59654
|
+
"File is empty (0 bytes); write content before uploading."
|
|
59655
|
+
);
|
|
59656
|
+
}
|
|
59657
|
+
if (bytes3.byteLength > MRRLIN_ARTIFACT_FILE_MAX_BYTES) {
|
|
59396
59658
|
throw new McpToolCodedError(
|
|
59397
|
-
|
|
59398
|
-
|
|
59659
|
+
"ARTIFACT_FILE_TOO_LARGE",
|
|
59660
|
+
"Artifact exceeds 5MB; split or summarize instead."
|
|
59399
59661
|
);
|
|
59400
59662
|
}
|
|
59663
|
+
return uploadArtifactBytes(c, {
|
|
59664
|
+
bytes: bytes3,
|
|
59665
|
+
class: artifactClass,
|
|
59666
|
+
contentType,
|
|
59667
|
+
description,
|
|
59668
|
+
filename,
|
|
59669
|
+
projectSlug,
|
|
59670
|
+
runId,
|
|
59671
|
+
taskId
|
|
59672
|
+
});
|
|
59401
59673
|
}
|
|
59402
59674
|
),
|
|
59403
59675
|
[mcpToolNames.listArtifactFiles]: makeTool(
|
|
@@ -59688,13 +59960,15 @@ function installService(deps) {
|
|
|
59688
59960
|
}
|
|
59689
59961
|
const resolvedBins = bins.filter((b) => b !== null);
|
|
59690
59962
|
const pathEnv = Array.from(new Set(resolvedBins.map((b) => import_node_path21.default.dirname(b)))).join(":");
|
|
59963
|
+
const apiBaseUrl = deps.env.MRRLIN_API_BASE_URL?.trim() || void 0;
|
|
59964
|
+
const staging = deps.env.MRRLIN_STAGING === "1" || !apiBaseUrl && bridgeUrlImpliesStaging(deps.env.MRRLIN_BRIDGE_URL);
|
|
59691
59965
|
const text = renderEcosystemConfig({
|
|
59692
59966
|
cwd: resolved.cwd,
|
|
59693
59967
|
home,
|
|
59694
59968
|
codexHome: deps.env.CODEX_HOME?.trim() || void 0,
|
|
59695
59969
|
pathEnv,
|
|
59696
|
-
staging
|
|
59697
|
-
apiBaseUrl
|
|
59970
|
+
staging,
|
|
59971
|
+
apiBaseUrl
|
|
59698
59972
|
});
|
|
59699
59973
|
const ecoPath = import_node_path21.default.join(home, ".mrrlin", "ecosystem.config.cjs");
|
|
59700
59974
|
deps.writeFile(ecoPath, text);
|
|
@@ -59817,22 +60091,22 @@ Usage:
|
|
|
59817
60091
|
mrrlin-mcp install-browser Idempotently install the dedicated, pinned
|
|
59818
60092
|
Chromium into ~/.mrrlin/browser/browsers (its own
|
|
59819
60093
|
copy, isolated from the operator's Chrome and
|
|
59820
|
-
codex-chrome). Run by
|
|
60094
|
+
codex-chrome). Run by configure bridge; safe to
|
|
59821
60095
|
re-run. Exits non-zero on download failure.
|
|
59822
60096
|
|
|
59823
60097
|
mrrlin-mcp browser-serve Launch the vendored @playwright/mcp against the
|
|
59824
60098
|
dedicated persistent profile
|
|
59825
60099
|
(~/.mrrlin/browser/profile, headed). This is the
|
|
59826
|
-
command
|
|
60100
|
+
command configure bridge wires for the
|
|
59827
60101
|
[mcp_servers.mrrlin-browser] block.
|
|
59828
60102
|
|
|
59829
60103
|
mrrlin-mcp external-agents-serve
|
|
59830
60104
|
Launch the bundled @mrrlin-dev/external-agents
|
|
59831
60105
|
MCP server (multi-LLM dispatch pool). This is the
|
|
59832
|
-
command
|
|
60106
|
+
command configure bridge wires for the
|
|
59833
60107
|
[mcp_servers.external-agents] block.
|
|
59834
60108
|
|
|
59835
|
-
mrrlin-mcp
|
|
60109
|
+
mrrlin-mcp configure bridge Idempotently register Mrrlin in
|
|
59836
60110
|
[--force] ~/.codex/config.toml (or CODEX_HOME). Adds an
|
|
59837
60111
|
[mcp_servers.mrrlin] block. Development
|
|
59838
60112
|
checkouts register the local dist/bin.cjs;
|
|
@@ -59841,12 +60115,12 @@ Usage:
|
|
|
59841
60115
|
Bakes API-target env vars into the block as an
|
|
59842
60116
|
inline env table so \`serve\` boots even when the
|
|
59843
60117
|
local 127.0.0.1:8787 is not running. Setup guide:
|
|
59844
|
-
MRRLIN_STAGING=1 mrrlin-mcp
|
|
60118
|
+
MRRLIN_STAGING=1 mrrlin-mcp configure bridge
|
|
59845
60119
|
is the canonical path (staging alias + remote-
|
|
59846
60120
|
allow gate in one flag). For a non-staging remote,
|
|
59847
60121
|
pass BOTH the URL AND the allow gate:
|
|
59848
60122
|
MRRLIN_API_BASE_URL=https://... \\
|
|
59849
|
-
MRRLIN_API_ALLOW_REMOTE=1 mrrlin-mcp
|
|
60123
|
+
MRRLIN_API_ALLOW_REMOTE=1 mrrlin-mcp configure bridge
|
|
59850
60124
|
Without an allow gate, \`serve\` still refuses any
|
|
59851
60125
|
non-loopback URL (see \`mrrlin-mcp serve\` above).
|
|
59852
60126
|
URL and MRRLIN_STAGING are mutually exclusive at
|
|
@@ -59959,8 +60233,8 @@ Usage:
|
|
|
59959
60233
|
mrrlin-mcp --help Show this help.
|
|
59960
60234
|
|
|
59961
60235
|
Operator notes:
|
|
59962
|
-
-
|
|
59963
|
-
-
|
|
60236
|
+
- configure bridge is idempotent: a second run with the same target is a no-op.
|
|
60237
|
+
- configure bridge auto-detects how it was installed. Development checkouts keep
|
|
59964
60238
|
using the local dist/bin.cjs; npm installs use
|
|
59965
60239
|
\`mrrlin-mcp serve\`.
|
|
59966
60240
|
`;
|
|
@@ -59995,16 +60269,29 @@ async function main() {
|
|
|
59995
60269
|
process.exitCode = r.status ?? 1;
|
|
59996
60270
|
return;
|
|
59997
60271
|
}
|
|
59998
|
-
case "
|
|
59999
|
-
const
|
|
60272
|
+
case "configure": {
|
|
60273
|
+
const [target, ...configureRest] = rest;
|
|
60274
|
+
if (target !== "bridge") {
|
|
60275
|
+
process.stderr.write(
|
|
60276
|
+
`configure requires a target. The only supported form is:
|
|
60277
|
+
mrrlin-mcp configure bridge [--force]
|
|
60278
|
+
`
|
|
60279
|
+
);
|
|
60280
|
+
if (target !== void 0) {
|
|
60281
|
+
process.stderr.write(`Unknown configure target: ${target}
|
|
60282
|
+
`);
|
|
60283
|
+
}
|
|
60284
|
+
process.exit(2);
|
|
60285
|
+
}
|
|
60286
|
+
const force = configureRest.includes("--force");
|
|
60000
60287
|
const binPath = resolveSelfBinPath();
|
|
60001
60288
|
try {
|
|
60002
60289
|
const b = await installBrowser();
|
|
60003
|
-
process.stderr.write(`[mrrlin-mcp
|
|
60290
|
+
process.stderr.write(`[mrrlin-mcp configure bridge] install-browser ${b.action} ${b.browsersPath}
|
|
60004
60291
|
`);
|
|
60005
60292
|
} catch (error51) {
|
|
60006
60293
|
process.stderr.write(
|
|
60007
|
-
`[mrrlin-mcp
|
|
60294
|
+
`[mrrlin-mcp configure bridge] install-browser FAILED \u2014 config.toml left untouched: ${error51 instanceof Error ? error51.message : String(error51)}
|
|
60008
60295
|
`
|
|
60009
60296
|
);
|
|
60010
60297
|
process.exit(2);
|
|
@@ -60015,18 +60302,18 @@ async function main() {
|
|
|
60015
60302
|
force,
|
|
60016
60303
|
serveEnv
|
|
60017
60304
|
});
|
|
60018
|
-
process.stderr.write(`[mrrlin-mcp
|
|
60305
|
+
process.stderr.write(`[mrrlin-mcp configure bridge] ${result.action} ${result.configPath}
|
|
60019
60306
|
`);
|
|
60020
60307
|
for (const preserved of result.preservedEnvBlocks) {
|
|
60021
60308
|
process.stderr.write(`${renderEnvPreservedNotice(preserved.blockId, preserved.envKeys)}
|
|
60022
60309
|
`);
|
|
60023
60310
|
}
|
|
60024
60311
|
for (const p of result.prompts) {
|
|
60025
|
-
process.stderr.write(`[mrrlin-mcp
|
|
60312
|
+
process.stderr.write(`[mrrlin-mcp configure bridge] prompt ${p.name}: ${p.action} ${p.promptPath}
|
|
60026
60313
|
`);
|
|
60027
60314
|
if (p.action === "skipped-modified") {
|
|
60028
60315
|
process.stderr.write(
|
|
60029
|
-
`[mrrlin-mcp
|
|
60316
|
+
`[mrrlin-mcp configure bridge] prompt ${p.name}: kept your local edits; run with --force-prompts to overwrite (or delete ${p.promptPath} to take the new bundled version)
|
|
60030
60317
|
`
|
|
60031
60318
|
);
|
|
60032
60319
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrrlin-dev/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mrrlin-mcp": "dist/bin.cjs"
|
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"@types/ws": "^8.18.1",
|
|
22
22
|
"esbuild": "^0.24.0",
|
|
23
23
|
"tsx": "^4.22.3",
|
|
24
|
-
"@mrrlin/wiki": "0.0.0",
|
|
25
|
-
"@mrrlin/schemas": "0.0.0",
|
|
26
24
|
"@mrrlin/client": "0.0.0",
|
|
27
|
-
"@mrrlin/
|
|
25
|
+
"@mrrlin/codex-client": "0.0.0",
|
|
28
26
|
"@mrrlin/director-e2e": "0.0.0",
|
|
29
|
-
"@mrrlin/
|
|
27
|
+
"@mrrlin/schemas": "0.0.0",
|
|
28
|
+
"@mrrlin/tsconfig": "0.0.0",
|
|
29
|
+
"@mrrlin/wiki": "0.0.0"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@iarna/toml": "^2.2.5",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"dev": "tsx watch src/bin.ts serve",
|
|
48
48
|
"lint": "eslint .",
|
|
49
49
|
"start": "node dist/bin.cjs serve",
|
|
50
|
-
"test": "node scripts/write-version.mjs && node --import tsx --test $(find src -name '*.test.ts' | sort | tr '\\n' ' ')",
|
|
50
|
+
"test": "pnpm --filter @mrrlin/codex-client build && node scripts/write-version.mjs && node --import tsx --test $(find src -name '*.test.ts' | sort | tr '\\n' ' ')",
|
|
51
51
|
"typecheck": "node scripts/write-version.mjs && pnpm --filter @mrrlin/schemas build && pnpm --filter @mrrlin/client build && pnpm --filter @mrrlin/wiki build && pnpm --filter @mrrlin/codex-client build && pnpm --filter @mrrlin/director-e2e build && tsc -p tsconfig.json --noEmit"
|
|
52
52
|
}
|
|
53
53
|
}
|