infinicode 2.8.113 → 2.8.114

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.
@@ -1258,7 +1258,7 @@ footer.cmd{left:var(--global-nav-width);transition:left .24s cubic-bezier(.2,.8,
1258
1258
  <div class="rp-field"><label>Enrollment token</label><input id="rp-command-enrollment" placeholder="optional" spellcheck="false"></div>
1259
1259
  <div class="rp-field"><label>Control token</label><input id="rp-command-token" type="password" spellcheck="false"></div>
1260
1260
  <div class="rp-field"><label>RoboVoice folder on livekit-1</label><input id="rp-command-robovoice" value="C:\ROBOVOICE-main" spellcheck="false"></div>
1261
- <div class="rp-field"><label>Release</label><input id="rp-command-release" value="2.8.113" spellcheck="false"></div>
1261
+ <div class="rp-field"><label>Release</label><input id="rp-command-release" value="2.8.114" spellcheck="false"></div>
1262
1262
  </div>
1263
1263
  <div class="rp-command-toolbar">
1264
1264
  <input type="search" id="rp-command-search" placeholder="Search logs, camera, Docker, motors, npm...">
@@ -2843,7 +2843,7 @@ footer.cmd{left:var(--global-nav-width);transition:left .24s cubic-bezier(.2,.8,
2843
2843
  var RP_COMMAND_ENV_KEY='rp-command-env-v2';
2844
2844
  var RP_CUSTOM_COMMANDS_KEY='rp-custom-commands-v1';
2845
2845
  var rpVisibleCommands=[];
2846
- function rpCommandDefaults(){return {lan:'192.168.0.9',tail:'100.84.147.24',site:'Tel Aviv',robot:'bmw',character:'vixen',device:'',enrollment:'',token:dashboardMeshToken(),robovoice:'C:\\ROBOVOICE-main',release:'2.8.113',network:'lan'};}
2846
+ function rpCommandDefaults(){return {lan:'192.168.0.9',tail:'100.84.147.24',site:'Tel Aviv',robot:'bmw',character:'vixen',device:'',enrollment:'',token:dashboardMeshToken(),robovoice:'C:\\ROBOVOICE-main',release:'2.8.114',network:'lan'};}
2847
2847
  function rpLoadStoredJson(key,fallback){try{var value=JSON.parse(localStorage.getItem(key)||'null');return value&&typeof value==='object'?value:fallback;}catch(e){return fallback;}}
2848
2848
  function rpCommandEnv(){
2849
2849
  var d=rpCommandDefaults(),s=rpLoadStoredJson(RP_COMMAND_ENV_KEY,{});
@@ -2852,7 +2852,7 @@ footer.cmd{left:var(--global-nav-width);transition:left .24s cubic-bezier(.2,.8,
2852
2852
  }
2853
2853
  function rpSaveCommandEnv(){try{localStorage.setItem(RP_COMMAND_ENV_KEY,JSON.stringify(rpCommandEnv()));}catch(e){}}
2854
2854
  function rpShellArg(value){var text=String(value||'');return /^[A-Za-z0-9._:\/-]+$/.test(text)?text:'"'+text.replace(/"/g,'\\"')+'"';}
2855
- function rpCompleteRobotCommand(setupCommand){var release=rpCommandEnv().release||'2.8.113';return 'sudo npm install -g infinicode@'+rpShellArg(release)+' --force && hash -r && (sudo robopark stop || true) && '+setupCommand;}
2855
+ function rpCompleteRobotCommand(setupCommand){var release=rpCommandEnv().release||'2.8.114';return 'sudo npm install -g infinicode@'+rpShellArg(release)+' --force && hash -r && (sudo robopark stop || true) && '+setupCommand;}
2856
2856
  function rpRobotSetupCommand(){
2857
2857
  var e=rpCommandEnv(),control=rpControlUrl(e.network),argv=['sudo','robopark','setup','--robot','--name',e.robot,'--site',e.site,'--hub-url',control,'--token',e.token,'--port','47913',e.network==='tailscale'?'--tailscale':'--lan'];
2858
2858
  if(e.enrollment)argv.push('--enrollment-token',e.enrollment);if(e.character)argv.push('--character',e.character);argv.push('--start','--auto-start','--yes');
@@ -2860,11 +2860,11 @@ footer.cmd{left:var(--global-nav-width);transition:left .24s cubic-bezier(.2,.8,
2860
2860
  }
2861
2861
  function rpCommandCatalog(){
2862
2862
  var e=rpCommandEnv(),control=rpControlUrl(e.network),device=e.device||e.robot,enroll=e.enrollment?' --enrollment-token '+rpShellArg(e.enrollment):'',auth='?token='+encodeURIComponent(e.token);
2863
- var api=control+'/robopark/api',release=e.release||'2.8.113';
2863
+ var api=control+'/robopark/api',release=e.release||'2.8.114';
2864
2864
  return [
2865
2865
  {id:'hub-up',category:'Provision',title:'Install and start RoboVoice-first control host',description:'Run in elevated PowerShell on livekit-1. Starts the private compatibility data service, proven RoboVoice stack, mesh relay, and full Control Center.',command:'npm install -g infinicode@'+rpShellArg(release)+' --force; robopark serve --port 8080 --no-open; robopark agent-up --path '+rpShellArg(e.robovoice)+' --scheduler-url http://127.0.0.1:8080 --token '+rpShellArg(e.token)+'; infinicode serve --hub --name livekit-1 --port 47913 --token '+rpShellArg(e.token)+' --lan --dashboard --scheduler-url http://127.0.0.1:8080 --auto-update --supervised'},
2866
2866
  {id:'robot-install',category:'Provision',title:'Install or repair selected robot',description:'Run on the Pi. One control URL, one token, one supervised runtime; camera, audio, motion, motor server, and mesh start together.',command:rpRobotSetupCommand()},
2867
- {id:'operator-tail',category:'Provision',title:'Connect operator agents to control mesh',description:'Connects Codex/OpenCode tools through the livekit-1 control URL without exposing the private data service.',command:'infinicode mcp --lan --tailscale --seed '+rpControlUrl('tailscale').replace(/^http:\\/\\//,'')+' --name dev-laptop --token '+rpShellArg(e.token)+' --mesh-port 47913'},
2867
+ {id:'operator-tail',category:'Provision',title:'Direct agent mesh link',description:'Copy only this URL and give it to the agent on the other Tailscale device. It contains the exact control endpoint and mesh credential; the agent can run infinicode mesh join <link>.',command:rpControlUrl('tailscale')+'/fed/join?token='+encodeURIComponent(e.token)},
2868
2868
  {id:'production-on',category:'Production',title:'Arm always-on motion conversations',description:'Enables local motion-triggered RoboVoice calls for the canonical device.',command:'Invoke-RestMethod -Method Patch -ContentType "application/json" -Body (@{production_mode=$true} | ConvertTo-Json) "'+api+'/devices/'+encodeURIComponent(device)+auth+'"'},
2869
2869
  {id:'production-off',category:'Production',title:'Disarm production conversations',description:'Stops new motion-triggered calls without taking camera monitoring or remote control offline.',command:'Invoke-RestMethod -Method Patch -ContentType "application/json" -Body (@{production_mode=$false} | ConvertTo-Json) "'+api+'/devices/'+encodeURIComponent(device)+auth+'"'},
2870
2870
  {id:'session-start',category:'Voice',title:'Start one production conversation',description:'Runs the same robot motion-to-RoboVoice path used onsite.',command:'Invoke-RestMethod -Method Post "'+api+'/robots/'+encodeURIComponent(device)+'/pipeline-test/start'+auth+'" | ConvertTo-Json -Depth 8'},
@@ -25,6 +25,8 @@ export type { ComputeCandidate, ComputeNeed } from './compute-router.js';
25
25
  export { loadRole, saveRole, rolePreamble } from './role-context.js';
26
26
  export { discoverTailscalePeers, tailscaleAvailable } from './discovery.js';
27
27
  export type { DiscoverOptions } from './discovery.js';
28
+ export { buildMeshJoinLink, parseMeshJoinLink, redactMeshJoinLink, MESH_JOIN_PATH } from './mesh-link.js';
29
+ export type { MeshJoinLink } from './mesh-link.js';
28
30
  export { LanBeacon, DEFAULT_LAN_DISCOVERY_PORT } from './lan-discovery.js';
29
31
  export type { LanBeaconOptions, DiscoveredLanPeer } from './lan-discovery.js';
30
32
  export { envelope, reply, frame, frameToSSE, parseSSE, newId } from './protocol.js';
@@ -18,6 +18,7 @@ export { AutoUpdate, compareVersions } from './auto-update.js';
18
18
  export { ComputeRouter } from './compute-router.js';
19
19
  export { loadRole, saveRole, rolePreamble } from './role-context.js';
20
20
  export { discoverTailscalePeers, tailscaleAvailable } from './discovery.js';
21
+ export { buildMeshJoinLink, parseMeshJoinLink, redactMeshJoinLink, MESH_JOIN_PATH } from './mesh-link.js';
21
22
  export { LanBeacon, DEFAULT_LAN_DISCOVERY_PORT } from './lan-discovery.js';
22
23
  export { envelope, reply, frame, frameToSSE, parseSSE, newId } from './protocol.js';
23
24
  export * as moltfed from './moltfed-adapter.js';
@@ -0,0 +1,16 @@
1
+ /** Canonical, copyable connection link for one Infinicode mesh node. */
2
+ export declare const MESH_JOIN_PATH = "/fed/join";
3
+ export interface MeshJoinLink {
4
+ /** Authenticated HTTP base URL consumed by Federation.connect(). */
5
+ seed: string;
6
+ /** Shared mesh bearer token, when the target mesh is protected. */
7
+ token?: string;
8
+ /** Original normalized link, suitable for MCP --connect. */
9
+ link: string;
10
+ }
11
+ /** Build a single shareable URL from a reachable mesh base URL. */
12
+ export declare function buildMeshJoinLink(baseUrl: string, token?: string): string;
13
+ /** Parse and validate a canonical mesh URL without making a network request. */
14
+ export declare function parseMeshJoinLink(value: string): MeshJoinLink;
15
+ /** Safe for terminals and logs while retaining enough information to identify the link. */
16
+ export declare function redactMeshJoinLink(value: string): string;
@@ -0,0 +1,52 @@
1
+ /** Canonical, copyable connection link for one Infinicode mesh node. */
2
+ export const MESH_JOIN_PATH = '/fed/join';
3
+ function parsedHttpUrl(value) {
4
+ let url;
5
+ try {
6
+ url = new URL(value.trim());
7
+ }
8
+ catch {
9
+ throw new Error('mesh link must be a valid http:// or https:// URL');
10
+ }
11
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
12
+ throw new Error('mesh link must use http:// or https://');
13
+ }
14
+ if (url.username || url.password)
15
+ throw new Error('mesh link must not contain URL user credentials');
16
+ return url;
17
+ }
18
+ /** Build a single shareable URL from a reachable mesh base URL. */
19
+ export function buildMeshJoinLink(baseUrl, token) {
20
+ const url = parsedHttpUrl(baseUrl);
21
+ url.pathname = MESH_JOIN_PATH;
22
+ url.search = '';
23
+ url.hash = '';
24
+ if (token)
25
+ url.searchParams.set('token', token);
26
+ return url.toString();
27
+ }
28
+ /** Parse and validate a canonical mesh URL without making a network request. */
29
+ export function parseMeshJoinLink(value) {
30
+ const url = parsedHttpUrl(value);
31
+ if (url.pathname.replace(/\/+$/, '') !== MESH_JOIN_PATH) {
32
+ throw new Error(`mesh link path must be ${MESH_JOIN_PATH}`);
33
+ }
34
+ const token = url.searchParams.get('token')?.trim() || undefined;
35
+ for (const key of url.searchParams.keys()) {
36
+ if (key !== 'token')
37
+ throw new Error(`unsupported mesh link parameter: ${key}`);
38
+ }
39
+ url.hash = '';
40
+ const seed = `${url.protocol}//${url.host}`;
41
+ return { seed, token, link: buildMeshJoinLink(seed, token) };
42
+ }
43
+ /** Safe for terminals and logs while retaining enough information to identify the link. */
44
+ export function redactMeshJoinLink(value) {
45
+ try {
46
+ const parsed = parseMeshJoinLink(value);
47
+ return buildMeshJoinLink(parsed.seed, parsed.token ? '<redacted>' : undefined);
48
+ }
49
+ catch {
50
+ return '<invalid mesh link>';
51
+ }
52
+ }
@@ -22,6 +22,7 @@ import { readFileSync } from 'node:fs';
22
22
  import { createRequire } from 'node:module';
23
23
  import { once } from 'node:events';
24
24
  import { frameToSSE, parseSSE } from './protocol.js';
25
+ import { buildMeshJoinLink, MESH_JOIN_PATH } from './mesh-link.js';
25
26
  const execFileAsync = promisify(execFile);
26
27
  /** Read the livekit-client UMD bundle from the installed dependency, once.
27
28
  * Returns null (cached) if the package isn't present — the dashboard then
@@ -363,6 +364,29 @@ export class MeshServer {
363
364
  return;
364
365
  }
365
366
  const remote = req.socket.remoteAddress ?? 'unknown';
367
+ if (req.method === 'GET' && path === MESH_JOIN_PATH) {
368
+ const rawHost = String(req.headers.host ?? '');
369
+ const authority = /^[A-Za-z0-9.:[\]-]+$/.test(rawHost) ? rawHost : `127.0.0.1:${this.opts.port}`;
370
+ const scheme = this.opts.tls ? 'https' : 'http';
371
+ const link = buildMeshJoinLink(`${scheme}://${authority}`, this.opts.token ? this.presentedToken(req) : undefined);
372
+ const manifest = this.opts.getManifest();
373
+ res.writeHead(200, {
374
+ 'content-type': 'application/json; charset=utf-8',
375
+ 'cache-control': 'no-store',
376
+ 'referrer-policy': 'no-referrer',
377
+ });
378
+ res.end(JSON.stringify({
379
+ protocol: 'infinicode-mesh-join',
380
+ version: 1,
381
+ link,
382
+ node: { id: manifest.nodeId, name: manifest.displayName, role: manifest.role },
383
+ use: {
384
+ direct: `infinicode mcp --connect "${link}"`,
385
+ install: `infinicode mesh join "${link}" --host all`,
386
+ },
387
+ }));
388
+ return;
389
+ }
366
390
  if (req.method === 'GET' && path === '/fed/ui-build') {
367
391
  const marker = this.opts.dashboardHtml?.match(/<meta name="robopark-ui-build" content="([^"]+)">/)?.[1] ?? 'none';
368
392
  res.writeHead(200, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infinicode",
3
- "version": "2.8.113",
3
+ "version": "2.8.114",
4
4
  "description": "OpenKernel — provider-agnostic AI execution kernel. Native coding agent + mission-driven execution runtime.",
5
5
  "type": "module",
6
6
  "main": "./dist/kernel/index.js",