dsh-deeptutor 0.1.3 → 0.1.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 +177 -136
- package/README.zh.md +131 -107
- package/cordis.patch.yml +17 -17
- package/package.json +62 -56
- package/scripts/install-profile.mjs +233 -0
- package/scripts/md-to-html.js +353 -353
- package/skills/deeptutor/README.md +106 -0
- package/skills/deeptutor/SKILL.md +182 -0
- package/skills/html-doc/SKILL.md +91 -0
- package/skills/html-doc/assets/template.html +420 -0
- package/skills/html-doc/scripts/md-to-html.js +353 -0
- package/src/cli-exec.ts +251 -251
- package/src/config.ts +70 -70
- package/src/html-render.ts +53 -53
- package/src/http-api.ts +83 -83
- package/src/index.ts +449 -449
- package/src/turn.ts +174 -174
package/package.json
CHANGED
|
@@ -1,56 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dsh-deeptutor",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "DeepTutor bridge bundle for DeepSeek Harness: learning capabilities, knowledge bases, and note archiving (HTTP/WS first, CLI fallback; auto-adapts local/remote deployment).",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"dsh",
|
|
7
|
-
"dsh-plugin",
|
|
8
|
-
"dsh-bundle",
|
|
9
|
-
"deeptutor",
|
|
10
|
-
"tutoring",
|
|
11
|
-
"rag",
|
|
12
|
-
"agent"
|
|
13
|
-
],
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"type": "module",
|
|
16
|
-
"main": "./lib/index.js",
|
|
17
|
-
"types": "./lib/index.d.ts",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
"src",
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
},
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"@
|
|
54
|
-
"
|
|
55
|
-
}
|
|
56
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-deeptutor",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "DeepTutor bridge bundle for DeepSeek Harness: learning capabilities, knowledge bases, and note archiving (HTTP/WS first, CLI fallback; auto-adapts local/remote deployment).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dsh",
|
|
7
|
+
"dsh-plugin",
|
|
8
|
+
"dsh-bundle",
|
|
9
|
+
"deeptutor",
|
|
10
|
+
"tutoring",
|
|
11
|
+
"rag",
|
|
12
|
+
"agent"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./lib/index.js",
|
|
17
|
+
"types": "./lib/index.d.ts",
|
|
18
|
+
"bin": {
|
|
19
|
+
"dsh-deeptutor": "scripts/install-profile.mjs"
|
|
20
|
+
},
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./lib/index.d.ts",
|
|
24
|
+
"default": "./lib/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
27
|
+
"./scripts/*": "./scripts/*",
|
|
28
|
+
"./skills/*": "./skills/*",
|
|
29
|
+
"./src/*": "./src/*",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"lib",
|
|
34
|
+
"src",
|
|
35
|
+
"scripts",
|
|
36
|
+
"skills",
|
|
37
|
+
"cordis.patch.yml",
|
|
38
|
+
"README.md",
|
|
39
|
+
"README.zh.md"
|
|
40
|
+
],
|
|
41
|
+
"dsh": {
|
|
42
|
+
"bundle": {
|
|
43
|
+
"patch": "./cordis.patch.yml"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc -p tsconfig.build.json",
|
|
48
|
+
"typecheck": "tsc --noEmit",
|
|
49
|
+
"prepack": "npm run build && npm run typecheck",
|
|
50
|
+
"pack:check": "npm pack --dry-run"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
54
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
58
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
|
|
59
|
+
"@types/node": "^24.0.0",
|
|
60
|
+
"typescript": "^5.9.3"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* One-shot profile installer for the dsh-deeptutor bundle.
|
|
4
|
+
*
|
|
5
|
+
* Wraps `dsh plugin --profile <name> add dsh-deeptutor` and works around the
|
|
6
|
+
* pnpm workspace-root check: the dsh profile scaffold always writes a
|
|
7
|
+
* `pnpm-workspace.yaml`, which makes the profile directory a pnpm workspace
|
|
8
|
+
* root, so on pnpm >= 8 `pnpm add` aborts with ERR_PNPM_ADDING_TO_ROOT unless
|
|
9
|
+
* the explicit `-w`/`--workspace-root` flag is passed. The plain command is
|
|
10
|
+
* tried first (older pnpm versions / older dsh templates don't need the
|
|
11
|
+
* flag), and when the check trips the installer retries with the correct
|
|
12
|
+
* flag automatically — one command that works on any setup.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* node scripts/install-profile.mjs [--profile <name>] (from a checkout)
|
|
16
|
+
* pnpm dlx dsh-deeptutor --profile web (published one-liner)
|
|
17
|
+
*
|
|
18
|
+
* Options:
|
|
19
|
+
* -p, --profile <name> dsh profile to install into (default: web)
|
|
20
|
+
* -h, --help show this help
|
|
21
|
+
*
|
|
22
|
+
* Besides installing the bundle, the installer copies the package's bundled
|
|
23
|
+
* skills (`skills/deeptutor`, `skills/html-doc`) into
|
|
24
|
+
* `<DSH_HOME>/skills/<name>/`, where dsh auto-discovers them. Existing files
|
|
25
|
+
* are overwritten; files not shipped by the package are never deleted.
|
|
26
|
+
*/
|
|
27
|
+
import { spawnSync } from 'node:child_process';
|
|
28
|
+
import { cpSync, existsSync, mkdirSync, readdirSync } from 'node:fs';
|
|
29
|
+
import { homedir } from 'node:os';
|
|
30
|
+
import { delimiter, dirname, join } from 'node:path';
|
|
31
|
+
import { fileURLToPath } from 'node:url';
|
|
32
|
+
|
|
33
|
+
const PKG = 'dsh-deeptutor';
|
|
34
|
+
const NAME = 'dsh-deeptutor-install';
|
|
35
|
+
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
36
|
+
const SKILLS_DIR = join(SCRIPT_DIR, '..', 'skills');
|
|
37
|
+
|
|
38
|
+
const USAGE = `usage: dsh-deeptutor [--profile <name>]
|
|
39
|
+
|
|
40
|
+
Install the ${PKG} bundle into a dsh profile via \`dsh plugin add\`,
|
|
41
|
+
automatically handling the pnpm workspace-root check.
|
|
42
|
+
|
|
43
|
+
options:
|
|
44
|
+
-p, --profile <name> dsh profile to install into (default: web)
|
|
45
|
+
-h, --help show this help`;
|
|
46
|
+
|
|
47
|
+
function parseArgs(argv) {
|
|
48
|
+
const out = { profile: 'web', help: false };
|
|
49
|
+
for (let i = 0; i < argv.length; i++) {
|
|
50
|
+
const arg = argv[i];
|
|
51
|
+
if (arg === '--profile' || arg === '-p') {
|
|
52
|
+
const value = argv[++i];
|
|
53
|
+
if (!value) throw new Error(`${arg} requires a value`);
|
|
54
|
+
out.profile = value;
|
|
55
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
56
|
+
out.help = true;
|
|
57
|
+
} else {
|
|
58
|
+
throw new Error(`unknown argument: ${arg}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!/^[A-Za-z0-9_.-]+$/.test(out.profile)) {
|
|
62
|
+
throw new Error(`invalid profile name: ${out.profile} (allowed: letters, digits, . _ -)`);
|
|
63
|
+
}
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Locate the dsh CLI. On Windows the shim is usually a .ps1 (sometimes a
|
|
69
|
+
* .cmd/.exe sibling); a plain `spawnSync('dsh', ...)` would not resolve the
|
|
70
|
+
* PowerShell shim, so walk PATH explicitly and fall back to `powershell -File`.
|
|
71
|
+
* Note: with `shell: true` Node does not quote the command itself, so a
|
|
72
|
+
* .cmd/.bat path containing spaces must carry its own quotes.
|
|
73
|
+
*/
|
|
74
|
+
function resolveDsh() {
|
|
75
|
+
if (process.platform !== 'win32') {
|
|
76
|
+
return { file: 'dsh', args: [], shell: false, describe: 'dsh' };
|
|
77
|
+
}
|
|
78
|
+
const dirs = (process.env.PATH || '').split(delimiter).filter(Boolean);
|
|
79
|
+
for (const dir of dirs) {
|
|
80
|
+
for (const name of ['dsh.exe']) {
|
|
81
|
+
const file = join(dir, name);
|
|
82
|
+
if (existsSync(file)) return { file, args: [], shell: false, describe: file };
|
|
83
|
+
}
|
|
84
|
+
for (const name of ['dsh.cmd', 'dsh.bat']) {
|
|
85
|
+
const file = join(dir, name);
|
|
86
|
+
if (existsSync(file)) {
|
|
87
|
+
return { file: `"${file}"`, args: [], shell: true, describe: file };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const ps1 = join(dir, 'dsh.ps1');
|
|
91
|
+
if (existsSync(ps1)) {
|
|
92
|
+
return {
|
|
93
|
+
file: 'powershell.exe',
|
|
94
|
+
args: ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', ps1],
|
|
95
|
+
shell: false,
|
|
96
|
+
describe: ps1,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Run `dsh plugin --profile <name> add dsh-deeptutor [flags]`.
|
|
105
|
+
* Both streams are captured (note: pnpm 8 on Windows prints its errors —
|
|
106
|
+
* including ERR_PNPM_ADDING_TO_ROOT — on stdout), so the workspace-root
|
|
107
|
+
* check can be detected programmatically; captured output is replayed on
|
|
108
|
+
* success/failure instead of streamed live.
|
|
109
|
+
*/
|
|
110
|
+
function runDsh(dsh, profile, flag) {
|
|
111
|
+
const args = [
|
|
112
|
+
...dsh.args,
|
|
113
|
+
'plugin',
|
|
114
|
+
'--profile',
|
|
115
|
+
profile,
|
|
116
|
+
'add',
|
|
117
|
+
PKG,
|
|
118
|
+
...(flag ? ['-w'] : []),
|
|
119
|
+
];
|
|
120
|
+
return spawnSync(dsh.file, args, {
|
|
121
|
+
shell: dsh.shell,
|
|
122
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
123
|
+
encoding: 'utf8',
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const combinedOutput = (result) => `${result.stdout ?? ''}${result.stderr ?? ''}`;
|
|
128
|
+
|
|
129
|
+
function verifyHint(profile) {
|
|
130
|
+
const grep = process.platform === 'win32' ? 'findstr dsh-deeptutor' : 'grep dsh-deeptutor';
|
|
131
|
+
return `dsh --profile ${profile} --dump-config | ${grep}`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function main() {
|
|
135
|
+
let opts;
|
|
136
|
+
try {
|
|
137
|
+
opts = parseArgs(process.argv.slice(2));
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.error(`error: ${error.message}\n\n${USAGE}`);
|
|
140
|
+
process.exit(2);
|
|
141
|
+
}
|
|
142
|
+
if (opts.help) {
|
|
143
|
+
console.log(USAGE);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const dsh = resolveDsh();
|
|
148
|
+
if (!dsh) {
|
|
149
|
+
console.error(`error: cannot find the dsh CLI on PATH — install dsh first, then re-run this installer`);
|
|
150
|
+
process.exit(2);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Plain command first; retry with `-w` only when the workspace-root check
|
|
154
|
+
// trips (fresh profiles and pnpm >= 8), or back off `-w` if a previous run
|
|
155
|
+
// left a stray flag in an environment that rejects it.
|
|
156
|
+
let attempt = runDsh(dsh, opts.profile, false);
|
|
157
|
+
if (attempt.error) {
|
|
158
|
+
console.error(`error: failed to run dsh via ${dsh.describe}: ${attempt.error.message}`);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (attempt.status === 0) {
|
|
163
|
+
process.stdout.write(attempt.stdout ?? '');
|
|
164
|
+
finish(opts.profile);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const firstOutput = combinedOutput(attempt);
|
|
169
|
+
let retryFlag = null;
|
|
170
|
+
if (/ERR_PNPM_ADDING_TO_ROOT|workspace root/i.test(firstOutput)) retryFlag = true;
|
|
171
|
+
else if (/may only be used inside a workspace/i.test(firstOutput)) retryFlag = false;
|
|
172
|
+
|
|
173
|
+
if (retryFlag !== null) {
|
|
174
|
+
console.error(`\n${NAME}: pnpm flagged the workspace-root check — retrying with ${retryFlag ? '-w' : 'no'} workspace-root flag...\n`);
|
|
175
|
+
const retried = runDsh(dsh, opts.profile, retryFlag);
|
|
176
|
+
if (retried.error) {
|
|
177
|
+
console.error(`error: failed to run dsh via ${dsh.describe}: ${retried.error.message}`);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
if (retried.status === 0) {
|
|
181
|
+
process.stdout.write(retried.stdout ?? '');
|
|
182
|
+
finish(opts.profile);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
process.stderr.write(`${firstOutput}\n--- retry output (${retryFlag ? '-w' : 'plain'}) ---\n${combinedOutput(retried)}\n`);
|
|
186
|
+
process.exit(retried.status ?? 1);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (/pnpm not found/i.test(firstOutput)) {
|
|
190
|
+
process.stderr.write(`${firstOutput}\n${NAME}: pnpm is required to manage profile plugins — install pnpm and re-run\n`);
|
|
191
|
+
} else {
|
|
192
|
+
process.stderr.write(firstOutput);
|
|
193
|
+
}
|
|
194
|
+
process.exit(attempt.status ?? 1);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function finish(profile) {
|
|
198
|
+
const skills = installSkills();
|
|
199
|
+
console.log(`
|
|
200
|
+
\u2714 ${PKG} installed into profile '${profile}'
|
|
201
|
+
\u00b7 dependency added and dsh.profile.bundles reconciled (bundle patch auto-registered)${skills}
|
|
202
|
+
|
|
203
|
+
next steps:
|
|
204
|
+
1. restart dsh (the bundle list is resolved at boot)
|
|
205
|
+
2. verify: ${verifyHint(profile)}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Copy the package's bundled skills into <DSH_HOME>/skills/<name>/ (dsh
|
|
210
|
+
* auto-discovers skills there). Existing files are overwritten in place;
|
|
211
|
+
* anything not shipped by this package is left untouched. Returns a
|
|
212
|
+
* human-readable summary line (or '' when there is nothing to install).
|
|
213
|
+
*/
|
|
214
|
+
function installSkills() {
|
|
215
|
+
if (!existsSync(SKILLS_DIR)) {
|
|
216
|
+
console.error(`\n${NAME}: warning: no skills/ directory in this package — skill install skipped (old version?)`);
|
|
217
|
+
return '';
|
|
218
|
+
}
|
|
219
|
+
const dshHome = process.env.DSH_HOME || join(homedir(), '.dsh');
|
|
220
|
+
const installed = [];
|
|
221
|
+
for (const entry of readdirSync(SKILLS_DIR, { withFileTypes: true })) {
|
|
222
|
+
if (!entry.isDirectory()) continue;
|
|
223
|
+
const src = join(SKILLS_DIR, entry.name);
|
|
224
|
+
const dest = join(dshHome, 'skills', entry.name);
|
|
225
|
+
mkdirSync(dest, { recursive: true });
|
|
226
|
+
cpSync(src, dest, { recursive: true, force: true });
|
|
227
|
+
installed.push(entry.name);
|
|
228
|
+
}
|
|
229
|
+
if (installed.length === 0) return '';
|
|
230
|
+
return `\n \u00b7 skills installed: ${installed.join(', ')} -> ${join(dshHome, 'skills')}`;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
main();
|