@zixt/host 0.0.44 → 0.0.46
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 +939 -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.46",
|
|
35
35
|
type: "module",
|
|
36
36
|
exports: {
|
|
37
37
|
".": "./src/client.ts",
|
|
@@ -14651,12 +14651,16 @@ var ID_PREFIXES = {
|
|
|
14651
14651
|
memory: "mry",
|
|
14652
14652
|
/** Org-singleton Manager configuration (PRD §8.13). */
|
|
14653
14653
|
manager: "mgr",
|
|
14654
|
+
/** One organization fact the Manager keeps across threads (MG-11). */
|
|
14655
|
+
managerMemory: "mgm",
|
|
14654
14656
|
/** One Manager conversation thread (MG-2). */
|
|
14655
14657
|
conversation: "cnv",
|
|
14656
14658
|
/** One immutable Conversation timeline entry. */
|
|
14657
14659
|
conversationEvent: "cve",
|
|
14658
14660
|
/** One Manager inference call's token-metering row (MG-8). */
|
|
14659
|
-
managerUsage: "mgu"
|
|
14661
|
+
managerUsage: "mgu",
|
|
14662
|
+
/** One ordered Manager reply awaiting Slack delivery. */
|
|
14663
|
+
managerSlackOutbox: "mso"
|
|
14660
14664
|
};
|
|
14661
14665
|
var idPattern = (prefix) => new RegExp(`^${prefix}_[0-9a-f]{32}$`);
|
|
14662
14666
|
function newId(prefix) {
|
|
@@ -14680,6 +14684,7 @@ var BrowserSessionId = idSchema(ID_PREFIXES.browserSession, "browser session id"
|
|
|
14680
14684
|
var AttachmentId = idSchema(ID_PREFIXES.attachment, "attachment id");
|
|
14681
14685
|
var MemoryId = idSchema(ID_PREFIXES.memory, "memory id");
|
|
14682
14686
|
var ManagerId = idSchema(ID_PREFIXES.manager, "manager id");
|
|
14687
|
+
var ManagerMemoryId = idSchema(ID_PREFIXES.managerMemory, "manager memory id");
|
|
14683
14688
|
var ConversationId = idSchema(ID_PREFIXES.conversation, "conversation id");
|
|
14684
14689
|
var ConversationEventId = idSchema(ID_PREFIXES.conversationEvent, "conversation event id");
|
|
14685
14690
|
|
|
@@ -14786,15 +14791,24 @@ var WebLoginValue = external_exports.object({
|
|
|
14786
14791
|
username: external_exports.string().min(1).max(500),
|
|
14787
14792
|
password: external_exports.string().min(1).max(5e3)
|
|
14788
14793
|
}).strict();
|
|
14794
|
+
var BrowserProfileContext = external_exports.object({
|
|
14795
|
+
taskMachineName: external_exports.string().min(1).max(120),
|
|
14796
|
+
savedProfileMachineName: external_exports.string().min(1).max(120)
|
|
14797
|
+
}).strict();
|
|
14789
14798
|
var BrowserSessionProjection = external_exports.object({
|
|
14790
14799
|
status: external_exports.enum(["none", "starting", "live"]),
|
|
14791
14800
|
session: BrowserSessionState.optional(),
|
|
14792
14801
|
/** Whether Start would find an online Machine with a working browser. */
|
|
14793
14802
|
canStart: external_exports.boolean(),
|
|
14794
14803
|
/** Member-safe reason when canStart is false. */
|
|
14795
|
-
reason: external_exports.string().max(300).optional()
|
|
14804
|
+
reason: external_exports.string().max(300).optional(),
|
|
14805
|
+
/** Present only when active work must use a different Machine-local profile. */
|
|
14806
|
+
profileContext: BrowserProfileContext.optional()
|
|
14807
|
+
}).strict();
|
|
14808
|
+
var StartBrowserSessionResponse = external_exports.object({
|
|
14809
|
+
session: BrowserSessionState,
|
|
14810
|
+
profileContext: BrowserProfileContext.optional()
|
|
14796
14811
|
}).strict();
|
|
14797
|
-
var StartBrowserSessionResponse = external_exports.object({ session: BrowserSessionState }).strict();
|
|
14798
14812
|
var StopBrowserSessionResponse = external_exports.object({ stopped: external_exports.boolean() }).strict();
|
|
14799
14813
|
var BrowserViewTicketResponse = external_exports.object({ ticket: external_exports.string().min(1).max(200) }).strict();
|
|
14800
14814
|
|
|
@@ -14818,6 +14832,7 @@ var ACTION_CATEGORIES = [
|
|
|
14818
14832
|
"records.modify",
|
|
14819
14833
|
"records.delete",
|
|
14820
14834
|
"docker",
|
|
14835
|
+
"browser.use",
|
|
14821
14836
|
"mcp.call",
|
|
14822
14837
|
"spend_money"
|
|
14823
14838
|
];
|
|
@@ -14856,6 +14871,7 @@ var DEFAULT_GUARDRAIL_POLICY = {
|
|
|
14856
14871
|
"records.modify": "allow",
|
|
14857
14872
|
"records.delete": "allow",
|
|
14858
14873
|
docker: "allow",
|
|
14874
|
+
"browser.use": "allow",
|
|
14859
14875
|
"mcp.call": "allow",
|
|
14860
14876
|
spend_money: "allow"
|
|
14861
14877
|
};
|
|
@@ -15317,6 +15333,16 @@ var Agent = external_exports.object({
|
|
|
15317
15333
|
orgId: OrgId,
|
|
15318
15334
|
name: external_exports.string().min(1).max(120),
|
|
15319
15335
|
status: AgentStatus,
|
|
15336
|
+
/**
|
|
15337
|
+
* Archive has fenced new work but is still waiting for one or more exact
|
|
15338
|
+
* Machines to acknowledge deletion of saved website sessions. `archived`
|
|
15339
|
+
* is exposed only after this becomes null.
|
|
15340
|
+
*/
|
|
15341
|
+
profileCleanup: external_exports.object({
|
|
15342
|
+
state: external_exports.literal("pending"),
|
|
15343
|
+
remainingProfiles: external_exports.number().int().min(1),
|
|
15344
|
+
intent: external_exports.enum(["archive", "restore"])
|
|
15345
|
+
}).strict().nullable().default(null),
|
|
15320
15346
|
roleDescription: external_exports.string().max(2e3).default(""),
|
|
15321
15347
|
/** Persona instructions — system-prompt-like free text (AG-1). */
|
|
15322
15348
|
instructions: external_exports.string().max(5e4).default(""),
|
|
@@ -15492,6 +15518,11 @@ var Host = external_exports.object({
|
|
|
15492
15518
|
status: HostStatus,
|
|
15493
15519
|
/** Persistent assignment admission; pausing never changes socket presence or live work. */
|
|
15494
15520
|
acceptingNewWork: external_exports.boolean().default(true),
|
|
15521
|
+
/**
|
|
15522
|
+
* Removal is fenced but the Machine remains paired solely so an offline
|
|
15523
|
+
* Host can reconnect and delete its saved browser profiles truthfully.
|
|
15524
|
+
*/
|
|
15525
|
+
profileCleanup: external_exports.object({ state: external_exports.literal("pending"), remainingProfiles: external_exports.number().int().min(1) }).strict().nullable().default(null),
|
|
15495
15526
|
/** `desktop` today; `cloud` when pods run the same host (PRD §7.6). */
|
|
15496
15527
|
kind: external_exports.enum(["desktop", "cloud"]),
|
|
15497
15528
|
lastSeenAt: IsoDate2.nullable(),
|
|
@@ -16012,6 +16043,8 @@ var Task = external_exports.object({
|
|
|
16012
16043
|
* its first Machine; assignment then records that choice for later runs.
|
|
16013
16044
|
*/
|
|
16014
16045
|
requestedHostId: HostId.nullable().default(null),
|
|
16046
|
+
/** Browser-dependent work runs only on a Machine with fresh Browser capability. */
|
|
16047
|
+
requiresBrowser: external_exports.boolean().default(false),
|
|
16015
16048
|
/** TS-16: per-Task runner/model/effort selection; null runs the teammate's configuration. */
|
|
16016
16049
|
runner: TaskRunnerSelection.nullable().default(null),
|
|
16017
16050
|
/**
|
|
@@ -16169,6 +16202,8 @@ var CreateTaskInput = external_exports.object({
|
|
|
16169
16202
|
* another Machine truthfully queues this Task rather than overriding it.
|
|
16170
16203
|
*/
|
|
16171
16204
|
requestedHostId: HostId.optional(),
|
|
16205
|
+
/** Require a fresh, working AI teammate Browser on the selected Machine. */
|
|
16206
|
+
requiresBrowser: external_exports.boolean().optional(),
|
|
16172
16207
|
/** Per-Task runner/model/effort selection (TS-16); absent fields fall back to the teammate's configuration. */
|
|
16173
16208
|
runner: TaskRunnerSelection.optional(),
|
|
16174
16209
|
/** Files uploaded ahead of this message; each may belong to one Task only (TS-15). */
|
|
@@ -16470,12 +16505,15 @@ var TaskSupportBundle = external_exports.object({
|
|
|
16470
16505
|
})
|
|
16471
16506
|
)
|
|
16472
16507
|
});
|
|
16508
|
+
var TASK_LIST_MAX_LIMIT = 200;
|
|
16473
16509
|
var ListTasksResponse = external_exports.object({
|
|
16474
|
-
tasks: external_exports.array(TaskProjection)
|
|
16475
|
-
|
|
16510
|
+
tasks: external_exports.array(TaskProjection).max(TASK_LIST_MAX_LIMIT),
|
|
16511
|
+
nextCursor: external_exports.string().nullable()
|
|
16512
|
+
}).strict();
|
|
16476
16513
|
|
|
16477
16514
|
// ../../packages/contracts/src/protocol.ts
|
|
16478
|
-
var PROTOCOL_VERSION =
|
|
16515
|
+
var PROTOCOL_VERSION = 7;
|
|
16516
|
+
var BROWSER_PROFILE_INVENTORY_PAGE_SIZE = 200;
|
|
16479
16517
|
var TASK_CANCEL_ACK_EVENT = "zixt.task.cancel.acknowledged";
|
|
16480
16518
|
var TASK_CREDENTIAL_ROLLOVER_ACK_EVENT = "zixt.task.credential_rollover.acknowledged";
|
|
16481
16519
|
var UnwoundAssignmentRef = external_exports.object({
|
|
@@ -16753,6 +16791,11 @@ var AgentOp = external_exports.union([
|
|
|
16753
16791
|
}),
|
|
16754
16792
|
external_exports.object({ kind: external_exports.literal("secret.list") }),
|
|
16755
16793
|
external_exports.object({ kind: external_exports.literal("agents.list") }),
|
|
16794
|
+
/** Speak to the organization Manager without addressing a human channel directly. */
|
|
16795
|
+
external_exports.object({
|
|
16796
|
+
kind: external_exports.literal("manager.message"),
|
|
16797
|
+
message: external_exports.string().min(1).max(5e4)
|
|
16798
|
+
}),
|
|
16756
16799
|
/** Read one teammate's non-secret standing configuration; omission means self. */
|
|
16757
16800
|
external_exports.object({ kind: external_exports.literal("agent.get"), agentId: AgentId.optional() }),
|
|
16758
16801
|
/**
|
|
@@ -16953,6 +16996,12 @@ var TaskAssign = external_exports.object({
|
|
|
16953
16996
|
type: external_exports.literal("task.assign"),
|
|
16954
16997
|
taskId: TaskId,
|
|
16955
16998
|
agentId: AgentId,
|
|
16999
|
+
/**
|
|
17000
|
+
* A current assignment is a trusted authorization to create a fresh
|
|
17001
|
+
* profile after an explicit restore. Missing legacy values never clear a
|
|
17002
|
+
* Host-side purge tombstone.
|
|
17003
|
+
*/
|
|
17004
|
+
browserProfileRevision: external_exports.number().int().min(0).optional(),
|
|
16956
17005
|
epoch: external_exports.number().int().min(1),
|
|
16957
17006
|
/**
|
|
16958
17007
|
* Host-enforced task authority deadline, when anything forces one.
|
|
@@ -17029,6 +17078,11 @@ var TaskAssign = external_exports.object({
|
|
|
17029
17078
|
titleWanted: external_exports.boolean().optional(),
|
|
17030
17079
|
/** Advisory Ask / Plan / Act snapshot for this attempt (TS-12). */
|
|
17031
17080
|
interactionMode: InteractionMode.optional(),
|
|
17081
|
+
/**
|
|
17082
|
+
* Browser-dependent placement requirement (BR-7). Additive/optional so
|
|
17083
|
+
* persisted assignments from an older cloud remain parseable.
|
|
17084
|
+
*/
|
|
17085
|
+
requiresBrowser: external_exports.boolean().optional(),
|
|
17032
17086
|
/** Configured workspace selected by the cloud; absence means no repository context. */
|
|
17033
17087
|
workspace: SafeDisplayPath.optional(),
|
|
17034
17088
|
/** Verified provider repository selected independently of a local workspace path. */
|
|
@@ -17439,6 +17493,12 @@ var BrowserOpenFrame = external_exports.object({
|
|
|
17439
17493
|
type: external_exports.literal("browser.open"),
|
|
17440
17494
|
requestId: external_exports.string().min(1).max(200),
|
|
17441
17495
|
agentId: AgentId,
|
|
17496
|
+
/**
|
|
17497
|
+
* Cloud-owned browser-profile lifecycle revision. A Host persists the last
|
|
17498
|
+
* purged revision and refuses a stale open, so a delayed frame cannot
|
|
17499
|
+
* recreate an archived teammate's website sessions after cleanup.
|
|
17500
|
+
*/
|
|
17501
|
+
profileRevision: external_exports.number().int().min(0).optional(),
|
|
17442
17502
|
/** Cloud-minted; the host adopts it for the session it opens. */
|
|
17443
17503
|
browserSessionId: external_exports.string().min(1).max(200),
|
|
17444
17504
|
viewport: BrowserViewport
|
|
@@ -17467,6 +17527,18 @@ var BrowserCommandFrame = external_exports.object({
|
|
|
17467
17527
|
browserSessionId: external_exports.string().min(1).max(200),
|
|
17468
17528
|
command: BrowserCommand
|
|
17469
17529
|
});
|
|
17530
|
+
var BrowserProfilePurge = external_exports.object({
|
|
17531
|
+
type: external_exports.literal("browser.profile.purge"),
|
|
17532
|
+
purgeId: external_exports.uuid(),
|
|
17533
|
+
agentId: AgentId,
|
|
17534
|
+
profileRevision: external_exports.number().int().min(1)
|
|
17535
|
+
}).strict();
|
|
17536
|
+
var BrowserProfilePurged = external_exports.object({
|
|
17537
|
+
type: external_exports.literal("browser.profile.purged"),
|
|
17538
|
+
purgeId: external_exports.uuid(),
|
|
17539
|
+
agentId: AgentId,
|
|
17540
|
+
profileRevision: external_exports.number().int().min(1)
|
|
17541
|
+
}).strict();
|
|
17470
17542
|
var TaskInput = external_exports.object({
|
|
17471
17543
|
type: external_exports.literal("task.input"),
|
|
17472
17544
|
taskId: TaskId,
|
|
@@ -17480,7 +17552,8 @@ var DurableDownMessage = external_exports.discriminatedUnion("type", [
|
|
|
17480
17552
|
TaskInput,
|
|
17481
17553
|
SecretsGrant,
|
|
17482
17554
|
ApprovalDecision,
|
|
17483
|
-
ConnectionsGrant
|
|
17555
|
+
ConnectionsGrant,
|
|
17556
|
+
BrowserProfilePurge
|
|
17484
17557
|
]);
|
|
17485
17558
|
var TaskEvent = external_exports.object({
|
|
17486
17559
|
type: external_exports.literal("task.event"),
|
|
@@ -17633,6 +17706,15 @@ var HelloFrame = external_exports.object({
|
|
|
17633
17706
|
protocolVersion: external_exports.number().int(),
|
|
17634
17707
|
/** Highest outbox seq the host has durably processed; cloud replays after it. */
|
|
17635
17708
|
cursor: external_exports.number().int().min(0),
|
|
17709
|
+
/**
|
|
17710
|
+
* Bounded, path-validated persistent profile inventory from this Machine.
|
|
17711
|
+
* It migrates profiles created before cloud custody tracking existed.
|
|
17712
|
+
*/
|
|
17713
|
+
browserProfileInventory: external_exports.object({
|
|
17714
|
+
agentIds: external_exports.array(AgentId).max(BROWSER_PROFILE_INVENTORY_PAGE_SIZE),
|
|
17715
|
+
/** False keeps conservative legacy migration fencing enabled. */
|
|
17716
|
+
complete: external_exports.boolean()
|
|
17717
|
+
}).strict().optional(),
|
|
17636
17718
|
/**
|
|
17637
17719
|
* Exact assignments whose local executors finished unwinding after the
|
|
17638
17720
|
* prior socket died. Optional for rolling v5 hosts; repeated references are
|
|
@@ -17640,6 +17722,11 @@ var HelloFrame = external_exports.object({
|
|
|
17640
17722
|
*/
|
|
17641
17723
|
unwoundAssignments: external_exports.array(UnwoundAssignmentRef).max(1e3).optional()
|
|
17642
17724
|
});
|
|
17725
|
+
var BrowserProfileInventoryFrame = external_exports.object({
|
|
17726
|
+
type: external_exports.literal("browser.profile.inventory"),
|
|
17727
|
+
agentIds: external_exports.array(AgentId).max(BROWSER_PROFILE_INVENTORY_PAGE_SIZE),
|
|
17728
|
+
complete: external_exports.boolean()
|
|
17729
|
+
}).strict();
|
|
17643
17730
|
var HelloAckFrame = external_exports.object({
|
|
17644
17731
|
type: external_exports.literal("helloAck"),
|
|
17645
17732
|
protocolVersion: external_exports.number().int(),
|
|
@@ -17722,6 +17809,7 @@ var PingFrame = external_exports.object({ type: external_exports.literal("ping")
|
|
|
17722
17809
|
var PongFrame = external_exports.object({ type: external_exports.literal("pong"), at: external_exports.iso.datetime() });
|
|
17723
17810
|
var HostToCloudFrame = external_exports.discriminatedUnion("type", [
|
|
17724
17811
|
HelloFrame,
|
|
17812
|
+
BrowserProfileInventoryFrame,
|
|
17725
17813
|
AckFrame,
|
|
17726
17814
|
UpFrame,
|
|
17727
17815
|
ProviderOperationGrantRequestFrame,
|
|
@@ -17729,6 +17817,7 @@ var HostToCloudFrame = external_exports.discriminatedUnion("type", [
|
|
|
17729
17817
|
BrowserScreencastFrame,
|
|
17730
17818
|
BrowserSessionEndedFrame,
|
|
17731
17819
|
BrowserCredentialRequestFrame,
|
|
17820
|
+
BrowserProfilePurged,
|
|
17732
17821
|
PingFrame,
|
|
17733
17822
|
PongFrame
|
|
17734
17823
|
]);
|
|
@@ -18045,7 +18134,9 @@ var HostRemovalOutcome = external_exports.object({
|
|
|
18045
18134
|
});
|
|
18046
18135
|
var RevokeHostResponse = external_exports.object({
|
|
18047
18136
|
host: AdminHostProjection,
|
|
18048
|
-
removal: HostRemovalOutcome
|
|
18137
|
+
removal: HostRemovalOutcome,
|
|
18138
|
+
/** False while the paired Host is retained solely to finish profile deletion. */
|
|
18139
|
+
removed: external_exports.boolean()
|
|
18049
18140
|
});
|
|
18050
18141
|
var MemberHostProjection = Host.pick({
|
|
18051
18142
|
id: true,
|
|
@@ -18054,6 +18145,7 @@ var MemberHostProjection = Host.pick({
|
|
|
18054
18145
|
operatingSystem: true,
|
|
18055
18146
|
status: true,
|
|
18056
18147
|
acceptingNewWork: true,
|
|
18148
|
+
profileCleanup: true,
|
|
18057
18149
|
kind: true,
|
|
18058
18150
|
lastSeenAt: true,
|
|
18059
18151
|
telemetryAt: true,
|
|
@@ -18632,22 +18724,60 @@ var UpdateManagerRequest = external_exports.object({
|
|
|
18632
18724
|
ctx.addIssue({ code: "custom", message: "nothing to update" });
|
|
18633
18725
|
}
|
|
18634
18726
|
});
|
|
18727
|
+
var ManagerMemoryKind = external_exports.enum([
|
|
18728
|
+
/** How recurring organization work is actually done ("releases ship Thursday"). */
|
|
18729
|
+
"process",
|
|
18730
|
+
/** A settled organization decision and, ideally, why. */
|
|
18731
|
+
"decision",
|
|
18732
|
+
/** A standing preference for how the organization wants to be served. */
|
|
18733
|
+
"preference",
|
|
18734
|
+
/** A durable organization fact that is not derivable from configuration. */
|
|
18735
|
+
"fact"
|
|
18736
|
+
]);
|
|
18737
|
+
var MANAGER_MEMORY_SUBJECT_MAX = 60;
|
|
18738
|
+
var MANAGER_MEMORY_TEXT_MAX = 300;
|
|
18739
|
+
var MANAGER_MEMORY_MAX_ITEMS = 60;
|
|
18740
|
+
var ManagerMemoryProjection = external_exports.object({
|
|
18741
|
+
id: ManagerMemoryId,
|
|
18742
|
+
kind: ManagerMemoryKind,
|
|
18743
|
+
/** Short normalized topic; (kind, subject) is the deduplication key. */
|
|
18744
|
+
subject: external_exports.string().min(1).max(MANAGER_MEMORY_SUBJECT_MAX),
|
|
18745
|
+
text: external_exports.string().min(1).max(MANAGER_MEMORY_TEXT_MAX),
|
|
18746
|
+
/** Thread the Manager learned it in, for provenance. */
|
|
18747
|
+
sourceConversationId: ConversationId.nullable(),
|
|
18748
|
+
createdAt: external_exports.string(),
|
|
18749
|
+
updatedAt: external_exports.string()
|
|
18750
|
+
}).strict();
|
|
18751
|
+
var ListManagerMemoriesResponse = external_exports.object({
|
|
18752
|
+
memories: external_exports.array(ManagerMemoryProjection).max(MANAGER_MEMORY_MAX_ITEMS),
|
|
18753
|
+
limit: external_exports.number().int().min(1)
|
|
18754
|
+
}).strict();
|
|
18635
18755
|
var ConversationChannel = external_exports.enum(["web", "slack", "whatsapp"]);
|
|
18636
18756
|
var ConversationStatus = external_exports.enum(["idle", "thinking"]);
|
|
18637
18757
|
var ConversationProjection = external_exports.object({
|
|
18638
18758
|
id: ConversationId,
|
|
18639
|
-
/** First
|
|
18759
|
+
/** First-message prefix until the one creation-time Manager title call settles. */
|
|
18640
18760
|
title: external_exports.string().min(1).max(200),
|
|
18641
18761
|
channel: ConversationChannel,
|
|
18642
18762
|
status: ConversationStatus,
|
|
18643
18763
|
/** TS-10 origin trust of the channel; propagated into every delegated Task. */
|
|
18644
18764
|
trust: external_exports.enum(["internal", "external"]),
|
|
18645
|
-
/**
|
|
18646
|
-
|
|
18765
|
+
/** One-use override for the next Task delegated from this thread. */
|
|
18766
|
+
nextDelegationRunner: TaskRunnerSelection.nullable(),
|
|
18647
18767
|
createdAt: external_exports.string(),
|
|
18648
18768
|
lastActivityAt: external_exports.string(),
|
|
18769
|
+
/** Archived, but at least one executor has not yet proven it stopped. */
|
|
18770
|
+
archiveState: external_exports.literal("stopping").nullable().optional(),
|
|
18649
18771
|
archivedAt: external_exports.string().nullable()
|
|
18650
|
-
}).strict()
|
|
18772
|
+
}).strict().superRefine((conversation, ctx) => {
|
|
18773
|
+
if (conversation.archiveState === "stopping" && conversation.archivedAt === null) {
|
|
18774
|
+
ctx.addIssue({
|
|
18775
|
+
code: "custom",
|
|
18776
|
+
path: ["archivedAt"],
|
|
18777
|
+
message: "a stopping Manager Task must already be in Archived"
|
|
18778
|
+
});
|
|
18779
|
+
}
|
|
18780
|
+
});
|
|
18651
18781
|
var conversationEventBase = {
|
|
18652
18782
|
id: ConversationEventId,
|
|
18653
18783
|
at: external_exports.string()
|
|
@@ -18658,7 +18788,9 @@ var ConversationEventProjection = external_exports.discriminatedUnion("kind", [
|
|
|
18658
18788
|
...conversationEventBase,
|
|
18659
18789
|
kind: external_exports.literal("user"),
|
|
18660
18790
|
text: external_exports.string(),
|
|
18661
|
-
|
|
18791
|
+
/** Display attribution only; authentication subjects remain internal. */
|
|
18792
|
+
author: external_exports.object({ displayName: external_exports.string().nullable() }).strict(),
|
|
18793
|
+
attachments: external_exports.array(TaskAttachmentRef).max(TASK_MESSAGE_MAX_ATTACHMENTS).optional()
|
|
18662
18794
|
}).strict(),
|
|
18663
18795
|
/** The Manager's prose reply. */
|
|
18664
18796
|
external_exports.object({ ...conversationEventBase, kind: external_exports.literal("manager"), text: external_exports.string() }).strict(),
|
|
@@ -18677,21 +18809,70 @@ var ConversationEventProjection = external_exports.discriminatedUnion("kind", [
|
|
|
18677
18809
|
kind: external_exports.literal("task"),
|
|
18678
18810
|
taskId: TaskId,
|
|
18679
18811
|
agentId: AgentId.nullable(),
|
|
18680
|
-
eventKind: external_exports.enum(["response", "error", "status", "question"]),
|
|
18812
|
+
eventKind: external_exports.enum(["response", "error", "status", "question", "message"]),
|
|
18681
18813
|
summary: external_exports.string(),
|
|
18682
|
-
taskStatus: TaskStatus.nullable()
|
|
18814
|
+
taskStatus: TaskStatus.nullable(),
|
|
18815
|
+
/**
|
|
18816
|
+
* Opaque presentation key shared by the useful report and its synthetic
|
|
18817
|
+
* terminal wake-up. It is never shown to people; clients use it only to
|
|
18818
|
+
* render one outcome when recovery commits those records out of order.
|
|
18819
|
+
* Missing on legacy/non-terminal events.
|
|
18820
|
+
*/
|
|
18821
|
+
terminalGroup: external_exports.string().min(1).max(200).nullable().optional()
|
|
18683
18822
|
}).strict(),
|
|
18684
18823
|
/** A Manager loop failure a person should see (provider outage, refusal). */
|
|
18685
18824
|
external_exports.object({ ...conversationEventBase, kind: external_exports.literal("error"), message: external_exports.string() }).strict()
|
|
18686
18825
|
]);
|
|
18826
|
+
var NonEmptyTaskRunnerSelection = TaskRunnerSelection.refine(
|
|
18827
|
+
(selection) => selection.type !== void 0 || selection.model !== void 0 || selection.effort !== void 0,
|
|
18828
|
+
"choose at least one runtime preference"
|
|
18829
|
+
);
|
|
18687
18830
|
var CreateConversationRequest = external_exports.object({
|
|
18688
18831
|
/** Stable client-generated key: retrying the same submission returns one Conversation. */
|
|
18689
18832
|
requestId: external_exports.uuid(),
|
|
18690
|
-
message: external_exports.string().
|
|
18691
|
-
|
|
18692
|
-
|
|
18833
|
+
message: external_exports.string().max(CONVERSATION_MESSAGE_MAX),
|
|
18834
|
+
attachmentIds: external_exports.array(AttachmentId).max(TASK_MESSAGE_MAX_ATTACHMENTS).refine((ids) => new Set(ids).size === ids.length, "duplicate attachment").optional(),
|
|
18835
|
+
/**
|
|
18836
|
+
* Teammate whose persistent Browser is selected beside this web turn.
|
|
18837
|
+
* This is bounded routing context for Browser-directed requests only; it
|
|
18838
|
+
* is never a general delegation preference.
|
|
18839
|
+
*/
|
|
18840
|
+
browserAgentId: AgentId.optional(),
|
|
18841
|
+
/**
|
|
18842
|
+
* One-time runtime override for the first Task this thread delegates.
|
|
18843
|
+
* Omission preserves the selected teammate's configured defaults.
|
|
18844
|
+
*/
|
|
18845
|
+
initialDelegation: external_exports.object({
|
|
18846
|
+
runner: NonEmptyTaskRunnerSelection
|
|
18847
|
+
}).strict().optional()
|
|
18848
|
+
}).strict().superRefine((value, ctx) => {
|
|
18849
|
+
if (!value.message.trim() && !value.attachmentIds?.length) {
|
|
18850
|
+
ctx.addIssue({
|
|
18851
|
+
code: "custom",
|
|
18852
|
+
path: ["message"],
|
|
18853
|
+
message: "a message needs text or an attachment"
|
|
18854
|
+
});
|
|
18855
|
+
}
|
|
18856
|
+
});
|
|
18857
|
+
var PostConversationMessageRequest = external_exports.object({
|
|
18858
|
+
/** Stable client-generated key: an ambiguous retry appends exactly once. */
|
|
18859
|
+
requestId: external_exports.uuid(),
|
|
18860
|
+
message: external_exports.string().max(CONVERSATION_MESSAGE_MAX),
|
|
18861
|
+
attachmentIds: external_exports.array(AttachmentId).max(TASK_MESSAGE_MAX_ATTACHMENTS).refine((ids) => new Set(ids).size === ids.length, "duplicate attachment").optional(),
|
|
18862
|
+
/** Selected Manager Browser teammate for Browser-directed requests only. */
|
|
18863
|
+
browserAgentId: AgentId.optional()
|
|
18864
|
+
}).strict().superRefine((value, ctx) => {
|
|
18865
|
+
if (!value.message.trim() && !value.attachmentIds?.length) {
|
|
18866
|
+
ctx.addIssue({
|
|
18867
|
+
code: "custom",
|
|
18868
|
+
path: ["message"],
|
|
18869
|
+
message: "a message needs text or an attachment"
|
|
18870
|
+
});
|
|
18871
|
+
}
|
|
18872
|
+
});
|
|
18873
|
+
var UpdateNextDelegationRuntimeRequest = external_exports.object({ runner: NonEmptyTaskRunnerSelection.nullable() }).strict();
|
|
18693
18874
|
var UpdateConversationRequest = external_exports.object({
|
|
18694
|
-
title: external_exports.string().min(1).max(200).optional(),
|
|
18875
|
+
title: external_exports.string().trim().min(1).max(200).optional(),
|
|
18695
18876
|
archived: external_exports.boolean().optional()
|
|
18696
18877
|
}).strict().superRefine((value, ctx) => {
|
|
18697
18878
|
if (value.title === void 0 && value.archived === void 0) {
|
|
@@ -18699,7 +18880,47 @@ var UpdateConversationRequest = external_exports.object({
|
|
|
18699
18880
|
}
|
|
18700
18881
|
});
|
|
18701
18882
|
var ConversationResponse = external_exports.object({ conversation: ConversationProjection }).strict();
|
|
18702
|
-
var ListConversationsResponse = external_exports.object({
|
|
18883
|
+
var ListConversationsResponse = external_exports.object({
|
|
18884
|
+
conversations: external_exports.array(ConversationProjection).max(CONVERSATION_LIST_LIMIT),
|
|
18885
|
+
nextCursor: external_exports.string().nullable()
|
|
18886
|
+
}).strict();
|
|
18887
|
+
var ManagerTaskRailSummariesRequest = external_exports.object({
|
|
18888
|
+
conversationIds: external_exports.array(ConversationId).min(1).max(CONVERSATION_LIST_LIMIT),
|
|
18889
|
+
archived: external_exports.boolean(),
|
|
18890
|
+
agentId: AgentId.optional(),
|
|
18891
|
+
statuses: external_exports.array(TaskStatus).min(1).max(TaskStatus.options.length).optional()
|
|
18892
|
+
}).strict().superRefine((value, ctx) => {
|
|
18893
|
+
if (new Set(value.conversationIds).size !== value.conversationIds.length) {
|
|
18894
|
+
ctx.addIssue({
|
|
18895
|
+
code: "custom",
|
|
18896
|
+
path: ["conversationIds"],
|
|
18897
|
+
message: "conversationIds must be unique"
|
|
18898
|
+
});
|
|
18899
|
+
}
|
|
18900
|
+
if (value.statuses && new Set(value.statuses).size !== value.statuses.length) {
|
|
18901
|
+
ctx.addIssue({
|
|
18902
|
+
code: "custom",
|
|
18903
|
+
path: ["statuses"],
|
|
18904
|
+
message: "statuses must be unique"
|
|
18905
|
+
});
|
|
18906
|
+
}
|
|
18907
|
+
});
|
|
18908
|
+
var ManagerTaskRailRepresentative = external_exports.object({
|
|
18909
|
+
id: TaskId,
|
|
18910
|
+
agentId: AgentId,
|
|
18911
|
+
status: TaskStatus,
|
|
18912
|
+
gitSummary: TaskGitSummary.nullable(),
|
|
18913
|
+
createdAt: external_exports.string(),
|
|
18914
|
+
updatedAt: external_exports.string()
|
|
18915
|
+
}).strict();
|
|
18916
|
+
var ManagerTaskRailSummary = external_exports.object({
|
|
18917
|
+
conversationId: ConversationId,
|
|
18918
|
+
hasChildren: external_exports.boolean(),
|
|
18919
|
+
hasAgentMatch: external_exports.boolean(),
|
|
18920
|
+
hasStatusMatch: external_exports.boolean(),
|
|
18921
|
+
representative: ManagerTaskRailRepresentative.nullable()
|
|
18922
|
+
}).strict();
|
|
18923
|
+
var ManagerTaskRailSummariesResponse = external_exports.object({ summaries: external_exports.array(ManagerTaskRailSummary).max(CONVERSATION_LIST_LIMIT) }).strict();
|
|
18703
18924
|
var ConversationDetailResponse = external_exports.object({
|
|
18704
18925
|
conversation: ConversationProjection,
|
|
18705
18926
|
events: external_exports.array(ConversationEventProjection)
|
|
@@ -19451,7 +19672,7 @@ async function generateTaskTitle(instructions, runner) {
|
|
|
19451
19672
|
instructions.slice(0, INSTRUCTIONS_BUDGET),
|
|
19452
19673
|
"</task_request>"
|
|
19453
19674
|
].join("\n");
|
|
19454
|
-
return new Promise((
|
|
19675
|
+
return new Promise((resolve15) => {
|
|
19455
19676
|
const child = spawnCli(
|
|
19456
19677
|
command,
|
|
19457
19678
|
[
|
|
@@ -19474,7 +19695,7 @@ async function generateTaskTitle(instructions, runner) {
|
|
|
19474
19695
|
if (settled) return;
|
|
19475
19696
|
settled = true;
|
|
19476
19697
|
clearTimeout(timer);
|
|
19477
|
-
|
|
19698
|
+
resolve15(value);
|
|
19478
19699
|
};
|
|
19479
19700
|
const timer = setTimeout(() => {
|
|
19480
19701
|
child.kill();
|
|
@@ -19796,11 +20017,11 @@ function createWorkerWatchdogSendDrain() {
|
|
|
19796
20017
|
if (completed) return;
|
|
19797
20018
|
completed = true;
|
|
19798
20019
|
pending--;
|
|
19799
|
-
if (pending === 0) drained.splice(0).forEach((
|
|
20020
|
+
if (pending === 0) drained.splice(0).forEach((resolve15) => resolve15());
|
|
19800
20021
|
};
|
|
19801
20022
|
},
|
|
19802
20023
|
drain: async () => {
|
|
19803
|
-
if (pending > 0) await new Promise((
|
|
20024
|
+
if (pending > 0) await new Promise((resolve15) => drained.push(resolve15));
|
|
19804
20025
|
}
|
|
19805
20026
|
};
|
|
19806
20027
|
}
|
|
@@ -20045,7 +20266,7 @@ async function waitForOperationGrantRetry(retryAt, signal) {
|
|
|
20045
20266
|
const deadline = Date.parse(retryAt);
|
|
20046
20267
|
if (!Number.isFinite(deadline) || signal.aborted) return false;
|
|
20047
20268
|
if (deadline <= Date.now()) return true;
|
|
20048
|
-
return await new Promise((
|
|
20269
|
+
return await new Promise((resolve15) => {
|
|
20049
20270
|
let settled = false;
|
|
20050
20271
|
let timer;
|
|
20051
20272
|
const finish = (ready) => {
|
|
@@ -20053,7 +20274,7 @@ async function waitForOperationGrantRetry(retryAt, signal) {
|
|
|
20053
20274
|
settled = true;
|
|
20054
20275
|
if (timer) clearTimeout(timer);
|
|
20055
20276
|
signal.removeEventListener("abort", onAbort);
|
|
20056
|
-
|
|
20277
|
+
resolve15(ready);
|
|
20057
20278
|
};
|
|
20058
20279
|
const onAbort = () => finish(false);
|
|
20059
20280
|
const schedule = () => {
|
|
@@ -20321,22 +20542,22 @@ var HostClient = class _HostClient {
|
|
|
20321
20542
|
const unwindingAssignments = [...this.activeAssignments.values()];
|
|
20322
20543
|
for (const cancel of this.cancels.values()) cancel(stopReason);
|
|
20323
20544
|
for (const entry of this.secretGrants.values()) {
|
|
20324
|
-
for (const
|
|
20545
|
+
for (const resolve15 of entry.resolvers) resolve15({});
|
|
20325
20546
|
entry.resolvers = [];
|
|
20326
20547
|
delete entry.value;
|
|
20327
20548
|
}
|
|
20328
20549
|
for (const entry of this.connectionGrants.values()) {
|
|
20329
|
-
for (const
|
|
20550
|
+
for (const resolve15 of entry.resolvers) resolve15([]);
|
|
20330
20551
|
entry.resolvers = [];
|
|
20331
20552
|
delete entry.value;
|
|
20332
20553
|
}
|
|
20333
20554
|
for (const entry of this.providerGrants.values()) {
|
|
20334
|
-
for (const
|
|
20555
|
+
for (const resolve15 of entry.resolvers) resolve15([]);
|
|
20335
20556
|
entry.resolvers = [];
|
|
20336
20557
|
delete entry.value;
|
|
20337
20558
|
}
|
|
20338
20559
|
for (const waiters of this.approvalWaiters.values()) {
|
|
20339
|
-
for (const
|
|
20560
|
+
for (const resolve15 of waiters.values()) resolve15({ approved: false, guidance: reason });
|
|
20340
20561
|
}
|
|
20341
20562
|
for (const waiters of this.agentOpWaiters.values()) {
|
|
20342
20563
|
for (const waiter of waiters.values()) {
|
|
@@ -20362,9 +20583,9 @@ var HostClient = class _HostClient {
|
|
|
20362
20583
|
let drainTimer;
|
|
20363
20584
|
const drained = await Promise.race([
|
|
20364
20585
|
Promise.allSettled(runs).then(() => true),
|
|
20365
|
-
new Promise((
|
|
20586
|
+
new Promise((resolve15) => {
|
|
20366
20587
|
drainTimer = setTimeout(
|
|
20367
|
-
() =>
|
|
20588
|
+
() => resolve15(false),
|
|
20368
20589
|
this.opts.unwindTimeoutMs ?? _HostClient.DEFAULT_UNWIND_TIMEOUT_MS
|
|
20369
20590
|
);
|
|
20370
20591
|
drainTimer.unref?.();
|
|
@@ -20395,9 +20616,70 @@ var HostClient = class _HostClient {
|
|
|
20395
20616
|
let awaitingHeartbeatReply = false;
|
|
20396
20617
|
let closeReason;
|
|
20397
20618
|
let frameTail = Promise.resolve();
|
|
20619
|
+
let inventoryRetryTimer;
|
|
20620
|
+
let inventoryRetryAttempts = 0;
|
|
20621
|
+
const inventoryRetryBaseMs = Math.max(20, Number(this.opts.backoffMs ?? 1e3));
|
|
20398
20622
|
this.ws = ws;
|
|
20399
20623
|
this.protocolReady = false;
|
|
20624
|
+
const retryInventory = async () => {
|
|
20625
|
+
if (this.stopped || this.ws !== ws || ws.readyState !== WebSocket.OPEN) return;
|
|
20626
|
+
let sawComplete = false;
|
|
20627
|
+
try {
|
|
20628
|
+
const pages = this.opts.browser?.profileInventoryPages?.();
|
|
20629
|
+
if (pages) {
|
|
20630
|
+
for await (const page2 of pages) {
|
|
20631
|
+
if (!this.send(
|
|
20632
|
+
{
|
|
20633
|
+
type: "browser.profile.inventory",
|
|
20634
|
+
agentIds: page2.agentIds,
|
|
20635
|
+
complete: page2.complete
|
|
20636
|
+
},
|
|
20637
|
+
ws
|
|
20638
|
+
)) {
|
|
20639
|
+
return;
|
|
20640
|
+
}
|
|
20641
|
+
sawComplete = page2.complete;
|
|
20642
|
+
}
|
|
20643
|
+
} else {
|
|
20644
|
+
const page2 = await this.opts.browser?.profileInventory?.();
|
|
20645
|
+
if (!page2) return;
|
|
20646
|
+
if (!this.send(
|
|
20647
|
+
{
|
|
20648
|
+
type: "browser.profile.inventory",
|
|
20649
|
+
agentIds: page2.agentIds,
|
|
20650
|
+
complete: page2.complete
|
|
20651
|
+
},
|
|
20652
|
+
ws
|
|
20653
|
+
)) {
|
|
20654
|
+
return;
|
|
20655
|
+
}
|
|
20656
|
+
sawComplete = page2.complete;
|
|
20657
|
+
}
|
|
20658
|
+
} catch {
|
|
20659
|
+
sawComplete = false;
|
|
20660
|
+
}
|
|
20661
|
+
if (sawComplete) {
|
|
20662
|
+
inventoryRetryAttempts = 0;
|
|
20663
|
+
} else {
|
|
20664
|
+
scheduleInventoryRetry();
|
|
20665
|
+
}
|
|
20666
|
+
};
|
|
20667
|
+
function scheduleInventoryRetry() {
|
|
20668
|
+
if (inventoryRetryTimer || ws.readyState !== WebSocket.OPEN) return;
|
|
20669
|
+
const delayMs = Math.min(
|
|
20670
|
+
6e4,
|
|
20671
|
+
inventoryRetryBaseMs * 2 ** Math.min(inventoryRetryAttempts++, 6)
|
|
20672
|
+
);
|
|
20673
|
+
inventoryRetryTimer = setTimeout(() => {
|
|
20674
|
+
inventoryRetryTimer = void 0;
|
|
20675
|
+
void retryInventory();
|
|
20676
|
+
}, delayMs);
|
|
20677
|
+
inventoryRetryTimer.unref?.();
|
|
20678
|
+
}
|
|
20400
20679
|
ws.on("open", () => {
|
|
20680
|
+
const inventoryConfigured = Boolean(
|
|
20681
|
+
this.opts.browser?.profileInventoryPages || this.opts.browser?.profileInventory
|
|
20682
|
+
);
|
|
20401
20683
|
const unwoundAssignments = [...this.pendingUnwoundAssignments.values()].sort(
|
|
20402
20684
|
(left, right) => left.taskId === right.taskId ? left.epoch - right.epoch : left.taskId.localeCompare(right.taskId)
|
|
20403
20685
|
);
|
|
@@ -20406,6 +20688,7 @@ var HostClient = class _HostClient {
|
|
|
20406
20688
|
type: "hello",
|
|
20407
20689
|
protocolVersion: PROTOCOL_VERSION,
|
|
20408
20690
|
cursor: this.cursor,
|
|
20691
|
+
...inventoryConfigured ? { browserProfileInventory: { agentIds: [], complete: false } } : {},
|
|
20409
20692
|
...unwoundAssignments.length > 0 ? { unwoundAssignments } : {}
|
|
20410
20693
|
},
|
|
20411
20694
|
ws
|
|
@@ -20422,6 +20705,7 @@ var HostClient = class _HostClient {
|
|
|
20422
20705
|
this.send({ type: "ping", at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
20423
20706
|
void this.reportTelemetry();
|
|
20424
20707
|
}, heartbeatMs);
|
|
20708
|
+
if (inventoryConfigured) void retryInventory();
|
|
20425
20709
|
});
|
|
20426
20710
|
ws.on("message", (raw) => {
|
|
20427
20711
|
if (this.ws !== ws) return;
|
|
@@ -20431,6 +20715,7 @@ var HostClient = class _HostClient {
|
|
|
20431
20715
|
});
|
|
20432
20716
|
});
|
|
20433
20717
|
ws.on("close", (code) => {
|
|
20718
|
+
if (inventoryRetryTimer) clearTimeout(inventoryRetryTimer);
|
|
20434
20719
|
void this.handleClose(ws, code, closeReason, frameTail);
|
|
20435
20720
|
});
|
|
20436
20721
|
ws.on("error", () => {
|
|
@@ -20444,9 +20729,9 @@ var HostClient = class _HostClient {
|
|
|
20444
20729
|
let frameDrainTimer;
|
|
20445
20730
|
const framesDrained = await Promise.race([
|
|
20446
20731
|
frameTail.then(() => true),
|
|
20447
|
-
new Promise((
|
|
20732
|
+
new Promise((resolve15) => {
|
|
20448
20733
|
frameDrainTimer = setTimeout(
|
|
20449
|
-
() =>
|
|
20734
|
+
() => resolve15(false),
|
|
20450
20735
|
this.opts.unwindTimeoutMs ?? _HostClient.DEFAULT_UNWIND_TIMEOUT_MS
|
|
20451
20736
|
);
|
|
20452
20737
|
frameDrainTimer.unref?.();
|
|
@@ -20823,7 +21108,13 @@ var HostClient = class _HostClient {
|
|
|
20823
21108
|
case "browser.open": {
|
|
20824
21109
|
const bridge = this.opts.browser;
|
|
20825
21110
|
if (!bridge) return;
|
|
20826
|
-
void bridge.open(
|
|
21111
|
+
void bridge.open(
|
|
21112
|
+
frame.agentId,
|
|
21113
|
+
frame.browserSessionId,
|
|
21114
|
+
frame.viewport,
|
|
21115
|
+
frame.requestId,
|
|
21116
|
+
frame.profileRevision
|
|
21117
|
+
).catch(() => {
|
|
20827
21118
|
this.sendBrowserFrame({
|
|
20828
21119
|
type: "browser.session.ended",
|
|
20829
21120
|
browserSessionId: frame.browserSessionId,
|
|
@@ -20834,7 +21125,8 @@ var HostClient = class _HostClient {
|
|
|
20834
21125
|
return;
|
|
20835
21126
|
}
|
|
20836
21127
|
case "browser.close":
|
|
20837
|
-
void this.opts.browser?.close(frame.agentId, "stopped")
|
|
21128
|
+
void this.opts.browser?.close(frame.agentId, "stopped").catch(() => {
|
|
21129
|
+
});
|
|
20838
21130
|
return;
|
|
20839
21131
|
case "browser.view":
|
|
20840
21132
|
void this.opts.browser?.setViewers(frame.agentId, frame.active, frame.viewerCount);
|
|
@@ -20935,8 +21227,34 @@ var HostClient = class _HostClient {
|
|
|
20935
21227
|
async handleMessage(message) {
|
|
20936
21228
|
switch (message.type) {
|
|
20937
21229
|
case "task.assign":
|
|
21230
|
+
if (message.browserProfileRevision !== void 0) {
|
|
21231
|
+
try {
|
|
21232
|
+
await this.opts.browser?.authorizeProfile?.(
|
|
21233
|
+
message.agentId,
|
|
21234
|
+
message.browserProfileRevision
|
|
21235
|
+
);
|
|
21236
|
+
} catch {
|
|
21237
|
+
}
|
|
21238
|
+
}
|
|
20938
21239
|
this.startTask(message);
|
|
20939
21240
|
return;
|
|
21241
|
+
case "browser.profile.purge": {
|
|
21242
|
+
const browser = this.opts.browser;
|
|
21243
|
+
void (async () => {
|
|
21244
|
+
try {
|
|
21245
|
+
if (!browser?.purge) return;
|
|
21246
|
+
await browser.purge(message.agentId, message.purgeId, message.profileRevision);
|
|
21247
|
+
this.send({
|
|
21248
|
+
type: "browser.profile.purged",
|
|
21249
|
+
purgeId: message.purgeId,
|
|
21250
|
+
agentId: message.agentId,
|
|
21251
|
+
profileRevision: message.profileRevision
|
|
21252
|
+
});
|
|
21253
|
+
} catch {
|
|
21254
|
+
}
|
|
21255
|
+
})();
|
|
21256
|
+
return;
|
|
21257
|
+
}
|
|
20940
21258
|
case "task.cancel":
|
|
20941
21259
|
this.cancels.get(`${message.taskId}:${message.epoch}`)?.(
|
|
20942
21260
|
message.purpose === "credential_rollover" ? "credential_rollover" : "cloud_cancel"
|
|
@@ -20957,7 +21275,7 @@ var HostClient = class _HostClient {
|
|
|
20957
21275
|
const entry = this.secretGrants.get(key) ?? { resolvers: [] };
|
|
20958
21276
|
entry.value = message.secrets;
|
|
20959
21277
|
entry.expiresAt = expiresAt;
|
|
20960
|
-
for (const
|
|
21278
|
+
for (const resolve15 of entry.resolvers) resolve15(message.secrets);
|
|
20961
21279
|
entry.resolvers = [];
|
|
20962
21280
|
this.secretGrants.set(key, entry);
|
|
20963
21281
|
return;
|
|
@@ -20988,13 +21306,13 @@ var HostClient = class _HostClient {
|
|
|
20988
21306
|
const entry = this.connectionGrants.get(key) ?? { resolvers: [] };
|
|
20989
21307
|
entry.value = message.connections;
|
|
20990
21308
|
entry.expiresAt = expiresAt;
|
|
20991
|
-
for (const
|
|
21309
|
+
for (const resolve15 of entry.resolvers) resolve15(message.connections);
|
|
20992
21310
|
entry.resolvers = [];
|
|
20993
21311
|
this.connectionGrants.set(key, entry);
|
|
20994
21312
|
const providerEntry = this.providerGrants.get(key) ?? { resolvers: [] };
|
|
20995
21313
|
providerEntry.value = providers;
|
|
20996
21314
|
providerEntry.expiresAt = authorityExpiresAt;
|
|
20997
|
-
for (const
|
|
21315
|
+
for (const resolve15 of providerEntry.resolvers) resolve15(providers);
|
|
20998
21316
|
providerEntry.resolvers = [];
|
|
20999
21317
|
this.providerGrants.set(key, providerEntry);
|
|
21000
21318
|
return;
|
|
@@ -21128,8 +21446,8 @@ var HostClient = class _HostClient {
|
|
|
21128
21446
|
return redactCredentialText(text, sensitiveSnapshot()).slice(0, maxLength);
|
|
21129
21447
|
};
|
|
21130
21448
|
let resolveCancelled;
|
|
21131
|
-
const cancelledPromise = new Promise((
|
|
21132
|
-
resolveCancelled =
|
|
21449
|
+
const cancelledPromise = new Promise((resolve15) => {
|
|
21450
|
+
resolveCancelled = resolve15;
|
|
21133
21451
|
});
|
|
21134
21452
|
const endAuthority = (reason = "cloud_cancel") => {
|
|
21135
21453
|
if (stopReason) return;
|
|
@@ -21138,21 +21456,21 @@ var HostClient = class _HostClient {
|
|
|
21138
21456
|
authorityController.abort(reason);
|
|
21139
21457
|
const secretEntry = this.secretGrants.get(cancelKey);
|
|
21140
21458
|
if (secretEntry) {
|
|
21141
|
-
for (const
|
|
21459
|
+
for (const resolve15 of secretEntry.resolvers) resolve15({});
|
|
21142
21460
|
secretEntry.resolvers = [];
|
|
21143
21461
|
delete secretEntry.value;
|
|
21144
21462
|
}
|
|
21145
21463
|
this.secretGrants.delete(cancelKey);
|
|
21146
21464
|
const connectionEntry = this.connectionGrants.get(cancelKey);
|
|
21147
21465
|
if (connectionEntry) {
|
|
21148
|
-
for (const
|
|
21466
|
+
for (const resolve15 of connectionEntry.resolvers) resolve15([]);
|
|
21149
21467
|
connectionEntry.resolvers = [];
|
|
21150
21468
|
delete connectionEntry.value;
|
|
21151
21469
|
}
|
|
21152
21470
|
this.connectionGrants.delete(cancelKey);
|
|
21153
21471
|
const providerEntry = this.providerGrants.get(cancelKey);
|
|
21154
21472
|
if (providerEntry) {
|
|
21155
|
-
for (const
|
|
21473
|
+
for (const resolve15 of providerEntry.resolvers) resolve15([]);
|
|
21156
21474
|
providerEntry.resolvers = [];
|
|
21157
21475
|
delete providerEntry.value;
|
|
21158
21476
|
}
|
|
@@ -21160,8 +21478,8 @@ var HostClient = class _HostClient {
|
|
|
21160
21478
|
this.clearAuthorityExpiry(cancelKey);
|
|
21161
21479
|
const approvalWaiters = this.approvalWaiters.get(cancelKey);
|
|
21162
21480
|
if (approvalWaiters) {
|
|
21163
|
-
for (const
|
|
21164
|
-
|
|
21481
|
+
for (const resolve15 of approvalWaiters.values()) {
|
|
21482
|
+
resolve15({ approved: false, guidance: "task was cancelled" });
|
|
21165
21483
|
}
|
|
21166
21484
|
approvalWaiters.clear();
|
|
21167
21485
|
}
|
|
@@ -21287,9 +21605,9 @@ var HostClient = class _HostClient {
|
|
|
21287
21605
|
return value;
|
|
21288
21606
|
};
|
|
21289
21607
|
if (entry.value) return Promise.resolve(capture(entry.value));
|
|
21290
|
-
return new Promise((
|
|
21291
|
-
entry.resolvers.push((value) =>
|
|
21292
|
-
setTimeout(() =>
|
|
21608
|
+
return new Promise((resolve15) => {
|
|
21609
|
+
entry.resolvers.push((value) => resolve15(capture(value)));
|
|
21610
|
+
setTimeout(() => resolve15(capture(entry.value ?? {})), _HostClient.SECRETS_WAIT_MS);
|
|
21293
21611
|
});
|
|
21294
21612
|
};
|
|
21295
21613
|
const connections = () => {
|
|
@@ -21306,9 +21624,9 @@ var HostClient = class _HostClient {
|
|
|
21306
21624
|
return value;
|
|
21307
21625
|
};
|
|
21308
21626
|
if (entry.value) return Promise.resolve(capture(entry.value));
|
|
21309
|
-
return new Promise((
|
|
21310
|
-
entry.resolvers.push((value) =>
|
|
21311
|
-
setTimeout(() =>
|
|
21627
|
+
return new Promise((resolve15) => {
|
|
21628
|
+
entry.resolvers.push((value) => resolve15(capture(value)));
|
|
21629
|
+
setTimeout(() => resolve15(capture(entry.value ?? [])), _HostClient.SECRETS_WAIT_MS);
|
|
21312
21630
|
});
|
|
21313
21631
|
};
|
|
21314
21632
|
const providers = () => {
|
|
@@ -21325,9 +21643,9 @@ var HostClient = class _HostClient {
|
|
|
21325
21643
|
return value;
|
|
21326
21644
|
};
|
|
21327
21645
|
if (entry.value !== void 0) return Promise.resolve(capture(entry.value));
|
|
21328
|
-
return new Promise((
|
|
21329
|
-
entry.resolvers.push((value) =>
|
|
21330
|
-
setTimeout(() =>
|
|
21646
|
+
return new Promise((resolve15) => {
|
|
21647
|
+
entry.resolvers.push((value) => resolve15(capture(value)));
|
|
21648
|
+
setTimeout(() => resolve15(capture(entry.value ?? [])), _HostClient.SECRETS_WAIT_MS);
|
|
21331
21649
|
});
|
|
21332
21650
|
};
|
|
21333
21651
|
const linear = async () => {
|
|
@@ -21353,13 +21671,13 @@ var HostClient = class _HostClient {
|
|
|
21353
21671
|
payload: safe(payload, 5e4),
|
|
21354
21672
|
...questionChoices ? { questionChoices: [...questionChoices] } : {}
|
|
21355
21673
|
});
|
|
21356
|
-
return new Promise((
|
|
21674
|
+
return new Promise((resolve15) => {
|
|
21357
21675
|
const waiters = this.approvalWaiters.get(cancelKey) ?? /* @__PURE__ */ new Map();
|
|
21358
21676
|
this.approvalWaiters.set(cancelKey, waiters);
|
|
21359
|
-
waiters.set(requestId,
|
|
21677
|
+
waiters.set(requestId, resolve15);
|
|
21360
21678
|
void cancelledPromise.then(() => {
|
|
21361
21679
|
if (waiters.delete(requestId)) {
|
|
21362
|
-
|
|
21680
|
+
resolve15({ approved: false, guidance: "task was cancelled" });
|
|
21363
21681
|
}
|
|
21364
21682
|
});
|
|
21365
21683
|
});
|
|
@@ -21397,11 +21715,11 @@ var HostClient = class _HostClient {
|
|
|
21397
21715
|
if (existing) message = existing;
|
|
21398
21716
|
else terminalMessages.set(requestId, message);
|
|
21399
21717
|
}
|
|
21400
|
-
return new Promise((
|
|
21718
|
+
return new Promise((resolve15) => {
|
|
21401
21719
|
const waiters = this.agentOpWaiters.get(cancelKey) ?? /* @__PURE__ */ new Map();
|
|
21402
21720
|
this.agentOpWaiters.set(cancelKey, waiters);
|
|
21403
21721
|
if (waiters.has(requestId)) {
|
|
21404
|
-
|
|
21722
|
+
resolve15({ ok: false, error: "provider settlement request is already in flight" });
|
|
21405
21723
|
return;
|
|
21406
21724
|
}
|
|
21407
21725
|
const timer = setTimeout(() => {
|
|
@@ -21412,7 +21730,7 @@ var HostClient = class _HostClient {
|
|
|
21412
21730
|
(pending) => !(pending.type === "agent.op" && pending.requestId === requestId)
|
|
21413
21731
|
);
|
|
21414
21732
|
}
|
|
21415
|
-
|
|
21733
|
+
resolve15({
|
|
21416
21734
|
ok: false,
|
|
21417
21735
|
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
21736
|
});
|
|
@@ -21420,7 +21738,7 @@ var HostClient = class _HostClient {
|
|
|
21420
21738
|
}, _HostClient.AGENT_OP_TIMEOUT_MS);
|
|
21421
21739
|
timer.unref?.();
|
|
21422
21740
|
waiters.set(requestId, {
|
|
21423
|
-
resolve:
|
|
21741
|
+
resolve: resolve15,
|
|
21424
21742
|
timer,
|
|
21425
21743
|
...terminal ? { terminalMessage: message } : {}
|
|
21426
21744
|
});
|
|
@@ -21466,12 +21784,12 @@ var HostClient = class _HostClient {
|
|
|
21466
21784
|
"No GitHub change was attempted; the authority grant request was invalid."
|
|
21467
21785
|
);
|
|
21468
21786
|
}
|
|
21469
|
-
const outcome = await new Promise((
|
|
21787
|
+
const outcome = await new Promise((resolve15) => {
|
|
21470
21788
|
const timer = setTimeout(() => {
|
|
21471
21789
|
const waiter = this.operationGrantWaiters.get(requestId);
|
|
21472
21790
|
if (!waiter) return;
|
|
21473
21791
|
this.operationGrantWaiters.delete(requestId);
|
|
21474
|
-
|
|
21792
|
+
resolve15({ grant: null, retryable: true, reason: "no_reply_from_zixt" });
|
|
21475
21793
|
}, this.operationGrantTimeoutMs);
|
|
21476
21794
|
timer.unref?.();
|
|
21477
21795
|
this.operationGrantWaiters.set(requestId, {
|
|
@@ -21484,9 +21802,9 @@ var HostClient = class _HostClient {
|
|
|
21484
21802
|
timer,
|
|
21485
21803
|
accept: (grant) => {
|
|
21486
21804
|
addSensitiveValues(providerGrantSensitiveValues(grant));
|
|
21487
|
-
|
|
21805
|
+
resolve15({ grant });
|
|
21488
21806
|
},
|
|
21489
|
-
deny: (retryable, reason, detail, retryAt, retryCode) =>
|
|
21807
|
+
deny: (retryable, reason, detail, retryAt, retryCode) => resolve15({
|
|
21490
21808
|
grant: null,
|
|
21491
21809
|
retryable,
|
|
21492
21810
|
reason,
|
|
@@ -21500,7 +21818,7 @@ var HostClient = class _HostClient {
|
|
|
21500
21818
|
} catch {
|
|
21501
21819
|
clearTimeout(timer);
|
|
21502
21820
|
this.operationGrantWaiters.delete(requestId);
|
|
21503
|
-
|
|
21821
|
+
resolve15({ grant: null, retryable: false, reason: "connection_unavailable" });
|
|
21504
21822
|
}
|
|
21505
21823
|
});
|
|
21506
21824
|
if (outcome.grant) {
|
|
@@ -21556,7 +21874,7 @@ var HostClient = class _HostClient {
|
|
|
21556
21874
|
)
|
|
21557
21875
|
);
|
|
21558
21876
|
}
|
|
21559
|
-
return new Promise((
|
|
21877
|
+
return new Promise((resolve15, reject3) => {
|
|
21560
21878
|
const timer = setTimeout(() => {
|
|
21561
21879
|
if (this.browserCredentialWaiters.delete(requestId)) {
|
|
21562
21880
|
reject3(
|
|
@@ -21575,7 +21893,7 @@ var HostClient = class _HostClient {
|
|
|
21575
21893
|
timer,
|
|
21576
21894
|
accept: (credential) => {
|
|
21577
21895
|
addSensitiveValues(webLoginSensitiveValues(credential));
|
|
21578
|
-
|
|
21896
|
+
resolve15(credential);
|
|
21579
21897
|
},
|
|
21580
21898
|
deny: (reason) => reject3(new Error(reason))
|
|
21581
21899
|
});
|
|
@@ -21881,6 +22199,9 @@ var ProcessTreeTerminationError = class extends Error {
|
|
|
21881
22199
|
}
|
|
21882
22200
|
name = "ProcessTreeTerminationError";
|
|
21883
22201
|
};
|
|
22202
|
+
function posixIdentityReadMeansMissing(error52) {
|
|
22203
|
+
return ["ENOENT", "ESRCH"].includes(error52.code ?? "");
|
|
22204
|
+
}
|
|
21884
22205
|
function commandContainsNonce(command, nonce) {
|
|
21885
22206
|
const escaped = nonce.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
21886
22207
|
return new RegExp(`(?:^|[\\s"'])${escaped}(?:$|[\\s"'])`).test(command);
|
|
@@ -21893,14 +22214,14 @@ async function observeWindowsGuardianNonce(pid, nonce) {
|
|
|
21893
22214
|
"Windows runner identity could not be observed"
|
|
21894
22215
|
);
|
|
21895
22216
|
}
|
|
21896
|
-
return new Promise((
|
|
22217
|
+
return new Promise((resolve15, reject3) => {
|
|
21897
22218
|
let done = false;
|
|
21898
22219
|
const finish = (result) => {
|
|
21899
22220
|
if (done) return;
|
|
21900
22221
|
done = true;
|
|
21901
22222
|
clearTimeout(timeout);
|
|
21902
22223
|
if (result instanceof Error) reject3(result);
|
|
21903
|
-
else
|
|
22224
|
+
else resolve15(result);
|
|
21904
22225
|
};
|
|
21905
22226
|
const timeout = setTimeout(
|
|
21906
22227
|
() => finish(
|
|
@@ -21938,14 +22259,14 @@ async function observePosixGuardianNonce(pid, nonce) {
|
|
|
21938
22259
|
const args = command.toString("utf8").split("\0");
|
|
21939
22260
|
return args.includes(nonce) ? "match" : "mismatch";
|
|
21940
22261
|
} catch (error52) {
|
|
21941
|
-
if (error52
|
|
22262
|
+
if (posixIdentityReadMeansMissing(error52)) return "missing";
|
|
21942
22263
|
throw new ProcessTreeTerminationError(
|
|
21943
22264
|
"state_unknown",
|
|
21944
22265
|
"POSIX runner identity could not be observed"
|
|
21945
22266
|
);
|
|
21946
22267
|
}
|
|
21947
22268
|
}
|
|
21948
|
-
return new Promise((
|
|
22269
|
+
return new Promise((resolve15, reject3) => {
|
|
21949
22270
|
const observer = spawn2("/bin/ps", ["-ww", "-o", "command=", "-p", String(pid)], {
|
|
21950
22271
|
stdio: ["ignore", "pipe", "ignore"]
|
|
21951
22272
|
});
|
|
@@ -21956,7 +22277,7 @@ async function observePosixGuardianNonce(pid, nonce) {
|
|
|
21956
22277
|
done = true;
|
|
21957
22278
|
clearTimeout(timeout);
|
|
21958
22279
|
if (result instanceof Error) reject3(result);
|
|
21959
|
-
else
|
|
22280
|
+
else resolve15(result);
|
|
21960
22281
|
};
|
|
21961
22282
|
const timeout = setTimeout(() => {
|
|
21962
22283
|
observer.kill("SIGKILL");
|
|
@@ -22003,7 +22324,7 @@ async function observeGuardianIdentity(pid, identity) {
|
|
|
22003
22324
|
return process.platform === "win32" ? observeWindowsGuardianNonce(pid, identity.nonce) : observePosixGuardianNonce(pid, identity.nonce);
|
|
22004
22325
|
}
|
|
22005
22326
|
function delay(ms) {
|
|
22006
|
-
return new Promise((
|
|
22327
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
22007
22328
|
}
|
|
22008
22329
|
function posixProcessRecordsFromPs(output) {
|
|
22009
22330
|
const records = [];
|
|
@@ -22036,7 +22357,7 @@ function posixProcessRecordsFromPs(output) {
|
|
|
22036
22357
|
return records;
|
|
22037
22358
|
}
|
|
22038
22359
|
async function snapshotPosixProcesses() {
|
|
22039
|
-
return new Promise((
|
|
22360
|
+
return new Promise((resolve15, reject3) => {
|
|
22040
22361
|
const observer = spawn2("/bin/ps", ["-axo", "uid=,pid=,ppid=,pgid=,stat="], {
|
|
22041
22362
|
stdio: ["ignore", "pipe", "ignore"]
|
|
22042
22363
|
});
|
|
@@ -22049,7 +22370,7 @@ async function snapshotPosixProcesses() {
|
|
|
22049
22370
|
if (error52) reject3(error52);
|
|
22050
22371
|
else {
|
|
22051
22372
|
try {
|
|
22052
|
-
|
|
22373
|
+
resolve15(posixProcessRecordsFromPs(output));
|
|
22053
22374
|
} catch (caught) {
|
|
22054
22375
|
reject3(caught);
|
|
22055
22376
|
}
|
|
@@ -22384,7 +22705,7 @@ async function snapshotWindowsDescendants(rootPid) {
|
|
|
22384
22705
|
"Windows process-tree observation could not start"
|
|
22385
22706
|
);
|
|
22386
22707
|
}
|
|
22387
|
-
return new Promise((
|
|
22708
|
+
return new Promise((resolve15, reject3) => {
|
|
22388
22709
|
let done = false;
|
|
22389
22710
|
const timeout = setTimeout(() => {
|
|
22390
22711
|
if (done) return;
|
|
@@ -22411,7 +22732,7 @@ async function snapshotWindowsDescendants(rootPid) {
|
|
|
22411
22732
|
return;
|
|
22412
22733
|
}
|
|
22413
22734
|
try {
|
|
22414
|
-
|
|
22735
|
+
resolve15(completeWindowsDescendantPids(rootPid, processes));
|
|
22415
22736
|
} catch (caught) {
|
|
22416
22737
|
reject3(caught);
|
|
22417
22738
|
}
|
|
@@ -22458,7 +22779,7 @@ async function waitForProcessesExit(pids, timeoutMs) {
|
|
|
22458
22779
|
}
|
|
22459
22780
|
async function runTaskkill(pid, command, timeoutMs = TASKKILL_TIMEOUT_MS, independentlyTrackedPids = []) {
|
|
22460
22781
|
const trustedCommand = command ?? defaultTaskkillCommand();
|
|
22461
|
-
const result = await new Promise((
|
|
22782
|
+
const result = await new Promise((resolve15, reject3) => {
|
|
22462
22783
|
const killer = spawn2(trustedCommand, ["/PID", String(pid), "/T", "/F"], {
|
|
22463
22784
|
stdio: ["ignore", "pipe", "pipe"],
|
|
22464
22785
|
windowsHide: true
|
|
@@ -22493,7 +22814,7 @@ async function runTaskkill(pid, command, timeoutMs = TASKKILL_TIMEOUT_MS, indepe
|
|
|
22493
22814
|
done = true;
|
|
22494
22815
|
clearTimeout(timeout);
|
|
22495
22816
|
if (error52) reject3(error52);
|
|
22496
|
-
else
|
|
22817
|
+
else resolve15({ code: killer.exitCode, output, outputTruncated });
|
|
22497
22818
|
};
|
|
22498
22819
|
killer.once(
|
|
22499
22820
|
"error",
|
|
@@ -23170,12 +23491,12 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
23170
23491
|
stderr = `${stderr}${String(chunk)}`.slice(-HELPER_OUTPUT_LIMIT);
|
|
23171
23492
|
});
|
|
23172
23493
|
const helperEvents = helper;
|
|
23173
|
-
const exited = new Promise((
|
|
23494
|
+
const exited = new Promise((resolve15) => {
|
|
23174
23495
|
let completed = false;
|
|
23175
23496
|
const complete = (code, signal) => {
|
|
23176
23497
|
if (completed) return;
|
|
23177
23498
|
completed = true;
|
|
23178
|
-
|
|
23499
|
+
resolve15({ code, signal });
|
|
23179
23500
|
};
|
|
23180
23501
|
helperEvents.once("error", () => {
|
|
23181
23502
|
failProtocol(new Error("Windows Job Object helper could not start"));
|
|
@@ -23188,7 +23509,7 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
23188
23509
|
});
|
|
23189
23510
|
const nextLine = async (expected) => {
|
|
23190
23511
|
if (protocolFailure) throw protocolFailure;
|
|
23191
|
-
const line = lines.shift() ?? await new Promise((
|
|
23512
|
+
const line = lines.shift() ?? await new Promise((resolve15, reject3) => {
|
|
23192
23513
|
const timer = setTimeout(
|
|
23193
23514
|
() => reject3(timeoutError("Windows Job Object helper did not answer in time")),
|
|
23194
23515
|
timeoutMs
|
|
@@ -23196,7 +23517,7 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
23196
23517
|
timer.unref?.();
|
|
23197
23518
|
lineWaiters.push((value) => {
|
|
23198
23519
|
clearTimeout(timer);
|
|
23199
|
-
|
|
23520
|
+
resolve15(value);
|
|
23200
23521
|
});
|
|
23201
23522
|
});
|
|
23202
23523
|
if (protocolFailure) throw protocolFailure;
|
|
@@ -23209,8 +23530,8 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
23209
23530
|
}
|
|
23210
23531
|
const stopped = await Promise.race([
|
|
23211
23532
|
exited.then(() => true),
|
|
23212
|
-
new Promise((
|
|
23213
|
-
const timer = setTimeout(() =>
|
|
23533
|
+
new Promise((resolve15) => {
|
|
23534
|
+
const timer = setTimeout(() => resolve15(false), timeoutMs);
|
|
23214
23535
|
timer.unref?.();
|
|
23215
23536
|
})
|
|
23216
23537
|
]);
|
|
@@ -23269,7 +23590,7 @@ async function awaitWindowsContainmentGate(env = process.env, input = process.st
|
|
|
23269
23590
|
if (nonce === void 0) return true;
|
|
23270
23591
|
if (!SAFE_NONCE2.test(nonce)) return false;
|
|
23271
23592
|
const expected = windowsContainmentGate(nonce).trimEnd();
|
|
23272
|
-
return new Promise((
|
|
23593
|
+
return new Promise((resolve15) => {
|
|
23273
23594
|
let pending = Buffer.alloc(0);
|
|
23274
23595
|
let settled = false;
|
|
23275
23596
|
const finish = (result) => {
|
|
@@ -23280,7 +23601,7 @@ async function awaitWindowsContainmentGate(env = process.env, input = process.st
|
|
|
23280
23601
|
input.off("end", onEnd);
|
|
23281
23602
|
input.off("error", onEnd);
|
|
23282
23603
|
if (result) input.pause();
|
|
23283
|
-
|
|
23604
|
+
resolve15(result);
|
|
23284
23605
|
};
|
|
23285
23606
|
const onData = (chunk) => {
|
|
23286
23607
|
pending = Buffer.concat([pending, chunk]);
|
|
@@ -23705,7 +24026,7 @@ async function installRelease(version2, options = {}) {
|
|
|
23705
24026
|
installerContainmentSetupError = error52;
|
|
23706
24027
|
return null;
|
|
23707
24028
|
}) : Promise.resolve(null);
|
|
23708
|
-
const installed = await new Promise((
|
|
24029
|
+
const installed = await new Promise((resolve15, reject3) => {
|
|
23709
24030
|
let finished = false;
|
|
23710
24031
|
let cleanupStarted = false;
|
|
23711
24032
|
let exitObserved = false;
|
|
@@ -23721,7 +24042,7 @@ async function installRelease(version2, options = {}) {
|
|
|
23721
24042
|
finished = true;
|
|
23722
24043
|
clearTimeout(timer);
|
|
23723
24044
|
options.signal?.removeEventListener("abort", requestCleanup);
|
|
23724
|
-
|
|
24045
|
+
resolve15(result);
|
|
23725
24046
|
};
|
|
23726
24047
|
const requestCleanup = () => {
|
|
23727
24048
|
if (cleanupStarted || finished) return;
|
|
@@ -24034,11 +24355,11 @@ async function runWorkerCompatibilityProxy(env = process.env, argv = process.arg
|
|
|
24034
24355
|
child.stdin?.on("error", () => {
|
|
24035
24356
|
});
|
|
24036
24357
|
process.stdin.pipe(child.stdin);
|
|
24037
|
-
return new Promise((
|
|
24038
|
-
child.once("error", () =>
|
|
24358
|
+
return new Promise((resolve15) => {
|
|
24359
|
+
child.once("error", () => resolve15(1));
|
|
24039
24360
|
child.once("exit", (code) => {
|
|
24040
24361
|
process.stdin.unpipe(child.stdin);
|
|
24041
|
-
|
|
24362
|
+
resolve15(code ?? 1);
|
|
24042
24363
|
});
|
|
24043
24364
|
});
|
|
24044
24365
|
}
|
|
@@ -24116,11 +24437,11 @@ async function launchHostSupervisor(options = {}) {
|
|
|
24116
24437
|
const waitOrStop = async (ms) => {
|
|
24117
24438
|
if (stopping) return false;
|
|
24118
24439
|
if (!customDelay) {
|
|
24119
|
-
await new Promise((
|
|
24440
|
+
await new Promise((resolve15) => {
|
|
24120
24441
|
const finish = () => {
|
|
24121
24442
|
clearTimeout(timer);
|
|
24122
24443
|
stopController.signal.removeEventListener("abort", finish);
|
|
24123
|
-
|
|
24444
|
+
resolve15();
|
|
24124
24445
|
};
|
|
24125
24446
|
const timer = setTimeout(finish, ms);
|
|
24126
24447
|
stopController.signal.addEventListener("abort", finish, { once: true });
|
|
@@ -24128,8 +24449,8 @@ async function launchHostSupervisor(options = {}) {
|
|
|
24128
24449
|
return !stopping;
|
|
24129
24450
|
}
|
|
24130
24451
|
let finishStop;
|
|
24131
|
-
const stopped = new Promise((
|
|
24132
|
-
finishStop = () =>
|
|
24452
|
+
const stopped = new Promise((resolve15) => {
|
|
24453
|
+
finishStop = () => resolve15();
|
|
24133
24454
|
stopController.signal.addEventListener("abort", finishStop, { once: true });
|
|
24134
24455
|
});
|
|
24135
24456
|
await Promise.race([customDelay(ms), stopped]);
|
|
@@ -24252,19 +24573,19 @@ async function launchHostSupervisor(options = {}) {
|
|
|
24252
24573
|
child = spawnSupervisor(entry, version2, ownershipDirectory, containmentGateNonce);
|
|
24253
24574
|
const launchedSupervisor = child;
|
|
24254
24575
|
let resolveChildExited;
|
|
24255
|
-
const childExited = new Promise((
|
|
24256
|
-
resolveChildExited =
|
|
24576
|
+
const childExited = new Promise((resolve15) => {
|
|
24577
|
+
resolveChildExited = resolve15;
|
|
24257
24578
|
});
|
|
24258
24579
|
const supervisorContainmentAbort = new AbortController();
|
|
24259
24580
|
void childExited.then(() => supervisorContainmentAbort.abort());
|
|
24260
24581
|
const outcomePromise = new Promise(
|
|
24261
|
-
(
|
|
24582
|
+
(resolve15) => {
|
|
24262
24583
|
let observed = false;
|
|
24263
24584
|
const finish = (code, signal) => {
|
|
24264
24585
|
if (observed) return;
|
|
24265
24586
|
observed = true;
|
|
24266
24587
|
resolveChildExited();
|
|
24267
|
-
|
|
24588
|
+
resolve15({ code, signal });
|
|
24268
24589
|
};
|
|
24269
24590
|
child.once("error", () => finish(1, null));
|
|
24270
24591
|
child.once("exit", finish);
|
|
@@ -24285,12 +24606,12 @@ async function launchHostSupervisor(options = {}) {
|
|
|
24285
24606
|
if (!supervisorContainment || !launchedSupervisor.stdin) {
|
|
24286
24607
|
throw new Error("supervisor Job Object gate is unavailable");
|
|
24287
24608
|
}
|
|
24288
|
-
await new Promise((
|
|
24609
|
+
await new Promise((resolve15, reject3) => {
|
|
24289
24610
|
launchedSupervisor.stdin.write(
|
|
24290
24611
|
windowsContainmentGate(containmentGateNonce),
|
|
24291
24612
|
(error52) => {
|
|
24292
24613
|
if (error52) reject3(error52);
|
|
24293
|
-
else
|
|
24614
|
+
else resolve15();
|
|
24294
24615
|
}
|
|
24295
24616
|
);
|
|
24296
24617
|
});
|
|
@@ -24432,18 +24753,18 @@ async function superviseHost(options = {}) {
|
|
|
24432
24753
|
}
|
|
24433
24754
|
}
|
|
24434
24755
|
let announceShutdown;
|
|
24435
|
-
const shutdownAnnounced = new Promise((
|
|
24436
|
-
announceShutdown =
|
|
24756
|
+
const shutdownAnnounced = new Promise((resolve15) => {
|
|
24757
|
+
announceShutdown = resolve15;
|
|
24437
24758
|
});
|
|
24438
24759
|
const attempted = /* @__PURE__ */ new Set();
|
|
24439
24760
|
const waitOrShutdown = async (ms) => {
|
|
24440
24761
|
if (shuttingDown2) return false;
|
|
24441
24762
|
if (!customDelay) {
|
|
24442
|
-
await new Promise((
|
|
24763
|
+
await new Promise((resolve15) => {
|
|
24443
24764
|
const finish = () => {
|
|
24444
24765
|
clearTimeout(timer);
|
|
24445
24766
|
shutdownController.signal.removeEventListener("abort", finish);
|
|
24446
|
-
|
|
24767
|
+
resolve15();
|
|
24447
24768
|
};
|
|
24448
24769
|
const timer = setTimeout(finish, ms);
|
|
24449
24770
|
shutdownController.signal.addEventListener("abort", finish, { once: true });
|
|
@@ -24586,19 +24907,19 @@ async function superviseHost(options = {}) {
|
|
|
24586
24907
|
child = spawnWorker(command, watchdogLaunch, compatibilityOwnership, containmentGateNonce);
|
|
24587
24908
|
const watchedChild = child;
|
|
24588
24909
|
let resolveChildExited;
|
|
24589
|
-
const childExited = new Promise((
|
|
24590
|
-
resolveChildExited =
|
|
24910
|
+
const childExited = new Promise((resolve15) => {
|
|
24911
|
+
resolveChildExited = resolve15;
|
|
24591
24912
|
});
|
|
24592
24913
|
const workerContainmentAbort = new AbortController();
|
|
24593
24914
|
void childExited.then(() => workerContainmentAbort.abort());
|
|
24594
24915
|
const outcomePromise = new Promise(
|
|
24595
|
-
(
|
|
24916
|
+
(resolve15) => {
|
|
24596
24917
|
let observed = false;
|
|
24597
24918
|
const finish = (result) => {
|
|
24598
24919
|
if (observed) return;
|
|
24599
24920
|
observed = true;
|
|
24600
24921
|
resolveChildExited();
|
|
24601
|
-
|
|
24922
|
+
resolve15(result);
|
|
24602
24923
|
};
|
|
24603
24924
|
watchedChild.once("error", () => finish({ code: 1, signal: null }));
|
|
24604
24925
|
watchedChild.once(
|
|
@@ -24620,10 +24941,10 @@ async function superviseHost(options = {}) {
|
|
|
24620
24941
|
if (!workerContainment || !watchedChild.stdin) {
|
|
24621
24942
|
throw new Error("worker Job Object gate is unavailable");
|
|
24622
24943
|
}
|
|
24623
|
-
await new Promise((
|
|
24944
|
+
await new Promise((resolve15, reject3) => {
|
|
24624
24945
|
watchedChild.stdin.write(windowsContainmentGate(containmentGateNonce), (error52) => {
|
|
24625
24946
|
if (error52) reject3(error52);
|
|
24626
|
-
else
|
|
24947
|
+
else resolve15();
|
|
24627
24948
|
});
|
|
24628
24949
|
});
|
|
24629
24950
|
}
|
|
@@ -24890,6 +25211,20 @@ async function superviseHost(options = {}) {
|
|
|
24890
25211
|
import { hostname as hostname3 } from "node:os";
|
|
24891
25212
|
|
|
24892
25213
|
// src/browser/adapter.ts
|
|
25214
|
+
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.";
|
|
25215
|
+
function requireBrowserLoginOrigin(currentUrl, loginUrl) {
|
|
25216
|
+
try {
|
|
25217
|
+
const current = new URL(currentUrl);
|
|
25218
|
+
const expected = new URL(loginUrl);
|
|
25219
|
+
const currentIsWeb = current.protocol === "https:" || current.protocol === "http:";
|
|
25220
|
+
const expectedIsWeb = expected.protocol === "https:" || expected.protocol === "http:";
|
|
25221
|
+
if (currentIsWeb && expectedIsWeb && current.origin === expected.origin) {
|
|
25222
|
+
return expected.origin;
|
|
25223
|
+
}
|
|
25224
|
+
} catch {
|
|
25225
|
+
}
|
|
25226
|
+
throw new Error(BROWSER_LOGIN_ORIGIN_CHANGED);
|
|
25227
|
+
}
|
|
24893
25228
|
var DEMO_FRAME_JPEG_BASE64 = "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAIAAgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigD//2Q==";
|
|
24894
25229
|
function createDemoBrowserAdapterFactory() {
|
|
24895
25230
|
return {
|
|
@@ -25039,6 +25374,7 @@ function createDemoBrowserAdapterFactory() {
|
|
|
25039
25374
|
return frame();
|
|
25040
25375
|
},
|
|
25041
25376
|
async fillLogin(credential) {
|
|
25377
|
+
requireBrowserLoginOrigin(active().url, credential.loginUrl);
|
|
25042
25378
|
const landedUrl = new URL("/account", credential.loginUrl).toString();
|
|
25043
25379
|
const tab = active();
|
|
25044
25380
|
tab.url = landedUrl;
|
|
@@ -25061,9 +25397,9 @@ function createDemoBrowserAdapterFactory() {
|
|
|
25061
25397
|
}
|
|
25062
25398
|
|
|
25063
25399
|
// src/browser/manager.ts
|
|
25064
|
-
import { mkdir as mkdir4 } from "node:fs/promises";
|
|
25400
|
+
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
25401
|
import { homedir as homedir2 } from "node:os";
|
|
25066
|
-
import { join as join7 } from "node:path";
|
|
25402
|
+
import { dirname as dirname4, join as join7, resolve as resolve4 } from "node:path";
|
|
25067
25403
|
var SAFE_SEGMENT = /^[A-Za-z0-9_-]{1,200}$/;
|
|
25068
25404
|
var FRAME_MIN_INTERVAL_MS = 100;
|
|
25069
25405
|
var IDLE_TIMEOUT_MS = 15 * 6e4;
|
|
@@ -25071,18 +25407,34 @@ var BrowserManager = class {
|
|
|
25071
25407
|
constructor(opts) {
|
|
25072
25408
|
this.opts = opts;
|
|
25073
25409
|
this.profileRoot = opts.profileRoot ?? join7(homedir2(), ".zixt", "browser-profiles");
|
|
25410
|
+
this.profileStateRoot = join7(this.profileRoot, ".profile-state");
|
|
25074
25411
|
this.viewport = opts.viewport ?? BROWSER_DEFAULT_VIEWPORT;
|
|
25075
25412
|
this.idleTimeoutMs = opts.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
25076
25413
|
this.frameMinIntervalMs = opts.frameMinIntervalMs ?? FRAME_MIN_INTERVAL_MS;
|
|
25414
|
+
this.profileInventoryLimit = Math.max(
|
|
25415
|
+
1,
|
|
25416
|
+
Math.min(
|
|
25417
|
+
BROWSER_PROFILE_INVENTORY_PAGE_SIZE,
|
|
25418
|
+
Math.trunc(opts.profileInventoryLimit ?? BROWSER_PROFILE_INVENTORY_PAGE_SIZE)
|
|
25419
|
+
)
|
|
25420
|
+
);
|
|
25077
25421
|
}
|
|
25078
25422
|
sessions = /* @__PURE__ */ new Map();
|
|
25423
|
+
/**
|
|
25424
|
+
* Fail closed after lifecycle authorization could not be durably checked or
|
|
25425
|
+
* written. Non-browser runner work may continue, but no local Browser can
|
|
25426
|
+
* open until a later trusted revision is successfully authorized.
|
|
25427
|
+
*/
|
|
25428
|
+
deniedAuthorizations = /* @__PURE__ */ new Map();
|
|
25079
25429
|
/** Serializes open/close per teammate: one profile allows one live browser. */
|
|
25080
25430
|
locks = /* @__PURE__ */ new Map();
|
|
25081
25431
|
events = null;
|
|
25082
25432
|
profileRoot;
|
|
25433
|
+
profileStateRoot;
|
|
25083
25434
|
viewport;
|
|
25084
25435
|
idleTimeoutMs;
|
|
25085
25436
|
frameMinIntervalMs;
|
|
25437
|
+
profileInventoryLimit;
|
|
25086
25438
|
/**
|
|
25087
25439
|
* Wired once by the host client; replaces any prior socket generation's
|
|
25088
25440
|
* sink. Attaching re-announces every live session, because the cloud keeps
|
|
@@ -25099,6 +25451,31 @@ var BrowserManager = class {
|
|
|
25099
25451
|
capability() {
|
|
25100
25452
|
return this.opts.factory.capability();
|
|
25101
25453
|
}
|
|
25454
|
+
/**
|
|
25455
|
+
* Page a path-validated migration inventory without holding an unbounded
|
|
25456
|
+
* directory in memory. A final `complete: true` page is emitted even when
|
|
25457
|
+
* the directory contains an exact multiple of the page size.
|
|
25458
|
+
*/
|
|
25459
|
+
async *profileInventoryPages() {
|
|
25460
|
+
await this.ensureOwnedDirectory(this.profileRoot);
|
|
25461
|
+
const agentIds = [];
|
|
25462
|
+
const directory = await opendir(this.profileRoot);
|
|
25463
|
+
for await (const entry of directory) {
|
|
25464
|
+
if (!entry.isDirectory() || entry.isSymbolicLink() || !AgentId.safeParse(entry.name).success) {
|
|
25465
|
+
continue;
|
|
25466
|
+
}
|
|
25467
|
+
if (agentIds.length === this.profileInventoryLimit) {
|
|
25468
|
+
yield { agentIds: agentIds.splice(0).sort(), complete: false };
|
|
25469
|
+
}
|
|
25470
|
+
agentIds.push(entry.name);
|
|
25471
|
+
}
|
|
25472
|
+
yield { agentIds: agentIds.sort(), complete: true };
|
|
25473
|
+
}
|
|
25474
|
+
/** First bounded page retained for embedders that have not adopted continuations. */
|
|
25475
|
+
async profileInventory() {
|
|
25476
|
+
const first = await this.profileInventoryPages().next();
|
|
25477
|
+
return first.value ?? { agentIds: [], complete: true };
|
|
25478
|
+
}
|
|
25102
25479
|
sessionState(agentId) {
|
|
25103
25480
|
const session = this.sessions.get(agentId);
|
|
25104
25481
|
return session && !session.closed ? this.stateOf(session) : null;
|
|
@@ -25114,6 +25491,122 @@ var BrowserManager = class {
|
|
|
25114
25491
|
);
|
|
25115
25492
|
return next;
|
|
25116
25493
|
}
|
|
25494
|
+
validateAgentId(agentId) {
|
|
25495
|
+
if (!SAFE_SEGMENT.test(agentId) || !AgentId.safeParse(agentId).success) {
|
|
25496
|
+
throw new Error("invalid agent id for a browser profile path");
|
|
25497
|
+
}
|
|
25498
|
+
}
|
|
25499
|
+
exactChild(root, child) {
|
|
25500
|
+
const canonicalRoot = resolve4(root);
|
|
25501
|
+
const target = resolve4(canonicalRoot, child);
|
|
25502
|
+
if (dirname4(target) !== canonicalRoot) {
|
|
25503
|
+
throw new Error("browser profile path escaped its owned root");
|
|
25504
|
+
}
|
|
25505
|
+
return target;
|
|
25506
|
+
}
|
|
25507
|
+
async ensureOwnedDirectory(path) {
|
|
25508
|
+
await mkdir4(path, { recursive: true, mode: 448 });
|
|
25509
|
+
const stat3 = await lstat4(path);
|
|
25510
|
+
if (!stat3.isDirectory() || stat3.isSymbolicLink()) {
|
|
25511
|
+
throw new Error("browser profile root must be an owned directory, not a symbolic link");
|
|
25512
|
+
}
|
|
25513
|
+
}
|
|
25514
|
+
/**
|
|
25515
|
+
* POSIX needs directory fsync for a rename/unlink to survive sudden power
|
|
25516
|
+
* loss. Windows does not support opening directories this way, so only its
|
|
25517
|
+
* unsupported-operation errors are tolerated; file fsync still remains
|
|
25518
|
+
* mandatory on every platform.
|
|
25519
|
+
*/
|
|
25520
|
+
async syncDirectory(path) {
|
|
25521
|
+
try {
|
|
25522
|
+
const directory = await open4(path, "r");
|
|
25523
|
+
try {
|
|
25524
|
+
await directory.sync();
|
|
25525
|
+
} finally {
|
|
25526
|
+
await directory.close();
|
|
25527
|
+
}
|
|
25528
|
+
} catch (error52) {
|
|
25529
|
+
const code = error52.code;
|
|
25530
|
+
if (process.platform === "win32" && (code === "EISDIR" || code === "EACCES" || code === "EPERM" || code === "EINVAL" || code === "ENOTSUP")) {
|
|
25531
|
+
return;
|
|
25532
|
+
}
|
|
25533
|
+
throw error52;
|
|
25534
|
+
}
|
|
25535
|
+
}
|
|
25536
|
+
profilePath(agentId) {
|
|
25537
|
+
return this.exactChild(this.profileRoot, agentId);
|
|
25538
|
+
}
|
|
25539
|
+
statePath(agentId) {
|
|
25540
|
+
return this.exactChild(this.profileStateRoot, `${agentId}.json`);
|
|
25541
|
+
}
|
|
25542
|
+
async readProfileState(agentId) {
|
|
25543
|
+
try {
|
|
25544
|
+
const raw = JSON.parse(await readFile5(this.statePath(agentId), "utf8"));
|
|
25545
|
+
if (typeof raw !== "object" || raw === null || !Number.isInteger(raw.revision) || Number(raw.revision) < 0 || !["allowed", "purged"].includes(String(raw.state))) {
|
|
25546
|
+
throw new Error("browser profile lifecycle marker is invalid");
|
|
25547
|
+
}
|
|
25548
|
+
return raw;
|
|
25549
|
+
} catch (error52) {
|
|
25550
|
+
if (error52.code === "ENOENT") return null;
|
|
25551
|
+
throw error52;
|
|
25552
|
+
}
|
|
25553
|
+
}
|
|
25554
|
+
async writeProfileState(agentId, state) {
|
|
25555
|
+
await this.ensureOwnedDirectory(this.profileRoot);
|
|
25556
|
+
await this.ensureOwnedDirectory(this.profileStateRoot);
|
|
25557
|
+
const destination = this.statePath(agentId);
|
|
25558
|
+
const temporary = this.exactChild(
|
|
25559
|
+
this.profileStateRoot,
|
|
25560
|
+
`${agentId}.${crypto.randomUUID()}.tmp`
|
|
25561
|
+
);
|
|
25562
|
+
try {
|
|
25563
|
+
const marker = await open4(temporary, "wx+", 384);
|
|
25564
|
+
try {
|
|
25565
|
+
await marker.writeFile(JSON.stringify(state), "utf8");
|
|
25566
|
+
await marker.sync();
|
|
25567
|
+
} finally {
|
|
25568
|
+
await marker.close();
|
|
25569
|
+
}
|
|
25570
|
+
await rename3(temporary, destination);
|
|
25571
|
+
await this.syncDirectory(this.profileStateRoot);
|
|
25572
|
+
await this.syncDirectory(this.profileRoot);
|
|
25573
|
+
} catch (error52) {
|
|
25574
|
+
await rm4(temporary, { force: true }).catch(() => {
|
|
25575
|
+
});
|
|
25576
|
+
throw error52;
|
|
25577
|
+
}
|
|
25578
|
+
}
|
|
25579
|
+
/** Trusted cloud lifecycle authorization after an explicit restore/current assignment. */
|
|
25580
|
+
async authorizeProfile(agentId, revision) {
|
|
25581
|
+
this.validateAgentId(agentId);
|
|
25582
|
+
if (!Number.isInteger(revision) || revision < 0) {
|
|
25583
|
+
throw new Error("invalid browser profile lifecycle revision");
|
|
25584
|
+
}
|
|
25585
|
+
try {
|
|
25586
|
+
await this.withLock(agentId, async () => {
|
|
25587
|
+
const current = await this.readProfileState(agentId);
|
|
25588
|
+
if (current && current.revision > revision) {
|
|
25589
|
+
throw new Error("stale browser profile authorization was refused");
|
|
25590
|
+
}
|
|
25591
|
+
if (current?.state === "purged" && current.revision === revision) {
|
|
25592
|
+
throw new Error("this browser profile remains retired until the AI teammate is restored");
|
|
25593
|
+
}
|
|
25594
|
+
if (!current || current.revision < revision || current.state !== "allowed") {
|
|
25595
|
+
await this.writeProfileState(agentId, { revision, state: "allowed" });
|
|
25596
|
+
}
|
|
25597
|
+
});
|
|
25598
|
+
const deniedRevision = this.deniedAuthorizations.get(agentId);
|
|
25599
|
+
if (deniedRevision !== void 0 && revision >= deniedRevision) {
|
|
25600
|
+
this.deniedAuthorizations.delete(agentId);
|
|
25601
|
+
}
|
|
25602
|
+
} catch (error52) {
|
|
25603
|
+
this.deniedAuthorizations.set(
|
|
25604
|
+
agentId,
|
|
25605
|
+
Math.max(revision, this.deniedAuthorizations.get(agentId) ?? revision)
|
|
25606
|
+
);
|
|
25607
|
+
throw error52;
|
|
25608
|
+
}
|
|
25609
|
+
}
|
|
25117
25610
|
/**
|
|
25118
25611
|
* Ensure a live session for this teammate. An existing session is adopted
|
|
25119
25612
|
* as-is (the cloud-minted id loses to the live one — the cloud reconciles
|
|
@@ -25121,16 +25614,39 @@ var BrowserManager = class {
|
|
|
25121
25614
|
* with the install remedy.
|
|
25122
25615
|
*/
|
|
25123
25616
|
ensure(agentId, browserSessionId) {
|
|
25124
|
-
|
|
25125
|
-
|
|
25617
|
+
try {
|
|
25618
|
+
this.validateAgentId(agentId);
|
|
25619
|
+
} catch (error52) {
|
|
25620
|
+
return Promise.reject(error52);
|
|
25126
25621
|
}
|
|
25127
25622
|
return this.withLock(agentId, async () => {
|
|
25623
|
+
if (this.deniedAuthorizations.has(agentId)) {
|
|
25624
|
+
throw new Error(
|
|
25625
|
+
"this browser profile is unavailable until its lifecycle authorization succeeds"
|
|
25626
|
+
);
|
|
25627
|
+
}
|
|
25628
|
+
const lifecycle = await this.readProfileState(agentId);
|
|
25629
|
+
if (lifecycle?.state === "purged") {
|
|
25630
|
+
throw new Error("this browser profile was retired and cannot be recreated locally");
|
|
25631
|
+
}
|
|
25128
25632
|
const existing = this.sessions.get(agentId);
|
|
25633
|
+
if (existing?.closeFailed) {
|
|
25634
|
+
throw new Error("the previous browser termination is not yet confirmed");
|
|
25635
|
+
}
|
|
25129
25636
|
if (existing && !existing.closed) {
|
|
25130
25637
|
this.markActivity(agentId);
|
|
25131
25638
|
return this.stateOf(existing);
|
|
25132
25639
|
}
|
|
25133
|
-
|
|
25640
|
+
await this.ensureOwnedDirectory(this.profileRoot);
|
|
25641
|
+
const profileDir = this.profilePath(agentId);
|
|
25642
|
+
try {
|
|
25643
|
+
const existingProfile = await lstat4(profileDir);
|
|
25644
|
+
if (existingProfile.isSymbolicLink() || !existingProfile.isDirectory()) {
|
|
25645
|
+
throw new Error("browser profile path is not an owned directory");
|
|
25646
|
+
}
|
|
25647
|
+
} catch (error52) {
|
|
25648
|
+
if (error52.code !== "ENOENT") throw error52;
|
|
25649
|
+
}
|
|
25134
25650
|
await mkdir4(profileDir, { recursive: true, mode: 448 });
|
|
25135
25651
|
const adapter = await this.opts.factory.open({
|
|
25136
25652
|
agentId,
|
|
@@ -25151,7 +25667,8 @@ var BrowserManager = class {
|
|
|
25151
25667
|
framesPaused: false,
|
|
25152
25668
|
inputQueue: Promise.resolve(),
|
|
25153
25669
|
resizeGeneration: 0,
|
|
25154
|
-
closed: false
|
|
25670
|
+
closed: false,
|
|
25671
|
+
closeFailed: false
|
|
25155
25672
|
};
|
|
25156
25673
|
this.sessions.set(agentId, session);
|
|
25157
25674
|
adapter.onStateChanged(() => {
|
|
@@ -25163,7 +25680,8 @@ var BrowserManager = class {
|
|
|
25163
25680
|
});
|
|
25164
25681
|
}
|
|
25165
25682
|
/** browser.open handler: ensure, then announce with the request correlation. */
|
|
25166
|
-
async open(agentId, browserSessionId, _viewport, openRequestId) {
|
|
25683
|
+
async open(agentId, browserSessionId, _viewport, openRequestId, profileRevision) {
|
|
25684
|
+
if (profileRevision !== void 0) await this.authorizeProfile(agentId, profileRevision);
|
|
25167
25685
|
const state = await this.ensure(agentId, browserSessionId);
|
|
25168
25686
|
this.events?.state(state, openRequestId);
|
|
25169
25687
|
return state;
|
|
@@ -25173,18 +25691,45 @@ var BrowserManager = class {
|
|
|
25173
25691
|
}
|
|
25174
25692
|
async closeLocked(agentId, reason) {
|
|
25175
25693
|
const session = this.sessions.get(agentId);
|
|
25176
|
-
if (!session || session.closed) return;
|
|
25694
|
+
if (!session || session.closed && !session.closeFailed) return;
|
|
25177
25695
|
session.closed = true;
|
|
25696
|
+
session.closeFailed = false;
|
|
25178
25697
|
if (session.frameTimer) clearTimeout(session.frameTimer);
|
|
25179
25698
|
if (session.idleTimer) clearTimeout(session.idleTimer);
|
|
25180
|
-
this.sessions.delete(agentId);
|
|
25181
25699
|
try {
|
|
25182
|
-
await session.adapter.setFrameSink(null)
|
|
25700
|
+
await session.adapter.setFrameSink(null).catch(() => {
|
|
25701
|
+
});
|
|
25183
25702
|
await session.adapter.close();
|
|
25184
|
-
} catch {
|
|
25703
|
+
} catch (error52) {
|
|
25704
|
+
session.closeFailed = true;
|
|
25705
|
+
throw error52;
|
|
25185
25706
|
}
|
|
25707
|
+
this.sessions.delete(agentId);
|
|
25186
25708
|
this.events?.ended(session.browserSessionId, agentId, reason);
|
|
25187
25709
|
}
|
|
25710
|
+
/** Persist retirement, close a live Chromium, then delete only this exact profile. */
|
|
25711
|
+
purge(agentId, purgeId, profileRevision) {
|
|
25712
|
+
try {
|
|
25713
|
+
this.validateAgentId(agentId);
|
|
25714
|
+
} catch (error52) {
|
|
25715
|
+
return Promise.reject(error52);
|
|
25716
|
+
}
|
|
25717
|
+
if (!Number.isInteger(profileRevision) || profileRevision < 1) {
|
|
25718
|
+
return Promise.reject(new Error("invalid browser profile purge revision"));
|
|
25719
|
+
}
|
|
25720
|
+
return this.withLock(agentId, async () => {
|
|
25721
|
+
const current = await this.readProfileState(agentId);
|
|
25722
|
+
if (current && current.revision > profileRevision) return;
|
|
25723
|
+
await this.writeProfileState(agentId, {
|
|
25724
|
+
revision: profileRevision,
|
|
25725
|
+
state: "purged",
|
|
25726
|
+
purgeId
|
|
25727
|
+
});
|
|
25728
|
+
await this.closeLocked(agentId, "stopped");
|
|
25729
|
+
await rm4(this.profilePath(agentId), { recursive: true, force: true, maxRetries: 3 });
|
|
25730
|
+
await this.syncDirectory(this.profileRoot);
|
|
25731
|
+
});
|
|
25732
|
+
}
|
|
25188
25733
|
async closeAll(reason) {
|
|
25189
25734
|
await Promise.allSettled(
|
|
25190
25735
|
[...this.sessions.keys()].map((agentId) => this.close(agentId, reason))
|
|
@@ -25224,8 +25769,8 @@ var BrowserManager = class {
|
|
|
25224
25769
|
return this.enqueue(session, async () => {
|
|
25225
25770
|
if (resizeGeneration !== null && resizeGeneration !== session.resizeGeneration) return;
|
|
25226
25771
|
await session.adapter.command(command);
|
|
25227
|
-
const
|
|
25228
|
-
if (
|
|
25772
|
+
const needsImmediateFrame = command.action === "resize" || command.action === "activateTab" || command.action === "newTab" || command.action === "closeTab";
|
|
25773
|
+
if (needsImmediateFrame && session.viewerCount > 0) {
|
|
25229
25774
|
try {
|
|
25230
25775
|
this.enqueueFrame(session, await session.adapter.screenshot());
|
|
25231
25776
|
} catch {
|
|
@@ -25331,7 +25876,8 @@ var BrowserManager = class {
|
|
|
25331
25876
|
this.armIdleTimer(session);
|
|
25332
25877
|
return;
|
|
25333
25878
|
}
|
|
25334
|
-
void this.close(session.agentId, "idle_timeout")
|
|
25879
|
+
void this.close(session.agentId, "idle_timeout").catch(() => {
|
|
25880
|
+
});
|
|
25335
25881
|
}, this.idleTimeoutMs);
|
|
25336
25882
|
session.idleTimer.unref?.();
|
|
25337
25883
|
}
|
|
@@ -25348,12 +25894,13 @@ async function loadPlaywright() {
|
|
|
25348
25894
|
return import("playwright-core");
|
|
25349
25895
|
}
|
|
25350
25896
|
var KEY_ALIASES = { " ": "Space" };
|
|
25351
|
-
function createPlaywrightBrowserAdapterFactory() {
|
|
25897
|
+
function createPlaywrightBrowserAdapterFactory(dependencies = {}) {
|
|
25898
|
+
const load = dependencies.loadPlaywright ?? loadPlaywright;
|
|
25352
25899
|
return {
|
|
25353
25900
|
kind: "playwright",
|
|
25354
25901
|
async capability() {
|
|
25355
25902
|
try {
|
|
25356
|
-
const playwright = await
|
|
25903
|
+
const playwright = await load();
|
|
25357
25904
|
const executable = playwright.chromium.executablePath();
|
|
25358
25905
|
if (!executable) return { status: "unavailable", error: BROWSER_INSTALL_REMEDY };
|
|
25359
25906
|
await access3(executable);
|
|
@@ -25363,7 +25910,7 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25363
25910
|
}
|
|
25364
25911
|
},
|
|
25365
25912
|
async open({ profileDir, viewport }) {
|
|
25366
|
-
const playwright = await
|
|
25913
|
+
const playwright = await load();
|
|
25367
25914
|
const context = await playwright.chromium.launchPersistentContext(profileDir, {
|
|
25368
25915
|
headless: true,
|
|
25369
25916
|
viewport,
|
|
@@ -25732,8 +26279,10 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25732
26279
|
async fillLogin(credential) {
|
|
25733
26280
|
const tab = requireActive();
|
|
25734
26281
|
const { page: page2 } = tab;
|
|
26282
|
+
const expectedOrigin = requireBrowserLoginOrigin(safeUrl(page2), credential.loginUrl);
|
|
25735
26283
|
const password = page2.locator('input[type="password"]:visible').first();
|
|
25736
26284
|
await password.waitFor({ state: "visible", timeout: ACTION_TIMEOUT_MS });
|
|
26285
|
+
requireBrowserLoginOrigin(safeUrl(page2), credential.loginUrl);
|
|
25737
26286
|
const username = page2.locator(
|
|
25738
26287
|
[
|
|
25739
26288
|
'input[autocomplete="username"]:visible',
|
|
@@ -25743,14 +26292,66 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25743
26292
|
'input[type="text"]:visible'
|
|
25744
26293
|
].join(", ")
|
|
25745
26294
|
).first();
|
|
25746
|
-
|
|
25747
|
-
|
|
25748
|
-
|
|
25749
|
-
|
|
26295
|
+
const [passwordInputHandle] = await password.elementHandles();
|
|
26296
|
+
if (!passwordInputHandle) throw new Error("the password field disappeared");
|
|
26297
|
+
const [usernameInputHandle] = await username.elementHandles();
|
|
26298
|
+
const originSentinel = "ZIXT_BROWSER_LOGIN_ORIGIN_CHANGED";
|
|
26299
|
+
try {
|
|
26300
|
+
await passwordInputHandle.evaluate(
|
|
26301
|
+
(node, values) => {
|
|
26302
|
+
const browser = globalThis;
|
|
26303
|
+
const passwordInput = node;
|
|
26304
|
+
if (passwordInput.tagName !== "INPUT" || browser.location.origin !== values.origin) {
|
|
26305
|
+
throw new Error(values.originSentinel);
|
|
26306
|
+
}
|
|
26307
|
+
const visible = (input) => {
|
|
26308
|
+
const style = browser.getComputedStyle(input);
|
|
26309
|
+
const bounds = input.getBoundingClientRect();
|
|
26310
|
+
return input.isConnected && !input.disabled && style.display !== "none" && style.visibility !== "hidden" && bounds.width > 0 && bounds.height > 0;
|
|
26311
|
+
};
|
|
26312
|
+
const write = (input, value) => {
|
|
26313
|
+
input.focus();
|
|
26314
|
+
const setter = Object.getOwnPropertyDescriptor(
|
|
26315
|
+
browser.HTMLInputElement.prototype,
|
|
26316
|
+
"value"
|
|
26317
|
+
)?.set;
|
|
26318
|
+
if (setter) setter.call(input, value);
|
|
26319
|
+
else input.value = value;
|
|
26320
|
+
input.dispatchEvent(
|
|
26321
|
+
new browser.Event("input", { bubbles: true, composed: true })
|
|
26322
|
+
);
|
|
26323
|
+
input.dispatchEvent(new browser.Event("change", { bubbles: true }));
|
|
26324
|
+
};
|
|
26325
|
+
const usernameInput = values.usernameInput;
|
|
26326
|
+
if (usernameInput && usernameInput.ownerDocument === passwordInput.ownerDocument && visible(usernameInput)) {
|
|
26327
|
+
write(usernameInput, values.username);
|
|
26328
|
+
}
|
|
26329
|
+
if (!passwordInput.isConnected || browser.location.origin !== values.origin) {
|
|
26330
|
+
throw new Error(values.originSentinel);
|
|
26331
|
+
}
|
|
26332
|
+
write(passwordInput, values.password);
|
|
26333
|
+
},
|
|
26334
|
+
{
|
|
26335
|
+
usernameInput: usernameInputHandle ?? null,
|
|
26336
|
+
origin: expectedOrigin,
|
|
26337
|
+
originSentinel,
|
|
26338
|
+
username: credential.username,
|
|
26339
|
+
password: credential.password
|
|
26340
|
+
}
|
|
26341
|
+
);
|
|
26342
|
+
requireBrowserLoginOrigin(safeUrl(page2), credential.loginUrl);
|
|
26343
|
+
await passwordInputHandle.press("Enter");
|
|
26344
|
+
} catch (error52) {
|
|
26345
|
+
if (String(error52).includes(originSentinel)) {
|
|
26346
|
+
throw new Error(BROWSER_LOGIN_ORIGIN_CHANGED);
|
|
25750
26347
|
}
|
|
26348
|
+
throw error52;
|
|
26349
|
+
} finally {
|
|
26350
|
+
await Promise.allSettled([
|
|
26351
|
+
passwordInputHandle.dispose(),
|
|
26352
|
+
...usernameInputHandle ? [usernameInputHandle.dispose()] : []
|
|
26353
|
+
]);
|
|
25751
26354
|
}
|
|
25752
|
-
await password.fill(credential.password, { timeout: ACTION_TIMEOUT_MS });
|
|
25753
|
-
await password.press("Enter");
|
|
25754
26355
|
try {
|
|
25755
26356
|
await page2.waitForLoadState("load", { timeout: 15e3 });
|
|
25756
26357
|
} catch {
|
|
@@ -25796,10 +26397,7 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25796
26397
|
async close() {
|
|
25797
26398
|
closed = true;
|
|
25798
26399
|
for (const tab of tabs) await detachSession(tab);
|
|
25799
|
-
|
|
25800
|
-
await context.close();
|
|
25801
|
-
} catch {
|
|
25802
|
-
}
|
|
26400
|
+
await context.close();
|
|
25803
26401
|
}
|
|
25804
26402
|
};
|
|
25805
26403
|
}
|
|
@@ -25809,9 +26407,9 @@ function createPlaywrightBrowserAdapterFactory() {
|
|
|
25809
26407
|
// src/runners/cli-runner.ts
|
|
25810
26408
|
import { spawn as spawn8 } from "node:child_process";
|
|
25811
26409
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
25812
|
-
import { lstat as
|
|
26410
|
+
import { lstat as lstat10, mkdir as mkdir10, realpath as realpath7 } from "node:fs/promises";
|
|
25813
26411
|
import { homedir as homedir4 } from "node:os";
|
|
25814
|
-
import { dirname as
|
|
26412
|
+
import { dirname as dirname7, isAbsolute as isAbsolute13, join as join14, resolve as resolve8 } from "node:path";
|
|
25815
26413
|
|
|
25816
26414
|
// src/tool-packs/browser/tool-definitions.ts
|
|
25817
26415
|
function definition(name, description, properties, required2 = []) {
|
|
@@ -26033,9 +26631,13 @@ function createBrowserToolPack(deps) {
|
|
|
26033
26631
|
});
|
|
26034
26632
|
const credential = await deps.requestWebLogin(credentialName, origin);
|
|
26035
26633
|
try {
|
|
26634
|
+
requireBrowserLoginOrigin(tool.state().url, credential.loginUrl);
|
|
26036
26635
|
const { landedUrl } = await tool.fillLogin(credential);
|
|
26037
26636
|
return { ok: true, result: { loggedIn: true, landedUrl } };
|
|
26038
|
-
} catch {
|
|
26637
|
+
} catch (error52) {
|
|
26638
|
+
if (error52 instanceof Error && error52.message === BROWSER_LOGIN_ORIGIN_CHANGED) {
|
|
26639
|
+
return { ok: false, error: BROWSER_LOGIN_ORIGIN_CHANGED };
|
|
26640
|
+
}
|
|
26039
26641
|
return {
|
|
26040
26642
|
ok: false,
|
|
26041
26643
|
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 +29102,13 @@ function createGithubPushOrchestrator(input) {
|
|
|
28500
29102
|
// src/tool-packs/github/git-bridge.ts
|
|
28501
29103
|
import { spawn as spawn5 } from "node:child_process";
|
|
28502
29104
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
28503
|
-
import { chmod as chmod3, lstat as
|
|
28504
|
-
import { dirname as
|
|
29105
|
+
import { chmod as chmod3, lstat as lstat6, mkdir as mkdir5, realpath as realpath3, rm as rm5 } from "node:fs/promises";
|
|
29106
|
+
import { dirname as dirname5, isAbsolute as isAbsolute8, join as join9, relative as relative4 } from "node:path";
|
|
28505
29107
|
|
|
28506
29108
|
// src/tool-packs/github/git-credential-broker.ts
|
|
28507
29109
|
import { createServer } from "node:http";
|
|
28508
29110
|
import { randomBytes, randomUUID as randomUUID6, timingSafeEqual } from "node:crypto";
|
|
28509
|
-
import { chmod as chmod2, lstat as
|
|
29111
|
+
import { chmod as chmod2, lstat as lstat5, realpath as realpath2, writeFile } from "node:fs/promises";
|
|
28510
29112
|
import { isAbsolute as isAbsolute7, join as join8, relative as relative3 } from "node:path";
|
|
28511
29113
|
var MAX_REQUEST_BYTES = 16 * 1024;
|
|
28512
29114
|
var FILE_MODE = 384;
|
|
@@ -28631,7 +29233,7 @@ async function createGithubGitCredentialBroker(input) {
|
|
|
28631
29233
|
throw new Error("GitHub credential authority has expired");
|
|
28632
29234
|
}
|
|
28633
29235
|
assertRepositoryFullName(input.repositoryFullName);
|
|
28634
|
-
const rootEntry = await
|
|
29236
|
+
const rootEntry = await lstat5(input.runArtifactsRoot);
|
|
28635
29237
|
if (!rootEntry.isDirectory() || rootEntry.isSymbolicLink()) {
|
|
28636
29238
|
throw new Error("Git credential broker requires a private real run directory");
|
|
28637
29239
|
}
|
|
@@ -28742,7 +29344,7 @@ function assertBelow(parent, child, label) {
|
|
|
28742
29344
|
void label;
|
|
28743
29345
|
}
|
|
28744
29346
|
async function requireRealDirectory(path, label) {
|
|
28745
|
-
const entry = await
|
|
29347
|
+
const entry = await lstat6(path).catch(() => null);
|
|
28746
29348
|
if (!entry || !entry.isDirectory() || entry.isSymbolicLink()) {
|
|
28747
29349
|
void label;
|
|
28748
29350
|
throw new GithubGitProcessError("invalid_input");
|
|
@@ -28752,9 +29354,9 @@ async function requireRealDirectory(path, label) {
|
|
|
28752
29354
|
async function validateTokenlessPaths(command) {
|
|
28753
29355
|
if (command.kind === "clone-from-bridge") {
|
|
28754
29356
|
if (!isAbsolute8(command.destination)) throw new GithubGitProcessError("invalid_input");
|
|
28755
|
-
const parent = await requireRealDirectory(
|
|
29357
|
+
const parent = await requireRealDirectory(dirname5(command.destination), "clone parent");
|
|
28756
29358
|
assertBelow(parent, command.destination, "clone destination");
|
|
28757
|
-
const destination = await
|
|
29359
|
+
const destination = await lstat6(command.destination).catch((error52) => {
|
|
28758
29360
|
if (error52.code === "ENOENT") return null;
|
|
28759
29361
|
throw error52;
|
|
28760
29362
|
});
|
|
@@ -28862,8 +29464,8 @@ async function runGit(input, args, env) {
|
|
|
28862
29464
|
let settled = false;
|
|
28863
29465
|
let stopping = false;
|
|
28864
29466
|
let resolveExited;
|
|
28865
|
-
const exited = new Promise((
|
|
28866
|
-
resolveExited =
|
|
29467
|
+
const exited = new Promise((resolve15) => {
|
|
29468
|
+
resolveExited = resolve15;
|
|
28867
29469
|
});
|
|
28868
29470
|
child.once("exit", resolveExited);
|
|
28869
29471
|
const cleanup = () => {
|
|
@@ -29059,7 +29661,7 @@ function createGithubGitBridge(input) {
|
|
|
29059
29661
|
const real = await requireRealDirectory(path, "git bridge");
|
|
29060
29662
|
assertBelow(current.bridges, real, "git bridge");
|
|
29061
29663
|
const hooks = join9(real, "hooks");
|
|
29062
|
-
await
|
|
29664
|
+
await rm5(hooks, { recursive: true, force: true });
|
|
29063
29665
|
await mkdir5(hooks, { mode: DIRECTORY_MODE });
|
|
29064
29666
|
await chmod3(hooks, DIRECTORY_MODE);
|
|
29065
29667
|
const config2 = join9(real, "config");
|
|
@@ -29067,7 +29669,7 @@ function createGithubGitBridge(input) {
|
|
|
29067
29669
|
active.add(real);
|
|
29068
29670
|
return real;
|
|
29069
29671
|
} catch (error52) {
|
|
29070
|
-
await
|
|
29672
|
+
await rm5(path, { recursive: true, force: true }).catch(() => {
|
|
29071
29673
|
});
|
|
29072
29674
|
throw error52;
|
|
29073
29675
|
}
|
|
@@ -29161,7 +29763,7 @@ function createGithubGitBridge(input) {
|
|
|
29161
29763
|
},
|
|
29162
29764
|
async destroyPrivateBridge(path) {
|
|
29163
29765
|
const bridge = await requireBridge(path);
|
|
29164
|
-
await
|
|
29766
|
+
await rm5(bridge, { recursive: true, force: true });
|
|
29165
29767
|
active.delete(bridge);
|
|
29166
29768
|
credentialed2.delete(bridge);
|
|
29167
29769
|
},
|
|
@@ -29169,7 +29771,7 @@ function createGithubGitBridge(input) {
|
|
|
29169
29771
|
if (closed) return;
|
|
29170
29772
|
closed = true;
|
|
29171
29773
|
const paths = [...active];
|
|
29172
|
-
await Promise.all(paths.map((path) =>
|
|
29774
|
+
await Promise.all(paths.map((path) => rm5(path, { recursive: true, force: true })));
|
|
29173
29775
|
active.clear();
|
|
29174
29776
|
credentialed2.clear();
|
|
29175
29777
|
}
|
|
@@ -29510,8 +30112,8 @@ function createRepositoryTools(runtime) {
|
|
|
29510
30112
|
|
|
29511
30113
|
// src/tool-packs/github/workspace.ts
|
|
29512
30114
|
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
|
|
30115
|
+
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";
|
|
30116
|
+
import { isAbsolute as isAbsolute9, join as join10, relative as relative5, resolve as resolve5 } from "node:path";
|
|
29515
30117
|
var SAFE_LOCAL_ID = /^[A-Za-z0-9_-]{1,200}$/;
|
|
29516
30118
|
var FULL_NAME2 = /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/;
|
|
29517
30119
|
var DIRECTORY_MODE2 = 448;
|
|
@@ -29534,10 +30136,10 @@ function assertBelow2(parent, child, label) {
|
|
|
29534
30136
|
}
|
|
29535
30137
|
}
|
|
29536
30138
|
function samePath(left, right) {
|
|
29537
|
-
return process.platform === "win32" ?
|
|
30139
|
+
return process.platform === "win32" ? resolve5(left).toLowerCase() === resolve5(right).toLowerCase() : resolve5(left) === resolve5(right);
|
|
29538
30140
|
}
|
|
29539
30141
|
async function requireRealDirectory2(path, label) {
|
|
29540
|
-
const entry = await
|
|
30142
|
+
const entry = await lstat7(path).catch(() => null);
|
|
29541
30143
|
if (!entry || !entry.isDirectory() || entry.isSymbolicLink()) {
|
|
29542
30144
|
throw new Error(`${label} must be a real directory, not a symbolic link or junction`);
|
|
29543
30145
|
}
|
|
@@ -29574,7 +30176,7 @@ function parseMetadata(text) {
|
|
|
29574
30176
|
}
|
|
29575
30177
|
async function pathExists(path) {
|
|
29576
30178
|
try {
|
|
29577
|
-
await
|
|
30179
|
+
await lstat7(path);
|
|
29578
30180
|
return true;
|
|
29579
30181
|
} catch (error52) {
|
|
29580
30182
|
if (error52.code === "ENOENT") return false;
|
|
@@ -29636,11 +30238,11 @@ async function createGithubWorkspaceService(input) {
|
|
|
29636
30238
|
if (!await pathExists(destination) || !await pathExists(metadataPath)) {
|
|
29637
30239
|
throw new Error("GitHub repository workspace has not been prepared");
|
|
29638
30240
|
}
|
|
29639
|
-
const metadataEntry = await
|
|
30241
|
+
const metadataEntry = await lstat7(metadataPath);
|
|
29640
30242
|
if (!metadataEntry.isFile() || metadataEntry.isSymbolicLink()) {
|
|
29641
30243
|
throw new Error("GitHub workspace metadata is invalid");
|
|
29642
30244
|
}
|
|
29643
|
-
const metadata = parseMetadata(await
|
|
30245
|
+
const metadata = parseMetadata(await readFile6(metadataPath, "utf8"));
|
|
29644
30246
|
if (metadata.repositoryId !== parsed.data || metadata.fullName !== repository.fullName || !samePath(metadata.path, destination)) {
|
|
29645
30247
|
throw new Error("GitHub workspace metadata does not match this repository");
|
|
29646
30248
|
}
|
|
@@ -29690,15 +30292,15 @@ async function createGithubWorkspaceService(input) {
|
|
|
29690
30292
|
});
|
|
29691
30293
|
await chmod4(metadataTemporary, FILE_MODE2);
|
|
29692
30294
|
try {
|
|
29693
|
-
await
|
|
30295
|
+
await rename4(temporaryReal, destination);
|
|
29694
30296
|
try {
|
|
29695
|
-
await
|
|
30297
|
+
await rename4(metadataTemporary, metadataPath);
|
|
29696
30298
|
} catch (error52) {
|
|
29697
|
-
await
|
|
30299
|
+
await rm6(destination, { recursive: true, force: true });
|
|
29698
30300
|
throw error52;
|
|
29699
30301
|
}
|
|
29700
30302
|
} finally {
|
|
29701
|
-
await
|
|
30303
|
+
await rm6(metadataTemporary, { force: true }).catch(() => {
|
|
29702
30304
|
});
|
|
29703
30305
|
}
|
|
29704
30306
|
const path = await requireRealDirectory2(destination, "GitHub repository");
|
|
@@ -29710,7 +30312,7 @@ async function createGithubWorkspaceService(input) {
|
|
|
29710
30312
|
headSha
|
|
29711
30313
|
};
|
|
29712
30314
|
} finally {
|
|
29713
|
-
await
|
|
30315
|
+
await rm6(temporary, { recursive: true, force: true }).catch(() => {
|
|
29714
30316
|
});
|
|
29715
30317
|
}
|
|
29716
30318
|
};
|
|
@@ -29738,11 +30340,11 @@ async function createGithubWorkspaceService(input) {
|
|
|
29738
30340
|
expiresAt: authority.expiresAt
|
|
29739
30341
|
});
|
|
29740
30342
|
}
|
|
29741
|
-
const metadataEntry = await
|
|
30343
|
+
const metadataEntry = await lstat7(metadataPath);
|
|
29742
30344
|
if (!metadataEntry.isFile() || metadataEntry.isSymbolicLink()) {
|
|
29743
30345
|
throw new Error("GitHub workspace metadata is invalid");
|
|
29744
30346
|
}
|
|
29745
|
-
const metadata = parseMetadata(await
|
|
30347
|
+
const metadata = parseMetadata(await readFile6(metadataPath, "utf8"));
|
|
29746
30348
|
if (metadata.repositoryId !== repository.repositoryId || metadata.fullName !== repository.fullName || !samePath(metadata.path, destination)) {
|
|
29747
30349
|
throw new Error("GitHub workspace metadata does not match this repository");
|
|
29748
30350
|
}
|
|
@@ -31351,8 +31953,8 @@ var linearToolPackFactory = {
|
|
|
31351
31953
|
async create(grant, context) {
|
|
31352
31954
|
let resolveCancelled;
|
|
31353
31955
|
let closed = false;
|
|
31354
|
-
const cancelled = new Promise((
|
|
31355
|
-
resolveCancelled =
|
|
31956
|
+
const cancelled = new Promise((resolve15) => {
|
|
31957
|
+
resolveCancelled = resolve15;
|
|
31356
31958
|
});
|
|
31357
31959
|
const cancel = () => {
|
|
31358
31960
|
if (closed) return;
|
|
@@ -31721,6 +32323,21 @@ var TOOLS = [
|
|
|
31721
32323
|
required: ["agent_id", "message"]
|
|
31722
32324
|
}
|
|
31723
32325
|
},
|
|
32326
|
+
{
|
|
32327
|
+
name: "message_manager",
|
|
32328
|
+
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.",
|
|
32329
|
+
inputSchema: {
|
|
32330
|
+
type: "object",
|
|
32331
|
+
properties: {
|
|
32332
|
+
message: {
|
|
32333
|
+
type: "string",
|
|
32334
|
+
description: "A self-contained report, request, or question for the Manager."
|
|
32335
|
+
}
|
|
32336
|
+
},
|
|
32337
|
+
required: ["message"],
|
|
32338
|
+
additionalProperties: false
|
|
32339
|
+
}
|
|
32340
|
+
},
|
|
31724
32341
|
{
|
|
31725
32342
|
name: "get_org_config",
|
|
31726
32343
|
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 +32580,8 @@ function opFor(name, args) {
|
|
|
31963
32580
|
message: str("message"),
|
|
31964
32581
|
...typeof args["task_id"] === "string" && args["task_id"] ? { taskId: args["task_id"] } : {}
|
|
31965
32582
|
};
|
|
32583
|
+
case "message_manager":
|
|
32584
|
+
return { kind: "manager.message", message: str("message") };
|
|
31966
32585
|
case "get_org_config":
|
|
31967
32586
|
return { kind: "org.config" };
|
|
31968
32587
|
case "read_credential": {
|
|
@@ -32021,7 +32640,7 @@ function createAskUserServer() {
|
|
|
32021
32640
|
let server;
|
|
32022
32641
|
let listening;
|
|
32023
32642
|
function ensureListening() {
|
|
32024
|
-
listening ??= new Promise((
|
|
32643
|
+
listening ??= new Promise((resolve15, reject3) => {
|
|
32025
32644
|
server = createServer2((req, res) => {
|
|
32026
32645
|
res.on("error", () => {
|
|
32027
32646
|
});
|
|
@@ -32037,7 +32656,7 @@ function createAskUserServer() {
|
|
|
32037
32656
|
server.on("error", reject3);
|
|
32038
32657
|
server.listen(0, "127.0.0.1", () => {
|
|
32039
32658
|
const address = server.address();
|
|
32040
|
-
if (address && typeof address === "object")
|
|
32659
|
+
if (address && typeof address === "object") resolve15(address.port);
|
|
32041
32660
|
else reject3(new Error("ask_user server failed to bind"));
|
|
32042
32661
|
});
|
|
32043
32662
|
server.unref();
|
|
@@ -32369,7 +32988,7 @@ function buildRunnerEnv(input) {
|
|
|
32369
32988
|
// src/runners/github-shell-auth.ts
|
|
32370
32989
|
import { execFile } from "node:child_process";
|
|
32371
32990
|
import { randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
32372
|
-
import { chmod as chmod5, lstat as
|
|
32991
|
+
import { chmod as chmod5, lstat as lstat8, mkdir as mkdir8, realpath as realpath5, writeFile as writeFile4 } from "node:fs/promises";
|
|
32373
32992
|
import { createServer as createServer3 } from "node:http";
|
|
32374
32993
|
import { isAbsolute as isAbsolute11, join as join12, relative as relative6 } from "node:path";
|
|
32375
32994
|
var MAX_REQUEST_BYTES2 = 16 * 1024;
|
|
@@ -32754,7 +33373,7 @@ async function writePrivate(path, content, executable = false) {
|
|
|
32754
33373
|
await chmod5(path, executable ? EXECUTABLE_FILE_MODE : PRIVATE_FILE_MODE);
|
|
32755
33374
|
}
|
|
32756
33375
|
async function prepareHelpers(input) {
|
|
32757
|
-
const rootEntry = await
|
|
33376
|
+
const rootEntry = await lstat8(input.runRoot);
|
|
32758
33377
|
if (!rootEntry.isDirectory() || rootEntry.isSymbolicLink()) {
|
|
32759
33378
|
throw new Error("GitHub shell authentication requires a private real run directory");
|
|
32760
33379
|
}
|
|
@@ -33001,7 +33620,7 @@ password=${credential.accessToken}
|
|
|
33001
33620
|
|
|
33002
33621
|
// src/runners/working-context.ts
|
|
33003
33622
|
import { spawn as spawn6 } from "node:child_process";
|
|
33004
|
-
import { resolve as
|
|
33623
|
+
import { resolve as resolve6 } from "node:path";
|
|
33005
33624
|
var COMMAND_TIMEOUT_MS = 5e3;
|
|
33006
33625
|
var OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
33007
33626
|
var COMMAND_STOP_TIMEOUT_MS = 2e4;
|
|
@@ -33359,8 +33978,8 @@ async function repositoryState(directory, git, env, signal) {
|
|
|
33359
33978
|
const pathLines = paths.trim().split(/\r?\n/);
|
|
33360
33979
|
if (pathLines.length < 3 || !pathLines[0] || !pathLines[1] || !pathLines[2]) return null;
|
|
33361
33980
|
const root = pathLines[0];
|
|
33362
|
-
const gitDirectory =
|
|
33363
|
-
const commonDirectory =
|
|
33981
|
+
const gitDirectory = resolve6(directory, pathLines[1]);
|
|
33982
|
+
const commonDirectory = resolve6(directory, pathLines[2]);
|
|
33364
33983
|
const records = status.split(/\0|\r?\n/).filter(Boolean);
|
|
33365
33984
|
const rawBranch = statusField(records, "branch.head");
|
|
33366
33985
|
if (!rawBranch || rawBranch.length > 512 || !isSafeSingleLineDisplayText(rawBranch)) return null;
|
|
@@ -33507,18 +34126,18 @@ var WorkingContextPullRequestCache = class {
|
|
|
33507
34126
|
import { spawn as spawn7 } from "node:child_process";
|
|
33508
34127
|
import {
|
|
33509
34128
|
chmod as chmod6,
|
|
33510
|
-
lstat as
|
|
34129
|
+
lstat as lstat9,
|
|
33511
34130
|
mkdir as mkdir9,
|
|
33512
|
-
open as
|
|
34131
|
+
open as open5,
|
|
33513
34132
|
readdir as readdir3,
|
|
33514
|
-
readFile as
|
|
34133
|
+
readFile as readFile7,
|
|
33515
34134
|
realpath as realpath6,
|
|
33516
|
-
rename as
|
|
33517
|
-
rm as
|
|
34135
|
+
rename as rename5,
|
|
34136
|
+
rm as rm7,
|
|
33518
34137
|
writeFile as writeFile5
|
|
33519
34138
|
} from "node:fs/promises";
|
|
33520
34139
|
import { homedir as homedir3 } from "node:os";
|
|
33521
|
-
import { dirname as
|
|
34140
|
+
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
34141
|
var SAFE_SEGMENT2 = /^[A-Za-z0-9_-]{1,200}$/;
|
|
33523
34142
|
var DIRECTORY_MODE4 = 448;
|
|
33524
34143
|
var FILE_MODE3 = 384;
|
|
@@ -33751,7 +34370,7 @@ function assertBelow3(parent, child) {
|
|
|
33751
34370
|
if (escapes) throw new Error("run artifact path escapes its private root");
|
|
33752
34371
|
}
|
|
33753
34372
|
async function requireRealDirectory3(path, label) {
|
|
33754
|
-
const entry = await
|
|
34373
|
+
const entry = await lstat9(path);
|
|
33755
34374
|
if (entry.isSymbolicLink()) throw new Error(`${label} must not be a symbolic link`);
|
|
33756
34375
|
if (!entry.isDirectory()) throw new Error(`${label} must be a directory`);
|
|
33757
34376
|
return realpath6(path);
|
|
@@ -33768,7 +34387,7 @@ async function rejectWindowsSymlinkAncestors(profile, target) {
|
|
|
33768
34387
|
for (const segment of path.split("\\").filter(Boolean)) {
|
|
33769
34388
|
current = win322.join(current, segment);
|
|
33770
34389
|
try {
|
|
33771
|
-
const entry = await
|
|
34390
|
+
const entry = await lstat9(current);
|
|
33772
34391
|
if (entry.isSymbolicLink()) {
|
|
33773
34392
|
throw new Error("run artifact path must not contain symbolic links or junctions");
|
|
33774
34393
|
}
|
|
@@ -33779,16 +34398,16 @@ async function rejectWindowsSymlinkAncestors(profile, target) {
|
|
|
33779
34398
|
}
|
|
33780
34399
|
}
|
|
33781
34400
|
async function prepareRoot(root) {
|
|
33782
|
-
const absolute =
|
|
34401
|
+
const absolute = resolve7(root);
|
|
33783
34402
|
let realProfile;
|
|
33784
34403
|
if (process.platform === "win32") {
|
|
33785
|
-
const profile =
|
|
34404
|
+
const profile = resolve7(homedir3());
|
|
33786
34405
|
assertWindowsProfileBoundary(profile, absolute);
|
|
33787
34406
|
await rejectWindowsSymlinkAncestors(profile, absolute);
|
|
33788
34407
|
realProfile = await realpath6(profile);
|
|
33789
34408
|
}
|
|
33790
34409
|
try {
|
|
33791
|
-
await
|
|
34410
|
+
await lstat9(absolute);
|
|
33792
34411
|
} catch (error52) {
|
|
33793
34412
|
if (!isMissing(error52)) throw error52;
|
|
33794
34413
|
await mkdir9(absolute, { recursive: true, mode: DIRECTORY_MODE4 });
|
|
@@ -33802,7 +34421,7 @@ async function prepareAgentRoot(root, agentId) {
|
|
|
33802
34421
|
const path = join13(root, agentId);
|
|
33803
34422
|
assertBelow3(root, path);
|
|
33804
34423
|
try {
|
|
33805
|
-
await
|
|
34424
|
+
await lstat9(path);
|
|
33806
34425
|
} catch (error52) {
|
|
33807
34426
|
if (!isMissing(error52)) throw error52;
|
|
33808
34427
|
try {
|
|
@@ -33893,7 +34512,7 @@ async function createRunArtifacts(input) {
|
|
|
33893
34512
|
requireSafeSegment(input.agentId, "agentId");
|
|
33894
34513
|
requireSafeSegment(input.runToken, "runToken");
|
|
33895
34514
|
const root = await prepareRoot(input.root);
|
|
33896
|
-
const removeTree = input.removeTree ?? ((path) =>
|
|
34515
|
+
const removeTree = input.removeTree ?? ((path) => rm7(path, { recursive: true, force: true }));
|
|
33897
34516
|
const cleanupRetryDelayMs = input.cleanupRetryDelayMs ?? CLEANUP_RETRY_DELAY_MS;
|
|
33898
34517
|
const agentRoot = await prepareAgentRoot(root, input.agentId);
|
|
33899
34518
|
await lockDownWindowsDirectories([root, agentRoot]);
|
|
@@ -33952,10 +34571,10 @@ async function removePrivateTreeWithRetries(path, removeTree, retryDelayMs) {
|
|
|
33952
34571
|
}
|
|
33953
34572
|
}
|
|
33954
34573
|
async function sweepOrphanedRunArtifacts(root) {
|
|
33955
|
-
const absolute =
|
|
34574
|
+
const absolute = resolve7(root);
|
|
33956
34575
|
let realProfile;
|
|
33957
34576
|
if (process.platform === "win32") {
|
|
33958
|
-
const profile =
|
|
34577
|
+
const profile = resolve7(homedir3());
|
|
33959
34578
|
assertWindowsProfileBoundary(profile, absolute);
|
|
33960
34579
|
await rejectWindowsSymlinkAncestors(profile, absolute);
|
|
33961
34580
|
realProfile = await realpath6(profile);
|
|
@@ -33980,7 +34599,7 @@ async function sweepOrphanedRunArtifacts(root) {
|
|
|
33980
34599
|
if (!SAFE_SEGMENT2.test(run3.name) || !run3.isDirectory() || run3.isSymbolicLink()) continue;
|
|
33981
34600
|
const runPath = join13(agentPath, run3.name);
|
|
33982
34601
|
assertBelow3(agentPath, runPath);
|
|
33983
|
-
await
|
|
34602
|
+
await rm7(runPath, { recursive: true, force: true });
|
|
33984
34603
|
removed++;
|
|
33985
34604
|
}
|
|
33986
34605
|
}
|
|
@@ -33990,7 +34609,7 @@ function defaultRunRegistryRoot() {
|
|
|
33990
34609
|
return join13(homedir3(), ".zixt", "run-registry");
|
|
33991
34610
|
}
|
|
33992
34611
|
async function syncRunRegistryDirectory(path) {
|
|
33993
|
-
const handle = await
|
|
34612
|
+
const handle = await open5(path, "r");
|
|
33994
34613
|
try {
|
|
33995
34614
|
await handle.sync();
|
|
33996
34615
|
} finally {
|
|
@@ -34000,9 +34619,9 @@ async function syncRunRegistryDirectory(path) {
|
|
|
34000
34619
|
async function ensureDurableRunRegistryRoot(registryRoot, syncDirectory7) {
|
|
34001
34620
|
const firstCreated = await mkdir9(registryRoot, { recursive: true, mode: DIRECTORY_MODE4 });
|
|
34002
34621
|
if (firstCreated && process.platform !== "win32") {
|
|
34003
|
-
const first =
|
|
34004
|
-
const target =
|
|
34005
|
-
await syncDirectory7(
|
|
34622
|
+
const first = resolve7(firstCreated);
|
|
34623
|
+
const target = resolve7(registryRoot);
|
|
34624
|
+
await syncDirectory7(dirname6(first));
|
|
34006
34625
|
let current = first;
|
|
34007
34626
|
for (const part of relative7(first, target).split(sep3).filter(Boolean)) {
|
|
34008
34627
|
await syncDirectory7(current);
|
|
@@ -34019,12 +34638,12 @@ async function recordRunAssignment(runToken, record2, registryRoot = defaultRunR
|
|
|
34019
34638
|
try {
|
|
34020
34639
|
const syncDirectory7 = options.syncDirectory ?? syncRunRegistryDirectory;
|
|
34021
34640
|
await ensureDurableRunRegistryRoot(registryRoot, syncDirectory7);
|
|
34022
|
-
handle = await
|
|
34641
|
+
handle = await open5(temporary, "wx", FILE_MODE3);
|
|
34023
34642
|
await handle.writeFile(JSON.stringify(record2), "utf8");
|
|
34024
34643
|
await handle.sync();
|
|
34025
34644
|
await handle.close();
|
|
34026
34645
|
handle = void 0;
|
|
34027
|
-
await
|
|
34646
|
+
await rename5(temporary, destination);
|
|
34028
34647
|
if (process.platform !== "win32") {
|
|
34029
34648
|
await syncDirectory7(registryRoot);
|
|
34030
34649
|
}
|
|
@@ -34034,7 +34653,7 @@ async function recordRunAssignment(runToken, record2, registryRoot = defaultRunR
|
|
|
34034
34653
|
} finally {
|
|
34035
34654
|
await handle?.close().catch(() => {
|
|
34036
34655
|
});
|
|
34037
|
-
await
|
|
34656
|
+
await rm7(temporary, { force: true }).catch(() => {
|
|
34038
34657
|
});
|
|
34039
34658
|
}
|
|
34040
34659
|
}
|
|
@@ -34046,7 +34665,7 @@ async function forgetRunAssignment(runToken, registryRoot = defaultRunRegistryRo
|
|
|
34046
34665
|
if (retainingAssignments) return;
|
|
34047
34666
|
if (!SAFE_SEGMENT2.test(runToken)) return;
|
|
34048
34667
|
try {
|
|
34049
|
-
await
|
|
34668
|
+
await rm7(join13(registryRoot, `${runToken}.json`), { force: true });
|
|
34050
34669
|
} catch {
|
|
34051
34670
|
}
|
|
34052
34671
|
}
|
|
@@ -34091,7 +34710,7 @@ async function readRecordedRunAssignmentEntries(registryRoot = defaultRunRegistr
|
|
|
34091
34710
|
if (!SAFE_SEGMENT2.test(runToken)) continue;
|
|
34092
34711
|
let text;
|
|
34093
34712
|
try {
|
|
34094
|
-
text = await
|
|
34713
|
+
text = await readFile7(join13(registryRoot, entry.name), "utf8");
|
|
34095
34714
|
} catch {
|
|
34096
34715
|
continue;
|
|
34097
34716
|
}
|
|
@@ -34103,7 +34722,7 @@ async function readRecordedRunAssignmentEntries(registryRoot = defaultRunRegistr
|
|
|
34103
34722
|
async function readRecordedRunAssignmentEntriesStrict(registryRoot = defaultRunRegistryRoot()) {
|
|
34104
34723
|
let rootStat;
|
|
34105
34724
|
try {
|
|
34106
|
-
rootStat = await
|
|
34725
|
+
rootStat = await lstat9(registryRoot);
|
|
34107
34726
|
} catch (error52) {
|
|
34108
34727
|
if (isMissing(error52)) return [];
|
|
34109
34728
|
throw new Error("run registry state could not be observed");
|
|
@@ -34127,7 +34746,7 @@ async function readRecordedRunAssignmentEntriesStrict(registryRoot = defaultRunR
|
|
|
34127
34746
|
}
|
|
34128
34747
|
let text;
|
|
34129
34748
|
try {
|
|
34130
|
-
text = await
|
|
34749
|
+
text = await readFile7(join13(registryRoot, entry.name), "utf8");
|
|
34131
34750
|
} catch {
|
|
34132
34751
|
throw new Error("committed run registry witness could not be read");
|
|
34133
34752
|
}
|
|
@@ -34144,13 +34763,13 @@ async function forgetAcknowledgedRunAssignments(assignments, registryRoot = defa
|
|
|
34144
34763
|
);
|
|
34145
34764
|
const entries = await readRecordedRunAssignmentEntries(registryRoot);
|
|
34146
34765
|
await Promise.all(
|
|
34147
|
-
entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) =>
|
|
34766
|
+
entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) => rm7(join13(registryRoot, `${runToken}.json`), { force: true }))
|
|
34148
34767
|
);
|
|
34149
34768
|
}
|
|
34150
34769
|
async function forgetSupersededRunAssignments(taskId, epoch, registryRoot = defaultRunRegistryRoot()) {
|
|
34151
34770
|
const entries = await readRecordedRunAssignmentEntries(registryRoot);
|
|
34152
34771
|
await Promise.all(
|
|
34153
|
-
entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) =>
|
|
34772
|
+
entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) => rm7(join13(registryRoot, `${runToken}.json`), { force: true }))
|
|
34154
34773
|
);
|
|
34155
34774
|
}
|
|
34156
34775
|
|
|
@@ -34221,7 +34840,7 @@ function truncateThought(text) {
|
|
|
34221
34840
|
}
|
|
34222
34841
|
var MAX_APPROVAL_PAYLOAD = 5e4;
|
|
34223
34842
|
async function requireRealDirectory4(path, label) {
|
|
34224
|
-
const entry = await
|
|
34843
|
+
const entry = await lstat10(path).catch(() => null);
|
|
34225
34844
|
if (!entry) throw new Error(`${label} does not exist`);
|
|
34226
34845
|
if (entry.isSymbolicLink()) throw new Error(`${label} must not be a symbolic link`);
|
|
34227
34846
|
if (!entry.isDirectory()) throw new Error(`${label} must be a directory`);
|
|
@@ -34237,7 +34856,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
34237
34856
|
const prefixArgs = opts.commandPrefixArgs ?? [];
|
|
34238
34857
|
const maxWallTimeMs = opts.maxWallTimeMs;
|
|
34239
34858
|
const workspaceRoot = opts.workspaceRoot ?? defaultRunnerWorkspaceRoot();
|
|
34240
|
-
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join14(
|
|
34859
|
+
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join14(dirname7(workspaceRoot), "run-artifacts"));
|
|
34241
34860
|
const runRegistryRoot2 = opts.runRegistryRoot ?? defaultRunRegistryRoot();
|
|
34242
34861
|
const createArtifacts = opts.createArtifacts ?? createRunArtifacts;
|
|
34243
34862
|
const toolPackRegistry2 = opts.toolPackRegistry ?? createDefaultToolPackRegistry();
|
|
@@ -34281,7 +34900,12 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
34281
34900
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
34282
34901
|
});
|
|
34283
34902
|
if (task.cancelledNow()) return cancelledBeforeRun();
|
|
34284
|
-
const
|
|
34903
|
+
const configuredRunner = task.spec.runner ?? {
|
|
34904
|
+
type: "claude-code",
|
|
34905
|
+
auth: "machine"
|
|
34906
|
+
};
|
|
34907
|
+
const runner = { ...configuredRunner };
|
|
34908
|
+
if (runner.model === "default") delete runner.model;
|
|
34285
34909
|
if (runner.type !== adapter.type) {
|
|
34286
34910
|
return {
|
|
34287
34911
|
outcome: "failed",
|
|
@@ -34393,7 +35017,13 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
34393
35017
|
)
|
|
34394
35018
|
);
|
|
34395
35019
|
}
|
|
34396
|
-
|
|
35020
|
+
const browserAvailable = opts.browserAvailable ? await opts.browserAvailable() : true;
|
|
35021
|
+
if (task.spec.requiresBrowser && (!opts.browserManager || !browserAvailable)) {
|
|
35022
|
+
throw new Error(
|
|
35023
|
+
"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."
|
|
35024
|
+
);
|
|
35025
|
+
}
|
|
35026
|
+
if (task.spec.requiresBrowser && opts.browserManager && browserAvailable) {
|
|
34397
35027
|
toolPacks.push(
|
|
34398
35028
|
createBrowserToolPack({
|
|
34399
35029
|
manager: opts.browserManager,
|
|
@@ -34564,8 +35194,8 @@ ${attachmentSection}` : prompt;
|
|
|
34564
35194
|
let changed = false;
|
|
34565
35195
|
for (const path of paths) {
|
|
34566
35196
|
if (!path || path.length > 4096) continue;
|
|
34567
|
-
const absolutePath = isAbsolute13(path) ? path :
|
|
34568
|
-
const directory =
|
|
35197
|
+
const absolutePath = isAbsolute13(path) ? path : resolve8(cwd, path);
|
|
35198
|
+
const directory = dirname7(absolutePath);
|
|
34569
35199
|
observedWorkingDirectories.delete(directory);
|
|
34570
35200
|
observedWorkingDirectories.add(directory);
|
|
34571
35201
|
while (observedWorkingDirectories.size > 19) {
|
|
@@ -34987,7 +35617,7 @@ function runCliProcess(options) {
|
|
|
34987
35617
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
34988
35618
|
});
|
|
34989
35619
|
}
|
|
34990
|
-
return new Promise((
|
|
35620
|
+
return new Promise((resolve15) => {
|
|
34991
35621
|
const platform = options.platform ?? process.platform;
|
|
34992
35622
|
const containmentGateNonce = options.guardian && platform === "win32" ? randomUUID10() : void 0;
|
|
34993
35623
|
const child = options.guardian ? spawn8(
|
|
@@ -35001,7 +35631,7 @@ function runCliProcess(options) {
|
|
|
35001
35631
|
// The idle pre-assignment guardian must never load from or depend
|
|
35002
35632
|
// on an untrusted Task checkout. Only the post-gate target enters
|
|
35003
35633
|
// the requested working directory from its private release frame.
|
|
35004
|
-
cwd:
|
|
35634
|
+
cwd: dirname7(options.guardian.scriptPath),
|
|
35005
35635
|
env: runnerGuardianEnv(process.env, containmentGateNonce),
|
|
35006
35636
|
stdio: ["pipe", "pipe", "pipe"],
|
|
35007
35637
|
windowsHide: true,
|
|
@@ -35048,7 +35678,7 @@ function runCliProcess(options) {
|
|
|
35048
35678
|
clearInterval(timer);
|
|
35049
35679
|
unregisterFollowUps?.();
|
|
35050
35680
|
parser.stop?.();
|
|
35051
|
-
|
|
35681
|
+
resolve15(result);
|
|
35052
35682
|
};
|
|
35053
35683
|
const terminate = (result) => {
|
|
35054
35684
|
if (settled || forcedResult) return;
|
|
@@ -35279,7 +35909,7 @@ function runCliProcess(options) {
|
|
|
35279
35909
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
35280
35910
|
|
|
35281
35911
|
// src/runners/runtime-observation.ts
|
|
35282
|
-
import { open as
|
|
35912
|
+
import { open as open6, readdir as readdir4, realpath as realpath8 } from "node:fs/promises";
|
|
35283
35913
|
import { homedir as homedir5 } from "node:os";
|
|
35284
35914
|
import { join as join15 } from "node:path";
|
|
35285
35915
|
var READ_WINDOW_BYTES = 1024 * 1024;
|
|
@@ -35291,7 +35921,7 @@ function homeFrom(env) {
|
|
|
35291
35921
|
async function readHead(path) {
|
|
35292
35922
|
let handle;
|
|
35293
35923
|
try {
|
|
35294
|
-
handle = await
|
|
35924
|
+
handle = await open6(path, "r");
|
|
35295
35925
|
const buffer = Buffer.alloc(READ_WINDOW_BYTES);
|
|
35296
35926
|
const { bytesRead } = await handle.read(buffer, 0, READ_WINDOW_BYTES, 0);
|
|
35297
35927
|
return buffer.subarray(0, bytesRead).toString("utf8");
|
|
@@ -35305,7 +35935,7 @@ async function readHead(path) {
|
|
|
35305
35935
|
async function readTail(path) {
|
|
35306
35936
|
let handle;
|
|
35307
35937
|
try {
|
|
35308
|
-
handle = await
|
|
35938
|
+
handle = await open6(path, "r");
|
|
35309
35939
|
const { size } = await handle.stat();
|
|
35310
35940
|
const start = Math.max(0, size - READ_WINDOW_BYTES);
|
|
35311
35941
|
const length = Math.min(size, READ_WINDOW_BYTES);
|
|
@@ -35393,7 +36023,7 @@ async function readCodexSessionRuntime(input) {
|
|
|
35393
36023
|
}
|
|
35394
36024
|
var codexCatalogCache = /* @__PURE__ */ new Map();
|
|
35395
36025
|
async function loadCodexModelCatalog(command, prefixArgs, env) {
|
|
35396
|
-
const output = await new Promise((
|
|
36026
|
+
const output = await new Promise((resolve15) => {
|
|
35397
36027
|
const child = spawnCli(command, [...prefixArgs, "debug", "models"], {
|
|
35398
36028
|
stdio: ["ignore", "pipe", "ignore"],
|
|
35399
36029
|
windowsHide: true,
|
|
@@ -35408,7 +36038,7 @@ async function loadCodexModelCatalog(command, prefixArgs, env) {
|
|
|
35408
36038
|
if (settled) return;
|
|
35409
36039
|
settled = true;
|
|
35410
36040
|
clearTimeout(timer);
|
|
35411
|
-
|
|
36041
|
+
resolve15(value);
|
|
35412
36042
|
};
|
|
35413
36043
|
const timer = setTimeout(() => {
|
|
35414
36044
|
child.kill();
|
|
@@ -35513,8 +36143,8 @@ function createRuntimeReporter(input, sessionId) {
|
|
|
35513
36143
|
var EFFORT_READ_ATTEMPTS = 5;
|
|
35514
36144
|
var EFFORT_READ_INTERVAL_MS = 3e3;
|
|
35515
36145
|
function delay2(ms) {
|
|
35516
|
-
return new Promise((
|
|
35517
|
-
const timer = setTimeout(
|
|
36146
|
+
return new Promise((resolve15) => {
|
|
36147
|
+
const timer = setTimeout(resolve15, ms);
|
|
35518
36148
|
timer.unref?.();
|
|
35519
36149
|
});
|
|
35520
36150
|
}
|
|
@@ -35591,10 +36221,10 @@ function createClaudeLiveParser(onStream, onSessionModel) {
|
|
|
35591
36221
|
},
|
|
35592
36222
|
async steer(followUp) {
|
|
35593
36223
|
if (!write) return false;
|
|
35594
|
-
return await new Promise((
|
|
35595
|
-
acknowledgements.set(followUp.inputId,
|
|
36224
|
+
return await new Promise((resolve15) => {
|
|
36225
|
+
acknowledgements.set(followUp.inputId, resolve15);
|
|
35596
36226
|
void write(input(followUp.inputId, followUp.text)).catch(() => {
|
|
35597
|
-
if (acknowledgements.delete(followUp.inputId))
|
|
36227
|
+
if (acknowledgements.delete(followUp.inputId)) resolve15(false);
|
|
35598
36228
|
});
|
|
35599
36229
|
});
|
|
35600
36230
|
},
|
|
@@ -35748,13 +36378,13 @@ function improveErrorMessage(error52) {
|
|
|
35748
36378
|
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
36379
|
}
|
|
35750
36380
|
if (lower.includes("issue with the selected model") || lower.includes("model_not_found")) {
|
|
35751
|
-
return "The selected model is not available.
|
|
36381
|
+
return "The selected model is not available. Open the failed Task, choose another model or Default in its runtime controls, then Retry.";
|
|
35752
36382
|
}
|
|
35753
36383
|
return error52;
|
|
35754
36384
|
}
|
|
35755
36385
|
|
|
35756
36386
|
// src/runners/codex.ts
|
|
35757
|
-
import { mkdir as mkdir11, readFile as
|
|
36387
|
+
import { mkdir as mkdir11, readFile as readFile8, writeFile as writeFile6 } from "node:fs/promises";
|
|
35758
36388
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
35759
36389
|
import { homedir as homedir6 } from "node:os";
|
|
35760
36390
|
import { join as join16 } from "node:path";
|
|
@@ -35769,7 +36399,7 @@ function threadIndexPath(root, agentId, sessionKey) {
|
|
|
35769
36399
|
}
|
|
35770
36400
|
async function readThreadId(path) {
|
|
35771
36401
|
try {
|
|
35772
|
-
const parsed = JSON.parse(await
|
|
36402
|
+
const parsed = JSON.parse(await readFile8(path, "utf8"));
|
|
35773
36403
|
return typeof parsed.threadId === "string" && /^[A-Za-z0-9-]{1,120}$/.test(parsed.threadId) ? parsed.threadId : null;
|
|
35774
36404
|
} catch {
|
|
35775
36405
|
return null;
|
|
@@ -35901,8 +36531,8 @@ ${value}` : value;
|
|
|
35901
36531
|
var RUNTIME_READ_ATTEMPTS = 5;
|
|
35902
36532
|
var RUNTIME_READ_INTERVAL_MS = 2e3;
|
|
35903
36533
|
function delay3(ms) {
|
|
35904
|
-
return new Promise((
|
|
35905
|
-
const timer = setTimeout(
|
|
36534
|
+
return new Promise((resolve15) => {
|
|
36535
|
+
const timer = setTimeout(resolve15, ms);
|
|
35906
36536
|
timer.unref?.();
|
|
35907
36537
|
});
|
|
35908
36538
|
}
|
|
@@ -35941,7 +36571,7 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
35941
36571
|
const turnReadyWaiters = /* @__PURE__ */ new Set();
|
|
35942
36572
|
const usage = () => ({ inputTokens, outputTokens });
|
|
35943
36573
|
const settleTurnReadiness = (ready) => {
|
|
35944
|
-
for (const
|
|
36574
|
+
for (const resolve15 of turnReadyWaiters) resolve15(ready);
|
|
35945
36575
|
turnReadyWaiters.clear();
|
|
35946
36576
|
};
|
|
35947
36577
|
const send = async (message) => {
|
|
@@ -36122,12 +36752,12 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
36122
36752
|
async steer(input) {
|
|
36123
36753
|
if (stopped) return false;
|
|
36124
36754
|
if (!activeTurnId) {
|
|
36125
|
-
const ready = await new Promise((
|
|
36755
|
+
const ready = await new Promise((resolve15) => turnReadyWaiters.add(resolve15));
|
|
36126
36756
|
if (!ready || stopped) return false;
|
|
36127
36757
|
}
|
|
36128
36758
|
if (!threadId || !activeTurnId) return false;
|
|
36129
|
-
return await new Promise((
|
|
36130
|
-
steerWaiters.set(input.inputId,
|
|
36759
|
+
return await new Promise((resolve15) => {
|
|
36760
|
+
steerWaiters.set(input.inputId, resolve15);
|
|
36131
36761
|
void send({
|
|
36132
36762
|
id: `steer:${input.inputId}`,
|
|
36133
36763
|
method: "turn/steer",
|
|
@@ -36138,7 +36768,7 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
36138
36768
|
clientUserMessageId: input.inputId
|
|
36139
36769
|
}
|
|
36140
36770
|
}).catch(() => {
|
|
36141
|
-
if (steerWaiters.delete(input.inputId))
|
|
36771
|
+
if (steerWaiters.delete(input.inputId)) resolve15(false);
|
|
36142
36772
|
});
|
|
36143
36773
|
});
|
|
36144
36774
|
},
|
|
@@ -36146,7 +36776,7 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
36146
36776
|
stopped = true;
|
|
36147
36777
|
write = null;
|
|
36148
36778
|
settleTurnReadiness(false);
|
|
36149
|
-
for (const
|
|
36779
|
+
for (const resolve15 of steerWaiters.values()) resolve15(false);
|
|
36150
36780
|
steerWaiters.clear();
|
|
36151
36781
|
},
|
|
36152
36782
|
push(chunk) {
|
|
@@ -36317,7 +36947,7 @@ function improveCodexErrorMessage(error52) {
|
|
|
36317
36947
|
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
36948
|
}
|
|
36319
36949
|
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.
|
|
36950
|
+
return "The selected model is not available. Open the failed Task, choose another model or Default in its runtime controls, then Retry.";
|
|
36321
36951
|
}
|
|
36322
36952
|
return error52;
|
|
36323
36953
|
}
|
|
@@ -36325,7 +36955,7 @@ function improveCodexErrorMessage(error52) {
|
|
|
36325
36955
|
// src/runners/git-preflight.ts
|
|
36326
36956
|
import { spawn as spawn9 } from "node:child_process";
|
|
36327
36957
|
import { realpath as realpath9 } from "node:fs/promises";
|
|
36328
|
-
import { isAbsolute as isAbsolute14, resolve as
|
|
36958
|
+
import { isAbsolute as isAbsolute14, resolve as resolve9 } from "node:path";
|
|
36329
36959
|
var OUTPUT_LIMIT = 8192;
|
|
36330
36960
|
var DEFAULT_TIMEOUT_MS4 = 1e4;
|
|
36331
36961
|
var VERSION_PATTERN = /^git version [^\r\n]{1,108}$/;
|
|
@@ -36344,7 +36974,7 @@ async function preflightGit(options = {}) {
|
|
|
36344
36974
|
if (configured !== void 0 && !isAbsolute14(configured)) {
|
|
36345
36975
|
return unavailable("configured git command must be an absolute file", checkedAt);
|
|
36346
36976
|
}
|
|
36347
|
-
const trustedCwd = await realpath9(
|
|
36977
|
+
const trustedCwd = await realpath9(resolve9(options.trustedCwd ?? process.cwd())).catch(() => null);
|
|
36348
36978
|
if (!trustedCwd)
|
|
36349
36979
|
return unavailable("Host-owned git preflight directory is unavailable", checkedAt);
|
|
36350
36980
|
const executablePath = await resolveTrustedCliCommand(configured ?? "git", {
|
|
@@ -36566,7 +37196,7 @@ function parseAuth(result) {
|
|
|
36566
37196
|
return "unknown";
|
|
36567
37197
|
}
|
|
36568
37198
|
function run2(command, args) {
|
|
36569
|
-
return new Promise((
|
|
37199
|
+
return new Promise((resolve15) => {
|
|
36570
37200
|
const child = spawnCli(command, args, {
|
|
36571
37201
|
stdio: ["ignore", "pipe", "pipe"],
|
|
36572
37202
|
windowsHide: true
|
|
@@ -36582,7 +37212,7 @@ function run2(command, args) {
|
|
|
36582
37212
|
if (settled) return;
|
|
36583
37213
|
settled = true;
|
|
36584
37214
|
clearTimeout(timeout);
|
|
36585
|
-
|
|
37215
|
+
resolve15(result);
|
|
36586
37216
|
};
|
|
36587
37217
|
const timeout = setTimeout(() => {
|
|
36588
37218
|
child.kill();
|
|
@@ -36596,9 +37226,9 @@ function run2(command, args) {
|
|
|
36596
37226
|
// src/linux-service.ts
|
|
36597
37227
|
import { spawn as spawn10 } from "node:child_process";
|
|
36598
37228
|
import { constants as constants2 } from "node:fs";
|
|
36599
|
-
import { access as access4, chmod as chmod7, mkdir as mkdir12, open as
|
|
37229
|
+
import { access as access4, chmod as chmod7, mkdir as mkdir12, open as open7, rename as rename6, rm as rm8 } from "node:fs/promises";
|
|
36600
37230
|
import { homedir as homedir7, userInfo } from "node:os";
|
|
36601
|
-
import { basename as basename3, dirname as
|
|
37231
|
+
import { basename as basename3, dirname as dirname8, join as join17, relative as relative8, resolve as resolve10, sep as sep4 } from "node:path";
|
|
36602
37232
|
var SERVICE_NAME = "zixt-host.service";
|
|
36603
37233
|
var SYSTEM_SERVICE_COMMAND_TIMEOUT_MS = 7e4;
|
|
36604
37234
|
var SERVICE_STABILITY_DELAY_MS = 2e3;
|
|
@@ -36626,7 +37256,7 @@ function boundedAppend(current, chunk) {
|
|
|
36626
37256
|
}
|
|
36627
37257
|
async function defaultRunCommand(command, args) {
|
|
36628
37258
|
const commandEnvironment3 = systemServiceCommandEnvironment();
|
|
36629
|
-
return new Promise((
|
|
37259
|
+
return new Promise((resolve15) => {
|
|
36630
37260
|
const child = spawn10(command, [...args], {
|
|
36631
37261
|
stdio: ["ignore", "pipe", "pipe"],
|
|
36632
37262
|
env: commandEnvironment3,
|
|
@@ -36640,7 +37270,7 @@ async function defaultRunCommand(command, args) {
|
|
|
36640
37270
|
if (settled) return;
|
|
36641
37271
|
settled = true;
|
|
36642
37272
|
if (timer) clearTimeout(timer);
|
|
36643
|
-
|
|
37273
|
+
resolve15(result);
|
|
36644
37274
|
};
|
|
36645
37275
|
child.stdout?.on("data", (chunk) => {
|
|
36646
37276
|
stdout = boundedAppend(stdout, chunk);
|
|
@@ -36682,11 +37312,16 @@ function systemdQuotedValue(value, escapeDollar) {
|
|
|
36682
37312
|
function systemdUnitValue(value) {
|
|
36683
37313
|
return systemdQuotedValue(value, true);
|
|
36684
37314
|
}
|
|
36685
|
-
function
|
|
36686
|
-
|
|
37315
|
+
function systemdDirectivePath(value) {
|
|
37316
|
+
const path = oneLine(value, "service path");
|
|
37317
|
+
if (!path.startsWith("/")) throw new Error("service path must be absolute");
|
|
37318
|
+
return path.replace(/[%\s"'\\$]/gu, (character) => {
|
|
37319
|
+
if (character === "%") return "%%";
|
|
37320
|
+
return [...Buffer.from(character, "utf8")].map((byte) => `\\x${byte.toString(16).padStart(2, "0")}`).join("");
|
|
37321
|
+
});
|
|
36687
37322
|
}
|
|
36688
37323
|
async function defaultSyncDirectory(path) {
|
|
36689
|
-
const directory = await
|
|
37324
|
+
const directory = await open7(path, "r");
|
|
36690
37325
|
try {
|
|
36691
37326
|
await directory.sync();
|
|
36692
37327
|
} finally {
|
|
@@ -36696,9 +37331,9 @@ async function defaultSyncDirectory(path) {
|
|
|
36696
37331
|
async function ensureDirectory(path, mode, syncDirectory7) {
|
|
36697
37332
|
const firstCreated = await mkdir12(path, { recursive: true, mode });
|
|
36698
37333
|
if (!firstCreated) return;
|
|
36699
|
-
const first =
|
|
36700
|
-
const target =
|
|
36701
|
-
await syncDirectory7(
|
|
37334
|
+
const first = resolve10(firstCreated);
|
|
37335
|
+
const target = resolve10(path);
|
|
37336
|
+
await syncDirectory7(dirname8(first));
|
|
36702
37337
|
let current = first;
|
|
36703
37338
|
const descendants = relative8(first, target);
|
|
36704
37339
|
for (const part of descendants ? descendants.split(sep4) : []) {
|
|
@@ -36707,20 +37342,20 @@ async function ensureDirectory(path, mode, syncDirectory7) {
|
|
|
36707
37342
|
}
|
|
36708
37343
|
}
|
|
36709
37344
|
async function replacePrivateFile(path, contents, mode, syncDirectory7) {
|
|
36710
|
-
const parent =
|
|
37345
|
+
const parent = dirname8(path);
|
|
36711
37346
|
await ensureDirectory(parent, 448, syncDirectory7);
|
|
36712
37347
|
const temporary = join17(parent, `.${basename3(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
36713
|
-
const handle = await
|
|
37348
|
+
const handle = await open7(temporary, "wx", mode);
|
|
36714
37349
|
try {
|
|
36715
37350
|
await handle.writeFile(contents, "utf8");
|
|
36716
37351
|
await handle.sync();
|
|
36717
37352
|
await handle.close();
|
|
36718
|
-
await
|
|
37353
|
+
await rename6(temporary, path);
|
|
36719
37354
|
await chmod7(path, mode);
|
|
36720
37355
|
await syncDirectory7(parent);
|
|
36721
37356
|
} catch (error52) {
|
|
36722
37357
|
await handle.close().catch(() => void 0);
|
|
36723
|
-
await
|
|
37358
|
+
await rm8(temporary, { force: true }).catch(() => void 0);
|
|
36724
37359
|
throw error52;
|
|
36725
37360
|
}
|
|
36726
37361
|
}
|
|
@@ -36771,7 +37406,7 @@ async function installLinuxService(options) {
|
|
|
36771
37406
|
const resolveCommand = options.resolveCommand ?? defaultResolveCommand;
|
|
36772
37407
|
const run3 = options.runCommand ?? defaultRunCommand;
|
|
36773
37408
|
const syncDirectory7 = options.syncDirectory ?? defaultSyncDirectory;
|
|
36774
|
-
const stabilityDelay = options.delay ?? ((ms) => new Promise((
|
|
37409
|
+
const stabilityDelay = options.delay ?? ((ms) => new Promise((resolve15) => setTimeout(resolve15, ms)));
|
|
36775
37410
|
const [systemctl, loginctl] = await Promise.all([
|
|
36776
37411
|
resolveCommand("systemctl"),
|
|
36777
37412
|
resolveCommand("loginctl")
|
|
@@ -36818,7 +37453,7 @@ async function installLinuxService(options) {
|
|
|
36818
37453
|
// Type=exec does not report startup success until the kernel has executed
|
|
36819
37454
|
// Node, so a missing/corrupt release cannot masquerade as an active Host.
|
|
36820
37455
|
"Type=exec",
|
|
36821
|
-
`EnvironmentFile=${
|
|
37456
|
+
`EnvironmentFile=${systemdDirectivePath(environmentPath)}`,
|
|
36822
37457
|
`ExecStart=${systemdUnitValue(process.execPath)} ${systemdUnitValue(currentEntry)}`,
|
|
36823
37458
|
"Restart=on-failure",
|
|
36824
37459
|
"RestartPreventExitStatus=64",
|
|
@@ -36884,9 +37519,9 @@ async function installLinuxService(options) {
|
|
|
36884
37519
|
// src/macos-service.ts
|
|
36885
37520
|
import { spawn as spawn11 } from "node:child_process";
|
|
36886
37521
|
import { constants as constants3 } from "node:fs";
|
|
36887
|
-
import { access as access5, chmod as chmod8, mkdir as mkdir13, open as
|
|
37522
|
+
import { access as access5, chmod as chmod8, mkdir as mkdir13, open as open8, rename as rename7, rm as rm9 } from "node:fs/promises";
|
|
36888
37523
|
import { homedir as homedir8, userInfo as userInfo2 } from "node:os";
|
|
36889
|
-
import { basename as basename4, dirname as
|
|
37524
|
+
import { basename as basename4, dirname as dirname9, join as join18, relative as relative9, resolve as resolve11, sep as sep5 } from "node:path";
|
|
36890
37525
|
var LAUNCH_AGENT_LABEL = "ai.zixt.host";
|
|
36891
37526
|
var SERVICE_STABILITY_DELAY_MS2 = 2e3;
|
|
36892
37527
|
var COMMAND_TIMEOUT_MS2 = 7e4;
|
|
@@ -36902,7 +37537,7 @@ function shellValue(value) {
|
|
|
36902
37537
|
return `'${oneLine2(value, "service setting").replaceAll("'", `'"'"'`)}'`;
|
|
36903
37538
|
}
|
|
36904
37539
|
async function syncDirectory4(path) {
|
|
36905
|
-
const directory = await
|
|
37540
|
+
const directory = await open8(path, "r");
|
|
36906
37541
|
try {
|
|
36907
37542
|
await directory.sync();
|
|
36908
37543
|
} finally {
|
|
@@ -36912,9 +37547,9 @@ async function syncDirectory4(path) {
|
|
|
36912
37547
|
async function ensureDirectory2(path, sync) {
|
|
36913
37548
|
const firstCreated = await mkdir13(path, { recursive: true, mode: 448 });
|
|
36914
37549
|
if (!firstCreated) return;
|
|
36915
|
-
const first =
|
|
36916
|
-
const target =
|
|
36917
|
-
await sync(
|
|
37550
|
+
const first = resolve11(firstCreated);
|
|
37551
|
+
const target = resolve11(path);
|
|
37552
|
+
await sync(dirname9(first));
|
|
36918
37553
|
let current = first;
|
|
36919
37554
|
for (const part of relative9(first, target).split(sep5).filter(Boolean)) {
|
|
36920
37555
|
await sync(current);
|
|
@@ -36922,20 +37557,20 @@ async function ensureDirectory2(path, sync) {
|
|
|
36922
37557
|
}
|
|
36923
37558
|
}
|
|
36924
37559
|
async function replacePrivateFile2(path, contents, mode, sync) {
|
|
36925
|
-
const parent =
|
|
37560
|
+
const parent = dirname9(path);
|
|
36926
37561
|
await ensureDirectory2(parent, sync);
|
|
36927
37562
|
const temporary = join18(parent, `.${basename4(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
36928
|
-
const handle = await
|
|
37563
|
+
const handle = await open8(temporary, "wx", mode);
|
|
36929
37564
|
try {
|
|
36930
37565
|
await handle.writeFile(contents, "utf8");
|
|
36931
37566
|
await handle.sync();
|
|
36932
37567
|
await handle.close();
|
|
36933
|
-
await
|
|
37568
|
+
await rename7(temporary, path);
|
|
36934
37569
|
await chmod8(path, mode);
|
|
36935
37570
|
await sync(parent);
|
|
36936
37571
|
} catch (error52) {
|
|
36937
37572
|
await handle.close().catch(() => void 0);
|
|
36938
|
-
await
|
|
37573
|
+
await rm9(temporary, { force: true }).catch(() => void 0);
|
|
36939
37574
|
throw error52;
|
|
36940
37575
|
}
|
|
36941
37576
|
}
|
|
@@ -37115,9 +37750,9 @@ async function installMacosService(options) {
|
|
|
37115
37750
|
// src/windows-service.ts
|
|
37116
37751
|
import { spawn as spawn12 } from "node:child_process";
|
|
37117
37752
|
import { constants as constants4 } from "node:fs";
|
|
37118
|
-
import { access as access6, mkdir as mkdir14, open as
|
|
37753
|
+
import { access as access6, mkdir as mkdir14, open as open9, readFile as readFile9, rename as rename8, rm as rm10 } from "node:fs/promises";
|
|
37119
37754
|
import { homedir as homedir9 } from "node:os";
|
|
37120
|
-
import { basename as basename5, dirname as
|
|
37755
|
+
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
37756
|
var TASK_NAME = "Zixt Host";
|
|
37122
37757
|
var COMMAND_TIMEOUT_MS3 = 7e4;
|
|
37123
37758
|
var SERVICE_STABILITY_DELAY_MS3 = 2e3;
|
|
@@ -37135,7 +37770,7 @@ function psLiteral(value) {
|
|
|
37135
37770
|
}
|
|
37136
37771
|
async function syncDirectory5(path) {
|
|
37137
37772
|
if (process.platform === "win32") return;
|
|
37138
|
-
const directory = await
|
|
37773
|
+
const directory = await open9(path, "r");
|
|
37139
37774
|
try {
|
|
37140
37775
|
await directory.sync();
|
|
37141
37776
|
} finally {
|
|
@@ -37145,9 +37780,9 @@ async function syncDirectory5(path) {
|
|
|
37145
37780
|
async function ensureDirectory3(path, sync) {
|
|
37146
37781
|
const firstCreated = await mkdir14(path, { recursive: true, mode: 448 });
|
|
37147
37782
|
if (!firstCreated) return;
|
|
37148
|
-
const first =
|
|
37149
|
-
const target =
|
|
37150
|
-
await sync(
|
|
37783
|
+
const first = resolve12(firstCreated);
|
|
37784
|
+
const target = resolve12(path);
|
|
37785
|
+
await sync(dirname10(first));
|
|
37151
37786
|
let current = first;
|
|
37152
37787
|
for (const part of relative10(first, target).split(sep6).filter(Boolean)) {
|
|
37153
37788
|
await sync(current);
|
|
@@ -37155,19 +37790,19 @@ async function ensureDirectory3(path, sync) {
|
|
|
37155
37790
|
}
|
|
37156
37791
|
}
|
|
37157
37792
|
async function replacePrivateFile3(path, contents, sync) {
|
|
37158
|
-
const parent =
|
|
37793
|
+
const parent = dirname10(path);
|
|
37159
37794
|
await ensureDirectory3(parent, sync);
|
|
37160
37795
|
const temporary = join19(parent, `.${basename5(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
37161
|
-
const handle = await
|
|
37796
|
+
const handle = await open9(temporary, "wx", 384);
|
|
37162
37797
|
try {
|
|
37163
37798
|
await handle.writeFile(contents, "utf8");
|
|
37164
37799
|
await handle.sync();
|
|
37165
37800
|
await handle.close();
|
|
37166
|
-
await
|
|
37801
|
+
await rename8(temporary, path);
|
|
37167
37802
|
await sync(parent);
|
|
37168
37803
|
} catch (error52) {
|
|
37169
37804
|
await handle.close().catch(() => void 0);
|
|
37170
|
-
await
|
|
37805
|
+
await rm10(temporary, { force: true }).catch(() => void 0);
|
|
37171
37806
|
throw error52;
|
|
37172
37807
|
}
|
|
37173
37808
|
}
|
|
@@ -37300,7 +37935,7 @@ exit $code
|
|
|
37300
37935
|
}
|
|
37301
37936
|
async function defaultObserveStatus(path, generation) {
|
|
37302
37937
|
try {
|
|
37303
|
-
const text = (await
|
|
37938
|
+
const text = (await readFile9(path, "utf8")).replace(/^\uFEFF/, "");
|
|
37304
37939
|
const value = JSON.parse(text);
|
|
37305
37940
|
if (value.schema !== 1 || value.generation !== generation || typeof value.pid !== "number" || !Number.isSafeInteger(value.pid) || value.pid <= 0) {
|
|
37306
37941
|
return null;
|
|
@@ -37402,7 +38037,7 @@ async function installWindowsService(options) {
|
|
|
37402
38037
|
);
|
|
37403
38038
|
await replacePrivateFile3(launcherPath, launcherSource2(configPath, statusPath), sync);
|
|
37404
38039
|
await replacePrivateFile3(taskXmlPath, taskXml({ sid, powershell, launcherPath, home }), sync);
|
|
37405
|
-
await
|
|
38040
|
+
await rm10(statusPath, { force: true });
|
|
37406
38041
|
const acl = await run3(icacls, [
|
|
37407
38042
|
configRoot,
|
|
37408
38043
|
"/inheritance:r",
|
|
@@ -37454,9 +38089,9 @@ async function installSystemService(options) {
|
|
|
37454
38089
|
}
|
|
37455
38090
|
|
|
37456
38091
|
// src/terminal-outcomes.ts
|
|
37457
|
-
import { chmod as chmod9, lstat as
|
|
38092
|
+
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
38093
|
import { homedir as homedir10 } from "node:os";
|
|
37459
|
-
import { dirname as
|
|
38094
|
+
import { dirname as dirname11, join as join20, relative as relative11, resolve as resolve13, sep as sep7 } from "node:path";
|
|
37460
38095
|
var DIRECTORY_MODE5 = 448;
|
|
37461
38096
|
var FILE_MODE4 = 384;
|
|
37462
38097
|
var MAX_OUTCOME_BYTES = 4 * 1024 * 1024;
|
|
@@ -37474,7 +38109,7 @@ function outcomePath(root, hostId, taskId, epoch) {
|
|
|
37474
38109
|
}
|
|
37475
38110
|
async function syncDirectory6(root) {
|
|
37476
38111
|
if (process.platform === "win32") return;
|
|
37477
|
-
const handle = await
|
|
38112
|
+
const handle = await open10(root, "r");
|
|
37478
38113
|
try {
|
|
37479
38114
|
await handle.sync();
|
|
37480
38115
|
} finally {
|
|
@@ -37484,16 +38119,16 @@ async function syncDirectory6(root) {
|
|
|
37484
38119
|
async function requirePrivateRoot(root, sync = syncDirectory6) {
|
|
37485
38120
|
const firstCreated = await mkdir15(root, { recursive: true, mode: DIRECTORY_MODE5 });
|
|
37486
38121
|
if (firstCreated) {
|
|
37487
|
-
const first =
|
|
37488
|
-
const target =
|
|
37489
|
-
await sync(
|
|
38122
|
+
const first = resolve13(firstCreated);
|
|
38123
|
+
const target = resolve13(root);
|
|
38124
|
+
await sync(dirname11(first));
|
|
37490
38125
|
let current = first;
|
|
37491
38126
|
for (const part of relative11(first, target).split(sep7).filter(Boolean)) {
|
|
37492
38127
|
await sync(current);
|
|
37493
38128
|
current = join20(current, part);
|
|
37494
38129
|
}
|
|
37495
38130
|
}
|
|
37496
|
-
const stat3 = await
|
|
38131
|
+
const stat3 = await lstat11(root);
|
|
37497
38132
|
if (stat3.isSymbolicLink() || !stat3.isDirectory()) {
|
|
37498
38133
|
throw new Error("terminal outcome journal root is not a trusted directory");
|
|
37499
38134
|
}
|
|
@@ -37521,7 +38156,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
37521
38156
|
const destination = outcomePath(root, hostId, outcome.taskId, outcome.epoch);
|
|
37522
38157
|
try {
|
|
37523
38158
|
const existing = parseCommittedOutcome(
|
|
37524
|
-
await
|
|
38159
|
+
await readFile10(destination, { encoding: "utf8", flag: "r" }),
|
|
37525
38160
|
outcome.taskId,
|
|
37526
38161
|
outcome.epoch
|
|
37527
38162
|
);
|
|
@@ -37536,25 +38171,25 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
37536
38171
|
);
|
|
37537
38172
|
let handle;
|
|
37538
38173
|
try {
|
|
37539
|
-
handle = await
|
|
38174
|
+
handle = await open10(temporary, "wx", FILE_MODE4);
|
|
37540
38175
|
await handle.writeFile(JSON.stringify(outcome), "utf8");
|
|
37541
38176
|
await handle.sync();
|
|
37542
38177
|
await handle.close();
|
|
37543
38178
|
handle = void 0;
|
|
37544
|
-
await
|
|
38179
|
+
await rename9(temporary, destination);
|
|
37545
38180
|
await sync(scopedRoot);
|
|
37546
38181
|
await sync(root);
|
|
37547
38182
|
} finally {
|
|
37548
38183
|
await handle?.close().catch(() => {
|
|
37549
38184
|
});
|
|
37550
|
-
await
|
|
38185
|
+
await rm11(temporary, { force: true }).catch(() => {
|
|
37551
38186
|
});
|
|
37552
38187
|
}
|
|
37553
38188
|
}
|
|
37554
38189
|
async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
37555
38190
|
let rootStat;
|
|
37556
38191
|
try {
|
|
37557
|
-
rootStat = await
|
|
38192
|
+
rootStat = await lstat11(root);
|
|
37558
38193
|
} catch (error52) {
|
|
37559
38194
|
if (error52.code === "ENOENT") return [];
|
|
37560
38195
|
throw new Error("terminal outcome journal could not be observed");
|
|
@@ -37571,7 +38206,7 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
37571
38206
|
throw new Error("terminal outcome Host scope is not a trusted directory");
|
|
37572
38207
|
}
|
|
37573
38208
|
const scopedRoot = hostOutcomeRoot(root, hostEntry.name);
|
|
37574
|
-
const scopedStat = await
|
|
38209
|
+
const scopedStat = await lstat11(scopedRoot);
|
|
37575
38210
|
if (scopedStat.isSymbolicLink() || !scopedStat.isDirectory()) {
|
|
37576
38211
|
throw new Error("terminal outcome Host scope is not a trusted directory");
|
|
37577
38212
|
}
|
|
@@ -37584,12 +38219,12 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
37584
38219
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
37585
38220
|
}
|
|
37586
38221
|
const path = join20(scopedRoot, entry.name);
|
|
37587
|
-
const stat3 = await
|
|
38222
|
+
const stat3 = await lstat11(path);
|
|
37588
38223
|
if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_OUTCOME_BYTES) {
|
|
37589
38224
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
37590
38225
|
}
|
|
37591
38226
|
const outcome = parseCommittedOutcome(
|
|
37592
|
-
await
|
|
38227
|
+
await readFile10(path, "utf8"),
|
|
37593
38228
|
match[1],
|
|
37594
38229
|
Number(match[2])
|
|
37595
38230
|
);
|
|
@@ -37616,7 +38251,7 @@ async function forgetAcknowledgedTerminalOutcomes(refs, root = defaultTerminalOu
|
|
|
37616
38251
|
if (acknowledged.get(`${hostId}:${outcome.taskId}:${outcome.epoch}`) !== outcome.resultId) {
|
|
37617
38252
|
continue;
|
|
37618
38253
|
}
|
|
37619
|
-
await
|
|
38254
|
+
await rm11(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
37620
38255
|
changedHostRoots.add(hostOutcomeRoot(root, hostId));
|
|
37621
38256
|
}
|
|
37622
38257
|
for (const scopedRoot of changedHostRoots) await syncDirectory6(scopedRoot);
|
|
@@ -37628,7 +38263,7 @@ async function forgetSupersededTerminalOutcomes(hostId, taskId, epoch, root = de
|
|
|
37628
38263
|
if (scoped.hostId !== hostId) continue;
|
|
37629
38264
|
const { outcome } = scoped;
|
|
37630
38265
|
if (outcome.taskId !== taskId || outcome.epoch >= epoch) continue;
|
|
37631
|
-
await
|
|
38266
|
+
await rm11(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
37632
38267
|
removed = true;
|
|
37633
38268
|
}
|
|
37634
38269
|
if (removed) await syncDirectory6(hostOutcomeRoot(root, hostId));
|
|
@@ -37736,12 +38371,12 @@ function createHostLogger(options = {}) {
|
|
|
37736
38371
|
}
|
|
37737
38372
|
|
|
37738
38373
|
// src/demo-state.ts
|
|
37739
|
-
import { isAbsolute as isAbsolute16, join as join21, parse as parse3, resolve as
|
|
38374
|
+
import { isAbsolute as isAbsolute16, join as join21, parse as parse3, resolve as resolve14 } from "node:path";
|
|
37740
38375
|
var DEMO_STATE_ROOT_ENV = "ZIXT_DEMO_STATE_ROOT";
|
|
37741
38376
|
function resolveDemoHostStatePaths(env = process.env) {
|
|
37742
38377
|
const configured = env.ZIXT_RUNNER === "demo" ? env[DEMO_STATE_ROOT_ENV] : void 0;
|
|
37743
38378
|
if (!configured) return null;
|
|
37744
|
-
const root =
|
|
38379
|
+
const root = resolve14(configured);
|
|
37745
38380
|
if (!isAbsolute16(configured) || root === parse3(root).root) {
|
|
37746
38381
|
throw new Error(`${DEMO_STATE_ROOT_ENV} must be a dedicated absolute directory`);
|
|
37747
38382
|
}
|
|
@@ -38063,6 +38698,7 @@ var claudeCode = createClaudeCodeRunner({
|
|
|
38063
38698
|
...runRegistryRoot ? { runRegistryRoot } : {},
|
|
38064
38699
|
toolPackRegistry,
|
|
38065
38700
|
browserManager,
|
|
38701
|
+
browserAvailable: async () => (await currentBrowserCapability()).status === "ok",
|
|
38066
38702
|
gitPreflight: currentGitPreflight,
|
|
38067
38703
|
onUnsafeRunnerCleanup: restartAfterUnsafeRunnerCleanup
|
|
38068
38704
|
});
|
|
@@ -38073,6 +38709,7 @@ var codex = createCodexRunner({
|
|
|
38073
38709
|
...codexThreadIndexRoot ? { threadIndexRoot: codexThreadIndexRoot } : {},
|
|
38074
38710
|
toolPackRegistry,
|
|
38075
38711
|
browserManager,
|
|
38712
|
+
browserAvailable: async () => (await currentBrowserCapability()).status === "ok",
|
|
38076
38713
|
gitPreflight: currentGitPreflight,
|
|
38077
38714
|
onUnsafeRunnerCleanup: restartAfterUnsafeRunnerCleanup
|
|
38078
38715
|
});
|