junis 0.3.5 → 0.3.6

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 (2) hide show
  1. package/dist/cli/index.js +133 -0
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -126,6 +126,39 @@ async function authenticate(deviceName, platform3, onBrowserOpen, onWaiting, exi
126
126
  }
127
127
  throw new Error("Authentication timed out (5 min). Please try again.");
128
128
  }
129
+ async function ensureTeam(deviceKey, token) {
130
+ let res;
131
+ try {
132
+ res = await fetch(`${JUNIS_API}/api/auth/device/ensure-team`, {
133
+ method: "POST",
134
+ headers: {
135
+ "Content-Type": "application/json",
136
+ Authorization: `Bearer ${token}`
137
+ },
138
+ body: JSON.stringify({ device_key: deviceKey })
139
+ });
140
+ } catch {
141
+ throw new Error("Network error: cannot reach server");
142
+ }
143
+ if (res.status === 401) {
144
+ return { status: "auth_expired" };
145
+ }
146
+ if (res.status === 404) {
147
+ return { status: "device_not_found" };
148
+ }
149
+ if (!res.ok) {
150
+ throw new Error(`ensure-team failed: ${res.status}`);
151
+ }
152
+ const data = await res.json();
153
+ return {
154
+ status: data.status,
155
+ // "ready" or "created"
156
+ organization_id: data.organization_id,
157
+ agent_id: data.agent_id,
158
+ agent_name: data.agent_name,
159
+ token: data.token
160
+ };
161
+ }
129
162
  function sleep(ms) {
130
163
  return new Promise((resolve) => setTimeout(resolve, ms));
131
164
  }
@@ -207,6 +240,13 @@ var RelayClient = class {
207
240
  }
208
241
  return;
209
242
  }
243
+ if (code === 4004 || code === 4005) {
244
+ this.destroyed = true;
245
+ console.error(
246
+ "\n\u274C Device or team configuration is invalid. Run `npx junis --reset` to re-authenticate."
247
+ );
248
+ process.exit(1);
249
+ }
210
250
  console.log(`\u26A0\uFE0F Disconnected. Reconnecting in ${this.reconnectDelay / 1e3}s...`);
211
251
  setTimeout(() => this.connect(), this.reconnectDelay);
212
252
  this.reconnectDelay = Math.min(this.reconnectDelay * 2, 3e4);
@@ -2398,6 +2438,27 @@ function printStep1(port) {
2398
2438
  console.log(` \u25C9 Local MCP endpoint ........... http://localhost:${port}/mcp`);
2399
2439
  console.log("");
2400
2440
  }
2441
+ async function checkEnsureTeam(config, label) {
2442
+ try {
2443
+ const result = await ensureTeam(config.device_key, config.token);
2444
+ if (result.status === "ready") {
2445
+ return config;
2446
+ }
2447
+ if (result.status === "created") {
2448
+ console.log(`[${label}] Team restored automatically`);
2449
+ if (result.token) {
2450
+ config.token = result.token;
2451
+ saveConfig(config);
2452
+ }
2453
+ return config;
2454
+ }
2455
+ console.log(`[${label}] ${result.status} \u2014 re-authentication required`);
2456
+ clearConfig();
2457
+ return null;
2458
+ } catch {
2459
+ return config;
2460
+ }
2461
+ }
2401
2462
  async function runForeground(config, port) {
2402
2463
  const deviceName = config.device_name;
2403
2464
  const platformName = process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : "linux";
@@ -2552,6 +2613,39 @@ program.command("start", { isDefault: true }).description("Start Junis agent con
2552
2613
  console.log("");
2553
2614
  }
2554
2615
  } else {
2616
+ const checked = await checkEnsureTeam(config2, "junis");
2617
+ if (!checked) {
2618
+ let waitingPrinted = false;
2619
+ const authResult = await authenticate(
2620
+ deviceName2,
2621
+ platformName2,
2622
+ (uri) => {
2623
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2624
+ console.log(" STEP 2 \xB7 Connect to Junis Cloud");
2625
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2626
+ console.log(" Opening browser...");
2627
+ console.log(` \u2192 ${uri}`);
2628
+ process.stdout.write(" Waiting for login \xB7");
2629
+ },
2630
+ () => {
2631
+ if (!waitingPrinted) {
2632
+ waitingPrinted = true;
2633
+ } else {
2634
+ process.stdout.write("\xB7");
2635
+ }
2636
+ }
2637
+ );
2638
+ console.log("");
2639
+ console.log(` \u2705 Authenticated as ${authResult.email ?? "your account"}`);
2640
+ console.log("");
2641
+ config2 = {
2642
+ device_key: authResult.device_key,
2643
+ token: authResult.token,
2644
+ device_name: deviceName2,
2645
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
2646
+ };
2647
+ saveConfig(config2);
2648
+ }
2555
2649
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2556
2650
  console.log(" STEP 3 \xB7 Register Device");
2557
2651
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
@@ -2576,6 +2670,12 @@ program.command("start", { isDefault: true }).description("Start Junis agent con
2576
2670
  console.error("\u274C No credentials found. Run npx junis first.");
2577
2671
  process.exit(1);
2578
2672
  }
2673
+ const checked = await checkEnsureTeam(config2, "junis daemon");
2674
+ if (!checked) {
2675
+ console.error("\u274C Device or team invalid. Run npx junis --reset to re-authenticate.");
2676
+ process.exit(1);
2677
+ }
2678
+ config2 = checked;
2579
2679
  const deviceName2 = config2.device_name;
2580
2680
  const platformName2 = process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : "linux";
2581
2681
  const actualPort = await startMCPServer(port);
@@ -2699,6 +2799,39 @@ program.command("start", { isDefault: true }).description("Start Junis agent con
2699
2799
  console.log("");
2700
2800
  }
2701
2801
  } else {
2802
+ const checked = await checkEnsureTeam(config, "junis");
2803
+ if (!checked) {
2804
+ let waitingPrinted = false;
2805
+ const authResult = await authenticate(
2806
+ deviceName,
2807
+ platformName,
2808
+ (uri) => {
2809
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2810
+ console.log(" STEP 2 \xB7 Connect to Junis Cloud");
2811
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2812
+ console.log(" Opening browser...");
2813
+ console.log(` \u2192 ${uri}`);
2814
+ process.stdout.write(" Waiting for login \xB7");
2815
+ },
2816
+ () => {
2817
+ if (!waitingPrinted) {
2818
+ waitingPrinted = true;
2819
+ } else {
2820
+ process.stdout.write("\xB7");
2821
+ }
2822
+ }
2823
+ );
2824
+ console.log("");
2825
+ console.log(` \u2705 Authenticated as ${authResult.email ?? "your account"}`);
2826
+ console.log("");
2827
+ config = {
2828
+ device_key: authResult.device_key,
2829
+ token: authResult.token,
2830
+ device_name: deviceName,
2831
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
2832
+ };
2833
+ saveConfig(config);
2834
+ }
2702
2835
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2703
2836
  console.log(" STEP 3 \xB7 Register Device");
2704
2837
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "junis",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "One-line device control for AI agents",
5
5
  "type": "module",
6
6
  "bin": {