robopark 3.3.36 → 3.3.38

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.
Files changed (50) hide show
  1. package/dist/robopark/add-robot.js +2 -2
  2. package/dist/robopark/add-robot.js.map +1 -1
  3. package/dist/robopark/audio-select.js +128 -0
  4. package/dist/robopark/audio-select.js.map +1 -0
  5. package/dist/robopark/device-preempt.js +185 -0
  6. package/dist/robopark/device-preempt.js.map +1 -0
  7. package/dist/robopark/kiosk-browser.js +145 -0
  8. package/dist/robopark/kiosk-browser.js.map +1 -0
  9. package/dist/robopark/start.js +455 -0
  10. package/dist/robopark/start.js.map +1 -0
  11. package/dist/robopark/voice-list.js +23 -12
  12. package/dist/robopark/voice-list.js.map +1 -1
  13. package/dist/robopark-cli.js +25 -0
  14. package/dist/robopark-cli.js.map +1 -1
  15. package/package.json +7 -3
  16. package/scheduler/main.py +150 -30
  17. package/scheduler/static/voice-join.html +48 -2
  18. package/ui/standalone/.next/BUILD_ID +1 -1
  19. package/ui/standalone/.next/app-build-manifest.json +72 -72
  20. package/ui/standalone/.next/app-path-routes-manifest.json +16 -16
  21. package/ui/standalone/.next/build-manifest.json +2 -2
  22. package/ui/standalone/.next/server/app/api/robovoice/robots/[robotId]/media-health/route.js +1 -1
  23. package/ui/standalone/.next/server/app/fed/[...path]/route.js +2 -2
  24. package/ui/standalone/.next/server/app/fed/media/robots/[robotId]/video_feed/route.js +1 -1
  25. package/ui/standalone/.next/server/app/robopark/[...path]/route.js +1 -1
  26. package/ui/standalone/.next/server/app/robopark/api/robots/[robotId]/stream/route.js +1 -1
  27. package/ui/standalone/.next/server/app-paths-manifest.json +16 -16
  28. package/ui/standalone/.next/server/functions-config-manifest.json +1 -1
  29. package/ui/standalone/.next/server/pages/500.html +1 -1
  30. package/ui/standalone/public/voice-join.html +48 -2
  31. package/scheduler/__pycache__/main.cpython-312.pyc +0 -0
  32. package/ui/standalone/.next/server/chunks/5123.js +0 -11
  33. package/ui/standalone/.next/server/chunks/7661.js +0 -11
  34. package/ui/standalone/.next/static/ULHwbueNr3RGevy8FSrTW/_buildManifest.js +0 -1
  35. package/ui/standalone/.next/static/ULHwbueNr3RGevy8FSrTW/_ssgManifest.js +0 -1
  36. package/ui/standalone/.next/static/Xg-e8h70WpdFcsZ2vcfOG/_buildManifest.js +0 -1
  37. package/ui/standalone/.next/static/Xg-e8h70WpdFcsZ2vcfOG/_ssgManifest.js +0 -1
  38. package/ui/standalone/.next/static/chunks/app/(app)/voice/page-d98593eea4888404.js +0 -1
  39. package/ui/standalone/.next/static/chunks/app/_not-found/page-9f0acae7481c60bb.js +0 -1
  40. package/ui/standalone/.next/static/chunks/app/layout-4829e027e68fded4.js +0 -1
  41. package/ui/standalone/.next/static/chunks/app/voice-tester/page-f5ad3acef9248b78.js +0 -1
  42. package/ui/standalone/.next/static/chunks/main-app-f2b2a716b0f3924b.js +0 -1
  43. package/ui/standalone/.next/static/gGysrZrp8HXGK_0MbZa9v/_buildManifest.js +0 -1
  44. package/ui/standalone/.next/static/gGysrZrp8HXGK_0MbZa9v/_ssgManifest.js +0 -1
  45. package/ui/standalone/.next/static/tDI_bBJ7vZjqqxcXg1GZn/_buildManifest.js +0 -1
  46. package/ui/standalone/.next/static/tDI_bBJ7vZjqqxcXg1GZn/_ssgManifest.js +0 -1
  47. package/ui/standalone/.next/static/zAWQgn-m46BFpT3z33lh-/_buildManifest.js +0 -1
  48. package/ui/standalone/.next/static/zAWQgn-m46BFpT3z33lh-/_ssgManifest.js +0 -1
  49. /package/ui/standalone/.next/static/{KwY1YC79lI9nQqOVYXOmY → 2zW74Q0KZAsncyNMwT9yQ}/_buildManifest.js +0 -0
  50. /package/ui/standalone/.next/static/{KwY1YC79lI9nQqOVYXOmY → 2zW74Q0KZAsncyNMwT9yQ}/_ssgManifest.js +0 -0
