@openscout/scout 0.2.52 → 0.2.54
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/client/assets/{arc.es-iPbdMi1H.js → arc.es-CCzVmJbw.js} +1 -1
- package/dist/client/assets/index-CazCcdzO.css +1 -0
- package/dist/client/assets/index-D0N02a0Z.js +139 -0
- package/dist/client/index.html +2 -2
- package/dist/main.mjs +124 -0
- package/dist/pair-supervisor.mjs +122 -0
- package/dist/scout-control-plane-web.mjs +153 -82
- package/package.json +2 -2
- package/dist/client/assets/index-B0J1M8O7.css +0 -1
- package/dist/client/assets/index-DtTw9kL1.js +0 -139
package/dist/client/index.html
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&family=Spectral:wght@500;600&display=swap" rel="stylesheet" />
|
|
10
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
10
|
+
<script type="module" crossorigin src="/assets/index-D0N02a0Z.js"></script>
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CazCcdzO.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<div id="root"></div>
|
package/dist/main.mjs
CHANGED
|
@@ -4899,6 +4899,55 @@ class BaseAdapter {
|
|
|
4899
4899
|
this.emit("event", { event: "session:update", session: { ...this.session } });
|
|
4900
4900
|
}
|
|
4901
4901
|
}
|
|
4902
|
+
|
|
4903
|
+
// ../agent-sessions/src/protocol/approval-normalization.ts
|
|
4904
|
+
function defaultApprovalTitle(block) {
|
|
4905
|
+
switch (block.action.kind) {
|
|
4906
|
+
case "command":
|
|
4907
|
+
return "Approve Command";
|
|
4908
|
+
case "file_change":
|
|
4909
|
+
return "Approve File Change";
|
|
4910
|
+
case "tool_call":
|
|
4911
|
+
return "Approve Tool Call";
|
|
4912
|
+
case "subagent":
|
|
4913
|
+
return "Approve Subagent";
|
|
4914
|
+
}
|
|
4915
|
+
}
|
|
4916
|
+
function defaultApprovalDetail(block) {
|
|
4917
|
+
switch (block.action.kind) {
|
|
4918
|
+
case "command":
|
|
4919
|
+
return block.action.command?.trim() || null;
|
|
4920
|
+
case "file_change":
|
|
4921
|
+
return block.action.path?.trim() || null;
|
|
4922
|
+
case "tool_call":
|
|
4923
|
+
return block.action.toolName?.trim() || null;
|
|
4924
|
+
case "subagent":
|
|
4925
|
+
return block.action.agentName?.trim() || block.action.agentId?.trim() || null;
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
function normalizeApprovalRequest(session, turnId, block) {
|
|
4929
|
+
if (block.action.status !== "awaiting_approval" || !block.action.approval) {
|
|
4930
|
+
return null;
|
|
4931
|
+
}
|
|
4932
|
+
const title = defaultApprovalTitle(block);
|
|
4933
|
+
const detail = defaultApprovalDetail(block);
|
|
4934
|
+
const description = block.action.approval.description?.trim() || detail || title;
|
|
4935
|
+
return {
|
|
4936
|
+
sessionId: session.id,
|
|
4937
|
+
sessionName: session.name,
|
|
4938
|
+
adapterType: session.adapterType,
|
|
4939
|
+
turnId,
|
|
4940
|
+
blockId: block.id,
|
|
4941
|
+
version: block.action.approval.version,
|
|
4942
|
+
risk: block.action.approval.risk ?? "medium",
|
|
4943
|
+
title,
|
|
4944
|
+
description,
|
|
4945
|
+
detail,
|
|
4946
|
+
actionKind: block.action.kind,
|
|
4947
|
+
actionStatus: block.action.status
|
|
4948
|
+
};
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4902
4951
|
// ../agent-sessions/src/state.ts
|
|
4903
4952
|
class StateTracker {
|
|
4904
4953
|
states = new Map;
|
|
@@ -50795,6 +50844,68 @@ function getEventSessionId(event) {
|
|
|
50795
50844
|
function trackedSequencedEventId(event) {
|
|
50796
50845
|
return `${getEventSessionId(event) ?? "unknown"}:${event.seq}`;
|
|
50797
50846
|
}
|
|
50847
|
+
function approvalInboxItemId(sessionId, turnId, blockId, version2) {
|
|
50848
|
+
return `approval:${sessionId}:${turnId}:${blockId}:v${version2}`;
|
|
50849
|
+
}
|
|
50850
|
+
function projectApprovalInboxItem(snapshot, turn, block) {
|
|
50851
|
+
const normalized = normalizeApprovalRequest(snapshot.session, turn.id, block);
|
|
50852
|
+
if (!normalized) {
|
|
50853
|
+
return null;
|
|
50854
|
+
}
|
|
50855
|
+
return {
|
|
50856
|
+
id: approvalInboxItemId(normalized.sessionId, normalized.turnId, normalized.blockId, normalized.version),
|
|
50857
|
+
kind: "approval",
|
|
50858
|
+
createdAt: turn.startedAt,
|
|
50859
|
+
sessionId: normalized.sessionId,
|
|
50860
|
+
sessionName: normalized.sessionName,
|
|
50861
|
+
adapterType: normalized.adapterType,
|
|
50862
|
+
turnId: normalized.turnId,
|
|
50863
|
+
blockId: normalized.blockId,
|
|
50864
|
+
version: normalized.version,
|
|
50865
|
+
risk: normalized.risk,
|
|
50866
|
+
title: normalized.title,
|
|
50867
|
+
description: normalized.description,
|
|
50868
|
+
detail: normalized.detail,
|
|
50869
|
+
actionKind: normalized.actionKind,
|
|
50870
|
+
actionStatus: normalized.actionStatus
|
|
50871
|
+
};
|
|
50872
|
+
}
|
|
50873
|
+
function lookupMobileInboxApprovalItem(bridge, sessionId, turnId, blockId) {
|
|
50874
|
+
const snapshot = bridge.getSessionSnapshot(sessionId);
|
|
50875
|
+
if (!snapshot) {
|
|
50876
|
+
return null;
|
|
50877
|
+
}
|
|
50878
|
+
const turn = snapshot.turns.find((candidate) => candidate.id === turnId);
|
|
50879
|
+
if (!turn) {
|
|
50880
|
+
return null;
|
|
50881
|
+
}
|
|
50882
|
+
const blockState = turn.blocks.find((candidate) => candidate.block.id === blockId);
|
|
50883
|
+
if (!blockState || blockState.block.type !== "action") {
|
|
50884
|
+
return null;
|
|
50885
|
+
}
|
|
50886
|
+
return projectApprovalInboxItem(snapshot, turn, blockState.block);
|
|
50887
|
+
}
|
|
50888
|
+
function queryMobileInboxItems(bridge) {
|
|
50889
|
+
const items = [];
|
|
50890
|
+
for (const session of bridge.getSessionSummaries()) {
|
|
50891
|
+
const snapshot = bridge.getSessionSnapshot(session.sessionId);
|
|
50892
|
+
if (!snapshot) {
|
|
50893
|
+
continue;
|
|
50894
|
+
}
|
|
50895
|
+
for (const turn of snapshot.turns) {
|
|
50896
|
+
for (const blockState of turn.blocks) {
|
|
50897
|
+
if (blockState.block.type !== "action") {
|
|
50898
|
+
continue;
|
|
50899
|
+
}
|
|
50900
|
+
const item = projectApprovalInboxItem(snapshot, turn, blockState.block);
|
|
50901
|
+
if (item) {
|
|
50902
|
+
items.push(item);
|
|
50903
|
+
}
|
|
50904
|
+
}
|
|
50905
|
+
}
|
|
50906
|
+
}
|
|
50907
|
+
return items.sort((left, right) => right.createdAt - left.createdAt || left.id.localeCompare(right.id));
|
|
50908
|
+
}
|
|
50798
50909
|
function toTRPCRegistryError(error48) {
|
|
50799
50910
|
if (!isSessionRegistryError(error48)) {
|
|
50800
50911
|
return null;
|
|
@@ -50919,6 +51030,9 @@ var init_router = __esm(async () => {
|
|
|
50919
51030
|
})
|
|
50920
51031
|
});
|
|
50921
51032
|
mobileRouter = t.router({
|
|
51033
|
+
inbox: procedure.query(({ ctx }) => ({
|
|
51034
|
+
items: queryMobileInboxItems(ctx.bridge)
|
|
51035
|
+
})),
|
|
50922
51036
|
home: procedure.input(exports_external.object({
|
|
50923
51037
|
workspaceLimit: exports_external.number().optional(),
|
|
50924
51038
|
agentLimit: exports_external.number().optional(),
|
|
@@ -55576,6 +55690,16 @@ function startBridgeServerTRPC(options) {
|
|
|
55576
55690
|
state.unsub = bridge.onEvent((sequenced) => {
|
|
55577
55691
|
logBridgeEvent(sequenced.event, sequenced.seq);
|
|
55578
55692
|
sendEvent(JSON.stringify({ seq: sequenced.seq, event: sequenced.event }));
|
|
55693
|
+
if (sequenced.event.event === "block:action:approval") {
|
|
55694
|
+
const item = lookupMobileInboxApprovalItem(bridge, sequenced.event.sessionId, sequenced.event.turnId, sequenced.event.blockId);
|
|
55695
|
+
if (item) {
|
|
55696
|
+
sendEvent(JSON.stringify({
|
|
55697
|
+
event: "operator:notify",
|
|
55698
|
+
tier: "interrupt",
|
|
55699
|
+
item
|
|
55700
|
+
}));
|
|
55701
|
+
}
|
|
55702
|
+
}
|
|
55579
55703
|
});
|
|
55580
55704
|
}
|
|
55581
55705
|
const server = Bun.serve({
|
package/dist/pair-supervisor.mjs
CHANGED
|
@@ -3420,6 +3420,53 @@ class BaseAdapter {
|
|
|
3420
3420
|
this.emit("event", { event: "session:update", session: { ...this.session } });
|
|
3421
3421
|
}
|
|
3422
3422
|
}
|
|
3423
|
+
// ../agent-sessions/src/protocol/approval-normalization.ts
|
|
3424
|
+
function defaultApprovalTitle(block) {
|
|
3425
|
+
switch (block.action.kind) {
|
|
3426
|
+
case "command":
|
|
3427
|
+
return "Approve Command";
|
|
3428
|
+
case "file_change":
|
|
3429
|
+
return "Approve File Change";
|
|
3430
|
+
case "tool_call":
|
|
3431
|
+
return "Approve Tool Call";
|
|
3432
|
+
case "subagent":
|
|
3433
|
+
return "Approve Subagent";
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
function defaultApprovalDetail(block) {
|
|
3437
|
+
switch (block.action.kind) {
|
|
3438
|
+
case "command":
|
|
3439
|
+
return block.action.command?.trim() || null;
|
|
3440
|
+
case "file_change":
|
|
3441
|
+
return block.action.path?.trim() || null;
|
|
3442
|
+
case "tool_call":
|
|
3443
|
+
return block.action.toolName?.trim() || null;
|
|
3444
|
+
case "subagent":
|
|
3445
|
+
return block.action.agentName?.trim() || block.action.agentId?.trim() || null;
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
function normalizeApprovalRequest(session, turnId, block) {
|
|
3449
|
+
if (block.action.status !== "awaiting_approval" || !block.action.approval) {
|
|
3450
|
+
return null;
|
|
3451
|
+
}
|
|
3452
|
+
const title = defaultApprovalTitle(block);
|
|
3453
|
+
const detail = defaultApprovalDetail(block);
|
|
3454
|
+
const description = block.action.approval.description?.trim() || detail || title;
|
|
3455
|
+
return {
|
|
3456
|
+
sessionId: session.id,
|
|
3457
|
+
sessionName: session.name,
|
|
3458
|
+
adapterType: session.adapterType,
|
|
3459
|
+
turnId,
|
|
3460
|
+
blockId: block.id,
|
|
3461
|
+
version: block.action.approval.version,
|
|
3462
|
+
risk: block.action.approval.risk ?? "medium",
|
|
3463
|
+
title,
|
|
3464
|
+
description,
|
|
3465
|
+
detail,
|
|
3466
|
+
actionKind: block.action.kind,
|
|
3467
|
+
actionStatus: block.action.status
|
|
3468
|
+
};
|
|
3469
|
+
}
|
|
3423
3470
|
// ../agent-sessions/src/state.ts
|
|
3424
3471
|
class StateTracker {
|
|
3425
3472
|
states = new Map;
|
|
@@ -30357,6 +30404,68 @@ function getEventSessionId(event) {
|
|
|
30357
30404
|
function trackedSequencedEventId(event) {
|
|
30358
30405
|
return `${getEventSessionId(event) ?? "unknown"}:${event.seq}`;
|
|
30359
30406
|
}
|
|
30407
|
+
function approvalInboxItemId(sessionId, turnId, blockId, version2) {
|
|
30408
|
+
return `approval:${sessionId}:${turnId}:${blockId}:v${version2}`;
|
|
30409
|
+
}
|
|
30410
|
+
function projectApprovalInboxItem(snapshot, turn, block) {
|
|
30411
|
+
const normalized = normalizeApprovalRequest(snapshot.session, turn.id, block);
|
|
30412
|
+
if (!normalized) {
|
|
30413
|
+
return null;
|
|
30414
|
+
}
|
|
30415
|
+
return {
|
|
30416
|
+
id: approvalInboxItemId(normalized.sessionId, normalized.turnId, normalized.blockId, normalized.version),
|
|
30417
|
+
kind: "approval",
|
|
30418
|
+
createdAt: turn.startedAt,
|
|
30419
|
+
sessionId: normalized.sessionId,
|
|
30420
|
+
sessionName: normalized.sessionName,
|
|
30421
|
+
adapterType: normalized.adapterType,
|
|
30422
|
+
turnId: normalized.turnId,
|
|
30423
|
+
blockId: normalized.blockId,
|
|
30424
|
+
version: normalized.version,
|
|
30425
|
+
risk: normalized.risk,
|
|
30426
|
+
title: normalized.title,
|
|
30427
|
+
description: normalized.description,
|
|
30428
|
+
detail: normalized.detail,
|
|
30429
|
+
actionKind: normalized.actionKind,
|
|
30430
|
+
actionStatus: normalized.actionStatus
|
|
30431
|
+
};
|
|
30432
|
+
}
|
|
30433
|
+
function lookupMobileInboxApprovalItem(bridge, sessionId, turnId, blockId) {
|
|
30434
|
+
const snapshot = bridge.getSessionSnapshot(sessionId);
|
|
30435
|
+
if (!snapshot) {
|
|
30436
|
+
return null;
|
|
30437
|
+
}
|
|
30438
|
+
const turn = snapshot.turns.find((candidate) => candidate.id === turnId);
|
|
30439
|
+
if (!turn) {
|
|
30440
|
+
return null;
|
|
30441
|
+
}
|
|
30442
|
+
const blockState = turn.blocks.find((candidate) => candidate.block.id === blockId);
|
|
30443
|
+
if (!blockState || blockState.block.type !== "action") {
|
|
30444
|
+
return null;
|
|
30445
|
+
}
|
|
30446
|
+
return projectApprovalInboxItem(snapshot, turn, blockState.block);
|
|
30447
|
+
}
|
|
30448
|
+
function queryMobileInboxItems(bridge) {
|
|
30449
|
+
const items = [];
|
|
30450
|
+
for (const session of bridge.getSessionSummaries()) {
|
|
30451
|
+
const snapshot = bridge.getSessionSnapshot(session.sessionId);
|
|
30452
|
+
if (!snapshot) {
|
|
30453
|
+
continue;
|
|
30454
|
+
}
|
|
30455
|
+
for (const turn of snapshot.turns) {
|
|
30456
|
+
for (const blockState of turn.blocks) {
|
|
30457
|
+
if (blockState.block.type !== "action") {
|
|
30458
|
+
continue;
|
|
30459
|
+
}
|
|
30460
|
+
const item = projectApprovalInboxItem(snapshot, turn, blockState.block);
|
|
30461
|
+
if (item) {
|
|
30462
|
+
items.push(item);
|
|
30463
|
+
}
|
|
30464
|
+
}
|
|
30465
|
+
}
|
|
30466
|
+
}
|
|
30467
|
+
return items.sort((left, right) => right.createdAt - left.createdAt || left.id.localeCompare(right.id));
|
|
30468
|
+
}
|
|
30360
30469
|
function toTRPCRegistryError(error48) {
|
|
30361
30470
|
if (!isSessionRegistryError(error48)) {
|
|
30362
30471
|
return null;
|
|
@@ -30431,6 +30540,9 @@ var sessionRouter = t.router({
|
|
|
30431
30540
|
})
|
|
30432
30541
|
});
|
|
30433
30542
|
var mobileRouter = t.router({
|
|
30543
|
+
inbox: procedure.query(({ ctx }) => ({
|
|
30544
|
+
items: queryMobileInboxItems(ctx.bridge)
|
|
30545
|
+
})),
|
|
30434
30546
|
home: procedure.input(exports_external.object({
|
|
30435
30547
|
workspaceLimit: exports_external.number().optional(),
|
|
30436
30548
|
agentLimit: exports_external.number().optional(),
|
|
@@ -35006,6 +35118,16 @@ function startBridgeServerTRPC(options) {
|
|
|
35006
35118
|
state.unsub = bridge.onEvent((sequenced) => {
|
|
35007
35119
|
logBridgeEvent(sequenced.event, sequenced.seq);
|
|
35008
35120
|
sendEvent(JSON.stringify({ seq: sequenced.seq, event: sequenced.event }));
|
|
35121
|
+
if (sequenced.event.event === "block:action:approval") {
|
|
35122
|
+
const item = lookupMobileInboxApprovalItem(bridge, sequenced.event.sessionId, sequenced.event.turnId, sequenced.event.blockId);
|
|
35123
|
+
if (item) {
|
|
35124
|
+
sendEvent(JSON.stringify({
|
|
35125
|
+
event: "operator:notify",
|
|
35126
|
+
tier: "interrupt",
|
|
35127
|
+
item
|
|
35128
|
+
}));
|
|
35129
|
+
}
|
|
35130
|
+
}
|
|
35009
35131
|
});
|
|
35010
35132
|
}
|
|
35011
35133
|
const server = Bun.serve({
|
|
@@ -14,7 +14,6 @@ var __export = (target, all) => {
|
|
|
14
14
|
});
|
|
15
15
|
};
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
|
-
var __require = import.meta.require;
|
|
18
17
|
// packages/agent-sessions/src/protocol/adapter.ts
|
|
19
18
|
class BaseAdapter {
|
|
20
19
|
config;
|
|
@@ -11852,7 +11851,7 @@ var init_local_agents = __esm(async () => {
|
|
|
11852
11851
|
|
|
11853
11852
|
// packages/web/server/index.ts
|
|
11854
11853
|
import { existsSync as existsSync13 } from "fs";
|
|
11855
|
-
import { dirname as dirname12, join as join20 } from "path";
|
|
11854
|
+
import { dirname as dirname12, join as join20, resolve as resolve9 } from "path";
|
|
11856
11855
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
11857
11856
|
|
|
11858
11857
|
// packages/web/server/create-openscout-web-server.ts
|
|
@@ -14529,80 +14528,22 @@ function installScoutApiMiddleware(app, label = "api") {
|
|
|
14529
14528
|
});
|
|
14530
14529
|
}
|
|
14531
14530
|
async function registerScoutWebAssets(app, options) {
|
|
14532
|
-
|
|
14533
|
-
|
|
14534
|
-
const fs = await import("fs");
|
|
14535
|
-
const path = await import("path");
|
|
14536
|
-
const vite = await createServer({
|
|
14537
|
-
configFile: options.viteConfigPath,
|
|
14538
|
-
server: { middlewareMode: true, hmr: { port: 5183 } },
|
|
14539
|
-
appType: "custom"
|
|
14540
|
-
});
|
|
14541
|
-
const viteRoot = (vite.config.root ?? process.cwd()).replace(/\/$/, "");
|
|
14542
|
-
const proxyToVite = (req, url) => {
|
|
14543
|
-
return new Promise((resolve5) => {
|
|
14544
|
-
const http = __require("http");
|
|
14545
|
-
const { Duplex } = __require("stream");
|
|
14546
|
-
const socket = new Duplex({
|
|
14547
|
-
read() {},
|
|
14548
|
-
write(_chunk, _encoding, cb) {
|
|
14549
|
-
cb();
|
|
14550
|
-
}
|
|
14551
|
-
});
|
|
14552
|
-
const nodeReq = new http.IncomingMessage(socket);
|
|
14553
|
-
nodeReq.method = req.method;
|
|
14554
|
-
nodeReq.url = url.pathname + url.search;
|
|
14555
|
-
nodeReq.headers = {};
|
|
14556
|
-
for (const [key, value] of req.headers.entries()) {
|
|
14557
|
-
nodeReq.headers[key.toLowerCase()] = value;
|
|
14558
|
-
}
|
|
14559
|
-
const nodeRes = new http.ServerResponse(nodeReq);
|
|
14560
|
-
const chunks = [];
|
|
14561
|
-
nodeRes.write = function(chunk) {
|
|
14562
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
14563
|
-
return true;
|
|
14564
|
-
};
|
|
14565
|
-
const originalEnd = nodeRes.end.bind(nodeRes);
|
|
14566
|
-
nodeRes.end = function(chunk) {
|
|
14567
|
-
if (chunk) {
|
|
14568
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
14569
|
-
}
|
|
14570
|
-
const body = Buffer.concat(chunks);
|
|
14571
|
-
const headers = new Headers;
|
|
14572
|
-
for (const [key, val] of Object.entries(nodeRes.getHeaders())) {
|
|
14573
|
-
if (val == null)
|
|
14574
|
-
continue;
|
|
14575
|
-
if (Array.isArray(val)) {
|
|
14576
|
-
for (const v of val)
|
|
14577
|
-
headers.append(key, v);
|
|
14578
|
-
} else {
|
|
14579
|
-
headers.set(key, String(val));
|
|
14580
|
-
}
|
|
14581
|
-
}
|
|
14582
|
-
resolve5(new Response(body.length > 0 ? body : null, {
|
|
14583
|
-
status: nodeRes.statusCode,
|
|
14584
|
-
headers
|
|
14585
|
-
}));
|
|
14586
|
-
return originalEnd();
|
|
14587
|
-
};
|
|
14588
|
-
vite.middlewares.handle(nodeReq, nodeRes, async () => {
|
|
14589
|
-
try {
|
|
14590
|
-
const indexPath = path.join(viteRoot, "index.html");
|
|
14591
|
-
let html2 = fs.readFileSync(indexPath, "utf-8");
|
|
14592
|
-
html2 = await vite.transformIndexHtml(url.pathname, html2);
|
|
14593
|
-
resolve5(new Response(html2, {
|
|
14594
|
-
status: 200,
|
|
14595
|
-
headers: { "content-type": "text/html; charset=utf-8" }
|
|
14596
|
-
}));
|
|
14597
|
-
} catch {
|
|
14598
|
-
resolve5(new Response("Not Found", { status: 404 }));
|
|
14599
|
-
}
|
|
14600
|
-
});
|
|
14601
|
-
});
|
|
14602
|
-
};
|
|
14531
|
+
const viteUrl = options.viteDevUrl?.trim() || options.defaultViteUrl;
|
|
14532
|
+
if (options.assetMode === "vite-proxy") {
|
|
14603
14533
|
app.all("/*", async (c) => {
|
|
14604
|
-
const
|
|
14605
|
-
|
|
14534
|
+
const target = new URL(c.req.path, viteUrl);
|
|
14535
|
+
target.search = new URL(c.req.url).search;
|
|
14536
|
+
const headers = new Headers(c.req.header());
|
|
14537
|
+
headers.delete("host");
|
|
14538
|
+
const response = await fetch(target.toString(), {
|
|
14539
|
+
method: c.req.method,
|
|
14540
|
+
headers,
|
|
14541
|
+
body: c.req.method !== "GET" && c.req.method !== "HEAD" ? c.req.raw.body : undefined
|
|
14542
|
+
});
|
|
14543
|
+
return new Response(response.body, {
|
|
14544
|
+
status: response.status,
|
|
14545
|
+
headers: response.headers
|
|
14546
|
+
});
|
|
14606
14547
|
});
|
|
14607
14548
|
return;
|
|
14608
14549
|
}
|
|
@@ -15912,6 +15853,128 @@ function queryFleet(opts) {
|
|
|
15912
15853
|
activity
|
|
15913
15854
|
};
|
|
15914
15855
|
}
|
|
15856
|
+
var WINDOW_TIERS = [
|
|
15857
|
+
{ ms: 30 * 60000, label: "30m" },
|
|
15858
|
+
{ ms: 60 * 60000, label: "1h" },
|
|
15859
|
+
{ ms: 6 * 60 * 60000, label: "6h" },
|
|
15860
|
+
{ ms: 24 * 60 * 60000, label: "24h" },
|
|
15861
|
+
{ ms: 7 * 24 * 60 * 60000, label: "7d" }
|
|
15862
|
+
];
|
|
15863
|
+
var MIN_FILLED_BUCKETS = 3;
|
|
15864
|
+
var _sealedCounts = new Map;
|
|
15865
|
+
var _cachedTier = null;
|
|
15866
|
+
function queryHeartrate(numBuckets = 48) {
|
|
15867
|
+
const nowMs = Date.now();
|
|
15868
|
+
let chosenTier = WINDOW_TIERS[WINDOW_TIERS.length - 1];
|
|
15869
|
+
for (const tier of WINDOW_TIERS) {
|
|
15870
|
+
const bucketMs2 = tier.ms / numBuckets;
|
|
15871
|
+
const currentBucketStart2 = Math.floor(nowMs / bucketMs2) * bucketMs2;
|
|
15872
|
+
const alignedStart2 = currentBucketStart2 - (numBuckets - 1) * bucketMs2;
|
|
15873
|
+
if (_cachedTier === tier.label) {
|
|
15874
|
+
let sealedHits = 0;
|
|
15875
|
+
let filledSealed = 0;
|
|
15876
|
+
for (let i = 0;i < numBuckets - 1; i++) {
|
|
15877
|
+
const key = String(alignedStart2 + i * bucketMs2);
|
|
15878
|
+
if (_sealedCounts.has(key)) {
|
|
15879
|
+
sealedHits++;
|
|
15880
|
+
if (_sealedCounts.get(key) > 0)
|
|
15881
|
+
filledSealed++;
|
|
15882
|
+
}
|
|
15883
|
+
}
|
|
15884
|
+
if (sealedHits === numBuckets - 1 && filledSealed >= MIN_FILLED_BUCKETS) {
|
|
15885
|
+
chosenTier = tier;
|
|
15886
|
+
break;
|
|
15887
|
+
}
|
|
15888
|
+
}
|
|
15889
|
+
const rows2 = db().prepare(`SELECT ts FROM activity_items WHERE ts >= ? ORDER BY ts ASC`).all(alignedStart2);
|
|
15890
|
+
const counts2 = new Array(numBuckets).fill(0);
|
|
15891
|
+
for (const row of rows2) {
|
|
15892
|
+
const ms = row.ts < 1000000000000 ? row.ts * 1000 : row.ts;
|
|
15893
|
+
if (ms < alignedStart2)
|
|
15894
|
+
continue;
|
|
15895
|
+
const idx = Math.min(numBuckets - 1, Math.floor((ms - alignedStart2) / bucketMs2));
|
|
15896
|
+
if (idx >= 0)
|
|
15897
|
+
counts2[idx]++;
|
|
15898
|
+
}
|
|
15899
|
+
const filled = counts2.filter((c) => c > 0).length;
|
|
15900
|
+
if (filled >= MIN_FILLED_BUCKETS) {
|
|
15901
|
+
if (_cachedTier !== tier.label) {
|
|
15902
|
+
_sealedCounts.clear();
|
|
15903
|
+
_cachedTier = tier.label;
|
|
15904
|
+
}
|
|
15905
|
+
for (let i = 0;i < numBuckets - 1; i++) {
|
|
15906
|
+
_sealedCounts.set(String(alignedStart2 + i * bucketMs2), counts2[i]);
|
|
15907
|
+
}
|
|
15908
|
+
const peak2 = Math.max(1, ...counts2);
|
|
15909
|
+
return {
|
|
15910
|
+
windowLabel: tier.label,
|
|
15911
|
+
buckets: counts2.map((count, i) => ({
|
|
15912
|
+
ts: Math.round(alignedStart2 + i * bucketMs2),
|
|
15913
|
+
count,
|
|
15914
|
+
value: count / peak2
|
|
15915
|
+
}))
|
|
15916
|
+
};
|
|
15917
|
+
}
|
|
15918
|
+
}
|
|
15919
|
+
const bucketMs = chosenTier.ms / numBuckets;
|
|
15920
|
+
const currentBucketStart = Math.floor(nowMs / bucketMs) * bucketMs;
|
|
15921
|
+
const alignedStart = currentBucketStart - (numBuckets - 1) * bucketMs;
|
|
15922
|
+
if (_cachedTier === chosenTier.label) {
|
|
15923
|
+
const counts2 = new Array(numBuckets).fill(0);
|
|
15924
|
+
let allSealed = true;
|
|
15925
|
+
for (let i = 0;i < numBuckets - 1; i++) {
|
|
15926
|
+
const key = String(alignedStart + i * bucketMs);
|
|
15927
|
+
if (_sealedCounts.has(key)) {
|
|
15928
|
+
counts2[i] = _sealedCounts.get(key);
|
|
15929
|
+
} else {
|
|
15930
|
+
allSealed = false;
|
|
15931
|
+
break;
|
|
15932
|
+
}
|
|
15933
|
+
}
|
|
15934
|
+
if (allSealed) {
|
|
15935
|
+
const liveStart = alignedStart + (numBuckets - 1) * bucketMs;
|
|
15936
|
+
const row = db().prepare(`SELECT COUNT(*) AS c FROM activity_items WHERE ts >= ?`).get(liveStart);
|
|
15937
|
+
counts2[numBuckets - 1] = row.c;
|
|
15938
|
+
const peak2 = Math.max(1, ...counts2);
|
|
15939
|
+
return {
|
|
15940
|
+
windowLabel: chosenTier.label,
|
|
15941
|
+
buckets: counts2.map((count, i) => ({
|
|
15942
|
+
ts: Math.round(alignedStart + i * bucketMs),
|
|
15943
|
+
count,
|
|
15944
|
+
value: count / peak2
|
|
15945
|
+
}))
|
|
15946
|
+
};
|
|
15947
|
+
}
|
|
15948
|
+
}
|
|
15949
|
+
_sealedCounts.clear();
|
|
15950
|
+
_cachedTier = chosenTier.label;
|
|
15951
|
+
const rows = db().prepare(`SELECT ts FROM activity_items WHERE ts >= ? ORDER BY ts ASC`).all(alignedStart);
|
|
15952
|
+
const counts = new Array(numBuckets).fill(0);
|
|
15953
|
+
for (const row of rows) {
|
|
15954
|
+
const ms = row.ts < 1000000000000 ? row.ts * 1000 : row.ts;
|
|
15955
|
+
if (ms < alignedStart)
|
|
15956
|
+
continue;
|
|
15957
|
+
const idx = Math.min(numBuckets - 1, Math.floor((ms - alignedStart) / bucketMs));
|
|
15958
|
+
if (idx >= 0)
|
|
15959
|
+
counts[idx]++;
|
|
15960
|
+
}
|
|
15961
|
+
for (let i = 0;i < numBuckets - 1; i++) {
|
|
15962
|
+
_sealedCounts.set(String(alignedStart + i * bucketMs), counts[i]);
|
|
15963
|
+
}
|
|
15964
|
+
for (const key of _sealedCounts.keys()) {
|
|
15965
|
+
if (Number(key) < alignedStart)
|
|
15966
|
+
_sealedCounts.delete(key);
|
|
15967
|
+
}
|
|
15968
|
+
const peak = Math.max(1, ...counts);
|
|
15969
|
+
return {
|
|
15970
|
+
windowLabel: chosenTier.label,
|
|
15971
|
+
buckets: counts.map((count, i) => ({
|
|
15972
|
+
ts: Math.round(alignedStart + i * bucketMs),
|
|
15973
|
+
count,
|
|
15974
|
+
value: count / peak
|
|
15975
|
+
}))
|
|
15976
|
+
};
|
|
15977
|
+
}
|
|
15915
15978
|
|
|
15916
15979
|
// packages/web/server/core/broker/service.ts
|
|
15917
15980
|
init_src2();
|
|
@@ -17258,6 +17321,7 @@ async function createOpenScoutWebServer(options) {
|
|
|
17258
17321
|
app.get("/api/shell-state/refresh", async (c) => c.json(await shellStateCache.refresh()));
|
|
17259
17322
|
app.get("/api/agents", (c) => c.json(queryAgents()));
|
|
17260
17323
|
app.get("/api/activity", (c) => c.json(queryActivity()));
|
|
17324
|
+
app.get("/api/heartrate", (c) => c.json(queryHeartrate()));
|
|
17261
17325
|
app.get("/api/fleet", (c) => c.json(queryFleet({
|
|
17262
17326
|
limit: parseOptionalPositiveInt(c.req.query("limit")),
|
|
17263
17327
|
activityLimit: parseOptionalPositiveInt(c.req.query("activityLimit"))
|
|
@@ -17479,7 +17543,8 @@ async function createOpenScoutWebServer(options) {
|
|
|
17479
17543
|
await registerScoutWebAssets(app, {
|
|
17480
17544
|
assetMode: options.assetMode,
|
|
17481
17545
|
staticRoot: resolveStaticRoot(options.staticRoot),
|
|
17482
|
-
|
|
17546
|
+
viteDevUrl: options.viteDevUrl,
|
|
17547
|
+
defaultViteUrl: "http://127.0.0.1:5180"
|
|
17483
17548
|
});
|
|
17484
17549
|
const warmupCaches = () => Promise.allSettled([
|
|
17485
17550
|
shellStateCache.refresh(),
|
|
@@ -17887,19 +17952,25 @@ function resolveStaticRoot2() {
|
|
|
17887
17952
|
return process.env.OPENSCOUT_WEB_STATIC_ROOT.trim();
|
|
17888
17953
|
}
|
|
17889
17954
|
const selfDir = dirname12(fileURLToPath8(import.meta.url));
|
|
17890
|
-
const
|
|
17891
|
-
if (existsSync13(
|
|
17892
|
-
return
|
|
17955
|
+
const siblingClientRoot = join20(selfDir, "client");
|
|
17956
|
+
if (existsSync13(join20(siblingClientRoot, "index.html"))) {
|
|
17957
|
+
return siblingClientRoot;
|
|
17958
|
+
}
|
|
17959
|
+
const sourceDistClientRoot = resolve9(selfDir, "../dist/client");
|
|
17960
|
+
if (existsSync13(join20(sourceDistClientRoot, "index.html"))) {
|
|
17961
|
+
return sourceDistClientRoot;
|
|
17893
17962
|
}
|
|
17894
17963
|
return;
|
|
17895
17964
|
}
|
|
17896
17965
|
var staticRoot = resolveStaticRoot2();
|
|
17897
|
-
var
|
|
17898
|
-
var
|
|
17966
|
+
var viteDevUrl = process.env.OPENSCOUT_WEB_VITE_URL?.trim() || undefined;
|
|
17967
|
+
var useViteProxy = Boolean(viteDevUrl) || !staticRoot;
|
|
17968
|
+
var idleTimeoutSeconds = Number.parseInt(process.env.OPENSCOUT_WEB_IDLE_TIMEOUT_SECONDS?.trim() || (useViteProxy ? "180" : "30"), 10);
|
|
17899
17969
|
var { app, warmupCaches } = await createOpenScoutWebServer({
|
|
17900
17970
|
currentDirectory,
|
|
17901
17971
|
shellStateCacheTtlMs,
|
|
17902
|
-
assetMode:
|
|
17972
|
+
assetMode: useViteProxy ? "vite-proxy" : "static",
|
|
17973
|
+
viteDevUrl,
|
|
17903
17974
|
staticRoot
|
|
17904
17975
|
});
|
|
17905
17976
|
var honoFetch = app.fetch;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openscout/scout",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.54",
|
|
4
4
|
"description": "Published Scout package that installs the `scout` command",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -23,6 +23,6 @@
|
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@openscout/runtime": "0.2.
|
|
26
|
+
"@openscout/runtime": "0.2.54"
|
|
27
27
|
}
|
|
28
28
|
}
|