dsh-agentone 0.5.44 → 1.0.0
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/defaults-sync.js +11 -1
- package/lib/index.js +1 -1
- package/lib/page.js +131 -39
- package/lib/proc.js +14 -4
- package/package.json +2 -2
package/lib/defaults-sync.js
CHANGED
|
@@ -259,7 +259,17 @@ export function createDefaultsSync({ config, profiles, credentials, log, interva
|
|
|
259
259
|
promise.finally(() => manualOperations.delete(promise)).catch(() => {});
|
|
260
260
|
return promise;
|
|
261
261
|
}
|
|
262
|
-
|
|
262
|
+
// 快照是 /api/status(5s 轮询)与 defaults/status 的下发边界:description
|
|
263
|
+
// (技能包全文,几百字/条)只在展示层被引用,而新版页面已彻底不渲染——
|
|
264
|
+
// 在出口剥掉,轮询不再背着几十 KB 死重;内部 state 保持完整
|
|
265
|
+
const snapshot = () => {
|
|
266
|
+
const clone = structuredClone(state);
|
|
267
|
+
for (const list of [clone.skills, clone.plugins]) {
|
|
268
|
+
for (const entry of list || []) delete entry.description;
|
|
269
|
+
}
|
|
270
|
+
return clone;
|
|
271
|
+
};
|
|
272
|
+
return { sync, manualOperation, snapshot,
|
|
263
273
|
reset() { stop(); profiles.setPolicy([]); state = { source: null, revision: null,
|
|
264
274
|
checked_at: null, user_id: null, error: null, running: false, skills: [], plugins: [] }; },
|
|
265
275
|
dispose() { disposed = true; stop(); return Promise.allSettled([inFlight, ...manualOperations.keys()]); },
|
package/lib/index.js
CHANGED
|
@@ -1057,7 +1057,7 @@ export function apply(ctx, config) {
|
|
|
1057
1057
|
invalidateStatusCache();
|
|
1058
1058
|
sendJson(response, 200, { ok: true, installed: result?.installed ?? 0, failed: result?.failed ?? 0 });
|
|
1059
1059
|
} catch (error) {
|
|
1060
|
-
sendJson(response, 502, { error: error?.message || '
|
|
1060
|
+
sendJson(response, 502, { error: error?.message || '同步技能失败' });
|
|
1061
1061
|
}
|
|
1062
1062
|
});
|
|
1063
1063
|
|
package/lib/page.js
CHANGED
|
@@ -395,52 +395,87 @@ const renderPlan = async () => {
|
|
|
395
395
|
).then(() => renderPlan());
|
|
396
396
|
});
|
|
397
397
|
};
|
|
398
|
+
// 平台清单同步态与插件列表的同名合并:renderDefaults 记录待处理插件并排除
|
|
399
|
+
// 已列名条目,renderPlugins 把同步状态/原因/重试合并进同名行——同一个包只
|
|
400
|
+
// 出现一行(真实用户机 dsh-im:清单同步失败 + 本机未启用曾显示成两条)
|
|
401
|
+
let defaultsPendingPlugins = [];
|
|
402
|
+
let listedPluginNames = new Set();
|
|
403
|
+
let mergedPendingSig = '';
|
|
404
|
+
const DEFAULTS_STATE_LABELS = { current: '已符合', missing: '待安装', pending: '待应用', running: '同步中',
|
|
405
|
+
failed: '失败', conflict: '本机冲突', report_pending: '已安装,待回报', restart_required: '已安装,重启后生效' };
|
|
406
|
+
/** 同步动作按钮的统一绑定(待处理块与合并进插件行的按钮同一契约)。 */
|
|
407
|
+
const bindDefaultsActions = (el) => {
|
|
408
|
+
el.querySelectorAll('[data-default-action]').forEach((btn) => {
|
|
409
|
+
const request = () => fetch('api/defaults/' + btn.dataset.defaultAction, { method: 'POST',
|
|
410
|
+
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ kind: btn.dataset.kind,
|
|
411
|
+
name: btn.dataset.name, confirm: btn.dataset.defaultAction === 'apply' }) });
|
|
412
|
+
btn.onclick = () => btn.dataset.defaultAction === 'apply'
|
|
413
|
+
? confirmThen(btn, '替换当前版本?', request, '已开始应用,请查看同步状态')
|
|
414
|
+
: withLoading(btn, request, '已开始重试,请查看同步状态');
|
|
415
|
+
});
|
|
416
|
+
};
|
|
417
|
+
const defaultsPendingSig = () => defaultsPendingPlugins.map((item) => [item.name, item.state,
|
|
418
|
+
item.target_version || '', item.error || ''].join('~')).join('|');
|
|
419
|
+
|
|
398
420
|
const renderDefaults = (s) => {
|
|
399
|
-
const body = $('defaults-body');
|
|
400
421
|
const config = s.defaults;
|
|
401
|
-
const
|
|
402
|
-
|
|
422
|
+
const syncBtn = $('defaults-sync-btn');
|
|
423
|
+
const labels = DEFAULTS_STATE_LABELS;
|
|
403
424
|
const sources = { platform: '平台清单', compatibility: '旧平台兼容默认', cache: '本机缓存' };
|
|
404
|
-
|
|
425
|
+
const clearBlock = (el) => { el.innerHTML = ''; delete el.dataset.fingerprint; };
|
|
426
|
+
if (!config || !s.logged_in) {
|
|
427
|
+
syncBtn.hidden = true;
|
|
428
|
+
for (const id of ['defaults-meta', 'defaults-plugins', 'defaults-skills']) clearBlock($(id));
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
syncBtn.hidden = false;
|
|
432
|
+
syncBtn.disabled = Boolean(config.running);
|
|
405
433
|
const entries = [...(config.skills || []), ...(config.plugins || [])];
|
|
406
434
|
// legacy:0.5.39 之前装的技能只有平台台账、没有本机记录(见 defaults-sync)。
|
|
407
435
|
// 这类条目单独给一个批量入口,不然升级后每台机器都要点 N 次「确认应用」。
|
|
408
436
|
const legacyCount = entries.filter((item) => item.legacy).length;
|
|
409
|
-
const
|
|
410
|
-
|
|
437
|
+
const pendingCount = entries.filter((item) => item.state !== 'current').length;
|
|
438
|
+
// 待处理插件交给 renderPlugins 合并进同名行(见顶部说明)
|
|
439
|
+
defaultsPendingPlugins = (config.plugins || []).filter((item) => item.state !== 'current');
|
|
440
|
+
// 清单状态收成插件卡头一行 meta(来源/版本/时间/符合统计/错误):健康项不
|
|
441
|
+
// 铺开——技能与插件分别在各自 Tab 的列表里以「平台默认/受管」标签呈现,
|
|
442
|
+
// 这里只按类型冒泡待处理项,长描述彻底退出列表。
|
|
443
|
+
const metaHtml = '<div class="skill-sub">' + esc(sources[config.source] || '尚未检查')
|
|
444
|
+
+ (config.revision !== null ? ' · 清单版本 ' + esc(config.revision) : '')
|
|
411
445
|
+ (config.checked_at ? ' · ' + esc(new Date(config.checked_at).toLocaleString()) : '')
|
|
446
|
+
+ ' · <span style="color:var(--ok)">' + (entries.length - pendingCount) + ' 项已符合</span>'
|
|
447
|
+
+ (pendingCount ? ' · <span style="color:var(--warn)">' + pendingCount + ' 项待处理(见下)</span>' : '')
|
|
448
|
+
+ (!entries.length ? ' · 当前清单为空' : '')
|
|
412
449
|
+ (config.running ? ' · 正在检查' : '') + '</div>'
|
|
413
|
-
+ (config.error || config.profile_error
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const
|
|
450
|
+
+ (config.error || config.profile_error
|
|
451
|
+
? '<div class="skill-sub" style="color:var(--err)">' + esc(config.error || config.profile_error) + '</div>' : '');
|
|
452
|
+
const meta = $('defaults-meta');
|
|
453
|
+
if (meta.dataset.fingerprint !== metaHtml) { meta.dataset.fingerprint = metaHtml; meta.innerHTML = metaHtml; }
|
|
454
|
+
const statePill = (state) => state === 'failed' || state === 'conflict'
|
|
455
|
+
? '<span class="pill" style="font-size:11px;background:var(--err-weak);color:var(--err)">'
|
|
456
|
+
+ esc(labels[state] || state) + '</span>'
|
|
457
|
+
: '<span class="pill warn" style="font-size:11px">' + esc(labels[state] || state) + '</span>';
|
|
458
|
+
// 单行紧凑条目:名称 · 类型徽标 · 状态徽标 · 版本(→ 目标版本)+ 行内操作
|
|
459
|
+
const rowHtml = (item) => {
|
|
418
460
|
const action = ['failed', 'report_pending', 'missing'].includes(item.state) ? 'retry'
|
|
419
461
|
: ['conflict', 'pending'].includes(item.state) ? 'apply' : null;
|
|
420
462
|
const button = action ? '<button class="btn small ghost" data-default-action="' + action
|
|
421
463
|
+ '" data-kind="' + item.kind + '" data-name="' + esc(item.name) + '"'
|
|
422
464
|
+ (config.running ? ' disabled' : '') + '>' + (action === 'retry' ? '重试' : '确认应用') + '</button>' : '';
|
|
423
465
|
return '<div class="skill-item"><div class="skill-info"><div class="skill-name">'
|
|
424
|
-
+ esc(item.
|
|
425
|
-
+
|
|
426
|
-
+ (item.legacy ? '
|
|
427
|
-
+
|
|
466
|
+
+ esc(item.name) + ' <span class="tag">' + (item.kind === 'skill' ? '技能' : '插件') + '</span>'
|
|
467
|
+
+ statePill(item.state)
|
|
468
|
+
+ (item.legacy ? ' <span class="tag">旧版安装</span>' : '')
|
|
469
|
+
+ '</div><div class="skill-sub">'
|
|
470
|
+
+ (item.version ? esc(item.version) : '')
|
|
428
471
|
+ (item.target_version && item.target_version !== item.version ? ' → ' + esc(item.target_version) : '')
|
|
429
472
|
+ (item.error ? '<br><span style="color:var(--err)">' + esc(item.error) + '</span>' : '')
|
|
430
473
|
+ '</div></div>' + button + '</div>';
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ kind: btn.dataset.kind,
|
|
437
|
-
name: btn.dataset.name, confirm: btn.dataset.defaultAction === 'apply' }) });
|
|
438
|
-
btn.onclick = () => btn.dataset.defaultAction === 'apply'
|
|
439
|
-
? confirmThen(btn, '替换当前版本?', request, '已开始应用,请查看同步状态')
|
|
440
|
-
: withLoading(btn, request, '已开始重试,请查看同步状态');
|
|
441
|
-
});
|
|
442
|
-
const repair = body.querySelector('#defaults-repair');
|
|
443
|
-
if (repair) repair.onclick = async () => {
|
|
474
|
+
};
|
|
475
|
+
const bindRepair = (el) => {
|
|
476
|
+
const repair = el.querySelector('#defaults-repair');
|
|
477
|
+
if (!repair) return;
|
|
478
|
+
repair.onclick = async () => {
|
|
444
479
|
if (repair.dataset.confirming !== '1') {
|
|
445
480
|
repair.dataset.confirming = '1';
|
|
446
481
|
repair.dataset.originalLabel = repair.textContent;
|
|
@@ -470,8 +505,31 @@ const renderDefaults = (s) => {
|
|
|
470
505
|
await refresh();
|
|
471
506
|
}
|
|
472
507
|
};
|
|
473
|
-
}
|
|
474
|
-
|
|
508
|
+
};
|
|
509
|
+
// 按类型各归其位:待处理插件进插件 Tab、待处理技能进技能 Tab,只列非已符合
|
|
510
|
+
// 项;5s 轮询高频调用,块内容没变时靠指纹跳过重绘(不打断进行中的点击)
|
|
511
|
+
const renderBlock = (id, list) => {
|
|
512
|
+
const el = $(id);
|
|
513
|
+
// 插件待处理项:已进插件列表的同名条目不在这里重复出现(合并进那一行)
|
|
514
|
+
const pending = (list || []).filter((item) => item.state !== 'current'
|
|
515
|
+
&& !(id === 'defaults-plugins' && listedPluginNames.has(item.name)));
|
|
516
|
+
const legacy = id === 'defaults-skills' && legacyCount
|
|
517
|
+
? '<div class="skill-sub"><button id="defaults-repair" class="btn small ghost"'
|
|
518
|
+
+ (config.running ? ' disabled' : '') + '>重新应用旧版安装的技能(' + legacyCount + ')</button>'
|
|
519
|
+
+ ' 技能目录会按平台当前版本覆盖</div>'
|
|
520
|
+
: '';
|
|
521
|
+
const html = (pending.length || legacy)
|
|
522
|
+
? '<div class="skill-sub" style="margin-top:10px">平台同步待处理</div>'
|
|
523
|
+
+ pending.map(rowHtml).join('') + legacy
|
|
524
|
+
: '';
|
|
525
|
+
if (el.dataset.fingerprint !== html) { el.dataset.fingerprint = html; el.innerHTML = html; bindDefaultsActions(el); bindRepair(el); }
|
|
526
|
+
};
|
|
527
|
+
renderBlock('defaults-plugins', config.plugins);
|
|
528
|
+
renderBlock('defaults-skills', config.skills);
|
|
529
|
+
// 待处理集合变化(新失败/恢复)→ 让已加载的插件列表行重新合并;
|
|
530
|
+
// renderPlugins 侧会先对齐 mergedPendingSig,不会互相触发死循环
|
|
531
|
+
const pendingSig = defaultsPendingSig();
|
|
532
|
+
if (renderPlugins._loaded && pendingSig !== mergedPendingSig) void renderPlugins();
|
|
475
533
|
};
|
|
476
534
|
const renderSkills = (s) => {
|
|
477
535
|
const skillhubEnabled = s.capabilities?.channels?.skillhub?.enabled !== false;
|
|
@@ -1044,8 +1102,14 @@ const renderPlugins = async () => {
|
|
|
1044
1102
|
}
|
|
1045
1103
|
// 渲染成功即标记已加载:避免切 tab 重复拉取(outdated 查询有网络开销)
|
|
1046
1104
|
renderPlugins._loaded = true;
|
|
1105
|
+
// 同名合并登记(见 renderDefaults 顶部说明):已列名的插件,其清单同步
|
|
1106
|
+
// 状态合并进本行;待处理块不再单列一条
|
|
1107
|
+
listedPluginNames = new Set(data.plugins.map((plugin) => plugin.name));
|
|
1108
|
+
const pendingByN = new Map(defaultsPendingPlugins.map((item) => [item.name, item]));
|
|
1047
1109
|
if (!data.plugins?.length) {
|
|
1048
1110
|
list.innerHTML = '<div class="skill-sub">暂无已安装插件;内置插件缺失时会在 dsh 启动时自动恢复。</div>';
|
|
1111
|
+
mergedPendingSig = defaultsPendingSig();
|
|
1112
|
+
if (lastStatus) renderDefaults(lastStatus);
|
|
1049
1113
|
return;
|
|
1050
1114
|
}
|
|
1051
1115
|
const rows = data.plugins.map((plugin) => {
|
|
@@ -1065,6 +1129,15 @@ const renderPlugins = async () => {
|
|
|
1065
1129
|
const builtinTag = plugin.builtin
|
|
1066
1130
|
? '<span class="tag">受管</span>'
|
|
1067
1131
|
: '';
|
|
1132
|
+
// 清单同步态合并:同名待处理插件在本行直接给出状态/原因/动作
|
|
1133
|
+
const pending = pendingByN.get(plugin.name);
|
|
1134
|
+
const syncPill = pending
|
|
1135
|
+
? (['failed', 'conflict'].includes(pending.state)
|
|
1136
|
+
? '<span class="pill" style="font-size:11px;background:var(--err-weak);color:var(--err)">同步'
|
|
1137
|
+
+ esc(DEFAULTS_STATE_LABELS[pending.state] || pending.state) + '</span>'
|
|
1138
|
+
: '<span class="pill warn" style="font-size:11px">同步'
|
|
1139
|
+
+ esc(DEFAULTS_STATE_LABELS[pending.state] || pending.state) + '</span>')
|
|
1140
|
+
: '';
|
|
1068
1141
|
const version = plugin.latest
|
|
1069
1142
|
? esc(plugin.version) + ' → <b>' + esc(plugin.latest) + '</b>'
|
|
1070
1143
|
: esc(plugin.version || '—');
|
|
@@ -1084,17 +1157,25 @@ const renderPlugins = async () => {
|
|
|
1084
1157
|
actions.push('<button class="btn small danger" data-remove="' + esc(plugin.name) + '">卸载</button>');
|
|
1085
1158
|
}
|
|
1086
1159
|
}
|
|
1160
|
+
if (pending && ['failed', 'report_pending', 'missing'].includes(pending.state)) {
|
|
1161
|
+
actions.push('<button class="btn small ghost" data-default-action="retry" data-kind="plugin" data-name="' + esc(plugin.name) + '">重试</button>');
|
|
1162
|
+
} else if (pending && ['conflict', 'pending'].includes(pending.state)) {
|
|
1163
|
+
actions.push('<button class="btn small ghost" data-default-action="apply" data-kind="plugin" data-name="' + esc(plugin.name) + '">确认应用</button>');
|
|
1164
|
+
}
|
|
1087
1165
|
const actionHtml = actions.length
|
|
1088
1166
|
? '<div style="display:flex;gap:6px">' + actions.join('') + '</div>'
|
|
1089
1167
|
: '';
|
|
1090
1168
|
return '<div class="skill-item"><div class="skill-info"><div class="skill-name">'
|
|
1091
|
-
+ esc(plugin.name) + builtinTag + statePill
|
|
1169
|
+
+ esc(plugin.name) + builtinTag + statePill + syncPill
|
|
1092
1170
|
+ '</div><div class="skill-sub">' + desc + esc(plugin.source) + ' · ' + version
|
|
1093
1171
|
+ (plugin.registered ? ' · 已启用,重启后生效' : plugin.bundled ? ' · 已安装,未启用当前 profile(「升级」或重装可启用)' : '')
|
|
1172
|
+
+ (pending ? ' · 平台同步 ' + esc(pending.version || '') + (pending.target_version && pending.target_version !== pending.version ? ' → ' + esc(pending.target_version) : '') : '')
|
|
1173
|
+
+ (pending?.error ? '<br><span style="color:var(--err)">' + esc(pending.error) + '</span>' : '')
|
|
1094
1174
|
+ '</div></div>' + actionHtml + '</div>';
|
|
1095
1175
|
});
|
|
1096
1176
|
// 指纹保护(与 renderSkills 同思路):内容没变不碰 innerHTML——升级后
|
|
1097
|
-
// 的定向刷新、切 tab
|
|
1177
|
+
// 的定向刷新、切 tab 重入都不会重建按钮节点(打断卸载二次确认)或闪动。
|
|
1178
|
+
// 清单同步态参与指纹:失败/恢复会让行内容变化
|
|
1098
1179
|
const fingerprint = data.plugins.map((plugin) => [
|
|
1099
1180
|
plugin.name,
|
|
1100
1181
|
plugin.version || '',
|
|
@@ -1102,6 +1183,10 @@ const renderPlugins = async () => {
|
|
|
1102
1183
|
plugin.registered ? 1 : 0,
|
|
1103
1184
|
plugin.bundled ? 1 : 0,
|
|
1104
1185
|
plugin.self_managed ? 1 : 0,
|
|
1186
|
+
pendingByN.get(plugin.name)
|
|
1187
|
+
? [pendingByN.get(plugin.name).state, pendingByN.get(plugin.name).target_version || '',
|
|
1188
|
+
pendingByN.get(plugin.name).error || ''].join('~')
|
|
1189
|
+
: '',
|
|
1105
1190
|
].join(':')).join('|');
|
|
1106
1191
|
if (list.dataset.fingerprint !== fingerprint) {
|
|
1107
1192
|
list.dataset.fingerprint = fingerprint;
|
|
@@ -1125,6 +1210,12 @@ const renderPlugins = async () => {
|
|
|
1125
1210
|
body: JSON.stringify({ name: btn.dataset.remove }),
|
|
1126
1211
|
}).then(() => renderPlugins()), '插件已卸载');
|
|
1127
1212
|
});
|
|
1213
|
+
// 合并进插件行的同步动作按钮(与待处理块同一契约)
|
|
1214
|
+
bindDefaultsActions(list);
|
|
1215
|
+
// 对齐「已合并的待处理集合」:renderDefaults 的变化触发到此为止(不会回环);
|
|
1216
|
+
// 列名登记可能让待处理块的排除集变化,定向重绘一次
|
|
1217
|
+
mergedPendingSig = defaultsPendingSig();
|
|
1218
|
+
if (lastStatus) renderDefaults(lastStatus);
|
|
1128
1219
|
};
|
|
1129
1220
|
// ==about-upgrade-begin==
|
|
1130
1221
|
// 关于页版本行:aboutSelf(GET api/plugin/self)有值时展示升级入口或
|
|
@@ -1403,7 +1494,7 @@ $('skillhub-sync-btn').onclick = () => withLoading(
|
|
|
1403
1494
|
() => fetch('api/skillhub/sync', { method: 'POST' }),
|
|
1404
1495
|
'SkillHub 配置已同步',
|
|
1405
1496
|
);
|
|
1406
|
-
//
|
|
1497
|
+
// 手动同步技能:文案按结果给(装了几个),失败由 withLoading 展示
|
|
1407
1498
|
$('skill-sync-btn').onclick = () => withLoading(
|
|
1408
1499
|
$('skill-sync-btn'),
|
|
1409
1500
|
async () => {
|
|
@@ -1514,9 +1605,10 @@ export function statusPageHtml() {
|
|
|
1514
1605
|
<div class="card" id="skills-card">
|
|
1515
1606
|
<h3>平台技能 <span class="muted">套餐自动同步</span></h3>
|
|
1516
1607
|
<div id="skills-list"></div>
|
|
1608
|
+
<div id="defaults-skills"></div>
|
|
1517
1609
|
<div class="hint" id="skills-meta"></div>
|
|
1518
1610
|
<div class="row" style="margin-top:8px">
|
|
1519
|
-
<button id="skill-sync-btn" class="btn ghost small" data-loading="同步中…"
|
|
1611
|
+
<button id="skill-sync-btn" class="btn ghost small" data-loading="同步中…">同步技能</button>
|
|
1520
1612
|
</div>
|
|
1521
1613
|
<div class="search" style="margin-top:12px">
|
|
1522
1614
|
<input id="search-input" placeholder="搜索技能市场,如:数据 / 报告 / lark" />
|
|
@@ -1532,11 +1624,11 @@ export function statusPageHtml() {
|
|
|
1532
1624
|
|
|
1533
1625
|
<div class="tabpane" id="pane-plugins" hidden>
|
|
1534
1626
|
<div class="card">
|
|
1535
|
-
<h3
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
<
|
|
1627
|
+
<h3>dsh 插件 <span class="muted">当前 profile 已安装的插件</span>
|
|
1628
|
+
<button id="defaults-sync-btn" class="btn ghost small" style="margin-left:auto" hidden>检查并更新</button>
|
|
1629
|
+
</h3>
|
|
1630
|
+
<div id="defaults-meta" aria-live="polite"></div>
|
|
1631
|
+
<div id="defaults-plugins"></div>
|
|
1540
1632
|
<div id="plugins-list"></div>
|
|
1541
1633
|
<div class="hint" id="plugins-hint">受管技能和插件始终更新到最新发布版本;仅管理员停用后可卸载受管插件。</div>
|
|
1542
1634
|
</div>
|
package/lib/proc.js
CHANGED
|
@@ -288,7 +288,13 @@ export function scriptInvocation(resolved, args, {
|
|
|
288
288
|
execPath = process.execPath,
|
|
289
289
|
} = {}) {
|
|
290
290
|
if (!/\.(?:mjs|cjs)$/i.test(String(resolved || ''))) return null;
|
|
291
|
-
if (runtime?.node)
|
|
291
|
+
if (runtime?.node) {
|
|
292
|
+
// Windows 的 node 启动器可能是 .cmd shim(runtime/bin/node.cmd 要求
|
|
293
|
+
// DSH_DESKTOP_NODE_EXECUTABLE 指向真实可执行文件,与
|
|
294
|
+
// desktopShimEnvDefaults 同一约定);真实 node.exe 则无需任何变量
|
|
295
|
+
const env = /\.cmd$/i.test(runtime.node) ? { DSH_DESKTOP_NODE_EXECUTABLE: execPath } : {};
|
|
296
|
+
return { file: runtime.node, args: [resolved, ...args], env };
|
|
297
|
+
}
|
|
292
298
|
if (electron) {
|
|
293
299
|
return { file: execPath, args: [resolved, ...args], env: { ELECTRON_RUN_AS_NODE: '1' } };
|
|
294
300
|
}
|
|
@@ -590,10 +596,14 @@ export async function runCliTool(tool, args, { timeoutMs = 300000, cwd, env, sig
|
|
|
590
596
|
function missingCommandGuidance(tool) {
|
|
591
597
|
if (tool === 'npm' || tool === 'npx') {
|
|
592
598
|
// 触达这里的机器连桌面壳自带工具链都没有(scriptInvocation/兜底映射
|
|
593
|
-
//
|
|
599
|
+
// 均未命中)——重启通常能恢复探测,再给手动安装出路。社区桌面端
|
|
600
|
+
// (DSH Desktop/NEXT)与官方壳分开点名,避免指错重启对象
|
|
601
|
+
const brand = /DSH (?:Desktop|NEXT)\.(?:app|exe)/i.test(process.execPath)
|
|
602
|
+
? 'DSH Desktop'
|
|
603
|
+
: 'DeepSeek Harness';
|
|
594
604
|
return process.platform === 'win32'
|
|
595
|
-
?
|
|
596
|
-
:
|
|
605
|
+
? `未找到 npm/npx 命令:lark-cli 依赖 Node.js 环境,请先从 https://nodejs.org 下载安装 Node.js(LTS 版,安装时保持默认选项),安装完成后重启 ${brand} 再点「安装」`
|
|
606
|
+
: `未找到 npm/npx 命令:lark-cli 依赖 Node.js 环境,且未探测到 ${brand} 自带的 Node 运行时。请重启 ${brand} 后重试;仍失败时安装 Node.js(推荐 nvm:nvm install --lts)后再点「安装」`;
|
|
597
607
|
}
|
|
598
608
|
if (tool === 'pnpm') {
|
|
599
609
|
return '未找到 pnpm 命令,无法查询插件最新版本。可安装 pnpm(npm install -g pnpm)后重启 DSH Desktop;不影响插件正常使用,仅影响升级提示。';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-agentone",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "AgentOne 平台集成:平台模型、SkillHub 技能、套餐与 CLI
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AgentOne 平台集成:平台模型、SkillHub 技能、套餐与 CLI;平台清单融入技能/插件双 Tab,无 Node 机器用桌面壳自带工具链装 lark-cli",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"smoke": "node scripts/env-matrix-smoke.mjs"
|