@dsh-plus/actual 0.2.7 → 0.2.9
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/client.js +963 -227
- package/lib/index.d.ts +0 -2
- package/lib/index.js +0 -2
- package/package.json +8 -8
- package/src/client/card.tsx +7 -26
- package/src/client/client.ts +3 -26
- package/src/client/draft.ts +0 -4
- package/src/client/i18n.ts +0 -7
- package/src/client/secrets.ts +17 -121
- package/src/config.ts +0 -5
- package/src/index.ts +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { Context, Service } from "@deepseek-ai/cordis";
|
|
|
5
5
|
import { PresetDefinition } from "@deepseek-ai/dsh-agent-preset-registry";
|
|
6
6
|
//#region src/config.d.ts
|
|
7
7
|
declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
8
|
-
enabled: z<boolean, boolean, "volatile-defined">;
|
|
9
8
|
name: z<string, string, "volatile-defined">;
|
|
10
9
|
description: z<string, string, "volatile-defined">;
|
|
11
10
|
order: z<number, number, "volatile-defined">;
|
|
@@ -31,7 +30,6 @@ declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
31
30
|
toolCallTimeoutMs: z<number, number, "volatile-defined">;
|
|
32
31
|
namePrefix: z<string, string, "volatile-defined">;
|
|
33
32
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
34
|
-
enabled: z<boolean, boolean, "volatile-defined">;
|
|
35
33
|
name: z<string, string, "volatile-defined">;
|
|
36
34
|
description: z<string, string, "volatile-defined">;
|
|
37
35
|
order: z<number, number, "volatile-defined">;
|
package/lib/index.js
CHANGED
|
@@ -35,7 +35,6 @@ const SETTINGS_NS = "dsh-plus-actual";
|
|
|
35
35
|
* @module @dsh-plus/actual/config
|
|
36
36
|
*/
|
|
37
37
|
const Config = z.object({
|
|
38
|
-
enabled: z.boolean().description("总开关(false = 不注册 actual 预设,等价插件未安装)").default(true).volatile(),
|
|
39
38
|
name: z.string().description("预设显示名(设置 → Agent 预设卡片标题)").default("Actual Budget").volatile(),
|
|
40
39
|
description: z.string().description("预设说明(设置 → Agent 预设卡片描述)").default("专注操作 Actual Budget:仅暴露从本机 Actual CLI 自动派生的工具(help 树 × MCP tools/list),另配 web 检索/提问/待办辅助工具,写操作需确认。").volatile(),
|
|
41
40
|
order: z.number().description("预设名册排序位").default(11).volatile(),
|
|
@@ -790,7 +789,6 @@ const inject = [];
|
|
|
790
789
|
*/
|
|
791
790
|
function apply(ctx, config) {
|
|
792
791
|
const plain = () => unwrapVolatile(config);
|
|
793
|
-
if (plain().enabled !== true) return;
|
|
794
792
|
const logger = ctx.logger("actual");
|
|
795
793
|
ctx.plugin(ActualService, config);
|
|
796
794
|
ctx.inject(["agentPresets"], (scope) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-plus/actual",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "dsh-plus service + UI plugin: Actual Budget 能力发现(@actual-app/cli help 树运行时派生 × 进程内 MCP tools/list)、actual agent 预设注册与配置卡片——零手工工具清单",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -33,17 +33,17 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@modelcontextprotocol/client": "2.3.0",
|
|
35
35
|
"@dsh-plus/actual-mcp": "0.2.0",
|
|
36
|
-
"@dsh-plus/shared": "0.1.
|
|
36
|
+
"@dsh-plus/shared": "0.1.44"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@deepseek-ai/cordis": "^4.0.5
|
|
40
|
-
"@deepseek-ai/dsh-agent-preset-registry": "^0.2.1-
|
|
41
|
-
"@deepseek-ai/schemastery": "^3.18.5
|
|
39
|
+
"@deepseek-ai/cordis": "^4.0.5",
|
|
40
|
+
"@deepseek-ai/dsh-agent-preset-registry": "^0.2.1-rc.2",
|
|
41
|
+
"@deepseek-ai/schemastery": "^3.18.5"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@deepseek-ai/cordis": "4.0.5
|
|
45
|
-
"@deepseek-ai/dsh-agent-preset-registry": "0.2.1-
|
|
46
|
-
"@deepseek-ai/schemastery": "3.18.5
|
|
44
|
+
"@deepseek-ai/cordis": "4.0.5",
|
|
45
|
+
"@deepseek-ai/dsh-agent-preset-registry": "0.2.1-rc.2",
|
|
46
|
+
"@deepseek-ai/schemastery": "3.18.5",
|
|
47
47
|
"@types/react": "~18.3.31",
|
|
48
48
|
"react": "^18.2.0"
|
|
49
49
|
},
|
package/src/client/card.tsx
CHANGED
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
-
CardChrome,
|
|
16
15
|
CardLoading,
|
|
17
16
|
CheckRow,
|
|
17
|
+
ConfigShell,
|
|
18
18
|
type NamespaceSettingsApi,
|
|
19
|
+
Note,
|
|
19
20
|
type PluginConfigViewProps,
|
|
20
21
|
type Scope,
|
|
21
22
|
SelectField,
|
|
@@ -72,16 +73,6 @@ function violationProps(
|
|
|
72
73
|
return active ? { invalid: true, invalidLabel: label } : { invalid: false }
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
/** 说明段落(无编辑器的字段在此交代落点)。 */
|
|
76
|
-
function Note(props: { title: string; body: string }): ReactElement {
|
|
77
|
-
return (
|
|
78
|
-
<div className="act-note">
|
|
79
|
-
<p className="act-noteTitle">{props.title}</p>
|
|
80
|
-
<p className="act-noteBody">{props.body}</p>
|
|
81
|
-
</div>
|
|
82
|
-
)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
76
|
/** 连接小节:服务器地址、预算、CLI 命令与版本策略。 */
|
|
86
77
|
function ConnectionSection(props: SectionProps): ReactElement {
|
|
87
78
|
const { t, draft, disabled, violation, onEdit } = props
|
|
@@ -146,7 +137,7 @@ function PolicySection(props: SectionProps): ReactElement {
|
|
|
146
137
|
disabled={disabled}
|
|
147
138
|
onEdit={(value) => onEdit({ confirmWrites: value })}
|
|
148
139
|
/>
|
|
149
|
-
<p className="act-
|
|
140
|
+
<p className="act-hint">{t('confirmWritesHint')}</p>
|
|
150
141
|
<CheckRow
|
|
151
142
|
prefix="act"
|
|
152
143
|
id="act-aux-tools"
|
|
@@ -155,7 +146,7 @@ function PolicySection(props: SectionProps): ReactElement {
|
|
|
155
146
|
disabled={disabled}
|
|
156
147
|
onEdit={(value) => onEdit({ auxTools: value })}
|
|
157
148
|
/>
|
|
158
|
-
<p className="act-
|
|
149
|
+
<p className="act-hint">{t('auxToolsHint')}</p>
|
|
159
150
|
<TextField
|
|
160
151
|
prefix="act"
|
|
161
152
|
id="act-name-prefix"
|
|
@@ -184,11 +175,10 @@ export function ActualCard(props: CardProps): ReactElement | string | null {
|
|
|
184
175
|
const section: SectionProps = { t, draft, disabled, violation, onEdit: edit }
|
|
185
176
|
|
|
186
177
|
return (
|
|
187
|
-
<
|
|
178
|
+
<ConfigShell
|
|
188
179
|
prefix="act"
|
|
189
180
|
title={t('title')}
|
|
190
181
|
description={t('description')}
|
|
191
|
-
statusBadge={{ text: t(draft.enabled ? 'enabledOn' : 'enabledOff'), on: draft.enabled }}
|
|
192
182
|
dirty={dirty}
|
|
193
183
|
dirtyLabel={t('unsaved')}
|
|
194
184
|
readOnlyNotice={disabled ? t('readOnly') : undefined}
|
|
@@ -204,19 +194,10 @@ export function ActualCard(props: CardProps): ReactElement | string | null {
|
|
|
204
194
|
},
|
|
205
195
|
]}
|
|
206
196
|
>
|
|
207
|
-
<CheckRow
|
|
208
|
-
prefix="act"
|
|
209
|
-
id="act-enabled"
|
|
210
|
-
label={t('enabled')}
|
|
211
|
-
checked={draft.enabled}
|
|
212
|
-
disabled={disabled}
|
|
213
|
-
onEdit={(value) => edit({ enabled: value })}
|
|
214
|
-
/>
|
|
215
|
-
<p className="act-noteBody">{t('enabledHint')}</p>
|
|
216
197
|
<ConnectionSection {...section} />
|
|
217
198
|
<SecretsSection t={t} face={credentials} />
|
|
218
199
|
<PolicySection {...section} />
|
|
219
|
-
<Note title={t('advancedTitle')} body={t('advancedBody')} />
|
|
220
|
-
</
|
|
200
|
+
<Note prefix="act" title={t('advancedTitle')} body={t('advancedBody')} />
|
|
201
|
+
</ConfigShell>
|
|
221
202
|
)
|
|
222
203
|
}
|
package/src/client/client.ts
CHANGED
|
@@ -12,15 +12,15 @@ import type { Context } from '@deepseek-ai/cordis'
|
|
|
12
12
|
import {
|
|
13
13
|
createNamespaceApi,
|
|
14
14
|
createSettingsScope,
|
|
15
|
+
credentialsFace,
|
|
15
16
|
injectPluginConfigCard,
|
|
16
17
|
type PluginClientContext,
|
|
17
|
-
type
|
|
18
|
+
type RemoteWithCredentials,
|
|
18
19
|
} from '@dsh-plus/shared/client'
|
|
19
20
|
|
|
20
21
|
import { SETTINGS_NS } from '../ns.ts'
|
|
21
22
|
import { ActualCard } from './card.tsx'
|
|
22
23
|
import { type DictKey, en, NS, zh } from './i18n.ts'
|
|
23
|
-
import type { CredentialsRemoteFace } from './secrets.ts'
|
|
24
24
|
import { injectStyle } from './styles.ts'
|
|
25
25
|
|
|
26
26
|
export const name = 'dsh-plus-actual'
|
|
@@ -41,29 +41,6 @@ export const inject = [
|
|
|
41
41
|
/** 宿主窄面收编在 @dsh-plus/shared/client;TKey 传入本包 DictKey 使键名受检。 */
|
|
42
42
|
type ClientContext = PluginClientContext<DictKey>
|
|
43
43
|
|
|
44
|
-
/** `remote` 服务加上凭据命名空间(inject 已声明,故按存在处理)。 */
|
|
45
|
-
type RemoteWithCredentials = RemoteLike & {
|
|
46
|
-
credentials: Omit<CredentialsRemoteFace, 'onChange'>
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 把官方 `remote.credentials` 收成窄面:只补一个把宿主事件包成订阅的方法,
|
|
51
|
-
* 让状态层不必认识 `$on` 的事件名与载荷形状。
|
|
52
|
-
*/
|
|
53
|
-
function credentialsFace(c: ClientContext): CredentialsRemoteFace {
|
|
54
|
-
const remote = c.get('remote') as RemoteWithCredentials
|
|
55
|
-
const { credentials } = remote
|
|
56
|
-
return {
|
|
57
|
-
describe: (refs) => credentials.describe(refs),
|
|
58
|
-
set: (ref, value) => credentials.set(ref, value),
|
|
59
|
-
unset: (ref) => credentials.unset(ref),
|
|
60
|
-
onChange: (listener) =>
|
|
61
|
-
remote.$on('credentials/reference-updated', (ref) => {
|
|
62
|
-
if (typeof ref === 'string') listener(ref)
|
|
63
|
-
}),
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
44
|
export function apply(ctx: Context): void {
|
|
68
45
|
const c = ctx as unknown as ClientContext
|
|
69
46
|
const tag = injectStyle()
|
|
@@ -76,7 +53,7 @@ export function apply(ctx: Context): void {
|
|
|
76
53
|
c.effect(() => c.locale.register(NS, { zh, en }), 'actual: locale')
|
|
77
54
|
const scope = createSettingsScope(c, SETTINGS_NS, 'actual: settings scope')
|
|
78
55
|
const api = createNamespaceApi(c.get('remote').settings, SETTINGS_NS)
|
|
79
|
-
const credentials = credentialsFace(c)
|
|
56
|
+
const credentials = credentialsFace(c.get('remote') as RemoteWithCredentials)
|
|
80
57
|
injectPluginConfigCard(c.slots, {
|
|
81
58
|
ns: SETTINGS_NS,
|
|
82
59
|
rowId: 'dsh-plus-actual',
|
package/src/client/draft.ts
CHANGED
|
@@ -13,7 +13,6 @@ export type CliVersionPolicy = 'warn' | 'strict'
|
|
|
13
13
|
|
|
14
14
|
/** settings 命名空间里本卡片负责的字段(其余字段不出现在卡片中)。 */
|
|
15
15
|
export interface ConfigValue {
|
|
16
|
-
enabled: boolean
|
|
17
16
|
serverUrl: string
|
|
18
17
|
syncId: string
|
|
19
18
|
cliCommand: string[]
|
|
@@ -25,7 +24,6 @@ export interface ConfigValue {
|
|
|
25
24
|
|
|
26
25
|
/** 编辑草稿:`cliCommand` 以文本承载(空格分隔的 argv)。 */
|
|
27
26
|
export interface Draft {
|
|
28
|
-
enabled: boolean
|
|
29
27
|
serverUrl: string
|
|
30
28
|
syncId: string
|
|
31
29
|
cliCommand: string
|
|
@@ -55,7 +53,6 @@ export function textToArgv(text: string): string[] {
|
|
|
55
53
|
/** 命名空间解析值 → 草稿。 */
|
|
56
54
|
export function draftFromValue(value: ConfigValue): Draft {
|
|
57
55
|
return {
|
|
58
|
-
enabled: value.enabled,
|
|
59
56
|
serverUrl: value.serverUrl,
|
|
60
57
|
syncId: value.syncId,
|
|
61
58
|
cliCommand: argvToText(value.cliCommand),
|
|
@@ -69,7 +66,6 @@ export function draftFromValue(value: ConfigValue): Draft {
|
|
|
69
66
|
/** 草稿 → 命名空间补丁(仅本卡片负责的字段)。 */
|
|
70
67
|
export function patchFromDraft(draft: Draft): Record<string, unknown> {
|
|
71
68
|
return {
|
|
72
|
-
enabled: draft.enabled,
|
|
73
69
|
serverUrl: draft.serverUrl.trim(),
|
|
74
70
|
syncId: draft.syncId.trim(),
|
|
75
71
|
cliCommand: textToArgv(draft.cliCommand),
|
package/src/client/i18n.ts
CHANGED
|
@@ -16,9 +16,6 @@ const ownZh = {
|
|
|
16
16
|
'配置本机 Actual 同步服务器与 CLI 行为。改动热生效,无需重载:连接相关字段会触发能力重新发现。',
|
|
17
17
|
summaryLine: 'Actual 服务器地址、预算 Sync ID、CLI 与工具策略。',
|
|
18
18
|
|
|
19
|
-
enabled: '启用 actual 预设',
|
|
20
|
-
enabledHint: '关闭即不注册该预设(等价插件未安装);已开的会话保持原组合,新会话起不再出现。',
|
|
21
|
-
|
|
22
19
|
serverUrl: '同步服务器地址',
|
|
23
20
|
serverUrlHint:
|
|
24
21
|
'自托管默认 http://127.0.0.1:5006。服务端版本从 <地址>/info 读取,用于版本一致性告警。',
|
|
@@ -78,10 +75,6 @@ const ownEn = {
|
|
|
78
75
|
'Configure the local Actual sync server and CLI behaviour. Changes apply hot — connection fields trigger a fresh capability discovery.',
|
|
79
76
|
summaryLine: 'Actual server address, budget sync ID, CLI and tool policy.',
|
|
80
77
|
|
|
81
|
-
enabled: 'Enable the actual preset',
|
|
82
|
-
enabledHint:
|
|
83
|
-
'Off stops registering the preset (equivalent to not installed). Live sessions keep their composition; new ones will not see it.',
|
|
84
|
-
|
|
85
78
|
serverUrl: 'Sync server URL',
|
|
86
79
|
serverUrlHint:
|
|
87
80
|
'Self-hosted default is http://127.0.0.1:5006. The server version is read from <url>/info for the version-mismatch warning.',
|
package/src/client/secrets.ts
CHANGED
|
@@ -1,132 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* **值只写不读**——describe 只回「已配置 / 来源 / 可写」,没有任何方法回传值。
|
|
2
|
+
* 浏览器半的凭据面:复用 `@dsh-plus/shared/client` 的凭据 hook(describe/set/unset,
|
|
3
|
+
* 支持多引用),此处只绑定本插件关心的引用清单。
|
|
5
4
|
*
|
|
5
|
+
* **值只写不读**——describe 只回「已配置 / 来源 / 可写」,没有任何方法回传值。
|
|
6
6
|
* 凭据与 settings 草稿相互独立:它不进命名空间、不参与脏判定,保存即落
|
|
7
|
-
* `$DSH_HOME/.credentials.yaml` 并热生效(宿主每次工具调用重新 resolve
|
|
8
|
-
* 因此改口令不需要保存卡片、也不需要 /reload 或重启。
|
|
7
|
+
* `$DSH_HOME/.credentials.yaml` 并热生效(宿主每次工具调用重新 resolve)。
|
|
9
8
|
* @module @dsh-plus/actual/client/secrets
|
|
10
9
|
*/
|
|
11
|
-
import
|
|
12
|
-
|
|
10
|
+
import {
|
|
11
|
+
type CredentialsRemoteFace,
|
|
12
|
+
type CredentialsState,
|
|
13
|
+
useCredentials as useSharedCredentials,
|
|
14
|
+
} from '@dsh-plus/shared/client'
|
|
13
15
|
|
|
14
16
|
import { CREDENTIAL_REFS } from '../refs.ts'
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
18
|
+
export type {
|
|
19
|
+
CredentialsRemoteFace,
|
|
20
|
+
CredentialsState,
|
|
21
|
+
CredentialView,
|
|
22
|
+
} from '@dsh-plus/shared/client'
|
|
23
|
+
export { failureOf, viewOf } from '@dsh-plus/shared/client'
|
|
22
24
|
|
|
23
|
-
/**
|
|
24
|
-
export interface CredentialsRemoteFace {
|
|
25
|
-
describe(refs: readonly string[]): Promise<RemoteResult<Record<string, CredentialView>>>
|
|
26
|
-
set(ref: string, value: string): Promise<RemoteResult<unknown>>
|
|
27
|
-
unset(ref: string): Promise<RemoteResult<unknown>>
|
|
28
|
-
/** 订阅引用变更(宿主提交写入或观察到凭据文件被外部编辑时触发)。 */
|
|
29
|
-
onChange(listener: (ref: string) => void): () => void
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** 未答(或应答缺项)时的视图:按「未配置、可写」呈现。 */
|
|
33
|
-
export const ABSENT_VIEW: CredentialView = { configured: false, writable: true }
|
|
34
|
-
|
|
35
|
-
/** 取某引用的视图;应答缺项回落为 {@link ABSENT_VIEW}。 */
|
|
36
|
-
export function viewOf(views: Record<string, CredentialView>, ref: string): CredentialView {
|
|
37
|
-
return views[ref] ?? ABSENT_VIEW
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** 应答信封的错误文案(成功为空串)。 */
|
|
41
|
-
export function failureOf(result: RemoteResult<unknown>): string {
|
|
42
|
-
return result.ok ? '' : (result.error.message ?? '')
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** 提取异常文本。 */
|
|
46
|
-
function messageOf(error: unknown): string {
|
|
47
|
-
return error instanceof Error ? error.message : String(error)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** 凭据读写的卡片状态。 */
|
|
51
|
-
export interface CredentialsState {
|
|
52
|
-
views: Record<string, CredentialView>
|
|
53
|
-
/** 有写入在途(按钮禁用用)。 */
|
|
54
|
-
busy: boolean
|
|
55
|
-
/** 最近一次失败文案(空串 = 无)。 */
|
|
56
|
-
error: string
|
|
57
|
-
/** 写入成功返回 true(调用方据此决定是否清空输入框)。 */
|
|
58
|
-
save(ref: string, value: string): Promise<boolean>
|
|
59
|
-
clear(ref: string): Promise<boolean>
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 订阅宿主凭据变更:只认本插件关心的引用,其余(别的插件写自己的密钥)
|
|
64
|
-
* 不触发重读。
|
|
65
|
-
*/
|
|
66
|
-
function useCredentialChanges(face: CredentialsRemoteFace, read: () => void): void {
|
|
67
|
-
useEffect(
|
|
68
|
-
() =>
|
|
69
|
-
face.onChange((ref) => {
|
|
70
|
-
if ((CREDENTIAL_REFS as readonly string[]).includes(ref)) read()
|
|
71
|
-
}),
|
|
72
|
-
[face, read],
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* 凭据行状态:挂载即 describe 一次,写入后重新 describe;
|
|
78
|
-
* 外部改动经 `credentials/reference-updated` 触发同一路径刷新。
|
|
79
|
-
*/
|
|
25
|
+
/** 本插件的凭据行状态(引用清单固定为 {@link CREDENTIAL_REFS})。 */
|
|
80
26
|
export function useCredentials(face: CredentialsRemoteFace): CredentialsState {
|
|
81
|
-
|
|
82
|
-
const [busy, setBusy] = useState(false)
|
|
83
|
-
const [error, setError] = useState('')
|
|
84
|
-
|
|
85
|
-
const read = useCallback(async (): Promise<void> => {
|
|
86
|
-
const result = await face.describe([...CREDENTIAL_REFS])
|
|
87
|
-
if (!result.ok) {
|
|
88
|
-
setError(failureOf(result))
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
setError('')
|
|
92
|
-
setViews(result.value)
|
|
93
|
-
}, [face])
|
|
94
|
-
|
|
95
|
-
useEffect(() => {
|
|
96
|
-
void read()
|
|
97
|
-
}, [read])
|
|
98
|
-
useCredentialChanges(face, read)
|
|
99
|
-
|
|
100
|
-
const write = useCallback(
|
|
101
|
-
async (run: () => Promise<RemoteResult<unknown>>): Promise<boolean> => {
|
|
102
|
-
setBusy(true)
|
|
103
|
-
try {
|
|
104
|
-
const result = await run()
|
|
105
|
-
if (!result.ok) {
|
|
106
|
-
setError(failureOf(result))
|
|
107
|
-
return false
|
|
108
|
-
}
|
|
109
|
-
setError('')
|
|
110
|
-
await read()
|
|
111
|
-
return true
|
|
112
|
-
} catch (thrown: unknown) {
|
|
113
|
-
setError(messageOf(thrown))
|
|
114
|
-
return false
|
|
115
|
-
} finally {
|
|
116
|
-
setBusy(false)
|
|
117
|
-
}
|
|
118
|
-
},
|
|
119
|
-
[read],
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
const save = useCallback(
|
|
123
|
-
(ref: string, value: string): Promise<boolean> => write(() => face.set(ref, value)),
|
|
124
|
-
[face, write],
|
|
125
|
-
)
|
|
126
|
-
const clear = useCallback(
|
|
127
|
-
(ref: string): Promise<boolean> => write(() => face.unset(ref)),
|
|
128
|
-
[face, write],
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
return { views, busy, error, save, clear }
|
|
27
|
+
return useSharedCredentials(face, CREDENTIAL_REFS)
|
|
132
28
|
}
|
package/src/config.ts
CHANGED
|
@@ -28,11 +28,6 @@ import { SETTINGS_NS as NS_LITERAL } from './ns.ts'
|
|
|
28
28
|
export const SETTINGS_NS = NS_LITERAL
|
|
29
29
|
|
|
30
30
|
export const Config = z.object({
|
|
31
|
-
enabled: z
|
|
32
|
-
.boolean()
|
|
33
|
-
.description('总开关(false = 不注册 actual 预设,等价插件未安装)')
|
|
34
|
-
.default(true)
|
|
35
|
-
.volatile(),
|
|
36
31
|
name: z
|
|
37
32
|
.string()
|
|
38
33
|
.description('预设显示名(设置 → Agent 预设卡片标题)')
|
package/src/index.ts
CHANGED
|
@@ -71,8 +71,8 @@ declare module '@deepseek-ai/cordis' {
|
|
|
71
71
|
*/
|
|
72
72
|
export function apply(ctx: Context, config: ActualConfig | ActualConfigFields): void {
|
|
73
73
|
// 活动引用现取即热;预设声明在注册时定格,之后的改动经工具行策略热取。
|
|
74
|
+
// 整行开关由官方行开关承担(profile patch `disabled`),插件内不再有第二套总开关。
|
|
74
75
|
const plain = (): ActualConfig => unwrapVolatile(config) as ActualConfig
|
|
75
|
-
if (plain().enabled !== true) return
|
|
76
76
|
const logger = ctx.logger('actual')
|
|
77
77
|
|
|
78
78
|
// 服务先行:子插件行 inject `actual`,预设激活即能接线。
|