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