@zixt/host 0.0.43 → 0.0.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1060 -295
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ import { homedir } from "node:os";
31
31
  // package.json
32
32
  var package_default = {
33
33
  name: "@zixt/host",
34
- version: "0.0.43",
34
+ version: "0.0.45",
35
35
  type: "module",
36
36
  exports: {
37
37
  ".": "./src/client.ts",
@@ -14648,7 +14648,17 @@ var ID_PREFIXES = {
14648
14648
  /** One file a person attached to a chat message ('att' is taken by attempt). */
14649
14649
  attachment: "atc",
14650
14650
  /** One curated memory entry an agent chose to keep ('mem' is taken by member). */
14651
- memory: "mry"
14651
+ memory: "mry",
14652
+ /** Org-singleton Manager configuration (PRD §8.13). */
14653
+ manager: "mgr",
14654
+ /** One Manager conversation thread (MG-2). */
14655
+ conversation: "cnv",
14656
+ /** One immutable Conversation timeline entry. */
14657
+ conversationEvent: "cve",
14658
+ /** One Manager inference call's token-metering row (MG-8). */
14659
+ managerUsage: "mgu",
14660
+ /** One ordered Manager reply awaiting Slack delivery. */
14661
+ managerSlackOutbox: "mso"
14652
14662
  };
14653
14663
  var idPattern = (prefix) => new RegExp(`^${prefix}_[0-9a-f]{32}$`);
14654
14664
  function newId(prefix) {
@@ -14671,6 +14681,9 @@ var OrgRoutineId = idSchema(ID_PREFIXES.orgRoutine, "organization routine id");
14671
14681
  var BrowserSessionId = idSchema(ID_PREFIXES.browserSession, "browser session id");
14672
14682
  var AttachmentId = idSchema(ID_PREFIXES.attachment, "attachment id");
14673
14683
  var MemoryId = idSchema(ID_PREFIXES.memory, "memory id");
14684
+ var ManagerId = idSchema(ID_PREFIXES.manager, "manager id");
14685
+ var ConversationId = idSchema(ID_PREFIXES.conversation, "conversation id");
14686
+ var ConversationEventId = idSchema(ID_PREFIXES.conversationEvent, "conversation event id");
14674
14687
 
14675
14688
  // ../../packages/contracts/src/browser.ts
14676
14689
  var BrowserViewport = external_exports.object({
@@ -14775,15 +14788,24 @@ var WebLoginValue = external_exports.object({
14775
14788
  username: external_exports.string().min(1).max(500),
14776
14789
  password: external_exports.string().min(1).max(5e3)
14777
14790
  }).strict();
14791
+ var BrowserProfileContext = external_exports.object({
14792
+ taskMachineName: external_exports.string().min(1).max(120),
14793
+ savedProfileMachineName: external_exports.string().min(1).max(120)
14794
+ }).strict();
14778
14795
  var BrowserSessionProjection = external_exports.object({
14779
14796
  status: external_exports.enum(["none", "starting", "live"]),
14780
14797
  session: BrowserSessionState.optional(),
14781
14798
  /** Whether Start would find an online Machine with a working browser. */
14782
14799
  canStart: external_exports.boolean(),
14783
14800
  /** Member-safe reason when canStart is false. */
14784
- reason: external_exports.string().max(300).optional()
14801
+ reason: external_exports.string().max(300).optional(),
14802
+ /** Present only when active work must use a different Machine-local profile. */
14803
+ profileContext: BrowserProfileContext.optional()
14804
+ }).strict();
14805
+ var StartBrowserSessionResponse = external_exports.object({
14806
+ session: BrowserSessionState,
14807
+ profileContext: BrowserProfileContext.optional()
14785
14808
  }).strict();
14786
- var StartBrowserSessionResponse = external_exports.object({ session: BrowserSessionState }).strict();
14787
14809
  var StopBrowserSessionResponse = external_exports.object({ stopped: external_exports.boolean() }).strict();
14788
14810
  var BrowserViewTicketResponse = external_exports.object({ ticket: external_exports.string().min(1).max(200) }).strict();
14789
14811
 
@@ -14807,6 +14829,7 @@ var ACTION_CATEGORIES = [
14807
14829
  "records.modify",
14808
14830
  "records.delete",
14809
14831
  "docker",
14832
+ "browser.use",
14810
14833
  "mcp.call",
14811
14834
  "spend_money"
14812
14835
  ];
@@ -14845,6 +14868,7 @@ var DEFAULT_GUARDRAIL_POLICY = {
14845
14868
  "records.modify": "allow",
14846
14869
  "records.delete": "allow",
14847
14870
  docker: "allow",
14871
+ "browser.use": "allow",
14848
14872
  "mcp.call": "allow",
14849
14873
  spend_money: "allow"
14850
14874
  };
@@ -14853,7 +14877,7 @@ var ApprovalDeliveryStatus = external_exports.enum(["pending", "delivered", "no_
14853
14877
  var ApprovalCategory = external_exports.union([ActionCategory, external_exports.literal("agent.question")]);
14854
14878
  var ApprovalRequestContext = external_exports.object({
14855
14879
  requester: external_exports.object({
14856
- source: external_exports.enum(["manual", "webhook", "message", "schedule", "agent", "handoff"]).nullable(),
14880
+ source: external_exports.enum(["manual", "webhook", "message", "schedule", "agent", "handoff", "manager"]).nullable(),
14857
14881
  trust: external_exports.enum(["internal", "external"]).nullable(),
14858
14882
  contentTrust: PromptContentTrust.nullable(),
14859
14883
  requestedBy: external_exports.string().min(1).nullable(),
@@ -15306,6 +15330,16 @@ var Agent = external_exports.object({
15306
15330
  orgId: OrgId,
15307
15331
  name: external_exports.string().min(1).max(120),
15308
15332
  status: AgentStatus,
15333
+ /**
15334
+ * Archive has fenced new work but is still waiting for one or more exact
15335
+ * Machines to acknowledge deletion of saved website sessions. `archived`
15336
+ * is exposed only after this becomes null.
15337
+ */
15338
+ profileCleanup: external_exports.object({
15339
+ state: external_exports.literal("pending"),
15340
+ remainingProfiles: external_exports.number().int().min(1),
15341
+ intent: external_exports.enum(["archive", "restore"])
15342
+ }).strict().nullable().default(null),
15309
15343
  roleDescription: external_exports.string().max(2e3).default(""),
15310
15344
  /** Persona instructions — system-prompt-like free text (AG-1). */
15311
15345
  instructions: external_exports.string().max(5e4).default(""),
@@ -15481,6 +15515,11 @@ var Host = external_exports.object({
15481
15515
  status: HostStatus,
15482
15516
  /** Persistent assignment admission; pausing never changes socket presence or live work. */
15483
15517
  acceptingNewWork: external_exports.boolean().default(true),
15518
+ /**
15519
+ * Removal is fenced but the Machine remains paired solely so an offline
15520
+ * Host can reconnect and delete its saved browser profiles truthfully.
15521
+ */
15522
+ profileCleanup: external_exports.object({ state: external_exports.literal("pending"), remainingProfiles: external_exports.number().int().min(1) }).strict().nullable().default(null),
15484
15523
  /** `desktop` today; `cloud` when pods run the same host (PRD §7.6). */
15485
15524
  kind: external_exports.enum(["desktop", "cloud"]),
15486
15525
  lastSeenAt: IsoDate2.nullable(),
@@ -15801,7 +15840,7 @@ var TaskAttemptExecutionContext = external_exports.object({
15801
15840
  identity: external_exports.object({
15802
15841
  actingAgentId: AgentId,
15803
15842
  source: external_exports.object({
15804
- source: external_exports.enum(["manual", "webhook", "message", "schedule", "agent", "handoff"]),
15843
+ source: external_exports.enum(["manual", "webhook", "message", "schedule", "agent", "handoff", "manager"]),
15805
15844
  trust: external_exports.enum(["internal", "external"]),
15806
15845
  /** Current attempt prompt authority; absent only on pre-TS-10 snapshots. */
15807
15846
  contentTrust: PromptContentTrust.optional(),
@@ -15830,7 +15869,7 @@ var MemberTaskAttemptExecutionContext = TaskAttemptExecutionContext.omit({
15830
15869
  identity: external_exports.object({
15831
15870
  actingAgentId: AgentId,
15832
15871
  source: external_exports.object({
15833
- source: external_exports.enum(["manual", "webhook", "message", "schedule", "agent", "handoff"]),
15872
+ source: external_exports.enum(["manual", "webhook", "message", "schedule", "agent", "handoff", "manager"]),
15834
15873
  trust: external_exports.enum(["internal", "external"]),
15835
15874
  contentTrust: PromptContentTrust.optional(),
15836
15875
  requestedBy: external_exports.null(),
@@ -15915,7 +15954,8 @@ var TaskStatus = external_exports.enum([
15915
15954
  "cancelled"
15916
15955
  ]);
15917
15956
  var TaskOrigin = external_exports.object({
15918
- source: external_exports.enum(["manual", "webhook", "message", "schedule", "agent", "handoff"]),
15957
+ /** `manager` = delegated from a Manager Conversation (MG-4). */
15958
+ source: external_exports.enum(["manual", "webhook", "message", "schedule", "agent", "handoff", "manager"]),
15919
15959
  /** TS-10: external content is data, not instructions. */
15920
15960
  trust: external_exports.enum(["internal", "external"]),
15921
15961
  /** Member id, connector name, or agent id — whoever caused the task. */
@@ -15984,6 +16024,12 @@ var Task = external_exports.object({
15984
16024
  /** Higher runs first; FIFO within equal priority. */
15985
16025
  priority: external_exports.number().int().min(0).max(9),
15986
16026
  origin: TaskOrigin,
16027
+ /**
16028
+ * The Manager thread this Task was delegated from (MG-4); null for
16029
+ * engine-born work (webhook, schedule, provider). Lets task lists tell
16030
+ * thread-backed work from standalone rows without a second lookup.
16031
+ */
16032
+ conversationId: ConversationId.nullable().default(null),
15987
16033
  /** Formal human review is opt-in per Task; ordinary Chat defaults to none. */
15988
16034
  reviewMode: TaskReviewMode.default("none"),
15989
16035
  /** Assignment epoch — bumped every time the task is (re)assigned (PRD §7.4). */
@@ -15994,6 +16040,8 @@ var Task = external_exports.object({
15994
16040
  * its first Machine; assignment then records that choice for later runs.
15995
16041
  */
15996
16042
  requestedHostId: HostId.nullable().default(null),
16043
+ /** Browser-dependent work runs only on a Machine with fresh Browser capability. */
16044
+ requiresBrowser: external_exports.boolean().default(false),
15997
16045
  /** TS-16: per-Task runner/model/effort selection; null runs the teammate's configuration. */
15998
16046
  runner: TaskRunnerSelection.nullable().default(null),
15999
16047
  /**
@@ -16151,6 +16199,8 @@ var CreateTaskInput = external_exports.object({
16151
16199
  * another Machine truthfully queues this Task rather than overriding it.
16152
16200
  */
16153
16201
  requestedHostId: HostId.optional(),
16202
+ /** Require a fresh, working AI teammate Browser on the selected Machine. */
16203
+ requiresBrowser: external_exports.boolean().optional(),
16154
16204
  /** Per-Task runner/model/effort selection (TS-16); absent fields fall back to the teammate's configuration. */
16155
16205
  runner: TaskRunnerSelection.optional(),
16156
16206
  /** Files uploaded ahead of this message; each may belong to one Task only (TS-15). */
@@ -16452,12 +16502,15 @@ var TaskSupportBundle = external_exports.object({
16452
16502
  })
16453
16503
  )
16454
16504
  });
16505
+ var TASK_LIST_MAX_LIMIT = 200;
16455
16506
  var ListTasksResponse = external_exports.object({
16456
- tasks: external_exports.array(TaskProjection)
16457
- });
16507
+ tasks: external_exports.array(TaskProjection).max(TASK_LIST_MAX_LIMIT),
16508
+ nextCursor: external_exports.string().nullable()
16509
+ }).strict();
16458
16510
 
16459
16511
  // ../../packages/contracts/src/protocol.ts
16460
- var PROTOCOL_VERSION = 5;
16512
+ var PROTOCOL_VERSION = 7;
16513
+ var BROWSER_PROFILE_INVENTORY_PAGE_SIZE = 200;
16461
16514
  var TASK_CANCEL_ACK_EVENT = "zixt.task.cancel.acknowledged";
16462
16515
  var TASK_CREDENTIAL_ROLLOVER_ACK_EVENT = "zixt.task.credential_rollover.acknowledged";
16463
16516
  var UnwoundAssignmentRef = external_exports.object({
@@ -16735,6 +16788,11 @@ var AgentOp = external_exports.union([
16735
16788
  }),
16736
16789
  external_exports.object({ kind: external_exports.literal("secret.list") }),
16737
16790
  external_exports.object({ kind: external_exports.literal("agents.list") }),
16791
+ /** Speak to the organization Manager without addressing a human channel directly. */
16792
+ external_exports.object({
16793
+ kind: external_exports.literal("manager.message"),
16794
+ message: external_exports.string().min(1).max(5e4)
16795
+ }),
16738
16796
  /** Read one teammate's non-secret standing configuration; omission means self. */
16739
16797
  external_exports.object({ kind: external_exports.literal("agent.get"), agentId: AgentId.optional() }),
16740
16798
  /**
@@ -16935,6 +16993,12 @@ var TaskAssign = external_exports.object({
16935
16993
  type: external_exports.literal("task.assign"),
16936
16994
  taskId: TaskId,
16937
16995
  agentId: AgentId,
16996
+ /**
16997
+ * A current assignment is a trusted authorization to create a fresh
16998
+ * profile after an explicit restore. Missing legacy values never clear a
16999
+ * Host-side purge tombstone.
17000
+ */
17001
+ browserProfileRevision: external_exports.number().int().min(0).optional(),
16938
17002
  epoch: external_exports.number().int().min(1),
16939
17003
  /**
16940
17004
  * Host-enforced task authority deadline, when anything forces one.
@@ -16960,7 +17024,18 @@ var TaskAssign = external_exports.object({
16960
17024
  * so protocol-v5 outbox rows and hosts remain parseable during rollout;
16961
17025
  * current clouds always populate it for newly dispatched work.
16962
17026
  */
16963
- origin: TaskOrigin.pick({ source: true, trust: true }).extend({
17027
+ origin: TaskOrigin.pick({ trust: true }).extend({
17028
+ /**
17029
+ * Trigger classification, kept as a lenient string on the wire on
17030
+ * purpose. The Host uses it for a display label and telemetry only,
17031
+ * never for behavior, while the enum on the durable Task keeps its
17032
+ * closed meaning. Parsing it strictly here made adding one source
17033
+ * (`manager`) a breaking wire change: a Host built against the older
17034
+ * enum failed the whole frame union and dropped `task.assign`
17035
+ * silently, so the work sat Assigned forever with no diagnosis. An
17036
+ * unknown value now degrades to an unlabeled source instead.
17037
+ */
17038
+ source: external_exports.string().min(1).max(64),
16964
17039
  /** Cloud-verified provider source; never inferred from provider-authored text. */
16965
17040
  provider: ProviderKind.optional(),
16966
17041
  /**
@@ -17000,6 +17075,11 @@ var TaskAssign = external_exports.object({
17000
17075
  titleWanted: external_exports.boolean().optional(),
17001
17076
  /** Advisory Ask / Plan / Act snapshot for this attempt (TS-12). */
17002
17077
  interactionMode: InteractionMode.optional(),
17078
+ /**
17079
+ * Browser-dependent placement requirement (BR-7). Additive/optional so
17080
+ * persisted assignments from an older cloud remain parseable.
17081
+ */
17082
+ requiresBrowser: external_exports.boolean().optional(),
17003
17083
  /** Configured workspace selected by the cloud; absence means no repository context. */
17004
17084
  workspace: SafeDisplayPath.optional(),
17005
17085
  /** Verified provider repository selected independently of a local workspace path. */
@@ -17410,6 +17490,12 @@ var BrowserOpenFrame = external_exports.object({
17410
17490
  type: external_exports.literal("browser.open"),
17411
17491
  requestId: external_exports.string().min(1).max(200),
17412
17492
  agentId: AgentId,
17493
+ /**
17494
+ * Cloud-owned browser-profile lifecycle revision. A Host persists the last
17495
+ * purged revision and refuses a stale open, so a delayed frame cannot
17496
+ * recreate an archived teammate's website sessions after cleanup.
17497
+ */
17498
+ profileRevision: external_exports.number().int().min(0).optional(),
17413
17499
  /** Cloud-minted; the host adopts it for the session it opens. */
17414
17500
  browserSessionId: external_exports.string().min(1).max(200),
17415
17501
  viewport: BrowserViewport
@@ -17438,6 +17524,18 @@ var BrowserCommandFrame = external_exports.object({
17438
17524
  browserSessionId: external_exports.string().min(1).max(200),
17439
17525
  command: BrowserCommand
17440
17526
  });
17527
+ var BrowserProfilePurge = external_exports.object({
17528
+ type: external_exports.literal("browser.profile.purge"),
17529
+ purgeId: external_exports.uuid(),
17530
+ agentId: AgentId,
17531
+ profileRevision: external_exports.number().int().min(1)
17532
+ }).strict();
17533
+ var BrowserProfilePurged = external_exports.object({
17534
+ type: external_exports.literal("browser.profile.purged"),
17535
+ purgeId: external_exports.uuid(),
17536
+ agentId: AgentId,
17537
+ profileRevision: external_exports.number().int().min(1)
17538
+ }).strict();
17441
17539
  var TaskInput = external_exports.object({
17442
17540
  type: external_exports.literal("task.input"),
17443
17541
  taskId: TaskId,
@@ -17451,7 +17549,8 @@ var DurableDownMessage = external_exports.discriminatedUnion("type", [
17451
17549
  TaskInput,
17452
17550
  SecretsGrant,
17453
17551
  ApprovalDecision,
17454
- ConnectionsGrant
17552
+ ConnectionsGrant,
17553
+ BrowserProfilePurge
17455
17554
  ]);
17456
17555
  var TaskEvent = external_exports.object({
17457
17556
  type: external_exports.literal("task.event"),
@@ -17604,6 +17703,15 @@ var HelloFrame = external_exports.object({
17604
17703
  protocolVersion: external_exports.number().int(),
17605
17704
  /** Highest outbox seq the host has durably processed; cloud replays after it. */
17606
17705
  cursor: external_exports.number().int().min(0),
17706
+ /**
17707
+ * Bounded, path-validated persistent profile inventory from this Machine.
17708
+ * It migrates profiles created before cloud custody tracking existed.
17709
+ */
17710
+ browserProfileInventory: external_exports.object({
17711
+ agentIds: external_exports.array(AgentId).max(BROWSER_PROFILE_INVENTORY_PAGE_SIZE),
17712
+ /** False keeps conservative legacy migration fencing enabled. */
17713
+ complete: external_exports.boolean()
17714
+ }).strict().optional(),
17607
17715
  /**
17608
17716
  * Exact assignments whose local executors finished unwinding after the
17609
17717
  * prior socket died. Optional for rolling v5 hosts; repeated references are
@@ -17611,6 +17719,11 @@ var HelloFrame = external_exports.object({
17611
17719
  */
17612
17720
  unwoundAssignments: external_exports.array(UnwoundAssignmentRef).max(1e3).optional()
17613
17721
  });
17722
+ var BrowserProfileInventoryFrame = external_exports.object({
17723
+ type: external_exports.literal("browser.profile.inventory"),
17724
+ agentIds: external_exports.array(AgentId).max(BROWSER_PROFILE_INVENTORY_PAGE_SIZE),
17725
+ complete: external_exports.boolean()
17726
+ }).strict();
17614
17727
  var HelloAckFrame = external_exports.object({
17615
17728
  type: external_exports.literal("helloAck"),
17616
17729
  protocolVersion: external_exports.number().int(),
@@ -17693,6 +17806,7 @@ var PingFrame = external_exports.object({ type: external_exports.literal("ping")
17693
17806
  var PongFrame = external_exports.object({ type: external_exports.literal("pong"), at: external_exports.iso.datetime() });
17694
17807
  var HostToCloudFrame = external_exports.discriminatedUnion("type", [
17695
17808
  HelloFrame,
17809
+ BrowserProfileInventoryFrame,
17696
17810
  AckFrame,
17697
17811
  UpFrame,
17698
17812
  ProviderOperationGrantRequestFrame,
@@ -17700,6 +17814,7 @@ var HostToCloudFrame = external_exports.discriminatedUnion("type", [
17700
17814
  BrowserScreencastFrame,
17701
17815
  BrowserSessionEndedFrame,
17702
17816
  BrowserCredentialRequestFrame,
17817
+ BrowserProfilePurged,
17703
17818
  PingFrame,
17704
17819
  PongFrame
17705
17820
  ]);
@@ -18016,7 +18131,9 @@ var HostRemovalOutcome = external_exports.object({
18016
18131
  });
18017
18132
  var RevokeHostResponse = external_exports.object({
18018
18133
  host: AdminHostProjection,
18019
- removal: HostRemovalOutcome
18134
+ removal: HostRemovalOutcome,
18135
+ /** False while the paired Host is retained solely to finish profile deletion. */
18136
+ removed: external_exports.boolean()
18020
18137
  });
18021
18138
  var MemberHostProjection = Host.pick({
18022
18139
  id: true,
@@ -18025,6 +18142,7 @@ var MemberHostProjection = Host.pick({
18025
18142
  operatingSystem: true,
18026
18143
  status: true,
18027
18144
  acceptingNewWork: true,
18145
+ profileCleanup: true,
18028
18146
  kind: true,
18029
18147
  lastSeenAt: true,
18030
18148
  telemetryAt: true,
@@ -18553,6 +18671,235 @@ var LinearOAuthPopupMessage = external_exports.discriminatedUnion("ok", [
18553
18671
  LinearOAuthPopupFailure
18554
18672
  ]);
18555
18673
 
18674
+ // ../../packages/contracts/src/manager.ts
18675
+ var MANAGER_DISPLAY_NAME_MAX = 60;
18676
+ var MANAGER_INSTRUCTIONS_MAX = 2e4;
18677
+ var CONVERSATION_MESSAGE_MAX = 1e5;
18678
+ var CONVERSATION_LIST_LIMIT = 50;
18679
+ var ManagerReasoningEffort = external_exports.enum([
18680
+ "none",
18681
+ "minimal",
18682
+ "low",
18683
+ "medium",
18684
+ "high",
18685
+ "xhigh",
18686
+ "max"
18687
+ ]);
18688
+ var ManagerConfigProjection = external_exports.object({
18689
+ id: ManagerId,
18690
+ /** Shown in the UI and on chat channels; the persona carries the personality (MG-7). */
18691
+ displayName: external_exports.string().min(1).max(MANAGER_DISPLAY_NAME_MAX),
18692
+ /** Appended to the product-owned built-in system prompt; never replaces it. */
18693
+ instructions: external_exports.string().max(MANAGER_INSTRUCTIONS_MAX),
18694
+ model: external_exports.string().min(1).max(100),
18695
+ reasoningEffort: ManagerReasoningEffort,
18696
+ /**
18697
+ * Where the Manager answers on Slack. The workspace bot speaks for the
18698
+ * Manager (MG-1), so the per-teammate mention/DM switches that used to
18699
+ * decide this belong here now — an organization keeps a truthful off
18700
+ * switch for each surface without disconnecting the workspace.
18701
+ */
18702
+ slack: external_exports.object({ answerMentions: external_exports.boolean(), answerDirectMessages: external_exports.boolean() }).strict(),
18703
+ revision: external_exports.number().int().min(0),
18704
+ updatedAt: external_exports.string().nullable()
18705
+ }).strict();
18706
+ var ManagerMode = external_exports.enum(["openai", "demo", "unconfigured"]);
18707
+ var GetManagerResponse = external_exports.object({ manager: ManagerConfigProjection, mode: ManagerMode }).strict();
18708
+ var UpdateManagerRequest = external_exports.object({
18709
+ displayName: external_exports.string().min(1).max(MANAGER_DISPLAY_NAME_MAX).optional(),
18710
+ instructions: external_exports.string().max(MANAGER_INSTRUCTIONS_MAX).optional(),
18711
+ model: external_exports.string().min(1).max(100).optional(),
18712
+ reasoningEffort: ManagerReasoningEffort.optional(),
18713
+ slack: external_exports.object({
18714
+ answerMentions: external_exports.boolean().optional(),
18715
+ answerDirectMessages: external_exports.boolean().optional()
18716
+ }).strict().optional(),
18717
+ /** Optimistic concurrency: refuse when another admin saved first. */
18718
+ expectedRevision: external_exports.number().int().min(0).optional()
18719
+ }).strict().superRefine((value, ctx) => {
18720
+ if (value.displayName === void 0 && value.instructions === void 0 && value.model === void 0 && value.reasoningEffort === void 0 && value.slack === void 0) {
18721
+ ctx.addIssue({ code: "custom", message: "nothing to update" });
18722
+ }
18723
+ });
18724
+ var ConversationChannel = external_exports.enum(["web", "slack", "whatsapp"]);
18725
+ var ConversationStatus = external_exports.enum(["idle", "thinking"]);
18726
+ var ConversationProjection = external_exports.object({
18727
+ id: ConversationId,
18728
+ /** First-message prefix until the one creation-time Manager title call settles. */
18729
+ title: external_exports.string().min(1).max(200),
18730
+ channel: ConversationChannel,
18731
+ status: ConversationStatus,
18732
+ /** TS-10 origin trust of the channel; propagated into every delegated Task. */
18733
+ trust: external_exports.enum(["internal", "external"]),
18734
+ /** One-use override for the next Task delegated from this thread. */
18735
+ nextDelegationRunner: TaskRunnerSelection.nullable(),
18736
+ createdAt: external_exports.string(),
18737
+ lastActivityAt: external_exports.string(),
18738
+ /** Archived, but at least one executor has not yet proven it stopped. */
18739
+ archiveState: external_exports.literal("stopping").nullable().optional(),
18740
+ archivedAt: external_exports.string().nullable()
18741
+ }).strict().superRefine((conversation, ctx) => {
18742
+ if (conversation.archiveState === "stopping" && conversation.archivedAt === null) {
18743
+ ctx.addIssue({
18744
+ code: "custom",
18745
+ path: ["archivedAt"],
18746
+ message: "a stopping Manager Task must already be in Archived"
18747
+ });
18748
+ }
18749
+ });
18750
+ var conversationEventBase = {
18751
+ id: ConversationEventId,
18752
+ at: external_exports.string()
18753
+ };
18754
+ var ConversationEventProjection = external_exports.discriminatedUnion("kind", [
18755
+ /** A human message into the Conversation. */
18756
+ external_exports.object({
18757
+ ...conversationEventBase,
18758
+ kind: external_exports.literal("user"),
18759
+ text: external_exports.string(),
18760
+ /** Display attribution only; authentication subjects remain internal. */
18761
+ author: external_exports.object({ displayName: external_exports.string().nullable() }).strict(),
18762
+ attachments: external_exports.array(TaskAttachmentRef).max(TASK_MESSAGE_MAX_ATTACHMENTS).optional()
18763
+ }).strict(),
18764
+ /** The Manager's prose reply. */
18765
+ external_exports.object({ ...conversationEventBase, kind: external_exports.literal("manager"), text: external_exports.string() }).strict(),
18766
+ /** One Manager tool step: a delegation, follow-up, or status check. */
18767
+ external_exports.object({
18768
+ ...conversationEventBase,
18769
+ kind: external_exports.literal("tool"),
18770
+ tool: external_exports.string(),
18771
+ summary: external_exports.string(),
18772
+ taskId: TaskId.nullable(),
18773
+ agentId: AgentId.nullable()
18774
+ }).strict(),
18775
+ /** A mirrored child-Task event: what the teammate wrote or became. */
18776
+ external_exports.object({
18777
+ ...conversationEventBase,
18778
+ kind: external_exports.literal("task"),
18779
+ taskId: TaskId,
18780
+ agentId: AgentId.nullable(),
18781
+ eventKind: external_exports.enum(["response", "error", "status", "question", "message"]),
18782
+ summary: external_exports.string(),
18783
+ taskStatus: TaskStatus.nullable(),
18784
+ /**
18785
+ * Opaque presentation key shared by the useful report and its synthetic
18786
+ * terminal wake-up. It is never shown to people; clients use it only to
18787
+ * render one outcome when recovery commits those records out of order.
18788
+ * Missing on legacy/non-terminal events.
18789
+ */
18790
+ terminalGroup: external_exports.string().min(1).max(200).nullable().optional()
18791
+ }).strict(),
18792
+ /** A Manager loop failure a person should see (provider outage, refusal). */
18793
+ external_exports.object({ ...conversationEventBase, kind: external_exports.literal("error"), message: external_exports.string() }).strict()
18794
+ ]);
18795
+ var NonEmptyTaskRunnerSelection = TaskRunnerSelection.refine(
18796
+ (selection) => selection.type !== void 0 || selection.model !== void 0 || selection.effort !== void 0,
18797
+ "choose at least one runtime preference"
18798
+ );
18799
+ var CreateConversationRequest = external_exports.object({
18800
+ /** Stable client-generated key: retrying the same submission returns one Conversation. */
18801
+ requestId: external_exports.uuid(),
18802
+ message: external_exports.string().max(CONVERSATION_MESSAGE_MAX),
18803
+ attachmentIds: external_exports.array(AttachmentId).max(TASK_MESSAGE_MAX_ATTACHMENTS).refine((ids) => new Set(ids).size === ids.length, "duplicate attachment").optional(),
18804
+ /**
18805
+ * Teammate whose persistent Browser is selected beside this web turn.
18806
+ * This is bounded routing context for Browser-directed requests only; it
18807
+ * is never a general delegation preference.
18808
+ */
18809
+ browserAgentId: AgentId.optional(),
18810
+ /**
18811
+ * One-time runtime override for the first Task this thread delegates.
18812
+ * Omission preserves the selected teammate's configured defaults.
18813
+ */
18814
+ initialDelegation: external_exports.object({
18815
+ runner: NonEmptyTaskRunnerSelection
18816
+ }).strict().optional()
18817
+ }).strict().superRefine((value, ctx) => {
18818
+ if (!value.message.trim() && !value.attachmentIds?.length) {
18819
+ ctx.addIssue({
18820
+ code: "custom",
18821
+ path: ["message"],
18822
+ message: "a message needs text or an attachment"
18823
+ });
18824
+ }
18825
+ });
18826
+ var PostConversationMessageRequest = external_exports.object({
18827
+ /** Stable client-generated key: an ambiguous retry appends exactly once. */
18828
+ requestId: external_exports.uuid(),
18829
+ message: external_exports.string().max(CONVERSATION_MESSAGE_MAX),
18830
+ attachmentIds: external_exports.array(AttachmentId).max(TASK_MESSAGE_MAX_ATTACHMENTS).refine((ids) => new Set(ids).size === ids.length, "duplicate attachment").optional(),
18831
+ /** Selected Manager Browser teammate for Browser-directed requests only. */
18832
+ browserAgentId: AgentId.optional()
18833
+ }).strict().superRefine((value, ctx) => {
18834
+ if (!value.message.trim() && !value.attachmentIds?.length) {
18835
+ ctx.addIssue({
18836
+ code: "custom",
18837
+ path: ["message"],
18838
+ message: "a message needs text or an attachment"
18839
+ });
18840
+ }
18841
+ });
18842
+ var UpdateNextDelegationRuntimeRequest = external_exports.object({ runner: NonEmptyTaskRunnerSelection.nullable() }).strict();
18843
+ var UpdateConversationRequest = external_exports.object({
18844
+ title: external_exports.string().trim().min(1).max(200).optional(),
18845
+ archived: external_exports.boolean().optional()
18846
+ }).strict().superRefine((value, ctx) => {
18847
+ if (value.title === void 0 && value.archived === void 0) {
18848
+ ctx.addIssue({ code: "custom", message: "nothing to update" });
18849
+ }
18850
+ });
18851
+ var ConversationResponse = external_exports.object({ conversation: ConversationProjection }).strict();
18852
+ var ListConversationsResponse = external_exports.object({
18853
+ conversations: external_exports.array(ConversationProjection).max(CONVERSATION_LIST_LIMIT),
18854
+ nextCursor: external_exports.string().nullable()
18855
+ }).strict();
18856
+ var ManagerTaskRailSummariesRequest = external_exports.object({
18857
+ conversationIds: external_exports.array(ConversationId).min(1).max(CONVERSATION_LIST_LIMIT),
18858
+ archived: external_exports.boolean(),
18859
+ agentId: AgentId.optional(),
18860
+ statuses: external_exports.array(TaskStatus).min(1).max(TaskStatus.options.length).optional()
18861
+ }).strict().superRefine((value, ctx) => {
18862
+ if (new Set(value.conversationIds).size !== value.conversationIds.length) {
18863
+ ctx.addIssue({
18864
+ code: "custom",
18865
+ path: ["conversationIds"],
18866
+ message: "conversationIds must be unique"
18867
+ });
18868
+ }
18869
+ if (value.statuses && new Set(value.statuses).size !== value.statuses.length) {
18870
+ ctx.addIssue({
18871
+ code: "custom",
18872
+ path: ["statuses"],
18873
+ message: "statuses must be unique"
18874
+ });
18875
+ }
18876
+ });
18877
+ var ManagerTaskRailRepresentative = external_exports.object({
18878
+ id: TaskId,
18879
+ agentId: AgentId,
18880
+ status: TaskStatus,
18881
+ gitSummary: TaskGitSummary.nullable(),
18882
+ createdAt: external_exports.string(),
18883
+ updatedAt: external_exports.string()
18884
+ }).strict();
18885
+ var ManagerTaskRailSummary = external_exports.object({
18886
+ conversationId: ConversationId,
18887
+ hasChildren: external_exports.boolean(),
18888
+ hasAgentMatch: external_exports.boolean(),
18889
+ hasStatusMatch: external_exports.boolean(),
18890
+ representative: ManagerTaskRailRepresentative.nullable()
18891
+ }).strict();
18892
+ var ManagerTaskRailSummariesResponse = external_exports.object({ summaries: external_exports.array(ManagerTaskRailSummary).max(CONVERSATION_LIST_LIMIT) }).strict();
18893
+ var ConversationDetailResponse = external_exports.object({
18894
+ conversation: ConversationProjection,
18895
+ events: external_exports.array(ConversationEventProjection)
18896
+ }).strict();
18897
+ var ManagerStreamFrame = external_exports.discriminatedUnion("type", [
18898
+ external_exports.object({ type: external_exports.literal("event"), event: ConversationEventProjection }).strict(),
18899
+ external_exports.object({ type: external_exports.literal("delta"), text: external_exports.string() }).strict(),
18900
+ external_exports.object({ type: external_exports.literal("conversation"), conversation: ConversationProjection }).strict()
18901
+ ]);
18902
+
18556
18903
  // ../../packages/contracts/src/slack.ts
18557
18904
  var SlackInstallationProjection = external_exports.object({
18558
18905
  id: external_exports.string(),
@@ -19294,7 +19641,7 @@ async function generateTaskTitle(instructions, runner) {
19294
19641
  instructions.slice(0, INSTRUCTIONS_BUDGET),
19295
19642
  "</task_request>"
19296
19643
  ].join("\n");
19297
- return new Promise((resolve14) => {
19644
+ return new Promise((resolve15) => {
19298
19645
  const child = spawnCli(
19299
19646
  command,
19300
19647
  [
@@ -19317,7 +19664,7 @@ async function generateTaskTitle(instructions, runner) {
19317
19664
  if (settled) return;
19318
19665
  settled = true;
19319
19666
  clearTimeout(timer);
19320
- resolve14(value);
19667
+ resolve15(value);
19321
19668
  };
19322
19669
  const timer = setTimeout(() => {
19323
19670
  child.kill();
@@ -19639,11 +19986,11 @@ function createWorkerWatchdogSendDrain() {
19639
19986
  if (completed) return;
19640
19987
  completed = true;
19641
19988
  pending--;
19642
- if (pending === 0) drained.splice(0).forEach((resolve14) => resolve14());
19989
+ if (pending === 0) drained.splice(0).forEach((resolve15) => resolve15());
19643
19990
  };
19644
19991
  },
19645
19992
  drain: async () => {
19646
- if (pending > 0) await new Promise((resolve14) => drained.push(resolve14));
19993
+ if (pending > 0) await new Promise((resolve15) => drained.push(resolve15));
19647
19994
  }
19648
19995
  };
19649
19996
  }
@@ -19888,7 +20235,7 @@ async function waitForOperationGrantRetry(retryAt, signal) {
19888
20235
  const deadline = Date.parse(retryAt);
19889
20236
  if (!Number.isFinite(deadline) || signal.aborted) return false;
19890
20237
  if (deadline <= Date.now()) return true;
19891
- return await new Promise((resolve14) => {
20238
+ return await new Promise((resolve15) => {
19892
20239
  let settled = false;
19893
20240
  let timer;
19894
20241
  const finish = (ready) => {
@@ -19896,7 +20243,7 @@ async function waitForOperationGrantRetry(retryAt, signal) {
19896
20243
  settled = true;
19897
20244
  if (timer) clearTimeout(timer);
19898
20245
  signal.removeEventListener("abort", onAbort);
19899
- resolve14(ready);
20246
+ resolve15(ready);
19900
20247
  };
19901
20248
  const onAbort = () => finish(false);
19902
20249
  const schedule = () => {
@@ -20164,22 +20511,22 @@ var HostClient = class _HostClient {
20164
20511
  const unwindingAssignments = [...this.activeAssignments.values()];
20165
20512
  for (const cancel of this.cancels.values()) cancel(stopReason);
20166
20513
  for (const entry of this.secretGrants.values()) {
20167
- for (const resolve14 of entry.resolvers) resolve14({});
20514
+ for (const resolve15 of entry.resolvers) resolve15({});
20168
20515
  entry.resolvers = [];
20169
20516
  delete entry.value;
20170
20517
  }
20171
20518
  for (const entry of this.connectionGrants.values()) {
20172
- for (const resolve14 of entry.resolvers) resolve14([]);
20519
+ for (const resolve15 of entry.resolvers) resolve15([]);
20173
20520
  entry.resolvers = [];
20174
20521
  delete entry.value;
20175
20522
  }
20176
20523
  for (const entry of this.providerGrants.values()) {
20177
- for (const resolve14 of entry.resolvers) resolve14([]);
20524
+ for (const resolve15 of entry.resolvers) resolve15([]);
20178
20525
  entry.resolvers = [];
20179
20526
  delete entry.value;
20180
20527
  }
20181
20528
  for (const waiters of this.approvalWaiters.values()) {
20182
- for (const resolve14 of waiters.values()) resolve14({ approved: false, guidance: reason });
20529
+ for (const resolve15 of waiters.values()) resolve15({ approved: false, guidance: reason });
20183
20530
  }
20184
20531
  for (const waiters of this.agentOpWaiters.values()) {
20185
20532
  for (const waiter of waiters.values()) {
@@ -20205,9 +20552,9 @@ var HostClient = class _HostClient {
20205
20552
  let drainTimer;
20206
20553
  const drained = await Promise.race([
20207
20554
  Promise.allSettled(runs).then(() => true),
20208
- new Promise((resolve14) => {
20555
+ new Promise((resolve15) => {
20209
20556
  drainTimer = setTimeout(
20210
- () => resolve14(false),
20557
+ () => resolve15(false),
20211
20558
  this.opts.unwindTimeoutMs ?? _HostClient.DEFAULT_UNWIND_TIMEOUT_MS
20212
20559
  );
20213
20560
  drainTimer.unref?.();
@@ -20238,9 +20585,70 @@ var HostClient = class _HostClient {
20238
20585
  let awaitingHeartbeatReply = false;
20239
20586
  let closeReason;
20240
20587
  let frameTail = Promise.resolve();
20588
+ let inventoryRetryTimer;
20589
+ let inventoryRetryAttempts = 0;
20590
+ const inventoryRetryBaseMs = Math.max(20, Number(this.opts.backoffMs ?? 1e3));
20241
20591
  this.ws = ws;
20242
20592
  this.protocolReady = false;
20593
+ const retryInventory = async () => {
20594
+ if (this.stopped || this.ws !== ws || ws.readyState !== WebSocket.OPEN) return;
20595
+ let sawComplete = false;
20596
+ try {
20597
+ const pages = this.opts.browser?.profileInventoryPages?.();
20598
+ if (pages) {
20599
+ for await (const page2 of pages) {
20600
+ if (!this.send(
20601
+ {
20602
+ type: "browser.profile.inventory",
20603
+ agentIds: page2.agentIds,
20604
+ complete: page2.complete
20605
+ },
20606
+ ws
20607
+ )) {
20608
+ return;
20609
+ }
20610
+ sawComplete = page2.complete;
20611
+ }
20612
+ } else {
20613
+ const page2 = await this.opts.browser?.profileInventory?.();
20614
+ if (!page2) return;
20615
+ if (!this.send(
20616
+ {
20617
+ type: "browser.profile.inventory",
20618
+ agentIds: page2.agentIds,
20619
+ complete: page2.complete
20620
+ },
20621
+ ws
20622
+ )) {
20623
+ return;
20624
+ }
20625
+ sawComplete = page2.complete;
20626
+ }
20627
+ } catch {
20628
+ sawComplete = false;
20629
+ }
20630
+ if (sawComplete) {
20631
+ inventoryRetryAttempts = 0;
20632
+ } else {
20633
+ scheduleInventoryRetry();
20634
+ }
20635
+ };
20636
+ function scheduleInventoryRetry() {
20637
+ if (inventoryRetryTimer || ws.readyState !== WebSocket.OPEN) return;
20638
+ const delayMs = Math.min(
20639
+ 6e4,
20640
+ inventoryRetryBaseMs * 2 ** Math.min(inventoryRetryAttempts++, 6)
20641
+ );
20642
+ inventoryRetryTimer = setTimeout(() => {
20643
+ inventoryRetryTimer = void 0;
20644
+ void retryInventory();
20645
+ }, delayMs);
20646
+ inventoryRetryTimer.unref?.();
20647
+ }
20243
20648
  ws.on("open", () => {
20649
+ const inventoryConfigured = Boolean(
20650
+ this.opts.browser?.profileInventoryPages || this.opts.browser?.profileInventory
20651
+ );
20244
20652
  const unwoundAssignments = [...this.pendingUnwoundAssignments.values()].sort(
20245
20653
  (left, right) => left.taskId === right.taskId ? left.epoch - right.epoch : left.taskId.localeCompare(right.taskId)
20246
20654
  );
@@ -20249,6 +20657,7 @@ var HostClient = class _HostClient {
20249
20657
  type: "hello",
20250
20658
  protocolVersion: PROTOCOL_VERSION,
20251
20659
  cursor: this.cursor,
20660
+ ...inventoryConfigured ? { browserProfileInventory: { agentIds: [], complete: false } } : {},
20252
20661
  ...unwoundAssignments.length > 0 ? { unwoundAssignments } : {}
20253
20662
  },
20254
20663
  ws
@@ -20265,6 +20674,7 @@ var HostClient = class _HostClient {
20265
20674
  this.send({ type: "ping", at: (/* @__PURE__ */ new Date()).toISOString() });
20266
20675
  void this.reportTelemetry();
20267
20676
  }, heartbeatMs);
20677
+ if (inventoryConfigured) void retryInventory();
20268
20678
  });
20269
20679
  ws.on("message", (raw) => {
20270
20680
  if (this.ws !== ws) return;
@@ -20274,6 +20684,7 @@ var HostClient = class _HostClient {
20274
20684
  });
20275
20685
  });
20276
20686
  ws.on("close", (code) => {
20687
+ if (inventoryRetryTimer) clearTimeout(inventoryRetryTimer);
20277
20688
  void this.handleClose(ws, code, closeReason, frameTail);
20278
20689
  });
20279
20690
  ws.on("error", () => {
@@ -20287,9 +20698,9 @@ var HostClient = class _HostClient {
20287
20698
  let frameDrainTimer;
20288
20699
  const framesDrained = await Promise.race([
20289
20700
  frameTail.then(() => true),
20290
- new Promise((resolve14) => {
20701
+ new Promise((resolve15) => {
20291
20702
  frameDrainTimer = setTimeout(
20292
- () => resolve14(false),
20703
+ () => resolve15(false),
20293
20704
  this.opts.unwindTimeoutMs ?? _HostClient.DEFAULT_UNWIND_TIMEOUT_MS
20294
20705
  );
20295
20706
  frameDrainTimer.unref?.();
@@ -20666,7 +21077,13 @@ var HostClient = class _HostClient {
20666
21077
  case "browser.open": {
20667
21078
  const bridge = this.opts.browser;
20668
21079
  if (!bridge) return;
20669
- void bridge.open(frame.agentId, frame.browserSessionId, frame.viewport, frame.requestId).catch(() => {
21080
+ void bridge.open(
21081
+ frame.agentId,
21082
+ frame.browserSessionId,
21083
+ frame.viewport,
21084
+ frame.requestId,
21085
+ frame.profileRevision
21086
+ ).catch(() => {
20670
21087
  this.sendBrowserFrame({
20671
21088
  type: "browser.session.ended",
20672
21089
  browserSessionId: frame.browserSessionId,
@@ -20677,7 +21094,8 @@ var HostClient = class _HostClient {
20677
21094
  return;
20678
21095
  }
20679
21096
  case "browser.close":
20680
- void this.opts.browser?.close(frame.agentId, "stopped");
21097
+ void this.opts.browser?.close(frame.agentId, "stopped").catch(() => {
21098
+ });
20681
21099
  return;
20682
21100
  case "browser.view":
20683
21101
  void this.opts.browser?.setViewers(frame.agentId, frame.active, frame.viewerCount);
@@ -20778,8 +21196,34 @@ var HostClient = class _HostClient {
20778
21196
  async handleMessage(message) {
20779
21197
  switch (message.type) {
20780
21198
  case "task.assign":
21199
+ if (message.browserProfileRevision !== void 0) {
21200
+ try {
21201
+ await this.opts.browser?.authorizeProfile?.(
21202
+ message.agentId,
21203
+ message.browserProfileRevision
21204
+ );
21205
+ } catch {
21206
+ }
21207
+ }
20781
21208
  this.startTask(message);
20782
21209
  return;
21210
+ case "browser.profile.purge": {
21211
+ const browser = this.opts.browser;
21212
+ void (async () => {
21213
+ try {
21214
+ if (!browser?.purge) return;
21215
+ await browser.purge(message.agentId, message.purgeId, message.profileRevision);
21216
+ this.send({
21217
+ type: "browser.profile.purged",
21218
+ purgeId: message.purgeId,
21219
+ agentId: message.agentId,
21220
+ profileRevision: message.profileRevision
21221
+ });
21222
+ } catch {
21223
+ }
21224
+ })();
21225
+ return;
21226
+ }
20783
21227
  case "task.cancel":
20784
21228
  this.cancels.get(`${message.taskId}:${message.epoch}`)?.(
20785
21229
  message.purpose === "credential_rollover" ? "credential_rollover" : "cloud_cancel"
@@ -20800,7 +21244,7 @@ var HostClient = class _HostClient {
20800
21244
  const entry = this.secretGrants.get(key) ?? { resolvers: [] };
20801
21245
  entry.value = message.secrets;
20802
21246
  entry.expiresAt = expiresAt;
20803
- for (const resolve14 of entry.resolvers) resolve14(message.secrets);
21247
+ for (const resolve15 of entry.resolvers) resolve15(message.secrets);
20804
21248
  entry.resolvers = [];
20805
21249
  this.secretGrants.set(key, entry);
20806
21250
  return;
@@ -20831,13 +21275,13 @@ var HostClient = class _HostClient {
20831
21275
  const entry = this.connectionGrants.get(key) ?? { resolvers: [] };
20832
21276
  entry.value = message.connections;
20833
21277
  entry.expiresAt = expiresAt;
20834
- for (const resolve14 of entry.resolvers) resolve14(message.connections);
21278
+ for (const resolve15 of entry.resolvers) resolve15(message.connections);
20835
21279
  entry.resolvers = [];
20836
21280
  this.connectionGrants.set(key, entry);
20837
21281
  const providerEntry = this.providerGrants.get(key) ?? { resolvers: [] };
20838
21282
  providerEntry.value = providers;
20839
21283
  providerEntry.expiresAt = authorityExpiresAt;
20840
- for (const resolve14 of providerEntry.resolvers) resolve14(providers);
21284
+ for (const resolve15 of providerEntry.resolvers) resolve15(providers);
20841
21285
  providerEntry.resolvers = [];
20842
21286
  this.providerGrants.set(key, providerEntry);
20843
21287
  return;
@@ -20971,8 +21415,8 @@ var HostClient = class _HostClient {
20971
21415
  return redactCredentialText(text, sensitiveSnapshot()).slice(0, maxLength);
20972
21416
  };
20973
21417
  let resolveCancelled;
20974
- const cancelledPromise = new Promise((resolve14) => {
20975
- resolveCancelled = resolve14;
21418
+ const cancelledPromise = new Promise((resolve15) => {
21419
+ resolveCancelled = resolve15;
20976
21420
  });
20977
21421
  const endAuthority = (reason = "cloud_cancel") => {
20978
21422
  if (stopReason) return;
@@ -20981,21 +21425,21 @@ var HostClient = class _HostClient {
20981
21425
  authorityController.abort(reason);
20982
21426
  const secretEntry = this.secretGrants.get(cancelKey);
20983
21427
  if (secretEntry) {
20984
- for (const resolve14 of secretEntry.resolvers) resolve14({});
21428
+ for (const resolve15 of secretEntry.resolvers) resolve15({});
20985
21429
  secretEntry.resolvers = [];
20986
21430
  delete secretEntry.value;
20987
21431
  }
20988
21432
  this.secretGrants.delete(cancelKey);
20989
21433
  const connectionEntry = this.connectionGrants.get(cancelKey);
20990
21434
  if (connectionEntry) {
20991
- for (const resolve14 of connectionEntry.resolvers) resolve14([]);
21435
+ for (const resolve15 of connectionEntry.resolvers) resolve15([]);
20992
21436
  connectionEntry.resolvers = [];
20993
21437
  delete connectionEntry.value;
20994
21438
  }
20995
21439
  this.connectionGrants.delete(cancelKey);
20996
21440
  const providerEntry = this.providerGrants.get(cancelKey);
20997
21441
  if (providerEntry) {
20998
- for (const resolve14 of providerEntry.resolvers) resolve14([]);
21442
+ for (const resolve15 of providerEntry.resolvers) resolve15([]);
20999
21443
  providerEntry.resolvers = [];
21000
21444
  delete providerEntry.value;
21001
21445
  }
@@ -21003,8 +21447,8 @@ var HostClient = class _HostClient {
21003
21447
  this.clearAuthorityExpiry(cancelKey);
21004
21448
  const approvalWaiters = this.approvalWaiters.get(cancelKey);
21005
21449
  if (approvalWaiters) {
21006
- for (const resolve14 of approvalWaiters.values()) {
21007
- resolve14({ approved: false, guidance: "task was cancelled" });
21450
+ for (const resolve15 of approvalWaiters.values()) {
21451
+ resolve15({ approved: false, guidance: "task was cancelled" });
21008
21452
  }
21009
21453
  approvalWaiters.clear();
21010
21454
  }
@@ -21130,9 +21574,9 @@ var HostClient = class _HostClient {
21130
21574
  return value;
21131
21575
  };
21132
21576
  if (entry.value) return Promise.resolve(capture(entry.value));
21133
- return new Promise((resolve14) => {
21134
- entry.resolvers.push((value) => resolve14(capture(value)));
21135
- setTimeout(() => resolve14(capture(entry.value ?? {})), _HostClient.SECRETS_WAIT_MS);
21577
+ return new Promise((resolve15) => {
21578
+ entry.resolvers.push((value) => resolve15(capture(value)));
21579
+ setTimeout(() => resolve15(capture(entry.value ?? {})), _HostClient.SECRETS_WAIT_MS);
21136
21580
  });
21137
21581
  };
21138
21582
  const connections = () => {
@@ -21149,9 +21593,9 @@ var HostClient = class _HostClient {
21149
21593
  return value;
21150
21594
  };
21151
21595
  if (entry.value) return Promise.resolve(capture(entry.value));
21152
- return new Promise((resolve14) => {
21153
- entry.resolvers.push((value) => resolve14(capture(value)));
21154
- setTimeout(() => resolve14(capture(entry.value ?? [])), _HostClient.SECRETS_WAIT_MS);
21596
+ return new Promise((resolve15) => {
21597
+ entry.resolvers.push((value) => resolve15(capture(value)));
21598
+ setTimeout(() => resolve15(capture(entry.value ?? [])), _HostClient.SECRETS_WAIT_MS);
21155
21599
  });
21156
21600
  };
21157
21601
  const providers = () => {
@@ -21168,9 +21612,9 @@ var HostClient = class _HostClient {
21168
21612
  return value;
21169
21613
  };
21170
21614
  if (entry.value !== void 0) return Promise.resolve(capture(entry.value));
21171
- return new Promise((resolve14) => {
21172
- entry.resolvers.push((value) => resolve14(capture(value)));
21173
- setTimeout(() => resolve14(capture(entry.value ?? [])), _HostClient.SECRETS_WAIT_MS);
21615
+ return new Promise((resolve15) => {
21616
+ entry.resolvers.push((value) => resolve15(capture(value)));
21617
+ setTimeout(() => resolve15(capture(entry.value ?? [])), _HostClient.SECRETS_WAIT_MS);
21174
21618
  });
21175
21619
  };
21176
21620
  const linear = async () => {
@@ -21196,13 +21640,13 @@ var HostClient = class _HostClient {
21196
21640
  payload: safe(payload, 5e4),
21197
21641
  ...questionChoices ? { questionChoices: [...questionChoices] } : {}
21198
21642
  });
21199
- return new Promise((resolve14) => {
21643
+ return new Promise((resolve15) => {
21200
21644
  const waiters = this.approvalWaiters.get(cancelKey) ?? /* @__PURE__ */ new Map();
21201
21645
  this.approvalWaiters.set(cancelKey, waiters);
21202
- waiters.set(requestId, resolve14);
21646
+ waiters.set(requestId, resolve15);
21203
21647
  void cancelledPromise.then(() => {
21204
21648
  if (waiters.delete(requestId)) {
21205
- resolve14({ approved: false, guidance: "task was cancelled" });
21649
+ resolve15({ approved: false, guidance: "task was cancelled" });
21206
21650
  }
21207
21651
  });
21208
21652
  });
@@ -21240,11 +21684,11 @@ var HostClient = class _HostClient {
21240
21684
  if (existing) message = existing;
21241
21685
  else terminalMessages.set(requestId, message);
21242
21686
  }
21243
- return new Promise((resolve14) => {
21687
+ return new Promise((resolve15) => {
21244
21688
  const waiters = this.agentOpWaiters.get(cancelKey) ?? /* @__PURE__ */ new Map();
21245
21689
  this.agentOpWaiters.set(cancelKey, waiters);
21246
21690
  if (waiters.has(requestId)) {
21247
- resolve14({ ok: false, error: "provider settlement request is already in flight" });
21691
+ resolve15({ ok: false, error: "provider settlement request is already in flight" });
21248
21692
  return;
21249
21693
  }
21250
21694
  const timer = setTimeout(() => {
@@ -21255,7 +21699,7 @@ var HostClient = class _HostClient {
21255
21699
  (pending) => !(pending.type === "agent.op" && pending.requestId === requestId)
21256
21700
  );
21257
21701
  }
21258
- resolve14({
21702
+ resolve15({
21259
21703
  ok: false,
21260
21704
  error: terminal ? "The provider call completed, but Zixt could not record its outcome. Do not retry; wait for reconciliation." : "the platform did not answer in time; verify with a list_* tool before retrying a mutating call"
21261
21705
  });
@@ -21263,7 +21707,7 @@ var HostClient = class _HostClient {
21263
21707
  }, _HostClient.AGENT_OP_TIMEOUT_MS);
21264
21708
  timer.unref?.();
21265
21709
  waiters.set(requestId, {
21266
- resolve: resolve14,
21710
+ resolve: resolve15,
21267
21711
  timer,
21268
21712
  ...terminal ? { terminalMessage: message } : {}
21269
21713
  });
@@ -21309,12 +21753,12 @@ var HostClient = class _HostClient {
21309
21753
  "No GitHub change was attempted; the authority grant request was invalid."
21310
21754
  );
21311
21755
  }
21312
- const outcome = await new Promise((resolve14) => {
21756
+ const outcome = await new Promise((resolve15) => {
21313
21757
  const timer = setTimeout(() => {
21314
21758
  const waiter = this.operationGrantWaiters.get(requestId);
21315
21759
  if (!waiter) return;
21316
21760
  this.operationGrantWaiters.delete(requestId);
21317
- resolve14({ grant: null, retryable: true, reason: "no_reply_from_zixt" });
21761
+ resolve15({ grant: null, retryable: true, reason: "no_reply_from_zixt" });
21318
21762
  }, this.operationGrantTimeoutMs);
21319
21763
  timer.unref?.();
21320
21764
  this.operationGrantWaiters.set(requestId, {
@@ -21327,9 +21771,9 @@ var HostClient = class _HostClient {
21327
21771
  timer,
21328
21772
  accept: (grant) => {
21329
21773
  addSensitiveValues(providerGrantSensitiveValues(grant));
21330
- resolve14({ grant });
21774
+ resolve15({ grant });
21331
21775
  },
21332
- deny: (retryable, reason, detail, retryAt, retryCode) => resolve14({
21776
+ deny: (retryable, reason, detail, retryAt, retryCode) => resolve15({
21333
21777
  grant: null,
21334
21778
  retryable,
21335
21779
  reason,
@@ -21343,7 +21787,7 @@ var HostClient = class _HostClient {
21343
21787
  } catch {
21344
21788
  clearTimeout(timer);
21345
21789
  this.operationGrantWaiters.delete(requestId);
21346
- resolve14({ grant: null, retryable: false, reason: "connection_unavailable" });
21790
+ resolve15({ grant: null, retryable: false, reason: "connection_unavailable" });
21347
21791
  }
21348
21792
  });
21349
21793
  if (outcome.grant) {
@@ -21399,7 +21843,7 @@ var HostClient = class _HostClient {
21399
21843
  )
21400
21844
  );
21401
21845
  }
21402
- return new Promise((resolve14, reject3) => {
21846
+ return new Promise((resolve15, reject3) => {
21403
21847
  const timer = setTimeout(() => {
21404
21848
  if (this.browserCredentialWaiters.delete(requestId)) {
21405
21849
  reject3(
@@ -21418,7 +21862,7 @@ var HostClient = class _HostClient {
21418
21862
  timer,
21419
21863
  accept: (credential) => {
21420
21864
  addSensitiveValues(webLoginSensitiveValues(credential));
21421
- resolve14(credential);
21865
+ resolve15(credential);
21422
21866
  },
21423
21867
  deny: (reason) => reject3(new Error(reason))
21424
21868
  });
@@ -21724,6 +22168,9 @@ var ProcessTreeTerminationError = class extends Error {
21724
22168
  }
21725
22169
  name = "ProcessTreeTerminationError";
21726
22170
  };
22171
+ function posixIdentityReadMeansMissing(error52) {
22172
+ return ["ENOENT", "ESRCH"].includes(error52.code ?? "");
22173
+ }
21727
22174
  function commandContainsNonce(command, nonce) {
21728
22175
  const escaped = nonce.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
21729
22176
  return new RegExp(`(?:^|[\\s"'])${escaped}(?:$|[\\s"'])`).test(command);
@@ -21736,14 +22183,14 @@ async function observeWindowsGuardianNonce(pid, nonce) {
21736
22183
  "Windows runner identity could not be observed"
21737
22184
  );
21738
22185
  }
21739
- return new Promise((resolve14, reject3) => {
22186
+ return new Promise((resolve15, reject3) => {
21740
22187
  let done = false;
21741
22188
  const finish = (result) => {
21742
22189
  if (done) return;
21743
22190
  done = true;
21744
22191
  clearTimeout(timeout);
21745
22192
  if (result instanceof Error) reject3(result);
21746
- else resolve14(result);
22193
+ else resolve15(result);
21747
22194
  };
21748
22195
  const timeout = setTimeout(
21749
22196
  () => finish(
@@ -21781,14 +22228,14 @@ async function observePosixGuardianNonce(pid, nonce) {
21781
22228
  const args = command.toString("utf8").split("\0");
21782
22229
  return args.includes(nonce) ? "match" : "mismatch";
21783
22230
  } catch (error52) {
21784
- if (error52.code === "ENOENT") return "missing";
22231
+ if (posixIdentityReadMeansMissing(error52)) return "missing";
21785
22232
  throw new ProcessTreeTerminationError(
21786
22233
  "state_unknown",
21787
22234
  "POSIX runner identity could not be observed"
21788
22235
  );
21789
22236
  }
21790
22237
  }
21791
- return new Promise((resolve14, reject3) => {
22238
+ return new Promise((resolve15, reject3) => {
21792
22239
  const observer = spawn2("/bin/ps", ["-ww", "-o", "command=", "-p", String(pid)], {
21793
22240
  stdio: ["ignore", "pipe", "ignore"]
21794
22241
  });
@@ -21799,7 +22246,7 @@ async function observePosixGuardianNonce(pid, nonce) {
21799
22246
  done = true;
21800
22247
  clearTimeout(timeout);
21801
22248
  if (result instanceof Error) reject3(result);
21802
- else resolve14(result);
22249
+ else resolve15(result);
21803
22250
  };
21804
22251
  const timeout = setTimeout(() => {
21805
22252
  observer.kill("SIGKILL");
@@ -21846,7 +22293,7 @@ async function observeGuardianIdentity(pid, identity) {
21846
22293
  return process.platform === "win32" ? observeWindowsGuardianNonce(pid, identity.nonce) : observePosixGuardianNonce(pid, identity.nonce);
21847
22294
  }
21848
22295
  function delay(ms) {
21849
- return new Promise((resolve14) => setTimeout(resolve14, ms));
22296
+ return new Promise((resolve15) => setTimeout(resolve15, ms));
21850
22297
  }
21851
22298
  function posixProcessRecordsFromPs(output) {
21852
22299
  const records = [];
@@ -21879,7 +22326,7 @@ function posixProcessRecordsFromPs(output) {
21879
22326
  return records;
21880
22327
  }
21881
22328
  async function snapshotPosixProcesses() {
21882
- return new Promise((resolve14, reject3) => {
22329
+ return new Promise((resolve15, reject3) => {
21883
22330
  const observer = spawn2("/bin/ps", ["-axo", "uid=,pid=,ppid=,pgid=,stat="], {
21884
22331
  stdio: ["ignore", "pipe", "ignore"]
21885
22332
  });
@@ -21892,7 +22339,7 @@ async function snapshotPosixProcesses() {
21892
22339
  if (error52) reject3(error52);
21893
22340
  else {
21894
22341
  try {
21895
- resolve14(posixProcessRecordsFromPs(output));
22342
+ resolve15(posixProcessRecordsFromPs(output));
21896
22343
  } catch (caught) {
21897
22344
  reject3(caught);
21898
22345
  }
@@ -22227,7 +22674,7 @@ async function snapshotWindowsDescendants(rootPid) {
22227
22674
  "Windows process-tree observation could not start"
22228
22675
  );
22229
22676
  }
22230
- return new Promise((resolve14, reject3) => {
22677
+ return new Promise((resolve15, reject3) => {
22231
22678
  let done = false;
22232
22679
  const timeout = setTimeout(() => {
22233
22680
  if (done) return;
@@ -22254,7 +22701,7 @@ async function snapshotWindowsDescendants(rootPid) {
22254
22701
  return;
22255
22702
  }
22256
22703
  try {
22257
- resolve14(completeWindowsDescendantPids(rootPid, processes));
22704
+ resolve15(completeWindowsDescendantPids(rootPid, processes));
22258
22705
  } catch (caught) {
22259
22706
  reject3(caught);
22260
22707
  }
@@ -22301,7 +22748,7 @@ async function waitForProcessesExit(pids, timeoutMs) {
22301
22748
  }
22302
22749
  async function runTaskkill(pid, command, timeoutMs = TASKKILL_TIMEOUT_MS, independentlyTrackedPids = []) {
22303
22750
  const trustedCommand = command ?? defaultTaskkillCommand();
22304
- const result = await new Promise((resolve14, reject3) => {
22751
+ const result = await new Promise((resolve15, reject3) => {
22305
22752
  const killer = spawn2(trustedCommand, ["/PID", String(pid), "/T", "/F"], {
22306
22753
  stdio: ["ignore", "pipe", "pipe"],
22307
22754
  windowsHide: true
@@ -22336,7 +22783,7 @@ async function runTaskkill(pid, command, timeoutMs = TASKKILL_TIMEOUT_MS, indepe
22336
22783
  done = true;
22337
22784
  clearTimeout(timeout);
22338
22785
  if (error52) reject3(error52);
22339
- else resolve14({ code: killer.exitCode, output, outputTruncated });
22786
+ else resolve15({ code: killer.exitCode, output, outputTruncated });
22340
22787
  };
22341
22788
  killer.once(
22342
22789
  "error",
@@ -23013,12 +23460,12 @@ async function createWindowsJobContainment(pid, options) {
23013
23460
  stderr = `${stderr}${String(chunk)}`.slice(-HELPER_OUTPUT_LIMIT);
23014
23461
  });
23015
23462
  const helperEvents = helper;
23016
- const exited = new Promise((resolve14) => {
23463
+ const exited = new Promise((resolve15) => {
23017
23464
  let completed = false;
23018
23465
  const complete = (code, signal) => {
23019
23466
  if (completed) return;
23020
23467
  completed = true;
23021
- resolve14({ code, signal });
23468
+ resolve15({ code, signal });
23022
23469
  };
23023
23470
  helperEvents.once("error", () => {
23024
23471
  failProtocol(new Error("Windows Job Object helper could not start"));
@@ -23031,7 +23478,7 @@ async function createWindowsJobContainment(pid, options) {
23031
23478
  });
23032
23479
  const nextLine = async (expected) => {
23033
23480
  if (protocolFailure) throw protocolFailure;
23034
- const line = lines.shift() ?? await new Promise((resolve14, reject3) => {
23481
+ const line = lines.shift() ?? await new Promise((resolve15, reject3) => {
23035
23482
  const timer = setTimeout(
23036
23483
  () => reject3(timeoutError("Windows Job Object helper did not answer in time")),
23037
23484
  timeoutMs
@@ -23039,7 +23486,7 @@ async function createWindowsJobContainment(pid, options) {
23039
23486
  timer.unref?.();
23040
23487
  lineWaiters.push((value) => {
23041
23488
  clearTimeout(timer);
23042
- resolve14(value);
23489
+ resolve15(value);
23043
23490
  });
23044
23491
  });
23045
23492
  if (protocolFailure) throw protocolFailure;
@@ -23052,8 +23499,8 @@ async function createWindowsJobContainment(pid, options) {
23052
23499
  }
23053
23500
  const stopped = await Promise.race([
23054
23501
  exited.then(() => true),
23055
- new Promise((resolve14) => {
23056
- const timer = setTimeout(() => resolve14(false), timeoutMs);
23502
+ new Promise((resolve15) => {
23503
+ const timer = setTimeout(() => resolve15(false), timeoutMs);
23057
23504
  timer.unref?.();
23058
23505
  })
23059
23506
  ]);
@@ -23112,7 +23559,7 @@ async function awaitWindowsContainmentGate(env = process.env, input = process.st
23112
23559
  if (nonce === void 0) return true;
23113
23560
  if (!SAFE_NONCE2.test(nonce)) return false;
23114
23561
  const expected = windowsContainmentGate(nonce).trimEnd();
23115
- return new Promise((resolve14) => {
23562
+ return new Promise((resolve15) => {
23116
23563
  let pending = Buffer.alloc(0);
23117
23564
  let settled = false;
23118
23565
  const finish = (result) => {
@@ -23123,7 +23570,7 @@ async function awaitWindowsContainmentGate(env = process.env, input = process.st
23123
23570
  input.off("end", onEnd);
23124
23571
  input.off("error", onEnd);
23125
23572
  if (result) input.pause();
23126
- resolve14(result);
23573
+ resolve15(result);
23127
23574
  };
23128
23575
  const onData = (chunk) => {
23129
23576
  pending = Buffer.concat([pending, chunk]);
@@ -23548,7 +23995,7 @@ async function installRelease(version2, options = {}) {
23548
23995
  installerContainmentSetupError = error52;
23549
23996
  return null;
23550
23997
  }) : Promise.resolve(null);
23551
- const installed = await new Promise((resolve14, reject3) => {
23998
+ const installed = await new Promise((resolve15, reject3) => {
23552
23999
  let finished = false;
23553
24000
  let cleanupStarted = false;
23554
24001
  let exitObserved = false;
@@ -23564,7 +24011,7 @@ async function installRelease(version2, options = {}) {
23564
24011
  finished = true;
23565
24012
  clearTimeout(timer);
23566
24013
  options.signal?.removeEventListener("abort", requestCleanup);
23567
- resolve14(result);
24014
+ resolve15(result);
23568
24015
  };
23569
24016
  const requestCleanup = () => {
23570
24017
  if (cleanupStarted || finished) return;
@@ -23877,11 +24324,11 @@ async function runWorkerCompatibilityProxy(env = process.env, argv = process.arg
23877
24324
  child.stdin?.on("error", () => {
23878
24325
  });
23879
24326
  process.stdin.pipe(child.stdin);
23880
- return new Promise((resolve14) => {
23881
- child.once("error", () => resolve14(1));
24327
+ return new Promise((resolve15) => {
24328
+ child.once("error", () => resolve15(1));
23882
24329
  child.once("exit", (code) => {
23883
24330
  process.stdin.unpipe(child.stdin);
23884
- resolve14(code ?? 1);
24331
+ resolve15(code ?? 1);
23885
24332
  });
23886
24333
  });
23887
24334
  }
@@ -23959,11 +24406,11 @@ async function launchHostSupervisor(options = {}) {
23959
24406
  const waitOrStop = async (ms) => {
23960
24407
  if (stopping) return false;
23961
24408
  if (!customDelay) {
23962
- await new Promise((resolve14) => {
24409
+ await new Promise((resolve15) => {
23963
24410
  const finish = () => {
23964
24411
  clearTimeout(timer);
23965
24412
  stopController.signal.removeEventListener("abort", finish);
23966
- resolve14();
24413
+ resolve15();
23967
24414
  };
23968
24415
  const timer = setTimeout(finish, ms);
23969
24416
  stopController.signal.addEventListener("abort", finish, { once: true });
@@ -23971,8 +24418,8 @@ async function launchHostSupervisor(options = {}) {
23971
24418
  return !stopping;
23972
24419
  }
23973
24420
  let finishStop;
23974
- const stopped = new Promise((resolve14) => {
23975
- finishStop = () => resolve14();
24421
+ const stopped = new Promise((resolve15) => {
24422
+ finishStop = () => resolve15();
23976
24423
  stopController.signal.addEventListener("abort", finishStop, { once: true });
23977
24424
  });
23978
24425
  await Promise.race([customDelay(ms), stopped]);
@@ -24095,19 +24542,19 @@ async function launchHostSupervisor(options = {}) {
24095
24542
  child = spawnSupervisor(entry, version2, ownershipDirectory, containmentGateNonce);
24096
24543
  const launchedSupervisor = child;
24097
24544
  let resolveChildExited;
24098
- const childExited = new Promise((resolve14) => {
24099
- resolveChildExited = resolve14;
24545
+ const childExited = new Promise((resolve15) => {
24546
+ resolveChildExited = resolve15;
24100
24547
  });
24101
24548
  const supervisorContainmentAbort = new AbortController();
24102
24549
  void childExited.then(() => supervisorContainmentAbort.abort());
24103
24550
  const outcomePromise = new Promise(
24104
- (resolve14) => {
24551
+ (resolve15) => {
24105
24552
  let observed = false;
24106
24553
  const finish = (code, signal) => {
24107
24554
  if (observed) return;
24108
24555
  observed = true;
24109
24556
  resolveChildExited();
24110
- resolve14({ code, signal });
24557
+ resolve15({ code, signal });
24111
24558
  };
24112
24559
  child.once("error", () => finish(1, null));
24113
24560
  child.once("exit", finish);
@@ -24128,12 +24575,12 @@ async function launchHostSupervisor(options = {}) {
24128
24575
  if (!supervisorContainment || !launchedSupervisor.stdin) {
24129
24576
  throw new Error("supervisor Job Object gate is unavailable");
24130
24577
  }
24131
- await new Promise((resolve14, reject3) => {
24578
+ await new Promise((resolve15, reject3) => {
24132
24579
  launchedSupervisor.stdin.write(
24133
24580
  windowsContainmentGate(containmentGateNonce),
24134
24581
  (error52) => {
24135
24582
  if (error52) reject3(error52);
24136
- else resolve14();
24583
+ else resolve15();
24137
24584
  }
24138
24585
  );
24139
24586
  });
@@ -24275,18 +24722,18 @@ async function superviseHost(options = {}) {
24275
24722
  }
24276
24723
  }
24277
24724
  let announceShutdown;
24278
- const shutdownAnnounced = new Promise((resolve14) => {
24279
- announceShutdown = resolve14;
24725
+ const shutdownAnnounced = new Promise((resolve15) => {
24726
+ announceShutdown = resolve15;
24280
24727
  });
24281
24728
  const attempted = /* @__PURE__ */ new Set();
24282
24729
  const waitOrShutdown = async (ms) => {
24283
24730
  if (shuttingDown2) return false;
24284
24731
  if (!customDelay) {
24285
- await new Promise((resolve14) => {
24732
+ await new Promise((resolve15) => {
24286
24733
  const finish = () => {
24287
24734
  clearTimeout(timer);
24288
24735
  shutdownController.signal.removeEventListener("abort", finish);
24289
- resolve14();
24736
+ resolve15();
24290
24737
  };
24291
24738
  const timer = setTimeout(finish, ms);
24292
24739
  shutdownController.signal.addEventListener("abort", finish, { once: true });
@@ -24429,19 +24876,19 @@ async function superviseHost(options = {}) {
24429
24876
  child = spawnWorker(command, watchdogLaunch, compatibilityOwnership, containmentGateNonce);
24430
24877
  const watchedChild = child;
24431
24878
  let resolveChildExited;
24432
- const childExited = new Promise((resolve14) => {
24433
- resolveChildExited = resolve14;
24879
+ const childExited = new Promise((resolve15) => {
24880
+ resolveChildExited = resolve15;
24434
24881
  });
24435
24882
  const workerContainmentAbort = new AbortController();
24436
24883
  void childExited.then(() => workerContainmentAbort.abort());
24437
24884
  const outcomePromise = new Promise(
24438
- (resolve14) => {
24885
+ (resolve15) => {
24439
24886
  let observed = false;
24440
24887
  const finish = (result) => {
24441
24888
  if (observed) return;
24442
24889
  observed = true;
24443
24890
  resolveChildExited();
24444
- resolve14(result);
24891
+ resolve15(result);
24445
24892
  };
24446
24893
  watchedChild.once("error", () => finish({ code: 1, signal: null }));
24447
24894
  watchedChild.once(
@@ -24463,10 +24910,10 @@ async function superviseHost(options = {}) {
24463
24910
  if (!workerContainment || !watchedChild.stdin) {
24464
24911
  throw new Error("worker Job Object gate is unavailable");
24465
24912
  }
24466
- await new Promise((resolve14, reject3) => {
24913
+ await new Promise((resolve15, reject3) => {
24467
24914
  watchedChild.stdin.write(windowsContainmentGate(containmentGateNonce), (error52) => {
24468
24915
  if (error52) reject3(error52);
24469
- else resolve14();
24916
+ else resolve15();
24470
24917
  });
24471
24918
  });
24472
24919
  }
@@ -24733,6 +25180,20 @@ async function superviseHost(options = {}) {
24733
25180
  import { hostname as hostname3 } from "node:os";
24734
25181
 
24735
25182
  // src/browser/adapter.ts
25183
+ var BROWSER_LOGIN_ORIGIN_CHANGED = "No sign-in was attempted: the browser left the approved sign-in site. Return to that site and try again.";
25184
+ function requireBrowserLoginOrigin(currentUrl, loginUrl) {
25185
+ try {
25186
+ const current = new URL(currentUrl);
25187
+ const expected = new URL(loginUrl);
25188
+ const currentIsWeb = current.protocol === "https:" || current.protocol === "http:";
25189
+ const expectedIsWeb = expected.protocol === "https:" || expected.protocol === "http:";
25190
+ if (currentIsWeb && expectedIsWeb && current.origin === expected.origin) {
25191
+ return expected.origin;
25192
+ }
25193
+ } catch {
25194
+ }
25195
+ throw new Error(BROWSER_LOGIN_ORIGIN_CHANGED);
25196
+ }
24736
25197
  var DEMO_FRAME_JPEG_BASE64 = "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAIAAgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigD//2Q==";
24737
25198
  function createDemoBrowserAdapterFactory() {
24738
25199
  return {
@@ -24882,6 +25343,7 @@ function createDemoBrowserAdapterFactory() {
24882
25343
  return frame();
24883
25344
  },
24884
25345
  async fillLogin(credential) {
25346
+ requireBrowserLoginOrigin(active().url, credential.loginUrl);
24885
25347
  const landedUrl = new URL("/account", credential.loginUrl).toString();
24886
25348
  const tab = active();
24887
25349
  tab.url = landedUrl;
@@ -24904,9 +25366,9 @@ function createDemoBrowserAdapterFactory() {
24904
25366
  }
24905
25367
 
24906
25368
  // src/browser/manager.ts
24907
- import { mkdir as mkdir4 } from "node:fs/promises";
25369
+ import { lstat as lstat4, mkdir as mkdir4, open as open4, opendir, readFile as readFile5, rename as rename3, rm as rm4 } from "node:fs/promises";
24908
25370
  import { homedir as homedir2 } from "node:os";
24909
- import { join as join7 } from "node:path";
25371
+ import { dirname as dirname4, join as join7, resolve as resolve4 } from "node:path";
24910
25372
  var SAFE_SEGMENT = /^[A-Za-z0-9_-]{1,200}$/;
24911
25373
  var FRAME_MIN_INTERVAL_MS = 100;
24912
25374
  var IDLE_TIMEOUT_MS = 15 * 6e4;
@@ -24914,18 +25376,34 @@ var BrowserManager = class {
24914
25376
  constructor(opts) {
24915
25377
  this.opts = opts;
24916
25378
  this.profileRoot = opts.profileRoot ?? join7(homedir2(), ".zixt", "browser-profiles");
25379
+ this.profileStateRoot = join7(this.profileRoot, ".profile-state");
24917
25380
  this.viewport = opts.viewport ?? BROWSER_DEFAULT_VIEWPORT;
24918
25381
  this.idleTimeoutMs = opts.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
24919
25382
  this.frameMinIntervalMs = opts.frameMinIntervalMs ?? FRAME_MIN_INTERVAL_MS;
25383
+ this.profileInventoryLimit = Math.max(
25384
+ 1,
25385
+ Math.min(
25386
+ BROWSER_PROFILE_INVENTORY_PAGE_SIZE,
25387
+ Math.trunc(opts.profileInventoryLimit ?? BROWSER_PROFILE_INVENTORY_PAGE_SIZE)
25388
+ )
25389
+ );
24920
25390
  }
24921
25391
  sessions = /* @__PURE__ */ new Map();
25392
+ /**
25393
+ * Fail closed after lifecycle authorization could not be durably checked or
25394
+ * written. Non-browser runner work may continue, but no local Browser can
25395
+ * open until a later trusted revision is successfully authorized.
25396
+ */
25397
+ deniedAuthorizations = /* @__PURE__ */ new Map();
24922
25398
  /** Serializes open/close per teammate: one profile allows one live browser. */
24923
25399
  locks = /* @__PURE__ */ new Map();
24924
25400
  events = null;
24925
25401
  profileRoot;
25402
+ profileStateRoot;
24926
25403
  viewport;
24927
25404
  idleTimeoutMs;
24928
25405
  frameMinIntervalMs;
25406
+ profileInventoryLimit;
24929
25407
  /**
24930
25408
  * Wired once by the host client; replaces any prior socket generation's
24931
25409
  * sink. Attaching re-announces every live session, because the cloud keeps
@@ -24942,6 +25420,31 @@ var BrowserManager = class {
24942
25420
  capability() {
24943
25421
  return this.opts.factory.capability();
24944
25422
  }
25423
+ /**
25424
+ * Page a path-validated migration inventory without holding an unbounded
25425
+ * directory in memory. A final `complete: true` page is emitted even when
25426
+ * the directory contains an exact multiple of the page size.
25427
+ */
25428
+ async *profileInventoryPages() {
25429
+ await this.ensureOwnedDirectory(this.profileRoot);
25430
+ const agentIds = [];
25431
+ const directory = await opendir(this.profileRoot);
25432
+ for await (const entry of directory) {
25433
+ if (!entry.isDirectory() || entry.isSymbolicLink() || !AgentId.safeParse(entry.name).success) {
25434
+ continue;
25435
+ }
25436
+ if (agentIds.length === this.profileInventoryLimit) {
25437
+ yield { agentIds: agentIds.splice(0).sort(), complete: false };
25438
+ }
25439
+ agentIds.push(entry.name);
25440
+ }
25441
+ yield { agentIds: agentIds.sort(), complete: true };
25442
+ }
25443
+ /** First bounded page retained for embedders that have not adopted continuations. */
25444
+ async profileInventory() {
25445
+ const first = await this.profileInventoryPages().next();
25446
+ return first.value ?? { agentIds: [], complete: true };
25447
+ }
24945
25448
  sessionState(agentId) {
24946
25449
  const session = this.sessions.get(agentId);
24947
25450
  return session && !session.closed ? this.stateOf(session) : null;
@@ -24957,6 +25460,122 @@ var BrowserManager = class {
24957
25460
  );
24958
25461
  return next;
24959
25462
  }
25463
+ validateAgentId(agentId) {
25464
+ if (!SAFE_SEGMENT.test(agentId) || !AgentId.safeParse(agentId).success) {
25465
+ throw new Error("invalid agent id for a browser profile path");
25466
+ }
25467
+ }
25468
+ exactChild(root, child) {
25469
+ const canonicalRoot = resolve4(root);
25470
+ const target = resolve4(canonicalRoot, child);
25471
+ if (dirname4(target) !== canonicalRoot) {
25472
+ throw new Error("browser profile path escaped its owned root");
25473
+ }
25474
+ return target;
25475
+ }
25476
+ async ensureOwnedDirectory(path) {
25477
+ await mkdir4(path, { recursive: true, mode: 448 });
25478
+ const stat3 = await lstat4(path);
25479
+ if (!stat3.isDirectory() || stat3.isSymbolicLink()) {
25480
+ throw new Error("browser profile root must be an owned directory, not a symbolic link");
25481
+ }
25482
+ }
25483
+ /**
25484
+ * POSIX needs directory fsync for a rename/unlink to survive sudden power
25485
+ * loss. Windows does not support opening directories this way, so only its
25486
+ * unsupported-operation errors are tolerated; file fsync still remains
25487
+ * mandatory on every platform.
25488
+ */
25489
+ async syncDirectory(path) {
25490
+ try {
25491
+ const directory = await open4(path, "r");
25492
+ try {
25493
+ await directory.sync();
25494
+ } finally {
25495
+ await directory.close();
25496
+ }
25497
+ } catch (error52) {
25498
+ const code = error52.code;
25499
+ if (process.platform === "win32" && (code === "EISDIR" || code === "EACCES" || code === "EPERM" || code === "EINVAL" || code === "ENOTSUP")) {
25500
+ return;
25501
+ }
25502
+ throw error52;
25503
+ }
25504
+ }
25505
+ profilePath(agentId) {
25506
+ return this.exactChild(this.profileRoot, agentId);
25507
+ }
25508
+ statePath(agentId) {
25509
+ return this.exactChild(this.profileStateRoot, `${agentId}.json`);
25510
+ }
25511
+ async readProfileState(agentId) {
25512
+ try {
25513
+ const raw = JSON.parse(await readFile5(this.statePath(agentId), "utf8"));
25514
+ if (typeof raw !== "object" || raw === null || !Number.isInteger(raw.revision) || Number(raw.revision) < 0 || !["allowed", "purged"].includes(String(raw.state))) {
25515
+ throw new Error("browser profile lifecycle marker is invalid");
25516
+ }
25517
+ return raw;
25518
+ } catch (error52) {
25519
+ if (error52.code === "ENOENT") return null;
25520
+ throw error52;
25521
+ }
25522
+ }
25523
+ async writeProfileState(agentId, state) {
25524
+ await this.ensureOwnedDirectory(this.profileRoot);
25525
+ await this.ensureOwnedDirectory(this.profileStateRoot);
25526
+ const destination = this.statePath(agentId);
25527
+ const temporary = this.exactChild(
25528
+ this.profileStateRoot,
25529
+ `${agentId}.${crypto.randomUUID()}.tmp`
25530
+ );
25531
+ try {
25532
+ const marker = await open4(temporary, "wx+", 384);
25533
+ try {
25534
+ await marker.writeFile(JSON.stringify(state), "utf8");
25535
+ await marker.sync();
25536
+ } finally {
25537
+ await marker.close();
25538
+ }
25539
+ await rename3(temporary, destination);
25540
+ await this.syncDirectory(this.profileStateRoot);
25541
+ await this.syncDirectory(this.profileRoot);
25542
+ } catch (error52) {
25543
+ await rm4(temporary, { force: true }).catch(() => {
25544
+ });
25545
+ throw error52;
25546
+ }
25547
+ }
25548
+ /** Trusted cloud lifecycle authorization after an explicit restore/current assignment. */
25549
+ async authorizeProfile(agentId, revision) {
25550
+ this.validateAgentId(agentId);
25551
+ if (!Number.isInteger(revision) || revision < 0) {
25552
+ throw new Error("invalid browser profile lifecycle revision");
25553
+ }
25554
+ try {
25555
+ await this.withLock(agentId, async () => {
25556
+ const current = await this.readProfileState(agentId);
25557
+ if (current && current.revision > revision) {
25558
+ throw new Error("stale browser profile authorization was refused");
25559
+ }
25560
+ if (current?.state === "purged" && current.revision === revision) {
25561
+ throw new Error("this browser profile remains retired until the AI teammate is restored");
25562
+ }
25563
+ if (!current || current.revision < revision || current.state !== "allowed") {
25564
+ await this.writeProfileState(agentId, { revision, state: "allowed" });
25565
+ }
25566
+ });
25567
+ const deniedRevision = this.deniedAuthorizations.get(agentId);
25568
+ if (deniedRevision !== void 0 && revision >= deniedRevision) {
25569
+ this.deniedAuthorizations.delete(agentId);
25570
+ }
25571
+ } catch (error52) {
25572
+ this.deniedAuthorizations.set(
25573
+ agentId,
25574
+ Math.max(revision, this.deniedAuthorizations.get(agentId) ?? revision)
25575
+ );
25576
+ throw error52;
25577
+ }
25578
+ }
24960
25579
  /**
24961
25580
  * Ensure a live session for this teammate. An existing session is adopted
24962
25581
  * as-is (the cloud-minted id loses to the live one — the cloud reconciles
@@ -24964,16 +25583,39 @@ var BrowserManager = class {
24964
25583
  * with the install remedy.
24965
25584
  */
24966
25585
  ensure(agentId, browserSessionId) {
24967
- if (!SAFE_SEGMENT.test(agentId)) {
24968
- return Promise.reject(new Error("invalid agent id for a browser profile path"));
25586
+ try {
25587
+ this.validateAgentId(agentId);
25588
+ } catch (error52) {
25589
+ return Promise.reject(error52);
24969
25590
  }
24970
25591
  return this.withLock(agentId, async () => {
25592
+ if (this.deniedAuthorizations.has(agentId)) {
25593
+ throw new Error(
25594
+ "this browser profile is unavailable until its lifecycle authorization succeeds"
25595
+ );
25596
+ }
25597
+ const lifecycle = await this.readProfileState(agentId);
25598
+ if (lifecycle?.state === "purged") {
25599
+ throw new Error("this browser profile was retired and cannot be recreated locally");
25600
+ }
24971
25601
  const existing = this.sessions.get(agentId);
25602
+ if (existing?.closeFailed) {
25603
+ throw new Error("the previous browser termination is not yet confirmed");
25604
+ }
24972
25605
  if (existing && !existing.closed) {
24973
25606
  this.markActivity(agentId);
24974
25607
  return this.stateOf(existing);
24975
25608
  }
24976
- const profileDir = join7(this.profileRoot, agentId);
25609
+ await this.ensureOwnedDirectory(this.profileRoot);
25610
+ const profileDir = this.profilePath(agentId);
25611
+ try {
25612
+ const existingProfile = await lstat4(profileDir);
25613
+ if (existingProfile.isSymbolicLink() || !existingProfile.isDirectory()) {
25614
+ throw new Error("browser profile path is not an owned directory");
25615
+ }
25616
+ } catch (error52) {
25617
+ if (error52.code !== "ENOENT") throw error52;
25618
+ }
24977
25619
  await mkdir4(profileDir, { recursive: true, mode: 448 });
24978
25620
  const adapter = await this.opts.factory.open({
24979
25621
  agentId,
@@ -24994,7 +25636,8 @@ var BrowserManager = class {
24994
25636
  framesPaused: false,
24995
25637
  inputQueue: Promise.resolve(),
24996
25638
  resizeGeneration: 0,
24997
- closed: false
25639
+ closed: false,
25640
+ closeFailed: false
24998
25641
  };
24999
25642
  this.sessions.set(agentId, session);
25000
25643
  adapter.onStateChanged(() => {
@@ -25006,7 +25649,8 @@ var BrowserManager = class {
25006
25649
  });
25007
25650
  }
25008
25651
  /** browser.open handler: ensure, then announce with the request correlation. */
25009
- async open(agentId, browserSessionId, _viewport, openRequestId) {
25652
+ async open(agentId, browserSessionId, _viewport, openRequestId, profileRevision) {
25653
+ if (profileRevision !== void 0) await this.authorizeProfile(agentId, profileRevision);
25010
25654
  const state = await this.ensure(agentId, browserSessionId);
25011
25655
  this.events?.state(state, openRequestId);
25012
25656
  return state;
@@ -25016,18 +25660,45 @@ var BrowserManager = class {
25016
25660
  }
25017
25661
  async closeLocked(agentId, reason) {
25018
25662
  const session = this.sessions.get(agentId);
25019
- if (!session || session.closed) return;
25663
+ if (!session || session.closed && !session.closeFailed) return;
25020
25664
  session.closed = true;
25665
+ session.closeFailed = false;
25021
25666
  if (session.frameTimer) clearTimeout(session.frameTimer);
25022
25667
  if (session.idleTimer) clearTimeout(session.idleTimer);
25023
- this.sessions.delete(agentId);
25024
25668
  try {
25025
- await session.adapter.setFrameSink(null);
25669
+ await session.adapter.setFrameSink(null).catch(() => {
25670
+ });
25026
25671
  await session.adapter.close();
25027
- } catch {
25672
+ } catch (error52) {
25673
+ session.closeFailed = true;
25674
+ throw error52;
25028
25675
  }
25676
+ this.sessions.delete(agentId);
25029
25677
  this.events?.ended(session.browserSessionId, agentId, reason);
25030
25678
  }
25679
+ /** Persist retirement, close a live Chromium, then delete only this exact profile. */
25680
+ purge(agentId, purgeId, profileRevision) {
25681
+ try {
25682
+ this.validateAgentId(agentId);
25683
+ } catch (error52) {
25684
+ return Promise.reject(error52);
25685
+ }
25686
+ if (!Number.isInteger(profileRevision) || profileRevision < 1) {
25687
+ return Promise.reject(new Error("invalid browser profile purge revision"));
25688
+ }
25689
+ return this.withLock(agentId, async () => {
25690
+ const current = await this.readProfileState(agentId);
25691
+ if (current && current.revision > profileRevision) return;
25692
+ await this.writeProfileState(agentId, {
25693
+ revision: profileRevision,
25694
+ state: "purged",
25695
+ purgeId
25696
+ });
25697
+ await this.closeLocked(agentId, "stopped");
25698
+ await rm4(this.profilePath(agentId), { recursive: true, force: true, maxRetries: 3 });
25699
+ await this.syncDirectory(this.profileRoot);
25700
+ });
25701
+ }
25031
25702
  async closeAll(reason) {
25032
25703
  await Promise.allSettled(
25033
25704
  [...this.sessions.keys()].map((agentId) => this.close(agentId, reason))
@@ -25067,8 +25738,8 @@ var BrowserManager = class {
25067
25738
  return this.enqueue(session, async () => {
25068
25739
  if (resizeGeneration !== null && resizeGeneration !== session.resizeGeneration) return;
25069
25740
  await session.adapter.command(command);
25070
- const changesCaptureTarget = command.action === "activateTab" || command.action === "newTab" || command.action === "closeTab";
25071
- if (changesCaptureTarget && session.viewerCount > 0) {
25741
+ const needsImmediateFrame = command.action === "resize" || command.action === "activateTab" || command.action === "newTab" || command.action === "closeTab";
25742
+ if (needsImmediateFrame && session.viewerCount > 0) {
25072
25743
  try {
25073
25744
  this.enqueueFrame(session, await session.adapter.screenshot());
25074
25745
  } catch {
@@ -25174,7 +25845,8 @@ var BrowserManager = class {
25174
25845
  this.armIdleTimer(session);
25175
25846
  return;
25176
25847
  }
25177
- void this.close(session.agentId, "idle_timeout");
25848
+ void this.close(session.agentId, "idle_timeout").catch(() => {
25849
+ });
25178
25850
  }, this.idleTimeoutMs);
25179
25851
  session.idleTimer.unref?.();
25180
25852
  }
@@ -25191,12 +25863,13 @@ async function loadPlaywright() {
25191
25863
  return import("playwright-core");
25192
25864
  }
25193
25865
  var KEY_ALIASES = { " ": "Space" };
25194
- function createPlaywrightBrowserAdapterFactory() {
25866
+ function createPlaywrightBrowserAdapterFactory(dependencies = {}) {
25867
+ const load = dependencies.loadPlaywright ?? loadPlaywright;
25195
25868
  return {
25196
25869
  kind: "playwright",
25197
25870
  async capability() {
25198
25871
  try {
25199
- const playwright = await loadPlaywright();
25872
+ const playwright = await load();
25200
25873
  const executable = playwright.chromium.executablePath();
25201
25874
  if (!executable) return { status: "unavailable", error: BROWSER_INSTALL_REMEDY };
25202
25875
  await access3(executable);
@@ -25206,7 +25879,7 @@ function createPlaywrightBrowserAdapterFactory() {
25206
25879
  }
25207
25880
  },
25208
25881
  async open({ profileDir, viewport }) {
25209
- const playwright = await loadPlaywright();
25882
+ const playwright = await load();
25210
25883
  const context = await playwright.chromium.launchPersistentContext(profileDir, {
25211
25884
  headless: true,
25212
25885
  viewport,
@@ -25575,8 +26248,10 @@ function createPlaywrightBrowserAdapterFactory() {
25575
26248
  async fillLogin(credential) {
25576
26249
  const tab = requireActive();
25577
26250
  const { page: page2 } = tab;
26251
+ const expectedOrigin = requireBrowserLoginOrigin(safeUrl(page2), credential.loginUrl);
25578
26252
  const password = page2.locator('input[type="password"]:visible').first();
25579
26253
  await password.waitFor({ state: "visible", timeout: ACTION_TIMEOUT_MS });
26254
+ requireBrowserLoginOrigin(safeUrl(page2), credential.loginUrl);
25580
26255
  const username = page2.locator(
25581
26256
  [
25582
26257
  'input[autocomplete="username"]:visible',
@@ -25586,14 +26261,66 @@ function createPlaywrightBrowserAdapterFactory() {
25586
26261
  'input[type="text"]:visible'
25587
26262
  ].join(", ")
25588
26263
  ).first();
25589
- if (await username.count() > 0) {
25590
- try {
25591
- await username.fill(credential.username, { timeout: ACTION_TIMEOUT_MS });
25592
- } catch {
26264
+ const [passwordInputHandle] = await password.elementHandles();
26265
+ if (!passwordInputHandle) throw new Error("the password field disappeared");
26266
+ const [usernameInputHandle] = await username.elementHandles();
26267
+ const originSentinel = "ZIXT_BROWSER_LOGIN_ORIGIN_CHANGED";
26268
+ try {
26269
+ await passwordInputHandle.evaluate(
26270
+ (node, values) => {
26271
+ const browser = globalThis;
26272
+ const passwordInput = node;
26273
+ if (passwordInput.tagName !== "INPUT" || browser.location.origin !== values.origin) {
26274
+ throw new Error(values.originSentinel);
26275
+ }
26276
+ const visible = (input) => {
26277
+ const style = browser.getComputedStyle(input);
26278
+ const bounds = input.getBoundingClientRect();
26279
+ return input.isConnected && !input.disabled && style.display !== "none" && style.visibility !== "hidden" && bounds.width > 0 && bounds.height > 0;
26280
+ };
26281
+ const write = (input, value) => {
26282
+ input.focus();
26283
+ const setter = Object.getOwnPropertyDescriptor(
26284
+ browser.HTMLInputElement.prototype,
26285
+ "value"
26286
+ )?.set;
26287
+ if (setter) setter.call(input, value);
26288
+ else input.value = value;
26289
+ input.dispatchEvent(
26290
+ new browser.Event("input", { bubbles: true, composed: true })
26291
+ );
26292
+ input.dispatchEvent(new browser.Event("change", { bubbles: true }));
26293
+ };
26294
+ const usernameInput = values.usernameInput;
26295
+ if (usernameInput && usernameInput.ownerDocument === passwordInput.ownerDocument && visible(usernameInput)) {
26296
+ write(usernameInput, values.username);
26297
+ }
26298
+ if (!passwordInput.isConnected || browser.location.origin !== values.origin) {
26299
+ throw new Error(values.originSentinel);
26300
+ }
26301
+ write(passwordInput, values.password);
26302
+ },
26303
+ {
26304
+ usernameInput: usernameInputHandle ?? null,
26305
+ origin: expectedOrigin,
26306
+ originSentinel,
26307
+ username: credential.username,
26308
+ password: credential.password
26309
+ }
26310
+ );
26311
+ requireBrowserLoginOrigin(safeUrl(page2), credential.loginUrl);
26312
+ await passwordInputHandle.press("Enter");
26313
+ } catch (error52) {
26314
+ if (String(error52).includes(originSentinel)) {
26315
+ throw new Error(BROWSER_LOGIN_ORIGIN_CHANGED);
25593
26316
  }
26317
+ throw error52;
26318
+ } finally {
26319
+ await Promise.allSettled([
26320
+ passwordInputHandle.dispose(),
26321
+ ...usernameInputHandle ? [usernameInputHandle.dispose()] : []
26322
+ ]);
25594
26323
  }
25595
- await password.fill(credential.password, { timeout: ACTION_TIMEOUT_MS });
25596
- await password.press("Enter");
25597
26324
  try {
25598
26325
  await page2.waitForLoadState("load", { timeout: 15e3 });
25599
26326
  } catch {
@@ -25639,10 +26366,7 @@ function createPlaywrightBrowserAdapterFactory() {
25639
26366
  async close() {
25640
26367
  closed = true;
25641
26368
  for (const tab of tabs) await detachSession(tab);
25642
- try {
25643
- await context.close();
25644
- } catch {
25645
- }
26369
+ await context.close();
25646
26370
  }
25647
26371
  };
25648
26372
  }
@@ -25652,9 +26376,9 @@ function createPlaywrightBrowserAdapterFactory() {
25652
26376
  // src/runners/cli-runner.ts
25653
26377
  import { spawn as spawn8 } from "node:child_process";
25654
26378
  import { randomUUID as randomUUID10 } from "node:crypto";
25655
- import { lstat as lstat9, mkdir as mkdir10, realpath as realpath7 } from "node:fs/promises";
26379
+ import { lstat as lstat10, mkdir as mkdir10, realpath as realpath7 } from "node:fs/promises";
25656
26380
  import { homedir as homedir4 } from "node:os";
25657
- import { dirname as dirname6, isAbsolute as isAbsolute13, join as join14, resolve as resolve7 } from "node:path";
26381
+ import { dirname as dirname7, isAbsolute as isAbsolute13, join as join14, resolve as resolve8 } from "node:path";
25658
26382
 
25659
26383
  // src/tool-packs/browser/tool-definitions.ts
25660
26384
  function definition(name, description, properties, required2 = []) {
@@ -25876,9 +26600,13 @@ function createBrowserToolPack(deps) {
25876
26600
  });
25877
26601
  const credential = await deps.requestWebLogin(credentialName, origin);
25878
26602
  try {
26603
+ requireBrowserLoginOrigin(tool.state().url, credential.loginUrl);
25879
26604
  const { landedUrl } = await tool.fillLogin(credential);
25880
26605
  return { ok: true, result: { loggedIn: true, landedUrl } };
25881
- } catch {
26606
+ } catch (error52) {
26607
+ if (error52 instanceof Error && error52.message === BROWSER_LOGIN_ORIGIN_CHANGED) {
26608
+ return { ok: false, error: BROWSER_LOGIN_ORIGIN_CHANGED };
26609
+ }
25882
26610
  return {
25883
26611
  ok: false,
25884
26612
  error: "no login form was found or the sign-in did not complete; browser_read the page and try again, or ask a human to take over from the Browser panel"
@@ -28343,13 +29071,13 @@ function createGithubPushOrchestrator(input) {
28343
29071
  // src/tool-packs/github/git-bridge.ts
28344
29072
  import { spawn as spawn5 } from "node:child_process";
28345
29073
  import { randomUUID as randomUUID7 } from "node:crypto";
28346
- import { chmod as chmod3, lstat as lstat5, mkdir as mkdir5, realpath as realpath3, rm as rm4 } from "node:fs/promises";
28347
- import { dirname as dirname4, isAbsolute as isAbsolute8, join as join9, relative as relative4 } from "node:path";
29074
+ import { chmod as chmod3, lstat as lstat6, mkdir as mkdir5, realpath as realpath3, rm as rm5 } from "node:fs/promises";
29075
+ import { dirname as dirname5, isAbsolute as isAbsolute8, join as join9, relative as relative4 } from "node:path";
28348
29076
 
28349
29077
  // src/tool-packs/github/git-credential-broker.ts
28350
29078
  import { createServer } from "node:http";
28351
29079
  import { randomBytes, randomUUID as randomUUID6, timingSafeEqual } from "node:crypto";
28352
- import { chmod as chmod2, lstat as lstat4, realpath as realpath2, writeFile } from "node:fs/promises";
29080
+ import { chmod as chmod2, lstat as lstat5, realpath as realpath2, writeFile } from "node:fs/promises";
28353
29081
  import { isAbsolute as isAbsolute7, join as join8, relative as relative3 } from "node:path";
28354
29082
  var MAX_REQUEST_BYTES = 16 * 1024;
28355
29083
  var FILE_MODE = 384;
@@ -28474,7 +29202,7 @@ async function createGithubGitCredentialBroker(input) {
28474
29202
  throw new Error("GitHub credential authority has expired");
28475
29203
  }
28476
29204
  assertRepositoryFullName(input.repositoryFullName);
28477
- const rootEntry = await lstat4(input.runArtifactsRoot);
29205
+ const rootEntry = await lstat5(input.runArtifactsRoot);
28478
29206
  if (!rootEntry.isDirectory() || rootEntry.isSymbolicLink()) {
28479
29207
  throw new Error("Git credential broker requires a private real run directory");
28480
29208
  }
@@ -28585,7 +29313,7 @@ function assertBelow(parent, child, label) {
28585
29313
  void label;
28586
29314
  }
28587
29315
  async function requireRealDirectory(path, label) {
28588
- const entry = await lstat5(path).catch(() => null);
29316
+ const entry = await lstat6(path).catch(() => null);
28589
29317
  if (!entry || !entry.isDirectory() || entry.isSymbolicLink()) {
28590
29318
  void label;
28591
29319
  throw new GithubGitProcessError("invalid_input");
@@ -28595,9 +29323,9 @@ async function requireRealDirectory(path, label) {
28595
29323
  async function validateTokenlessPaths(command) {
28596
29324
  if (command.kind === "clone-from-bridge") {
28597
29325
  if (!isAbsolute8(command.destination)) throw new GithubGitProcessError("invalid_input");
28598
- const parent = await requireRealDirectory(dirname4(command.destination), "clone parent");
29326
+ const parent = await requireRealDirectory(dirname5(command.destination), "clone parent");
28599
29327
  assertBelow(parent, command.destination, "clone destination");
28600
- const destination = await lstat5(command.destination).catch((error52) => {
29328
+ const destination = await lstat6(command.destination).catch((error52) => {
28601
29329
  if (error52.code === "ENOENT") return null;
28602
29330
  throw error52;
28603
29331
  });
@@ -28705,8 +29433,8 @@ async function runGit(input, args, env) {
28705
29433
  let settled = false;
28706
29434
  let stopping = false;
28707
29435
  let resolveExited;
28708
- const exited = new Promise((resolve14) => {
28709
- resolveExited = resolve14;
29436
+ const exited = new Promise((resolve15) => {
29437
+ resolveExited = resolve15;
28710
29438
  });
28711
29439
  child.once("exit", resolveExited);
28712
29440
  const cleanup = () => {
@@ -28902,7 +29630,7 @@ function createGithubGitBridge(input) {
28902
29630
  const real = await requireRealDirectory(path, "git bridge");
28903
29631
  assertBelow(current.bridges, real, "git bridge");
28904
29632
  const hooks = join9(real, "hooks");
28905
- await rm4(hooks, { recursive: true, force: true });
29633
+ await rm5(hooks, { recursive: true, force: true });
28906
29634
  await mkdir5(hooks, { mode: DIRECTORY_MODE });
28907
29635
  await chmod3(hooks, DIRECTORY_MODE);
28908
29636
  const config2 = join9(real, "config");
@@ -28910,7 +29638,7 @@ function createGithubGitBridge(input) {
28910
29638
  active.add(real);
28911
29639
  return real;
28912
29640
  } catch (error52) {
28913
- await rm4(path, { recursive: true, force: true }).catch(() => {
29641
+ await rm5(path, { recursive: true, force: true }).catch(() => {
28914
29642
  });
28915
29643
  throw error52;
28916
29644
  }
@@ -29004,7 +29732,7 @@ function createGithubGitBridge(input) {
29004
29732
  },
29005
29733
  async destroyPrivateBridge(path) {
29006
29734
  const bridge = await requireBridge(path);
29007
- await rm4(bridge, { recursive: true, force: true });
29735
+ await rm5(bridge, { recursive: true, force: true });
29008
29736
  active.delete(bridge);
29009
29737
  credentialed2.delete(bridge);
29010
29738
  },
@@ -29012,7 +29740,7 @@ function createGithubGitBridge(input) {
29012
29740
  if (closed) return;
29013
29741
  closed = true;
29014
29742
  const paths = [...active];
29015
- await Promise.all(paths.map((path) => rm4(path, { recursive: true, force: true })));
29743
+ await Promise.all(paths.map((path) => rm5(path, { recursive: true, force: true })));
29016
29744
  active.clear();
29017
29745
  credentialed2.clear();
29018
29746
  }
@@ -29353,8 +30081,8 @@ function createRepositoryTools(runtime) {
29353
30081
 
29354
30082
  // src/tool-packs/github/workspace.ts
29355
30083
  import { randomUUID as randomUUID8 } from "node:crypto";
29356
- import { chmod as chmod4, lstat as lstat6, mkdir as mkdir6, readFile as readFile5, realpath as realpath4, rename as rename3, rm as rm5, writeFile as writeFile2 } from "node:fs/promises";
29357
- import { isAbsolute as isAbsolute9, join as join10, relative as relative5, resolve as resolve4 } from "node:path";
30084
+ import { chmod as chmod4, lstat as lstat7, mkdir as mkdir6, readFile as readFile6, realpath as realpath4, rename as rename4, rm as rm6, writeFile as writeFile2 } from "node:fs/promises";
30085
+ import { isAbsolute as isAbsolute9, join as join10, relative as relative5, resolve as resolve5 } from "node:path";
29358
30086
  var SAFE_LOCAL_ID = /^[A-Za-z0-9_-]{1,200}$/;
29359
30087
  var FULL_NAME2 = /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/;
29360
30088
  var DIRECTORY_MODE2 = 448;
@@ -29377,10 +30105,10 @@ function assertBelow2(parent, child, label) {
29377
30105
  }
29378
30106
  }
29379
30107
  function samePath(left, right) {
29380
- return process.platform === "win32" ? resolve4(left).toLowerCase() === resolve4(right).toLowerCase() : resolve4(left) === resolve4(right);
30108
+ return process.platform === "win32" ? resolve5(left).toLowerCase() === resolve5(right).toLowerCase() : resolve5(left) === resolve5(right);
29381
30109
  }
29382
30110
  async function requireRealDirectory2(path, label) {
29383
- const entry = await lstat6(path).catch(() => null);
30111
+ const entry = await lstat7(path).catch(() => null);
29384
30112
  if (!entry || !entry.isDirectory() || entry.isSymbolicLink()) {
29385
30113
  throw new Error(`${label} must be a real directory, not a symbolic link or junction`);
29386
30114
  }
@@ -29417,7 +30145,7 @@ function parseMetadata(text) {
29417
30145
  }
29418
30146
  async function pathExists(path) {
29419
30147
  try {
29420
- await lstat6(path);
30148
+ await lstat7(path);
29421
30149
  return true;
29422
30150
  } catch (error52) {
29423
30151
  if (error52.code === "ENOENT") return false;
@@ -29479,11 +30207,11 @@ async function createGithubWorkspaceService(input) {
29479
30207
  if (!await pathExists(destination) || !await pathExists(metadataPath)) {
29480
30208
  throw new Error("GitHub repository workspace has not been prepared");
29481
30209
  }
29482
- const metadataEntry = await lstat6(metadataPath);
30210
+ const metadataEntry = await lstat7(metadataPath);
29483
30211
  if (!metadataEntry.isFile() || metadataEntry.isSymbolicLink()) {
29484
30212
  throw new Error("GitHub workspace metadata is invalid");
29485
30213
  }
29486
- const metadata = parseMetadata(await readFile5(metadataPath, "utf8"));
30214
+ const metadata = parseMetadata(await readFile6(metadataPath, "utf8"));
29487
30215
  if (metadata.repositoryId !== parsed.data || metadata.fullName !== repository.fullName || !samePath(metadata.path, destination)) {
29488
30216
  throw new Error("GitHub workspace metadata does not match this repository");
29489
30217
  }
@@ -29533,15 +30261,15 @@ async function createGithubWorkspaceService(input) {
29533
30261
  });
29534
30262
  await chmod4(metadataTemporary, FILE_MODE2);
29535
30263
  try {
29536
- await rename3(temporaryReal, destination);
30264
+ await rename4(temporaryReal, destination);
29537
30265
  try {
29538
- await rename3(metadataTemporary, metadataPath);
30266
+ await rename4(metadataTemporary, metadataPath);
29539
30267
  } catch (error52) {
29540
- await rm5(destination, { recursive: true, force: true });
30268
+ await rm6(destination, { recursive: true, force: true });
29541
30269
  throw error52;
29542
30270
  }
29543
30271
  } finally {
29544
- await rm5(metadataTemporary, { force: true }).catch(() => {
30272
+ await rm6(metadataTemporary, { force: true }).catch(() => {
29545
30273
  });
29546
30274
  }
29547
30275
  const path = await requireRealDirectory2(destination, "GitHub repository");
@@ -29553,7 +30281,7 @@ async function createGithubWorkspaceService(input) {
29553
30281
  headSha
29554
30282
  };
29555
30283
  } finally {
29556
- await rm5(temporary, { recursive: true, force: true }).catch(() => {
30284
+ await rm6(temporary, { recursive: true, force: true }).catch(() => {
29557
30285
  });
29558
30286
  }
29559
30287
  };
@@ -29581,11 +30309,11 @@ async function createGithubWorkspaceService(input) {
29581
30309
  expiresAt: authority.expiresAt
29582
30310
  });
29583
30311
  }
29584
- const metadataEntry = await lstat6(metadataPath);
30312
+ const metadataEntry = await lstat7(metadataPath);
29585
30313
  if (!metadataEntry.isFile() || metadataEntry.isSymbolicLink()) {
29586
30314
  throw new Error("GitHub workspace metadata is invalid");
29587
30315
  }
29588
- const metadata = parseMetadata(await readFile5(metadataPath, "utf8"));
30316
+ const metadata = parseMetadata(await readFile6(metadataPath, "utf8"));
29589
30317
  if (metadata.repositoryId !== repository.repositoryId || metadata.fullName !== repository.fullName || !samePath(metadata.path, destination)) {
29590
30318
  throw new Error("GitHub workspace metadata does not match this repository");
29591
30319
  }
@@ -31194,8 +31922,8 @@ var linearToolPackFactory = {
31194
31922
  async create(grant, context) {
31195
31923
  let resolveCancelled;
31196
31924
  let closed = false;
31197
- const cancelled = new Promise((resolve14) => {
31198
- resolveCancelled = resolve14;
31925
+ const cancelled = new Promise((resolve15) => {
31926
+ resolveCancelled = resolve15;
31199
31927
  });
31200
31928
  const cancel = () => {
31201
31929
  if (closed) return;
@@ -31564,6 +32292,21 @@ var TOOLS = [
31564
32292
  required: ["agent_id", "message"]
31565
32293
  }
31566
32294
  },
32295
+ {
32296
+ name: "message_manager",
32297
+ description: "Message the organization Manager. Use this when a human should be informed or asked through the organization\u2019s conversation front door, or when the Manager should decide how to route what you need. This does not address Slack or WhatsApp directly.",
32298
+ inputSchema: {
32299
+ type: "object",
32300
+ properties: {
32301
+ message: {
32302
+ type: "string",
32303
+ description: "A self-contained report, request, or question for the Manager."
32304
+ }
32305
+ },
32306
+ required: ["message"],
32307
+ additionalProperties: false
32308
+ }
32309
+ },
31567
32310
  {
31568
32311
  name: "get_org_config",
31569
32312
  description: "The organization inventory: connected integrations with their ids and endpoints, MCP connections, and the names of credentials that reach your session as environment variables. Read this before deciding how to reach a system nothing wrapped in a tool.",
@@ -31806,6 +32549,8 @@ function opFor(name, args) {
31806
32549
  message: str("message"),
31807
32550
  ...typeof args["task_id"] === "string" && args["task_id"] ? { taskId: args["task_id"] } : {}
31808
32551
  };
32552
+ case "message_manager":
32553
+ return { kind: "manager.message", message: str("message") };
31809
32554
  case "get_org_config":
31810
32555
  return { kind: "org.config" };
31811
32556
  case "read_credential": {
@@ -31864,7 +32609,7 @@ function createAskUserServer() {
31864
32609
  let server;
31865
32610
  let listening;
31866
32611
  function ensureListening() {
31867
- listening ??= new Promise((resolve14, reject3) => {
32612
+ listening ??= new Promise((resolve15, reject3) => {
31868
32613
  server = createServer2((req, res) => {
31869
32614
  res.on("error", () => {
31870
32615
  });
@@ -31880,7 +32625,7 @@ function createAskUserServer() {
31880
32625
  server.on("error", reject3);
31881
32626
  server.listen(0, "127.0.0.1", () => {
31882
32627
  const address = server.address();
31883
- if (address && typeof address === "object") resolve14(address.port);
32628
+ if (address && typeof address === "object") resolve15(address.port);
31884
32629
  else reject3(new Error("ask_user server failed to bind"));
31885
32630
  });
31886
32631
  server.unref();
@@ -32212,7 +32957,7 @@ function buildRunnerEnv(input) {
32212
32957
  // src/runners/github-shell-auth.ts
32213
32958
  import { execFile } from "node:child_process";
32214
32959
  import { randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
32215
- import { chmod as chmod5, lstat as lstat7, mkdir as mkdir8, realpath as realpath5, writeFile as writeFile4 } from "node:fs/promises";
32960
+ import { chmod as chmod5, lstat as lstat8, mkdir as mkdir8, realpath as realpath5, writeFile as writeFile4 } from "node:fs/promises";
32216
32961
  import { createServer as createServer3 } from "node:http";
32217
32962
  import { isAbsolute as isAbsolute11, join as join12, relative as relative6 } from "node:path";
32218
32963
  var MAX_REQUEST_BYTES2 = 16 * 1024;
@@ -32597,7 +33342,7 @@ async function writePrivate(path, content, executable = false) {
32597
33342
  await chmod5(path, executable ? EXECUTABLE_FILE_MODE : PRIVATE_FILE_MODE);
32598
33343
  }
32599
33344
  async function prepareHelpers(input) {
32600
- const rootEntry = await lstat7(input.runRoot);
33345
+ const rootEntry = await lstat8(input.runRoot);
32601
33346
  if (!rootEntry.isDirectory() || rootEntry.isSymbolicLink()) {
32602
33347
  throw new Error("GitHub shell authentication requires a private real run directory");
32603
33348
  }
@@ -32844,7 +33589,7 @@ password=${credential.accessToken}
32844
33589
 
32845
33590
  // src/runners/working-context.ts
32846
33591
  import { spawn as spawn6 } from "node:child_process";
32847
- import { resolve as resolve5 } from "node:path";
33592
+ import { resolve as resolve6 } from "node:path";
32848
33593
  var COMMAND_TIMEOUT_MS = 5e3;
32849
33594
  var OUTPUT_LIMIT_BYTES = 128 * 1024;
32850
33595
  var COMMAND_STOP_TIMEOUT_MS = 2e4;
@@ -33202,8 +33947,8 @@ async function repositoryState(directory, git, env, signal) {
33202
33947
  const pathLines = paths.trim().split(/\r?\n/);
33203
33948
  if (pathLines.length < 3 || !pathLines[0] || !pathLines[1] || !pathLines[2]) return null;
33204
33949
  const root = pathLines[0];
33205
- const gitDirectory = resolve5(directory, pathLines[1]);
33206
- const commonDirectory = resolve5(directory, pathLines[2]);
33950
+ const gitDirectory = resolve6(directory, pathLines[1]);
33951
+ const commonDirectory = resolve6(directory, pathLines[2]);
33207
33952
  const records = status.split(/\0|\r?\n/).filter(Boolean);
33208
33953
  const rawBranch = statusField(records, "branch.head");
33209
33954
  if (!rawBranch || rawBranch.length > 512 || !isSafeSingleLineDisplayText(rawBranch)) return null;
@@ -33350,18 +34095,18 @@ var WorkingContextPullRequestCache = class {
33350
34095
  import { spawn as spawn7 } from "node:child_process";
33351
34096
  import {
33352
34097
  chmod as chmod6,
33353
- lstat as lstat8,
34098
+ lstat as lstat9,
33354
34099
  mkdir as mkdir9,
33355
- open as open4,
34100
+ open as open5,
33356
34101
  readdir as readdir3,
33357
- readFile as readFile6,
34102
+ readFile as readFile7,
33358
34103
  realpath as realpath6,
33359
- rename as rename4,
33360
- rm as rm6,
34104
+ rename as rename5,
34105
+ rm as rm7,
33361
34106
  writeFile as writeFile5
33362
34107
  } from "node:fs/promises";
33363
34108
  import { homedir as homedir3 } from "node:os";
33364
- import { dirname as dirname5, isAbsolute as isAbsolute12, join as join13, relative as relative7, resolve as resolve6, sep as sep3, win32 as win322 } from "node:path";
34109
+ import { dirname as dirname6, isAbsolute as isAbsolute12, join as join13, relative as relative7, resolve as resolve7, sep as sep3, win32 as win322 } from "node:path";
33365
34110
  var SAFE_SEGMENT2 = /^[A-Za-z0-9_-]{1,200}$/;
33366
34111
  var DIRECTORY_MODE4 = 448;
33367
34112
  var FILE_MODE3 = 384;
@@ -33594,7 +34339,7 @@ function assertBelow3(parent, child) {
33594
34339
  if (escapes) throw new Error("run artifact path escapes its private root");
33595
34340
  }
33596
34341
  async function requireRealDirectory3(path, label) {
33597
- const entry = await lstat8(path);
34342
+ const entry = await lstat9(path);
33598
34343
  if (entry.isSymbolicLink()) throw new Error(`${label} must not be a symbolic link`);
33599
34344
  if (!entry.isDirectory()) throw new Error(`${label} must be a directory`);
33600
34345
  return realpath6(path);
@@ -33611,7 +34356,7 @@ async function rejectWindowsSymlinkAncestors(profile, target) {
33611
34356
  for (const segment of path.split("\\").filter(Boolean)) {
33612
34357
  current = win322.join(current, segment);
33613
34358
  try {
33614
- const entry = await lstat8(current);
34359
+ const entry = await lstat9(current);
33615
34360
  if (entry.isSymbolicLink()) {
33616
34361
  throw new Error("run artifact path must not contain symbolic links or junctions");
33617
34362
  }
@@ -33622,16 +34367,16 @@ async function rejectWindowsSymlinkAncestors(profile, target) {
33622
34367
  }
33623
34368
  }
33624
34369
  async function prepareRoot(root) {
33625
- const absolute = resolve6(root);
34370
+ const absolute = resolve7(root);
33626
34371
  let realProfile;
33627
34372
  if (process.platform === "win32") {
33628
- const profile = resolve6(homedir3());
34373
+ const profile = resolve7(homedir3());
33629
34374
  assertWindowsProfileBoundary(profile, absolute);
33630
34375
  await rejectWindowsSymlinkAncestors(profile, absolute);
33631
34376
  realProfile = await realpath6(profile);
33632
34377
  }
33633
34378
  try {
33634
- await lstat8(absolute);
34379
+ await lstat9(absolute);
33635
34380
  } catch (error52) {
33636
34381
  if (!isMissing(error52)) throw error52;
33637
34382
  await mkdir9(absolute, { recursive: true, mode: DIRECTORY_MODE4 });
@@ -33645,7 +34390,7 @@ async function prepareAgentRoot(root, agentId) {
33645
34390
  const path = join13(root, agentId);
33646
34391
  assertBelow3(root, path);
33647
34392
  try {
33648
- await lstat8(path);
34393
+ await lstat9(path);
33649
34394
  } catch (error52) {
33650
34395
  if (!isMissing(error52)) throw error52;
33651
34396
  try {
@@ -33736,7 +34481,7 @@ async function createRunArtifacts(input) {
33736
34481
  requireSafeSegment(input.agentId, "agentId");
33737
34482
  requireSafeSegment(input.runToken, "runToken");
33738
34483
  const root = await prepareRoot(input.root);
33739
- const removeTree = input.removeTree ?? ((path) => rm6(path, { recursive: true, force: true }));
34484
+ const removeTree = input.removeTree ?? ((path) => rm7(path, { recursive: true, force: true }));
33740
34485
  const cleanupRetryDelayMs = input.cleanupRetryDelayMs ?? CLEANUP_RETRY_DELAY_MS;
33741
34486
  const agentRoot = await prepareAgentRoot(root, input.agentId);
33742
34487
  await lockDownWindowsDirectories([root, agentRoot]);
@@ -33795,10 +34540,10 @@ async function removePrivateTreeWithRetries(path, removeTree, retryDelayMs) {
33795
34540
  }
33796
34541
  }
33797
34542
  async function sweepOrphanedRunArtifacts(root) {
33798
- const absolute = resolve6(root);
34543
+ const absolute = resolve7(root);
33799
34544
  let realProfile;
33800
34545
  if (process.platform === "win32") {
33801
- const profile = resolve6(homedir3());
34546
+ const profile = resolve7(homedir3());
33802
34547
  assertWindowsProfileBoundary(profile, absolute);
33803
34548
  await rejectWindowsSymlinkAncestors(profile, absolute);
33804
34549
  realProfile = await realpath6(profile);
@@ -33823,7 +34568,7 @@ async function sweepOrphanedRunArtifacts(root) {
33823
34568
  if (!SAFE_SEGMENT2.test(run3.name) || !run3.isDirectory() || run3.isSymbolicLink()) continue;
33824
34569
  const runPath = join13(agentPath, run3.name);
33825
34570
  assertBelow3(agentPath, runPath);
33826
- await rm6(runPath, { recursive: true, force: true });
34571
+ await rm7(runPath, { recursive: true, force: true });
33827
34572
  removed++;
33828
34573
  }
33829
34574
  }
@@ -33833,7 +34578,7 @@ function defaultRunRegistryRoot() {
33833
34578
  return join13(homedir3(), ".zixt", "run-registry");
33834
34579
  }
33835
34580
  async function syncRunRegistryDirectory(path) {
33836
- const handle = await open4(path, "r");
34581
+ const handle = await open5(path, "r");
33837
34582
  try {
33838
34583
  await handle.sync();
33839
34584
  } finally {
@@ -33843,9 +34588,9 @@ async function syncRunRegistryDirectory(path) {
33843
34588
  async function ensureDurableRunRegistryRoot(registryRoot, syncDirectory7) {
33844
34589
  const firstCreated = await mkdir9(registryRoot, { recursive: true, mode: DIRECTORY_MODE4 });
33845
34590
  if (firstCreated && process.platform !== "win32") {
33846
- const first = resolve6(firstCreated);
33847
- const target = resolve6(registryRoot);
33848
- await syncDirectory7(dirname5(first));
34591
+ const first = resolve7(firstCreated);
34592
+ const target = resolve7(registryRoot);
34593
+ await syncDirectory7(dirname6(first));
33849
34594
  let current = first;
33850
34595
  for (const part of relative7(first, target).split(sep3).filter(Boolean)) {
33851
34596
  await syncDirectory7(current);
@@ -33862,12 +34607,12 @@ async function recordRunAssignment(runToken, record2, registryRoot = defaultRunR
33862
34607
  try {
33863
34608
  const syncDirectory7 = options.syncDirectory ?? syncRunRegistryDirectory;
33864
34609
  await ensureDurableRunRegistryRoot(registryRoot, syncDirectory7);
33865
- handle = await open4(temporary, "wx", FILE_MODE3);
34610
+ handle = await open5(temporary, "wx", FILE_MODE3);
33866
34611
  await handle.writeFile(JSON.stringify(record2), "utf8");
33867
34612
  await handle.sync();
33868
34613
  await handle.close();
33869
34614
  handle = void 0;
33870
- await rename4(temporary, destination);
34615
+ await rename5(temporary, destination);
33871
34616
  if (process.platform !== "win32") {
33872
34617
  await syncDirectory7(registryRoot);
33873
34618
  }
@@ -33877,7 +34622,7 @@ async function recordRunAssignment(runToken, record2, registryRoot = defaultRunR
33877
34622
  } finally {
33878
34623
  await handle?.close().catch(() => {
33879
34624
  });
33880
- await rm6(temporary, { force: true }).catch(() => {
34625
+ await rm7(temporary, { force: true }).catch(() => {
33881
34626
  });
33882
34627
  }
33883
34628
  }
@@ -33889,7 +34634,7 @@ async function forgetRunAssignment(runToken, registryRoot = defaultRunRegistryRo
33889
34634
  if (retainingAssignments) return;
33890
34635
  if (!SAFE_SEGMENT2.test(runToken)) return;
33891
34636
  try {
33892
- await rm6(join13(registryRoot, `${runToken}.json`), { force: true });
34637
+ await rm7(join13(registryRoot, `${runToken}.json`), { force: true });
33893
34638
  } catch {
33894
34639
  }
33895
34640
  }
@@ -33934,7 +34679,7 @@ async function readRecordedRunAssignmentEntries(registryRoot = defaultRunRegistr
33934
34679
  if (!SAFE_SEGMENT2.test(runToken)) continue;
33935
34680
  let text;
33936
34681
  try {
33937
- text = await readFile6(join13(registryRoot, entry.name), "utf8");
34682
+ text = await readFile7(join13(registryRoot, entry.name), "utf8");
33938
34683
  } catch {
33939
34684
  continue;
33940
34685
  }
@@ -33946,7 +34691,7 @@ async function readRecordedRunAssignmentEntries(registryRoot = defaultRunRegistr
33946
34691
  async function readRecordedRunAssignmentEntriesStrict(registryRoot = defaultRunRegistryRoot()) {
33947
34692
  let rootStat;
33948
34693
  try {
33949
- rootStat = await lstat8(registryRoot);
34694
+ rootStat = await lstat9(registryRoot);
33950
34695
  } catch (error52) {
33951
34696
  if (isMissing(error52)) return [];
33952
34697
  throw new Error("run registry state could not be observed");
@@ -33970,7 +34715,7 @@ async function readRecordedRunAssignmentEntriesStrict(registryRoot = defaultRunR
33970
34715
  }
33971
34716
  let text;
33972
34717
  try {
33973
- text = await readFile6(join13(registryRoot, entry.name), "utf8");
34718
+ text = await readFile7(join13(registryRoot, entry.name), "utf8");
33974
34719
  } catch {
33975
34720
  throw new Error("committed run registry witness could not be read");
33976
34721
  }
@@ -33987,13 +34732,13 @@ async function forgetAcknowledgedRunAssignments(assignments, registryRoot = defa
33987
34732
  );
33988
34733
  const entries = await readRecordedRunAssignmentEntries(registryRoot);
33989
34734
  await Promise.all(
33990
- entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) => rm6(join13(registryRoot, `${runToken}.json`), { force: true }))
34735
+ entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) => rm7(join13(registryRoot, `${runToken}.json`), { force: true }))
33991
34736
  );
33992
34737
  }
33993
34738
  async function forgetSupersededRunAssignments(taskId, epoch, registryRoot = defaultRunRegistryRoot()) {
33994
34739
  const entries = await readRecordedRunAssignmentEntries(registryRoot);
33995
34740
  await Promise.all(
33996
- entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) => rm6(join13(registryRoot, `${runToken}.json`), { force: true }))
34741
+ entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) => rm7(join13(registryRoot, `${runToken}.json`), { force: true }))
33997
34742
  );
33998
34743
  }
33999
34744
 
@@ -34064,7 +34809,7 @@ function truncateThought(text) {
34064
34809
  }
34065
34810
  var MAX_APPROVAL_PAYLOAD = 5e4;
34066
34811
  async function requireRealDirectory4(path, label) {
34067
- const entry = await lstat9(path).catch(() => null);
34812
+ const entry = await lstat10(path).catch(() => null);
34068
34813
  if (!entry) throw new Error(`${label} does not exist`);
34069
34814
  if (entry.isSymbolicLink()) throw new Error(`${label} must not be a symbolic link`);
34070
34815
  if (!entry.isDirectory()) throw new Error(`${label} must be a directory`);
@@ -34080,7 +34825,7 @@ function createCliRunner(adapter, opts = {}) {
34080
34825
  const prefixArgs = opts.commandPrefixArgs ?? [];
34081
34826
  const maxWallTimeMs = opts.maxWallTimeMs;
34082
34827
  const workspaceRoot = opts.workspaceRoot ?? defaultRunnerWorkspaceRoot();
34083
- const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join14(dirname6(workspaceRoot), "run-artifacts"));
34828
+ const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join14(dirname7(workspaceRoot), "run-artifacts"));
34084
34829
  const runRegistryRoot2 = opts.runRegistryRoot ?? defaultRunRegistryRoot();
34085
34830
  const createArtifacts = opts.createArtifacts ?? createRunArtifacts;
34086
34831
  const toolPackRegistry2 = opts.toolPackRegistry ?? createDefaultToolPackRegistry();
@@ -34124,7 +34869,12 @@ function createCliRunner(adapter, opts = {}) {
34124
34869
  usage: { inputTokens: 0, outputTokens: 0 }
34125
34870
  });
34126
34871
  if (task.cancelledNow()) return cancelledBeforeRun();
34127
- const runner = task.spec.runner ?? { type: "claude-code", auth: "machine" };
34872
+ const configuredRunner = task.spec.runner ?? {
34873
+ type: "claude-code",
34874
+ auth: "machine"
34875
+ };
34876
+ const runner = { ...configuredRunner };
34877
+ if (runner.model === "default") delete runner.model;
34128
34878
  if (runner.type !== adapter.type) {
34129
34879
  return {
34130
34880
  outcome: "failed",
@@ -34236,7 +34986,13 @@ function createCliRunner(adapter, opts = {}) {
34236
34986
  )
34237
34987
  );
34238
34988
  }
34239
- if (opts.browserManager) {
34989
+ const browserAvailable = opts.browserAvailable ? await opts.browserAvailable() : true;
34990
+ if (task.spec.requiresBrowser && (!opts.browserManager || !browserAvailable)) {
34991
+ throw new Error(
34992
+ "This Task needs a web browser, but the Browser is no longer available on this Machine. Install the pinned Chromium build or continue the Task on a Browser-ready Machine."
34993
+ );
34994
+ }
34995
+ if (task.spec.requiresBrowser && opts.browserManager && browserAvailable) {
34240
34996
  toolPacks.push(
34241
34997
  createBrowserToolPack({
34242
34998
  manager: opts.browserManager,
@@ -34407,8 +35163,8 @@ ${attachmentSection}` : prompt;
34407
35163
  let changed = false;
34408
35164
  for (const path of paths) {
34409
35165
  if (!path || path.length > 4096) continue;
34410
- const absolutePath = isAbsolute13(path) ? path : resolve7(cwd, path);
34411
- const directory = dirname6(absolutePath);
35166
+ const absolutePath = isAbsolute13(path) ? path : resolve8(cwd, path);
35167
+ const directory = dirname7(absolutePath);
34412
35168
  observedWorkingDirectories.delete(directory);
34413
35169
  observedWorkingDirectories.add(directory);
34414
35170
  while (observedWorkingDirectories.size > 19) {
@@ -34830,7 +35586,7 @@ function runCliProcess(options) {
34830
35586
  usage: { inputTokens: 0, outputTokens: 0 }
34831
35587
  });
34832
35588
  }
34833
- return new Promise((resolve14) => {
35589
+ return new Promise((resolve15) => {
34834
35590
  const platform = options.platform ?? process.platform;
34835
35591
  const containmentGateNonce = options.guardian && platform === "win32" ? randomUUID10() : void 0;
34836
35592
  const child = options.guardian ? spawn8(
@@ -34844,7 +35600,7 @@ function runCliProcess(options) {
34844
35600
  // The idle pre-assignment guardian must never load from or depend
34845
35601
  // on an untrusted Task checkout. Only the post-gate target enters
34846
35602
  // the requested working directory from its private release frame.
34847
- cwd: dirname6(options.guardian.scriptPath),
35603
+ cwd: dirname7(options.guardian.scriptPath),
34848
35604
  env: runnerGuardianEnv(process.env, containmentGateNonce),
34849
35605
  stdio: ["pipe", "pipe", "pipe"],
34850
35606
  windowsHide: true,
@@ -34891,7 +35647,7 @@ function runCliProcess(options) {
34891
35647
  clearInterval(timer);
34892
35648
  unregisterFollowUps?.();
34893
35649
  parser.stop?.();
34894
- resolve14(result);
35650
+ resolve15(result);
34895
35651
  };
34896
35652
  const terminate = (result) => {
34897
35653
  if (settled || forcedResult) return;
@@ -35122,7 +35878,7 @@ function runCliProcess(options) {
35122
35878
  import { randomUUID as randomUUID11 } from "node:crypto";
35123
35879
 
35124
35880
  // src/runners/runtime-observation.ts
35125
- import { open as open5, readdir as readdir4, realpath as realpath8 } from "node:fs/promises";
35881
+ import { open as open6, readdir as readdir4, realpath as realpath8 } from "node:fs/promises";
35126
35882
  import { homedir as homedir5 } from "node:os";
35127
35883
  import { join as join15 } from "node:path";
35128
35884
  var READ_WINDOW_BYTES = 1024 * 1024;
@@ -35134,7 +35890,7 @@ function homeFrom(env) {
35134
35890
  async function readHead(path) {
35135
35891
  let handle;
35136
35892
  try {
35137
- handle = await open5(path, "r");
35893
+ handle = await open6(path, "r");
35138
35894
  const buffer = Buffer.alloc(READ_WINDOW_BYTES);
35139
35895
  const { bytesRead } = await handle.read(buffer, 0, READ_WINDOW_BYTES, 0);
35140
35896
  return buffer.subarray(0, bytesRead).toString("utf8");
@@ -35148,7 +35904,7 @@ async function readHead(path) {
35148
35904
  async function readTail(path) {
35149
35905
  let handle;
35150
35906
  try {
35151
- handle = await open5(path, "r");
35907
+ handle = await open6(path, "r");
35152
35908
  const { size } = await handle.stat();
35153
35909
  const start = Math.max(0, size - READ_WINDOW_BYTES);
35154
35910
  const length = Math.min(size, READ_WINDOW_BYTES);
@@ -35236,7 +35992,7 @@ async function readCodexSessionRuntime(input) {
35236
35992
  }
35237
35993
  var codexCatalogCache = /* @__PURE__ */ new Map();
35238
35994
  async function loadCodexModelCatalog(command, prefixArgs, env) {
35239
- const output = await new Promise((resolve14) => {
35995
+ const output = await new Promise((resolve15) => {
35240
35996
  const child = spawnCli(command, [...prefixArgs, "debug", "models"], {
35241
35997
  stdio: ["ignore", "pipe", "ignore"],
35242
35998
  windowsHide: true,
@@ -35251,7 +36007,7 @@ async function loadCodexModelCatalog(command, prefixArgs, env) {
35251
36007
  if (settled) return;
35252
36008
  settled = true;
35253
36009
  clearTimeout(timer);
35254
- resolve14(value);
36010
+ resolve15(value);
35255
36011
  };
35256
36012
  const timer = setTimeout(() => {
35257
36013
  child.kill();
@@ -35356,8 +36112,8 @@ function createRuntimeReporter(input, sessionId) {
35356
36112
  var EFFORT_READ_ATTEMPTS = 5;
35357
36113
  var EFFORT_READ_INTERVAL_MS = 3e3;
35358
36114
  function delay2(ms) {
35359
- return new Promise((resolve14) => {
35360
- const timer = setTimeout(resolve14, ms);
36115
+ return new Promise((resolve15) => {
36116
+ const timer = setTimeout(resolve15, ms);
35361
36117
  timer.unref?.();
35362
36118
  });
35363
36119
  }
@@ -35434,10 +36190,10 @@ function createClaudeLiveParser(onStream, onSessionModel) {
35434
36190
  },
35435
36191
  async steer(followUp) {
35436
36192
  if (!write) return false;
35437
- return await new Promise((resolve14) => {
35438
- acknowledgements.set(followUp.inputId, resolve14);
36193
+ return await new Promise((resolve15) => {
36194
+ acknowledgements.set(followUp.inputId, resolve15);
35439
36195
  void write(input(followUp.inputId, followUp.text)).catch(() => {
35440
- if (acknowledgements.delete(followUp.inputId)) resolve14(false);
36196
+ if (acknowledgements.delete(followUp.inputId)) resolve15(false);
35441
36197
  });
35442
36198
  });
35443
36199
  },
@@ -35591,13 +36347,13 @@ function improveErrorMessage(error52) {
35591
36347
  return "Anthropic authentication failed. Sign in with `claude` on this host, or set a valid ANTHROPIC_API_KEY secret and switch the agent to API-key auth.";
35592
36348
  }
35593
36349
  if (lower.includes("issue with the selected model") || lower.includes("model_not_found")) {
35594
- return "The selected model is not available. Pick a different model in the agent profile.";
36350
+ return "The selected model is not available. Open the failed Task, choose another model or Default in its runtime controls, then Retry.";
35595
36351
  }
35596
36352
  return error52;
35597
36353
  }
35598
36354
 
35599
36355
  // src/runners/codex.ts
35600
- import { mkdir as mkdir11, readFile as readFile7, writeFile as writeFile6 } from "node:fs/promises";
36356
+ import { mkdir as mkdir11, readFile as readFile8, writeFile as writeFile6 } from "node:fs/promises";
35601
36357
  import { randomUUID as randomUUID12 } from "node:crypto";
35602
36358
  import { homedir as homedir6 } from "node:os";
35603
36359
  import { join as join16 } from "node:path";
@@ -35612,7 +36368,7 @@ function threadIndexPath(root, agentId, sessionKey) {
35612
36368
  }
35613
36369
  async function readThreadId(path) {
35614
36370
  try {
35615
- const parsed = JSON.parse(await readFile7(path, "utf8"));
36371
+ const parsed = JSON.parse(await readFile8(path, "utf8"));
35616
36372
  return typeof parsed.threadId === "string" && /^[A-Za-z0-9-]{1,120}$/.test(parsed.threadId) ? parsed.threadId : null;
35617
36373
  } catch {
35618
36374
  return null;
@@ -35744,8 +36500,8 @@ ${value}` : value;
35744
36500
  var RUNTIME_READ_ATTEMPTS = 5;
35745
36501
  var RUNTIME_READ_INTERVAL_MS = 2e3;
35746
36502
  function delay3(ms) {
35747
- return new Promise((resolve14) => {
35748
- const timer = setTimeout(resolve14, ms);
36503
+ return new Promise((resolve15) => {
36504
+ const timer = setTimeout(resolve15, ms);
35749
36505
  timer.unref?.();
35750
36506
  });
35751
36507
  }
@@ -35784,7 +36540,7 @@ function createCodexAppServerParser(onStream, options) {
35784
36540
  const turnReadyWaiters = /* @__PURE__ */ new Set();
35785
36541
  const usage = () => ({ inputTokens, outputTokens });
35786
36542
  const settleTurnReadiness = (ready) => {
35787
- for (const resolve14 of turnReadyWaiters) resolve14(ready);
36543
+ for (const resolve15 of turnReadyWaiters) resolve15(ready);
35788
36544
  turnReadyWaiters.clear();
35789
36545
  };
35790
36546
  const send = async (message) => {
@@ -35965,12 +36721,12 @@ function createCodexAppServerParser(onStream, options) {
35965
36721
  async steer(input) {
35966
36722
  if (stopped) return false;
35967
36723
  if (!activeTurnId) {
35968
- const ready = await new Promise((resolve14) => turnReadyWaiters.add(resolve14));
36724
+ const ready = await new Promise((resolve15) => turnReadyWaiters.add(resolve15));
35969
36725
  if (!ready || stopped) return false;
35970
36726
  }
35971
36727
  if (!threadId || !activeTurnId) return false;
35972
- return await new Promise((resolve14) => {
35973
- steerWaiters.set(input.inputId, resolve14);
36728
+ return await new Promise((resolve15) => {
36729
+ steerWaiters.set(input.inputId, resolve15);
35974
36730
  void send({
35975
36731
  id: `steer:${input.inputId}`,
35976
36732
  method: "turn/steer",
@@ -35981,7 +36737,7 @@ function createCodexAppServerParser(onStream, options) {
35981
36737
  clientUserMessageId: input.inputId
35982
36738
  }
35983
36739
  }).catch(() => {
35984
- if (steerWaiters.delete(input.inputId)) resolve14(false);
36740
+ if (steerWaiters.delete(input.inputId)) resolve15(false);
35985
36741
  });
35986
36742
  });
35987
36743
  },
@@ -35989,7 +36745,7 @@ function createCodexAppServerParser(onStream, options) {
35989
36745
  stopped = true;
35990
36746
  write = null;
35991
36747
  settleTurnReadiness(false);
35992
- for (const resolve14 of steerWaiters.values()) resolve14(false);
36748
+ for (const resolve15 of steerWaiters.values()) resolve15(false);
35993
36749
  steerWaiters.clear();
35994
36750
  },
35995
36751
  push(chunk) {
@@ -36160,7 +36916,7 @@ function improveCodexErrorMessage(error52) {
36160
36916
  return "OpenAI authentication failed. Sign in with `codex login` on this host, or set a valid OPENAI_API_KEY secret and switch the agent to API-key auth.";
36161
36917
  }
36162
36918
  if (lower.includes("model_not_found") || lower.includes("model") && (lower.includes("not found") || lower.includes("unsupported") || lower.includes("invalid"))) {
36163
- return "The selected model is not available. Pick a different model in the agent profile.";
36919
+ return "The selected model is not available. Open the failed Task, choose another model or Default in its runtime controls, then Retry.";
36164
36920
  }
36165
36921
  return error52;
36166
36922
  }
@@ -36168,7 +36924,7 @@ function improveCodexErrorMessage(error52) {
36168
36924
  // src/runners/git-preflight.ts
36169
36925
  import { spawn as spawn9 } from "node:child_process";
36170
36926
  import { realpath as realpath9 } from "node:fs/promises";
36171
- import { isAbsolute as isAbsolute14, resolve as resolve8 } from "node:path";
36927
+ import { isAbsolute as isAbsolute14, resolve as resolve9 } from "node:path";
36172
36928
  var OUTPUT_LIMIT = 8192;
36173
36929
  var DEFAULT_TIMEOUT_MS4 = 1e4;
36174
36930
  var VERSION_PATTERN = /^git version [^\r\n]{1,108}$/;
@@ -36187,7 +36943,7 @@ async function preflightGit(options = {}) {
36187
36943
  if (configured !== void 0 && !isAbsolute14(configured)) {
36188
36944
  return unavailable("configured git command must be an absolute file", checkedAt);
36189
36945
  }
36190
- const trustedCwd = await realpath9(resolve8(options.trustedCwd ?? process.cwd())).catch(() => null);
36946
+ const trustedCwd = await realpath9(resolve9(options.trustedCwd ?? process.cwd())).catch(() => null);
36191
36947
  if (!trustedCwd)
36192
36948
  return unavailable("Host-owned git preflight directory is unavailable", checkedAt);
36193
36949
  const executablePath = await resolveTrustedCliCommand(configured ?? "git", {
@@ -36409,7 +37165,7 @@ function parseAuth(result) {
36409
37165
  return "unknown";
36410
37166
  }
36411
37167
  function run2(command, args) {
36412
- return new Promise((resolve14) => {
37168
+ return new Promise((resolve15) => {
36413
37169
  const child = spawnCli(command, args, {
36414
37170
  stdio: ["ignore", "pipe", "pipe"],
36415
37171
  windowsHide: true
@@ -36425,7 +37181,7 @@ function run2(command, args) {
36425
37181
  if (settled) return;
36426
37182
  settled = true;
36427
37183
  clearTimeout(timeout);
36428
- resolve14(result);
37184
+ resolve15(result);
36429
37185
  };
36430
37186
  const timeout = setTimeout(() => {
36431
37187
  child.kill();
@@ -36439,9 +37195,9 @@ function run2(command, args) {
36439
37195
  // src/linux-service.ts
36440
37196
  import { spawn as spawn10 } from "node:child_process";
36441
37197
  import { constants as constants2 } from "node:fs";
36442
- import { access as access4, chmod as chmod7, mkdir as mkdir12, open as open6, rename as rename5, rm as rm7 } from "node:fs/promises";
37198
+ import { access as access4, chmod as chmod7, mkdir as mkdir12, open as open7, rename as rename6, rm as rm8 } from "node:fs/promises";
36443
37199
  import { homedir as homedir7, userInfo } from "node:os";
36444
- import { basename as basename3, dirname as dirname7, join as join17, relative as relative8, resolve as resolve9, sep as sep4 } from "node:path";
37200
+ import { basename as basename3, dirname as dirname8, join as join17, relative as relative8, resolve as resolve10, sep as sep4 } from "node:path";
36445
37201
  var SERVICE_NAME = "zixt-host.service";
36446
37202
  var SYSTEM_SERVICE_COMMAND_TIMEOUT_MS = 7e4;
36447
37203
  var SERVICE_STABILITY_DELAY_MS = 2e3;
@@ -36469,7 +37225,7 @@ function boundedAppend(current, chunk) {
36469
37225
  }
36470
37226
  async function defaultRunCommand(command, args) {
36471
37227
  const commandEnvironment3 = systemServiceCommandEnvironment();
36472
- return new Promise((resolve14) => {
37228
+ return new Promise((resolve15) => {
36473
37229
  const child = spawn10(command, [...args], {
36474
37230
  stdio: ["ignore", "pipe", "pipe"],
36475
37231
  env: commandEnvironment3,
@@ -36483,7 +37239,7 @@ async function defaultRunCommand(command, args) {
36483
37239
  if (settled) return;
36484
37240
  settled = true;
36485
37241
  if (timer) clearTimeout(timer);
36486
- resolve14(result);
37242
+ resolve15(result);
36487
37243
  };
36488
37244
  child.stdout?.on("data", (chunk) => {
36489
37245
  stdout = boundedAppend(stdout, chunk);
@@ -36525,11 +37281,16 @@ function systemdQuotedValue(value, escapeDollar) {
36525
37281
  function systemdUnitValue(value) {
36526
37282
  return systemdQuotedValue(value, true);
36527
37283
  }
36528
- function systemdDirectiveValue(value) {
36529
- return systemdQuotedValue(value, false);
37284
+ function systemdDirectivePath(value) {
37285
+ const path = oneLine(value, "service path");
37286
+ if (!path.startsWith("/")) throw new Error("service path must be absolute");
37287
+ return path.replace(/[%\s"'\\$]/gu, (character) => {
37288
+ if (character === "%") return "%%";
37289
+ return [...Buffer.from(character, "utf8")].map((byte) => `\\x${byte.toString(16).padStart(2, "0")}`).join("");
37290
+ });
36530
37291
  }
36531
37292
  async function defaultSyncDirectory(path) {
36532
- const directory = await open6(path, "r");
37293
+ const directory = await open7(path, "r");
36533
37294
  try {
36534
37295
  await directory.sync();
36535
37296
  } finally {
@@ -36539,9 +37300,9 @@ async function defaultSyncDirectory(path) {
36539
37300
  async function ensureDirectory(path, mode, syncDirectory7) {
36540
37301
  const firstCreated = await mkdir12(path, { recursive: true, mode });
36541
37302
  if (!firstCreated) return;
36542
- const first = resolve9(firstCreated);
36543
- const target = resolve9(path);
36544
- await syncDirectory7(dirname7(first));
37303
+ const first = resolve10(firstCreated);
37304
+ const target = resolve10(path);
37305
+ await syncDirectory7(dirname8(first));
36545
37306
  let current = first;
36546
37307
  const descendants = relative8(first, target);
36547
37308
  for (const part of descendants ? descendants.split(sep4) : []) {
@@ -36550,20 +37311,20 @@ async function ensureDirectory(path, mode, syncDirectory7) {
36550
37311
  }
36551
37312
  }
36552
37313
  async function replacePrivateFile(path, contents, mode, syncDirectory7) {
36553
- const parent = dirname7(path);
37314
+ const parent = dirname8(path);
36554
37315
  await ensureDirectory(parent, 448, syncDirectory7);
36555
37316
  const temporary = join17(parent, `.${basename3(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
36556
- const handle = await open6(temporary, "wx", mode);
37317
+ const handle = await open7(temporary, "wx", mode);
36557
37318
  try {
36558
37319
  await handle.writeFile(contents, "utf8");
36559
37320
  await handle.sync();
36560
37321
  await handle.close();
36561
- await rename5(temporary, path);
37322
+ await rename6(temporary, path);
36562
37323
  await chmod7(path, mode);
36563
37324
  await syncDirectory7(parent);
36564
37325
  } catch (error52) {
36565
37326
  await handle.close().catch(() => void 0);
36566
- await rm7(temporary, { force: true }).catch(() => void 0);
37327
+ await rm8(temporary, { force: true }).catch(() => void 0);
36567
37328
  throw error52;
36568
37329
  }
36569
37330
  }
@@ -36614,7 +37375,7 @@ async function installLinuxService(options) {
36614
37375
  const resolveCommand = options.resolveCommand ?? defaultResolveCommand;
36615
37376
  const run3 = options.runCommand ?? defaultRunCommand;
36616
37377
  const syncDirectory7 = options.syncDirectory ?? defaultSyncDirectory;
36617
- const stabilityDelay = options.delay ?? ((ms) => new Promise((resolve14) => setTimeout(resolve14, ms)));
37378
+ const stabilityDelay = options.delay ?? ((ms) => new Promise((resolve15) => setTimeout(resolve15, ms)));
36618
37379
  const [systemctl, loginctl] = await Promise.all([
36619
37380
  resolveCommand("systemctl"),
36620
37381
  resolveCommand("loginctl")
@@ -36661,7 +37422,7 @@ async function installLinuxService(options) {
36661
37422
  // Type=exec does not report startup success until the kernel has executed
36662
37423
  // Node, so a missing/corrupt release cannot masquerade as an active Host.
36663
37424
  "Type=exec",
36664
- `EnvironmentFile=${systemdDirectiveValue(environmentPath)}`,
37425
+ `EnvironmentFile=${systemdDirectivePath(environmentPath)}`,
36665
37426
  `ExecStart=${systemdUnitValue(process.execPath)} ${systemdUnitValue(currentEntry)}`,
36666
37427
  "Restart=on-failure",
36667
37428
  "RestartPreventExitStatus=64",
@@ -36727,9 +37488,9 @@ async function installLinuxService(options) {
36727
37488
  // src/macos-service.ts
36728
37489
  import { spawn as spawn11 } from "node:child_process";
36729
37490
  import { constants as constants3 } from "node:fs";
36730
- import { access as access5, chmod as chmod8, mkdir as mkdir13, open as open7, rename as rename6, rm as rm8 } from "node:fs/promises";
37491
+ import { access as access5, chmod as chmod8, mkdir as mkdir13, open as open8, rename as rename7, rm as rm9 } from "node:fs/promises";
36731
37492
  import { homedir as homedir8, userInfo as userInfo2 } from "node:os";
36732
- import { basename as basename4, dirname as dirname8, join as join18, relative as relative9, resolve as resolve10, sep as sep5 } from "node:path";
37493
+ import { basename as basename4, dirname as dirname9, join as join18, relative as relative9, resolve as resolve11, sep as sep5 } from "node:path";
36733
37494
  var LAUNCH_AGENT_LABEL = "ai.zixt.host";
36734
37495
  var SERVICE_STABILITY_DELAY_MS2 = 2e3;
36735
37496
  var COMMAND_TIMEOUT_MS2 = 7e4;
@@ -36745,7 +37506,7 @@ function shellValue(value) {
36745
37506
  return `'${oneLine2(value, "service setting").replaceAll("'", `'"'"'`)}'`;
36746
37507
  }
36747
37508
  async function syncDirectory4(path) {
36748
- const directory = await open7(path, "r");
37509
+ const directory = await open8(path, "r");
36749
37510
  try {
36750
37511
  await directory.sync();
36751
37512
  } finally {
@@ -36755,9 +37516,9 @@ async function syncDirectory4(path) {
36755
37516
  async function ensureDirectory2(path, sync) {
36756
37517
  const firstCreated = await mkdir13(path, { recursive: true, mode: 448 });
36757
37518
  if (!firstCreated) return;
36758
- const first = resolve10(firstCreated);
36759
- const target = resolve10(path);
36760
- await sync(dirname8(first));
37519
+ const first = resolve11(firstCreated);
37520
+ const target = resolve11(path);
37521
+ await sync(dirname9(first));
36761
37522
  let current = first;
36762
37523
  for (const part of relative9(first, target).split(sep5).filter(Boolean)) {
36763
37524
  await sync(current);
@@ -36765,20 +37526,20 @@ async function ensureDirectory2(path, sync) {
36765
37526
  }
36766
37527
  }
36767
37528
  async function replacePrivateFile2(path, contents, mode, sync) {
36768
- const parent = dirname8(path);
37529
+ const parent = dirname9(path);
36769
37530
  await ensureDirectory2(parent, sync);
36770
37531
  const temporary = join18(parent, `.${basename4(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
36771
- const handle = await open7(temporary, "wx", mode);
37532
+ const handle = await open8(temporary, "wx", mode);
36772
37533
  try {
36773
37534
  await handle.writeFile(contents, "utf8");
36774
37535
  await handle.sync();
36775
37536
  await handle.close();
36776
- await rename6(temporary, path);
37537
+ await rename7(temporary, path);
36777
37538
  await chmod8(path, mode);
36778
37539
  await sync(parent);
36779
37540
  } catch (error52) {
36780
37541
  await handle.close().catch(() => void 0);
36781
- await rm8(temporary, { force: true }).catch(() => void 0);
37542
+ await rm9(temporary, { force: true }).catch(() => void 0);
36782
37543
  throw error52;
36783
37544
  }
36784
37545
  }
@@ -36958,9 +37719,9 @@ async function installMacosService(options) {
36958
37719
  // src/windows-service.ts
36959
37720
  import { spawn as spawn12 } from "node:child_process";
36960
37721
  import { constants as constants4 } from "node:fs";
36961
- import { access as access6, mkdir as mkdir14, open as open8, readFile as readFile8, rename as rename7, rm as rm9 } from "node:fs/promises";
37722
+ import { access as access6, mkdir as mkdir14, open as open9, readFile as readFile9, rename as rename8, rm as rm10 } from "node:fs/promises";
36962
37723
  import { homedir as homedir9 } from "node:os";
36963
- import { basename as basename5, dirname as dirname9, isAbsolute as isAbsolute15, join as join19, relative as relative10, resolve as resolve11, sep as sep6 } from "node:path";
37724
+ import { basename as basename5, dirname as dirname10, isAbsolute as isAbsolute15, join as join19, relative as relative10, resolve as resolve12, sep as sep6 } from "node:path";
36964
37725
  var TASK_NAME = "Zixt Host";
36965
37726
  var COMMAND_TIMEOUT_MS3 = 7e4;
36966
37727
  var SERVICE_STABILITY_DELAY_MS3 = 2e3;
@@ -36978,7 +37739,7 @@ function psLiteral(value) {
36978
37739
  }
36979
37740
  async function syncDirectory5(path) {
36980
37741
  if (process.platform === "win32") return;
36981
- const directory = await open8(path, "r");
37742
+ const directory = await open9(path, "r");
36982
37743
  try {
36983
37744
  await directory.sync();
36984
37745
  } finally {
@@ -36988,9 +37749,9 @@ async function syncDirectory5(path) {
36988
37749
  async function ensureDirectory3(path, sync) {
36989
37750
  const firstCreated = await mkdir14(path, { recursive: true, mode: 448 });
36990
37751
  if (!firstCreated) return;
36991
- const first = resolve11(firstCreated);
36992
- const target = resolve11(path);
36993
- await sync(dirname9(first));
37752
+ const first = resolve12(firstCreated);
37753
+ const target = resolve12(path);
37754
+ await sync(dirname10(first));
36994
37755
  let current = first;
36995
37756
  for (const part of relative10(first, target).split(sep6).filter(Boolean)) {
36996
37757
  await sync(current);
@@ -36998,19 +37759,19 @@ async function ensureDirectory3(path, sync) {
36998
37759
  }
36999
37760
  }
37000
37761
  async function replacePrivateFile3(path, contents, sync) {
37001
- const parent = dirname9(path);
37762
+ const parent = dirname10(path);
37002
37763
  await ensureDirectory3(parent, sync);
37003
37764
  const temporary = join19(parent, `.${basename5(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
37004
- const handle = await open8(temporary, "wx", 384);
37765
+ const handle = await open9(temporary, "wx", 384);
37005
37766
  try {
37006
37767
  await handle.writeFile(contents, "utf8");
37007
37768
  await handle.sync();
37008
37769
  await handle.close();
37009
- await rename7(temporary, path);
37770
+ await rename8(temporary, path);
37010
37771
  await sync(parent);
37011
37772
  } catch (error52) {
37012
37773
  await handle.close().catch(() => void 0);
37013
- await rm9(temporary, { force: true }).catch(() => void 0);
37774
+ await rm10(temporary, { force: true }).catch(() => void 0);
37014
37775
  throw error52;
37015
37776
  }
37016
37777
  }
@@ -37143,7 +37904,7 @@ exit $code
37143
37904
  }
37144
37905
  async function defaultObserveStatus(path, generation) {
37145
37906
  try {
37146
- const text = (await readFile8(path, "utf8")).replace(/^\uFEFF/, "");
37907
+ const text = (await readFile9(path, "utf8")).replace(/^\uFEFF/, "");
37147
37908
  const value = JSON.parse(text);
37148
37909
  if (value.schema !== 1 || value.generation !== generation || typeof value.pid !== "number" || !Number.isSafeInteger(value.pid) || value.pid <= 0) {
37149
37910
  return null;
@@ -37245,7 +38006,7 @@ async function installWindowsService(options) {
37245
38006
  );
37246
38007
  await replacePrivateFile3(launcherPath, launcherSource2(configPath, statusPath), sync);
37247
38008
  await replacePrivateFile3(taskXmlPath, taskXml({ sid, powershell, launcherPath, home }), sync);
37248
- await rm9(statusPath, { force: true });
38009
+ await rm10(statusPath, { force: true });
37249
38010
  const acl = await run3(icacls, [
37250
38011
  configRoot,
37251
38012
  "/inheritance:r",
@@ -37297,9 +38058,9 @@ async function installSystemService(options) {
37297
38058
  }
37298
38059
 
37299
38060
  // src/terminal-outcomes.ts
37300
- import { chmod as chmod9, lstat as lstat10, mkdir as mkdir15, open as open9, readdir as readdir5, readFile as readFile9, rename as rename8, rm as rm10 } from "node:fs/promises";
38061
+ import { chmod as chmod9, lstat as lstat11, mkdir as mkdir15, open as open10, readdir as readdir5, readFile as readFile10, rename as rename9, rm as rm11 } from "node:fs/promises";
37301
38062
  import { homedir as homedir10 } from "node:os";
37302
- import { dirname as dirname10, join as join20, relative as relative11, resolve as resolve12, sep as sep7 } from "node:path";
38063
+ import { dirname as dirname11, join as join20, relative as relative11, resolve as resolve13, sep as sep7 } from "node:path";
37303
38064
  var DIRECTORY_MODE5 = 448;
37304
38065
  var FILE_MODE4 = 384;
37305
38066
  var MAX_OUTCOME_BYTES = 4 * 1024 * 1024;
@@ -37317,7 +38078,7 @@ function outcomePath(root, hostId, taskId, epoch) {
37317
38078
  }
37318
38079
  async function syncDirectory6(root) {
37319
38080
  if (process.platform === "win32") return;
37320
- const handle = await open9(root, "r");
38081
+ const handle = await open10(root, "r");
37321
38082
  try {
37322
38083
  await handle.sync();
37323
38084
  } finally {
@@ -37327,16 +38088,16 @@ async function syncDirectory6(root) {
37327
38088
  async function requirePrivateRoot(root, sync = syncDirectory6) {
37328
38089
  const firstCreated = await mkdir15(root, { recursive: true, mode: DIRECTORY_MODE5 });
37329
38090
  if (firstCreated) {
37330
- const first = resolve12(firstCreated);
37331
- const target = resolve12(root);
37332
- await sync(dirname10(first));
38091
+ const first = resolve13(firstCreated);
38092
+ const target = resolve13(root);
38093
+ await sync(dirname11(first));
37333
38094
  let current = first;
37334
38095
  for (const part of relative11(first, target).split(sep7).filter(Boolean)) {
37335
38096
  await sync(current);
37336
38097
  current = join20(current, part);
37337
38098
  }
37338
38099
  }
37339
- const stat3 = await lstat10(root);
38100
+ const stat3 = await lstat11(root);
37340
38101
  if (stat3.isSymbolicLink() || !stat3.isDirectory()) {
37341
38102
  throw new Error("terminal outcome journal root is not a trusted directory");
37342
38103
  }
@@ -37364,7 +38125,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
37364
38125
  const destination = outcomePath(root, hostId, outcome.taskId, outcome.epoch);
37365
38126
  try {
37366
38127
  const existing = parseCommittedOutcome(
37367
- await readFile9(destination, { encoding: "utf8", flag: "r" }),
38128
+ await readFile10(destination, { encoding: "utf8", flag: "r" }),
37368
38129
  outcome.taskId,
37369
38130
  outcome.epoch
37370
38131
  );
@@ -37379,25 +38140,25 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
37379
38140
  );
37380
38141
  let handle;
37381
38142
  try {
37382
- handle = await open9(temporary, "wx", FILE_MODE4);
38143
+ handle = await open10(temporary, "wx", FILE_MODE4);
37383
38144
  await handle.writeFile(JSON.stringify(outcome), "utf8");
37384
38145
  await handle.sync();
37385
38146
  await handle.close();
37386
38147
  handle = void 0;
37387
- await rename8(temporary, destination);
38148
+ await rename9(temporary, destination);
37388
38149
  await sync(scopedRoot);
37389
38150
  await sync(root);
37390
38151
  } finally {
37391
38152
  await handle?.close().catch(() => {
37392
38153
  });
37393
- await rm10(temporary, { force: true }).catch(() => {
38154
+ await rm11(temporary, { force: true }).catch(() => {
37394
38155
  });
37395
38156
  }
37396
38157
  }
37397
38158
  async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
37398
38159
  let rootStat;
37399
38160
  try {
37400
- rootStat = await lstat10(root);
38161
+ rootStat = await lstat11(root);
37401
38162
  } catch (error52) {
37402
38163
  if (error52.code === "ENOENT") return [];
37403
38164
  throw new Error("terminal outcome journal could not be observed");
@@ -37414,7 +38175,7 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
37414
38175
  throw new Error("terminal outcome Host scope is not a trusted directory");
37415
38176
  }
37416
38177
  const scopedRoot = hostOutcomeRoot(root, hostEntry.name);
37417
- const scopedStat = await lstat10(scopedRoot);
38178
+ const scopedStat = await lstat11(scopedRoot);
37418
38179
  if (scopedStat.isSymbolicLink() || !scopedStat.isDirectory()) {
37419
38180
  throw new Error("terminal outcome Host scope is not a trusted directory");
37420
38181
  }
@@ -37427,12 +38188,12 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
37427
38188
  throw new Error("committed terminal outcome is not a trusted regular file");
37428
38189
  }
37429
38190
  const path = join20(scopedRoot, entry.name);
37430
- const stat3 = await lstat10(path);
38191
+ const stat3 = await lstat11(path);
37431
38192
  if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_OUTCOME_BYTES) {
37432
38193
  throw new Error("committed terminal outcome is not a trusted regular file");
37433
38194
  }
37434
38195
  const outcome = parseCommittedOutcome(
37435
- await readFile9(path, "utf8"),
38196
+ await readFile10(path, "utf8"),
37436
38197
  match[1],
37437
38198
  Number(match[2])
37438
38199
  );
@@ -37459,7 +38220,7 @@ async function forgetAcknowledgedTerminalOutcomes(refs, root = defaultTerminalOu
37459
38220
  if (acknowledged.get(`${hostId}:${outcome.taskId}:${outcome.epoch}`) !== outcome.resultId) {
37460
38221
  continue;
37461
38222
  }
37462
- await rm10(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
38223
+ await rm11(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
37463
38224
  changedHostRoots.add(hostOutcomeRoot(root, hostId));
37464
38225
  }
37465
38226
  for (const scopedRoot of changedHostRoots) await syncDirectory6(scopedRoot);
@@ -37471,7 +38232,7 @@ async function forgetSupersededTerminalOutcomes(hostId, taskId, epoch, root = de
37471
38232
  if (scoped.hostId !== hostId) continue;
37472
38233
  const { outcome } = scoped;
37473
38234
  if (outcome.taskId !== taskId || outcome.epoch >= epoch) continue;
37474
- await rm10(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
38235
+ await rm11(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
37475
38236
  removed = true;
37476
38237
  }
37477
38238
  if (removed) await syncDirectory6(hostOutcomeRoot(root, hostId));
@@ -37579,12 +38340,12 @@ function createHostLogger(options = {}) {
37579
38340
  }
37580
38341
 
37581
38342
  // src/demo-state.ts
37582
- import { isAbsolute as isAbsolute16, join as join21, parse as parse3, resolve as resolve13 } from "node:path";
38343
+ import { isAbsolute as isAbsolute16, join as join21, parse as parse3, resolve as resolve14 } from "node:path";
37583
38344
  var DEMO_STATE_ROOT_ENV = "ZIXT_DEMO_STATE_ROOT";
37584
38345
  function resolveDemoHostStatePaths(env = process.env) {
37585
38346
  const configured = env.ZIXT_RUNNER === "demo" ? env[DEMO_STATE_ROOT_ENV] : void 0;
37586
38347
  if (!configured) return null;
37587
- const root = resolve13(configured);
38348
+ const root = resolve14(configured);
37588
38349
  if (!isAbsolute16(configured) || root === parse3(root).root) {
37589
38350
  throw new Error(`${DEMO_STATE_ROOT_ENV} must be a dedicated absolute directory`);
37590
38351
  }
@@ -37694,6 +38455,8 @@ function taskSourceLabel(origin) {
37694
38455
  return "Message";
37695
38456
  case "webhook":
37696
38457
  return "Webhook";
38458
+ case "manager":
38459
+ return "Manager";
37697
38460
  default:
37698
38461
  return void 0;
37699
38462
  }
@@ -37904,6 +38667,7 @@ var claudeCode = createClaudeCodeRunner({
37904
38667
  ...runRegistryRoot ? { runRegistryRoot } : {},
37905
38668
  toolPackRegistry,
37906
38669
  browserManager,
38670
+ browserAvailable: async () => (await currentBrowserCapability()).status === "ok",
37907
38671
  gitPreflight: currentGitPreflight,
37908
38672
  onUnsafeRunnerCleanup: restartAfterUnsafeRunnerCleanup
37909
38673
  });
@@ -37914,6 +38678,7 @@ var codex = createCodexRunner({
37914
38678
  ...codexThreadIndexRoot ? { threadIndexRoot: codexThreadIndexRoot } : {},
37915
38679
  toolPackRegistry,
37916
38680
  browserManager,
38681
+ browserAvailable: async () => (await currentBrowserCapability()).status === "ok",
37917
38682
  gitPreflight: currentGitPreflight,
37918
38683
  onUnsafeRunnerCleanup: restartAfterUnsafeRunnerCleanup
37919
38684
  });