github-router 0.3.168 → 0.3.176

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.
@@ -1072,13 +1072,15 @@ function pickClaudeDefault(opusFamily = DEFAULT_OPUS_FAMILY) {
1072
1072
  return bareSlug;
1073
1073
  }
1074
1074
  /**
1075
- * Default model for `github-router codex`. `gpt-5.5` is the new flagship
1076
- * `/responses` model; the fallback chain handles older Copilot tiers where
1077
- * 5.5 hasn't rolled out yet. `resolveCodexModel` provides a final
1078
- * "best available `/responses` model" safety net beyond this list.
1075
+ * Default model for `github-router codex`. `gpt-5.6-sol` is the flagship
1076
+ * `/responses` model; the fallback chain (led by `gpt-5.5`) handles older
1077
+ * Copilot tiers or a rollout-lag window where sol hasn't appeared yet.
1078
+ * `resolveCodexModel` provides a final "best available `/responses` model"
1079
+ * safety net beyond this list.
1079
1080
  */
1080
- const DEFAULT_CODEX_MODEL = "gpt-5.5";
1081
+ const DEFAULT_CODEX_MODEL = "gpt-5.6-sol";
1081
1082
  const DEFAULT_CODEX_MODEL_FALLBACKS = [
1083
+ "gpt-5.5",
1082
1084
  "gpt-5.4",
1083
1085
  "gpt-5.3-codex",
1084
1086
  "gpt-5.2-codex"
@@ -1565,7 +1567,7 @@ function tool(toolNameHttp, description, inputSchema, handler) {
1565
1567
  };
1566
1568
  }
1567
1569
  const ARTIFACT_TOOLS = Object.freeze([
1568
- 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({
1570
+ tool("artifact_open", "Opens a workspace file in ai-or-die's Artifact review panel for human review, replacing the current review if one is already open. The caller provides a workspace-relative or absolute file path and can set mode:\"interactive\" when the HTML carries data-aod-* action controls. It returns the review URL/session identifiers plus next-step guidance for draining feedback. Use it when the user should review a durable artifact before work continues; it is not for one-line status updates or non-file content. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({
1569
1571
  file: stringProp$2("Workspace-relative or absolute file path to show in the Artifact panel."),
1570
1572
  mode: enumProp$1(["static", "interactive"], "Advisory. \"interactive\" signals the HTML contains data-aod-* action controls the panel should wire; \"static\" (default) is a read-and-annotate artifact.")
1571
1573
  }, ["file"]), async (args, signal) => {
@@ -1584,7 +1586,7 @@ const ARTIFACT_TOOLS = Object.freeze([
1584
1586
  next_step: "Tell the user to review at the Artifact panel, then call artifact_await to receive their feedback."
1585
1587
  });
1586
1588
  }),
1587
- 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({
1589
+ tool("artifact_update", "Replaces the current Artifact review's content in place without opening a separate review. The caller provides exactly one of file, a workspace-relative or absolute file path, or html, raw HTML written into the existing review sandbox; html requires an already-open review, and idempotencyKey can make retries deduplicate on the server. It returns a minimal success signal plus next-step guidance for awaiting further feedback. Use it when revised content should replace what the human is already reviewing; use artifact_refresh instead when the existing on-disk artifact only needs to be reloaded. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({
1588
1590
  file: stringProp$2("Workspace-relative or absolute file path to become the review's new content."),
1589
1591
  html: stringProp$2("Raw HTML to write into the review's existing sandboxed file, then reload."),
1590
1592
  idempotencyKey: stringProp$2("Optional stable key so a retried update is de-duplicated by the server.")
@@ -1595,27 +1597,19 @@ const ARTIFACT_TOOLS = Object.freeze([
1595
1597
  const html = optionalString$2(args, "html");
1596
1598
  if (file === void 0 === (html === void 0)) throw new ArtifactToolInputError("INVALID_ARGUMENT", "artifact_update requires EXACTLY ONE of arguments.file or arguments.html");
1597
1599
  const idempotencyKey = optionalString$2(args, "idempotencyKey");
1598
- return ok$2({
1599
- ...await clientFromEnv(env).update({
1600
- file,
1601
- html,
1602
- idempotencyKey,
1603
- signal
1604
- }),
1605
- ok: true,
1606
- next_step: "The panel now shows the updated content. Call artifact_await for further feedback."
1607
- });
1600
+ return ok$2(formatUpdateSuccess(await clientFromEnv(env).update({
1601
+ file,
1602
+ html,
1603
+ idempotencyKey,
1604
+ signal
1605
+ })));
1608
1606
  }),
1609
- 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) => {
1607
+ tool("artifact_refresh", "Reloads the currently-open Artifact review from its existing on-disk file without changing the content source. The tool takes no inputs and returns a minimal success signal plus next-step guidance for awaiting feedback. Use it after an out-of-band edit changes the reviewed file on disk and the panel needs to pick up that version. Do not use it to replace the artifact with a new file or raw HTML; use artifact_update for that. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({}, []), async (_args, signal) => {
1610
1608
  const env = readArtifactEnv();
1611
1609
  if (!env) return missingEnvResult();
1612
- return ok$2({
1613
- ...await clientFromEnv(env).refresh(signal),
1614
- ok: true,
1615
- next_step: "The panel reloaded the artifact. Call artifact_await for feedback."
1616
- });
1610
+ return ok$2(formatRefreshSuccess(await clientFromEnv(env).refresh(signal)));
1617
1611
  }),
1618
- 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({
1612
+ tool("artifact_await", "Waits for the human's next Artifact review events and returns a typed drain containing comments, structured action-button or checkbox events, status, cursor, and next-step guidance. The caller can pass the cursor from a previous response to receive only newer events and can provide timeoutMs as the server long-hold budget. It may return an empty events list on a quiet long-hold; callers should pass the returned cursor on the next artifact_await call. Use it as the primary review-feedback drain after artifact_open or artifact_update; it supersedes artifact_poll, which is legacy comments-only. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({
1619
1613
  cursor: stringProp$2("High-water cursor from the previous artifact_await response. Omit on the first call."),
1620
1614
  timeoutMs: numberProp$2("Optional server long-hold budget in ms (default ~25000).")
1621
1615
  }, []), async (args, signal) => {
@@ -1629,35 +1623,23 @@ const ARTIFACT_TOOLS = Object.freeze([
1629
1623
  signal
1630
1624
  })));
1631
1625
  }),
1632
- 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) => {
1626
+ tool("artifact_dismiss", "Hides the ai-or-die Artifact panel UI while keeping the current review alive. The tool takes no inputs and returns a minimal success signal plus next-step guidance for reopening or awaiting later feedback. Use it when the panel should get out of the way but queued feedback should remain preserved, the channel should stay open, and the review should be re-openable. Do not use it when the review loop is finished; use artifact_end to close the review instead. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({}, []), async (_args, signal) => {
1633
1627
  const env = readArtifactEnv();
1634
1628
  if (!env) return missingEnvResult();
1635
- return ok$2({
1636
- ...await clientFromEnv(env).dismiss(signal),
1637
- ok: true,
1638
- next_step: "The panel is hidden but the review is still live. Re-open the artifact or call artifact_await when ready."
1639
- });
1629
+ return ok$2(formatDismissSuccess(await clientFromEnv(env).dismiss(signal)));
1640
1630
  }),
1641
- 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) => {
1631
+ tool("artifact_reply", "Sends the agent's reply back to the ai-or-die Artifact review panel after applying or responding to human feedback. The caller provides the reply text, and the tool returns a minimal success signal plus next-step guidance for either continuing the review loop or moving on. Use it to acknowledge what changed, answer a reviewer question, or summarize how feedback was handled after artifact_await returns events. Do not use it to replace panel content, wait for more feedback, hide the UI, or close the review. 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) => {
1642
1632
  const env = readArtifactEnv();
1643
1633
  if (!env) return missingEnvResult();
1644
1634
  const text = requiredString$2(args, "text");
1645
- return ok$2({
1646
- ...await clientFromEnv(env).agentReply(text, signal),
1647
- ok: true,
1648
- next_step: "Wait for further human review, or continue if the review loop is complete."
1649
- });
1635
+ return ok$2(formatReplySuccess(await clientFromEnv(env).agentReply(text, signal)));
1650
1636
  }),
1651
- tool("artifact_end", "End/close the ai-or-die Artifact review panel when the review loop is complete. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({}, []), async (_args, signal) => {
1637
+ tool("artifact_end", "Ends and closes the ai-or-die Artifact review panel when the review loop is complete. The tool takes no inputs and returns a minimal success signal plus terminal next-step guidance. Use it after the human review is finished and no further feedback should arrive. Do not use it for a temporary hide or pause; use artifact_dismiss when the review should stay live. Only works inside an ai-or-die tab-backed Claude session.", objectSchema$2({}, []), async (_args, signal) => {
1652
1638
  const env = readArtifactEnv();
1653
1639
  if (!env) return missingEnvResult();
1654
- return ok$2({
1655
- ...await clientFromEnv(env).end(signal),
1656
- ok: true,
1657
- next_step: "Artifact review loop ended."
1658
- });
1640
+ return ok$2(formatEndSuccess(await clientFromEnv(env).end(signal)));
1659
1641
  }),
1660
- 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) => {
1642
+ tool("artifact_poll", "Provides the frozen legacy polling path for Artifact review feedback. The caller may provide timeoutMs as an advisory per-call budget, and the tool returns the old comments-only payload with status, prompts, and next-step guidance rather than typed action events or a cursor. Use it only for compatibility with older clients or flows that still require the old payload shape. New callers should use artifact_await instead because it returns typed comments and structured action-button or checkbox events. 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) => {
1661
1643
  const env = readArtifactEnv();
1662
1644
  if (!env) return missingEnvResult();
1663
1645
  return ok$2(formatPollResponse(await pollUntilReady(clientFromEnv(env), signal)));
@@ -1735,6 +1717,50 @@ function formatPollResponse(response) {
1735
1717
  next_step: response.next_step ?? defaultPollNextStep(response.status)
1736
1718
  });
1737
1719
  }
