@vibedev-si/dsh-vibedev 0.2.4 → 0.2.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.
package/README.md CHANGED
@@ -29,7 +29,7 @@
29
29
 
30
30
  - **VibeDev 应用**:已内置本插件,不用另装。VibeDev 账号就是应用的主账号:侧边栏最底下一行和设置里的第一项都是它,DeepSeek 账号作为第二个账号显示在它上方。
31
31
 
32
- 新版本在 npm 上发布后的 24 小时内,只写包名可能装到上一个版本(pnpm 默认不装发布未满一天的版本),想马上用新版就写明版本号,例如 `@vibedev-si/dsh-vibedev@0.2.4`。
32
+ 新版本在 npm 上发布后的 24 小时内,只写包名可能装到上一个版本(pnpm 默认不装发布未满一天的版本),想马上用新版就写明版本号,例如 `@vibedev-si/dsh-vibedev@0.2.5`。
33
33
 
34
34
  ## 登录 VibeDev
35
35
 
@@ -39,7 +39,7 @@
39
39
 
40
40
  0.2.3 起修复了重启后再次要求登录的问题:启动时凭据服务未就绪或临时读取失败,会在服务就绪后恢复,不把空结果永久缓存;正常关闭应用保留登录。过去写到本地备用文件的会话在宿主凭据服务可用后迁入,宿主已有记录优先,显式退出会清理备用会话。VibeDev 应用内置的插件需要随应用升级到修复版;单独安装在 DeepSeek Harness 中的插件可直接升级。
41
41
 
42
- 0.2.4 起在「设置 → VibeDev 账号」页尾加了「创作工具」一行:缺影视工作台或媒体预览时说明用途,都能用了就只留一个进入 VibeDev 插件中心的入口。是否显示按宿主真实的安装状态判断,已装或应用内置的组件不会再推荐安装;这里不会自动安装任何东西,装上、升级都由插件中心或插件页在你自己点击后完成。升级插件不影响已保存的剧本、分镜和作品文件,也不影响现有登录。
42
+ 0.2.5 起撤回了 0.2.4 加在「设置 → VibeDev 账号」页尾的「创作工具」推荐行:那一行属于插件之间的推荐位,放在设置页会影响观感,等重新设计后再考虑。撤销只涉及这一处界面,账号、余额、模型列表、登录与已保存的剧本分镜作品都不受影响。
43
43
 
44
44
  ## VibeDev 的模型
45
45
 
@@ -47,6 +47,7 @@
47
47
  - 模型在选择器里的「VibeDev」组;默认模型仍是 DeepSeek Harness 原来的,想用 VibeDev 的模型就在选择器里选。
48
48
  - 没登录就用了 VibeDev 的模型,或登录已失效时,对话里会提示到侧边栏或设置里登录;余额不足时会提示并给出充值链接。这些提示和 DeepSeek 账号的登录、充值提示是分开的。
49
49
  - 访问令牌过期时插件会自动续期并重发请求,不会重复输出。
50
+ - 网关到上游模型服务的连接中途断开(例如 `upstream_http2_stream_error`、上游响应流被中断)属于可恢复的传输故障,会和超时、5xx、限流一样按退避自动重试,不再直接判定成一次不可重试的失败;重试会重新发起该次请求,已经输出的内容不会续写。
50
51
 
51
52
  ## 网页搜索
52
53
 
@@ -132,13 +133,13 @@ Sign in to VibeDev in DeepSeek Harness, next to the DeepSeek account:
132
133
 
133
134
  Everything is paid from your VibeDev balance; the DeepSeek account stays DeepSeek Harness's own, and the two do not affect each other. To create an account, register at [vibedev.jzsaas.com](https://vibedev.jzsaas.com). This plugin was renamed from `dsh-media`.
134
135
 
