@whyshu/argent 0.1.5 → 0.1.7

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/bin/argent.mjs CHANGED
@@ -16,6 +16,7 @@ import { homedir } from 'node:os';
16
16
  import {
17
17
  DSH_EXACT_VERSION, PROFILE_NAME, PROD_BUNDLES, buildLaunchdPlist, buildProfile, dshHomeOf, runnerScriptPath,
18
18
  depsInstalled, health, installDeps, loginWithPhone, pairRunner, probeDshVersion, readAuthToken, repoRoot, runnerConfigPath, sendLoginCode, versionMatches,
19
+ engineRoot, materializeRuntime,
19
20
  } from '../lib/index.mjs';
20
21
 
21
22
  const argv = process.argv.slice(2);
@@ -26,9 +27,9 @@ const DRY_RUN = has('--dry-run');
26
27
 
27
28
  const command = (() => {
28
29
  const positional = argv.filter((a) => !a.startsWith('--') && !['-h'].includes(a));
29
- const i = argv.findIndex((a) => a === 'web' || a === 'health' || a === 'setup' || a === 'pair' || a === 'login' || a === 'service');
30
+ const i = argv.findIndex((a) => a === 'web' || a === 'health' || a === 'setup' || a === 'pair' || a === 'login' || a === 'service' || a === 'runtime');
30
31
  if (i < 0) return '';
31
- if (argv[i] === 'service') return `service ${argv[i + 1] || ''}`.trim();
32
+ if (argv[i] === 'service' || argv[i] === 'runtime') return `${argv[i]} ${argv[i + 1] || ''}`.trim();
32
33
  return argv[i];
33
34
  })();
34
35
 
@@ -37,6 +38,8 @@ const opts = {
37
38
  profile: val('--profile', PROFILE_NAME),
38
39
  repo: repoRoot({ repo: val('--repo') }),
39
40
  port: Number(val('--port', '3080')) || 3080,
41
+ target: val('--target', join(homedir(), '.argent-dsh')),
42
+ skillsTarget: has('--no-skills') ? '' : val('--skills-target', join(dshHomeOf(val('--dsh-home')), 'skills')),
40
43
  extraBundles: (() => { const raw = val('--bundles', '').split(',').map((x) => x.trim()).filter(Boolean); return raw.flatMap((x) => (x === 'prod' ? PROD_BUNDLES : [x])); })(),
41
44
  };
42
45
 
@@ -179,6 +182,23 @@ function setupCommand() {
179
182
  print({ ok: true, profile: built.dir, bundles: built.bundles.join(', '), plugins: built.plugins.join(', '), preset: built.preset, depsInstalled: depsInstalled(opts.dshHome, opts.profile) });
180
183
  }
181
184
 
