agents-dojo 0.1.10 → 0.1.11
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/claude-bridge.js +23 -8
- package/dist/cli.js +4 -3
- package/dist/server.js +5 -0
- package/monitor/src/components/LogPage.tsx +1 -1
- package/monitor/src/lib/dojo-app.ts +91 -83
- package/monitor/src/lib/interactables.ts +2 -2
- package/monitor/src/lib/ws-client.ts +28 -9
- package/monitor/vite.config.ts +8 -2
- package/package.json +1 -1
package/dist/claude-bridge.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/claude-bridge.ts
|
|
2
2
|
import { join } from 'path';
|
|
3
|
-
import { existsSync, mkdirSync, symlinkSync } from 'fs';
|
|
3
|
+
import { existsSync, mkdirSync, symlinkSync, lstatSync, unlinkSync } from 'fs';
|
|
4
4
|
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
5
5
|
export async function* runClaude(params) {
|
|
6
6
|
const { agent, contentBlocks, onEvent, abortController } = params;
|
|
@@ -22,16 +22,31 @@ export async function* runClaude(params) {
|
|
|
22
22
|
? (m.configDir.startsWith('/') ? m.configDir : join(agent.agentDir, m.configDir))
|
|
23
23
|
: join(agent.agentDir, '.claude');
|
|
24
24
|
env.CLAUDE_CONFIG_DIR = agentConfigDir;
|
|
25
|
-
// Ensure the agent's .claude dir exists and symlink global
|
|
26
|
-
//
|
|
25
|
+
// Ensure the agent's .claude dir exists and symlink global config files.
|
|
26
|
+
// Symlinks keep all agents in sync with the user's global config automatically.
|
|
27
27
|
mkdirSync(agentConfigDir, { recursive: true });
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const globalDir = join(process.env.HOME ?? '', '.claude');
|
|
29
|
+
// Symlink settings.json, .credentials.json (auth), and .claude.json (user identity)
|
|
30
|
+
for (const file of ['settings.json', '.credentials.json', '.claude.json']) {
|
|
31
|
+
const globalFile = join(globalDir, file);
|
|
32
|
+
const localFile = join(agentConfigDir, file);
|
|
33
|
+
if (!existsSync(globalFile))
|
|
34
|
+
continue;
|
|
35
|
+
// Replace regular files with symlinks (but keep existing symlinks)
|
|
31
36
|
try {
|
|
32
|
-
|
|
37
|
+
const stat = lstatSync(localFile);
|
|
38
|
+
if (!stat.isSymbolicLink()) {
|
|
39
|
+
unlinkSync(localFile);
|
|
40
|
+
symlinkSync(globalFile, localFile);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// File doesn't exist — create symlink
|
|
45
|
+
try {
|
|
46
|
+
symlinkSync(globalFile, localFile);
|
|
47
|
+
}
|
|
48
|
+
catch { /* ignore */ }
|
|
33
49
|
}
|
|
34
|
-
catch { /* race or permission — ignore */ }
|
|
35
50
|
}
|
|
36
51
|
const options = {
|
|
37
52
|
cwd: agent.agentDir,
|
package/dist/cli.js
CHANGED
|
@@ -238,7 +238,7 @@ function installCallAgentSkill(agentDir) {
|
|
|
238
238
|
export const DEFAULT_ARGS = {
|
|
239
239
|
agentsDir: './agents',
|
|
240
240
|
port: 41241,
|
|
241
|
-
monitorPort: 0, // 0 = OS picks a free port
|
|
241
|
+
monitorPort: 0, // 0 = OS picks a free port; frontend discovers via /monitor/info
|
|
242
242
|
singleAgent: null,
|
|
243
243
|
help: false,
|
|
244
244
|
};
|
|
@@ -305,7 +305,7 @@ function resolveMonitorDir() {
|
|
|
305
305
|
// __dirname is dist/ after build, so monitor/ is one level up
|
|
306
306
|
return resolve(__dirname, '..', 'monitor');
|
|
307
307
|
}
|
|
308
|
-
function startMonitorGui(monitorWsPort) {
|
|
308
|
+
function startMonitorGui(monitorWsPort, a2aPort = 41241) {
|
|
309
309
|
const monitorDir = resolveMonitorDir();
|
|
310
310
|
if (!existsSync(join(monitorDir, 'package.json'))) {
|
|
311
311
|
console.warn('[agents-dojo] Monitor GUI not found — skipping.');
|
|
@@ -329,6 +329,7 @@ function startMonitorGui(monitorWsPort) {
|
|
|
329
329
|
env: {
|
|
330
330
|
...process.env,
|
|
331
331
|
VITE_MONITOR_WS_URL: wsUrl,
|
|
332
|
+
VITE_A2A_PORT: String(a2aPort),
|
|
332
333
|
},
|
|
333
334
|
});
|
|
334
335
|
child.stdout?.on('data', (data) => {
|
|
@@ -417,7 +418,7 @@ async function main() {
|
|
|
417
418
|
// Auto-start monitor GUI
|
|
418
419
|
if (server.monitorPort) {
|
|
419
420
|
console.log(`[agents-dojo] Monitor WS port: ${server.monitorPort}`);
|
|
420
|
-
const monitorChild = startMonitorGui(server.monitorPort);
|
|
421
|
+
const monitorChild = startMonitorGui(server.monitorPort, args.port);
|
|
421
422
|
if (monitorChild) {
|
|
422
423
|
registerCleanup(monitorChild);
|
|
423
424
|
}
|
package/dist/server.js
CHANGED
|
@@ -71,6 +71,11 @@ export async function createServer(opts) {
|
|
|
71
71
|
createMonitorWs({ server: monitorHttp, bus, path: '/monitor', registry, executors: a2a.executors });
|
|
72
72
|
await new Promise((r) => monitorHttp.listen(opts.monitorPort, r));
|
|
73
73
|
actualMonitorPort = monitorHttp.address().port;
|
|
74
|
+
// Discovery endpoint: frontend fetches this to find the WS port
|
|
75
|
+
app.get('/monitor/info', (_req, res) => {
|
|
76
|
+
res.header('Access-Control-Allow-Origin', '*');
|
|
77
|
+
res.json({ wsPort: actualMonitorPort, wsUrl: `ws://localhost:${actualMonitorPort}/monitor` });
|
|
78
|
+
});
|
|
74
79
|
}
|
|
75
80
|
return {
|
|
76
81
|
registry,
|
|
@@ -126,6 +126,14 @@ export class DojoApp {
|
|
|
126
126
|
private agents = new Map<string, AgentState>();
|
|
127
127
|
private interactables: InteractableState[] = [];
|
|
128
128
|
private ready = false;
|
|
129
|
+
// Master state
|
|
130
|
+
private masterContainer!: Container;
|
|
131
|
+
private masterSprite!: Sprite;
|
|
132
|
+
private masterX = MASTER_POS.x;
|
|
133
|
+
private masterY = MASTER_POS.y;
|
|
134
|
+
private masterTargetX = MASTER_POS.x;
|
|
135
|
+
private masterTargetY = MASTER_POS.y;
|
|
136
|
+
private masterFacingLeft = false;
|
|
129
137
|
// Master bubble state
|
|
130
138
|
private masterBubble!: Container;
|
|
131
139
|
private masterBubbleBg!: Graphics;
|
|
@@ -247,13 +255,13 @@ export class DojoApp {
|
|
|
247
255
|
}
|
|
248
256
|
|
|
249
257
|
private createMaster() {
|
|
250
|
-
|
|
251
|
-
masterContainer.x = MASTER_POS.x;
|
|
252
|
-
masterContainer.y = MASTER_POS.y;
|
|
258
|
+
this.masterContainer = new Container();
|
|
259
|
+
this.masterContainer.x = MASTER_POS.x;
|
|
260
|
+
this.masterContainer.y = MASTER_POS.y;
|
|
253
261
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
262
|
+
this.masterSprite = new Sprite(this.masterFrames[0]);
|
|
263
|
+
this.masterSprite.anchor.set(0.5, 1);
|
|
264
|
+
this.masterSprite.scale.set(SPRITE_SCALE);
|
|
257
265
|
|
|
258
266
|
const nameBg = new Graphics();
|
|
259
267
|
nameBg.roundRect(-28, -FRAME_SIZE * SPRITE_SCALE - 14, 56, 14, 3);
|
|
@@ -271,8 +279,8 @@ export class DojoApp {
|
|
|
271
279
|
this.masterBubbleText.anchor.set(0.5, 0);
|
|
272
280
|
this.masterBubble.addChild(this.masterBubbleBg, this.masterBubbleText);
|
|
273
281
|
|
|
274
|
-
masterContainer.addChild(
|
|
275
|
-
this.scene.addChild(masterContainer);
|
|
282
|
+
this.masterContainer.addChild(this.masterSprite, nameBg, label, this.masterBubble);
|
|
283
|
+
this.scene.addChild(this.masterContainer);
|
|
276
284
|
}
|
|
277
285
|
|
|
278
286
|
private createAgent(id: string, agent: Agent) {
|
|
@@ -428,27 +436,29 @@ export class DojoApp {
|
|
|
428
436
|
}
|
|
429
437
|
// Priority 3: Client task states
|
|
430
438
|
else if (state === 'submitted') {
|
|
431
|
-
//
|
|
432
|
-
s.animKey = '
|
|
433
|
-
s.targetX =
|
|
439
|
+
// Agent stays on cushion (sit), Master walks to agent
|
|
440
|
+
s.animKey = 'sit';
|
|
441
|
+
s.targetX = agent.homePosition.x; s.targetY = agent.homePosition.y;
|
|
442
|
+
// Tell Master to walk to this agent
|
|
443
|
+
this.masterTargetX = agent.homePosition.x + 30;
|
|
444
|
+
this.masterTargetY = agent.homePosition.y;
|
|
434
445
|
s.visitedMaster = false;
|
|
435
446
|
}
|
|
436
447
|
else if (state === 'working' || state === 'tool_call') {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
s.targetX = agent.stakePosition.x + STAKE_ATTACK_OFFSET_X;
|
|
445
|
-
s.targetY = agent.stakePosition.y;
|
|
446
|
-
}
|
|
448
|
+
// Agent walks to stake and attacks
|
|
449
|
+
s.animKey = s.arrived ? 'attack' : 'walk';
|
|
450
|
+
s.targetX = agent.stakePosition.x + STAKE_ATTACK_OFFSET_X;
|
|
451
|
+
s.targetY = agent.stakePosition.y;
|
|
452
|
+
// Master returns home
|
|
453
|
+
this.masterTargetX = MASTER_POS.x;
|
|
454
|
+
this.masterTargetY = MASTER_POS.y;
|
|
447
455
|
}
|
|
448
456
|
else if (state === 'input-required' || state === 'auth-required') {
|
|
449
|
-
//
|
|
457
|
+
// Agent waits at stake, Master comes back to agent
|
|
450
458
|
s.animKey = s.arrived ? 'idle' : 'walk';
|
|
451
|
-
s.targetX =
|
|
459
|
+
s.targetX = agent.homePosition.x; s.targetY = agent.homePosition.y;
|
|
460
|
+
this.masterTargetX = agent.homePosition.x + 30;
|
|
461
|
+
this.masterTargetY = agent.homePosition.y;
|
|
452
462
|
}
|
|
453
463
|
else if (state === 'completed' || state === 'canceled') {
|
|
454
464
|
// Walk home
|
|
@@ -477,19 +487,20 @@ export class DojoApp {
|
|
|
477
487
|
}
|
|
478
488
|
}
|
|
479
489
|
else if (state === 'rejected') {
|
|
480
|
-
//
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
490
|
+
// Agent stays at cushion, shakes head when Master arrives
|
|
491
|
+
s.targetX = agent.homePosition.x; s.targetY = agent.homePosition.y;
|
|
492
|
+
this.masterTargetX = agent.homePosition.x + 30;
|
|
493
|
+
this.masterTargetY = agent.homePosition.y;
|
|
494
|
+
if (s.rejectTimer === undefined) {
|
|
485
495
|
s.animKey = 'head_shake';
|
|
486
496
|
s.rejectTimer = 0;
|
|
487
497
|
} else if (s.rejectTimer < 1500) {
|
|
488
498
|
s.animKey = 'head_shake';
|
|
489
499
|
} else {
|
|
490
|
-
|
|
491
|
-
s.
|
|
492
|
-
|
|
500
|
+
// Done shaking, go back to sit
|
|
501
|
+
s.animKey = 'sit';
|
|
502
|
+
this.masterTargetX = MASTER_POS.x;
|
|
503
|
+
this.masterTargetY = MASTER_POS.y;
|
|
493
504
|
}
|
|
494
505
|
}
|
|
495
506
|
// else: idle — handled by auto-behavior in tick
|
|
@@ -546,36 +557,10 @@ export class DojoApp {
|
|
|
546
557
|
}
|
|
547
558
|
if (s.idleGrace > 0) s.idleGrace -= dt;
|
|
548
559
|
|
|
549
|
-
// Auto-behavior when idle
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
if (action.kind === 'sit') {
|
|
554
|
-
// Sit on cushion (home position)
|
|
555
|
-
s.animKey = 'sit';
|
|
556
|
-
s.targetX = agent.homePosition.x; s.targetY = agent.homePosition.y;
|
|
557
|
-
action.timer += dt;
|
|
558
|
-
if (action.timer >= (action.duration ?? 5000)) {
|
|
559
|
-
s.autoAction = this.pickAutoAction();
|
|
560
|
-
s.arrived = false;
|
|
561
|
-
}
|
|
562
|
-
} else if (action.kind === 'wander') {
|
|
563
|
-
s.animKey = 'walk';
|
|
564
|
-
s.targetX = action.target!.x;
|
|
565
|
-
s.targetY = action.target!.y;
|
|
566
|
-
if (s.arrived) {
|
|
567
|
-
s.autoAction = this.pickAutoAction();
|
|
568
|
-
s.arrived = false;
|
|
569
|
-
}
|
|
570
|
-
} else if (action.kind === 'daydream' || action.kind === 'pause') {
|
|
571
|
-
s.animKey = action.kind === 'daydream' ? 'daydream' : 'idle';
|
|
572
|
-
s.targetX = s.x; s.targetY = s.y;
|
|
573
|
-
action.timer += dt;
|
|
574
|
-
if (action.timer >= (action.duration ?? 3000)) {
|
|
575
|
-
s.autoAction = this.pickAutoAction();
|
|
576
|
-
s.arrived = false;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
560
|
+
// Auto-behavior when idle: always sit on cushion
|
|
561
|
+
if (isIdle && !isInPeerChat) {
|
|
562
|
+
s.animKey = s.arrived ? 'sit' : 'walk';
|
|
563
|
+
s.targetX = agent.homePosition.x; s.targetY = agent.homePosition.y;
|
|
579
564
|
}
|
|
580
565
|
|
|
581
566
|
// Advance fail/reject timers
|
|
@@ -595,28 +580,17 @@ export class DojoApp {
|
|
|
595
580
|
if (Math.abs(dx) > 0.5) s.facingLeft = dx < 0;
|
|
596
581
|
let nx = s.x + (dx / dist) * MOVE_SPEED;
|
|
597
582
|
let ny = s.y + (dy / dist) * MOVE_SPEED;
|
|
598
|
-
// Obstacle avoidance when
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const od = Math.hypot(nx - o.x, ny - o.y);
|
|
602
|
-
if (od < o.r + 8 && od > 0.1) {
|
|
603
|
-
nx = o.x + ((nx - o.x) / od) * (o.r + 8);
|
|
604
|
-
ny = o.y + ((ny - o.y) / od) * (o.r + 8);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
583
|
+
// Obstacle avoidance: only when not heading to a specific target
|
|
584
|
+
// (idle agents heading home, or task agents heading to stake/master, skip avoidance)
|
|
585
|
+
// Avoidance is only useful during peer-chat or other free movement
|
|
608
586
|
s.x = nx; s.y = ny;
|
|
609
587
|
} else {
|
|
610
588
|
if (!s.arrived) { s.x = s.targetX; s.y = s.targetY; }
|
|
611
589
|
s.arrived = true;
|
|
612
590
|
}
|
|
613
591
|
|
|
614
|
-
//
|
|
615
|
-
|
|
616
|
-
&& Math.hypot(s.x - MASTER_POS.x - 30, s.y - MASTER_POS.y) < MOVE_SPEED * 3) {
|
|
617
|
-
s.visitedMaster = true;
|
|
618
|
-
s.arrived = false;
|
|
619
|
-
}
|
|
592
|
+
// Note: visitedMaster is now set by the Master movement block when Master
|
|
593
|
+
// arrives at the agent's cushion position.
|
|
620
594
|
|
|
621
595
|
// Peer chat: face toward partner when arrived
|
|
622
596
|
if (isInPeerChat && s.arrived) {
|
|
@@ -687,6 +661,44 @@ export class DojoApp {
|
|
|
687
661
|
}
|
|
688
662
|
}
|
|
689
663
|
|
|
664
|
+
// ── Master movement ──────────────────────────────────────
|
|
665
|
+
{
|
|
666
|
+
const dx = this.masterTargetX - this.masterX;
|
|
667
|
+
const dy = this.masterTargetY - this.masterY;
|
|
668
|
+
const dist = Math.hypot(dx, dy);
|
|
669
|
+
if (dist > MOVE_SPEED * 2) {
|
|
670
|
+
if (Math.abs(dx) > 0.5) this.masterFacingLeft = dx < 0;
|
|
671
|
+
this.masterX += (dx / dist) * MOVE_SPEED;
|
|
672
|
+
this.masterY += (dy / dist) * MOVE_SPEED;
|
|
673
|
+
// Use walk frame for master (alternate between frame 0 and 1)
|
|
674
|
+
const walkFrame = Math.floor(performance.now() / 200) % 2;
|
|
675
|
+
this.masterSprite.texture = this.masterFrames[walkFrame] ?? this.masterFrames[0];
|
|
676
|
+
} else {
|
|
677
|
+
this.masterX = this.masterTargetX;
|
|
678
|
+
this.masterY = this.masterTargetY;
|
|
679
|
+
this.masterSprite.texture = this.masterFrames[0];
|
|
680
|
+
|
|
681
|
+
// When Master arrives at an agent in submitted state → transition agent to working
|
|
682
|
+
// (The store will handle this via the normal task_status flow from backend,
|
|
683
|
+
// but visually we detect Master arrival to trigger agent getting up)
|
|
684
|
+
for (const [, s] of this.agents) {
|
|
685
|
+
if (!s.visitedMaster && s.animKey === 'sit') {
|
|
686
|
+
const agentStore = [...useMonitorStore.getState().agents.values()].find(
|
|
687
|
+
a => a.state === 'submitted' &&
|
|
688
|
+
Math.abs(a.homePosition.x + 30 - this.masterX) < 5 &&
|
|
689
|
+
Math.abs(a.homePosition.y - this.masterY) < 5
|
|
690
|
+
);
|
|
691
|
+
if (agentStore) {
|
|
692
|
+
s.visitedMaster = true;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
this.masterSprite.scale.x = (this.masterFacingLeft ? -1 : 1) * SPRITE_SCALE;
|
|
698
|
+
this.masterContainer.x = this.masterX;
|
|
699
|
+
this.masterContainer.y = this.masterY;
|
|
700
|
+
}
|
|
701
|
+
|
|
690
702
|
// Master bubble: show client's message with chunked display
|
|
691
703
|
const masterMsg = useMonitorStore.getState().masterMessage;
|
|
692
704
|
if (masterMsg) {
|
|
@@ -768,12 +780,8 @@ export class DojoApp {
|
|
|
768
780
|
}
|
|
769
781
|
|
|
770
782
|
private pickAutoAction() {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
if (r < 0.45) return { kind: 'sit', duration: 5000 + Math.random() * 8000, timer: 0 };
|
|
774
|
-
if (r < 0.70) return { kind: 'wander', target: randomFloorPos(), timer: 0 };
|
|
775
|
-
if (r < 0.85) return { kind: 'daydream', duration: 3000 + Math.random() * 5000, timer: 0 };
|
|
776
|
-
return { kind: 'pause', duration: 1000 + Math.random() * 2000, timer: 0 };
|
|
783
|
+
// Idle agents always sit on cushion
|
|
784
|
+
return { kind: 'sit', timer: 0 };
|
|
777
785
|
}
|
|
778
786
|
|
|
779
787
|
private animToStoreAnim(key: string): AgentAnim {
|
|
@@ -66,8 +66,8 @@ const STAKE_HALF_W = 21;
|
|
|
66
66
|
const STAKE_AGENT_GAP = 4; // gap between agent and stake edge
|
|
67
67
|
const STAKE_AGENT_OFFSET_X = STAKE_HALF_W + STAKE_AGENT_GAP; // 25px
|
|
68
68
|
|
|
69
|
-
// Cushion: agent sits
|
|
70
|
-
const CUSHION_SIT_OFFSET_Y =
|
|
69
|
+
// Cushion: agent sits on top of cushion — offset positions feet below cushion center
|
|
70
|
+
const CUSHION_SIT_OFFSET_Y = 7;
|
|
71
71
|
|
|
72
72
|
// ── Build interactable list from positions data ────────────
|
|
73
73
|
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
import { useMonitorStore } from './store.js';
|
|
2
2
|
import type { MonitorEvent } from './types.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/** Discover WS URL from the server's /monitor/info endpoint (proxied by Vite). */
|
|
5
|
+
async function discoverWsUrl(): Promise<string> {
|
|
6
|
+
try {
|
|
7
|
+
const resp = await fetch('/monitor/info');
|
|
8
|
+
const data = await resp.json();
|
|
9
|
+
if (data.wsUrl) return data.wsUrl;
|
|
10
|
+
} catch { /* fallback */ }
|
|
11
|
+
return import.meta.env.VITE_MONITOR_WS_URL || 'ws://localhost:41242/monitor';
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
/** Shared persistent connection for both events and commands. */
|
|
7
15
|
let sharedWs: WebSocket | null = null;
|
|
8
16
|
|
|
9
17
|
export function connectWs(): () => void {
|
|
10
|
-
|
|
18
|
+
let cancelled = false;
|
|
19
|
+
|
|
20
|
+
discoverWsUrl().then((wsUrl) => {
|
|
21
|
+
if (cancelled) return;
|
|
22
|
+
const ws = new WebSocket(wsUrl);
|
|
23
|
+
setupWs(ws);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return () => { cancelled = true; if (sharedWs) sharedWs.close(); };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function setupWs(ws: WebSocket): void {
|
|
11
30
|
sharedWs = ws;
|
|
12
31
|
|
|
13
32
|
ws.addEventListener('open', () => {
|
|
@@ -32,8 +51,6 @@ export function connectWs(): () => void {
|
|
|
32
51
|
console.error('[ws-client] bad message:', err);
|
|
33
52
|
}
|
|
34
53
|
});
|
|
35
|
-
|
|
36
|
-
return () => ws.close();
|
|
37
54
|
}
|
|
38
55
|
|
|
39
56
|
export function sendCommand(cmd: object): void {
|
|
@@ -41,11 +58,13 @@ export function sendCommand(cmd: object): void {
|
|
|
41
58
|
sharedWs.send(JSON.stringify(cmd));
|
|
42
59
|
return;
|
|
43
60
|
}
|
|
44
|
-
// Fallback: open a one-shot connection
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
ws.
|
|
48
|
-
|
|
61
|
+
// Fallback: discover URL and open a one-shot connection
|
|
62
|
+
discoverWsUrl().then((url) => {
|
|
63
|
+
const ws = new WebSocket(url);
|
|
64
|
+
ws.addEventListener('open', () => {
|
|
65
|
+
ws.send(JSON.stringify(cmd));
|
|
66
|
+
ws.close();
|
|
67
|
+
});
|
|
49
68
|
});
|
|
50
69
|
}
|
|
51
70
|
|
package/monitor/vite.config.ts
CHANGED
|
@@ -9,8 +9,14 @@ export default defineConfig({
|
|
|
9
9
|
server: {
|
|
10
10
|
port: 5173,
|
|
11
11
|
proxy: {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
'/monitor/info': {
|
|
13
|
+
target: `http://localhost:${process.env.VITE_A2A_PORT || '41241'}`,
|
|
14
|
+
changeOrigin: true,
|
|
15
|
+
},
|
|
16
|
+
'/logs': {
|
|
17
|
+
target: `http://localhost:${process.env.VITE_A2A_PORT || '41241'}`,
|
|
18
|
+
changeOrigin: true,
|
|
19
|
+
},
|
|
14
20
|
},
|
|
15
21
|
},
|
|
16
22
|
});
|