@vibedev-si/dsh-vibedev 0.2.1 → 0.2.3
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 +12 -2
- package/THIRD-PARTY-NOTICES.txt +1 -1
- package/lib/auth/credentials.d.ts +1 -0
- package/lib/auth/login.d.ts +6 -1
- package/lib/index.js +104 -17
- package/package.json +1 -1
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.
|
|
32
|
+
新版本在 npm 上发布后的 24 小时内,只写包名可能装到上一个版本(pnpm 默认不装发布未满一天的版本),想马上用新版就写明版本号,例如 `@vibedev-si/dsh-vibedev@0.2.3`。
|
|
33
33
|
|
|
34
34
|
## 登录 VibeDev
|
|
35
35
|
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
|
|
38
38
|
「设置 → VibeDev 账号」里能看到当前账号、余额和 VibeDev 模型的数量,可以充值、查看用量明细、退出登录。登录会自动续期;退出后 VibeDev 的模型会从选择器里消失,DeepSeek 账号不受影响。
|
|
39
39
|
|
|
40
|
+
0.2.3 起修复了重启后再次要求登录的问题:启动时凭据服务未就绪或临时读取失败,会在服务就绪后恢复,不把空结果永久缓存;正常关闭应用保留登录。过去写到本地备用文件的会话在宿主凭据服务可用后迁入,宿主已有记录优先,显式退出会清理备用会话。VibeDev 应用内置的插件需要随应用升级到修复版;单独安装在 DeepSeek Harness 中的插件可直接升级。
|
|
41
|
+
|
|
40
42
|
## VibeDev 的模型
|
|
41
43
|
|
|
42
44
|
- 模型列表来自 VibeDev 网关,按你的账号下发,所以**未登录时不显示**,登录后立即出现,不用重启。
|
|
@@ -128,10 +130,12 @@ Sign in to VibeDev in DeepSeek Harness, next to the DeepSeek account:
|
|
|
128
130
|
|
|
129
131
|
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`.
|
|
130
132
|
|
|
131
|
-
**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.
|
|
133
|
+
**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.3`): pnpm does not install versions younger than a day by default.
|
|
132
134
|
|
|
133
135
|
**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.
|
|
134
136
|
|
|
137
|
+
**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.
|
|
138
|
+
|
|
135
139
|
**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.
|
|
136
140
|
|
|
137
141
|
**Web search**: the plugin registers the web search provider `vibedev-gateway`, signed in with your VibeDev account. Registering does not select it: DeepSeek Harness keeps its own search unless the profile sets `searchProvider: vibedev-gateway` on the `web` row (the VibeDev app does). Searching is free, but the gateway refuses every request, searches included, while the balance is zero.
|
|
@@ -150,6 +154,12 @@ Everything is paid from your VibeDev balance; the DeepSeek account stays DeepSee
|
|
|
150
154
|
|
|
151
155
|
**Third-party code**: the model route in `src/llm/` is ported from the VibeDev app; `context.ts`, `replay.ts` and `stream.ts` are copied from DeepSeek Harness's `@deepseek-ai/dsh-llm-pi-ai` (MIT). The licences of the bundled pi-ai, Anthropic SDK, OpenAI SDK and their dependencies are in `THIRD-PARTY-NOTICES.txt`.
|
|
152
156
|
|
|
157
|
+
## Maintainer releases
|
|
158
|
+
|
|
159
|
+
Build, typecheck and test locally, pack the tested archive, tag the matching source version, and publish a GitHub Release with `vibedev-si-dsh-vibedev-<version>.tgz` attached. `.github/workflows/publish.yml` publishes that exact archive with npm OIDC; it does not rebuild the package. The job checks the source/tag/archive identities and Release asset digest, refuses an existing version with different bytes, and skips an identical already-published version. It verifies the complete npm tarball after publication. For a manual retry of an unpublished version, run the workflow on the version's tag ref.
|
|
160
|
+
|
|
161
|
+
Configure npm Trusted Publisher with GitHub owner `VibeDev-Si`, repository `dsh-vibedev`, workflow `publish.yml`, no environment, and **Allow npm publish**. Enable **Allow npm dist-tag** as well to use the manual `dist-tag` operation for `latest` or `next`. No npm token is stored in this repository. Trusted publishing does not authorize `npm deprecate`; that maintenance operation still uses interactive authentication.
|
|
162
|
+
|
|
153
163
|
## License
|
|
154
164
|
|
|
155
165
|
MIT
|
package/THIRD-PARTY-NOTICES.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
THIRD-PARTY NOTICES · @vibedev-si/dsh-vibedev 0.2.
|
|
1
|
+
THIRD-PARTY NOTICES · @vibedev-si/dsh-vibedev 0.2.3
|
|
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.
|
|
@@ -36,6 +36,7 @@ export declare class CredentialChain {
|
|
|
36
36
|
*/
|
|
37
37
|
reject(credential: GatewayCredential): Promise<void>;
|
|
38
38
|
}
|
|
39
|
+
export declare const GRANT_KEY: import("@deepseek-ai/dsh-credentials").CredentialKey;
|
|
39
40
|
/**
|
|
40
41
|
* Grant storage: the host's credential store when one is loaded (a grant
|
|
41
42
|
* record the store keeps verbatim), else a private file in the state
|
package/lib/auth/login.d.ts
CHANGED
|
@@ -88,7 +88,9 @@ export declare function openInBrowser(url: string): Promise<boolean>;
|
|
|
88
88
|
export declare class PluginLogin {
|
|
89
89
|
private readonly options;
|
|
90
90
|
private grant;
|
|
91
|
-
private
|
|
91
|
+
private reading;
|
|
92
|
+
private revision;
|
|
93
|
+
private readFailureReported;
|
|
92
94
|
private refreshing;
|
|
93
95
|
private pending;
|
|
94
96
|
private readonly listeners;
|
|
@@ -98,7 +100,10 @@ export declare class PluginLogin {
|
|
|
98
100
|
* @param options - gateway origin, storage and test seams.
|
|
99
101
|
*/
|
|
100
102
|
constructor(options: PluginLoginOptions);
|
|
103
|
+
private readStored;
|
|
101
104
|
private load;
|
|
105
|
+
/** Re-read after the credential provider becomes ready or its record changes, without starting a browser sign-in. */
|
|
106
|
+
restore(): Promise<void>;
|
|
102
107
|
/** Take a grant as current and tell listeners when it changed. */
|
|
103
108
|
private adopt;
|
|
104
109
|
private save;
|
package/lib/index.js
CHANGED
|
@@ -569,27 +569,77 @@ function grantStorage(stateDir, credentials) {
|
|
|
569
569
|
const deviceFile = join(stateDir, "device.json");
|
|
570
570
|
let device;
|
|
571
571
|
const readFileGrant = async () => {
|
|
572
|
-
|
|
572
|
+
let text;
|
|
573
|
+
try {
|
|
574
|
+
text = await readFile(sessionFile, "utf8");
|
|
575
|
+
} catch (error) {
|
|
576
|
+
if (error.code === "ENOENT") return void 0;
|
|
577
|
+
throw error;
|
|
578
|
+
}
|
|
579
|
+
const parsed = JSON.parse(text);
|
|
573
580
|
return isGrant(parsed) ? parsed : void 0;
|
|
574
581
|
};
|
|
575
582
|
const writeFileGrant = (grant) => writeFileAtomic(sessionFile, new TextEncoder().encode(grant === void 0 ? "null" : JSON.stringify(grant)), { mode: 384 });
|
|
583
|
+
const clearFileGrant = async () => {
|
|
584
|
+
try {
|
|
585
|
+
await stat(sessionFile);
|
|
586
|
+
} catch (error) {
|
|
587
|
+
if (error.code === "ENOENT") return;
|
|
588
|
+
throw error;
|
|
589
|
+
}
|
|
590
|
+
await writeFileGrant(void 0);
|
|
591
|
+
};
|
|
592
|
+
const clearFileGrantQuietly = async () => {
|
|
593
|
+
try {
|
|
594
|
+
await clearFileGrant();
|
|
595
|
+
} catch {}
|
|
596
|
+
};
|
|
597
|
+
const readHostGrant = async (store) => {
|
|
598
|
+
const stored = await store.readRecord(GRANT_KEY);
|
|
599
|
+
if (stored !== void 0) {
|
|
600
|
+
const grant = stored.kind === "grant" && isGrant(stored.payload) ? stored.payload : void 0;
|
|
601
|
+
if (grant !== void 0) await clearFileGrantQuietly();
|
|
602
|
+
return grant;
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
if ((await stat(sessionFile)).size <= 4) return void 0;
|
|
606
|
+
} catch (error) {
|
|
607
|
+
if (error.code === "ENOENT") return void 0;
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
610
|
+
let adopted;
|
|
611
|
+
await store.modifyRecord(GRANT_KEY, async (current) => {
|
|
612
|
+
if (current !== void 0) {
|
|
613
|
+
adopted = current.kind === "grant" && isGrant(current.payload) ? current.payload : void 0;
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
adopted = await readFileGrant();
|
|
617
|
+
return adopted === void 0 ? void 0 : {
|
|
618
|
+
kind: "grant",
|
|
619
|
+
payload: adopted
|
|
620
|
+
};
|
|
621
|
+
});
|
|
622
|
+
if (adopted !== void 0) await clearFileGrantQuietly();
|
|
623
|
+
return adopted;
|
|
624
|
+
};
|
|
576
625
|
return {
|
|
577
626
|
async read() {
|
|
578
627
|
const store = credentials();
|
|
579
|
-
|
|
580
|
-
const stored = await store.readRecord(GRANT_KEY);
|
|
581
|
-
return stored?.kind === "grant" && isGrant(stored.payload) ? stored.payload : void 0;
|
|
582
|
-
}
|
|
583
|
-
return readFileGrant();
|
|
628
|
+
return store === void 0 ? readFileGrant() : readHostGrant(store);
|
|
584
629
|
},
|
|
585
630
|
async write(grant) {
|
|
586
631
|
const store = credentials();
|
|
587
632
|
if (store !== void 0) {
|
|
588
|
-
if (grant === void 0)
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
633
|
+
if (grant === void 0) {
|
|
634
|
+
await clearFileGrant();
|
|
635
|
+
await store.deleteRecord(GRANT_KEY);
|
|
636
|
+
} else {
|
|
637
|
+
await store.modifyRecord(GRANT_KEY, () => Promise.resolve({
|
|
638
|
+
kind: "grant",
|
|
639
|
+
payload: grant
|
|
640
|
+
}));
|
|
641
|
+
await clearFileGrantQuietly();
|
|
642
|
+
}
|
|
593
643
|
return;
|
|
594
644
|
}
|
|
595
645
|
await writeFileGrant(grant);
|
|
@@ -597,6 +647,7 @@ function grantStorage(stateDir, credentials) {
|
|
|
597
647
|
async update(change) {
|
|
598
648
|
const store = credentials();
|
|
599
649
|
if (store !== void 0) {
|
|
650
|
+
await readHostGrant(store);
|
|
600
651
|
let remove = false;
|
|
601
652
|
await store.modifyRecord(GRANT_KEY, async (current) => {
|
|
602
653
|
const result = await change(current?.kind === "grant" && isGrant(current.payload) ? current.payload : void 0);
|
|
@@ -606,7 +657,10 @@ function grantStorage(stateDir, credentials) {
|
|
|
606
657
|
};
|
|
607
658
|
remove = result.kind === "delete";
|
|
608
659
|
});
|
|
609
|
-
if (remove)
|
|
660
|
+
if (remove) {
|
|
661
|
+
await clearFileGrant();
|
|
662
|
+
await store.deleteRecord(GRANT_KEY);
|
|
663
|
+
}
|
|
610
664
|
return;
|
|
611
665
|
}
|
|
612
666
|
const result = await change(await readFileGrant());
|
|
@@ -709,7 +763,9 @@ const PAGE = (title, body) => `<!doctype html><html><head><meta charset="utf-8">
|
|
|
709
763
|
var PluginLogin = class {
|
|
710
764
|
options;
|
|
711
765
|
grant;
|
|
712
|
-
|
|
766
|
+
reading;
|
|
767
|
+
revision = 0;
|
|
768
|
+
readFailureReported = false;
|
|
713
769
|
refreshing;
|
|
714
770
|
pending;
|
|
715
771
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -723,14 +779,36 @@ var PluginLogin = class {
|
|
|
723
779
|
this.now = options.now ?? Date.now;
|
|
724
780
|
this.origin = options.origin.trim().replace(/\/+$/, "");
|
|
725
781
|
}
|
|
782
|
+
readStored(notify) {
|
|
783
|
+
if (this.reading !== void 0) return this.reading;
|
|
784
|
+
const revision = this.revision;
|
|
785
|
+
this.reading = this.options.storage.read().then((grant) => {
|
|
786
|
+
this.readFailureReported = false;
|
|
787
|
+
if (this.revision !== revision) return;
|
|
788
|
+
if (notify) this.adopt(grant);
|
|
789
|
+
else {
|
|
790
|
+
this.grant = grant;
|
|
791
|
+
this.revision++;
|
|
792
|
+
}
|
|
793
|
+
}, () => {
|
|
794
|
+
if (!this.readFailureReported) this.options.log?.("dsh-vibedev: stored sign-in is temporarily unreadable; it will be checked again");
|
|
795
|
+
this.readFailureReported = true;
|
|
796
|
+
}).finally(() => {
|
|
797
|
+
this.reading = void 0;
|
|
798
|
+
});
|
|
799
|
+
return this.reading;
|
|
800
|
+
}
|
|
726
801
|
load() {
|
|
727
|
-
this.
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
802
|
+
return this.grant === void 0 ? this.readStored(false) : Promise.resolve();
|
|
803
|
+
}
|
|
804
|
+
/** Re-read after the credential provider becomes ready or its record changes, without starting a browser sign-in. */
|
|
805
|
+
async restore() {
|
|
806
|
+
await this.reading;
|
|
807
|
+
await this.readStored(true);
|
|
731
808
|
}
|
|
732
809
|
/** Take a grant as current and tell listeners when it changed. */
|
|
733
810
|
adopt(grant) {
|
|
811
|
+
this.revision++;
|
|
734
812
|
const changed = this.grant?.accessToken !== grant?.accessToken;
|
|
735
813
|
this.grant = grant;
|
|
736
814
|
if (!changed) return;
|
|
@@ -7168,6 +7246,15 @@ function apply(ctx, config) {
|
|
|
7168
7246
|
client: config.client.trim() || "vibedev-plugin",
|
|
7169
7247
|
openBrowser: (url) => config.openBrowserOnSignIn ? openInBrowser(url) : Promise.resolve(false)
|
|
7170
7248
|
});
|
|
7249
|
+
ctx.inject(["credentials"], (scoped) => {
|
|
7250
|
+
scoped.on("credentials/record-updated", (key) => {
|
|
7251
|
+
if (key === GRANT_KEY) login.restore();
|
|
7252
|
+
});
|
|
7253
|
+
scoped.effect(async () => {
|
|
7254
|
+
await login.restore();
|
|
7255
|
+
return () => {};
|
|
7256
|
+
}, "dsh-vibedev: restore stored sign-in");
|
|
7257
|
+
});
|
|
7171
7258
|
const chain = new CredentialChain({
|
|
7172
7259
|
origin,
|
|
7173
7260
|
plugin: login,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibedev-si/dsh-vibedev",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
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",
|