@parall/daemon 1.50.0 → 1.50.1
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/bundle/manifest.json +11 -11
- package/bundle/parall-browser-pod.js +267 -104
- package/bundle/parall-claude-agent.js +25 -18
- package/bundle/parall-codex-agent.js +25 -18
- package/bundle/parall-daemon.js +317 -184
- package/dist/browser-pod.d.ts.map +1 -1
- package/dist/browser-pod.js +9 -14
- package/dist/browser-profile-viewer-control.d.ts +15 -0
- package/dist/browser-profile-viewer-control.d.ts.map +1 -0
- package/dist/browser-profile-viewer-control.js +27 -0
- package/dist/clip-runtime/bb-viewer-command-client.d.ts +19 -0
- package/dist/clip-runtime/bb-viewer-command-client.d.ts.map +1 -0
- package/dist/clip-runtime/bb-viewer-command-client.js +89 -0
- package/dist/clip-runtime/browser-profile-manager.d.ts +3 -1
- package/dist/clip-runtime/browser-profile-manager.d.ts.map +1 -1
- package/dist/clip-runtime/browser-profile-manager.js +2 -2
- package/dist/clip-runtime/browser-viewer-streamer.d.ts +7 -7
- package/dist/clip-runtime/browser-viewer-streamer.d.ts.map +1 -1
- package/dist/clip-runtime/browser-viewer-streamer.js +39 -47
- package/dist/clip-runtime/clip-provider.d.ts +3 -2
- package/dist/clip-runtime/clip-provider.d.ts.map +1 -1
- package/dist/clip-runtime/clip-provider.js +13 -6
- package/dist/clip-runtime/hosted-viewer-command-queue.d.ts +43 -0
- package/dist/clip-runtime/hosted-viewer-command-queue.d.ts.map +1 -0
- package/dist/clip-runtime/hosted-viewer-command-queue.js +72 -0
- package/dist/clip-runtime/index.d.ts +1 -0
- package/dist/clip-runtime/index.d.ts.map +1 -1
- package/dist/clip-runtime/index.js +1 -0
- package/dist/clip-runtime/viewer-command-deadline.d.ts +14 -0
- package/dist/clip-runtime/viewer-command-deadline.d.ts.map +1 -0
- package/dist/clip-runtime/viewer-command-deadline.js +29 -0
- package/dist/clip-runtime/viewer-command-error.d.ts +18 -0
- package/dist/clip-runtime/viewer-command-error.d.ts.map +1 -0
- package/dist/clip-runtime/viewer-command-error.js +23 -0
- package/dist/supervisor.d.ts +0 -8
- package/dist/supervisor.d.ts.map +1 -1
- package/dist/supervisor.js +3 -32
- package/package.json +6 -6
package/bundle/parall-daemon.js
CHANGED
|
@@ -123,10 +123,20 @@ var init_lane_key = __esm({
|
|
|
123
123
|
}
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
-
// ts/sdk/dist/
|
|
127
|
-
|
|
128
|
-
"
|
|
126
|
+
// ts/sdk/dist/browser-viewer.js
|
|
127
|
+
function browserViewerRequestOptions(command, opts) {
|
|
128
|
+
if (command !== "stream.answer" && command !== "stream.switch")
|
|
129
|
+
return opts;
|
|
130
|
+
return {
|
|
131
|
+
...opts,
|
|
132
|
+
timeoutMs: Math.max(opts?.timeoutMs ?? 0, BROWSER_VIEWER_READINESS_TIMEOUT_MS)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
var BROWSER_VIEWER_READINESS_TIMEOUT_MS;
|
|
136
|
+
var init_browser_viewer = __esm({
|
|
137
|
+
"ts/sdk/dist/browser-viewer.js"() {
|
|
129
138
|
"use strict";
|
|
139
|
+
BROWSER_VIEWER_READINESS_TIMEOUT_MS = 6e4;
|
|
130
140
|
}
|
|
131
141
|
});
|
|
132
142
|
|
|
@@ -655,6 +665,7 @@ var ParallClient, ApiError;
|
|
|
655
665
|
var init_client = __esm({
|
|
656
666
|
"ts/sdk/dist/client.js"() {
|
|
657
667
|
"use strict";
|
|
668
|
+
init_browser_viewer();
|
|
658
669
|
init_constants();
|
|
659
670
|
ParallClient = class _ParallClient {
|
|
660
671
|
baseUrl;
|
|
@@ -1607,11 +1618,7 @@ var init_client = __esm({
|
|
|
1607
1618
|
async postBrowseResponse(requestId, response) {
|
|
1608
1619
|
return this.request("POST", ENDPOINTS.MACHINES_ME_BROWSE_RESPONSE(requestId), response);
|
|
1609
1620
|
}
|
|
1610
|
-
/**
|
|
1611
|
-
* `POST /machines/me/browser-profiles/viewer-response/{requestId}` — daemon
|
|
1612
|
-
* reply to a `machine.browser_profile.viewer` control command. Wakes the
|
|
1613
|
-
* api-server request/reply bridge (mirrors {@link postBrowseResponse}).
|
|
1614
|
-
*/
|
|
1621
|
+
/** Reply to `machine.browser_profile.viewer` and wake its request/reply bridge. */
|
|
1615
1622
|
async postBrowserProfileViewerResponse(requestId, response) {
|
|
1616
1623
|
return this.request("POST", ENDPOINTS.MACHINES_ME_BROWSER_PROFILE_VIEWER_RESPONSE(requestId), response);
|
|
1617
1624
|
}
|
|
@@ -1621,7 +1628,7 @@ var init_client = __esm({
|
|
|
1621
1628
|
* owner or org admin. api-server brokers the command to the host daemon.
|
|
1622
1629
|
*/
|
|
1623
1630
|
async browserViewerCommand(orgId, profileId, req, opts) {
|
|
1624
|
-
return this.request("POST", ENDPOINTS.BROWSER_PROFILE_VIEWER_COMMAND(orgId, profileId), req, void 0, false, opts);
|
|
1631
|
+
return this.request("POST", ENDPOINTS.BROWSER_PROFILE_VIEWER_COMMAND(orgId, profileId), req, void 0, false, browserViewerRequestOptions(req.command, opts));
|
|
1625
1632
|
}
|
|
1626
1633
|
/**
|
|
1627
1634
|
* Drive the Cloud Edge live viewer (V1b, design §6): WebRTC signaling + input +
|
|
@@ -2770,6 +2777,13 @@ var init_client = __esm({
|
|
|
2770
2777
|
}
|
|
2771
2778
|
});
|
|
2772
2779
|
|
|
2780
|
+
// ts/sdk/dist/types.js
|
|
2781
|
+
var init_types2 = __esm({
|
|
2782
|
+
"ts/sdk/dist/types.js"() {
|
|
2783
|
+
"use strict";
|
|
2784
|
+
}
|
|
2785
|
+
});
|
|
2786
|
+
|
|
2773
2787
|
// ts/sdk/dist/ws.js
|
|
2774
2788
|
function isRetryableNetworkError(err) {
|
|
2775
2789
|
return err instanceof Error && err.name === "ApiError" && "status" in err && err.status === 0;
|
|
@@ -3114,9 +3128,10 @@ var init_ws = __esm({
|
|
|
3114
3128
|
var init_dist = __esm({
|
|
3115
3129
|
"ts/sdk/dist/index.js"() {
|
|
3116
3130
|
"use strict";
|
|
3117
|
-
|
|
3118
|
-
init_constants();
|
|
3131
|
+
init_browser_viewer();
|
|
3119
3132
|
init_client();
|
|
3133
|
+
init_constants();
|
|
3134
|
+
init_types2();
|
|
3120
3135
|
init_ws();
|
|
3121
3136
|
}
|
|
3122
3137
|
});
|
|
@@ -56255,6 +56270,147 @@ var init_cli = __esm({
|
|
|
56255
56270
|
}
|
|
56256
56271
|
});
|
|
56257
56272
|
|
|
56273
|
+
// ts/daemon/dist/browser-profile-reconcile.js
|
|
56274
|
+
async function reconcileBrowserProfiles(ctx) {
|
|
56275
|
+
const pool = ctx.pool;
|
|
56276
|
+
const activeBeforeList = new Set(pool.activeProfileIds());
|
|
56277
|
+
const pendingReviveBeforeList = ctx.pendingReviveIds();
|
|
56278
|
+
const localStateBeforeList = new Set(pool.localStateProfileIds());
|
|
56279
|
+
let profiles;
|
|
56280
|
+
try {
|
|
56281
|
+
profiles = await ctx.client.listMachineBrowserProfiles();
|
|
56282
|
+
} catch (err) {
|
|
56283
|
+
ctx.log.warn(`browser profile reconcile: list failed: ${String(err)}`);
|
|
56284
|
+
return;
|
|
56285
|
+
}
|
|
56286
|
+
if (ctx.currentPool() !== pool)
|
|
56287
|
+
return;
|
|
56288
|
+
const desiredLive = /* @__PURE__ */ new Set();
|
|
56289
|
+
const serverIds = /* @__PURE__ */ new Set();
|
|
56290
|
+
const serverResetGen = /* @__PURE__ */ new Map();
|
|
56291
|
+
const ops = [];
|
|
56292
|
+
const missedResetGen = (profileId) => {
|
|
56293
|
+
const gen = serverResetGen.get(profileId) ?? 0;
|
|
56294
|
+
return gen > pool.appliedResetGeneration(profileId) ? gen : null;
|
|
56295
|
+
};
|
|
56296
|
+
const enqueueResetWipeIfMissed = (profileId) => {
|
|
56297
|
+
const gen = missedResetGen(profileId);
|
|
56298
|
+
if (gen === null)
|
|
56299
|
+
return false;
|
|
56300
|
+
pool.fence(profileId);
|
|
56301
|
+
ops.push(ctx.enqueueOp(profileId, () => pool.applyResetWipe(profileId, gen)));
|
|
56302
|
+
return true;
|
|
56303
|
+
};
|
|
56304
|
+
for (const profile of profiles) {
|
|
56305
|
+
if (!profile.machine_id)
|
|
56306
|
+
continue;
|
|
56307
|
+
serverIds.add(profile.id);
|
|
56308
|
+
serverResetGen.set(profile.id, profile.reset_generation ?? 0);
|
|
56309
|
+
if (profile.status !== "running" && profile.status !== "pending")
|
|
56310
|
+
continue;
|
|
56311
|
+
desiredLive.add(profile.id);
|
|
56312
|
+
const wipeGen = missedResetGen(profile.id);
|
|
56313
|
+
if (wipeGen !== null)
|
|
56314
|
+
pool.fence(profile.id);
|
|
56315
|
+
const sinceSeq = pool.stopSeqOf(profile.id);
|
|
56316
|
+
const generation = profile.lifecycle_generation;
|
|
56317
|
+
const forceStatusReport = profile.status === "pending";
|
|
56318
|
+
ops.push(ctx.enqueueRevive(profile.id, async () => {
|
|
56319
|
+
if (wipeGen !== null)
|
|
56320
|
+
await ctx.wipeBeforeRevive(pool, profile.id, wipeGen, generation);
|
|
56321
|
+
await pool.ensureRuntime(profile.id, sinceSeq, generation, { forceStatusReport });
|
|
56322
|
+
}));
|
|
56323
|
+
}
|
|
56324
|
+
const candidates = /* @__PURE__ */ new Set([
|
|
56325
|
+
...activeBeforeList,
|
|
56326
|
+
...pendingReviveBeforeList,
|
|
56327
|
+
...localStateBeforeList
|
|
56328
|
+
]);
|
|
56329
|
+
for (const profileId of candidates) {
|
|
56330
|
+
if (desiredLive.has(profileId))
|
|
56331
|
+
continue;
|
|
56332
|
+
const isActive = activeBeforeList.has(profileId);
|
|
56333
|
+
const hasLocalState = localStateBeforeList.has(profileId);
|
|
56334
|
+
if (!isActive && !hasLocalState) {
|
|
56335
|
+
pool.fence(profileId);
|
|
56336
|
+
let cleanup;
|
|
56337
|
+
if (!serverIds.has(profileId)) {
|
|
56338
|
+
cleanup = pool.wipeAbsent(profileId);
|
|
56339
|
+
} else {
|
|
56340
|
+
const wipeGen = missedResetGen(profileId);
|
|
56341
|
+
cleanup = wipeGen !== null ? pool.applyResetWipe(profileId, wipeGen) : pool.releaseRuntime(profileId);
|
|
56342
|
+
}
|
|
56343
|
+
void cleanup.catch((err) => ctx.log.warn(`browser profile pending-revive cleanup failed for ${profileId}: ${String(err)}`));
|
|
56344
|
+
continue;
|
|
56345
|
+
}
|
|
56346
|
+
if (!serverIds.has(profileId)) {
|
|
56347
|
+
pool.fence(profileId);
|
|
56348
|
+
ops.push(ctx.enqueueOp(profileId, () => pool.wipeAbsent(profileId)));
|
|
56349
|
+
} else if (enqueueResetWipeIfMissed(profileId)) {
|
|
56350
|
+
} else if (isActive) {
|
|
56351
|
+
pool.fence(profileId);
|
|
56352
|
+
ops.push(ctx.enqueueOp(profileId, () => pool.releaseRuntime(profileId)));
|
|
56353
|
+
}
|
|
56354
|
+
}
|
|
56355
|
+
for (const result of await Promise.allSettled(ops)) {
|
|
56356
|
+
if (result.status === "rejected") {
|
|
56357
|
+
ctx.log.warn(`browser profile reconcile op failed: ${String(result.reason)}`);
|
|
56358
|
+
}
|
|
56359
|
+
}
|
|
56360
|
+
}
|
|
56361
|
+
var init_browser_profile_reconcile = __esm({
|
|
56362
|
+
"ts/daemon/dist/browser-profile-reconcile.js"() {
|
|
56363
|
+
"use strict";
|
|
56364
|
+
}
|
|
56365
|
+
});
|
|
56366
|
+
|
|
56367
|
+
// ts/daemon/dist/clip-runtime/viewer-command-error.js
|
|
56368
|
+
function viewerCommandFailure(error) {
|
|
56369
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
56370
|
+
if (error instanceof ViewerCommandError && error.code) {
|
|
56371
|
+
return { code: error.code, message };
|
|
56372
|
+
}
|
|
56373
|
+
return { message };
|
|
56374
|
+
}
|
|
56375
|
+
var ViewerCommandError;
|
|
56376
|
+
var init_viewer_command_error = __esm({
|
|
56377
|
+
"ts/daemon/dist/clip-runtime/viewer-command-error.js"() {
|
|
56378
|
+
"use strict";
|
|
56379
|
+
ViewerCommandError = class extends Error {
|
|
56380
|
+
code;
|
|
56381
|
+
constructor(message, code) {
|
|
56382
|
+
super(message);
|
|
56383
|
+
this.code = code;
|
|
56384
|
+
this.name = "ViewerCommandError";
|
|
56385
|
+
}
|
|
56386
|
+
};
|
|
56387
|
+
}
|
|
56388
|
+
});
|
|
56389
|
+
|
|
56390
|
+
// ts/daemon/dist/browser-profile-viewer-control.js
|
|
56391
|
+
async function handleBrowserProfileViewerCommand(deps, data) {
|
|
56392
|
+
if (!deps.pool) {
|
|
56393
|
+
await deps.client.postBrowserProfileViewerResponse(data.request_id, {
|
|
56394
|
+
error: { message: "Browser profile runtime is disabled on this daemon" }
|
|
56395
|
+
}).catch((err) => deps.log.warn(`browser profile viewer negative ACK failed: ${String(err)}`));
|
|
56396
|
+
return;
|
|
56397
|
+
}
|
|
56398
|
+
try {
|
|
56399
|
+
const result = await deps.pool.handleViewerCommand(data.profile_id, data.session_id, data.command, data.input, data.turn);
|
|
56400
|
+
await deps.client.postBrowserProfileViewerResponse(data.request_id, { result });
|
|
56401
|
+
} catch (err) {
|
|
56402
|
+
const failure = viewerCommandFailure(err);
|
|
56403
|
+
deps.log.warn(`browser profile viewer command failed (profile=${data.profile_id}, command=${data.command}): ${failure.message}`);
|
|
56404
|
+
await deps.client.postBrowserProfileViewerResponse(data.request_id, { error: failure }).catch((replyErr) => deps.log.warn(`browser profile viewer error ACK failed: ${String(replyErr)}`));
|
|
56405
|
+
}
|
|
56406
|
+
}
|
|
56407
|
+
var init_browser_profile_viewer_control = __esm({
|
|
56408
|
+
"ts/daemon/dist/browser-profile-viewer-control.js"() {
|
|
56409
|
+
"use strict";
|
|
56410
|
+
init_viewer_command_error();
|
|
56411
|
+
}
|
|
56412
|
+
});
|
|
56413
|
+
|
|
56258
56414
|
// ts/node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/constants.js
|
|
56259
56415
|
var require_constants9 = __commonJS({
|
|
56260
56416
|
"ts/node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/constants.js"(exports2, module2) {
|
|
@@ -62445,6 +62601,31 @@ var init_process_manager = __esm({
|
|
|
62445
62601
|
}
|
|
62446
62602
|
});
|
|
62447
62603
|
|
|
62604
|
+
// ts/daemon/dist/clip-runtime/viewer-command-deadline.js
|
|
62605
|
+
function isViewerReadinessCommand(command) {
|
|
62606
|
+
return command === "stream.answer" || command === "stream.switch";
|
|
62607
|
+
}
|
|
62608
|
+
function parseViewerDispatchDeadlineUnixMs(value) {
|
|
62609
|
+
let parsed;
|
|
62610
|
+
if (typeof value === "number") {
|
|
62611
|
+
parsed = value;
|
|
62612
|
+
} else if (typeof value === "string" && /^[1-9]\d*$/.test(value)) {
|
|
62613
|
+
parsed = Number(value);
|
|
62614
|
+
} else {
|
|
62615
|
+
return void 0;
|
|
62616
|
+
}
|
|
62617
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : void 0;
|
|
62618
|
+
}
|
|
62619
|
+
function viewerReadinessDeadlineError(phase) {
|
|
62620
|
+
return new ViewerCommandError(`viewer readiness deadline elapsed ${phase}`, "VIEWER_STREAM_CANCELLED");
|
|
62621
|
+
}
|
|
62622
|
+
var init_viewer_command_deadline = __esm({
|
|
62623
|
+
"ts/daemon/dist/clip-runtime/viewer-command-deadline.js"() {
|
|
62624
|
+
"use strict";
|
|
62625
|
+
init_viewer_command_error();
|
|
62626
|
+
}
|
|
62627
|
+
});
|
|
62628
|
+
|
|
62448
62629
|
// ts/daemon/dist/clip-runtime/clip-provider.js
|
|
62449
62630
|
import * as http23 from "node:http2";
|
|
62450
62631
|
function encodeEnvelope2(msg) {
|
|
@@ -62462,8 +62643,10 @@ var ENVELOPE_FLAG_DATA2, ENVELOPE_FLAG_TRAILER2, EnvelopeDecoder2, ClipProvider;
|
|
|
62462
62643
|
var init_clip_provider = __esm({
|
|
62463
62644
|
"ts/daemon/dist/clip-runtime/clip-provider.js"() {
|
|
62464
62645
|
"use strict";
|
|
62465
|
-
init_process();
|
|
62466
62646
|
init_browser_dependency();
|
|
62647
|
+
init_process();
|
|
62648
|
+
init_viewer_command_deadline();
|
|
62649
|
+
init_viewer_command_error();
|
|
62467
62650
|
ENVELOPE_FLAG_DATA2 = 0;
|
|
62468
62651
|
ENVELOPE_FLAG_TRAILER2 = 2;
|
|
62469
62652
|
EnvelopeDecoder2 = class _EnvelopeDecoder {
|
|
@@ -62819,8 +63002,8 @@ var init_clip_provider = __esm({
|
|
|
62819
63002
|
/**
|
|
62820
63003
|
* Handle a hosted-browser live-viewer command relayed by clip-service over the
|
|
62821
63004
|
* stream and reply on the same stream (design §3.4). Always answers the
|
|
62822
|
-
* request/reply bridge exactly once — `{result}` on success,
|
|
62823
|
-
* on failure — and never throws into the message loop, mirroring the BYOC
|
|
63005
|
+
* request/reply bridge exactly once — `{result}` on success,
|
|
63006
|
+
* `{error:{code?,message}}` on failure — and never throws into the message loop, mirroring the BYOC
|
|
62824
63007
|
* daemon's handleBrowserProfileViewer (which replies over HTTP instead).
|
|
62825
63008
|
*/
|
|
62826
63009
|
async handleViewerCommand(cmd) {
|
|
@@ -62833,6 +63016,10 @@ var init_clip_provider = __esm({
|
|
|
62833
63016
|
return;
|
|
62834
63017
|
}
|
|
62835
63018
|
try {
|
|
63019
|
+
const dispatchDeadlineUnixMs = parseViewerDispatchDeadlineUnixMs(cmd.dispatchDeadlineUnixMs);
|
|
63020
|
+
if (isViewerReadinessCommand(cmd.command) && dispatchDeadlineUnixMs === void 0) {
|
|
63021
|
+
throw viewerReadinessDeadlineError("because the ProviderStream command has no authenticated deadline");
|
|
63022
|
+
}
|
|
62836
63023
|
let input;
|
|
62837
63024
|
if (cmd.input) {
|
|
62838
63025
|
const decoded = Buffer.from(cmd.input, "base64").toString("utf-8");
|
|
@@ -62847,13 +63034,14 @@ var init_clip_provider = __esm({
|
|
|
62847
63034
|
sessionId: cmd.sessionId,
|
|
62848
63035
|
command: cmd.command,
|
|
62849
63036
|
input,
|
|
62850
|
-
turn: cmd.turn
|
|
63037
|
+
turn: cmd.turn,
|
|
63038
|
+
dispatchDeadlineUnixMs
|
|
62851
63039
|
});
|
|
62852
63040
|
await this.sendViewerReply(requestId, { result });
|
|
62853
63041
|
} catch (err) {
|
|
62854
|
-
const
|
|
62855
|
-
this.opts.log.warn(`[clip-provider] viewer command failed (profile=${cmd.profileId}, command=${cmd.command}): ${message}`);
|
|
62856
|
-
await this.sendViewerReply(requestId, { error:
|
|
63042
|
+
const failure = viewerCommandFailure(err);
|
|
63043
|
+
this.opts.log.warn(`[clip-provider] viewer command failed (profile=${cmd.profileId}, command=${cmd.command}): ${failure.message}`);
|
|
63044
|
+
await this.sendViewerReply(requestId, { error: failure }).catch(() => {
|
|
62857
63045
|
});
|
|
62858
63046
|
}
|
|
62859
63047
|
}
|
|
@@ -63234,6 +63422,80 @@ var init_browser_target_registry = __esm({
|
|
|
63234
63422
|
}
|
|
63235
63423
|
});
|
|
63236
63424
|
|
|
63425
|
+
// ts/daemon/dist/clip-runtime/bb-viewer-command-client.js
|
|
63426
|
+
function bbViewerCommandTimeoutMs(method) {
|
|
63427
|
+
return method === "answer" || method === "switch" ? BB_VIEWER_READINESS_COMMAND_TIMEOUT_MS : BB_VIEWER_COMMAND_TIMEOUT_MS;
|
|
63428
|
+
}
|
|
63429
|
+
function bbViewerCommandEffectiveTimeoutMs(method, deadlineUnixMs, now = Date.now()) {
|
|
63430
|
+
const configured = bbViewerCommandTimeoutMs(method);
|
|
63431
|
+
if (deadlineUnixMs === void 0)
|
|
63432
|
+
return configured;
|
|
63433
|
+
const remaining = deadlineUnixMs - now;
|
|
63434
|
+
if (remaining <= 0) {
|
|
63435
|
+
throw viewerReadinessDeadlineError(`before bb-viewer ${method}`);
|
|
63436
|
+
}
|
|
63437
|
+
return Math.max(1, Math.min(configured, remaining));
|
|
63438
|
+
}
|
|
63439
|
+
async function sendBBViewerCommand(port, method, params, deadlineUnixMs) {
|
|
63440
|
+
const controller = new AbortController();
|
|
63441
|
+
const timeoutMs = bbViewerCommandEffectiveTimeoutMs(method, deadlineUnixMs);
|
|
63442
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
63443
|
+
try {
|
|
63444
|
+
const resp = await fetch(`http://127.0.0.1:${port}/command`, {
|
|
63445
|
+
method: "POST",
|
|
63446
|
+
headers: { "Content-Type": "application/json" },
|
|
63447
|
+
body: JSON.stringify({ method, params }),
|
|
63448
|
+
signal: controller.signal
|
|
63449
|
+
});
|
|
63450
|
+
const text = await resp.text();
|
|
63451
|
+
return parseBBViewerCommandResponse(resp.status, text, method);
|
|
63452
|
+
} catch (err) {
|
|
63453
|
+
if (controller.signal.aborted && (method === "answer" || method === "switch")) {
|
|
63454
|
+
throw viewerReadinessDeadlineError(`while waiting for bb-viewer ${method}`);
|
|
63455
|
+
}
|
|
63456
|
+
throw err;
|
|
63457
|
+
} finally {
|
|
63458
|
+
clearTimeout(timer);
|
|
63459
|
+
}
|
|
63460
|
+
}
|
|
63461
|
+
function parseBBViewerCommandResponse(status, text, method) {
|
|
63462
|
+
let parsed;
|
|
63463
|
+
try {
|
|
63464
|
+
parsed = text ? JSON.parse(text) : {};
|
|
63465
|
+
} catch {
|
|
63466
|
+
throw new ViewerCommandError(`bb-viewer ${method} returned invalid JSON`);
|
|
63467
|
+
}
|
|
63468
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
63469
|
+
throw new ViewerCommandError(`bb-viewer ${method} returned an invalid response`);
|
|
63470
|
+
}
|
|
63471
|
+
const envelope = parsed;
|
|
63472
|
+
if (envelope.error) {
|
|
63473
|
+
const code = typeof envelope.error.code === "string" && envelope.error.code.trim() ? envelope.error.code.trim() : void 0;
|
|
63474
|
+
const message = typeof envelope.error.message === "string" && envelope.error.message.trim() ? envelope.error.message : `bb-viewer ${method} failed`;
|
|
63475
|
+
throw new ViewerCommandError(message, code);
|
|
63476
|
+
}
|
|
63477
|
+
if (status < 200 || status >= 300) {
|
|
63478
|
+
throw new ViewerCommandError(`bb-viewer ${method} returned ${status}`);
|
|
63479
|
+
}
|
|
63480
|
+
if (envelope.result === void 0 || envelope.result === null) {
|
|
63481
|
+
return {};
|
|
63482
|
+
}
|
|
63483
|
+
if (typeof envelope.result !== "object" || Array.isArray(envelope.result)) {
|
|
63484
|
+
throw new ViewerCommandError(`bb-viewer ${method} returned an invalid result`);
|
|
63485
|
+
}
|
|
63486
|
+
return envelope.result;
|
|
63487
|
+
}
|
|
63488
|
+
var BB_VIEWER_COMMAND_TIMEOUT_MS, BB_VIEWER_READINESS_COMMAND_TIMEOUT_MS;
|
|
63489
|
+
var init_bb_viewer_command_client = __esm({
|
|
63490
|
+
"ts/daemon/dist/clip-runtime/bb-viewer-command-client.js"() {
|
|
63491
|
+
"use strict";
|
|
63492
|
+
init_viewer_command_deadline();
|
|
63493
|
+
init_viewer_command_error();
|
|
63494
|
+
BB_VIEWER_COMMAND_TIMEOUT_MS = 15e3;
|
|
63495
|
+
BB_VIEWER_READINESS_COMMAND_TIMEOUT_MS = 3e4;
|
|
63496
|
+
}
|
|
63497
|
+
});
|
|
63498
|
+
|
|
63237
63499
|
// ts/daemon/dist/clip-runtime/browser-viewer-streamer.js
|
|
63238
63500
|
import { spawn as spawn3 } from "node:child_process";
|
|
63239
63501
|
function isLoopbackBindHost(host) {
|
|
@@ -63277,13 +63539,15 @@ function filterTabListToAccount(result, account) {
|
|
|
63277
63539
|
const owned = tabs.filter((t) => t?.account === account);
|
|
63278
63540
|
return { ...result, tabs: owned, activeIndex: owned.findIndex((t) => t?.active === true) };
|
|
63279
63541
|
}
|
|
63280
|
-
var BB_VIEWER_HEALTH_TIMEOUT_MS,
|
|
63542
|
+
var BB_VIEWER_HEALTH_TIMEOUT_MS, BB_VIEWER_UNANSWERED_REAP_MS, BB_VIEWER_TERM_GRACE_MS, BrowserViewerStreamer, REFLESS_PIN_NAV, VIEWER_NAVIGABLE_PROTOCOLS;
|
|
63281
63543
|
var init_browser_viewer_streamer = __esm({
|
|
63282
63544
|
"ts/daemon/dist/clip-runtime/browser-viewer-streamer.js"() {
|
|
63283
63545
|
"use strict";
|
|
63546
|
+
init_bb_viewer_command_client();
|
|
63284
63547
|
init_subprocess();
|
|
63548
|
+
init_viewer_command_deadline();
|
|
63549
|
+
init_bb_viewer_command_client();
|
|
63285
63550
|
BB_VIEWER_HEALTH_TIMEOUT_MS = 1e4;
|
|
63286
|
-
BB_VIEWER_COMMAND_TIMEOUT_MS = 15e3;
|
|
63287
63551
|
BB_VIEWER_UNANSWERED_REAP_MS = 9e4;
|
|
63288
63552
|
BB_VIEWER_TERM_GRACE_MS = 5e3;
|
|
63289
63553
|
BrowserViewerStreamer = class {
|
|
@@ -63312,7 +63576,7 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63312
63576
|
* partial result. `data.input` / `data.turn` / `data.session_id` come from
|
|
63313
63577
|
* MachineBrowserProfileViewerData.
|
|
63314
63578
|
*/
|
|
63315
|
-
async handleViewerCommand(profileId, sessionId, command, input, turn) {
|
|
63579
|
+
async handleViewerCommand(profileId, sessionId, command, input, turn, execution) {
|
|
63316
63580
|
if (!profileId)
|
|
63317
63581
|
throw new Error("browser profile id is required");
|
|
63318
63582
|
if (command !== "stream.start" && sessionId && this.kickedSessions.get(profileId) === sessionId) {
|
|
@@ -63322,11 +63586,11 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63322
63586
|
case "stream.start":
|
|
63323
63587
|
return this.viewerStreamStart(profileId, sessionId, turn);
|
|
63324
63588
|
case "stream.answer":
|
|
63325
|
-
return this.viewerStreamAnswer(profileId, sessionId, input);
|
|
63589
|
+
return this.viewerStreamAnswer(profileId, sessionId, input, execution?.deadlineUnixMs);
|
|
63326
63590
|
case "stream.close":
|
|
63327
63591
|
return this.viewerStreamClose(profileId, sessionId, input);
|
|
63328
63592
|
case "stream.switch":
|
|
63329
|
-
return this.viewerStreamSwitch(profileId, sessionId, input);
|
|
63593
|
+
return this.viewerStreamSwitch(profileId, sessionId, input, execution?.deadlineUnixMs);
|
|
63330
63594
|
case "kick":
|
|
63331
63595
|
return this.viewerKick(profileId, sessionId, input);
|
|
63332
63596
|
case "close":
|
|
@@ -63378,7 +63642,7 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63378
63642
|
await this.bringTargetToFront(cdpUrl);
|
|
63379
63643
|
const streamer = await this.spawnStreamer(profileId, sessionId, turn);
|
|
63380
63644
|
try {
|
|
63381
|
-
const result = await
|
|
63645
|
+
const result = await sendBBViewerCommand(streamer.port, "connect", { cdpUrl });
|
|
63382
63646
|
streamer.streamedTabId = targetIdFromCdpUrl(cdpUrl);
|
|
63383
63647
|
const reapTimer = setTimeout(() => {
|
|
63384
63648
|
const current = this.streamers.get(profileId);
|
|
@@ -63399,14 +63663,17 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63399
63663
|
* Rejects if the streamer's sessionId no longer matches (a stale viewer
|
|
63400
63664
|
* session from a superseded stream.start).
|
|
63401
63665
|
*/
|
|
63402
|
-
async viewerStreamAnswer(profileId, sessionId, input) {
|
|
63666
|
+
async viewerStreamAnswer(profileId, sessionId, input, deadlineUnixMs) {
|
|
63403
63667
|
const streamer = this.streamers.get(profileId);
|
|
63404
63668
|
if (!streamer)
|
|
63405
63669
|
throw new Error("no active viewer streamer for profile");
|
|
63406
63670
|
if (streamer.sessionId !== sessionId)
|
|
63407
63671
|
throw new Error("stale viewer session");
|
|
63672
|
+
this.assertViewerExecutionDeadline(deadlineUnixMs, "before bb-viewer answer");
|
|
63408
63673
|
streamer.answered = true;
|
|
63409
|
-
|
|
63674
|
+
const result = await sendBBViewerCommand(streamer.port, "answer", input ?? {}, deadlineUnixMs);
|
|
63675
|
+
this.assertViewerExecutionDeadline(deadlineUnixMs, "after bb-viewer answer");
|
|
63676
|
+
return result;
|
|
63410
63677
|
}
|
|
63411
63678
|
/**
|
|
63412
63679
|
* stream.close — best-effort stop the streamer, then kill + remove it. A
|
|
@@ -63427,7 +63694,7 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63427
63694
|
return { ok: true, stale: true };
|
|
63428
63695
|
}
|
|
63429
63696
|
try {
|
|
63430
|
-
await
|
|
63697
|
+
await sendBBViewerCommand(streamer.port, "stop", {});
|
|
63431
63698
|
} catch (err) {
|
|
63432
63699
|
this.host.log.warn(`[bb-viewer] stop command failed for ${profileId} (killing anyway): ${formatErrorForLog(err)}`);
|
|
63433
63700
|
}
|
|
@@ -63444,7 +63711,7 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63444
63711
|
* the stream.start response), so a session-less switch is by definition not
|
|
63445
63712
|
* the current viewer.
|
|
63446
63713
|
*/
|
|
63447
|
-
async viewerStreamSwitch(profileId, sessionId, input) {
|
|
63714
|
+
async viewerStreamSwitch(profileId, sessionId, input, deadlineUnixMs) {
|
|
63448
63715
|
const streamer = this.streamers.get(profileId);
|
|
63449
63716
|
if (!streamer)
|
|
63450
63717
|
throw new Error("no active viewer streamer for profile");
|
|
@@ -63454,9 +63721,13 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63454
63721
|
if (tab === void 0 || tab === null || tab === "") {
|
|
63455
63722
|
throw new Error("stream.switch requires input.tab");
|
|
63456
63723
|
}
|
|
63724
|
+
this.assertViewerExecutionDeadline(deadlineUnixMs, "before resolving the switch target");
|
|
63457
63725
|
const cdpUrl = await this.host.withDaemonRecovery(() => this.resolveAccountPageCdpUrl(profileId, tab), `viewer stream.switch ${profileId}`);
|
|
63458
|
-
|
|
63459
|
-
|
|
63726
|
+
this.assertViewerExecutionDeadline(deadlineUnixMs, "after resolving the switch target");
|
|
63727
|
+
await this.bringTargetToFront(cdpUrl, deadlineUnixMs);
|
|
63728
|
+
this.assertViewerExecutionDeadline(deadlineUnixMs, "before bb-viewer switch");
|
|
63729
|
+
const result = await sendBBViewerCommand(streamer.port, "switch", { cdpUrl }, deadlineUnixMs);
|
|
63730
|
+
this.assertViewerExecutionDeadline(deadlineUnixMs, "after bb-viewer switch");
|
|
63460
63731
|
streamer.streamedTabId = targetIdFromCdpUrl(cdpUrl);
|
|
63461
63732
|
return { ...result, streamed_tab_id: streamer.streamedTabId };
|
|
63462
63733
|
}
|
|
@@ -63480,7 +63751,7 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63480
63751
|
}
|
|
63481
63752
|
const cdpUrl = await this.host.withDaemonRecovery(() => this.resolveAccountPageCdpUrl(profileId), `viewer close re-switch ${profileId}`);
|
|
63482
63753
|
await this.bringTargetToFront(cdpUrl);
|
|
63483
|
-
const sw = await
|
|
63754
|
+
const sw = await sendBBViewerCommand(streamer.port, "switch", { cdpUrl });
|
|
63484
63755
|
streamer.streamedTabId = targetIdFromCdpUrl(cdpUrl);
|
|
63485
63756
|
return { ...result, ...sw, streamed_tab_id: streamer.streamedTabId };
|
|
63486
63757
|
}
|
|
@@ -63492,15 +63763,17 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63492
63763
|
* must not block the stream. host:port + targetId are parsed from the cdpUrl
|
|
63493
63764
|
* (`ws://host:port/devtools/page/<targetId>`) to avoid an extra /status call.
|
|
63494
63765
|
*/
|
|
63495
|
-
async bringTargetToFront(cdpUrl) {
|
|
63766
|
+
async bringTargetToFront(cdpUrl, deadlineUnixMs) {
|
|
63496
63767
|
const m = /^ws:\/\/([^/]+)\/devtools\/page\/(.+)$/.exec(cdpUrl);
|
|
63497
63768
|
if (!m)
|
|
63498
63769
|
return;
|
|
63499
63770
|
const [, hostPort, targetId] = m;
|
|
63771
|
+
this.assertViewerExecutionDeadline(deadlineUnixMs, "before foregrounding the switch target");
|
|
63772
|
+
const timeoutMs = deadlineUnixMs === void 0 ? 5e3 : Math.max(1, Math.min(5e3, deadlineUnixMs - Date.now()));
|
|
63500
63773
|
try {
|
|
63501
63774
|
const resp = await fetch(`http://${hostPort}/json/activate/${targetId}`, {
|
|
63502
63775
|
method: "GET",
|
|
63503
|
-
signal: AbortSignal.timeout(
|
|
63776
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
63504
63777
|
});
|
|
63505
63778
|
if (!resp.ok) {
|
|
63506
63779
|
this.host.log.warn(`[bb-viewer] activate target ${targetId} returned ${resp.status} (continuing)`);
|
|
@@ -63509,6 +63782,11 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63509
63782
|
this.host.log.warn(`[bb-viewer] activate target ${targetId} failed (continuing): ${formatErrorForLog(err)}`);
|
|
63510
63783
|
}
|
|
63511
63784
|
}
|
|
63785
|
+
assertViewerExecutionDeadline(deadlineUnixMs, phase) {
|
|
63786
|
+
if (deadlineUnixMs !== void 0 && Date.now() >= deadlineUnixMs) {
|
|
63787
|
+
throw viewerReadinessDeadlineError(phase);
|
|
63788
|
+
}
|
|
63789
|
+
}
|
|
63512
63790
|
/**
|
|
63513
63791
|
* Forward a navigation command (tab_list/tab_new/open/reload/back/forward/
|
|
63514
63792
|
* close) to bb-browser scoped to the profile's account. This lets the human
|
|
@@ -63709,34 +63987,6 @@ var init_browser_viewer_streamer = __esm({
|
|
|
63709
63987
|
killTimer.unref?.();
|
|
63710
63988
|
child.once("exit", () => clearTimeout(killTimer));
|
|
63711
63989
|
}
|
|
63712
|
-
/**
|
|
63713
|
-
* POST a command to the profile's bb-viewer `/command` endpoint. Parses the
|
|
63714
|
-
* `{result}` / `{error:{message}}` envelope (bb-viewer api.go) and returns
|
|
63715
|
-
* the inner result, throwing the error message on failure.
|
|
63716
|
-
*/
|
|
63717
|
-
async streamerCommand(streamer, method, params) {
|
|
63718
|
-
const controller = new AbortController();
|
|
63719
|
-
const timer = setTimeout(() => controller.abort(), BB_VIEWER_COMMAND_TIMEOUT_MS);
|
|
63720
|
-
try {
|
|
63721
|
-
const resp = await fetch(`http://127.0.0.1:${streamer.port}/command`, {
|
|
63722
|
-
method: "POST",
|
|
63723
|
-
headers: { "Content-Type": "application/json" },
|
|
63724
|
-
body: JSON.stringify({ method, params }),
|
|
63725
|
-
signal: controller.signal
|
|
63726
|
-
});
|
|
63727
|
-
const text = await resp.text();
|
|
63728
|
-
const parsed = text ? JSON.parse(text) : {};
|
|
63729
|
-
if (parsed.error) {
|
|
63730
|
-
throw new Error(parsed.error.message || `bb-viewer ${method} failed`);
|
|
63731
|
-
}
|
|
63732
|
-
if (!resp.ok) {
|
|
63733
|
-
throw new Error(`bb-viewer ${method} returned ${resp.status}: ${text}`);
|
|
63734
|
-
}
|
|
63735
|
-
return parsed.result ?? {};
|
|
63736
|
-
} finally {
|
|
63737
|
-
clearTimeout(timer);
|
|
63738
|
-
}
|
|
63739
|
-
}
|
|
63740
63990
|
/**
|
|
63741
63991
|
* Kill + remove the profile's bb-viewer streamer, if any. Idempotent. Also
|
|
63742
63992
|
* clears any kick marker for the profile: a (re)kill establishes a clean
|
|
@@ -64032,8 +64282,8 @@ var init_browser_profile_manager = __esm({
|
|
|
64032
64282
|
* (browser-viewer-streamer.ts), which owns the per-profile bb-viewer
|
|
64033
64283
|
* subprocesses and viewer tab navigation.
|
|
64034
64284
|
*/
|
|
64035
|
-
async handleViewerCommand(profileId, sessionId, command, input, turn) {
|
|
64036
|
-
return this.viewer.handleViewerCommand(profileId, sessionId, command, input, turn);
|
|
64285
|
+
async handleViewerCommand(profileId, sessionId, command, input, turn, execution) {
|
|
64286
|
+
return this.viewer.handleViewerCommand(profileId, sessionId, command, input, turn, execution);
|
|
64037
64287
|
}
|
|
64038
64288
|
/** Read cdpHost/cdpPort from the bb-browser daemon `GET /status`. */
|
|
64039
64289
|
async cdpEndpoint() {
|
|
@@ -64991,104 +65241,11 @@ var init_clip_runtime = __esm({
|
|
|
64991
65241
|
init_hub_client();
|
|
64992
65242
|
init_browser_profile_manager();
|
|
64993
65243
|
init_browser_profile_pool();
|
|
65244
|
+
init_viewer_command_error();
|
|
64994
65245
|
init_clip_installer();
|
|
64995
65246
|
}
|
|
64996
65247
|
});
|
|
64997
65248
|
|
|
64998
|
-
// ts/daemon/dist/browser-profile-reconcile.js
|
|
64999
|
-
async function reconcileBrowserProfiles(ctx) {
|
|
65000
|
-
const pool = ctx.pool;
|
|
65001
|
-
const activeBeforeList = new Set(pool.activeProfileIds());
|
|
65002
|
-
const pendingReviveBeforeList = ctx.pendingReviveIds();
|
|
65003
|
-
const localStateBeforeList = new Set(pool.localStateProfileIds());
|
|
65004
|
-
let profiles;
|
|
65005
|
-
try {
|
|
65006
|
-
profiles = await ctx.client.listMachineBrowserProfiles();
|
|
65007
|
-
} catch (err) {
|
|
65008
|
-
ctx.log.warn(`browser profile reconcile: list failed: ${String(err)}`);
|
|
65009
|
-
return;
|
|
65010
|
-
}
|
|
65011
|
-
if (ctx.currentPool() !== pool)
|
|
65012
|
-
return;
|
|
65013
|
-
const desiredLive = /* @__PURE__ */ new Set();
|
|
65014
|
-
const serverIds = /* @__PURE__ */ new Set();
|
|
65015
|
-
const serverResetGen = /* @__PURE__ */ new Map();
|
|
65016
|
-
const ops = [];
|
|
65017
|
-
const missedResetGen = (profileId) => {
|
|
65018
|
-
const gen = serverResetGen.get(profileId) ?? 0;
|
|
65019
|
-
return gen > pool.appliedResetGeneration(profileId) ? gen : null;
|
|
65020
|
-
};
|
|
65021
|
-
const enqueueResetWipeIfMissed = (profileId) => {
|
|
65022
|
-
const gen = missedResetGen(profileId);
|
|
65023
|
-
if (gen === null)
|
|
65024
|
-
return false;
|
|
65025
|
-
pool.fence(profileId);
|
|
65026
|
-
ops.push(ctx.enqueueOp(profileId, () => pool.applyResetWipe(profileId, gen)));
|
|
65027
|
-
return true;
|
|
65028
|
-
};
|
|
65029
|
-
for (const profile of profiles) {
|
|
65030
|
-
if (!profile.machine_id)
|
|
65031
|
-
continue;
|
|
65032
|
-
serverIds.add(profile.id);
|
|
65033
|
-
serverResetGen.set(profile.id, profile.reset_generation ?? 0);
|
|
65034
|
-
if (profile.status !== "running" && profile.status !== "pending")
|
|
65035
|
-
continue;
|
|
65036
|
-
desiredLive.add(profile.id);
|
|
65037
|
-
const wipeGen = missedResetGen(profile.id);
|
|
65038
|
-
if (wipeGen !== null)
|
|
65039
|
-
pool.fence(profile.id);
|
|
65040
|
-
const sinceSeq = pool.stopSeqOf(profile.id);
|
|
65041
|
-
const generation = profile.lifecycle_generation;
|
|
65042
|
-
const forceStatusReport = profile.status === "pending";
|
|
65043
|
-
ops.push(ctx.enqueueRevive(profile.id, async () => {
|
|
65044
|
-
if (wipeGen !== null)
|
|
65045
|
-
await ctx.wipeBeforeRevive(pool, profile.id, wipeGen, generation);
|
|
65046
|
-
await pool.ensureRuntime(profile.id, sinceSeq, generation, { forceStatusReport });
|
|
65047
|
-
}));
|
|
65048
|
-
}
|
|
65049
|
-
const candidates = /* @__PURE__ */ new Set([
|
|
65050
|
-
...activeBeforeList,
|
|
65051
|
-
...pendingReviveBeforeList,
|
|
65052
|
-
...localStateBeforeList
|
|
65053
|
-
]);
|
|
65054
|
-
for (const profileId of candidates) {
|
|
65055
|
-
if (desiredLive.has(profileId))
|
|
65056
|
-
continue;
|
|
65057
|
-
const isActive = activeBeforeList.has(profileId);
|
|
65058
|
-
const hasLocalState = localStateBeforeList.has(profileId);
|
|
65059
|
-
if (!isActive && !hasLocalState) {
|
|
65060
|
-
pool.fence(profileId);
|
|
65061
|
-
let cleanup;
|
|
65062
|
-
if (!serverIds.has(profileId)) {
|
|
65063
|
-
cleanup = pool.wipeAbsent(profileId);
|
|
65064
|
-
} else {
|
|
65065
|
-
const wipeGen = missedResetGen(profileId);
|
|
65066
|
-
cleanup = wipeGen !== null ? pool.applyResetWipe(profileId, wipeGen) : pool.releaseRuntime(profileId);
|
|
65067
|
-
}
|
|
65068
|
-
void cleanup.catch((err) => ctx.log.warn(`browser profile pending-revive cleanup failed for ${profileId}: ${String(err)}`));
|
|
65069
|
-
continue;
|
|
65070
|
-
}
|
|
65071
|
-
if (!serverIds.has(profileId)) {
|
|
65072
|
-
pool.fence(profileId);
|
|
65073
|
-
ops.push(ctx.enqueueOp(profileId, () => pool.wipeAbsent(profileId)));
|
|
65074
|
-
} else if (enqueueResetWipeIfMissed(profileId)) {
|
|
65075
|
-
} else if (isActive) {
|
|
65076
|
-
pool.fence(profileId);
|
|
65077
|
-
ops.push(ctx.enqueueOp(profileId, () => pool.releaseRuntime(profileId)));
|
|
65078
|
-
}
|
|
65079
|
-
}
|
|
65080
|
-
for (const result of await Promise.allSettled(ops)) {
|
|
65081
|
-
if (result.status === "rejected") {
|
|
65082
|
-
ctx.log.warn(`browser profile reconcile op failed: ${String(result.reason)}`);
|
|
65083
|
-
}
|
|
65084
|
-
}
|
|
65085
|
-
}
|
|
65086
|
-
var init_browser_profile_reconcile = __esm({
|
|
65087
|
-
"ts/daemon/dist/browser-profile-reconcile.js"() {
|
|
65088
|
-
"use strict";
|
|
65089
|
-
}
|
|
65090
|
-
});
|
|
65091
|
-
|
|
65092
65249
|
// ts/daemon/dist/filesystem.js
|
|
65093
65250
|
import * as fs9 from "fs";
|
|
65094
65251
|
import * as path16 from "path";
|
|
@@ -66444,12 +66601,13 @@ var init_supervisor = __esm({
|
|
|
66444
66601
|
"use strict";
|
|
66445
66602
|
init_dist2();
|
|
66446
66603
|
init_dist();
|
|
66604
|
+
init_browser_profile_reconcile();
|
|
66605
|
+
init_browser_profile_viewer_control();
|
|
66447
66606
|
init_browser_readiness();
|
|
66448
66607
|
init_clip_installer();
|
|
66449
66608
|
init_manifest();
|
|
66450
66609
|
init_clip_runtime();
|
|
66451
66610
|
init_config();
|
|
66452
|
-
init_browser_profile_reconcile();
|
|
66453
66611
|
init_filesystem();
|
|
66454
66612
|
init_local_profile_control();
|
|
66455
66613
|
init_home_isolation();
|
|
@@ -66693,7 +66851,7 @@ var init_supervisor = __esm({
|
|
|
66693
66851
|
});
|
|
66694
66852
|
this.ws.on("machine.browser_profile.viewer", (data) => {
|
|
66695
66853
|
this.log.info(`WS: browser profile viewer command \u2014 profile=${data.profile_id} command=${data.command}`);
|
|
66696
|
-
this.
|
|
66854
|
+
void this.enqueueBrowserProfileOp(data.profile_id, () => handleBrowserProfileViewerCommand({ pool: this.browserProfilePool, client: this.client, log: this.log }, data));
|
|
66697
66855
|
});
|
|
66698
66856
|
this.ws.onStateChange((state) => {
|
|
66699
66857
|
if (state === "disconnected" || state === "reconnecting") {
|
|
@@ -67156,31 +67314,6 @@ var init_supervisor = __esm({
|
|
|
67156
67314
|
this.browserProfilePendingRevives.set(profileId, remaining);
|
|
67157
67315
|
});
|
|
67158
67316
|
}
|
|
67159
|
-
/**
|
|
67160
|
-
* Handle one viewer control command and reply via REST. Always answers the
|
|
67161
|
-
* request/reply bridge exactly once ({result} on success, {error:{message}}
|
|
67162
|
-
* on failure) and never throws into the WS event loop — mirrors
|
|
67163
|
-
* handleFilesystemBrowse. Serialized per profile by enqueueBrowserProfileViewer.
|
|
67164
|
-
*/
|
|
67165
|
-
async handleBrowserProfileViewer(data) {
|
|
67166
|
-
if (!this.browserProfilePool) {
|
|
67167
|
-
await this.client.postBrowserProfileViewerResponse(data.request_id, {
|
|
67168
|
-
error: { message: "Browser profile runtime is disabled on this daemon" }
|
|
67169
|
-
}).catch((err) => this.log.warn(`browser profile viewer negative ACK failed: ${String(err)}`));
|
|
67170
|
-
return;
|
|
67171
|
-
}
|
|
67172
|
-
try {
|
|
67173
|
-
const result = await this.browserProfilePool.handleViewerCommand(data.profile_id, data.session_id, data.command, data.input, data.turn);
|
|
67174
|
-
await this.client.postBrowserProfileViewerResponse(data.request_id, { result });
|
|
67175
|
-
} catch (err) {
|
|
67176
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
67177
|
-
this.log.warn(`browser profile viewer command failed (profile=${data.profile_id}, command=${data.command}): ${message}`);
|
|
67178
|
-
await this.client.postBrowserProfileViewerResponse(data.request_id, { error: { message } }).catch((replyErr) => this.log.warn(`browser profile viewer error ACK failed: ${String(replyErr)}`));
|
|
67179
|
-
}
|
|
67180
|
-
}
|
|
67181
|
-
enqueueBrowserProfileViewer(data) {
|
|
67182
|
-
void this.enqueueBrowserProfileOp(data.profile_id, () => this.handleBrowserProfileViewer(data));
|
|
67183
|
-
}
|
|
67184
67317
|
async handleClipSync(_data) {
|
|
67185
67318
|
await this.reconcileMachineClips();
|
|
67186
67319
|
}
|