github-router 0.3.151 → 0.3.152

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.
@@ -1176,35 +1176,172 @@ var ArtifactError = class extends Error {
1176
1176
  this.detail = args.detail;
1177
1177
  }
1178
1178
  };
1179
+ const AWAIT_DEFAULT_TIMEOUT_MS = 25e3;
1180
+ const AWAIT_ABORT_MARGIN_MS = 5e3;
1181
+ const DEFAULT_RETRY_BASE_MS = 250;
1182
+ const TRANSIENT_RETRIES = 2;
1183
+ const DEFAULT_RETRYABLE_CODES = new Set(["UNREACHABLE", "TIMEOUT"]);
1184
+ const AWAIT_RETRYABLE_CODES = new Set(["UNREACHABLE"]);
1179
1185
  var ArtifactClient = class {
1180
1186
  baseUrl;
1181
1187
  token;
1182
1188
  sessionId;
1183
1189
  fetchFn;
1184
1190
  insecureTLS;
1191
+ retryBaseMs;
1185
1192
  constructor(options) {
1186
1193
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
1187
1194
  this.token = options.token;
1188
1195
  this.sessionId = options.sessionId;
1189
1196
  this.fetchFn = options.fetchFn ?? globalThis.fetch.bind(globalThis);
1190
1197
  this.insecureTLS = options.insecureTLS ?? false;
1198
+ this.retryBaseMs = options.retryBaseMs ?? DEFAULT_RETRY_BASE_MS;
1191
1199
  }
1192
- open(file, signal) {
1193
- return this.request("POST", `/api/artifact/${encodeURIComponent(this.sessionId)}/open`, { file }, signal);
1200
+ /**
1201
+ * Open (or replace) the review for this session. `mode` is advisory metadata
1202
+ * forwarded to the server (forward-compat: ignored if unknown); the actual
1203
+ * interactivity comes from the served HTML's `data-aod-*` markup. Retried on a
1204
+ * transient failure with a STABLE idempotency key so a retry-after-success does
1205
+ * not double-open.
1206
+ */
1207
+ open(file, opts = {}) {
1208
+ const idempotencyKey = opts.idempotencyKey ?? randomUUID();
1209
+ const body = { file };
1210
+ if (opts.mode) body.mode = opts.mode;
1211
+ return this.withRetry(() => this.requestOnce({
1212
+ method: "POST",
1213
+ pathname: this.path("/open"),
1214
+ body,
1215
+ signal: opts.signal,
1216
+ idempotencyKey
1217
+ }), TRANSIENT_RETRIES, opts.signal);
1194
1218
  }
1195
- poll(timeoutMsHint, signal) {
1196
- return this.request("GET", `/api/artifact/${encodeURIComponent(this.sessionId)}/poll`, void 0, signal, timeoutMsHint);
1219
+ /**
1220
+ * Replace the current review's content. Exactly one of `file` | `html` (the
1221
+ * caller-facing tool enforces that). `html` is written by the SERVER to the
1222
+ * review's existing sandboxed file, so `html` with no existing review is an
1223
+ * INVALID_REQUEST from the server. Retried with a stable idempotency key.
1224
+ */
1225
+ update(opts) {
1226
+ const idempotencyKey = opts.idempotencyKey ?? randomUUID();
1227
+ const body = {};
1228
+ if (opts.file !== void 0) body.file = opts.file;
1229
+ if (opts.html !== void 0) body.html = opts.html;
1230
+ return this.withRetry(() => this.requestOnce({
1231
+ method: "POST",
1232
+ pathname: this.path("/update"),
1233
+ body,
1234
+ signal: opts.signal,
1235
+ idempotencyKey,
1236
+ allowEmptyJson: true
1237
+ }), TRANSIENT_RETRIES, opts.signal);
1238
+ }
1239
+ /** Force a reload from disk (no content change). Single-shot (idempotent, cheap). */
1240
+ refresh(signal) {
1241
+ return this.requestOnce({
1242
+ method: "POST",
1243
+ pathname: this.path("/refresh"),
1244
+ signal,
1245
+ allowEmptyJson: true
1246
+ });
1247
+ }
1248
+ /** Hide the panel UI while keeping the review alive. Single-shot; server idempotent. */
1249
+ dismiss(signal) {
1250
+ return this.requestOnce({
1251
+ method: "POST",
1252
+ pathname: this.path("/dismiss"),
1253
+ signal,
1254
+ allowEmptyJson: true
1255
+ });
1256
+ }
1257
+ /**
1258
+ * Typed drain (contract v2.2 §1/§2). Long-holds up to the server cap, returns
1259
+ * events with `id > cursor` plus the new high-water `cursor`. Idempotent by
1260
+ * (cursor, event.id): re-calling with the same cursor replays the same window
1261
+ * from the server's bounded buffer, so a lost cursor (compaction) is
1262
+ * recoverable. Retried on a transient network failure (the cursor makes retry
1263
+ * safe — no double-consumption).
1264
+ */
1265
+ awaitEvents(opts = {}) {
1266
+ const serverTimeoutMs = typeof opts.timeoutMs === "number" && Number.isFinite(opts.timeoutMs) && opts.timeoutMs > 0 ? opts.timeoutMs : AWAIT_DEFAULT_TIMEOUT_MS;
1267
+ const clientTimeoutMs = serverTimeoutMs + AWAIT_ABORT_MARGIN_MS;
1268
+ return this.withRetry(() => this.requestOnce({
1269
+ method: "GET",
1270
+ pathname: this.path("/await"),
1271
+ query: {
1272
+ cursor: opts.cursor,
1273
+ timeoutMs: String(serverTimeoutMs)
1274
+ },
1275
+ signal: opts.signal,
1276
+ timeoutMsHint: clientTimeoutMs
1277
+ }), TRANSIENT_RETRIES, opts.signal, AWAIT_RETRYABLE_CODES);
1197
1278
  }
1279
+ /** Free-text agent->human reply. SINGLE-SHOT (not retried): a retry-after-success
1280
+ * would render a duplicate chat bubble server-side. */
1198
1281
  agentReply(text, signal) {
1199
- return this.request("POST", `/api/artifact/${encodeURIComponent(this.sessionId)}/agent-reply`, { text }, signal, void 0, true);
1282
+ return this.requestOnce({
1283
+ method: "POST",
1284
+ pathname: this.path("/agent-reply"),
1285
+ body: { text },
1286
+ signal,
1287
+ allowEmptyJson: true
1288
+ });
1289
+ }
1290
+ /**
1291
+ * End the review. Retried with a stable idempotency key; a NOT_FOUND (the
1292
+ * review is already ended — whether by a prior call or by a retry landing after
1293
+ * the first attempt succeeded) is mapped to a successful `{ ok, status:"ended" }`
1294
+ * rather than surfaced as a 404 (contract v2.2 §1.1).
1295
+ */
1296
+ async end(signal) {
1297
+ const idempotencyKey = randomUUID();
1298
+ try {
1299
+ return await this.withRetry(() => this.requestOnce({
1300
+ method: "POST",
1301
+ pathname: this.path("/end"),
1302
+ signal,
1303
+ idempotencyKey,
1304
+ allowEmptyJson: true
1305
+ }), TRANSIENT_RETRIES, signal);
1306
+ } catch (err) {
1307
+ if (err instanceof ArtifactError && err.code === "NOT_FOUND") return {
1308
+ ok: true,
1309
+ status: "ended"
1310
+ };
1311
+ throw err;
1312
+ }
1313
+ }
1314
+ /**
1315
+ * FROZEN legacy long-poll (contract v2.2 §1). Old payload shape,
1316
+ * comment-equivalent only. New agents use `awaitEvents`. Single request per
1317
+ * call (the caller-facing tool owns the bounded re-poll budget).
1318
+ */
1319
+ poll(timeoutMsHint, signal) {
1320
+ return this.requestOnce({
1321
+ method: "GET",
1322
+ pathname: this.path("/poll"),
1323
+ signal,
1324
+ timeoutMsHint
1325
+ });
1200
1326
  }
1201
- end(signal) {
1202
- return this.request("POST", `/api/artifact/${encodeURIComponent(this.sessionId)}/end`, void 0, signal, void 0, true);
1327
+ path(suffix) {
1328
+ return `/api/artifact/${encodeURIComponent(this.sessionId)}${suffix}`;
1329
+ }
1330
+ async withRetry(fn, retries, signal, retryableCodes = DEFAULT_RETRYABLE_CODES) {
1331
+ let attempt = 0;
1332
+ for (;;) try {
1333
+ return await fn();
1334
+ } catch (err) {
1335
+ attempt += 1;
1336
+ if (!(err instanceof ArtifactError && err.retryable && retryableCodes.has(err.code)) || attempt > retries || signal?.aborted) throw err;
1337
+ const base = this.retryBaseMs;
1338
+ await sleep$1(base <= 0 ? 0 : Math.round(base * 2 ** (attempt - 1) * (.5 + Math.random() * .5)), signal);
1339
+ }
1203
1340
  }
1204
- async request(method, pathname, body, signal, timeoutMsHint, allowEmptyJson = false) {
1341
+ async requestOnce(o) {
1205
1342
  let url;
1206
1343
  try {
1207
- url = new URL(pathname, `${this.baseUrl}/`);
1344
+ url = new URL(o.pathname, `${this.baseUrl}/`);
1208
1345
  } catch (err) {
1209
1346
  throw new ArtifactError({
1210
1347
  code: "UNREACHABLE",
@@ -1213,48 +1350,73 @@ var ArtifactClient = class {
1213
1350
  detail: err
1214
1351
  });
1215
1352
  }
1216
- const timeout = combineSignalAndTimeout(signal, timeoutMsHint);
1217
- let response;
1353
+ if (o.query) {
1354
+ for (const [key, value] of Object.entries(o.query)) if (value !== void 0) url.searchParams.set(key, value);
1355
+ }
1356
+ const timeout = combineSignalAndTimeout(o.signal, o.timeoutMsHint);
1218
1357
  try {
1358
+ const headers = { Authorization: `Bearer ${this.token}` };
1359
+ if (o.body !== void 0) headers["Content-Type"] = "application/json";
1360
+ if (o.idempotencyKey) headers["Idempotency-Key"] = o.idempotencyKey;
1219
1361
  const init = {
1220
- method,
1221
- headers: {
1222
- Authorization: `Bearer ${this.token}`,
1223
- ...body === void 0 ? {} : { "Content-Type": "application/json" }
1224
- },
1225
- body: body === void 0 ? void 0 : JSON.stringify(body),
1362
+ method: o.method,
1363
+ headers,
1364
+ body: o.body === void 0 ? void 0 : JSON.stringify(o.body),
1226
1365
  redirect: "error",
1227
1366
  signal: timeout.signal
1228
1367
  };
1229
1368
  if (this.insecureTLS) applyInsecureTls(init);
1230
- response = await this.fetchFn(url.toString(), init);
1369
+ const response = await this.fetchFn(url.toString(), init);
1370
+ if (!response.ok) throw await mapHttpError$1(response);
1371
+ let text;
1372
+ try {
1373
+ text = await response.text();
1374
+ } catch (err) {
1375
+ if (isAbortLike$2(err)) throw mapNetworkError$1(err);
1376
+ throw new ArtifactError({
1377
+ code: "INVALID_RESPONSE",
1378
+ message: "artifact API response body could not be read",
1379
+ retryable: false,
1380
+ detail: err
1381
+ });
1382
+ }
1383
+ if (!text && o.allowEmptyJson) return {};
1384
+ try {
1385
+ return JSON.parse(text);
1386
+ } catch (err) {
1387
+ throw new ArtifactError({
1388
+ code: "INVALID_RESPONSE",
1389
+ message: "artifact API returned a non-JSON response",
1390
+ retryable: false,
1391
+ detail: err
1392
+ });
1393
+ }
1231
1394
  } catch (err) {
1395
+ if (err instanceof ArtifactError) throw err;
1232
1396
  throw mapNetworkError$1(err);
1233
1397
  } finally {
1234
1398
  timeout.cleanup();
1235
1399
  }
1236
- if (!response.ok) throw await mapHttpError$1(response);
1237
- const text = await response.text().catch((err) => {
1238
- throw new ArtifactError({
1239
- code: "INVALID_RESPONSE",
1240
- message: "artifact API response body could not be read",
1241
- retryable: false,
1242
- detail: err
1243
- });
1244
- });
1245
- if (!text && allowEmptyJson) return {};
1246
- try {
1247
- return JSON.parse(text);
1248
- } catch (err) {
1249
- throw new ArtifactError({
1250
- code: "INVALID_RESPONSE",
1251
- message: "artifact API returned a non-JSON response",
1252
- retryable: false,
1253
- detail: err
1254
- });
1255
- }
1256
1400
  }
1257
1401
  };
1402
+ function sleep$1(ms, signal) {
1403
+ if (ms <= 0) return Promise.resolve();
1404
+ return new Promise((resolve, reject) => {
1405
+ const onAbort = () => {
1406
+ clearTimeout(timer);
1407
+ reject(new DOMException("retry backoff aborted", "AbortError"));
1408
+ };
1409
+ const timer = setTimeout(() => {
1410
+ signal?.removeEventListener("abort", onAbort);
1411
+ resolve();
1412
+ }, ms);
1413
+ if (signal?.aborted) {
1414
+ onAbort();
1415
+ return;
1416
+ }
1417
+ signal?.addEventListener("abort", onAbort, { once: true });
1418
+ });
1419
+ }
1258
1420
  function combineSignalAndTimeout(signal, timeoutMsHint) {
1259
1421
  const timeoutMs = typeof timeoutMsHint === "number" && Number.isFinite(timeoutMsHint) && timeoutMsHint > 0 ? timeoutMsHint : void 0;
1260
1422
  if (timeoutMs === void 0) return {
@@ -1311,6 +1473,13 @@ async function mapHttpError$1(response) {
1311
1473
  status: response.status,
1312
1474
  detail
1313
1475
  });
1476
+ if (response.status === 400 && detailToCode(detail)?.toUpperCase() === "INVALID_REQUEST") return new ArtifactError({
1477
+ code: "INVALID_REQUEST",
1478
+ message: `artifact API rejected the request (400)${suffix}`,
1479
+ retryable: false,
1480
+ status: response.status,
1481
+ detail
1482
+ });
1314
1483
  return new ArtifactError({
1315
1484
  code: "UPSTREAM_ERROR",
1316
1485
  message: `artifact API returned HTTP ${response.status}${suffix}`,
@@ -1355,6 +1524,18 @@ function detailToMessage$1(detail) {
1355
1524
  }
1356
1525
  if (typeof record.message === "string") return record.message;
1357
1526
  }
1527
+ /** Extract a machine `code` from an upstream error body (`{error:{code}}` or
1528
+ * `{code}`) so a tagged 400 can be classified (INVALID_REQUEST). */
1529
+ function detailToCode(detail) {
1530
+ if (typeof detail !== "object" || detail === null) return void 0;
1531
+ const record = detail;
1532
+ const error = record.error;
1533
+ if (typeof error === "object" && error !== null) {
1534
+ const code = error.code;
1535
+ if (typeof code === "string") return code;
1536
+ }
1537
+ if (typeof record.code === "string") return record.code;
1538
+ }
1358
1539
  function isAbortLike$2(err) {
1359
1540
  return err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
1360
1541
  }
@@ -1383,27 +1564,86 @@ function tool(toolNameHttp, description, inputSchema, handler) {
1383
1564
  };
1384
1565
  }
1385
1566
  const ARTIFACT_TOOLS = Object.freeze([
1386
- tool("artifact_open", "Open a workspace file in ai-or-die's Artifact review panel for human review. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({ file: stringProp$2("Workspace-relative or absolute file path to show in the Artifact panel.") }, ["file"]), async (args, signal) => {
1567
+ tool("artifact_open", "Open a workspace file in ai-or-die's Artifact review panel for human review. Pass mode:\"interactive\" when the HTML carries data-aod-* action controls. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({
1568
+ file: stringProp$2("Workspace-relative or absolute file path to show in the Artifact panel."),
1569
+ mode: enumProp(["static", "interactive"], "Advisory. \"interactive\" signals the HTML contains data-aod-* action controls the panel should wire; \"static\" (default) is a read-and-annotate artifact.")
1570
+ }, ["file"]), async (args, signal) => {
1387
1571
  const env = readArtifactEnv();
1388
1572
  if (!env) return missingEnvResult();
1389
1573
  const file = requiredString$2(args, "file");
1574
+ const mode = optionalEnum(args, "mode", ["static", "interactive"]);
1575
+ const response = await clientFromEnv(env).open(file, {
1576
+ mode,
1577
+ signal
1578
+ });
1390
1579
  return ok$2({
1391
- viewUrl: (await clientFromEnv(env).open(file, signal)).viewUrl,
1392
- next_step: "Tell the user to review at the Artifact panel, then call artifact_poll."
1580
+ viewUrl: response.viewUrl,
1581
+ sessionId: response.sessionId,
1582
+ key: response.key,
1583
+ next_step: "Tell the user to review at the Artifact panel, then call artifact_await to receive their feedback."
1393
1584
  });
1394
1585
  }),
1395
- tool("artifact_poll", "Wait for human Artifact review feedback from ai-or-die and return the prompts/layout warnings/DOM snapshot for the agent to act on. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({}, []), async (_args, signal) => {
1586
+ tool("artifact_update", "Replace the current Artifact review's content in place. Provide EXACTLY ONE of file (a workspace file path) or html (raw HTML the server writes to the review's sandboxed file). html requires an already-open review. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({
1587
+ file: stringProp$2("Workspace-relative or absolute file path to become the review's new content."),
1588
+ html: stringProp$2("Raw HTML to write into the review's existing sandboxed file, then reload."),
1589
+ idempotencyKey: stringProp$2("Optional stable key so a retried update is de-duplicated by the server.")
1590
+ }, []), async (args, signal) => {
1396
1591
  const env = readArtifactEnv();
1397
1592
  if (!env) return missingEnvResult();
1398
- return ok$2(formatPollResponse(await pollUntilReady(clientFromEnv(env), signal)));
1593
+ const file = optionalString$2(args, "file");
1594
+ const html = optionalString$2(args, "html");
1595
+ if (file === void 0 === (html === void 0)) throw new ArtifactToolInputError("INVALID_ARGUMENT", "artifact_update requires EXACTLY ONE of arguments.file or arguments.html");
1596
+ const idempotencyKey = optionalString$2(args, "idempotencyKey");
1597
+ return ok$2({
1598
+ ...await clientFromEnv(env).update({
1599
+ file,
1600
+ html,
1601
+ idempotencyKey,
1602
+ signal
1603
+ }),
1604
+ ok: true,
1605
+ next_step: "The panel now shows the updated content. Call artifact_await for further feedback."
1606
+ });
1607
+ }),
1608
+ tool("artifact_refresh", "Force the ai-or-die Artifact panel to reload the current artifact from disk (no content change). Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({}, []), async (_args, signal) => {
1609
+ const env = readArtifactEnv();
1610
+ if (!env) return missingEnvResult();
1611
+ return ok$2({
1612
+ ...await clientFromEnv(env).refresh(signal),
1613
+ ok: true,
1614
+ next_step: "The panel reloaded the artifact. Call artifact_await for feedback."
1615
+ });
1616
+ }),
1617
+ tool("artifact_await", "Wait for the human's next Artifact review events (typed drain: comments AND structured action-button/checkbox events) and return them with a cursor. Pass the returned cursor on the next call to receive only newer events. Supersedes artifact_poll. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({
1618
+ cursor: stringProp$2("High-water cursor from the previous artifact_await response. Omit on the first call."),
1619
+ timeoutMs: numberProp$2("Optional server long-hold budget in ms (default ~25000).")
1620
+ }, []), async (args, signal) => {
1621
+ const env = readArtifactEnv();
1622
+ if (!env) return missingEnvResult();
1623
+ const cursor = optionalString$2(args, "cursor");
1624
+ const timeoutMs = optionalNumber$2(args, "timeoutMs");
1625
+ return ok$2(formatAwaitResponse(await clientFromEnv(env).awaitEvents({
1626
+ cursor,
1627
+ timeoutMs,
1628
+ signal
1629
+ })));
1630
+ }),
1631
+ tool("artifact_dismiss", "Hide the ai-or-die Artifact panel UI while keeping the review alive (queued feedback preserved, channel open, re-openable). Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({}, []), async (_args, signal) => {
1632
+ const env = readArtifactEnv();
1633
+ if (!env) return missingEnvResult();
1634
+ return ok$2({
1635
+ ...await clientFromEnv(env).dismiss(signal),
1636
+ ok: true,
1637
+ next_step: "The panel is hidden but the review is still live. Re-open the artifact or call artifact_await when ready."
1638
+ });
1399
1639
  }),
1400
1640
  tool("artifact_reply", "Send the agent's reply back to the ai-or-die Artifact review panel after applying or responding to human feedback. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({ text: stringProp$2("Agent reply text to deliver to the human Artifact review panel.") }, ["text"]), async (args, signal) => {
1401
1641
  const env = readArtifactEnv();
1402
1642
  if (!env) return missingEnvResult();
1403
1643
  const text = requiredString$2(args, "text");
1404
1644
  return ok$2({
1405
- ok: true,
1406
1645
  ...await clientFromEnv(env).agentReply(text, signal),
1646
+ ok: true,
1407
1647
  next_step: "Wait for further human review, or continue if the review loop is complete."
1408
1648
  });
1409
1649
  }),
@@ -1411,10 +1651,15 @@ const ARTIFACT_TOOLS = Object.freeze([
1411
1651
  const env = readArtifactEnv();
1412
1652
  if (!env) return missingEnvResult();
1413
1653
  return ok$2({
1414
- ok: true,
1415
1654
  ...await clientFromEnv(env).end(signal),
1655
+ ok: true,
1416
1656
  next_step: "Artifact review loop ended."
1417
1657
  });
1658
+ }),
1659
+ tool("artifact_poll", "FROZEN legacy alias for artifact_await (old payload, human comments only, no structured actions). New agents should call artifact_await instead. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({ timeoutMs: numberProp$2("Optional per-call budget hint in ms (advisory).") }, []), async (_args, signal) => {
1660
+ const env = readArtifactEnv();
1661
+ if (!env) return missingEnvResult();
1662
+ return ok$2(formatPollResponse(await pollUntilReady(clientFromEnv(env), signal)));
1418
1663
  })
