@arjun-shah/agentbar-cli 0.1.8 → 0.1.10

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 (3) hide show
  1. package/README.md +9 -1
  2. package/bin/agentbar.js +101 -238
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -20,9 +20,17 @@ npm install -g @arjun-shah/agentbar-cli
20
20
  agentbar init
21
21
  agentbar snippet
22
22
  agentbar set siteUrl https://your-site.com
23
+ agentbar stats
23
24
  ```
24
25
 
25
- The CLI writes `agentbar.config.json` in your project directory.
26
+ The CLI writes `agentbar.config.json` in your project directory. `agentbar init` only asks
27
+ for your site URL and syncs settings to the hosted dashboard so your embed is a single line:
28
+
29
+ ```html
30
+ <script src="https://agent-pug.vercel.app/agentbar.js" data-site-key="your-site-key"></script>
31
+ ```
32
+
33
+ Open the deployed dashboard to edit settings and copy the snippet again.
26
34
 
27
35
  ## Customization
28
36
 
package/bin/agentbar.js CHANGED
@@ -90,197 +90,59 @@ const saveConfig = (config) => {
90
90
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
91
91
  };
92
92
 
93
- const renderSnippet = (config) => {
94
- const lines = [
95
- "<script",
96
- ` src=\"${config.apiBase.replace(/\/$/, "")}/agentbar.js\"`,
97
- ` data-site=\"${config.siteUrl || "https://your-site.com"}\"`,
98
- ` data-api=\"${config.apiBase.replace(/\/$/, "")}\"`,
99
- ` data-depth=\"${config.depth}\"`,
100
- ` data-max-pages=\"${config.maxPages}\"`,
101
- ];
102
- if (config.siteKey) {
103
- lines.push(` data-site-key=\"${config.siteKey}\"`);
104
- }
105
- if (config.themeColor) {
106
- lines.push(` data-theme-color=\"${config.themeColor}\"`);
107
- }
108
- if (config.position) {
109
- lines.push(` data-position=\"${config.position}\"`);
110
- }
111
- if (config.title) {
112
- lines.push(` data-title=\"${config.title}\"`);
113
- }
114
- if (config.subtitle) {
115
- lines.push(` data-subtitle=\"${config.subtitle}\"`);
116
- }
117
- if (config.buttonLabel) {
118
- lines.push(` data-button-label=\"${config.buttonLabel}\"`);
119
- }
120
- if (config.fontFamily) {
121
- lines.push(` data-font-family=\"${config.fontFamily}\"`);
122
- }
123
- if (config.panelBackground) {
124
- lines.push(` data-panel-background=\"${config.panelBackground}\"`);
125
- }
126
- if (config.textColor) {
127
- lines.push(` data-text-color=\"${config.textColor}\"`);
128
- }
129
- if (config.mutedTextColor) {
130
- lines.push(` data-muted-text-color=\"${config.mutedTextColor}\"`);
131
- }
132
- if (config.borderColor) {
133
- lines.push(` data-border-color=\"${config.borderColor}\"`);
134
- }
135
- if (config.buttonBackground) {
136
- lines.push(` data-button-background=\"${config.buttonBackground}\"`);
137
- }
138
- if (config.buttonTextColor) {
139
- lines.push(` data-button-text-color=\"${config.buttonTextColor}\"`);
140
- }
141
- if (config.accentTextColor) {
142
- lines.push(` data-accent-text-color=\"${config.accentTextColor}\"`);
143
- }
144
- if (config.buttonShadow) {
145
- lines.push(` data-button-shadow=\"${config.buttonShadow}\"`);
146
- }
147
- if (config.panelShadow) {
148
- lines.push(` data-panel-shadow=\"${config.panelShadow}\"`);
149
- }
150
- if (config.badgeLabel) {
151
- lines.push(` data-badge-label=\"${config.badgeLabel}\"`);
152
- }
153
- if (config.badgeBackground) {
154
- lines.push(` data-badge-background=\"${config.badgeBackground}\"`);
155
- }
156
- if (config.badgeTextColor) {
157
- lines.push(` data-badge-text-color=\"${config.badgeTextColor}\"`);
158
- }
159
- if (config.userBubbleBackground) {
160
- lines.push(` data-user-bubble-background=\"${config.userBubbleBackground}\"`);
161
- }
162
- if (config.userBubbleText) {
163
- lines.push(` data-user-bubble-text=\"${config.userBubbleText}\"`);
164
- }
165
- if (config.userBubbleBorder) {
166
- lines.push(` data-user-bubble-border=\"${config.userBubbleBorder}\"`);
167
- }
168
- if (config.assistantBubbleBackground) {
169
- lines.push(` data-assistant-bubble-background=\"${config.assistantBubbleBackground}\"`);
170
- }
171
- if (config.assistantBubbleText) {
172
- lines.push(` data-assistant-bubble-text=\"${config.assistantBubbleText}\"`);
173
- }
174
- if (config.assistantBubbleBorder) {
175
- lines.push(` data-assistant-bubble-border=\"${config.assistantBubbleBorder}\"`);
176
- }
177
- if (config.panelWidth) {
178
- lines.push(` data-panel-width=\"${config.panelWidth}\"`);
179
- }
180
- if (config.panelMaxHeight) {
181
- lines.push(` data-panel-max-height=\"${config.panelMaxHeight}\"`);
182
- }
183
- if (config.panelRadius) {
184
- lines.push(` data-panel-radius=\"${config.panelRadius}\"`);
185
- }
186
- if (config.buttonRadius) {
187
- lines.push(` data-button-radius=\"${config.buttonRadius}\"`);
188
- }
189
- if (typeof config.offsetX === "number") {
190
- lines.push(` data-offset-x=\"${config.offsetX}\"`);
191
- }
192
- if (typeof config.offsetY === "number") {
193
- lines.push(` data-offset-y=\"${config.offsetY}\"`);
194
- }
195
- if (config.inputPlaceholder) {
196
- lines.push(` data-input-placeholder=\"${config.inputPlaceholder}\"`);
197
- }
198
- if (config.sendLabel) {
199
- lines.push(` data-send-label=\"${config.sendLabel}\"`);
200
- }
201
- if (config.suggestions?.length) {
202
- lines.push(` data-suggestions=\"${config.suggestions.join(" | ")}\"`);
203
- }
204
- if (config.greeting) {
205
- lines.push(` data-greeting=\"${config.greeting}\"`);
206
- }
207
- if (typeof config.draggable === "boolean") {
208
- lines.push(` data-draggable=\"${config.draggable}\"`);
209
- }
210
- if (typeof config.dragOffset === "number" && config.dragOffset !== 0) {
211
- lines.push(` data-drag-offset=\"${config.dragOffset}\"`);
212
- }
213
- if (typeof config.persistPosition === "boolean") {
214
- lines.push(` data-persist-position=\"${config.persistPosition}\"`);
215
- }
216
- if (config.positionKey) {
217
- lines.push(` data-position-key=\"${config.positionKey}\"`);
218
- }
219
- if (config.openOnLoad) {
220
- lines.push(` data-open=\"${config.openOnLoad}\"`);
221
- }
222
- if (config.showReset) {
223
- lines.push(` data-show-reset=\"${config.showReset}\"`);
93
+ const syncConfig = async (config) => {
94
+ const apiBase = (config.apiBase || DEFAULT_CONFIG.apiBase).replace(/\/$/, "");
95
+ const siteKey = resolveSiteKey(config);
96
+ if (!siteKey) {
97
+ return;
224
98
  }
225
- if (config.persist) {
226
- lines.push(` data-persist=\"${config.persist}\"`);
227
- }
228
- if (config.storageKey) {
229
- lines.push(` data-storage-key=\"${config.storageKey}\"`);
230
- }
231
- if (typeof config.showTypingIndicator === "boolean") {
232
- lines.push(` data-show-typing-indicator=\"${config.showTypingIndicator}\"`);
233
- }
234
- if (typeof config.showExport === "boolean") {
235
- lines.push(` data-show-export=\"${config.showExport}\"`);
236
- }
237
- if (config.exportLabel) {
238
- lines.push(` data-export-label=\"${config.exportLabel}\"`);
239
- }
240
- if (typeof config.showScrollButton === "boolean") {
241
- lines.push(` data-show-scroll-button=\"${config.showScrollButton}\"`);
242
- }
243
- if (config.scrollLabel) {
244
- lines.push(` data-scroll-label=\"${config.scrollLabel}\"`);
245
- }
246
- if (typeof config.showMinimize === "boolean") {
247
- lines.push(` data-show-minimize=\"${config.showMinimize}\"`);
248
- }
249
- if (typeof config.minimizedOnLoad === "boolean") {
250
- lines.push(` data-minimized-on-load=\"${config.minimizedOnLoad}\"`);
251
- }
252
- if (config.minimizeLabel) {
253
- lines.push(` data-minimize-label=\"${config.minimizeLabel}\"`);
254
- }
255
- if (config.expandLabel) {
256
- lines.push(` data-expand-label=\"${config.expandLabel}\"`);
257
- }
258
- if (typeof config.showTimestamps === "boolean") {
259
- lines.push(` data-show-timestamps=\"${config.showTimestamps}\"`);
260
- }
261
- if (config.timestampLocale) {
262
- lines.push(` data-timestamp-locale=\"${config.timestampLocale}\"`);
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.");
263
110
  }
264
- if (typeof config.autoScroll === "boolean") {
265
- lines.push(` data-auto-scroll=\"${config.autoScroll}\"`);
111
+ };
112
+
113
+ const normalizeUrl = (value) => {
114
+ if (!value || typeof value !== "string") {
115
+ return "";
266
116
  }
267
- if (typeof config.autoScrollThreshold === "number") {
268
- lines.push(` data-auto-scroll-threshold=\"${config.autoScrollThreshold}\"`);
117
+ const trimmed = value.trim();
118
+ if (!trimmed) {
119
+ return "";
269
120
  }
270
- if (config.messageMaxWidth) {
271
- lines.push(` data-message-max-width=\"${config.messageMaxWidth}\"`);
121
+ if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
122
+ return trimmed;
272
123
  }
273
- if (config.launcherTooltip) {
274
- lines.push(` data-launcher-tooltip=\"${config.launcherTooltip}\"`);
124
+ return `https://${trimmed}`;
125
+ };
126
+
127
+ const resolveSiteKey = (config) => {
128
+ if (config.siteKey) {
129
+ return config.siteKey;
275
130
  }
276
- if (typeof config.autoIngest === "boolean") {
277
- lines.push(` data-auto-ingest=\"${config.autoIngest}\"`);
131
+ const normalized = normalizeUrl(config.siteUrl);
132
+ if (!normalized) {
133
+ return "";
278
134
  }
279
- if (typeof config.closeOnOutsideClick === "boolean") {
280
- lines.push(` data-close-on-outside-click=\"${config.closeOnOutsideClick}\"`);
135
+ try {
136
+ return new URL(normalized).hostname;
137
+ } catch {
138
+ return "";
281
139
  }
282
- lines.push("></script>");
283
- return lines.join("\n");
140
+ };
141
+
142
+ const renderSnippet = (config) => {
143
+ const apiBase = (config.apiBase || DEFAULT_CONFIG.apiBase).replace(/\/$/, "");
144
+ const siteKey = resolveSiteKey(config) || "your-site-key";
145
+ return `<script src="${apiBase}/agentbar.js" data-site-key="${siteKey}"></script>`;
284
146
  };
285
147
 
286
148
  const printHelp = () => {
@@ -289,6 +151,7 @@ const printHelp = () => {
289
151
  console.log(" agentbar init Interactive setup and snippet output");
290
152
  console.log(" agentbar snippet Print current embed snippet");
291
153
  console.log(" agentbar set <key> <v> Update config value");
154
+ console.log(" agentbar stats Fetch indexing status from the API");
292
155
  console.log(" agentbar config Print config JSON");
293
156
  console.log(" agentbar help Show help\n");
294
157
  console.log("Config keys:");
@@ -343,70 +206,63 @@ const init = async () => {
343
206
  });
344
207
 
345
208
  try {
346
- config.siteUrl = await ask(rl, "Site URL", config.siteUrl || "https://your-site.com");
347
- config.apiBase = await ask(rl, "API base URL", config.apiBase);
348
- config.depth = Number(await ask(rl, "Crawl depth", String(config.depth)) || config.depth);
349
- config.maxPages = Number(
350
- await ask(rl, "Max pages", String(config.maxPages)) || config.maxPages
351
- );
352
- config.siteKey = await ask(rl, "Site key (optional)", config.siteKey);
353
- config.themeColor = await ask(rl, "Theme color", config.themeColor);
354
- config.position = await ask(rl, "Position (left/right/bottom)", config.position);
355
- config.title = await ask(rl, "Widget title", config.title);
356
- config.subtitle = await ask(rl, "Widget subtitle", config.subtitle);
357
- config.buttonLabel = await ask(rl, "Button label", config.buttonLabel);
358
- config.fontFamily = await ask(rl, "Font family", config.fontFamily);
359
- config.inputPlaceholder = await ask(rl, "Input placeholder", config.inputPlaceholder);
360
- config.sendLabel = await ask(rl, "Send button label", config.sendLabel);
361
- const suggestionInput = await ask(
362
- rl,
363
- "Suggestions (pipe or comma separated)",
364
- config.suggestions.join(" | ")
365
- );
366
- config.suggestions = suggestionInput
367
- .split(/[|,]/)
368
- .map((value) => value.trim())
369
- .filter(Boolean);
370
- config.greeting = await ask(rl, "Greeting (optional)", config.greeting);
371
- config.draggable =
372
- (await ask(rl, "Draggable launcher (true/false)", String(config.draggable))) === "true";
373
- config.persistPosition =
374
- (await ask(rl, "Persist position (true/false)", String(config.persistPosition))) === "true";
375
- config.openOnLoad = (await ask(rl, "Open on load (true/false)", String(config.openOnLoad))) === "true";
376
- config.showReset = (await ask(rl, "Show reset button (true/false)", String(config.showReset))) === "true";
377
- config.persist = (await ask(rl, "Persist chat (true/false)", String(config.persist))) === "true";
378
- config.showTypingIndicator =
379
- (await ask(rl, "Show typing indicator (true/false)", String(config.showTypingIndicator))) ===
380
- "true";
381
- config.showExport =
382
- (await ask(rl, "Show export button (true/false)", String(config.showExport))) === "true";
383
- config.exportLabel = await ask(rl, "Export label", config.exportLabel);
384
- config.showScrollButton =
385
- (await ask(rl, "Show scroll button (true/false)", String(config.showScrollButton))) ===
386
- "true";
387
- config.scrollLabel = await ask(rl, "Scroll button label", config.scrollLabel);
388
- config.showMinimize =
389
- (await ask(rl, "Show minimize button (true/false)", String(config.showMinimize))) ===
390
- "true";
391
- config.minimizedOnLoad =
392
- (await ask(rl, "Minimized on load (true/false)", String(config.minimizedOnLoad))) ===
393
- "true";
394
- config.showTimestamps =
395
- (await ask(rl, "Show timestamps (true/false)", String(config.showTimestamps))) === "true";
396
- config.autoScroll =
397
- (await ask(rl, "Auto scroll (true/false)", String(config.autoScroll))) === "true";
398
- config.autoIngest = (await ask(rl, "Auto ingest (true/false)", String(config.autoIngest))) === "true";
209
+ const siteUrlInput = await ask(rl, "Site URL", config.siteUrl || "https://your-site.com");
210
+ config.siteUrl = normalizeUrl(siteUrlInput);
211
+ if (!config.siteUrl) {
212
+ config.siteUrl = "https://your-site.com";
213
+ }
214
+ config.siteKey = resolveSiteKey(config);
399
215
  } finally {
400
216
  rl.close();
401
217
  }
402
218
 
403
219
  saveConfig(config);
220
+ await syncConfig(config);
404
221
  console.log("\nSaved config to", configPath);
405
222
  console.log("\nEmbed snippet:\n");
406
223
  console.log(renderSnippet(config));
224
+ console.log(`\nDashboard: ${(config.apiBase || DEFAULT_CONFIG.apiBase).replace(/\/$/, "")}\n`);
407
225
  };
408
226
 
409
- const setValue = (key, value) => {
227
+ const printStats = async () => {
228
+ const config = loadConfig();
229
+ const apiBase = (config.apiBase || DEFAULT_CONFIG.apiBase).replace(/\/$/, "");
230
+ const siteKey = resolveSiteKey(config);
231
+
232
+ if (!siteKey) {
233
+ console.error("Missing siteUrl. Run `agentbar init` or `agentbar set siteUrl <url>` first.");
234
+ process.exit(1);
235
+ }
236
+
237
+ try {
238
+ const response = await fetch(`${apiBase}/api/status`);
239
+ if (!response.ok) {
240
+ const data = await response.json().catch(() => ({}));
241
+ throw new Error(data?.error || `Status request failed (${response.status})`);
242
+ }
243
+ const data = await response.json();
244
+ const items = Array.isArray(data?.items) ? data.items : [];
245
+ const matched = items.filter((item) => item.key === siteKey);
246
+ if (!matched.length) {
247
+ console.log("No indexed content found for", siteKey);
248
+ console.log("Send a message in the widget to trigger ingest.");
249
+ return;
250
+ }
251
+ matched.forEach((item) => {
252
+ console.log(`Site: ${item.url}`);
253
+ console.log(`Pages indexed: ${item.pages?.length ?? 0}`);
254
+ console.log(`Chunks: ${item.chunkCount ?? 0}`);
255
+ console.log(`Updated: ${item.updatedAt ? new Date(item.updatedAt).toLocaleString() : "N/A"}`);
256
+ console.log("");
257
+ });
258
+ } catch (error) {
259
+ const message = error instanceof Error ? error.message : "Failed to load stats.";
260
+ console.error(message);
261
+ process.exit(1);
262
+ }
263
+ };
264
+
265
+ const setValue = async (key, value) => {
410
266
  if (!key || typeof value === "undefined") {
411
267
  console.error("Usage: agentbar set <key> <value>");
412
268
  process.exit(1);
@@ -463,11 +319,15 @@ const setValue = (key, value) => {
463
319
  .split(/[|,]/)
464
320
  .map((item) => item.trim())
465
321
  .filter(Boolean);
322
+ } else if (key === "siteUrl") {
323
+ config[key] = normalizeUrl(value);
324
+ config.siteKey = resolveSiteKey(config);
466
325
  } else {
467
326
  config[key] = value;
468
327
  }
469
328
 
470
329
  saveConfig(config);
330
+ await syncConfig(config);
471
331
  console.log("Updated", key, "in", configPath);
472
332
  };
473
333
 
@@ -483,8 +343,11 @@ const main = async () => {
483
343
  console.log(renderSnippet(config));
484
344
  return;
485
345
  }
346
+ case "stats":
347
+ await printStats();
348
+ return;
486
349
  case "set":
487
- setValue(arg1, arg2);
350
+ await setValue(arg1, arg2);
488
351
  return;
489
352
  case "config":
490
353
  console.log(JSON.stringify(loadConfig(), null, 2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arjun-shah/agentbar-cli",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "description": "Agent Plugin Bar CLI helper.",
6
6
  "bin": {