dsh-nextsteps 1.4.5 → 1.4.6

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.
Files changed (3) hide show
  1. package/client.js +33 -38
  2. package/index.js +5 -1
  3. package/package.json +1 -1
package/client.js CHANGED
@@ -369,6 +369,16 @@ window.__ModuleLoader__.load({
369
369
  'zh-CN': {"header":"建议的后续操作","srFollowupSent":"后续操作已发送","sendFailed":"发送失败:","intro":"在每个智能体回合完成后的下方推荐下一步提示——单击即可发送。","setLanguage":"语言","setLanguageTip":"后续操作提示将以此语言生成。“自动”会跟随对话语言。","optAuto":"自动(跟随对话)","setModel":"模型","setModelTip":"生成建议的模型。自动会跟随对话所用的模型。","optModelAuto":"自动(与对话相同的模型)","modelUnavailable":"此安装没有可用的模型列表","setMax":"每回合提示数","setMaxTip":"模型应生成的建议提示数量(1-6)。","setHeader":"显示标题","setHeaderTip":"卡片上方的小标题“建议的后续操作”。","updates":"更新","current":"版本","checking":"检查中…","upToDate":"已是最新","available":"{v} 可用","manualCopy":"开发或重命名的副本——请手动更新。","installing":"正在安装 {v}…","restartMsg":"版本 {v} 已安装。请重启 dsh 以使用。","noReleases":"尚未发布任何版本","checkFailed":"检查更新失败({e})","updateNow":"立即更新","check":"检查更新","openRelease":"打开发布页","releaseNotes":"发布说明","repo":"GitHub 仓库","issues":"反馈问题"}
370
370
  };
371
371
  let pluginSettings = { lang: 'auto', maxFollowups: 3, showHeader: true };
372
+ let updateManager = undefined;
373
+
374
+ function compareVersions(a, b) {
375
+ const pa = String(a ?? '').replace(/^v/, '').split('.').map((part) => Number(part) || 0);
376
+ const pb = String(b ?? '').replace(/^v/, '').split('.').map((part) => Number(part) || 0);
377
+ for (let index = 0; index < Math.max(pa.length, pb.length); index += 1) {
378
+ if ((pa[index] ?? 0) !== (pb[index] ?? 0)) return (pa[index] ?? 0) < (pb[index] ?? 0) ? -1 : 1;
379
+ }
380
+ return 0;
381
+ }
372
382
  let pluginVersion;
373
383
 
374
384
  async function responseJson(response) {
@@ -555,58 +565,34 @@ window.__ModuleLoader__.load({
555
565
  const response = await fetch(UPDATE_ROUTE, { cache: 'no-store' });
556
566
  const info = await responseJson(response);
557
567
  if (!response.ok || info === null || typeof info !== 'object' || info.error !== undefined) throw new Error(info?.error ?? 'HTTP ' + response.status);
558
- setUpdate({ status: info.newer === true ? (info.managed ? 'available' : 'manual') : 'current', info });
568
+ const installedNewer = compareVersions(info.installed, info.current) > 0;
569
+ const status = installedNewer ? 'restart' : info.newer !== true ? 'current' : info.managed ? 'available' : 'manual';
570
+ setUpdate({ status, info });
559
571
  } catch (error) {
560
572
  setUpdate((previous) => previous.status === 'restart' ? previous : { status: 'error', info: previous.info, error: String(error?.message ?? error) });
561
573
  }
562
574
  };
563
575
  const install = async () => {
564
576
  const { info } = update;
565
- let pluginManager;
566
- try {
567
- pluginManager = ctx.remote?.pluginManager ?? ctx.get?.('remote')?.pluginManager;
568
- } catch { pluginManager = undefined; }
569
- if (info === undefined) return;
570
- if (pluginManager === undefined || typeof pluginManager.installBundle !== 'function') {
577
+ if (info === undefined || updateManager === undefined) {
571
578
  setUpdate({ status: 'error', info, error: 'the plugin manager is not available in this install' });
572
579
  return;
573
580
  }
574
581
  setUpdate({ status: 'installing', info });
575
582
  try {
576
583
  const requestId = NS + '-update-' + info.latest + '-' + Date.now();
577
- const recoverInstall = async (manager, id) => {
578
- if (typeof manager.waitForInstall !== 'function') return undefined;
579
- try {
580
- const reply = await manager.waitForInstall(id);
581
- if (reply === null || typeof reply !== 'object' || reply.ok !== true) return undefined;
582
- return reply.value ?? undefined;
583
- } catch { return undefined; }
584
- };
585
- const attempt = async (spec) => {
586
- const reply = await pluginManager.installBundle(spec, { enabled: true, requestId });
587
- if (reply === null || typeof reply !== 'object' || reply.ok !== true) throw new Error(reply?.error?.message ?? 'plugin manager did not answer');
584
+ const installSpec = async (spec) => {
585
+ const reply = await updateManager.installBundle(spec, { requestId });
586
+ if (!reply?.ok) throw new Error(reply?.error?.message ?? 'plugin manager did not answer');
588
587
  return reply.value;
589
588
  };
590
- let result;
591
- if (typeof pluginManager.updateBundle === 'function') {
592
- const reply = await pluginManager.updateBundle(NPM_NAME, info.latest, { requestId });
593
- if (reply === null || typeof reply !== 'object' || reply.ok !== true) {
594
- const recovered = await recoverInstall(pluginManager, requestId);
595
- if (recovered === undefined) throw new Error(reply?.error?.message ?? 'plugin manager did not answer');
596
- result = recovered;
597
- } else {
598
- result = reply.value;
599
- }
600
- } else {
601
- result = await attempt(NPM_NAME + '@' + info.latest);
602
- if (result !== null && typeof result === 'object' && result.error?.code === 'already-installed') result = await attempt('https://registry.npmjs.org/' + NPM_NAME + '/-/' + NPM_NAME + '-' + info.latest + '.tgz');
603
- }
604
- const applied = result !== null && typeof result === 'object' && (result.application === 'applied' || result.application === 'restart-required' || result.version === info.latest);
605
- if (!applied) {
606
- const diagnostic = typeof result?.error?.diagnostic === 'string' ? result.error.diagnostic.split('\n').find((entry) => entry.trim() !== '') : undefined;
607
- throw new Error(diagnostic ?? result?.error?.code ?? 'install failed');
608
- }
609
- setUpdate(result.application === 'applied'
589
+ let result = await installSpec(NPM_NAME + '@' + info.latest);
590
+ if (result?.error?.code === 'already-installed') result = await installSpec('https://registry.npmjs.org/' + NPM_NAME + '/-/' + NPM_NAME + '-' + info.latest + '.tgz');
591
+ const firstLine = () => result?.error?.diagnostic?.split(String.fromCharCode(10)).find((line) => line.trim() !== '') ?? result?.error?.code ?? result?.application;
592
+ const live = result?.application === 'applied';
593
+ if (!live && result?.application !== 'restart-required' && result?.version !== info.latest) throw new Error(firstLine());
594
+ if (result?.application === 'failed') console.warn(`dsh-nextsteps: ${info.latest} is installed; dsh could not start it before a restart: ${firstLine()}`);
595
+ setUpdate(live
610
596
  ? { status: 'current', info: { ...info, current: info.latest, newer: false } }
611
597
  : { status: 'restart', info });
612
598
  } catch (error) {
@@ -665,6 +651,15 @@ window.__ModuleLoader__.load({
665
651
  return {
666
652
  inject: ['slots', 'locale', 'remote'],
667
653
  apply(ctx) {
654
+ const injectScope = (deps, setup) => {
655
+ if (ctx.inject === undefined) return [];
656
+ const fiber = ctx.inject(deps, setup);
657
+ return [() => fiber.dispose()];
658
+ };
659
+ for (const off of injectScope(['remote.pluginManager'], (scope) => {
660
+ updateManager = scope.remote?.pluginManager;
661
+ scope.effect(() => () => { updateManager = undefined; }, 'dsh-nextsteps: update installer');
662
+ })) if (ctx.effect !== undefined) ctx.effect(() => off, 'dsh-nextsteps: update installer scope');
668
663
  installStyles(ctx);
669
664
  rehydrateCaptures();
670
665
  refreshPluginSettings();
package/index.js CHANGED
@@ -172,6 +172,10 @@ function nextstepsSectionText() {
172
172
  ].join('\n');
173
173
  }
174
174
 
175
+ function onDiskVersion() {
176
+ try { return JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')).version ?? null; } catch { return null; }
177
+ }
178
+
175
179
  const PLUGIN_REV = 'sf-2';
176
180
 
177
181
  function toolSpec(settings = { lang: 'auto', maxFollowups: 3, model: '' }) {
@@ -449,7 +453,7 @@ async function apply(ctx) {
449
453
  fetch: async (request) => {
450
454
  try {
451
455
  const info = await checkUpdate(fetch, PACKAGE, request.signal);
452
- return json({ ...info, installed: undefined });
456
+ return json({ ...info, installed: onDiskVersion() });
453
457
  } catch (error) {
454
458
  return json({ error: String(error?.message ?? error) }, 502);
455
459
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-nextsteps",
3
- "version": "1.4.5",
3
+ "version": "1.4.6",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js",