shadok-ai 0.2.51 → 0.2.53
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/dist/claude-auth.d.ts +17 -1
- package/dist/claude-auth.js +23 -8
- package/dist/claude-auth.js.map +1 -1
- package/dist/server.js +45 -4
- package/dist/server.js.map +1 -1
- package/dist/telegram.d.ts +22 -0
- package/dist/telegram.js +51 -7
- package/dist/telegram.js.map +1 -1
- package/package.json +1 -1
- package/public/echo-author.js +23 -0
- package/public/index.html +147 -5
package/dist/claude-auth.d.ts
CHANGED
|
@@ -10,13 +10,27 @@
|
|
|
10
10
|
*
|
|
11
11
|
* See docs/superpowers/specs/2026-08-08-claude-onboarding-design.md.
|
|
12
12
|
*/
|
|
13
|
+
/**
|
|
14
|
+
* Three states, not two.
|
|
15
|
+
*
|
|
16
|
+
* "I observed that it is signed out" and "I could not look" are different
|
|
17
|
+
* facts, and collapsing them was a real bug: `claude auth status` takes ~850ms
|
|
18
|
+
* and can fail (timeout, truncated output, a busy machine), which produced an
|
|
19
|
+
* empty stdout, which read as *signed out* — so the cockpit popped its sign-in
|
|
20
|
+
* card and spawned a `claude auth login` child on an instance that was
|
|
21
|
+
* perfectly signed in. Only `signed-out` is ever asserted; `unknown` is
|
|
22
|
+
* reported as such and acted on conservatively but never announced to the user.
|
|
23
|
+
*/
|
|
24
|
+
export type AuthState = "signed-in" | "signed-out" | "unknown";
|
|
13
25
|
export interface AuthStatus {
|
|
26
|
+
/** True only for `signed-in`. Kept for callers that just need a boolean. */
|
|
14
27
|
loggedIn: boolean;
|
|
28
|
+
state: AuthState;
|
|
15
29
|
authMethod?: string;
|
|
16
30
|
email?: string;
|
|
17
31
|
subscriptionType?: string;
|
|
18
32
|
}
|
|
19
|
-
/** Pure: `claude auth status --json`.
|
|
33
|
+
/** Pure: `claude auth status --json`. Unreadable output is `unknown`, NOT signed out. */
|
|
20
34
|
export declare function parseAuthStatus(stdout: string): AuthStatus;
|
|
21
35
|
/** Pure: the OAuth URL the CLI printed, or null if it hasn't printed one yet. */
|
|
22
36
|
export declare function parseLoginUrl(chunk: string): string | null;
|
|
@@ -35,6 +49,8 @@ export declare function loginPending(): boolean;
|
|
|
35
49
|
export declare function cancelLogin(): void;
|
|
36
50
|
export declare function startLogin(): Promise<{
|
|
37
51
|
url: string;
|
|
52
|
+
} | {
|
|
53
|
+
alreadySignedIn: true;
|
|
38
54
|
} | {
|
|
39
55
|
error: string;
|
|
40
56
|
}>;
|
package/dist/claude-auth.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { execFile, spawn } from "node:child_process";
|
|
2
|
-
/** Pure: `claude auth status --json`.
|
|
2
|
+
/** Pure: `claude auth status --json`. Unreadable output is `unknown`, NOT signed out. */
|
|
3
3
|
export function parseAuthStatus(stdout) {
|
|
4
4
|
try {
|
|
5
5
|
const j = JSON.parse(stdout);
|
|
6
6
|
if (!j || typeof j !== "object" || Array.isArray(j))
|
|
7
|
-
return { loggedIn: false };
|
|
7
|
+
return { loggedIn: false, state: "unknown" };
|
|
8
8
|
if (j.loggedIn !== true)
|
|
9
|
-
return { loggedIn: false };
|
|
9
|
+
return { loggedIn: false, state: "signed-out" };
|
|
10
10
|
return {
|
|
11
11
|
loggedIn: true,
|
|
12
|
+
state: "signed-in",
|
|
12
13
|
...(typeof j.authMethod === "string" ? { authMethod: j.authMethod } : {}),
|
|
13
14
|
...(typeof j.email === "string" ? { email: j.email } : {}),
|
|
14
15
|
...(typeof j.subscriptionType === "string" ? { subscriptionType: j.subscriptionType } : {}),
|
|
15
16
|
};
|
|
16
17
|
}
|
|
17
18
|
catch {
|
|
18
|
-
return { loggedIn: false };
|
|
19
|
+
return { loggedIn: false, state: "unknown" };
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
@@ -57,13 +58,22 @@ let cached = null;
|
|
|
57
58
|
export function invalidateAuthStatus() {
|
|
58
59
|
cached = null;
|
|
59
60
|
}
|
|
61
|
+
const probe = () => new Promise((resolve) => {
|
|
62
|
+
execFile("claude", ["auth", "status", "--json"], { timeout: 15_000 }, (_err, stdout) => resolve(parseAuthStatus(stdout ?? "")));
|
|
63
|
+
});
|
|
60
64
|
export async function authStatus(force = false) {
|
|
61
65
|
if (!force && cached && Date.now() - cached.at < STATUS_TTL_MS)
|
|
62
66
|
return cached.status;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
let status = await probe();
|
|
68
|
+
// One retry, because the probe is a ~850ms process spawn and a busy machine
|
|
69
|
+
// makes it flake. A single retry turns the common transient failure into a
|
|
70
|
+
// definite answer instead of a wrong one.
|
|
71
|
+
if (status.state === "unknown")
|
|
72
|
+
status = await probe();
|
|
73
|
+
// NEVER cache "unknown": holding a failed probe for 30s would keep the whole
|
|
74
|
+
// instance in a doubtful state long after the cause passed.
|
|
75
|
+
if (status.state !== "unknown")
|
|
76
|
+
cached = { at: Date.now(), status };
|
|
67
77
|
return status;
|
|
68
78
|
}
|
|
69
79
|
/**
|
|
@@ -90,6 +100,11 @@ export async function startLogin() {
|
|
|
90
100
|
// second tab, would otherwise do.
|
|
91
101
|
if (flow && !flow.ended && flow.url)
|
|
92
102
|
return { url: flow.url };
|
|
103
|
+
// Never spawn a sign-in on an instance that is already signed in. This is the
|
|
104
|
+
// backstop for the whole class of "it launched for nothing": whatever led the
|
|
105
|
+
// caller here, a forced re-check has the last word.
|
|
106
|
+
if ((await authStatus(true)).state === "signed-in")
|
|
107
|
+
return { alreadySignedIn: true };
|
|
93
108
|
cancelLogin();
|
|
94
109
|
const child = spawn("claude", ["auth", "login", "--claudeai"], {
|
|
95
110
|
// BROWSER is neutralised: on a desktop host the CLI would otherwise open a
|
package/dist/claude-auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-auth.js","sourceRoot":"","sources":["../src/claude-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAuC,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-auth.js","sourceRoot":"","sources":["../src/claude-auth.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -23,7 +23,7 @@ import { scanUsage, sessionFilePath, tailSession, clearTailPos, isNothingToShow
|
|
|
23
23
|
import { computePace, paceBlock, WINDOW_SEC } from "./pace.js";
|
|
24
24
|
import { getUsage } from "./usage.js";
|
|
25
25
|
import { loadChannels, loadGroups, saveGroups, upsertChannel, removeChannel, mergeClientChannels, loadTgGroup, saveTgGroup, } from "./channels.js";
|
|
26
|
-
import { startTelegram, renameTelegramTopic, closeTelegramTopic, probeToken, isStalePreface, announceLoggedOut, resetLoggedOutNotice, } from "./telegram.js";
|
|
26
|
+
import { startTelegram, renameTelegramTopic, closeTelegramTopic, probeToken, isStalePreface, announceLoggedOut, resetLoggedOutNotice, attachmentPrompt, pasteExtension, MEDIA_DIR, } from "./telegram.js";
|
|
27
27
|
import { migrateTgBindings } from "./channels.js";
|
|
28
28
|
import { loadCrons, saveCrons, upsertCron, removeCron, resolveCronId, resolveCronTarget, nextRunFor, nextRunAfterFailure, isTransient, CRON_MAX_RETRIES, markCronPrompt, normalizeSchedule, scheduleLabel, cronTimeZone, defaultTimeZone, systemTimeZone, isValidTimeZone, } from "./crons.js";
|
|
29
29
|
import { linkRefusal, markAgentPrompt, notificationText, } from "./kinship.js";
|
|
@@ -62,6 +62,8 @@ if (!instanceLock.ok) {
|
|
|
62
62
|
process.on("exit", () => releaseInstanceLock());
|
|
63
63
|
const app = express();
|
|
64
64
|
app.use(express.json({ limit: "1mb" }));
|
|
65
|
+
/** A pasted screenshot is a few hundred kB; past this it is not a paste. */
|
|
66
|
+
const PASTE_LIMIT = "12mb";
|
|
65
67
|
// ── Optional GUI password ────────────────────────────────────────────────
|
|
66
68
|
// If SHADOK_GUI_PASSWORD is set (at startup, via env or the CLI --password
|
|
67
69
|
// flag), the whole GUI — pages, endpoints AND the WebSocket — requires a login.
|
|
@@ -538,6 +540,36 @@ app.get(["/", "/index.html"], (_req, res) => {
|
|
|
538
540
|
res.setHeader("Content-Security-Policy", cspHeader(nonce));
|
|
539
541
|
res.type("html").send(injectNonce(html, nonce));
|
|
540
542
|
});
|
|
543
|
+
/**
|
|
544
|
+
* An image pasted into the composer. The web had no way to hand a file to an
|
|
545
|
+
* agent at all — only Telegram did — so a screenshot meant saving it somewhere
|
|
546
|
+
* and typing the path by hand.
|
|
547
|
+
*
|
|
548
|
+
* Same destination as the Telegram attachments (`MEDIA_DIR`): one folder, one
|
|
549
|
+
* purge, and the agent reads the file by absolute path exactly the same way.
|
|
550
|
+
*
|
|
551
|
+
* `requestFromBrowser` (stricter than the WS origin guard, cf. the profile
|
|
552
|
+
* guardrails): this route WRITES a file, so an `Origin`-less caller — a script,
|
|
553
|
+
* a curl — has no business here even on loopback.
|
|
554
|
+
*/
|
|
555
|
+
app.post("/paste", express.raw({ type: "image/*", limit: PASTE_LIMIT }), (req, res) => {
|
|
556
|
+
if (!requestFromBrowser(req))
|
|
557
|
+
return res.status(403).json({ error: "same-origin browser only" });
|
|
558
|
+
const body = req.body;
|
|
559
|
+
if (!Buffer.isBuffer(body) || !body.length)
|
|
560
|
+
return res.status(400).json({ error: "empty body" });
|
|
561
|
+
const ext = pasteExtension(String(req.headers["content-type"] ?? ""));
|
|
562
|
+
try {
|
|
563
|
+
fs.mkdirSync(MEDIA_DIR, { recursive: true });
|
|
564
|
+
const file = path.join(MEDIA_DIR, `paste-${randomUUID()}.${ext}`);
|
|
565
|
+
fs.writeFileSync(file, body);
|
|
566
|
+
// The very wording Telegram already uses, so an agent sees one format.
|
|
567
|
+
res.json({ path: file, line: attachmentPrompt([{ path: file, kind: "image" }]) });
|
|
568
|
+
}
|
|
569
|
+
catch (e) {
|
|
570
|
+
res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
|
|
571
|
+
}
|
|
572
|
+
});
|
|
541
573
|
app.use(express.static(path.join(__dirname, "..", "public")));
|
|
542
574
|
// Markdown parser served locally (history rendering on the client).
|
|
543
575
|
// Résolu via require.resolve, pas un chemin en dur : dans l'install npm
|
|
@@ -652,7 +684,7 @@ app.post("/auth/login", async (_req, res) => {
|
|
|
652
684
|
const r = await startLogin();
|
|
653
685
|
if ("error" in r)
|
|
654
686
|
return res.status(502).json(r);
|
|
655
|
-
res.json(r);
|
|
687
|
+
res.json(r); // {url} or {alreadySignedIn:true} — the latter spawns nothing
|
|
656
688
|
});
|
|
657
689
|
app.post("/auth/code", async (req, res) => {
|
|
658
690
|
const code = typeof req.body?.code === "string" ? req.body.code : "";
|
|
@@ -1781,7 +1813,16 @@ wss.on("connection", (ws) => {
|
|
|
1781
1813
|
// allowed to start without one", and then sat on the first-run screen
|
|
1782
1814
|
// for a day. `code` lets a machine client classify the refusal
|
|
1783
1815
|
// without matching on message text (same contract as "busy").
|
|
1784
|
-
|
|
1816
|
+
// Only a state we OBSERVED refuses a spawn. A probe that failed
|
|
1817
|
+
// ("unknown") means we could not look, not that the instance is
|
|
1818
|
+
// signed out — punishing the user for our own flakiness would block
|
|
1819
|
+
// an agent on a machine that is perfectly fine. The seeding already
|
|
1820
|
+
// removed the silent-zombie failure this guard was protecting
|
|
1821
|
+
// against, and an agent spawned without credentials now fails loudly.
|
|
1822
|
+
const auth = await authStatus();
|
|
1823
|
+
if (auth.state === "unknown")
|
|
1824
|
+
console.log(`auth: could not verify sign-in state, allowing the spawn anyway`);
|
|
1825
|
+
if (auth.state === "signed-out") {
|
|
1785
1826
|
// Telling the user is the whole point: a cron refused at 4am must
|
|
1786
1827
|
// not be discovered a day later. Deduplicated inside, so a
|
|
1787
1828
|
// five-minute cron does not turn one sign-out into a flood.
|
|
@@ -2007,7 +2048,7 @@ wss.on("connection", (ws) => {
|
|
|
2007
2048
|
// dump de sa garde) noyait la réponse dans les deux interfaces. La
|
|
2008
2049
|
// marque dans le contenu assure le même masquage à la relecture.
|
|
2009
2050
|
if (origin !== "cron")
|
|
2010
|
-
broadcast(session, { type: "prompt-echo", text, ...(origin ? { origin } : {}) }, ws);
|
|
2051
|
+
broadcast(session, { type: "prompt-echo", text, ...(origin ? { origin } : {}), ...(msg.from ? { from: msg.from } : {}) }, ws);
|
|
2011
2052
|
session.busy = true;
|
|
2012
2053
|
session.turnStartedAt = Date.now();
|
|
2013
2054
|
broadcast(session, workingMessage(session));
|