@mrrlin-dev/mcp 0.4.97 → 0.4.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin.cjs +485 -207
  2. package/package.json +1 -1
package/dist/bin.cjs CHANGED
@@ -1647,20 +1647,20 @@ var require_parse_async = __commonJS({
1647
1647
  const index = 0;
1648
1648
  const blocksize = opts.blocksize || 40960;
1649
1649
  const parser = new TOMLParser();
1650
- return new Promise((resolve, reject) => {
1651
- setImmediate(parseAsyncNext, index, blocksize, resolve, reject);
1650
+ return new Promise((resolve2, reject) => {
1651
+ setImmediate(parseAsyncNext, index, blocksize, resolve2, reject);
1652
1652
  });
1653
- function parseAsyncNext(index2, blocksize2, resolve, reject) {
1653
+ function parseAsyncNext(index2, blocksize2, resolve2, reject) {
1654
1654
  if (index2 >= str.length) {
1655
1655
  try {
1656
- return resolve(parser.finish());
1656
+ return resolve2(parser.finish());
1657
1657
  } catch (err) {
1658
1658
  return reject(prettyError(err, str));
1659
1659
  }
1660
1660
  }
1661
1661
  try {
1662
1662
  parser.parse(str.slice(index2, index2 + blocksize2));
1663
- setImmediate(parseAsyncNext, index2 + blocksize2, blocksize2, resolve, reject);
1663
+ setImmediate(parseAsyncNext, index2 + blocksize2, blocksize2, resolve2, reject);
1664
1664
  } catch (err) {
1665
1665
  reject(prettyError(err, str));
1666
1666
  }
@@ -1686,7 +1686,7 @@ var require_parse_stream = __commonJS({
1686
1686
  function parseReadable(stm) {
1687
1687
  const parser = new TOMLParser();
1688
1688
  stm.setEncoding("utf8");
1689
- return new Promise((resolve, reject) => {
1689
+ return new Promise((resolve2, reject) => {
1690
1690
  let readable;
1691
1691
  let ended = false;
1692
1692
  let errored = false;
@@ -1694,7 +1694,7 @@ var require_parse_stream = __commonJS({
1694
1694
  ended = true;
1695
1695
  if (readable) return;
1696
1696
  try {
1697
- resolve(parser.finish());
1697
+ resolve2(parser.finish());
1698
1698
  } catch (err) {
1699
1699
  reject(err);
1700
1700
  }
@@ -4980,7 +4980,7 @@ var require_compile = __commonJS({
4980
4980
  const schOrFunc = root.refs[ref];
4981
4981
  if (schOrFunc)
4982
4982
  return schOrFunc;
4983
- let _sch = resolve.call(this, root, ref);
4983
+ let _sch = resolve2.call(this, root, ref);
4984
4984
  if (_sch === void 0) {
4985
4985
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
4986
4986
  const { schemaId } = this.opts;
@@ -5007,7 +5007,7 @@ var require_compile = __commonJS({
5007
5007
  function sameSchemaEnv(s1, s2) {
5008
5008
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
5009
5009
  }
5010
- function resolve(root, ref) {
5010
+ function resolve2(root, ref) {
5011
5011
  let sch;
5012
5012
  while (typeof (sch = this.refs[ref]) == "string")
5013
5013
  ref = sch;
@@ -5837,7 +5837,7 @@ var require_fast_uri = __commonJS({
5837
5837
  }
5838
5838
  return uri;
5839
5839
  }
5840
- function resolve(baseURI, relativeURI, options) {
5840
+ function resolve2(baseURI, relativeURI, options) {
5841
5841
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
5842
5842
  const {
5843
5843
  parsed: baseParsed,
@@ -6206,7 +6206,7 @@ var require_fast_uri = __commonJS({
6206
6206
  var fastUri = {
6207
6207
  SCHEMES,
6208
6208
  normalize: normalize2,
6209
- resolve,
6209
+ resolve: resolve2,
6210
6210
  resolveComponent,
6211
6211
  equal,
6212
6212
  serialize,
@@ -9393,12 +9393,12 @@ var require_isexe = __commonJS({
9393
9393
  if (typeof Promise !== "function") {
9394
9394
  throw new TypeError("callback not provided");
9395
9395
  }
9396
- return new Promise(function(resolve, reject) {
9396
+ return new Promise(function(resolve2, reject) {
9397
9397
  isexe(path29, options || {}, function(er, is) {
9398
9398
  if (er) {
9399
9399
  reject(er);
9400
9400
  } else {
9401
- resolve(is);
9401
+ resolve2(is);
9402
9402
  }
9403
9403
  });
9404
9404
  });
@@ -9464,27 +9464,27 @@ var require_which = __commonJS({
9464
9464
  opt = {};
9465
9465
  const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
9466
9466
  const found = [];
9467
- const step = (i) => new Promise((resolve, reject) => {
9467
+ const step = (i) => new Promise((resolve2, reject) => {
9468
9468
  if (i === pathEnv.length)
9469
- return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
9469
+ return opt.all && found.length ? resolve2(found) : reject(getNotFoundError(cmd));
9470
9470
  const ppRaw = pathEnv[i];
9471
9471
  const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
9472
9472
  const pCmd = path29.join(pathPart, cmd);
9473
9473
  const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
9474
- resolve(subStep(p, i, 0));
9474
+ resolve2(subStep(p, i, 0));
9475
9475
  });
9476
- const subStep = (p, i, ii) => new Promise((resolve, reject) => {
9476
+ const subStep = (p, i, ii) => new Promise((resolve2, reject) => {
9477
9477
  if (ii === pathExt.length)
9478
- return resolve(step(i + 1));
9478
+ return resolve2(step(i + 1));
9479
9479
  const ext = pathExt[ii];
9480
9480
  isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
9481
9481
  if (!er && is) {
9482
9482
  if (opt.all)
9483
9483
  found.push(p + ext);
9484
9484
  else
9485
- return resolve(p + ext);
9485
+ return resolve2(p + ext);
9486
9486
  }
9487
- return resolve(subStep(p, i, ii + 1));
9487
+ return resolve2(subStep(p, i, ii + 1));
9488
9488
  });
9489
9489
  });
9490
9490
  return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
@@ -14017,7 +14017,7 @@ var require_websocket = __commonJS({
14017
14017
  var http2 = require("http");
14018
14018
  var net = require("net");
14019
14019
  var tls = require("tls");
14020
- var { randomBytes: randomBytes5, createHash: createHash5 } = require("crypto");
14020
+ var { randomBytes: randomBytes5, createHash: createHash6 } = require("crypto");
14021
14021
  var { Duplex, Readable } = require("stream");
14022
14022
  var { URL: URL2 } = require("url");
14023
14023
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -14685,7 +14685,7 @@ var require_websocket = __commonJS({
14685
14685
  abortHandshake(websocket, socket, "Invalid Upgrade header");
14686
14686
  return;
14687
14687
  }
14688
- const digest = createHash5("sha1").update(key + GUID).digest("base64");
14688
+ const digest = createHash6("sha1").update(key + GUID).digest("base64");
14689
14689
  if (res.headers["sec-websocket-accept"] !== digest) {
14690
14690
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
14691
14691
  return;
@@ -15054,7 +15054,7 @@ var require_websocket_server = __commonJS({
15054
15054
  var EventEmitter3 = require("events");
15055
15055
  var http2 = require("http");
15056
15056
  var { Duplex } = require("stream");
15057
- var { createHash: createHash5 } = require("crypto");
15057
+ var { createHash: createHash6 } = require("crypto");
15058
15058
  var extension2 = require_extension();
15059
15059
  var PerMessageDeflate2 = require_permessage_deflate();
15060
15060
  var subprotocol2 = require_subprotocol();
@@ -15361,7 +15361,7 @@ var require_websocket_server = __commonJS({
15361
15361
  );
15362
15362
  }
15363
15363
  if (this._state > RUNNING) return abortHandshake(socket, 503);
15364
- const digest = createHash5("sha1").update(key + GUID).digest("base64");
15364
+ const digest = createHash6("sha1").update(key + GUID).digest("base64");
15365
15365
  const headers = [
15366
15366
  "HTTP/1.1 101 Switching Protocols",
15367
15367
  "Upgrade: websocket",
@@ -16947,12 +16947,12 @@ var require_adapter = __commonJS({
16947
16947
  return newFs;
16948
16948
  }
16949
16949
  function toPromise(method) {
16950
- return (...args) => new Promise((resolve, reject) => {
16950
+ return (...args) => new Promise((resolve2, reject) => {
16951
16951
  args.push((err, result) => {
16952
16952
  if (err) {
16953
16953
  reject(err);
16954
16954
  } else {
16955
- resolve(result);
16955
+ resolve2(result);
16956
16956
  }
16957
16957
  });
16958
16958
  method(...args);
@@ -21406,10 +21406,10 @@ var require_browser = __commonJS({
21406
21406
  text = canvas;
21407
21407
  canvas = void 0;
21408
21408
  }
21409
- return new Promise(function(resolve, reject) {
21409
+ return new Promise(function(resolve2, reject) {
21410
21410
  try {
21411
21411
  const data = QRCode2.create(text, opts);
21412
- resolve(renderFunc(data, canvas, opts));
21412
+ resolve2(renderFunc(data, canvas, opts));
21413
21413
  } catch (e) {
21414
21414
  reject(e);
21415
21415
  }
@@ -21490,11 +21490,11 @@ var require_server = __commonJS({
21490
21490
  }
21491
21491
  function render(renderFunc, text, params) {
21492
21492
  if (!params.cb) {
21493
- return new Promise(function(resolve, reject) {
21493
+ return new Promise(function(resolve2, reject) {
21494
21494
  try {
21495
21495
  const data = QRCode2.create(text, params.opts);
21496
21496
  return renderFunc(data, params.opts, function(err, data2) {
21497
- return err ? reject(err) : resolve(data2);
21497
+ return err ? reject(err) : resolve2(data2);
21498
21498
  });
21499
21499
  } catch (e) {
21500
21500
  reject(e);
@@ -37189,6 +37189,39 @@ function date4(params) {
37189
37189
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
37190
37190
  config(en_default());
37191
37191
 
37192
+ // ../../packages/schemas/dist/plans.js
37193
+ var PLAN_TIERS = ["base", "pro", "team", "ultra"];
37194
+ var planTierSchema = external_exports.enum(PLAN_TIERS);
37195
+ var billingPriceSchema = external_exports.object({
37196
+ amount: external_exports.number().int().nonnegative(),
37197
+ currency: external_exports.string().length(3)
37198
+ });
37199
+ var billingPlansResponseSchema = external_exports.object({
37200
+ data: external_exports.object({
37201
+ plans: external_exports.array(external_exports.object({
37202
+ tier: planTierSchema,
37203
+ name: external_exports.string().min(1),
37204
+ limits: external_exports.object({
37205
+ projects: external_exports.number().int(),
37206
+ seats: external_exports.number().int()
37207
+ }),
37208
+ prices: external_exports.object({
37209
+ month: billingPriceSchema.optional(),
37210
+ year: billingPriceSchema.optional()
37211
+ })
37212
+ }))
37213
+ })
37214
+ });
37215
+ var createCheckoutSessionRequestSchema = external_exports.object({
37216
+ tier: planTierSchema,
37217
+ interval: external_exports.enum(["month", "year"])
37218
+ });
37219
+ var billingUrlResponseSchema = external_exports.object({
37220
+ data: external_exports.object({
37221
+ url: external_exports.string().url()
37222
+ })
37223
+ });
37224
+
37192
37225
  // ../../packages/schemas/dist/artifact-checks.js
37193
37226
  var artifactKindSchema = external_exports.enum([
37194
37227
  "document",
@@ -37394,7 +37427,16 @@ var openApiOperationIds = {
37394
37427
  confirmFirstWrite: "confirmFirstWrite",
37395
37428
  resolveArtifactKindRoute: "resolveArtifactKindRoute",
37396
37429
  resolveDeliveryForArtifactKind: "resolveDeliveryForArtifactKind",
37397
- recordCapabilityUse: "recordCapabilityUse"
37430
+ recordCapabilityUse: "recordCapabilityUse",
37431
+ resolveAccount: "resolveAccount",
37432
+ linkAccountIdentity: "linkAccountIdentity",
37433
+ getMyAccount: "getMyAccount",
37434
+ getMyEntitlement: "getMyEntitlement",
37435
+ listBillingPlans: "listBillingPlans",
37436
+ createCheckoutSession: "createCheckoutSession",
37437
+ createBillingPortalSession: "createBillingPortalSession",
37438
+ syncBilling: "syncBilling",
37439
+ redeemAppsumoCode: "redeemAppsumoCode"
37398
37440
  };
37399
37441
 
37400
37442
  // ../../packages/schemas/dist/session.js
@@ -37414,10 +37456,13 @@ var operatorSessionSchema = external_exports.object({
37414
37456
  // Default 'project' for backward-compat: tokens minted before this field existed parse
37415
37457
  // cleanly into the project branch of the middleware (which mirrors today's behavior).
37416
37458
  scope: external_exports.enum(["project", "operator"]).default("project"),
37459
+ accountId: external_exports.string().uuid().optional(),
37460
+ identitySubject: external_exports.string().min(1).optional(),
37461
+ purpose: external_exports.enum(["session", "identity_assertion"]).default("session"),
37417
37462
  // Billing entitlement carried on the session. Optional because a GitHub session never has one
37418
37463
  // and a Firebase session has one only once the claims exist. `determinedAt` is what makes it
37419
37464
  // falsifiable: the token lives for 7 days, so a value that can go stale needs a freshness bound
37420
- // enforced by the reader (readEffectivePlan), not by the cookie.
37465
+ // enforced by the reader, not by the cookie.
37421
37466
  entitlement: external_exports.object({
37422
37467
  plan: external_exports.string(),
37423
37468
  status: external_exports.enum(["active", "none"]),
@@ -38064,6 +38109,24 @@ var TASK_NOTES_JOURNAL_SECTIONS = [
38064
38109
  ];
38065
38110
  var JOURNAL_HEADING_RE = new RegExp(`^##[ \\t]+(${TASK_NOTES_JOURNAL_SECTIONS.map((s) => s.heading).join("|")})\\b[ \\t]*(?:[\u2014\u2013-][ \\t]*(\\S.*?))?[ \\t]*$`);
38066
38111
 
38112
+ // ../../packages/schemas/dist/appsumo.js
38113
+ var APPSUMO_CODE_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
38114
+ var APPSUMO_ALPHABET_SET = new Set(APPSUMO_CODE_ALPHABET);
38115
+ var redeemAppsumoCodeRequestSchema = external_exports.object({
38116
+ code: external_exports.string().min(1).max(64)
38117
+ });
38118
+ var redeemAppsumoCodeResponseSchema = external_exports.object({
38119
+ data: external_exports.object({
38120
+ outcome: external_exports.enum(["redeemed", "already_redeemed_by_you"]),
38121
+ codes: external_exports.number().int().min(1).max(4),
38122
+ tier: planTierSchema,
38123
+ limits: external_exports.object({
38124
+ projects: external_exports.number().int().nonnegative(),
38125
+ seats: external_exports.number().int().nonnegative()
38126
+ })
38127
+ })
38128
+ });
38129
+
38067
38130
  // ../../packages/schemas/dist/integration-route-defaults.js
38068
38131
  var DEFAULT_INTEGRATION_ROUTES = {
38069
38132
  github: {
@@ -38665,9 +38728,12 @@ var mrrlinProjectSummarySchema = external_exports.object({
38665
38728
  clientName: external_exports.string().trim().max(80).nullable().optional(),
38666
38729
  scopeDescription: external_exports.string().trim().max(240).nullable().optional()
38667
38730
  });
38731
+ var mrrlinProjectOperatorInputSchema = external_exports.string().regex(/^@[!-~]+$/, "operator must be '@' followed by printable ASCII with no whitespace");
38668
38732
  var mrrlinProjectUpsertSchema = mrrlinProjectSummarySchema.omit({
38669
38733
  onboardingKickoffState: true,
38670
38734
  slug: true
38735
+ }).extend({
38736
+ github: mrrlinGithubBindingSchema.extend({ operator: mrrlinProjectOperatorInputSchema })
38671
38737
  });
38672
38738
  var mrrlinProjectRenameSchema = external_exports.object({
38673
38739
  displayName: external_exports.string().trim().min(1).max(120).optional(),
@@ -39091,13 +39157,61 @@ var projectSnapshotResponseSchema = external_exports.object({
39091
39157
  var projectSummaryResponseSchema = external_exports.object({
39092
39158
  data: mrrlinProjectSummarySchema
39093
39159
  });
39160
+ var projectListItemSchema = mrrlinProjectSummarySchema.extend({
39161
+ viewerRole: external_exports.enum(["owner", "collaborator"]).optional(),
39162
+ // True when this caller would get 402 (owner plan inactive, project over limit, or no seat) on
39163
+ // the project's routes. Lets the web skip paused projects when picking a default and offer the
39164
+ // ones that still open. Absent when the API runs without a session (auth disabled).
39165
+ paused: external_exports.boolean().optional()
39166
+ });
39094
39167
  var projectSummaryListResponseSchema = external_exports.object({
39095
- data: external_exports.array(mrrlinProjectSummarySchema),
39168
+ data: external_exports.array(projectListItemSchema),
39096
39169
  entitlement: external_exports.object({
39097
39170
  plan: external_exports.string(),
39098
39171
  status: external_exports.union([external_exports.literal("active"), external_exports.literal("none")])
39099
39172
  })
39100
39173
  });
39174
+ var accountEntitlementSchema = external_exports.object({
39175
+ accountId: external_exports.string(),
39176
+ standing: external_exports.enum(["entitled", "collaborator", "none"]),
39177
+ lapsed: external_exports.boolean(),
39178
+ tier: planTierSchema.nullable(),
39179
+ source: external_exports.enum(["stripe", "appsumo", "grant"]).nullable(),
39180
+ stripe: external_exports.object({
39181
+ status: external_exports.string(),
39182
+ tier: planTierSchema.nullable(),
39183
+ interval: external_exports.enum(["month", "year"]).nullable(),
39184
+ currentPeriodEnd: external_exports.string().nullable(),
39185
+ cancelAtPeriodEnd: external_exports.boolean()
39186
+ }).nullable(),
39187
+ appsumo: external_exports.object({
39188
+ codes: external_exports.number().int(),
39189
+ tier: planTierSchema
39190
+ }).nullable(),
39191
+ grant: external_exports.object({
39192
+ tier: planTierSchema,
39193
+ reason: external_exports.string()
39194
+ }).nullable(),
39195
+ limits: external_exports.object({
39196
+ projects: external_exports.number().int(),
39197
+ seats: external_exports.number().int()
39198
+ }).nullable(),
39199
+ usage: external_exports.object({
39200
+ projects: external_exports.number().int(),
39201
+ seats: external_exports.number().int()
39202
+ }),
39203
+ collaboratorProjects: external_exports.number().int(),
39204
+ upgradePath: external_exports.enum(["stripe", "appsumo", "none"]),
39205
+ tiers: external_exports.array(external_exports.object({
39206
+ tier: planTierSchema,
39207
+ projects: external_exports.number().int(),
39208
+ seats: external_exports.number().int(),
39209
+ selfServe: external_exports.boolean()
39210
+ }))
39211
+ });
39212
+ var accountEntitlementResponseSchema = external_exports.object({
39213
+ data: accountEntitlementSchema
39214
+ });
39101
39215
  var taskResponseSchema = external_exports.object({
39102
39216
  data: mrrlinTaskSchema
39103
39217
  });
@@ -40021,6 +40135,47 @@ function resolveProjectClientScope(project) {
40021
40135
  scopeDescription
40022
40136
  };
40023
40137
  }
40138
+ var resolvedAccountSchema = external_exports.object({
40139
+ accountId: external_exports.string().uuid(),
40140
+ principal: external_exports.string().min(1),
40141
+ emails: external_exports.array(external_exports.string().email()),
40142
+ providers: external_exports.array(external_exports.enum(["github", "firebase"]))
40143
+ });
40144
+ var resolveAccountResponseSchema = external_exports.object({
40145
+ data: external_exports.discriminatedUnion("outcome", [
40146
+ resolvedAccountSchema.extend({ outcome: external_exports.literal("resolved") }),
40147
+ resolvedAccountSchema.extend({ outcome: external_exports.literal("created") }),
40148
+ external_exports.object({
40149
+ outcome: external_exports.literal("link_required"),
40150
+ accountId: external_exports.string().uuid(),
40151
+ principal: external_exports.null(),
40152
+ emails: external_exports.array(external_exports.string()).length(0),
40153
+ providers: external_exports.array(external_exports.enum(["github", "firebase"])).min(1)
40154
+ }),
40155
+ external_exports.object({
40156
+ outcome: external_exports.literal("refused"),
40157
+ accountId: external_exports.string().uuid().nullable().optional(),
40158
+ principal: external_exports.null().optional(),
40159
+ emails: external_exports.array(external_exports.string()).optional(),
40160
+ providers: external_exports.array(external_exports.enum(["github", "firebase"])).optional()
40161
+ })
40162
+ ])
40163
+ });
40164
+ var linkAccountIdentityRequestSchema = external_exports.object({
40165
+ assertion: external_exports.string().min(1)
40166
+ });
40167
+ var accountSummaryResponseSchema = external_exports.object({
40168
+ data: external_exports.object({
40169
+ accountId: external_exports.string().uuid(),
40170
+ principal: external_exports.string().min(1),
40171
+ emails: external_exports.array(external_exports.string().email()),
40172
+ identities: external_exports.array(external_exports.object({
40173
+ provider: external_exports.enum(["github", "firebase"]),
40174
+ login: external_exports.string().nullable(),
40175
+ email: external_exports.string().nullable()
40176
+ }))
40177
+ })
40178
+ });
40024
40179
 
40025
40180
  // ../../packages/client/dist/agent-token-provider.js
40026
40181
  var AgentTokenProviderError = class extends Error {
@@ -41143,6 +41298,60 @@ function createMrrlinClient(config2) {
41143
41298
  await request(`/operator/agent-credentials/${encodeURIComponent(credentialId)}`, {
41144
41299
  method: "DELETE"
41145
41300
  });
41301
+ },
41302
+ async resolveAccount() {
41303
+ const body = await request("/auth/account/resolve", {
41304
+ method: "POST"
41305
+ });
41306
+ return resolveAccountResponseSchema.parse(body);
41307
+ },
41308
+ async linkAccountIdentity(assertion) {
41309
+ const body = await request("/auth/account/link", {
41310
+ body: JSON.stringify({ assertion }),
41311
+ headers: { "content-type": "application/json" },
41312
+ method: "POST"
41313
+ });
41314
+ return resolveAccountResponseSchema.parse(body);
41315
+ },
41316
+ async getMyAccount() {
41317
+ const body = await request("/me/account");
41318
+ return accountSummaryResponseSchema.parse(body);
41319
+ },
41320
+ async getMyEntitlement() {
41321
+ const body = await request("/me/entitlement");
41322
+ return accountEntitlementResponseSchema.parse(body).data;
41323
+ },
41324
+ async listBillingPlans() {
41325
+ const body = await request("/billing/plans");
41326
+ return billingPlansResponseSchema.parse(body).data.plans;
41327
+ },
41328
+ async createCheckoutSession(input) {
41329
+ const body = await request("/billing/checkout-session", {
41330
+ body: JSON.stringify(input),
41331
+ headers: { "content-type": "application/json" },
41332
+ method: "POST"
41333
+ });
41334
+ return billingUrlResponseSchema.parse(body).data;
41335
+ },
41336
+ async createBillingPortalSession() {
41337
+ const body = await request("/billing/portal-session", {
41338
+ method: "POST"
41339
+ });
41340
+ return billingUrlResponseSchema.parse(body).data;
41341
+ },
41342
+ async syncBilling() {
41343
+ const body = await request("/billing/sync", {
41344
+ method: "POST"
41345
+ });
41346
+ return accountEntitlementResponseSchema.parse(body).data;
41347
+ },
41348
+ async redeemAppsumoCode(code) {
41349
+ const body = await request("/appsumo/redeem", {
41350
+ body: JSON.stringify({ code }),
41351
+ headers: { "content-type": "application/json" },
41352
+ method: "POST"
41353
+ });
41354
+ return redeemAppsumoCodeResponseSchema.parse(body).data;
41146
41355
  }
41147
41356
  };
41148
41357
  }
@@ -41493,7 +41702,7 @@ function createBoundedSemaphore(slots) {
41493
41702
  let available = slots;
41494
41703
  const queue = [];
41495
41704
  return {
41496
- acquire: () => available > 0 ? (available -= 1, Promise.resolve()) : new Promise((resolve) => queue.push(resolve)),
41705
+ acquire: () => available > 0 ? (available -= 1, Promise.resolve()) : new Promise((resolve2) => queue.push(resolve2)),
41497
41706
  release: () => {
41498
41707
  const next = queue.shift();
41499
41708
  if (next) next();
@@ -42524,22 +42733,22 @@ var CodexJsonRpcClient = class {
42524
42733
  const payload = { jsonrpc: "2.0", id, method, params };
42525
42734
  const line = `${JSON.stringify(payload)}
42526
42735
  `;
42527
- const resultPromise = new Promise((resolve, reject) => {
42736
+ const resultPromise = new Promise((resolve2, reject) => {
42528
42737
  const onResponse = (response) => {
42529
42738
  if (response.error) {
42530
42739
  reject(new Error(response.error.message ?? "Codex JSON-RPC error"));
42531
42740
  return;
42532
42741
  }
42533
- resolve(response.result);
42742
+ resolve2(response.result);
42534
42743
  };
42535
42744
  this.emitter.once(`response:${id}`, onResponse);
42536
42745
  });
42537
- await new Promise((resolve, reject) => {
42746
+ await new Promise((resolve2, reject) => {
42538
42747
  this.writeStream.write(line, (error51) => {
42539
42748
  if (error51)
42540
42749
  reject(error51);
42541
42750
  else
42542
- resolve();
42751
+ resolve2();
42543
42752
  });
42544
42753
  });
42545
42754
  return await resultPromise;
@@ -42702,11 +42911,11 @@ var CodexServerManager = class {
42702
42911
  env: config2?.env ?? process.env,
42703
42912
  shell: true
42704
42913
  });
42705
- await new Promise((resolve, reject) => {
42914
+ await new Promise((resolve2, reject) => {
42706
42915
  child.on("error", (err) => {
42707
42916
  reject(new Error(`Failed to spawn codex app-server: ${err.message}`));
42708
42917
  });
42709
- child.on("spawn", () => resolve());
42918
+ child.on("spawn", () => resolve2());
42710
42919
  });
42711
42920
  if (!child.stdin || !child.stdout) {
42712
42921
  child.kill();
@@ -43485,7 +43694,7 @@ var ClaudeProcess = class {
43485
43694
  cwd: options.cwd?.trim() || void 0,
43486
43695
  // Inherit the operator's env so the CLI picks up their own ~/.claude.json tool registry —
43487
43696
  // unless an explicit mcpConfig was provided in options.
43488
- env: process.env,
43697
+ env: options.env ?? process.env,
43489
43698
  stdio: ["pipe", "pipe", "pipe"]
43490
43699
  });
43491
43700
  this.child.stdout.setEncoding("utf8");
@@ -43580,15 +43789,15 @@ var ClaudeProcess = class {
43580
43789
  return Promise.resolve();
43581
43790
  }
43582
43791
  if (this.disposed) {
43583
- return new Promise((resolve) => {
43792
+ return new Promise((resolve2) => {
43584
43793
  const off = this.onExit(() => {
43585
43794
  off();
43586
- resolve();
43795
+ resolve2();
43587
43796
  });
43588
43797
  });
43589
43798
  }
43590
43799
  this.disposed = true;
43591
- return new Promise((resolve) => {
43800
+ return new Promise((resolve2) => {
43592
43801
  const forceKill = setTimeout(() => {
43593
43802
  if (!this.exited)
43594
43803
  this.child.kill("SIGKILL");
@@ -43597,7 +43806,7 @@ var ClaudeProcess = class {
43597
43806
  const off = this.onExit(() => {
43598
43807
  clearTimeout(forceKill);
43599
43808
  off();
43600
- resolve();
43809
+ resolve2();
43601
43810
  });
43602
43811
  this.child.kill("SIGTERM");
43603
43812
  });
@@ -43797,11 +44006,16 @@ function permissionModeFor(sandbox) {
43797
44006
  return { permissionMode: "bypassPermissions" };
43798
44007
  }
43799
44008
  var ClaudeAgentHandle = class {
44009
+ childEnv;
43800
44010
  // One resident child + one mapper per thread — mirrors ClaudeProcess's own per-thread residency
43801
44011
  // and ClaudeBridgeEventMapper's documented "fresh instance per thread" contract (its tool-use
43802
44012
  // dedup sets must not leak across threads).
43803
44013
  processes = /* @__PURE__ */ new Map();
43804
44014
  mappers = /* @__PURE__ */ new Map();
44015
+ /** Exact complete environment passed unchanged to every process this handle spawns. */
44016
+ constructor(childEnv) {
44017
+ this.childEnv = childEnv;
44018
+ }
43805
44019
  async startThread(params) {
43806
44020
  const { permissionMode, disallowedTools } = permissionModeFor(params.sandbox);
43807
44021
  const child = new ClaudeProcess({
@@ -43811,7 +44025,8 @@ var ClaudeAgentHandle = class {
43811
44025
  model: params.model,
43812
44026
  cwd: params.cwd,
43813
44027
  mcpConfig: params.mcpConfig,
43814
- appendSystemPrompt: params.baseInstructions
44028
+ appendSystemPrompt: params.baseInstructions,
44029
+ ...this.childEnv === void 0 ? {} : { env: this.childEnv }
43815
44030
  });
43816
44031
  this.processes.set(child.sessionId, child);
43817
44032
  this.mappers.set(child.sessionId, new ClaudeBridgeEventMapper());
@@ -43826,7 +44041,8 @@ var ClaudeAgentHandle = class {
43826
44041
  model: params.model,
43827
44042
  cwd: params.cwd,
43828
44043
  mcpConfig: params.mcpConfig,
43829
- appendSystemPrompt: params.baseInstructions
44044
+ appendSystemPrompt: params.baseInstructions,
44045
+ ...this.childEnv === void 0 ? {} : { env: this.childEnv }
43830
44046
  });
43831
44047
  this.processes.set(threadId, child);
43832
44048
  this.mappers.set(threadId, new ClaudeBridgeEventMapper());
@@ -43986,7 +44202,7 @@ var AgyProcess = class _AgyProcess {
43986
44202
  const cwd = options.cwd?.trim() || void 0;
43987
44203
  this.child = (0, import_node_child_process4.spawn)(executable, args, {
43988
44204
  cwd,
43989
- env: process.env,
44205
+ env: options.env ?? process.env,
43990
44206
  stdio: ["pipe", "pipe", "pipe"]
43991
44207
  });
43992
44208
  activeProcesses.add(this.child);
@@ -44298,16 +44514,22 @@ function permissionModeFor2(sandbox, approvalPolicy) {
44298
44514
  return { permissionMode: "acceptEdits" };
44299
44515
  }
44300
44516
  var AgyAgentHandle = class {
44517
+ childEnv;
44301
44518
  processes = /* @__PURE__ */ new Map();
44302
44519
  mappers = /* @__PURE__ */ new Map();
44303
44520
  baseInstructions = /* @__PURE__ */ new Map();
44521
+ /** Exact complete environment passed unchanged to every process this handle spawns. */
44522
+ constructor(childEnv) {
44523
+ this.childEnv = childEnv;
44524
+ }
44304
44525
  async startThread(params) {
44305
44526
  const { permissionMode } = permissionModeFor2(params.sandbox, params.approvalPolicy);
44306
44527
  const child = new AgyProcess({
44307
44528
  mode: { kind: "new" },
44308
44529
  permissionMode,
44309
44530
  model: params.model,
44310
- cwd: params.cwd
44531
+ cwd: params.cwd,
44532
+ ...this.childEnv === void 0 ? {} : { env: this.childEnv }
44311
44533
  });
44312
44534
  this.processes.set(child.sessionId, child);
44313
44535
  this.mappers.set(child.sessionId, new AgyBridgeEventMapper());
@@ -44327,7 +44549,8 @@ var AgyAgentHandle = class {
44327
44549
  mode: { kind: "resume", resumeId: threadId },
44328
44550
  permissionMode,
44329
44551
  model: params.model,
44330
- cwd: params.cwd
44552
+ cwd: params.cwd,
44553
+ ...this.childEnv === void 0 ? {} : { env: this.childEnv }
44331
44554
  });
44332
44555
  this.processes.set(threadId, child);
44333
44556
  this.mappers.set(threadId, new AgyBridgeEventMapper());
@@ -44383,6 +44606,14 @@ ${text}`;
44383
44606
  async readRateLimits() {
44384
44607
  return null;
44385
44608
  }
44609
+ disposeAll() {
44610
+ for (const child of this.processes.values())
44611
+ void child.dispose().catch(() => {
44612
+ });
44613
+ this.processes.clear();
44614
+ this.mappers.clear();
44615
+ this.baseInstructions.clear();
44616
+ }
44386
44617
  requireProcess(threadId) {
44387
44618
  const child = this.processes.get(threadId);
44388
44619
  if (!child)
@@ -44555,7 +44786,7 @@ ${input.prompt}` : input.prompt;
44555
44786
  args.push("-m", input.model);
44556
44787
  }
44557
44788
  args.push(fullPrompt);
44558
- return new Promise((resolve) => {
44789
+ return new Promise((resolve2) => {
44559
44790
  let settled = false;
44560
44791
  const timerRef = { id: void 0 };
44561
44792
  const finish = (result) => {
@@ -44564,7 +44795,7 @@ ${input.prompt}` : input.prompt;
44564
44795
  settled = true;
44565
44796
  if (timerRef.id)
44566
44797
  clearTimeout(timerRef.id);
44567
- resolve(result);
44798
+ resolve2(result);
44568
44799
  };
44569
44800
  const options = {
44570
44801
  stdio: ["ignore", "pipe", "pipe"],
@@ -44642,7 +44873,7 @@ function runClaudeExec(input, deps) {
44642
44873
  args.push("--model", input.model);
44643
44874
  }
44644
44875
  args.push(input.prompt);
44645
- return new Promise((resolve) => {
44876
+ return new Promise((resolve2) => {
44646
44877
  let settled = false;
44647
44878
  const timerRef = { id: void 0 };
44648
44879
  const finish = (result) => {
@@ -44651,7 +44882,7 @@ function runClaudeExec(input, deps) {
44651
44882
  settled = true;
44652
44883
  if (timerRef.id)
44653
44884
  clearTimeout(timerRef.id);
44654
- resolve(result);
44885
+ resolve2(result);
44655
44886
  };
44656
44887
  const options = {
44657
44888
  stdio: ["ignore", "pipe", "pipe"],
@@ -44763,7 +44994,7 @@ function runAgyExec(input, deps) {
44763
44994
  }
44764
44995
  }
44765
44996
  args.push(`--print=${prompt}`);
44766
- return new Promise((resolve) => {
44997
+ return new Promise((resolve2) => {
44767
44998
  let settled = false;
44768
44999
  const timerRef = { id: void 0 };
44769
45000
  const finish = (result) => {
@@ -44772,7 +45003,7 @@ function runAgyExec(input, deps) {
44772
45003
  settled = true;
44773
45004
  if (timerRef.id)
44774
45005
  clearTimeout(timerRef.id);
44775
- resolve(result);
45006
+ resolve2(result);
44776
45007
  };
44777
45008
  const options = {
44778
45009
  stdio: ["ignore", "pipe", "pipe"],
@@ -45112,14 +45343,14 @@ var DIFF_MAX_BYTES = 2e5;
45112
45343
  var FASTGATE_OUTPUT_MAX_BYTES = 16e3;
45113
45344
  var GIT_TIMEOUT_MS = 6e4;
45114
45345
  var FASTGATE_TIMEOUT_MS = 3e5;
45115
- var defaultRunCmd = (cmd, args, opts) => new Promise((resolve) => {
45346
+ var defaultRunCmd = (cmd, args, opts) => new Promise((resolve2) => {
45116
45347
  let settled = false;
45117
45348
  const timerRef = { id: void 0 };
45118
45349
  const finish = (result) => {
45119
45350
  if (settled) return;
45120
45351
  settled = true;
45121
45352
  if (timerRef.id) clearTimeout(timerRef.id);
45122
- resolve(result);
45353
+ resolve2(result);
45123
45354
  };
45124
45355
  let child;
45125
45356
  try {
@@ -46037,14 +46268,14 @@ function errMessage3(err) {
46037
46268
  return err instanceof Error ? err.message : String(err);
46038
46269
  }
46039
46270
  function runExternalAgentsStatus(bin, args, timeoutMs, spawn6) {
46040
- return new Promise((resolve) => {
46271
+ return new Promise((resolve2) => {
46041
46272
  let settled = false;
46042
46273
  const timerRef = { id: void 0 };
46043
46274
  const finish = (r) => {
46044
46275
  if (settled) return;
46045
46276
  settled = true;
46046
46277
  if (timerRef.id) clearTimeout(timerRef.id);
46047
- resolve(r);
46278
+ resolve2(r);
46048
46279
  };
46049
46280
  const options = { stdio: ["ignore", "pipe", "pipe"], env: process.env, shell: false };
46050
46281
  let child;
@@ -46124,14 +46355,14 @@ function errMessage4(err) {
46124
46355
  return err instanceof Error ? err.message : String(err);
46125
46356
  }
46126
46357
  function runExternalAgents(bin, args, label, timeoutMs, spawn6) {
46127
- return new Promise((resolve) => {
46358
+ return new Promise((resolve2) => {
46128
46359
  let settled = false;
46129
46360
  const timerRef = { id: void 0 };
46130
46361
  const finish = (r) => {
46131
46362
  if (settled) return;
46132
46363
  settled = true;
46133
46364
  if (timerRef.id) clearTimeout(timerRef.id);
46134
- resolve(r);
46365
+ resolve2(r);
46135
46366
  };
46136
46367
  const options = {
46137
46368
  stdio: ["ignore", "pipe", "pipe"],
@@ -48630,7 +48861,7 @@ var Protocol = class {
48630
48861
  return;
48631
48862
  }
48632
48863
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
48633
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
48864
+ await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
48634
48865
  options?.signal?.throwIfAborted();
48635
48866
  }
48636
48867
  } catch (error51) {
@@ -48647,7 +48878,7 @@ var Protocol = class {
48647
48878
  */
48648
48879
  request(request, resultSchema, options) {
48649
48880
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
48650
- return new Promise((resolve, reject) => {
48881
+ return new Promise((resolve2, reject) => {
48651
48882
  const earlyReject = (error51) => {
48652
48883
  reject(error51);
48653
48884
  };
@@ -48725,7 +48956,7 @@ var Protocol = class {
48725
48956
  if (!parseResult.success) {
48726
48957
  reject(parseResult.error);
48727
48958
  } else {
48728
- resolve(parseResult.data);
48959
+ resolve2(parseResult.data);
48729
48960
  }
48730
48961
  } catch (error51) {
48731
48962
  reject(error51);
@@ -48986,12 +49217,12 @@ var Protocol = class {
48986
49217
  }
48987
49218
  } catch {
48988
49219
  }
48989
- return new Promise((resolve, reject) => {
49220
+ return new Promise((resolve2, reject) => {
48990
49221
  if (signal.aborted) {
48991
49222
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
48992
49223
  return;
48993
49224
  }
48994
- const timeoutId = setTimeout(resolve, interval);
49225
+ const timeoutId = setTimeout(resolve2, interval);
48995
49226
  signal.addEventListener("abort", () => {
48996
49227
  clearTimeout(timeoutId);
48997
49228
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -51427,7 +51658,7 @@ var StdioClientTransport = class {
51427
51658
  if (this._process) {
51428
51659
  throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
51429
51660
  }
51430
- return new Promise((resolve, reject) => {
51661
+ return new Promise((resolve2, reject) => {
51431
51662
  this._process = (0, import_cross_spawn.default)(this._serverParams.command, this._serverParams.args ?? [], {
51432
51663
  // merge default env with server env because mcp server needs some env vars
51433
51664
  env: {
@@ -51444,7 +51675,7 @@ var StdioClientTransport = class {
51444
51675
  this.onerror?.(error51);
51445
51676
  });
51446
51677
  this._process.on("spawn", () => {
51447
- resolve();
51678
+ resolve2();
51448
51679
  });
51449
51680
  this._process.on("close", (_code) => {
51450
51681
  this._process = void 0;
@@ -51509,22 +51740,22 @@ var StdioClientTransport = class {
51509
51740
  if (this._process) {
51510
51741
  const processToClose = this._process;
51511
51742
  this._process = void 0;
51512
- const closePromise = new Promise((resolve) => {
51743
+ const closePromise = new Promise((resolve2) => {
51513
51744
  processToClose.once("close", () => {
51514
- resolve();
51745
+ resolve2();
51515
51746
  });
51516
51747
  });
51517
51748
  try {
51518
51749
  processToClose.stdin?.end();
51519
51750
  } catch {
51520
51751
  }
51521
- await Promise.race([closePromise, new Promise((resolve) => setTimeout(resolve, 2e3).unref())]);
51752
+ await Promise.race([closePromise, new Promise((resolve2) => setTimeout(resolve2, 2e3).unref())]);
51522
51753
  if (processToClose.exitCode === null) {
51523
51754
  try {
51524
51755
  processToClose.kill("SIGTERM");
51525
51756
  } catch {
51526
51757
  }
51527
- await Promise.race([closePromise, new Promise((resolve) => setTimeout(resolve, 2e3).unref())]);
51758
+ await Promise.race([closePromise, new Promise((resolve2) => setTimeout(resolve2, 2e3).unref())]);
51528
51759
  }
51529
51760
  if (processToClose.exitCode === null) {
51530
51761
  try {
@@ -51536,15 +51767,15 @@ var StdioClientTransport = class {
51536
51767
  this._readBuffer.clear();
51537
51768
  }
51538
51769
  send(message) {
51539
- return new Promise((resolve) => {
51770
+ return new Promise((resolve2) => {
51540
51771
  if (!this._process?.stdin) {
51541
51772
  throw new Error("Not connected");
51542
51773
  }
51543
51774
  const json2 = serializeMessage(message);
51544
51775
  if (this._process.stdin.write(json2)) {
51545
- resolve();
51776
+ resolve2();
51546
51777
  } else {
51547
- this._process.stdin.once("drain", resolve);
51778
+ this._process.stdin.once("drain", resolve2);
51548
51779
  }
51549
51780
  });
51550
51781
  }
@@ -53380,7 +53611,7 @@ var DRAFT_SPEC_TLDR_MAX_CHARS = 300;
53380
53611
  var DRAFT_SPEC_PERSONA = "spec-author";
53381
53612
  var PAGE_ID_MAX_ATTEMPTS = 5;
53382
53613
  function defaultSleep(ms) {
53383
- return new Promise((resolve) => setTimeout(resolve, ms));
53614
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
53384
53615
  }
53385
53616
  function enforceSpecOutputContract(markdown, taskId, title) {
53386
53617
  let body = normalizeAcceptanceCriteria(markdown.trim());
@@ -56195,22 +56426,6 @@ function createMrrlinTools(options) {
56195
56426
  );
56196
56427
  }
56197
56428
  }
56198
- async function autoRetirePendingScopeQuestions(c, projectSlug, resolutionContext) {
56199
- try {
56200
- const pendingQuestions = await c.listInboxItems(projectSlug, { status: "pending", kind: "question" });
56201
- for (const item of pendingQuestions) {
56202
- if (!item.taskId) {
56203
- await c.decideInboxItem(projectSlug, item.id, {
56204
- decidedBy: "director",
56205
- verdict: "acknowledged",
56206
- answer: `Addressed in materialized plan/tasks (${resolutionContext})`
56207
- }).catch(() => {
56208
- });
56209
- }
56210
- }
56211
- } catch {
56212
- }
56213
- }
56214
56429
  return {
56215
56430
  [mcpToolNames.archivePlan]: makeTool(
56216
56431
  client,
@@ -56229,9 +56444,7 @@ function createMrrlinTools(options) {
56229
56444
  "Unable to create plan.",
56230
56445
  async (c, { projectSlug, ...input }) => {
56231
56446
  await checkTenantBoundary(projectSlug, "plan");
56232
- const plan = await c.createPlan(projectSlug, input);
56233
- await autoRetirePendingScopeQuestions(c, projectSlug, `Plan ${plan.id}: ${plan.name}`);
56234
- return plan;
56447
+ return await c.createPlan(projectSlug, input);
56235
56448
  }
56236
56449
  ),
56237
56450
  [mcpToolNames.createTaskDependency]: makeTool(
@@ -56360,9 +56573,7 @@ function createMrrlinTools(options) {
56360
56573
  async (c, { projectSlug, ...input }) => {
56361
56574
  await checkTenantBoundary(projectSlug, "task");
56362
56575
  const status = input.status ?? "todo";
56363
- const task = await c.createTask(projectSlug, { ...input, status });
56364
- await autoRetirePendingScopeQuestions(c, projectSlug, `Task ${task.id}: ${task.title}`);
56365
- return task;
56576
+ return await c.createTask(projectSlug, { ...input, status });
56366
56577
  }
56367
56578
  ),
56368
56579
  [mcpToolNames.getProject]: makeTool(
@@ -57564,7 +57775,7 @@ var import_node_http = __toESM(require("node:http"), 1);
57564
57775
  var import_node_os17 = __toESM(require("node:os"), 1);
57565
57776
  var import_node_path38 = __toESM(require("node:path"), 1);
57566
57777
  var import_node_child_process21 = require("node:child_process");
57567
- var import_node_crypto15 = __toESM(require("node:crypto"), 1);
57778
+ var import_node_crypto16 = __toESM(require("node:crypto"), 1);
57568
57779
 
57569
57780
  // src/turn-replay-buffer.ts
57570
57781
  var DEFAULT_MAX_EVENTS = 2e3;
@@ -58083,7 +58294,7 @@ function createTurnLock() {
58083
58294
  } else {
58084
58295
  autonomousTotalActive += 1;
58085
58296
  }
58086
- return new Promise((resolve, reject) => {
58297
+ return new Promise((resolve2, reject) => {
58087
58298
  const start = () => {
58088
58299
  let bodyPromise;
58089
58300
  try {
@@ -58091,7 +58302,7 @@ function createTurnLock() {
58091
58302
  } catch (e) {
58092
58303
  bodyPromise = Promise.reject(e);
58093
58304
  }
58094
- bodyPromise.then((v) => resolve(v)).catch((e) => reject(e)).finally(() => {
58305
+ bodyPromise.then((v) => resolve2(v)).catch((e) => reject(e)).finally(() => {
58095
58306
  if (lane === "chat") {
58096
58307
  chatTotalActive -= 1;
58097
58308
  } else {
@@ -58693,7 +58904,7 @@ Do NOT derail the current task - if the operator has an in-flight question, answ
58693
58904
  }
58694
58905
 
58695
58906
  // src/_generated/version.ts
58696
- var PKG_VERSION = "0.4.97";
58907
+ var PKG_VERSION = "0.4.99";
58697
58908
 
58698
58909
  // src/director-closure.ts
58699
58910
  var CLOSURE_SNAPSHOT_TIMEOUT_MS = 2e3;
@@ -58952,7 +59163,6 @@ function closureFor(input) {
58952
59163
  var LEDGER_MAX_ITEMS = 20;
58953
59164
  var LEDGER_MAX_QUESTIONS_PER_TURN = 5;
58954
59165
  var LEDGER_MAX_EXTRACTED_QUESTIONS = 50;
58955
- var LEDGER_REASK_JACCARD = 0.6;
58956
59166
  var LEDGER_MAX_QUESTION_CHARS = 300;
58957
59167
  function emptyLedger() {
58958
59168
  return { turn: 0, items: [] };
@@ -59043,13 +59253,12 @@ function tokenMatches(a, b) {
59043
59253
  }
59044
59254
  return false;
59045
59255
  }
59256
+ function normalizeQuestionIdentity(value) {
59257
+ return value.normalize("NFKC").toLowerCase().replace(/\s+/gu, " ").trim();
59258
+ }
59046
59259
  function isSameQuestion(a, b) {
59047
- const ta = tokens(a);
59048
- const tb = tokens(b);
59049
- if (ta.size === 0 || tb.size === 0) return false;
59050
- let shared = 0;
59051
- for (const token of ta) if (tb.has(token)) shared += 1;
59052
- return shared / (ta.size + tb.size - shared) >= LEDGER_REASK_JACCARD;
59260
+ const left = normalizeQuestionIdentity(a);
59261
+ return /[\p{L}\p{N}]/u.test(left) && left === normalizeQuestionIdentity(b);
59053
59262
  }
59054
59263
  function isAffirmativeResolutionForQuestion(question, text, otherQuestions) {
59055
59264
  if (!text || !RESOLUTION_MARKER_RE.test(text)) return false;
@@ -59884,7 +60093,7 @@ async function writeCrashSentinel(stateDir, sentinel) {
59884
60093
  }
59885
60094
  function withTimeout(fn, ms = DEFAULT_OPERATION_TIMEOUT_MS) {
59886
60095
  const controller = new AbortController();
59887
- return new Promise((resolve, reject) => {
60096
+ return new Promise((resolve2, reject) => {
59888
60097
  const timer = setTimeout(() => {
59889
60098
  controller.abort();
59890
60099
  const timeoutError = new Error(`operation timed out after ${ms}ms`);
@@ -59894,7 +60103,7 @@ function withTimeout(fn, ms = DEFAULT_OPERATION_TIMEOUT_MS) {
59894
60103
  fn(controller.signal).then(
59895
60104
  (value) => {
59896
60105
  clearTimeout(timer);
59897
- resolve(value);
60106
+ resolve2(value);
59898
60107
  },
59899
60108
  (error51) => {
59900
60109
  clearTimeout(timer);
@@ -60840,7 +61049,7 @@ function runExternalAgentsCli(args, opts) {
60840
61049
  }
60841
61050
  const useStdin = opts.stdinValue !== void 0;
60842
61051
  const stdioConfig = useStdin ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"];
60843
- return new Promise((resolve) => {
61052
+ return new Promise((resolve2) => {
60844
61053
  let stdout = "";
60845
61054
  let stderr = "";
60846
61055
  let settled = false;
@@ -60848,7 +61057,7 @@ function runExternalAgentsCli(args, opts) {
60848
61057
  const done = (code) => {
60849
61058
  if (!settled) {
60850
61059
  settled = true;
60851
- resolve({ stdout, stderr, code, timedOut, source, triedPath });
61060
+ resolve2({ stdout, stderr, code, timedOut, source, triedPath });
60852
61061
  }
60853
61062
  };
60854
61063
  let spawned;
@@ -61016,7 +61225,7 @@ function startProviderReadinessLoop(deps) {
61016
61225
 
61017
61226
  // src/execution-consumer.ts
61018
61227
  var import_node_child_process19 = require("node:child_process");
61019
- var import_node_crypto13 = __toESM(require("node:crypto"), 1);
61228
+ var import_node_crypto14 = __toESM(require("node:crypto"), 1);
61020
61229
  var import_node_path31 = __toESM(require("node:path"), 1);
61021
61230
  var import_node_util2 = require("node:util");
61022
61231
 
@@ -61872,6 +62081,7 @@ async function awaitTurnWithDeadline(opts) {
61872
62081
 
61873
62082
  // src/worktree.ts
61874
62083
  var import_node_child_process18 = require("node:child_process");
62084
+ var import_node_crypto13 = require("node:crypto");
61875
62085
  var import_node_fs17 = require("node:fs");
61876
62086
  var import_node_path30 = require("node:path");
61877
62087
 
@@ -61899,8 +62109,43 @@ function worktreeBranch(runId) {
61899
62109
  return `mrrlin/run-${runId}`;
61900
62110
  }
61901
62111
  var defaultGitExec = (args, env) => (0, import_node_child_process18.execFileSync)("git", args, { encoding: "utf8", timeout: 3e4, env });
61902
- function git(checkout, args) {
61903
- return (0, import_node_child_process18.execFileSync)("git", ["-C", checkout, ...args], {
62112
+ function disabledGitHooksPath(locksDir, scope) {
62113
+ const scopeKey = (0, import_node_crypto13.createHash)("sha256").update(scope).digest("hex").slice(0, 32);
62114
+ return (0, import_node_path30.resolve)(locksDir, "..", "disabled-git-hooks", scopeKey);
62115
+ }
62116
+ function prepareDisabledGitHooksDir(locksDir, scope) {
62117
+ const hooksDir = disabledGitHooksPath(locksDir, scope);
62118
+ const hooksRoot = (0, import_node_path30.resolve)(hooksDir, "..");
62119
+ (0, import_node_fs17.mkdirSync)(hooksRoot, { recursive: true, mode: 448 });
62120
+ (0, import_node_fs17.mkdirSync)(hooksDir, { recursive: true, mode: 320 });
62121
+ if ((0, import_node_fs17.readdirSync)(hooksDir).length > 0) {
62122
+ throw new Error(`disabled_git_hooks_dir_not_empty: ${hooksDir}`);
62123
+ }
62124
+ try {
62125
+ (0, import_node_fs17.chmodSync)(hooksDir, 320);
62126
+ } catch {
62127
+ }
62128
+ return hooksDir;
62129
+ }
62130
+ function removeDisabledGitHooksDir(locksDir, scope) {
62131
+ try {
62132
+ (0, import_node_fs17.rmdirSync)(disabledGitHooksPath(locksDir, scope));
62133
+ } catch {
62134
+ }
62135
+ }
62136
+ function withDisabledGitHooksEnv(env, hooksDir) {
62137
+ const rawCount = env.GIT_CONFIG_COUNT;
62138
+ const parsedCount = rawCount === void 0 ? 0 : Number(rawCount);
62139
+ const count2 = Number.isSafeInteger(parsedCount) && parsedCount >= 0 ? parsedCount : 0;
62140
+ return {
62141
+ ...env,
62142
+ GIT_CONFIG_COUNT: String(count2 + 1),
62143
+ [`GIT_CONFIG_KEY_${count2}`]: "core.hooksPath",
62144
+ [`GIT_CONFIG_VALUE_${count2}`]: hooksDir
62145
+ };
62146
+ }
62147
+ function git(checkout, args, hooksDir) {
62148
+ return (0, import_node_child_process18.execFileSync)("git", ["-C", checkout, "-c", `core.hooksPath=${hooksDir}`, ...args], {
61904
62149
  encoding: "utf8",
61905
62150
  timeout: 3e4,
61906
62151
  env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
@@ -61908,20 +62153,21 @@ function git(checkout, args) {
61908
62153
  }
61909
62154
  async function createRunWorktree(opts) {
61910
62155
  const worktreePath = (0, import_node_path30.join)(opts.worktreeRoot, opts.slug, opts.runId);
62156
+ const hooksDir = prepareDisabledGitHooksDir(opts.locksDir, opts.runId);
61911
62157
  await withCheckoutLock(opts.locksDir, opts.slug, async () => {
61912
62158
  (0, import_node_fs17.mkdirSync)(opts.worktreeRoot, { recursive: true });
61913
62159
  try {
61914
- git(opts.checkout, ["fetch", "origin", opts.defaultBranch]);
62160
+ git(opts.checkout, ["fetch", "origin", opts.defaultBranch], hooksDir);
61915
62161
  if (!(0, import_node_fs17.existsSync)(worktreePath)) {
61916
62162
  git(opts.checkout, [
61917
62163
  "worktree",
61918
62164
  "add",
62165
+ "--no-track",
61919
62166
  "-b",
61920
62167
  worktreeBranch(opts.runId),
61921
62168
  worktreePath,
61922
62169
  `origin/${opts.defaultBranch}`
61923
- ]);
61924
- git(worktreePath, ["config", "core.hooksPath", "/dev/null"]);
62170
+ ], hooksDir);
61925
62171
  }
61926
62172
  } catch (error51) {
61927
62173
  const detail = error51 instanceof Error ? error51.message : String(error51);
@@ -61933,12 +62179,14 @@ async function createRunWorktree(opts) {
61933
62179
  return worktreePath;
61934
62180
  }
61935
62181
  async function removeRunWorktree(opts) {
62182
+ const hooksDir = prepareDisabledGitHooksDir(opts.locksDir, (0, import_node_path30.basename)(opts.worktreePath));
61936
62183
  await withCheckoutLock(opts.locksDir, opts.slug, async () => {
61937
62184
  try {
61938
- git(opts.checkout, ["worktree", "remove", "--force", opts.worktreePath]);
62185
+ git(opts.checkout, ["worktree", "remove", "--force", opts.worktreePath], hooksDir);
61939
62186
  } catch {
61940
62187
  }
61941
- git(opts.checkout, ["worktree", "prune"]);
62188
+ git(opts.checkout, ["worktree", "prune"], hooksDir);
62189
+ removeDisabledGitHooksDir(opts.locksDir, (0, import_node_path30.basename)(opts.worktreePath));
61942
62190
  });
61943
62191
  }
61944
62192
  async function pushRunBranch(opts, execGit = defaultGitExec) {
@@ -61961,6 +62209,7 @@ async function hasCommitsToPush(opts, execGit = defaultGitExec) {
61961
62209
  }
61962
62210
  async function doPushRunBranch(opts, execGit) {
61963
62211
  const branch = worktreeBranch(opts.runId);
62212
+ const hooksDir = prepareDisabledGitHooksDir(opts.locksDir, opts.runId);
61964
62213
  const pushEnv = {
61965
62214
  PATH: process.env.PATH ?? "",
61966
62215
  ...process.env.HOME !== void 0 ? { HOME: process.env.HOME } : {},
@@ -62006,7 +62255,7 @@ async function doPushRunBranch(opts, execGit) {
62006
62255
  "-C",
62007
62256
  opts.worktreePath,
62008
62257
  "-c",
62009
- "core.hooksPath=/dev/null",
62258
+ `core.hooksPath=${hooksDir}`,
62010
62259
  "push",
62011
62260
  "--no-verify",
62012
62261
  "origin",
@@ -62018,6 +62267,7 @@ async function doPushRunBranch(opts, execGit) {
62018
62267
  }
62019
62268
  async function sweepOrphanWorktrees(opts) {
62020
62269
  const reaped = [];
62270
+ const hooksDir = prepareDisabledGitHooksDir(opts.locksDir, `sweep:${opts.slug}`);
62021
62271
  const ownedPrefix = (() => {
62022
62272
  try {
62023
62273
  return (import_node_fs17.realpathSync.native ?? import_node_fs17.realpathSync)(opts.worktreeRoot);
@@ -62025,32 +62275,37 @@ async function sweepOrphanWorktrees(opts) {
62025
62275
  return opts.worktreeRoot;
62026
62276
  }
62027
62277
  })() + import_node_path30.sep + opts.slug + import_node_path30.sep;
62028
- await withCheckoutLock(opts.locksDir, opts.slug, async () => {
62029
- const listing = git(opts.checkout, ["worktree", "list", "--porcelain"]);
62030
- for (const block of listing.split("\n\n")) {
62031
- const m = /^worktree (.+)$/m.exec(block);
62032
- const wt = m?.[1]?.trim();
62033
- if (!wt) continue;
62034
- const canonicalWt = (() => {
62035
- try {
62036
- return (import_node_fs17.realpathSync.native ?? import_node_fs17.realpathSync)(wt);
62037
- } catch {
62038
- return wt;
62039
- }
62040
- })();
62041
- const normWt = (0, import_node_path30.normalize)(canonicalWt);
62042
- const normPrefix = (0, import_node_path30.normalize)(ownedPrefix);
62043
- const isMatch = process.platform === "win32" ? normWt.toLowerCase().startsWith(normPrefix.toLowerCase()) : normWt.startsWith(normPrefix);
62044
- if (isMatch && opts.isReapable(wt)) {
62045
- try {
62046
- git(opts.checkout, ["worktree", "remove", "--force", wt]);
62047
- reaped.push(wt);
62048
- } catch {
62278
+ try {
62279
+ await withCheckoutLock(opts.locksDir, opts.slug, async () => {
62280
+ const listing = git(opts.checkout, ["worktree", "list", "--porcelain"], hooksDir);
62281
+ for (const block of listing.split("\n\n")) {
62282
+ const m = /^worktree (.+)$/m.exec(block);
62283
+ const wt = m?.[1]?.trim();
62284
+ if (!wt) continue;
62285
+ const canonicalWt = (() => {
62286
+ try {
62287
+ return (import_node_fs17.realpathSync.native ?? import_node_fs17.realpathSync)(wt);
62288
+ } catch {
62289
+ return wt;
62290
+ }
62291
+ })();
62292
+ const normWt = (0, import_node_path30.normalize)(canonicalWt);
62293
+ const normPrefix = (0, import_node_path30.normalize)(ownedPrefix);
62294
+ const isMatch = process.platform === "win32" ? normWt.toLowerCase().startsWith(normPrefix.toLowerCase()) : normWt.startsWith(normPrefix);
62295
+ if (isMatch && opts.isReapable(wt)) {
62296
+ try {
62297
+ git(opts.checkout, ["worktree", "remove", "--force", wt], hooksDir);
62298
+ removeDisabledGitHooksDir(opts.locksDir, (0, import_node_path30.basename)(wt));
62299
+ reaped.push(wt);
62300
+ } catch {
62301
+ }
62049
62302
  }
62050
62303
  }
62051
- }
62052
- git(opts.checkout, ["worktree", "prune"]);
62053
- });
62304
+ git(opts.checkout, ["worktree", "prune"], hooksDir);
62305
+ });
62306
+ } finally {
62307
+ removeDisabledGitHooksDir(opts.locksDir, `sweep:${opts.slug}`);
62308
+ }
62054
62309
  return reaped;
62055
62310
  }
62056
62311
 
@@ -62244,7 +62499,7 @@ function readPositiveIntEnv(name, fallback) {
62244
62499
  return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
62245
62500
  }
62246
62501
  function delayMs(ms) {
62247
- return new Promise((resolve) => setTimeout(resolve, ms));
62502
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
62248
62503
  }
62249
62504
  function executionBundleBudget() {
62250
62505
  if ((process.env.MRRLIN_RETRIEVAL_BUDGET_DISABLE ?? "").trim() === "1") return void 0;
@@ -62572,7 +62827,7 @@ function isBridgeGeneratedArtifact(artifact) {
62572
62827
  return typeof payload === "object" && payload !== null && "event" in payload;
62573
62828
  }
62574
62829
  function newArtifactId() {
62575
- return `EA-${import_node_crypto13.default.randomUUID()}`;
62830
+ return `EA-${import_node_crypto14.default.randomUUID()}`;
62576
62831
  }
62577
62832
  var BLAST_RADIUS_FLOOR_PATTERNS = [/^supabase\/migrations\//, /^packages\/db\/src\/schema\.ts$/];
62578
62833
  function isBlastRadiusFloorPath(path29) {
@@ -62741,8 +62996,8 @@ async function driveTurn(deps, codex, projectSlug, runId, leaseId, threadId, inp
62741
62996
  return deps.run("exec", async () => {
62742
62997
  const pending = [];
62743
62998
  let resolveTurnEnded = null;
62744
- const turnEnded = new Promise((resolve) => {
62745
- resolveTurnEnded = resolve;
62999
+ const turnEnded = new Promise((resolve2) => {
63000
+ resolveTurnEnded = resolve2;
62746
63001
  });
62747
63002
  let acceptedTurnId = null;
62748
63003
  const unsubActivity = codex.onActivity(threadId, () => {
@@ -62823,7 +63078,7 @@ async function driveRun(deps, projectSlug, runId) {
62823
63078
  if (!claimed) return;
62824
63079
  if (!claimed.leaseId) {
62825
63080
  await deps.client.createInboxItem(projectSlug, {
62826
- id: `II-${import_node_crypto13.default.randomUUID()}`,
63081
+ id: `II-${import_node_crypto14.default.randomUUID()}`,
62827
63082
  kind: "handoff",
62828
63083
  taskId: claimed.taskId,
62829
63084
  body: `Execution run ${runId} was claimed but returned no leaseId. This indicates DB/API corruption and requires operator attention.`
@@ -64274,7 +64529,7 @@ async function reconcileTaskAwaitingMerge(deps, projectSlug, task, runId, reason
64274
64529
  }
64275
64530
  try {
64276
64531
  await deps.client.createInboxItem(projectSlug, {
64277
- id: `II-${import_node_crypto13.default.randomUUID()}`,
64532
+ id: `II-${import_node_crypto14.default.randomUUID()}`,
64278
64533
  kind: "handoff",
64279
64534
  taskId: task.id,
64280
64535
  body: `Task ${task.id} (${task.title}) still needs operator follow-up: ${reason}. Mrrlin could not move the task back to Handoff needed automatically.`
@@ -64309,7 +64564,7 @@ async function notifyOperatorHandoff(deps, projectSlug, task, runId, reason) {
64309
64564
  }
64310
64565
  try {
64311
64566
  await deps.client.createInboxItem(projectSlug, {
64312
- id: `II-${import_node_crypto13.default.randomUUID()}`,
64567
+ id: `II-${import_node_crypto14.default.randomUUID()}`,
64313
64568
  kind: "handoff",
64314
64569
  taskId: task.id,
64315
64570
  body: `Execution run ${runId} for task ${task.id} (${task.title}) needs operator attention: ${reason}`
@@ -64470,7 +64725,7 @@ async function deployGateHandoff(deps, projectSlug, task, runId, reason, leaseId
64470
64725
  }).catch(() => {
64471
64726
  });
64472
64727
  await deps.client.createInboxItem(projectSlug, {
64473
- id: `II-${import_node_crypto13.default.randomUUID()}`,
64728
+ id: `II-${import_node_crypto14.default.randomUUID()}`,
64474
64729
  kind: "handoff",
64475
64730
  taskId: task.id,
64476
64731
  body: `Deploy gate for run ${runId} (task ${task.id} \u2014 ${task.title}) needs operator attention: ${reason}`
@@ -64489,7 +64744,7 @@ function maxLeaseReclaims() {
64489
64744
  }
64490
64745
 
64491
64746
  // src/async-job-consumer.ts
64492
- var import_node_crypto14 = __toESM(require("node:crypto"), 1);
64747
+ var import_node_crypto15 = __toESM(require("node:crypto"), 1);
64493
64748
  var ASYNC_JOB_MAX_ATTEMPTS = 2;
64494
64749
  function ASYNC_UNOWNED_TTL_DAYS() {
64495
64750
  const raw = Number(process.env.MRRLIN_ASYNC_UNOWNED_TTL_DAYS);
@@ -64614,7 +64869,7 @@ async function driveAsyncJob(deps, projectSlug, jobId) {
64614
64869
  const delivery = descriptor2.onComplete(outcome, input);
64615
64870
  if (!delivery.suppressInbox) {
64616
64871
  await deps.client.createInboxItem(projectSlug, {
64617
- id: delivery.id ?? `II-${import_node_crypto14.default.randomUUID()}`,
64872
+ id: delivery.id ?? `II-${import_node_crypto15.default.randomUUID()}`,
64618
64873
  kind: delivery.kind,
64619
64874
  body: delivery.body,
64620
64875
  ...delivery.taskId ? { taskId: delivery.taskId } : {},
@@ -64632,13 +64887,13 @@ async function deriveRequestedHash(client, toolName, input) {
64632
64887
  if (input.requestedHash) return input.requestedHash;
64633
64888
  if (toolName === "run_spec_consensus" && input.pageId) {
64634
64889
  const page = await client.getWikiPage(input.projectSlug, input.pageId);
64635
- return page.contentHash ?? import_node_crypto14.default.createHash("sha256").update(page.markdownBody).digest("hex");
64890
+ return page.contentHash ?? import_node_crypto15.default.createHash("sha256").update(page.markdownBody).digest("hex");
64636
64891
  }
64637
64892
  if (toolName === "draft_task_spec" && input.taskId) {
64638
64893
  const task = await client.getTask(input.projectSlug, input.taskId);
64639
- return task.updatedAt ?? import_node_crypto14.default.createHash("sha256").update(JSON.stringify(task)).digest("hex");
64894
+ return task.updatedAt ?? import_node_crypto15.default.createHash("sha256").update(JSON.stringify(task)).digest("hex");
64640
64895
  }
64641
- return import_node_crypto14.default.createHash("sha256").update(JSON.stringify(input)).digest("hex");
64896
+ return import_node_crypto15.default.createHash("sha256").update(JSON.stringify(input)).digest("hex");
64642
64897
  }
64643
64898
  async function runAsyncBackstopSweep(deps, drive = (slug, jobId) => driveAsyncJob(deps, slug, jobId)) {
64644
64899
  const projects = await deps.client.listProjects();
@@ -68742,7 +68997,7 @@ function saveAgentPairing(record2) {
68742
68997
  }
68743
68998
  }
68744
68999
  function runPhoneTurn(handler, directorSessionId, text, emit) {
68745
- return new Promise((resolve) => {
69000
+ return new Promise((resolve2) => {
68746
69001
  const emitter = new import_node_events3.EventEmitter();
68747
69002
  const fakeSocket = {
68748
69003
  on: (event, cb) => {
@@ -68757,7 +69012,7 @@ function runPhoneTurn(handler, directorSessionId, text, emit) {
68757
69012
  settled = true;
68758
69013
  if (timer) clearTimeout(timer);
68759
69014
  emitter.removeAllListeners();
68760
- resolve();
69015
+ resolve2();
68761
69016
  };
68762
69017
  const send = (msg) => {
68763
69018
  if (msg.type === "error") {
@@ -68917,13 +69172,19 @@ async function renderPairingQrSvg(payload) {
68917
69172
  // src/executor-server.ts
68918
69173
  var import_node_child_process20 = require("node:child_process");
68919
69174
  function defaultReadinessRunner(provider) {
68920
- const command = provider === "claude" ? "claude" : "codex";
69175
+ if (provider !== "codex" && provider !== "claude" && provider !== "agy") {
69176
+ throw new Error(`unsupported executor provider: ${String(provider)}`);
69177
+ }
69178
+ const command = provider === "claude" ? "claude" : provider === "agy" ? "agy" : "codex";
68921
69179
  return (args) => {
68922
69180
  const r = (0, import_node_child_process20.spawnSync)(command, args, { encoding: "utf8", timeout: 8e3, shell: true });
68923
69181
  return { status: r.status, stdout: r.stdout ?? "", stderr: r.stderr ?? "" };
68924
69182
  };
68925
69183
  }
68926
69184
  async function startExecutorServer(opts) {
69185
+ if (opts.provider !== "codex" && opts.provider !== "claude" && opts.provider !== "agy") {
69186
+ throw new Error(`unsupported executor provider: ${String(opts.provider)}`);
69187
+ }
68927
69188
  const verify = opts.verifyReadiness ?? verifyProviderReadiness;
68928
69189
  const runner = opts.readinessRunner ?? defaultReadinessRunner(opts.provider);
68929
69190
  const readiness = await verify(opts.provider, runner);
@@ -68936,8 +69197,37 @@ async function startExecutorServer(opts) {
68936
69197
  error51.details = readiness.details;
68937
69198
  throw error51;
68938
69199
  }
69200
+ const baseEnv = { ...opts.env ?? process.env };
69201
+ const childEnv = withDisabledGitHooksEnv(baseEnv, opts.disabledGitHooksDir);
69202
+ if (opts.provider === "codex") {
69203
+ const manager = new CodexServerManager();
69204
+ try {
69205
+ const client = await manager.acquire({
69206
+ cwd: opts.worktree,
69207
+ approvalPolicy: "never",
69208
+ env: childEnv,
69209
+ ...opts.spawn ? { spawn: opts.spawn } : {}
69210
+ });
69211
+ let disposed = false;
69212
+ const dispose = () => {
69213
+ if (disposed) return;
69214
+ disposed = true;
69215
+ try {
69216
+ manager.shutdown();
69217
+ } catch {
69218
+ }
69219
+ };
69220
+ return { handle: createCodexAgentHandle(client), dispose };
69221
+ } catch (error51) {
69222
+ try {
69223
+ manager.shutdown();
69224
+ } catch {
69225
+ }
69226
+ throw error51;
69227
+ }
69228
+ }
68939
69229
  if (opts.provider === "claude") {
68940
- const handle = new ClaudeAgentHandle();
69230
+ const handle = new ClaudeAgentHandle(childEnv);
68941
69231
  let disposed = false;
68942
69232
  const dispose = () => {
68943
69233
  if (disposed) return;
@@ -68946,30 +69236,17 @@ async function startExecutorServer(opts) {
68946
69236
  };
68947
69237
  return { handle, dispose };
68948
69238
  }
68949
- const manager = new CodexServerManager();
68950
- try {
68951
- const client = await manager.acquire({
68952
- cwd: opts.worktree,
68953
- approvalPolicy: "never",
68954
- ...opts.spawn ? { spawn: opts.spawn } : {}
68955
- });
69239
+ if (opts.provider === "agy") {
69240
+ const handle = new AgyAgentHandle(childEnv);
68956
69241
  let disposed = false;
68957
69242
  const dispose = () => {
68958
69243
  if (disposed) return;
68959
69244
  disposed = true;
68960
- try {
68961
- manager.shutdown();
68962
- } catch {
68963
- }
69245
+ handle.disposeAll();
68964
69246
  };
68965
- return { handle: createCodexAgentHandle(client), dispose };
68966
- } catch (error51) {
68967
- try {
68968
- manager.shutdown();
68969
- } catch {
68970
- }
68971
- throw error51;
69247
+ return { handle, dispose };
68972
69248
  }
69249
+ throw new Error(`unsupported executor provider: ${String(opts.provider)}`);
68973
69250
  }
68974
69251
 
68975
69252
  // src/self-review.ts
@@ -69758,9 +70035,9 @@ function readCodexFallbackModels() {
69758
70035
  return [...models.values()];
69759
70036
  }
69760
70037
  function selfUpdateInboxItemId(offeredVersion) {
69761
- if (!offeredVersion) return `II-MCPUPD-${(0, import_node_crypto15.randomUUID)()}`;
70038
+ if (!offeredVersion) return `II-MCPUPD-${(0, import_node_crypto16.randomUUID)()}`;
69762
70039
  if (/^[A-Za-z0-9._-]+$/.test(offeredVersion)) return `II-MCPUPD-${offeredVersion}`;
69763
- const hash3 = import_node_crypto15.default.createHash("sha256").update(offeredVersion).digest("hex").slice(0, 10);
70040
+ const hash3 = import_node_crypto16.default.createHash("sha256").update(offeredVersion).digest("hex").slice(0, 10);
69764
70041
  return `II-MCPUPD-${offeredVersion.replace(/[^A-Za-z0-9._-]/g, "-")}-${hash3}`;
69765
70042
  }
69766
70043
  function neutralCheckoutCwd(stateDir) {
@@ -69797,7 +70074,7 @@ function buildThreadStartParams(msg, config2, desiredModel) {
69797
70074
  "- Spec pages in folder Specs must contain `## Acceptance criteria` followed by `- [ ]` items.",
69798
70075
  "- AGNOSTIC DELIVERY MANDATE: Mrrlin is an Agnostic Delivery Platform decoupled from mandatory GitHub. Delivery is routed strictly by artifact kind: (1) document -> wiki (specs, policies, legal compliance playbooks, project documentation); (2) page -> publish (web pages, landing pages, interactive HTML previews); (3) file_set -> artifacts (file uploads, bundles, build zips); (4) message -> send (outbound webhooks, Slack, notifications); (5) code_change -> repo_host (git / GitHub ONLY when modifying source repository code). NEVER stall or refuse non-code tasks (such as marketing landing pages, GDPR checklists, or legal compliance playbooks) by demanding a Git repository. Non-code tasks deliver directly via page (Publish) or document (Wiki).",
69799
70076
  "- 3-TIER COMMERCIAL SCOPE GOVERNANCE: Treat tasks by domain governance tier. (1) Tier 1 Core Tech Delivery (backend, frontend, SRE, databases): decompose autonomously into repository code changes (when a repo is bound) or code artifacts. (2) Tier 2 Planning & Content (landing pages, SEO, marketing): create actionable drafts; when details such as a phone number, brand name or copy are missing, do not loop on questions \u2014 create the task, record `## Placeholders: [NEED_INPUT: <item>]` in the Wiki spec, and set `autonomyLevel: 'human_review'`. (3) Tier 3 Guardrailed Advisory (high risk: privacy/GDPR, security/SOC 2, billing, production database migrations, infrastructure): always set `autonomyLevel: 'human_review'`, put the domain's standard safety controls into the spec, and state that irreversible actions need human sign-off.",
69800
- "- INBOX QUESTION RETIREMENT MANDATE: If clarifying questions were banked or exist as pending items in Inbox from a previous turn (e.g. via `create_inbox_item(kind: 'question')`), and the operator has now answered them in chat in Turn 2+, you MUST call `decide_inbox_item(id, verdict: 'acknowledged', note: ...)` (or `verdict: 'rejected'` if moot) to retire the pending questions BEFORE creating tasks or plans on the board. Never leave questions you received answers to lingering as unanswered items in Inbox.",
70077
+ "- INBOX QUESTION RETIREMENT MANDATE \u2014 Retiring answered questions: Before creating a task/plan, retire only pending Inbox questions the operator actually answered. Call `decide_inbox_item(itemId: <exact id>, decidedBy: 'director', verdict: 'acknowledged', answer: <actual answer>)`. Use `verdict: 'rejected', reason: ...` only if moot. Never close an unrelated item.",
69801
70078
  "- CHAT CLARIFICATIONS ARE IN CHAT ONLY: During synchronous interactive Director chat, ask clarifying questions directly in your chat response. DO NOT call `create_inbox_item(kind: 'question')` for routine conversational clarifications in Turn 1 \u2014 Inbox questions are reserved for autonomous background workers or asynchronous gate pauses that occur while the operator is away.",
69802
70079
  "- AUTOPILOT PRESENCE FENCE TRANSPARENCY: Autopilot requires operator web app presence to trigger execution ticks (`operator_absent`). When the operator asks about autopilot starting, remind them that keeping the web tab open allows the scheduler to advance the queue automatically.",
69803
70080
  "",
@@ -70142,7 +70419,7 @@ function buildThreadStartParams(msg, config2, desiredModel) {
70142
70419
  '- In synchronous live Director chat (Turn 1 scoping), ask your questions directly in your chat reply without creating Inbox items. Only bank questions in Inbox (`create_inbox_item` with `kind="question"`, `taskId` set, `directorSessionId` from Context JSON, `questionOptions` = 2-3 concrete answer options) when an autonomous background task pauses, when a task requires operator decision while the operator is away, or when explicitly requested. Each banked option MUST include a short `label`, a concise `description`, and a self-contained durable `answer`; you MAY mark at most one option as `recommended` when you explicitly prefer a path.',
70143
70420
  '- When the operator answers in chat, write the answer into the Specs/{taskId} Clarifications section, and if an Inbox question was previously open, `decide_inbox_item` with `verdict="acknowledged"` and `answer` = the resolved answer.',
70144
70421
  "- Project-level ambiguity (scope or direction not yet tied to a specific task) in live chat stays in chat; for genuine asynchronous pauses it MAY be banked with `taskId` OMITTED. Reserve taskless Inbox questions for genuine project-level scope.",
70145
- "- Retiring answered questions: When the operator answers a previously banked question (task-specific or taskless) in chat, you MUST immediately call `decide_inbox_item` with `verdict=\"acknowledged\"` and note/answer BEFORE calling `create_task`. Do NOT leave answered questions in status 'pending' in Inbox.",
70422
+ "- When the operator answers a banked question, immediately call `decide_inbox_item` with its exact `itemId`, `decidedBy='director'`, `verdict='acknowledged'`, and the actual `answer` before any `create_task`. Never close another pending question.",
70146
70423
  "- Binding taskless answers to a task: WHEN you create a task out of project-level scoping,",
70147
70424
  " call `list_inbox_items` (kind=question), fold any relevant `acknowledged` TASKLESS answer",
70148
70425
  " into the new task's Specs/{id} Clarifications, and `reject` (with a reason) any taskless",
@@ -70248,8 +70525,8 @@ async function runCollectedAgentTurn(handle, prompt, cwd, baseInstructions) {
70248
70525
  let acceptedTurnId;
70249
70526
  let turnError = null;
70250
70527
  let resolveTurnEnded = null;
70251
- const turnEnded = new Promise((resolve) => {
70252
- resolveTurnEnded = resolve;
70528
+ const turnEnded = new Promise((resolve2) => {
70529
+ resolveTurnEnded = resolve2;
70253
70530
  });
70254
70531
  const unsub = handle.onEvent(threadId, (event) => {
70255
70532
  if (event.type === "assistant") chunks.push(event.content);
@@ -70468,7 +70745,7 @@ function createBridgeRequestListener(opts) {
70468
70745
  res.end(JSON.stringify({ ok: false, error: "Origin not allowed." }));
70469
70746
  return;
70470
70747
  }
70471
- const nonce = import_node_crypto15.default.randomBytes(16).toString("base64url");
70748
+ const nonce = import_node_crypto16.default.randomBytes(16).toString("base64url");
70472
70749
  res.writeHead(200, { "content-type": "application/json" });
70473
70750
  const publicHost = host === "0.0.0.0" ? "127.0.0.1" : host;
70474
70751
  res.end(JSON.stringify({ ok: true, wsUrl: `ws://${publicHost}:${port}/ws`, token, nonce }));
@@ -70772,7 +71049,7 @@ function createBridgeMessageHandler(deps) {
70772
71049
  }
70773
71050
  }
70774
71051
  socket.on("message", async (data) => {
70775
- const spanId = import_node_crypto15.default.randomUUID();
71052
+ const spanId = import_node_crypto16.default.randomUUID();
70776
71053
  if (logCtx) {
70777
71054
  logCtx.span.id = spanId;
70778
71055
  logCtx.span.at = Date.now();
@@ -71379,7 +71656,7 @@ function createBridgeMessageHandler(deps) {
71379
71656
  let desiredInstructionHash = null;
71380
71657
  try {
71381
71658
  const startParams = deps.buildStartParams(msg, desiredModel);
71382
- desiredInstructionHash = import_node_crypto15.default.createHash("sha256").update(startParams.baseInstructions ?? "").digest("hex");
71659
+ desiredInstructionHash = import_node_crypto16.default.createHash("sha256").update(startParams.baseInstructions ?? "").digest("hex");
71383
71660
  if (!thread) {
71384
71661
  const newThread = {
71385
71662
  threadId: "",
@@ -71456,7 +71733,7 @@ function createBridgeMessageHandler(deps) {
71456
71733
  thread.inFlight = true;
71457
71734
  pendingTurnSessions.delete(directorSessionId);
71458
71735
  thread.replay = createReplayBuffer({
71459
- turnId: (0, import_node_crypto15.randomUUID)(),
71736
+ turnId: (0, import_node_crypto16.randomUUID)(),
71460
71737
  spanId,
71461
71738
  ...deps.retentionMs !== void 0 ? { retentionMs: deps.retentionMs } : {},
71462
71739
  ...deps.ackLingerMs !== void 0 ? { ackLingerMs: deps.ackLingerMs } : {}
@@ -71609,8 +71886,8 @@ function createBridgeMessageHandler(deps) {
71609
71886
  }
71610
71887
  let resolveTurn = null;
71611
71888
  let rejectTurn = null;
71612
- const turnFinished = new Promise((resolve, reject) => {
71613
- resolveTurn = resolve;
71889
+ const turnFinished = new Promise((resolve2, reject) => {
71890
+ resolveTurn = resolve2;
71614
71891
  rejectTurn = (error51) => reject(error51);
71615
71892
  });
71616
71893
  let outputEvents = 0;
@@ -72239,6 +72516,7 @@ async function startDirectorBridge() {
72239
72516
  acquireExecutorAgent: async (worktreePath, providerId) => {
72240
72517
  const executor = await startExecutorServer({
72241
72518
  worktree: worktreePath,
72519
+ disabledGitHooksDir: prepareDisabledGitHooksDir(import_node_path38.default.join(config2.stateDir, "locks"), import_node_path38.default.basename(worktreePath)),
72242
72520
  provider: providerId
72243
72521
  });
72244
72522
  return { handle: executor.handle, dispose: executor.dispose };
@@ -72277,7 +72555,7 @@ async function startDirectorBridge() {
72277
72555
  };
72278
72556
  const sessionSinks = createSessionSinkRegistry();
72279
72557
  const tombstones = /* @__PURE__ */ new Map();
72280
- const bridgeInstanceId = (0, import_node_crypto15.randomUUID)();
72558
+ const bridgeInstanceId = (0, import_node_crypto16.randomUUID)();
72281
72559
  const asyncConsumerDeps = {
72282
72560
  client,
72283
72561
  run: wrappedTurnLock.run,
@@ -72604,7 +72882,7 @@ async function startDirectorBridge() {
72604
72882
  const bridgeLogger = createBridgeLogger(config2.stateDir, process.env);
72605
72883
  let bridgeBinShaShort = "unknown00000";
72606
72884
  try {
72607
- bridgeBinShaShort = import_node_crypto15.default.createHash("sha256").update(import_node_fs23.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
72885
+ bridgeBinShaShort = import_node_crypto16.default.createHash("sha256").update(import_node_fs23.default.readFileSync(process.argv[1] ?? "")).digest("hex").slice(0, 12);
72608
72886
  } catch {
72609
72887
  }
72610
72888
  attachBridgeWss(server, {
@@ -72695,9 +72973,9 @@ async function startDirectorBridge() {
72695
72973
  res.writeHead(400).end();
72696
72974
  });
72697
72975
  });
72698
- await new Promise((resolve, reject) => {
72976
+ await new Promise((resolve2, reject) => {
72699
72977
  dispatchServer.on("error", reject);
72700
- dispatchServer.listen(workerPort(), "127.0.0.1", () => resolve());
72978
+ dispatchServer.listen(workerPort(), "127.0.0.1", () => resolve2());
72701
72979
  });
72702
72980
  const bridgeHealth = new BridgeHealthTracker({
72703
72981
  stateDir: config2.stateDir,
@@ -72888,7 +73166,7 @@ async function startDirectorBridge() {
72888
73166
  )
72889
73167
  });
72890
73168
  }
72891
- await new Promise((resolve, reject) => {
73169
+ await new Promise((resolve2, reject) => {
72892
73170
  server.on("error", (err) => {
72893
73171
  if (err.code === "EADDRINUSE") {
72894
73172
  const conflictingPids = scanForOtherBridges();
@@ -72904,7 +73182,7 @@ async function startDirectorBridge() {
72904
73182
  }
72905
73183
  reject(err);
72906
73184
  });
72907
- server.listen(config2.port, config2.host, () => resolve());
73185
+ server.listen(config2.port, config2.host, () => resolve2());
72908
73186
  });
72909
73187
  const orphans = scanForOtherBridges();
72910
73188
  if (orphans.length > 0) {
@@ -73045,10 +73323,10 @@ function timingSafeTokenEqual(provided, expected) {
73045
73323
  const a = Buffer.from(provided);
73046
73324
  const b = Buffer.from(expected);
73047
73325
  if (a.length !== b.length) return false;
73048
- return import_node_crypto15.default.timingSafeEqual(a, b);
73326
+ return import_node_crypto16.default.timingSafeEqual(a, b);
73049
73327
  }
73050
73328
  function readDispatchBody(req) {
73051
- return new Promise((resolve, reject) => {
73329
+ return new Promise((resolve2, reject) => {
73052
73330
  const chunks = [];
73053
73331
  let size = 0;
73054
73332
  req.on("data", (chunk) => {
@@ -73060,7 +73338,7 @@ function readDispatchBody(req) {
73060
73338
  }
73061
73339
  chunks.push(chunk);
73062
73340
  });
73063
- req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
73341
+ req.on("end", () => resolve2(Buffer.concat(chunks).toString("utf8")));
73064
73342
  req.on("error", reject);
73065
73343
  });
73066
73344
  }
@@ -73074,7 +73352,7 @@ function readOrCreateBridgeToken(stateDir) {
73074
73352
  } catch {
73075
73353
  }
73076
73354
  import_node_fs23.default.mkdirSync(stateDir, { recursive: true, mode: 448 });
73077
- const token = import_node_crypto15.default.randomBytes(32).toString("base64url");
73355
+ const token = import_node_crypto16.default.randomBytes(32).toString("base64url");
73078
73356
  import_node_fs23.default.writeFileSync(tokenPath, `${token}
73079
73357
  `, { mode: 384 });
73080
73358
  return token;
@@ -73772,12 +74050,12 @@ var StdioServerTransport = class {
73772
74050
  this.onclose?.();
73773
74051
  }
73774
74052
  send(message) {
73775
- return new Promise((resolve) => {
74053
+ return new Promise((resolve2) => {
73776
74054
  const json2 = serializeMessage(message);
73777
74055
  if (this._stdout.write(json2)) {
73778
- resolve();
74056
+ resolve2();
73779
74057
  } else {
73780
- this._stdout.once("drain", resolve);
74058
+ this._stdout.once("drain", resolve2);
73781
74059
  }
73782
74060
  });
73783
74061
  }