1419
1664
  ]);
1420
1665
  function readArtifactEnv() {
@@ -1489,6 +1734,30 @@ function formatPollResponse(response) {
1489
1734
  next_step: response.next_step ?? defaultPollNextStep(response.status)
1490
1735
  });
1491
1736
  }
1737
+ /**
1738
+ * Shape the typed drain for the model: pass events through verbatim (unknown
1739
+ * `kind`s preserved — the model ignores what it does not understand), echo the
1740
+ * cursor to thread into the next call, and pick a next_step from the events.
1741
+ */
1742
+ function formatAwaitResponse(response) {
1743
+ const events$1 = Array.isArray(response.events) ? response.events : [];
1744
+ const status = typeof response.status === "string" ? response.status : void 0;
1745
+ return definedObject$1({
1746
+ events: events$1,
1747
+ status,
1748
+ cursor: response.cursor,
1749
+ next_step: awaitNextStep(status ?? "", events$1)
1750
+ });
1751
+ }
1752
+ function awaitNextStep(status, events$1) {
1753
+ if ((status ?? "").toLowerCase() === "ended") return "The review has ended. No further feedback will arrive.";
1754
+ if (events$1.length === 0) return "No feedback yet. Call artifact_await again, passing the returned cursor.";
1755
+ const hasAction = events$1.some((e) => e.kind === "action");
1756
+ const hasComment = events$1.some((e) => e.kind === "comment");
1757
+ if (hasAction && hasComment) return "Act on the action events (buttons/checkboxes) and the comments, reply with artifact_reply, then call artifact_await with the returned cursor.";
1758
+ if (hasAction) return "The human triggered action controls. Act on them, optionally artifact_reply, then call artifact_await with the returned cursor.";
1759
+ return "Apply the human comments, call artifact_reply with a concise summary, then artifact_await with the returned cursor.";
1760
+ }
1492
1761
  function defaultPollNextStep(status) {
1493
1762
  return isWaitingStatus(status) ? "No human feedback is ready yet. Call artifact_poll again." : "Apply the human Artifact review feedback, then call artifact_reply with a concise summary.";
1494
1763
  }
