shadok-ai 0.15.49 → 0.15.50

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 CHANGED
@@ -204,8 +204,8 @@ Enter to skip; you can add it later from the web UI).
204
204
  browser, since shell mode sits outside the agent's guardrails. The command and
205
205
  its output stay in the chat, reload included — as does one you typed yourself
206
206
  in the terminal view.
207
- - **Files you hand an agent** — paste or drop a file into the composer (an
208
- image, a PDF, a CSV…) and it becomes a **chip** above the text box: a
207
+ - **Files you hand an agent** — paste or drop a file into the composer, or pick
208
+ one with the 📎 button beside it (an image, a PDF, a CSV…), and it becomes a **chip** above the text box: a
209
209
  thumbnail for an image, a named tag for anything else, each with a ✕ to
210
210
  remove it. On send, an image shows **inline in your own message bubble**;
211
211
  under the hood the agent still receives it as an `[Attached …: path]` line,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadok-ai",
3
- "version": "0.15.49",
3
+ "version": "0.15.50",
4
4
  "main": "dist/session.js",
5
5
  "scripts": {
6
6
  "test": "node --import tsx --test --test-timeout=120000 test/*.ts context/*/test/*.test.mjs",
package/public/index.html CHANGED
@@ -1535,6 +1535,25 @@
1535
1535
  line-height: 1.45;
1536
1536
  }
1537
1537
  #composer textarea:focus-visible { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px var(--amber-soft); }
1538
+ /* The paperclip: a square as tall as the one-line textarea, aligned to its
1539
+ bottom so it stays beside the last line while the field grows. */
1540
+ .cmp-attach {
1541
+ flex: none;
1542
+ align-self: flex-end;
1543
+ width: 42px;
1544
+ height: 42px;
1545
+ padding: 0;
1546
+ display: inline-flex;
1547
+ align-items: center;
1548
+ justify-content: center;
1549
+ background: transparent;
1550
+ color: var(--text-dim);
1551
+ border: 1px solid var(--line);
1552
+ border-radius: var(--radius);
1553
+ cursor: pointer;
1554
+ }
1555
+ .cmp-attach:hover:not(:disabled) { color: var(--amber); border-color: var(--amber); }
1556
+ .cmp-attach:disabled { opacity: 0.4; cursor: default; }
1538
1557
 
1539
1558
  /* ── Engine room (live terminal) ─────────────────────── */
1540
1559
  #machine {
@@ -2946,6 +2965,11 @@
2946
2965
  <form id="composer" hidden>
2947
2966
  <!-- Thumbnails of the files dropped / pasted into this agent's composer. -->
2948
2967
  <div id="composerAtts" class="cmp-atts" hidden></div>
2968
+ <!-- Pick a file to send: the same path as a paste or a drop (attachFile). -->
2969
+ <button type="button" id="attachBtn" class="cmp-attach" title="Attach a file" aria-label="Attach a file">
2970
+ <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path d="M21 11.5l-8.6 8.6a5.5 5.5 0 0 1-7.8-7.8l8.6-8.6a3.7 3.7 0 0 1 5.2 5.2l-8.6 8.6a1.8 1.8 0 0 1-2.6-2.6l7.9-7.9" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>
2971
+ </button>
2972
+ <input type="file" id="attachInput" multiple hidden>
2949
2973
  <textarea id="promptInput" rows="1"
2950
2974
  placeholder="Write your prompt — Enter to send, Shift+Enter for a new line"></textarea>
2951
2975
  <button type="submit" class="primary" id="sendBtn">Send</button>
@@ -8216,6 +8240,17 @@
8216
8240
  for (const item of items) await attachFile(item.getAsFile());
8217
8241
  });
8218
8242
 
8243
+ // The paperclip opens the OS file picker; what is picked goes through
8244
+ // attachFile exactly like a paste or a drop.
8245
+ const attachInput = $("attachInput");
8246
+ $("attachBtn").addEventListener("click", () => { if (active) attachInput.click(); });
8247
+ attachInput.addEventListener("change", async () => {
8248
+ const files = [...(attachInput.files || [])];
8249
+ attachInput.value = ""; // picking the same file again must fire `change` again
8250
+ for (const f of files) await attachFile(f);
8251
+ promptInput.focus();
8252
+ });
8253
+
8219
8254
  // Drag-and-drop files anywhere on the chat pane → attach them, same path as
8220
8255
  // paste. Only reacts to an OS file drag (`types` includes "Files"), so the
8221
8256
  // internal tab/group reordering DnD is untouched. A depth counter keeps the