@zixt/host 0.0.44 → 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.
- package/dist/index.js +908 -302
- 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.
|
|
34
|
+
version: "0.0.45",
|
|
35
35
|
type: "module",
|
|
36
36
|
exports: {
|
|
37
37
|
".": "./src/client.ts",
|
|
@@ -14656,7 +14656,9 @@ var ID_PREFIXES = {
|
|
|
14656
14656
|
/** One immutable Conversation timeline entry. */
|
|
14657
14657
|
conversationEvent: "cve",
|
|
14658
14658
|
/** One Manager inference call's token-metering row (MG-8). */
|
|
14659
|
-
managerUsage: "mgu"
|
|
14659
|
+
managerUsage: "mgu",
|
|
14660
|
+
/** One ordered Manager reply awaiting Slack delivery. */
|
|
14661
|
+
managerSlackOutbox: "mso"
|
|
14660
14662
|
};
|
|
14661
14663
|
var idPattern = (prefix) => new RegExp(`^${prefix}_[0-9a-f]{32}$`);
|
|
14662
14664
|
function newId(prefix) {
|
|
@@ -14786,15 +14788,24 @@ var WebLoginValue = external_exports.object({
|
|
|
14786
14788
|
username: external_exports.string().min(1).max(500),
|
|
14787
14789
|
password: external_exports.string().min(1).max(5e3)
|
|
14788
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();
|
|
14789
14795
|
var BrowserSessionProjection = external_exports.object({
|
|
14790
14796
|
status: external_exports.enum(["none", "starting", "live"]),
|
|
14791
14797
|
session: BrowserSessionState.optional(),
|
|
14792
14798
|
/** Whether Start would find an online Machine with a working browser. */
|
|
14793
14799
|
canStart: external_exports.boolean(),
|
|
14794
14800
|
/** Member-safe reason when canStart is false. */
|
|
14795
|
-
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()
|
|
14796
14808
|
}).strict();
|
|
14797
|
-
var StartBrowserSessionResponse = external_exports.object({ session: BrowserSessionState }).strict();
|
|
14798
14809
|
var StopBrowserSessionResponse = external_exports.object({ stopped: external_exports.boolean() }).strict();
|
|
14799
14810
|
var BrowserViewTicketResponse = external_exports.object({ ticket: external_exports.string().min(1).max(200) }).strict();
|
|
14800
14811
|
|
|
@@ -14818,6 +14829,7 @@ var ACTION_CATEGORIES = [
|
|
|
14818
14829
|
"records.modify",
|
|
14819
14830
|
"records.delete",
|
|
14820
14831
|
"docker",
|
|
14832
|
+
"browser.use",
|
|
14821
14833
|
"mcp.call",
|
|
14822
14834
|
"spend_money"
|
|
14823
14835
|
];
|
|
@@ -14856,6 +14868,7 @@ var DEFAULT_GUARDRAIL_POLICY = {
|
|
|
14856
14868
|
"records.modify": "allow",
|
|
14857
14869
|
"records.delete": "allow",
|
|
14858
14870
|
docker: "allow",
|
|
14871
|
+
"browser.use": "allow",
|
|
14859
14872
|
"mcp.call": "allow",
|
|
14860
14873
|
spend_money: "allow"
|
|
14861
14874
|
};
|
|
@@ -15317,6 +15330,16 @@ var Agent = external_exports.object({
|
|
|
15317
15330
|
orgId: OrgId,
|
|
15318
15331
|
name: external_exports.string().min(1).max(120),
|
|
15319
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),
|
|
15320
15343
|
roleDescription: external_exports.string().max(2e3).default(""),
|
|
15321
15344
|
/** Persona instructions — system-prompt-like free text (AG-1). */
|
|
15322
15345
|
instructions: external_exports.string().max(5e4).default(""),
|
|
@@ -15492,6 +15515,11 @@ var Host = external_exports.object({
|
|
|
15492
15515
|
status: HostStatus,
|
|
15493
15516
|
/** Persistent assignment admission; pausing never changes socket presence or live work. */
|
|
15494
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),
|
|
15495
15523
|
/** `desktop` today; `cloud` when pods run the same host (PRD §7.6). */
|
|
15496
15524
|
kind: external_exports.enum(["desktop", "cloud"]),
|
|
15497
15525
|
lastSeenAt: IsoDate2.nullable(),
|
|
@@ -16012,6 +16040,8 @@ var Task = external_exports.object({
|
|
|
16012
16040
|
* its first Machine; assignment then records that choice for later runs.
|
|
16013
16041
|
*/
|
|
16014
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),
|
|
16015
16045
|
/** TS-16: per-Task runner/model/effort selection; null runs the teammate's configuration. */
|
|
16016
16046
|
runner: TaskRunnerSelection.nullable().default(null),
|
|
16017
16047
|
/**
|
|
@@ -16169,6 +16199,8 @@ var CreateTaskInput = external_exports.object({
|
|
|
16169
16199
|
* another Machine truthfully queues this Task rather than overriding it.
|
|
16170
16200
|
*/
|
|
16171
16201
|
requestedHostId: HostId.optional(),
|
|
16202
|
+
/** Require a fresh, working AI teammate Browser on the selected Machine. */
|
|
16203
|
+
requiresBrowser: external_exports.boolean().optional(),
|
|
16172
16204
|
/** Per-Task runner/model/effort selection (TS-16); absent fields fall back to the teammate's configuration. */
|
|
16173
16205
|
runner: TaskRunnerSelection.optional(),
|
|
16174
16206
|
/** Files uploaded ahead of this message; each may belong to one Task only (TS-15). */
|
|
@@ -16470,12 +16502,15 @@ var TaskSupportBundle = external_exports.object({
|
|
|
16470
16502
|
})
|
|
16471
16503
|
)
|
|
16472
16504
|
});
|
|
16505
|
+
var TASK_LIST_MAX_LIMIT = 200;
|
|
16473
16506
|
var ListTasksResponse = external_exports.object({
|
|
16474
|
-
tasks: external_exports.array(TaskProjection)
|
|
16475
|
-
|
|
16507
|
+
tasks: external_exports.array(TaskProjection).max(TASK_LIST_MAX_LIMIT),
|
|
16508
|
+
nextCursor: external_exports.string().nullable()
|
|
16509
|
+
}).strict();
|
|
16476
16510
|
|
|
16477
16511
|
// ../../packages/contracts/src/protocol.ts
|
|
16478
|
-
var PROTOCOL_VERSION =
|
|
16512
|
+
var PROTOCOL_VERSION = 7;
|
|
16513
|
+
var BROWSER_PROFILE_INVENTORY_PAGE_SIZE = 200;
|
|
16479
16514
|
var TASK_CANCEL_ACK_EVENT = "zixt.task.cancel.acknowledged";
|
|
16480
16515
|
var TASK_CREDENTIAL_ROLLOVER_ACK_EVENT = "zixt.task.credential_rollover.acknowledged";
|
|
16481
16516
|
var UnwoundAssignmentRef = external_exports.object({
|
|
@@ -16753,6 +16788,11 @@ var AgentOp = external_exports.union([
|
|
|
16753
16788
|
}),
|
|
16754
16789
|
external_exports.object({ kind: external_exports.literal("secret.list") }),
|
|
16755
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
|
+
}),
|
|
16756
16796
|
/** Read one teammate's non-secret standing configuration; omission means self. */
|
|
16757
16797
|
external_exports.object({ kind: external_exports.literal("agent.get"), agentId: AgentId.optional() }),
|
|
16758
16798
|
/**
|
|
@@ -16953,6 +16993,12 @@ var TaskAssign = external_exports.object({
|
|
|
16953
16993
|
type: external_exports.literal("task.assign"),
|
|
16954
16994
|
taskId: TaskId,
|
|
16955
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(),
|
|
16956
17002
|
epoch: external_exports.number().int().min(1),
|
|
16957
17003
|
/**
|
|
16958
17004
|
* Host-enforced task authority deadline, when anything forces one.
|
|
@@ -17029,6 +17075,11 @@ var TaskAssign = external_exports.object({
|
|
|
17029
17075
|
titleWanted: external_exports.boolean().optional(),
|
|
17030
17076
|
/** Advisory Ask / Plan / Act snapshot for this attempt (TS-12). */
|
|
17031
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(),
|
|
17032
17083
|
/** Configured workspace selected by the cloud; absence means no repository context. */
|
|
17033
17084
|
workspace: SafeDisplayPath.optional(),
|
|
17034
17085
|
/** Verified provider repository selected independently of a local workspace path. */
|
|
@@ -17439,6 +17490,12 @@ var BrowserOpenFrame = external_exports.object({
|
|
|
17439
17490
|
type: external_exports.literal("browser.open"),
|
|
17440
17491
|
requestId: external_exports.string().min(1).max(200),
|
|
17441
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(),
|
|
17442
17499
|
/** Cloud-minted; the host adopts it for the session it opens. */
|
|
17443
17500
|
browserSessionId: external_exports.string().min(1).max(200),
|
|
17444
17501
|
viewport: BrowserViewport
|
|
@@ -17467,6 +17524,18 @@ var BrowserCommandFrame = external_exports.object({
|
|
|
17467
17524
|
browserSessionId: external_exports.string().min(1).max(200),
|
|
17468
17525
|
command: BrowserCommand
|
|
17469
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();
|
|
17470
17539
|
var TaskInput = external_exports.object({
|
|
17471
17540
|
type: external_exports.literal("task.input"),
|
|
17472
17541
|
taskId: TaskId,
|
|
@@ -17480,7 +17549,8 @@ var DurableDownMessage = external_exports.discriminatedUnion("type", [
|
|
|
17480
17549
|
TaskInput,
|
|
17481
17550
|
SecretsGrant,
|
|
17482
17551
|
ApprovalDecision,
|
|
17483
|
-
ConnectionsGrant
|
|
17552
|
+
ConnectionsGrant,
|
|
17553
|
+
BrowserProfilePurge
|
|
17484
17554
|
]);
|
|
17485
17555
|
var TaskEvent = external_exports.object({
|
|
17486
17556
|
type: external_exports.literal("task.event"),
|
|
@@ -17633,6 +17703,15 @@ var HelloFrame = external_exports.object({
|
|
|
17633
17703
|
protocolVersion: external_exports.number().int(),
|
|
17634
17704
|
/** Highest outbox seq the host has durably processed; cloud replays after it. */
|
|
17635
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(),
|
|
17636
17715
|
/**
|
|
17637
17716
|
* Exact assignments whose local executors finished unwinding after the
|
|
17638
17717
|
* prior socket died. Optional for rolling v5 hosts; repeated references are
|
|
@@ -17640,6 +17719,11 @@ var HelloFrame = external_exports.object({
|
|
|
17640
17719
|
*/
|
|
17641
17720
|
unwoundAssignments: external_exports.array(UnwoundAssignmentRef).max(1e3).optional()
|
|
17642
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();
|
|
17643
17727
|
var HelloAckFrame = external_exports.object({
|
|
17644
17728
|
type: external_exports.literal("helloAck"),
|
|
17645
17729
|
protocolVersion: external_exports.number().int(),
|
|
@@ -17722,6 +17806,7 @@ var PingFrame = external_exports.object({ type: external_exports.literal("ping")
|
|
|
17722
17806
|
var PongFrame = external_exports.object({ type: external_exports.literal("pong"), at: external_exports.iso.datetime() });
|
|
17723
17807
|
var HostToCloudFrame = external_exports.discriminatedUnion("type", [
|
|
17724
17808
|
HelloFrame,
|
|
17809
|
+
BrowserProfileInventoryFrame,
|
|
17725
17810
|
AckFrame,
|
|
17726
17811
|
UpFrame,
|
|
17727
17812
|
ProviderOperationGrantRequestFrame,
|
|
@@ -17729,6 +17814,7 @@ var HostToCloudFrame = external_exports.discriminatedUnion("type", [
|
|
|
17729
17814
|
BrowserScreencastFrame,
|
|
17730
17815
|
BrowserSessionEndedFrame,
|
|
17731
17816
|
BrowserCredentialRequestFrame,
|
|
17817
|
+
BrowserProfilePurged,
|
|
17732
17818
|
PingFrame,
|
|
17733
17819
|
PongFrame
|
|
17734
17820
|
]);
|
|
@@ -18045,7 +18131,9 @@ var HostRemovalOutcome = external_exports.object({
|
|
|
18045
18131
|
});
|
|
18046
18132
|
var RevokeHostResponse = external_exports.object({
|
|
18047
18133
|
host: AdminHostProjection,
|
|
18048
|
-
removal: HostRemovalOutcome
|
|
18134
|
+
removal: HostRemovalOutcome,
|
|
18135
|
+
/** False while the paired Host is retained solely to finish profile deletion. */
|
|
18136
|
+
removed: external_exports.boolean()
|
|
18049
18137
|
});
|
|
18050
18138
|
var MemberHostProjection = Host.pick({
|
|
18051
18139
|
id: true,
|
|
@@ -18054,6 +18142,7 @@ var MemberHostProjection = Host.pick({
|
|
|
18054
18142
|
operatingSystem: true,
|
|
18055
18143
|
status: true,
|
|
18056
18144
|
acceptingNewWork: true,
|
|
18145
|
+
profileCleanup: true,
|
|
18057
18146
|
kind: true,
|
|
18058
18147
|
lastSeenAt: true,
|
|
18059
18148
|
telemetryAt: true,
|
|
@@ -18636,18 +18725,28 @@ var ConversationChannel = external_exports.enum(["web", "slack", "whatsapp"]);
|
|
|
18636
18725
|
var ConversationStatus = external_exports.enum(["idle", "thinking"]);
|
|
18637
18726
|
var ConversationProjection = external_exports.object({
|
|
18638
18727
|
id: ConversationId,
|
|
18639
|
-
/** First
|
|
18728
|
+
/** First-message prefix until the one creation-time Manager title call settles. */
|
|
18640
18729
|
title: external_exports.string().min(1).max(200),
|
|
18641
18730
|
channel: ConversationChannel,
|
|
18642
18731
|
status: ConversationStatus,
|
|
18643
18732
|
/** TS-10 origin trust of the channel; propagated into every delegated Task. */
|
|
18644
18733
|
trust: external_exports.enum(["internal", "external"]),
|
|
18645
|
-
/**
|
|
18646
|
-
|
|
18734
|
+
/** One-use override for the next Task delegated from this thread. */
|
|
18735
|
+
nextDelegationRunner: TaskRunnerSelection.nullable(),
|
|
18647
18736
|
createdAt: external_exports.string(),
|
|
18648
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(),
|
|
18649
18740
|
archivedAt: external_exports.string().nullable()
|
|
18650
|
-
}).strict()
|
|
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
|
+
});
|
|
18651
18750
|
var conversationEventBase = {
|
|
18652
18751
|
id: ConversationEventId,
|
|
18653
18752
|
at: external_exports.string()
|
|
@@ -18658,7 +18757,9 @@ var ConversationEventProjection = external_exports.discriminatedUnion("kind", [
|
|
|
18658
18757
|
...conversationEventBase,
|
|
18659
18758
|
kind: external_exports.literal("user"),
|
|
18660
18759
|
text: external_exports.string(),
|
|
18661
|
-
|
|
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()
|
|
18662
18763
|
}).strict(),
|
|
18663
18764
|
/** The Manager's prose reply. */
|
|
18664
18765
|
external_exports.object({ ...conversationEventBase, kind: external_exports.literal("manager"), text: external_exports.string() }).strict(),
|
|
@@ -18677,21 +18778,70 @@ var ConversationEventProjection = external_exports.discriminatedUnion("kind", [
|
|
|
18677
18778
|
kind: external_exports.literal("task"),
|
|
18678
18779
|
taskId: TaskId,
|
|
18679
18780
|
agentId: AgentId.nullable(),
|
|
18680
|
-
eventKind: external_exports.enum(["response", "error", "status", "question"]),
|
|
18781
|
+
eventKind: external_exports.enum(["response", "error", "status", "question", "message"]),
|
|
18681
18782
|
summary: external_exports.string(),
|
|
18682
|
-
taskStatus: TaskStatus.nullable()
|
|
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()
|
|
18683
18791
|
}).strict(),
|
|
18684
18792
|
/** A Manager loop failure a person should see (provider outage, refusal). */
|
|
18685
18793
|
external_exports.object({ ...conversationEventBase, kind: external_exports.literal("error"), message: external_exports.string() }).strict()
|
|
18686
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
|
+
);
|
|
18687
18799
|
var CreateConversationRequest = external_exports.object({
|
|
18688
18800
|
/** Stable client-generated key: retrying the same submission returns one Conversation. */
|
|
18689
18801
|
requestId: external_exports.uuid(),
|
|
18690
|
-
message: external_exports.string().
|
|
18691
|
-
|
|
18692
|
-
|
|
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();
|
|
18693
18843
|
var UpdateConversationRequest = external_exports.object({
|
|
18694
|
-
title: external_exports.string().min(1).max(200).optional(),
|
|
18844
|
+
title: external_exports.string().trim().min(1).max(200).optional(),
|
|
18695
18845
|
archived: external_exports.boolean().optional()
|
|
18696
18846
|
}).strict().superRefine((value, ctx) => {
|
|
18697
18847
|
if (value.title === void 0 && value.archived === void 0) {
|
|
@@ -18699,7 +18849,47 @@ var UpdateConversationRequest = external_exports.object({
|
|
|
18699
18849
|
}
|
|
18700
18850
|
});
|
|
18701
18851
|
var ConversationResponse = external_exports.object({ conversation: ConversationProjection }).strict();
|
|
18702
|
-
var ListConversationsResponse = external_exports.object({
|
|
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();
|
|
18703
18893
|
var ConversationDetailResponse = external_exports.object({
|
|
18704
18894
|
conversation: ConversationProjection,
|
|
18705
18895
|
events: external_exports.array(ConversationEventProjection)
|
|
@@ -19451,7 +19641,7 @@ async function generateTaskTitle(instructions, runner) {
|
|
|
19451
19641
|
instructions.slice(0, INSTRUCTIONS_BUDGET),
|
|
19452
19642
|
"</task_request>"
|
|
19453
19643
|
].join("\n");
|
|
19454
|
-
return new Promise((
|
|
19644
|
+
return new Promise((resolve15) => {
|
|
19455
19645
|
const child = spawnCli(
|
|
19456
19646
|
command,
|
|
19457
19647
|
[
|
|
@@ -19474,7 +19664,7 @@ async function generateTaskTitle(instructions, runner) {
|
|
|
19474
19664
|
if (settled) return;
|
|
19475
19665
|
settled = true;
|
|
19476
19666
|
clearTimeout(timer);
|
|
19477
|
-
|
|
19667
|
+
resolve15(value);
|
|
19478
19668
|
};
|
|
19479
19669
|
const timer = setTimeout(() => {
|
|
19480
19670
|
child.kill();
|
|
@@ -19796,11 +19986,11 @@ function createWorkerWatchdogSendDrain() {
|
|
|
19796
19986
|
if (completed) return;
|
|
19797
19987
|
completed = true;
|
|
19798
19988
|
pending--;
|
|
19799
|
-
if (pending === 0) drained.splice(0).forEach((
|
|
19989
|
+
if (pending === 0) drained.splice(0).forEach((resolve15) => resolve15());
|
|
19800
19990
|
};
|
|
19801
19991
|
},
|
|
19802
19992
|
drain: async () => {
|
|
19803
|
-
if (pending > 0) await new Promise((
|
|
19993
|
+
if (pending > 0) await new Promise((resolve15) => drained.push(resolve15));
|
|
19804
19994
|
}
|
|
19805
19995
|
};
|
|
19806
19996
|
}
|
|
@@ -20045,7 +20235,7 @@ async function waitForOperationGrantRetry(retryAt, signal) {
|
|
|
20045
20235
|
const deadline = Date.parse(retryAt);
|
|
20046
20236
|
if (!Number.isFinite(deadline) || signal.aborted) return false;
|
|
20047
20237
|
if (deadline <= Date.now()) return true;
|
|
20048
|
-
return await new Promise((
|
|
20238
|
+
return await new Promise((resolve15) => {
|
|
20049
20239
|
let settled = false;
|
|
20050
20240
|
let timer;
|
|
20051
20241
|
const finish = (ready) => {
|
|
@@ -20053,7 +20243,7 @@ async function waitForOperationGrantRetry(retryAt, signal) {
|
|
|
20053
20243
|
settled = true;
|
|
20054
20244
|
if (timer) clearTimeout(timer);
|
|
20055
20245
|
signal.removeEventListener("abort", onAbort);
|
|
20056
|
-
|
|
20246
|
+
resolve15(ready);
|
|
20057
20247
|
};
|
|
20058
20248
|
const onAbort = () => finish(false);
|
|
20059
20249
|
const schedule = () => {
|
|
@@ -20321,22 +20511,22 @@ var HostClient = class _HostClient {
|
|
|
20321
20511
|
const unwindingAssignments = [...this.activeAssignments.values()];
|
|
20322
20512
|
for (const cancel of this.cancels.values()) cancel(stopReason);
|
|
20323
20513
|
for (const entry of this.secretGrants.values()) {
|
|
20324
|
-
for (const
|
|
20514
|
+
for (const resolve15 of entry.resolvers) resolve15({});
|
|
20325
20515
|
entry.resolvers = [];
|
|
20326
20516
|
delete entry.value;
|
|
20327
20517
|
}
|
|
20328
20518
|
for (const entry of this.connectionGrants.values()) {
|
|
20329
|
-
for (const
|
|
20519
|
+
for (const resolve15 of entry.resolvers) resolve15([]);
|
|
20330
20520
|
entry.resolvers = [];
|
|
20331
20521
|
delete entry.value;
|
|
20332
20522
|
}
|
|
20333
20523
|
for (const entry of this.providerGrants.values()) {
|
|
20334
|
-
for (const
|
|
20524
|
+
for (const resolve15 of entry.resolvers) resolve15([]);
|
|
20335
20525
|
entry.resolvers = [];
|
|
20336
20526
|
delete entry.value;
|
|
20337
20527
|
}
|
|
20338
20528
|
for (const waiters of this.approvalWaiters.values()) {
|
|
20339
|
-
for (const
|
|
20529
|
+
for (const resolve15 of waiters.values()) resolve15({ approved: false, guidance: reason });
|
|
20340
20530
|
}
|
|
20341
20531
|
for (const waiters of this.agentOpWaiters.values()) {
|
|
20342
20532
|
for (const waiter of waiters.values()) {
|
|
@@ -20362,9 +20552,9 @@ var HostClient = class _HostClient {
|
|
|
20362
20552
|
let drainTimer;
|
|
20363
20553
|
const drained = await Promise.race([
|
|
20364
20554
|
Promise.allSettled(runs).then(() => true),
|
|
20365
|
-
new Promise((
|
|
20555
|
+
new Promise((resolve15) => {
|
|
20366
20556
|
drainTimer = setTimeout(
|
|
20367
|
-
() =>
|
|
20557
|
+
() => resolve15(false),
|
|
20368
20558
|
this.opts.unwindTimeoutMs ?? _HostClient.DEFAULT_UNWIND_TIMEOUT_MS
|
|
20369
20559
|
);
|
|
20370
20560
|
drainTimer.unref?.();
|
|
@@ -20395,9 +20585,70 @@ var HostClient = class _HostClient {
|
|
|
20395
20585
|
let awaitingHeartbeatReply = false;
|
|
20396
20586
|
let closeReason;
|
|
20397
20587
|
let frameTail = Promise.resolve();
|
|
20588
|
+
let inventoryRetryTimer;
|
|
20589
|
+
let inventoryRetryAttempts = 0;
|
|
20590
|
+
const inventoryRetryBaseMs = Math.max(20, Number(this.opts.backoffMs ?? 1e3));
|
|
20398
20591
|
this.ws = ws;
|
|
20399
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
|
+
}
|
|
20400
20648
|
ws.on("open", () => {
|
|
20649
|
+
const inventoryConfigured = Boolean(
|
|
20650
|
+
this.opts.browser?.profileInventoryPages || this.opts.browser?.profileInventory
|
|
20651
|
+
);
|
|
20401
20652
|
const unwoundAssignments = [...this.pendingUnwoundAssignments.values()].sort(
|
|
20402
20653
|
(left, right) => left.taskId === right.taskId ? left.epoch - right.epoch : left.taskId.localeCompare(right.taskId)
|
|
20403
20654
|
);
|
|
@@ -20406,6 +20657,7 @@ var HostClient = class _HostClient {
|
|
|
20406
20657
|
type: "hello",
|
|
20407
20658
|
protocolVersion: PROTOCOL_VERSION,
|
|
20408
20659
|
cursor: this.cursor,
|
|
20660
|
+
...inventoryConfigured ? { browserProfileInventory: { agentIds: [], complete: false } } : {},
|
|
20409
20661
|
...unwoundAssignments.length > 0 ? { unwoundAssignments } : {}
|
|
20410
20662
|
},
|
|
20411
20663
|
ws
|
|
@@ -20422,6 +20674,7 @@ var HostClient = class _HostClient {
|
|
|
20422
20674
|
this.send({ type: "ping", at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
20423
20675
|
void this.reportTelemetry();
|
|
20424
20676
|
}, heartbeatMs);
|
|
20677
|
+
if (inventoryConfigured) void retryInventory();
|
|
20425
20678
|
});
|
|
20426
20679
|
ws.on("message", (raw) => {
|
|
20427
20680
|
if (this.ws !== ws) return;
|
|
@@ -20431,6 +20684,7 @@ var HostClient = class _HostClient {
|
|
|
20431
20684
|
});
|
|
20432
20685
|
});
|
|
20433
20686
|
ws.on("close", (code) => {
|
|
20687
|
+
if (inventoryRetryTimer) clearTimeout(inventoryRetryTimer);
|
|
20434
20688
|
void this.handleClose(ws, code, closeReason, frameTail);
|
|
20435
20689
|
});
|
|
20436
20690
|
ws.on("error", () => {
|
|
@@ -20444,9 +20698,9 @@ var HostClient = class _HostClient {
|
|
|
20444
20698
|
let frameDrainTimer;
|
|
20445
20699
|
const framesDrained = await Promise.race([
|
|
20446
20700
|
frameTail.then(() => true),
|
|
20447
|
-
new Promise((
|
|
20701
|
+
new Promise((resolve15) => {
|
|
20448
20702
|
frameDrainTimer = setTimeout(
|
|
20449
|
-
() =>
|
|
20703
|
+
() => resolve15(false),
|
|
20450
20704
|
this.opts.unwindTimeoutMs ?? _HostClient.DEFAULT_UNWIND_TIMEOUT_MS
|
|
20451
20705
|
);
|
|
20452
20706
|
frameDrainTimer.unref?.();
|
|
@@ -20823,7 +21077,13 @@ var HostClient = class _HostClient {
|
|
|
20823
21077
|
case "browser.open": {
|
|
20824
21078
|
const bridge = this.opts.browser;
|
|
20825
21079
|
if (!bridge) return;
|
|
20826
|
-
void bridge.open(
|
|
21080
|
+
void bridge.open(
|
|
21081
|
+
frame.agentId,
|
|
21082
|
+
frame.browserSessionId,
|
|
21083
|
+
frame.viewport,
|
|
21084
|
+
frame.requestId,
|
|
21085
|
+
frame.profileRevision
|
|
21086
|
+
).catch(() => {
|
|
20827
21087
|
this.sendBrowserFrame({
|
|
20828
21088
|
type: "browser.session.ended",
|
|
20829
21089
|
browserSessionId: frame.browserSessionId,
|
|
@@ -20834,7 +21094,8 @@ var HostClient = class _HostClient {
|
|
|
20834
21094
|
return;
|
|
20835
21095
|
}
|
|
20836
21096
|
case "browser.close":
|
|
20837
|
-
void this.opts.browser?.close(frame.agentId, "stopped")
|
|
21097
|
+
void this.opts.browser?.close(frame.agentId, "stopped").catch(() => {
|
|
21098
|
+
});
|
|
20838
21099
|
return;
|
|
20839
21100
|
case "browser.view":
|
|
20840
21101
|
void this.opts.browser?.setViewers(frame.agentId, frame.active, frame.viewerCount);
|
|
@@ -20935,8 +21196,34 @@ var HostClient = class _HostClient {
|
|
|
20935
21196
|
async handleMessage(message) {
|
|
20936
21197
|
switch (message.type) {
|
|
20937
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
|
+
}
|
|
20938
21208
|
this.startTask(message);
|
|
20939
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
|
+
}
|
|
20940
21227
|
case "task.cancel":
|
|
20941
21228
|
this.cancels.get(`${message.taskId}:${message.epoch}`)?.(
|
|
20942
21229
|
message.purpose === "credential_rollover" ? "credential_rollover" : "cloud_cancel"
|
|
@@ -20957,7 +21244,7 @@ var HostClient = class _HostClient {
|
|
|
20957
21244
|
const entry = this.secretGrants.get(key) ?? { resolvers: [] };
|
|
20958
21245
|
entry.value = message.secrets;
|
|
20959
21246
|
entry.expiresAt = expiresAt;
|
|
20960
|
-
for (const
|
|
21247
|
+
for (const resolve15 of entry.resolvers) resolve15(message.secrets);
|
|
20961
21248
|
entry.resolvers = [];
|
|
20962
21249
|
this.secretGrants.set(key, entry);
|
|
20963
21250
|
return;
|
|
@@ -20988,13 +21275,13 @@ var HostClient = class _HostClient {
|
|
|
20988
21275
|
const entry = this.connectionGrants.get(key) ?? { resolvers: [] };
|
|
20989
21276
|
entry.value = message.connections;
|
|
20990
21277
|
entry.expiresAt = expiresAt;
|
|
20991
|
-
for (const
|
|
21278
|
+
for (const resolve15 of entry.resolvers) resolve15(message.connections);
|
|
20992
21279
|
entry.resolvers = [];
|
|
20993
21280
|
this.connectionGrants.set(key, entry);
|
|
20994
21281
|
const providerEntry = this.providerGrants.get(key) ?? { resolvers: [] };
|
|
20995
21282
|
providerEntry.value = providers;
|
|
20996
21283
|
providerEntry.expiresAt = authorityExpiresAt;
|
|
20997
|
-
for (const
|
|
21284
|
+
for (const resolve15 of providerEntry.resolvers) resolve15(providers);
|
|
20998
21285
|
providerEntry.resolvers = [];
|
|
20999
21286
|
this.providerGrants.set(key, providerEntry);
|
|
21000
21287
|
return;
|
|
@@ -21128,8 +21415,8 @@ var HostClient = class _HostClient {
|
|
|
21128
21415
|
return redactCredentialText(text, sensitiveSnapshot()).slice(0, maxLength);
|
|
21129
21416
|
};
|
|
21130
21417
|
let resolveCancelled;
|
|
21131
|
-
const cancelledPromise = new Promise((
|
|
21132
|
-
resolveCancelled =
|
|
21418
|
+
const cancelledPromise = new Promise((resolve15) => {
|
|
21419
|
+
resolveCancelled = resolve15;
|
|
21133
21420
|
});
|
|
21134
21421
|
const endAuthority = (reason = "cloud_cancel") => {
|
|
21135
21422
|
if (stopReason) return;
|
|
@@ -21138,21 +21425,21 @@ var HostClient = class _HostClient {
|
|
|
21138
21425
|
authorityController.abort(reason);
|
|
21139
21426
|
const secretEntry = this.secretGrants.get(cancelKey);
|
|
21140
21427
|
if (secretEntry) {
|
|
21141
|
-
for (const
|
|
21428
|
+
for (const resolve15 of secretEntry.resolvers) resolve15({});
|
|
21142
21429
|
secretEntry.resolvers = [];
|
|
21143
21430
|
delete secretEntry.value;
|
|
21144
21431
|
}
|
|
21145
21432
|
this.secretGrants.delete(cancelKey);
|
|
21146
21433
|
const connectionEntry = this.connectionGrants.get(cancelKey);
|
|
21147
21434
|
if (connectionEntry) {
|
|
21148
|
-
for (const
|
|
21435
|
+
for (const resolve15 of connectionEntry.resolvers) resolve15([]);
|
|
21149
21436
|
connectionEntry.resolvers = [];
|
|
21150
21437
|
delete connectionEntry.value;
|
|
21151
21438
|
}
|
|
21152
21439
|
this.connectionGrants.delete(cancelKey);
|
|
21153
21440
|
const providerEntry = this.providerGrants.get(cancelKey);
|
|
21154
21441
|
if (providerEntry) {
|
|
21155
|
-
for (const
|
|
21442
|
+
for (const resolve15 of providerEntry.resolvers) resolve15([]);
|
|
21156
21443
|
providerEntry.resolvers = [];
|
|
21157
21444
|
delete providerEntry.value;
|
|
21158
21445
|
}
|
|
@@ -21160,8 +21447,8 @@ var HostClient = class _HostClient {
|
|
|
21160
21447
|
this.clearAuthorityExpiry(cancelKey);
|
|
21161
21448
|
const approvalWaiters = this.approvalWaiters.get(cancelKey);
|
|
21162
21449
|
if (approvalWaiters) {
|
|
21163
|
-
for (const
|
|
21164
|
-
|
|
21450
|
+
for (const resolve15 of approvalWaiters.values()) {
|
|
21451
|
+
resolve15({ approved: false, guidance: "task was cancelled" });
|
|
21165
21452
|
}
|
|
21166
21453
|
approvalWaiters.clear();
|
|
21167
21454
|
}
|
|
@@ -21287,9 +21574,9 @@ var HostClient = class _HostClient {
|
|
|
21287
21574
|
return value;
|
|
21288
21575
|
};
|
|
21289
21576
|
if (entry.value) return Promise.resolve(capture(entry.value));
|
|
21290
|
-
return new Promise((
|
|
21291
|
-
entry.resolvers.push((value) =>
|
|
21292
|
-
setTimeout(() =>
|
|
21577
|
+
return new Promise((resolve15) => {
|
|
21578
|
+
entry.resolvers.push((value) => resolve15(capture(value)));
|
|
21579
|
+
setTimeout(() => resolve15(capture(entry.value ?? {})), _HostClient.SECRETS_WAIT_MS);
|
|
21293
21580
|
});
|
|
21294
21581
|
};
|
|
21295
21582
|
const connections = () => {
|
|
@@ -21306,9 +21593,9 @@ var HostClient = class _HostClient {
|
|
|
21306
21593
|
return value;
|
|
21307
21594
|
};
|
|
21308
21595
|
if (entry.value) return Promise.resolve(capture(entry.value));
|
|
21309
|
-
return new Promise((
|
|
21310
|
-
entry.resolvers.push((value) =>
|
|
21311
|
-
setTimeout(() =>
|
|
21596
|
+
return new Promise((resolve15) => {
|
|
21597
|
+
entry.resolvers.push((value) => resolve15(capture(value)));
|
|
21598
|
+
setTimeout(() => resolve15(capture(entry.value ?? [])), _HostClient.SECRETS_WAIT_MS);
|
|
21312
21599
|
});
|
|
21313
21600
|
};
|
|
21314
21601
|
const providers = () => {
|
|
@@ -21325,9 +21612,9 @@ var HostClient = class _HostClient {
|
|
|
21325
21612
|
return value;
|
|
21326
21613
|
};
|
|
21327
21614
|
if (entry.value !== void 0) return Promise.resolve(capture(entry.value));
|
|
21328
|
-
return new Promise((
|
|
21329
|
-
entry.resolvers.push((value) =>
|
|
21330
|
-
setTimeout(() =>
|
|
21615
|
+
return new Promise((resolve15) => {
|
|
21616
|
+
entry.resolvers.push((value) => resolve15(capture(value)));
|
|
21617
|
+
setTimeout(() => resolve15(capture(entry.value ?? [])), _HostClient.SECRETS_WAIT_MS);
|
|
21331
21618
|
});
|
|
21332
21619
|
};
|
|
21333
21620
|
const linear = async () => {
|
|
@@ -21353,13 +21640,13 @@ var HostClient = class _HostClient {
|
|
|
21353
21640
|
payload: safe(payload, 5e4),
|
|
21354
21641
|
...questionChoices ? { questionChoices: [...questionChoices] } : {}
|
|
21355
21642
|
});
|
|
21356
|
-
return new Promise((
|
|
21643
|
+
return new Promise((resolve15) => {
|
|
21357
21644
|
const waiters = this.approvalWaiters.get(cancelKey) ?? /* @__PURE__ */ new Map();
|
|
21358
21645
|
this.approvalWaiters.set(cancelKey, waiters);
|
|
21359
|
-
waiters.set(requestId,
|
|
21646
|
+
waiters.set(requestId, resolve15);
|
|
21360
21647
|
void cancelledPromise.then(() => {
|
|
21361
21648
|
if (waiters.delete(requestId)) {
|
|
21362
|
-
|
|
21649
|
+
resolve15({ approved: false, guidance: "task was cancelled" });
|
|
21363
21650
|
}
|
|
21364
21651
|
});
|
|
21365
21652
|
});
|
|
@@ -21397,11 +21684,11 @@ var HostClient = class _HostClient {
|
|
|
21397
21684
|
if (existing) message = existing;
|
|
21398
21685
|
else terminalMessages.set(requestId, message);
|
|
21399
21686
|
}
|
|
21400
|
-
return new Promise((
|
|
21687
|
+
return new Promise((resolve15) => {
|
|
21401
21688
|
const waiters = this.agentOpWaiters.get(cancelKey) ?? /* @__PURE__ */ new Map();
|
|
21402
21689
|
this.agentOpWaiters.set(cancelKey, waiters);
|
|
21403
21690
|
if (waiters.has(requestId)) {
|
|
21404
|
-
|
|
21691
|
+
resolve15({ ok: false, error: "provider settlement request is already in flight" });
|
|
21405
21692
|
return;
|
|
21406
21693
|
}
|
|
21407
21694
|
const timer = setTimeout(() => {
|
|
@@ -21412,7 +21699,7 @@ var HostClient = class _HostClient {
|
|
|
21412
21699
|
(pending) => !(pending.type === "agent.op" && pending.requestId === requestId)
|
|
21413
21700
|
);
|
|
21414
21701
|
}
|
|
21415
|
-
|
|
21702
|
+
resolve15({
|
|
21416
21703
|
ok: false,
|
|
21417
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"
|
|
21418
21705
|
});
|
|
@@ -21420,7 +21707,7 @@ var HostClient = class _HostClient {
|
|
|
21420
21707
|
}, _HostClient.AGENT_OP_TIMEOUT_MS);
|
|
21421
21708
|
timer.unref?.();
|
|
21422
21709
|
waiters.set(requestId, {
|
|
21423
|
-
resolve:
|
|
21710
|
+
resolve: resolve15,
|
|
21424
21711
|
timer,
|
|
21425
21712
|
...terminal ? { terminalMessage: message } : {}
|
|
21426
21713
|
});
|
|
@@ -21466,12 +21753,12 @@ var HostClient = class _HostClient {
|
|
|
21466
21753
|
"No GitHub change was attempted; the authority grant request was invalid."
|
|
21467
21754
|
);
|
|
21468
21755
|
}
|
|
21469
|
-
const outcome = await new Promise((
|
|
21756
|
+
const outcome = await new Promise((resolve15) => {
|
|
21470
21757
|
const timer = setTimeout(() => {
|
|
21471
21758
|
const waiter = this.operationGrantWaiters.get(requestId);
|
|
21472
21759
|
if (!waiter) return;
|
|
21473
21760
|
this.operationGrantWaiters.delete(requestId);
|
|
21474
|
-
|
|
21761
|
+
resolve15({ grant: null, retryable: true, reason: "no_reply_from_zixt" });
|
|
21475
21762
|
}, this.operationGrantTimeoutMs);
|
|
21476
21763
|
timer.unref?.();
|
|
21477
21764
|
this.operationGrantWaiters.set(requestId, {
|
|
@@ -21484,9 +21771,9 @@ var HostClient = class _HostClient {
|
|
|
21484
21771
|
timer,
|
|
21485
21772
|
accept: (grant) => {
|
|
21486
21773
|
addSensitiveValues(providerGrantSensitiveValues(grant));
|
|
21487
|
-
|
|
21774
|
+
resolve15({ grant });
|
|
21488
21775
|
},
|
|
21489
|
-
deny: (retryable, reason, detail, retryAt, retryCode) =>
|
|
21776
|
+
deny: (retryable, reason, detail, retryAt, retryCode) => resolve15({
|
|
21490
21777
|
grant: null,
|
|
21491
21778
|
retryable,
|
|
21492
21779
|
reason,
|
|
@@ -21500,7 +21787,7 @@ var HostClient = class _HostClient {
|
|
|
21500
21787
|
} catch {
|
|
21501
21788
|
clearTimeout(timer);
|
|
21502
21789
|
this.operationGrantWaiters.delete(requestId);
|
|
21503
|
-
|
|
21790
|
+
resolve15({ grant: null, retryable: false, reason: "connection_unavailable" });
|
|
21504
21791
|
}
|
|
21505
21792
|
});
|
|
21506
21793
|
if (outcome.grant) {
|
|
@@ -21556,7 +21843,7 @@ var HostClient = class _HostClient {
|
|
|
21556
21843
|
)
|
|
21557
21844
|
);
|
|
21558
21845
|
}
|
|
21559
|
-
return new Promise((
|
|
21846
|
+
return new Promise((resolve15, reject3) => {
|
|
21560
21847
|
const timer = setTimeout(() => {
|
|
21561
21848
|
if (this.browserCredentialWaiters.delete(requestId)) {
|
|
21562
21849
|
reject3(
|
|
@@ -21575,7 +21862,7 @@ var HostClient = class _HostClient {
|
|
|
21575
21862
|
timer,
|
|
21576
21863
|
accept: (credential) => {
|
|
21577
21864
|
addSensitiveValues(webLoginSensitiveValues(credential));
|
|
21578
|
-
|
|
21865
|
+
resolve15(credential);
|
|
21579
21866
|
},
|
|
21580
21867
|
deny: (reason) => reject3(new Error(reason))
|
|
21581
21868
|
});
|
|
@@ -21881,6 +22168,9 @@ var ProcessTreeTerminationError = class extends Error {
|
|
|
21881
22168
|
}
|
|
21882
22169
|
name = "ProcessTreeTerminationError";
|
|
21883
22170
|
};
|
|
22171
|
+
function posixIdentityReadMeansMissing(error52) {
|
|
22172
|
+
return ["ENOENT", "ESRCH"].includes(error52.code ?? "");
|
|
22173
|
+
}
|
|
21884
22174
|
function commandContainsNonce(command, nonce) {
|
|
21885
22175
|
const escaped = nonce.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
21886
22176
|
return new RegExp(`(?:^|[\\s"'])${escaped}(?:$|[\\s"'])`).test(command);
|
|
@@ -21893,14 +22183,14 @@ async function observeWindowsGuardianNonce(pid, nonce) {
|
|
|
21893
22183
|
"Windows runner identity could not be observed"
|
|
21894
22184
|
);
|
|
21895
22185
|
}
|
|
21896
|
-
return new Promise((
|
|
22186
|
+
return new Promise((resolve15, reject3) => {
|
|
21897
22187
|
let done = false;
|
|
21898
22188
|
const finish = (result) => {
|
|
21899
22189
|
if (done) return;
|
|
21900
22190
|
done = true;
|
|
21901
22191
|
clearTimeout(timeout);
|
|
21902
22192
|
if (result instanceof Error) reject3(result);
|
|
21903
|
-
else
|
|
22193
|
+
else resolve15(result);
|
|
21904
22194
|
};
|
|
21905
22195
|
const timeout = setTimeout(
|
|
21906
22196
|
() => finish(
|
|
@@ -21938,14 +22228,14 @@ async function observePosixGuardianNonce(pid, nonce) {
|
|
|
21938
22228
|
const args = command.toString("utf8").split("\0");
|
|
21939
22229
|
return args.includes(nonce) ? "match" : "mismatch";
|
|
21940
22230
|
} catch (error52) {
|
|
21941
|
-
if (error52
|
|
22231
|
+
if (posixIdentityReadMeansMissing(error52)) return "missing";
|
|
21942
22232
|
throw new ProcessTreeTerminationError(
|
|
21943
22233
|
"state_unknown",
|
|
21944
22234
|
"POSIX runner identity could not be observed"
|
|
21945
22235
|
);
|
|
21946
22236
|
}
|
|
21947
22237
|
}
|
|
21948
|
-
return new Promise((
|
|
22238
|
+
return new Promise((resolve15, reject3) => {
|
|
21949
22239
|
const observer = spawn2("/bin/ps", ["-ww", "-o", "command=", "-p", String(pid)], {
|
|
21950
22240
|
stdio: ["ignore", "pipe", "ignore"]
|
|
21951
22241
|
});
|
|
@@ -21956,7 +22246,7 @@ async function observePosixGuardianNonce(pid, nonce) {
|
|
|
21956
22246
|
done = true;
|
|
21957
22247
|
clearTimeout(timeout);
|
|
21958
22248
|
if (result instanceof Error) reject3(result);
|
|
21959
|
-
else
|
|
22249
|
+
else resolve15(result);
|
|
21960
22250
|
};
|
|
21961
22251
|
const timeout = setTimeout(() => {
|
|
21962
22252
|
observer.kill("SIGKILL");
|
|
@@ -22003,7 +22293,7 @@ async function observeGuardianIdentity(pid, identity) {
|
|
|
22003
22293
|
return process.platform === "win32" ? observeWindowsGuardianNonce(pid, identity.nonce) : observePosixGuardianNonce(pid, identity.nonce);
|
|
22004
22294
|
}
|
|
22005
22295
|
function delay(ms) {
|
|
22006
|
-
return new Promise((
|
|
22296
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
22007
22297
|
}
|
|
22008
22298
|
function posixProcessRecordsFromPs(output) {
|
|
22009
22299
|
const records = [];
|
|
@@ -22036,7 +22326,7 @@ function posixProcessRecordsFromPs(output) {
|
|
|
22036
22326
|
return records;
|
|
22037
22327
|
}
|
|
22038
22328
|
async function snapshotPosixProcesses() {
|
|
22039
|
-
return new Promise((
|
|
22329
|
+
return new Promise((resolve15, reject3) => {
|
|
22040
22330
|
const observer = spawn2("/bin/ps", ["-axo", "uid=,pid=,ppid=,pgid=,stat="], {
|
|
22041
22331
|
stdio: ["ignore", "pipe", "ignore"]
|
|
22042
22332
|
});
|
|
@@ -22049,7 +22339,7 @@ async function snapshotPosixProcesses() {
|
|
|
22049
22339
|
if (error52) reject3(error52);
|
|
22050
22340
|
else {
|
|
22051
22341
|
try {
|
|
22052
|
-
|
|
22342
|
+
resolve15(posixProcessRecordsFromPs(output));
|
|
22053
22343
|
} catch (caught) {
|
|
22054
22344
|
reject3(caught);
|
|
22055
22345
|
}
|
|
@@ -22384,7 +22674,7 @@ async function snapshotWindowsDescendants(rootPid) {
|
|
|
22384
22674
|
"Windows process-tree observation could not start"
|
|
22385
22675
|
);
|
|
22386
22676
|
}
|
|
22387
|
-
return new Promise((
|
|
22677
|
+
return new Promise((resolve15, reject3) => {
|
|
22388
22678
|
let done = false;
|
|
22389
22679
|
const timeout = setTimeout(() => {
|
|
22390
22680
|
if (done) return;
|
|
@@ -22411,7 +22701,7 @@ async function snapshotWindowsDescendants(rootPid) {
|
|
|
22411
22701
|
return;
|
|
22412
22702
|
}
|
|
22413
22703
|
try {
|
|
22414
|
-
|
|
22704
|
+
resolve15(completeWindowsDescendantPids(rootPid, processes));
|
|
22415
22705
|
} catch (caught) {
|
|
22416
22706
|
reject3(caught);
|
|
22417
22707
|
}
|
|
@@ -22458,7 +22748,7 @@ async function waitForProcessesExit(pids, timeoutMs) {
|
|
|
22458
22748
|
}
|
|
22459
22749
|
async function runTaskkill(pid, command, timeoutMs = TASKKILL_TIMEOUT_MS, independentlyTrackedPids = []) {
|
|
22460
22750
|
const trustedCommand = command ?? defaultTaskkillCommand();
|
|
22461
|
-
const result = await new Promise((
|
|
22751
|
+
const result = await new Promise((resolve15, reject3) => {
|
|
22462
22752
|
const killer = spawn2(trustedCommand, ["/PID", String(pid), "/T", "/F"], {
|
|
22463
22753
|
stdio: ["ignore", "pipe", "pipe"],
|
|
22464
22754
|
windowsHide: true
|
|
@@ -22493,7 +22783,7 @@ async function runTaskkill(pid, command, timeoutMs = TASKKILL_TIMEOUT_MS, indepe
|
|
|
22493
22783
|
done = true;
|
|
22494
22784
|
clearTimeout(timeout);
|
|
22495
22785
|
if (error52) reject3(error52);
|
|
22496
|
-
else
|
|
22786
|
+
else resolve15({ code: killer.exitCode, output, outputTruncated });
|
|
22497
22787
|
};
|
|
22498
22788
|
killer.once(
|
|
22499
22789
|
"error",
|
|
@@ -23170,12 +23460,12 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
23170
23460
|
stderr = `${stderr}${String(chunk)}`.slice(-HELPER_OUTPUT_LIMIT);
|
|
23171
23461
|
});
|
|
23172
23462
|
const helperEvents = helper;
|
|
23173
|
-
const exited = new Promise((
|
|
23463
|
+
const exited = new Promise((resolve15) => {
|
|
23174
23464
|
let completed = false;
|
|
23175
23465
|
const complete = (code, signal) => {
|
|
23176
23466
|
if (completed) return;
|
|
23177
23467
|
completed = true;
|
|
23178
|
-
|
|
23468
|
+
resolve15({ code, signal });
|
|
23179
23469
|
};
|
|
23180
23470
|
helperEvents.once("error", () => {
|
|
23181
23471
|
failProtocol(new Error("Windows Job Object helper could not start"));
|
|
@@ -23188,7 +23478,7 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
23188
23478
|
});
|
|
23189
23479
|
const nextLine = async (expected) => {
|
|
23190
23480
|
if (protocolFailure) throw protocolFailure;
|
|
23191
|
-
const line = lines.shift() ?? await new Promise((
|
|
23481
|
+
const line = lines.shift() ?? await new Promise((resolve15, reject3) => {
|
|
23192
23482
|
const timer = setTimeout(
|
|
23193
23483
|
() => reject3(timeoutError("Windows Job Object helper did not answer in time")),
|
|
23194
23484
|
timeoutMs
|
|
@@ -23196,7 +23486,7 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
23196
23486
|
timer.unref?.();
|
|
23197
23487
|
lineWaiters.push((value) => {
|
|
23198
23488
|
clearTimeout(timer);
|
|
23199
|
-
|
|
23489
|
+
resolve15(value);
|
|
23200
23490
|
});
|
|
23201
23491
|
});
|
|
23202
23492
|
if (protocolFailure) throw protocolFailure;
|
|
@@ -23209,8 +23499,8 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
23209
23499
|
}
|
|
23210
23500
|
const stopped = await Promise.race([
|
|
23211
23501
|
exited.then(() => true),
|
|
23212
|
-
new Promise((
|
|
23213
|
-
const timer = setTimeout(() =>
|
|
23502
|
+
new Promise((resolve15) => {
|
|
23503
|
+
const timer = setTimeout(() => resolve15(false), timeoutMs);
|
|
23214
23504
|
timer.unref?.();
|
|
23215
23505
|
})
|
|
23216
23506
|
]);
|
|
@@ -23269,7 +23559,7 @@ async function awaitWindowsContainmentGate(env = process.env, input = process.st
|
|
|
23269
23559
|
if (nonce === void 0) return true;
|
|
23270
23560
|
if (!SAFE_NONCE2.test(nonce)) return false;
|
|
23271
23561
|
const expected = windowsContainmentGate(nonce).trimEnd();
|
|
23272
|
-
return new Promise((
|
|
23562
|
+
return new Promise((resolve15) => {
|
|
23273
23563
|
let pending = Buffer.alloc(0);
|
|
23274
23564
|
let settled = false;
|
|
23275
23565
|
const finish = (result) => {
|
|
@@ -23280,7 +23570,7 @@ async function awaitWindowsContainmentGate(env = process.env, input = process.st
|
|
|
23280
23570
|
input.off("end", onEnd);
|
|
23281
23571
|
input.off("error", onEnd);
|
|
23282
23572
|
if (result) input.pause();
|
|
23283
|
-
|
|
23573
|
+
resolve15(result);
|
|
23284
23574
|
};
|
|
23285
23575
|
const onData = (chunk) => {
|
|
23286
23576
|
pending = Buffer.concat([pending, chunk]);
|
|
@@ -23705,7 +23995,7 @@ async function installRelease(version2, options = {}) {
|
|
|
23705
23995
|
installerContainmentSetupError = error52;
|
|
23706
23996
|
return null;
|
|
23707
23997
|
}) : Promise.resolve(null);
|
|
23708
|
-
const installed = await new Promise((
|
|
23998
|
+
const installed = await new Promise((resolve15, reject3) => {
|
|
23709
23999
|
let finished = false;
|
|
23710
24000
|
let cleanupStarted = false;
|
|
23711
24001
|
let exitObserved = false;
|
|
@@ -23721,7 +24011,7 @@ async function installRelease(version2, options = {}) {
|
|
|
23721
24011
|
finished = true;
|
|
23722
24012
|
clearTimeout(timer);
|
|
23723
24013
|
options.signal?.removeEventListener("abort", requestCleanup);
|
|
23724
|
-
|
|
24014
|
+
resolve15(result);
|
|
23725
24015
|
};
|
|
23726
24016
|
const requestCleanup = () => {
|
|
23727
24017
|
if (cleanupStarted || finished) return;
|
|
@@ -24034,11 +24324,11 @@ async function runWorkerCompatibilityProxy(env = process.env, argv = process.arg
|
|
|
24034
24324
|
child.stdin?.on("error", () => {
|
|
24035
24325
|
});
|
|
24036
24326
|
process.stdin.pipe(child.stdin);
|
|
24037
|
-
return new Promise((
|
|
24038
|
-
child.once("error", () =>
|
|
24327
|
+
return new Promise((resolve15) => {
|
|
24328
|
+
child.once("error", () => resolve15(1));
|
|
24039
24329
|
child.once("exit", (code) => {
|
|
24040
24330
|
process.stdin.unpipe(child.stdin);
|
|
24041
|
-
|
|
24331
|
+
resolve15(code ?? 1);
|
|
24042
24332
|
});
|
|
24043
24333
|
});
|
|
24044
24334
|
}
|
|
@@ -24116,11 +24406,11 @@ async function launchHostSupervisor(options = {}) {
|
|
|
24116
24406
|
const waitOrStop = async (ms) => {
|
|
24117
24407
|
if (stopping) return false;
|
|
24118
24408
|
if (!customDelay) {
|
|
24119
|
-
await new Promise((
|
|
24409
|
+
await new Promise((resolve15) => {
|
|
24120
24410
|
const finish = () => {
|
|
24121
24411
|
clearTimeout(timer);
|
|
24122
24412
|
stopController.signal.removeEventListener("abort", finish);
|
|
24123
|
-
|
|
24413
|
+
resolve15();
|
|
24124
24414
|
};
|
|
24125
24415
|
const timer = setTimeout(finish, ms);
|
|
24126
24416
|
stopController.signal.addEventListener("abort", finish, { once: true });
|
|
@@ -24128,8 +24418,8 @@ async function launchHostSupervisor(options = {}) {
|
|
|
24128
24418
|
return !stopping;
|
|
24129
24419
|
}
|
|
24130
24420
|
let finishStop;
|
|
24131
|
-
const stopped = new Promise((
|
|
24132
|
-
finishStop = () =>
|
|
24421
|
+
const stopped = new Promise((resolve15) => {
|
|
24422
|
+
finishStop = () => resolve15();
|
|
24133
24423
|
stopController.signal.addEventListener("abort", finishStop, { once: true });
|
|
24134
24424
|
});
|
|
24135
24425
|
await Promise.race([customDelay(ms), stopped]);
|
|
@@ -24252,19 +24542,19 @@ async function launchHostSupervisor(options = {}) {
|
|
|
24252
24542
|
child = spawnSupervisor(entry, version2, ownershipDirectory, containmentGateNonce);
|
|
24253
24543
|
const launchedSupervisor = child;
|
|
24254
24544
|
let resolveChildExited;
|
|
24255
|
-
const childExited = new Promise((
|
|
24256
|
-
resolveChildExited =
|
|
24545
|
+
const childExited = new Promise((resolve15) => {
|
|
24546
|
+
resolveChildExited = resolve15;
|
|
24257
24547
|
});
|
|
24258
24548
|
const supervisorContainmentAbort = new AbortController();
|
|
24259
24549
|
void childExited.then(() => supervisorContainmentAbort.abort());
|
|
24260
24550
|
const outcomePromise = new Promise(
|
|
24261
|
-
(
|
|
24551
|
+
(resolve15) => {
|
|
24262
24552
|
let observed = false;
|
|
24263
24553
|
const finish = (code, signal) => {
|
|
24264
24554
|
if (observed) return;
|
|
24265
24555
|
observed = true;
|
|
24266
24556
|
resolveChildExited();
|
|
24267
|
-
|
|
24557
|
+
resolve15({ code, signal });
|
|
24268
24558
|
};
|
|
24269
24559
|
child.once("error", () => finish(1, null));
|
|
24270
24560
|
child.once("exit", finish);
|
|
@@ -24285,12 +24575,12 @@ async function launchHostSupervisor(options = {}) {
|
|
|
24285
24575
|
if (!supervisorContainment || !launchedSupervisor.stdin) {
|
|
24286
24576
|
throw new Error("supervisor Job Object gate is unavailable");
|
|
24287
24577
|
}
|
|
24288
|
-
await new Promise((
|
|
24578
|
+
await new Promise((resolve15, reject3) => {
|
|
24289
24579
|
launchedSupervisor.stdin.write(
|
|
24290
24580
|
windowsContainmentGate(containmentGateNonce),
|
|
24291
24581
|
(error52) => {
|
|
24292
24582
|
if (error52) reject3(error52);
|
|
24293
|
-
else
|
|
24583
|
+
else resolve15();
|
|
24294
24584
|
}
|
|
24295
24585
|
);
|
|
24296
24586
|
});
|
|
@@ -24432,18 +24722,18 @@ async function superviseHost(options = {}) {
|
|
|
24432
24722
|
}
|
|
24433
24723
|
}
|
|
24434
24724
|
let announceShutdown;
|
|
24435
|
-
const shutdownAnnounced = new Promise((
|
|
24436
|
-
announceShutdown =
|
|
24725
|
+
const shutdownAnnounced = new Promise((resolve15) => {
|
|
24726
|
+
announceShutdown = resolve15;
|
|
24437
24727
|
});
|
|
24438
24728
|
const attempted = /* @__PURE__ */ new Set();
|
|
24439
24729
|
const waitOrShutdown = async (ms) => {
|
|
24440
24730
|
if (shuttingDown2) return false;
|
|
24441
24731
|
if (!customDelay) {
|
|
24442
|
-
await new Promise((
|
|
24732
|
+
await new Promise((resolve15) => {
|
|
24443
24733
|
const finish = () => {
|
|
24444
24734
|
clearTimeout(timer);
|
|
24445
24735
|
shutdownController.signal.removeEventListener("abort", finish);
|
|
24446
|
-
|
|
24736
|
+
resolve15();
|
|
24447
24737
|
};
|
|
24448
24738
|
const timer = setTimeout(finish, ms);
|
|
24449
24739
|
shutdownController.signal.addEventListener("abort", finish, { once: true });
|
|
@@ -24586,19 +24876,19 @@ async function superviseHost(options = {}) {
|
|
|
24586
24876
|
child = spawnWorker(command, watchdogLaunch, compatibilityOwnership, containmentGateNonce);
|
|
24587
24877
|
const watchedChild = child;
|
|
24588
24878
|
let resolveChildExited;
|
|
24589
|
-
const childExited = new Promise((
|
|
24590
|
-
resolveChildExited =
|
|
24879
|
+
const childExited = new Promise((resolve15) => {
|
|
24880
|
+
resolveChildExited = resolve15;
|
|
24591
24881
|
});
|
|
24592
24882
|
const workerContainmentAbort = new AbortController();
|
|
24593
24883
|
void childExited.then(() => workerContainmentAbort.abort());
|
|
24594
24884
|
const outcomePromise = new Promise(
|
|
24595
|
-
(
|
|
24885
|
+
(resolve15) => {
|
|
24596
24886
|
let observed = false;
|
|
24597
24887
|
const finish = (result) => {
|
|
24598
24888
|
if (observed) return;
|
|
24599
24889
|
observed = true;
|
|
24600
24890
|
resolveChildExited();
|
|
24601
|
-
|
|
24891
|
+
resolve15(result);
|
|
24602
24892
|
};
|
|
24603
24893
|
watchedChild.once("error", () => finish({ code: 1, signal: null }));
|
|
24604
24894
|
watchedChild.once(
|
|
@@ -24620,10 +24910,10 @@ async function superviseHost(options = {}) {
|
|
|
24620
24910
|
if (!workerContainment || !watchedChild.stdin) {
|
|
24621
24911
|
throw new Error("worker Job Object gate is unavailable");
|
|
24622
24912
|
}
|
|
24623
|
-
await new Promise((
|
|
24913
|
+
await new Promise((resolve15, reject3) => {
|
|
24624
24914
|
watchedChild.stdin.write(windowsContainmentGate(containmentGateNonce), (error52) => {
|
|
24625
24915
|
if (error52) reject3(error52);
|
|
24626
|
-
else
|
|
24916
|
+
else resolve15();
|
|
24627
24917
|
});
|
|
24628
24918
|
});
|
|
24629
24919
|
}
|
|
@@ -24890,6 +25180,20 @@ async function superviseHost(options = {}) {
|
|
|
24890
25180
|
import { hostname as hostname3 } from "node:os";
|
|
24891
25181
|
|
|
24892
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
|
+
}
|
|
24893
25197
|
var DEMO_FRAME_JPEG_BASE64 = "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAIAAgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigD//2Q==";
|
|
24894
25198
|
function createDemoBrowserAdapterFactory() {
|
|
24895
25199
|
return {
|
|
@@ -25039,6 +25343,7 @@ function createDemoBrowserAdapterFactory() {
|
|
|
25039
25343
|
return frame();
|
|
25040
25344
|
},
|
|
25041
25345
|
async fillLogin(credential) {
|
|
25346
|
+
requireBrowserLoginOrigin(active().url, credential.loginUrl);
|
|
25042
25347
|
const landedUrl = new URL("/account", credential.loginUrl).toString();
|
|
25043
25348
|
const tab = active();
|
|
25044
25349
|
tab.url = landedUrl;
|
|
@@ -25061,9 +25366,9 @@ function createDemoBrowserAdapterFactory() {
|
|
|
25061
25366
|
}
|
|
25062
25367
|
|
|
25063
25368
|
// src/browser/manager.ts
|
|
25064
|
-
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";
|
|
25065
25370
|
import { homedir as homedir2 } from "node:os";
|
|
25066
|
-
import { join as join7 } from "node:path";
|
|
25371
|
+
import { dirname as dirname4, join as join7, resolve as resolve4 } from "node:path";
|
|
25067
25372
|
var SAFE_SEGMENT = /^[A-Za-z0-9_-]{1,200}$/;
|
|
25068
25373
|
var FRAME_MIN_INTERVAL_MS = 100;
|
|
25069
25374
|
var IDLE_TIMEOUT_MS = 15 * 6e4;
|
|
@@ -25071,18 +25376,34 @@ var BrowserManager = class {
|
|
|
25071
25376
|
constructor(opts) {
|
|
25072
25377
|
this.opts = opts;
|
|
25073
25378
|
this.profileRoot = opts.profileRoot ?? join7(homedir2(), ".zixt", "browser-profiles");
|
|
25379
|
+
this.profileStateRoot = join7(this.profileRoot, ".profile-state");
|
|
25074
25380
|
this.viewport = opts.viewport ?? BROWSER_DEFAULT_VIEWPORT;
|
|
25075
25381
|
this.idleTimeoutMs = opts.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
25076
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
|
+
);
|
|
25077
25390
|
}
|
|
25078
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();
|
|
25079
25398
|
/** Serializes open/close per teammate: one profile allows one live browser. */
|
|
25080
25399
|
locks = /* @__PURE__ */ new Map();
|
|
25081
25400
|
events = null;
|
|
25082
25401
|
profileRoot;
|
|
25402
|
+
profileStateRoot;
|
|
25083
25403
|
viewport;
|
|
25084
25404
|
idleTimeoutMs;
|
|
25085
25405
|
frameMinIntervalMs;
|
|
25406
|
+
profileInventoryLimit;
|
|
25086
25407
|
/**
|
|
25087
25408
|
* Wired once by the host client; replaces any prior socket generation's
|
|
25088
25409
|
* sink. Attaching re-announces every live session, because the cloud keeps
|
|
@@ -25099,6 +25420,31 @@ var BrowserManager = class {
|
|
|
25099
25420
|
capability() {
|
|
25100
25421
|
return this.opts.factory.capability();
|
|
25101
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
|
+
}
|
|
25102
25448
|
sessionState(agentId) {
|
|
25103
25449
|
const session = this.sessions.get(agentId);
|
|
25104
25450
|
return session && !session.closed ? this.stateOf(session) : null;
|
|
@@ -25114,6 +25460,122 @@ var BrowserManager = class {
|
|
|
25114
25460
|
);
|
|
25115
25461
|
return next;
|
|
25116
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
|
+
}
|
|
25117
25579
|
/**
|
|
25118
25580
|
* Ensure a live session for this teammate. An existing session is adopted
|
|
25119
25581
|
* as-is (the cloud-minted id loses to the live one — the cloud reconciles
|
|
@@ -25121,16 +25583,39 @@ var BrowserManager = class {
|
|
|
25121
25583
|
* with the install remedy.
|
|
25122
25584
|
*/
|
|
25123
25585
|
ensure(agentId, browserSessionId) {
|
|
25124
|
-
|
|
25125
|
-
|
|
25586
|
+
try {
|
|
25587
|
+
this.validateAgentId(agentId);
|
|
25588
|
+
} catch (error52) {
|
|
25589
|
+
return Promise.reject(error52);
|
|
25126
25590
|
}
|
|
25127
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
|
+
}
|
|
25128
25601
|
const existing = this.sessions.get(agentId);
|
|
25602
|
+
if (existing?.closeFailed) {
|
|
25603
|
+
throw new Error("the previous browser termination is not yet confirmed");
|
|
25604
|
+
}
|
|
25129
25605
|
if (existing && !existing.closed) {
|
|
25130
25606
|
this.markActivity(agentId);
|
|
25131
25607
|
return this.stateOf(existing);
|
|
25132
25608
|
}
|
|
25133
|
-
|
|
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
|
+
}
|
|
25134
25619
|
await mkdir4(profileDir, { recursive: true, mode: 448 });
|
|
25135
25620
|
const adapter = await this.opts.factory.open({
|
|
25136
25621
|
agentId,
|
|
@@ -25151,7 +25636,8 @@ var BrowserManager = class {
|
|
|
25151
25636
|
framesPaused: false,
|
|
25152
25637
|
inputQueue: Promise.resolve(),
|
|
25153
25638
|
resizeGeneration: 0,
|
|
25154
|
-
closed: false
|
|
25639
|
+
closed: false,
|
|
25640
|
+
closeFailed: false
|
|
25155
25641
|
};
|
|
25156
25642
|
this.sessions.set(agentId, session);
|
|
25157
25643
|
adapter.onStateChanged(() => {
|
|
@@ -25163,7 +25649,8 @@ var BrowserManager = class {
|
|
|
25163
25649
|
});
|
|
25164
25650
|
}
|
|
25165
25651
|
/** browser.open handler: ensure, then announce with the request correlation. */
|
|
25166
|
-
async open(agentId, browserSessionId, _viewport, openRequestId) {
|
|
25652
|
+
async open(agentId, browserSessionId, _viewport, openRequestId, profileRevision) {
|
|
25653
|
+
if (profileRevision !== void 0) await this.authorizeProfile(agentId, profileRevision);
|
|
25167
25654
|
const state = await this.ensure(agentId, browserSessionId);
|
|
25168
25655
|
this.events?.state(state, openRequestId);
|
|
25169
25656
|
return state;
|
|
@@ -25173,18 +25660,45 @@ var BrowserManager = class {
|
|
|
25173
25660
|
}
|
|
25174
25661
|
async closeLocked(agentId, reason) {
|
|
25175
25662
|
const session = this.sessions.get(agentId);
|
|
25176
|
-
if (!session || session.closed) return;
|
|
25663
|
+
if (!session || session.closed && !session.closeFailed) return;
|
|
25177
25664
|
session.closed = true;
|
|
25665
|
+
session.closeFailed = false;
|
|
25178
25666
|
if (session.frameTimer) clearTimeout(session.frameTimer);
|
|
25179
25667
|
if (session.idleTimer) clearTimeout(session.idleTimer);
|
|
25180
|
-
this.sessions.delete(agentId);
|
|
25181
25668
|
try {
|
|
25182
|
-
await session.adapter.setFrameSink(null)
|
|
25669
|
+
await session.adapter.setFrameSink(null).catch(() => {
|
|
25670
|
+
});
|
|
25183
25671
|
await session.adapter.close();
|
|
25184
|
-
} catch {
|
|
25672
|
+
} catch (error52) {
|
|
25673
|
+
session.closeFailed = true;
|
|
25674
|
+
throw error52;
|
|
25185
25675
|
}
|
|
25676
|
+
this.sessions.delete(agentId);
|
|
25186
25677
|
this.events?.ended(session.browserSessionId, agentId, reason);
|
|
25187
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
|
+
}
|
|
25188
25702
|
async closeAll(reason) {
|
|
25189
25703
|
await Promise.allSettled(
|
|
25190
25704
|
[...this.sessions.keys()].map((agentId) => this.close(agentId, reason))
|
|
@@ -25224,8 +25738,8 @@ var BrowserManager = class {
|
|
|
25224
25738
|
return this.enqueue(session, async () => {
|
|
25225
25739
|
if (resizeGeneration !== null && resizeGeneration !== session.resizeGeneration) return;
|
|
25226
25740
|
await session.adapter.command(command);
|
|
25227
|
-
const
|
|
25228
|
-
if (
|
|
25741
|
+
const needsImmediateFrame = command.action === "resize" || command.action === "activateTab" || command.action === "newTab" || command.action === "closeTab";
|
|
25742
|
+
if (needsImmediateFrame && session.viewerCount > 0) {
|
|
25229
25743
|
try {
|
|
25230
25744
|
this.enqueueFrame(session, await session.adapter.screenshot());
|
|
25231
25745
|
} catch {
|
|
@@ -25331,7 +25845,8 @@ var BrowserManager = class {
|
|
|
25331
25845
|
this.armIdleTimer(session);
|
|
25332
25846
|
return;
|
|
25333
25847
|
}
|
|
25334
|
-
void this.close(session.agentId, "idle_timeout")
|
|
25848
|
+
void this.close(session.agentId, "idle_timeout").catch(() => {
|
|
25849
|
+
});
|
|
25335
25850
|
}, this.idleTimeoutMs);
|
|
25336
25851
|
session.idleTimer.unref?.();
|
|
25337
25852
|
}
|
|
@@ -25348,12 +25863,13 @@ async function loadPlaywright() {
|
|
|
25348
25863
|
return import("playwright-core");
|
|
25349
25864
|
}
|
|
25350
25865
|
var KEY_ALIASES = { " ": "Space" };
|
|
25351
|
-
function createPlaywrightBrowserAdapterFactory() {
|
|
25866
|
+
function createPlaywrightBrowserAdapterFactory(dependencies = {}) {
|
|
25867
|
+
const load = dependencies.loadPlaywright ?? loadPlaywright;
|
|
25352
25868
|
return {
|
|
25353
25869
|
kind: "playwright",
|
|
25354
25870
|
async capability() {
|
|
25355
25871
|
try {
|
|
25356
|
-
const playwright = await
|
|
25872
|
+
const playwright = await load();
|
|
25357
25873
|
const executable = playwright.chromium.executablePath();
|
|
25358
25874
|
if (!executable) return { status: "unavailable", error: BROWSER_INSTALL_REMEDY };
|
|
25359
25875
|
await access3(executable);
|
|
@@ -25363,7 +25879,7 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25363
25879
|
}
|
|
25364
25880
|
},
|
|
25365
25881
|
async open({ profileDir, viewport }) {
|
|
25366
|
-
const playwright = await
|
|
25882
|
+
const playwright = await load();
|
|
25367
25883
|
const context = await playwright.chromium.launchPersistentContext(profileDir, {
|
|
25368
25884
|
headless: true,
|
|
25369
25885
|
viewport,
|
|
@@ -25732,8 +26248,10 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25732
26248
|
async fillLogin(credential) {
|
|
25733
26249
|
const tab = requireActive();
|
|
25734
26250
|
const { page: page2 } = tab;
|
|
26251
|
+
const expectedOrigin = requireBrowserLoginOrigin(safeUrl(page2), credential.loginUrl);
|
|
25735
26252
|
const password = page2.locator('input[type="password"]:visible').first();
|
|
25736
26253
|
await password.waitFor({ state: "visible", timeout: ACTION_TIMEOUT_MS });
|
|
26254
|
+
requireBrowserLoginOrigin(safeUrl(page2), credential.loginUrl);
|
|
25737
26255
|
const username = page2.locator(
|
|
25738
26256
|
[
|
|
25739
26257
|
'input[autocomplete="username"]:visible',
|
|
@@ -25743,14 +26261,66 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25743
26261
|
'input[type="text"]:visible'
|
|
25744
26262
|
].join(", ")
|
|
25745
26263
|
).first();
|
|
25746
|
-
|
|
25747
|
-
|
|
25748
|
-
|
|
25749
|
-
|
|
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);
|
|
25750
26316
|
}
|
|
26317
|
+
throw error52;
|
|
26318
|
+
} finally {
|
|
26319
|
+
await Promise.allSettled([
|
|
26320
|
+
passwordInputHandle.dispose(),
|
|
26321
|
+
...usernameInputHandle ? [usernameInputHandle.dispose()] : []
|
|
26322
|
+
]);
|
|
25751
26323
|
}
|
|
25752
|
-
await password.fill(credential.password, { timeout: ACTION_TIMEOUT_MS });
|
|
25753
|
-
await password.press("Enter");
|
|
25754
26324
|
try {
|
|
25755
26325
|
await page2.waitForLoadState("load", { timeout: 15e3 });
|
|
25756
26326
|
} catch {
|
|
@@ -25796,10 +26366,7 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25796
26366
|
async close() {
|
|
25797
26367
|
closed = true;
|
|
25798
26368
|
for (const tab of tabs) await detachSession(tab);
|
|
25799
|
-
|
|
25800
|
-
await context.close();
|
|
25801
|
-
} catch {
|
|
25802
|
-
}
|
|
26369
|
+
await context.close();
|
|
25803
26370
|
}
|
|
25804
26371
|
};
|
|
25805
26372
|
}
|
|
@@ -25809,9 +26376,9 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25809
26376
|
// src/runners/cli-runner.ts
|
|
25810
26377
|
import { spawn as spawn8 } from "node:child_process";
|
|
25811
26378
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
25812
|
-
import { lstat as
|
|
26379
|
+
import { lstat as lstat10, mkdir as mkdir10, realpath as realpath7 } from "node:fs/promises";
|
|
25813
26380
|
import { homedir as homedir4 } from "node:os";
|
|
25814
|
-
import { dirname as
|
|
26381
|
+
import { dirname as dirname7, isAbsolute as isAbsolute13, join as join14, resolve as resolve8 } from "node:path";
|
|
25815
26382
|
|
|
25816
26383
|
// src/tool-packs/browser/tool-definitions.ts
|
|
25817
26384
|
function definition(name, description, properties, required2 = []) {
|
|
@@ -26033,9 +26600,13 @@ function createBrowserToolPack(deps) {
|
|
|
26033
26600
|
});
|
|
26034
26601
|
const credential = await deps.requestWebLogin(credentialName, origin);
|
|
26035
26602
|
try {
|
|
26603
|
+
requireBrowserLoginOrigin(tool.state().url, credential.loginUrl);
|
|
26036
26604
|
const { landedUrl } = await tool.fillLogin(credential);
|
|
26037
26605
|
return { ok: true, result: { loggedIn: true, landedUrl } };
|
|
26038
|
-
} 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
|
+
}
|
|
26039
26610
|
return {
|
|
26040
26611
|
ok: false,
|
|
26041
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"
|
|
@@ -28500,13 +29071,13 @@ function createGithubPushOrchestrator(input) {
|
|
|
28500
29071
|
// src/tool-packs/github/git-bridge.ts
|
|
28501
29072
|
import { spawn as spawn5 } from "node:child_process";
|
|
28502
29073
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
28503
|
-
import { chmod as chmod3, lstat as
|
|
28504
|
-
import { dirname as
|
|
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";
|
|
28505
29076
|
|
|
28506
29077
|
// src/tool-packs/github/git-credential-broker.ts
|
|
28507
29078
|
import { createServer } from "node:http";
|
|
28508
29079
|
import { randomBytes, randomUUID as randomUUID6, timingSafeEqual } from "node:crypto";
|
|
28509
|
-
import { chmod as chmod2, lstat as
|
|
29080
|
+
import { chmod as chmod2, lstat as lstat5, realpath as realpath2, writeFile } from "node:fs/promises";
|
|
28510
29081
|
import { isAbsolute as isAbsolute7, join as join8, relative as relative3 } from "node:path";
|
|
28511
29082
|
var MAX_REQUEST_BYTES = 16 * 1024;
|
|
28512
29083
|
var FILE_MODE = 384;
|
|
@@ -28631,7 +29202,7 @@ async function createGithubGitCredentialBroker(input) {
|
|
|
28631
29202
|
throw new Error("GitHub credential authority has expired");
|
|
28632
29203
|
}
|
|
28633
29204
|
assertRepositoryFullName(input.repositoryFullName);
|
|
28634
|
-
const rootEntry = await
|
|
29205
|
+
const rootEntry = await lstat5(input.runArtifactsRoot);
|
|
28635
29206
|
if (!rootEntry.isDirectory() || rootEntry.isSymbolicLink()) {
|
|
28636
29207
|
throw new Error("Git credential broker requires a private real run directory");
|
|
28637
29208
|
}
|
|
@@ -28742,7 +29313,7 @@ function assertBelow(parent, child, label) {
|
|
|
28742
29313
|
void label;
|
|
28743
29314
|
}
|
|
28744
29315
|
async function requireRealDirectory(path, label) {
|
|
28745
|
-
const entry = await
|
|
29316
|
+
const entry = await lstat6(path).catch(() => null);
|
|
28746
29317
|
if (!entry || !entry.isDirectory() || entry.isSymbolicLink()) {
|
|
28747
29318
|
void label;
|
|
28748
29319
|
throw new GithubGitProcessError("invalid_input");
|
|
@@ -28752,9 +29323,9 @@ async function requireRealDirectory(path, label) {
|
|
|
28752
29323
|
async function validateTokenlessPaths(command) {
|
|
28753
29324
|
if (command.kind === "clone-from-bridge") {
|
|
28754
29325
|
if (!isAbsolute8(command.destination)) throw new GithubGitProcessError("invalid_input");
|
|
28755
|
-
const parent = await requireRealDirectory(
|
|
29326
|
+
const parent = await requireRealDirectory(dirname5(command.destination), "clone parent");
|
|
28756
29327
|
assertBelow(parent, command.destination, "clone destination");
|
|
28757
|
-
const destination = await
|
|
29328
|
+
const destination = await lstat6(command.destination).catch((error52) => {
|
|
28758
29329
|
if (error52.code === "ENOENT") return null;
|
|
28759
29330
|
throw error52;
|
|
28760
29331
|
});
|
|
@@ -28862,8 +29433,8 @@ async function runGit(input, args, env) {
|
|
|
28862
29433
|
let settled = false;
|
|
28863
29434
|
let stopping = false;
|
|
28864
29435
|
let resolveExited;
|
|
28865
|
-
const exited = new Promise((
|
|
28866
|
-
resolveExited =
|
|
29436
|
+
const exited = new Promise((resolve15) => {
|
|
29437
|
+
resolveExited = resolve15;
|
|
28867
29438
|
});
|
|
28868
29439
|
child.once("exit", resolveExited);
|
|
28869
29440
|
const cleanup = () => {
|
|
@@ -29059,7 +29630,7 @@ function createGithubGitBridge(input) {
|
|
|
29059
29630
|
const real = await requireRealDirectory(path, "git bridge");
|
|
29060
29631
|
assertBelow(current.bridges, real, "git bridge");
|
|
29061
29632
|
const hooks = join9(real, "hooks");
|
|
29062
|
-
await
|
|
29633
|
+
await rm5(hooks, { recursive: true, force: true });
|
|
29063
29634
|
await mkdir5(hooks, { mode: DIRECTORY_MODE });
|
|
29064
29635
|
await chmod3(hooks, DIRECTORY_MODE);
|
|
29065
29636
|
const config2 = join9(real, "config");
|
|
@@ -29067,7 +29638,7 @@ function createGithubGitBridge(input) {
|
|
|
29067
29638
|
active.add(real);
|
|
29068
29639
|
return real;
|
|
29069
29640
|
} catch (error52) {
|
|
29070
|
-
await
|
|
29641
|
+
await rm5(path, { recursive: true, force: true }).catch(() => {
|
|
29071
29642
|
});
|
|
29072
29643
|
throw error52;
|
|
29073
29644
|
}
|
|
@@ -29161,7 +29732,7 @@ function createGithubGitBridge(input) {
|
|
|
29161
29732
|
},
|
|
29162
29733
|
async destroyPrivateBridge(path) {
|
|
29163
29734
|
const bridge = await requireBridge(path);
|
|
29164
|
-
await
|
|
29735
|
+
await rm5(bridge, { recursive: true, force: true });
|
|
29165
29736
|
active.delete(bridge);
|
|
29166
29737
|
credentialed2.delete(bridge);
|
|
29167
29738
|
},
|
|
@@ -29169,7 +29740,7 @@ function createGithubGitBridge(input) {
|
|
|
29169
29740
|
if (closed) return;
|
|
29170
29741
|
closed = true;
|
|
29171
29742
|
const paths = [...active];
|
|
29172
|
-
await Promise.all(paths.map((path) =>
|
|
29743
|
+
await Promise.all(paths.map((path) => rm5(path, { recursive: true, force: true })));
|
|
29173
29744
|
active.clear();
|
|
29174
29745
|
credentialed2.clear();
|
|
29175
29746
|
}
|
|
@@ -29510,8 +30081,8 @@ function createRepositoryTools(runtime) {
|
|
|
29510
30081
|
|
|
29511
30082
|
// src/tool-packs/github/workspace.ts
|
|
29512
30083
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
29513
|
-
import { chmod as chmod4, lstat as
|
|
29514
|
-
import { isAbsolute as isAbsolute9, join as join10, relative as relative5, resolve as
|
|
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";
|
|
29515
30086
|
var SAFE_LOCAL_ID = /^[A-Za-z0-9_-]{1,200}$/;
|
|
29516
30087
|
var FULL_NAME2 = /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/;
|
|
29517
30088
|
var DIRECTORY_MODE2 = 448;
|
|
@@ -29534,10 +30105,10 @@ function assertBelow2(parent, child, label) {
|
|
|
29534
30105
|
}
|
|
29535
30106
|
}
|
|
29536
30107
|
function samePath(left, right) {
|
|
29537
|
-
return process.platform === "win32" ?
|
|
30108
|
+
return process.platform === "win32" ? resolve5(left).toLowerCase() === resolve5(right).toLowerCase() : resolve5(left) === resolve5(right);
|
|
29538
30109
|
}
|
|
29539
30110
|
async function requireRealDirectory2(path, label) {
|
|
29540
|
-
const entry = await
|
|
30111
|
+
const entry = await lstat7(path).catch(() => null);
|
|
29541
30112
|
if (!entry || !entry.isDirectory() || entry.isSymbolicLink()) {
|
|
29542
30113
|
throw new Error(`${label} must be a real directory, not a symbolic link or junction`);
|
|
29543
30114
|
}
|
|
@@ -29574,7 +30145,7 @@ function parseMetadata(text) {
|
|
|
29574
30145
|
}
|
|
29575
30146
|
async function pathExists(path) {
|
|
29576
30147
|
try {
|
|
29577
|
-
await
|
|
30148
|
+
await lstat7(path);
|
|
29578
30149
|
return true;
|
|
29579
30150
|
} catch (error52) {
|
|
29580
30151
|
if (error52.code === "ENOENT") return false;
|
|
@@ -29636,11 +30207,11 @@ async function createGithubWorkspaceService(input) {
|
|
|
29636
30207
|
if (!await pathExists(destination) || !await pathExists(metadataPath)) {
|
|
29637
30208
|
throw new Error("GitHub repository workspace has not been prepared");
|
|
29638
30209
|
}
|
|
29639
|
-
const metadataEntry = await
|
|
30210
|
+
const metadataEntry = await lstat7(metadataPath);
|
|
29640
30211
|
if (!metadataEntry.isFile() || metadataEntry.isSymbolicLink()) {
|
|
29641
30212
|
throw new Error("GitHub workspace metadata is invalid");
|
|
29642
30213
|
}
|
|
29643
|
-
const metadata = parseMetadata(await
|
|
30214
|
+
const metadata = parseMetadata(await readFile6(metadataPath, "utf8"));
|
|
29644
30215
|
if (metadata.repositoryId !== parsed.data || metadata.fullName !== repository.fullName || !samePath(metadata.path, destination)) {
|
|
29645
30216
|
throw new Error("GitHub workspace metadata does not match this repository");
|
|
29646
30217
|
}
|
|
@@ -29690,15 +30261,15 @@ async function createGithubWorkspaceService(input) {
|
|
|
29690
30261
|
});
|
|
29691
30262
|
await chmod4(metadataTemporary, FILE_MODE2);
|
|
29692
30263
|
try {
|
|
29693
|
-
await
|
|
30264
|
+
await rename4(temporaryReal, destination);
|
|
29694
30265
|
try {
|
|
29695
|
-
await
|
|
30266
|
+
await rename4(metadataTemporary, metadataPath);
|
|
29696
30267
|
} catch (error52) {
|
|
29697
|
-
await
|
|
30268
|
+
await rm6(destination, { recursive: true, force: true });
|
|
29698
30269
|
throw error52;
|
|
29699
30270
|
}
|
|
29700
30271
|
} finally {
|
|
29701
|
-
await
|
|
30272
|
+
await rm6(metadataTemporary, { force: true }).catch(() => {
|
|
29702
30273
|
});
|
|
29703
30274
|
}
|
|
29704
30275
|
const path = await requireRealDirectory2(destination, "GitHub repository");
|
|
@@ -29710,7 +30281,7 @@ async function createGithubWorkspaceService(input) {
|
|
|
29710
30281
|
headSha
|
|
29711
30282
|
};
|
|
29712
30283
|
} finally {
|
|
29713
|
-
await
|
|
30284
|
+
await rm6(temporary, { recursive: true, force: true }).catch(() => {
|
|
29714
30285
|
});
|
|
29715
30286
|
}
|
|
29716
30287
|
};
|
|
@@ -29738,11 +30309,11 @@ async function createGithubWorkspaceService(input) {
|
|
|
29738
30309
|
expiresAt: authority.expiresAt
|
|
29739
30310
|
});
|
|
29740
30311
|
}
|
|
29741
|
-
const metadataEntry = await
|
|
30312
|
+
const metadataEntry = await lstat7(metadataPath);
|
|
29742
30313
|
if (!metadataEntry.isFile() || metadataEntry.isSymbolicLink()) {
|
|
29743
30314
|
throw new Error("GitHub workspace metadata is invalid");
|
|
29744
30315
|
}
|
|
29745
|
-
const metadata = parseMetadata(await
|
|
30316
|
+
const metadata = parseMetadata(await readFile6(metadataPath, "utf8"));
|
|
29746
30317
|
if (metadata.repositoryId !== repository.repositoryId || metadata.fullName !== repository.fullName || !samePath(metadata.path, destination)) {
|
|
29747
30318
|
throw new Error("GitHub workspace metadata does not match this repository");
|
|
29748
30319
|
}
|
|
@@ -31351,8 +31922,8 @@ var linearToolPackFactory = {
|
|
|
31351
31922
|
async create(grant, context) {
|
|
31352
31923
|
let resolveCancelled;
|
|
31353
31924
|
let closed = false;
|
|
31354
|
-
const cancelled = new Promise((
|
|
31355
|
-
resolveCancelled =
|
|
31925
|
+
const cancelled = new Promise((resolve15) => {
|
|
31926
|
+
resolveCancelled = resolve15;
|
|
31356
31927
|
});
|
|
31357
31928
|
const cancel = () => {
|
|
31358
31929
|
if (closed) return;
|
|
@@ -31721,6 +32292,21 @@ var TOOLS = [
|
|
|
31721
32292
|
required: ["agent_id", "message"]
|
|
31722
32293
|
}
|
|
31723
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
|
+
},
|
|
31724
32310
|
{
|
|
31725
32311
|
name: "get_org_config",
|
|
31726
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.",
|
|
@@ -31963,6 +32549,8 @@ function opFor(name, args) {
|
|
|
31963
32549
|
message: str("message"),
|
|
31964
32550
|
...typeof args["task_id"] === "string" && args["task_id"] ? { taskId: args["task_id"] } : {}
|
|
31965
32551
|
};
|
|
32552
|
+
case "message_manager":
|
|
32553
|
+
return { kind: "manager.message", message: str("message") };
|
|
31966
32554
|
case "get_org_config":
|
|
31967
32555
|
return { kind: "org.config" };
|
|
31968
32556
|
case "read_credential": {
|
|
@@ -32021,7 +32609,7 @@ function createAskUserServer() {
|
|
|
32021
32609
|
let server;
|
|
32022
32610
|
let listening;
|
|
32023
32611
|
function ensureListening() {
|
|
32024
|
-
listening ??= new Promise((
|
|
32612
|
+
listening ??= new Promise((resolve15, reject3) => {
|
|
32025
32613
|
server = createServer2((req, res) => {
|
|
32026
32614
|
res.on("error", () => {
|
|
32027
32615
|
});
|
|
@@ -32037,7 +32625,7 @@ function createAskUserServer() {
|
|
|
32037
32625
|
server.on("error", reject3);
|
|
32038
32626
|
server.listen(0, "127.0.0.1", () => {
|
|
32039
32627
|
const address = server.address();
|
|
32040
|
-
if (address && typeof address === "object")
|
|
32628
|
+
if (address && typeof address === "object") resolve15(address.port);
|
|
32041
32629
|
else reject3(new Error("ask_user server failed to bind"));
|
|
32042
32630
|
});
|
|
32043
32631
|
server.unref();
|
|
@@ -32369,7 +32957,7 @@ function buildRunnerEnv(input) {
|
|
|
32369
32957
|
// src/runners/github-shell-auth.ts
|
|
32370
32958
|
import { execFile } from "node:child_process";
|
|
32371
32959
|
import { randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
32372
|
-
import { chmod as chmod5, lstat as
|
|
32960
|
+
import { chmod as chmod5, lstat as lstat8, mkdir as mkdir8, realpath as realpath5, writeFile as writeFile4 } from "node:fs/promises";
|
|
32373
32961
|
import { createServer as createServer3 } from "node:http";
|
|
32374
32962
|
import { isAbsolute as isAbsolute11, join as join12, relative as relative6 } from "node:path";
|
|
32375
32963
|
var MAX_REQUEST_BYTES2 = 16 * 1024;
|
|
@@ -32754,7 +33342,7 @@ async function writePrivate(path, content, executable = false) {
|
|
|
32754
33342
|
await chmod5(path, executable ? EXECUTABLE_FILE_MODE : PRIVATE_FILE_MODE);
|
|
32755
33343
|
}
|
|
32756
33344
|
async function prepareHelpers(input) {
|
|
32757
|
-
const rootEntry = await
|
|
33345
|
+
const rootEntry = await lstat8(input.runRoot);
|
|
32758
33346
|
if (!rootEntry.isDirectory() || rootEntry.isSymbolicLink()) {
|
|
32759
33347
|
throw new Error("GitHub shell authentication requires a private real run directory");
|
|
32760
33348
|
}
|
|
@@ -33001,7 +33589,7 @@ password=${credential.accessToken}
|
|
|
33001
33589
|
|
|
33002
33590
|
// src/runners/working-context.ts
|
|
33003
33591
|
import { spawn as spawn6 } from "node:child_process";
|
|
33004
|
-
import { resolve as
|
|
33592
|
+
import { resolve as resolve6 } from "node:path";
|
|
33005
33593
|
var COMMAND_TIMEOUT_MS = 5e3;
|
|
33006
33594
|
var OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
33007
33595
|
var COMMAND_STOP_TIMEOUT_MS = 2e4;
|
|
@@ -33359,8 +33947,8 @@ async function repositoryState(directory, git, env, signal) {
|
|
|
33359
33947
|
const pathLines = paths.trim().split(/\r?\n/);
|
|
33360
33948
|
if (pathLines.length < 3 || !pathLines[0] || !pathLines[1] || !pathLines[2]) return null;
|
|
33361
33949
|
const root = pathLines[0];
|
|
33362
|
-
const gitDirectory =
|
|
33363
|
-
const commonDirectory =
|
|
33950
|
+
const gitDirectory = resolve6(directory, pathLines[1]);
|
|
33951
|
+
const commonDirectory = resolve6(directory, pathLines[2]);
|
|
33364
33952
|
const records = status.split(/\0|\r?\n/).filter(Boolean);
|
|
33365
33953
|
const rawBranch = statusField(records, "branch.head");
|
|
33366
33954
|
if (!rawBranch || rawBranch.length > 512 || !isSafeSingleLineDisplayText(rawBranch)) return null;
|
|
@@ -33507,18 +34095,18 @@ var WorkingContextPullRequestCache = class {
|
|
|
33507
34095
|
import { spawn as spawn7 } from "node:child_process";
|
|
33508
34096
|
import {
|
|
33509
34097
|
chmod as chmod6,
|
|
33510
|
-
lstat as
|
|
34098
|
+
lstat as lstat9,
|
|
33511
34099
|
mkdir as mkdir9,
|
|
33512
|
-
open as
|
|
34100
|
+
open as open5,
|
|
33513
34101
|
readdir as readdir3,
|
|
33514
|
-
readFile as
|
|
34102
|
+
readFile as readFile7,
|
|
33515
34103
|
realpath as realpath6,
|
|
33516
|
-
rename as
|
|
33517
|
-
rm as
|
|
34104
|
+
rename as rename5,
|
|
34105
|
+
rm as rm7,
|
|
33518
34106
|
writeFile as writeFile5
|
|
33519
34107
|
} from "node:fs/promises";
|
|
33520
34108
|
import { homedir as homedir3 } from "node:os";
|
|
33521
|
-
import { dirname as
|
|
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";
|
|
33522
34110
|
var SAFE_SEGMENT2 = /^[A-Za-z0-9_-]{1,200}$/;
|
|
33523
34111
|
var DIRECTORY_MODE4 = 448;
|
|
33524
34112
|
var FILE_MODE3 = 384;
|
|
@@ -33751,7 +34339,7 @@ function assertBelow3(parent, child) {
|
|
|
33751
34339
|
if (escapes) throw new Error("run artifact path escapes its private root");
|
|
33752
34340
|
}
|
|
33753
34341
|
async function requireRealDirectory3(path, label) {
|
|
33754
|
-
const entry = await
|
|
34342
|
+
const entry = await lstat9(path);
|
|
33755
34343
|
if (entry.isSymbolicLink()) throw new Error(`${label} must not be a symbolic link`);
|
|
33756
34344
|
if (!entry.isDirectory()) throw new Error(`${label} must be a directory`);
|
|
33757
34345
|
return realpath6(path);
|
|
@@ -33768,7 +34356,7 @@ async function rejectWindowsSymlinkAncestors(profile, target) {
|
|
|
33768
34356
|
for (const segment of path.split("\\").filter(Boolean)) {
|
|
33769
34357
|
current = win322.join(current, segment);
|
|
33770
34358
|
try {
|
|
33771
|
-
const entry = await
|
|
34359
|
+
const entry = await lstat9(current);
|
|
33772
34360
|
if (entry.isSymbolicLink()) {
|
|
33773
34361
|
throw new Error("run artifact path must not contain symbolic links or junctions");
|
|
33774
34362
|
}
|
|
@@ -33779,16 +34367,16 @@ async function rejectWindowsSymlinkAncestors(profile, target) {
|
|
|
33779
34367
|
}
|
|
33780
34368
|
}
|
|
33781
34369
|
async function prepareRoot(root) {
|
|
33782
|
-
const absolute =
|
|
34370
|
+
const absolute = resolve7(root);
|
|
33783
34371
|
let realProfile;
|
|
33784
34372
|
if (process.platform === "win32") {
|
|
33785
|
-
const profile =
|
|
34373
|
+
const profile = resolve7(homedir3());
|
|
33786
34374
|
assertWindowsProfileBoundary(profile, absolute);
|
|
33787
34375
|
await rejectWindowsSymlinkAncestors(profile, absolute);
|
|
33788
34376
|
realProfile = await realpath6(profile);
|
|
33789
34377
|
}
|
|
33790
34378
|
try {
|
|
33791
|
-
await
|
|
34379
|
+
await lstat9(absolute);
|
|
33792
34380
|
} catch (error52) {
|
|
33793
34381
|
if (!isMissing(error52)) throw error52;
|
|
33794
34382
|
await mkdir9(absolute, { recursive: true, mode: DIRECTORY_MODE4 });
|
|
@@ -33802,7 +34390,7 @@ async function prepareAgentRoot(root, agentId) {
|
|
|
33802
34390
|
const path = join13(root, agentId);
|
|
33803
34391
|
assertBelow3(root, path);
|
|
33804
34392
|
try {
|
|
33805
|
-
await
|
|
34393
|
+
await lstat9(path);
|
|
33806
34394
|
} catch (error52) {
|
|
33807
34395
|
if (!isMissing(error52)) throw error52;
|
|
33808
34396
|
try {
|
|
@@ -33893,7 +34481,7 @@ async function createRunArtifacts(input) {
|
|
|
33893
34481
|
requireSafeSegment(input.agentId, "agentId");
|
|
33894
34482
|
requireSafeSegment(input.runToken, "runToken");
|
|
33895
34483
|
const root = await prepareRoot(input.root);
|
|
33896
|
-
const removeTree = input.removeTree ?? ((path) =>
|
|
34484
|
+
const removeTree = input.removeTree ?? ((path) => rm7(path, { recursive: true, force: true }));
|
|
33897
34485
|
const cleanupRetryDelayMs = input.cleanupRetryDelayMs ?? CLEANUP_RETRY_DELAY_MS;
|
|
33898
34486
|
const agentRoot = await prepareAgentRoot(root, input.agentId);
|
|
33899
34487
|
await lockDownWindowsDirectories([root, agentRoot]);
|
|
@@ -33952,10 +34540,10 @@ async function removePrivateTreeWithRetries(path, removeTree, retryDelayMs) {
|
|
|
33952
34540
|
}
|
|
33953
34541
|
}
|
|
33954
34542
|
async function sweepOrphanedRunArtifacts(root) {
|
|
33955
|
-
const absolute =
|
|
34543
|
+
const absolute = resolve7(root);
|
|
33956
34544
|
let realProfile;
|
|
33957
34545
|
if (process.platform === "win32") {
|
|
33958
|
-
const profile =
|
|
34546
|
+
const profile = resolve7(homedir3());
|
|
33959
34547
|
assertWindowsProfileBoundary(profile, absolute);
|
|
33960
34548
|
await rejectWindowsSymlinkAncestors(profile, absolute);
|
|
33961
34549
|
realProfile = await realpath6(profile);
|
|
@@ -33980,7 +34568,7 @@ async function sweepOrphanedRunArtifacts(root) {
|
|
|
33980
34568
|
if (!SAFE_SEGMENT2.test(run3.name) || !run3.isDirectory() || run3.isSymbolicLink()) continue;
|
|
33981
34569
|
const runPath = join13(agentPath, run3.name);
|
|
33982
34570
|
assertBelow3(agentPath, runPath);
|
|
33983
|
-
await
|
|
34571
|
+
await rm7(runPath, { recursive: true, force: true });
|
|
33984
34572
|
removed++;
|
|
33985
34573
|
}
|
|
33986
34574
|
}
|
|
@@ -33990,7 +34578,7 @@ function defaultRunRegistryRoot() {
|
|
|
33990
34578
|
return join13(homedir3(), ".zixt", "run-registry");
|
|
33991
34579
|
}
|
|
33992
34580
|
async function syncRunRegistryDirectory(path) {
|
|
33993
|
-
const handle = await
|
|
34581
|
+
const handle = await open5(path, "r");
|
|
33994
34582
|
try {
|
|
33995
34583
|
await handle.sync();
|
|
33996
34584
|
} finally {
|
|
@@ -34000,9 +34588,9 @@ async function syncRunRegistryDirectory(path) {
|
|
|
34000
34588
|
async function ensureDurableRunRegistryRoot(registryRoot, syncDirectory7) {
|
|
34001
34589
|
const firstCreated = await mkdir9(registryRoot, { recursive: true, mode: DIRECTORY_MODE4 });
|
|
34002
34590
|
if (firstCreated && process.platform !== "win32") {
|
|
34003
|
-
const first =
|
|
34004
|
-
const target =
|
|
34005
|
-
await syncDirectory7(
|
|
34591
|
+
const first = resolve7(firstCreated);
|
|
34592
|
+
const target = resolve7(registryRoot);
|
|
34593
|
+
await syncDirectory7(dirname6(first));
|
|
34006
34594
|
let current = first;
|
|
34007
34595
|
for (const part of relative7(first, target).split(sep3).filter(Boolean)) {
|
|
34008
34596
|
await syncDirectory7(current);
|
|
@@ -34019,12 +34607,12 @@ async function recordRunAssignment(runToken, record2, registryRoot = defaultRunR
|
|
|
34019
34607
|
try {
|
|
34020
34608
|
const syncDirectory7 = options.syncDirectory ?? syncRunRegistryDirectory;
|
|
34021
34609
|
await ensureDurableRunRegistryRoot(registryRoot, syncDirectory7);
|
|
34022
|
-
handle = await
|
|
34610
|
+
handle = await open5(temporary, "wx", FILE_MODE3);
|
|
34023
34611
|
await handle.writeFile(JSON.stringify(record2), "utf8");
|
|
34024
34612
|
await handle.sync();
|
|
34025
34613
|
await handle.close();
|
|
34026
34614
|
handle = void 0;
|
|
34027
|
-
await
|
|
34615
|
+
await rename5(temporary, destination);
|
|
34028
34616
|
if (process.platform !== "win32") {
|
|
34029
34617
|
await syncDirectory7(registryRoot);
|
|
34030
34618
|
}
|
|
@@ -34034,7 +34622,7 @@ async function recordRunAssignment(runToken, record2, registryRoot = defaultRunR
|
|
|
34034
34622
|
} finally {
|
|
34035
34623
|
await handle?.close().catch(() => {
|
|
34036
34624
|
});
|
|
34037
|
-
await
|
|
34625
|
+
await rm7(temporary, { force: true }).catch(() => {
|
|
34038
34626
|
});
|
|
34039
34627
|
}
|
|
34040
34628
|
}
|
|
@@ -34046,7 +34634,7 @@ async function forgetRunAssignment(runToken, registryRoot = defaultRunRegistryRo
|
|
|
34046
34634
|
if (retainingAssignments) return;
|
|
34047
34635
|
if (!SAFE_SEGMENT2.test(runToken)) return;
|
|
34048
34636
|
try {
|
|
34049
|
-
await
|
|
34637
|
+
await rm7(join13(registryRoot, `${runToken}.json`), { force: true });
|
|
34050
34638
|
} catch {
|
|
34051
34639
|
}
|
|
34052
34640
|
}
|
|
@@ -34091,7 +34679,7 @@ async function readRecordedRunAssignmentEntries(registryRoot = defaultRunRegistr
|
|
|
34091
34679
|
if (!SAFE_SEGMENT2.test(runToken)) continue;
|
|
34092
34680
|
let text;
|
|
34093
34681
|
try {
|
|
34094
|
-
text = await
|
|
34682
|
+
text = await readFile7(join13(registryRoot, entry.name), "utf8");
|
|
34095
34683
|
} catch {
|
|
34096
34684
|
continue;
|
|
34097
34685
|
}
|
|
@@ -34103,7 +34691,7 @@ async function readRecordedRunAssignmentEntries(registryRoot = defaultRunRegistr
|
|
|
34103
34691
|
async function readRecordedRunAssignmentEntriesStrict(registryRoot = defaultRunRegistryRoot()) {
|
|
34104
34692
|
let rootStat;
|
|
34105
34693
|
try {
|
|
34106
|
-
rootStat = await
|
|
34694
|
+
rootStat = await lstat9(registryRoot);
|
|
34107
34695
|
} catch (error52) {
|
|
34108
34696
|
if (isMissing(error52)) return [];
|
|
34109
34697
|
throw new Error("run registry state could not be observed");
|
|
@@ -34127,7 +34715,7 @@ async function readRecordedRunAssignmentEntriesStrict(registryRoot = defaultRunR
|
|
|
34127
34715
|
}
|
|
34128
34716
|
let text;
|
|
34129
34717
|
try {
|
|
34130
|
-
text = await
|
|
34718
|
+
text = await readFile7(join13(registryRoot, entry.name), "utf8");
|
|
34131
34719
|
} catch {
|
|
34132
34720
|
throw new Error("committed run registry witness could not be read");
|
|
34133
34721
|
}
|
|
@@ -34144,13 +34732,13 @@ async function forgetAcknowledgedRunAssignments(assignments, registryRoot = defa
|
|
|
34144
34732
|
);
|
|
34145
34733
|
const entries = await readRecordedRunAssignmentEntries(registryRoot);
|
|
34146
34734
|
await Promise.all(
|
|
34147
|
-
entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) =>
|
|
34735
|
+
entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) => rm7(join13(registryRoot, `${runToken}.json`), { force: true }))
|
|
34148
34736
|
);
|
|
34149
34737
|
}
|
|
34150
34738
|
async function forgetSupersededRunAssignments(taskId, epoch, registryRoot = defaultRunRegistryRoot()) {
|
|
34151
34739
|
const entries = await readRecordedRunAssignmentEntries(registryRoot);
|
|
34152
34740
|
await Promise.all(
|
|
34153
|
-
entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) =>
|
|
34741
|
+
entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) => rm7(join13(registryRoot, `${runToken}.json`), { force: true }))
|
|
34154
34742
|
);
|
|
34155
34743
|
}
|
|
34156
34744
|
|
|
@@ -34221,7 +34809,7 @@ function truncateThought(text) {
|
|
|
34221
34809
|
}
|
|
34222
34810
|
var MAX_APPROVAL_PAYLOAD = 5e4;
|
|
34223
34811
|
async function requireRealDirectory4(path, label) {
|
|
34224
|
-
const entry = await
|
|
34812
|
+
const entry = await lstat10(path).catch(() => null);
|
|
34225
34813
|
if (!entry) throw new Error(`${label} does not exist`);
|
|
34226
34814
|
if (entry.isSymbolicLink()) throw new Error(`${label} must not be a symbolic link`);
|
|
34227
34815
|
if (!entry.isDirectory()) throw new Error(`${label} must be a directory`);
|
|
@@ -34237,7 +34825,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
34237
34825
|
const prefixArgs = opts.commandPrefixArgs ?? [];
|
|
34238
34826
|
const maxWallTimeMs = opts.maxWallTimeMs;
|
|
34239
34827
|
const workspaceRoot = opts.workspaceRoot ?? defaultRunnerWorkspaceRoot();
|
|
34240
|
-
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join14(
|
|
34828
|
+
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join14(dirname7(workspaceRoot), "run-artifacts"));
|
|
34241
34829
|
const runRegistryRoot2 = opts.runRegistryRoot ?? defaultRunRegistryRoot();
|
|
34242
34830
|
const createArtifacts = opts.createArtifacts ?? createRunArtifacts;
|
|
34243
34831
|
const toolPackRegistry2 = opts.toolPackRegistry ?? createDefaultToolPackRegistry();
|
|
@@ -34281,7 +34869,12 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
34281
34869
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
34282
34870
|
});
|
|
34283
34871
|
if (task.cancelledNow()) return cancelledBeforeRun();
|
|
34284
|
-
const
|
|
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;
|
|
34285
34878
|
if (runner.type !== adapter.type) {
|
|
34286
34879
|
return {
|
|
34287
34880
|
outcome: "failed",
|
|
@@ -34393,7 +34986,13 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
34393
34986
|
)
|
|
34394
34987
|
);
|
|
34395
34988
|
}
|
|
34396
|
-
|
|
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) {
|
|
34397
34996
|
toolPacks.push(
|
|
34398
34997
|
createBrowserToolPack({
|
|
34399
34998
|
manager: opts.browserManager,
|
|
@@ -34564,8 +35163,8 @@ ${attachmentSection}` : prompt;
|
|
|
34564
35163
|
let changed = false;
|
|
34565
35164
|
for (const path of paths) {
|
|
34566
35165
|
if (!path || path.length > 4096) continue;
|
|
34567
|
-
const absolutePath = isAbsolute13(path) ? path :
|
|
34568
|
-
const directory =
|
|
35166
|
+
const absolutePath = isAbsolute13(path) ? path : resolve8(cwd, path);
|
|
35167
|
+
const directory = dirname7(absolutePath);
|
|
34569
35168
|
observedWorkingDirectories.delete(directory);
|
|
34570
35169
|
observedWorkingDirectories.add(directory);
|
|
34571
35170
|
while (observedWorkingDirectories.size > 19) {
|
|
@@ -34987,7 +35586,7 @@ function runCliProcess(options) {
|
|
|
34987
35586
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
34988
35587
|
});
|
|
34989
35588
|
}
|
|
34990
|
-
return new Promise((
|
|
35589
|
+
return new Promise((resolve15) => {
|
|
34991
35590
|
const platform = options.platform ?? process.platform;
|
|
34992
35591
|
const containmentGateNonce = options.guardian && platform === "win32" ? randomUUID10() : void 0;
|
|
34993
35592
|
const child = options.guardian ? spawn8(
|
|
@@ -35001,7 +35600,7 @@ function runCliProcess(options) {
|
|
|
35001
35600
|
// The idle pre-assignment guardian must never load from or depend
|
|
35002
35601
|
// on an untrusted Task checkout. Only the post-gate target enters
|
|
35003
35602
|
// the requested working directory from its private release frame.
|
|
35004
|
-
cwd:
|
|
35603
|
+
cwd: dirname7(options.guardian.scriptPath),
|
|
35005
35604
|
env: runnerGuardianEnv(process.env, containmentGateNonce),
|
|
35006
35605
|
stdio: ["pipe", "pipe", "pipe"],
|
|
35007
35606
|
windowsHide: true,
|
|
@@ -35048,7 +35647,7 @@ function runCliProcess(options) {
|
|
|
35048
35647
|
clearInterval(timer);
|
|
35049
35648
|
unregisterFollowUps?.();
|
|
35050
35649
|
parser.stop?.();
|
|
35051
|
-
|
|
35650
|
+
resolve15(result);
|
|
35052
35651
|
};
|
|
35053
35652
|
const terminate = (result) => {
|
|
35054
35653
|
if (settled || forcedResult) return;
|
|
@@ -35279,7 +35878,7 @@ function runCliProcess(options) {
|
|
|
35279
35878
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
35280
35879
|
|
|
35281
35880
|
// src/runners/runtime-observation.ts
|
|
35282
|
-
import { open as
|
|
35881
|
+
import { open as open6, readdir as readdir4, realpath as realpath8 } from "node:fs/promises";
|
|
35283
35882
|
import { homedir as homedir5 } from "node:os";
|
|
35284
35883
|
import { join as join15 } from "node:path";
|
|
35285
35884
|
var READ_WINDOW_BYTES = 1024 * 1024;
|
|
@@ -35291,7 +35890,7 @@ function homeFrom(env) {
|
|
|
35291
35890
|
async function readHead(path) {
|
|
35292
35891
|
let handle;
|
|
35293
35892
|
try {
|
|
35294
|
-
handle = await
|
|
35893
|
+
handle = await open6(path, "r");
|
|
35295
35894
|
const buffer = Buffer.alloc(READ_WINDOW_BYTES);
|
|
35296
35895
|
const { bytesRead } = await handle.read(buffer, 0, READ_WINDOW_BYTES, 0);
|
|
35297
35896
|
return buffer.subarray(0, bytesRead).toString("utf8");
|
|
@@ -35305,7 +35904,7 @@ async function readHead(path) {
|
|
|
35305
35904
|
async function readTail(path) {
|
|
35306
35905
|
let handle;
|
|
35307
35906
|
try {
|
|
35308
|
-
handle = await
|
|
35907
|
+
handle = await open6(path, "r");
|
|
35309
35908
|
const { size } = await handle.stat();
|
|
35310
35909
|
const start = Math.max(0, size - READ_WINDOW_BYTES);
|
|
35311
35910
|
const length = Math.min(size, READ_WINDOW_BYTES);
|
|
@@ -35393,7 +35992,7 @@ async function readCodexSessionRuntime(input) {
|
|
|
35393
35992
|
}
|
|
35394
35993
|
var codexCatalogCache = /* @__PURE__ */ new Map();
|
|
35395
35994
|
async function loadCodexModelCatalog(command, prefixArgs, env) {
|
|
35396
|
-
const output = await new Promise((
|
|
35995
|
+
const output = await new Promise((resolve15) => {
|
|
35397
35996
|
const child = spawnCli(command, [...prefixArgs, "debug", "models"], {
|
|
35398
35997
|
stdio: ["ignore", "pipe", "ignore"],
|
|
35399
35998
|
windowsHide: true,
|
|
@@ -35408,7 +36007,7 @@ async function loadCodexModelCatalog(command, prefixArgs, env) {
|
|
|
35408
36007
|
if (settled) return;
|
|
35409
36008
|
settled = true;
|
|
35410
36009
|
clearTimeout(timer);
|
|
35411
|
-
|
|
36010
|
+
resolve15(value);
|
|
35412
36011
|
};
|
|
35413
36012
|
const timer = setTimeout(() => {
|
|
35414
36013
|
child.kill();
|
|
@@ -35513,8 +36112,8 @@ function createRuntimeReporter(input, sessionId) {
|
|
|
35513
36112
|
var EFFORT_READ_ATTEMPTS = 5;
|
|
35514
36113
|
var EFFORT_READ_INTERVAL_MS = 3e3;
|
|
35515
36114
|
function delay2(ms) {
|
|
35516
|
-
return new Promise((
|
|
35517
|
-
const timer = setTimeout(
|
|
36115
|
+
return new Promise((resolve15) => {
|
|
36116
|
+
const timer = setTimeout(resolve15, ms);
|
|
35518
36117
|
timer.unref?.();
|
|
35519
36118
|
});
|
|
35520
36119
|
}
|
|
@@ -35591,10 +36190,10 @@ function createClaudeLiveParser(onStream, onSessionModel) {
|
|
|
35591
36190
|
},
|
|
35592
36191
|
async steer(followUp) {
|
|
35593
36192
|
if (!write) return false;
|
|
35594
|
-
return await new Promise((
|
|
35595
|
-
acknowledgements.set(followUp.inputId,
|
|
36193
|
+
return await new Promise((resolve15) => {
|
|
36194
|
+
acknowledgements.set(followUp.inputId, resolve15);
|
|
35596
36195
|
void write(input(followUp.inputId, followUp.text)).catch(() => {
|
|
35597
|
-
if (acknowledgements.delete(followUp.inputId))
|
|
36196
|
+
if (acknowledgements.delete(followUp.inputId)) resolve15(false);
|
|
35598
36197
|
});
|
|
35599
36198
|
});
|
|
35600
36199
|
},
|
|
@@ -35748,13 +36347,13 @@ function improveErrorMessage(error52) {
|
|
|
35748
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.";
|
|
35749
36348
|
}
|
|
35750
36349
|
if (lower.includes("issue with the selected model") || lower.includes("model_not_found")) {
|
|
35751
|
-
return "The selected model is not available.
|
|
36350
|
+
return "The selected model is not available. Open the failed Task, choose another model or Default in its runtime controls, then Retry.";
|
|
35752
36351
|
}
|
|
35753
36352
|
return error52;
|
|
35754
36353
|
}
|
|
35755
36354
|
|
|
35756
36355
|
// src/runners/codex.ts
|
|
35757
|
-
import { mkdir as mkdir11, readFile as
|
|
36356
|
+
import { mkdir as mkdir11, readFile as readFile8, writeFile as writeFile6 } from "node:fs/promises";
|
|
35758
36357
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
35759
36358
|
import { homedir as homedir6 } from "node:os";
|
|
35760
36359
|
import { join as join16 } from "node:path";
|
|
@@ -35769,7 +36368,7 @@ function threadIndexPath(root, agentId, sessionKey) {
|
|
|
35769
36368
|
}
|
|
35770
36369
|
async function readThreadId(path) {
|
|
35771
36370
|
try {
|
|
35772
|
-
const parsed = JSON.parse(await
|
|
36371
|
+
const parsed = JSON.parse(await readFile8(path, "utf8"));
|
|
35773
36372
|
return typeof parsed.threadId === "string" && /^[A-Za-z0-9-]{1,120}$/.test(parsed.threadId) ? parsed.threadId : null;
|
|
35774
36373
|
} catch {
|
|
35775
36374
|
return null;
|
|
@@ -35901,8 +36500,8 @@ ${value}` : value;
|
|
|
35901
36500
|
var RUNTIME_READ_ATTEMPTS = 5;
|
|
35902
36501
|
var RUNTIME_READ_INTERVAL_MS = 2e3;
|
|
35903
36502
|
function delay3(ms) {
|
|
35904
|
-
return new Promise((
|
|
35905
|
-
const timer = setTimeout(
|
|
36503
|
+
return new Promise((resolve15) => {
|
|
36504
|
+
const timer = setTimeout(resolve15, ms);
|
|
35906
36505
|
timer.unref?.();
|
|
35907
36506
|
});
|
|
35908
36507
|
}
|
|
@@ -35941,7 +36540,7 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
35941
36540
|
const turnReadyWaiters = /* @__PURE__ */ new Set();
|
|
35942
36541
|
const usage = () => ({ inputTokens, outputTokens });
|
|
35943
36542
|
const settleTurnReadiness = (ready) => {
|
|
35944
|
-
for (const
|
|
36543
|
+
for (const resolve15 of turnReadyWaiters) resolve15(ready);
|
|
35945
36544
|
turnReadyWaiters.clear();
|
|
35946
36545
|
};
|
|
35947
36546
|
const send = async (message) => {
|
|
@@ -36122,12 +36721,12 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
36122
36721
|
async steer(input) {
|
|
36123
36722
|
if (stopped) return false;
|
|
36124
36723
|
if (!activeTurnId) {
|
|
36125
|
-
const ready = await new Promise((
|
|
36724
|
+
const ready = await new Promise((resolve15) => turnReadyWaiters.add(resolve15));
|
|
36126
36725
|
if (!ready || stopped) return false;
|
|
36127
36726
|
}
|
|
36128
36727
|
if (!threadId || !activeTurnId) return false;
|
|
36129
|
-
return await new Promise((
|
|
36130
|
-
steerWaiters.set(input.inputId,
|
|
36728
|
+
return await new Promise((resolve15) => {
|
|
36729
|
+
steerWaiters.set(input.inputId, resolve15);
|
|
36131
36730
|
void send({
|
|
36132
36731
|
id: `steer:${input.inputId}`,
|
|
36133
36732
|
method: "turn/steer",
|
|
@@ -36138,7 +36737,7 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
36138
36737
|
clientUserMessageId: input.inputId
|
|
36139
36738
|
}
|
|
36140
36739
|
}).catch(() => {
|
|
36141
|
-
if (steerWaiters.delete(input.inputId))
|
|
36740
|
+
if (steerWaiters.delete(input.inputId)) resolve15(false);
|
|
36142
36741
|
});
|
|
36143
36742
|
});
|
|
36144
36743
|
},
|
|
@@ -36146,7 +36745,7 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
36146
36745
|
stopped = true;
|
|
36147
36746
|
write = null;
|
|
36148
36747
|
settleTurnReadiness(false);
|
|
36149
|
-
for (const
|
|
36748
|
+
for (const resolve15 of steerWaiters.values()) resolve15(false);
|
|
36150
36749
|
steerWaiters.clear();
|
|
36151
36750
|
},
|
|
36152
36751
|
push(chunk) {
|
|
@@ -36317,7 +36916,7 @@ function improveCodexErrorMessage(error52) {
|
|
|
36317
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.";
|
|
36318
36917
|
}
|
|
36319
36918
|
if (lower.includes("model_not_found") || lower.includes("model") && (lower.includes("not found") || lower.includes("unsupported") || lower.includes("invalid"))) {
|
|
36320
|
-
return "The selected model is not available.
|
|
36919
|
+
return "The selected model is not available. Open the failed Task, choose another model or Default in its runtime controls, then Retry.";
|
|
36321
36920
|
}
|
|
36322
36921
|
return error52;
|
|
36323
36922
|
}
|
|
@@ -36325,7 +36924,7 @@ function improveCodexErrorMessage(error52) {
|
|
|
36325
36924
|
// src/runners/git-preflight.ts
|
|
36326
36925
|
import { spawn as spawn9 } from "node:child_process";
|
|
36327
36926
|
import { realpath as realpath9 } from "node:fs/promises";
|
|
36328
|
-
import { isAbsolute as isAbsolute14, resolve as
|
|
36927
|
+
import { isAbsolute as isAbsolute14, resolve as resolve9 } from "node:path";
|
|
36329
36928
|
var OUTPUT_LIMIT = 8192;
|
|
36330
36929
|
var DEFAULT_TIMEOUT_MS4 = 1e4;
|
|
36331
36930
|
var VERSION_PATTERN = /^git version [^\r\n]{1,108}$/;
|
|
@@ -36344,7 +36943,7 @@ async function preflightGit(options = {}) {
|
|
|
36344
36943
|
if (configured !== void 0 && !isAbsolute14(configured)) {
|
|
36345
36944
|
return unavailable("configured git command must be an absolute file", checkedAt);
|
|
36346
36945
|
}
|
|
36347
|
-
const trustedCwd = await realpath9(
|
|
36946
|
+
const trustedCwd = await realpath9(resolve9(options.trustedCwd ?? process.cwd())).catch(() => null);
|
|
36348
36947
|
if (!trustedCwd)
|
|
36349
36948
|
return unavailable("Host-owned git preflight directory is unavailable", checkedAt);
|
|
36350
36949
|
const executablePath = await resolveTrustedCliCommand(configured ?? "git", {
|
|
@@ -36566,7 +37165,7 @@ function parseAuth(result) {
|
|
|
36566
37165
|
return "unknown";
|
|
36567
37166
|
}
|
|
36568
37167
|
function run2(command, args) {
|
|
36569
|
-
return new Promise((
|
|
37168
|
+
return new Promise((resolve15) => {
|
|
36570
37169
|
const child = spawnCli(command, args, {
|
|
36571
37170
|
stdio: ["ignore", "pipe", "pipe"],
|
|
36572
37171
|
windowsHide: true
|
|
@@ -36582,7 +37181,7 @@ function run2(command, args) {
|
|
|
36582
37181
|
if (settled) return;
|
|
36583
37182
|
settled = true;
|
|
36584
37183
|
clearTimeout(timeout);
|
|
36585
|
-
|
|
37184
|
+
resolve15(result);
|
|
36586
37185
|
};
|
|
36587
37186
|
const timeout = setTimeout(() => {
|
|
36588
37187
|
child.kill();
|
|
@@ -36596,9 +37195,9 @@ function run2(command, args) {
|
|
|
36596
37195
|
// src/linux-service.ts
|
|
36597
37196
|
import { spawn as spawn10 } from "node:child_process";
|
|
36598
37197
|
import { constants as constants2 } from "node:fs";
|
|
36599
|
-
import { access as access4, chmod as chmod7, mkdir as mkdir12, open as
|
|
37198
|
+
import { access as access4, chmod as chmod7, mkdir as mkdir12, open as open7, rename as rename6, rm as rm8 } from "node:fs/promises";
|
|
36600
37199
|
import { homedir as homedir7, userInfo } from "node:os";
|
|
36601
|
-
import { basename as basename3, dirname as
|
|
37200
|
+
import { basename as basename3, dirname as dirname8, join as join17, relative as relative8, resolve as resolve10, sep as sep4 } from "node:path";
|
|
36602
37201
|
var SERVICE_NAME = "zixt-host.service";
|
|
36603
37202
|
var SYSTEM_SERVICE_COMMAND_TIMEOUT_MS = 7e4;
|
|
36604
37203
|
var SERVICE_STABILITY_DELAY_MS = 2e3;
|
|
@@ -36626,7 +37225,7 @@ function boundedAppend(current, chunk) {
|
|
|
36626
37225
|
}
|
|
36627
37226
|
async function defaultRunCommand(command, args) {
|
|
36628
37227
|
const commandEnvironment3 = systemServiceCommandEnvironment();
|
|
36629
|
-
return new Promise((
|
|
37228
|
+
return new Promise((resolve15) => {
|
|
36630
37229
|
const child = spawn10(command, [...args], {
|
|
36631
37230
|
stdio: ["ignore", "pipe", "pipe"],
|
|
36632
37231
|
env: commandEnvironment3,
|
|
@@ -36640,7 +37239,7 @@ async function defaultRunCommand(command, args) {
|
|
|
36640
37239
|
if (settled) return;
|
|
36641
37240
|
settled = true;
|
|
36642
37241
|
if (timer) clearTimeout(timer);
|
|
36643
|
-
|
|
37242
|
+
resolve15(result);
|
|
36644
37243
|
};
|
|
36645
37244
|
child.stdout?.on("data", (chunk) => {
|
|
36646
37245
|
stdout = boundedAppend(stdout, chunk);
|
|
@@ -36682,11 +37281,16 @@ function systemdQuotedValue(value, escapeDollar) {
|
|
|
36682
37281
|
function systemdUnitValue(value) {
|
|
36683
37282
|
return systemdQuotedValue(value, true);
|
|
36684
37283
|
}
|
|
36685
|
-
function
|
|
36686
|
-
|
|
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
|
+
});
|
|
36687
37291
|
}
|
|
36688
37292
|
async function defaultSyncDirectory(path) {
|
|
36689
|
-
const directory = await
|
|
37293
|
+
const directory = await open7(path, "r");
|
|
36690
37294
|
try {
|
|
36691
37295
|
await directory.sync();
|
|
36692
37296
|
} finally {
|
|
@@ -36696,9 +37300,9 @@ async function defaultSyncDirectory(path) {
|
|
|
36696
37300
|
async function ensureDirectory(path, mode, syncDirectory7) {
|
|
36697
37301
|
const firstCreated = await mkdir12(path, { recursive: true, mode });
|
|
36698
37302
|
if (!firstCreated) return;
|
|
36699
|
-
const first =
|
|
36700
|
-
const target =
|
|
36701
|
-
await syncDirectory7(
|
|
37303
|
+
const first = resolve10(firstCreated);
|
|
37304
|
+
const target = resolve10(path);
|
|
37305
|
+
await syncDirectory7(dirname8(first));
|
|
36702
37306
|
let current = first;
|
|
36703
37307
|
const descendants = relative8(first, target);
|
|
36704
37308
|
for (const part of descendants ? descendants.split(sep4) : []) {
|
|
@@ -36707,20 +37311,20 @@ async function ensureDirectory(path, mode, syncDirectory7) {
|
|
|
36707
37311
|
}
|
|
36708
37312
|
}
|
|
36709
37313
|
async function replacePrivateFile(path, contents, mode, syncDirectory7) {
|
|
36710
|
-
const parent =
|
|
37314
|
+
const parent = dirname8(path);
|
|
36711
37315
|
await ensureDirectory(parent, 448, syncDirectory7);
|
|
36712
37316
|
const temporary = join17(parent, `.${basename3(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
36713
|
-
const handle = await
|
|
37317
|
+
const handle = await open7(temporary, "wx", mode);
|
|
36714
37318
|
try {
|
|
36715
37319
|
await handle.writeFile(contents, "utf8");
|
|
36716
37320
|
await handle.sync();
|
|
36717
37321
|
await handle.close();
|
|
36718
|
-
await
|
|
37322
|
+
await rename6(temporary, path);
|
|
36719
37323
|
await chmod7(path, mode);
|
|
36720
37324
|
await syncDirectory7(parent);
|
|
36721
37325
|
} catch (error52) {
|
|
36722
37326
|
await handle.close().catch(() => void 0);
|
|
36723
|
-
await
|
|
37327
|
+
await rm8(temporary, { force: true }).catch(() => void 0);
|
|
36724
37328
|
throw error52;
|
|
36725
37329
|
}
|
|
36726
37330
|
}
|
|
@@ -36771,7 +37375,7 @@ async function installLinuxService(options) {
|
|
|
36771
37375
|
const resolveCommand = options.resolveCommand ?? defaultResolveCommand;
|
|
36772
37376
|
const run3 = options.runCommand ?? defaultRunCommand;
|
|
36773
37377
|
const syncDirectory7 = options.syncDirectory ?? defaultSyncDirectory;
|
|
36774
|
-
const stabilityDelay = options.delay ?? ((ms) => new Promise((
|
|
37378
|
+
const stabilityDelay = options.delay ?? ((ms) => new Promise((resolve15) => setTimeout(resolve15, ms)));
|
|
36775
37379
|
const [systemctl, loginctl] = await Promise.all([
|
|
36776
37380
|
resolveCommand("systemctl"),
|
|
36777
37381
|
resolveCommand("loginctl")
|
|
@@ -36818,7 +37422,7 @@ async function installLinuxService(options) {
|
|
|
36818
37422
|
// Type=exec does not report startup success until the kernel has executed
|
|
36819
37423
|
// Node, so a missing/corrupt release cannot masquerade as an active Host.
|
|
36820
37424
|
"Type=exec",
|
|
36821
|
-
`EnvironmentFile=${
|
|
37425
|
+
`EnvironmentFile=${systemdDirectivePath(environmentPath)}`,
|
|
36822
37426
|
`ExecStart=${systemdUnitValue(process.execPath)} ${systemdUnitValue(currentEntry)}`,
|
|
36823
37427
|
"Restart=on-failure",
|
|
36824
37428
|
"RestartPreventExitStatus=64",
|
|
@@ -36884,9 +37488,9 @@ async function installLinuxService(options) {
|
|
|
36884
37488
|
// src/macos-service.ts
|
|
36885
37489
|
import { spawn as spawn11 } from "node:child_process";
|
|
36886
37490
|
import { constants as constants3 } from "node:fs";
|
|
36887
|
-
import { access as access5, chmod as chmod8, mkdir as mkdir13, open as
|
|
37491
|
+
import { access as access5, chmod as chmod8, mkdir as mkdir13, open as open8, rename as rename7, rm as rm9 } from "node:fs/promises";
|
|
36888
37492
|
import { homedir as homedir8, userInfo as userInfo2 } from "node:os";
|
|
36889
|
-
import { basename as basename4, dirname as
|
|
37493
|
+
import { basename as basename4, dirname as dirname9, join as join18, relative as relative9, resolve as resolve11, sep as sep5 } from "node:path";
|
|
36890
37494
|
var LAUNCH_AGENT_LABEL = "ai.zixt.host";
|
|
36891
37495
|
var SERVICE_STABILITY_DELAY_MS2 = 2e3;
|
|
36892
37496
|
var COMMAND_TIMEOUT_MS2 = 7e4;
|
|
@@ -36902,7 +37506,7 @@ function shellValue(value) {
|
|
|
36902
37506
|
return `'${oneLine2(value, "service setting").replaceAll("'", `'"'"'`)}'`;
|
|
36903
37507
|
}
|
|
36904
37508
|
async function syncDirectory4(path) {
|
|
36905
|
-
const directory = await
|
|
37509
|
+
const directory = await open8(path, "r");
|
|
36906
37510
|
try {
|
|
36907
37511
|
await directory.sync();
|
|
36908
37512
|
} finally {
|
|
@@ -36912,9 +37516,9 @@ async function syncDirectory4(path) {
|
|
|
36912
37516
|
async function ensureDirectory2(path, sync) {
|
|
36913
37517
|
const firstCreated = await mkdir13(path, { recursive: true, mode: 448 });
|
|
36914
37518
|
if (!firstCreated) return;
|
|
36915
|
-
const first =
|
|
36916
|
-
const target =
|
|
36917
|
-
await sync(
|
|
37519
|
+
const first = resolve11(firstCreated);
|
|
37520
|
+
const target = resolve11(path);
|
|
37521
|
+
await sync(dirname9(first));
|
|
36918
37522
|
let current = first;
|
|
36919
37523
|
for (const part of relative9(first, target).split(sep5).filter(Boolean)) {
|
|
36920
37524
|
await sync(current);
|
|
@@ -36922,20 +37526,20 @@ async function ensureDirectory2(path, sync) {
|
|
|
36922
37526
|
}
|
|
36923
37527
|
}
|
|
36924
37528
|
async function replacePrivateFile2(path, contents, mode, sync) {
|
|
36925
|
-
const parent =
|
|
37529
|
+
const parent = dirname9(path);
|
|
36926
37530
|
await ensureDirectory2(parent, sync);
|
|
36927
37531
|
const temporary = join18(parent, `.${basename4(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
36928
|
-
const handle = await
|
|
37532
|
+
const handle = await open8(temporary, "wx", mode);
|
|
36929
37533
|
try {
|
|
36930
37534
|
await handle.writeFile(contents, "utf8");
|
|
36931
37535
|
await handle.sync();
|
|
36932
37536
|
await handle.close();
|
|
36933
|
-
await
|
|
37537
|
+
await rename7(temporary, path);
|
|
36934
37538
|
await chmod8(path, mode);
|
|
36935
37539
|
await sync(parent);
|
|
36936
37540
|
} catch (error52) {
|
|
36937
37541
|
await handle.close().catch(() => void 0);
|
|
36938
|
-
await
|
|
37542
|
+
await rm9(temporary, { force: true }).catch(() => void 0);
|
|
36939
37543
|
throw error52;
|
|
36940
37544
|
}
|
|
36941
37545
|
}
|
|
@@ -37115,9 +37719,9 @@ async function installMacosService(options) {
|
|
|
37115
37719
|
// src/windows-service.ts
|
|
37116
37720
|
import { spawn as spawn12 } from "node:child_process";
|
|
37117
37721
|
import { constants as constants4 } from "node:fs";
|
|
37118
|
-
import { access as access6, mkdir as mkdir14, open as
|
|
37722
|
+
import { access as access6, mkdir as mkdir14, open as open9, readFile as readFile9, rename as rename8, rm as rm10 } from "node:fs/promises";
|
|
37119
37723
|
import { homedir as homedir9 } from "node:os";
|
|
37120
|
-
import { basename as basename5, dirname as
|
|
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";
|
|
37121
37725
|
var TASK_NAME = "Zixt Host";
|
|
37122
37726
|
var COMMAND_TIMEOUT_MS3 = 7e4;
|
|
37123
37727
|
var SERVICE_STABILITY_DELAY_MS3 = 2e3;
|
|
@@ -37135,7 +37739,7 @@ function psLiteral(value) {
|
|
|
37135
37739
|
}
|
|
37136
37740
|
async function syncDirectory5(path) {
|
|
37137
37741
|
if (process.platform === "win32") return;
|
|
37138
|
-
const directory = await
|
|
37742
|
+
const directory = await open9(path, "r");
|
|
37139
37743
|
try {
|
|
37140
37744
|
await directory.sync();
|
|
37141
37745
|
} finally {
|
|
@@ -37145,9 +37749,9 @@ async function syncDirectory5(path) {
|
|
|
37145
37749
|
async function ensureDirectory3(path, sync) {
|
|
37146
37750
|
const firstCreated = await mkdir14(path, { recursive: true, mode: 448 });
|
|
37147
37751
|
if (!firstCreated) return;
|
|
37148
|
-
const first =
|
|
37149
|
-
const target =
|
|
37150
|
-
await sync(
|
|
37752
|
+
const first = resolve12(firstCreated);
|
|
37753
|
+
const target = resolve12(path);
|
|
37754
|
+
await sync(dirname10(first));
|
|
37151
37755
|
let current = first;
|
|
37152
37756
|
for (const part of relative10(first, target).split(sep6).filter(Boolean)) {
|
|
37153
37757
|
await sync(current);
|
|
@@ -37155,19 +37759,19 @@ async function ensureDirectory3(path, sync) {
|
|
|
37155
37759
|
}
|
|
37156
37760
|
}
|
|
37157
37761
|
async function replacePrivateFile3(path, contents, sync) {
|
|
37158
|
-
const parent =
|
|
37762
|
+
const parent = dirname10(path);
|
|
37159
37763
|
await ensureDirectory3(parent, sync);
|
|
37160
37764
|
const temporary = join19(parent, `.${basename5(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
37161
|
-
const handle = await
|
|
37765
|
+
const handle = await open9(temporary, "wx", 384);
|
|
37162
37766
|
try {
|
|
37163
37767
|
await handle.writeFile(contents, "utf8");
|
|
37164
37768
|
await handle.sync();
|
|
37165
37769
|
await handle.close();
|
|
37166
|
-
await
|
|
37770
|
+
await rename8(temporary, path);
|
|
37167
37771
|
await sync(parent);
|
|
37168
37772
|
} catch (error52) {
|
|
37169
37773
|
await handle.close().catch(() => void 0);
|
|
37170
|
-
await
|
|
37774
|
+
await rm10(temporary, { force: true }).catch(() => void 0);
|
|
37171
37775
|
throw error52;
|
|
37172
37776
|
}
|
|
37173
37777
|
}
|
|
@@ -37300,7 +37904,7 @@ exit $code
|
|
|
37300
37904
|
}
|
|
37301
37905
|
async function defaultObserveStatus(path, generation) {
|
|
37302
37906
|
try {
|
|
37303
|
-
const text = (await
|
|
37907
|
+
const text = (await readFile9(path, "utf8")).replace(/^\uFEFF/, "");
|
|
37304
37908
|
const value = JSON.parse(text);
|
|
37305
37909
|
if (value.schema !== 1 || value.generation !== generation || typeof value.pid !== "number" || !Number.isSafeInteger(value.pid) || value.pid <= 0) {
|
|
37306
37910
|
return null;
|
|
@@ -37402,7 +38006,7 @@ async function installWindowsService(options) {
|
|
|
37402
38006
|
);
|
|
37403
38007
|
await replacePrivateFile3(launcherPath, launcherSource2(configPath, statusPath), sync);
|
|
37404
38008
|
await replacePrivateFile3(taskXmlPath, taskXml({ sid, powershell, launcherPath, home }), sync);
|
|
37405
|
-
await
|
|
38009
|
+
await rm10(statusPath, { force: true });
|
|
37406
38010
|
const acl = await run3(icacls, [
|
|
37407
38011
|
configRoot,
|
|
37408
38012
|
"/inheritance:r",
|
|
@@ -37454,9 +38058,9 @@ async function installSystemService(options) {
|
|
|
37454
38058
|
}
|
|
37455
38059
|
|
|
37456
38060
|
// src/terminal-outcomes.ts
|
|
37457
|
-
import { chmod as chmod9, lstat as
|
|
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";
|
|
37458
38062
|
import { homedir as homedir10 } from "node:os";
|
|
37459
|
-
import { dirname as
|
|
38063
|
+
import { dirname as dirname11, join as join20, relative as relative11, resolve as resolve13, sep as sep7 } from "node:path";
|
|
37460
38064
|
var DIRECTORY_MODE5 = 448;
|
|
37461
38065
|
var FILE_MODE4 = 384;
|
|
37462
38066
|
var MAX_OUTCOME_BYTES = 4 * 1024 * 1024;
|
|
@@ -37474,7 +38078,7 @@ function outcomePath(root, hostId, taskId, epoch) {
|
|
|
37474
38078
|
}
|
|
37475
38079
|
async function syncDirectory6(root) {
|
|
37476
38080
|
if (process.platform === "win32") return;
|
|
37477
|
-
const handle = await
|
|
38081
|
+
const handle = await open10(root, "r");
|
|
37478
38082
|
try {
|
|
37479
38083
|
await handle.sync();
|
|
37480
38084
|
} finally {
|
|
@@ -37484,16 +38088,16 @@ async function syncDirectory6(root) {
|
|
|
37484
38088
|
async function requirePrivateRoot(root, sync = syncDirectory6) {
|
|
37485
38089
|
const firstCreated = await mkdir15(root, { recursive: true, mode: DIRECTORY_MODE5 });
|
|
37486
38090
|
if (firstCreated) {
|
|
37487
|
-
const first =
|
|
37488
|
-
const target =
|
|
37489
|
-
await sync(
|
|
38091
|
+
const first = resolve13(firstCreated);
|
|
38092
|
+
const target = resolve13(root);
|
|
38093
|
+
await sync(dirname11(first));
|
|
37490
38094
|
let current = first;
|
|
37491
38095
|
for (const part of relative11(first, target).split(sep7).filter(Boolean)) {
|
|
37492
38096
|
await sync(current);
|
|
37493
38097
|
current = join20(current, part);
|
|
37494
38098
|
}
|
|
37495
38099
|
}
|
|
37496
|
-
const stat3 = await
|
|
38100
|
+
const stat3 = await lstat11(root);
|
|
37497
38101
|
if (stat3.isSymbolicLink() || !stat3.isDirectory()) {
|
|
37498
38102
|
throw new Error("terminal outcome journal root is not a trusted directory");
|
|
37499
38103
|
}
|
|
@@ -37521,7 +38125,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
37521
38125
|
const destination = outcomePath(root, hostId, outcome.taskId, outcome.epoch);
|
|
37522
38126
|
try {
|
|
37523
38127
|
const existing = parseCommittedOutcome(
|
|
37524
|
-
await
|
|
38128
|
+
await readFile10(destination, { encoding: "utf8", flag: "r" }),
|
|
37525
38129
|
outcome.taskId,
|
|
37526
38130
|
outcome.epoch
|
|
37527
38131
|
);
|
|
@@ -37536,25 +38140,25 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
37536
38140
|
);
|
|
37537
38141
|
let handle;
|
|
37538
38142
|
try {
|
|
37539
|
-
handle = await
|
|
38143
|
+
handle = await open10(temporary, "wx", FILE_MODE4);
|
|
37540
38144
|
await handle.writeFile(JSON.stringify(outcome), "utf8");
|
|
37541
38145
|
await handle.sync();
|
|
37542
38146
|
await handle.close();
|
|
37543
38147
|
handle = void 0;
|
|
37544
|
-
await
|
|
38148
|
+
await rename9(temporary, destination);
|
|
37545
38149
|
await sync(scopedRoot);
|
|
37546
38150
|
await sync(root);
|
|
37547
38151
|
} finally {
|
|
37548
38152
|
await handle?.close().catch(() => {
|
|
37549
38153
|
});
|
|
37550
|
-
await
|
|
38154
|
+
await rm11(temporary, { force: true }).catch(() => {
|
|
37551
38155
|
});
|
|
37552
38156
|
}
|
|
37553
38157
|
}
|
|
37554
38158
|
async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
37555
38159
|
let rootStat;
|
|
37556
38160
|
try {
|
|
37557
|
-
rootStat = await
|
|
38161
|
+
rootStat = await lstat11(root);
|
|
37558
38162
|
} catch (error52) {
|
|
37559
38163
|
if (error52.code === "ENOENT") return [];
|
|
37560
38164
|
throw new Error("terminal outcome journal could not be observed");
|
|
@@ -37571,7 +38175,7 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
37571
38175
|
throw new Error("terminal outcome Host scope is not a trusted directory");
|
|
37572
38176
|
}
|
|
37573
38177
|
const scopedRoot = hostOutcomeRoot(root, hostEntry.name);
|
|
37574
|
-
const scopedStat = await
|
|
38178
|
+
const scopedStat = await lstat11(scopedRoot);
|
|
37575
38179
|
if (scopedStat.isSymbolicLink() || !scopedStat.isDirectory()) {
|
|
37576
38180
|
throw new Error("terminal outcome Host scope is not a trusted directory");
|
|
37577
38181
|
}
|
|
@@ -37584,12 +38188,12 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
37584
38188
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
37585
38189
|
}
|
|
37586
38190
|
const path = join20(scopedRoot, entry.name);
|
|
37587
|
-
const stat3 = await
|
|
38191
|
+
const stat3 = await lstat11(path);
|
|
37588
38192
|
if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_OUTCOME_BYTES) {
|
|
37589
38193
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
37590
38194
|
}
|
|
37591
38195
|
const outcome = parseCommittedOutcome(
|
|
37592
|
-
await
|
|
38196
|
+
await readFile10(path, "utf8"),
|
|
37593
38197
|
match[1],
|
|
37594
38198
|
Number(match[2])
|
|
37595
38199
|
);
|
|
@@ -37616,7 +38220,7 @@ async function forgetAcknowledgedTerminalOutcomes(refs, root = defaultTerminalOu
|
|
|
37616
38220
|
if (acknowledged.get(`${hostId}:${outcome.taskId}:${outcome.epoch}`) !== outcome.resultId) {
|
|
37617
38221
|
continue;
|
|
37618
38222
|
}
|
|
37619
|
-
await
|
|
38223
|
+
await rm11(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
37620
38224
|
changedHostRoots.add(hostOutcomeRoot(root, hostId));
|
|
37621
38225
|
}
|
|
37622
38226
|
for (const scopedRoot of changedHostRoots) await syncDirectory6(scopedRoot);
|
|
@@ -37628,7 +38232,7 @@ async function forgetSupersededTerminalOutcomes(hostId, taskId, epoch, root = de
|
|
|
37628
38232
|
if (scoped.hostId !== hostId) continue;
|
|
37629
38233
|
const { outcome } = scoped;
|
|
37630
38234
|
if (outcome.taskId !== taskId || outcome.epoch >= epoch) continue;
|
|
37631
|
-
await
|
|
38235
|
+
await rm11(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
37632
38236
|
removed = true;
|
|
37633
38237
|
}
|
|
37634
38238
|
if (removed) await syncDirectory6(hostOutcomeRoot(root, hostId));
|
|
@@ -37736,12 +38340,12 @@ function createHostLogger(options = {}) {
|
|
|
37736
38340
|
}
|
|
37737
38341
|
|
|
37738
38342
|
// src/demo-state.ts
|
|
37739
|
-
import { isAbsolute as isAbsolute16, join as join21, parse as parse3, resolve as
|
|
38343
|
+
import { isAbsolute as isAbsolute16, join as join21, parse as parse3, resolve as resolve14 } from "node:path";
|
|
37740
38344
|
var DEMO_STATE_ROOT_ENV = "ZIXT_DEMO_STATE_ROOT";
|
|
37741
38345
|
function resolveDemoHostStatePaths(env = process.env) {
|
|
37742
38346
|
const configured = env.ZIXT_RUNNER === "demo" ? env[DEMO_STATE_ROOT_ENV] : void 0;
|
|
37743
38347
|
if (!configured) return null;
|
|
37744
|
-
const root =
|
|
38348
|
+
const root = resolve14(configured);
|
|
37745
38349
|
if (!isAbsolute16(configured) || root === parse3(root).root) {
|
|
37746
38350
|
throw new Error(`${DEMO_STATE_ROOT_ENV} must be a dedicated absolute directory`);
|
|
37747
38351
|
}
|
|
@@ -38063,6 +38667,7 @@ var claudeCode = createClaudeCodeRunner({
|
|
|
38063
38667
|
...runRegistryRoot ? { runRegistryRoot } : {},
|
|
38064
38668
|
toolPackRegistry,
|
|
38065
38669
|
browserManager,
|
|
38670
|
+
browserAvailable: async () => (await currentBrowserCapability()).status === "ok",
|
|
38066
38671
|
gitPreflight: currentGitPreflight,
|
|
38067
38672
|
onUnsafeRunnerCleanup: restartAfterUnsafeRunnerCleanup
|
|
38068
38673
|
});
|
|
@@ -38073,6 +38678,7 @@ var codex = createCodexRunner({
|
|
|
38073
38678
|
...codexThreadIndexRoot ? { threadIndexRoot: codexThreadIndexRoot } : {},
|
|
38074
38679
|
toolPackRegistry,
|
|
38075
38680
|
browserManager,
|
|
38681
|
+
browserAvailable: async () => (await currentBrowserCapability()).status === "ok",
|
|
38076
38682
|
gitPreflight: currentGitPreflight,
|
|
38077
38683
|
onUnsafeRunnerCleanup: restartAfterUnsafeRunnerCleanup
|
|
38078
38684
|
});
|