1720
+ function formatUpdateSuccess(response) {
1721
+ return definedObject$1({
1722
+ ok: true,
1723
+ viewUrl: stringField$1(response, "viewUrl"),
1724
+ next_step: "The panel now shows the updated content. Call artifact_await for further feedback."
1725
+ });
1726
+ }
1727
+ function formatRefreshSuccess(response) {
1728
+ return definedObject$1({
1729
+ ok: true,
1730
+ viewUrl: stringField$1(response, "viewUrl"),
1731
+ panelUrl: stringField$1(response, "panelUrl"),
1732
+ status: stringField$1(response, "status"),
1733
+ visibility: stringField$1(response, "visibility"),
1734
+ next_step: "The panel reloaded the artifact. Call artifact_await for feedback."
1735
+ });
1736
+ }
1737
+ function formatDismissSuccess(response) {
1738
+ return definedObject$1({
1739
+ ok: true,
1740
+ viewUrl: stringField$1(response, "viewUrl"),
1741
+ panelUrl: stringField$1(response, "panelUrl"),
1742
+ status: stringField$1(response, "status"),
1743
+ visibility: stringField$1(response, "visibility"),
1744
+ next_step: "The panel is hidden but the review is still live. Re-open the artifact or call artifact_await when ready."
1745
+ });
1746
+ }
1747
+ function formatReplySuccess(response) {
1748
+ return definedObject$1({
1749
+ ok: true,
1750
+ reply: response.reply,
1751
+ delivered: booleanField(response, "delivered"),
1752
+ confirmed: booleanField(response, "confirmed"),
1753
+ status: stringField$1(response, "status"),
1754
+ next_step: "Wait for further human review, or continue if the review loop is complete."
1755
+ });
1756
+ }
1757
+ function formatEndSuccess(response) {
1758
+ return definedObject$1({
1759
+ ok: true,
1760
+ status: response.status,
1761
+ next_step: "Artifact review loop ended."
1762
+ });
1763
+ }
1738
1764
  /**
1739
1765
  * Shape the typed drain for the model: pass events through verbatim (unknown
1740
1766
  * `kind`s preserved — the model ignores what it does not understand), echo the
@@ -1839,6 +1865,14 @@ function definedObject$1(input) {
1839
1865
  for (const [key, value] of Object.entries(input)) if (value !== void 0) result[key] = value;
1840
1866
  return result;
1841
1867
  }
1868
+ function stringField$1(input, key) {
1869
+ const value = input[key];
1870
+ return typeof value === "string" ? value : void 0;
1871
+ }
1872
+ function booleanField(input, key) {
1873
+ const value = input[key];
1874
+ return typeof value === "boolean" ? value : void 0;
1875
+ }
1842
1876
  function objectSchema$2(properties, required) {
1843
1877
  return {
1844
1878
  type: "object",
@@ -3596,10 +3630,10 @@ function createFleetTools(options = {}) {
3596
3630
  };
3597
3631
  }
3598
3632
  return Object.freeze([
3599
- tool$1("list_instances", "List registered remote ai-or-die instances in the fleet registry. Tokens are never returned.", objectSchema$1({}, []), async () => {
3633
+ tool$1("list_instances", "Lists registered remote ai-or-die fleet instances and probes whether each instance is currently reachable. It takes no input; the registry decides which instances exist, and credentials or tunnel tokens are not returned. It returns instances with id, label, reachable status, sessionCount and lastSeen for reachable hosts, or error and hint for unreachable hosts. It is useful as the discovery entry point before list_sessions, create_session, or other fleet tools that need an instance id. It is not for local repository search or for reading sessions; use local tools for this machine and list_sessions after choosing an instance.", objectSchema$1({}, []), async () => {
3600
3634
  return ok$1({ instances: await mapWithConcurrency(await getRegistry().listInstances(), fleetFanoutConcurrency(LIST_INSTANCES_FANOUT_CONCURRENCY), (instance) => probeInstance(instance)) });
3601
3635
  }),
3602
- tool$1("list_sessions", "List sessions on one fleet instance, returning globally-addressable session ids.", objectSchema$1({ instance: stringProp$1("Instance id or label. Defaults to the registry default, or the sole instance.") }, []), async (args, signal) => {
3636
+ tool$1("list_sessions", "Lists sessions on one remote ai-or-die fleet instance and returns session ids that can be used by the other fleet session tools. The optional instance input is an id or label; when it is omitted, the registry default or sole instance is used. It returns resolvedInstance and sessions, with each sessionId globalized as instanceId:localSessionId. It is useful after list_instances to choose a remote session to inspect, message, drive, or stop. It is not a fleet-wide listing and does not read transcript output; call it per instance, and use read_session for a session's text tail.", objectSchema$1({ instance: stringProp$1("Instance id or label. Defaults to the registry default, or the sole instance.") }, []), async (args, signal) => {
3603
3637
  const instance = await resolve(optionalString$1(args, "instance"));
3604
3638
  const response = await clientFor(instance).listSessions(signal);
3605
3639
  return ok$1({
@@ -3607,11 +3641,10 @@ function createFleetTools(options = {}) {
3607
3641
  sessions: response.sessions.map((session) => globalizeSession(instance.id, session))
3608
3642
  });
3609
3643
  }),
3610
- tool$1("read_session", "Read recent text output from an addressed fleet session.", objectSchema$1({
3644
+ tool$1("read_session", "Reads recent text output from an addressed remote ai-or-die fleet session. The required sessionId must be a global id in instanceId:localSessionId form; the optional instance input is only a cross-check and must resolve to the same instance. It returns resolvedInstance, sessionId, text, truncated, source, and the session status snapshot. It is useful for inspecting the transcript tail after send_message, await_turn, or drive_task. It is not for lifecycle-only checks or live waiting; use session_status for point-in-time state and await_turn to wait for new events.", objectSchema$1({
3611
3645
  sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
3612
3646
  instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId."),
3613
- lines: numberProp$1("Number of recent lines to read."),
3614
- format: stringProp$1("Reserved for future formatting; results are JSON text today.")
3647
+ lines: numberProp$1("Number of recent lines to read.")
3615
3648
  }, ["sessionId"]), async (args, signal) => {
3616
3649
  const { instance, localId, globalId } = await resolveSession(args);
3617
3650
  const lines = optionalNumber$1(args, "lines");
@@ -3622,7 +3655,7 @@ function createFleetTools(options = {}) {
3622
3655
  sessionId: globalId
3623
3656
  });
3624
3657
  }),
3625
- tool$1("session_status", "Fetch lifecycle and interaction status for an addressed fleet session.", objectSchema$1({
3658
+ tool$1("session_status", "Fetches the lifecycle and interaction status for an addressed remote ai-or-die fleet session. The required sessionId must be a global id in instanceId:localSessionId form; the optional instance input is only a cross-check and must resolve to the same instance. It returns resolvedInstance, sessionId, and a status object that can include lifecycle, interactionState, canAcceptInput, blockReason, and awaiting details. It is useful before deciding whether a session can accept a message or is awaiting a prompt. It is not a transcript reader or event watcher; use read_session for output text and await_turn for turn-completion events.", objectSchema$1({
3626
3659
  sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
3627
3660
  instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId.")
3628
3661
  }, ["sessionId"]), async (args, signal) => {
@@ -3634,7 +3667,7 @@ function createFleetTools(options = {}) {
3634
3667
  sessionId: globalId
3635
3668
  });
3636
3669
  }),
3637
- tool$1("send_message", "Send a message to a fleet session. By DEFAULT it first checks the session is idle / awaiting the next message and REFUSES (structured notReady, isError) rather than blind-type into a busy composer or a pending prompt set requireIdle:false to force the legacy unconditional send, or waitForIdleMs to wait briefly for idle first. isError reflects DELIVERY: true when the message was not delivered (transport/precondition failure) OR refused as notReady. A delivered message whose confirmation did not arrive within awaitMs is NOT an error it returns delivered:true with confirmationPending/confirmationTimedOut, because a long turn legitimately outruns awaitMs. The additive `submitted` field is true only when ai-or-die's submission sub-status proves the message reached the composer. Recommended pattern: send with awaitMs:0 for a fast delivery ack, then call await_turn (filtered to this sessionId) to observe the session's actual turn completion. The idempotencyKey makes a retried send safe (a retry never re-types the message).", objectSchema$1({
3670
+ tool$1("send_message", "Sends a free-text message to an existing remote ai-or-die fleet session. The required sessionId must be global, message is the text to deliver, requireIdle defaults to true, waitForIdleMs can wait briefly for readiness, awaitMs waits only for best-effort delivery confirmation, and idempotencyKey is usually auto-generated unless retrying the same send. It returns resolvedInstance, sessionId, delivered, confirmed, submitted when the remote proves the composer accepted the message, and confirmationPending/confirmationTimedOut when delivery succeeded but the turn outran the await window; delivered:false or notReady is reported as an error result. It is useful for sending the next free-text instruction to an idle session, especially with awaitMs:0 followed by await_turn for the actual turn boundary. It is not for answering an awaited choice prompt or sending control keys; use respond for prompts and send_keys for submit, interrupt, or literal key sequences.", objectSchema$1({
3638
3671
  sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
3639
3672
  instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId."),
3640
3673
  message: stringProp$1("Message text to deliver to the session."),
@@ -3691,7 +3724,7 @@ function createFleetTools(options = {}) {
3691
3724
  ...isError ? { message: "message was not delivered to the session by the upstream instance" } : confirmationTimedOut ? { message: "delivered; turn completion not confirmed in the await window. Use await_turn filtered to this sessionId to observe completion (the idempotencyKey makes a retried send safe)." } : {}
3692
3725
  }, isError);
3693
3726
  }),
3694
- tool$1("send_keys", "Send key input to a fleet session. Prefer the higher-level `op`: 'submit' presses Enter and 'interrupt' sends Ctrl-C, each mapped to ai-or-die's NAMED key (never a literal control byte like \"\\r\"). Use `keys` only for literal input; `raw` is strictly for literal bytes. Provide exactly one of `op` or `keys`.", objectSchema$1({
3727
+ tool$1("send_keys", "Sends key input to an existing remote ai-or-die fleet session. The required sessionId must be global; provide exactly one of op or keys, where op is a named operation (`submit` for Enter or `interrupt` for Ctrl-C) and keys is a literal key sequence; raw only applies to literal keys. It returns resolvedInstance, sessionId, delivered, duplicated when an idempotency retry was deduped, and the mapped key name when op was used. It is useful for control-key actions such as submitting a typed prompt or interrupting a busy turn without stopping the session. It is not the normal free-text path and not the prompt-answer path; use send_message for free text and respond for awaited prompts.", objectSchema$1({
3695
3728
  sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
3696
3729
  instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId."),
3697
3730
  op: stringProp$1("Higher-level named op: 'submit' (Enter) or 'interrupt' (Ctrl-C). Mapped to the ai-or-die named key with raw off. Do NOT also pass keys."),
@@ -3726,10 +3759,11 @@ function createFleetTools(options = {}) {
3726
3759
  op,
3727
3760
  mappedKeys: keys
3728
3761
  },
3729
- ...response
3762
+ delivered: response.delivered,
3763
+ ...response.duplicated === void 0 ? {} : { duplicated: response.duplicated }
3730
3764
  });
3731
3765
  }),
3732
- tool$1("respond", "Answer an awaited prompt in a fleet session by choice, option value, or explicit key override.", objectSchema$1({
3766
+ tool$1("respond", "Answers an awaited prompt in an existing remote ai-or-die fleet session by selecting a choice, selecting an exact option value, or sending explicit keys. The required sessionId must be global; choose the answer mode that matches the prompt, and idempotencyKey is usually auto-generated unless retrying the same response. It returns resolvedInstance, sessionId, delivered, duplicated when an idempotency retry was deduped, and any awaitingKind or mappedKeys supplied by the remote; delivered:false is reported as an error result. It is useful only when session_status or await_turn shows the session is waiting for a prompt or choice. It is not for ordinary free-text instructions or control keys; use send_message for free text and send_keys for submit or interrupt.", objectSchema$1({
3733
3767
  sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
3734
3768
  instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId."),
3735
3769
  choice: stringProp$1("Named or numbered choice to select."),
@@ -3745,23 +3779,35 @@ function createFleetTools(options = {}) {
3745
3779
  idempotencyKey: optionalString$1(args, "idempotencyKey") ?? randomUUID()
3746
3780
  });
3747
3781
  const response = await clientFor(instance).respond(localId, input, signal);
3748
- return ok$1({
3782
+ const delivered = response.delivered !== false;
3783
+ return jsonResult$1({
3749
3784
  resolvedInstance: publicInstance(instance),
3750
3785
  sessionId: globalId,
3751
- ...response
3752
- });
3786
+ ...response,
3787
+ delivered,
3788
+ ...delivered ? {} : { message: "response was not delivered to the session by the upstream instance" }
3789
+ }, !delivered);
3753
3790
  }),
3754
- tool$1("create_session", "Create a new session on a specific fleet instance. The instance argument is required; no default is used.", objectSchema$1({
3791
+ tool$1("create_session", "Creates a new session on a specific remote ai-or-die fleet instance. The instance input is required and never defaults; agent is required and must be one of claude, codex, copilot, gemini, or terminal; start:true is required for the session to actually run and be driveable. It returns resolvedInstance plus the remote create response, with sessionId converted to the global instanceId:localSessionId form when creation succeeds. It is useful when the user wants a new remote session to run on a named fleet host before using drive_task, send_message, or await_turn. It is not for selecting or inspecting an existing session; use list_instances and list_sessions first when the target is unknown.", objectSchema$1({
3755
3792
  instance: stringProp$1("Required instance id or label. Create never uses the registry default."),
3756
- agent: stringProp$1("Agent/runtime to create on the instance."),
3793
+ agent: {
3794
+ ...stringProp$1("Required agent/runtime to create on the instance. Valid values: claude, codex, copilot, gemini, terminal."),
3795
+ enum: [
3796
+ "claude",
3797
+ "codex",
3798
+ "copilot",
3799
+ "gemini",
3800
+ "terminal"
3801
+ ]
3802
+ },
3757
3803
  name: stringProp$1("Optional display name for the session."),
3758
3804
  workingDir: stringProp$1("Optional working directory on the remote instance."),
3759
3805
  idempotencyKey: stringProp$1("Optional caller idempotency key; auto-generated when omitted."),
3760
- start: booleanProp("Whether the remote instance should start the session immediately."),
3761
- readyTimeoutMs: numberProp$1("F17: bounded ms to wait for the agent to become driveable before returning. The response carries ready/bound/blocker."),
3762
- permissionMode: stringProp$1("F10 (claude only): permission mode the launched agent starts in — one of plan | acceptEdits | default | bypassPermissions. Rejected with BAD_REQUEST if unknown or if agentArgs also sets it."),
3763
- agentArgs: arrayProp("F10 (claude only): extra launcher args appended after the github-router prefix. Must NOT include --permission-mode or --dangerously-skip-permissions (use permissionMode) — rejected with BAD_REQUEST."),
3764
- disableStopGate: booleanProp("C3 (claude only): disable the structural Stop-gate on the launched session by injecting --no-stop-gate into agentArgs, so a driven session's turn-end never hangs on a blocking Stop hook. Requires a remote github-router that understands the flag (uses the agent_args capability).")
3806
+ start: booleanProp("Set true to start the remote session immediately; without start:true the created session is not running or driveable."),
3807
+ readyTimeoutMs: numberProp$1("Bounded milliseconds to wait for the agent to become driveable before returning. The response carries ready, bound, and blocker."),
3808
+ permissionMode: stringProp$1("Claude-only permission mode for the launched agent: plan, acceptEdits, default, or bypassPermissions. Rejected with BAD_REQUEST if unknown or if agentArgs also sets it."),
3809
+ agentArgs: arrayProp("Claude-only extra launcher args appended after the github-router prefix. Do not include --permission-mode or --dangerously-skip-permissions; use permissionMode instead."),
3810
+ disableStopGate: booleanProp("Claude-only option to disable the structural Stop-gate on the launched session by injecting --no-stop-gate into agentArgs, so a driven session's turn-end does not hang on a blocking Stop hook. Requires a remote github-router that understands the flag.")
3765
3811
  }, ["instance", "agent"]), async (args, signal) => {
3766
3812
  const instance = await resolve(requiredString$1(args, "instance"));
3767
3813
  const agent = requiredString$1(args, "agent");
@@ -3789,7 +3835,7 @@ function createFleetTools(options = {}) {
3789
3835
  sessionId: localSessionId ? encodeSessionId(instance.id, localSessionId) : response.sessionId
3790
3836
  });
3791
3837
  }),
3792
- tool$1("stop_session", "Stop a fleet session.", objectSchema$1({
3838
+ tool$1("stop_session", "Terminates an existing remote ai-or-die fleet session. The required sessionId must be global; instance is only a cross-check, mode is an optional remote-understood stop mode, and idempotencyKey is usually auto-generated unless retrying the same stop. It returns resolvedInstance, sessionId, stopped, and lifecycle. It is useful when the remote session should be ended and its in-flight turn should be killed. It is destructive and irreversible, with no resume companion; to merely unstick or interrupt a busy session without terminating it, use send_keys with op `interrupt`.", objectSchema$1({
3793
3839
  sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
3794
3840
  instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId."),
3795
3841
  idempotencyKey: stringProp$1("Optional caller idempotency key; auto-generated when omitted."),
@@ -3807,10 +3853,10 @@ function createFleetTools(options = {}) {
3807
3853
  ...response
3808
3854
  });
3809
3855
  }),
3810
- tool$1("await_turn", "Long-poll session events across fleet instances. The server owns per-target opaque cursors, so callers do not pass cursor tokens. Distinct concurrent watchers over the same instance set should pass a distinct watcherId so they do not share a cursor.", objectSchema$1({
3856
+ tool$1("await_turn", "Long-polls session events across remote ai-or-die fleet instances. The caller selects targets with instances, sessionIds, or neither for every registered instance; timeoutMs bounds each per-instance long poll, kinds filters event kinds, and watcherId isolates cursor state for concurrent watchers. It returns resolvedInstances, time-sorted stamped events, gaps, cursors, more, optional per-session settled classifications, and optional per-instance errors. It is useful after send_message with awaitMs:0 to observe the real turn boundary; a settled status such as turn_ended or waiting_input is the reliable completion signal, while idle flickers are not completion. It is not a transcript reader or a one-shot task driver; use read_session for text output and drive_task when sending one prompt and waiting for its report should be a single composite operation.", objectSchema$1({
3811
3857
  instances: arrayProp("Instance ids or labels to poll. Omit with sessionIds to target those session instances; omit both to poll every registered instance."),
3812
3858
  sessionIds: arrayProp("Global session ids to filter to."),
3813
- timeoutMs: numberProp$1("Long-poll timeout per instance in milliseconds."),
3859
+ timeoutMs: numberProp$1(`Long-poll timeout per instance in milliseconds (default ${AWAIT_TURN_DEFAULT_TIMEOUT_MS}).`),
3814
3860
  kinds: arrayProp("Optional event kinds to filter to."),
3815
3861
  watcherId: stringProp$1("Optional stable id for this watcher. Use a distinct value for concurrent watchers over the same target set to keep cursors isolated.")
3816
3862
  }, []), async (args, signal) => {
@@ -3873,7 +3919,7 @@ function createFleetTools(options = {}) {
3873
3919
  ...errors.length > 0 ? { errors } : {}
3874
3920
  });
3875
3921
  }),
3876
- tool$1("drive_task", "Drive one prompt on a session to completion and return the parsed operator report. Composes the reliable path: ensure the composer is idle (else return a structured busy/not-ready result), send and surface whether the message reached the composer (submitted; a delivered-but-unconfirmed send still proceeds), wait for the RELIABLE turn boundary (turn_ended / waiting_input never the became_idle flicker), read the transcript tail, and parse the OPERATOR REPORT trailer into {state, summary, ask, artifact, raw}. A per-call REPORT_ID nonce is embedded in the trailer instruction and the parsed report is trusted ONLY when it echoes that nonce, so a stale prior-turn trailer left in the tail can never be returned as this turn's result. A reliable waiting_input outranks the model's self-reported STATE (a still-blocked session is never reported as done). If the turn does not end within timeoutMs (e.g. a blocking Stop hook that would otherwise hang ~10 min), it AUTO-RECOVERS with a Ctrl-C interrupt rather than blocking, then re-waits briefly and re-reads; a caller ABORT is distinct (settled:'aborted', state:'aborted') and never injects a Ctrl-C. Read `state` TOGETHER with `settled`/`interrupted`/`recovered`: state:'done' with settled:'timeout' + interrupted:true means the model reported done but the turn had to be interrupted to recover, so treat it as needs-verification rather than a clean completion; `submitted` is a best-effort positive signal that CAN be false even on a successful turn. Robust to a busy session (state:'busy'), a missing/stale/placeholder trailer (state falls back to the settle-derived value, reportFound:false), and a hung hook (interrupted:true, recovered:true/false). By default it appends the trailer instruction so the driven session emits a parseable report; set expectReport:false to send the prompt verbatim (a trailer left in the tail is then never trusted).", objectSchema$1({
3922
+ tool$1("drive_task", "Drives one prompt on an existing remote ai-or-die fleet session to completion and returns a parsed operator report. The required sessionId must be global, prompt is the single instruction to send, timeoutMs controls when a hung turn is interrupted for recovery, and expectReport defaults to true so a nonce-guarded OPERATOR REPORT trailer is appended and parsed. It returns resolvedInstance, sessionId, state, summary, ask, artifact, raw, settled, submitted, reportFound, and recovery fields such as interrupted or recovered; state must be read together with settled and interrupted because a timeout recovery can leave work needing verification. It is useful as the composite path that performs the safe send_message plus await_turn plus read_session sequence for one already-created session. It is not a session creator, a multi-turn conversation loop, or a simple transcript read; use create_session first when needed, send_message and await_turn when controlling each step manually, and read_session when only the transcript tail is needed.", objectSchema$1({
3877
3923
  sessionId: stringProp$1("Global session id in the form instanceId:localSessionId."),
3878
3924
  instance: stringProp$1("Optional instance id/label; when supplied it must agree with sessionId."),
3879
3925
  prompt: stringProp$1("The task/prompt to drive on the session."),
@@ -3898,7 +3944,7 @@ function createFleetTools(options = {}) {
3898
3944
  ...result
3899
3945
  }, result.error !== void 0);
3900
3946
  }),
3901
- tool$1("read_file", "Read a file from one fleet instance via its existing /api/files/content endpoint.", objectSchema$1({
3947
+ tool$1("read_file", "Reads a file from one remote ai-or-die fleet instance's filesystem. The required path is passed to the remote host as an unsanitized read request; this router does not confine it to a local workspace, and path policy is delegated to the remote instance. It returns resolvedInstance plus the remote file-content response. It is useful for reading a known file on a remote fleet host after choosing an instance. It is not for local files, directory browsing, text search, git revisions, or session transcripts; use local Read for this machine, list_dir to browse remote directories, search to find remote files, git_show for revision content, and read_session for terminal output.", objectSchema$1({
3902
3948
  instance: stringProp$1("Instance id or label. Defaults to the registry default, or the sole instance."),
3903
3949
  path: stringProp$1("Remote file path to read.")
3904
3950
  }, ["path"]), async (args, signal) => {
@@ -3909,7 +3955,7 @@ function createFleetTools(options = {}) {
3909
3955
  ...response
3910
3956
  });
3911
3957
  }),
3912
- tool$1("list_dir", "List a directory on one fleet instance via its existing /api/files endpoint.", objectSchema$1({
3958
+ tool$1("list_dir", "Lists a directory on one remote ai-or-die fleet instance. The required path is the remote directory path, and instance can select a registered host or default to the registry default or sole instance. It returns resolvedInstance plus the remote directory-listing response. It is useful for browsing a remote workspace before choosing a file to read or search. It is not for local directories, file contents, git revisions, or session transcripts; use local filesystem tools for this machine, read_file for remote file contents, git_show for revision content, and read_session for terminal output.", objectSchema$1({
3913
3959
  instance: stringProp$1("Instance id or label. Defaults to the registry default, or the sole instance."),
3914
3960
  path: stringProp$1("Remote directory path to list.")
3915
3961
  }, ["path"]), async (args, signal) => {
@@ -3920,7 +3966,7 @@ function createFleetTools(options = {}) {
3920
3966
  ...response
3921
3967
  });
3922
3968
  }),
3923
- tool$1("search", "Search files on one fleet instance via its existing /api/search endpoint.", objectSchema$1({
3969
+ tool$1("search", "Searches files on one remote ai-or-die fleet instance's workspace, where a fleet instance is a registered remote host exposed through the fleet MCP server. The required query is sent to that remote instance, and path can narrow the remote search scope; this does not search the local repository or the web. It returns resolvedInstance plus the remote search response. It is useful when the target content lives on a remote fleet host. It is not for this checkout, semantic code discovery, or internet research; use mcp__search__code for the local workspace and mcp__search__web for web search.", objectSchema$1({
3924
3970
  instance: stringProp$1("Instance id or label. Defaults to the registry default, or the sole instance."),
3925
3971
  query: stringProp$1("Search query."),
3926
3972
  path: stringProp$1("Optional path scope.")
@@ -3932,18 +3978,16 @@ function createFleetTools(options = {}) {
3932
3978
  ...response
3933
3979
  });
3934
3980
  }),
3935
- tool$1("git_show", "Read a file/revision through one fleet instance's existing /api/files/git-show endpoint.", objectSchema$1({
3981
+ tool$1("git_show", "Shows git content on one remote ai-or-die fleet instance, such as a file at a specific revision or a commit object. The required path identifies the remote repository path or file path, and the optional ref is a git commit-ish such as HEAD, a branch, a tag, or a commit SHA. It returns resolvedInstance plus the remote git-show response. It is useful when the caller needs repository content as it existed at a revision on the remote host. It is not for current working-tree reads, directory listings, local git commands, or web search; use read_file for current remote file content and local tools for this checkout.", objectSchema$1({
3936
3982
  instance: stringProp$1("Instance id or label. Defaults to the registry default, or the sole instance."),
3937
3983
  path: stringProp$1("Remote repository path or file path for git-show."),
3938
- ref: stringProp$1("Optional git ref/revision."),
3939
- rev: stringProp$1("Optional git revision alias."),
3940
- commit: stringProp$1("Optional commit id.")
3984
+ ref: stringProp$1("Optional git ref, revision, or commit-ish, such as HEAD, a branch, a tag, or a commit SHA.")
3941
3985
  }, ["path"]), async (args, signal) => {
3942
3986
  const instance = await resolve(optionalString$1(args, "instance"));
3943
- const response = await clientFor(instance).gitShow({
3944
- ...args,
3945
- instance: void 0
3946
- }, signal);
3987
+ const response = await clientFor(instance).gitShow(definedObject({
3988
+ path: requiredString$1(args, "path"),
3989
+ ref: optionalString$1(args, "ref")
3990
+ }), signal);
3947
3991
  return ok$1({
3948
3992
  resolvedInstance: publicInstance(instance),
3949
3993
  ...response
@@ -6037,10 +6081,12 @@ const T0_MODEL_CHAIN = [
6037
6081
  const T1_MODEL_CHAIN = [
6038
6082
  "gpt-5.4-mini",
6039
6083
  "gpt-5-mini",
6084
+ "gpt-5.6-sol",
6040
6085
  "gpt-5.5",
6041
6086
  "gemini-3.1-pro-preview"
6042
6087
  ];
6043
6088
  const T2_MODEL_CHAIN = [
6089
+ "gpt-5.6-sol",
6044
6090
  "gpt-5.5",
6045
6091
  "claude-opus-4.8",
6046
6092
  "gemini-3.1-pro-preview"
@@ -6942,7 +6988,7 @@ async function observeUnit(unit) {
6942
6988
  * present — an explicitly-chosen model that Copilot can't serve THROWS rather
6943
6989
  * than being silently swapped for a fallback (a silent class-switch could send
6944
6990
  * the task to a weaker/wrong model the operator never asked for).
6945
- * - `chosen` unset: default to {@link DEFAULT_CODEX_MODEL} (gpt-5.5), walking
6991
+ * - `chosen` unset: default to {@link DEFAULT_CODEX_MODEL} (gpt-5.6-sol), walking
6946
6992
  * {@link DEFAULT_CODEX_MODEL_FALLBACKS} only when a catalog says the preferred
6947
6993
  * default is absent (older Copilot tiers).
6948
6994
  *
@@ -9282,7 +9328,7 @@ function buildRoleAgent(role) {
9282
9328
  "Verification commands and outcomes",
9283
9329
  "Risks and follow-ups"
9284
9330
  ],
9285
- model: "gpt-5.5"
9331
+ model: "gpt-5.6-sol"
9286
9332
  },
9287
9333
  reviewer: {
9288
9334
  description: "Adversarial code reviewer for concrete diffs; reports real findings with severity and file:line.",
@@ -9362,7 +9408,7 @@ function buildRoleAgent(role) {
9362
9408
  "Commands run and outcomes",
9363
9409
  "Failures that require implementation work"
9364
9410
  ],
9365
- model: "gpt-5.5"
9411
+ model: "gpt-5.6-sol"
9366
9412
  }
9367
9413
  }[role];
9368
9414
  const modelLine = spec.model === void 0 ? "" : `model: ${spec.model}\n`;
@@ -10421,13 +10467,13 @@ function createFirstMateTools(depsOverride = {}) {
10421
10467
  };
10422
10468
  }
10423
10469
  return Object.freeze([
10424
- tool$1("start_mission", "Register a first-mate mission for one or more GitHub repositories. Unit decomposition is handled by later controller/model wakes.", objectSchema({
10470
+ tool$1("start_mission", "Registers a first-mate mission in the local durable controller for one or more GitHub repositories; it does not dispatch work or touch GitHub on this call. Inputs provide the mission goal, owner/name repos, user-blessed acceptance criteria, and optional priority, house rules, default cloud-agent model, plan gate, and CI requirement. Returns the new mission id and normalized repo list so later wakes can decompose and dispatch units. Use when the operator has accepted mission scope and wants the first-mate loop to own tracking. It is not for one-off status reads, adding units to an existing mission, or missions whose acceptance criteria are still unsettled.", objectSchema({
10425
10471
  goal: stringProp("Mission goal."),
10426
10472
  repos: stringArrayProp("Repositories as owner/name strings."),
10427
10473
  acceptance_criteria: stringProp("User-blessed acceptance criteria for the mission."),
10428
10474
  priority: numberProp("Optional numeric priority; higher values are handled by controller policy."),
10429
10475
  house_rules: stringProp("Optional repository or operator constraints."),
10430
- default_model: stringProp("Model the GitHub cloud coding agent uses for this mission's tasks; defaults to gpt-5.5."),
10476
+ default_model: stringProp("Model the GitHub cloud coding agent uses for this mission's tasks; defaults to gpt-5.6-sol."),
10431
10477
  plan_gate: enumProp(["hard", "soft"], "Plan-review gate. hard (default) requires the flow's review before build and re-plans on a rejecting review; soft auto-advances a passing plan review to build without human approval but escalates a rejecting review to a human."),
10432
10478
  ci_required: boolProp("When true, refuse merge approval if the repository reports no CI for the PR head.")
10433
10479
  }, [
@@ -10460,7 +10506,7 @@ function createFirstMateTools(depsOverride = {}) {
10460
10506
  repos
10461
10507
  });
10462
10508
  }),
10463
- tool$1("scaffold_repo", "Seed deterministic agentic-dev convention files into a GitHub repository on a pull-request branch.", objectSchema({
10509
+ tool$1("scaffold_repo", "Seeds first-mate and agentic-dev convention files into a GitHub repository by creating a scaffold branch, committing deterministic files, and opening a pull request; it does not write directly to the default branch. Inputs name the owner/name repo, optional base ref, handling mode, and optional detection overrides for stack, OS, package manager, commands, and UI evidence. Returns the pull request plus committed, preserved, and per-file report data, or a no-op note when nothing needs seeding. Use when preparing an owned repository for the first-mate cloud-agent workflow. It is not for arbitrary third-party repositories, normal feature work, or repeated runs unless the operator intentionally wants missing or enhanced convention files.", objectSchema({
10464
10510
  repo: stringProp("Repository as an owner/name string."),
10465
10511
  mode: enumProp([
10466
10512
  "add-missing-only",
@@ -10521,7 +10567,7 @@ function createFirstMateTools(depsOverride = {}) {
10521
10567
  report: plan.reports
10522
10568
  });
10523
10569
  }),
10524
- tool$1("advance", "Wake the first-mate controller once, applying model answers or human decisions, then return the compact board and pending requests.", objectSchema({
10570
+ tool$1("advance", "Wakes the first-mate controller once, optionally applying model answers and human decisions before driving eligible missions. Inputs can supply prior request answers, bound returned request count, provider concurrency, scope the wake to one mission, or include inactive missions in the returned view. Returns the compact board, inactive summary, pending model and human requests, applied answer count, next wake timing, and whether this caller actually drove or deferred to another driver. Use when the operator is advancing the durable loop, responding to needsModel/needsHuman, or scheduling the next wake from nextWakeSeconds. It is not for read-only status checks; board reads the whole portfolio without a wake, and mission_status reads a mission-id-scoped status view.", objectSchema({
10525
10571
  model_answers: arrayOfObjectsProp("Optional model judgments to apply before the wake.", {
10526
10572
  requestId: stringProp("Request id from a previous needsModel entry."),
10527
10573
  verdict: anyProp("Structured verdict for the request kind.")
@@ -10575,7 +10621,7 @@ function createFirstMateTools(depsOverride = {}) {
10575
10621
  drove: result.drove !== false
10576
10622
  });
10577
10623
  }),
10578
- tool$1("board", "Read compact board status. Defaults to active missions only; pass include_all to include inactive missions.", objectSchema({ include_all: boolProp("When true, include inactive missions in the board. Default returns active missions only and summarizes inactive counts.") }, []), async (args) => {
10624
+ tool$1("board", "Reads the compact first-mate portfolio board without waking the controller, dispatching work, or applying answers. Inputs only choose whether inactive missions are included; active missions are returned by default with inactive counts summarized separately. Returns the same board shape that advance returns as a side effect, including mission phase counts, blocked counts, unit rows, and inactive summary. Use when the operator needs a whole-portfolio snapshot. It is not for driving progress or applying pending requests; advance does that, and mission_status is the read path scoped to a single mission id.", objectSchema({ include_all: boolProp("When true, include inactive missions in the board. Default returns active missions only and summarizes inactive counts.") }, []), async (args) => {
10579
10625
  const includeAll = optionalBoolean(args, "include_all") ?? false;
10580
10626
  const [missions, units] = await Promise.all([readMissions(), loadAllUnits()]);
10581
10627
  return ok({
@@ -10583,7 +10629,7 @@ function createFirstMateTools(depsOverride = {}) {
10583
10629
  inactiveSummary: summarizeInactiveMissions(missions)
10584
10630
  });
10585
10631
  }),
10586
- tool$1("merge_pr", "Merge a GitHub pull request the operator has reviewed. Head-guarded (rejects a moved head), ownership-scoped (agent-authored or an active first-mate mission repo, else requires allow_unowned), and gated on a pre-merge safety check (OPEN, not draft, MERGEABLE, CI green).", objectSchema({
10632
+ tool$1("merge_pr", "Merges a live GitHub pull request immediately, which is irreversible through this tool once GitHub accepts the merge. Inputs identify the repo and PR, bind the action to the exact reviewed head SHA, optionally bind the reviewed base branch, select the merge method, and can explicitly override ownership with allow_unowned. Returns GitHub's merge result and merge SHA after the live PR passes head-SHA and optional base concurrency checks, ownership checks, OPEN/not-draft/mergeable checks, and available CI or workflow checks. Use only after out-of-band human authorization for this exact head; this tool does not consult the first-mate approval ledger. It is not for PRs that are not agent-authored or correlated to a first-mate unit (unit.pr === pr) unless allow_unowned is intentionally set; a repo with no configured CI can merge on operator review plus the non-CI guards.", objectSchema({
10587
10633
  repo: stringProp("Repository as an owner/name string."),
10588
10634
  pr: numberProp("Pull request number."),
10589
10635
  expected_head_sha: stringProp("The exact head commit SHA the operator reviewed. The merge is REJECTED if the live head has moved from this value; re-review the new head before merging."),
@@ -10593,7 +10639,7 @@ function createFirstMateTools(depsOverride = {}) {
10593
10639
  "squash",
10594
10640
  "rebase"
10595
10641
  ], "Merge method. Defaults to squash."),
10596
- allow_unowned: boolProp("Set true to merge a PR that is neither agent-authored nor part of an active first-mate mission. Dangerous, explicit opt-in; the override is audit-logged.")
10642
+ allow_unowned: boolProp("Set true to merge a PR that is neither agent-authored nor correlated to a first-mate unit (unit.pr === pr). Dangerous, explicit opt-in; the override is audit-logged.")
10597
10643
  }, [
10598
10644
  "repo",
10599
10645
  "pr",
@@ -10625,10 +10671,10 @@ function createFirstMateTools(depsOverride = {}) {
10625
10671
  sha: merged.sha
10626
10672
  });
10627
10673
  }),
10628
- tool$1("close_pr", "Close a GitHub pull request WITHOUT merging it. Ownership-scoped identically to merge_pr (agent-authored or active first-mate mission repo, else requires allow_unowned).", objectSchema({
10674
+ tool$1("close_pr", "Closes a live GitHub pull request without merging it and reconciles any correlated first-mate units as terminal in the local ledger. Inputs identify the owner/name repo and PR, with allow_unowned as an explicit override for PRs outside first-mate ownership. Returns the closed state plus reconciliation counts, or an already-closed note when the PR was previously closed. Use when the operator wants to stop an open PR rather than merge it. It is not for merged PRs, or for PRs that are not agent-authored or correlated to a first-mate unit (unit.pr === pr), unless allow_unowned is intentionally set.", objectSchema({
10629
10675
  repo: stringProp("Repository as an owner/name string."),
10630
10676
  pr: numberProp("Pull request number."),
10631
- allow_unowned: boolProp("Set true to close a PR that is neither agent-authored nor part of an active first-mate mission. Explicit opt-in; audit-logged.")
10677
+ allow_unowned: boolProp("Set true to close a PR that is neither agent-authored nor correlated to a first-mate unit (unit.pr === pr). Explicit opt-in; audit-logged.")
10632
10678
  }, ["repo", "pr"]), async (args) => {
10633
10679
  const repoSlug = requiredString(args, "repo");
10634
10680
  const repo = parseRepoSlug(repoSlug);
@@ -10655,10 +10701,10 @@ function createFirstMateTools(depsOverride = {}) {
10655
10701
  reconciled
10656
10702
  });
10657
10703
  }),
10658
- tool$1("mark_ready", "Mark a draft GitHub pull request ready for review. Ownership-scoped identically to merge_pr/close_pr (agent-authored or active first-mate mission repo, else requires allow_unowned).", objectSchema({
10704
+ tool$1("mark_ready", "Marks an open draft GitHub pull request ready for review through GitHub's ready-for-review mutation. Inputs identify the owner/name repo and PR, with allow_unowned as an explicit override for PRs outside first-mate ownership. Returns whether the PR is ready and whether it was already non-draft. Use when a first-mate or operator-owned draft PR should enter human or CI review. It is not for closed or merged PRs, or for PRs that are not agent-authored or correlated to a first-mate unit (unit.pr === pr), unless allow_unowned is intentionally set.", objectSchema({
10659
10705
  repo: stringProp("Repository as an owner/name string."),
10660
10706
  pr: numberProp("Pull request number."),
10661
- allow_unowned: boolProp("Set true to mark a PR ready when it is neither agent-authored nor part of an active first-mate mission. Explicit opt-in; audit-logged.")
10707
+ allow_unowned: boolProp("Set true to mark a PR ready when it is neither agent-authored nor correlated to a first-mate unit (unit.pr === pr). Explicit opt-in; audit-logged.")
10662
10708
  }, ["repo", "pr"]), async (args) => {
10663
10709
  const repoSlug = requiredString(args, "repo");
10664
10710
  const repo = parseRepoSlug(repoSlug);
@@ -10681,7 +10727,7 @@ function createFirstMateTools(depsOverride = {}) {
10681
10727
  alreadyReady: false
10682
10728
  });
10683
10729
  }),
10684
- tool$1("add_units", "Add dispatchable units to an existing active first-mate mission. DependsOn entries are 0-based indices within the submitted units list.", objectSchema({
10730
+ tool$1("add_units", "Adds dispatchable units to an existing active first-mate mission without dispatching them immediately. Inputs name the mission and unit list; each unit supplies a title plus optional repo, provider, same-call dependency indices, and model override. Returns the mission id and the units actually added after validation and deduplication. Use when the operator has decomposed additional work for a mission that is already active. It is not for creating a new mission, adding work to inactive missions, or expressing dependencies on units from earlier calls; dependsOn indices are 0-based within this submitted list, invalid or self indices are ignored, and cycles are rejected.", objectSchema({
10685
10731
  mission_id: stringProp("Mission id to add units to."),
10686
10732
  units: arrayOfObjectsProp("Units to add to the mission.", {
10687
10733
  title: stringProp("Unit title."),
@@ -10711,7 +10757,7 @@ function createFirstMateTools(depsOverride = {}) {
10711
10757
  added: await addUnitsToMission(mission, units, deps, existingUnits)
10712
10758
  });
10713
10759
  }),
10714
- tool$1("abandon_mission", "Mark a first-mate mission abandoned so it drops from the active board. Existing units are marked terminal without merging.", objectSchema({
10760
+ tool$1("abandon_mission", "Marks a first-mate mission abandoned in the local durable ledgers so it drops from the active board, and terminalizes live units without merging. Inputs name the mission and can include a short operator reason returned in the tool result. Returns the abandoned mission id and the number of units marked terminal. Use when the operator is permanently retiring a mission from first-mate tracking. It is local-ledger-only and terminal, not a remote cancellation tool: open PRs stay open and GitHub cloud agents keep running unless the operator closes or stops that work separately.", objectSchema({
10715
10761
  mission_id: stringProp("Mission id to abandon."),
10716
10762
  reason: stringProp("Optional short reason for the abandonment.")
10717
10763
  }, ["mission_id"]), async (args) => {
@@ -10742,7 +10788,7 @@ function createFirstMateTools(depsOverride = {}) {
10742
10788
  ...reason !== void 0 ? { reason } : {}
10743
10789
  });
10744
10790
  }),
10745
- tool$1("mission_status", "Read compact status for all first-mate missions, or for one mission id. Defaults to active missions only; pass include_all for inactive missions too.", objectSchema({
10791
+ tool$1("mission_status", "Reads compact first-mate mission status without waking the controller or dispatching work. Inputs can filter by mission_id and can include inactive missions; active missions are returned by default with inactive counts summarized separately. Returns mission status rows built from the same board data, including counts, blocked count, unit rows, and done/failed summary. Use when the operator needs a mission-id-scoped read or a compact status list. It is not for the whole portfolio board without a mission filter, which is board, and it is not for driving progress, which is advance.", objectSchema({
10746
10792
  mission_id: stringProp("Optional mission id to filter to."),
10747
10793
  include_all: boolProp("When true, include inactive missions in the status list. Default returns active missions only and summarizes inactive counts.")
10748
10794
  }, []), async (args) => {
@@ -18487,7 +18533,7 @@ function toolEnvelope(data, isError) {
18487
18533
  * and (3) opens a WS to the bridge, sends the tool call, awaits the
18488
18534
  * response with a per-tool timeout.
18489
18535
  *
18490
- * Each entry carries `capability: "browser"` so `browserToolsEnabled()`
18536
+ * Each entry carries a browser capability tag so `browserToolsEnabled()`
18491
18537
  * in `src/routes/mcp/handler.ts` drops them at both list-time and
18492
18538
  * call-time when the operator hasn't opted in via `--browse` or
18493
18539
  * `GH_ROUTER_ENABLE_BROWSE=1`.
@@ -18505,7 +18551,7 @@ function toolEnvelope(data, isError) {
18505
18551
  const BROWSER_TOOLS = Object.freeze([
18506
18552
  {
18507
18553
  toolNameHttp: "browser_list_tabs",
18508
- description: "List all open tabs across all browser windows. Returns each tab's id (used by other browser_* tools), URL, title, active flag, and window id.",
18554
+ description: "Lists open tabs across all browser windows. It takes no input and returns each tab's id, URL, title, active flag, and window id. The returned tab ids are the inputs used by tab-scoped browser tools, especially for pre-existing tabs that were not opened by browser_open_tab. It is a power-tier discovery tool for tab selection and inventory, not a page-content reader or navigation tool.",
18509
18555
  inputSchema: {
18510
18556
  type: "object",
18511
18557
  additionalProperties: false,
@@ -18518,7 +18564,7 @@ const BROWSER_TOOLS = Object.freeze([
18518
18564
  },
18519
18565
  {
18520
18566
  toolNameHttp: "browser_open_tab",
18521
- description: "Open a URL in a new browser tab and wait for the page to finish loading. Returns the new tab's id, final URL after redirects, and HTTP status. Refuses to navigate to browser-internal settings / preferences / extensions / flags pages (returns {blocked: true, reason}); devtools://* is allowed.",
18567
+ description: "Opens a URL in a new browser tab, or navigates the currently active tab when reuseActive is true, then waits briefly for the tab load state to reach complete. It takes a URL and optional reuseActive flag, and returns the tab id, final URL, and a synthetic statusCode load flag where 200 means the tab reported complete and 0 means it did not. The statusCode is not the page's HTTP response code, so a loaded 404 page can still return 200. Use this to establish a tab before other browser tools; blocked URLs return {blocked, reason}, including browser settings/preferences/extensions/flags pages, file:// by default, and extension options/popup pages, while devtools:// is allowed.",
18522
18568
  inputSchema: {
18523
18569
  type: "object",
18524
18570
  required: ["url"],
@@ -18526,11 +18572,11 @@ const BROWSER_TOOLS = Object.freeze([
18526
18572
  properties: {
18527
18573
  url: {
18528
18574
  type: "string",
18529
- description: "The URL to load. Maximum 8 KB. Settings / preferences / extensions / flags pages are blocked."
18575
+ description: "URL to load. Browser-internal settings, preferences, extensions, flags, password/management pages, extension options/popup pages, and file:// URLs by default are blocked before dispatch."
18530
18576
  },
18531
18577
  reuseActive: {
18532
18578
  type: "boolean",
18533
- description: "When true, navigate the currently active tab instead of opening a new one. Default false."
18579
+ description: "When true, navigates the currently active tab instead of opening a new tab. Default false. Use browser_navigate when you already know the target tab id."
18534
18580
  }
18535
18581
  }
18536
18582
  },
@@ -18541,7 +18587,7 @@ const BROWSER_TOOLS = Object.freeze([
18541
18587
  },
18542
18588
  {
18543
18589
  toolNameHttp: "browser_close_tab",
18544
- description: "Close one or more tabs by tab id.",
18590
+ description: "Closes one or more browser tabs by id. It takes a non-empty tabIds array, usually obtained from browser_list_tabs, and returns {closed: N} after requesting Chrome to remove those tabs. This is a power-tier tab lifecycle tool for cleanup or closing known throwaway tabs. Avoid using it when the user may still need a tab, and prefer leaving the tab open if the id was not freshly discovered or created for the current task.",
18545
18591
  inputSchema: {
18546
18592
  type: "object",
18547
18593
  required: ["tabIds"],
@@ -18549,7 +18595,7 @@ const BROWSER_TOOLS = Object.freeze([
18549
18595
  properties: { tabIds: {
18550
18596
  type: "array",
18551
18597
  items: { type: "number" },
18552
- description: "Array of tab ids to close (from browser_list_tabs)."
18598
+ description: "Non-empty array of tab ids to close, usually from browser_list_tabs or browser_open_tab."
18553
18599
  } }
18554
18600
  },
18555
18601
  capability: "browser_power",
@@ -18559,7 +18605,7 @@ const BROWSER_TOOLS = Object.freeze([
18559
18605
  },
18560
18606
  {
18561
18607
  toolNameHttp: "browser_navigate",
18562
- description: "Navigate an existing tab: goto a URL, go back, go forward, or reload. Same URL-blocking policy as browser_open_tab.",
18608
+ description: "Navigates an existing tab by going to a URL, moving back or forward in history, or reloading. It takes a tab id plus an action, with url required only for action='goto', and returns {finalUrl, statusCode} for completed navigation or {blocked, reason} for a policy-blocked URL. The statusCode is a synthetic load-complete flag, not the page's HTTP response code. Use this when the target tab already exists; use browser_open_tab to create a new tab, and expect the same URL policy blocks as open_tab, including browser-internal pages, file:// by default, and extension options/popup pages.",
18563
18609
  inputSchema: {
18564
18610
  type: "object",
18565
18611
  required: ["tabId", "action"],
@@ -18567,7 +18613,7 @@ const BROWSER_TOOLS = Object.freeze([
18567
18613
  properties: {
18568
18614
  tabId: {
18569
18615
  type: "number",
18570
- description: "Tab id from browser_list_tabs / browser_open_tab."
18616
+ description: "Tab id from browser_list_tabs or browser_open_tab."
18571
18617
  },
18572
18618
  action: {
18573
18619
  type: "string",
@@ -18577,15 +18623,15 @@ const BROWSER_TOOLS = Object.freeze([
18577
18623
  "forward",
18578
18624
  "reload"
18579
18625
  ],
18580
- description: "The navigation action."
18626
+ description: "Navigation action: goto a URL, go back, go forward, or reload the current page."
18581
18627
  },
18582
18628
  url: {
18583
18629
  type: "string",
18584
- description: "Required when action=goto. Max 8 KB."
18630
+ description: "URL to load when action='goto'. Ignored for back, forward, and reload."
18585
18631
  },
18586
18632
  hard: {
18587
18633
  type: "boolean",
18588
- description: "Reload only: bypass cache (Ctrl+Shift+R behavior). Default false."
18634
+ description: "Reload only: when true, bypasses cache like Ctrl+Shift+R. Default false."
18589
18635
  }
18590
18636
  }
18591
18637
  },
@@ -18596,7 +18642,7 @@ const BROWSER_TOOLS = Object.freeze([
18596
18642
  },
18597
18643
  {
18598
18644
  toolNameHttp: "browser_screenshot",
18599
- description: "Capture a PNG screenshot of the visible area of a tab. Returns base64-encoded image bytes plus contentType. The tab must be active in its window; this tool auto-activates if needed.",
18645
+ description: "Captures a screenshot of the visible area of a tab, as PNG by default or JPEG when requested. It takes a tab id and optional format, then returns base64-encoded image bytes plus contentType. The tab must be active in its window, so this tool auto-activates the tab if needed and that changes which tab is focused. Use screenshot for visual layout, canvas, SVG, maps, or image-only regions; prefer browser_observe when page text and actionable state are enough.",
18600
18646
  inputSchema: {
18601
18647
  type: "object",
18602
18648
  required: ["tabId"],
@@ -18604,12 +18650,12 @@ const BROWSER_TOOLS = Object.freeze([
18604
18650
  properties: {
18605
18651
  tabId: {
18606
18652
  type: "number",
18607
- description: "Tab id from browser_list_tabs / browser_open_tab."
18653
+ description: "Tab id from browser_list_tabs or browser_open_tab."
18608
18654
  },
18609
18655
  format: {
18610
18656
  type: "string",
18611
18657
  enum: ["png", "jpeg"],
18612
- description: "Image format. Default 'png'."
18658
+ description: "Image format for the returned screenshot. Default 'png'; use 'jpeg' when smaller image bytes are preferable."
18613
18659
  }
18614
18660
  }
18615
18661
  },
@@ -18620,7 +18666,7 @@ const BROWSER_TOOLS = Object.freeze([
18620
18666
  },
18621
18667
  {
18622
18668
  toolNameHttp: "browser_read_page",
18623
- description: "Compressed page snapshot for the model: visible text, interactive elements with stable refs, viewport metadata, and (when present) `visualSurfaces` listing canvas / svg regions that need vision. Each element entry carries `bbox: [x, y, w, h]` in CSS viewport pixels (same coord space as browser_mouse / drag / scroll-at-pointer). Refs (e.g. `e42`) are stable for the lifetime of one read_page snapshot and are the preferred input to follow-up actions over brittle CSS selectors. The `viewport` block (`width`, `height`, `devicePixelRatio`, `scrollX`, `scrollY`) lets you map CSS-px bbox to device-px pixels for browser_screenshot. Mode controls what ships back: `summary` (default, ~5-15 KB) returns only viewport-visible elements/text and drops nameless non-interactive nodes; `full` returns up to 200 elements + 256 KiB of innerText (the legacy behavior — use only when you need off-screen content unscrolled). PREFER browser_act / browser_find for intent-driven interaction; read_page is the lower-level snapshot when you need to enumerate.",
18669
+ description: "Returns a compressed page snapshot for a tab: visible text, interactive elements with refs, viewport metadata, and visualSurfaces for canvas or SVG regions that need vision. It takes a tab id and optional mode, and each element includes a ref plus bbox in CSS viewport pixels, the same coordinate space used by browser_mouse, browser_drag, and scroll at-pointer. Refs persist across snapshots of the same document until navigation or DOM replacement, and are a better input to follow-up actions than brittle CSS selectors. Use read_page when enumeration, coordinates, refs, or raw snapshot structure are needed; prefer browser_act or browser_find for intent-driven interaction, browser_observe for a short natural-language page summary, and browser_screenshot for visual pixels.",
18624
18670
  inputSchema: {
18625
18671
  type: "object",
18626
18672
  required: ["tabId"],
@@ -18628,12 +18674,12 @@ const BROWSER_TOOLS = Object.freeze([
18628
18674
  properties: {
18629
18675
  tabId: {
18630
18676
  type: "number",
18631
- description: "Tab id from browser_list_tabs / browser_open_tab."
18677
+ description: "Tab id from browser_list_tabs or browser_open_tab."
18632
18678
  },
18633
18679
  mode: {
18634
18680
  type: "string",
18635
18681
  enum: ["summary", "full"],
18636
- description: "Snapshot scope. Default 'summary' returns viewport-visible elements + text capped at 20 KiB. 'full' returns up to 200 interactive elements page-wide + 256 KiB of innerText."
18682
+ description: "Snapshot scope. Default 'summary' focuses on viewport-visible text and elements; 'full' asks for a broader page-wide snapshot. The default CDP extractor caps around 500 elements and 32 KiB text, with legacy fallback caps possibly lower or higher by mode."
18637
18683
  }
18638
18684
  }
18639
18685
  },
@@ -18644,13 +18690,16 @@ const BROWSER_TOOLS = Object.freeze([
18644
18690
  },
18645
18691
  {
18646
18692
  toolNameHttp: "browser_scroll",
18647
- description: "Scroll a tab. Five modes: top / bottom of the page, by an absolute pixel delta, to a specific element (by ref), or wheel-scroll a sub-region at a pointer location ('at-pointer' the path that works for chat windows / infinite-scroll lists / modal bodies that don't respond to window.scrollTo because they have their own scroll container).",
18693
+ description: "Scrolls a tab or a scrollable region inside a tab. It takes a tab id, target mode, and mode-specific fields for page top/bottom, pixel deltas, element centering, or wheel scrolling at a pointer. The at-pointer path dispatches a real wheel event at a ref, selector, or CSS viewport coordinate, which is the path for chat panes, infinite lists, and modal bodies with their own scroll containers. Use browser_act with action='scroll_into_view' or intent mode for simple element reveal; use browser_scroll when page-level movement, precise deltas, or sub-container wheel scrolling are needed.",
18648
18694
  inputSchema: {
18649
18695
  type: "object",
18650
18696
  required: ["tabId", "target"],
18651
18697
  additionalProperties: false,
18652
18698
  properties: {
18653
- tabId: { type: "number" },
18699
+ tabId: {
18700
+ type: "number",
18701
+ description: "Tab id from browser_list_tabs or browser_open_tab."
18702
+ },
18654
18703
  target: {
18655
18704
  type: "string",
18656
18705
  enum: [
@@ -18660,39 +18709,39 @@ const BROWSER_TOOLS = Object.freeze([
18660
18709
  "element",
18661
18710
  "at-pointer"
18662
18711
  ],
18663
- description: "Scroll target type."
18712
+ description: "Scroll target mode: page top, page bottom, pixel delta, element centering, or wheel event at a pointer."
18664
18713
  },
18665
18714
  pixels: {
18666
18715
  type: "number",
18667
- description: "Pixel delta when target=pixels. Positive scrolls down, negative scrolls up."
18716
+ description: "Pixel delta when target='pixels'. Positive scrolls down and negative scrolls up."
18668
18717
  },
18669
18718
  ref: {
18670
18719
  type: "string",
18671
- description: "Element ref. For target=element, scrolls so the element is centered. For target=at-pointer, resolves to the bbox center as the wheel position."
18720
+ description: "Element ref. For target='element', the element is centered; for target='at-pointer', the element bbox center becomes the wheel position."
18672
18721
  },
18673
18722
  selector: {
18674
18723
  type: "string",
18675
- description: "CSS selector. For target=at-pointer, fallback when no ref. Resolves to bbox center."
18724
+ description: "CSS selector fallback when no ref is available. For target='at-pointer', resolves to the element bbox center."
18676
18725
  },
18677
18726
  x: {
18678
18727
  type: "number",
18679
- description: "Pointer x (CSS viewport px) for target=at-pointer. Pair with y. Exactly one of (ref, selector, or x+y) is required for at-pointer."
18728
+ description: "Pointer x in CSS viewport pixels for target='at-pointer'. Pair with y. Exactly one of ref, selector, or x+y is required for at-pointer."
18680
18729
  },
18681
18730
  y: {
18682
18731
  type: "number",
18683
- description: "Pointer y (CSS viewport px) for target=at-pointer. Pair with x."
18732
+ description: "Pointer y in CSS viewport pixels for target='at-pointer'. Pair with x."
18684
18733
  },
18685
18734
  deltaX: {
18686
18735
  type: "number",
18687
- description: "Wheel delta x (CSS px) for target=at-pointer. Default 0. Clamped to |10000|."
18736
+ description: "Wheel delta x in CSS pixels for target='at-pointer'. Default 0. Clamped to absolute value 10000."
18688
18737
  },
18689
18738
  deltaY: {
18690
18739
  type: "number",
18691
- description: "Wheel delta y (CSS px) for target=at-pointer. Positive scrolls down. Default 0. Clamped to |10000|. At least one of deltaX/deltaY must be non-zero."
18740
+ description: "Wheel delta y in CSS pixels for target='at-pointer'. Positive scrolls down. Default 0. Clamped to absolute value 10000; at least one of deltaX or deltaY must be non-zero."
18692
18741
  },
18693
18742
  force: {
18694
18743
  type: "boolean",
18695
- description: "Skip the pre-wheel elementFromPoint hit-test for target=at-pointer. Default false. Set true when an overlay covers the target but forwards wheel events."
18744
+ description: "For target='at-pointer', skips the pre-wheel elementFromPoint hit-test. Default false. Set true only when an overlay covers the target but forwards wheel events."
18696
18745
  }
18697
18746
  }
18698
18747
  },
@@ -18703,16 +18752,19 @@ const BROWSER_TOOLS = Object.freeze([
18703
18752
  },
18704
18753
  {
18705
18754
  toolNameHttp: "browser_keyboard",
18706
- description: "Send a keystroke or chord to the focused element. Use 'Control+L' / 'Command+L' for browser shortcuts, single characters for typing. Uses chrome.debugger so browser-level shortcuts (Ctrl+T, Ctrl+W, etc) actually fire.",
18755
+ description: "Sends a discrete key or chord to the focused element or browser via CDP Input.dispatchKeyEvent. It takes a tab id and a keys string such as 'Control+L', 'Command+L', 'Enter', 'Escape', or 'ArrowDown', and returns the extension dispatch result. Browser-level shortcuts such as Ctrl+T and Ctrl+W actually fire because this uses chrome.debugger input rather than synthetic DOM events. Use keyboard for shortcuts and non-printable control keys; prefer browser_type for literal text entry into a focused field and browser_act with action='fill' for plain form values.",
18707
18756
  inputSchema: {
18708
18757
  type: "object",
18709
18758
  required: ["tabId", "keys"],
18710
18759
  additionalProperties: false,
18711
18760
  properties: {
18712
- tabId: { type: "number" },
18761
+ tabId: {
18762
+ type: "number",
18763
+ description: "Tab id from browser_list_tabs or browser_open_tab."
18764
+ },
18713
18765
  keys: {
18714
18766
  type: "string",
18715
- description: "Key or chord. Modifiers (Control, Alt, Shift, Meta / Command) joined with '+'. Example: 'Control+L'."
18767
+ description: "Key or chord. Join modifiers with '+', using Control, Ctrl, Alt, Shift, Meta, Command, or Cmd. A single named key such as Enter or Escape is also valid."
18716
18768
  }
18717
18769
  }
18718
18770
  },
@@ -18723,13 +18775,16 @@ const BROWSER_TOOLS = Object.freeze([
18723
18775
  },
18724
18776
  {
18725
18777
  toolNameHttp: "browser_wait",
18726
- description: "Wait for an element to appear (until='selector'), the tab URL to match a regex (until='url'), or the network to go idle (until='networkIdle' - heuristic: tab status complete + 500ms quiet). Returns {ok: true, elapsedMs} on success, {ok: false, reason: 'timeout'} on miss.",
18778
+ description: "Waits for a tab condition without mutating the page. It takes a tab id, an until mode, and the matching operand: a CSS selector for element appearance, a JavaScript regex string for URL matching, or networkIdle for the heuristic of tab status complete plus 500 ms quiet. It returns {ok: true, elapsedMs} on success and {ok: false, reason: 'timeout'} when the condition is not reached before the timeout. Use wait after navigation or actions that trigger asynchronous rendering; do not use it as a page reader, and prefer browser_observe or browser_read_page when the task is to inspect current content.",
18727
18779
  inputSchema: {
18728
18780
  type: "object",
18729
18781
  required: ["tabId", "until"],
18730
18782
  additionalProperties: false,
18731
18783
  properties: {
18732
- tabId: { type: "number" },
18784
+ tabId: {
18785
+ type: "number",
18786
+ description: "Tab id from browser_list_tabs or browser_open_tab."
18787
+ },
18733
18788
  until: {
18734
18789
  type: "string",
18735
18790
  enum: [
@@ -18737,19 +18792,19 @@ const BROWSER_TOOLS = Object.freeze([
18737
18792
  "url",
18738
18793
  "networkIdle"
18739
18794
  ],
18740
- description: "What to wait for."
18795
+ description: "Condition to wait for: selector, URL regex match, or network-idle heuristic."
18741
18796
  },
18742
18797
  selector: {
18743
18798
  type: "string",
18744
- description: "CSS selector when until=selector."
18799
+ description: "CSS selector required when until='selector'."
18745
18800
  },
18746
18801
  urlPattern: {
18747
18802
  type: "string",
18748
- description: "JS regex (string form) when until=url."
18803
+ description: "JavaScript regex source string required when until='url'."
18749
18804
  },
18750
18805
  timeoutMs: {
18751
18806
  type: "number",
18752
- description: "Max wait. Default 10000, hard cap 60000."
18807
+ description: "Maximum wait in milliseconds. Default 10000, hard cap 60000."
18753
18808
  }
18754
18809
  }
18755
18810
  },
@@ -18760,20 +18815,23 @@ const BROWSER_TOOLS = Object.freeze([
18760
18815
  },
18761
18816
  {
18762
18817
  toolNameHttp: "browser_eval_js",
18763
- description: "Evaluate a JavaScript expression in the tab's main world (equivalent to typing in the DevTools console). Returns {result} or {error}. Awaits promises returned by the expression. Single narrowly-named escape hatch for behaviors the other tools don't cover.",
18818
+ description: "Evaluates a JavaScript expression in the tab's main world, equivalent to typing in the DevTools console. It takes a tab id, expression, and optional timeout, awaits promises returned by the expression, and returns {result} or {error}. The expression can read or mutate the page, storage, cookies, or location, so this is the power-tier escape hatch for behaviors the structured browser tools do not cover. Prefer dedicated tools for navigation, clicking, filling, extraction, diagnostics, and screenshots; note that URL policy checks only apply directly to browser_open_tab and browser_navigate, while extension-side navigation blocking still applies to many browser-internal pages.",
18764
18819
  inputSchema: {
18765
18820
  type: "object",
18766
18821
  required: ["tabId", "expression"],
18767
18822
  additionalProperties: false,
18768
18823
  properties: {
18769
- tabId: { type: "number" },
18824
+ tabId: {
18825
+ type: "number",
18826
+ description: "Tab id from browser_list_tabs or browser_open_tab."
18827
+ },
18770
18828
  expression: {
18771
18829
  type: "string",
18772
- description: "JS expression. Max 100 KB. Top-level await NOT supported - wrap in (async () => ...)()."
18830
+ description: "JavaScript expression to evaluate. Size should stay small for reliability, but no schema length cap is enforced. Top-level await is not supported; wrap async work in (async () => ...)()."
18773
18831
  },
18774
18832
  timeoutMs: {
18775
18833
  type: "number",
18776
- description: "Max evaluation time. Default 5000, hard cap 30000."
18834
+ description: "Maximum evaluation time in milliseconds. Default 5000, hard cap 30000."
18777
18835
  }
18778
18836
  }
18779
18837
  },
@@ -18784,7 +18842,7 @@ const BROWSER_TOOLS = Object.freeze([
18784
18842
  },
18785
18843
  {
18786
18844
  toolNameHttp: "browser_download",
18787
- description: "Trigger a download by URL and wait for it to complete. Returns {downloadId, path, bytes, mimeType}. The file lands in Chrome's default Downloads dir unless saveAs is given.",
18845
+ description: "Triggers a browser download from a direct URL and waits for the extension's completion signal. It takes a tab id for association, source='url', the URL, and optional saveAs path, then returns {downloadId, path, bytes, mimeType} when Chrome reports the download complete. The file lands in Chrome's default Downloads directory unless saveAs provides a relative filename or subdirectory, and conflicts are auto-uniquified by the browser. Use this for known direct download URLs; it does not click page links, and the extension currently waits up to 60 seconds internally, so downloads that finish after 60 seconds can report timeout even though the outer wire budget is larger.",
18788
18846
  inputSchema: {
18789
18847
  type: "object",
18790
18848
  required: ["tabId", "url"],
@@ -18792,20 +18850,20 @@ const BROWSER_TOOLS = Object.freeze([
18792
18850
  properties: {
18793
18851
  tabId: {
18794
18852
  type: "number",
18795
- description: "Tab id is logged but the download itself is window-scoped, not tab-scoped."
18853
+ description: "Tab id for association and logging; the download itself is window-scoped, not tab-scoped."
18796
18854
  },
18797
18855
  source: {
18798
18856
  type: "string",
18799
18857
  enum: ["url"],
18800
- description: "Download source. Only 'url' supported in v1; click-then-wait awaits Phase 5."
18858
+ description: "Download source. Only 'url' is supported in v1; click-then-wait is not on this surface."
18801
18859
  },
18802
18860
  url: {
18803
18861
  type: "string",
18804
- description: "Direct URL to download. Max 8 KB."
18862
+ description: "Direct URL to download. No schema length cap is enforced."
18805
18863
  },
18806
18864
  saveAs: {
18807
18865
  type: "string",
18808
- description: "Optional filename / relative subdir under Downloads. Conflicts auto-uniquify."
18866
+ description: "Optional relative filename or subdirectory under Downloads. Chrome enforces download-path restrictions and auto-uniquifies conflicts."
18809
18867
  }
18810
18868
  }
18811
18869
  },
@@ -18816,13 +18874,16 @@ const BROWSER_TOOLS = Object.freeze([
18816
18874
  },
18817
18875
  {
18818
18876
  toolNameHttp: "browser_mouse",
18819
- description: "Move / click / hover / press / release the mouse via real CDP input events (Input.dispatchMouseEvent). Use this when you need behavior that synthetic .click() can't trigger: hover-to-reveal menus, canvas / map / image-map clicks, sites that check event.isTrusted, or precise coordinate targeting. Target with ref (from browser_read_page), CSS selector, or (x, y) in CSS viewport pixels — exactly one. action='move' is the hover (single mouseMoved fires :hover and pointerover reliably). action='dblclick' sends two press/release cycles with incrementing clickCount (a real double-click, not one cycle with clickCount=2). By default the target is hit-tested with elementFromPoint and the call fails with `target_obscured` if the topmost element isn't the target or a descendant — pass force:true to bypass when you know an overlay forwards events.",
18877
+ description: "Moves, clicks, double-clicks, presses, or releases the mouse through real CDP Input.dispatchMouseEvent calls. It takes a tab id, action, exactly one target form (ref, selector, or x+y CSS viewport coordinates), and optional button, trajectory, and force settings. Use mouse for hover-to-reveal menus, canvas/map/image-map clicks, event.isTrusted checks, precise coordinate targeting, or low-level press/release sequences that browser_act cannot express. Prefer browser_act for ordinary element clicks and fills; by default ref/selector targets are hit-tested with elementFromPoint and fail with target_obscured unless force is true.",
18820
18878
  inputSchema: {
18821
18879
  type: "object",
18822
18880
  required: ["tabId", "action"],
18823
18881
  additionalProperties: false,
18824
18882
  properties: {
18825
- tabId: { type: "number" },
18883
+ tabId: {
18884
+ type: "number",
18885
+ description: "Tab id from browser_list_tabs or browser_open_tab."
18886
+ },
18826
18887
  action: {
18827
18888
  type: "string",
18828
18889
  enum: [
@@ -18832,19 +18893,19 @@ const BROWSER_TOOLS = Object.freeze([
18832
18893
  "down",
18833
18894
  "up"
18834
18895
  ],
18835
- description: "What to do. move=position cursor (hover). click=press+release. dblclick=two press+release with clickCount 1 then 2. down=press only. up=release only."
18896
+ description: "Mouse action. move positions the cursor for hover; click sends press+release; dblclick sends two press/release cycles; down presses only; up releases only."
18836
18897
  },
18837
18898
  ref: {
18838
18899
  type: "string",
18839
- description: "Element ref from browser_read_page (preferred). Resolves to bbox center. Exactly one of ref / selector / (x+y) required."
18900
+ description: "Element ref from browser_read_page or browser_find. Resolves to bbox center. Exactly one of ref, selector, or x+y is required."
18840
18901
  },
18841
18902
  selector: {
18842
18903
  type: "string",
18843
- description: "CSS selector (fallback). Resolves to bbox center."
18904
+ description: "CSS selector fallback. Resolves to bbox center. Exactly one of ref, selector, or x+y is required."
18844
18905
  },
18845
18906
  x: {
18846
18907
  type: "number",
18847
- description: "Target x in CSS viewport pixels. Pair with y. Use when working from a screenshot or eval_js output."
18908
+ description: "Target x in CSS viewport pixels. Pair with y. Use when working from a screenshot, canvas coordinate, or eval_js output."
18848
18909
  },
18849
18910
  y: {
18850
18911
  type: "number",
@@ -18857,19 +18918,19 @@ const BROWSER_TOOLS = Object.freeze([
18857
18918
  "right",
18858
18919
  "middle"
18859
18920
  ],
18860
- description: "Mouse button for click / dblclick / down / up. Default 'left'. Ignored for action=move."
18921
+ description: "Mouse button for click, dblclick, down, or up. Default 'left'. Ignored for action='move'."
18861
18922
  },
18862
18923
  steps: {
18863
18924
  type: "number",
18864
- description: "Humanlike trajectory. >1 interpolates the cursor approach over N mouseMoved events. Default 1 (teleport). Clamped to [1, 100]."
18925
+ description: "Trajectory step count. Values greater than 1 interpolate the cursor approach over multiple mouseMoved events. Default 1. Clamped to [1, 100]."
18865
18926
  },
18866
18927
  stepDelayMs: {
18867
18928
  type: "number",
18868
- description: "Pause between interpolated mouseMoved events when steps > 1. Default 8. Clamped to [0, 50]."
18929
+ description: "Pause between interpolated mouseMoved events when steps is greater than 1. Default 8. Clamped to [0, 50]."
18869
18930
  },
18870
18931
  force: {
18871
18932
  type: "boolean",
18872
- description: "Skip the pre-click elementFromPoint hit-test (ref/selector mode only). Default false."
18933
+ description: "For ref or selector targets, skips the elementFromPoint hit-test. Default false. Use only when an overlay covers the target but forwards pointer events."
18873
18934
  }
18874
18935
  }
18875
18936
  },
@@ -18880,20 +18941,23 @@ const BROWSER_TOOLS = Object.freeze([
18880
18941
  },
18881
18942
  {
18882
18943
  toolNameHttp: "browser_drag",
18883
- description: "Drag from a source to a destination. Auto-detects whether to use HTML5 native DnD (for elements with draggable='true', via CDP Input.setInterceptDrags + Input.dispatchDragEvent the only path that triggers Chromium's native dragstart pipeline) or pointer-based DnD (for react-dnd / Sortable.js / mouse-event-based drag handlers via CDP mouse events with buttons:1 held throughout). Each of from/to can be a ref (preferred), a CSS selector, or x+y coordinates. Returns { ok: true, mode_used: 'pointer'|'html5' } so you can verify which path ran.",
18944
+ description: "Drags from a source target to a destination target through CDP input events. It takes a tab id, one source target, one destination target, and optional button, trajectory, mode, and force settings; targets can be refs, selectors, or CSS viewport coordinates. Auto mode chooses HTML5 native drag-and-drop for draggable='true' sources, using Input.setInterceptDrags plus Input.dispatchDragEvent, and otherwise uses pointer drag events for libraries such as react-dnd, Sortable.js, and mouse-event-based handlers. Use drag for actual drag-and-drop interactions; use browser_mouse for simple clicks, hover, or isolated press/release gestures. Returns {ok: true, mode_used, from, to} so the caller can verify whether pointer or html5 ran and which coordinates were used.",
18884
18945
  inputSchema: {
18885
18946
  type: "object",
18886
18947
  required: ["tabId"],
18887
18948
  additionalProperties: false,
18888
18949
  properties: {
18889
- tabId: { type: "number" },
18950
+ tabId: {
18951
+ type: "number",
18952
+ description: "Tab id from browser_list_tabs or browser_open_tab."
18953
+ },
18890
18954
  fromRef: {
18891
18955
  type: "string",
18892
- description: "Source ref from browser_read_page (preferred)."
18956
+ description: "Source element ref from browser_read_page or browser_find. Preferred when available."
18893
18957
  },
18894
18958
  fromSelector: {
18895
18959
  type: "string",
18896
- description: "Source CSS selector (fallback)."
18960
+ description: "Source CSS selector fallback when no source ref is available."
18897
18961
  },
18898
18962
  fromX: {
18899
18963
  type: "number",
@@ -18905,11 +18969,11 @@ const BROWSER_TOOLS = Object.freeze([
18905
18969
  },
18906
18970
  toRef: {
18907
18971
  type: "string",
18908
- description: "Destination ref from browser_read_page (preferred)."
18972
+ description: "Destination element ref from browser_read_page or browser_find. Preferred when available."
18909
18973
  },
18910
18974
  toSelector: {
18911
18975
  type: "string",
18912
- description: "Destination CSS selector (fallback)."
18976
+ description: "Destination CSS selector fallback when no destination ref is available."
18913
18977
  },
18914
18978
  toX: {
18915
18979
  type: "number",
@@ -18922,15 +18986,15 @@ const BROWSER_TOOLS = Object.freeze([
18922
18986
  button: {
18923
18987
  type: "string",
18924
18988
  enum: ["left", "middle"],
18925
- description: "Mouse button held during drag. Default 'left'."
18989
+ description: "Mouse button held during the drag. Default 'left'."
18926
18990
  },
18927
18991
  steps: {
18928
18992
  type: "number",
18929
- description: "Intermediate mouseMoved events fromto with the button held. Drag-detect libraries need a trajectory to fire. Default 15. Clamped to [1, 100]."
18993
+ description: "Intermediate mouseMoved events from source to destination with the button held. Drag-detect libraries often need a trajectory. Default 15. Clamped to [1, 100]."
18930
18994
  },
18931
18995
  stepDelayMs: {
18932
18996
  type: "number",
18933
- description: "Pause between intermediate moves. Default 12. Clamped to [0, 50]."
18997
+ description: "Pause between intermediate moves in milliseconds. Default 12. Clamped to [0, 50]."
18934
18998
  },
18935
18999
  mode: {
18936
19000
  type: "string",
@@ -18939,11 +19003,11 @@ const BROWSER_TOOLS = Object.freeze([
18939
19003
  "pointer",
18940
19004
  "html5"
18941
19005
  ],
18942
- description: "Drag mode. 'auto' (default) picks html5 if the source has draggable='true', else pointer. Override only when auto detection misses."
19006
+ description: "Drag mode. 'auto' is the default and picks html5 if the source has draggable='true', else pointer. Override only when auto detection chooses the wrong path."
18943
19007
  },
18944
19008
  force: {
18945
19009
  type: "boolean",
18946
- description: "Skip the pre-press elementFromPoint hit-test on the source. Default false."
19010
+ description: "Skips the pre-press elementFromPoint hit-test on the source only. Default false. The destination is used as-is."
18947
19011
  }
18948
19012
  }
18949
19013
  },
@@ -18954,20 +19018,23 @@ const BROWSER_TOOLS = Object.freeze([
18954
19018
  },
18955
19019
  {
18956
19020
  toolNameHttp: "browser_type",
18957
- description: "Type a string into the currently-focused element per-keystroke via CDP Input.dispatchKeyEvent. Each character fires keydown + keypress + input this is the tool for keystroke-driven autocomplete, chips, search-as-you-type, and any site whose handlers listen on keydown rather than just reading element.value. For plain form-value entry use browser_fill (faster, sets value directly). For chord shortcuts (Control+L, etc) use browser_keyboard. Special characters in text: \\nEnter, \\tTab, \\bBackspace (dispatched as the named key, not as a literal control char). Other control chars (< 0x20) are rejected with an actionable error. Uppercase letters come from the natural code point event.shiftKey is false but the typed value is correct.",
19021
+ description: "Types text into the currently focused element one character at a time via CDP Input.dispatchKeyEvent. It takes a tab id, text, and optional per-character delay; each character fires keyboard/input events, which supports autocomplete, chips, search-as-you-type fields, and handlers that listen on keydown rather than only reading element.value. Special text characters map to named keys: \\n sends Enter, \\t sends Tab, and \\b sends Backspace; other control characters below 0x20 are rejected with an actionable error. Use browser_type when real keystrokes matter, use browser_act with action='fill' for plain form-value entry, and use browser_keyboard for shortcuts or named control keys such as Control+L or Escape.",
18958
19022
  inputSchema: {
18959
19023
  type: "object",
18960
19024
  required: ["tabId", "text"],
18961
19025
  additionalProperties: false,
18962
19026
  properties: {
18963
- tabId: { type: "number" },
19027
+ tabId: {
19028
+ type: "number",
19029
+ description: "Tab id from browser_list_tabs or browser_open_tab. The text goes to whatever element is currently focused in that tab."
19030
+ },
18964
19031
  text: {
18965
19032
  type: "string",
18966
- description: "The text to type. Max 4096 chars. Iterates as Unicode code points (surrogate pairs handled correctly)."
19033
+ description: "Text to type, up to 4096 Unicode code points. Newline, tab, and backspace are dispatched as Enter, Tab, and Backspace."
18967
19034
  },
18968
19035
  delayMs: {
18969
19036
  type: "number",
18970
- description: "Pause between characters. Default 0. Clamped to [0, 50]. Set > 0 when typing into search-as-you-type inputs that debounce."
19037
+ description: "Pause between characters in milliseconds. Default 0. Clamped to [0, 50]. Set above 0 for debounced search-as-you-type inputs."
18971
19038
  }
18972
19039
  }
18973
19040
  },
@@ -18978,17 +19045,20 @@ const BROWSER_TOOLS = Object.freeze([
18978
19045
  },
18979
19046
  {
18980
19047
  toolNameHttp: "browser_diagnostics",
18981
- description: "Drain console messages or network responses for a tab, with filtering. Replaces the prior browser_console_logs / browser_network_log primitives. `kind` selects the stream; remaining params filter the result before it ships to the model so the response carries only what the caller asked for instead of a raw 1000-entry array dump. Lazy-attach behavior: first call for a tab attaches chrome.debugger; very-early-load events from before the first call are missed.",
19048
+ description: "Drains buffered console messages or network responses for a tab, with filtering before the result is returned. It takes a tab id, kind='console' or 'network', and optional level, regex, and limit filters, then returns {kind, total, returned, entries}; total is the pre-filter count and returned is the post-filter limited count. The first call for a tab lazily attaches chrome.debugger, so very-early load events from before that call are missed. Use diagnostics to investigate console errors, warnings, and request URLs; do not use it as a page-content reader, and raise limit or loosen regex when returned equals the requested limit.",
18982
19049
  inputSchema: {
18983
19050
  type: "object",
18984
19051
  required: ["tabId", "kind"],
18985
19052
  additionalProperties: false,
18986
19053
  properties: {
18987
- tabId: { type: "number" },
19054
+ tabId: {
19055
+ type: "number",
19056
+ description: "Tab id from browser_list_tabs or browser_open_tab."
19057
+ },
18988
19058
  kind: {
18989
19059
  type: "string",
18990
19060
  enum: ["console", "network"],
18991
- description: "Which stream to drain."
19061
+ description: "Diagnostic stream to drain: console messages or network responses."
18992
19062
  },
18993
19063
  level: {
18994
19064
  type: "string",
@@ -19000,15 +19070,15 @@ const BROWSER_TOOLS = Object.freeze([
19000
19070
  "debug",
19001
19071
  "all"
19002
19072
  ],
19003
- description: "Console only. Default 'all'. Ignored when kind=network."
19073
+ description: "Console only. Default 'all'. Ignored when kind='network'."
19004
19074
  },
19005
19075
  regex: {
19006
19076
  type: "string",
19007
- description: "Optional JS-regex string. Console: matches the message body. Network: matches the request URL."
19077
+ description: "Optional JavaScript regex source string. For console, matches message text; for network, matches request URL."
19008
19078
  },
19009
19079
  limit: {
19010
19080
  type: "number",
19011
- description: "Max entries to return after filtering. Default 100. Hard cap 1000."
19081
+ description: "Maximum entries to return after filtering. Default 100. Hard cap 1000."
19012
19082
  }
19013
19083
  }
19014
19084
  },
@@ -19056,20 +19126,23 @@ const BROWSER_TOOLS = Object.freeze([
19056
19126
  },
19057
19127
  {
19058
19128
  toolNameHttp: "browser_find",
19059
- description: "Find up to 5 elements matching a natural-language intent ('the search box at the top', 'the Submit button at the bottom of the login form'). Returns ranked candidates with stable refs the model can pass to browser_act (ref mode) or browser_mouse. Cheaper than browser_read_page when you know what you're looking for the inner compressor (a small fast model) filters the snapshot for you instead of sending the full element list to the lead model.",
19129
+ description: "Finds up to 5 page elements that match a natural-language intent. It takes a tab id and intent, reads a fresh snapshot internally, and returns ranked candidates with refs, roles, names, bboxes, and match reasons when available. The returned refs can be passed to browser_act in REF mode or to low-level power tools such as browser_mouse. Use find when a specific element is needed and a short candidate list is better than the full browser_read_page snapshot; use read_page when broad enumeration or raw text/context is needed.",
19060
19130
  inputSchema: {
19061
19131
  type: "object",
19062
19132
  required: ["tabId", "intent"],
19063
19133
  additionalProperties: false,
19064
19134
  properties: {
19065
- tabId: { type: "number" },
19135
+ tabId: {
19136
+ type: "number",
19137
+ description: "Tab id from browser_list_tabs or browser_open_tab."
19138
+ },
19066
19139
  intent: {
19067
19140
  type: "string",
19068
- description: "Natural-language description of what to find."
19141
+ description: "Natural-language description of the element to find, such as 'the search box at the top' or 'the Submit button'."
19069
19142
  }
19070
19143
  }
19071
19144
  },
19072
- capability: "browser_power",
19145
+ capability: "browser_compound",
19073
19146
  async handler(args, signal) {
19074
19147
  const tabId = typeof args.tabId === "number" ? args.tabId : void 0;
19075
19148
  const intent = typeof args.intent === "string" ? args.intent : "";
@@ -19095,20 +19168,23 @@ const BROWSER_TOOLS = Object.freeze([
19095
19168
  },
19096
19169
  {
19097
19170
  toolNameHttp: "browser_act",
19098
- description: "Preferred for any click / fill / type / scroll-to action against a tab. Two modes: (1) INTENT mode pass `intent` as natural language ('click the submit button'); the inner compressor (a small fast model) maps it to an element + action. Auto-escalates to visual fallback (screenshot + multimodal model + pixel-coord click) when the intent points into a canvas / svg region the a11y tree can't see. (2) REF mode pass `ref` (from a prior browser_find or browser_read_page) and optionally `value`; dispatches directly with zero compressor latency. This is the fold-in path for the now-removed browser_click and browser_fill. Returns {ok, action_taken, target_ref, navigated}.",
19171
+ description: "Performs a high-level click, fill, type, select, or scroll-into-view action against a tab. It has two modes: INTENT mode takes a natural-language intent and resolves the element/action internally, while REF mode takes a ref from browser_find or browser_read_page plus optional action and value for direct dispatch without a compressor round trip. Visual fallback can click canvas or SVG regions by combining screenshot analysis with a coordinate click when text-based matching fails. Use act for ordinary page interaction before reaching for browser_mouse, browser_type, browser_keyboard, or browser_scroll; single-action results include {ok, action_taken, target_ref, navigated}, multi-step intents return summary/steps fields, and visual fallback returns click_visual with x/y coordinates.",
19099
19172
  inputSchema: {
19100
19173
  type: "object",
19101
19174
  required: ["tabId"],
19102
19175
  additionalProperties: false,
19103
19176
  properties: {
19104
- tabId: { type: "number" },
19177
+ tabId: {
19178
+ type: "number",
19179
+ description: "Tab id from browser_list_tabs or browser_open_tab."
19180
+ },
19105
19181
  intent: {
19106
19182
  type: "string",
19107
- description: "Natural-language description of the action. Triggers INTENT mode. Mutually exclusive with `ref`."
19183
+ description: "Natural-language description of the action for INTENT mode. If both intent and ref are provided, ref mode wins and intent is ignored."
19108
19184
  },
19109
19185
  ref: {
19110
19186
  type: "string",
19111
- description: "Element ref from browser_find / browser_read_page. Triggers REF mode (no compressor round-trip)."
19187
+ description: "Element ref from browser_find or browser_read_page for REF mode, which dispatches directly without a compressor round trip."
19112
19188
  },
19113
19189
  action: {
19114
19190
  type: "string",
@@ -19119,15 +19195,15 @@ const BROWSER_TOOLS = Object.freeze([
19119
19195
  "select",
19120
19196
  "scroll_into_view"
19121
19197
  ],
19122
- description: "REF mode only. Defaults to 'click'. In INTENT mode, the compressor picks the action."
19198
+ description: "REF mode action. Defaults to 'click'. Ignored in INTENT mode, where the resolved action comes from the intent and matched element."
19123
19199
  },
19124
19200
  value: {
19125
19201
  type: "string",
19126
- description: "For fill / type / select: the string value to set. In INTENT mode the compressor uses this when an action requires a value."
19202
+ description: "String value for fill, type, or select actions. In INTENT mode, this is available to the resolver when the action requires a value."
19127
19203
  }
19128
19204
  }
19129
19205
  },
19130
- capability: "browser",
19206
+ capability: "browser_compound",
19131
19207
  async handler(args, signal) {
19132
19208
  const tabId = typeof args.tabId === "number" ? args.tabId : void 0;
19133
19209
  if (!tabId) return toolEnvelope({ error: "tabId required" }, true);
@@ -19220,16 +19296,19 @@ const BROWSER_TOOLS = Object.freeze([
19220
19296
  },
19221
19297
  {
19222
19298
  toolNameHttp: "browser_observe",
19223
- description: "Get a natural-language description of the current page's user-actionable state what forms, buttons, links, and content sections are visible in 2-4 sentences. Optional `intent` focuses the description on a region ('describe the login form', 'what's in the comments section'). Use this BEFORE browser_act when you don't know what's on the page, or AFTER navigation to confirm the page loaded. Cheaper than screenshots when text is enough. Does not include canvas/SVG content those surface as a `hasVisualSurfaces` flag; switch to browser_screenshot for visuals.",
19299
+ description: "Produces a short natural-language description of the current page's user-actionable state, including visible forms, buttons, links, and content sections. It takes a tab id and optional intent focus, then returns a 2-4 sentence summary plus whether visualSurfaces such as canvas or SVG are present. Use observe before browser_act when the page state is unknown, or after navigation to confirm what loaded. Prefer observe over screenshot when text and controls are enough; switch to browser_screenshot for visual layout or canvas/SVG details, and use browser_read_page when raw refs, bboxes, or element lists are needed.",
19224
19300
  inputSchema: {
19225
19301
  type: "object",
19226
19302
  required: ["tabId"],
19227
19303
  additionalProperties: false,
19228
19304
  properties: {
19229
- tabId: { type: "number" },
19305
+ tabId: {
19306
+ type: "number",
19307
+ description: "Tab id from browser_list_tabs or browser_open_tab."
19308
+ },
19230
19309
  intent: {
19231
19310
  type: "string",
19232
- description: "Optional natural-language focus ('describe the form', 'what's in the sidebar')."
19311
+ description: "Optional natural-language focus for the summary, such as 'describe the form' or 'what is in the sidebar'."
19233
19312
  }
19234
19313
  }
19235
19314
  },
@@ -19243,7 +19322,7 @@ const BROWSER_TOOLS = Object.freeze([
19243
19322
  },
19244
19323
  {
19245
19324
  toolNameHttp: "browser_extract",
19246
- description: "Structured extraction from the current page into a JSON object matching the provided schema. The inner compressor reads the page snapshot (text + elements) and synthesizes the typed object. Use this instead of browser_read_page + lead-model parsing when you know the shape you want (e.g. a list of {title, author, url} rows from a PR list).",
19325
+ description: "Extracts structured data from the current page into a JSON object matching the provided schema. It takes a tab id, a schema or schema-shaped descriptor, and a plain-language instruction; the inner compressor reads the page snapshot and returns only the typed object rather than the raw element list. Use extract when the desired output shape is known, such as rows of {title, author, url}; use browser_observe for a prose overview and browser_read_page when the lead model needs raw refs, bboxes, or page text. Bad schemas or wrong-shape compressor results are returned as fixable error envelopes so the caller can simplify the schema or clarify the instruction.",
19247
19326
  inputSchema: {
19248
19327
  type: "object",
19249
19328
  required: [
@@ -19253,11 +19332,14 @@ const BROWSER_TOOLS = Object.freeze([
19253
19332
  ],
19254
19333
  additionalProperties: false,
19255
19334
  properties: {
19256
- tabId: { type: "number" },
19257
- schema: { description: "JSON schema (or schema-shaped descriptor) for the desired output shape." },
19335
+ tabId: {
19336
+ type: "number",
19337
+ description: "Tab id from browser_list_tabs or browser_open_tab."
19338
+ },
19339
+ schema: { description: "JSON schema, or a schema-shaped descriptor, for the desired output shape." },
19258
19340
  instruction: {
19259
19341
  type: "string",
19260
- description: "What to extract, in plain language ('the visible PR list')."
19342
+ description: "Plain-language extraction instruction, such as 'the visible PR list' or 'all product cards with price and URL'."
19261
19343
  }
19262
19344
  }
19263
19345
  },
@@ -23416,7 +23498,8 @@ async function countTokens(body, extraHeaders, callerSignal, retryTransient = fa
23416
23498
  *
23417
23499
  * Returns true iff Copilot's live catalog (`state.models?.data`) contains
23418
23500
  * ALL THREE peer models the consensus protocol needs:
23419
- * - `gpt-5.5` (codex_critic's model)
23501
+ * - an OpenAI frontier model (`gpt-5.6-sol`, else `gpt-5.5` — see
23502
+ * `resolveOpenAiFrontier`)
23420
23503
  * - `claude-opus-4-7` (opus_critic's model)
23421
23504
  * - any `gemini-3.X.*pro` (gemini_critic's model family — matches the
23422
23505
  * same regex `geminiAvailable()` uses, so the gate stays in sync if
@@ -23432,22 +23515,47 @@ async function countTokens(body, extraHeaders, callerSignal, retryTransient = fa
23432
23515
  * slug too — `state.models?.data` mirrors Copilot's catalog where these
23433
23516
  * land under the dotted slug, so we match by Copilot's actual id shape.
23434
23517
  */