185
+ function runtimeCommand(sub) {
186
+ const engine = engineRoot();
187
+ if (!engine) { console.error('❌ 未找到 @whyshu/argent-engine;请用新版启动器(npm 依赖应随包安装)'); process.exit(2); }
188
+ const version = readFileSync(join(engine, 'VERSION'), 'utf8').trim();
189
+ if (sub === 'status' || sub === '') {
190
+ let current = null;
191
+ try { current = JSON.parse(readFileSync(join(opts.target, 'RUNTIME_VERSION.json'), 'utf8')); } catch { current = null; }
192
+ print({ ok: true, engine, engineVersion: version, target: opts.target, current: current ? current.version : null, installed: Boolean(current) });
193
+ return;
194
+ }
195
+ if (sub !== 'install') { console.error('用法:argent runtime install|status [--target <dir>] [--dry-run]'); process.exit(2); }
196
+ if (DRY_RUN) { print({ ok: true, dryRun: true, engine, version, target: opts.target, action: 'materialize runtime files' }); return; }
197
+ const r = materializeRuntime({ target: opts.target, engine, skillsTarget: opts.skillsTarget });
198
+ if (!r.ok) { console.error(`❌ runtime 安装失败:${r.message}`); process.exit(2); }
199
+ print({ ok: true, package: '@whyshu/argent-engine', version: r.version, files: r.files, skillsFiles: r.skillsFiles, target: r.target, skillsTarget: r.skillsTarget, backupDir: r.backupDir });
200
+ }
201
+
182
202
  function serviceCommand(sub) {
183
203
  const bundled = runnerScriptPath({ repo: opts.repo });
184
204
  // 固定 runner 路径:复制进 DSH_HOME,避免 launchd 指向 npx 临时缓存(缓存清理后失效)
@@ -218,13 +238,14 @@ function serviceCommand(sub) {
218
238
 
219
239
  const main = async () => {
220
240
  if (!command || has('-h') || has('--help')) {
221
- console.log('用法:argent <web|health|setup|login|pair|service install|service uninstall> [--dsh-home <dir>] [--json] [--dry-run]');
241
+ console.log('用法:argent <web|health|setup|login|pair|runtime install|runtime status|service install|service uninstall> [--dsh-home <dir>] [--target <dir>] [--skills-target <dir>|--no-skills] [--json] [--dry-run]');
222
242
  process.exit(command ? 0 : 2);
223
243
  }
224
244
  if (command === 'health') return healthCommand();
225
245
  if (command === 'setup') return setupCommand();
226
246
  if (command === 'pair') return pairCommand();
227
247
  if (command === 'login') return loginCommand();
248
+ if (command === 'runtime install' || command === 'runtime status') return runtimeCommand(command.split(' ')[1]);
228
249
  if (command === 'service install' || command === 'service uninstall') return serviceCommand(command.split(' ')[1]);
229
250
  return webCommand();
230
251
  };
package/lib/index.mjs CHANGED
@@ -8,7 +8,7 @@
8
8
  * · 状态自检(版本/profile/runner 配置/端口)。
9
9
  * ⛔ 不读写任何凭据内容(runner.json 由首跑引导写,权限 600)。
10
10
  */
11
- import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from 'node:fs';
11
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync, cpSync, readdirSync } from 'node:fs';
12
12
  import { spawnSync } from 'node:child_process';
13
13
  import { homedir, hostname as osHostname } from 'node:os';
14
14
  import { dirname, join, resolve } from 'node:path';
@@ -83,6 +83,70 @@ export const PUBLISHED_BUNDLE_VERSIONS = {
83
83
  '@linxin666/dsh-client-ui-task-board': '0.4.7',
84
84
  };
85
85
 
86
+
87
+ /** 发布模式随启动器安装的 runtime(@whyshu/argent-engine)根目录;本地联调回退 dist。 */
88
+ export function engineRoot({ env = process.env, launcherLib = dirname(fileURLToPath(import.meta.url)) } = {}) {
89
+ const candidates = [];
90
+ if (env.ARGENT_ENGINE_ROOT) candidates.push(resolve(env.ARGENT_ENGINE_ROOT));
91
+ // npx/global 安装:node_modules/@whyshu/argent-engine/engine
92
+ candidates.push(resolve(launcherLib, '..', '..', '..', '@whyshu', 'argent-engine', 'engine'));
93
+ candidates.push(resolve(launcherLib, '..', '..', 'node_modules', '@whyshu', 'argent-engine', 'engine'));
94
+ // 本地仓库联调:dist/argent-engine/engine
95
+ candidates.push(resolve(launcherLib, '..', '..', 'dist', 'argent-engine', 'engine'));
96
+ for (const c of candidates) {
97
+ if (existsSync(join(c, 'scripts')) && existsSync(join(c, 'VERSION'))) return c;
98
+ }
99
+ return '';
100
+ }
101
+
102
+ function walkFiles(dir, base = dir) {
103
+ const out = [];
104
+ for (const e of readdirSync(dir)) {
105
+ const p = join(dir, e);
106
+ const rel = p.slice(base.length + 1).split('\\').join('/');
107
+ const st = statSync(p);
108
+ if (st.isDirectory()) out.push(...walkFiles(p, base));
109
+ else out.push(rel);
110
+ }
111
+ return out;
112
+ }
113
+
114
+ /**
115
+ * 把 npm runtime 包物化到客户机既有资产目录(默认 ~/.argent-dsh)。
116
+ * 只覆盖 engine 包内的文件;客户配置/凭据/.git 不动;被覆盖文件先备份。
117
+ */
118
+ export function materializeRuntime({ target = join(homedir(), '.argent-dsh'), engine = engineRoot(), skillsTarget = '', now = new Date() } = {}) {
119
+ if (!engine) return { ok: false, code: 'engine_missing', message: '未找到 @whyshu/argent-engine(启动器依赖未安装)' };
120
+ if (!existsSync(target)) mkdirSync(target, { recursive: true });
121
+ const version = readFileSync(join(engine, 'VERSION'), 'utf8').trim();
122
+ const stamp = now.toISOString().replace(/[:.]/g, '-');
123
+ const backupDir = join(target, '.runtime-backup', stamp);
124
+ const files = walkFiles(engine);
125
+ let copied = 0;
126
+ const copyFile = (src, dst, rel) => {
127
+ if (existsSync(dst)) {
128
+ const b = join(backupDir, rel);
129
+ mkdirSync(dirname(b), { recursive: true });
130
+ cpSync(dst, b);
131
+ }
132
+ mkdirSync(dirname(dst), { recursive: true });
133
+ cpSync(src, dst);
134
+ copied += 1;
135
+ };
136
+ for (const rel of files) copyFile(join(engine, rel), join(target, rel), rel);
137
+ let skillsFiles = 0;
138
+ if (skillsTarget) {
139
+ const skillsSrc = join(engine, 'skills');
140
+ if (existsSync(skillsSrc)) {
141
+ for (const rel of walkFiles(skillsSrc)) copyFile(join(skillsSrc, rel), join(skillsTarget, rel), `skills/${rel}`);
142
+ skillsFiles = walkFiles(skillsSrc).length;
143
+ }
144
+ }
145
+ mkdirSync(join(target, '.runtime-backup'), { recursive: true });
146
+ writeFileSync(join(target, 'RUNTIME_VERSION.json'), JSON.stringify({ package: '@whyshu/argent-engine', version, installedAt: now.toISOString(), files: copied, skillsFiles, skillsTarget: skillsTarget || null, backupDir }, null, 2) + '\n');
147
+ return { ok: true, version, files: copied, skillsFiles, target, skillsTarget, backupDir };
148
+ }
149
+
86
150
  export function profileDir(dshHome, profile = PROFILE_NAME) {
87
151
  return join(dshHome, 'profiles', profile);
88
152
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whyshu/argent",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Argent 启动器:一条命令启动「打包好的 dsh + Argent 插件/角色预设」,并管理本机 runner 常驻。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,8 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@deepseek-ai/dsh": "0.2.1-rc.2"
17
+ "@deepseek-ai/dsh": "0.2.1-rc.2",
18
+ "@whyshu/argent-engine": "0.7.4"
18
19
  },
19
20
  "files": [
20
21
  "bin/",