bunnyquery 1.5.3 → 1.5.5

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/bunnyquery.css CHANGED
@@ -246,14 +246,16 @@
246
246
  /* ============================================================================
247
247
  * AUTH VIEWS (login / signup / forgot / verify / settings)
248
248
  * ==========================================================================*/
249
- /* padded parent that nests a standalone page (login / signup / verify / …) */
249
+ /* padded parent that nests a standalone page (login / signup / verify / …).
250
+ Sits below the shared .bq-section-title header (the top-left service badge),
251
+ so the top padding is small — the header supplies the top spacing. */
250
252
  .bq-page {
251
253
  flex: 1;
252
254
  min-height: 0;
253
255
  overflow-y: auto;
254
256
  display: flex;
255
257
  flex-direction: column;
256
- padding: 2.5rem 1.5rem;
258
+ padding: 1rem 1.5rem 2.5rem;
257
259
  }
258
260
  .bq-settings {
259
261
  flex: 1;
@@ -264,6 +266,15 @@
264
266
  color: var(--bq-ink);
265
267
  }
266
268
 
269
+ /* full-box loading view: fill the space above the footer and center the bunny */
270
+ .bq-page-loading {
271
+ flex: 1;
272
+ min-height: 0;
273
+ display: flex;
274
+ align-items: center;
275
+ justify-content: center;
276
+ }
277
+
267
278
  .bq-page-footer {
268
279
  flex-shrink: 0;
269
280
  text-align: center;
@@ -276,6 +287,12 @@
276
287
  text-decoration: none;
277
288
  }
278
289
  .bq-page-footer-link:hover { text-decoration: underline; }
290
+ .bq-page-footer-version {
291
+ font-family: var(--bq-mono);
292
+ font-size: 0.7rem;
293
+ color: var(--bq-muted);
294
+ margin-top: 0.25rem;
295
+ }
279
296
 
280
297
  .bq-settings-title {
281
298
  font-size: 1.5rem;
@@ -559,11 +576,11 @@
559
576
  align-items: center;
560
577
  gap: 0.45rem;
561
578
  padding: 0.3rem 0.6rem;
562
- border: 1px solid var(--bq-line);
563
- background: var(--bq-paper);
579
+ border: 1px solid var(--bq-main);
580
+ background: var(--bq-main-bg);
564
581
  font-size: 0.75rem;
565
582
  font-family: var(--bq-mono);
566
- color: var(--bq-ink);
583
+ color: var(--bq-main);
567
584
  max-width: 100%;
568
585
  overflow: hidden;
569
586
  }
@@ -608,7 +625,16 @@
608
625
  margin: 0 auto;
609
626
  padding: 1.25rem 0 2rem;
610
627
  }
611
- .bq-chat-settings-loading { text-align: center; padding: 2.5rem 0; color: var(--bq-muted); }
628
+ /* fill the messages box and center the bunny (matches .bq-history-loading.is-initial).
629
+ Resolves against .bq-messages (position: relative), not the max-width settings wrap. */
630
+ .bq-chat-settings-loading {
631
+ position: absolute;
632
+ inset: 0;
633
+ display: flex;
634
+ align-items: center;
635
+ justify-content: center;
636
+ color: var(--bq-muted);
637
+ }
612
638
 
613
639
  /* chat container + scroll area */
