@ljwei-stak/dsh-model-router 0.13.1 → 0.13.3
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/.dsh-plugin/shared/official-tool-executor.mjs +80 -10
- package/.dsh-plugin/shared/task-executors.mjs +31 -2
- package/CHANGELOG.md +19 -0
- package/INSTALLATION_GUIDE.zh.md +9 -9
- package/MIGRATION.md +3 -3
- package/README.md +10 -8
- package/README.zh.md +11 -9
- package/package.json +1 -1
|
@@ -24,7 +24,7 @@ import { ensureNpmPrefixOnPath } from './official-tools-runtime.mjs'
|
|
|
24
24
|
import { buildMiniMaxInvocation, createMiniMaxStreamParser } from './vendor-minimax-adapter.mjs'
|
|
25
25
|
import { discoverZCodeBundle } from './zcode-bundle.mjs'
|
|
26
26
|
import { resolveMiMoGrokLaunch, createMiMoGrokParser } from './vendor-mimo-grok-adapter.mjs'
|
|
27
|
-
import { usageFromEvents, usageFromOutput } from './task-executors.mjs'
|
|
27
|
+
import { emptyOutputError, outputIsEmpty, usageFromEvents, usageFromOutput } from './task-executors.mjs'
|
|
28
28
|
|
|
29
29
|
const IS_WINDOWS = process.platform === 'win32'
|
|
30
30
|
const MAX_TASK_BYTES = 64_000
|
|
@@ -394,11 +394,7 @@ async function launchSpec(toolId, workspace, mode, modelId, task = 'Check readin
|
|
|
394
394
|
if (!found) return { unsupported: '未找到具有 OpenAI 有效签名的 codex.exe。' }
|
|
395
395
|
return {
|
|
396
396
|
file: found.entry,
|
|
397
|
-
args:
|
|
398
|
-
'--ask-for-approval', 'never', 'exec',
|
|
399
|
-
...(modelId ? ['--model', modelId] : []),
|
|
400
|
-
'--sandbox', mode, '--json', '-',
|
|
401
|
-
],
|
|
397
|
+
args: codexExecArgs(mode, modelId),
|
|
402
398
|
format: 'codex-jsonl',
|
|
403
399
|
source: found.source,
|
|
404
400
|
}
|
|
@@ -469,6 +465,71 @@ async function launchSpec(toolId, workspace, mode, modelId, task = 'Check readin
|
|
|
469
465
|
return { unsupported: CAPABILITIES[toolId]?.reason ?? '此官方工具尚无已核验的安全执行适配器。' }
|
|
470
466
|
}
|
|
471
467
|
|
|
468
|
+
/**
|
|
469
|
+
* Codex `exec` argv for the signed runner. `--skip-git-repo-check` is required:
|
|
470
|
+
* without it Codex refuses any workspace that is not a Git repository or a
|
|
471
|
+
* directory trusted in the user's config ("Not inside a trusted directory and
|
|
472
|
+
* --skip-git-repo-check was not specified.", exit 1). The workbench lets the user
|
|
473
|
+
* pick any absolute directory, and read-only runs are still confined by
|
|
474
|
+
* `--sandbox read-only` and the Harness process sandbox; write runs use an
|
|
475
|
+
* isolated Git worktree, so the flag changes nothing there.
|
|
476
|
+
*/
|
|
477
|
+
export function codexExecArgs(mode, modelId = null) {
|
|
478
|
+
return [
|
|
479
|
+
'--ask-for-approval', 'never', 'exec', '--skip-git-repo-check',
|
|
480
|
+
...(modelId ? ['--model', modelId] : []),
|
|
481
|
+
'--sandbox', mode, '--json', '-',
|
|
482
|
+
]
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/** Failure text when Codex exits without a successful turn; names the cause when it is known. */
|
|
486
|
+
export function codexIncompleteError(eventCount, stderr = '') {
|
|
487
|
+
const text = String(stderr ?? '')
|
|
488
|
+
if (/not inside a trusted directory/i.test(text)) {
|
|
489
|
+
return 'Codex 拒绝在非 Git 仓库/未信任目录中运行(Not inside a trusted directory)。'
|
|
490
|
+
}
|
|
491
|
+
if (!eventCount) {
|
|
492
|
+
const last = text.split(/\r?\n/u).map(line => line.trim()).filter(Boolean).at(-1)
|
|
493
|
+
return `Codex 未输出任何 JSON 事件就退出了(未开始回合,没有调用模型)。${last ? `CLI 输出:${last.slice(0, 300)}` : '未收到 CLI 输出。'}`
|
|
494
|
+
}
|
|
495
|
+
return 'Codex 未返回完整成功终态和回答。'
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Extra environment the Harness sandbox runner itself needs. On Desktop the
|
|
500
|
+
* runner prefix is `[process.execPath, …/runner.js]` and process.execPath is
|
|
501
|
+
* the Electron app (DeepSeek Harness.exe). Harness starts such Node-mode
|
|
502
|
+
* children with ELECTRON_RUN_AS_NODE=1; without it the executable boots the
|
|
503
|
+
* GUI, loses the single-instance lock and exits 0 with no output, so the
|
|
504
|
+
* wrapped CLI never runs. The minimal CLI environment must therefore carry it
|
|
505
|
+
* whenever the confined argv starts with this Electron executable.
|
|
506
|
+
*/
|
|
507
|
+
export function runnerEnvironment(argv0, { execPath = process.execPath, electron = process.versions?.electron, platform = process.platform } = {}) {
|
|
508
|
+
if (!electron || typeof argv0 !== 'string' || typeof execPath !== 'string') return {}
|
|
509
|
+
const normalize = value => {
|
|
510
|
+
const resolved = resolve(value)
|
|
511
|
+
return platform === 'win32' ? resolved.replace(/\//g, '\\').toLowerCase() : resolved
|
|
512
|
+
}
|
|
513
|
+
return normalize(argv0) === normalize(execPath) ? { ELECTRON_RUN_AS_NODE: '1' } : {}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* CLIs that cannot start inside the Harness Windows ACL process sandbox.
|
|
518
|
+
* Codex 0.157 must write CODEX_HOME (~/.codex: app-server state, sessions,
|
|
519
|
+
* temp aliases) before its first turn; the ACL runner denies every write in
|
|
520
|
+
* read-only mode and every write outside the workspace in workspace-write, so
|
|
521
|
+
* Codex exits with "failed to initialize in-process app-server client: Access
|
|
522
|
+
* is denied (os error 5)". Returning "unsupported" lets a read-only step use
|
|
523
|
+
* the direct `codex exec --sandbox read-only` launch the user approves as
|
|
524
|
+
* "unsandboxed CLI", instead of failing every time.
|
|
525
|
+
*/
|
|
526
|
+
export function harnessSandboxBlocker(toolId, platform = process.platform) {
|
|
527
|
+
if (toolId === 'codex' && platform === 'win32') {
|
|
528
|
+
return 'Codex 启动时必须写入 CODEX_HOME(~/.codex),Harness 的 Windows 进程沙箱会拒绝这些写入(os error 5);改用 Codex 自带的只读沙箱直接启动。'
|
|
529
|
+
}
|
|
530
|
+
return null
|
|
531
|
+
}
|
|
532
|
+
|
|
472
533
|
/** Check the actual trusted launch entry without starting an account call. */
|
|
473
534
|
export async function officialToolReadiness(toolId, workspace = process.cwd()) {
|
|
474
535
|
const tool = getOfficialTool(toolId)
|
|
@@ -513,7 +574,7 @@ function stopProcessTree(child) {
|
|
|
513
574
|
}
|
|
514
575
|
}
|
|
515
576
|
|
|
516
|
-
function captureProcess(spec, task, workspace, signal, timeoutMs, toolId, sessionOnly = false) {
|
|
577
|
+
function captureProcess(spec, task, workspace, signal, timeoutMs, toolId, sessionOnly = false, extraEnv = {}) {
|
|
517
578
|
return new Promise(resolveResult => {
|
|
518
579
|
let child
|
|
519
580
|
try {
|
|
@@ -523,7 +584,7 @@ function captureProcess(spec, task, workspace, signal, timeoutMs, toolId, sessio
|
|
|
523
584
|
windowsHide: true,
|
|
524
585
|
detached: !IS_WINDOWS,
|
|
525
586
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
526
|
-
env: executionEnvironment(toolId, { sessionOnly }),
|
|
587
|
+
env: { ...executionEnvironment(toolId, { sessionOnly }), ...extraEnv },
|
|
527
588
|
})
|
|
528
589
|
} catch (error) {
|
|
529
590
|
resolveResult({ status: 'failed', error: String(error?.message ?? error), exitCode: null })
|
|
@@ -538,6 +599,7 @@ function captureProcess(spec, task, workspace, signal, timeoutMs, toolId, sessio
|
|
|
538
599
|
let outputBytes = 0
|
|
539
600
|
let jsonlBuffer = ''
|
|
540
601
|
let codexUsageLine = ''
|
|
602
|
+
let codexEvents = 0
|
|
541
603
|
let reportedUsage = null
|
|
542
604
|
let terminal = null
|
|
543
605
|
let failedEvent = false
|
|
@@ -601,6 +663,7 @@ function captureProcess(spec, task, workspace, signal, timeoutMs, toolId, sessio
|
|
|
601
663
|
}
|
|
602
664
|
return
|
|
603
665
|
}
|
|
666
|
+
codexEvents += 1
|
|
604
667
|
if (event.type === 'turn.completed' && event.usage) codexUsageLine = line
|
|
605
668
|
if (event.type === 'turn.completed' && !failedEvent) terminal = 'completed'
|
|
606
669
|
// Top-level `error` events include transient reconnect notices; only turn.failed is terminal.
|
|
@@ -677,6 +740,11 @@ function captureProcess(spec, task, workspace, signal, timeoutMs, toolId, sessio
|
|
|
677
740
|
settle({ status: stopReason, exitCode: code, exitSignal })
|
|
678
741
|
return
|
|
679
742
|
}
|
|
743
|
+
if (outputIsEmpty(stdoutTail, stderrTail)) {
|
|
744
|
+
settle({ status: 'failed', exitCode: code, exitSignal, emptyOutput: true,
|
|
745
|
+
error: emptyOutputError(getOfficialTool(toolId)?.label ?? toolId, code) })
|
|
746
|
+
return
|
|
747
|
+
}
|
|
680
748
|
if (miniMaxParser) {
|
|
681
749
|
const outcome = miniMaxParser.finish(code)
|
|
682
750
|
const reported = usageFromEvents('minimax-result', outcome)
|
|
@@ -725,7 +793,7 @@ function captureProcess(spec, task, workspace, signal, timeoutMs, toolId, sessio
|
|
|
725
793
|
}
|
|
726
794
|
terminal = 'completed'
|
|
727
795
|
} else if (protocolError || terminal !== 'completed' || !finalText.trim()) {
|
|
728
|
-
settle({ status: 'failed', exitCode: code, error: protocolError ??
|
|
796
|
+
settle({ status: 'failed', exitCode: code, error: protocolError ?? codexIncompleteError(codexEvents, stderrTail) })
|
|
729
797
|
return
|
|
730
798
|
}
|
|
731
799
|
if (!reportedUsage && codexUsageLine) reportedUsage = usageFromOutput('codex-jsonl', codexUsageLine)
|
|
@@ -765,6 +833,8 @@ export async function runOfficialTool({
|
|
|
765
833
|
if (executionMode === 'workspace-write') await checkedWriteWorkspace(cwd, isolatedRoot)
|
|
766
834
|
const timeout = checkedTimeout(timeoutMs)
|
|
767
835
|
if (signal?.aborted) return { toolId: tool.id, status: 'cancelled', workspace: cwd }
|
|
836
|
+
const blocker = harnessSandboxBlocker(tool.id)
|
|
837
|
+
if (blocker) return { toolId: tool.id, status: 'unsupported', reason: blocker }
|
|
768
838
|
const spec = await launchSpec(tool.id, cwd, executionMode, requestedModel, prompt)
|
|
769
839
|
if (spec.unsupported) return { toolId: tool.id, status: 'unsupported', reason: spec.unsupported }
|
|
770
840
|
if (typeof sandbox?.confine !== 'function') {
|
|
@@ -783,7 +853,7 @@ export async function runOfficialTool({
|
|
|
783
853
|
}
|
|
784
854
|
const startedAt = Date.now()
|
|
785
855
|
const outcome = await captureProcess({ ...spec, file: confined.argv[0], args: confined.argv.slice(1) },
|
|
786
|
-
prompt, cwd, signal, timeout, tool.id, sessionOnly === true)
|
|
856
|
+
prompt, cwd, signal, timeout, tool.id, sessionOnly === true, runnerEnvironment(confined.argv[0]))
|
|
787
857
|
return {
|
|
788
858
|
toolId: tool.id,
|
|
789
859
|
mode: executionMode,
|
|
@@ -254,6 +254,33 @@ function parseClaude(stdout) {
|
|
|
254
254
|
return { ok: true, answer: result.result }
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
/** Short CLI name for messages: "Codex CLI" -> "Codex". */
|
|
258
|
+
function shortLabel(label) {
|
|
259
|
+
return String(label ?? '官方 CLI').replace(/\s+CLI$/u, '')
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Explicit failure text when a CLI exited without writing anything to stdout
|
|
264
|
+
* or stderr (whitespace-only counts as nothing), instead of a generic
|
|
265
|
+
* "incomplete answer" message that hides that the CLI never produced output.
|
|
266
|
+
*/
|
|
267
|
+
export function emptyOutputError(label, exitCode) {
|
|
268
|
+
return `${shortLabel(label)} 退出码 ${exitCode ?? '未知'},无任何输出(stdout 与 stderr 均为空)。`
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** True when neither stream carries anything but whitespace. */
|
|
272
|
+
export function outputIsEmpty(stdout, stderr) {
|
|
273
|
+
return !String(stdout ?? '').trim() && !String(stderr ?? '').trim()
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** First non-empty diagnostic from a signed-runner result (an empty stderr must not hide stdout). */
|
|
277
|
+
export function verifiedDiagnostic(verified) {
|
|
278
|
+
for (const value of [verified?.detail, verified?.stderrTail, verified?.stdoutTail]) {
|
|
279
|
+
if (typeof value === 'string' && value.trim()) return value
|
|
280
|
+
}
|
|
281
|
+
return ''
|
|
282
|
+
}
|
|
283
|
+
|
|
257
284
|
function parseCodex(stdout) {
|
|
258
285
|
let answer = ''
|
|
259
286
|
let completed = false
|
|
@@ -695,7 +722,7 @@ export async function executeAssignedTask({
|
|
|
695
722
|
route, task: prompt, signal, adapter, preference, exitCode: verified.exitCode ?? null,
|
|
696
723
|
timedOut: verified.status === 'timed-out', attempted: true,
|
|
697
724
|
reason: verified.error || verified.reason || '官方 CLI 执行失败,已回退模型目录 API。',
|
|
698
|
-
detail: redactDiagnostic(verified
|
|
725
|
+
detail: redactDiagnostic(verifiedDiagnostic(verified), childEnvironment(adapter, credentials, credentialMode).secret),
|
|
699
726
|
raw: [verified.error, verified.reason, verified.detail, verified.stderrTail, verified.stdoutTail].filter(item => typeof item === 'string').join('\n'),
|
|
700
727
|
})
|
|
701
728
|
}
|
|
@@ -738,7 +765,9 @@ export async function executeAssignedTask({
|
|
|
738
765
|
raw: `${run.stdout.slice(-20_000)}\n${run.stderr.slice(-20_000)}`,
|
|
739
766
|
})
|
|
740
767
|
}
|
|
741
|
-
const parsed =
|
|
768
|
+
const parsed = outputIsEmpty(run.stdout, run.stderr)
|
|
769
|
+
? { ok: false, error: emptyOutputError(adapter.label, run.exitCode) }
|
|
770
|
+
: parseAdapterOutput(adapter.format, run.stdout)
|
|
742
771
|
if (!parsed.ok) {
|
|
743
772
|
return useApi(apiFallback, {
|
|
744
773
|
route, task: prompt, signal, adapter, preference, exitCode: run.exitCode, attempted: true,
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.3 — 2026-10-03
|
|
4
|
+
|
|
5
|
+
Bug-fix release for DeepSeek Harness Desktop 0.2.0-rc.1 / 0.2.0-rc.2, published under the npm `next` and `latest` tags.
|
|
6
|
+
|
|
7
|
+
**After updating, quit Harness completely (including the tray icon) and start it again.** A live patch reload does not replace plugin code that the running Host has already imported.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- On Harness Desktop for Windows, every official CLI run that went through the Harness process sandbox exited 0 with no output, so the step paused with "Codex 未返回完整成功终态和回答" and no model was called. The sandbox runner is started as `DeepSeek Harness.exe …/runner.js`, which needs `ELECTRON_RUN_AS_NODE=1`; the plugin's minimal CLI environment dropped it, so the executable started the desktop app instead, lost the single-instance lock and quit. The runner now gets that variable whenever it is the Electron executable.
|
|
11
|
+
- Codex cannot start inside the Harness Windows sandbox at all: it must write `CODEX_HOME` (`~/.codex`) and the sandbox denies those writes (`failed to initialize in-process app-server client: … (os error 5)`). On Windows, Codex now skips the Harness sandbox and starts directly with its own `--sandbox read-only`. This is the launch the "不经沙箱启动 CLI" confirmation already describes.
|
|
12
|
+
- A CLI that exits without writing anything to stdout or stderr is now reported as such, for example "Codex 退出码 0,无任何输出(stdout 与 stderr 均为空)。", instead of a generic "incomplete answer" message.
|
|
13
|
+
|
|
14
|
+
## 0.13.2 — 2026-10-03
|
|
15
|
+
|
|
16
|
+
Bug-fix release for DeepSeek Harness Desktop 0.2.0-rc.1 / 0.2.0-rc.2, published under the npm `next` and `latest` tags.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- Codex runs through the signed Windows runner failed in any workspace that is not a Git repository (for example a plain project folder chosen in the workbench). The step paused with "Codex 未返回完整成功终态和回答" and no model call was made. Codex 0.157.1 refuses such directories unless `--skip-git-repo-check` is passed (`Not inside a trusted directory and --skip-git-repo-check was not specified.`). The flag was only in the portable adapter; the signed runner now passes it too. Read-only runs stay confined by `--sandbox read-only` and the Harness process sandbox.
|
|
20
|
+
- When Codex exits without a successful turn, the error now names the cause: an untrusted directory, or no JSON events at all (with the last CLI output line). The pause detail no longer comes out empty when stderr is empty but stdout has output.
|
|
21
|
+
|
|
3
22
|
## 0.13.1 — 2026-10-03
|
|
4
23
|
|
|
5
24
|
Bug-fix release for DeepSeek Harness Desktop 0.2.0-rc.1 / 0.2.0-rc.2, published under the npm `next` and `latest` tags.
|
package/INSTALLATION_GUIDE.zh.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
| 需求 | 添加插件输入框 | 安装后的入口 |
|
|
10
10
|
| --- | --- | --- |
|
|
11
|
-
| 分析复杂度、按质量和费用选模型、调用官方工具 | `@ljwei-stak/dsh-model-router@0.13.
|
|
11
|
+
| 分析复杂度、按质量和费用选模型、调用官方工具 | `@ljwei-stak/dsh-model-router@0.13.3` | 模型路由 |
|
|
12
12
|
| 剧情、立绘、音乐、存档、自由对话 | `@ljwei-stak/dsh-galgame@0.1.0` | Gal 模块 |
|
|
13
13
|
| 两者都要 | 分别安装上面两个包 | 模型路由 + Gal 模块 |
|
|
14
14
|
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
2. 在“包名、GitHub 仓库地址或本地目录路径”输入框填一个完整包名,例如:
|
|
23
23
|
|
|
24
24
|
```text
|
|
25
|
-
@ljwei-stak/dsh-model-router@0.13.
|
|
25
|
+
@ljwei-stak/dsh-model-router@0.13.3
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
只想安装 GAL 时填写:
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
4. 核对预览的包名、版本和宿主兼容信息,安装并启用。有重启提示时重启桌面程序。
|
|
41
|
-
5. 检查插件详情与侧边栏:路由应为 **0.13.
|
|
41
|
+
5. 检查插件详情与侧边栏:路由应为 **0.13.3 / 模型路由**;GAL 应为 **0.1.0 / Gal 模块**。仅装路由时没有 GAL 入口是预期行为。
|
|
42
42
|
|
|
43
43
|
普通用户无需 `npm install -g`,该命令不会把插件注册到当前 Harness profile。
|
|
44
44
|
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
|
|
47
47
|
进入对应 Release 下载 `.tgz`:
|
|
48
48
|
|
|
49
|
-
- [模型路由 v0.13.
|
|
49
|
+
- [模型路由 v0.13.3](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.3)
|
|
50
50
|
- [独立 GAL v0.1.0](https://github.com/Alice-Marx/deepseek-harness-galgame/releases/tag/v0.1.0)
|
|
51
51
|
|
|
52
52
|
在“添加插件”填写下载文件的**绝对路径**,例如:
|
|
53
53
|
|
|
54
54
|
```text
|
|
55
|
-
D:\Plugins\ljwei-stak-dsh-model-router-0.13.
|
|
55
|
+
D:\Plugins\ljwei-stak-dsh-model-router-0.13.3.tgz
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
```text
|
|
@@ -62,7 +62,7 @@ D:\Plugins\ljwei-stak-dsh-galgame-0.1.0.tgz
|
|
|
62
62
|
如附有 `.sha256` 文件,用 PowerShell 计算并比较摘要:
|
|
63
63
|
|
|
64
64
|
```powershell
|
|
65
|
-
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-model-router-0.13.
|
|
65
|
+
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-model-router-0.13.3.tgz'
|
|
66
66
|
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-galgame-0.1.0.tgz'
|
|
67
67
|
```
|
|
68
68
|
|
|
@@ -72,7 +72,7 @@ Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-galgame-0
|
|
|
72
72
|
|
|
73
73
|
1. 在旧合并插件的 GAL 播放器导出需要保留的剧情进度,并备份整个 Harness profile。每份 JSON 仅保存**当前剧情状态**,不含所有手动槽、设置、已读记录或本地音乐;重要槽位可依次读档再导出。
|
|
74
74
|
2. 在**同一个 profile**安装独立 `@ljwei-stak/dsh-galgame@0.1.0`。
|
|
75
|
-
3. 0.13.0 起包名改为 `@ljwei-stak/dsh-model-router`(旧包名最后版本为 0.13.0,内容相同,之后不再更新):在插件管理器卸载原 `@ljwei-stak/model-router-galgame`(保留 profile 与应用数据),再添加 `@ljwei-stak/dsh-model-router@0.13.
|
|
75
|
+
3. 0.13.0 起包名改为 `@ljwei-stak/dsh-model-router`(旧包名最后版本为 0.13.0,内容相同,之后不再更新):在插件管理器卸载原 `@ljwei-stak/model-router-galgame`(保留 profile 与应用数据),再添加 `@ljwei-stak/dsh-model-router@0.13.3`。不要两个同时安装(条目 id 与工具名相同);条目 id 未变,路由设置与执行记录会保留。完成两项更新后再玩剧情,避免同时操作旧合并入口和新入口。
|
|
76
76
|
4. 现在路由与 GAL 各有一个入口。独立 GAL 沿用旧存档 localStorage 键,核对当前进度和三槽;更换 profile 或进度未恢复时,先切换到匹配剧目,再导入 JSON 备份。
|
|
77
77
|
5. 后续分别更新需要的插件;只用路由可以不启用或不安装 GAL。保留 profile 与应用数据,卸载插件时不要清理故事数据。
|
|
78
78
|
|
|
@@ -104,7 +104,7 @@ Claude、Codex、MiMo、Grok 支持只读或可编辑;Kimi、MiniMax、ZCode
|
|
|
104
104
|
| 检查 | 预期 |
|
|
105
105
|
| --- | --- |
|
|
106
106
|
| 宿主版本 | 0.2.0-rc.1 或 0.2.0-rc.2;包括 `rc` 后缀。 |
|
|
107
|
-
| 路由独立安装 | 0.13.
|
|
107
|
+
| 路由独立安装 | 0.13.3 详情、模型路由入口、目录和模型档案可用;不出现旧合并 GAL 入口。 |
|
|
108
108
|
| GAL 独立安装 | 0.1.0 详情、Gal 模块入口、标题与两部核心剧情可用;不要求安装路由。 |
|
|
109
109
|
| 共同安装 | 两个入口各一份,路由工具和 GAL 播放器均能使用。 |
|
|
110
110
|
| 存档迁移 | 同 profile 可读旧键;跨 profile 用匹配剧目 JSON 导入;旧篇目的数据不覆盖。 |
|
|
@@ -116,7 +116,7 @@ Claude、Codex、MiMo、Grok 支持只读或可编辑;Kimi、MiniMax、ZCode
|
|
|
116
116
|
|
|
117
117
|
## 8. 开发者从完整源码构建
|
|
118
118
|
|
|
119
|
-
路由仓库检出 `v0.13.
|
|
119
|
+
路由仓库检出 `v0.13.3`;GAL 仓库检出 `v0.1.0`。使用 Node.js **22.19+** 与 pnpm,各自在根目录运行:
|
|
120
120
|
|
|
121
121
|
```powershell
|
|
122
122
|
pnpm install --frozen-lockfile
|
package/MIGRATION.md
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
| 插件 | 安装输入 | 所属项目 |
|
|
6
6
|
| --- | --- | --- |
|
|
7
|
-
| 模型路由 | `@ljwei-stak/dsh-model-router@0.13.
|
|
7
|
+
| 模型路由 | `@ljwei-stak/dsh-model-router@0.13.3`(0.12.0 起独立;0.13.0 起改名) | [路由仓库](https://github.com/Alice-Marx/dsh-model-router);旧包名 `@ljwei-stak/model-router-galgame` 最后版本为 0.13.0(与新包 0.13.0 内容相同),之后不再更新。 |
|
|
8
8
|
| GAL | `@ljwei-stak/dsh-galgame@0.1.0` | [新 GAL 仓库](https://github.com/Alice-Marx/deepseek-harness-galgame);独立安装与更新。 |
|
|
9
9
|
|
|
10
10
|
路由 0.12.0 只注册**模型路由**侧边栏入口。剧情引擎、角色美术、音乐、存档与自由模式全部归独立 GAL;两个插件互不依赖。
|
|
11
11
|
|
|
12
12
|
## 0.13.0 包名变更
|
|
13
13
|
|
|
14
|
-
0.13.0 起 npm 包名由 `@ljwei-stak/model-router-galgame` 改为 **`@ljwei-stak/dsh-model-router`**。旧包名的最后版本是 0.13.0(`next`;`latest` 仍为 0.4.32),内容与新包 `@ljwei-stak/dsh-model-router@0.13.
|
|
14
|
+
0.13.0 起 npm 包名由 `@ljwei-stak/model-router-galgame` 改为 **`@ljwei-stak/dsh-model-router`**。旧包名的最后版本是 0.13.0(`next`;`latest` 仍为 0.4.32),内容与新包 `@ljwei-stak/dsh-model-router@0.13.3` 相同;旧包名之后不再更新,但不会被弃用或删除。已装旧包 0.13.0 的用户功能不缺,但应按下面步骤换到新包名以获得后续更新。
|
|
15
15
|
|
|
16
16
|
- 插件管理器把两者视为不同的包,不能原地“更新”:先卸载旧包(保留 profile 与应用数据),再添加新包。
|
|
17
17
|
- 不要同时安装:二者使用同一个 profile 条目 id `model-router-galgame` 和相同的 `model_router_*` 工具名。
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
1. **升级前备份**:旧 GAL 播放器导出需要保留的进度 JSON,并备份 Harness profile。JSON 保存当前剧情状态,不包含全部槽位、设置、已读记录或音乐;重要手动槽可依次读取后导出。
|
|
24
24
|
2. 在**同一个 Harness profile**安装 `@ljwei-stak/dsh-galgame@0.1.0`。
|
|
25
|
-
3. 在官方插件管理器卸载原包 `@ljwei-stak/model-router-galgame`,再添加 `@ljwei-stak/dsh-model-router@0.13.
|
|
25
|
+
3. 在官方插件管理器卸载原包 `@ljwei-stak/model-router-galgame`,再添加 `@ljwei-stak/dsh-model-router@0.13.3`。完成两项安装后再打开剧情,避免并行使用旧合并 GAL 与新 GAL 入口。
|
|
26
26
|
4. 核对只有一个**模型路由**和一个**Gal 模块**入口。打开独立 GAL 检查当前进度、三槽及设置;同 profile 继续使用原 localStorage 键。
|
|
27
27
|
5. 若使用不同 profile 或没有读到进度,在 GAL 选择匹配剧目,再导入保存的 JSON。导入上限 **2 MB**,确认后替换当前剧情进度。
|
|
28
28
|
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[简体中文说明](README.zh.md) · [Installation guide (Chinese)](INSTALLATION_GUIDE.zh.md) · [Migration guide](MIGRATION.md) · [GAL repository](https://github.com/Alice-Marx/deepseek-harness-galgame)
|
|
8
8
|
|
|
9
|
-
> **Host compatibility:** both the router 0.13.
|
|
9
|
+
> **Host compatibility:** both the router 0.13.3 and GAL 0.1.0 target DeepSeek Harness Desktop **0.2.0-rc.1 and 0.2.0-rc.2**. Use the exact installation versions below. Releases use npm's `next` tag while this host is a prerelease; a bare package name or a moving tag is not a version pin.
|
|
10
10
|
|
|
11
11
|

|
|
12
12
|
|
|
@@ -35,7 +35,7 @@ In **DeepSeek Harness Desktop → Plugins → Add plugin**, enter one exact pack
|
|
|
35
35
|
|
|
36
36
|
| What you want | Installation input | Repository |
|
|
37
37
|
| --- | --- | --- |
|
|
38
|
-
| Model routing and official tools | `@ljwei-stak/dsh-model-router@0.13.
|
|
38
|
+
| Model routing and official tools | `@ljwei-stak/dsh-model-router@0.13.3` | [Model Router](https://github.com/Alice-Marx/dsh-model-router) |
|
|
39
39
|
| GAL only, or GAL alongside the router | `@ljwei-stak/dsh-galgame@0.1.0` | [DeepSeek Harness GAL](https://github.com/Alice-Marx/deepseek-harness-galgame) |
|
|
40
40
|
|
|
41
41
|
For npm installation, select the official **HTTPS** source `https://registry.npmjs.org/` if a mirror has not synchronized the exact version. Install, enable, and restart when prompted. Router details should show **0.13.0** and its sidebar **Model Router**; the separate GAL package adds **Gal Module**. Either package can be installed without the other. Global `npm install -g` does not register a plugin in your Desktop profile.
|
|
@@ -45,30 +45,30 @@ For npm installation, select the official **HTTPS** source `https://registry.npm
|
|
|
45
45
|
The package was renamed in 0.13.0. The old name's last version is also 0.13.0, with identical content, so future updates only come under the new name. The plugin manager cannot update the old entry in place:
|
|
46
46
|
|
|
47
47
|
1. Remove `@ljwei-stak/model-router-galgame` in the plugin manager (keep profile and application data).
|
|
48
|
-
2. Add `@ljwei-stak/dsh-model-router@0.13.
|
|
48
|
+
2. Add `@ljwei-stak/dsh-model-router@0.13.3` and restart when prompted.
|
|
49
49
|
3. Do not keep both installed: they share the profile entry id `model-router-galgame` and the `model_router_*` tool names. Because the entry id is unchanged, router settings saved in the profile and the run history in `~/.dsh/model-router/state.json` carry over.
|
|
50
50
|
|
|
51
51
|
### Upgrade from the combined 0.11.x plugin
|
|
52
52
|
|
|
53
53
|
1. Before upgrading, use the old GAL player's **Export save** for each story progress you want to keep, and back up the Harness profile. A JSON export contains the current story state, not all slots, settings, read history, or local audio.
|
|
54
54
|
2. Install `@ljwei-stak/dsh-galgame@0.1.0` in the **same profile**.
|
|
55
|
-
3. Remove the old `@ljwei-stak/model-router-galgame` plugin and add `@ljwei-stak/dsh-model-router@0.13.
|
|
55
|
+
3. Remove the old `@ljwei-stak/model-router-galgame` plugin and add `@ljwei-stak/dsh-model-router@0.13.3` (see above). Finish both installations before continuing play; this removes the old combined GAL entry and leaves one entry from the independent GAL plugin.
|
|
56
56
|
4. Open the new GAL entry and verify your progress. The standalone plugin retains the old localStorage keys in the same profile. For a different profile or a missing state, select the matching story and import the JSON backup.
|
|
57
57
|
|
|
58
58
|
The standalone GAL core contains **Echo City: Main Saga** and **Old City Migration: The Unfinished Promise**. Previously separated stories remain in their source archive and are not shipped with either core plugin. See [migration notes](MIGRATION.md) for save limitations and older desktop integrations.
|
|
59
59
|
|
|
60
60
|
### Install a versioned release archive
|
|
61
61
|
|
|
62
|
-
Download the `.tgz` attachment from the [router v0.13.0 release](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.
|
|
62
|
+
Download the `.tgz` attachment from the [router v0.13.0 release](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.3) or [GAL v0.1.0 release](https://github.com/Alice-Marx/deepseek-harness-galgame/releases/tag/v0.1.0). Enter the downloaded file's absolute path, for example:
|
|
63
63
|
|
|
64
64
|
```text
|
|
65
|
-
D:\Plugins\ljwei-stak-dsh-model-router-0.13.
|
|
65
|
+
D:\Plugins\ljwei-stak-dsh-model-router-0.13.3.tgz
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
Where a checksum sidecar is supplied, compare it with:
|
|
69
69
|
|
|
70
70
|
```powershell
|
|
71
|
-
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-model-router-0.13.
|
|
71
|
+
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-model-router-0.13.3.tgz'
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
You can also extract the archive and enter its inner `package` directory, which contains `package.json` and `.dsh-plugin`. The download may be stored on your preferred drive; runtime data location is controlled by the Harness profile. Upgrade through the plugin manager without modifying `app.asar` or bypassing dependency checks.
|
|
@@ -77,7 +77,9 @@ You can also extract the archive and enter its inner `package` directory, which
|
|
|
77
77
|
|
|
78
78
|
| Version | Intended host | Scope |
|
|
79
79
|
| --- | --- | --- |
|
|
80
|
-
| **Router 0.13.
|
|
80
|
+
| **Router 0.13.3** | **0.2.0-rc.1 / 0.2.0-rc.2** | Official CLI runs work on Harness Desktop for Windows (sandbox runner environment; Codex uses its own read-only sandbox). Restart Harness fully after updating. Exact npm version, `@next` or `@latest`. |
|
|
81
|
+
| [Router 0.13.2](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.2) | 0.2.0-rc.1 / 0.2.0-rc.2 | Codex in non-Git workspaces; sandboxed CLI runs on Desktop for Windows still produced no output. |
|
|
82
|
+
| [Router 0.13.1](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.1) | 0.2.0-rc.1 / 0.2.0-rc.2 | Fixed `cannot get property "credentials" without inject`; Codex refused non-Git workspaces on Windows. |
|
|
81
83
|
| [Router 0.13.0](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.0) | 0.2.0-rc.1 / 0.2.0-rc.2 | Health check, cost control, subscription-first billing, run history; runs fail in the Harness (fixed in 0.13.1). |
|
|
82
84
|
| **GAL 0.1.0** | **0.2.0-rc.1 / 0.2.0-rc.2** | First standalone GAL package, two core stories. Exact npm version or `@next`. |
|
|
83
85
|
| [Router 0.12.0](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.12.0) | 0.2.0-rc.1 / 0.2.0-rc.2 | First independent router release (GAL split out). |
|
package/README.zh.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[English](README.md) · [安装与验证指南](INSTALLATION_GUIDE.zh.md) · [迁移说明](MIGRATION.md) · [独立 GAL 仓库](https://github.com/Alice-Marx/deepseek-harness-galgame)
|
|
8
8
|
|
|
9
|
-
> **宿主版本:**模型路由 0.13.
|
|
9
|
+
> **宿主版本:**模型路由 0.13.3 与 GAL 0.1.0 均声明支持 DeepSeek Harness Desktop **0.2.0-rc.1 和 0.2.0-rc.2**。宿主仍是预发布版本,本轮发布使用 npm `next` 标签;推荐精确版本安装,不要依赖裸包名或不断变化的标签。
|
|
10
10
|
|
|
11
11
|

|
|
12
12
|
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
|
|
35
35
|
| 安装内容 | 输入框填写 | GitHub 仓库 |
|
|
36
36
|
| --- | --- | --- |
|
|
37
|
-
| 模型路由、模型档案与官方工具 | `@ljwei-stak/dsh-model-router@0.13.
|
|
37
|
+
| 模型路由、模型档案与官方工具 | `@ljwei-stak/dsh-model-router@0.13.3` | [Model Router](https://github.com/Alice-Marx/dsh-model-router) |
|
|
38
38
|
| GAL 剧情、自由模式与播放器 | `@ljwei-stak/dsh-galgame@0.1.0` | [DeepSeek Harness GAL](https://github.com/Alice-Marx/deepseek-harness-galgame) |
|
|
39
39
|
|
|
40
40
|
1. npm 安装源选择官方 **HTTPS** 地址 `https://registry.npmjs.org/`;国内镜像尚未同步时可改用此源或版本化 GitHub 安装包。
|
|
41
41
|
2. 核对安装预览版本与宿主版本,安装并启用;有重启提示时重启。
|
|
42
|
-
3. 路由详情应为 **0.13.
|
|
42
|
+
3. 路由详情应为 **0.13.3**,侧边栏显示 **模型路由**;独立 GAL 详情应为 **0.1.0**,另显示 **Gal 模块**。
|
|
43
43
|
|
|
44
44
|
普通使用不需要 `npm install -g`:全局 npm 安装不会注册到当前 Harness profile。路由与 GAL 都可以不安装另一插件而运行。
|
|
45
45
|
|
|
@@ -49,30 +49,30 @@
|
|
|
49
49
|
0.13.0 起包名改为 `@ljwei-stak/dsh-model-router`。旧包名的最后版本同样是 0.13.0,内容相同,之后的更新只发布到新包名。插件管理器无法原地更新旧条目:
|
|
50
50
|
|
|
51
51
|
1. 在插件管理器卸载 `@ljwei-stak/model-router-galgame`(保留 profile 与应用数据)。
|
|
52
|
-
2. 添加 `@ljwei-stak/dsh-model-router@0.13.
|
|
52
|
+
2. 添加 `@ljwei-stak/dsh-model-router@0.13.3`,按提示重启。
|
|
53
53
|
3. 不要两个同时安装:二者使用相同的 profile 条目 id `model-router-galgame` 和相同的 `model_router_*` 工具名。条目 id 未变,所以 profile 中保存的路由设置以及 `~/.dsh/model-router/state.json` 里的执行记录会保留。
|
|
54
54
|
|
|
55
55
|
### 从合并版 0.11.x 升级
|
|
56
56
|
|
|
57
57
|
1. **先备份**:旧版 GAL 中对需要保留的剧情进度使用“导出存档”,并备份 Harness profile。JSON 仅包含当前剧情状态,不包含全部手动槽、设置、已读记录与本地音乐。
|
|
58
58
|
2. 在**同一个 profile**安装 `@ljwei-stak/dsh-galgame@0.1.0`。
|
|
59
|
-
3. 在插件管理器卸载原 `@ljwei-stak/model-router-galgame`,再添加 `@ljwei-stak/dsh-model-router@0.13.
|
|
59
|
+
3. 在插件管理器卸载原 `@ljwei-stak/model-router-galgame`,再添加 `@ljwei-stak/dsh-model-router@0.13.3`(见上文“从旧包名升级”)。完成两项安装后再游玩;旧合并插件的 GAL 入口随路由升级移除,只留下新 GAL 插件的入口。
|
|
60
60
|
4. 打开独立 GAL 检查进度。它保留原 localStorage 存档键;更换 profile 或没有读到旧进度时,先选择对应剧目,再导入备份 JSON。
|
|
61
61
|
|
|
62
62
|
独立 GAL 核心只内置**《回声之城·正篇》**和**《旧城迁移篇:未写完的约定》**。此前分出的其他篇目保留在源代码归档,不随这两个核心插件发布。完整迁移步骤见[迁移说明](MIGRATION.md)。
|
|
63
63
|
|
|
64
64
|
### 使用 GitHub 安装包
|
|
65
65
|
|
|
66
|
-
从[路由 v0.13.0 Release](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.
|
|
66
|
+
从[路由 v0.13.0 Release](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.3)或[GAL v0.1.0 Release](https://github.com/Alice-Marx/deepseek-harness-galgame/releases/tag/v0.1.0)下载 `.tgz`,在添加插件输入框填写文件绝对路径,例如:
|
|
67
67
|
|
|
68
68
|
```text
|
|
69
|
-
D:\Plugins\ljwei-stak-dsh-model-router-0.13.
|
|
69
|
+
D:\Plugins\ljwei-stak-dsh-model-router-0.13.3.tgz
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
如附有 `.sha256` 校验文件,使用以下命令计算摘要并比较:
|
|
73
73
|
|
|
74
74
|
```powershell
|
|
75
|
-
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-model-router-0.13.
|
|
75
|
+
Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-model-router-0.13.3.tgz'
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
也可解压并填写内层含 `package.json` 和 `.dsh-plugin` 的 `package` 目录。安装包可放到自选磁盘;运行数据位置由宿主 profile 决定。不要改 `app.asar` 或绕过依赖检查。
|
|
@@ -81,7 +81,9 @@ Get-FileHash -Algorithm SHA256 -LiteralPath 'D:\Plugins\ljwei-stak-dsh-model-rou
|
|
|
81
81
|
|
|
82
82
|
| 版本 | 声明的宿主 | 功能范围 |
|
|
83
83
|
| --- | --- | --- |
|
|
84
|
-
| **模型路由 0.13.
|
|
84
|
+
| **模型路由 0.13.3** | **0.2.0-rc.1 / rc.2** | 修复 Windows 版 Harness Desktop 中官方 CLI 执行无输出(沙箱启动器环境;Codex 改用自带只读沙箱)。更新后请完全重启 Harness。推荐精确版本,也可用 `@next` / `@latest`。 |
|
|
85
|
+
| [模型路由 0.13.2](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.2) | 0.2.0-rc.1 / rc.2 | Codex 支持非 Git 工作区;Windows Desktop 中经沙箱的 CLI 执行仍无输出。 |
|
|
86
|
+
| [模型路由 0.13.1](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.1) | 0.2.0-rc.1 / rc.2 | 修复 `cannot get property "credentials" without inject`;Windows 上 Codex 拒绝非 Git 工作区。 |
|
|
85
87
|
| [模型路由 0.13.0](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.13.0) | 0.2.0-rc.1 / rc.2 | 体检、成本控制、订阅优先、执行记录;在 Harness 中执行会失败(0.13.1 已修复)。 |
|
|
86
88
|
| **GAL 0.1.0** | **0.2.0-rc.1 / rc.2** | 独立 GAL 首版,两部核心剧目。推荐精确版本。 |
|
|
87
89
|
| [模型路由 0.12.0](https://github.com/Alice-Marx/dsh-model-router/releases/tag/v0.12.0) | 0.2.0-rc.1 / rc.2 | 首个独立路由版本(GAL 拆出)。 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ljwei-stak/dsh-model-router",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Model Router for official DeepSeek Harness Desktop: cost-aware task routing, dependent work packages and official vendor CLI discovery, installation and execution. GAL is available separately as @ljwei-stak/dsh-galgame.",
|
|
6
6
|
"repository": {
|