@@ -0,0 +1,455 @@
1
+ /**
2
+ * RoboPark — `robopark start <robot>`.
3
+ *
4
+ * One command on a kiosk: bring the local camera up and make it visible in the
5
+ * control center.
6
+ *
7
+ * This deliberately targets the MJPEG relay
8
+ * (`/fed/media/robots/<id>/video_feed` → `http://<host>:<visionPort>/video_feed`)
9
+ * rather than the LiveKit publisher path. MJPEG is one plain HTTP stream with
10
+ * no token, no room name, and no WebSocket for a publisher and a subscriber to
11
+ * agree on — which is where the publisher path kept failing. The camera grid
12
+ * already renders that URL in an <img>, so nothing downstream has to change.
13
+ *
14
+ * Hub/scheduler context comes from the profile `robopark hub-use` already
15
+ * saves; this command introduces no configuration of its own.
16
+ */
17
+ import { hostname } from 'node:os';
18
+ import chalk from 'chalk';
19
+ import { robotReachableSchedulerUrl, schedulerApiUrl } from './add-robot.js';
20
+ import { applyAudioSelection, planAudioSelection } from './audio-select.js';
21
+ import { preemptDevices } from './device-preempt.js';
22
+ import { findBrowser, kioskLaunch, launchCommandLine, launchKiosk } from './kiosk-browser.js';
23
+ import { loadHubProfile } from './profile.js';
24
+ import { resolveTailnet } from './tailscale.js';
25
+ import { roboparkVisionAgent } from './vision-agent-launcher.js';
26
+ import { roboparkVisionUp } from './vision-control.js';
27
+ import { characterCallUrl } from './voice-list.js';
28
+ const DEFAULT_VISION_PORT = 5000;
29
+ const DEFAULT_MESH_PORT = 47913;
30
+ const READY_TIMEOUT_MS = 30_000;
31
+ const READY_POLL_MS = 1_000;
32
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
33
+ /**
34
+ * True once the local vision server actually delivers a frame on /video_feed.
35
+ *
36
+ * Response headers are NOT enough: when the capture device cannot be opened,
37
+ * Flask still streams a multipart body whose generator never yields, so a
38
+ * 200 here can coexist with a completely dead camera. Requiring one real chunk
39
+ * is what makes "ready" mean the camera works. The body is an endless stream,
40
+ * so the reader is cancelled rather than drained — awaiting it would never
41
+ * resolve and the probe would look like a hang instead of a success.
42
+ */
43
+ async function feedReady(port) {
44
+ const controller = new AbortController();
45
+ const timer = setTimeout(() => controller.abort(), 4_000);
46
+ try {
47
+ const res = await fetch(`http://127.0.0.1:${port}/video_feed`, { signal: controller.signal });
48
+ if (!res.ok || !res.body) {
49
+ await res.body?.cancel();
50
+ return false;
51
+ }
52
+ const reader = res.body.getReader();
53
+ try {
54
+ const { value, done } = await reader.read();
55
+ return !done && Boolean(value?.length);
56
+ }
57
+ finally {
58
+ await reader.cancel().catch(() => { });
59
+ }
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ finally {
65
+ clearTimeout(timer);
66
+ }
67
+ }
68
+ /** True once Flask itself answers, whatever the camera is doing. */
69
+ async function serverAlive(port) {
70
+ try {
71
+ const res = await fetch(`http://127.0.0.1:${port}/`, { signal: AbortSignal.timeout(3_000) });
72
+ await res.body?.cancel();
73
+ return true;
74
+ }
75
+ catch {
76
+ return false;
77
+ }
78
+ }
79
+ /** The vision server's own view of the capture device, for the failure message. */
80
+ async function cameraStatus(port) {
81
+ try {
82
+ const res = await fetch(`http://127.0.0.1:${port}/api/camera/status`, { signal: AbortSignal.timeout(3_000) });
83
+ if (!res.ok)
84
+ return `HTTP ${res.status}`;
85
+ const status = (await res.json());
86
+ return `device=${status.device ?? '?'} open=${status.open ? 'yes' : 'no'}${status.read_stalled ? ' read=stalled' : ''}`;
87
+ }
88
+ catch {
89
+ return 'unavailable';
90
+ }
91
+ }
92
+ /**
93
+ * Distinguish "nothing is listening" from "Flask is up but the camera yields
94
+ * nothing" — the kongor failure, where `/` answered 200 and `/video_feed`
95
+ * answered nothing at all. Reporting both as "the vision server never
96
+ * answered" sent the operator looking for a process that was in fact running.
97
+ */
98
+ async function waitForFeed(port) {
99
+ const deadline = Date.now() + READY_TIMEOUT_MS;
100
+ let everAlive = false;
101
+ while (Date.now() < deadline) {
102
+ if (await feedReady(port))
103
+ return 'ready';
104
+ if (!everAlive && (await serverAlive(port)))
105
+ everAlive = true;
106
+ await sleep(READY_POLL_MS);
107
+ }
108
+ return everAlive ? 'camera-dead' : 'down';
109
+ }
110
+ /**
111
+ * Wait for the local feed; return null when ready, else the operator-facing
112
+ * reason it is not.
113
+ *
114
+ * Kept separate from the caller so the two failures can be told apart in the
115
+ * message: everything an operator would do about a server that never started
116
+ * is the wrong move for a server that is up with a dead camera.
117
+ */
118
+ export async function awaitVisionReady(port) {
119
+ const readiness = await waitForFeed(port);
120
+ if (readiness === 'ready')
121
+ return null;
122
+ if (readiness === 'camera-dead') {
123
+ return (`vision server up but camera not producing frames: http://127.0.0.1:${port}/ answers, ` +
124
+ `but /video_feed yielded nothing within ${READY_TIMEOUT_MS / 1000}s (camera status: ${await cameraStatus(port)}). ` +
125
+ 'Another process is probably still holding the camera, or the selected device is wrong — ' +
126
+ `check http://127.0.0.1:${port}/api/media/inventory, make sure you did not pass --no-preempt, ` +
127
+ "and rerun with --foreground to see the server's output");
128
+ }
129
+ return (`the vision server never started: nothing answered http://127.0.0.1:${port}/ within ${READY_TIMEOUT_MS / 1000}s — ` +
130
+ 'rerun with --foreground to see why the python process exited');
131
+ }
132
+ /**
133
+ * This machine's mesh identity, or null when no node is listening.
134
+ *
135
+ * The relay resolves a robot to a peer by nodeId or displayName
136
+ * (kernel/federation/transport-http.js), so this is the only thing that decides
137
+ * whether the mesh RELAY branch of /fed/media/robots/<name>/video_feed reaches
138
+ * this kiosk (the direct scheduler path does not go through here at all).
139
+ *
140
+ * KNOWN FALSE NEGATIVE: relay-role nodes dial the hub outbound and never listen
141
+ * on 47913 locally, so an already-enrolled machine (this laptop is on the mesh
142
+ * as `jaguar`, with nothing bound to 47913) reports "not enrolled" here and
143
+ * would be re-enrolled. Left as-is rather than guessed at: distinguishing the
144
+ * two needs a hub-side membership query this command does not have. It is no
145
+ * longer reachable by default now that enrollment is opt-in behind --mesh.
146
+ */
147
+ async function meshIdentity(token) {
148
+ try {
149
+ const res = await fetch(`http://127.0.0.1:${DEFAULT_MESH_PORT}/fed/manifest`, {
150
+ headers: token ? { authorization: `Bearer ${token}` } : {},
151
+ signal: AbortSignal.timeout(4_000),
152
+ });
153
+ if (!res.ok)
154
+ return null;
155
+ const manifest = (await res.json());
156
+ if (!manifest?.nodeId)
157
+ return null;
158
+ return { nodeId: String(manifest.nodeId), displayName: String(manifest.displayName ?? '') };
159
+ }
160
+ catch {
161
+ return null;
162
+ }
163
+ }
164
+ /**
165
+ * Ensure this machine is on the mesh as `name`, enrolling only if it is not.
166
+ *
167
+ * Enrolling reconfigures and restarts the local node, which is far heavier than
168
+ * anything else this command does — so it is announced, and it is skipped
169
+ * outright when a node is already answering under the right name. A node
170
+ * running under a DIFFERENT name is left strictly alone: renaming it would
171
+ * silently move an already-working robot, so this stops and says so instead.
172
+ */
173
+ async function ensureMesh(config, name, token) {
174
+ const identity = await meshIdentity(token);
175
+ if (identity) {
176
+ const wanted = name.toLowerCase();
177
+ if (identity.nodeId.toLowerCase() === wanted || identity.displayName.toLowerCase() === wanted) {
178
+ console.log(chalk.dim(` mesh: already enrolled as '${identity.displayName || identity.nodeId}' — skipping`));
179
+ return;
180
+ }
181
+ throw new Error(`a mesh node is already running on this machine as '${identity.displayName || identity.nodeId}', not '${name}'. ` +
182
+ `The camera relay resolves robots by that name, so rerun as \`robopark start ${identity.displayName || identity.nodeId}\`, ` +
183
+ 'or drop --mesh: video no longer needs mesh enrollment');
184
+ }
185
+ console.log(chalk.yellow(` mesh: no node on this machine — enrolling as '${name}' (this configures and starts the robot runtime)`));
186
+ await roboparkVisionUp(config, name, {});
187
+ if (!(await meshIdentity(token))) {
188
+ throw new Error(`enrollment finished but no mesh node answered on 127.0.0.1:${DEFAULT_MESH_PORT}`);
189
+ }
190
+ console.log(chalk.green(` ✓ enrolled on the mesh as '${name}'`));
191
+ }
192
+ /** This machine's address as another host on the fleet can reach it. */
193
+ function localHost() {
194
+ const { identity } = resolveTailnet();
195
+ return identity?.host ?? hostname().split('.')[0];
196
+ }
197
+ /**
198
+ * Ensure the scheduler knows this machine as `name`, with an address the
199
+ * control center can proxy to. Creates the device when it does not exist yet
200
+ * so a freshly imaged kiosk needs no separate enrollment step first.
201
+ */
202
+ async function registerDevice(schedulerUrl, name, host, token) {
203
+ const listed = await fetch(schedulerApiUrl(schedulerUrl, '/api/devices', token));
204
+ if (!listed.ok)
205
+ throw new Error(`scheduler returned ${listed.status} listing devices`);
206
+ const devices = (await listed.json());
207
+ const match = devices.find(d => String(d.name).toLowerCase() === name.toLowerCase() || String(d.id) === name);
208
+ let device = match;
209
+ let deviceId = match?.id;
210
+ if (!deviceId) {
211
+ const created = await fetch(schedulerApiUrl(schedulerUrl, '/api/devices', token), {
212
+ method: 'POST',
213
+ headers: { 'content-type': 'application/json' },
214
+ body: JSON.stringify({ name, device_role: 'voice_vision', lan_ip: host }),
215
+ });
216
+ if (!created.ok) {
217
+ const detail = await created.text().catch(() => '');
218
+ throw new Error(`could not register '${name}': ${created.status} ${detail}`.trim());
219
+ }
220
+ device = (await created.json());
221
+ deviceId = device.id;
222
+ }
223
+ const patched = await fetch(schedulerApiUrl(schedulerUrl, `/api/devices/${encodeURIComponent(deviceId)}`, token), {
224
+ method: 'PATCH',
225
+ headers: { 'content-type': 'application/json' },
226
+ body: JSON.stringify({ lan_ip: host, device_role: 'voice_vision', status: 'online' }),
227
+ });
228
+ if (!patched.ok) {
229
+ const detail = await patched.text().catch(() => '');
230
+ throw new Error(`could not update '${name}': ${patched.status} ${detail}`.trim());
231
+ }
232
+ return { ...(device ?? { name }), id: deviceId };
233
+ }
234
+ /**
235
+ * Apply `--mic` / `--speaker` (or, with neither, whatever a previous run
236
+ * persisted on the device row) to the vision server, and persist an explicit
237
+ * choice back to the scheduler so the next run reapplies it without the flags.
238
+ */
239
+ async function selectAudio(schedulerUrl, port, device, opts, token) {
240
+ const explicit = Boolean(opts.mic || opts.speaker);
241
+ const selection = await planAudioSelection(port, { mic: opts.mic, speaker: opts.speaker }, { audioDevice: device.audio_device, audioOutputDevice: device.audio_output_device });
242
+ if (!selection.audioDevice && !selection.audioOutputDevice) {
243
+ console.log(chalk.dim(' audio: no explicit device selected — the vision server keeps the system default'));
244
+ console.log(chalk.dim(' pin one with `robopark start <robot> --mic <name|index> --speaker <name|index>`'));
245
+ return;
246
+ }
247
+ const applied = await applyAudioSelection(port, selection);
248
+ const described = [
249
+ selection.audioDevice !== undefined ? `mic=${selection.audioDevice}` : null,
250
+ selection.audioOutputDevice !== undefined ? `speaker=${selection.audioOutputDevice}` : null,
251
+ ].filter(Boolean).join(' ');
252
+ if (applied)
253
+ console.log(chalk.green(` ✓ audio devices selected (${described})${explicit ? '' : ' — restored from the device record'}`));
254
+ else
255
+ console.log(chalk.yellow(` ⚠ the vision server did not accept the audio selection (${described})`));
256
+ if (!explicit)
257
+ return;
258
+ const patched = await fetch(schedulerApiUrl(schedulerUrl, `/api/devices/${encodeURIComponent(device.id)}`, token), {
259
+ method: 'PATCH',
260
+ headers: { 'content-type': 'application/json' },
261
+ body: JSON.stringify({
262
+ audio_device: selection.audioDevice,
263
+ audio_output_device: selection.audioOutputDevice,
264
+ }),
265
+ });
266
+ if (patched.ok)
267
+ console.log(chalk.dim(' persisted on the scheduler device record — reruns need no flags'));
268
+ else
269
+ console.log(chalk.yellow(` ⚠ could not persist the audio selection: HTTP ${patched.status}`));
270
+ }
271
+ /**
272
+ * The character this kiosk should answer as.
273
+ *
274
+ * The device's own `character_id` binding (set by `robopark add-robot`) wins;
275
+ * only when nothing is bound does this fall back to matching the robot name,
276
+ * the same way add-robot picks a pad in the first place.
277
+ */
278
+ async function resolveCharacter(schedulerUrl, name, boundId, token) {
279
+ try {
280
+ const res = await fetch(schedulerApiUrl(schedulerUrl, '/api/character-presets', token));
281
+ if (!res.ok)
282
+ return null;
283
+ const presets = (await res.json());
284
+ if (boundId) {
285
+ const bound = presets.find(p => p.id === boundId);
286
+ if (bound)
287
+ return bound;
288
+ }
289
+ const lower = name.toLowerCase();
290
+ return (presets.find(p => p.id.toLowerCase() === lower || (p.name ?? '').toLowerCase() === lower) ??
291
+ presets.find(p => lower.includes(p.id.toLowerCase()) || (p.name ?? '').toLowerCase().includes(lower)) ??
292
+ null);
293
+ }
294
+ catch {
295
+ return null;
296
+ }
297
+ }
298
+ /**
299
+ * Open the live call page on this kiosk with camera/mic already granted.
300
+ *
301
+ * Nothing here is fatal: the camera relay this command's earlier steps set up
302
+ * works whether or not a browser comes up, so a missing character binding or a
303
+ * headless box degrades to a printed URL instead of failing the whole start.
304
+ */
305
+ async function openKiosk(schedulerUrl, browserBase, name, device, opts, token) {
306
+ const preset = await resolveCharacter(schedulerUrl, name, device.character_id, token);
307
+ if (!preset?.elevenlabs_agent_id) {
308
+ console.log(chalk.yellow(` ⚠ no character with a bound ElevenLabs agent matched '${name}' — not opening a call page`));
309
+ console.log(chalk.dim(` bind one with \`robopark add-robot --name ${name} --character <id>\`, or see ${browserBase}/calls`));
310
+ return;
311
+ }
312
+ // mode=production ties the call to this device so the scheduler attaches the
313
+ // robot's video ref; kiosk=1 arms the page's motion trigger, which is what
314
+ // starts a conversation with nobody available to press "Join".
315
+ //
316
+ // camera=off is what keeps this page off the capture device entirely: the
317
+ // vision server owns it, the control-center feed is its MJPEG stream, and a
318
+ // browser getUserMedia({video}) here would either fail or steal the camera
319
+ // back. The page then takes its motion trigger from the vision server's own
320
+ // /api/motion/status instead of a local camera.
321
+ const url = characterCallUrl(browserBase, preset, 'production', {
322
+ robot: device.id,
323
+ kiosk: '1',
324
+ camera: 'off',
325
+ vision_base: `http://127.0.0.1:${opts.port ?? DEFAULT_VISION_PORT}`,
326
+ });
327
+ console.log(` call page: ${chalk.cyan(url)}`);
328
+ if (opts.browser === false) {
329
+ console.log(chalk.dim(' browser: --no-browser given — open the link above on the kiosk yourself'));
330
+ return;
331
+ }
332
+ const override = typeof opts.browser === 'string' ? opts.browser : undefined;
333
+ const exe = findBrowser(override);
334
+ if (!exe) {
335
+ console.log(chalk.yellow(` ⚠ no browser found${override ? ` at ${override}` : ''} — pass --browser <path> to the kiosk browser executable`));
336
+ return;
337
+ }
338
+ const launch = kioskLaunch(exe, url, name);
339
+ console.log(chalk.dim(` browser: ${launchCommandLine(launch)}`));
340
+ if (process.env.ROBOPARK_KIOSK_DRY_RUN) {
341
+ console.log(chalk.dim(' browser: ROBOPARK_KIOSK_DRY_RUN set — not spawning'));
342
+ return;
343
+ }
344
+ launchKiosk(launch, url);
345
+ // Rerunning start does not stack windows: both families hand the URL to the
346
+ // instance already owning this profile directory instead of opening a second.
347
+ console.log(chalk.green(` ✓ kiosk call page open (${launch.family}, camera+mic pre-granted)`));
348
+ }
349
+ export async function roboparkStart(config, name, opts) {
350
+ const profile = loadHubProfile();
351
+ if (!profile?.schedulerUrl) {
352
+ throw new Error('no saved hub profile; run `robopark hub-use --scheduler-url http://HUB:8080 --hub-url http://HUB:47913 --token TOKEN` once on this machine');
353
+ }
354
+ const port = Number(opts.port ?? DEFAULT_VISION_PORT);
355
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) {
356
+ throw new Error(`invalid --port ${opts.port}`);
357
+ }
358
+ const host = localHost();
359
+ const schedulerUrl = robotReachableSchedulerUrl(profile.schedulerUrl, profile.hubUrl);
360
+ if (schedulerUrl.endsWith('/robopark') && !profile.token) {
361
+ throw new Error('the saved hub profile has no mesh token; rerun `robopark hub-use --token TOKEN`');
362
+ }
363
+ console.log(chalk.bold(`\n robopark start ${name}`));
364
+ console.log(chalk.dim(' ' + '─'.repeat(52)));
365
+ console.log(` host: ${chalk.cyan(host)}`);
366
+ console.log(` vision: ${chalk.cyan(String(port))}`);
367
+ console.log(` scheduler: ${chalk.cyan(schedulerUrl)}`);
368
+ console.log();
369
+ // The mesh relay and the scheduler both hardcode 5000 for a robot's vision
370
+ // server, so a different port serves locally but is unreachable from the
371
+ // control center. Say so instead of reporting a feed nobody can watch.
372
+ if (port !== DEFAULT_VISION_PORT) {
373
+ console.log(chalk.yellow(` ⚠ the control-center relay only proxies port ${DEFAULT_VISION_PORT}; --port ${port} is local-only`));
374
+ }
375
+ // Mesh enrollment is opt-in. The control center now resolves this kiosk from
376
+ // its own scheduler device record and streams to <address>:5000 directly, so
377
+ // the mesh peer table is no longer on the video path and a dev-tooling outage
378
+ // can no longer take the cameras down.
379
+ if (opts.mesh === true)
380
+ await ensureMesh(config, name, profile.token);
381
+ else
382
+ console.log(chalk.dim(' mesh: skipped (video does not need it) — pass --mesh to enroll'));
383
+ // A prior run (or --mesh enrollment, which starts the robot runtime) often
384
+ // left the feed already live, so there may be nothing left to launch.
385
+ const alreadyLive = await feedReady(port);
386
+ // The vision server is the sole owner of this kiosk's camera and microphone.
387
+ // A USB camera on Windows cannot be opened twice, so a leftover holder — a
388
+ // previous vision agent, or the kiosk browser this command itself launched
389
+ // last run — is exactly what makes /video_feed answer nothing.
390
+ //
391
+ // A feed that is already producing frames proves nothing is competing, so it
392
+ // is left strictly alone: preempting there would kill a working camera and
393
+ // restart it for no reason.
394
+ if (opts.preempt === false) {
395
+ console.log(chalk.dim(' preempt: skipped (--no-preempt) — a leftover camera holder will block the feed'));
396
+ }
397
+ else if (alreadyLive && !opts.preemptDryRun) {
398
+ console.log(chalk.dim(' preempt: skipped — the feed is already producing frames, so nothing is competing'));
399
+ }
400
+ else {
401
+ const dryRun = Boolean(opts.preemptDryRun);
402
+ const result = preemptDevices(port, { dryRun });
403
+ console.log(chalk.dim(` preempt: ${dryRun ? 'DRY RUN — nothing will be killed' : 'terminating competing camera/audio holders'}`));
404
+ for (const target of result.targets) {
405
+ console.log(dryRun
406
+ ? chalk.yellow(` would kill pid ${target.pid} ${target.name} — ${target.reason}`)
407
+ : chalk.dim(` target pid ${target.pid} ${target.name} — ${target.reason}`));
408
+ }
409
+ for (const skip of result.skipped) {
410
+ console.log(chalk.yellow(` skipped pid ${skip.pid} ${skip.name} — ${skip.reason}`));
411
+ }
412
+ for (const killed of result.killed) {
413
+ console.log(chalk.green(` ✓ killed pid ${killed.pid} ${killed.name} (${killed.reason})`));
414
+ }
415
+ for (const fail of result.failed) {
416
+ console.log(chalk.red(` ✗ could not kill pid ${fail.pid} ${fail.name}: ${fail.detail}`));
417
+ }
418
+ if (!result.targets.length && !result.skipped.length) {
419
+ console.log(chalk.dim(' nothing competing for the camera or microphone'));
420
+ }
421
+ if (dryRun) {
422
+ console.log(chalk.yellow('\n --preempt-dry-run: stopping here without starting anything.\n'));
423
+ return;
424
+ }
425
+ }
426
+ let running = null;
427
+ if (alreadyLive) {
428
+ console.log(chalk.dim(' vision server already answering — reusing it'));
429
+ }
430
+ else {
431
+ const launch = roboparkVisionAgent({ port: String(port), foreground: opts.foreground });
432
+ // In --foreground the launcher only resolves when the camera exits, so it
433
+ // must not be awaited before the readiness probe or nothing is ever polled.
434
+ if (opts.foreground)
435
+ running = launch;
436
+ else
437
+ await launch;
438
+ }
439
+ const failure = await awaitVisionReady(port);
440
+ if (failure)
441
+ throw new Error(failure);
442
+ console.log(chalk.green(` ✓ local feed ready at http://127.0.0.1:${port}/video_feed`));
443
+ const device = await registerDevice(schedulerUrl, name, host, profile.token);
444
+ console.log(chalk.green(` ✓ registered '${name}' at the scheduler (device ${device.id})`));
445
+ await selectAudio(schedulerUrl, port, device, opts, profile.token);
446
+ const base = profile.schedulerUrl.replace(/\/+$/, '');
447
+ console.log();
448
+ console.log(` control center: ${chalk.cyan(base)}`);
449
+ console.log(` feed: ${chalk.cyan(`${base}/fed/media/robots/${encodeURIComponent(name)}/video_feed`)}`);
450
+ await openKiosk(schedulerUrl, base, name, device, opts, profile.token);
451
+ console.log();
452
+ if (running)
453
+ await running;
454
+ }
455
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/robopark/start.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,28 @@
8
8
  */
