shadok-ai 0.1.0
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 +196 -0
- package/dist/args.d.ts +8 -0
- package/dist/args.js +17 -0
- package/dist/args.js.map +1 -0
- package/dist/channels.d.ts +61 -0
- package/dist/channels.js +169 -0
- package/dist/channels.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +100 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.js +59 -0
- package/dist/config.js.map +1 -0
- package/dist/detect.d.ts +17 -0
- package/dist/detect.js +41 -0
- package/dist/detect.js.map +1 -0
- package/dist/extract.d.ts +55 -0
- package/dist/extract.js +269 -0
- package/dist/extract.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +90 -0
- package/dist/main.js.map +1 -0
- package/dist/pace.d.ts +33 -0
- package/dist/pace.js +53 -0
- package/dist/pace.js.map +1 -0
- package/dist/retry.d.ts +15 -0
- package/dist/retry.js +40 -0
- package/dist/retry.js.map +1 -0
- package/dist/secrets.d.ts +21 -0
- package/dist/secrets.js +71 -0
- package/dist/secrets.js.map +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +854 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +74 -0
- package/dist/session.js +244 -0
- package/dist/session.js.map +1 -0
- package/dist/setup-prompt.d.ts +6 -0
- package/dist/setup-prompt.js +25 -0
- package/dist/setup-prompt.js.map +1 -0
- package/dist/supervisor.d.ts +55 -0
- package/dist/supervisor.js +61 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/tail.d.ts +66 -0
- package/dist/tail.js +244 -0
- package/dist/tail.js.map +1 -0
- package/dist/telegram.d.ts +48 -0
- package/dist/telegram.js +565 -0
- package/dist/telegram.js.map +1 -0
- package/dist/tmux.d.ts +69 -0
- package/dist/tmux.js +267 -0
- package/dist/tmux.js.map +1 -0
- package/dist/update-flag.d.ts +13 -0
- package/dist/update-flag.js +36 -0
- package/dist/update-flag.js.map +1 -0
- package/dist/updater.d.ts +18 -0
- package/dist/updater.js +45 -0
- package/dist/updater.js.map +1 -0
- package/dist/usage.d.ts +23 -0
- package/dist/usage.js +125 -0
- package/dist/usage.js.map +1 -0
- package/dist/worktree.d.ts +63 -0
- package/dist/worktree.js +153 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +44 -0
- package/public/index.html +2583 -0
package/dist/tail.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
/** Max characters of a tool result to stream (long outputs are truncated). */
|
|
5
|
+
const MAX_RESULT = 4000;
|
|
6
|
+
/**
|
|
7
|
+
* Path of the .jsonl transcript Claude Code writes for a session.
|
|
8
|
+
*
|
|
9
|
+
* The obvious path is `<encoded cwd>/<id>.jsonl`, but Claude derives the
|
|
10
|
+
* encoded dir from the cwd it was LAUNCHED with. After a repo/worktree move
|
|
11
|
+
* (or the shadok-ai rename) a still-running agent keeps writing under its
|
|
12
|
+
* original encoded dir, which no longer matches the current cwd — so the tail
|
|
13
|
+
* would watch a stale file and nothing streams. To be immune to that drift we
|
|
14
|
+
* prefer the newest `<id>.jsonl` found anywhere under ~/.claude/projects; the
|
|
15
|
+
* file being actively appended is always the newest. Falls back to the
|
|
16
|
+
* cwd-derived path for a brand-new session whose file doesn't exist yet.
|
|
17
|
+
*/
|
|
18
|
+
export function sessionFilePath(cwd, sessionId) {
|
|
19
|
+
const newest = newestTranscriptById(sessionId);
|
|
20
|
+
if (newest)
|
|
21
|
+
return newest;
|
|
22
|
+
const encoded = path.resolve(cwd).replace(/[^a-zA-Z0-9]/g, "-");
|
|
23
|
+
return path.join(os.homedir(), ".claude", "projects", encoded, sessionId + ".jsonl");
|
|
24
|
+
}
|
|
25
|
+
/** The most-recently-modified `<id>.jsonl` across all project dirs, or null. */
|
|
26
|
+
export function newestTranscriptById(sessionId) {
|
|
27
|
+
const root = path.join(os.homedir(), ".claude", "projects");
|
|
28
|
+
let best = null;
|
|
29
|
+
let bestMtime = -1;
|
|
30
|
+
let dirs;
|
|
31
|
+
try {
|
|
32
|
+
dirs = fs.readdirSync(root);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
for (const d of dirs) {
|
|
38
|
+
const f = path.join(root, d, sessionId + ".jsonl");
|
|
39
|
+
try {
|
|
40
|
+
const m = fs.statSync(f).mtimeMs;
|
|
41
|
+
if (m > bestMtime) {
|
|
42
|
+
bestMtime = m;
|
|
43
|
+
best = f;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
/* no such file in this dir */
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return best;
|
|
51
|
+
}
|
|
52
|
+
/** One-line summary of a tool_use block (e.g. `Read auth.ts`, `Bash: npm test`). */
|
|
53
|
+
function toolSummary(input) {
|
|
54
|
+
if (!input || typeof input !== "object")
|
|
55
|
+
return "";
|
|
56
|
+
const v = input.file_path ?? input.path ?? input.command ?? input.pattern ?? input.query ?? input.url ?? input.description;
|
|
57
|
+
if (typeof v !== "string")
|
|
58
|
+
return "";
|
|
59
|
+
const s = v.replace(/\s+/g, " ").trim();
|
|
60
|
+
return s.length > 80 ? s.slice(0, 79) + "…" : s;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Tails a session .jsonl: watches for appended lines and yields the assistant
|
|
64
|
+
* `text` and `tool_use` blocks as they are written — the authoritative,
|
|
65
|
+
* untruncated content, streamed at message granularity.
|
|
66
|
+
*
|
|
67
|
+
* `onEvent` fires for each new block. Returns a stop() function.
|
|
68
|
+
* Starts from the current end of file, so only NEW turns are streamed
|
|
69
|
+
* (existing history is replayed separately via loadHistory).
|
|
70
|
+
*/
|
|
71
|
+
export function tailSession(file, onEvent, intervalMs = 250) {
|
|
72
|
+
let pos = 0;
|
|
73
|
+
try {
|
|
74
|
+
pos = fs.statSync(file).size; // start at EOF: only stream what comes next
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
pos = 0; // file not written yet (new session) — stream from the start
|
|
78
|
+
}
|
|
79
|
+
let buf = "";
|
|
80
|
+
let stopped = false;
|
|
81
|
+
const read = () => {
|
|
82
|
+
if (stopped)
|
|
83
|
+
return;
|
|
84
|
+
let size;
|
|
85
|
+
try {
|
|
86
|
+
size = fs.statSync(file).size;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return; // file not there yet
|
|
90
|
+
}
|
|
91
|
+
if (size < pos) {
|
|
92
|
+
// File shrank/rotated (rare) — reset.
|
|
93
|
+
pos = 0;
|
|
94
|
+
buf = "";
|
|
95
|
+
}
|
|
96
|
+
if (size === pos)
|
|
97
|
+
return;
|
|
98
|
+
let chunk = "";
|
|
99
|
+
try {
|
|
100
|
+
const fd = fs.openSync(file, "r");
|
|
101
|
+
try {
|
|
102
|
+
const b = Buffer.alloc(size - pos);
|
|
103
|
+
const n = fs.readSync(fd, b, 0, b.length, pos);
|
|
104
|
+
chunk = b.toString("utf8", 0, n);
|
|
105
|
+
pos += n;
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
fs.closeSync(fd);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
buf += chunk;
|
|
115
|
+
let nl;
|
|
116
|
+
while ((nl = buf.indexOf("\n")) >= 0) {
|
|
117
|
+
const line = buf.slice(0, nl);
|
|
118
|
+
buf = buf.slice(nl + 1);
|
|
119
|
+
emitLine(line, onEvent);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const timer = setInterval(read, intervalMs);
|
|
123
|
+
return () => {
|
|
124
|
+
stopped = true;
|
|
125
|
+
clearInterval(timer);
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function emitLine(line, onEvent) {
|
|
129
|
+
for (const ev of parseLine(line))
|
|
130
|
+
onEvent(ev);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Pure parser for one transcript line → the events it yields. Exported for
|
|
134
|
+
* tests; `tailSession` streams these live. Returns [] for anything that isn't
|
|
135
|
+
* a streamable assistant/user event.
|
|
136
|
+
*/
|
|
137
|
+
export function parseLine(line) {
|
|
138
|
+
if (!line.trim())
|
|
139
|
+
return [];
|
|
140
|
+
let e;
|
|
141
|
+
try {
|
|
142
|
+
e = JSON.parse(line);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
if (e.isMeta || !Array.isArray(e.message?.content))
|
|
148
|
+
return [];
|
|
149
|
+
const out = [];
|
|
150
|
+
if (e.type === "assistant") {
|
|
151
|
+
const usage = parseUsage(e.message);
|
|
152
|
+
if (usage)
|
|
153
|
+
out.push({ kind: "usage", messageId: e.message.id ?? e.uuid, usage });
|
|
154
|
+
for (const block of e.message.content) {
|
|
155
|
+
if (block?.type === "text" && typeof block.text === "string" && block.text.trim()) {
|
|
156
|
+
out.push({ kind: "text", text: block.text });
|
|
157
|
+
}
|
|
158
|
+
else if (block?.type === "tool_use" && typeof block.name === "string") {
|
|
159
|
+
out.push({
|
|
160
|
+
kind: "tool",
|
|
161
|
+
id: typeof block.id === "string" ? block.id : "",
|
|
162
|
+
name: block.name,
|
|
163
|
+
summary: toolSummary(block.input),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// `thinking` blocks are intentionally skipped.
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (e.type === "user") {
|
|
170
|
+
// User events carry tool results (command output, file reads…). The real
|
|
171
|
+
// user prompt is echoed by the server itself, so only results are emitted.
|
|
172
|
+
for (const block of e.message.content) {
|
|
173
|
+
if (block?.type !== "tool_result")
|
|
174
|
+
continue;
|
|
175
|
+
const text = resultText(block.content);
|
|
176
|
+
if (text) {
|
|
177
|
+
out.push({
|
|
178
|
+
kind: "result",
|
|
179
|
+
toolUseId: typeof block.tool_use_id === "string" ? block.tool_use_id : "",
|
|
180
|
+
text,
|
|
181
|
+
isError: !!block.is_error,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return out;
|
|
187
|
+
}
|
|
188
|
+
export function parseUsage(message) {
|
|
189
|
+
const u = message?.usage;
|
|
190
|
+
if (!u || typeof u !== "object")
|
|
191
|
+
return null;
|
|
192
|
+
return {
|
|
193
|
+
input: u.input_tokens ?? 0,
|
|
194
|
+
output: u.output_tokens ?? 0,
|
|
195
|
+
cacheCreation: u.cache_creation_input_tokens ?? 0,
|
|
196
|
+
cacheRead: u.cache_read_input_tokens ?? 0,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Sums the token usage already written to a transcript, keyed by message id.
|
|
201
|
+
* Streaming writes several records per message with the same id and growing
|
|
202
|
+
* counts — keeping the last record per id yields each message's final usage.
|
|
203
|
+
*/
|
|
204
|
+
export function scanUsage(file) {
|
|
205
|
+
const map = new Map();
|
|
206
|
+
let raw;
|
|
207
|
+
try {
|
|
208
|
+
raw = fs.readFileSync(file, "utf8");
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return map; // new session: nothing written yet
|
|
212
|
+
}
|
|
213
|
+
for (const line of raw.split("\n")) {
|
|
214
|
+
if (!line.trim())
|
|
215
|
+
continue;
|
|
216
|
+
let e;
|
|
217
|
+
try {
|
|
218
|
+
e = JSON.parse(line);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (e.type !== "assistant")
|
|
224
|
+
continue;
|
|
225
|
+
const usage = parseUsage(e.message);
|
|
226
|
+
if (usage)
|
|
227
|
+
map.set(e.message.id ?? e.uuid, usage);
|
|
228
|
+
}
|
|
229
|
+
return map;
|
|
230
|
+
}
|
|
231
|
+
/** Flattens a tool_result's content (string or block array) to display text. */
|
|
232
|
+
export function resultText(content) {
|
|
233
|
+
let s = "";
|
|
234
|
+
if (typeof content === "string")
|
|
235
|
+
s = content;
|
|
236
|
+
else if (Array.isArray(content))
|
|
237
|
+
s = content
|
|
238
|
+
.filter((b) => b?.type === "text" && typeof b.text === "string")
|
|
239
|
+
.map((b) => b.text)
|
|
240
|
+
.join("\n");
|
|
241
|
+
s = s.trimEnd();
|
|
242
|
+
return s.length > MAX_RESULT ? s.slice(0, MAX_RESULT) + "\n… (truncated)" : s;
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=tail.js.map
|
package/dist/tail.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tail.js","sourceRoot":"","sources":["../src/tail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** The binding key for a chat + optional forum topic thread. */
|
|
2
|
+
export declare function bindKey(chat: {
|
|
3
|
+
id: number;
|
|
4
|
+
type: string;
|
|
5
|
+
}, threadId?: number): string;
|
|
6
|
+
/** Split text into Telegram-sized chunks, preferring line boundaries. */
|
|
7
|
+
export declare function chunk(text: string, max?: number): string[];
|
|
8
|
+
/** Parse a leading bot command: "/spawn foo" → {cmd:"spawn", arg:"foo"}. */
|
|
9
|
+
export declare function parseCommand(text: string): {
|
|
10
|
+
cmd: string;
|
|
11
|
+
arg: string;
|
|
12
|
+
} | null;
|
|
13
|
+
/** Telegram's "typing…" indicator lives ~5 s per sendChatAction and dies on
|
|
14
|
+
* every sendMessage — a single beat can't cover a turn that runs for minutes.
|
|
15
|
+
* This keeps it alive: an immediate beat, then one every `intervalMs` until
|
|
16
|
+
* stop(). start() while beating is a no-op; stop() is idempotent. */
|
|
17
|
+
export declare function makeTyping(beat: () => void, intervalMs?: number): {
|
|
18
|
+
start: () => void;
|
|
19
|
+
stop: () => void;
|
|
20
|
+
};
|
|
21
|
+
interface DialogOption {
|
|
22
|
+
n: number;
|
|
23
|
+
label: string;
|
|
24
|
+
hint?: string;
|
|
25
|
+
checked?: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface Dialog {
|
|
28
|
+
question: string;
|
|
29
|
+
options: DialogOption[];
|
|
30
|
+
multi: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** Inline keyboard for a TUI dialog. Single-select → one button per option
|
|
33
|
+
* (choose); multi-select → toggle buttons (with ☑/☐) + a Submit row. */
|
|
34
|
+
export declare function dialogKeyboard(d: Dialog): {
|
|
35
|
+
inline_keyboard: {
|
|
36
|
+
text: string;
|
|
37
|
+
callback_data: string;
|
|
38
|
+
}[][];
|
|
39
|
+
};
|
|
40
|
+
/** Parse a dialog callback_data → an action for the WS. */
|
|
41
|
+
export declare function parseCallback(data: string): {
|
|
42
|
+
kind: "choose" | "toggle" | "confirm";
|
|
43
|
+
n?: number;
|
|
44
|
+
} | null;
|
|
45
|
+
export declare function renameTelegramTopic(chatId: number, threadId: number, name: string): void;
|
|
46
|
+
export declare function closeTelegramTopic(chatId: number, threadId: number): void;
|
|
47
|
+
export declare function startTelegram(port: number): void;
|
|
48
|
+
export {};
|