135
- **Install**: install `@vibedev-si/dsh-vibedev` by package name on the Plugins page (the `@vibedev-si/` scope is required), or from the [VibeDev Plugin Center](https://github.com/VibeDev-Si/dsh-ecosystem); from the command line, `dsh plugin add @vibedev-si/dsh-vibedev`, or `dsh plugin --profile desktop add @vibedev-si/dsh-vibedev` for the desktop app (quit it fully first). The VibeDev app ships with the plugin built in, and there the VibeDev account is the main account (the bottom row of the sidebar and the first Settings section), with the DeepSeek account as the second one. Within 24 hours of a release, name the version (e.g. `@vibedev-si/dsh-vibedev@0.2.4`): pnpm does not install versions younger than a day by default.
136
+ **Install**: install `@vibedev-si/dsh-vibedev` by package name on the Plugins page (the `@vibedev-si/` scope is required), or from the [VibeDev Plugin Center](https://github.com/VibeDev-Si/dsh-ecosystem); from the command line, `dsh plugin add @vibedev-si/dsh-vibedev`, or `dsh plugin --profile desktop add @vibedev-si/dsh-vibedev` for the desktop app (quit it fully first). The VibeDev app ships with the plugin built in, and there the VibeDev account is the main account (the bottom row of the sidebar and the first Settings section), with the DeepSeek account as the second one. Within 24 hours of a release, name the version (e.g. `@vibedev-si/dsh-vibedev@0.2.5`): pnpm does not install versions younger than a day by default.
136
137
 
137
138
  **Signing in**: choose "Sign in to VibeDev" at the bottom of the sidebar or in Settings → VibeDev account. The VibeDev sign-in page opens in your system browser: you type your password on VibeDev's own page, never in the plugin. Settings → VibeDev account shows the account, the balance and how many VibeDev models are listed, and lets you top up, see usage and sign out.
138
139
 
139
140
  **Sign-in persistence (0.2.3)**: an early empty or failed startup read is retried when storage becomes ready, and committed credential changes restore the account and model route. A late read cannot overwrite a newly saved sign-in. Normal app exit keeps the sign-in. A session saved in the local fallback is migrated into an available host store without overwriting an existing host record; signing out clears the fallback as well. A built-in copy is upgraded by updating VibeDev, while a separately installed plugin can be upgraded directly.
140
141
 
141
- **Creator tools (0.2.4)**: Settings → VibeDev account ends with a Creator tools line that names the film workbench or the media viewer while one is missing, and otherwise offers the VibeDev plugin centre alone. What appears follows the Host's real inventory, so an installed or app-provided component is never offered again; nothing is installed automatically. Upgrading changes neither saved screenplays, boards and film files nor the existing sign-in.
142
+ **Creator tools withdrawn (0.2.5)**: the Creator tools line 0.2.4 added at the end of Settings → VibeDev account is gone. It was a cross-plugin recommendation slot, and in the settings page it hurt the layout; a redesign can revisit it later. Only that interface change is reverted: the account, the balance, the model list, the sign-in and saved screenplays, boards and film files are untouched.
142
143
 
143
144
  **Models**: the list comes from the VibeDev gateway for your account, so nothing is listed before you sign in; models appear right after, without a restart. Using a VibeDev model while signed out, or after the sign-in has ended, asks you to sign in; a used-up balance says so with the top-up link. These messages are separate from the DeepSeek account's. An expired access token is renewed and the request sent again, without repeating any output.
144
145
 
@@ -1,4 +1,4 @@
1
- THIRD-PARTY NOTICES · @vibedev-si/dsh-vibedev 0.2.4
1
+ THIRD-PARTY NOTICES · @vibedev-si/dsh-vibedev 0.2.6
2
2
 
3
3
  This package bundles code from the projects below. Each is used under the licence that
4
4
  follows its name; the licence texts are reproduced as the projects ship them.
package/client/client.js CHANGED
@@ -246,19 +246,7 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
246
246
  sidebarMenu: "VibeDev 账号",
247
247
  sidebarIntro: "登录后可用 VibeDev 的模型和媒体生成",
248
248
  settings: "设置",
249
- accountMenu: "VibeDev 账号菜单",
250
- toolsTitle: "创作工具",
251
- toolsIntro: "这个账号可以和影视工作台、媒体预览与画廊一起用,也能生成片子要做的一切;它们都列在插件中心,可以一并查看和升级。",
252
- toolsQuiet: "装上或更新这些工具不会动你的登录、余额和进行中的任务。",
253
- toolsMissingTitle: "再装上这两件,就能从头做片子",
254
- toolsMissingIntro: "这个账号负责生成;下面这两件负责把生成的东西编排成片、看清楚。",
255
- toolsMissingKeep: "补齐之后,登录、余额和进行中的任务都不受影响;升级插件也不会动工作区里的文件。",
256
- "tools.film.missing": "影视工作台:剧本、分镜画布和导演台,Agent 还带 30 个影视工具。",
257
- "tools.viewer.missing": "媒体预览与画廊:在右侧栏直接看视频、音频和 HTML,或按文件夹浏览媒体。",
258
- toolsOpen: "在插件中心查看",
259
- toolsManual: "也可以打开「插件 → 添加插件」,填入这个包名:",
260
- toolsCopy: "复制包名",
261
- toolsCopied: "已复制"
249
+ accountMenu: "VibeDev 账号菜单"
262
250
  };
263
251
  const en = {
264
252
  spending: "Spending",
@@ -321,19 +309,7 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
321
309
  sidebarMenu: "VibeDev account",
322
310
  sidebarIntro: "Sign in to use the VibeDev models and media generation",
323
311
  settings: "Settings",
324
- accountMenu: "VibeDev account menu",
325
- toolsTitle: "Tools for creators",
326
- toolsIntro: "This account works with the film workbench and with Media Viewer, and it generates everything a film needs; all of them are listed in the plugin centre, where they can be reviewed and updated together.",
327
- toolsQuiet: "Installing or updating these tools leaves your sign-in, balance and running tasks alone.",
328
- toolsMissingTitle: "Two more tools turn this into film making end to end",
329
- toolsMissingIntro: "This account generates; the two below arrange what you generated into a film, and let you watch it closely.",
330
- toolsMissingKeep: "Adding them leaves your sign-in, balance and running tasks alone, and updating a plugin never touches the files in your workspace.",
331
- "tools.film.missing": "Film workbench: screenplay, storyboard canvas and director desk, with 30 film tools for the agent.",
332
- "tools.viewer.missing": "Media Viewer: play video, audio and HTML right in the sidebar, or browse a folder as a gallery.",
333
- toolsOpen: "Open the plugin centre",
334
- toolsManual: "You can also open Plugins → Add plugin and paste this package name:",
335
- toolsCopy: "Copy package name",
336
- toolsCopied: "Copied"
312
+ accountMenu: "VibeDev account menu"
337
313
  };
338
314
  /**
339
315
  * Fill `{name}` placeholders.
@@ -348,9 +324,7 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
348
324
  //#region src/client/AccountSection.tsx
349
325
  /**
350
326
  * Settings → VibeDev 账号: sign in to VibeDev, see who is signed in, the
351
- * balance and how many VibeDev models the pickers list, top up, sign out; and,
352
- * under all of that, the creator tools that work with this account — the film
353
- * workbench and the media viewer — with the plugin centre as the way to them.
327
+ * balance and how many VibeDev models the pickers list, top up, sign out.
354
328
  * The DeepSeek account keeps its own section; this one never touches it.
355
329
  */
356
330
  const styles$1 = {
@@ -422,102 +396,8 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
422
396
  fontSize: 12,
423
397
  lineHeight: 1.6,
424
398
  color: "var(--dsw-alias-state-error-primary, #d4380d)"
425
- },
426
- spec: {
427
- padding: "2px 6px",
428
- borderRadius: 6,
429
- background: "var(--dsw-alias-bg-l1, transparent)",
430
- color: "var(--dsw-alias-label-primary)",
431
- fontSize: 12,
432
- userSelect: "text"
433
399
  }
434
400
  };
