@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.
- package/README.md +9 -1
- package/bin/agentbar.js +101 -238
- 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
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
265
|
-
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const normalizeUrl = (value) => {
|
|
114
|
+
if (!value || typeof value !== "string") {
|
|
115
|
+
return "";
|
|
266
116
|
}
|
|
267
|
-
|
|
268
|
-
|
|
117
|
+
const trimmed = value.trim();
|
|
118
|
+
if (!trimmed) {
|
|
119
|
+
return "";
|
|
269
120
|
}
|
|
270
|
-
if (
|
|
271
|
-
|
|
121
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
|
|
122
|
+
return trimmed;
|
|
272
123
|
}
|
|
273
|
-
|
|
274
|
-
|
|
124
|
+
return `https://${trimmed}`;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const resolveSiteKey = (config) => {
|
|
128
|
+
if (config.siteKey) {
|
|
129
|
+
return config.siteKey;
|
|
275
130
|
}
|
|
276
|
-
|
|
277
|
-
|
|
131
|
+
const normalized = normalizeUrl(config.siteUrl);
|
|
132
|
+
if (!normalized) {
|
|
133
|
+
return "";
|
|
278
134
|
}
|
|
279
|
-
|
|
280
|
-
|
|
135
|
+
try {
|
|
136
|
+
return new URL(normalized).hostname;
|
|
137
|
+
} catch {
|
|
138
|
+
return "";
|
|
281
139
|
}
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
347
|
-
config.
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
|
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));
|