@arjun-shah/agentbar-cli 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/bin/agentbar.js +132 -34
- package/package.json +1 -1
package/bin/agentbar.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
|
-
import readline from "node:readline";
|
|
5
5
|
import process from "node:process";
|
|
6
|
+
import readline from "node:readline";
|
|
6
7
|
|
|
7
8
|
const CONFIG_FILE = "agentbar.config.json";
|
|
8
9
|
const DEFAULT_CONFIG = {
|
|
9
10
|
apiBase: "https://agent-pug.vercel.app",
|
|
11
|
+
authToken: "",
|
|
12
|
+
accountEmail: "",
|
|
10
13
|
siteUrl: "",
|
|
11
14
|
siteKey: "",
|
|
12
15
|
depth: 1,
|
|
@@ -90,26 +93,6 @@ const saveConfig = (config) => {
|
|
|
90
93
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
91
94
|
};
|
|
92
95
|
|
|
93
|
-
const syncConfig = async (config) => {
|
|
94
|
-
const apiBase = (config.apiBase || DEFAULT_CONFIG.apiBase).replace(/\/$/, "");
|
|
95
|
-
const siteKey = resolveSiteKey(config);
|
|
96
|
-
if (!siteKey) {
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
try {
|
|
100
|
-
await fetch(`${apiBase}/api/config`, {
|
|
101
|
-
method: "POST",
|
|
102
|
-
headers: { "Content-Type": "application/json" },
|
|
103
|
-
body: JSON.stringify({
|
|
104
|
-
siteKey,
|
|
105
|
-
config: { ...config, siteKey },
|
|
106
|
-
}),
|
|
107
|
-
});
|
|
108
|
-
} catch (_error) {
|
|
109
|
-
console.warn("Could not sync settings to the hosted dashboard.");
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
|
|
113
96
|
const normalizeUrl = (value) => {
|
|
114
97
|
if (!value || typeof value !== "string") {
|
|
115
98
|
return "";
|
|
@@ -139,15 +122,72 @@ const resolveSiteKey = (config) => {
|
|
|
139
122
|
}
|
|
140
123
|
};
|
|
141
124
|
|
|
125
|
+
const authHeaders = (config) =>
|
|
126
|
+
config.authToken
|
|
127
|
+
? {
|
|
128
|
+
Authorization: `Bearer ${config.authToken}`,
|
|
129
|
+
}
|
|
130
|
+
: {};
|
|
131
|
+
|
|
142
132
|
const renderSnippet = (config) => {
|
|
143
133
|
const apiBase = (config.apiBase || DEFAULT_CONFIG.apiBase).replace(/\/$/, "");
|
|
144
134
|
const siteKey = resolveSiteKey(config) || "your-site-key";
|
|
145
135
|
return `<script src="${apiBase}/agentbar.js" data-site-key="${siteKey}"></script>`;
|
|
146
136
|
};
|
|
147
137
|
|
|
138
|
+
const openBrowser = (url) => {
|
|
139
|
+
try {
|
|
140
|
+
if (process.platform === "darwin") {
|
|
141
|
+
spawn("open", [url], { stdio: "ignore", detached: true }).unref();
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
if (process.platform === "win32") {
|
|
145
|
+
spawn("cmd", ["/c", "start", "", url], { stdio: "ignore", detached: true }).unref();
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
if (process.platform === "linux") {
|
|
149
|
+
spawn("xdg-open", [url], { stdio: "ignore", detached: true }).unref();
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
return false;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
159
|
+
|
|
160
|
+
const syncConfig = async (config) => {
|
|
161
|
+
const apiBase = (config.apiBase || DEFAULT_CONFIG.apiBase).replace(/\/$/, "");
|
|
162
|
+
const siteKey = resolveSiteKey(config);
|
|
163
|
+
if (!siteKey || !config.authToken) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
const response = await fetch(`${apiBase}/api/config`, {
|
|
168
|
+
method: "POST",
|
|
169
|
+
headers: {
|
|
170
|
+
"Content-Type": "application/json",
|
|
171
|
+
...authHeaders(config),
|
|
172
|
+
},
|
|
173
|
+
body: JSON.stringify({
|
|
174
|
+
siteKey,
|
|
175
|
+
config: { ...config, siteKey },
|
|
176
|
+
}),
|
|
177
|
+
});
|
|
178
|
+
if (!response.ok) {
|
|
179
|
+
const data = await response.json().catch(() => ({}));
|
|
180
|
+
throw new Error(data?.error || "Could not sync hosted settings.");
|
|
181
|
+
}
|
|
182
|
+
} catch (_error) {
|
|
183
|
+
console.warn("Could not sync settings to the hosted dashboard.");
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
148
187
|
const printHelp = () => {
|
|
149
188
|
console.log("Agent Plugin Bar CLI\n");
|
|
150
189
|
console.log("Commands:");
|
|
190
|
+
console.log(" agentbar login Open the web login flow and save an auth token");
|
|
151
191
|
console.log(" agentbar init Interactive setup and snippet output");
|
|
152
192
|
console.log(" agentbar snippet Print current embed snippet");
|
|
153
193
|
console.log(" agentbar set <key> <v> Update config value");
|
|
@@ -156,7 +196,7 @@ const printHelp = () => {
|
|
|
156
196
|
console.log(" agentbar help Show help\n");
|
|
157
197
|
console.log("Config keys:");
|
|
158
198
|
console.log(
|
|
159
|
-
" siteUrl, apiBase, depth, maxPages, siteKey, themeColor, position, title, subtitle,"
|
|
199
|
+
" siteUrl, apiBase, authToken, accountEmail, depth, maxPages, siteKey, themeColor, position, title, subtitle,"
|
|
160
200
|
);
|
|
161
201
|
console.log(
|
|
162
202
|
" buttonLabel, fontFamily, panelBackground, textColor, mutedTextColor, borderColor,"
|
|
@@ -198,8 +238,60 @@ const ask = (rl, prompt, fallback) =>
|
|
|
198
238
|
});
|
|
199
239
|
});
|
|
200
240
|
|
|
241
|
+
const login = async (existingConfig = loadConfig()) => {
|
|
242
|
+
const config = { ...existingConfig };
|
|
243
|
+
const apiBase = (config.apiBase || DEFAULT_CONFIG.apiBase).replace(/\/$/, "");
|
|
244
|
+
|
|
245
|
+
const response = await fetch(`${apiBase}/api/auth/device/start`, {
|
|
246
|
+
method: "POST",
|
|
247
|
+
headers: { "Content-Type": "application/json" },
|
|
248
|
+
});
|
|
249
|
+
const data = await response.json().catch(() => ({}));
|
|
250
|
+
if (!response.ok) {
|
|
251
|
+
throw new Error(data?.error || "Failed to start login.");
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
console.log(`User code: ${data.userCode}`);
|
|
255
|
+
console.log(`Verification URL: ${data.verificationUrl}`);
|
|
256
|
+
if (!openBrowser(data.verificationUrl)) {
|
|
257
|
+
console.log("Open that URL in your browser to continue.");
|
|
258
|
+
}
|
|
259
|
+
console.log("Waiting for approval...\n");
|
|
260
|
+
|
|
261
|
+
const intervalMs = Math.max(1000, Number(data.interval || 2) * 1000);
|
|
262
|
+
const expiresAt = Number(data.expiresAt || 0);
|
|
263
|
+
|
|
264
|
+
while (!expiresAt || Date.now() < expiresAt) {
|
|
265
|
+
await sleep(intervalMs);
|
|
266
|
+
const pollResponse = await fetch(`${apiBase}/api/auth/device/poll`, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: { "Content-Type": "application/json" },
|
|
269
|
+
body: JSON.stringify({ deviceCode: data.deviceCode }),
|
|
270
|
+
});
|
|
271
|
+
const pollData = await pollResponse.json().catch(() => ({}));
|
|
272
|
+
if (!pollResponse.ok) {
|
|
273
|
+
throw new Error(pollData?.error || "Login polling failed.");
|
|
274
|
+
}
|
|
275
|
+
if (!pollData.approved) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
config.authToken = pollData.accessToken || "";
|
|
279
|
+
config.accountEmail = pollData.user?.email || "";
|
|
280
|
+
saveConfig(config);
|
|
281
|
+
console.log(`Logged in as ${config.accountEmail || "your account"}.`);
|
|
282
|
+
return config;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
throw new Error("Login request expired before approval.");
|
|
286
|
+
};
|
|
287
|
+
|
|
201
288
|
const init = async () => {
|
|
202
|
-
|
|
289
|
+
let config = loadConfig();
|
|
290
|
+
if (!config.authToken) {
|
|
291
|
+
console.log("No saved login found. Opening the web login flow...\n");
|
|
292
|
+
config = await login(config);
|
|
293
|
+
}
|
|
294
|
+
|
|
203
295
|
const rl = readline.createInterface({
|
|
204
296
|
input: process.stdin,
|
|
205
297
|
output: process.stdout,
|
|
@@ -234,8 +326,15 @@ const printStats = async () => {
|
|
|
234
326
|
process.exit(1);
|
|
235
327
|
}
|
|
236
328
|
|
|
329
|
+
if (!config.authToken) {
|
|
330
|
+
console.error("Missing auth token. Run `agentbar login` first.");
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
|
|
237
334
|
try {
|
|
238
|
-
const response = await fetch(`${apiBase}/api/status
|
|
335
|
+
const response = await fetch(`${apiBase}/api/status`, {
|
|
336
|
+
headers: authHeaders(config),
|
|
337
|
+
});
|
|
239
338
|
if (!response.ok) {
|
|
240
339
|
const data = await response.json().catch(() => ({}));
|
|
241
340
|
throw new Error(data?.error || `Status request failed (${response.status})`);
|
|
@@ -245,7 +344,7 @@ const printStats = async () => {
|
|
|
245
344
|
const matched = items.filter((item) => item.key === siteKey);
|
|
246
345
|
if (!matched.length) {
|
|
247
346
|
console.log("No indexed content found for", siteKey);
|
|
248
|
-
console.log("
|
|
347
|
+
console.log("Save the site config and run reindex from the console first.");
|
|
249
348
|
return;
|
|
250
349
|
}
|
|
251
350
|
matched.forEach((item) => {
|
|
@@ -283,7 +382,7 @@ const setValue = async (key, value) => {
|
|
|
283
382
|
process.exit(1);
|
|
284
383
|
}
|
|
285
384
|
config[key] = parsed;
|
|
286
|
-
} else if (key === "offsetX" || key === "offsetY") {
|
|
385
|
+
} else if (key === "offsetX" || key === "offsetY" || key === "dragOffset") {
|
|
287
386
|
const parsed = Number(value);
|
|
288
387
|
if (!Number.isFinite(parsed)) {
|
|
289
388
|
console.error(`${key} must be a number.`);
|
|
@@ -307,13 +406,6 @@ const setValue = async (key, value) => {
|
|
|
307
406
|
key === "autoScroll"
|
|
308
407
|
) {
|
|
309
408
|
config[key] = value === "true" || value === true;
|
|
310
|
-
} else if (key === "dragOffset") {
|
|
311
|
-
const parsed = Number(value);
|
|
312
|
-
if (!Number.isFinite(parsed)) {
|
|
313
|
-
console.error(`${key} must be a number.`);
|
|
314
|
-
process.exit(1);
|
|
315
|
-
}
|
|
316
|
-
config[key] = parsed;
|
|
317
409
|
} else if (key === "suggestions") {
|
|
318
410
|
config[key] = String(value)
|
|
319
411
|
.split(/[|,]/)
|
|
@@ -335,6 +427,9 @@ const main = async () => {
|
|
|
335
427
|
const [command, arg1, arg2] = process.argv.slice(2);
|
|
336
428
|
|
|
337
429
|
switch (command) {
|
|
430
|
+
case "login":
|
|
431
|
+
await login();
|
|
432
|
+
return;
|
|
338
433
|
case "init":
|
|
339
434
|
await init();
|
|
340
435
|
return;
|
|
@@ -364,4 +459,7 @@ const main = async () => {
|
|
|
364
459
|
}
|
|
365
460
|
};
|
|
366
461
|
|
|
367
|
-
main()
|
|
462
|
+
main().catch((error) => {
|
|
463
|
+
console.error(error instanceof Error ? error.message : "Unknown error");
|
|
464
|
+
process.exit(1);
|
|
465
|
+
});
|