614
640
  .bq-chat {
@@ -756,6 +782,8 @@
756
782
  .bq-input::placeholder { color: var(--bq-placeholder); }
757
783
  .bq-input:focus { outline: none; border-color: var(--bq-ink); }
758
784
  .bq-input:disabled { opacity: 0.5; cursor: default; }
785
+ /* Attach button hidden (frozen DB): reclaim the reserved left gutter. */
786
+ .bq-input.bq-input--noattach { padding-left: 0.7rem; }
759
787
  .bq-input-row .btn {
760
788
  align-self: flex-end;
761
789
  min-width: 5.5rem;
package/bunnyquery.js CHANGED
@@ -1794,22 +1794,22 @@ ${options.inlineContentPlaceholder}
1794
1794
  var id = this.host.getIdentity();
1795
1795
  var svcId = id.serviceId, plat = id.platform;
1796
1796
  if (!svcId || plat === "none" || !this.host.isViewMounted()) return;
1797
+ var presentIds = {};
1798
+ var pendingIds = {};
1799
+ this.state.messages.forEach(function(m) {
1800
+ var sid = m._serverItemId;
1801
+ if (sid == null) return;
1802
+ presentIds[sid] = true;
1803
+ if (m.isPending || m.isPendingInProcess || m.isPendingQueued) pendingIds[sid] = true;
1804
+ });
1797
1805
  for (var i = this.bgTaskQueue.length - 1; i >= 0; i--) {
1798
1806
  var e = this.bgTaskQueue[i];
1799
1807
  if (e.serviceId !== svcId || e.platform !== plat) continue;
1800
- var present = this.state.messages.some(function(m) {
1801
- return m._serverItemId === e.id;
1802
- });
1803
- var stillPending = this.state.messages.some(function(m) {
1804
- return m._serverItemId === e.id && (m.isPending || m.isPendingInProcess || m.isPendingQueued);
1805
- });
1806
- if (present && !stillPending) this.bgTaskQueue.splice(i, 1);
1808
+ if (presentIds[e.id] && !pendingIds[e.id]) this.bgTaskQueue.splice(i, 1);
1807
1809
  }
1808
1810
  this.bgTaskQueue.forEach(function(entry) {
1809
1811
  if (entry.serviceId !== svcId || entry.platform !== plat) return;
1810
- if (self.state.messages.some(function(m) {
1811
- return m._serverItemId === entry.id;
1812
- })) return;
1812
+ if (presentIds[entry.id]) return;
1813
1813
  var isRunning = entry.status === "running";
1814
1814
  var userBubble = { role: "user", content: self.host.formatIndexingLabel(entry.filename, entry.mime, entry.size, entry.storagePath, entry.isReindex), isBackgroundTask: true, _serverItemId: entry.id };
1815
1815
  if (isRunning) userBubble.isPendingInProcess = true;
@@ -1818,6 +1818,7 @@ ${options.inlineContentPlaceholder}
1818
1818
  if (isRunning) {
1819
1819
  self.state.messages.push({ role: "assistant", content: "", isPending: true, isPendingInProcess: true, isBackgroundTask: true, _serverItemId: entry.id });
1820
1820
  }
1821
+ presentIds[entry.id] = true;
1821
1822
  self.host.notify();
1822
1823
  self.updateHistoryCache();
1823
1824
  self.host.scrollToBottom(false);
@@ -2213,7 +2214,7 @@ ${options.inlineContentPlaceholder}
2213
2214
  (function() {
2214
2215
  var MCP_PROD = "https://mcp.broadwayinc.computer";
2215
2216
  var MCP_DEV = "https://mcp-dev.broadwayinc.computer";
2216
- var BQ_VERSION = "1.5.3" ;
2217
+ var BQ_VERSION = "1.5.5" ;
2217
2218
  var ATTACHMENT_URL_EXPIRES_SECONDS = 600;
2218
2219
  var GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
2219
2220
  var GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token";
@@ -2453,7 +2454,29 @@ ${options.inlineContentPlaceholder}
2453
2454
  if (node) S.root.appendChild(node);
2454
2455
  }
2455
2456
  function pageRoot(content) {
2456
- return h("div", { class: "bq-page" }, h("div", { class: "bq-settings" }, content), pageFooter());
2457
+ return h(
2458
+ "div",
2459
+ { class: "bq-meta" },
2460
+ h(
2461
+ "div",
2462
+ { class: "bq-section-title" },
2463
+ h(
2464
+ "div",
2465
+ { class: "bq-title-row" },
2466
+ h(
2467
+ "div",
2468
+ { class: "bq-title-left" },
2469
+ h("span", { class: "bq-agent-badge", text: agentBadgeText() })
2470
+ )
2471
+ )
2472
+ ),
2473
+ h(
2474
+ "div",
2475
+ { class: "bq-page" },
2476
+ h("div", { class: "bq-settings" }, content),
2477
+ pageFooter()
2478
+ )
2479
+ );
2457
2480
  }
2458
2481
  function pageFooter() {
2459
2482
  return h(
@@ -2465,7 +2488,8 @@ ${options.inlineContentPlaceholder}
2465
2488
  target: "_blank",
2466
2489
  rel: "noopener noreferrer",
2467
2490
  text: "www.bunnyquery.com"
2468
- })
2491
+ }),
2492
+ h("div", { class: "bq-page-footer-version", text: "v" + BQ_VERSION })
2469
2493
  );
2470
2494
  }
2471
2495
  var BUNNY_FRAME_A = ' (\\(\\\n ( - -)\n c(")(")';
@@ -2497,12 +2521,15 @@ ${options.inlineContentPlaceholder}
2497
2521
  }
