dsh-qqbot 1.0.1 → 1.0.2
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/LICENSE +21 -0
- package/README.md +5 -1
- package/lib/client.js +30 -36
- package/lib/index.js +1 -1
- package/lib/types/client/index.d.ts +3 -3
- package/lib/types/client/settings-controller.d.ts +8 -5
- package/package.json +33 -34
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 belowthetree
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ QQ 官方机器人插件,作为 DeepSeek Harness 的**树外插件**维护(
|
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
13
|
dsh plugin --profile <name> add -w dsh-qqbot # 最新版
|
|
14
|
-
dsh plugin --profile <name> add -w dsh-qqbot@1.0.
|
|
14
|
+
dsh plugin --profile <name> add -w dsh-qqbot@1.0.1 # 或固定版本
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
等价的手动方式(进入 profile 目录执行 pnpm):
|
|
@@ -113,3 +113,7 @@ npm publish
|
|
|
113
113
|
```sh
|
|
114
114
|
dsh plugin --profile web add dsh-qqbot -w
|
|
115
115
|
```
|
|
116
|
+
|
|
117
|
+
## 协议
|
|
118
|
+
|
|
119
|
+
本项目以 [MIT License](LICENSE) 发布(Copyright © 2025 belowthetree),详见 [LICENSE](LICENSE) 文件。
|
package/lib/client.js
CHANGED
|
@@ -4,7 +4,7 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
-
let
|
|
7
|
+
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
8
8
|
let react = require("react");
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
10
|
//#region src/client/settings-controller.ts
|
|
@@ -30,9 +30,9 @@ window.__ModuleLoader__.load({
|
|
|
30
30
|
* form re-renders from the fresh state and the user can re-apply the edit.
|
|
31
31
|
*/
|
|
32
32
|
var QqbotSettingsController = class {
|
|
33
|
-
|
|
33
|
+
credentials;
|
|
34
34
|
/** uSES-safe state source the section renders through its hooks compartment. */
|
|
35
|
-
store = (0,
|
|
35
|
+
store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
|
|
36
36
|
status: "idle",
|
|
37
37
|
appIdSet: false,
|
|
38
38
|
secretSet: false,
|
|
@@ -41,10 +41,10 @@ window.__ModuleLoader__.load({
|
|
|
41
41
|
});
|
|
42
42
|
generation = 0;
|
|
43
43
|
/**
|
|
44
|
-
* @param
|
|
44
|
+
* @param credentials - the credentials Remote wire face.
|
|
45
45
|
*/
|
|
46
|
-
constructor(
|
|
47
|
-
this.
|
|
46
|
+
constructor(credentials) {
|
|
47
|
+
this.credentials = credentials;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Refresh the snapshot from `credentials.describe`; a failure keeps the
|
|
@@ -58,9 +58,9 @@ window.__ModuleLoader__.load({
|
|
|
58
58
|
state.error = null;
|
|
59
59
|
});
|
|
60
60
|
try {
|
|
61
|
-
const response = await this.
|
|
62
|
-
if (!response.
|
|
63
|
-
const views = response.
|
|
61
|
+
const response = await this.credentials.describe([QQBOT_APP_ID_REF, QQBOT_APP_SECRET_REF]);
|
|
62
|
+
if (!response.ok) throw new Error(response.error.message);
|
|
63
|
+
const views = response.value;
|
|
64
64
|
const appIdView = views[QQBOT_APP_ID_REF];
|
|
65
65
|
const secretView = views[QQBOT_APP_SECRET_REF];
|
|
66
66
|
if (appIdView === void 0 || secretView === void 0) throw new Error("credentials domain did not answer the qqbot references");
|
|
@@ -88,25 +88,19 @@ window.__ModuleLoader__.load({
|
|
|
88
88
|
*/
|
|
89
89
|
async save(patch) {
|
|
90
90
|
const writes = [];
|
|
91
|
-
if (patch.clearAppId === true) writes.push(() => this.
|
|
91
|
+
if (patch.clearAppId === true) writes.push(() => this.credentials.unset(QQBOT_APP_ID_REF));
|
|
92
92
|
const appId = patch.appId;
|
|
93
|
-
if (appId !== void 0 && appId.length > 0) writes.push(() => this.
|
|
94
|
-
|
|
95
|
-
value: appId
|
|
96
|
-
}));
|
|
97
|
-
if (patch.clearSecret === true) writes.push(() => this.api.credentials.unset({ ref: QQBOT_APP_SECRET_REF }));
|
|
93
|
+
if (appId !== void 0 && appId.length > 0) writes.push(() => this.credentials.set(QQBOT_APP_ID_REF, appId));
|
|
94
|
+
if (patch.clearSecret === true) writes.push(() => this.credentials.unset(QQBOT_APP_SECRET_REF));
|
|
98
95
|
const appSecret = patch.appSecret;
|
|
99
|
-
if (appSecret !== void 0 && appSecret.length > 0) writes.push(() => this.
|
|
100
|
-
ref: QQBOT_APP_SECRET_REF,
|
|
101
|
-
value: appSecret
|
|
102
|
-
}));
|
|
96
|
+
if (appSecret !== void 0 && appSecret.length > 0) writes.push(() => this.credentials.set(QQBOT_APP_SECRET_REF, appSecret));
|
|
103
97
|
if (writes.length === 0) return null;
|
|
104
98
|
try {
|
|
105
99
|
for (const write of writes) {
|
|
106
100
|
const response = await write();
|
|
107
|
-
if (!response.
|
|
101
|
+
if (!response.ok) {
|
|
108
102
|
await this.load();
|
|
109
|
-
return response.
|
|
103
|
+
return response.error.message;
|
|
110
104
|
}
|
|
111
105
|
}
|
|
112
106
|
} catch (error) {
|
|
@@ -138,22 +132,22 @@ window.__ModuleLoader__.load({
|
|
|
138
132
|
document.head.appendChild(tag);
|
|
139
133
|
}
|
|
140
134
|
var QqbotSettingsSection_module_css_default = {
|
|
141
|
-
"
|
|
135
|
+
"actions": "TV8fAG_actions",
|
|
142
136
|
"bound": "TV8fAG_bound",
|
|
143
|
-
"field": "TV8fAG_field",
|
|
144
|
-
"chipUnset": "TV8fAG_chipUnset",
|
|
145
137
|
"section": "TV8fAG_section",
|
|
138
|
+
"chipUnset": "TV8fAG_chipUnset",
|
|
146
139
|
"desc": "TV8fAG_desc",
|
|
147
|
-
"messageError": "TV8fAG_messageError",
|
|
148
140
|
"saveButton": "TV8fAG_saveButton",
|
|
149
|
-
"
|
|
150
|
-
"
|
|
141
|
+
"messageError": "TV8fAG_messageError",
|
|
142
|
+
"input": "TV8fAG_input",
|
|
151
143
|
"title": "TV8fAG_title",
|
|
144
|
+
"secretRow": "TV8fAG_secretRow",
|
|
152
145
|
"fieldLabel": "TV8fAG_fieldLabel",
|
|
153
146
|
"chipSet": "TV8fAG_chipSet",
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
147
|
+
"field": "TV8fAG_field",
|
|
148
|
+
"fieldHint": "TV8fAG_fieldHint",
|
|
149
|
+
"clearButton": "TV8fAG_clearButton",
|
|
150
|
+
"messageOk": "TV8fAG_messageOk"
|
|
157
151
|
};
|
|
158
152
|
//#endregion
|
|
159
153
|
//#region src/client/QqbotSettingsSection.tsx
|
|
@@ -459,12 +453,12 @@ window.__ModuleLoader__.load({
|
|
|
459
453
|
*/
|
|
460
454
|
/** Dictionary namespace owned by this plugin. */
|
|
461
455
|
const NS = "qqbot";
|
|
462
|
-
/** Required services: the seats' slot registry,
|
|
456
|
+
/** Required services: the seats' slot registry, commands and credentials remotes, and locale. */
|
|
463
457
|
const inject = [
|
|
464
458
|
"slots",
|
|
465
459
|
"remote",
|
|
466
460
|
"remote.commands",
|
|
467
|
-
"
|
|
461
|
+
"remote.credentials",
|
|
468
462
|
"locale"
|
|
469
463
|
];
|
|
470
464
|
/**
|
|
@@ -477,7 +471,7 @@ window.__ModuleLoader__.load({
|
|
|
477
471
|
zh,
|
|
478
472
|
en
|
|
479
473
|
}), "ui-qqbot: dictionaries");
|
|
480
|
-
const bound = (0,
|
|
474
|
+
const bound = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({ sessionId: null });
|
|
481
475
|
ctx.slots.inject("conversation.input.left", () => ctx.slots.register({
|
|
482
476
|
name: "conversation.input.left",
|
|
483
477
|
id: "qqbot",
|
|
@@ -488,7 +482,7 @@ window.__ModuleLoader__.load({
|
|
|
488
482
|
toggle: async () => {
|
|
489
483
|
const active = bound.getSnapshot().sessionId === sessionId;
|
|
490
484
|
const line = active ? "/qqbot off" : "/qqbot on";
|
|
491
|
-
const result = await ctx.remote.commands.execute(sessionId, line);
|
|
485
|
+
const result = await ctx.remote.commands.execute(sessionId, line, []);
|
|
492
486
|
if (!result.ok) return `${result.error.message} (${result.error.code})`;
|
|
493
487
|
if (result.value === void 0) return `unknown command: ${line}`;
|
|
494
488
|
bound.set({ sessionId: active ? null : sessionId });
|
|
@@ -496,9 +490,9 @@ window.__ModuleLoader__.load({
|
|
|
496
490
|
}
|
|
497
491
|
})
|
|
498
492
|
}, QqbotToggle));
|
|
499
|
-
const settings = new QqbotSettingsController(ctx.
|
|
493
|
+
const settings = new QqbotSettingsController(ctx.remote.credentials);
|
|
500
494
|
ctx.effect(() => {
|
|
501
|
-
const disposers = [ctx.remote.$on("credentials/updated", (ref) => {
|
|
495
|
+
const disposers = [ctx.remote.$on("credentials/reference-updated", (ref) => {
|
|
502
496
|
if (ref === "QQBOT_CRED_APP_ID" || ref === "QQBOT_CRED_APP_SECRET") refreshIfLoaded(settings);
|
|
503
497
|
}), ctx.on("connection/reset", () => {
|
|
504
498
|
refreshIfLoaded(settings);
|
package/lib/index.js
CHANGED
|
@@ -815,7 +815,7 @@ function apply(ctx, config) {
|
|
|
815
815
|
};
|
|
816
816
|
}
|
|
817
817
|
});
|
|
818
|
-
ctx.on("credentials/updated", (ref) => {
|
|
818
|
+
ctx.on("credentials/reference-updated", (ref) => {
|
|
819
819
|
if (ref === QQBOT_APP_ID_REF || ref === QQBOT_APP_SECRET_REF) rejudgeIdentity();
|
|
820
820
|
});
|
|
821
821
|
installSettingsSection(ctx, QQBOT_SETTINGS_NAMESPACE, Config, config, {
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* `remote.commands`, and settings edits write through the Host's settings
|
|
10
10
|
* wire face.
|
|
11
11
|
*/
|
|
12
|
-
import { type SnapshotStore } from '@deepseek-ai/dsh-client-
|
|
13
|
-
import type { ClientContext } from '@deepseek-ai/
|
|
12
|
+
import { type SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
13
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
14
14
|
import { type QqbotSettingsPatch, type QqbotSettingsState } from './settings-controller.ts';
|
|
15
15
|
import { type QqbotKey } from './locales.ts';
|
|
16
16
|
export type { QqbotSettingsPatch, QqbotSettingsState } from './settings-controller.ts';
|
|
@@ -50,7 +50,7 @@ export interface QqbotSettingsInjected {
|
|
|
50
50
|
*/
|
|
51
51
|
save: (patch: QqbotSettingsPatch) => Promise<string | null>;
|
|
52
52
|
}
|
|
53
|
-
/** Required services: the seats' slot registry,
|
|
53
|
+
/** Required services: the seats' slot registry, commands and credentials remotes, and locale. */
|
|
54
54
|
export declare const inject: string[];
|
|
55
55
|
/**
|
|
56
56
|
* Client plugin body: register the connection toggle over the command channel
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
* namespace allowlist the harness owns; credentials take arbitrary reference
|
|
8
8
|
* names, so an out-of-tree plugin needs no harness patch.
|
|
9
9
|
*/
|
|
10
|
-
import type {
|
|
11
|
-
import type { SnapshotStore } from '@deepseek-ai/dsh-client-
|
|
10
|
+
import type { ClientRemote } from '@deepseek-ai/dsh-api-remotes/client';
|
|
11
|
+
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
12
|
+
/** The credentials Remote methods the QQ settings page reads and writes through. */
|
|
13
|
+
type CredentialsWire = Pick<ClientRemote['credentials'], 'describe' | 'set' | 'unset'>;
|
|
12
14
|
/**
|
|
13
15
|
* Credential reference holding the robot application id. Deliberately NOT the
|
|
14
16
|
* environment-variable name: the credential store's env layer shadows a
|
|
@@ -51,14 +53,14 @@ export interface QqbotSettingsState {
|
|
|
51
53
|
* form re-renders from the fresh state and the user can re-apply the edit.
|
|
52
54
|
*/
|
|
53
55
|
export declare class QqbotSettingsController {
|
|
54
|
-
private readonly
|
|
56
|
+
private readonly credentials;
|
|
55
57
|
/** uSES-safe state source the section renders through its hooks compartment. */
|
|
56
58
|
readonly store: SnapshotStore<QqbotSettingsState>;
|
|
57
59
|
private generation;
|
|
58
60
|
/**
|
|
59
|
-
* @param
|
|
61
|
+
* @param credentials - the credentials Remote wire face.
|
|
60
62
|
*/
|
|
61
|
-
constructor(
|
|
63
|
+
constructor(credentials: CredentialsWire);
|
|
62
64
|
/**
|
|
63
65
|
* Refresh the snapshot from `credentials.describe`; a failure keeps the
|
|
64
66
|
* last good state and surfaces the error.
|
|
@@ -79,3 +81,4 @@ export declare class QqbotSettingsController {
|
|
|
79
81
|
* @param controller - the page controller whose current status gates the reload.
|
|
80
82
|
*/
|
|
81
83
|
export declare function refreshIfLoaded(controller: QqbotSettingsController): void;
|
|
84
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-qqbot",
|
|
3
3
|
"description": "QQ official bot bridge for DeepSeek Harness: /qqbot command, bound-session routing, QQ-side approvals, the composer connection toggle, and the QQ Bot settings page",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@deepseek-ai/dsh-api-remotes",
|
|
28
28
|
"@deepseek-ai/dsh-client-connection",
|
|
29
29
|
"@deepseek-ai/dsh-client-locale",
|
|
30
|
-
"@deepseek-ai/dsh-client-
|
|
30
|
+
"@deepseek-ai/dsh-client-store",
|
|
31
31
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
32
32
|
"@deepseek-ai/dsh-client-ui-settings"
|
|
33
33
|
],
|
|
@@ -52,42 +52,41 @@
|
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
55
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
56
|
-
"@deepseek-ai/dsh-api-remotes": "^0.1.
|
|
57
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.
|
|
58
|
-
"@deepseek-ai/dsh-client-
|
|
59
|
-
"@deepseek-ai/dsh-client-ui-
|
|
60
|
-
"@deepseek-ai/dsh-
|
|
61
|
-
"@deepseek-ai/dsh-
|
|
62
|
-
"@deepseek-ai/dsh-
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
64
|
-
"@deepseek-ai/dsh-
|
|
65
|
-
"@deepseek-ai/dsh-
|
|
66
|
-
"@deepseek-ai/dsh-user-approval": "^0.1.
|
|
55
|
+
"@deepseek-ai/dsh-agent": "^0.1.2-alpha.1",
|
|
56
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.2-alpha.1",
|
|
57
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.2-alpha.1",
|
|
58
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-alpha.1",
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.1",
|
|
60
|
+
"@deepseek-ai/dsh-commands": "^0.1.2-alpha.1",
|
|
61
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.1",
|
|
62
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-alpha.1",
|
|
63
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.1",
|
|
64
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.2-alpha.1",
|
|
65
|
+
"@deepseek-ai/dsh-tools": "^0.1.2-alpha.1",
|
|
66
|
+
"@deepseek-ai/dsh-user-approval": "^0.1.2-alpha.1",
|
|
67
67
|
"react": "^18.2.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
71
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
72
|
-
"@deepseek-ai/dsh-agent-loop": "^0.1.
|
|
73
|
-
"@deepseek-ai/dsh-agent-loop-testkit": "^0.1.
|
|
74
|
-
"@deepseek-ai/dsh-api-remotes": "^0.1.
|
|
75
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.
|
|
76
|
-
"@deepseek-ai/dsh-client-
|
|
77
|
-
"@deepseek-ai/dsh-client-test-runtime": "^0.1.
|
|
78
|
-
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.
|
|
79
|
-
"@deepseek-ai/dsh-client-ui-settings": "^0.1.
|
|
80
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.
|
|
81
|
-
"@deepseek-ai/dsh-
|
|
82
|
-
"@deepseek-ai/dsh-
|
|
83
|
-
"@deepseek-ai/dsh-
|
|
84
|
-
"@deepseek-ai/dsh-
|
|
85
|
-
"@deepseek-ai/dsh-
|
|
86
|
-
"@deepseek-ai/dsh-
|
|
87
|
-
"@deepseek-ai/dsh-
|
|
88
|
-
"@deepseek-ai/dsh-
|
|
89
|
-
"@deepseek-ai/dsh-
|
|
90
|
-
"@deepseek-ai/dsh-user-approval": "^0.1.0-rc.5",
|
|
71
|
+
"@deepseek-ai/dsh-agent": "^0.1.2-alpha.1",
|
|
72
|
+
"@deepseek-ai/dsh-agent-loop": "^0.1.2-alpha.1",
|
|
73
|
+
"@deepseek-ai/dsh-agent-loop-testkit": "^0.1.2-alpha.1",
|
|
74
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.2-alpha.1",
|
|
75
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.2-alpha.1",
|
|
76
|
+
"@deepseek-ai/dsh-client-store": "^0.1.2-alpha.1",
|
|
77
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.2-alpha.1",
|
|
78
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.2-alpha.1",
|
|
79
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.2-alpha.1",
|
|
80
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.2-alpha.1",
|
|
81
|
+
"@deepseek-ai/dsh-commands": "^0.1.2-alpha.1",
|
|
82
|
+
"@deepseek-ai/dsh-credentials": "^0.1.2-alpha.1",
|
|
83
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.1",
|
|
84
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-alpha.1",
|
|
85
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.1",
|
|
86
|
+
"@deepseek-ai/dsh-settings": "^0.1.2-alpha.1",
|
|
87
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.2-alpha.1",
|
|
88
|
+
"@deepseek-ai/dsh-tools": "^0.1.2-alpha.1",
|
|
89
|
+
"@deepseek-ai/dsh-user-approval": "^0.1.2-alpha.1",
|
|
91
90
|
"@testing-library/react": "^16.3.2",
|
|
92
91
|
"@types/node": "^22.20.0",
|
|
93
92
|
"@types/react": "~18.3.1",
|