@carljia/omd-dsh 0.1.1 → 0.1.2
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/lib/cli.js +105 -10
- package/omd-matrix.json +14 -2
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { promises as fs, existsSync, realpathSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { promises as fs, existsSync, realpathSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { dirname, join, relative, resolve, basename } from "node:path";
|
|
5
5
|
import { homedir } from "node:os";
|
|
@@ -37,7 +37,7 @@ function usage() {
|
|
|
37
37
|
" setup interactive: discover DSH models, then guide per-mode/tier model selection",
|
|
38
38
|
" models print the discovered DSH model catalog",
|
|
39
39
|
" options:",
|
|
40
|
-
" --harness <path> node_modules dir of the DSH harness install (
|
|
40
|
+
" --harness <path> node_modules dir of the DSH harness install (saved locally after first use; otherwise auto-detected)",
|
|
41
41
|
" --dry-run (sync) print planned writes without touching the filesystem",
|
|
42
42
|
" --verbose (sync) print per-file detail",
|
|
43
43
|
].join("\n");
|
|
@@ -55,6 +55,60 @@ function findNodeModules(start) {
|
|
|
55
55
|
current = parent;
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
function harnessCachePath() { return join(dshHome(), "omd-dsh-harness.json"); }
|
|
59
|
+
/** Read the cached harness node_modules, ignoring a stale/missing entry. */
|
|
60
|
+
function readCachedHarness() {
|
|
61
|
+
try {
|
|
62
|
+
const p = harnessCachePath();
|
|
63
|
+
if (!existsSync(p))
|
|
64
|
+
return undefined;
|
|
65
|
+
const parsed = JSON.parse(readFileSync(p, "utf8"));
|
|
66
|
+
const nm = parsed && typeof parsed === "object" ? parsed.harnessNodeModules : undefined;
|
|
67
|
+
if (typeof nm !== "string" || nm === "")
|
|
68
|
+
return undefined;
|
|
69
|
+
if (!existsSync(join(nm, "@deepseek-ai", "dsh-scope", "package.json")))
|
|
70
|
+
return undefined;
|
|
71
|
+
return nm;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** Persist the resolved harness node_modules for later runs (best-effort). */
|
|
78
|
+
function writeCachedHarness(harnessNodeModules) {
|
|
79
|
+
try {
|
|
80
|
+
writeFileSync(harnessCachePath(), JSON.stringify({ harnessNodeModules }, null, 2) + "\n", "utf8");
|
|
81
|
+
}
|
|
82
|
+
catch { /* best-effort */ }
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolve the DSH harness node_modules:
|
|
86
|
+
* 1. --harness flag (and cache it for later);
|
|
87
|
+
* 2. auto-detect via the dsh executable on PATH;
|
|
88
|
+
* 3. fall back to the locally cached value.
|
|
89
|
+
*/
|
|
90
|
+
function resolveHarness(flags) {
|
|
91
|
+
let nm;
|
|
92
|
+
if (flags.harness !== undefined) {
|
|
93
|
+
nm = findNodeModules(flags.harness);
|
|
94
|
+
if (nm !== undefined) {
|
|
95
|
+
try {
|
|
96
|
+
nm = realpathSync(nm);
|
|
97
|
+
writeCachedHarness(nm);
|
|
98
|
+
}
|
|
99
|
+
catch { /* keep nm as-is */ }
|
|
100
|
+
}
|
|
101
|
+
return nm;
|
|
102
|
+
}
|
|
103
|
+
nm = locateHarnessViaDsh() ?? locateHarnessViaNpxCache() ?? readCachedHarness();
|
|
104
|
+
if (nm !== undefined) {
|
|
105
|
+
try {
|
|
106
|
+
nm = realpathSync(nm);
|
|
107
|
+
}
|
|
108
|
+
catch { /* keep */ }
|
|
109
|
+
}
|
|
110
|
+
return nm;
|
|
111
|
+
}
|
|
58
112
|
function locateHarnessViaDsh() {
|
|
59
113
|
const candidates = [];
|
|
60
114
|
try {
|
|
@@ -79,6 +133,51 @@ function locateHarnessViaDsh() {
|
|
|
79
133
|
}
|
|
80
134
|
return undefined;
|
|
81
135
|
}
|
|
136
|
+
/** Candidate npx cache roots where a non-global DSH install may live. */
|
|
137
|
+
function npxCacheRoots() {
|
|
138
|
+
const roots = [];
|
|
139
|
+
if (process.platform === "win32") {
|
|
140
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
141
|
+
if (localAppData)
|
|
142
|
+
roots.push(join(localAppData, "npm-cache", "_npx"));
|
|
143
|
+
const appData = process.env.APPDATA;
|
|
144
|
+
if (appData)
|
|
145
|
+
roots.push(join(appData, "npm-cache", "_npx"));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
roots.push(join(homedir(), ".npm", "_npx"));
|
|
149
|
+
}
|
|
150
|
+
return roots;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Best-effort scan of the npx cache for a DSH install whose node_modules
|
|
154
|
+
* carries @deepseek-ai/dsh-scope. Picks the most recently touched one.
|
|
155
|
+
*/
|
|
156
|
+
function locateHarnessViaNpxCache() {
|
|
157
|
+
const matches = [];
|
|
158
|
+
for (const root of npxCacheRoots()) {
|
|
159
|
+
let entries;
|
|
160
|
+
try {
|
|
161
|
+
entries = readdirSync(root);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
for (const entry of entries) {
|
|
167
|
+
const nm = join(root, entry, "node_modules");
|
|
168
|
+
if (!existsSync(join(nm, "@deepseek-ai", "dsh-scope", "package.json")))
|
|
169
|
+
continue;
|
|
170
|
+
let mtime = 0;
|
|
171
|
+
try {
|
|
172
|
+
mtime = statSync(join(root, entry)).mtimeMs;
|
|
173
|
+
}
|
|
174
|
+
catch { /* keep 0 */ }
|
|
175
|
+
matches.push({ nm, mtime });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
matches.sort((a, b) => b.mtime - a.mtime);
|
|
179
|
+
return matches.length > 0 ? matches[0].nm : undefined;
|
|
180
|
+
}
|
|
82
181
|
function resolveHarnessModule(harnessNodeModules, specifier) {
|
|
83
182
|
const segments = specifier.split("/");
|
|
84
183
|
const scope = segments[0].startsWith("@") ? segments[0] + "/" + segments[1] : segments[0];
|
|
@@ -451,7 +550,7 @@ async function runSetup(flags, harnessNodeModules) {
|
|
|
451
550
|
rl.close();
|
|
452
551
|
if (syncNow === "" || /^y/i.test(syncNow)) {
|
|
453
552
|
if (harnessNodeModules === undefined) {
|
|
454
|
-
console.error("omd-dsh setup: 无法定位 DSH harness node_modules
|
|
553
|
+
console.error("omd-dsh setup: 无法定位 DSH harness node_modules,跳过同步。首次请运行 `omd-dsh sync --harness <路径>`(之后会自动缓存,无需重复指定)。");
|
|
455
554
|
}
|
|
456
555
|
else {
|
|
457
556
|
await runSync(flags, harnessNodeModules);
|
|
@@ -501,19 +600,15 @@ async function main() {
|
|
|
501
600
|
return;
|
|
502
601
|
}
|
|
503
602
|
if (command === "setup") {
|
|
504
|
-
|
|
505
|
-
if (harnessNodeModules !== undefined)
|
|
506
|
-
harnessNodeModules = realpathSync(harnessNodeModules);
|
|
507
|
-
await runSetup(flags, harnessNodeModules);
|
|
603
|
+
await runSetup(flags, resolveHarness(flags));
|
|
508
604
|
return;
|
|
509
605
|
}
|
|
510
|
-
|
|
606
|
+
const harnessNodeModules = resolveHarness(flags);
|
|
511
607
|
if (harnessNodeModules === undefined || !existsSync(join(harnessNodeModules, "@deepseek-ai", "dsh-scope", "package.json"))) {
|
|
512
|
-
console.error("omd-dsh sync: cannot locate the DSH harness node_modules.\n - ensure the dsh executable is on PATH, or\n - pass --harness <path to the harness node_modules directory
|
|
608
|
+
console.error("omd-dsh sync: cannot locate the DSH harness node_modules.\n - ensure the dsh executable is on PATH, or\n - pass --harness <path to the harness node_modules directory> (saved for later runs).\n\n" + usage());
|
|
513
609
|
process.exitCode = 2;
|
|
514
610
|
return;
|
|
515
611
|
}
|
|
516
|
-
harnessNodeModules = realpathSync(harnessNodeModules);
|
|
517
612
|
await runSync(flags, harnessNodeModules);
|
|
518
613
|
}
|
|
519
614
|
main().catch((error) => {
|
package/omd-matrix.json
CHANGED
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
"model": "deepseek-v4-flash",
|
|
14
14
|
"hint": "cheap and fast — repetitive investigation, searching, summarising, mechanical work",
|
|
15
15
|
"persona": "You are a FAST worker subagent (快速执行子代理): complete the assigned task efficiently with the tools you have; prefer short, focused answers.",
|
|
16
|
-
"toolFilter": {
|
|
16
|
+
"toolFilter": {
|
|
17
|
+
"deny": [
|
|
18
|
+
"write",
|
|
19
|
+
"edit"
|
|
20
|
+
],
|
|
21
|
+
"denyShell": true
|
|
22
|
+
}
|
|
17
23
|
},
|
|
18
24
|
"deep": {
|
|
19
25
|
"provider": "deepseek-official",
|
|
@@ -32,7 +38,13 @@
|
|
|
32
38
|
"model": "deepseek-v4-flash",
|
|
33
39
|
"hint": "cheap and fast — repetitive investigation, searching, summarising, mechanical work",
|
|
34
40
|
"persona": "You are a FAST worker subagent (快速执行子代理): complete the assigned task efficiently with the tools you have; prefer short, focused answers.",
|
|
35
|
-
"toolFilter": {
|
|
41
|
+
"toolFilter": {
|
|
42
|
+
"deny": [
|
|
43
|
+
"write",
|
|
44
|
+
"edit"
|
|
45
|
+
],
|
|
46
|
+
"denyShell": true
|
|
47
|
+
}
|
|
36
48
|
},
|
|
37
49
|
"deep": {
|
|
38
50
|
"provider": "deepseek-official",
|