agent-relay 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bridge/spawner.d.ts +1 -1
- package/dist/bridge/spawner.js +189 -70
- package/dist/cli/index.js +25 -8
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/_next/static/chunks/64-2cf6a4c4286af350.js +1 -0
- package/dist/dashboard/out/app/onboarding.html +1 -1
- package/dist/dashboard/out/app/onboarding.txt +1 -1
- package/dist/dashboard/out/app.html +1 -1
- package/dist/dashboard/out/app.txt +2 -2
- package/dist/dashboard/out/cloud/link.html +1 -1
- package/dist/dashboard/out/cloud/link.txt +1 -1
- package/dist/dashboard/out/connect-repos.html +1 -1
- package/dist/dashboard/out/connect-repos.txt +1 -1
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +1 -1
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +2 -2
- package/dist/dashboard/out/login.html +1 -1
- package/dist/dashboard/out/login.txt +1 -1
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +1 -1
- package/dist/dashboard/out/pricing.html +1 -1
- package/dist/dashboard/out/pricing.txt +1 -1
- package/dist/dashboard/out/providers/setup/claude.html +1 -1
- package/dist/dashboard/out/providers/setup/claude.txt +1 -1
- package/dist/dashboard/out/providers/setup/codex.html +1 -1
- package/dist/dashboard/out/providers/setup/codex.txt +1 -1
- package/dist/dashboard/out/providers.html +1 -1
- package/dist/dashboard/out/providers.txt +1 -1
- package/dist/dashboard/out/signup.html +1 -1
- package/dist/dashboard/out/signup.txt +1 -1
- package/dist/dashboard-server/server.js +32 -7
- package/dist/dashboard-server/user-bridge.d.ts +6 -0
- package/dist/dashboard-server/user-bridge.js +23 -0
- package/package.json +1 -1
- package/dist/dashboard/out/_next/static/chunks/64-87ab9cd6bcf2f737.js +0 -1
- /package/dist/dashboard/out/_next/static/{IxxVRv94L1w3ReRGAiI-k → c6Ndf9KrCr5HE-vSoIyj6}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{IxxVRv94L1w3ReRGAiI-k → c6Ndf9KrCr5HE-vSoIyj6}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -190,7 +190,7 @@ npx prpm install @agent-relay/agent-relay-snippet
|
|
|
190
190
|
npx prpm install @agent-relay/agent-relay-snippet --location CLAUDE.md
|
|
191
191
|
```
|
|
192
192
|
|
|
193
|
-
View the rest of our packages on
|
|
193
|
+
View the rest of our packages on our [prpm organization page](https://prpm.dev/orgs?name=Agent%20Relay)
|
|
194
194
|
|
|
195
195
|
Or manually add the relay patterns to your agent instructions.
|
|
196
196
|
|
package/dist/bridge/spawner.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Handles spawning and releasing worker agents via node-pty.
|
|
4
4
|
* Workers run headlessly with output capture for logs.
|
|
5
5
|
*/
|
|
6
|
-
import type
|
|
6
|
+
import { type SummaryEvent, type SessionEndEvent } from '../wrapper/pty-wrapper.js';
|
|
7
7
|
import { AgentPolicyService, type CloudPolicyFetcher } from '../policy/agent-policy.js';
|
|
8
8
|
import type { SpawnRequest, SpawnResult, WorkerInfo, SpawnWithShadowRequest, SpawnWithShadowResult } from './types.js';
|
|
9
9
|
/**
|
package/dist/bridge/spawner.js
CHANGED
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import fs from 'node:fs';
|
|
7
7
|
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
8
9
|
import { sleep } from './utils.js';
|
|
9
10
|
import { getProjectPaths } from '../utils/project-namespace.js';
|
|
10
11
|
import { resolveCommand } from '../utils/command-resolver.js';
|
|
11
12
|
import { RelayPtyOrchestrator } from '../wrapper/relay-pty-orchestrator.js';
|
|
13
|
+
import { PtyWrapper } from '../wrapper/pty-wrapper.js';
|
|
12
14
|
import { selectShadowCli } from './shadow-cli.js';
|
|
15
|
+
// Get the directory where this module is located (for binary path resolution)
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = path.dirname(__filename);
|
|
13
18
|
import { AgentPolicyService } from '../policy/agent-policy.js';
|
|
14
19
|
import { buildClaudeArgs } from '../utils/agent-config.js';
|
|
15
20
|
import { getUserDirectoryService } from '../daemon/user-directory.js';
|
|
@@ -25,23 +30,108 @@ function getRelayInstructions(agentName) {
|
|
|
25
30
|
'',
|
|
26
31
|
'## Sending Messages',
|
|
27
32
|
'',
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
33
|
+
'Write a file to your outbox, then output the trigger:',
|
|
34
|
+
'',
|
|
35
|
+
'```bash',
|
|
36
|
+
`cat > /tmp/relay-outbox/${agentName}/msg << 'EOF'`,
|
|
37
|
+
'TO: TargetAgent',
|
|
38
|
+
'',
|
|
39
|
+
'Your message here.',
|
|
40
|
+
'EOF',
|
|
41
|
+
'```',
|
|
42
|
+
'',
|
|
43
|
+
'Then output: `->relay-file:msg`',
|
|
31
44
|
'',
|
|
32
45
|
'## Communication Rules',
|
|
33
46
|
'',
|
|
34
47
|
'1. **ACK immediately** - When you receive a task:',
|
|
35
|
-
'
|
|
36
|
-
|
|
48
|
+
'```bash',
|
|
49
|
+
`cat > /tmp/relay-outbox/${agentName}/ack << 'EOF'`,
|
|
50
|
+
'TO: Sender',
|
|
51
|
+
'',
|
|
52
|
+
'ACK: Brief description of task received',
|
|
53
|
+
'EOF',
|
|
54
|
+
'```',
|
|
55
|
+
'Then: `->relay-file:ack`',
|
|
37
56
|
'',
|
|
38
57
|
'2. **Report completion** - When done:',
|
|
39
|
-
'
|
|
40
|
-
|
|
58
|
+
'```bash',
|
|
59
|
+
`cat > /tmp/relay-outbox/${agentName}/done << 'EOF'`,
|
|
60
|
+
'TO: Sender',
|
|
61
|
+
'',
|
|
62
|
+
'DONE: Brief summary of what was completed',
|
|
63
|
+
'EOF',
|
|
64
|
+
'```',
|
|
65
|
+
'Then: `->relay-file:done`',
|
|
66
|
+
'',
|
|
67
|
+
'## Message Format',
|
|
41
68
|
'',
|
|
42
|
-
'
|
|
69
|
+
'```',
|
|
70
|
+
'TO: Target',
|
|
71
|
+
'THREAD: optional-thread',
|
|
72
|
+
'',
|
|
73
|
+
'Message body (everything after blank line)',
|
|
74
|
+
'```',
|
|
75
|
+
'',
|
|
76
|
+
'| TO Value | Behavior |',
|
|
77
|
+
'|----------|----------|',
|
|
78
|
+
'| `AgentName` | Direct message |',
|
|
79
|
+
'| `*` | Broadcast to all |',
|
|
80
|
+
'| `#channel` | Channel message |',
|
|
43
81
|
].join('\n');
|
|
44
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Check if the relay-pty binary is available.
|
|
85
|
+
* Returns the path to the binary if found, null otherwise.
|
|
86
|
+
*
|
|
87
|
+
* Search order:
|
|
88
|
+
* 1. bin/relay-pty in package root (installed by postinstall)
|
|
89
|
+
* 2. relay-pty/target/release/relay-pty (local Rust build)
|
|
90
|
+
* 3. /usr/local/bin/relay-pty (global install)
|
|
91
|
+
*/
|
|
92
|
+
function findRelayPtyBinary() {
|
|
93
|
+
// Get the package root (three levels up from dist/bridge/)
|
|
94
|
+
const packageRoot = path.join(__dirname, '..', '..');
|
|
95
|
+
const candidates = [
|
|
96
|
+
// Primary: installed by postinstall from platform-specific binary
|
|
97
|
+
path.join(packageRoot, 'bin', 'relay-pty'),
|
|
98
|
+
// Development: local Rust build
|
|
99
|
+
path.join(packageRoot, 'relay-pty', 'target', 'release', 'relay-pty'),
|
|
100
|
+
path.join(packageRoot, 'relay-pty', 'target', 'debug', 'relay-pty'),
|
|
101
|
+
// Local build in cwd (for development)
|
|
102
|
+
path.join(process.cwd(), 'relay-pty', 'target', 'release', 'relay-pty'),
|
|
103
|
+
// Installed globally
|
|
104
|
+
'/usr/local/bin/relay-pty',
|
|
105
|
+
// In node_modules (when installed as dependency)
|
|
106
|
+
path.join(process.cwd(), 'node_modules', 'agent-relay', 'bin', 'relay-pty'),
|
|
107
|
+
];
|
|
108
|
+
for (const candidate of candidates) {
|
|
109
|
+
if (fs.existsSync(candidate)) {
|
|
110
|
+
return candidate;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
/** Cached result of relay-pty binary check */
|
|
116
|
+
let relayPtyBinaryPath;
|
|
117
|
+
let relayPtyBinaryChecked = false;
|
|
118
|
+
/**
|
|
119
|
+
* Check if relay-pty binary is available (cached).
|
|
120
|
+
* Returns true if the binary exists, false otherwise.
|
|
121
|
+
*/
|
|
122
|
+
function hasRelayPtyBinary() {
|
|
123
|
+
if (!relayPtyBinaryChecked) {
|
|
124
|
+
relayPtyBinaryPath = findRelayPtyBinary();
|
|
125
|
+
relayPtyBinaryChecked = true;
|
|
126
|
+
if (relayPtyBinaryPath) {
|
|
127
|
+
console.log(`[spawner] relay-pty binary found: ${relayPtyBinaryPath}`);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
console.log('[spawner] relay-pty binary not found, will use PtyWrapper fallback');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return relayPtyBinaryPath !== null;
|
|
134
|
+
}
|
|
45
135
|
export class AgentSpawner {
|
|
46
136
|
activeWorkers = new Map();
|
|
47
137
|
agentsPath;
|
|
@@ -262,70 +352,99 @@ export class AgentSpawner {
|
|
|
262
352
|
}
|
|
263
353
|
if (debug)
|
|
264
354
|
console.log(`[spawner:debug] Socket path for ${name}: ${this.socketPath ?? 'undefined'}`);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
355
|
+
// Check if relay-pty binary is available - use PtyWrapper as fallback
|
|
356
|
+
const useRelayPty = hasRelayPtyBinary();
|
|
357
|
+
// Common exit handler for both wrapper types
|
|
358
|
+
const onExitHandler = (code) => {
|
|
359
|
+
if (debug)
|
|
360
|
+
console.log(`[spawner:debug] Worker ${name} exited with code ${code}`);
|
|
361
|
+
// Get the agentId and clean up listeners before removing from active workers
|
|
362
|
+
const worker = this.activeWorkers.get(name);
|
|
363
|
+
const agentId = worker?.pty?.getAgentId?.();
|
|
364
|
+
if (worker?.listeners) {
|
|
365
|
+
this.unbindListeners(worker.pty, worker.listeners);
|
|
366
|
+
}
|
|
367
|
+
this.activeWorkers.delete(name);
|
|
368
|
+
try {
|
|
369
|
+
this.saveWorkersMetadata();
|
|
370
|
+
}
|
|
371
|
+
catch (err) {
|
|
372
|
+
console.error(`[spawner] Failed to save metadata on exit:`, err);
|
|
373
|
+
}
|
|
374
|
+
// Notify if agent died unexpectedly (non-zero exit)
|
|
375
|
+
if (code !== 0 && code !== null && this.onAgentDeath) {
|
|
376
|
+
this.onAgentDeath({
|
|
377
|
+
name,
|
|
378
|
+
exitCode: code,
|
|
379
|
+
agentId,
|
|
380
|
+
resumeInstructions: agentId
|
|
381
|
+
? `To resume this agent's work, use: --resume ${agentId}`
|
|
382
|
+
: undefined,
|
|
290
383
|
});
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const agentId = worker?.pty?.getAgentId?.();
|
|
304
|
-
if (worker?.listeners) {
|
|
305
|
-
this.unbindListeners(worker.pty, worker.listeners);
|
|
306
|
-
}
|
|
307
|
-
this.activeWorkers.delete(name);
|
|
308
|
-
try {
|
|
309
|
-
this.saveWorkersMetadata();
|
|
310
|
-
}
|
|
311
|
-
catch (err) {
|
|
312
|
-
console.error(`[spawner] Failed to save metadata on exit:`, err);
|
|
313
|
-
}
|
|
314
|
-
// Notify if agent died unexpectedly (non-zero exit)
|
|
315
|
-
if (code !== 0 && code !== null && this.onAgentDeath) {
|
|
316
|
-
this.onAgentDeath({
|
|
317
|
-
name,
|
|
318
|
-
exitCode: code,
|
|
319
|
-
agentId,
|
|
320
|
-
resumeInstructions: agentId
|
|
321
|
-
? `To resume this agent's work, use: --resume ${agentId}`
|
|
322
|
-
: undefined,
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
},
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
// Common spawn/release handlers
|
|
387
|
+
const onSpawnHandler = this.dashboardPort ? undefined : async (workerName, workerCli, workerTask) => {
|
|
388
|
+
if (debug)
|
|
389
|
+
console.log(`[spawner:debug] Nested spawn: ${workerName}`);
|
|
390
|
+
await this.spawn({
|
|
391
|
+
name: workerName,
|
|
392
|
+
cli: workerCli,
|
|
393
|
+
task: workerTask,
|
|
394
|
+
userId,
|
|
395
|
+
});
|
|
326
396
|
};
|
|
327
|
-
|
|
328
|
-
|
|
397
|
+
const onReleaseHandler = this.dashboardPort ? undefined : async (workerName) => {
|
|
398
|
+
if (debug)
|
|
399
|
+
console.log(`[spawner:debug] Release request: ${workerName}`);
|
|
400
|
+
await this.release(workerName);
|
|
401
|
+
};
|
|
402
|
+
// Create the appropriate wrapper based on binary availability
|
|
403
|
+
let pty;
|
|
404
|
+
if (useRelayPty) {
|
|
405
|
+
const ptyConfig = {
|
|
406
|
+
name,
|
|
407
|
+
command,
|
|
408
|
+
args,
|
|
409
|
+
socketPath: this.socketPath,
|
|
410
|
+
cwd: agentCwd,
|
|
411
|
+
dashboardPort: this.dashboardPort,
|
|
412
|
+
env: userEnv,
|
|
413
|
+
streamLogs: true,
|
|
414
|
+
shadowOf: request.shadowOf,
|
|
415
|
+
shadowSpeakOn: request.shadowSpeakOn,
|
|
416
|
+
skipContinuity: true,
|
|
417
|
+
onSpawn: onSpawnHandler,
|
|
418
|
+
onRelease: onReleaseHandler,
|
|
419
|
+
onExit: onExitHandler,
|
|
420
|
+
};
|
|
421
|
+
pty = new RelayPtyOrchestrator(ptyConfig);
|
|
422
|
+
if (debug)
|
|
423
|
+
console.log(`[spawner:debug] Using RelayPtyOrchestrator for ${name}`);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
const ptyConfig = {
|
|
427
|
+
name,
|
|
428
|
+
command,
|
|
429
|
+
args,
|
|
430
|
+
socketPath: this.socketPath,
|
|
431
|
+
cwd: agentCwd,
|
|
432
|
+
dashboardPort: this.dashboardPort,
|
|
433
|
+
env: userEnv,
|
|
434
|
+
streamLogs: true,
|
|
435
|
+
shadowOf: request.shadowOf,
|
|
436
|
+
shadowSpeakOn: request.shadowSpeakOn,
|
|
437
|
+
skipContinuity: true,
|
|
438
|
+
onSpawn: onSpawnHandler,
|
|
439
|
+
onRelease: onReleaseHandler,
|
|
440
|
+
onExit: onExitHandler,
|
|
441
|
+
logsDir: this.logsDir,
|
|
442
|
+
allowSpawn: true,
|
|
443
|
+
};
|
|
444
|
+
pty = new PtyWrapper(ptyConfig);
|
|
445
|
+
if (debug)
|
|
446
|
+
console.log(`[spawner:debug] Using PtyWrapper fallback for ${name}`);
|
|
447
|
+
}
|
|
329
448
|
// Track listener references for proper cleanup
|
|
330
449
|
const listeners = {};
|
|
331
450
|
// Hook up output events for live log streaming
|
package/dist/cli/index.js
CHANGED
|
@@ -1117,20 +1117,37 @@ ${projectContext}
|
|
|
1117
1117
|
|
|
1118
1118
|
## Cross-Project Messaging
|
|
1119
1119
|
|
|
1120
|
-
|
|
1120
|
+
Write a file to your outbox, then output the trigger. Use project:AgentName syntax:
|
|
1121
1121
|
|
|
1122
|
+
\`\`\`bash
|
|
1123
|
+
# Message specific project lead
|
|
1124
|
+
cat > /tmp/relay-outbox/\$AGENT_RELAY_NAME/msg << 'EOF'
|
|
1125
|
+
TO: ${valid[0].id}:${valid[0].leadName}
|
|
1126
|
+
|
|
1127
|
+
Your message to this project's lead.
|
|
1128
|
+
EOF
|
|
1122
1129
|
\`\`\`
|
|
1123
|
-
|
|
1124
|
-
Your message to this project's lead>>>
|
|
1130
|
+
Then output: \`->relay-file:msg\`
|
|
1125
1131
|
|
|
1126
|
-
|
|
1127
|
-
Broadcast to all agents in a project
|
|
1132
|
+
\`\`\`bash
|
|
1133
|
+
# Broadcast to all agents in a project
|
|
1134
|
+
cat > /tmp/relay-outbox/\$AGENT_RELAY_NAME/broadcast << 'EOF'
|
|
1135
|
+
TO: ${valid.length > 1 ? valid[1].id : valid[0].id}:*
|
|
1128
1136
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1137
|
+
Broadcast to all agents in a project.
|
|
1138
|
+
EOF
|
|
1131
1139
|
\`\`\`
|
|
1140
|
+
Then output: \`->relay-file:broadcast\`
|
|
1141
|
+
|
|
1142
|
+
\`\`\`bash
|
|
1143
|
+
# Broadcast to ALL agents in ALL projects
|
|
1144
|
+
cat > /tmp/relay-outbox/\$AGENT_RELAY_NAME/all << 'EOF'
|
|
1145
|
+
TO: *:*
|
|
1132
1146
|
|
|
1133
|
-
|
|
1147
|
+
Broadcast to ALL agents in ALL projects.
|
|
1148
|
+
EOF
|
|
1149
|
+
\`\`\`
|
|
1150
|
+
Then output: \`->relay-file:all\`
|
|
1134
1151
|
|
|
1135
1152
|
## Getting Started
|
|
1136
1153
|
1. Check in with each project lead to understand current status
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/8f9ed310f454e5a5.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-1cdd8ed57114d5e1.js"/><script src="/_next/static/chunks/fd9d1056-609918ca7b6280bb.js" async=""></script><script src="/_next/static/chunks/117-c8afed19e821a35d.js" async=""></script><script src="/_next/static/chunks/main-app-6e8e8d3ef4e0192a.js" async=""></script><meta name="robots" content="noindex"/><title>404: This page could not be found.</title><title>Agent Relay Dashboard</title><meta name="description" content="Fleet control dashboard for Agent Relay"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><script src="/_next/static/chunks/webpack-1cdd8ed57114d5e1.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/8f9ed310f454e5a5.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[4707,[],\"\"]\n5:I[6423,[],\"\"]\nb:I[1060,[],\"\"]\n6:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n7:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n8:{\"display\":\"inline-block\"}\n9:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nc:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"
|
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/8f9ed310f454e5a5.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-1cdd8ed57114d5e1.js"/><script src="/_next/static/chunks/fd9d1056-609918ca7b6280bb.js" async=""></script><script src="/_next/static/chunks/117-c8afed19e821a35d.js" async=""></script><script src="/_next/static/chunks/main-app-6e8e8d3ef4e0192a.js" async=""></script><meta name="robots" content="noindex"/><title>404: This page could not be found.</title><title>Agent Relay Dashboard</title><meta name="description" content="Fleet control dashboard for Agent Relay"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><script src="/_next/static/chunks/webpack-1cdd8ed57114d5e1.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/8f9ed310f454e5a5.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[4707,[],\"\"]\n5:I[6423,[],\"\"]\nb:I[1060,[],\"\"]\n6:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n7:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n8:{\"display\":\"inline-block\"}\n9:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nc:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"c6Ndf9KrCr5HE-vSoIyj6\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"_not-found\"],\"initialTree\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null],null],null]},[null,[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"/_not-found\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/8f9ed310f454e5a5.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$6\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$7\",\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":\"$8\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$9\",\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],\"$La\"],\"globalErrorComponent\":\"$b\",\"missingSlots\":\"$Wc\"}]\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"Agent Relay Dashboard\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Fleet control dashboard for Agent Relay\"}]]\n3:null\n"])</script></body></html>
|