shadok-ai 0.7.7 → 0.7.8

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/package.json +1 -1
  2. package/public/index.html +15 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadok-ai",
3
- "version": "0.7.7",
3
+ "version": "0.7.8",
4
4
  "main": "dist/session.js",
5
5
  "scripts": {
6
6
  "test": "node --import tsx --test test/*.ts .claude/skills/shadok-ai-agents/test/*.test.mjs context/*/test/*.test.mjs",
package/public/index.html CHANGED
@@ -1948,6 +1948,14 @@
1948
1948
  const ungroupedEl = $("ungrouped"), groupsEl = $("groups");
1949
1949
  const transcripts = $("transcripts"), thinking = $("thinking");
1950
1950
  const composer = $("composer"), promptInput = $("promptInput"), sendBtn = $("sendBtn");
1951
+ // Attachments upload asynchronously and leave a "⏳ …" placeholder in the box
1952
+ // until the server returns the real reference. Sending while that's in flight
1953
+ // would ship the placeholder instead of the file — so Send is inert until
1954
+ // every upload settles. `updateSendDisabled` re-derives the button state.
1955
+ let pendingUploads = 0;
1956
+ function updateSendDisabled() {
1957
+ sendBtn.disabled = !active || active.status !== "ready" || !!active.pendingChoices || pendingUploads > 0;
1958
+ }
1951
1959
  const machine = $("machine"), screenEl = $("screen");
1952
1960
 
1953
1961
  // ── Channels ────────────────────────────────────────────
@@ -3270,7 +3278,7 @@
3270
3278
  $("chanBar").hidden = false;
3271
3279
  $("chanBarName").textContent = t.nameEl ? t.nameEl.textContent : "";
3272
3280
  $("chanBarName").title = t.cwd || "";
3273
- sendBtn.disabled = t.status !== "ready" || !!t.pendingChoices;
3281
+ updateSendDisabled(); // t === active here; also honours a pending upload
3274
3282
  thinking.classList.toggle("visible", t.status === "busy");
3275
3283
  // Showing/hiding "Shadok is working…" changes the transcript area's height:
3276
3284
  // without re-pinning to the bottom, the last message slips below the fold
@@ -4745,7 +4753,7 @@
4745
4753
  e.preventDefault();
4746
4754
  const t = active;
4747
4755
  const text = promptInput.value.trim();
4748
- if (!text || t.status !== "ready" || t.pendingChoices || !t.ws) return;
4756
+ if (!text || t.status !== "ready" || t.pendingChoices || pendingUploads > 0 || !t.ws) return;
4749
4757
  // Checked here so nothing is optimistically rendered before the server
4750
4758
  // refuses. The server re-checks anyway — it is the authority.
4751
4759
  if (paceBlocked) return renderPaceConfirm(t, text, paceReason);
@@ -4777,6 +4785,8 @@
4777
4785
  // (two screenshots are both "image.png") must not share a placeholder.
4778
4786
  const mark = "⏳ " + label + "…" + "​".repeat(++pasteSeq);
4779
4787
  insertAtCursor(promptInput, mark + "\n");
4788
+ pendingUploads++; // Send stays inert until this settles (success OR error)
4789
+ updateSendDisabled();
4780
4790
  try {
4781
4791
  const r = await fetch("/paste", {
4782
4792
  method: "POST",
@@ -4793,6 +4803,9 @@
4793
4803
  // Say it in the composer: a marker left with no explanation would look
4794
4804
  // like an upload in progress that will never arrive.
4795
4805
  promptInput.value = promptInput.value.replace(mark, `⚠️ ${label} not sent (${err.message})`);
4806
+ } finally {
4807
+ pendingUploads--;
4808
+ updateSendDisabled();
4796
4809
  }
4797
4810
  promptInput.dispatchEvent(new Event("input")); // height + draft
4798
4811
  }