dsh-model 0.21.1 → 0.21.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/README.en.md CHANGED
@@ -42,7 +42,7 @@ On a dsh-vps server, use `sudo dsh-model setup`. On Windows, run it in a normal
42
42
  `setup` is safe to re-run. It:
43
43
 
44
44
  1. downloads and verifies the engine and runs it on `127.0.0.1:8317/v1`, with key auth enforced;
45
- 2. connects OpenCode Zen (enter your key; it is tested before being saved) and WorkBuddy (dsh-model's own bridge);
45
+ 2. connects WorkBuddy (dsh-model's own bridge). Setup asks for no keys: turn on OpenCode Zen and other key-based sources from the management page when you need them;
46
46
  3. installs the management page into dsh and syncs the models into dsh;
47
47
  4. on a VPS, also opens a public address `https://<dsh's domain>:9443/v1` (or `<IP>.sslip.io` when there is no domain).
48
48
 
package/README.md CHANGED
@@ -42,7 +42,7 @@ dsh-model setup
42
42
  `setup` 可以重复执行,它会依次:
43
43
 
44
44
  1. 下载并校验引擎,在本机 `127.0.0.1:8317/v1` 上运行,强制 key 鉴权;
45
- 2. 接入 OpenCode Zen(输入你的 key,先实测再保存)和 WorkBuddy(dsh-model 自己的 bridge);
45
+ 2. 接入 WorkBuddy(dsh-model 自己的 bridge)。安装时不问任何 key,OpenCode Zen 等要 key 的来源,需要时在管理页里打开;
46
46
  3. 把管理页装进 dsh,把模型同步进 dsh;
47
47
  4. 在 VPS 上,额外开通对外地址 `https://<dsh 的域名>:9443/v1`(没有域名时用 `<IP>.sslip.io`)。
48
48
 
@@ -17,7 +17,7 @@ import { ensureDir } from '../util/fs.js';
17
17
  import { bold, info, next, ok, skip, warn } from '../util/output.js';
18
18
  import { findFreePort, isPortFree } from '../util/port.js';
19
19
  import { detectProxy, normalizeProxyUrl, redactProxy } from '../util/proxy.js';
20
- import { askOpencodeKey, configureOpencode } from './opencode.js';
20
+ import { configureOpencode } from './opencode.js';
21
21
  import { opencodeConfigured } from '../integrations/opencode.js';
22
22
  import { ensureDaemon } from '../daemon/service.js';
23
23
  import { installDshPlugin } from '../integrations/dshplugin.js';
@@ -26,8 +26,6 @@ import { installAdmin } from '../service/admin.js';
26
26
  import { DEFAULT_PUBLIC_PORT, publicHost } from '../remote/public.js';
27
27
  export async function setup(ctx, opts) {
28
28
  requireRootInVps(ctx);
29
- // 要问的先问完再拿锁:等你输入时不占着锁,dsh 管理页照常能用(实测:卡在问 key 时页面新增 key 报"另一个命令正在运行")
30
- const opencodeKey = opts.skipOpencode || (await opencodeConfigured(ctx)) ? undefined : await askOpencodeKey();
31
29
  return withLock(ctx, async () => {
32
30
  const all = await loadAll(ctx);
33
31
  await ensureDir(ctx.paths.home, { owner: ctx.owner });
@@ -75,8 +73,11 @@ export async function setup(ctx, opts) {
75
73
  info(bold('OpenCode Zen'));
76
74
  if (opts.skipOpencode)
77
75
  skip(L('已跳过(--skip-opencode)', 'Skipped (--skip-opencode)'));
76
+ // 安装时不问 key:要用的话在 dsh「设置 → dsh-model → 来源」里填,或执行 dsh-model opencode key
77
+ else if (await opencodeConfigured(ctx))
78
+ await step('opencode', () => configureOpencode(ctx, all));
78
79
  else
79
- await step('opencode', () => configureOpencode(ctx, all, opencodeKey !== undefined ? { key: opencodeKey } : {}));
80
+ skip(L('没填 key,跳过;需要时在 dsh「设置 → dsh-model → 来源」里打开它(或执行 dsh-model opencode key)', 'No key, skipped; when you need it, turn it on in dsh Settings → dsh-model → Sources (or run dsh-model opencode key)'));
80
81
  info('');
81
82
  info(bold('WorkBuddy'));
82
83
  if (opts.skipWorkbuddy)
@@ -1,5 +1,6 @@
1
1
  // service/launchd.ts — macOS 用户级 LaunchAgent(RunAtLoad + KeepAlive)
2
2
  import { rm } from 'node:fs/promises';
3
+ import { info } from '../util/output.js';
3
4
  import { DshModelError } from '../errors.js';
4
5
  import { L } from '../i18n.js';
5
6
  import { run } from '../util/exec.js';
@@ -41,11 +42,25 @@ ${envBlock} <key>WorkingDirectory</key>
41
42
  export function launchd(spec) {
42
43
  const domain = `gui/${process.getuid?.() ?? 501}`;
43
44
  const target = `${domain}/${spec.label}`;
45
+ /**
46
+ * 被关掉的后台服务(系统设置「登录项 → 允许在后台」被关,或清理软件关的)重新允许:
47
+ * 只动 dsh-model 自己的两个服务,用户点「修复」/ 执行 setup 就是要它们跑起来(2026-10-14 实测:被关后 bootstrap 报 5: Input/output error)。
48
+ */
49
+ const reenable = async () => {
50
+ const r = await run('launchctl', ['print-disabled', domain]);
51
+ if (!new RegExp(`"${spec.label.replace(/\./g, '\\.')}" => (disabled|true)`).test(r.stdout))
52
+ return false;
53
+ await run('launchctl', ['enable', target]);
54
+ info(L(`${spec.label} 之前被 macOS 关掉了后台运行,已重新允许`, `${spec.label} had background running turned off in macOS; allowed it again`));
55
+ return true;
56
+ };
57
+ const loaded = async () => (await run('launchctl', ['print', target])).code === 0;
44
58
  const bootstrap = async () => {
59
+ await reenable();
45
60
  const r = await run('launchctl', ['bootstrap', domain, spec.file]);
46
- // 已加载时返回 5 / 37("service already loaded"),当成功
47
- if (r.code !== 0 && !/already|in progress|5:|37:/i.test(r.stderr)) {
48
- throw new DshModelError('service_failed', L(`launchctl bootstrap 失败:${r.stderr.trim()}`, `launchctl bootstrap failed: ${r.stderr.trim()}`));
61
+ // 已经加载过会报错(5 / 37 等):不看错误码,直接看它到底加载上没有
62
+ if (r.code !== 0 && !(await loaded())) {
63
+ throw new DshModelError('service_failed', L(`后台服务 ${spec.label} 没能加载:${r.stderr.trim()}`, `Could not load background service ${spec.label}: ${r.stderr.trim()}`), L('看一下「系统设置 → 通用 → 登录项与扩展 → 允许在后台」里它是否被关掉了', 'Check System Settings → General → Login Items & Extensions → Allow in the Background'));
49
64
  }
50
65
  };
51
66
  const bootout = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-model",
3
- "version": "0.21.1",
3
+ "version": "0.21.3",
4
4
  "description": "Many model sources behind one authenticated OpenAI-compatible endpoint for DeepSeek Harness (dsh) and your tools: WorkBuddy, OpenCode Zen and your CLI subscriptions (Codex, Kimi…), with a management page inside dsh. 多家模型汇成一个 OpenAI 兼容地址,dsh 和其他软件都能直接用。",
5
5
  "keywords": [
6
6
  "dsh-plugin",