2498
2522
  function showLoading(label) {
2499
2523
  render("loading", function() {
2500
- return pageRoot(
2524
+ return h(
2525
+ "div",
2526
+ { class: "bq-page" },
2501
2527
  h(
2502
2528
  "div",
2503
- { class: "bq-disabled-inner", style: { marginTop: "3rem" } },
2529
+ { class: "bq-page-loading" },
2504
2530
  bunnyLoader("Loading...")
2505
- )
2531
+ ),
2532
+ pageFooter()
2506
2533
  );
2507
2534
  });
2508
2535
  }
@@ -2917,8 +2944,21 @@ ${options.inlineContentPlaceholder}
2917
2944
  }
2918
2945
  function authShell(title, children, opts) {
2919
2946
  opts = opts || {};
2920
- var kids = authHeader(title).concat(children);
2921
- if (opts.back !== false) {
2947
+ var kids = [];
2948
+ if (opts.topBack) {
2949
+ kids.push(h(
2950
+ "div",
2951
+ { class: "bq-settings-top" },
2952
+ h("button", {
2953
+ class: "bq-link",
2954
+ type: "button",
2955
+ onclick: opts.topBack.onClick,
2956
+ text: opts.topBack.label || "\u2190 Back"
2957
+ })
2958
+ ));
2959
+ }
2960
+ kids = kids.concat(authHeader(title)).concat(children);
2961
+ if (opts.back !== false && !opts.topBack) {
2922
2962
  kids.push(h(
2923
2963
  "div",
2924
2964
  { class: "bq-actions", style: { marginTop: "1.5rem" } },
@@ -3313,7 +3353,13 @@ ${options.inlineContentPlaceholder}
3313
3353
  note,
3314
3354
  h("div", { class: "bq-form-bottom" }, btn)
3315
3355
  )
3316
- ], { back: false });
3356
+ ], { topBack: {
3357
+ label: "\u2190 Back to settings",
3358
+ onClick: function() {
3359
+ renderChat();
3360
+ openChatSettings();
3361
+ }
3362
+ } });
3317
3363
  sendCode(note);
3318
3364
  return shell;
3319
3365
  }
@@ -3768,6 +3814,8 @@ ${options.inlineContentPlaceholder}
3768
3814
  // [{ id, name, file, status, progress, uploadedUrl, storagePath, errorMessage }]
3769
3815
  uploadingAttachments: false,
3770
3816
  attachmentWarning: "",
3817
+ attachmentCapNotice: "",
3818
+ // informational "N files not added" when an add hit MAX_ATTACHMENT_FILE_COUNT
3771
3819
  attachmentsRow: null,
3772
3820
  // .bq-attachments DOM node
3773
3821
  attachBtnEl: null,
@@ -4285,6 +4333,8 @@ ${options.inlineContentPlaceholder}
4285
4333
  var FILE_ICON_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>';
4286
4334
  var FOLDER_ICON_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>';
4287
4335
  var MAX_CHATBOX_FILE_COUNT = 20;