435
- /**
436
- * Draw the tools block from a settled read.
437
- * @param props - the translated hint, the manual fallback and the two clicks.
438
- * @returns the tools block.
439
- */
440
- function creatorToolsView({ t, hint, manual, copied, onOpen, onCopy }) {
441
- const missing = hint.kind === "missing";
442
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
443
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
444
- style: styles$1.title,
445
- children: t(missing ? "toolsMissingTitle" : "toolsTitle")
446
- }),
447
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
448
- style: styles$1.intro,
449
- children: missing ? t("toolsMissingIntro") : t("toolsIntro")
450
- }),
451
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
452
- style: styles$1.card,
453
- children: [
454
- hint.missing.map((want) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
455
- style: styles$1.line,
456
- children: want.line
457
- }, want.package)),
458
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
459
- style: styles$1.quiet,
460
- children: missing ? t("toolsMissingKeep") : t("toolsQuiet")
461
- }),
462
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
463
- style: styles$1.actions,
464
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
465
- variant: missing ? "primary" : "outline",
466
- size: "sm",
467
- onClick: onOpen,
468
- children: t("toolsOpen")
469
- })
470
- }),
471
- manual === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
472
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
473
- style: styles$1.quiet,
474
- children: t("toolsManual")
475
- }),
476
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
477
- style: styles$1.spec,
478
- children: manual.spec
479
- }),
480
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
481
- style: styles$1.actions,
482
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
483
- variant: "ghost",
484
- size: "sm",
485
- onClick: () => {
486
- onCopy(manual.spec);
487
- },
488
- children: t(copied ? "toolsCopied" : "toolsCopy")
489
- })
490
- })
491
- ] })
492
- ]
493
- })
494
- ] });
495
- }
496
- function CreatorTools({ suite, t }) {
497
- const { read, hint } = (0, react.useSyncExternalStore)(suite.subscribe, suite.getSnapshot, suite.getSnapshot);
498
- /** Set once a click found nothing to open: the spec to copy is then on screen. */
499
- const [manual, setManual] = (0, react.useState)(void 0);
500
- const [copied, setCopied] = (0, react.useState)(false);
501
- if (!read) return null;
502
- const open = () => {
503
- const target = suite.open();
504
- setCopied(false);
505
- setManual(target.kind === "manual" ? { spec: target.spec } : void 0);
506
- };
507
- const copy = (spec) => {
508
- suite.copy(spec).then((written) => {
509
- setCopied(written);
510
- });
511
- };
512
- return creatorToolsView({
513
- t,
514
- hint,
515
- manual,
516
- copied,
517
- onOpen: open,
518
- onCopy: copy
519
- });
520
- }
521
401
  /** The status dot for a state. */
