dsh-agentone 0.5.6 → 0.5.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/lib/index.js +47 -8
- package/lib/page.js +40 -3
- package/lib/proc.js +68 -2
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -32,7 +32,7 @@ import { applyPlatformModel, removePlatformModel } from './model.js';
|
|
|
32
32
|
import { installPlatformSkill, listPlatformSkills, removePlatformSkill } from './skill.js';
|
|
33
33
|
import { platformFetch } from './http.js';
|
|
34
34
|
import { donePageHtml, statusPageHtml } from './page.js';
|
|
35
|
-
import { dshPluginCli, pnpmViewLatest,
|
|
35
|
+
import { dshPluginCli, probeCliDetail, pnpmViewLatest, upgradeCliTool } from './proc.js';
|
|
36
36
|
|
|
37
37
|
import { clearCredentials, loadCredentials, resolveDshHome, saveCredentials, updateCredentials } from './store.js';
|
|
38
38
|
|
|
@@ -218,7 +218,22 @@ function specLabel(spec) {
|
|
|
218
218
|
return '';
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
/** dsh
|
|
221
|
+
/** dsh 插件与 CLI 操作白名单:用户输入不得进入 execFile 的 tool 位。 */
|
|
222
|
+
const CLI_TOOLS = new Set(['lark-cli', 'ccpg-cli']);
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 插件自身是否由平台托管镜像管理:镜像 Dockerfile 固有 ENV
|
|
226
|
+
* `DSH_FORWARDER_LISTEN_PORT`(forwarder 是镜像特有组件,独立桌面版不存在)。
|
|
227
|
+
* 托管镜像内插件版本随镜像走,禁自助升级;独立 dsh(用户自装)没有镜像
|
|
228
|
+
* 通道,允许在插件页自助升级 —— 否则用户会被卡在旧版只能命令行破局。
|
|
229
|
+
*/
|
|
230
|
+
function isSelfManaged() {
|
|
231
|
+
return Boolean(process.env.DSH_FORWARDER_LISTEN_PORT);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* dsh 官方 in-box bundle:profile 模板自带,不是用户可管理的插件。
|
|
236
|
+
*/
|
|
222
237
|
const INBOX_BUNDLES = new Set([
|
|
223
238
|
'@deepseek-ai/dsh-base',
|
|
224
239
|
'@deepseek-ai/dsh-web-app',
|
|
@@ -274,7 +289,7 @@ async function listProfilePlugins(config) {
|
|
|
274
289
|
active: bundle && bundles.includes(name),
|
|
275
290
|
builtin: BUILTIN_PLUGINS.includes(name),
|
|
276
291
|
// 自身随平台镜像升级:前端据此隐藏卸载/升级按钮(与后端拒绝逻辑同源)
|
|
277
|
-
self_managed: name === PLUGIN_PACKAGE_NAME,
|
|
292
|
+
self_managed: name === PLUGIN_PACKAGE_NAME && isSelfManaged(),
|
|
278
293
|
description: BUILTIN_PLUGIN_DESCRIPTIONS[name] || null,
|
|
279
294
|
});
|
|
280
295
|
}
|
|
@@ -347,7 +362,7 @@ async function upgradeProfilePlugin(config, name) {
|
|
|
347
362
|
if (INBOX_BUNDLES.has(name)) {
|
|
348
363
|
throw new Error('dsh 内置组件随 dsh 一同升级,请等待平台更新 dsh');
|
|
349
364
|
}
|
|
350
|
-
if (name === PLUGIN_PACKAGE_NAME) {
|
|
365
|
+
if (name === PLUGIN_PACKAGE_NAME && isSelfManaged()) {
|
|
351
366
|
throw new Error('AgentOne 插件随平台镜像一同升级,无需手动操作');
|
|
352
367
|
}
|
|
353
368
|
const dir = pluginProfileDir(config);
|
|
@@ -900,15 +915,39 @@ export function apply(ctx, config) {
|
|
|
900
915
|
response.end();
|
|
901
916
|
return;
|
|
902
917
|
}
|
|
903
|
-
// 真实探测本机 CLI
|
|
904
|
-
//
|
|
918
|
+
// 真实探测本机 CLI:三态与平台 cli-deployd 判定口径一致,附带版本
|
|
919
|
+
// 与最新版(查询失败降级 null,不阻塞三态)。并发探测,单个失败不影
|
|
920
|
+
// 响另一个。
|
|
905
921
|
const [lark, ccpg] = await Promise.all([
|
|
906
|
-
|
|
907
|
-
|
|
922
|
+
probeCliDetail('lark-cli').catch(() => ({ state: 'missing', version: null, latest: null })),
|
|
923
|
+
probeCliDetail('ccpg-cli').catch(() => ({ state: 'missing', version: null, latest: null })),
|
|
908
924
|
]);
|
|
909
925
|
sendJson(response, 200, { tools: { 'lark-cli': lark, 'ccpg-cli': ccpg } });
|
|
910
926
|
});
|
|
911
927
|
|
|
928
|
+
register('/agentone/api/cli/upgrade', async (request, response) => {
|
|
929
|
+
if (request.method !== 'POST') {
|
|
930
|
+
response.writeHead(405, { allow: 'POST' });
|
|
931
|
+
response.end();
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
try {
|
|
935
|
+
const body = await readJsonBody(request);
|
|
936
|
+
const tool = String(body.tool || '');
|
|
937
|
+
if (!CLI_TOOLS.has(tool)) {
|
|
938
|
+
sendJson(response, 400, { error: '不支持的 CLI 工具' });
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
// 官方自升级(ccpg 下载二进制可达分钟级),输出尾部透传给前端
|
|
942
|
+
// (lark-cli 手动安装时含 GitHub 下载地址)
|
|
943
|
+
const output = await upgradeCliTool(tool);
|
|
944
|
+
const detail = await probeCliDetail(tool).catch(() => null);
|
|
945
|
+
sendJson(response, 200, { ok: true, output, tool: detail });
|
|
946
|
+
} catch (error) {
|
|
947
|
+
sendJson(response, 502, { error: error?.message || 'CLI 升级失败,请稍后重试' });
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
|
|
912
951
|
register('/agentone/api/plan', async (request, response) => {
|
|
913
952
|
if (request.method !== 'GET') {
|
|
914
953
|
response.writeHead(405, { allow: 'GET' });
|
package/lib/page.js
CHANGED
|
@@ -423,19 +423,56 @@ const renderCli = async (s) => {
|
|
|
423
423
|
return;
|
|
424
424
|
}
|
|
425
425
|
const rows = Object.entries(CLI_TOOL_META).map(([name, meta]) => {
|
|
426
|
-
const
|
|
426
|
+
const info = tools[name] || { state: 'missing' };
|
|
427
|
+
const state = info.state || 'missing';
|
|
427
428
|
const status = state === 'authorized'
|
|
428
429
|
? '<span class="pill ok" style="font-size:11px">已授权</span>'
|
|
429
430
|
: state === 'unauthorized'
|
|
430
431
|
? '<span class="pill warn" style="font-size:11px">未授权</span>'
|
|
431
432
|
: '<span class="pill warn" style="font-size:11px">未安装</span>';
|
|
433
|
+
// 版本展示:当前版 · 有新版时「v旧 → v新」+ 升级按钮(查询失败静默退化)
|
|
434
|
+
const versionLine = meta.desc + ' · ' + meta.label
|
|
435
|
+
+ (info.version ? ' · v' + esc(info.version) : '')
|
|
436
|
+
+ (info.latest && info.latest !== info.version
|
|
437
|
+
? ' → <b>v' + esc(info.latest) + '</b>'
|
|
438
|
+
: '');
|
|
439
|
+
const upgradable = info.latest && info.latest !== info.version;
|
|
440
|
+
const actions = upgradable
|
|
441
|
+
? '<button class="btn small primary" data-cli-upgrade="' + esc(name) + '">升级</button>'
|
|
442
|
+
: '';
|
|
432
443
|
return '<div class="skill-item"><div class="skill-info"><div class="skill-name">'
|
|
433
444
|
+ esc(name) + status + '</div><div class="skill-sub">'
|
|
434
|
-
+
|
|
445
|
+
+ versionLine + '</div></div><div>' + actions + '</div></div>';
|
|
435
446
|
});
|
|
436
447
|
body.innerHTML = rows.join('')
|
|
437
448
|
+ '<div class="hint">在对话中直接使用(如 /lark 帮助),由 dsh 自动调用。</div>'
|
|
438
|
-
+ '<div class="hint"
|
|
449
|
+
+ '<div class="hint">未安装/未授权时,请联系管理员在镜像或本机完成安装与授权;有新版本时可在此一键升级。</div>';
|
|
450
|
+
body.querySelectorAll('[data-cli-upgrade]').forEach((btn) => {
|
|
451
|
+
btn.onclick = () => cliUpgrade(btn.dataset.cliUpgrade, btn);
|
|
452
|
+
});
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
/** CLI 一键升级:官方 tool update(ccpg 下载二进制可达分钟级)。 */
|
|
456
|
+
const cliUpgrade = async (tool, btn) => {
|
|
457
|
+
btn.disabled = true;
|
|
458
|
+
btn.textContent = '升级中,可能需要 1–2 分钟…';
|
|
459
|
+
try {
|
|
460
|
+
const resp = await fetch('api/cli/upgrade', {
|
|
461
|
+
method: 'POST',
|
|
462
|
+
headers: { 'Content-Type': 'application/json' },
|
|
463
|
+
body: JSON.stringify({ tool }),
|
|
464
|
+
});
|
|
465
|
+
const data = await resp.json().catch(() => ({}));
|
|
466
|
+
if (!resp.ok) throw new Error(data.error || 'CLI 升级失败');
|
|
467
|
+
// lark-cli 手动安装时 update 只会打印下载地址,原样展示给用户
|
|
468
|
+
if (data.output) alert(data.output);
|
|
469
|
+
renderCli._probedAt = 0;
|
|
470
|
+
renderCli(lastStatus);
|
|
471
|
+
} catch (error) {
|
|
472
|
+
alert(error.message || 'CLI 升级失败,请稍后重试');
|
|
473
|
+
btn.disabled = false;
|
|
474
|
+
btn.textContent = '升级';
|
|
475
|
+
}
|
|
439
476
|
};
|
|
440
477
|
const pluginAction = (name, action, btn) => withLoading(
|
|
441
478
|
btn,
|
package/lib/proc.js
CHANGED
|
@@ -89,7 +89,29 @@ export async function pnpmViewLatest(name, cwd) {
|
|
|
89
89
|
* ∈ {valid, needs_refresh}(access 过期但 refresh 可用仍算已授权)
|
|
90
90
|
*/
|
|
91
91
|
export async function probeCliTool(tool, { timeoutMs = 15000 } = {}) {
|
|
92
|
+
const detail = await probeCliDetail(tool, { timeoutMs });
|
|
93
|
+
return detail.state;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** --version 输出解析:提取首个 x.y[.z…] 版本号(两 CLI 均为
|
|
97
|
+
* "xxx version 1.2.3" 形态)。 */
|
|
98
|
+
export function parseCliVersion(stdout) {
|
|
99
|
+
const match = /(\d+\.\d+(?:\.\d+)*)/.exec(String(stdout || ''));
|
|
100
|
+
return match ? match[1] : null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 三态探测 + 版本 + 最新版(任一失败降级为 null,不阻塞三态):
|
|
105
|
+
* version: `tool --version`
|
|
106
|
+
* latest: ccpg-cli 走官方 `update --check --json`(结构化,为 agent
|
|
107
|
+
* 设计);lark-cli 无 check 子命令,用 `npm view @larksuite/cli
|
|
108
|
+
* version`(版本号全局一致,对 npm/pnpm/手动安装都成立)。
|
|
109
|
+
* npm view 需要 npm 在 PATH(node 环境下成立);查询超时/失败返回 null,
|
|
110
|
+
* 前端只显示当前版本不显示升级按钮。
|
|
111
|
+
*/
|
|
112
|
+
export async function probeCliDetail(tool, { timeoutMs = 15000 } = {}) {
|
|
92
113
|
let stdout;
|
|
114
|
+
let state = 'unauthorized';
|
|
93
115
|
try {
|
|
94
116
|
({ stdout } = await execFileAsync(tool, ['auth', 'status'], {
|
|
95
117
|
timeout: timeoutMs,
|
|
@@ -97,11 +119,55 @@ export async function probeCliTool(tool, { timeoutMs = 15000 } = {}) {
|
|
|
97
119
|
env: tool === 'ccpg-cli' ? { ...process.env, CCPG_FULL_CLI: '1' } : process.env,
|
|
98
120
|
}));
|
|
99
121
|
} catch (error) {
|
|
100
|
-
if (error.code === 'ENOENT') return 'missing';
|
|
122
|
+
if (error.code === 'ENOENT') return { state: 'missing', version: null, latest: null };
|
|
101
123
|
// 探测失败不区分超时/非零退出:统一按已装但状态未知处理
|
|
102
124
|
stdout = `${error.stdout || ''}`;
|
|
103
125
|
}
|
|
104
|
-
|
|
126
|
+
if (larkStyleAuthorized(stdout) || ccpgStyleAuthorized(stdout)) state = 'authorized';
|
|
127
|
+
|
|
128
|
+
const [version, latest] = await Promise.all([
|
|
129
|
+
execFileAsync(tool, ['--version'], { timeout: 10_000, killSignal: 'SIGKILL' })
|
|
130
|
+
.then((r) => parseCliVersion(r.stdout))
|
|
131
|
+
.catch(() => null),
|
|
132
|
+
cliLatestVersion(tool, timeoutMs).catch(() => null),
|
|
133
|
+
]);
|
|
134
|
+
return { state, version, latest };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** 最新版查询:ccpg-cli 官方 check 接口;lark-cli 查 npm 包 dist-tag。 */
|
|
138
|
+
async function cliLatestVersion(tool, timeoutMs) {
|
|
139
|
+
if (tool === 'ccpg-cli') {
|
|
140
|
+
const { stdout } = await execFileAsync(
|
|
141
|
+
tool,
|
|
142
|
+
['update', '--check', '--json'],
|
|
143
|
+
{ timeout: timeoutMs, killSignal: 'SIGKILL', env: { ...process.env, CCPG_FULL_CLI: '1' } },
|
|
144
|
+
);
|
|
145
|
+
const data = JSON.parse(String(stdout).trim());
|
|
146
|
+
return typeof data?.latest_version === 'string' ? data.latest_version : null;
|
|
147
|
+
}
|
|
148
|
+
if (tool === 'lark-cli') {
|
|
149
|
+
const { stdout } = await execFileAsync(
|
|
150
|
+
'npm',
|
|
151
|
+
['view', '@larksuite/cli', 'version'],
|
|
152
|
+
{ timeout: timeoutMs, killSignal: 'SIGKILL' },
|
|
153
|
+
);
|
|
154
|
+
return parseCliVersion(stdout);
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 触发 CLI 官方自升级(`tool update`):ccpg-cli 从更新服务器下载二进制
|
|
161
|
+
* (~17MB),lark-cli 自动探测 npm/pnpm/手动安装方式(手动时只打印
|
|
162
|
+
* GitHub 下载地址)。返回输出尾部给前端展示(含手动安装的下载链接)。
|
|
163
|
+
*/
|
|
164
|
+
export async function upgradeCliTool(tool, { timeoutMs = 300_000 } = {}) {
|
|
165
|
+
const { stdout } = await runCliTool(tool, ['update'], {
|
|
166
|
+
timeoutMs,
|
|
167
|
+
env: tool === 'ccpg-cli' ? { ...process.env, CCPG_FULL_CLI: '1' } : process.env,
|
|
168
|
+
});
|
|
169
|
+
const lines = String(stdout).split('\n').map((l) => l.trim()).filter(Boolean);
|
|
170
|
+
return lines.slice(-6).join('\n');
|
|
105
171
|
}
|
|
106
172
|
|
|
107
173
|
/** lark-cli 形态:identities 下的 tokenStatus 或新版 status/available 组合。 */
|
package/package.json
CHANGED