@hyperdrive.bot/paseo-server 0.3.10 → 0.3.12
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/agent/agent-loading.js +24 -3
- package/dist/server/server/agent/agent-manager.d.ts +22 -0
- package/dist/server/server/agent/agent-manager.js +36 -0
- package/dist/server/server/agent/agent-storage.d.ts +9 -0
- package/dist/server/server/agent/blocker-log.d.ts +81 -0
- package/dist/server/server/agent/blocker-log.js +113 -0
- package/dist/server/server/agent/card-move-log.d.ts +66 -0
- package/dist/server/server/agent/card-move-log.js +113 -0
- package/dist/server/server/agent/jarvis-judge.d.ts +121 -0
- package/dist/server/server/agent/jarvis-judge.js +225 -0
- package/dist/server/server/agent/judge-relay-gate.d.ts +70 -0
- package/dist/server/server/agent/judge-relay-gate.js +92 -0
- package/dist/server/server/agent/mcp-server.js +9 -0
- package/dist/server/server/agent/mcp-shared.d.ts +5 -0
- package/dist/server/server/agent/providers/claude/transport/pty-query.d.ts +92 -10
- package/dist/server/server/agent/providers/claude/transport/pty-query.js +615 -38
- package/dist/server/server/agent/session-digest-generator.d.ts +27 -0
- package/dist/server/server/agent/session-digest-generator.js +208 -17
- package/dist/server/server/agent/tools/paseo-tools.d.ts +12 -0
- package/dist/server/server/agent/tools/paseo-tools.js +48 -0
- package/dist/server/server/agent/tools/read-only-surface.d.ts +52 -0
- package/dist/server/server/agent/tools/read-only-surface.js +68 -0
- package/dist/server/server/agent/tools/types.d.ts +5 -0
- package/dist/server/server/bootstrap.js +73 -0
- package/dist/server/server/relay-transport.js +36 -5
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js → desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js} +5 -5
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js → desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js} +3 -3
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-461cf3ab1d54d6debea0e037829768e9.js → index-853ef1a7fc9c9b7a39577b79564e0896.js} +166 -165
- package/dist/server/web-ui/_expo/static/js/web/index-853ef1a7fc9c9b7a39577b79564e0896.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-853ef1a7fc9c9b7a39577b79564e0896.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-853ef1a7fc9c9b7a39577b79564e0896.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-461cf3ab1d54d6debea0e037829768e9.js.map.gz → index-853ef1a7fc9c9b7a39577b79564e0896.js.map.gz} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js → indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js} +3 -3
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-35fb4ddfe925b1fb6b7a6c1953b21621.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js → native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js} +5 -5
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-8602ccac919e2b56f2e9a252dd06483e.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js → profiler-b3dd30ba0a88aece50e7e403785f34ba.js} +11 -11
- package/dist/server/web-ui/_expo/static/js/web/profiler-b3dd30ba0a88aece50e7e403785f34ba.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-b3dd30ba0a88aece50e7e403785f34ba.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-b3dd30ba0a88aece50e7e403785f34ba.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-b3dd30ba0a88aece50e7e403785f34ba.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{startRecording-1b57837c4c358ef963a1392d9d96354b.js → startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.js} +60 -60
- package/dist/server/web-ui/_expo/static/js/web/startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{startRecording-1b57837c4c358ef963a1392d9d96354b.js.map.gz → startRecording-fd9fa11e24a3b8d94e5161aae7f42a5d.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/desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-9f03d060da06e8838a4e0fdd5c067757.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d0d9dffa612bf12bf551c5e513c28691.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-461cf3ab1d54d6debea0e037829768e9.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-461cf3ab1d54d6debea0e037829768e9.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-461cf3ab1d54d6debea0e037829768e9.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-54584275ea7a32061741c119074ff13f.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-b53f2ba81a9777f6f6d04a98b0a12c33.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js.map.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/profiler-7b2011c26cedb58cc00c02a7c25fc0a0.js.map.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-1b57837c4c358ef963a1392d9d96354b.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-1b57837c4c358ef963a1392d9d96354b.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/startRecording-1b57837c4c358ef963a1392d9d96354b.js.map.br +0 -0
|
@@ -91,6 +91,10 @@ import { getCaptureStreamWs } from "./meetings/capture-stream-ws.js";
|
|
|
91
91
|
import { createSpeechService } from "./speech/speech-runtime.js";
|
|
92
92
|
import { AgentManager } from "./agent/agent-manager.js";
|
|
93
93
|
import { scheduleSessionDigestRefresh } from "./agent/session-digest-generator.js";
|
|
94
|
+
import { CardMoveLog } from "./agent/card-move-log.js";
|
|
95
|
+
import { BlockerLog } from "./agent/blocker-log.js";
|
|
96
|
+
import { JudgeRelayGate } from "./agent/judge-relay-gate.js";
|
|
97
|
+
import { JarvisJudge } from "./agent/jarvis-judge.js";
|
|
94
98
|
import { registerAgentRoutes } from "./agent/agent-routes.js";
|
|
95
99
|
import { AgentStorage } from "./agent/agent-storage.js";
|
|
96
100
|
import { attachAgentStoragePersistence } from "./persistence-hooks.js";
|
|
@@ -560,11 +564,33 @@ export async function createPaseoDaemon(config, rootLogger) {
|
|
|
560
564
|
isDev: config.isDev === true,
|
|
561
565
|
extraClients: config.agentClients,
|
|
562
566
|
});
|
|
567
|
+
// Jarvis substrate (JARVIS-V1-SPEC §3.2). Append-only kanban move history.
|
|
568
|
+
// Prospective only: nothing before this ships is recoverable, which is why the
|
|
569
|
+
// spec sequences it ahead of every other piece.
|
|
570
|
+
const cardMoveLog = new CardMoveLog({ dir: config.paseoHome, logger });
|
|
571
|
+
// Blocker history. Same prospective-only property as the move log, and it
|
|
572
|
+
// answers a different question: not "how often was this deferred" but "who or
|
|
573
|
+
// what has kept blocking it". mergeDigest overwrites digest.blockers on every
|
|
574
|
+
// derivation, so without this the signal is destroyed on each idle.
|
|
575
|
+
const blockerLog = new BlockerLog({ dir: config.paseoHome, logger });
|
|
576
|
+
// Jarvis judge config (§5, §9.1). Env-driven in v1 to avoid protocol churn
|
|
577
|
+
// while the feature is still being shaped.
|
|
578
|
+
// Gate for the judge's one mutating capability. Enabled only when the judge
|
|
579
|
+
// itself is, so an unconfigured deployment cannot expose relay_to_agent.
|
|
580
|
+
const judgeRelayGate = new JudgeRelayGate({
|
|
581
|
+
enabled: Boolean(process.env.PASEO_JARVIS_AGENT_ID?.trim()),
|
|
582
|
+
});
|
|
583
|
+
const jarvisJudgeConfig = {
|
|
584
|
+
agentId: process.env.PASEO_JARVIS_AGENT_ID?.trim() || null,
|
|
585
|
+
shadow: process.env.PASEO_JARVIS_SHADOW === "1",
|
|
586
|
+
};
|
|
563
587
|
const initialAgentManagerState = providerSnapshotManager.getAgentManagerProviderState();
|
|
564
588
|
const agentManager = new AgentManager({
|
|
565
589
|
clients: initialAgentManagerState.clients,
|
|
566
590
|
providerDefinitions: initialAgentManagerState.providerDefinitions,
|
|
567
591
|
registry: agentStorage,
|
|
592
|
+
cardMoveLog,
|
|
593
|
+
blockerLog,
|
|
568
594
|
appendSystemPrompt: config.appendSystemPrompt,
|
|
569
595
|
onWorkspaceStateMayHaveChanged: ({ cwd }) => {
|
|
570
596
|
workspaceGitService.onWorkspaceStateMayHaveChanged(cwd);
|
|
@@ -577,14 +603,49 @@ export async function createPaseoDaemon(config, rootLogger) {
|
|
|
577
603
|
// and regenerate summary/accomplishments via the borrowed-provider rail (the
|
|
578
604
|
// same one auto-title uses; the daemon holds no API key of its own). Debounced +
|
|
579
605
|
// coalesced inside the scheduler; internal agents never broadcast attention.
|
|
606
|
+
// Jarvis judge (JARVIS-V1-SPEC §5.1). Constructed before the attention
|
|
607
|
+
// listener because the listener has to ORDER the two: see below.
|
|
608
|
+
const jarvisJudge = new JarvisJudge({
|
|
609
|
+
agentManager,
|
|
610
|
+
agentStorage,
|
|
611
|
+
cardMoveLog,
|
|
612
|
+
blockerLog,
|
|
613
|
+
relayGate: judgeRelayGate,
|
|
614
|
+
config: jarvisJudgeConfig,
|
|
615
|
+
logger,
|
|
616
|
+
});
|
|
617
|
+
if (jarvisJudge.enabled) {
|
|
618
|
+
logger.info({ judgeAgentId: jarvisJudgeConfig.agentId, shadow: jarvisJudgeConfig.shadow }, "Jarvis judge enabled");
|
|
619
|
+
}
|
|
580
620
|
agentManager.addAgentAttentionListener((params) => {
|
|
621
|
+
// Never let a judge failure take down attention handling for everyone else.
|
|
622
|
+
const wakeJudge = () => {
|
|
623
|
+
void jarvisJudge.handleAttention({ agentId: params.agentId, reason: params.reason });
|
|
624
|
+
};
|
|
625
|
+
// `error` and `permission` have no derivation step, so nothing to wait for.
|
|
581
626
|
if (params.reason !== "finished") {
|
|
627
|
+
if (jarvisJudge.enabled) {
|
|
628
|
+
wakeJudge();
|
|
629
|
+
}
|
|
582
630
|
return;
|
|
583
631
|
}
|
|
584
632
|
const agent = agentManager.getAgent(params.agentId);
|
|
585
633
|
if (!agent || agent.internal) {
|
|
586
634
|
return;
|
|
587
635
|
}
|
|
636
|
+
// ORDERING IS LOAD-BEARING, and getting it wrong is invisible.
|
|
637
|
+
//
|
|
638
|
+
// The digest refresh and the judge both hang off this one `finished` event.
|
|
639
|
+
// Fired in parallel, the judge wins the race every time and reads a digest
|
|
640
|
+
// that has not been written yet, so its briefing carries no summary, no
|
|
641
|
+
// blockers and no deadline. It then correctly concludes there is nothing
|
|
642
|
+
// worth saying and answers "quiet" forever. No error is raised anywhere: the
|
|
643
|
+
// feature looks healthy and delivers nothing. Verified live in the docker lab
|
|
644
|
+
// before this chaining existed.
|
|
645
|
+
//
|
|
646
|
+
// So the judge is woken from onSettled, which fires on success, skip AND
|
|
647
|
+
// failure. A judge that only ran on the happy path would go quiet exactly
|
|
648
|
+
// when something broke.
|
|
588
649
|
scheduleSessionDigestRefresh({
|
|
589
650
|
agentManager,
|
|
590
651
|
agentId: params.agentId,
|
|
@@ -597,6 +658,7 @@ export async function createPaseoDaemon(config, rootLogger) {
|
|
|
597
658
|
thinkingOptionId: agent.runtimeInfo?.thinkingOptionId ?? agent.config.thinkingOptionId ?? null,
|
|
598
659
|
},
|
|
599
660
|
logger,
|
|
661
|
+
onSettled: jarvisJudge.enabled ? wakeJudge : undefined,
|
|
600
662
|
});
|
|
601
663
|
});
|
|
602
664
|
// Epic 1, Story 1.2 — first-class workflow entity. WorkflowManager orchestrates
|
|
@@ -849,6 +911,17 @@ export async function createPaseoDaemon(config, rootLogger) {
|
|
|
849
911
|
callerAgentId: runtime.callerAgentId,
|
|
850
912
|
enableVoiceTools: runtime.enableVoiceTools,
|
|
851
913
|
voiceOnly: runtime.voiceOnly,
|
|
914
|
+
// JARVIS-V1-SPEC §6, HARD REQUIREMENT. The judge reads untrusted transcripts,
|
|
915
|
+
// so it must not hold a mutating tool. Keyed on identity rather than on a
|
|
916
|
+
// mode, because a mode is something the agent itself could change.
|
|
917
|
+
readOnly: runtime.readOnly ||
|
|
918
|
+
(jarvisJudgeConfig.agentId !== null && runtime.callerAgentId === jarvisJudgeConfig.agentId),
|
|
919
|
+
// Only the judge's own tool sessions get the relay tool, and even then its
|
|
920
|
+
// handler refuses unless a human turn is driving. Identity-keyed, like the
|
|
921
|
+
// read-only surface, so the agent cannot grant it to itself.
|
|
922
|
+
judgeRelayGate: jarvisJudgeConfig.agentId !== null && runtime.callerAgentId === jarvisJudgeConfig.agentId
|
|
923
|
+
? judgeRelayGate
|
|
924
|
+
: undefined,
|
|
852
925
|
resolveSpeakHandler: (agentId) => wsServer?.resolveVoiceSpeakHandler(agentId) ?? null,
|
|
853
926
|
resolveCallerContext: (agentId) => wsServer?.resolveVoiceCallerContext(agentId) ?? null,
|
|
854
927
|
logger,
|
|
@@ -3,6 +3,20 @@ import { EventEmitter } from "node:events";
|
|
|
3
3
|
import { WebSocket } from "ws";
|
|
4
4
|
import { createDaemonChannel, } from "@hyperdrive.bot/paseo-relay/e2ee";
|
|
5
5
|
import { buildRelayWebSocketUrl } from "@hyperdrive.bot/paseo-protocol/daemon-endpoints";
|
|
6
|
+
/**
|
|
7
|
+
* Monotonic milliseconds. Every liveness comparison in this file MUST use this, never
|
|
8
|
+
* Date.now().
|
|
9
|
+
*
|
|
10
|
+
* Date.now() can step. On a WSL2 host whose Windows Time service is stopped, this machine's
|
|
11
|
+
* wall clock oscillated +/-48.6s about six times a minute (69 steps in 11.7 minutes, while
|
|
12
|
+
* monotonic time advanced exactly on schedule). A forward step made a 10s-old ping look 58s
|
|
13
|
+
* stale, so healthy control sockets were terminated every few minutes and every phone client
|
|
14
|
+
* was dropped with them. performance.now() is immune: it cannot go backwards and no clock
|
|
15
|
+
* sync moves it.
|
|
16
|
+
*/
|
|
17
|
+
function monotonicNowMs() {
|
|
18
|
+
return performance.now();
|
|
19
|
+
}
|
|
6
20
|
const CONTROL_PING_INTERVAL_MS = 10000;
|
|
7
21
|
const CONTROL_STALE_TIMEOUT_MS = 30000;
|
|
8
22
|
const CONTROL_READY_TIMEOUT_MS = 8000;
|
|
@@ -138,7 +152,7 @@ export function startRelayTransport({ logger, attachSocket, relayEndpoint, relay
|
|
|
138
152
|
socket.on("open", () => {
|
|
139
153
|
if (controlWs !== socket)
|
|
140
154
|
return;
|
|
141
|
-
controlLastSeenAt =
|
|
155
|
+
controlLastSeenAt = monotonicNowMs();
|
|
142
156
|
if (controlKeepaliveInterval) {
|
|
143
157
|
clearInterval(controlKeepaliveInterval);
|
|
144
158
|
controlKeepaliveInterval = null;
|
|
@@ -162,14 +176,31 @@ export function startRelayTransport({ logger, attachSocket, relayEndpoint, relay
|
|
|
162
176
|
// ignore
|
|
163
177
|
}
|
|
164
178
|
}, CONTROL_READY_TIMEOUT_MS);
|
|
179
|
+
let lastTickAt = monotonicNowMs();
|
|
165
180
|
controlKeepaliveInterval = setInterval(() => {
|
|
166
181
|
if (stopped)
|
|
167
182
|
return;
|
|
168
|
-
|
|
183
|
+
// Instrumentation for a measured anomaly, see docs/tech-debt.md 2026-08-01.
|
|
184
|
+
// Terminations consistently report staleForMs ~58.3s (57455-58566 across 36 samples)
|
|
185
|
+
// although this ticks every 10s and trips past 30s, which can only produce 30-40s.
|
|
186
|
+
// Two candidates remain: the tick is not running at its configured interval, or an
|
|
187
|
+
// interval belonging to a superseded socket is doing the terminating (21 of the 36
|
|
188
|
+
// trips killed a connection whose replacement was already live, always 45.9-47.1s
|
|
189
|
+
// after it connected). These two lines distinguish them; neither is derivable from
|
|
190
|
+
// the logs we have today.
|
|
191
|
+
const tickNow = monotonicNowMs();
|
|
192
|
+
const sinceLastTickMs = tickNow - lastTickAt;
|
|
193
|
+
lastTickAt = tickNow;
|
|
194
|
+
if (sinceLastTickMs > CONTROL_PING_INTERVAL_MS * 1.5) {
|
|
195
|
+
relayLogger.warn({ connectionId, sinceLastTickMs, expectedMs: CONTROL_PING_INTERVAL_MS }, "relay_control_keepalive_tick_late");
|
|
196
|
+
}
|
|
197
|
+
if (controlWs !== socket) {
|
|
198
|
+
relayLogger.warn({ connectionId, sinceLastTickMs }, "relay_control_keepalive_orphaned");
|
|
169
199
|
return;
|
|
200
|
+
}
|
|
170
201
|
if (socket.readyState !== WebSocket.OPEN)
|
|
171
202
|
return;
|
|
172
|
-
const now =
|
|
203
|
+
const now = monotonicNowMs();
|
|
173
204
|
const staleForMs = now - controlLastSeenAt;
|
|
174
205
|
// If the control socket is half-open or silently dropped, ws may never emit "close".
|
|
175
206
|
// Use a WebSocket protocol ping to detect staleness and force a reconnect.
|
|
@@ -236,13 +267,13 @@ export function startRelayTransport({ logger, attachSocket, relayEndpoint, relay
|
|
|
236
267
|
socket.on("pong", () => {
|
|
237
268
|
if (controlWs !== socket)
|
|
238
269
|
return;
|
|
239
|
-
controlLastSeenAt =
|
|
270
|
+
controlLastSeenAt = monotonicNowMs();
|
|
240
271
|
relayLogger.debug({ connectionId }, "relay_control_pong_received");
|
|
241
272
|
});
|
|
242
273
|
socket.on("message", (data) => {
|
|
243
274
|
if (controlWs !== socket)
|
|
244
275
|
return;
|
|
245
|
-
controlLastSeenAt =
|
|
276
|
+
controlLastSeenAt = monotonicNowMs();
|
|
246
277
|
const msg = tryParseControlMessage(data);
|
|
247
278
|
if (msg) {
|
|
248
279
|
markControlReady();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},
|
|
2
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.writeDesktopAttachmentBase64=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_base64",{attachmentId:n.attachmentId,base64:n.base64,extension:n.extension??null})},e.writeDesktopAttachmentBytes=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_bytes",{attachmentId:n.attachmentId,bytes:n.bytes,extension:n.extension??null})},e.copyDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("copy_attachment_file",{attachmentId:n.attachmentId,sourcePath:n.sourcePath,extension:n.extension??null})},e.deleteDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("delete_attachment_file",{path:n.path})},e.garbageCollectDesktopAttachmentFiles=async function(n){return await(0,t.invokeDesktopCommand)("garbage_collect_attachment_files",{referencedIds:[...n.referencedIds]})};var t=r(d[0])},
|
|
3
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.readDesktopFileBase64=s,e.createDesktopFileReader=function(){return{readFileBase64:s}},e.createBrowserObjectUrlMinter=function(){return{tryCreate({mimeType:t,base64:n}){if("undefined"==typeof URL||"function"!=typeof URL.createObjectURL)return null;const o=c(n),s=new ArrayBuffer(o.byteLength);new Uint8Array(s).set(o);const u=new Blob([s],{type:t});return URL.createObjectURL(u)},revoke(t){"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL&&URL.revokeObjectURL(t)}}},e.createDesktopPreviewUrlResolver=function(t){const n=new Set;return{async resolve(o){const s=await t.reader.readFileBase64(o.storageKey),c=t.objectUrls.tryCreate({mimeType:o.mimeType,base64:s});return null===c?`data:${o.mimeType};base64,${s}`:(n.add(c),c)},async release({url:o}){n.has(o)&&(n.delete(o),t.objectUrls.revoke(o))}}};var t=r(d[0]),n=r(d[1]),o=r(d[2]);async function s(o){return await(0,n.invokeDesktopCommand)("read_file_base64",{path:(0,t.fileUriToPath)(o)})}function c(t){return new Uint8Array(o.Buffer.from(t,"base64"))}},
|
|
4
|
-
//# sourceMappingURL=/_expo/static/js/web/desktop-attachment-bridge-
|
|
5
|
-
//# debugId=
|
|
1
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},4780,[4785,4786]);
|
|
2
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.writeDesktopAttachmentBase64=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_base64",{attachmentId:n.attachmentId,base64:n.base64,extension:n.extension??null})},e.writeDesktopAttachmentBytes=async function(n){return await(0,t.invokeDesktopCommand)("write_attachment_bytes",{attachmentId:n.attachmentId,bytes:n.bytes,extension:n.extension??null})},e.copyDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("copy_attachment_file",{attachmentId:n.attachmentId,sourcePath:n.sourcePath,extension:n.extension??null})},e.deleteDesktopAttachmentFile=async function(n){return await(0,t.invokeDesktopCommand)("delete_attachment_file",{path:n.path})},e.garbageCollectDesktopAttachmentFiles=async function(n){return await(0,t.invokeDesktopCommand)("garbage_collect_attachment_files",{referencedIds:[...n.referencedIds]})};var t=r(d[0])},4785,[3406]);
|
|
3
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.readDesktopFileBase64=s,e.createDesktopFileReader=function(){return{readFileBase64:s}},e.createBrowserObjectUrlMinter=function(){return{tryCreate({mimeType:t,base64:n}){if("undefined"==typeof URL||"function"!=typeof URL.createObjectURL)return null;const o=c(n),s=new ArrayBuffer(o.byteLength);new Uint8Array(s).set(o);const u=new Blob([s],{type:t});return URL.createObjectURL(u)},revoke(t){"undefined"!=typeof URL&&"function"==typeof URL.revokeObjectURL&&URL.revokeObjectURL(t)}}},e.createDesktopPreviewUrlResolver=function(t){const n=new Set;return{async resolve(o){const s=await t.reader.readFileBase64(o.storageKey),c=t.objectUrls.tryCreate({mimeType:o.mimeType,base64:s});return null===c?`data:${o.mimeType};base64,${s}`:(n.add(c),c)},async release({url:o}){n.has(o)&&(n.delete(o),t.objectUrls.revoke(o))}}};var t=r(d[0]),n=r(d[1]),o=r(d[2]);async function s(o){return await(0,n.invokeDesktopCommand)("read_file_base64",{path:(0,t.fileUriToPath)(o)})}function c(t){return new Uint8Array(o.Buffer.from(t,"base64"))}},4786,[4481,3406,52]);
|
|
4
|
+
//# sourceMappingURL=/_expo/static/js/web/desktop-attachment-bridge-e6e0f92f1a2959279a7c3b2b50bf1df3.js.map
|
|
5
|
+
//# debugId=391ec10e-786a-4bd5-9972-7810ef469b73
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},
|
|
2
|
-
//# sourceMappingURL=/_expo/static/js/web/desktop-attachment-store-
|
|
3
|
-
//# debugId=
|
|
1
|
+
__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},4779,[4481]);
|
|
2
|
+
//# sourceMappingURL=/_expo/static/js/web/desktop-attachment-store-d5c93939344c993e52d655ccf8942928.js.map
|
|
3
|
+
//# debugId=af1fb756-487c-4cc0-940a-a1a6caef5527
|
|
Binary file
|
|
Binary file
|
|
Binary file
|