@@ -1501,6 +1770,24 @@ function requiredString$2(args, key) {
1501
1770
  if (typeof value !== "string" || value.trim() === "") throw new ArtifactToolInputError("INVALID_ARGUMENT", `arguments.${key} is required and must be a non-empty string`);
1502
1771
  return value;
1503
1772
  }
1773
+ function optionalString$2(args, key) {
1774
+ const value = args[key];
1775
+ if (value === void 0 || value === null) return void 0;
1776
+ if (typeof value !== "string" || value.trim() === "") throw new ArtifactToolInputError("INVALID_ARGUMENT", `arguments.${key} must be a non-empty string when provided`);
1777
+ return value;
1778
+ }
1779
+ function optionalNumber$2(args, key) {
1780
+ const value = args[key];
1781
+ if (value === void 0 || value === null) return void 0;
1782
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) throw new ArtifactToolInputError("INVALID_ARGUMENT", `arguments.${key} must be a positive number when provided`);
1783
+ return value;
1784
+ }
1785
+ function optionalEnum(args, key, allowed) {
1786
+ const value = optionalString$2(args, key);
1787
+ if (value === void 0) return void 0;
1788
+ if (!allowed.includes(value)) throw new ArtifactToolInputError("INVALID_ARGUMENT", `arguments.${key} must be one of ${allowed.join(", ")}`);
1789
+ return value;
1790
+ }
1504
1791
  var ArtifactToolInputError = class extends Error {
1505
1792
  code;
1506
1793
  constructor(code, message) {
@@ -1565,6 +1852,19 @@ function stringProp$2(description) {
1565
1852
  description
1566
1853
  };
1567
1854
  }
1855
+ function numberProp$2(description) {
1856
+ return {
1857
+ type: "number",
1858
+ description
1859
+ };
1860
+ }
1861
+ function enumProp(values, description) {
1862
+ return {
1863
+ type: "string",
1864
+ enum: [...values],
1865
+ description
1866
+ };
1867
+ }
1568
1868
 
1569
1869
  //#endregion
1570
1870
  //#region src/lib/fleet/mesh-egress-agent.ts
@@ -2769,7 +3069,7 @@ function isHardNotReady(reason) {
2769
3069
  */
2770
3070
  async function waitForMessageReady(client, localId, options = {}) {
2771
3071
  const now = options.now ?? Date.now;
2772
- const sleep$1 = options.sleep ?? realSleep;
3072
+ const sleep$2 = options.sleep ?? realSleep;
2773
3073
  const waitMs = Math.max(0, options.waitMs ?? 0);
2774
3074
  const pollMs = Math.max(1, options.pollMs ?? DEFAULT_READY_POLL_MS);
2775
3075
  const deadline = now() + waitMs;
@@ -2801,7 +3101,7 @@ async function waitForMessageReady(client, localId, options = {}) {
2801
3101
  ready: false,
2802
3102
  readiness: last
2803
3103
  };
2804
- await sleep$1(Math.min(pollMs, remaining));
3104
+ await sleep$2(Math.min(pollMs, remaining));
2805
3105
  }
2806
3106
  }
2807
3107
  /**
@@ -2879,7 +3179,7 @@ async function primeTurnCursor(client, localId, timeoutMs, signal) {
2879
3179
  */
2880
3180
  async function waitForTurnSettled(client, localId, options) {
2881
3181
  const now = options.now ?? Date.now;
2882
- const sleep$1 = options.sleep ?? realSleep;
3182
+ const sleep$2 = options.sleep ?? realSleep;
2883
3183
  const pollTimeoutMs = Math.max(1, options.pollTimeoutMs ?? DEFAULT_TURN_POLL_MS);
2884
3184
  const budget = Number.isFinite(options.timeoutMs) ? Math.max(0, options.timeoutMs) : 0;
2885
3185
  const deadline = now() + budget;
@@ -2911,7 +3211,7 @@ async function waitForTurnSettled(client, localId, options) {
2911
3211
  reason: "timeout",
2912
3212
  cursor
2913
3213
  };
2914
- await sleep$1(Math.min(TURN_POLL_ERROR_BACKOFF_MS, Math.max(0, deadline - now())));
3214
+ await sleep$2(Math.min(TURN_POLL_ERROR_BACKOFF_MS, Math.max(0, deadline - now())));
2915
3215
  continue;
2916
3216
  }
2917
3217
  cursor = response.cursor;
@@ -3028,13 +3328,13 @@ async function readTail(client, localId, lines, signal) {
3028
3328
  async function driveTask(deps) {
3029
3329
  const { client, localId, prompt, timeoutMs, expectReport, idempotencyKey, interruptKey, reportId, signal } = deps;
3030
3330
  const now = deps.now ?? Date.now;
3031
- const sleep$1 = deps.sleep ?? realSleep;
3331
+ const sleep$2 = deps.sleep ?? realSleep;
3032
3332
  const tailLines = deps.tailLines ?? DEFAULT_TAIL_LINES;
3033
3333
  const pollTimeoutMs = deps.pollTimeoutMs;
3034
3334
  const readyResult = await waitForMessageReady(client, localId, {
3035
3335
  waitMs: deps.idleWaitMs ?? DEFAULT_IDLE_WAIT_MS,
3036
3336
  now,
3037
- sleep: sleep$1,
3337
+ sleep: sleep$2,
3038
3338
  signal
3039
3339
  });
3040
3340
  if (!readyResult.ready && isHardNotReady(readyResult.readiness.reason)) return {
@@ -3077,7 +3377,7 @@ async function driveTask(deps) {
3077
3377
  pollTimeoutMs,
3078
3378
  cursor,
3079
3379
  now,
3080
- sleep: sleep$1,
3380
+ sleep: sleep$2,
3081
3381
  signal
3082
3382
  });
3083
3383
  cursor = settle.cursor;
@@ -3099,7 +3399,7 @@ async function driveTask(deps) {
3099
3399
  pollTimeoutMs,
3100
3400
  cursor,
3101
3401
  now,
3102
- sleep: sleep$1,
3402
+ sleep: sleep$2,
3103
3403
  signal
3104
3404
  });
3105
3405
  recovered = recovery.settled;
@@ -26890,4 +27190,4 @@ async function runStandInToolCall(args, signal) {
26890
27190
 
26891
27191
  //#endregion
26892
27192
  export { logStreamError as $, copilotBaseUrl as $t, BROWSE_DEFAULT_MODEL as A, UPSTREAM_FETCH_TIMEOUT_MS as At, toolbeltEnabled as B, cacheCopilotVersion as Bt, repoFingerprint as C, ArtifactClient as Ct, trustRepo as D, DEFAULT_CODEX_MODEL as Dt, stopReviewStateDir as E, DEFAULT_CLAUDE_MODEL_FALLBACKS as Et, appendPlanReminder as F, withInstallLock as Ft, searchWeb as G, resolveCodexModel as Gt, vscodeRipgrepPath as H, cacheVSCodeVersion as Ht, runWorkerAgent as I, setupCopilotToken as It, buildAdvisorStream as J, getModels as Jt, ADVISOR_INTERNAL_TOOL_NAME as K, resolveModel as Kt, withNoOutputRetry as L, setupGitHubAgentToken as Lt, IMPLEMENT_DEFAULT_MODEL as M, generateRandomPort as Mt, PLAN_DEFAULT_MODEL as N, pickClaudeDefault as Nt, resolveSealedGate as O, DEFAULT_CODEX_MODEL_FALLBACKS as Ot, REVIEW_DEFAULT_MODEL as P, getPackageVersion as Pt, isControllerClosedError as Q, GITHUB_API_BASE_URL as Qt, availableToolCommands as R, setupGitHubToken as Rt, isSubagentContext as S, shouldUseInsecureTls as St, stopGateEnabledForRepo as T, toolbeltPathOverride as Tt, TOOLBELT_TOOLS$1 as U, filterBetaHeader as Ut, toolbeltSkipSet as V, cacheModels as Vt, assetFor as W, isNullish as Wt, isAdvisorRequested as X, HTTPError as Xt, injectAdvisorTool as Y, fetchWithTransientRetry as Yt, buildOpenAIErrorEvent as Z, forwardError as Zt, stopReviewEnabled as _, provisionBrowserAssets as _t, buildPeerAwarenessSnippet as a, browserToolsEnabled as at, fileLastPromptStore as b, extractTarGzMember as bt, buildSessionBindHookCommand as c, workerToolsEnabled as ct, decideStopHook as d, getTokenCount as dt, copilotHeaders as en, readIteratorWithTimeout as et, fileBlockBudget as f, createResponses as ft, stopGateId as g, parseJsonOrDiagnose as gt, stopGateDisabled as h, readResponseBodyCapped as ht, buildAgentPrompt as i, agentToolsEnabled as it, DEFAULT_MODEL as j, UPSTREAM_INACTIVITY_TIMEOUT_MS as jt, liveExec as k, DEFAULT_PORT as kt, buildStopHookCommand as l, countTokens as lt, launchBaselineKey as m, MAX_RESPONSE_BODY_BYTES as mt, MCP_GROUPS as n, state as nn, handleMcpDelete as nt, personasFor as o, fleetToolsEnabled as ot, injectStopHookIntoSettingsFile as p, createChatCompletions as pt, ADVISOR_TOOL_INSTRUCTIONS as q, sleep as qt, assertMcpToolSurfaceConsistent as r, handleMcpPost as rt, buildArtifactOpenHookCommand as s, standInToolEnabled as st, GROUP_META as t, githubHeaders as tn, relayAnthropicStream as tt, captureLaunchBaseline as u, createMessages as ut, fileBaselineStore as v, hasSupportedBrowserInstalled as vt, repoRoot as w, collapsePathKeys as wt, fileReviewDebounce as x, extractZipMember as xt, fileFindingsStore as y, provisionAndIndexColbert as yt, buildToolbeltAwareness as z, tryRefreshAndRetry as zt };
26893
- //# sourceMappingURL=peer-mcp-personas-Dm3UCpXz.js.map
27193
+ //# sourceMappingURL=peer-mcp-personas-BQVOxB1i.js.map