23518
+ function geminiAvailable(source = state) {
23519
+ const models = source.models?.data;
23520
+ if (!models) return false;
23521
+ return models.some((m) => /^gemini-3\..*pro/i.test(m.id));
23522
+ }
23523
+ /**
23524
+ * OpenAI frontier reasoning models in preference order. `gpt-5.6-sol` is the
23525
+ * current default; `gpt-5.5` is retained as a fallback. Both share the same
23526
+ * `pro_plus/business/enterprise/max` restriction tier, so the fallback only
23527
+ * matters during a rollout-lag window where the newer slug hasn't yet appeared
23528
+ * in the account's catalog.
23529
+ */
23530
+ const OPENAI_FRONTIER_MODELS = ["gpt-5.6-sol", "gpt-5.5"];
23531
+ /**
23532
+ * First available OpenAI frontier model in the live catalog (prefer
23533
+ * `gpt-5.6-sol`, fall back to `gpt-5.5`). Returns undefined when neither is
23534
+ * present. With `requireToolCalls`, only returns a model whose catalog entry
23535
+ * advertises `tool_calls`.
23536
+ */
23537
+ function resolveOpenAiFrontier(opts) {
23538
+ const models = state.models?.data;
23539
+ if (!models) return void 0;
23540
+ for (const id of OPENAI_FRONTIER_MODELS) {
23541
+ const found = models.find((m) => m.id === id);
23542
+ if (!found) continue;
23543
+ if (opts?.requireToolCalls && found.capabilities?.supports?.tool_calls !== true) continue;
23544
+ return id;
23545
+ }
23546
+ }
23435
23547
  function standInToolEnabled() {
23436
23548
  const models = state.models?.data;
23437
23549
  if (!models) return false;
23438
- const hasGpt55 = models.some((m) => m.id === "gpt-5.5");
23550
+ const hasOpenAi = resolveOpenAiFrontier() != null;
23439
23551
  const hasOpus = models.some((m) => m.id === "claude-opus-4-7" || m.id === "claude-opus-4.7");
23440
- const hasGeminiPro = models.some((m) => /^gemini-3\..*pro/i.test(m.id));
23441
- return hasGpt55 && hasOpus && hasGeminiPro;
23552
+ const hasGeminiPro = geminiAvailable();
23553
+ return hasOpenAi && hasOpus && hasGeminiPro;
23442
23554
  }
