@hyperdrive.bot/fleet-server 0.3.167 → 0.3.168
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/server/server/stall-profiler.d.ts +91 -0
- package/dist/server/server/stall-profiler.js +265 -0
- package/dist/server/server/websocket-server.d.ts +2 -0
- package/dist/server/server/websocket-server.js +31 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-7ea1d05e574d152f403ceca6788d7528.js → index-e80e8b2f3ce4ebaef8f03195745588eb.js} +4 -4
- package/dist/server/web-ui/_expo/static/js/web/index-e80e8b2f3ce4ebaef8f03195745588eb.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-e80e8b2f3ce4ebaef8f03195745588eb.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-7ea1d05e574d152f403ceca6788d7528.js.map.br → index-e80e8b2f3ce4ebaef8f03195745588eb.js.map.br} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-7ea1d05e574d152f403ceca6788d7528.js.map.gz → index-e80e8b2f3ce4ebaef8f03195745588eb.js.map.gz} +0 -0
- package/dist/server/web-ui/index.html +1 -1
- package/dist/server/web-ui/index.html.br +0 -0
- package/dist/server/web-ui/index.html.gz +0 -0
- package/package.json +6 -6
- package/dist/server/web-ui/_expo/static/js/web/index-7ea1d05e574d152f403ceca6788d7528.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-7ea1d05e574d152f403ceca6788d7528.js.gz +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Logger } from "pino";
|
|
2
|
+
export interface StallProfilerOptions {
|
|
3
|
+
diagnosticsDir: string;
|
|
4
|
+
thresholdMs: number;
|
|
5
|
+
samplingIntervalUs: number;
|
|
6
|
+
maxFiles: number;
|
|
7
|
+
maxTotalBytes: number;
|
|
8
|
+
longTaskThresholdMs: number;
|
|
9
|
+
logger?: Pick<Logger, "info" | "warn">;
|
|
10
|
+
now?: () => number;
|
|
11
|
+
}
|
|
12
|
+
export interface StallProfilerEnv {
|
|
13
|
+
PASEO_STALL_PROFILE?: string;
|
|
14
|
+
PASEO_STALL_PROFILE_THRESHOLD_MS?: string;
|
|
15
|
+
PASEO_STALL_PROFILE_INTERVAL_US?: string;
|
|
16
|
+
PASEO_STALL_PROFILE_MAX_FILES?: string;
|
|
17
|
+
PASEO_STALL_PROFILE_MAX_BYTES?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const STALL_PROFILE_DEFAULTS: {
|
|
20
|
+
readonly thresholdMs: 500;
|
|
21
|
+
readonly samplingIntervalUs: 2000;
|
|
22
|
+
readonly maxFiles: 20;
|
|
23
|
+
readonly maxTotalBytes: number;
|
|
24
|
+
readonly longTaskThresholdMs: 300;
|
|
25
|
+
};
|
|
26
|
+
export interface LongTask {
|
|
27
|
+
endedAt: string;
|
|
28
|
+
blockedMs: number;
|
|
29
|
+
}
|
|
30
|
+
export interface StallSummaryFunction {
|
|
31
|
+
name: string;
|
|
32
|
+
location: string;
|
|
33
|
+
ms: number;
|
|
34
|
+
}
|
|
35
|
+
export interface StallSummary {
|
|
36
|
+
capturedAt: string;
|
|
37
|
+
maxEventLoopDelayMs: number;
|
|
38
|
+
thresholdMs: number;
|
|
39
|
+
windowStartedAt: string;
|
|
40
|
+
profileDurationMs: number;
|
|
41
|
+
sampleCount: number;
|
|
42
|
+
samplingIntervalUs: number;
|
|
43
|
+
topSelf: StallSummaryFunction[];
|
|
44
|
+
topInclusive: StallSummaryFunction[];
|
|
45
|
+
longTasks: LongTask[];
|
|
46
|
+
window: unknown;
|
|
47
|
+
}
|
|
48
|
+
interface ProfileNode {
|
|
49
|
+
id: number;
|
|
50
|
+
callFrame: {
|
|
51
|
+
functionName: string;
|
|
52
|
+
url: string;
|
|
53
|
+
lineNumber: number;
|
|
54
|
+
columnNumber: number;
|
|
55
|
+
};
|
|
56
|
+
children?: number[];
|
|
57
|
+
}
|
|
58
|
+
export interface CpuProfile {
|
|
59
|
+
nodes: ProfileNode[];
|
|
60
|
+
startTime: number;
|
|
61
|
+
endTime: number;
|
|
62
|
+
samples?: number[];
|
|
63
|
+
timeDeltas?: number[];
|
|
64
|
+
}
|
|
65
|
+
export declare function resolveStallProfilerOptions(env: StallProfilerEnv, paseoHome: string): StallProfilerOptions | null;
|
|
66
|
+
export declare function summarizeCpuProfile(profile: CpuProfile, topN?: number): {
|
|
67
|
+
topSelf: StallSummaryFunction[];
|
|
68
|
+
topInclusive: StallSummaryFunction[];
|
|
69
|
+
sampleCount: number;
|
|
70
|
+
};
|
|
71
|
+
export declare class StallProfiler {
|
|
72
|
+
private readonly options;
|
|
73
|
+
private readonly now;
|
|
74
|
+
private session;
|
|
75
|
+
private windowStartedAt;
|
|
76
|
+
private longTaskTimer;
|
|
77
|
+
private lastTick;
|
|
78
|
+
private longTasks;
|
|
79
|
+
private busy;
|
|
80
|
+
constructor(options: StallProfilerOptions);
|
|
81
|
+
start(): Promise<void>;
|
|
82
|
+
rollWindow(maxEventLoopDelayMs: number | null | undefined, window?: unknown): Promise<string | null>;
|
|
83
|
+
stop(): Promise<void>;
|
|
84
|
+
private checkDrift;
|
|
85
|
+
private post;
|
|
86
|
+
private doRoll;
|
|
87
|
+
private persist;
|
|
88
|
+
private rotate;
|
|
89
|
+
}
|
|
90
|
+
export {};
|
|
91
|
+
//# sourceMappingURL=stall-profiler.d.ts.map
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { Session } from "node:inspector";
|
|
2
|
+
import { mkdir, readdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
export const STALL_PROFILE_DEFAULTS = {
|
|
5
|
+
thresholdMs: 500,
|
|
6
|
+
// 1000us measured 0.5-6% CPU on a JSON-heavy loop (noisy, loaded box), 2000us
|
|
7
|
+
// stayed inside noise. Sampling every 2ms still resolves a 500ms stall.
|
|
8
|
+
samplingIntervalUs: 2000,
|
|
9
|
+
maxFiles: 20,
|
|
10
|
+
maxTotalBytes: 200 * 1024 * 1024,
|
|
11
|
+
longTaskThresholdMs: 300,
|
|
12
|
+
};
|
|
13
|
+
const LONG_TASK_TICK_MS = 50;
|
|
14
|
+
const MAX_LONG_TASKS_PER_WINDOW = 200;
|
|
15
|
+
const SUMMARY_TOP_N = 25;
|
|
16
|
+
function parsePositive(value, fallback) {
|
|
17
|
+
const parsed = Number(value);
|
|
18
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
19
|
+
}
|
|
20
|
+
export function resolveStallProfilerOptions(env, paseoHome) {
|
|
21
|
+
if (env.PASEO_STALL_PROFILE !== "1" && env.PASEO_STALL_PROFILE !== "true") {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
diagnosticsDir: join(paseoHome, "diagnostics"),
|
|
26
|
+
thresholdMs: parsePositive(env.PASEO_STALL_PROFILE_THRESHOLD_MS, STALL_PROFILE_DEFAULTS.thresholdMs),
|
|
27
|
+
samplingIntervalUs: parsePositive(env.PASEO_STALL_PROFILE_INTERVAL_US, STALL_PROFILE_DEFAULTS.samplingIntervalUs),
|
|
28
|
+
maxFiles: parsePositive(env.PASEO_STALL_PROFILE_MAX_FILES, STALL_PROFILE_DEFAULTS.maxFiles),
|
|
29
|
+
maxTotalBytes: parsePositive(env.PASEO_STALL_PROFILE_MAX_BYTES, STALL_PROFILE_DEFAULTS.maxTotalBytes),
|
|
30
|
+
longTaskThresholdMs: STALL_PROFILE_DEFAULTS.longTaskThresholdMs,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function describeFrame(node) {
|
|
34
|
+
const frame = node.callFrame;
|
|
35
|
+
const name = frame.functionName || "(anonymous)";
|
|
36
|
+
// V8 line numbers are zero-based; editors are one-based.
|
|
37
|
+
const location = frame.url ? `${frame.url}:${frame.lineNumber + 1}` : "";
|
|
38
|
+
return { name, location };
|
|
39
|
+
}
|
|
40
|
+
// Self time per sampled node, then inclusive time by walking each sample's
|
|
41
|
+
// ancestor chain once per distinct function so recursion is not double counted.
|
|
42
|
+
export function summarizeCpuProfile(profile, topN = SUMMARY_TOP_N) {
|
|
43
|
+
const byId = new Map();
|
|
44
|
+
const parent = new Map();
|
|
45
|
+
for (const node of profile.nodes) {
|
|
46
|
+
byId.set(node.id, node);
|
|
47
|
+
for (const child of node.children ?? []) {
|
|
48
|
+
parent.set(child, node.id);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const samples = profile.samples ?? [];
|
|
52
|
+
const deltas = profile.timeDeltas ?? [];
|
|
53
|
+
const selfUsByNode = new Map();
|
|
54
|
+
// timeDeltas[i] is the gap before sample i, so the time spent in sample i is
|
|
55
|
+
// the next delta. The last sample gets the gap to endTime.
|
|
56
|
+
let clock = profile.startTime;
|
|
57
|
+
const stamps = [];
|
|
58
|
+
for (let i = 0; i < samples.length; i += 1) {
|
|
59
|
+
clock += deltas[i] ?? 0;
|
|
60
|
+
stamps.push(clock);
|
|
61
|
+
}
|
|
62
|
+
for (let i = 0; i < samples.length; i += 1) {
|
|
63
|
+
const next = i + 1 < stamps.length ? stamps[i + 1] : profile.endTime;
|
|
64
|
+
const duration = Math.max(0, next - stamps[i]);
|
|
65
|
+
selfUsByNode.set(samples[i], (selfUsByNode.get(samples[i]) ?? 0) + duration);
|
|
66
|
+
}
|
|
67
|
+
const keyOf = (node) => {
|
|
68
|
+
const { name, location } = describeFrame(node);
|
|
69
|
+
return `${name}\u0000${location}`;
|
|
70
|
+
};
|
|
71
|
+
const selfByKey = new Map();
|
|
72
|
+
const inclusiveByKey = new Map();
|
|
73
|
+
for (const [nodeId, us] of selfUsByNode) {
|
|
74
|
+
const node = byId.get(nodeId);
|
|
75
|
+
if (!node)
|
|
76
|
+
continue;
|
|
77
|
+
const key = keyOf(node);
|
|
78
|
+
selfByKey.set(key, (selfByKey.get(key) ?? 0) + us);
|
|
79
|
+
const seen = new Set();
|
|
80
|
+
let cursor = nodeId;
|
|
81
|
+
while (cursor !== undefined) {
|
|
82
|
+
const current = byId.get(cursor);
|
|
83
|
+
if (!current)
|
|
84
|
+
break;
|
|
85
|
+
const currentKey = keyOf(current);
|
|
86
|
+
if (!seen.has(currentKey)) {
|
|
87
|
+
seen.add(currentKey);
|
|
88
|
+
inclusiveByKey.set(currentKey, (inclusiveByKey.get(currentKey) ?? 0) + us);
|
|
89
|
+
}
|
|
90
|
+
cursor = parent.get(cursor);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const top = (totals) => [...totals.entries()]
|
|
94
|
+
.filter(([key]) => !key.startsWith("(root)\u0000"))
|
|
95
|
+
.sort((a, b) => b[1] - a[1])
|
|
96
|
+
.slice(0, topN)
|
|
97
|
+
.map(([key, us]) => {
|
|
98
|
+
const [name, location] = key.split("\u0000");
|
|
99
|
+
return { name: name, location: location, ms: Math.round(us / 100) / 10 };
|
|
100
|
+
});
|
|
101
|
+
return {
|
|
102
|
+
topSelf: top(selfByKey),
|
|
103
|
+
topInclusive: top(inclusiveByKey),
|
|
104
|
+
sampleCount: samples.length,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export class StallProfiler {
|
|
108
|
+
constructor(options) {
|
|
109
|
+
this.session = null;
|
|
110
|
+
this.windowStartedAt = 0;
|
|
111
|
+
this.longTaskTimer = null;
|
|
112
|
+
this.lastTick = 0;
|
|
113
|
+
this.longTasks = [];
|
|
114
|
+
this.busy = Promise.resolve();
|
|
115
|
+
this.options = options;
|
|
116
|
+
this.now = options.now ?? Date.now;
|
|
117
|
+
}
|
|
118
|
+
async start() {
|
|
119
|
+
if (this.session)
|
|
120
|
+
return;
|
|
121
|
+
const session = new Session();
|
|
122
|
+
session.connect();
|
|
123
|
+
this.session = session;
|
|
124
|
+
await this.post("Profiler.enable");
|
|
125
|
+
await this.post("Profiler.setSamplingInterval", { interval: this.options.samplingIntervalUs });
|
|
126
|
+
await this.post("Profiler.start");
|
|
127
|
+
this.windowStartedAt = this.now();
|
|
128
|
+
this.lastTick = this.now();
|
|
129
|
+
const timer = setInterval(() => this.checkDrift(), LONG_TASK_TICK_MS);
|
|
130
|
+
timer.unref?.();
|
|
131
|
+
this.longTaskTimer = timer;
|
|
132
|
+
this.options.logger?.info({
|
|
133
|
+
thresholdMs: this.options.thresholdMs,
|
|
134
|
+
samplingIntervalUs: this.options.samplingIntervalUs,
|
|
135
|
+
diagnosticsDir: this.options.diagnosticsDir,
|
|
136
|
+
}, "stall_profiler_enabled");
|
|
137
|
+
}
|
|
138
|
+
// Called once per metrics window with that window's event-loop max. Returns
|
|
139
|
+
// the written profile path when the window was kept.
|
|
140
|
+
rollWindow(maxEventLoopDelayMs, window) {
|
|
141
|
+
const run = this.busy
|
|
142
|
+
.then(() => this.doRoll(maxEventLoopDelayMs ?? 0, window))
|
|
143
|
+
.catch((error) => {
|
|
144
|
+
this.options.logger?.warn({ err: error }, "stall_profiler_roll_failed");
|
|
145
|
+
return null;
|
|
146
|
+
});
|
|
147
|
+
this.busy = run.then(() => undefined);
|
|
148
|
+
return run;
|
|
149
|
+
}
|
|
150
|
+
async stop() {
|
|
151
|
+
await this.busy;
|
|
152
|
+
if (this.longTaskTimer) {
|
|
153
|
+
clearInterval(this.longTaskTimer);
|
|
154
|
+
this.longTaskTimer = null;
|
|
155
|
+
}
|
|
156
|
+
const session = this.session;
|
|
157
|
+
this.session = null;
|
|
158
|
+
if (!session)
|
|
159
|
+
return;
|
|
160
|
+
try {
|
|
161
|
+
await new Promise((resolve) => session.post("Profiler.stop", () => resolve()));
|
|
162
|
+
await new Promise((resolve) => session.post("Profiler.disable", () => resolve()));
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
session.disconnect();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
checkDrift() {
|
|
169
|
+
const now = this.now();
|
|
170
|
+
const blockedMs = now - this.lastTick - LONG_TASK_TICK_MS;
|
|
171
|
+
this.lastTick = now;
|
|
172
|
+
if (blockedMs >= this.options.longTaskThresholdMs &&
|
|
173
|
+
this.longTasks.length < MAX_LONG_TASKS_PER_WINDOW) {
|
|
174
|
+
this.longTasks.push({
|
|
175
|
+
endedAt: new Date(now).toISOString(),
|
|
176
|
+
blockedMs: Math.round(blockedMs),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
post(method, params) {
|
|
181
|
+
const session = this.session;
|
|
182
|
+
if (!session)
|
|
183
|
+
return Promise.reject(new Error("stall profiler not started"));
|
|
184
|
+
return new Promise((resolve, reject) => {
|
|
185
|
+
session.post(method, params ?? {}, (error, result) => {
|
|
186
|
+
if (error)
|
|
187
|
+
reject(error);
|
|
188
|
+
else
|
|
189
|
+
resolve(result);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
async doRoll(maxMs, window) {
|
|
194
|
+
if (!this.session)
|
|
195
|
+
return null;
|
|
196
|
+
// Capture the drift checker's pending gap too, so a block still running at
|
|
197
|
+
// the window edge is not lost.
|
|
198
|
+
this.checkDrift();
|
|
199
|
+
const longTasks = this.longTasks;
|
|
200
|
+
this.longTasks = [];
|
|
201
|
+
const windowStartedAt = this.windowStartedAt;
|
|
202
|
+
const { profile } = await this.post("Profiler.stop");
|
|
203
|
+
await this.post("Profiler.start");
|
|
204
|
+
this.windowStartedAt = this.now();
|
|
205
|
+
if (maxMs < this.options.thresholdMs) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
return await this.persist(profile, maxMs, longTasks, window, windowStartedAt);
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
this.options.logger?.warn({ err: error }, "stall_profiler_write_failed");
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async persist(profile, maxMs, longTasks, window, windowStartedAt) {
|
|
217
|
+
const dir = this.options.diagnosticsDir;
|
|
218
|
+
await mkdir(dir, { recursive: true });
|
|
219
|
+
const iso = new Date(this.now()).toISOString().replace(/[:.]/g, "-");
|
|
220
|
+
const base = `stall-${iso}-${Math.round(maxMs)}ms`;
|
|
221
|
+
const profilePath = join(dir, `${base}.cpuprofile`);
|
|
222
|
+
const summary = {
|
|
223
|
+
capturedAt: new Date(this.now()).toISOString(),
|
|
224
|
+
maxEventLoopDelayMs: maxMs,
|
|
225
|
+
thresholdMs: this.options.thresholdMs,
|
|
226
|
+
windowStartedAt: new Date(windowStartedAt).toISOString(),
|
|
227
|
+
profileDurationMs: Math.round((profile.endTime - profile.startTime) / 1000),
|
|
228
|
+
samplingIntervalUs: this.options.samplingIntervalUs,
|
|
229
|
+
...summarizeCpuProfile(profile),
|
|
230
|
+
longTasks,
|
|
231
|
+
window: window ?? null,
|
|
232
|
+
};
|
|
233
|
+
await writeFile(profilePath, JSON.stringify(profile));
|
|
234
|
+
await writeFile(join(dir, `${base}.summary.json`), `${JSON.stringify(summary, null, 2)}\n`);
|
|
235
|
+
this.options.logger?.info({ profilePath, maxEventLoopDelayMs: maxMs, top: summary.topSelf.slice(0, 3) }, "stall_profile_captured");
|
|
236
|
+
await this.rotate();
|
|
237
|
+
return profilePath;
|
|
238
|
+
}
|
|
239
|
+
// Oldest captures go first until both the count and the byte caps hold.
|
|
240
|
+
// A capture is its .cpuprofile plus its .summary.json.
|
|
241
|
+
async rotate() {
|
|
242
|
+
const dir = this.options.diagnosticsDir;
|
|
243
|
+
const names = (await readdir(dir)).filter((n) => n.startsWith("stall-") && n.endsWith(".cpuprofile"));
|
|
244
|
+
const captures = await Promise.all(names.map(async (name) => {
|
|
245
|
+
const base = name.slice(0, -".cpuprofile".length);
|
|
246
|
+
const info = await stat(join(dir, name));
|
|
247
|
+
const summarySize = await stat(join(dir, `${base}.summary.json`)).then((s) => s.size, () => 0);
|
|
248
|
+
return { base, mtimeMs: info.mtimeMs, bytes: info.size + summarySize };
|
|
249
|
+
}));
|
|
250
|
+
captures.sort((a, b) => a.mtimeMs - b.mtimeMs || a.base.localeCompare(b.base));
|
|
251
|
+
let total = captures.reduce((sum, c) => sum + c.bytes, 0);
|
|
252
|
+
let count = captures.length;
|
|
253
|
+
for (const capture of captures) {
|
|
254
|
+
if (count <= 1)
|
|
255
|
+
break;
|
|
256
|
+
if (count <= this.options.maxFiles && total <= this.options.maxTotalBytes)
|
|
257
|
+
break;
|
|
258
|
+
await unlink(join(dir, `${capture.base}.cpuprofile`)).catch(() => undefined);
|
|
259
|
+
await unlink(join(dir, `${capture.base}.summary.json`)).catch(() => undefined);
|
|
260
|
+
total -= capture.bytes;
|
|
261
|
+
count -= 1;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=stall-profiler.js.map
|
|
@@ -123,6 +123,7 @@ export declare class VoiceAssistantWebSocketServer {
|
|
|
123
123
|
private runtimeMetricsInterval;
|
|
124
124
|
private readonly daemonHealthWindow;
|
|
125
125
|
private eventLoopDelayMonitor;
|
|
126
|
+
private stallProfiler;
|
|
126
127
|
private unsubscribeSpeechReadiness;
|
|
127
128
|
private unsubscribeDaemonConfigChange;
|
|
128
129
|
private readonly providerUsageService;
|
|
@@ -188,6 +189,7 @@ export declare class VoiceAssistantWebSocketServer {
|
|
|
188
189
|
private assignOptionalServices;
|
|
189
190
|
private createWebSocketServer;
|
|
190
191
|
private startRuntimeMetricsInterval;
|
|
192
|
+
private startStallProfiler;
|
|
191
193
|
private snapshotEventLoopDelay;
|
|
192
194
|
private verifyWsUpgrade;
|
|
193
195
|
private attachAuthenticatedSocket;
|
|
@@ -3,6 +3,7 @@ import { basename, join } from "path";
|
|
|
3
3
|
import { hostname as getHostname } from "node:os";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { monitorEventLoopDelay } from "node:perf_hooks";
|
|
6
|
+
import { resolveStallProfilerOptions, StallProfiler } from "./stall-profiler.js";
|
|
6
7
|
import { WORKFLOWS_FEATURE_ENABLED } from "./workflow/workflow-feature.js";
|
|
7
8
|
import { recallSearchEnabled } from "./workspace/recall-search-feature.js";
|
|
8
9
|
import { WSInboundMessageSchema, wrapSessionMessage, } from "./messages.js";
|
|
@@ -268,6 +269,7 @@ export class VoiceAssistantWebSocketServer {
|
|
|
268
269
|
this.runtimeMetricsInterval = null;
|
|
269
270
|
this.daemonHealthWindow = new DaemonHealthWindow();
|
|
270
271
|
this.eventLoopDelayMonitor = null;
|
|
272
|
+
this.stallProfiler = null;
|
|
271
273
|
this.unsubscribeSpeechReadiness = null;
|
|
272
274
|
this.unsubscribeDaemonConfigChange = null;
|
|
273
275
|
this.unsubscribeTerminalActivity = null;
|
|
@@ -520,12 +522,27 @@ export class VoiceAssistantWebSocketServer {
|
|
|
520
522
|
startRuntimeMetricsInterval() {
|
|
521
523
|
this.eventLoopDelayMonitor = monitorEventLoopDelay({ resolution: 10 });
|
|
522
524
|
this.eventLoopDelayMonitor.enable();
|
|
525
|
+
this.startStallProfiler();
|
|
523
526
|
const runtimeMetricsInterval = setInterval(() => {
|
|
524
527
|
this.flushRuntimeMetrics();
|
|
525
528
|
}, WS_RUNTIME_METRICS_FLUSH_MS);
|
|
526
529
|
this.runtimeMetricsInterval = runtimeMetricsInterval;
|
|
527
530
|
runtimeMetricsInterval.unref?.();
|
|
528
531
|
}
|
|
532
|
+
// PASEO_STALL_PROFILE=1 keeps a rolling CPU profile per metrics window and
|
|
533
|
+
// saves the windows whose event-loop max crossed the threshold. Off by default.
|
|
534
|
+
startStallProfiler() {
|
|
535
|
+
const options = resolveStallProfilerOptions(process.env, this.paseoHome);
|
|
536
|
+
if (!options) {
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
const profiler = new StallProfiler({ ...options, logger: this.logger });
|
|
540
|
+
this.stallProfiler = profiler;
|
|
541
|
+
profiler.start().catch((error) => {
|
|
542
|
+
this.logger.warn({ err: error }, "stall_profiler_start_failed");
|
|
543
|
+
this.stallProfiler = null;
|
|
544
|
+
});
|
|
545
|
+
}
|
|
529
546
|
// Main-loop stall visibility: terminal frames and agent traffic share one event
|
|
530
547
|
// loop, so delay percentiles here are the ground truth for "the daemon is busy".
|
|
531
548
|
snapshotEventLoopDelay() {
|
|
@@ -625,6 +642,11 @@ export class VoiceAssistantWebSocketServer {
|
|
|
625
642
|
this.flushRuntimeMetrics({ final: true });
|
|
626
643
|
this.eventLoopDelayMonitor?.disable();
|
|
627
644
|
this.eventLoopDelayMonitor = null;
|
|
645
|
+
const stallProfiler = this.stallProfiler;
|
|
646
|
+
this.stallProfiler = null;
|
|
647
|
+
stallProfiler?.stop().catch((error) => {
|
|
648
|
+
this.logger.warn({ err: error }, "stall_profiler_stop_failed");
|
|
649
|
+
});
|
|
628
650
|
const uniqueConnections = new Set([
|
|
629
651
|
...this.sessions.values(),
|
|
630
652
|
...this.externalSessionsByKey.values(),
|
|
@@ -1566,6 +1588,15 @@ export class VoiceAssistantWebSocketServer {
|
|
|
1566
1588
|
...loggedMetrics,
|
|
1567
1589
|
};
|
|
1568
1590
|
this.logger.info(loggedMetrics, "ws_runtime_metrics");
|
|
1591
|
+
if (this.stallProfiler && !options?.final) {
|
|
1592
|
+
void this.stallProfiler.rollWindow(loggedMetrics.eventLoopDelay?.maxMs, {
|
|
1593
|
+
latency: loggedMetrics.latency,
|
|
1594
|
+
runtime: loggedMetrics.runtime,
|
|
1595
|
+
counters: loggedMetrics.counters,
|
|
1596
|
+
inboundSessionRequestTypesTop: loggedMetrics.inboundSessionRequestTypesTop,
|
|
1597
|
+
outboundSessionMessageTypesTop: loggedMetrics.outboundSessionMessageTypesTop,
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1569
1600
|
if (!options?.final) {
|
|
1570
1601
|
this.maybeBroadcastDaemonHealth(loggedMetrics);
|
|
1571
1602
|
}
|
|
@@ -849,7 +849,7 @@ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{v
|
|
|
849
849
|
__d(function(g,r,i,a,m,e,d){"use strict";var t=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0}),e.shouldAppendSitemap=u,e.shouldAppendNotFound=s,e.getRootStackRouteNames=function(){const t=[n.INTERNAL_SLOT_NAME];s()&&t.push(n.NOT_FOUND_ROUTE_NAME);u()&&t.push(n.SITEMAP_ROUTE_NAME);return t};const o=t(r(d[0])),n=r(d[1]);function u(){const t=o.default.expoConfig?.extra?.router;return!1!==t?.sitemap}function s(){const t=o.default.expoConfig?.extra?.router;return!1!==t?.notFound}},717,[718,721]);
|
|
850
850
|
__d(function(g,r,i,a,m,_e,d){"use strict";function e(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(_e,'__esModule',{value:!0}),Object.defineProperty(_e,"default",{enumerable:!0,get:function(){return N}}),Object.defineProperty(_e,"AppOwnership",{enumerable:!0,get:function(){return l.AppOwnership}}),Object.defineProperty(_e,"ExecutionEnvironment",{enumerable:!0,get:function(){return l.ExecutionEnvironment}}),Object.defineProperty(_e,"UserInterfaceIdiom",{enumerable:!0,get:function(){return l.UserInterfaceIdiom}});var n=e(r(d[0])),t=r(d[1]);r(d[2]);var u=e(r(d[3])),l=r(d[4]),o=e(r(d[5]));o.default||console.warn("No native ExponentConstants module found, are you sure the expo-constants's module is linked properly?");const s=(0,t.requireOptionalNativeModule)('ExpoUpdates');let f=null;if(s){let e;s.manifest?e=s.manifest:s.manifestString&&(e=JSON.parse(s.manifestString)),e&&Object.keys(e).length>0&&(f=e)}let c=null;if(u.default.EXDevLauncher){let e;u.default.EXDevLauncher.manifestString&&(e=JSON.parse(u.default.EXDevLauncher.manifestString)),e&&Object.keys(e).length>0&&(c=e)}let p=null;if(o.default&&o.default.manifest){const e=o.default.manifest;p='string'==typeof e?JSON.parse(e):e}let b=f??c??p;const E=o.default||{},{appOwnership:O}=E,x=(0,n.default)(E,["name","appOwnership"]),v=Object.assign({},x,{appOwnership:O??null});function _(e){return!h(e)}function h(e){return'metadata'in e}function S(e=!1){if(!b){const e=null===b?'null':'undefined';if(x.executionEnvironment,l.ExecutionEnvironment.Bare,x.executionEnvironment===l.ExecutionEnvironment.StoreClient||x.executionEnvironment===l.ExecutionEnvironment.Standalone)throw new t.CodedError('ERR_CONSTANTS_MANIFEST_UNAVAILABLE',`Constants.manifest is ${e}, must be an object.`)}return b}Object.defineProperties(v,{__unsafeNoWarnManifest:{get(){const e=S(!0);return e&&_(e)?e:null},enumerable:!1},__unsafeNoWarnManifest2:{get(){const e=S(!0);return e&&h(e)?e:null},enumerable:!1},manifest:{get(){const e=S();return e&&_(e)?e:null},enumerable:!0},manifest2:{get(){const e=S();return e&&h(e)?e:null},enumerable:!0},expoConfig:{get(){const e=S(!0);return e?s&&s.isEmbeddedLaunch?p:h(e)?e.extra?.expoClient??null:_(e)?e:null:null},enumerable:!0},expoGoConfig:{get(){const e=S(!0);return e?h(e)?e.extra?.expoGo??null:_(e)?e:null:null},enumerable:!0},easConfig:{get(){const e=S(!0);return e?h(e)?e.extra?.eas??null:_(e)?e:null:null},enumerable:!0},__rawManifest_TEST:{get:()=>b,set(e){b=e},enumerable:!1}});var N=v},718,[35,4,25,637,719,720]);
|
|
851
851
|
__d(function(g,r,i,a,m,e,d){"use strict";var t,n,o;Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"AppOwnership",{enumerable:!0,get:function(){return t}}),Object.defineProperty(e,"ExecutionEnvironment",{enumerable:!0,get:function(){return n}}),Object.defineProperty(e,"UserInterfaceIdiom",{enumerable:!0,get:function(){return o}}),(function(t){t.Expo="expo"})(t||(t={})),(function(t){t.Bare="bare",t.Standalone="standalone",t.StoreClient="storeClient"})(n||(n={})),(function(t){t.Handset="handset",t.Tablet="tablet",t.Desktop="desktop",t.TV="tv",t.Unsupported="unsupported"})(o||(o={}))},719,[]);
|
|
852
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return s}});var t=r(d[0]);const n=(Date.now()+'-'+Math.floor(1e9*Math.random())).toString();function o(){if('undefined'!=typeof navigator&&'string'==typeof navigator.userAgent){const t=navigator.userAgent.toLowerCase();if(t.includes('edge'))return'Edge';if(t.includes('edg'))return'Chromium Edge';if(t.includes('opr')&&'opr'in window&&window.opr)return'Opera';if(t.includes('chrome')&&'chrome'in window&&window.chrome)return'Chrome';if(t.includes('trident'))return'IE';if(t.includes('firefox'))return'Firefox';if(t.includes('safari'))return'Safari'}}var s={get appOwnership(){return null},get executionEnvironment(){return t.ExecutionEnvironment.Bare},get sessionId(){return n},get isHeadless(){return'undefined'==typeof navigator||/\bHeadlessChrome\//.test(navigator.userAgent)},get expoVersion(){return this.manifest.sdkVersion||null},get linkingUri(){return'undefined'!=typeof location?location.origin:''},get expoRuntimeVersion(){return this.expoVersion},get deviceName(){return o()},get systemFonts(){return[]},get statusBarHeight(){return 0},get deviceYearClass(){return null},get manifest(){return"{\"name\":\"Paseo\",\"slug\":\"paseo-hyperdrive\",\"version\":\"0.3.
|
|
852
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return s}});var t=r(d[0]);const n=(Date.now()+'-'+Math.floor(1e9*Math.random())).toString();function o(){if('undefined'!=typeof navigator&&'string'==typeof navigator.userAgent){const t=navigator.userAgent.toLowerCase();if(t.includes('edge'))return'Edge';if(t.includes('edg'))return'Chromium Edge';if(t.includes('opr')&&'opr'in window&&window.opr)return'Opera';if(t.includes('chrome')&&'chrome'in window&&window.chrome)return'Chrome';if(t.includes('trident'))return'IE';if(t.includes('firefox'))return'Firefox';if(t.includes('safari'))return'Safari'}}var s={get appOwnership(){return null},get executionEnvironment(){return t.ExecutionEnvironment.Bare},get sessionId(){return n},get isHeadless(){return'undefined'==typeof navigator||/\bHeadlessChrome\//.test(navigator.userAgent)},get expoVersion(){return this.manifest.sdkVersion||null},get linkingUri(){return'undefined'!=typeof location?location.origin:''},get expoRuntimeVersion(){return this.expoVersion},get deviceName(){return o()},get systemFonts(){return[]},get statusBarHeight(){return 0},get deviceYearClass(){return null},get manifest(){return"{\"name\":\"Paseo\",\"slug\":\"paseo-hyperdrive\",\"version\":\"0.3.168\",\"orientation\":\"portrait\",\"icon\":\"./assets/images/icon.png\",\"scheme\":\"paseo\",\"userInterfaceStyle\":\"automatic\",\"newArchEnabled\":true,\"web\":{\"output\":\"single\",\"favicon\":\"./assets/images/favicon.png\",\"shortName\":\"Paseo\",\"orientation\":\"portrait\",\"name\":\"Paseo\"},\"autolinking\":{\"searchPaths\":[\"../../node_modules\",\"./node_modules\"]},\"experiments\":{\"typedRoutes\":true,\"reactCompiler\":true,\"autolinkingModuleResolution\":true},\"extra\":{\"router\":{},\"eas\":{\"build\":{\"experimental\":{\"ios\":{\"appExtensions\":[{\"bundleIdentifier\":\"bot.hyperdrive.paseo.AgentActivity\",\"targetName\":\"AgentActivity\"}]}}}}},\"sdkVersion\":\"54.0.0\",\"platforms\":[\"ios\",\"android\",\"web\"]}"},get manifest2(){return null},get experienceUrl(){return'undefined'!=typeof location?location.origin:''},get debugMode(){return!1},getWebViewUserAgentAsync:async()=>'undefined'!=typeof navigator?navigator.userAgent:null}},720,[719]);
|
|
853
853
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.SITEMAP_ROUTE_NAME=e.NOT_FOUND_ROUTE_NAME=e.INTERNAL_SLOT_NAME=void 0,e.INTERNAL_SLOT_NAME='__root',e.NOT_FOUND_ROUTE_NAME='+not-found',e.SITEMAP_ROUTE_NAME='_sitemap'},721,[]);
|
|
854
854
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.resolveHref=void 0,e.resolveHrefStringWithSegments=function(t,{segments:n=[],params:s={}}={},{relativeToDirectory:o}={}){if(t.startsWith('.')){let c=n?.map(t=>{if(!t.startsWith('['))return t;if(t.startsWith('[...')){t=t.slice(4,-1);const n=s[t];return Array.isArray(n)?n.join('/'):n?.split(',')?.join('/')??''}return t=t.slice(1,-1),s[t]}).filter(Boolean).join('/')??'/';o&&(c=`${c}/`);const f=new URL(t,`http://hostname/${c}`);t=`${f.pathname}${f.search}`}return t};function t(t,s){for(const[o,c=""]of Object.entries(s)){const f=`[${o}]`,l=`[...${o}]`;if(t.includes(f))t=t.replace(f,n(c));else{if(!t.includes(l))continue;t=t.replace(l,n(c))}delete s[o]}return{pathname:t,params:s}}function n(t){return Array.isArray(t)?t.map(t=>n(t)).join('/'):encodeURIComponent(t.toString())}function s(t){return Object.entries(t).filter(([,t])=>null!=t).map(([t,n])=>`${t}=${encodeURIComponent(n.toString())}`).join('&')}e.resolveHref=n=>{if('string'==typeof n)return(0,e.resolveHref)({pathname:n});const o=n.pathname??'';if(!n?.params)return o;const{pathname:c,params:f}=t(o,Object.assign({},n.params)),l=s(f);return c+(l?`?${l}`:'')}},722,[]);
|
|
855
855
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.isRoutePreloadedInStack=function(t,o){if(!t||'stack'!==t.type)return!1;return t.preloadedRoutes.some(t=>t.key===o.key)}},723,[]);
|
|
@@ -15057,7 +15057,7 @@ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{v
|
|
|
15057
15057
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"decodeOfferFragmentPayload",{enumerable:!0,get:function(){return n.decodeOfferFragmentPayload}}),Object.defineProperty(e,"buildDaemonWebSocketUrl",{enumerable:!0,get:function(){return t.buildDaemonWebSocketUrl}}),Object.defineProperty(e,"deriveLabelFromEndpoint",{enumerable:!0,get:function(){return t.deriveLabelFromEndpoint}}),Object.defineProperty(e,"extractHostPortFromWebSocketUrl",{enumerable:!0,get:function(){return t.extractHostPortFromWebSocketUrl}}),Object.defineProperty(e,"normalizeHostPort",{enumerable:!0,get:function(){return t.normalizeHostPort}}),Object.defineProperty(e,"parseConnectionUri",{enumerable:!0,get:function(){return t.parseConnectionUri}}),Object.defineProperty(e,"parseHostPort",{enumerable:!0,get:function(){return t.parseHostPort}}),Object.defineProperty(e,"serializeConnectionUri",{enumerable:!0,get:function(){return t.serializeConnectionUri}}),Object.defineProperty(e,"serializeConnectionUriForStorage",{enumerable:!0,get:function(){return t.serializeConnectionUriForStorage}}),Object.defineProperty(e,"shouldUseTlsForDefaultHostedRelay",{enumerable:!0,get:function(){return t.shouldUseTlsForDefaultHostedRelay}}),e.buildRelayWebSocketUrl=function(n){return(0,t.buildRelayWebSocketUrl)(Object.assign({},n,{role:"client"}))};var t=r(d[0]),n=r(d[1])},3412,[3392,3413]);
|
|
15058
15058
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),Object.defineProperty(e,"ConnectionOfferV2Schema",{enumerable:!0,get:function(){return t}}),Object.defineProperty(e,"ConnectionOfferSchema",{enumerable:!0,get:function(){return o}}),e.decodeOfferFragmentPayload=l,e.parseConnectionOfferFromUrl=function(n){const t=f(n);if(!t)return null;const c=l(t);return o.parse(c)};var n=r(d[0]);const t=n.z.object({v:n.z.literal(2),serverId:n.z.string().min(1),daemonPublicKeyB64:n.z.string().min(1),relay:n.z.object({endpoint:n.z.string().min(1),useTls:n.z.boolean().optional()})}),o=t;function c(n){const t=n.replace(/-/g,"+").replace(/_/g,"/"),o=t.padEnd(t.length+(4-t.length%4)%4,"="),c=globalThis.atob(o),l=Uint8Array.from(c,n=>n.charCodeAt(0));return new TextDecoder("utf-8",{fatal:!0}).decode(l)}function l(n){const t=c(n);return JSON.parse(t)}const u="#offer=";function f(n){const t=n.trim();if(!t)return null;const o=t.indexOf(u);if(-1===o)return null;const c=t.slice(o+u.length).trim();return c.length>0?c:null}},3413,[3285]);
|
|
15059
15059
|
__d(function(g,r,i,a,m,_e,d){"use strict";function e(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(_e,'__esModule',{value:!0}),_e.resolveAppVersion=function(){const e=u(t.default?.version);if(e)return e;const o=u(n.default.expoConfig?.version);if(o)return o;const f=u(n.default.manifest?.version);if(f)return f;return null};var n=e(r(d[0])),t=e(r(d[1]));function u(e){if("string"!=typeof e)return null;const n=e.trim();return 0===n.length?null:n}},3414,[718,3415]);
|
|
15060
|
-
__d(function(e,t,r,a,o,i,n){o.exports={name:"@hyperdrive.bot/fleet-app",version:"0.3.
|
|
15060
|
+
__d(function(e,t,r,a,o,i,n){o.exports={name:"@hyperdrive.bot/fleet-app",version:"0.3.168",private:!0,main:"index.ts",scripts:{start:"npm run start:expo","start:expo":"cross-env APP_VARIANT=development expo start","reset-project":"node ./scripts/reset-project.js","build:terminal-webview":"node ./scripts/build-terminal-webview-html.mjs","eas-build-post-install":"npm --prefix ../.. run build:app-deps && npm run build:terminal-webview",android:"npm run android:development","android:development":"npm --prefix ../.. run build:client && cross-env APP_VARIANT=development expo prebuild --platform android --non-interactive && cross-env APP_VARIANT=development expo run:android --variant=debug","android:production":"npm --prefix ../.. run build:client && cross-env APP_VARIANT=production expo prebuild --platform android --non-interactive && cross-env APP_VARIANT=production expo run:android --variant=release","android:release":"npm run android:production","android:clear":"node -e \"require('node:fs').rmSync('android', { recursive: true, force: true })\"",ios:"npm --prefix ../.. run build:client && expo run:ios","ios:release":"npm --prefix ../.. run build:client && expo run:ios --configuration Release",web:"npm --prefix ../.. run build:client && concurrently --kill-others --names protocol,client,expo --prefix-colors yellow,blue,magenta \"npm --prefix ../.. run watch:protocol\" \"npm --prefix ../.. run watch:client\" \"npm run web:expo\"","web:expo":"expo start --web",lint:"expo lint",typecheck:"tsgo --noEmit",test:"vitest run","test:browser":"vitest run --project browser","test:e2e":"playwright test --project='Desktop Chrome'","test:e2e:reels":"cross-env NODE_ENV=development playwright test --config playwright.reels.config.ts","test:e2e:real":"cross-env E2E_FORK_PASEO_HOME_FROM=../../.dev/paseo-home playwright test --project=real-provider","test:e2e:ui":"playwright test --ui","test:coverage":"vitest run --project unit --coverage",build:"npm run build:web","build:web":"npm --prefix ../.. run build:app-deps && expo export --platform web --source-maps","profile:workspace-tabs":"node ./scripts/profile-workspace-tabs.mjs","deploy:web":"npm run build:web && wrangler pages deploy dist --project-name paseo-app --branch main"},dependencies:{"@bacons/apple-targets":"4.0.6","@datadog/browser-rum":"^6.23.0","@datadog/browser-rum-react":"^6.23.0","@datadog/mobile-react-native":"^2.7.0","@datadog/mobile-react-native-session-replay":"^2.14.8","@dnd-kit/core":"^6.3.1","@dnd-kit/sortable":"^10.0.0","@dnd-kit/utilities":"^3.2.2","@expo/image-utils":"0.8.8","@expo/plist":"0.4.9","@expo/prebuild-config":"54.0.8","@floating-ui/react-native":"^0.10.7","@gorhom/bottom-sheet":"^5.2.14","@gorhom/portal":"^1.0.14","@hyperdrive.bot/fleet-client":"*","@hyperdrive.bot/fleet-expo-two-way-audio":"*","@hyperdrive.bot/fleet-extension-sdk":"*","@hyperdrive.bot/fleet-highlight":"*","@react-native-async-storage/async-storage":"2.2.0","@react-native-masked-view/masked-view":"^0.3.2","@react-native/normalize-colors":"^0.81.5","@react-navigation/native":"^7.1.8","@sentry/electron":"^6.11.0","@sentry/react-native":"^6.20.0","@tanstack/react-query":"^5.90.11","@tanstack/react-virtual":"^3.13.21","@xterm/addon-clipboard":"^0.3.0-beta.213","@xterm/addon-fit":"^0.12.0-beta.213","@xterm/addon-image":"^0.10.0-beta.213","@xterm/addon-ligatures":"0.11.0-beta.213","@xterm/addon-search":"^0.17.0-beta.213","@xterm/addon-unicode11":"^0.10.0-beta.213","@xterm/addon-web-links":"^0.13.0-beta.213","@xterm/addon-webgl":"^0.20.0-beta.212","@xterm/xterm":"^6.1.0-beta.213",buffer:"^6.0.3",expo:"^54.0.18","expo-asset":"~12.0.12","expo-audio":"~1.0.13","expo-background-fetch":"~14.0.9","expo-build-properties":"^1.0.9","expo-camera":"~17.0.10","expo-clipboard":"~8.0.7","expo-constants":"~18.0.9","expo-crypto":"^15.0.8","expo-dev-client":"^6.0.15","expo-document-picker":"~14.0.8","expo-file-system":"~19.0.17","expo-haptics":"~15.0.7","expo-image":"~3.0.10","expo-image-manipulator":"~14.0.8","expo-image-picker":"^17.0.8","expo-keep-awake":"^15.0.7","expo-linking":"~8.0.8","expo-localization":"~17.0.9","expo-notifications":"^0.32.16","expo-router":"~6.0.13","expo-sharing":"^14.0.8","expo-speech":"~14.0.8","expo-speech-recognition":"^56.0.1","expo-splash-screen":"~31.0.10","expo-system-ui":"~6.0.7","expo-task-manager":"~14.0.9","expo-video":"~3.0.16","fast-deep-equal":"^3.1.3",htmlparser2:"^12.0.0",i18next:"^26.3.0","lucide-react-native":"^0.546.0","markdown-it":"^10.0.0","mnemonic-id":"^3.2.7","posthog-js":"^1.431.2","posthog-react-native":"^4.72.0",qrcode:"^1.5.4",react:"19.1.0","react-dom":"19.1.0","react-i18next":"^17.0.8","react-native":"0.81.5","react-native-draggable-flatlist":"^4.0.3","react-native-edge-to-edge":"^1.7.0","react-native-gesture-handler":"~2.28.0","react-native-keyboard-controller":"^1.21.7","react-native-markdown-display":"^7.0.2","react-native-nitro-modules":"0.35.5","react-native-reanimated":"~4.3.1","react-native-safe-area-context":"~5.6.0","react-native-screens":"~4.16.0","react-native-svg":"^15.14.0","react-native-uitextview":"^2.2.0","react-native-unistyles":"^3.2.4","react-native-web":"~0.21.0","react-native-webview":"^13.16.0","react-native-worklets":"~0.8.3","tiny-invariant":"^1.3.3","use-sync-external-store":"^1.6.0",zod:"^4.4.3",zustand:"^5.0.9"},devDependencies:{"@playwright/test":"^1.56.1","@testing-library/dom":"^10.4.1","@testing-library/react":"^16.3.2","@types/chai":"^5.2.2","@types/markdown-it":"^14.1.2","@types/qrcode":"^1.5.6","@types/react":"~19.2.0","@types/ws":"^8.18.1","@vitest/browser":"^4.1.7","@vitest/browser-playwright":"^4.1.7","@vitest/coverage-v8":"^4.1.7","@xterm/headless":"^6.1.0-beta.213",dotenv:"^17.2.3",eslint:"^9.25.0","eslint-config-expo":"~10.0.0",jsdom:"^20.0.3","material-icon-theme":"^5.32.0",playwright:"^1.56.1","serve-sim":"^0.1.40",typescript:"~5.9.2",vitest:"^4.1.6",wrangler:"^4.105.0",ws:"^8.20.0"}}},3415,[]);
|
|
15061
15061
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.shouldUseDesktopDaemon=function(){return(0,n.isElectronRuntime)()},e.getDesktopDaemonStatus=async function(){return c(await(0,t.invokeDesktopCommand)("desktop_daemon_status"))},e.startDesktopDaemon=async function(){return c(await(0,t.invokeDesktopCommand)("start_desktop_daemon"))},e.stopDesktopDaemon=async function(n="manual_ipc"){return c(await(0,t.invokeDesktopCommand)("stop_desktop_daemon",{reason:n}))},e.restartDesktopDaemon=async function(){return c(await(0,t.invokeDesktopCommand)("restart_desktop_daemon"))},e.getDesktopDaemonLogs=async function(){return p(await(0,t.invokeDesktopCommand)("desktop_daemon_logs"))},e.getDesktopDaemonPairing=async function(){return k(await(0,t.invokeDesktopCommand)("desktop_daemon_pairing"))},e.getCliDaemonStatus=async function(){const n=await(0,t.invokeDesktopCommand)("cli_daemon_status");if("string"!=typeof n)throw new Error("Unexpected CLI daemon status response.");return n},e.listenToLocalTransportEvents=async function(t){const u=(0,n.getDesktopHost)()?.events?.on;if("function"!=typeof u)throw new Error("Desktop events API is unavailable.");const c=await u("local-daemon-transport-event",n=>{o(n)&&t({sessionId:s(n.sessionId)??"",kind:s(n.kind)??"error",text:s(n.text),binaryBase64:s(n.binaryBase64),code:l(n.code),reason:s(n.reason),error:s(n.error)})});return"function"==typeof c?c:()=>{}},e.openLocalTransportSession=async function(n){const o=await(0,t.invokeDesktopCommand)("open_local_daemon_transport",n);if("string"!=typeof o||0===o.trim().length)throw new Error("Unexpected local transport session response.");return o},e.sendLocalTransportMessage=async function(n){await(0,t.invokeDesktopCommand)("send_local_daemon_transport_message",Object.assign({sessionId:n.sessionId},n.text?{text:n.text}:{},n.binaryBase64?{binaryBase64:n.binaryBase64}:{}))},e.closeLocalTransportSession=async function(n){await(0,t.invokeDesktopCommand)("close_local_daemon_transport",{sessionId:n})},e.getCliInstallStatus=async function(){return f(await(0,t.invokeDesktopCommand)("get_cli_install_status"))},e.installCli=async function(){return f(await(0,t.invokeDesktopCommand)("install_cli"))},e.getSkillsStatus=async function(){return y(await(0,t.invokeDesktopCommand)("get_skills_status"))},e.installSkills=async function(){return y(await(0,t.invokeDesktopCommand)("install_skills"))},e.updateSkills=async function(){return y(await(0,t.invokeDesktopCommand)("update_skills"))},e.uninstallSkills=async function(){return y(await(0,t.invokeDesktopCommand)("uninstall_skills"))};var n=r(d[0]),t=r(d[1]);function o(n){return"object"==typeof n&&null!==n}function s(n){return"string"==typeof n&&n.trim().length>0?n:null}function l(n){return"number"==typeof n&&Number.isFinite(n)?n:null}function u(n){const t=s(n)?.toLowerCase();switch(t){case"starting":return"starting";case"running":return"running";case"errored":case"error":return"errored";default:return"stopped"}}function c(n){if(!o(n))throw new Error("Unexpected desktop daemon status response.");return{serverId:s(n.serverId)??"",status:u(n.status),listen:s(n.listen),hostname:s(n.hostname),pid:l(n.pid),home:s(n.home)??"",version:s(n.version),desktopManaged:!0===n.desktopManaged,error:s(n.error)}}function p(n){if(!o(n))throw new Error("Unexpected desktop daemon logs response.");return{logPath:s(n.logPath)??"",contents:"string"==typeof n.contents?n.contents:""}}function k(n){if(!o(n))throw new Error("Unexpected desktop daemon pairing response.");return{relayEnabled:!0===n.relayEnabled,url:s(n.url),qr:s(n.qr)}}function f(n){if(!o(n))throw new Error("Unexpected install status response.");return{installed:!0===n.installed}}function w(n){switch(n){case"not-installed":case"up-to-date":case"drift":return n;default:throw new Error(`Unexpected skills status state: ${String(n)}`)}}function _(n){if(!o(n))throw new Error("Unexpected skill op response.");const t=s(n.name);if(!t)throw new Error("Skill op missing name.");switch(n.kind){case"add":return{kind:"add",name:t};case"update":return{kind:"update",name:t};case"delete":return{kind:"delete",name:t};default:throw new Error(`Unexpected skill op kind: ${String(n.kind)}`)}}function y(n){if(!o(n))throw new Error("Unexpected skills status response.");const t=Array.isArray(n.ops)?n.ops.map(_):[];return{state:w(n.state),ops:t}}},3416,[3417,3419]);
|
|
15062
15062
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.getDesktopHost=n,e.isElectronRuntime=o,e.isElectronRuntimeMac=function(){if(!o())return!1;if("undefined"==typeof navigator)return!1;const t=n()?.platform?.toLowerCase();if("darwin"===t||"mac"===t||"macos"===t)return!0;const u=navigator.userAgent;return u.includes("Mac OS")||u.includes("Macintosh")},r(d[0]);var t=r(d[1]);function n(){return(0,t.getElectronHost)()}function o(){return null!==n()}},3417,[25,3418]);
|
|
15063
15063
|
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.getElectronHost=function(){if("undefined"==typeof window)return null;const t=window.paseoDesktop;if(!t||"object"!=typeof t)return null;return t}},3418,[]);
|
|
@@ -16721,5 +16721,5 @@ __d(function(g,r,_i,a,_m,_e,d){"use strict";var e,t=r(d[0]),n=this&&this.__creat
|
|
|
16721
16721
|
__r(694);
|
|
16722
16722
|
__r(341);
|
|
16723
16723
|
__r(0);
|
|
16724
|
-
//# sourceMappingURL=/_expo/static/js/web/index-
|
|
16725
|
-
//# debugId=
|
|
16724
|
+
//# sourceMappingURL=/_expo/static/js/web/index-e80e8b2f3ce4ebaef8f03195745588eb.js.map
|
|
16725
|
+
//# debugId=20cf4c9f-e2a9-48fd-9125-a688ce5bf7e1
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -191,6 +191,6 @@
|
|
|
191
191
|
<body>
|
|
192
192
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
193
193
|
<div id="root"></div>
|
|
194
|
-
<script src="/_expo/static/js/web/index-
|
|
194
|
+
<script src="/_expo/static/js/web/index-e80e8b2f3ce4ebaef8f03195745588eb.js" defer></script>
|
|
195
195
|
</body>
|
|
196
196
|
</html>
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperdrive.bot/fleet-server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.168",
|
|
4
4
|
"description": "Paseo backend server",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"files": [
|
|
@@ -66,11 +66,11 @@
|
|
|
66
66
|
"@agentclientprotocol/sdk": "^0.17.1",
|
|
67
67
|
"@anthropic-ai/claude-agent-sdk": "^0.3.195",
|
|
68
68
|
"@anthropic-ai/sdk": "^0.104.2",
|
|
69
|
-
"@hyperdrive.bot/fleet-client": "0.3.
|
|
70
|
-
"@hyperdrive.bot/fleet-extension-sdk": "0.3.
|
|
71
|
-
"@hyperdrive.bot/fleet-highlight": "0.3.
|
|
72
|
-
"@hyperdrive.bot/fleet-protocol": "0.3.
|
|
73
|
-
"@hyperdrive.bot/fleet-relay": "0.3.
|
|
69
|
+
"@hyperdrive.bot/fleet-client": "0.3.168",
|
|
70
|
+
"@hyperdrive.bot/fleet-extension-sdk": "0.3.168",
|
|
71
|
+
"@hyperdrive.bot/fleet-highlight": "0.3.168",
|
|
72
|
+
"@hyperdrive.bot/fleet-protocol": "0.3.168",
|
|
73
|
+
"@hyperdrive.bot/fleet-relay": "0.3.168",
|
|
74
74
|
"@isaacs/ttlcache": "^2.1.4",
|
|
75
75
|
"@modelcontextprotocol/sdk": "^1.20.1",
|
|
76
76
|
"@opencode-ai/sdk": "1.2.6",
|
|
Binary file
|