agent-factorio 0.3.4 → 0.4.0

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/commands/login.mjs +46 -26
  2. package/package.json +1 -1
@@ -1,11 +1,31 @@
1
1
  /**
2
- * agent-factorio login — Connect to hub + join organization (with email verification)
2
+ * agent-factorio login — Browser-based authentication (like Claude Code /login)
3
3
  */
4
4
  import { ask, choose } from "../lib/prompt.mjs";
5
5
  import { readGlobalConfig, upsertOrg } from "../lib/config.mjs";
6
6
  import { apiCall, checkHub } from "../lib/api.mjs";
7
7
  import { success, error, info, dim } from "../lib/log.mjs";
8
8
 
9
+ /**
10
+ * Try to open a URL in the default browser
11
+ * @param {string} url
12
+ */
13
+ async function openBrowser(url) {
14
+ const { exec } = await import("child_process");
15
+ const { platform } = await import("os");
16
+
17
+ const cmd =
18
+ platform() === "darwin"
19
+ ? `open "${url}"`
20
+ : platform() === "win32"
21
+ ? `start "" "${url}"`
22
+ : `xdg-open "${url}"`;
23
+
24
+ return new Promise((resolve) => {
25
+ exec(cmd, (err) => resolve(!err));
26
+ });
27
+ }
28
+
9
29
  /**
10
30
  * Poll verification status until verified or expired
11
31
  * @param {string} hubUrl
@@ -23,7 +43,7 @@ async function waitForVerification(hubUrl, loginToken) {
23
43
  });
24
44
 
25
45
  if (res.status === 410) {
26
- throw new Error("Verification link expired. Please try again.");
46
+ throw new Error("Login session expired. Please try again.");
27
47
  }
28
48
 
29
49
  if (!res.ok) {
@@ -34,11 +54,10 @@ async function waitForVerification(hubUrl, loginToken) {
34
54
  return { userId: res.data.userId, email: res.data.email };
35
55
  }
36
56
 
37
- // Wait before next poll
38
57
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
39
58
  }
40
59
 
41
- throw new Error("Verification timed out. Please try again.");
60
+ throw new Error("Login timed out. Please try again.");
42
61
  }
43
62
 
44
63
  const DEFAULT_HUB_URL = "https://agent-factorio.vercel.app";
@@ -54,45 +73,46 @@ export async function loginCommand(options = {}) {
54
73
  process.exit(1);
55
74
  }
56
75
 
57
- // 2. Email input
58
- const email = await ask("Your email (used as your identifier)");
59
- if (!email) {
60
- error("Email is required.");
76
+ // 1. Initialize browser login session
77
+ const initRes = await apiCall(hubUrl, "/api/cli/login", {
78
+ body: { action: "init-browser-login" },
79
+ });
80
+
81
+ if (!initRes.ok) {
82
+ error(`Failed to initialize login: ${initRes.data?.error || "Unknown error"}`);
61
83
  process.exit(1);
62
84
  }
63
85
 
64
- // 3. Send verification email
65
- info("Sending verification email...");
66
- const sendRes = await apiCall(hubUrl, "/api/cli/login", {
67
- body: { action: "send-verification", email },
68
- });
86
+ const { loginToken, loginUrl } = initRes.data;
69
87
 
70
- if (!sendRes.ok) {
71
- error(`Failed to send verification email: ${sendRes.data?.error || "Unknown error"}`);
72
- process.exit(1);
88
+ // 2. Open browser
89
+ const opened = await openBrowser(loginUrl);
90
+ if (!opened) {
91
+ console.log();
92
+ info("Browser didn't open? Use the url below to sign in:");
93
+ console.log(` ${loginUrl}`);
73
94
  }
74
95
 
75
- const { loginToken } = sendRes.data;
76
- success("Verification email sent!");
77
- info("Check your inbox and click the verification link.");
78
- dim("Waiting for verification...");
96
+ console.log();
97
+ dim("Waiting for sign-in...");
79
98
 
80
- // 4. Poll for verification
81
- let userId;
99
+ // 3. Poll for verification
100
+ let userId, email;
82
101
  try {
83
102
  const result = await waitForVerification(hubUrl, loginToken);
84
103
  userId = result.userId;
104
+ email = result.email;
85
105
  } catch (err) {
86
106
  error(err.message);
87
107
  process.exit(1);
88
108
  }
89
109
 
90
- success("Email verified!");
110
+ success(`Logged in as ${email}`);
91
111
 
92
- // 5. Name input
112
+ // 4. Name input
93
113
  const memberName = await ask("Your name (displayed in the org)", "CLI User");
94
114
 
95
- // 6. Create or Join
115
+ // 5. Create or Join
96
116
  const { index: actionIdx } = await choose("Create or join an organization?", [
97
117
  "Create new",
98
118
  "Join existing (invite code)",
@@ -143,5 +163,5 @@ export async function loginCommand(options = {}) {
143
163
  success(`Joined "${orgName}" (${orgId})`);
144
164
  }
145
165
 
146
- console.log("\nLogged in! Run `agent-factorio push` in any project to register an agent.");
166
+ console.log("\nLogin successful! Run `agent-factorio push` in any project to register an agent.");
147
167
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-factorio",
3
- "version": "0.3.4",
3
+ "version": "0.4.0",
4
4
  "description": "CLI for AgentFactorio — AI Agent Fleet Management hub",
5
5
  "type": "module",
6
6
  "bin": {