23443
- const IMPLEMENTER_SUBAGENT_MODEL = "gpt-5.5";
23444
- /** Return the native implementer subagent model iff it is live with tool calls. */
23555
+ /** Return the native implementer subagent model iff it is live with tool calls.
23556
+ * Prefers `gpt-5.6-sol`, falls back to `gpt-5.5`. */
23445
23557
  function implementerSubagentModel() {
23446
- const models = state.models?.data;
23447
- if (!models) return void 0;
23448
- const found = models.find((m) => m.id === IMPLEMENTER_SUBAGENT_MODEL);
23449
- if (!found) return void 0;
23450
- return found.capabilities?.supports?.tool_calls === true ? IMPLEMENTER_SUBAGENT_MODEL : void 0;
23558
+ return resolveOpenAiFrontier({ requireToolCalls: true });
23451
23559
  }
23452
23560
  /**
23453
23561
  * Gate for the worker tools (`explore`, `review`, `implement`).
@@ -23459,7 +23567,7 @@ function implementerSubagentModel() {
23459
23567
  * true`. The worker loop is function-calling; a model that can't
23460
23568
  * emit tool_calls is unusable, so dormant-register (omit from
23461
23569
  * `tools/list`) keeps the surface honest. (The implement default
23462
- * `gpt-5.5` is NOT gated here — if it's absent, implement calls
23570
+ * `gpt-5.6-sol` is NOT gated here — if it's absent, implement calls
23463
23571
  * surface a clean resolve error rather than disabling all worker
23464
23572
  * tools, since explore/review still work.)
23465
23573
  * 2. The operator hasn't set `GH_ROUTER_DISABLE_WORKER_TOOLS=1`
@@ -23483,8 +23591,8 @@ function workerToolsEnabled() {
23483
23591
  return found.capabilities?.supports?.tool_calls === true;
23484
23592
  }
23485
23593
  /**
23486
- * Gate for the compound L2 browser tools (`browser_find`, `browser_act`
23487
- * in intent mode, `browser_extract`).
23594
+ * Gate for the compound L2 browser tools (`browser_act`, `browser_observe`,
23595
+ * `browser_extract`, `browser_find`).
23488
23596
  *
23489
23597
  * Returns true iff `compressorAvailable()` — i.e. at least one model in
23490
23598
  * the compressor fallback chain (`gpt-5.4-mini` → `claude-sonnet-4.6` →
@@ -23507,19 +23615,19 @@ function browserCompoundToolsEnabled() {
23507
23615
  * Gate for the L0/L1 power browser tools (`browser_read_page`,
23508
23616
  * `browser_mouse`, `browser_drag`, `browser_type`, `browser_keyboard`,
23509
23617
  * `browser_scroll`, `browser_eval_js`, `browser_diagnostics`,
23510
- * `browser_find`, `browser_close_tab`, `browser_list_tabs`,
23511
- * `browser_wait`, `browser_download`).
23618
+ * `browser_close_tab`, `browser_list_tabs`, `browser_wait`,
23619
+ * `browser_download`).
23512
23620
  *
23513
23621
  * Returns true iff `state.powerBrowseEnabled` (set by `--power-browse`
23514
23622
  * or `GH_ROUTER_ENABLE_POWER_BROWSE=1`). When off, the default
23515
- * `--browse` surface exposes only the 6 lead-model tools (`act`,
23516
- * `observe`, `extract`, `navigate`, `screenshot`, `open_tab`) that
23517
- * hide DOM details behind intent. Power mode adds the raw primitives
23518
- * for users who want direct coord/keystroke control.
23623
+ * `--browse` surface exposes the base lead tools (`navigate`, `screenshot`,
23624
+ * `open_tab`) and, when the compound gate passes, `act`, `observe`,
23625
+ * `extract`, and `find`. Power mode adds the raw primitives for users who
23626
+ * want direct coord/keystroke control.
23519
23627
  *
23520
23628
  * `handler.ts` filter chain ANDs this with `browserToolsEnabled()`
23521
- * (defense-in-depth power without basic is meaningless and the
23522
- * setup path already forces basic on when power is on).
23629
+ * (defense-in-depth: power without the base browser server is meaningless and
23630
+ * the setup path already forces basic on when power is on).
23523
23631
  */