4336
+ var MAX_ATTACHMENT_FILE_COUNT = 20;
4337
+ var VISIBLE_CHIP_CAP = 30;
4288
4338
  var ESTIMATED_BYTES_PER_TOKEN = 3;
4289
4339
  var ESTIMATED_PDF_BYTES_PER_TOKEN = 5e3;
4290
4340
  var ESTIMATED_IMAGE_TOKENS = 800;
@@ -4379,19 +4429,35 @@ ${options.inlineContentPlaceholder}
4379
4429
  CS.attachments.forEach(function(a) {
4380
4430
  seen[attachmentKey(a)] = true;
4381
4431
  });
4432
+ var remaining = MAX_ATTACHMENT_FILE_COUNT - attachmentFileCount();
4433
+ var dropped = 0;
4382
4434
  var changed = false;
4383
4435
  (attObjs || []).forEach(function(a) {
4384
4436
  if (!a) return;
4385
4437
  var k = attachmentKey(a);
4386
4438
  if (seen[k]) return;
4439
+ var count = a.kind === "folder" ? a.files ? a.files.length : 0 : 1;
4440
+ if (remaining <= 0) {
4441
+ dropped += count;
4442
+ return;
4443
+ }
4444
+ if (a.kind === "folder" && count > remaining) {
4445
+ dropped += count - remaining;
4446
+ a.files = a.files.slice(0, remaining);
4447
+ count = remaining;
4448
+ }
4387
4449
  seen[k] = true;
4388
4450
  CS.attachments.push(a);
4451
+ remaining -= count;
4389
4452
  changed = true;
4390
4453
  });
4454
+ CS.attachmentCapNotice = dropped > 0 ? "You can attach up to " + MAX_ATTACHMENT_FILE_COUNT + " files per message. " + dropped + " file" + (dropped === 1 ? " was" : "s were") + " not added." : "";
4391
4455
  if (changed) {
4392
4456
  recomputeAttachmentWarning();
4393
4457
  renderAttachmentChips();
4394
4458
  scheduleAttachmentOverflowRecompute();
4459
+ } else if (dropped > 0) {
4460
+ renderAttachmentChips();
4395
4461
  }
4396
4462
  updateComposerControls();
4397
4463
  }
@@ -4466,11 +4532,11 @@ ${options.inlineContentPlaceholder}
4466
4532
  CS.visibleAttachmentCount = Infinity;
4467
4533
  return;
4468
4534
  }
4469
- CS.visibleAttachmentCount = total;
4535
+ var count = Math.min(total, VISIBLE_CHIP_CAP);
4536
+ CS.visibleAttachmentCount = count;
4470
4537
  renderAttachmentChips();
4471
4538
  var maxHeight = chat.clientHeight * ATTACHMENTS_MAX_HEIGHT_RATIO;
4472
4539
  if (maxHeight <= 0) return;
4473
- var count = total;
4474
4540
  while (count > 0 && row.scrollHeight > maxHeight) {
4475
4541
  count--;
4476
4542
  CS.visibleAttachmentCount = count;
@@ -4495,6 +4561,7 @@ ${options.inlineContentPlaceholder}
4495
4561
  return true;
4496
4562
  });
4497
4563
  CS.visibleAttachmentCount = Infinity;
4564
+ CS.attachmentCapNotice = "";
4498
4565
  recomputeAttachmentWarning();
4499
4566
  renderAttachmentChips();
4500
4567
  updateComposerControls();
@@ -4513,6 +4580,7 @@ ${options.inlineContentPlaceholder}
4513
4580
  }
4514
4581
  }
4515
4582
  CS.attachments.splice(i, 1);
4583
+ CS.attachmentCapNotice = "";
4516
4584
  recomputeAttachmentWarning();
4517
4585
  renderAttachmentChips();
4518
4586
  updateComposerControls();
@@ -4529,6 +4597,7 @@ ${options.inlineContentPlaceholder}
4529
4597
  });
4530
4598
  CS.attachments = [];