522
402
  function statusDot(state) {
523
403
  const view = state.view;
@@ -536,10 +416,10 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
536
416
  }
537
417
  /**
538
418
  * The section.
539
- * @param props - the dictionary, the shared account store, the route's display name and the entry's suite view.
419
+ * @param props - the dictionary, the shared account store and the route's display name.
540
420
  * @returns the section content.
541
421
  */
542
- function AccountSection({ t, store, routeName, suite }) {
422
+ function AccountSection({ t, store, routeName }) {
543
423
  const state = (0, react.useSyncExternalStore)(store.subscribe, store.getSnapshot);
544
424
  (0, react.useEffect)(() => {
545
425
  store.refresh(true);
@@ -684,10 +564,6 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
684
564
  children: error
685
565
  })
686
566
  ]
687
- }),
688
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreatorTools, {
689
- suite,
690
- t
691
567
  })
692
568
  ]
693
569
  });
@@ -1328,302 +1204,6 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
1328
1204
  });
1329
1205
  }
1330
1206
  //#endregion
1331
- //#region src/client/suite.ts
1332
- /**
1333
- * The complementary VibeDev components this plugin's own work leans on, and the
1334
- * way to the plugin centre that lists the rest.
1335
- *
1336
- * What the Host actually has comes from its plugin inventory (a bundle the
1337
- * profile installed, or one the application provides itself); the centre's own
1338
- * page is opened where it is registered, and otherwise the Host's install
1339
- * entry, and otherwise the spec a person can paste into the Plugins page. Every
1340
- * service is read optionally through a property check, so a Host without a
1341
- * plugin manager, without a panel layout, or without the plugin navigation
1342
- * contract keeps this plugin working and simply shows no entry, or the manual
1343
- * one. Nothing here installs anything: the centre and the Plugins page own
1344
- * every install, approval and progress.
1345
- *
1346
- * Package names are the stable ones the centre's catalogue and the plugin
1347
- * manager know; no version is named here, because the catalogue and the install
1348
- * dialog are what discover the current one.
1349
- */
1350
- /** The VibeDev components by package name; the centre is the way to all of them. */
1351
- const SUITE = {
1352
- account: "@vibedev-si/dsh-vibedev",
1353
- center: "@vibedev-si/dsh-ecosystem",
1354
- film: "dsh-film",
1355
- viewer: "@vibedev-si/dsh-media-viewer"
1356
- };
1357
- /** The package a person can add on the Plugins page when nothing can open the centre. */
1358
- const CENTER_SPEC = SUITE.center;
1359
- /** The main panel the VibeDev plugin centre registers its page under. */
1360
- const CENTER_PANEL = "vibedev-center";
1361
- /** A property value read as a record, without trusting its declared type. */
1362
- function asRecord(value) {
1363
- return typeof value === "object" && value !== null ? value : void 0;
1364
- }
1365
- /**
1366
- * One service of the client context, read optionally.
1367
- * `ctx.get(name)` answers for an absent or inactive service without the strict property read;
1368
- * a Host, or a service, whose own getter throws answers undefined here rather than failing the plugin.
1369
- * @param ctx - the client context.
1370
- * @param name - the service name.
1371
- * @returns the service, or undefined when this Host does not serve it.
1372
- */
1373
- function service(ctx, name) {
1374
- const record = asRecord(ctx);
1375
- if (record === void 0) return void 0;
1376
- const get = record.get;
1377
- if (typeof get === "function") try {
1378
- const value = get.call(record, name);
1379
- if (value !== void 0) return value;
1380
- } catch (_error) {}
1381
- try {
1382
- return record[name];
1383
- } catch (_error) {
1384
- return;
1385
- }
1386
- }
1387
- /**
1388
- * Whether the Host has a bundle: the profile installed it, or the application provides it itself.
1389
- * @param bundle - one inventory row.
1390
- * @returns whether the component is usable without installing anything.
1391
- */
1392
- function bundlePresent(bundle) {
1393
- return bundle.installed === true || bundle.removable === false && !bundle.source;
1394
- }
1395
- /**
1396
- * The present package names of one inventory answer's rows.
1397
- * @param answer - the Host's answer to `listBundles`.
1398
- * @returns the names, empty when the answer carries no list.
1399
- */
1400
- function presentFrom(answer) {
1401
- const rows = asRecord(answer)?.value;
1402
- if (!Array.isArray(rows)) return /* @__PURE__ */ new Set();
1403
- const names = /* @__PURE__ */ new Set();
1404
- for (const row of rows) {
1405
- const bundle = asRecord(row);
1406
- if (bundle === void 0 || !bundlePresent(bundle)) continue;
1407
- if (typeof bundle.name === "string" && bundle.name !== "") names.add(bundle.name);
1408
- }
1409
- return names;
1410
- }
1411
- /**
1412
- * What one inventory answer means. Only an accepted envelope carrying a list is an inventory:
1413
- * a refused answer (`ok: false` with an error) and a value that is not a list are both unread,
1414
- * never an empty Host, so nothing is ever reported missing on the strength of a failure.
1415
- * A Host that answers with the list itself is accepted as well.
1416
- * @param answer - the Host's answer to `listBundles`.
1417
- * @returns the read, with `ok` false when nothing could be learned.
1418
- */
1419
- function presentFromAnswer(answer) {
1420
- const record = asRecord(answer);
1421
- if (record === void 0) return {
1422
- ok: false,
1423
- present: /* @__PURE__ */ new Set()
1424
- };
1425
- if (record.ok === true && Array.isArray(record.value)) return {
1426
- ok: true,
1427
- present: presentFrom(record)
1428
- };
1429
- if (Array.isArray(answer)) return {
1430
- ok: true,
1431
- present: presentFrom({ value: answer })
1432
- };
1433
- return {
1434
- ok: false,
1435
- present: /* @__PURE__ */ new Set()
1436
- };
1437
- }
1438
- /**
1439
- * Read the Host's plugin inventory once.
1440
- * @param ctx - the client context.
1441
- * @returns what is present, or `ok: false` when no inventory could be read.
1442
- */
1443
- async function readPresence(ctx) {
1444
- const manager = asRecord(service(service(ctx, "remote"), "pluginManager"));
1445
- const listBundles = manager?.listBundles;
1446
- if (typeof listBundles !== "function") return {
1447
- ok: false,
1448
- present: /* @__PURE__ */ new Set()
1449
- };
1450
- try {
1451
- return presentFromAnswer(await listBundles.call(manager));
1452
- } catch (_error) {
1453
- return {
1454
- ok: false,
1455
- present: /* @__PURE__ */ new Set()
1456
- };
1457
- }
1458
- }
1459
- /**
1460
- * Hear about installs, removals and activations.
1461
- * @param ctx - the client context.
1462
- * @param listener - called after every change.
1463
- * @returns the unsubscribe, a no-op on a Host without the event bus.
1464
- */
1465
- function observePresence(ctx, listener) {
1466
- const remote = asRecord(service(ctx, "remote"));
1467
- const on = remote?.$on;
1468
- if (typeof on !== "function") return () => {};
1469
- try {
1470
- const off = on.call(remote, "plugin-manager/changed", listener);
1471
- if (typeof off !== "function") return () => {};
1472
- const stop = off;
1473
- return () => {
1474
- stop();
1475
- };
1476
- } catch (_error) {
1477
- return () => {};
1478
- }
1479
- }
1480
- /**
1481
- * The centre's main panel, where this Host registered one.
1482
- * A slots entry keeps its identity in `options` (`options.key` is the panel id the layout
1483
- * selects); older shapes kept `key`/`id` at the top level, which is still read as a fallback.
1484
- * @param ctx - the client context.
1485
- * @returns the panel id the layout selects, or undefined when there is no centre page.
1486
- */
1487
- function centerPanel(ctx) {
1488
- const slots = asRecord(service(ctx, "slots"));
1489
- const entries = slots?.entries;
1490
- if (typeof entries !== "function") return void 0;
1491
- const listed = entries.call(slots, "main");
1492
- if (!Array.isArray(listed)) return void 0;
1493
- for (const entry of listed) {
1494
- const record = asRecord(entry);
1495
- const options = asRecord(record?.options);
1496
- if ((options?.key ?? record?.key ?? options?.id ?? record?.id) === CENTER_PANEL) return CENTER_PANEL;
1497
- }
1498
- }
1499
- /**
1500
- * Send the person to the VibeDev plugin centre, or to the Host's own way of installing it.
1501
- * A panel that is gone, a layout that refuses, and a missing navigation contract each fall
1502
- * through to the next, and the last answer is the spec to paste.
1503
- * @param ctx - the client context.
1504
- * @returns what was opened.
1505
- */
1506
- function openCenter(ctx) {
1507
- const panel = centerPanel(ctx);
1508
- const selectPanel = asRecord(service(ctx, "layout"))?.selectPanel;
1509
- if (panel !== void 0 && typeof selectPanel === "function") try {
1510
- selectPanel.call(service(ctx, "layout"), panel);
1511
- return { kind: "center" };
1512
- } catch (_error) {}
1513
- const navigation = asRecord(service(ctx, "pluginNavigation"));
1514
- const openBundle = navigation?.openBundle;
1515
- if (typeof openBundle === "function") try {
1516
- openBundle.call(navigation, SUITE.center);
1517
- return { kind: "plugins" };
1518
- } catch (_error) {}
1519
- const openInstall = navigation?.openInstall;
1520
- if (typeof openInstall === "function") try {
1521
- openInstall.call(navigation, { spec: CENTER_SPEC });
1522
- return { kind: "plugins" };
1523
- } catch (_error) {}
1524
- return {
1525
- kind: "manual",
1526
- spec: CENTER_SPEC
1527
- };
1528
- }
1529
- /**
1530
- * Which of `wanted` this Host does not have yet.
1531
- * @param present - what the Host has.
1532
- * @param wanted - the components, in the order the surface lists them.
1533
- * @returns the absent ones.
1534
- */
1535
- function missingFrom(present, wanted) {
1536
- return wanted.filter((want) => !present.has(want.package));
1537
- }
1538
- /**
1539
- * What a surface says: the reasons something is absent, or the one way to the rest.
1540
- * An inventory that could not be read claims nothing and offers the centre.
1541
- * @param read - the inventory read.
1542
- * @param wanted - the components this surface leans on.
1543
- * @param translate - the entry's bound dictionary, so a card renders lines rather than keys.
1544
- * @returns the hint the card renders.
1545
- */
1546
- function suiteHint(read, wanted, translate) {
1547
- if (!read.ok) return {
1548
- kind: "tools",
1549
- missing: []
1550
- };
1551
- const missing = missingFrom(read.present, wanted);
1552
- if (missing.length === 0) return {
1553
- kind: "tools",
1554
- missing: []
1555
- };
1556
- return {
1557
- kind: "missing",
1558
- missing: missing.map((want) => ({
1559
- package: want.package,
1560
- line: translate(want.key)
1561
- }))
1562
- };
1563
- }
1564
- /** Write text through the browser's clipboard, where the page has one. */
1565
- async function writeClipboard(text) {
1566
- const clipboard = asRecord(asRecord(globalThis)?.navigator)?.clipboard;
1567
- const writeText = asRecord(clipboard)?.writeText;
1568
- if (typeof writeText !== "function") return false;
1569
- try {
1570
- await writeText.call(clipboard, text);
1571
- return true;
1572
- } catch (_error) {
1573
- return false;
1574
- }
1575
- }
1576
- /**
1577
- * The entry's read of what this Host has, shared by every card it hands to the workbench.
1578
- * @param ctx - the client context.
1579
- * @param wanted - the components this plugin's own work leans on.
1580
- * @param translate - the entry's bound dictionary.
1581
- * @returns the store: subscribe and render through {@link SuiteView}, and start it inside an effect.
1582
- */
1583
- function createSuiteStore(ctx, wanted, translate) {
1584
- let snapshot = {
1585
- read: false,
1586
- found: {
1587
- ok: false,
1588
- present: /* @__PURE__ */ new Set()
1589
- },
1590
- hint: {
1591
- kind: "tools",
1592
- missing: []
1593
- }
1594
- };
1595
- const listeners = /* @__PURE__ */ new Set();
1596
- const publish = (next) => {
1597
- snapshot = next;
1598
- for (const listener of [...listeners]) listener();
1599
- };
1600
- const read = async () => {
1601
- const found = await readPresence(ctx);
1602
- publish({
1603
- read: true,
1604
- found,
1605
- hint: suiteHint(found, wanted, translate)
1606
- });
1607
- };
1608
- return {
1609
- subscribe(listener) {
1610
- listeners.add(listener);
1611
- return () => {
1612
- listeners.delete(listener);
1613
- };
1614
- },
1615
- getSnapshot: () => snapshot,
1616
- open: () => openCenter(ctx),
1617
- copy: writeClipboard,
1618
- start: () => {
1619
- read();
1620
- return observePresence(ctx, () => {
1621
- read();
1622
- });
1623
- }
1624
- };
1625
- }
1626
- //#endregion
1627
1207
  //#region src/client/index.ts