23524
23632
  function browserPowerToolsEnabled() {
23525
23633
  return state.powerBrowseEnabled === true;
@@ -23715,15 +23823,10 @@ function checkAuth(c) {
23715
23823
  };
23716
23824
  return { ok: true };
23717
23825
  }
23718
- function geminiAvailable() {
23719
- const models = state.models?.data;
23720
- if (!models) return false;
23721
- return models.some((m) => /^gemini-3\..*pro/i.test(m.id));
23722
- }
23723
23826
  /**
23724
23827
  * The 1M-context Opus 4.6 variant (`claude-opus-4.6-1m`, `max_prompt_tokens`
23725
23828
  * 936K). opus_critic prefers it so it can take large artifacts in one shot
23726
- * (the whole point of pairing it with gpt-5.5 as the big-window peers);
23829
+ * (the whole point of pairing it with gpt-5.6-sol as the big-window peers);
23727
23830
  * falls back to the 200K `claude-opus-4-6` when the catalog doesn't carry
23728
23831
  * a 1M 4.6 slug. The regex is version-anchored to 4.6 AND requires a
23729
23832
  * `-1m` suffix boundary (not a permissive `.*1m`), so it does NOT
@@ -23933,7 +24036,7 @@ async function predictedWindowOverflow(persona, prompt, context) {
23933
24036
  }
23934
24037
  if (tokens <= budget) return void 0;
23935
24038
  const opusHint = OPUS_1M_RE.test(id) ? "" : " / `opus_critic` (Opus-4.7 1M ≈ 936K tokens, when the enterprise catalog carries it)";
23936
- return `pre-flight rejected: this ${persona.toolNameHttp} brief is ≈${tokens} tokens, over the ${budget}-token budget for ${persona.model} (its ${maxPromptTokens}-token prompt window minus a ${PEER_PROMPT_TOKEN_RESERVE}-token framing reserve). Do NOT summarize or truncate the artifact to fit. Route the full artifact to a larger-window peer — \`codex_critic\` (gpt-5.5922K tokens)${opusHint} — or split it into focused sub-calls BY CONCERN and call them in parallel, then aggregate.`;
24039
+ return `pre-flight rejected: this ${persona.toolNameHttp} brief is ≈${tokens} tokens, over the ${budget}-token budget for ${persona.model} (its ${maxPromptTokens}-token prompt window minus a ${PEER_PROMPT_TOKEN_RESERVE}-token framing reserve). Do NOT summarize or truncate the artifact to fit. Route the full artifact to a larger-window peer — \`codex_critic\` (gpt-5.6-sol1M tokens)${opusHint} — or split it into focused sub-calls BY CONCERN and call them in parallel, then aggregate.`;
23937
24040
  }
23938
24041
  /**
23939
24042
  * JSON-path pre-flight predictedTooLong gate. Returns a JSON-RPC result
@@ -23992,7 +24095,7 @@ function jsonPathPreflightCap(body, scope) {
23992
24095
  * the `stand_in` orchestrator in `src/lib/stand-in.ts` — can reuse the
23993
24096
  * same per-endpoint request shaping without re-implementing it. The
23994
24097
  * stand_in tool needs to drive its own per-round system prompts across
23995
- * three concrete models (gpt-5.5, claude-opus-4-7, gemini-3.1-pro-preview),
24098
+ * three concrete models (gpt-5.6-sol, claude-opus-4-7, gemini-3.1-pro-preview),
23996
24099
  * each on a different endpoint; doing that with a `PersonaSpec` would
23997
24100
  * require either inventing throwaway personas per round or duplicating
23998
24101
  * the dispatch switch.
@@ -24683,13 +24786,13 @@ const ADVISOR_CLIENT_TOOL_NAME = "advisor";
24683
24786
  * times per session per cc-backup ADVISOR_TOOL_INSTRUCTIONS. */
24684
24787
  const ADVISOR_MAX_TURNS = 16;
24685
24788
  /** Default advisor model + reasoning effort. Per gemini-critic + user
24686
- * direction: hardcode to a cross-lab model (gpt-5.5 — Copilot's
24789
+ * direction: hardcode to a cross-lab model (gpt-5.6-sol — Copilot's
24687
24790
  * /responses-only flagship) at xhigh effort. The cross-lab choice
24688
24791
  * gives a true "second set of eyes" instead of the main model
24689
24792
  * reviewing itself; xhigh effort buys the deep-dive reasoning that
24690
24793
  * matches Anthropic's own ADVISOR (which uses a stronger reviewer
24691
24794
  * model — Opus 4.6/Sonnet 4.6 typically). */
24692
- const ADVISOR_DEFAULT_MODEL = "gpt-5.5";
24795
+ const ADVISOR_DEFAULT_MODEL = "gpt-5.6-sol";
24693
24796
  const ADVISOR_DEFAULT_EFFORT = "xhigh";
24694
24797
  /** ADVISOR_TOOL_INSTRUCTIONS verbatim from cc-backup
24695
24798
  * src/utils/advisor.ts — describes when the model should invoke
@@ -24786,7 +24889,7 @@ const ADVISOR_FALLBACK_MAX_TOKENS = 24e4;
24786
24889
  * budget is `max_prompt_tokens - reserve`. Generous on purpose: a 400
24787
24890
  * `model_max_prompt_tokens_exceeded` degrades to a silent advisor
24788
24891
  * fallback, and the marginal window we give up is irrelevant next to
24789
- * gpt-5.5's 922K. */
24892
+ * gpt-5.6-sol's ~1M. */
24790
24893
  const ADVISOR_PROMPT_TOKEN_RESERVE = 8e3;
24791
24894
  /**
24792
24895
  * Derive the TOKEN budget for the rendered transcript from the advisor
@@ -24805,7 +24908,7 @@ function resolveAdvisorMaxTokens(advisorModel) {
24805
24908
  /**
24806
24909
  * Render an Anthropic-shape conversation (messages array with
24807
24910
  * role/content blocks) as a single human-readable text blob. Used
24808
- * as the input to the advisor model (gpt-5.5 via /v1/responses
24911
+ * as the input to the advisor model (gpt-5.6-sol via /v1/responses
24809
24912
  * doesn't have a 1:1 mapping for Anthropic's tool_use/tool_result
24810
24913
  * blocks; serializing to text preserves the semantics — the advisor
24811
24914
  * just needs to READ the conversation, not produce more of it).
@@ -24887,7 +24990,7 @@ function truncateTailToUnits(text, maxUnits, measure) {
24887
24990
  * Routes by model family:
24888
24991
  * - gpt-5.x / codex / o-series (have `/responses` in supported_endpoints):
24889
24992
  * use createResponses with `reasoning.effort` set. This is the
24890
- * default path — gpt-5.5 at xhigh effort.
24993
+ * default path — gpt-5.6-sol at xhigh effort.
24891
24994
  * - claude-* (no `/responses`): fall back to createMessages.
24892
24995
  *
24893
24996
  * The conversation is serialized to text via renderConversationAsText
@@ -26990,7 +27093,7 @@ function advisorTool(getMessages) {
26990
27093
  return {
26991
27094
  name: "advisor",
26992
27095
  label: "Advisor",
26993
- description: "Consult a stronger reviewer model (cross-lab: gpt-5.5 xhigh by default) on a specific concern. Use BEFORE substantive work, WHEN stuck, or WHEN considering a change of approach. The advisor automatically receives the recent conversation transcript as context — give it a focused `concern`, not background.",
27096
+ description: "Consult a stronger reviewer model (cross-lab: gpt-5.6-sol xhigh by default) on a specific concern. Use BEFORE substantive work, WHEN stuck, or WHEN considering a change of approach. The advisor automatically receives the recent conversation transcript as context — give it a focused `concern`, not background.",
26994
27097
  parameters: ADVISOR_PARAMS,
26995
27098
  async execute(_toolCallId, params, signal) {
26996
27099
  if (networkDisabled()) throw new Error("rejected: network disabled");
@@ -27485,7 +27588,7 @@ const DEFAULT_THINKING = "xhigh";
27485
27588
  * (via `DEFAULT_THINKING`) — a strong, NATIVE (no-shim) tool-caller for repo
27486
27589
  * research. Native Claude models run as workers over `/chat/completions`, the
27487
27590
  * same path proven by `PLAN_DEFAULT_MODEL` (claude-opus-4.8). Like `implement`'s
27488
- * gpt-5.5 this is NOT a `workerToolsEnabled` gate input — if absent (e.g. a
27591
+ * gpt-5.6-sol this is NOT a `workerToolsEnabled` gate input — if absent (e.g. a
27489
27592
  * non-enterprise tier) `explore` errors helpfully at call time rather than
27490
27593
  * vanishing the whole worker surface. The caller (the main model) overrides
27491
27594
  * BOTH the model and the reasoning per call via the `model` / `thinking` args. */
@@ -27493,7 +27596,7 @@ const EXPLORE_DEFAULT_MODEL = "claude-sonnet-5";
27493
27596
  /** Default model + thinking for the READ-ONLY `review` mode.
27494
27597
  * `gemini-3.1-pro-preview` at `xhigh` (clamped to `high` at call time — gemini
27495
27598
  * advertises no xhigh). DELIBERATELY DECORRELATED FROM THE IMPLEMENTER: bounded
27496
- * implementation now defaults to gpt-5.5 (OpenAI) — both the `implement` worker
27599
+ * implementation now defaults to gpt-5.6-sol (OpenAI) — both the `implement` worker
27497
27600
  * and the native `implementer` subagent — and the main orchestrator is Opus
27498
27601
  * (Anthropic), so review runs on a THIRD lab (Google) to maximize blind-spot
27499
27602
  * diversity. A reviewer sharing the implementer's lab catches a correlated slice
@@ -27504,12 +27607,12 @@ const EXPLORE_DEFAULT_MODEL = "claude-sonnet-5";
27504
27607
  * `model` arg (e.g. `claude-opus-4.8` for an Anthropic-lab reviewer). */
27505
27608
  const REVIEW_DEFAULT_MODEL = "gemini-3.1-pro-preview";
27506
27609
  const REVIEW_DEFAULT_THINKING = "xhigh";
27507
- /** Default model + thinking for the READ+WRITE `implement` mode. `gpt-5.5`
27610
+ /** Default model + thinking for the READ+WRITE `implement` mode. `gpt-5.6-sol`
27508
27611
  * at `xhigh` — the strongest reasoning tier in the catalog, 1M+ context,
27509
27612
  * routed through `/responses` by the stream-fn endpoint split. Coding edits
27510
27613
  * benefit from maximum reasoning; the higher per-call cost is justified for
27511
27614
  * autonomous implementation. An explicit `opts.model` still wins. */
27512
- const IMPLEMENT_DEFAULT_MODEL = "gpt-5.5";
27615
+ const IMPLEMENT_DEFAULT_MODEL = "gpt-5.6-sol";
27513
27616
  const IMPLEMENT_DEFAULT_THINKING = "xhigh";
27514
27617
  /** Default model for `browse` mode. `gpt-5.4-mini` — the Gate-B-winning
27515
27618
  * browse model (small + fast enough to drive a tab at human pace, with
@@ -27534,7 +27637,7 @@ const BROWSE_DEFAULT_THINKING = "high";
27534
27637
  * Copilot catalog id (the worker resolver exact-matches `catalog.id`, it does
27535
27638
  * NOT translate the Anthropic dashed slug). Falls back to a helpful
27536
27639
  * unknown-model error at call time if opus-4.8 isn't in the catalog (e.g. a
27537
- * non-enterprise tier), exactly like `implement`'s `gpt-5.5`. Caller's `model`
27640
+ * non-enterprise tier), exactly like `implement`'s `gpt-5.6-sol`. Caller's `model`
27538
27641
  * arg still wins. */
27539
27642
  const PLAN_DEFAULT_MODEL = "claude-opus-4.8";
27540
27643
  const PLAN_DEFAULT_THINKING = "xhigh";