9
9
  import chalk from 'chalk';
10
10
  import { resolveTailnet } from './tailscale.js';
11
+ /**
12
+ * The one place a /voice-join.html link is assembled.
13
+ *
14
+ * Mirrors the scheduler's own `_call_link()` (scheduler/main.py) so a link the
15
+ * CLI hands to a kiosk is byte-for-byte the same shape as one copied off the
16
+ * /calls page — `extra` only adds the kiosk-specific params that page has no
17
+ * reason to carry.
18
+ */
19
+ export function characterCallUrl(host, preset, mode, extra) {
20
+ const params = new URLSearchParams({ character: preset.id });
21
+ if (preset.elevenlabs_agent_id)
22
+ params.set('agent_id', preset.elevenlabs_agent_id);
23
+ params.set('mode', mode);
24
+ // The branch pins the conversation to a specific agent variant. Dropping it
25
+ // would silently fall back to the agent's default, which is the wrong
26
+ // language when the branch is what selects it.
27
+ if (preset.elevenlabs_branch_id)
28
+ params.set('branch_id', preset.elevenlabs_branch_id);
29
+ for (const [key, value] of Object.entries(extra ?? {}))
30
+ params.set(key, value);
31
+ return `${host.replace(/\/+$/, '')}/voice-join.html?${params.toString()}`;
32
+ }
11
33
  export async function roboparkVoiceList(opts) {
12
34
  const configured = (opts.schedulerUrl || process.env.ROBOPARK_SCHEDULER_URL || 'http://127.0.0.1:8080').replace(/\/+$/, '');
13
35
  // Always talk to the scheduler over whatever address was given; only the
@@ -46,18 +68,7 @@ export async function roboparkVoiceList(opts) {
46
68
  }
47
69
  const wanted = (opts.mode || '').trim().toLowerCase();
48
70
  const modes = wanted === 'production' || wanted === 'test' ? [wanted] : ['production', 'test'];
49
- const link = (preset, mode) => {
50
- const params = new URLSearchParams({ character: preset.id });
51
- if (preset.elevenlabs_agent_id)
52
- params.set('agent_id', preset.elevenlabs_agent_id);
53
- params.set('mode', mode);
54
- // The branch pins the conversation to a specific agent variant. Dropping it
55
- // would silently fall back to the agent's default, which is the wrong
56
- // language when the branch is what selects it.
57
- if (preset.elevenlabs_branch_id)
58
- params.set('branch_id', preset.elevenlabs_branch_id);
59
- return `${linkHost}/voice-join.html?${params.toString()}`;
60
- };
71
+ const link = (preset, mode) => characterCallUrl(linkHost, preset, mode);
61
72
  if (opts.plain) {
62
73
  for (const preset of presets)
63
74
  for (const mode of modes)
@@ -1 +1 @@
1
- {"version":3,"file":"voice-list.js","sourceRoot":"","sources":["../../src/robopark/voice-list.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"voice-list.js","sourceRoot":"","sources":["../../src/robopark/voice-list.ts"],"names":[],"mappings":"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"}
@@ -701,6 +701,31 @@ program
701
701
  .action(async (name, opts) => {
702
702
  await roboparkAddRobot(config, { name, ...opts });
703
703
  });
704
+ program
705
+ .command('start <robot>')
706
+ .description('Bring this kiosk\'s camera up and publish it to the control center using the saved `robopark hub-use` profile')
707
+ .option('--port <port>', 'local vision server port', '5000')
708
+ .option('--foreground', 'stay in foreground; do not detach the vision server')
709
+ // Declaring --mesh before --no-mesh keeps commander's default at undefined
710
+ // (opt-out), so --no-mesh survives as a harmless no-op alias for scripts.
711
+ .option('--mesh', 'also enroll this machine on the infinicode mesh (not needed for video)')
712
+ .option('--no-mesh', 'accepted for compatibility; mesh enrollment is already off by default')
713
+ .option('--browser <path>', 'kiosk browser executable (default: first installed Edge/Chrome/Chromium/Firefox)')
714
+ .option('--no-browser', 'do not open the live call page; just print its URL')
715
+ .option('--no-preempt', 'do not terminate other processes holding this kiosk\'s camera or microphone')
716
+ .option('--preempt-dry-run', 'report which processes preemption would kill, then stop without starting anything')
717
+ .option('--mic <name|index>', 'microphone the vision server should capture from (name or device index)')
718
+ .option('--speaker <name|index>', 'speaker the vision server should play through (name or device index)')
719
+ .action(async (robot, opts) => {
720
+ const { roboparkStart } = await import('./robopark/start.js');
721
+ try {
722
+ await roboparkStart(config, robot, opts);
723
+ }
724
+ catch (err) {
725
+ console.error(chalk.red(` ✗ start failed: ${err?.message ?? err}`));
726
+ process.exitCode = 1;
727
+ }
728
+ });
704
729
  program
705
730
  .command('agent-up')
706
731
  .description('Start the ROBOVOICE docker stack and register its LiveKit server with the scheduler')