1628
1208
  /**
1629
1209
  * dsh-vibedev browser half:
@@ -1658,18 +1238,6 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
1658
1238
  const PRIMARY_SECTION_ORDER = -20;
1659
1239
  /** Below the default the DeepSeek account launcher registers with, so this row is the one the foot shows. */
1660
1240
  const LAUNCHER_PRIORITY = -1;
1661
- /**
1662
- * The creator tools that work with this account, offered under the account's own settings.
1663
- * The account itself is never listed: it is what the person is already looking at (and the
1664
- * VibeDev app ships with it built in), so only what is missing from the Host is named.
1665
- */
1666
- const CREATOR_WANTED = [{
1667
- package: SUITE.film,
1668
- key: "tools.film.missing"
1669
- }, {
1670
- package: SUITE.viewer,
1671
- key: "tools.viewer.missing"
1672
- }];
1673
1241
  const disposer = (value) => typeof value === "function" ? value : () => {};
1674
1242
  const name = "dsh-vibedev";
1675
1243
  const inject = ["slots", "locale"];
@@ -1702,8 +1270,6 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
1702
1270
  const t = ctx.locale.bind(LOCALE_NAMESPACE);
1703
1271
  const account = new AccountStore(windowOptions());
1704
1272
  ctx.effect(() => account.start(), "dsh-vibedev: account reads");