@@ -27889,8 +27992,8 @@ function appendPlanReminder(messages, planState) {
27889
27992
  */
27890
27993
  const STAND_IN_MODELS = Object.freeze([
27891
27994
  {
27892
- key: "gpt-5.5",
27893
- model: "gpt-5.5",
27995
+ key: "gpt-5.6-sol",
27996
+ model: "gpt-5.6-sol",
27894
27997
  endpoint: "/v1/responses",
27895
27998
  effort: "xhigh"
27896
27999
  },
@@ -28015,10 +28118,11 @@ async function runStandIn(input, signal) {
28015
28118
  };
28016
28119
  }
28017
28120
  async function callAndParse(cfg, instructions, userText, signal) {
28121
+ const model = cfg.key === "gpt-5.6-sol" ? resolveOpenAiFrontier() ?? cfg.model : cfg.model;
28018
28122
  let raw;
28019
28123
  try {
28020
28124
  raw = await dispatchModelCall({
28021
- model: cfg.model,
28125
+ model,
28022
28126
  endpoint: cfg.endpoint,
28023
28127
  instructions,
28024
28128
  userText,
@@ -28042,7 +28146,7 @@ async function callAndParse(cfg, instructions, userText, signal) {
28042
28146
  let retryRaw;
28043
28147
  try {
28044
28148
  retryRaw = await dispatchModelCall({
28045
- model: cfg.model,
28149
+ model,
28046
28150
  endpoint: cfg.endpoint,
28047
28151
  instructions,
28048
28152
  userText: userText + RETRY_PROMPT_SUFFIX,
@@ -28220,6 +28324,142 @@ function round2(n) {
28220
28324
  * into each sub-orchestration. The verifier only range-checks the declaration. */
28221
28325
  const MAX_RECURSION_DEPTH = 3;
28222
28326
 
28327
+ //#endregion
28328
+ //#region src/lib/orchestration/select.ts
28329
+ const subsetOf = (a, b) => {
28330
+ for (const x of a) if (!b.has(x)) return false;
28331
+ return true;
28332
+ };
28333
+ function selectChampion(orchestrated, baseline, canonicalGateIds, tiePolicy) {
28334
+ if (!subsetOf(orchestrated.passed, orchestrated.ran)) return {
28335
+ winner: "baseline",
28336
+ reason: "orchestrated outcome malformed (passed not a subset of ran)"
28337
+ };
28338
+ if (!subsetOf(baseline.passed, baseline.ran)) return {
28339
+ winner: "baseline",
28340
+ reason: "baseline outcome malformed (passed not a subset of ran)"
28341
+ };
28342
+ if (canonicalGateIds.size === 0) return {
28343
+ winner: "baseline",
28344
+ reason: "no executable gate for this ask — ship the baseline (judgment-only)"
28345
+ };
28346
+ for (const id of canonicalGateIds) if (!orchestrated.ran.has(id)) return {
28347
+ winner: "baseline",
28348
+ reason: `orchestrated did not run canonical gate "${id}"`
28349
+ };
28350
+ let baselinePass = 0;
28351
+ let orchestratedPass = 0;
28352
+ for (const id of canonicalGateIds) {
28353
+ if (baseline.passed.has(id)) baselinePass += 1;
28354
+ if (orchestrated.passed.has(id)) orchestratedPass += 1;
28355
+ else if (baseline.passed.has(id)) return {
28356
+ winner: "baseline",
28357
+ reason: `orchestrated regresses on canonical check "${id}" the baseline passed`
28358
+ };
28359
+ }
28360
+ if (orchestratedPass > baselinePass) return {
28361
+ winner: "orchestrated",
28362
+ reason: "orchestrated passes strictly more canonical executable checks"
28363
+ };
28364
+ if (tiePolicy === "superset") return {
28365
+ winner: "orchestrated",
28366
+ reason: "orchestrated matches the baseline on the canonical checks (superset policy)"
28367
+ };
28368
+ return {
28369
+ winner: "baseline",
28370
+ reason: "orchestrated does not pass strictly more canonical checks than the baseline (strict policy)"
28371
+ };
28372
+ }
28373
+
28374
+ //#endregion
28375
+ //#region src/lib/orchestration/gate-runner.ts
28376
+ async function runGateChecks(checks, cwd, exec) {
28377
+ const results = await Promise.all(checks.map(async (c) => {
28378
+ try {
28379
+ const r = await exec({
28380
+ command: c.command,
28381
+ cwd
28382
+ });
28383
+ return {
28384
+ id: c.id,
28385
+ passed: r.exitCode === 0
28386
+ };
28387
+ } catch {
28388
+ return {
28389
+ id: c.id,
28390
+ passed: false
28391
+ };
28392
+ }
28393
+ }));
28394
+ const passed = /* @__PURE__ */ new Set();
28395
+ const ran = /* @__PURE__ */ new Set();
28396
+ for (const r of results) {
28397
+ ran.add(r.id);
28398
+ if (r.passed) passed.add(r.id);
28399
+ }
28400
+ return {
28401
+ passed,
28402
+ ran
28403
+ };
28404
+ }
28405
+
28406
+ //#endregion
28407
+ //#region src/lib/orchestration/gate-registry.ts
28408
+ /**
28409
+ * Built-in sealed gates. Commands follow this repo's TS/Bun conventions (the
28410
+ * `bun run <script>` indirection means a repo without that script simply fails
28411
+ * the check, which the selector treats as not-passed rather than a crash). New
28412
+ * ecosystems get a new sealed id here, never a caller-supplied command.
28413
+ */
28414
+ const SEALED_GATES = {
28415
+ "default-ci": [
28416
+ {
28417
+ id: "typecheck",
28418
+ command: "bun run typecheck"
28419
+ },
28420
+ {
28421
+ id: "test",
28422
+ command: "bun test"
28423
+ },
28424
+ {
28425
+ id: "lint",
28426
+ command: "bun run lint"
28427
+ }
28428
+ ],
28429
+ "typecheck-test": [{
28430
+ id: "typecheck",
28431
+ command: "bun run typecheck"
28432
+ }, {
28433
+ id: "test",
28434
+ command: "bun test"
28435
+ }],
28436
+ "typecheck-only": [{
28437
+ id: "typecheck",
28438
+ command: "bun run typecheck"
28439
+ }]
28440
+ };
28441
+ /** The set of sealed gate ids, used as the kernel's `knownGateIds` so the IR
28442
+ * verifier rejects an executable gate that references an unregistered id. */
28443
+ function sealedGateIds() {
28444
+ return new Set(Object.keys(SEALED_GATES));
28445
+ }
28446
+ /**
28447
+ * Resolve a sealed gate by id. Returns a DEFENSIVE CLONE (fresh objects) so a
28448
+ * caller can never mutate the registry's command set. `undefined` for an
28449
+ * unknown id, which `run_workflow` rejects before executing anything.
28450
+ */
28451
+ function resolveSealedGate(gateId) {
28452
+ const checks = SEALED_GATES[gateId];
28453
+ if (!checks) return void 0;
28454
+ return {
28455
+ id: gateId,
28456
+ checks: checks.map((c) => ({
28457
+ id: c.id,
28458
+ command: c.command
28459
+ }))
28460
+ };
28461
+ }
28462
+
28223
28463
  //#endregion
28224
28464
  //#region src/lib/orchestration/verify.ts
28225
28465
  const VALID_ROLES = new Set([
@@ -28244,6 +28484,7 @@ const VALID_ON_FAIL = new Set([
28244
28484
  "escalate"
28245
28485
  ]);
28246
28486
  function verifyWorkflowIR(ir, opts = {}) {
28487
+ const knownGateIds = opts.knownGateIds ?? sealedGateIds();
28247
28488
  const v = [];
28248
28489
  const push = (code, message, nodeId) => {
28249
28490
  v.push(nodeId === void 0 ? {
@@ -28321,7 +28562,7 @@ function verifyWorkflowIR(ir, opts = {}) {
28321
28562
  const g = n.gate;
28322
28563
  if (g.kind === "executable") {
28323
28564
  if (typeof g.gateId !== "string" || g.gateId.length === 0) push("BAD_GATE", `executable gate on node "${n.id}" must reference a sealed gateId (gate-immutability)`, n.id);
28324
- else if (opts.knownGateIds && !opts.knownGateIds.has(g.gateId)) push("UNKNOWN_GATE_ID", `executable gate on node "${n.id}" references gateId "${g.gateId}" not in the kernel's sealed-gate registry`, n.id);
28565
+ else if (!knownGateIds.has(g.gateId)) push("UNKNOWN_GATE_ID", `executable gate on node "${n.id}" references gateId "${g.gateId}" not in the kernel's sealed-gate registry`, n.id);
28325
28566
  }
28326
28567
  if (g.kind === "cross_lab") {
28327
28568
  if (typeof g.checkerLab !== "string" || g.checkerLab.length === 0) push("BAD_GATE", `cross_lab gate on node "${n.id}" must name a checkerLab`, n.id);
@@ -28428,53 +28669,6 @@ function hasCycle(nodes, byId) {
28428
28669
  return false;
28429
28670
  }
28430
28671
 
28431
- //#endregion
28432
- //#region src/lib/orchestration/select.ts
28433
- const subsetOf = (a, b) => {
28434
- for (const x of a) if (!b.has(x)) return false;
28435
- return true;
28436
- };
28437
- function selectChampion(orchestrated, baseline, canonicalGateIds, tiePolicy) {
28438
- if (!subsetOf(orchestrated.passed, orchestrated.ran)) return {
28439
- winner: "baseline",
28440
- reason: "orchestrated outcome malformed (passed not a subset of ran)"
28441
- };
28442
- if (!subsetOf(baseline.passed, baseline.ran)) return {
28443
- winner: "baseline",
28444
- reason: "baseline outcome malformed (passed not a subset of ran)"
28445
- };
28446
- if (canonicalGateIds.size === 0) return {
28447
- winner: "baseline",
28448
- reason: "no executable gate for this ask — ship the baseline (judgment-only)"
28449
- };
28450
- for (const id of canonicalGateIds) if (!orchestrated.ran.has(id)) return {
28451
- winner: "baseline",
28452
- reason: `orchestrated did not run canonical gate "${id}"`
28453
- };
28454
- let baselinePass = 0;
28455
- let orchestratedPass = 0;
28456
- for (const id of canonicalGateIds) {
28457
- if (baseline.passed.has(id)) baselinePass += 1;
28458
- if (orchestrated.passed.has(id)) orchestratedPass += 1;
28459
- else if (baseline.passed.has(id)) return {
28460
- winner: "baseline",
28461
- reason: `orchestrated regresses on canonical check "${id}" the baseline passed`
28462
- };
28463
- }
28464
- if (orchestratedPass > baselinePass) return {
28465
- winner: "orchestrated",
28466
- reason: "orchestrated passes strictly more canonical executable checks"
28467
- };
28468
- if (tiePolicy === "superset") return {
28469
- winner: "orchestrated",
28470
- reason: "orchestrated matches the baseline on the canonical checks (superset policy)"
28471
- };
28472
- return {
28473
- winner: "baseline",
28474
- reason: "orchestrated does not pass strictly more canonical checks than the baseline (strict policy)"
28475
- };
28476
- }
28477
-
28478
28672
  //#endregion
28479
28673
  //#region src/lib/orchestration/kernel.ts
28480
28674
  const DEFAULT_MAX_RETRIES = 2;
@@ -28594,6 +28788,7 @@ const clone = (v) => typeof structuredClone === "function" ? structuredClone(v)
28594
28788
  async function decomposeWorkflow(ask, deps, opts = {}) {
28595
28789
  const maxRounds = Math.max(1, opts.maxRounds ?? DEFAULT_MAX_ROUNDS);
28596
28790
  const verifyOpts = opts.verify ?? {};
28791
+ const context = typeof opts.context === "string" && opts.context.trim().length > 0 ? opts.context.trim() : void 0;
28597
28792
  let feedback;
28598
28793
  let lastViolations = [{
28599
28794
  code: "NO_DRAFT",
@@ -28603,6 +28798,7 @@ async function decomposeWorkflow(ask, deps, opts = {}) {
28603
28798
  for (let round = 1; round <= maxRounds; round += 1) {
28604
28799
  const drafted = await safeDraft(deps, {
28605
28800
  ask,
28801
+ context,
28606
28802
  feedback
28607
28803
  });
28608
28804
  attempts += 1;
@@ -28627,6 +28823,7 @@ async function decomposeWorkflow(ask, deps, opts = {}) {
28627
28823
  if (round < maxRounds) {
28628
28824
  const next = await safeDraft(deps, {
28629
28825
  ask,
28826
+ context,
28630
28827
  feedback: concerns
28631
28828
  });
28632
28829
  attempts += 1;
@@ -28852,38 +29049,6 @@ function detectGateWeakening(diff) {
28852
29049
  };
28853
29050
  }
28854
29051
 
28855
- //#endregion
28856
- //#region src/lib/orchestration/gate-runner.ts
28857
- async function runGateChecks(checks, cwd, exec) {
28858
- const results = await Promise.all(checks.map(async (c) => {
28859
- try {
28860
- const r = await exec({
28861
- command: c.command,
28862
- cwd
28863
- });
28864
- return {
28865
- id: c.id,
28866
- passed: r.exitCode === 0
28867
- };
28868
- } catch {
28869
- return {
28870
- id: c.id,
28871
- passed: false
28872
- };
28873
- }
28874
- }));
28875
- const passed = /* @__PURE__ */ new Set();
28876
- const ran = /* @__PURE__ */ new Set();
28877
- for (const r of results) {
28878
- ran.add(r.id);
28879
- if (r.passed) passed.add(r.id);
28880
- }
28881
- return {
28882
- passed,
28883
- ran
28884
- };
28885
- }
28886
-
28887
29052
  //#endregion
28888
29053
  //#region src/lib/orchestration/stop-gate.ts
28889
29054
  async function evaluateStopGate(input) {
@@ -28929,63 +29094,6 @@ const liveExec = async ({ command, cwd }) => {
28929
29094
  }
28930
29095
  };
28931
29096
 
28932
- //#endregion
28933
- //#region src/lib/orchestration/gate-registry.ts
28934
- /**
28935
- * Built-in sealed gates. Commands follow this repo's TS/Bun conventions (the
28936
- * `bun run <script>` indirection means a repo without that script simply fails
28937
- * the check, which the selector treats as not-passed rather than a crash). New
28938
- * ecosystems get a new sealed id here, never a caller-supplied command.
28939
- */
28940
- const SEALED_GATES = {
28941
- "default-ci": [
28942
- {
28943
- id: "typecheck",
28944
- command: "bun run typecheck"
28945
- },
28946
- {
28947
- id: "test",
28948
- command: "bun test"
28949
- },
28950
- {
28951
- id: "lint",
28952
- command: "bun run lint"
28953
- }
28954
- ],
28955
- "typecheck-test": [{
28956
- id: "typecheck",
28957
- command: "bun run typecheck"
28958
- }, {
28959
- id: "test",
28960
- command: "bun test"
28961
- }],
28962
- "typecheck-only": [{
28963
- id: "typecheck",
28964
- command: "bun run typecheck"
28965
- }]
28966
- };
28967
- /** The set of sealed gate ids, used as the kernel's `knownGateIds` so the IR
28968
- * verifier rejects an executable gate that references an unregistered id. */
28969
- function sealedGateIds() {
28970
- return new Set(Object.keys(SEALED_GATES));
28971
- }
28972
- /**
28973
- * Resolve a sealed gate by id. Returns a DEFENSIVE CLONE (fresh objects) so a
28974
- * caller can never mutate the registry's command set. `undefined` for an
28975
- * unknown id, which `run_workflow` rejects before executing anything.
28976
- */
28977
- function resolveSealedGate(gateId) {
28978
- const checks = SEALED_GATES[gateId];
28979
- if (!checks) return void 0;
28980
- return {
28981
- id: gateId,
28982
- checks: checks.map((c) => ({
28983
- id: c.id,
28984
- command: c.command
28985
- }))
28986
- };
28987
- }
28988
-
28989
29097
  //#endregion
28990
29098
  //#region src/lib/orchestration/runner-live.ts
28991
29099
  /** Map a node role to the worker-engine mode. `baseline` is pre-mapped to
@@ -29476,6 +29584,19 @@ async function decideStopHook(input) {
29476
29584
  let dynamicBaselineKey;
29477
29585
  const planMode = input.planMode === true || payload.plan_mode === true;
29478
29586
  const scanDiff = (diff) => planMode ? stripPlanMemoryDiffHunks(diff) : diff;
29587
+ const capturedDiff = async (workdir) => {
29588
+ try {
29589
+ return {
29590
+ diff: await input.captureDiff(workdir),
29591
+ captured: true
29592
+ };
29593
+ } catch {
29594
+ return {
29595
+ diff: "",
29596
+ captured: false
29597
+ };
29598
+ }
29599
+ };
29479
29600
  const runGate = async () => {
29480
29601
  if (input.resolveChecks) {
29481
29602
  const resolved = await input.resolveChecks(cwd).catch(() => null);
@@ -29483,27 +29604,37 @@ async function decideStopHook(input) {
29483
29604
  resolvedKey = resolved.descriptorKey;
29484
29605
  dynamicBaselineKey = resolved.baselineKey;
29485
29606
  const workdir = resolved.workdir || cwd;
29486
- const diff$1 = await input.captureDiff(workdir).catch(() => "");
29607
+ const { diff: diff$1, captured: captured$1 } = await capturedDiff(workdir);
29608
+ if (captured$1 && diff$1.length === 0) return {
29609
+ kind: "no-diff",
29610
+ diff: diff$1
29611
+ };
29487
29612
  const result$1 = await evaluateStopGate({
29488
29613
  checks: resolved.checks,
29489
29614
  cwd: workdir,
29490
29615
  exec: input.exec,
29491
- diff: scanDiff(diff$1)
29616
+ diff: captured$1 ? scanDiff(diff$1) : ""
29492
29617
  });
29493
29618
  return {
29619
+ kind: "evaluated",
29494
29620
  failedChecks: [...result$1.failedChecks],
29495
29621
  weakeningPatterns: [...new Set(result$1.weakening.map((w) => w.pattern))],
29496
29622
  diff: diff$1
29497
29623
  };
29498
29624
  }
29499
- const diff = await input.captureDiff(cwd).catch(() => "");
29625
+ const { diff, captured } = await capturedDiff(cwd);
29626
+ if (captured && diff.length === 0) return {
29627
+ kind: "no-diff",
29628
+ diff
29629
+ };
29500
29630
  const result = await runStopGateForLaunch({
29501
29631
  workspace: cwd,
29502
29632
  gateId: input.gateId,
29503
29633
  exec: input.exec,
29504
- diff: scanDiff(diff)
29634
+ diff: captured ? scanDiff(diff) : ""
29505
29635
  });
29506
29636
  return {
29637
+ kind: "evaluated",
29507
29638
  failedChecks: [...result.failedChecks],
29508
29639
  weakeningPatterns: [...new Set(result.weakening.map((w) => w.pattern))],
29509
29640
  diff
@@ -29517,6 +29648,7 @@ async function decideStopHook(input) {
29517
29648
  if (timer) clearTimeout(timer);
29518
29649
  if (raced === "timeout") return { exitCode: 0 };
29519
29650
  if (raced === null) return { exitCode: 0 };
29651
+ if (raced.kind === "no-diff") return { exitCode: 0 };
29520
29652
  const baselineKey = dynamicBaselineKey ?? JSON.stringify([
29521
29653
  sessionId,
29522
29654
  cwd,
@@ -29553,7 +29685,7 @@ async function decideStopHook(input) {
29553
29685
  * `markReviewed` runs BEFORE the spawn so a crashing spawn still records the
29554
29686
  * debounce (an identical tree won't re-trigger on the next stop). The review is
29555
29687
  * gated on the diff CHANGING since the last review — without it, every stop of
29556
- * an unchanged tree would re-spend a background gpt-5.5 review.
29688
+ * an unchanged tree would re-spend a background gpt-5.6-sol review.
29557
29689
  *
29558
29690
  * The whole body is bounded by a short timeout (the stores are local temp files
29559
29691
  * that complete in well under a millisecond in practice, so the timeout never
@@ -29804,8 +29936,8 @@ function buildLiveDecomposeDeps(opts) {
29804
29936
  endpoint: "/v1/messages",
29805
29937
  effort: "xhigh"
29806
29938
  };
29807
- const deps = { async draftIR({ ask, feedback }) {
29808
- const userText = `Ask:\n${ask}` + (feedback && feedback.length > 0 ? `\n\nFix these issues from the previous draft:\n- ${feedback.join("\n- ")}` : "");
29939
+ const deps = { async draftIR({ ask, context, feedback }) {
29940
+ const userText = `Ask:\n${ask}` + (context && context.trim().length > 0 ? `\n\nContext:\n${context.trim()}` : "") + (feedback && feedback.length > 0 ? `\n\nFix these issues from the previous draft:\n- ${feedback.join("\n- ")}` : "");
29809
29941
  return extractJson(await dispatchModelCall({
29810
29942
  model: driver.model,
29811
29943
  endpoint: driver.endpoint,
@@ -29839,7 +29971,7 @@ const CRITIC_INSTRUCTIONS = "You are a cross-lab code reviewer. Review the diff
29839
29971
  function labPersona(lab) {
29840
29972
  switch (lab.toLowerCase()) {
29841
29973
  case "openai": return {
29842
- model: "gpt-5.5",
29974
+ model: "gpt-5.6-sol",
29843
29975
  endpoint: "/v1/responses",
29844
29976
  effort: "high"
29845
29977
  };
@@ -30066,7 +30198,7 @@ Cold-start contract for the lead orchestrator (Opus):
30066
30198
  (c) any prior decisions I should not relitigate.
30067
30199
  If your brief lacks (a), I will reply with a one-line request for the artifact instead of speculating.
30068
30200
  `.trim();
30069
- const CRITIC_BASE = `You are codex-critic, an adversarial reviewer running on gpt-5.5. Your single job is to overcome the lead orchestrator's blind spots — assumptions it didn't notice it was making, failure modes it didn't enumerate, alternatives it didn't consider.
30201
+ const CRITIC_BASE = `You are codex-critic, an adversarial reviewer running on gpt-5.6-sol. Your single job is to overcome the lead orchestrator's blind spots — assumptions it didn't notice it was making, failure modes it didn't enumerate, alternatives it didn't consider.
30070
30202
 
30071
30203
  You are NOT a helpful assistant. You are NOT a coach. Sycophancy is the failure mode you exist to fight. Manufactured contrarianism is a different failure of the same shape — silence on good work is a valid and welcome answer.
30072
30204
 
@@ -30154,9 +30286,9 @@ Reply format (markdown):
30154
30286
 
30155
30287
  Resilience reminder:
30156
30288
  If your session terminates abnormally before "Status: complete", the lead will retry once. On recovery, ask the lead to confirm what's already been done before re-applying changes — duplicate edits are worse than a slow restart.`;
30157
- const OPUS_CRITIC_BASE = `You are opus-critic, a fresh-context Anthropic-side adversarial reviewer running on Claude Opus 4.7 the same model and lab as the lead orchestrator that just delegated to you. You are NOT the lead. You did not see the lead's reasoning trace. You only see the brief.
30289
+ const OPUS_CRITIC_BASE = `You are opus-critic, a fresh-context same-lab adversarial reviewer running on Opus 4.6. The lead orchestrator that just delegated to you runs newer Opus-family context, but you are NOT the lead. You did not see the lead's reasoning trace. You only see the brief.
30158
30290
 
30159
- Your job is to spot what the lead missed because of cognitive momentum, sunk-cost on a plan, or motivated reasoning toward a particular fix. Your blind-spot diversification is LIMITED compared to codex-critic (gpt-5.5) and gemini-critic (gemini-3.1-pro) same training, same lab, same RLHF priors. Use that honestly: don't pretend to find a different perspective when the obvious read is "the lead got it right." Silence on good work is a valid and welcome answer.
30291
+ Your job is to spot what the lead missed because of cognitive momentum, sunk-cost on a plan, or motivated reasoning toward a particular fix. Your blind-spot diversification is LIMITED compared to codex-critic (gpt-5.6-sol) and gemini-critic (gemini-3.1-pro), same lab, adjacent model family, related priors. Use that honestly: don't pretend to find a different perspective when the obvious read is "the lead got it right." Silence on good work is a valid and welcome answer.
30160
30292
 
30161
30293
  Sycophancy is the failure mode you exist to fight. Manufactured contrarianism is a different failure of the same shape — do neither.
30162
30294
 
@@ -30167,9 +30299,9 @@ const PERSONAS_READ = Object.freeze([
30167
30299
  {
30168
30300
  agentName: "codex-critic",
30169
30301
  toolNameHttp: "codex_critic",
30170
- model: "gpt-5.5",
30302
+ model: "gpt-5.6-sol",
30171
30303
  endpoint: "/v1/responses",
30172
- description: "Adversarial second opinion on plans, designs, or code tradeoffs. Backed by gpt-5.5 (OpenAI, ≈922K-token input window) strongest reasoning model in the critic lineup, different lab than Opus. Best for architecture decisions, design reviews, and tradeoff analysis where cross-lab diversity matters. Not for line-level code review (use codex_reviewer). Pass artifact verbatim.",
30304
+ description: "Adversarial architecture and design critic backed by gpt-5.6-sol (OpenAI, ~1M-token input window), the strongest cross-lab reasoning critic in this surface. It reviews plans, designs, tradeoffs, and large code-change proposals for unsound assumptions, missing failure modes, and overlooked alternatives, then returns a calibrated objection or `no material objection`. Use when a decision or design needs a different-lab strategic challenge before implementation or merge. Not for line-level bug finding in a concrete diff or file, use codex_reviewer or gemini_reviewer; pass the artifact and constraints verbatim.",
30173
30305
  baseInstructions: CRITIC_BASE,
30174
30306
  agentPrompt: "",
30175
30307
  writeCapable: false,
@@ -30187,7 +30319,7 @@ const PERSONAS_READ = Object.freeze([
30187
30319
  toolNameHttp: "gemini_critic",
30188
30320
  model: "gemini-3.1-pro-preview",
30189
30321
  endpoint: "/v1/chat/completions",
30190
- description: "Adversarial second opinion. Backed by gemini-3.1-pro (Google) — third-lab triangulation, strong on formal reasoning, proofs, and invariants. Useful for cross-checking findings from codex_critic or codex_reviewer when you want a third perspective. Pass artifact verbatim.",
30322
+ description: "Adversarial third-lab critic backed by gemini-3.1-pro-preview (Google), strong on formal reasoning, invariants, proofs, and cross-checking another critic's conclusion. It reviews plans, designs, mathematical arguments, and large artifacts for assumption gaps or invariant failures, then returns a focused critique or no-material-objection style verdict. Use when codex_critic's result needs an independent lab check or when the artifact hinges on formal correctness. Not for line-level diff review, use gemini_reviewer or codex_reviewer; pass the artifact and constraints verbatim.",
30191
30323
  baseInstructions: GEMINI_CRITIC_BASE,
30192
30324
  agentPrompt: "",
30193
30325
  writeCapable: false,
@@ -30205,7 +30337,7 @@ const PERSONAS_READ = Object.freeze([
30205
30337
  toolNameHttp: "codex_reviewer",
30206
30338
  model: "gpt-5.3-codex",
30207
30339
  endpoint: "/v1/responses",
30208
- description: "Line-level review of a concrete diff or single file. Backed by gpt-5.3-codex (OpenAI, ≈272K-token input window) code-specialist, fastest critic (~16s). Surfaces bugs, edge cases, security issues, and idiom violations at specific line numbers. Not suited for architecture or design review (use codex_critic for plans). Pass artifact verbatim.",
30340
+ description: "Line-level code reviewer backed by gpt-5.3-codex (OpenAI, ≈272K-token input window), a code-specialist reviewer that is fastest around high effort (~16s at high effort). It reviews concrete diffs, files, or function bodies and returns findings with severity, file:line locations, issue impact, and a minimal suggested fix. Use when the artifact is actual code and the goal is bug, edge-case, security, concurrency, resource, or idiom review. Not for architecture or tradeoff review, use codex_critic or gemini_critic; pass the diff or file content verbatim.",
30209
30341
  baseInstructions: REVIEWER_BASE,
30210
30342
  agentPrompt: "",
30211
30343
  writeCapable: false,
@@ -30223,7 +30355,7 @@ const PERSONAS_READ = Object.freeze([
30223
30355
  toolNameHttp: "gemini_reviewer",
30224
30356
  model: "gemini-3.1-pro-preview",
30225
30357
  endpoint: "/v1/chat/completions",
30226
- description: "Line-level review of a concrete diff or single file on gemini-3.1-pro (Google, high reasoning): a second-lab code reviewer that catches a different slice of defects than codex_reviewer (OpenAI). Use alongside codex_reviewer for cross-lab coverage of a diff. Not for architecture (use codex_critic / gemini_critic for plans). Pass artifact verbatim.",
30358
+ description: "Line-level code reviewer backed by gemini-3.1-pro-preview (Google), providing second-lab coverage that catches a different slice of concrete-code defects than codex_reviewer. It reviews diffs, files, or function bodies and returns severity-ranked findings with file:line citations and suggested fixes. Use alongside codex_reviewer when a non-trivial diff benefits from cross-lab code-review coverage, especially around invariants or edge cases. Not for architecture or product-design review, use codex_critic or gemini_critic; pass the code artifact verbatim.",
30227
30359
  baseInstructions: GEMINI_REVIEWER_BASE,
30228
30360
  agentPrompt: "",
30229
30361
  writeCapable: false,
@@ -30241,7 +30373,7 @@ const PERSONAS_READ = Object.freeze([
30241
30373
  toolNameHttp: "opus_critic",
30242
30374
  model: "claude-opus-4-6",
30243
30375
  endpoint: "/v1/messages",
30244
- description: "Adversarial second opinion from a fresh-context Opus 4.6 same lab as the lead, limited blind-spot diversity vs cross-lab critics. On enterprise catalogs that carry Opus-4.6-1M it runs with a ≈936K-token input window; otherwise ≈168K. Pinned one minor behind the default Opus so the panel spans more of the version curve. Catches confabulation. Pass artifact verbatim.",
30376
+ description: "Adversarial same-lab critic backed by fresh-context Opus 4.6, with limited blind-spot diversity compared with cross-lab critics. It reviews plans, designs, or code tradeoffs for cognitive momentum, sunk-cost reasoning, and confabulated assumptions, then returns a calibrated objection or no material objection. Use when a same-family sanity check can catch lead-context drift or when comparing against codex_critic / gemini_critic findings. Not a substitute for cross-lab review on security-sensitive or high-risk changes; use codex_critic or gemini_critic for stronger diversity. On enterprise catalogs that carry Opus-4.6-1M it runs with ≈936K input tokens; otherwise ≈168K. Pinned two minors behind the default Opus so the panel spans more of the version curve. Pass artifact verbatim.",
30245
30377
  baseInstructions: OPUS_CRITIC_BASE,
30246
30378
  agentPrompt: "",
30247
30379
  writeCapable: false,
@@ -30259,7 +30391,7 @@ const PERSONAS_WRITE = Object.freeze([{
30259
30391
  toolNameHttp: "codex_implementer",
30260
30392
  model: "gpt-5.3-codex",
30261
30393
  endpoint: "/v1/responses",
30262
- description: "Targeted implementation of a self-contained coding task. Backed by gpt-5.3-codex with workspace-write access. Pass spec + files verbatim.",
30394
+ description: "Targeted implementation persona backed by gpt-5.3-codex with workspace-write access. It executes self-contained coding tasks from a pasted spec, reads the relevant files, edits the workspace, verifies the result, and returns changed files plus verification output. Use when the task is bounded enough for direct implementation and the caller can provide acceptance criteria and file context up front. Not for open-ended planning or broad repo exploration, use plan or explore first; not for read-only review, use codex_reviewer or gemini_reviewer. Because it can mutate the workspace, scope files and allowed changes explicitly and pass the spec verbatim.",
30263
30395
  baseInstructions: IMPLEMENTER_BASE,
30264
30396
  agentPrompt: "",
30265
30397
  writeCapable: true,
@@ -30354,8 +30486,8 @@ function buildAgentPrompt(persona, opts) {
30354
30486
  * - Conditionally lists gemini_critic only when `geminiAvailable`.
30355
30487
  * - Conditionally lists the `worker-*` background dispatcher subagents
30356
30488
  * (worker-explore / worker-review / worker-plan / worker-implement /
30357
- * worker-test), the non-blocking-guard fact, and "Workers themselves
30358
- * have code_search" only when `workerToolsAvailable` (mirrors
30489
+ * worker-test), the non-blocking-guard fact, and the worker code-search
30490
+ * affordance only when `workerToolsAvailable` (mirrors
30359
30491
  * `workerToolsEnabled()` so the snippet never names a surface gated out
30360
30492
  * of the live catalog). The raw `mcp__<workers>__*` tools are named only
30361
30493
  * as the guarded plumbing the dispatchers call, never as a main-agent
@@ -30379,15 +30511,19 @@ function buildPeerAwarenessSnippet(opts) {
30379
30511
  const orchestrateKey = key("orchestrate");
30380
30512
  const browserKey = key("browser");
30381
30513
  const decideKey = key("decide");
30382
- const criticList = ["`codex_critic` (gpt-5.5)", "`codex_reviewer` (gpt-5.3-codex)"];
30514
+ const fleetKey = key("fleet");
30515
+ const compoundBrowseAvailable = opts.browseAvailable && opts.compoundBrowseAvailable;
30516
+ const powerBrowseAvailable = opts.browseAvailable && opts.powerBrowseAvailable === true;
30517
+ const criticList = ["`codex_critic` (gpt-5.6-sol)", "`codex_reviewer` (gpt-5.3-codex)"];
30383
30518
  if (opts.geminiAvailable) {
30384
30519
  criticList.push("`gemini_reviewer` (gemini-3.1-pro, line-level code review)");
30385
30520
  criticList.push("`gemini_critic` (gemini-3.1-pro)");
30386
30521
  }
30387
- criticList.push("`opus_critic` (Opus 4.7)");
30522
+ criticList.push("`opus_critic` (Opus 4.6)");
30388
30523
  const codexCliClause = opts.codexCli ? " `mcp__codex-cli__codex` dispatches to `codex-implementer` (gpt-5.3-codex with workspace-write) for end-to-end coding tasks." : "";
30389
30524
  const para2Parts = [`\`mcp__${searchKey}__code\` is the one-stop code search (no extra model call). Its DEFAULT mode (or \`mode:"semantic"\`) ranks by MEANING via ColBERT over a per-workspace index, the first thing to reach for on intent/concept questions ("where is retry/backoff handled", "how does auth work"); when that index isn't ready it transparently falls back to lexical (the response \`source\` says which engine ran). Forced modes cover the rest: \`lexical\` (BM25F-ranked + tree-sitter, best for exact symbols), \`exact\`, \`regex\`, \`complete\` (exhaustive set), \`ast_pattern\`+\`ast_lang\` for multi-line AST shapes, \`scan\` for a whole-workspace symbol outline, \`multiline\` for cross-line regex. Multiple queries can run in a single turn. The index covers code-shaped files; for unstructured files (logs, \`.csv\`, \`.env*\`, config-only wiring), \`grep\`/\`glob\` still apply.`];
30390
30525
  if (opts.workerToolsAvailable) para2Parts.push(`\`worker-*\` are background Agent subagents (subagent_type) that run the matching worker in its own context and deliver the result as a completion notification, so a long run never blocks the turn: \`worker-explore\` (read-only research), \`worker-review\` (reads the code to verify a change or claim), \`worker-plan\` (ordered implementation plan), \`worker-implement\` (edit/write/bash; \`worktree: true\` isolates in a git worktree and returns the diff), \`worker-test\` (independent test author). The raw \`mcp__${workersKey}__*\` tools they call are guarded (a direct main-thread call is redirected to the matching agent); Workers themselves have \`code_search\`.`);
30526
+ if (opts.workerToolsAvailable && opts.implementerAvailable) para2Parts.push(`For a bounded, well-scoped implementation, prefer the \`implementer\` subagent (Task, runs on gpt-5.6-sol) over \`worker-implement\`; reach for \`worker-implement\` only when you specifically need git-worktree isolation, parallel variants, or a throwaway experiment.`);
30391
30527
  if (opts.workerToolsAvailable) para2Parts.push(`\`mcp__${orchestrateKey}__decompose\` composes an open-ended ask into a typed, VERIFIED workflow IR (a strong driver decorrelated by a cross-lab critic, so the decompose step isn't a single point of failure), and \`mcp__${orchestrateKey}__run_workflow\` executes that IR through a frozen kernel delivering max(orchestrated, baseline) over a sealed executable gate, so it never ships worse than a plain single-model run. \`mcp__${orchestrateKey}__verify_workflow\` checks an IR's floor invariants before you run it, and \`mcp__${orchestrateKey}__attest_step\` audits that a finished run's producers were each checked by a different lab. They suit non-trivial, role-separated asks; a trivial ask does not need them.`);
30392
30528
  else para2Parts.push(`\`mcp__${orchestrateKey}__verify_workflow\` statically checks a workflow IR's floor invariants and \`mcp__${orchestrateKey}__attest_step\` audits a run's cross-lab lineage (the \`decompose\`/\`run_workflow\` composer + kernel need the worker backend, unavailable here).`);
30393
30529
  if (opts.workerToolsAvailable) {
@@ -30396,10 +30532,10 @@ function buildPeerAwarenessSnippet(opts) {
30396
30532
  }
30397
30533
  para2Parts.push(`\`mcp__${searchKey}__web\` surfaces citable sources for docs, errors, and upstream issues.`);
30398
30534
  if (opts.standInAvailable) para2Parts.push(`\`mcp__${decideKey}__stand_in\` provides three-lab consensus for decision tiebreak when the user is unavailable.`);
30399
- if (opts.browseAvailable) {
30400
- const powerNote = opts.powerBrowseAvailable ? ` Power mode adds the L0/L1 primitives (\`mcp__${browserKey}__mouse\`, \`__drag\`, \`__type\`, \`__keyboard\`, \`__scroll\`, \`__eval_js\`, \`__read_page\`, \`__diagnostics\`, \`__find\`) for direct DOM / coordinate control.` : "";
30401
- para2Parts.push(`\`mcp__${browserKey}__*\` tools drive a real Chrome / Edge browser via a local extension. Lead surface: \`__act(intent, value?)\` for any click / fill / type / scroll-to (an inner fast model resolves intent), \`__observe(intent?)\` for a 2-4 sentence natural-language page description, \`__extract(schema, instruction)\` for typed extraction, \`__navigate\` / \`__open_tab\` / \`__screenshot\` for state and visuals. The lead never sees raw DOM: refs and bboxes stay internal.${powerNote}`);
30402
- }
30535
+ if (opts.browseAvailable) para2Parts.push(`\`mcp__${browserKey}__*\` tools drive a real Chrome / Edge browser via a local extension. Lead browse surface includes \`__navigate\` / \`__open_tab\` / \`__screenshot\` for state, visuals, and navigation.`);
30536
+ if (compoundBrowseAvailable) para2Parts.push(`Compound browse surface includes \`mcp__${browserKey}__act(intent, value?)\` / \`__observe(intent?)\` / \`__extract(schema, instruction)\` / \`__find\`; an inner fast model resolves intent, find/observe yield element refs act consumes, and the lead never sees raw DOM.`);
30537
+ if (powerBrowseAvailable) para2Parts.push(`Power browse surface adds \`mcp__${browserKey}__mouse\`, \`__drag\`, \`__type\`, \`__keyboard\`, \`__scroll\`, \`__eval_js\`, \`__read_page\`, \`__diagnostics\`, \`__list_tabs\`, \`__close_tab\`, \`__wait\`, and \`__download\` for direct DOM and coordinate control.`);
30538
+ if (opts.fleetAvailable) para2Parts.push(`\`mcp__${fleetKey}__*\` tools drive remote ai-or-die coding sessions (list / read / create / stop / await / drive, plus remote read_file / list_dir / search / git_show); they act on a REMOTE fleet instance, not the local repo.`);
30403
30539
  return [
30404
30540
  "## Peer review and advisor",
30405
30541
  "",
@@ -30408,6 +30544,31 @@ function buildPeerAwarenessSnippet(opts) {
30408
30544
  para2Parts.join(" ")
30409
30545
  ].join("\n");
30410
30546
  }
30547
+ /**
30548
+ * Compact, gated capability SUMMARY for the spawned session's system prompt
30549
+ * (`--append-system-prompt`). The FULL per-tool inventory lives once in the
30550
+ * mirrored CLAUDE.md (buildPeerAwarenessSnippet); this ~300-token summary gives
30551
+ * the main agent high-salience awareness of what is available without
30552
+ * duplicating the full snippet in the context window every turn. Gated
30553
+ * identically to the full snippet so it never names a surface the live
30554
+ * tools/list dropped. Factual present tense, no imperatives.
30555
+ */
30556
+ function buildPeerAwarenessSummary(opts) {
30557
+ const key = (g) => opts.groupKeys?.[g] ?? GROUP_META[g].preferredKey;
30558
+ const lines = [
30559
+ "## Injected capabilities (summary)",
30560
+ "",
30561
+ `A layer of MCP tools, background workers, and skills is injected into this session. Cross-lab peer critics under \`mcp__${key("peers")}__*\` (plus the \`peer-review-coordinator\` subagent) review plans and diffs adversarially, and Claude Code's built-in \`advisor\` catches approach drift. \`mcp__${key("search")}__code\` is meaning-first code search and \`mcp__${key("search")}__web\` returns citable web sources.`
30562
+ ];
30563
+ if (opts.workerToolsAvailable) lines.push(`Background \`worker-*\` agents (explore, review, plan, implement, test) run delegated work in their own context without blocking your turn, and \`mcp__${key("orchestrate")}__*\` composes, verifies, and runs floor-raising workflows.`);
30564
+ if (opts.standInAvailable) lines.push(`\`mcp__${key("decide")}__stand_in\` returns a three-lab consensus for a decision when the user is unavailable.`);
30565
+ if (opts.browseAvailable) lines.push(`\`mcp__${key("browser")}__*\` drives a real Chrome or Edge browser.`);
30566
+ if (opts.fleetAvailable) lines.push(`\`mcp__${key("fleet")}__*\` drives remote ai-or-die coding sessions.`);
30567
+ if (opts.agentToolsAvailable === true) lines.push("The `/gh-first-mate` skill drives a durable GitHub cloud-agent loop.");
30568
+ lines.push("");
30569
+ lines.push(`Each tool's own description carries when to use it and when not. The full per-tool inventory (models, gating, workers, skills) is in the "Peer review and advisor" section of your CLAUDE.md project instructions.`);
30570
+ return lines.join("\n");
30571
+ }
30411
30572
  /** Convenience: every persona that should be registered for the given mode. */
30412
30573
  function personasFor(opts) {
30413
30574
  const result = [];
@@ -30418,7 +30579,7 @@ function personasFor(opts) {
30418
30579
  if (opts.codexCli) for (const p of PERSONAS_WRITE) result.push(p);
30419
30580
  return result;
30420
30581
  }
30421
- const WEB_SEARCH_DESCRIPTION = "Web search via GitHub Copilot's MCP. Prefer over Claude Code's built-in WebSearch — surfaces source URLs you can cite. Use for API documentation lookups, error message diagnosis, upstream issue searches, and verifying claims against current sources. Returns content with reference links.";
30582
+ const WEB_SEARCH_DESCRIPTION = "Web search via GitHub Copilot's MCP that returns answer text plus source URLs the caller can cite. It accepts a natural-language `query`; the upstream provider rewrites for the search index and the handler formats any references as markdown links. Use for current external information such as API documentation, error-message diagnosis, upstream issue searches, and claims that need web sources. Not for local repository discovery or code navigation, use code, Read, Grep, or Glob for workspace content. Prefer it over the built-in WebSearch when source URLs are needed or the built-in surface is geographically constrained.";
30422
30583
  /**
30423
30584
  * Format a `searchWeb()` result as an MCP-friendly text block. Mirrors
30424
30585
  * the legacy inject format that `injectWebSearchIfNeeded` produces and
@@ -30453,7 +30614,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30453
30614
  if (!query) return {
30454
30615
  content: [{
30455
30616
  type: "text",
30456
- text: "web_search: arguments.query is required (must be a non-empty string)"
30617
+ text: "web: arguments.query is required (must be a non-empty string)"
30457
30618
  }],
30458
30619
  isError: true
30459
30620
  };
@@ -30466,7 +30627,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30466
30627
  return {
30467
30628
  content: [{
30468
30629
  type: "text",
30469
- text: `web_search failed: ${err instanceof Error ? err.message : String(err)}`
30630
+ text: `web failed: ${err instanceof Error ? err.message : String(err)}`
30470
30631
  }],
30471
30632
  isError: true
30472
30633
  };
@@ -30625,7 +30786,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30625
30786
  toolNameHttp: "explore",
30626
30787
  group: "workers",
30627
30788
  capability: "worker",
30628
- description: "Runs as the background `worker-explore` agent. Dispatch via the Agent tool (subagent_type: worker-explore) so your turn is never blocked; the result arrives as a completion notification. Read-only investigation by an autonomous worker (Pi runtime; default model `gpt-5.4-mini` at xhigh reasoning, override via the `model` arg with any Copilot-catalog model that advertises `tool_calls`). Tools: read, glob, grep, code_search (semantic-first), web_search, fetch_url, advisor (consult a stronger cross-lab model), update_plan (planning checklist), and toolbelt (run a read-only analysis CLI: rg/fd/jq/yq/sg/gron/tokei/difft/git). The worker's system prompt sandboxes it and gives one-line descriptions of each tool, so brief it on the investigation, not on tool semantics. Offloads bounded research that would otherwise eat your context window the worker plans its own tool calls and returns a single text answer. Examples: \"find files matching X then summarize\", \"how does library Y handle Z\", \"survey this codebase for usages of deprecated API\".",
30789
+ description: "Runs as the background `worker-explore` agent. Dispatch via the Agent tool (subagent_type: worker-explore) so the turn is never blocked; the result arrives as a completion notification. Read-only investigation by an autonomous worker (Pi runtime; default model `claude-sonnet-5` at xhigh reasoning, override via the `model` arg with any Copilot-catalog model that advertises `tool_calls`). It has read, glob, grep, semantic-first code search, web search, fetch_url, advisor, update_plan, and read-only toolbelt tools, and it returns a single text answer. Use for bounded research, repo discovery, dependency investigation, or multi-file reading that would otherwise consume the lead context window. Not for implementation, test authoring, or verification of a concrete diff; use implement, test, or review for those scopes. Brief the investigation goal and constraints, not step-by-step tool semantics.",
30629
30790
  inputSchema: {
30630
30791
  type: "object",
30631
30792
  required: ["prompt"],
@@ -30637,7 +30798,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30637
30798
  },
30638
30799
  model: {
30639
30800
  type: "string",
30640
- description: "Optional Copilot catalog model id (defaults to gpt-5.4-mini). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
30801
+ description: "Optional Copilot catalog model id (defaults to claude-sonnet-5). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
30641
30802
  },
30642
30803
  thinking: {
30643
30804
  type: "string",
@@ -30649,7 +30810,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30649
30810
  "high",
30650
30811
  "xhigh"
30651
30812
  ],
30652
- description: "Optional reasoning depth (default high). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
30813
+ description: "Optional reasoning depth (default xhigh). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
30653
30814
  },
30654
30815
  workspace: {
30655
30816
  type: "string",
@@ -30673,7 +30834,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30673
30834
  toolNameHttp: "implement",
30674
30835
  group: "workers",
30675
30836
  capability: "worker",
30676
- description: "Runs as the background `worker-implement` agent. Dispatch via the Agent tool (subagent_type: worker-implement) so your turn is never blocked; the result arrives as a completion notification. Delegates a scoped coding task to an autonomous worker (Pi runtime; default model `gpt-5.5` at xhigh reasoning, override via the `model` arg with any Copilot-catalog model that advertises `tool_calls`). Tools: the explore read-only set (read, glob, grep, code_search, web_search, fetch_url, advisor, update_plan, toolbelt) plus edit, write, bash, and codex_review (code review by codex-reviewer / gpt-5.3-codex). The worker's system prompt sandboxes it and gives one-line descriptions of each tool, so brief it on the task, not on tool semantics. With `worktree: false` (default) edits in place concurrent worker_implement calls and Claude's own edits to the same files will race. With `worktree: true` runs in an isolated git worktree and returns the diff for review. HARD ERROR if true and the workspace is not a git repository.",
30837
+ description: "Runs as the background `worker-implement` agent. Dispatch via the Agent tool (subagent_type: worker-implement) so the turn is never blocked; the result arrives as a completion notification. Delegates a scoped coding task to an autonomous worker (Pi runtime; default model `gpt-5.6-sol` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the explore read-only tools plus edit, write, bash, and codex_review, and it returns its final text with any changed files or worktree diff. Use for bounded implementation work that may take a while or benefits from isolated worker context. Not for pure research, planning, review, or independent test authoring; use explore, plan, review, or test for those scopes. With `worktree: false` (default) edits happen in place, so concurrent implement calls and lead edits to the same files can race. With `worktree: true` it runs in an isolated git worktree and returns the diff; this errors if the workspace is not a git repository.",
30677
30838
  inputSchema: {
30678
30839
  type: "object",
30679
30840
  required: ["prompt"],
@@ -30685,11 +30846,11 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30685
30846
  },
30686
30847
  worktree: {
30687
30848
  type: "boolean",
30688
- description: "When true, run inside a fresh git worktree and return Pi's final text followed by the unified diff (so the lead can review before merging). When false/omitted, edits the workspace in place concurrent worker calls and Claude's own edits will race. HARD ERROR if true and the workspace is not a git repository."
30849
+ description: "When true, run inside a fresh git worktree and return Pi's final text followed by the unified diff (so the lead can review before merging). When false/omitted, edits the workspace in place, so concurrent worker calls and lead edits can race. Errors if true and the workspace is not a git repository."
30689
30850
  },
30690
30851
  model: {
30691
30852
  type: "string",
30692
- description: "Optional Copilot catalog model id (defaults to gpt-5.5). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
30853
+ description: "Optional Copilot catalog model id (defaults to gpt-5.6-sol). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
30693
30854
  },
30694
30855
  thinking: {
30695
30856
  type: "string",
@@ -30725,7 +30886,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30725
30886
  toolNameHttp: "review",
30726
30887
  group: "workers",
30727
30888
  capability: "worker",
30728
- description: "Runs as the background `worker-review` agent. Dispatch via the Agent tool (subagent_type: worker-review) so your turn is never blocked; the result arrives as a completion notification. Read-only code review by an autonomous worker (Pi runtime; default model `gpt-5.5` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). Same read-only toolset as `explore` (read, glob, grep, code_search, web_search, fetch_url, advisor, update_plan, toolbelt) — it CANNOT edit — but the worker is framed as a reviewer: it verifies correctness against the actual code itself rather than trusting a claim, and reports findings (bugs, edge cases, security / concurrency / resource risks, missing handling) with a severity and `file:line`. Brief it with the change / diff / claim to verify (paste it, or name the files) it reads the code to confirm, so you get a self-verifying second opinion that doesn't depend on you having pre-extracted the relevant code. Unlike the `peers` critics (single stateless model calls on the artifact you paste), this worker can navigate the repo to check surrounding context for itself.",
30889
+ description: "Runs as the background `worker-review` agent. Dispatch via the Agent tool (subagent_type: worker-review) so the turn is never blocked; the result arrives as a completion notification. Read-only code review by an autonomous worker (Pi runtime; default model `gemini-3.1-pro-preview`, default thinking xhigh clamped to high for that model, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read-only toolset as explore and verifies claims against surrounding repository context before returning severity-ranked findings with `file:line` citations. Use for reviewing a change, diff, or correctness claim when the reviewer should read the code itself rather than trusting a pasted artifact. Not for architecture critique, implementation, or test authoring; use codex_critic or gemini_critic for design review, implement for edits, and test for independent test creation.",
30729
30890
  inputSchema: {
30730
30891
  type: "object",
30731
30892
  required: ["prompt"],
@@ -30737,7 +30898,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30737
30898
  },
30738
30899
  model: {
30739
30900
  type: "string",
30740
- description: "Optional Copilot catalog model id (defaults to gpt-5.5). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
30901
+ description: "Optional Copilot catalog model id (defaults to gemini-3.1-pro-preview). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
30741
30902
  },
30742
30903
  thinking: {
30743
30904
  type: "string",
@@ -30749,7 +30910,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30749
30910
  "high",
30750
30911
  "xhigh"
30751
30912
  ],
30752
- description: "Optional reasoning depth (default high). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
30913
+ description: "Optional reasoning depth (defaults to xhigh, clamped to high for the default review model). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
30753
30914
  },
30754
30915
  workspace: {
30755
30916
  type: "string",
@@ -30773,7 +30934,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30773
30934
  toolNameHttp: "plan",
30774
30935
  group: "workers",
30775
30936
  capability: "worker",
30776
- description: "Runs as the background `worker-plan` agent. Dispatch via the Agent tool (subagent_type: worker-plan) so your turn is never blocked; the result arrives as a completion notification. Read-only implementation planning by an autonomous worker (Pi runtime; default model `claude-opus-4.8`, override via `model` with any Copilot-catalog model that advertises `tool_calls`). Same read-only toolset as `explore` (read, glob, grep, code_search, web_search, fetch_url, advisor, update_plan, toolbelt) — it CANNOT edit — but the worker is framed as a planner: from the task and acceptance criteria it produces a concrete, ordered implementation plan (the files to change, the approach, the key risks, and how each acceptance criterion will be verified), grounded by reading the actual code. Brief it with the task and any acceptance criteria; it returns a single plan, not code.",
30937
+ description: "Runs as the background `worker-plan` agent. Dispatch via the Agent tool (subagent_type: worker-plan) so the turn is never blocked; the result arrives as a completion notification. Read-only implementation planning by an autonomous worker (Pi runtime; default model `claude-opus-4.8` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read-only toolset as explore and returns a concrete, ordered implementation plan covering files, approach, risks, and how acceptance criteria will be verified. Use before coding when the task needs repo-grounded sequencing or acceptance criteria translated into implementation steps. Not for editing files, running an implementation, writing tests, or adversarial review; use implement, test, or review for those scopes.",
30777
30938
  inputSchema: {
30778
30939
  type: "object",
30779
30940
  required: ["prompt"],
@@ -30797,7 +30958,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30797
30958
  "high",
30798
30959
  "xhigh"
30799
30960
  ],
30800
- description: "Optional reasoning depth (default high). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
30961
+ description: "Optional reasoning depth (default xhigh). Silently clamped to the model's allowed range; \"off\" drops the parameter entirely."
30801
30962
  },
30802
30963
  workspace: {
30803
30964
  type: "string",
@@ -30821,7 +30982,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30821
30982
  toolNameHttp: "test",
30822
30983
  group: "workers",
30823
30984
  capability: "worker",
30824
- description: "Runs as the background `worker-test` agent. Dispatch via the Agent tool (subagent_type: worker-test) so your turn is never blocked; the result arrives as a completion notification. Independent adversarial test authoring by an autonomous worker (Pi runtime; default model `gpt-5.5` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). Same read+write toolset as `implement` (the explore set plus edit, write, bash, codex_review). The worker is framed as an INDEPENDENT test author that did NOT write the code under test: from the task and acceptance criteria it writes tests that try to BREAK the implementation (edge cases, error paths, the acceptance criteria as executable checks), runs them, and reports which pass and fail it does NOT modify the implementation to make tests pass. With `worktree: true` runs in an isolated git worktree and returns the diff; HARD ERROR if true and the workspace is not a git repository.",
30985
+ description: "Runs as the background `worker-test` agent. Dispatch via the Agent tool (subagent_type: worker-test) so the turn is never blocked; the result arrives as a completion notification. Independent adversarial test authoring by an autonomous worker (Pi runtime; default model `gpt-5.6-sol` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read/write toolset as implement and writes tests that try to break the implementation through edge cases, error paths, and acceptance criteria, then runs them and reports pass/fail. Use when a separate test author should challenge an implementation without modifying the production code to make tests pass. Not for implementing fixes, broad research, or code review; use implement, explore, or review for those scopes. With `worktree: true` it runs in an isolated git worktree and returns the test diff; this errors if the workspace is not a git repository.",
30825
30986
  inputSchema: {
30826
30987
  type: "object",
30827
30988
  required: ["prompt"],
@@ -30833,11 +30994,11 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30833
30994
  },
30834
30995
  worktree: {
30835
30996
  type: "boolean",
30836
- description: "When true, run inside a fresh git worktree and return Pi's final text followed by the unified diff (so the lead can review the authored tests before merging). When false/omitted, writes tests in place concurrent worker calls and Claude's own edits will race. HARD ERROR if true and the workspace is not a git repository."
30997
+ description: "When true, run inside a fresh git worktree and return Pi's final text followed by the unified diff (so the lead can review the authored tests before merging). When false/omitted, writes tests in place, so concurrent worker calls and lead edits can race. Errors if true and the workspace is not a git repository."
30837
30998
  },
30838
30999
  model: {
30839
31000
  type: "string",
30840
- description: "Optional Copilot catalog model id (defaults to gpt-5.5). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
31001
+ description: "Optional Copilot catalog model id (defaults to gpt-5.6-sol). Must advertise tool_calls support; the engine emits an isError envelope listing the eligible catalog models on mismatch."
30841
31002
  },
30842
31003
  thinking: {
30843
31004
  type: "string",
@@ -30872,7 +31033,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30872
31033
  {
30873
31034
  toolNameHttp: "verify_workflow",
30874
31035
  group: "orchestrate",
30875
- description: "Statically verify a workflow IR against the orchestration floor invariants BEFORE running it. Input `ir`: the typed WorkflowIR (rawAskHash, acceptanceCriteriaHash, nodes[] with role/inputs/gate/onFail, maxDepth). Returns {ok, violations:[{code, message, nodeId?}]}. Each violation carries a stable code (e.g. NO_BASELINE, SELECTOR_NOT_RAW_ASK, SAME_LAB_CHECK, ORPHAN_NODE, MISSING_INTEGRATION_GATE) fix every one until `ok` is true. WHY: a workflow's floor guarantee (deliver max(orchestrated, baseline), producer != checker, cross-lab checks, sealed gates) is only as good as the IR's structure; a probabilistically-composed IR can silently violate it. This is the cheap, pure, side-effect-free pre-flight that catches those violations with actionable codes so you self-correct BEFORE paying for execution. Call it right after composing/decomposing a workflow.",
31036
+ description: "Statically verifies a workflow IR against the orchestration floor invariants before the kernel runs it. It accepts the typed WorkflowIR as `ir` and an optional `knownGateIds` allowlist, then returns {ok, violations:[{code, message, nodeId?}]} with stable violation codes such as NO_BASELINE, SELECTOR_NOT_RAW_ASK, SAME_LAB_CHECK, ORPHAN_NODE, or MISSING_INTEGRATION_GATE. Use immediately after composing or receiving a workflow IR, especially before paying for run_workflow, so structural floor failures can be fixed while still in data form. Not a runner, model reviewer, or proof that the user's spec is correct; use run_workflow to execute sealed gates and use critic/review tools for advisory review.",
30876
31037
  inputSchema: {
30877
31038
  type: "object",
30878
31039
  required: ["ir"],
@@ -30902,7 +31063,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30902
31063
  toolNameHttp: "decompose",
30903
31064
  group: "orchestrate",
30904
31065
  capability: "worker",
30905
- description: "Compose a VERIFIED, tool-routed workflow IR from an open-ended software ask. A single strong driver model drafts a typed WorkflowIR; a static verifier checks it against the floor invariants and the driver re-drafts on any violation; a cross-lab critic reviews a clean draft. Returns {ok, ir, rounds, concerns?} on success, or {ok:false, violations, rounds} if it never converged. WHY: a single model anchors on its own framing of a task (the decompose step is itself a single point of failure), so the driver is decorrelated by a cross-lab critic, and the output is a typed IR a verifier/kernel enforce in CODE rather than prose the model could quietly violate. The IR is DATA you then pass to run_workflow (or re-check with verify_workflow). Reach for it on non-trivial, role-separated asks where blind-spot reduction pays off; a trivial ask does not need it.",
31066
+ description: "Composes a verified, tool-routed WorkflowIR from an open-ended software ask. A strong driver model drafts the IR, the static verifier checks floor invariants, the driver re-drafts on violations, and a cross-lab critic reviews a clean draft; optional `context` supplies repo facts, constraints, or research findings to the driver. It returns {ok, ir, rounds, concerns?} on success, or {ok:false, violations, rounds} when it cannot converge. Use for non-trivial, role-separated asks where blind-spot reduction and sealed-gate structure justify orchestration. Not for trivial edits, direct implementation, or execution; use implement for a scoped code change and run_workflow only after the IR is verified.",
30906
31067
  inputSchema: {
30907
31068
  type: "object",
30908
31069
  required: ["ask"],
@@ -30935,7 +31096,10 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30935
31096
  effort: "high"
30936
31097
  },
30937
31098
  signal
30938
- }), { maxRounds: 3 });
31099
+ }), {
31100
+ maxRounds: 3,
31101
+ context: typeof args.context === "string" ? args.context : void 0
31102
+ });
30939
31103
  return {
30940
31104
  content: [{
30941
31105
  type: "text",
@@ -30949,7 +31113,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
30949
31113
  toolNameHttp: "run_workflow",
30950
31114
  group: "orchestrate",
30951
31115
  capability: "worker",
30952
- description: "Execute a VERIFIED workflow IR (from decompose / verify_workflow) through the frozen orchestration kernel. The kernel runs the single-model BASELINE plus the orchestrated DAG, gates every producer over a SEALED executable gate you name by `gateId` (the kernel owns the command; the IR cannot author it), and delivers max(orchestrated, baseline) by champion-retention: the orchestrated result ships only if it verifiably does not regress the baseline's executable checks, else the baseline ships. Returns {ok, outcome:{status, winner?, artifact?, reason, gatesPassed?}}. WHY: orchestration is a conditional bet (it helps on blind-spot/ambiguous asks, backfires on others), so the kernel NEVER ships something worse than a plain single-model run on the same ask. It enforces the floor in code (the model can't be trusted to honor it): a parallel baseline, a sealed executable gate as the selector, fail-to-baseline on any infra failure. Use after decompose for non-trivial asks on a harness-bearing repo.",
31116
+ description: "Executes a verified WorkflowIR through the frozen orchestration kernel. The kernel runs a single-model baseline beside the orchestrated DAG, gates producers over the sealed executable `gateId` selected by the caller, and returns {ok, outcome:{status, winner?, artifact?, reason, gatesPassed?}}. It uses champion retention: the orchestrated candidate wins only when it does not regress the baseline's executable checks; otherwise the baseline ships. Use after decompose and verify_workflow for non-trivial asks in a git workspace with a meaningful sealed gate. Not for composing an IR, performing advisory review, or running arbitrary model-authored shell commands; use decompose or verify_workflow before this tool, and use ordinary tests or review tools outside the workflow kernel.",
30953
31117
  inputSchema: {
30954
31118
  type: "object",
30955
31119
  required: [
@@ -31014,7 +31178,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
31014
31178
  {
31015
31179
  toolNameHttp: "attest_step",
31016
31180
  group: "orchestrate",
31017
- description: "Attest (audit) that an orchestrated run actually honored bias isolation: every producer node was checked by a DIFFERENT lab, and that check covered the producer's FINAL artifact (matched by content hash, so a check of a stale earlier version does not count). Input `nodes`: [{id, producerLab, artifactHash, checks:[{checkerLab, verifiedArtifactHash}]}]. Returns {attested, recommendation: 'accept'|'ship_baseline', nodes:[{id, attested, reason}]}. WHY: run_workflow's frozen kernel is the TAMPER-PROOF path (it controls the artifacts and computes the hashes). attest_step is for workflows you compose OUTSIDE the kernel: it deterministically checks your SELF-REPORTED lineage is structurally sound (a different-lab check whose hash equals each producer's final-artifact hash), catching the non-malicious failures (a missing / same-lab / stale check). It verifies consistency, NOT that the hashes are real a completeness gate, not a security boundary. Fail-closed: anything short of a valid different-lab check on EVERY node recommends shipping the baseline. It RECOMMENDS; it never executes.",
31181
+ description: "Audits self-reported producer lineage for bias-isolation structure. It accepts `nodes` with each producer lab, final artifact hash, and checker hashes, then returns {attested, recommendation:'accept'|'ship_baseline', nodes:[{id, attested, reason}]}. The check passes only when every producer has a different-lab check over the same final artifact hash, so missing, same-lab, or stale checks fail closed to a baseline recommendation. Use for workflows composed outside run_workflow, where lineage is self-reported and needs a deterministic completeness gate. Not a security boundary, hash authenticator, or executor; run_workflow is the kernel-owned path when the router must control artifacts, gates, and hashes.",
31018
31182
  inputSchema: {
31019
31183
  type: "object",
31020
31184
  required: ["nodes"],
@@ -31072,7 +31236,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
31072
31236
  toolNameHttp: "browse",
31073
31237
  group: "workers",
31074
31238
  capability: "browse_agent",
31075
- description: "Runs as the background `worker-browse` agent. Dispatch via the Agent tool (subagent_type: worker-browse) so your turn is never blocked; the result arrives as a completion notification. A Pi-driven autonomous browser agent (gpt-5.4-mini) that drives a real browser to accomplish `task` and returns the result. Runs in its own context to preserve the lead's window (raw DOM / page snapshots stay inside the agent). Pass `sessionId` to continue a prior session (its id is returned appended to the result as `[browse session: <id>]`); omit it for a fresh isolated session. Multiple concurrent calls run as parallel sessions on the one shared browser. Examples: \"find the cheapest flight LHR-JFK next Tuesday\", \"log into the dashboard and read the current MRR\", \"summarize the top 3 HN front-page stories\".",
31239
+ description: "Runs as the background `worker-browse` agent. Dispatch via the Agent tool (subagent_type: worker-browse) so the turn is never blocked; the result arrives as a completion notification. A Pi-driven autonomous browser worker (default model `gpt-5.4-mini`) drives a real browser to accomplish `task`, keeps raw DOM and page snapshots inside its own context, and returns a single text result. Use for delegated multi-step web tasks such as comparing prices, logging into a dashboard, or summarizing pages when the lead does not need to steer each click. Not for direct in-context browser control, screenshots, or precise element interactions; use the `browser` MCP tools for those. Pass `sessionId` to continue a prior browse session, or omit it for a fresh isolated session; multiple calls run as parallel sessions on the shared browser.",
31076
31240
  inputSchema: {
31077
31241
  type: "object",
31078
31242
  required: ["task"],
@@ -31100,7 +31264,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
31100
31264
  toolNameHttp: "stand_in",
31101
31265
  group: "decide",
31102
31266
  capability: "stand_in",
31103
- description: "**Away-mode decision tiebreak.** Three-lab advisor (gpt-5.5 xhigh, opus-4.7 xhigh, gemini-3.1-pro high) for **when the user is unavailable and you are stuck between two or more concrete options**. Polls all three across two structured rounds (blind vote informed re-vote with peer reasoning visible) and returns a ranked-choice verdict. Use when: you would otherwise halt and wait for the user. Do NOT use for: code review (use `peer-review-coordinator`), open-ended exploration, single-model second opinions (use `codex_critic` / `gemini_critic` / `opus_critic` directly), or as a substitute for user confirmation on irreversible actions (push, delete, drop, deploy those still require the user even with three-lab consensus).",
31267
+ description: "Three-lab away-mode decision tiebreak advisor for moments when the user is unavailable and the agent is stuck between two or more concrete options. It polls gpt-5.6-sol, Opus 4.7, and gemini-3.1-pro-preview across blind and informed voting rounds, then returns a ranked-choice verdict such as consensus, majority, no_consensus, or need_more_info. Use when work would otherwise halt on a bounded choice the user would normally make. Not for code review, open-ended exploration, single-model second opinions, or bypassing confirmation on irreversible actions such as push, delete, drop, or deploy; use peer-review-coordinator or the individual critics for review and still ask the user for destructive actions.",
31104
31268
  inputSchema: {
31105
31269
  type: "object",
31106
31270
  required: ["decision", "options"],
@@ -31189,7 +31353,7 @@ function assertMcpToolSurfaceConsistent() {
31189
31353
  * accessibility) and never throws — its `{text, isError?}` envelope
31190
31354
  * is forwarded verbatim into the MCP `tool result` shape.
31191
31355
  *
31192
- * Arg-validation policy mirrors `web_search`'s pattern: shape errors
31356
+ * Arg-validation policy mirrors `web`'s pattern: shape errors
31193
31357
  * surface as `isError: true` tool-result envelopes (NOT JSON-RPC -32602
31194
31358
  * errors). The MCP `tools/list` JSON schema already documents the
31195
31359
  * required/optional fields; this runtime check is defense against a
@@ -31396,7 +31560,7 @@ async function runBrowseToolCall(args, signal) {
31396
31560
  * failures, abstains) all surface inside the structured `StandInResult`
31397
31561
  * envelope, which we JSON-stringify into the single MCP text block.
31398
31562
  *
31399
- * Arg-validation policy mirrors `runWorkerToolCall` and `web_search`:
31563
+ * Arg-validation policy mirrors `runWorkerToolCall` and `web`:
31400
31564
  * shape errors surface as `isError: true` tool-result envelopes (NOT
31401
31565
  * JSON-RPC -32602). The `tools/list` JSON schema documents required
31402
31566
  * fields; this runtime check is defense against a schema-ignoring
@@ -31494,5 +31658,5 @@ async function runStandInToolCall(args, signal) {
31494
31658
  }
31495
31659
 
31496
31660
  //#endregion
31497
- export { buildAnthropicErrorEvent as $, resolveCodexModel as $t, liveExec as A, shouldUseInsecureTls as At, availableToolCommands as B, generateRandomPort as Bt, isSubagentContext as C, readResponseBodyCapped as Ct, stopReviewStateDir as D, provisionAndIndexColbert as Dt, stopGateEnabledForRepo as E, hasSupportedBrowserInstalled as Et, PLAN_DEFAULT_MODEL as F, DEFAULT_CODEX_MODEL as Ft, TOOLBELT_TOOLS$1 as G, setupGitHubAgentToken as Gt, toolbeltEnabled as H, getPackageVersion as Ht, REVIEW_DEFAULT_MODEL as I, DEFAULT_CODEX_MODEL_FALLBACKS as It, ADVISOR_INTERNAL_TOOL_NAME as J, cacheCopilotVersion as Jt, assetFor as K, setupGitHubToken as Kt, appendPlanReminder as L, DEFAULT_PORT as Lt, DEFAULT_MODEL as M, collapsePathKeys as Mt, EXPLORE_DEFAULT_MODEL as N, toolbeltPathOverride as Nt, trustRepo as O, extractTarGzMember as Ot, IMPLEMENT_DEFAULT_MODEL as P, DEFAULT_CLAUDE_MODEL_FALLBACKS as Pt, isAdvisorRequested as Q, isNullish as Qt, runWorkerAgent as R, UPSTREAM_FETCH_TIMEOUT_MS as Rt, fileReviewDebounce as S, MAX_RESPONSE_BODY_BYTES as St, repoRoot as T, provisionBrowserAssets as Tt, toolbeltSkipSet as U, withInstallLock as Ut, buildToolbeltAwareness as V, pickClaudeDefault as Vt, vscodeRipgrepPath as W, setupCopilotToken as Wt, buildAdvisorStream as X, cacheVSCodeVersion as Xt, ADVISOR_TOOL_INSTRUCTIONS as Y, cacheModels as Yt, injectAdvisorTool as Z, filterBetaHeader as Zt, stopGatePlanMode as _, assembleResponsesPayload as _t, buildPeerAwarenessSnippet as a, forwardError as an, handleMcpDelete as at, fileFindingsStore as b, createResponses as bt, buildSessionBindHookCommand as c, copilotHeaders as cn, browseAgentEnabled as ct, decideStopHook as d, implementerSubagentModel as dt, resolveModel as en, buildOpenAIErrorEvent as et, fileBlockBudget as f, standInToolEnabled as ft, stopGateId as g, getTokenCount as gt, stopGateDisabled as h, createMessages as ht, buildAgentPrompt as i, HTTPError as in, relayAnthropicStream as it, BROWSE_DEFAULT_MODEL as j, ArtifactClient as jt, resolveSealedGate as k, extractZipMember as kt, buildStopHookCommand as l, githubHeaders as ln, browserToolsEnabled as lt, launchBaselineKey as m, countTokens as mt, MCP_GROUPS as n, getModels as nn, logStreamError as nt, personasFor as o, GITHUB_API_BASE_URL as on, handleMcpPost as ot, injectStopHookIntoSettingsFile as p, workerToolsEnabled as pt, searchWeb as q, tryRefreshAndRetry as qt, assertMcpToolSurfaceConsistent as r, fetchWithTransientRetry as rn, readIteratorWithTimeout as rt, buildArtifactOpenHookCommand as s, copilotBaseUrl as sn, agentToolsEnabled as st, GROUP_META as t, sleep as tn, isControllerClosedError as tt, captureLaunchBaseline as u, state as un, fleetToolsEnabled as ut, stopReviewEnabled as v, resolveMcpToolTimeoutMs as vt, repoFingerprint as w, parseJsonOrDiagnose as wt, fileLastPromptStore as x, createChatCompletions as xt, fileBaselineStore as y, pickEndpoint as yt, withNoOutputRetry as z, UPSTREAM_INACTIVITY_TIMEOUT_MS as zt };
31498
- //# sourceMappingURL=peer-mcp-personas-D826LsJJ.js.map
31661
+ export { isAdvisorRequested as $, cacheModels as $t, liveExec as A, hasSupportedBrowserInstalled as At, withNoOutputRetry as B, DEFAULT_CODEX_MODEL_FALLBACKS as Bt, fileReviewDebounce as C, pickEndpoint as Ct, stopGateEnabledForRepo as D, readResponseBodyCapped as Dt, repoRoot as E, MAX_RESPONSE_BODY_BYTES as Et, IMPLEMENT_DEFAULT_MODEL as F, ArtifactClient as Ft, vscodeRipgrepPath as G, pickClaudeDefault as Gt, buildToolbeltAwareness as H, UPSTREAM_FETCH_TIMEOUT_MS as Ht, PLAN_DEFAULT_MODEL as I, collapsePathKeys as It, searchWeb as J, setupCopilotToken as Jt, TOOLBELT_TOOLS$1 as K, getPackageVersion as Kt, REVIEW_DEFAULT_MODEL as L, toolbeltPathOverride as Lt, BROWSE_DEFAULT_MODEL as M, extractTarGzMember as Mt, DEFAULT_MODEL as N, extractZipMember as Nt, stopReviewStateDir as O, parseJsonOrDiagnose as Ot, EXPLORE_DEFAULT_MODEL as P, shouldUseInsecureTls as Pt, injectAdvisorTool as Q, cacheCopilotVersion as Qt, appendPlanReminder as R, DEFAULT_CLAUDE_MODEL_FALLBACKS as Rt, fileLastPromptStore as S, resolveMcpToolTimeoutMs as St, repoFingerprint as T, createChatCompletions as Tt, toolbeltEnabled as U, UPSTREAM_INACTIVITY_TIMEOUT_MS as Ut, availableToolCommands as V, DEFAULT_PORT as Vt, toolbeltSkipSet as W, generateRandomPort as Wt, ADVISOR_TOOL_INSTRUCTIONS as X, setupGitHubToken as Xt, ADVISOR_INTERNAL_TOOL_NAME as Y, setupGitHubAgentToken as Yt, buildAdvisorStream as Z, tryRefreshAndRetry as Zt, stopGateId as _, workerToolsEnabled as _t, buildPeerAwarenessSnippet as a, sleep as an, relayAnthropicStream as at, fileBaselineStore as b, getTokenCount as bt, buildArtifactOpenHookCommand as c, HTTPError as cn, agentToolsEnabled as ct, captureLaunchBaseline as d, copilotBaseUrl as dn, browserCompoundToolsEnabled as dt, cacheVSCodeVersion as en, buildAnthropicErrorEvent as et, decideStopHook as f, copilotHeaders as fn, browserToolsEnabled as ft, stopGateDisabled as g, standInToolEnabled as gt, launchBaselineKey as h, implementerSubagentModel as ht, buildAgentPrompt as i, resolveModel as in, readIteratorWithTimeout as it, resolveSealedGate as j, provisionAndIndexColbert as jt, trustRepo as k, provisionBrowserAssets as kt, buildSessionBindHookCommand as l, forwardError as ln, artifactToolsEnabled as lt, injectStopHookIntoSettingsFile as m, state as mn, geminiAvailable as mt, MCP_GROUPS as n, isNullish as nn, isControllerClosedError as nt, buildPeerAwarenessSummary as o, getModels as on, handleMcpDelete as ot, fileBlockBudget as p, githubHeaders as pn, fleetToolsEnabled as pt, assetFor as q, withInstallLock as qt, assertMcpToolSurfaceConsistent as r, resolveCodexModel as rn, logStreamError as rt, personasFor as s, fetchWithTransientRetry as sn, handleMcpPost as st, GROUP_META as t, filterBetaHeader as tn, buildOpenAIErrorEvent as tt, buildStopHookCommand as u, GITHUB_API_BASE_URL as un, browseAgentEnabled as ut, stopGatePlanMode as v, countTokens as vt, isSubagentContext as w, createResponses as wt, fileFindingsStore as x, assembleResponsesPayload as xt, stopReviewEnabled as y, createMessages as yt, runWorkerAgent as z, DEFAULT_CODEX_MODEL as zt };
31662
+ //# sourceMappingURL=peer-mcp-personas-BKkdfOyK.js.map