shadok-ai 0.14.3 → 0.14.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/README.md +12 -1
- package/dist/detect.d.ts +19 -4
- package/dist/detect.js +24 -5
- package/dist/detect.js.map +1 -1
- package/dist/server.js +31 -0
- package/dist/server.js.map +1 -1
- package/dist/session.js +1 -0
- package/dist/session.js.map +1 -1
- package/dist/tmux.d.ts +6 -0
- package/dist/tmux.js +14 -0
- package/dist/tmux.js.map +1 -1
- package/package.json +1 -1
- package/public/index.html +192 -22
package/README.md
CHANGED
|
@@ -156,6 +156,15 @@ Enter to skip; you can add it later from the web UI).
|
|
|
156
156
|
refused for anything but your browser, since shell mode sits outside the
|
|
157
157
|
agent's guardrails. The command and its output stay in the chat, reload
|
|
158
158
|
included — as does one you typed yourself in the terminal view.
|
|
159
|
+
- **Files you hand an agent** — paste or drop a file into the composer (an
|
|
160
|
+
image, a PDF, a CSV…) and it becomes a **chip** above the text box: a
|
|
161
|
+
thumbnail for an image, a named tag for anything else, each with a ✕ to
|
|
162
|
+
remove it. On send, an image shows **inline in your own message bubble**;
|
|
163
|
+
under the hood the agent still receives it as an `[Attached …: path]` line,
|
|
164
|
+
the same format Telegram uses, so nothing about how the agent reads it
|
|
165
|
+
changes. A message can be attachments alone, with no words. The files are
|
|
166
|
+
served back to the browser by `GET /media/<name>` from the same directory
|
|
167
|
+
Telegram attachments land in.
|
|
159
168
|
- **Files an agent hands you** — when an agent's result IS a file (a report, an
|
|
160
169
|
export, a screenshot, an archive) it arrives as a download card in the chat,
|
|
161
170
|
inline if it is an image, and as an upload in the Telegram topic. It goes
|
|
@@ -690,7 +699,9 @@ endpoint — the accent is the instance's shared identity, the mode is personal)
|
|
|
690
699
|
`{pending, reason}`: whether this instance's lead agent is being started
|
|
691
700
|
right now), `/version`, `/autoupdate`,
|
|
692
701
|
`/update-channel` (POST `{channel}` — `alpha` or `beta`), `/permission-mode`, `/tweak/prepare` (POST — clone/refresh shadok-ai's own source,
|
|
693
|
-
returns the cwd to start the tweak agent in),
|
|
702
|
+
returns the cwd to start the tweak agent in), `/media/<name>` (GET — serves a
|
|
703
|
+
pasted/dropped or Telegram attachment back for inline display; sandboxed, basename
|
|
704
|
+
only), and the sign-in group: `/auth` (GET
|
|
694
705
|
— `{loggedIn, email?, subscriptionType?}`), `/auth/login` (POST — start a flow,
|
|
695
706
|
returns `{url}`; DELETE — cancel it), `/auth/code` (POST `{code}`).
|
|
696
707
|
|
package/dist/detect.d.ts
CHANGED
|
@@ -113,11 +113,13 @@ export interface DialogPilot {
|
|
|
113
113
|
* it entirely. `waitFor` polls until the move lands, which is correct on both.
|
|
114
114
|
*/
|
|
115
115
|
export declare function moveToOption(pilot: DialogPilot, n: number): Promise<boolean>;
|
|
116
|
-
/** The slice of a pilot `typeIntoBox` needs: put text in the
|
|
117
|
-
* and wait until the screen satisfies a predicate. Both
|
|
118
|
-
* match it; a fake one lets the doubled-prompt
|
|
119
|
-
* real TUI. */
|
|
116
|
+
/** The slice of a pilot `typeIntoBox` needs: read the screen, put text in the
|
|
117
|
+
* box, clear the box, and wait until the screen satisfies a predicate. Both
|
|
118
|
+
* PtyPilot and TmuxPilot match it; a fake one lets the doubled-prompt
|
|
119
|
+
* regression be tested without a real TUI. */
|
|
120
120
|
export interface TypingPilot {
|
|
121
|
+
/** The screen as it is NOW — read before each paste, as the baseline. */
|
|
122
|
+
screen(): string;
|
|
121
123
|
/** Bracketed-paste the text into the input box — never submits it. */
|
|
122
124
|
paste(text: string): void;
|
|
123
125
|
/** Ctrl-U: clear whatever is in the input box. */
|
|
@@ -154,6 +156,19 @@ export interface TypeOptions {
|
|
|
154
156
|
* before pasting again. A box that will not clear is left to the next attempt
|
|
155
157
|
* rather than pasted into blindly.
|
|
156
158
|
*
|
|
159
|
+
* "Landed" means the box DIFFERS from what it showed just before the paste, not
|
|
160
|
+
* that it is non-empty: an empty box is not always blank. Before the first
|
|
161
|
+
* prompt of a session, Claude Code (seen on 2.1.285) fills it with an example —
|
|
162
|
+
* `❯ Try "refactor <filepath>"` — which `inputText` reads like typed text, so
|
|
163
|
+
* "non-empty" was true before anything was pasted, and a paste the TUI dropped
|
|
164
|
+
* was followed by Enter on a box holding nothing. The example also comes back
|
|
165
|
+
* after a Ctrl-U, so "cleared" likewise means "back to that resting state".
|
|
166
|
+
* Comparing with the state read just before is still content-agnostic (a
|
|
167
|
+
* collapsed "[Pasted text +N lines]" differs from it as well as the text would)
|
|
168
|
+
* and needs no list of hint strings, which would rot with the next release. The
|
|
169
|
+
* baseline is re-read on every attempt, after the recovery has run, so a retry
|
|
170
|
+
* that pastes the same text again is compared with the box it pastes into.
|
|
171
|
+
*
|
|
157
172
|
* It lives here, next to `idleStep` and `moveToOption`, for the reason those do:
|
|
158
173
|
* it was written twice (node-pty and tmux), and could only be exercised by
|
|
159
174
|
* spawning a real process.
|
package/dist/detect.js
CHANGED
|
@@ -229,25 +229,44 @@ export async function moveToOption(pilot, n) {
|
|
|
229
229
|
* before pasting again. A box that will not clear is left to the next attempt
|
|
230
230
|
* rather than pasted into blindly.
|
|
231
231
|
*
|
|
232
|
+
* "Landed" means the box DIFFERS from what it showed just before the paste, not
|
|
233
|
+
* that it is non-empty: an empty box is not always blank. Before the first
|
|
234
|
+
* prompt of a session, Claude Code (seen on 2.1.285) fills it with an example —
|
|
235
|
+
* `❯ Try "refactor <filepath>"` — which `inputText` reads like typed text, so
|
|
236
|
+
* "non-empty" was true before anything was pasted, and a paste the TUI dropped
|
|
237
|
+
* was followed by Enter on a box holding nothing. The example also comes back
|
|
238
|
+
* after a Ctrl-U, so "cleared" likewise means "back to that resting state".
|
|
239
|
+
* Comparing with the state read just before is still content-agnostic (a
|
|
240
|
+
* collapsed "[Pasted text +N lines]" differs from it as well as the text would)
|
|
241
|
+
* and needs no list of hint strings, which would rot with the next release. The
|
|
242
|
+
* baseline is re-read on every attempt, after the recovery has run, so a retry
|
|
243
|
+
* that pastes the same text again is compared with the box it pastes into.
|
|
244
|
+
*
|
|
232
245
|
* It lives here, next to `idleStep` and `moveToOption`, for the reason those do:
|
|
233
246
|
* it was written twice (node-pty and tmux), and could only be exercised by
|
|
234
247
|
* spawning a real process.
|
|
235
248
|
*/
|
|
236
249
|
export async function typeIntoBox(pilot, text, { attempts = 6, appearMs = 2_000, settleMs = 400, clearMs = 1_000 } = {}) {
|
|
237
250
|
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
251
|
+
// Only "" and the resting state count as an empty box; anything else the
|
|
252
|
+
// box shows once we paste is our paste (whole, or collapsed).
|
|
253
|
+
const before = inputText(pilot.screen());
|
|
238
254
|
pilot.paste(text);
|
|
239
255
|
try {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
256
|
+
await pilot.waitFor((s) => {
|
|
257
|
+
const now = inputText(s);
|
|
258
|
+
return now !== "" && now !== before;
|
|
259
|
+
}, { timeoutMs: appearMs });
|
|
244
260
|
return true;
|
|
245
261
|
}
|
|
246
262
|
catch {
|
|
247
263
|
await delay(settleMs); // let a paste that is still in flight land
|
|
248
264
|
pilot.clearInput();
|
|
249
265
|
try {
|
|
250
|
-
await pilot.waitFor((s) =>
|
|
266
|
+
await pilot.waitFor((s) => {
|
|
267
|
+
const now = inputText(s);
|
|
268
|
+
return now === "" || now === before;
|
|
269
|
+
}, { timeoutMs: clearMs });
|
|
251
270
|
}
|
|
252
271
|
catch {
|
|
253
272
|
pilot.clearInput(); // stubborn — clear once more, then try again
|
package/dist/detect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -2033,6 +2033,37 @@ app.get("/download", (req, res) => {
|
|
|
2033
2033
|
fs.createReadStream(wanted).on("error", () => { if (!res.headersSent)
|
|
2034
2034
|
res.status(500); res.end(); }).pipe(res);
|
|
2035
2035
|
});
|
|
2036
|
+
// Serve a file the USER dropped / pasted (or a Telegram attachment) — they all
|
|
2037
|
+
// land in MEDIA_DIR, referenced in the chat as `[Attached image: <path>]`. The
|
|
2038
|
+
// web renders that inline instead of the raw path (both surfaces then SHOW the
|
|
2039
|
+
// image). Scoped to MEDIA_DIR by BASENAME, so it can never be walked into another
|
|
2040
|
+
// file: `path.basename` strips any directory, and the resolved path is checked to
|
|
2041
|
+
// stay inside MEDIA_DIR. Behind the same password gate as everything else; the
|
|
2042
|
+
// same `nosniff` + `sandbox` CSP as /download neutralises an SVG opened directly.
|
|
2043
|
+
app.get("/media/:name", (req, res) => {
|
|
2044
|
+
const base = path.basename(String(req.params.name ?? ""));
|
|
2045
|
+
const file = path.join(MEDIA_DIR, base);
|
|
2046
|
+
if (!file.startsWith(path.join(MEDIA_DIR, path.sep)) && path.dirname(file) !== MEDIA_DIR) {
|
|
2047
|
+
return res.status(400).type("text").send("bad name");
|
|
2048
|
+
}
|
|
2049
|
+
let stat;
|
|
2050
|
+
try {
|
|
2051
|
+
stat = fs.statSync(file);
|
|
2052
|
+
if (!stat.isFile())
|
|
2053
|
+
throw new Error("not a file");
|
|
2054
|
+
}
|
|
2055
|
+
catch {
|
|
2056
|
+
return res.status(404).type("text").send("no such media");
|
|
2057
|
+
}
|
|
2058
|
+
res.setHeader("Content-Type", contentTypeFor(base));
|
|
2059
|
+
res.setHeader("Content-Length", String(stat.size));
|
|
2060
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
2061
|
+
res.setHeader("Content-Security-Policy", "sandbox; default-src 'none'");
|
|
2062
|
+
const inline = isImageFile(base) && contentTypeFor(base) !== "image/svg+xml";
|
|
2063
|
+
res.setHeader("Content-Disposition", `${inline ? "inline" : "attachment"}; filename="${base.replace(/["\\]/g, "_")}"`);
|
|
2064
|
+
fs.createReadStream(file).on("error", () => { if (!res.headersSent)
|
|
2065
|
+
res.status(500); res.end(); }).pipe(res);
|
|
2066
|
+
});
|
|
2036
2067
|
// Install (or repair) the global Claude Code CLI on demand — `npm i -g
|
|
2037
2068
|
// @anthropic-ai/claude-code`. The cockpit shows this button when an agent's TUI
|
|
2038
2069
|
// footer reports "Auto-update failed"; running agents still need a reload
|