1705
- const creatorTools = createSuiteStore(ctx, CREATOR_WANTED, t);
1706
- ctx.effect(() => creatorTools.start(), "dsh-vibedev: creator tools presence");
1707
1273
  const section = (order) => disposer(ctx.slots.inject("settings.section", () => ctx.slots.register({
1708
1274
  name: "settings.section",
1709
1275
  id: "vibedev-account",
@@ -1713,8 +1279,7 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
1713
1279
  }, () => (0, react.createElement)(AccountSection, {
1714
1280
  t,
1715
1281
  store: account,
1716
- routeName: ROUTE_NAME,
1717
- suite: creatorTools
1282
+ routeName: ROUTE_NAME
1718
1283
  }))));
1719
1284
  const launcher = () => disposer(ctx.slots.inject("settings.launcher", () => ctx.slots.register({
1720
1285
  name: "settings.launcher",
@@ -1795,7 +1360,6 @@ window.__ModuleLoader__.load({ id: "@vibedev-si/dsh-vibedev", factory: (require)
1795
1360
  });
1796
1361
  }
1797
1362
  //#endregion
1798
- exports.CREATOR_WANTED = CREATOR_WANTED;
1799
1363
  exports.apply = apply;
1800
1364
  exports.inject = inject;
1801
1365
  exports.name = name;
package/lib/index.js CHANGED
@@ -2051,6 +2051,7 @@ function classifyPiAiError(message) {
2051
2051
  if (/\b5\d\d\b/.test(message)) return "SERVER";
2052
2052
  if (/\btime(?:d)?\s*out\b|timeout/i.test(message)) return "TIMEOUT";
2053
2053
  if (/stream ended (?:before|without)\b/i.test(message)) return "TRANSPORT";
2054
+ if (/\bhttp\/?2\b/i.test(message) || /upstream_(?:http2|stream)_\w*_?error/i.test(message) || /\bstream (?:was )?(?:interrupted|disconnected|reset)\b|\bstream failed\b/i.test(message)) return "TRANSPORT";
2054
2055
  if (/\b(?:network|connection|socket|fetch)\b|\bECONN[A-Z]+\b/i.test(message) || /\b(?:other side closed|HTTP2 request did not get a response|WebSocket closed unexpectedly)\b/i.test(message) || /\bterminated\b|premature close/i.test(message)) return "TRANSPORT";
2055
2056
  return "PI_AI_ERROR";
2056
2057
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibedev-si/dsh-vibedev",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "VibeDev 账号与模型:在 DeepSeek Harness 里登录 VibeDev,与 DeepSeek 账号并存,使用 VibeDev 网关的模型(Claude、GPT 等),并生成图片、视频、音乐和播客 · VibeDev account and models for DeepSeek Harness: sign in to VibeDev next to the DeepSeek account and use the VibeDev gateway's models (Claude, GPT and more), plus image, video, music and podcast generation",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",