4531
4599
  CS.attachmentWarning = "";
4600
+ CS.attachmentCapNotice = "";
4532
4601
  renderAttachmentChips();
4533
4602
  updateComposerControls();
4534
4603
  scheduleAttachmentOverflowRecompute();
@@ -4540,6 +4609,7 @@ ${options.inlineContentPlaceholder}
4540
4609
  CS.attachments.forEach(function(a) {
4541
4610
  a._abort = null;
4542
4611
  });
4612
+ CS.attachmentCapNotice = "";
4543
4613
  recomputeAttachmentWarning();
4544
4614
  renderAttachmentChips();
4545
4615
  updateComposerControls();
@@ -4567,16 +4637,19 @@ ${options.inlineContentPlaceholder}
4567
4637
  var row = CS.attachmentsRow;
4568
4638
  if (!row) return;
4569
4639
  row.innerHTML = "";
4570
- if (!CS.attachments.length && !CS.attachmentWarning) {
4640
+ if (!CS.attachments.length && !CS.attachmentWarning && !CS.attachmentCapNotice) {
4571
4641
  row.style.display = "none";
4572
4642
  return;
4573
4643
  }
4574
4644
  row.style.display = "";
4645
+ if (CS.attachmentCapNotice) {
4646
+ row.appendChild(h("div", { class: "bq-attachment-warning" }, h("span", { text: CS.attachmentCapNotice })));
4647
+ }
4575
4648
  if (CS.attachmentWarning) {
4576
4649
  row.appendChild(h("div", { class: "bq-attachment-warning" }, h("span", { text: CS.attachmentWarning })));
4577
4650
  }
4578
4651
  var sorted = sortedAttachments();
4579
- var vis = CS.visibleAttachmentCount;
4652
+ var vis = Math.min(CS.visibleAttachmentCount, VISIBLE_CHIP_CAP);
4580
4653
  var shown = vis >= sorted.length ? sorted : sorted.slice(0, Math.max(0, vis));
4581
4654
  var hidden = sorted.slice(shown.length);
4582
4655
  shown.forEach(function(att) {
@@ -4610,11 +4683,13 @@ ${options.inlineContentPlaceholder}
4610
4683
  row.appendChild(chip);
4611
4684
  });
4612
4685
  if (hidden.length > 0) {
4686
+ var moreNames = hidden.slice(0, 50).map(function(a) {
4687
+ return a.kind === "folder" ? a.name + "/" : a.name;
4688
+ });
4689
+ if (hidden.length > moreNames.length) moreNames.push("...and " + (hidden.length - moreNames.length) + " more");
4613
4690
  var moreChip = h("div", {
4614
4691
  class: "bq-attachment bq-attachment-more",
4615
- title: hidden.map(function(a) {
4616
- return a.kind === "folder" ? a.name + "/" : a.name;
4617
- }).join("\n")
4692
+ title: moreNames.join("\n")
4618
4693
  });
4619
4694
  moreChip.appendChild(h("span", { class: "bq-attachment-name", text: "\u2026(" + hidden.length + ") more" }));
4620
4695
  if (!CS.uploadingAttachments) {
@@ -4989,6 +5064,7 @@ ${options.inlineContentPlaceholder}
4989
5064
  CS.attachments = [];
4990
5065
  CS.uploadingAttachments = false;
4991
5066
  CS.attachmentWarning = "";
5067
+ CS.attachmentCapNotice = "";
4992
5068
  CS.attachmentsRow = null;
4993
5069
  CS.attachBtnEl = null;
4994
5070
  CS.sendBtnEl = null;
@@ -5076,6 +5152,7 @@ ${options.inlineContentPlaceholder}
5076
5152
  autoGrowInput(input);
5077
5153
  });
5078
5154
  var attachDisabled = uploadsFrozenForUser();
5155
+ if (attachDisabled) input.classList.add("bq-input--noattach");
5079
5156
  var attachFileInput = null, attachBtn = null;
5080
5157
  if (!attachDisabled) {
5081
5158
  attachFileInput = h("input", { class: "bq-attach-input", type: "file", multiple: "multiple" });
@@ -5228,7 +5305,7 @@ ${options.inlineContentPlaceholder}
5228
5305
  }
5229
5306
  function agentBadgeText() {
5230
5307
  if (S.aiPlatform === "none") return "No agent configured";
5231
- return S.serviceName ? "BunnyQuery \xB7 " + S.serviceName : "BunnyQuery";
5308
+ return S.serviceName || "BunnyQuery";
5232
5309
  }
5233
5310
  function parseAiAgentValue(value) {
5234
5311
  var raw = (value || "").trim();
@@ -5282,6 +5359,15 @@ ${options.inlineContentPlaceholder}
5282
5359
  }
5283
5360
  function boot() {
5284
5361
  showLoading();
5362
+ return loadServiceInfo().then(function(conn) {
5363
+ if (conn) {
5364
+ S.service = conn;
5365
+ applyAgentConfig();
5366
+ }
5367
+ }).catch(function() {
5368
+ }).then(bootFlow);
5369
+ }
5370
+ function bootFlow() {
5285
5371
  if (isInboundPlatformOAuth()) {
5286
5372
  stashInboundPlatformOAuth();
5287
5373
  return getProfile().then(function(user) {
package/dist/engine.cjs CHANGED
@@ -1828,22 +1828,22 @@ var ChatSession = class {
1828
1828
  var id = this.host.getIdentity();
1829
1829
  var svcId = id.serviceId, plat = id.platform;
1830
1830
  if (!svcId || plat === "none" || !this.host.isViewMounted()) return;
1831
+ var presentIds = {};
1832
+ var pendingIds = {};
1833
+ this.state.messages.forEach(function(m) {
1834
+ var sid = m._serverItemId;
1835
+ if (sid == null) return;
1836
+ presentIds[sid] = true;
1837
+ if (m.isPending || m.isPendingInProcess || m.isPendingQueued) pendingIds[sid] = true;
1838
+ });
1831
1839
  for (var i = this.bgTaskQueue.length - 1; i >= 0; i--) {
1832
1840
  var e = this.bgTaskQueue[i];
1833
1841
  if (e.serviceId !== svcId || e.platform !== plat) continue;
1834
- var present = this.state.messages.some(function(m) {
1835
- return m._serverItemId === e.id;
1836
- });
1837
- var stillPending = this.state.messages.some(function(m) {
1838
- return m._serverItemId === e.id && (m.isPending || m.isPendingInProcess || m.isPendingQueued);
1839
- });
1840
- if (present && !stillPending) this.bgTaskQueue.splice(i, 1);
1842
+ if (presentIds[e.id] && !pendingIds[e.id]) this.bgTaskQueue.splice(i, 1);
1841
1843
  }
1842
1844
  this.bgTaskQueue.forEach(function(entry) {
1843
1845
  if (entry.serviceId !== svcId || entry.platform !== plat) return;
1844
- if (self.state.messages.some(function(m) {
1845
- return m._serverItemId === entry.id;
1846
- })) return;
1846
+ if (presentIds[entry.id]) return;
1847
1847
  var isRunning = entry.status === "running";
1848
1848
  var userBubble = { role: "user", content: self.host.formatIndexingLabel(entry.filename, entry.mime, entry.size, entry.storagePath, entry.isReindex), isBackgroundTask: true, _serverItemId: entry.id };
1849
1849
  if (isRunning) userBubble.isPendingInProcess = true;
@@ -1852,6 +1852,7 @@ var ChatSession = class {
1852
1852
  if (isRunning) {
1853
1853
  self.state.messages.push({ role: "assistant", content: "", isPending: true, isPendingInProcess: true, isBackgroundTask: true, _serverItemId: entry.id });
1854
1854
  }
1855
+ presentIds[entry.id] = true;
1855
1856
  self.host.notify();
1856
1857
  self.updateHistoryCache();
1857
1858
  self.host.scrollToBottom(false);