dsh-deeptutor 0.1.11 → 0.2.1
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/.agents/skills/deeptutor/README.md +17 -36
- package/.agents/skills/deeptutor/SKILL.md +14 -14
- package/.agents/skills/html-doc/scripts/md-to-html.js +16 -7
- package/README.md +29 -22
- package/README.zh.md +13 -11
- package/lib/cli-exec.js +13 -2
- package/lib/config.d.ts +6 -6
- package/lib/config.js +16 -17
- package/lib/index.d.ts +8 -9
- package/lib/index.js +5 -111
- package/lib/turn.d.ts +2 -4
- package/lib/turn.js +4 -95
- package/lib/win-cmd.d.ts +27 -0
- package/lib/win-cmd.js +108 -0
- package/package.json +2 -2
- package/scripts/md-to-html.js +16 -7
- package/src/cli-exec.ts +18 -7
- package/src/config.ts +16 -17
- package/src/index.ts +13 -136
- package/src/turn.ts +5 -94
- package/src/win-cmd.ts +129 -0
- package/lib/http-api.d.ts +0 -10
- package/lib/http-api.js +0 -94
- package/scripts/sync-skills.mjs +0 -47
- package/src/http-api.ts +0 -98
package/src/http-api.ts
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DeepTutor bridge: HTTP/WS transport (API probing, SSH tunnel management, JSON calls).
|
|
3
|
-
*/
|
|
4
|
-
import { spawn } from "node:child_process";
|
|
5
|
-
import { API_BASE, SSH_HOST, TUNNEL_PORT } from "./config.ts";
|
|
6
|
-
|
|
7
|
-
let tunnelProc: ReturnType<typeof spawn> | null = null;
|
|
8
|
-
|
|
9
|
-
/** Kill the SSH tunnel process, if one is running (call on plugin disposal). */
|
|
10
|
-
export function killTunnel(): void {
|
|
11
|
-
if (tunnelProc && tunnelProc.exitCode === null) {
|
|
12
|
-
try {
|
|
13
|
-
tunnelProc.kill();
|
|
14
|
-
} catch {}
|
|
15
|
-
tunnelProc = null;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function apiProbe(timeoutMs = 1500): Promise<boolean> {
|
|
20
|
-
try {
|
|
21
|
-
const res = await fetch(`${API_BASE}/api/v1/system/status`, {
|
|
22
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
23
|
-
});
|
|
24
|
-
return res.ok;
|
|
25
|
-
} catch {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Ensure the local API is reachable: probe → start SSH tunnel if needed (remote only) → wait. */
|
|
31
|
-
export async function ensureApi(): Promise<boolean> {
|
|
32
|
-
if (await apiProbe(1200)) return true;
|
|
33
|
-
if (!SSH_HOST) return false; // Local deployment: fall back to local CLI when serve is down, no tunnel needed
|
|
34
|
-
let tunnelDead = false;
|
|
35
|
-
if (!tunnelProc || tunnelProc.exitCode !== null) {
|
|
36
|
-
tunnelProc = spawn(
|
|
37
|
-
"ssh",
|
|
38
|
-
[
|
|
39
|
-
"-N",
|
|
40
|
-
"-L",
|
|
41
|
-
`${TUNNEL_PORT}:127.0.0.1:${TUNNEL_PORT}`,
|
|
42
|
-
"-o",
|
|
43
|
-
"BatchMode=yes",
|
|
44
|
-
"-o",
|
|
45
|
-
"ExitOnForwardFailure=yes",
|
|
46
|
-
"-o",
|
|
47
|
-
"ServerAliveInterval=30",
|
|
48
|
-
"-o",
|
|
49
|
-
"ServerAliveCountMax=3",
|
|
50
|
-
"-o",
|
|
51
|
-
"ConnectTimeout=10",
|
|
52
|
-
SSH_HOST,
|
|
53
|
-
],
|
|
54
|
-
{ stdio: "ignore", windowsHide: true },
|
|
55
|
-
);
|
|
56
|
-
// Fast-fail: a tunnel that exits immediately (bad alias, port in use,
|
|
57
|
-
// refused connection) is not going to recover — stop waiting for it.
|
|
58
|
-
tunnelProc.once("exit", () => {
|
|
59
|
-
tunnelDead = true;
|
|
60
|
-
tunnelProc = null;
|
|
61
|
-
});
|
|
62
|
-
tunnelProc.unref();
|
|
63
|
-
}
|
|
64
|
-
for (let i = 0; i < 20; i++) {
|
|
65
|
-
if (tunnelDead) return false;
|
|
66
|
-
if (await apiProbe(1000)) return true;
|
|
67
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
68
|
-
}
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** JSON fetch against the DeepTutor API. Combines a fixed timeout with an optional caller-supplied abort signal. */
|
|
73
|
-
export async function apiJson(
|
|
74
|
-
path: string,
|
|
75
|
-
init?: RequestInit,
|
|
76
|
-
opts: { timeoutMs?: number; signal?: AbortSignal } = {},
|
|
77
|
-
): Promise<any> {
|
|
78
|
-
const controller = new AbortController();
|
|
79
|
-
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? 60_000);
|
|
80
|
-
const onAbort = () => controller.abort();
|
|
81
|
-
// An already-aborted signal never fires its "abort" event again — check the
|
|
82
|
-
// flag first so a pre-aborted call fails immediately instead of running to
|
|
83
|
-
// completion against a still-open controller.
|
|
84
|
-
if (opts.signal?.aborted) {
|
|
85
|
-
controller.abort();
|
|
86
|
-
} else {
|
|
87
|
-
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
88
|
-
}
|
|
89
|
-
try {
|
|
90
|
-
const res = await fetch(`${API_BASE}${path}`, { ...init, signal: controller.signal });
|
|
91
|
-
if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
92
|
-
const text = await res.text();
|
|
93
|
-
return text ? JSON.parse(text) : null;
|
|
94
|
-
} finally {
|
|
95
|
-
clearTimeout(timer);
|
|
96
|
-
opts.signal?.removeEventListener("abort", onAbort);
|
|
97
|
-
}
|
|
98
|
-
}
|