@linxin666/dsh-client-ui-task-board 0.1.1
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 +29 -0
- package/README.md +211 -0
- package/cordis.patch.yml +12 -0
- package/lib/client.js +2592 -0
- package/lib/index.js +54 -0
- package/lib/invariant.js +6 -0
- package/lib/types/client/PluginSettingsCard.d.ts +77 -0
- package/lib/types/client/TaskBoardSettingsCard.d.ts +51 -0
- package/lib/types/client/board/ConfirmDialog.d.ts +12 -0
- package/lib/types/client/board/NewTaskModal.d.ts +6 -0
- package/lib/types/client/board/TaskBoard.d.ts +5 -0
- package/lib/types/client/board/TaskCard.d.ts +12 -0
- package/lib/types/client/board/TaskDetail.d.ts +7 -0
- package/lib/types/client/board-mount.d.ts +10 -0
- package/lib/types/client/index.d.ts +43 -0
- package/lib/types/client/locales.d.ts +105 -0
- package/lib/types/client/settings-form.d.ts +118 -0
- package/lib/types/client/sidebar-entry.d.ts +25 -0
- package/lib/types/core/controller.d.ts +129 -0
- package/lib/types/core/execution.d.ts +136 -0
- package/lib/types/core/schedule.d.ts +40 -0
- package/lib/types/core/scheduler.d.ts +49 -0
- package/lib/types/core/store.d.ts +36 -0
- package/lib/types/core/tasks.d.ts +111 -0
- package/lib/types/index.d.ts +44 -0
- package/lib/types/invariant.d.ts +3 -0
- package/package.json +85 -0
- package/src/client/PluginSettingsCard.tsx +207 -0
- package/src/client/TaskBoardSettingsCard.tsx +124 -0
- package/src/client/board/ConfirmDialog.tsx +40 -0
- package/src/client/board/NewTaskModal.tsx +82 -0
- package/src/client/board/TaskBoard.tsx +107 -0
- package/src/client/board/TaskCard.tsx +62 -0
- package/src/client/board/TaskDetail.tsx +286 -0
- package/src/client/board-mount.tsx +74 -0
- package/src/client/board.module.css +849 -0
- package/src/client/css-modules.d.ts +5 -0
- package/src/client/index.ts +167 -0
- package/src/client/locales.ts +211 -0
- package/src/client/settings-card.module.css +261 -0
- package/src/client/settings-form.ts +294 -0
- package/src/client/sidebar-entry.ts +118 -0
- package/src/core/controller.ts +379 -0
- package/src/core/execution.ts +259 -0
- package/src/core/schedule.ts +140 -0
- package/src/core/scheduler.ts +104 -0
- package/src/core/store.ts +183 -0
- package/src/core/tasks.ts +204 -0
- package/src/index.ts +94 -0
- package/src/invariant.ts +4 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
2
|
+
import z from "schemastery";
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
/** Order of the announcement section within the tool-guidance band. */
|
|
5
|
+
const SECTION_ORDER = 200;
|
|
6
|
+
const inject = ["systemPrompt"];
|
|
7
|
+
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
8
|
+
const TASK_BOARD_GUIDANCE = "本机已安装 dsh-task-board 插件(DSH Web GUI 的任务看板):侧边栏「任务看板」入口;在 dsh-web-ui 插件全家桶仓库(packages/dsh-task-board)统一维护,经聚合包 web-ui-all 一键安装。能力:多列看板管理任务;任务可真实执行(驱动 agent 会话);任务支持 5 段 cron 定时执行(如 0 23 * * *);数据存浏览器 localStorage(键 dsh.taskBoard.v1)。限制:定时调度在浏览器端,需 GUI 标签页打开,错过即跳过;执行消耗 API 额度。用户提到「任务看板 / 看板 / 定时任务」时即指本插件,请据此协作。";
|
|
9
|
+
/**
|
|
10
|
+
* Settings namespace of the board's announcement capability — the section the
|
|
11
|
+
* web settings surface edits. Spelled here rather than imported: the browser
|
|
12
|
+
* half spells the same value and must not depend on a Host package.
|
|
13
|
+
*/
|
|
14
|
+
const TASK_BOARD_SETTINGS_NAMESPACE = settingsNamespace("task-board");
|
|
15
|
+
const Config = z.object({
|
|
16
|
+
announceToAgent: z.boolean().default(true),
|
|
17
|
+
enabled: z.boolean().default(true)
|
|
18
|
+
});
|
|
19
|
+
/** Schema default, re-read for hand-built test contexts (the loader applies them normally). */
|
|
20
|
+
const DEFAULT_ANNOUNCE = true;
|
|
21
|
+
/**
|
|
22
|
+
* Register the board's announcement section, gated on the composition entry's
|
|
23
|
+
* `announceToAgent` (and the live settings value once the web settings
|
|
24
|
+
* surface is served). The section is re-registered whenever the source
|
|
25
|
+
* changes, so a settings edit takes effect without a restart.
|
|
26
|
+
* @param ctx - the plugin context (systemPrompt injected).
|
|
27
|
+
* @param config - resolved plugin config (schema defaults applied by the loader).
|
|
28
|
+
*/
|
|
29
|
+
function apply(ctx, config) {
|
|
30
|
+
let current = () => config ?? {};
|
|
31
|
+
let disposeSection;
|
|
32
|
+
const sync = () => {
|
|
33
|
+
if (disposeSection !== void 0) {
|
|
34
|
+
disposeSection();
|
|
35
|
+
disposeSection = void 0;
|
|
36
|
+
}
|
|
37
|
+
if ((current().enabled ?? true) === false) return;
|
|
38
|
+
if ((current().announceToAgent ?? DEFAULT_ANNOUNCE) === false) return;
|
|
39
|
+
disposeSection = ctx.systemPrompt.section({
|
|
40
|
+
name: "plugin:task-board",
|
|
41
|
+
order: SECTION_ORDER,
|
|
42
|
+
text: TASK_BOARD_GUIDANCE
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
installSettingsSection(ctx, TASK_BOARD_SETTINGS_NAMESPACE, Config, config ?? {}, {
|
|
46
|
+
setSource: (source) => {
|
|
47
|
+
current = source;
|
|
48
|
+
},
|
|
49
|
+
onChange: sync
|
|
50
|
+
});
|
|
51
|
+
sync();
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { Config, TASK_BOARD_GUIDANCE, TASK_BOARD_SETTINGS_NAMESPACE, apply, inject };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared chrome for the plugin settings card: a disclosure header naming the
|
|
3
|
+
* plugin and what its settings govern, the controls inside, and the save that
|
|
4
|
+
* writes them. Renders nothing while the namespace is unavailable — a
|
|
5
|
+
* deployment that does not compose the owning plugin should show no trace of
|
|
6
|
+
* it. Mirrors the official ui-plugin-config PluginCard in a self-contained
|
|
7
|
+
* slice (this package must not depend on a sibling UI package).
|
|
8
|
+
*/
|
|
9
|
+
import { type ReactNode } from 'react';
|
|
10
|
+
import type { CardShell } from './settings-form.ts';
|
|
11
|
+
import type { SettingsCardKey } from './locales.ts';
|
|
12
|
+
/** Card chrome shared by every plugin settings card. */
|
|
13
|
+
export interface PluginSettingsCardProps {
|
|
14
|
+
/** Locale reader for this card's copy. */
|
|
15
|
+
t: (key: SettingsCardKey) => string;
|
|
16
|
+
/** Locale key of the plugin's name. */
|
|
17
|
+
titleKey: SettingsCardKey;
|
|
18
|
+
/** Locale key of the line describing what this plugin's settings govern. */
|
|
19
|
+
descriptionKey: SettingsCardKey;
|
|
20
|
+
/** The card's form state: availability, writability, and what a save would do. */
|
|
21
|
+
state: CardShell;
|
|
22
|
+
/** Write every staged edit. */
|
|
23
|
+
onSave: () => void;
|
|
24
|
+
/** Drop every staged edit. */
|
|
25
|
+
onDiscard: () => void;
|
|
26
|
+
/** The plugin's controls. */
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Render one plugin settings card.
|
|
31
|
+
* @param props - the plugin's copy keys, its form state, and its controls.
|
|
32
|
+
* @returns the card, or nothing when the namespace is unavailable.
|
|
33
|
+
*/
|
|
34
|
+
export declare function PluginSettingsCard(props: PluginSettingsCardProps): import("react").JSX.Element | null;
|
|
35
|
+
/** Props every field control needs regardless of its value type. */
|
|
36
|
+
export interface FieldProps {
|
|
37
|
+
/** Stable id associating the label with its control. */
|
|
38
|
+
id: string;
|
|
39
|
+
/** Visible label. */
|
|
40
|
+
label: string;
|
|
41
|
+
/** One-line explanation rendered under the control. */
|
|
42
|
+
hint: string;
|
|
43
|
+
/** Draft text this control renders. */
|
|
44
|
+
text: string;
|
|
45
|
+
/** True when saving would leave a user-layer entry for this field. */
|
|
46
|
+
overridden: boolean;
|
|
47
|
+
/** True when the draft is not a value this field accepts. */
|
|
48
|
+
invalid: boolean;
|
|
49
|
+
/** Copy for the overridden badge. */
|
|
50
|
+
overriddenLabel: string;
|
|
51
|
+
/** Copy for the reset control. */
|
|
52
|
+
resetLabel: string;
|
|
53
|
+
/** Copy shown in place of the hint while the draft is invalid. */
|
|
54
|
+
invalidLabel: string;
|
|
55
|
+
/** Disables every control (read-only document, or an unavailable namespace). */
|
|
56
|
+
disabled: boolean;
|
|
57
|
+
/** Stage draft text. */
|
|
58
|
+
onEdit: (text: string) => void;
|
|
59
|
+
/** Stage a clear so the field re-inherits the composition layer. */
|
|
60
|
+
onReset: () => void;
|
|
61
|
+
}
|
|
62
|
+
/** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */
|
|
63
|
+
export declare function ValueField(props: FieldProps & {
|
|
64
|
+
/** Hints a numeric keypad without narrowing what the control accepts. */
|
|
65
|
+
numeric?: boolean;
|
|
66
|
+
/** Placeholder shown while the draft is empty. */
|
|
67
|
+
placeholder?: string;
|
|
68
|
+
}): import("react").JSX.Element;
|
|
69
|
+
/** A staged boolean field: 继承 / 开 / 关. */
|
|
70
|
+
export declare function BooleanField(props: FieldProps & {
|
|
71
|
+
/** Copy for the inherit option. */
|
|
72
|
+
inheritLabel: string;
|
|
73
|
+
/** Copy for the on option. */
|
|
74
|
+
onLabel: string;
|
|
75
|
+
/** Copy for the off option. */
|
|
76
|
+
offLabel: string;
|
|
77
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The task-board settings card: whether the board announces itself in every
|
|
3
|
+
* agent's system prompt. Registers into the `settings.plugin.item` slot the
|
|
4
|
+
* plugin-configuration section renders, bound to the `task-board` settings
|
|
5
|
+
* namespace.
|
|
6
|
+
*/
|
|
7
|
+
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
8
|
+
import type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
|
|
9
|
+
import { type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts';
|
|
10
|
+
/** The task-board fields this card edits (the namespace's full schema). */
|
|
11
|
+
export interface TaskBoardSettings {
|
|
12
|
+
/** Master switch for the plugin. */
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
/** Whether the board announces itself in every agent's system prompt. */
|
|
15
|
+
announceToAgent?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** What the task-board card renders. */
|
|
18
|
+
export interface TaskBoardSettingsCardState extends CardShell {
|
|
19
|
+
/** Master switch. */
|
|
20
|
+
enabled: CardFieldState;
|
|
21
|
+
/** System-prompt announcement flag. */
|
|
22
|
+
announceToAgent: CardFieldState;
|
|
23
|
+
}
|
|
24
|
+
/** The registration-side face the card's slot entry injects. */
|
|
25
|
+
export interface TaskBoardSettingsCardFace extends CardActions {
|
|
26
|
+
hooks: {
|
|
27
|
+
/** Card snapshot bound by the renderer as useTaskBoardSettingsCard. */
|
|
28
|
+
taskBoardSettingsCard: SnapshotStore<TaskBoardSettingsCardState>;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Bridges the `task-board` scope onto the card's staged form. */
|
|
32
|
+
export declare class TaskBoardSettingsCardController {
|
|
33
|
+
private readonly form;
|
|
34
|
+
private readonly store;
|
|
35
|
+
/** @param scope - the bound settings scope for the `task-board` namespace. */
|
|
36
|
+
constructor(scope: SettingsScope<TaskBoardSettings>);
|
|
37
|
+
private projection;
|
|
38
|
+
/**
|
|
39
|
+
* Build the face the card's slot registration injects.
|
|
40
|
+
* @returns the card's snapshot and its form actions.
|
|
41
|
+
*/
|
|
42
|
+
inject(): TaskBoardSettingsCardFace;
|
|
43
|
+
}
|
|
44
|
+
/** Props the renderer binds for the task-board card. */
|
|
45
|
+
export type TaskBoardSettingsCardProps = PropsRuntime<'web-ui.plugin.item'> & PropsLocale<'task-board'> & InjectFace<TaskBoardSettingsCardFace>;
|
|
46
|
+
/**
|
|
47
|
+
* Render the task-board card.
|
|
48
|
+
* @param props - locale copy, the card snapshot, and its form actions.
|
|
49
|
+
* @returns the card.
|
|
50
|
+
*/
|
|
51
|
+
export declare function TaskBoardSettingsCard(props: TaskBoardSettingsCardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Confirm overlay props. */
|
|
2
|
+
export interface ConfirmDialogProps {
|
|
3
|
+
title: string;
|
|
4
|
+
message: string;
|
|
5
|
+
confirmLabel: string;
|
|
6
|
+
/** Render the confirm button in the danger style. */
|
|
7
|
+
danger?: boolean;
|
|
8
|
+
onCancel: () => void;
|
|
9
|
+
onConfirm: () => void;
|
|
10
|
+
}
|
|
11
|
+
/** Small confirm overlay. */
|
|
12
|
+
export declare function ConfirmDialog({ title, message, confirmLabel, danger, onCancel, onConfirm }: ConfirmDialogProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task card: the board's column item. Clicking opens the task detail — it
|
|
3
|
+
* never executes anything directly (detail holds the Run button).
|
|
4
|
+
*/
|
|
5
|
+
import type { TaskRecord } from '../../core/tasks.ts';
|
|
6
|
+
/** Compact relative/absolute time label. */
|
|
7
|
+
export declare function formatTime(ms: number): string;
|
|
8
|
+
/** One card in a column. */
|
|
9
|
+
export declare function TaskCard({ task, onClick }: {
|
|
10
|
+
task: TaskRecord;
|
|
11
|
+
onClick: () => void;
|
|
12
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BoardController } from '../../core/controller.ts';
|
|
2
|
+
import { type TaskRecord } from '../../core/tasks.ts';
|
|
3
|
+
/** Task detail overlay. */
|
|
4
|
+
export declare function TaskDetail({ controller, task }: {
|
|
5
|
+
controller: BoardController;
|
|
6
|
+
task: TaskRecord;
|
|
7
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BoardController } from '../core/controller.ts';
|
|
2
|
+
/** The injected board container (kept in the DOM, hidden when inactive). */
|
|
3
|
+
export declare const BOARD_VIEW_SELECTOR = "[data-dsh-taskboard-view]";
|
|
4
|
+
/**
|
|
5
|
+
* Mount the board React tree into the center column and bind its visibility
|
|
6
|
+
* to the controller's boardOpen state.
|
|
7
|
+
* @param controller - the board controller driving the view.
|
|
8
|
+
* @returns disposer unmounting the tree and restoring the column.
|
|
9
|
+
*/
|
|
10
|
+
export declare function mountBoard(controller: BoardController): () => void;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task-board client plugin: wires the framework-free core (controller,
|
|
3
|
+
* execution service, store) to the real client runtime and mounts the two
|
|
4
|
+
* DOM surfaces — the sidebar entry row and the board view in the center
|
|
5
|
+
* column.
|
|
6
|
+
*
|
|
7
|
+
* Failure policy: DOM mounting problems are logged, never thrown — the web
|
|
8
|
+
* shell fails the whole boot when a plugin apply throws, and an external
|
|
9
|
+
* plugin must not take the GUI down.
|
|
10
|
+
*/
|
|
11
|
+
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
12
|
+
import { type TaskBoardKey } from './locales.ts';
|
|
13
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
14
|
+
interface LocaleNamespaceMap {
|
|
15
|
+
/** Task-board surface copy. */
|
|
16
|
+
'task-board': TaskBoardKey;
|
|
17
|
+
}
|
|
18
|
+
interface SlotMap {
|
|
19
|
+
/**
|
|
20
|
+
* The child slot the Web UI plugin group declares; this card registers
|
|
21
|
+
* into the group instead of the top-level `settings.plugin.item` list.
|
|
22
|
+
* Spelled here with the same shape so this package can register without
|
|
23
|
+
* depending on the sibling UI package.
|
|
24
|
+
*/
|
|
25
|
+
'web-ui.plugin.item': {
|
|
26
|
+
kind: 'list';
|
|
27
|
+
scope: 'root';
|
|
28
|
+
owner: SettingsPluginItemOwnerProps;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Owner share of a plugin card (the section supplies nothing). */
|
|
33
|
+
export interface SettingsPluginItemOwnerProps {
|
|
34
|
+
/** Marker field: card owner props are intentionally empty. */
|
|
35
|
+
children?: never;
|
|
36
|
+
}
|
|
37
|
+
/** Required services (fiber inject waiting — the runtime must be up first). */
|
|
38
|
+
export declare const inject: string[];
|
|
39
|
+
/**
|
|
40
|
+
* Mount the task board.
|
|
41
|
+
* @param ctx - client root context (services: sessions, workspaces).
|
|
42
|
+
*/
|
|
43
|
+
export declare function apply(ctx: ClientContext): void;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task-board copy: zh-first dictionaries with an English fallback, selected
|
|
3
|
+
* by the document language. Kept dependency-free (no dsh locale service) so
|
|
4
|
+
* the DOM-injected entry row and the standalone board tree share one tiny
|
|
5
|
+
* lookup.
|
|
6
|
+
*/
|
|
7
|
+
/** zh dictionary (key-set source of truth). */
|
|
8
|
+
export declare const zh: {
|
|
9
|
+
'entry.label': string;
|
|
10
|
+
'board.title': string;
|
|
11
|
+
'board.close': string;
|
|
12
|
+
'board.new': string;
|
|
13
|
+
'board.search': string;
|
|
14
|
+
'board.empty': string;
|
|
15
|
+
'board.filterAll': string;
|
|
16
|
+
'board.status': string;
|
|
17
|
+
'board.status.backlog': string;
|
|
18
|
+
'board.status.todo': string;
|
|
19
|
+
'board.status.running': string;
|
|
20
|
+
'board.status.done': string;
|
|
21
|
+
'board.status.failed': string;
|
|
22
|
+
'board.runs': string;
|
|
23
|
+
'board.updated': string;
|
|
24
|
+
'board.created': string;
|
|
25
|
+
'new.title': string;
|
|
26
|
+
'new.titlePlaceholder': string;
|
|
27
|
+
'new.description': string;
|
|
28
|
+
'new.descriptionPlaceholder': string;
|
|
29
|
+
'new.prompt': string;
|
|
30
|
+
'new.promptPlaceholder': string;
|
|
31
|
+
'new.submit': string;
|
|
32
|
+
'new.cancel': string;
|
|
33
|
+
'new.required': string;
|
|
34
|
+
'detail.title': string;
|
|
35
|
+
'detail.close': string;
|
|
36
|
+
'detail.prompt': string;
|
|
37
|
+
'detail.description': string;
|
|
38
|
+
'detail.execution': string;
|
|
39
|
+
'detail.noExecution': string;
|
|
40
|
+
'detail.run': string;
|
|
41
|
+
'detail.rerun': string;
|
|
42
|
+
'detail.delete': string;
|
|
43
|
+
'detail.viewSession': string;
|
|
44
|
+
'detail.noSession': string;
|
|
45
|
+
'detail.executionStarted': string;
|
|
46
|
+
'detail.executionEnded': string;
|
|
47
|
+
'detail.result.succeeded': string;
|
|
48
|
+
'detail.result.failed': string;
|
|
49
|
+
'detail.result.cancelled': string;
|
|
50
|
+
'detail.result.running': string;
|
|
51
|
+
'delete.title': string;
|
|
52
|
+
'delete.confirm': string;
|
|
53
|
+
'delete.ok': string;
|
|
54
|
+
'delete.cancel': string;
|
|
55
|
+
'status.move.backlog': string;
|
|
56
|
+
'status.move.todo': string;
|
|
57
|
+
'exec.error.noWorkspace': string;
|
|
58
|
+
'exec.error.promptRejected': string;
|
|
59
|
+
'run.failed': string;
|
|
60
|
+
'time.justNow': string;
|
|
61
|
+
'detail.schedule': string;
|
|
62
|
+
'detail.schedule.enable': string;
|
|
63
|
+
'detail.schedule.cron': string;
|
|
64
|
+
'detail.schedule.presets': string;
|
|
65
|
+
'detail.schedule.preset.daily9': string;
|
|
66
|
+
'detail.schedule.preset.hourly': string;
|
|
67
|
+
'detail.schedule.preset.tenMin': string;
|
|
68
|
+
'detail.schedule.preset.weeklyMon9': string;
|
|
69
|
+
'detail.schedule.nextRun': string;
|
|
70
|
+
'detail.schedule.lastTriggered': string;
|
|
71
|
+
'detail.schedule.invalid': string;
|
|
72
|
+
'detail.schedule.notScheduled': string;
|
|
73
|
+
'detail.schedule.dueSoon': string;
|
|
74
|
+
'card.scheduled': string;
|
|
75
|
+
'settings.title': string;
|
|
76
|
+
'settings.description': string;
|
|
77
|
+
'settings.enabled': string;
|
|
78
|
+
'settings.enabledHint': string;
|
|
79
|
+
'settings.announceToAgent': string;
|
|
80
|
+
'settings.announceToAgentHint': string;
|
|
81
|
+
'settings.inherit': string;
|
|
82
|
+
'settings.on': string;
|
|
83
|
+
'settings.off': string;
|
|
84
|
+
'settings.overridden': string;
|
|
85
|
+
'settings.reset': string;
|
|
86
|
+
'settings.readOnly': string;
|
|
87
|
+
'settings.expand': string;
|
|
88
|
+
'settings.collapse': string;
|
|
89
|
+
'settings.save': string;
|
|
90
|
+
'settings.saving': string;
|
|
91
|
+
'settings.discard': string;
|
|
92
|
+
'settings.unsaved': string;
|
|
93
|
+
'settings.saveFailed': string;
|
|
94
|
+
'settings.invalidNumber': string;
|
|
95
|
+
};
|
|
96
|
+
/** en dictionary, complete against the zh key set. */
|
|
97
|
+
export declare const en: Record<keyof typeof zh, string>;
|
|
98
|
+
/** The dictionary key union. */
|
|
99
|
+
export type TaskBoardKey = keyof typeof zh;
|
|
100
|
+
/** The settings-card slice of the task-board dictionary. */
|
|
101
|
+
export type SettingsCardKey = TaskBoardKey;
|
|
102
|
+
/** Active dictionary, picked by the document language at call time. */
|
|
103
|
+
export declare function dictionary(): Record<TaskBoardKey, string>;
|
|
104
|
+
/** Translate a key with optional {name} template params. */
|
|
105
|
+
export declare function t(key: TaskBoardKey, params?: Record<string, string>): string;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Staged form model behind the plugin settings card. A card stages what the
|
|
3
|
+
* user types and writes it only when they save — the settings write is a
|
|
4
|
+
* durable, revision-fenced document mutation, so staging keeps what is on
|
|
5
|
+
* screen exactly what a save would store. Mirrors the official
|
|
6
|
+
* ui-plugin-config card-store pattern in a self-contained slice: this
|
|
7
|
+
* package must not depend on a sibling UI package.
|
|
8
|
+
*/
|
|
9
|
+
import type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
|
|
10
|
+
/** The write one field's staged text performs when the card is saved. */
|
|
11
|
+
export type FieldWrite = {
|
|
12
|
+
kind: 'set';
|
|
13
|
+
value: unknown;
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'clear';
|
|
16
|
+
};
|
|
17
|
+
/** How one field converts between its stored value and its draft text. */
|
|
18
|
+
export interface FieldSpec {
|
|
19
|
+
/** Field name inside the namespace section. */
|
|
20
|
+
field: string;
|
|
21
|
+
/** Render a stored value as draft text; the empty string when the section carries none. */
|
|
22
|
+
format: (value: unknown) => string;
|
|
23
|
+
/**
|
|
24
|
+
* The write this draft text stages, or undefined when the text is not a
|
|
25
|
+
* value this field accepts — which blocks the save rather than discarding it.
|
|
26
|
+
*/
|
|
27
|
+
parse: (text: string) => FieldWrite | undefined;
|
|
28
|
+
}
|
|
29
|
+
/** One field as the card renders it. */
|
|
30
|
+
export interface FieldState {
|
|
31
|
+
/** Draft text the control renders. */
|
|
32
|
+
text: string;
|
|
33
|
+
/** Whether saving would leave a user-layer entry for this field. */
|
|
34
|
+
overridden: boolean;
|
|
35
|
+
/** Whether the draft is not a value this field accepts, which blocks saving. */
|
|
36
|
+
invalid: boolean;
|
|
37
|
+
}
|
|
38
|
+
/** Form state every plugin settings card shares. */
|
|
39
|
+
export interface CardShell {
|
|
40
|
+
/** False while the namespace is not served to this client; the card renders nothing. */
|
|
41
|
+
available: boolean;
|
|
42
|
+
/** Whether the Host document accepts writes. */
|
|
43
|
+
writable: boolean;
|
|
44
|
+
/** Whether the form holds edits that a save would write. */
|
|
45
|
+
dirty: boolean;
|
|
46
|
+
/** Whether any staged draft is invalid, which blocks the save. */
|
|
47
|
+
invalid: boolean;
|
|
48
|
+
/** Whether a save is crossing the wire. */
|
|
49
|
+
saving: boolean;
|
|
50
|
+
/** Whether the last save did not land as staged; cleared by the next edit or save. */
|
|
51
|
+
failed: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** The write actions the card's slot entry injects. */
|
|
54
|
+
export interface CardActions {
|
|
55
|
+
/** Stage draft text for one field. */
|
|
56
|
+
edit: (field: string, text: string) => void;
|
|
57
|
+
/** Stage a clear, so saving lets the field re-inherit the composition layer. */
|
|
58
|
+
resetField: (field: string) => void;
|
|
59
|
+
/** Write every staged edit, then re-seed from what the Host accepted. */
|
|
60
|
+
save: () => void;
|
|
61
|
+
/** Drop every staged edit. */
|
|
62
|
+
discard: () => void;
|
|
63
|
+
}
|
|
64
|
+
/** A whole-number field. An empty draft clears the field; any other draft that is not a finite number blocks the save. */
|
|
65
|
+
export declare function numberField(field: string): FieldSpec;
|
|
66
|
+
/** A free-text field. An empty draft clears the field. */
|
|
67
|
+
export declare function textField(field: string): FieldSpec;
|
|
68
|
+
/** A boolean field, edited through true/false draft text. */
|
|
69
|
+
export declare function booleanField(field: string): FieldSpec;
|
|
70
|
+
/**
|
|
71
|
+
* Stages one card's edits over one settings namespace and writes them on save.
|
|
72
|
+
*
|
|
73
|
+
* The Host is the only authority on whether a value was accepted — its
|
|
74
|
+
* validators own the constraints no schema can express — so the outcome is
|
|
75
|
+
* read back from the section rather than predicted here. A save that did not
|
|
76
|
+
* land keeps its drafts, so the user can correct them instead of retyping.
|
|
77
|
+
*/
|
|
78
|
+
export declare class CardForm<T> {
|
|
79
|
+
private readonly scope;
|
|
80
|
+
private readonly specs;
|
|
81
|
+
private readonly staged;
|
|
82
|
+
private readonly listeners;
|
|
83
|
+
private saving;
|
|
84
|
+
private failed;
|
|
85
|
+
/** @param scope - the bound settings scope for this card's namespace. */
|
|
86
|
+
constructor(scope: SettingsScope<T>, specs: FieldSpec[]);
|
|
87
|
+
/** Publish a projection of this form, rebuilt whenever the scope or a draft changes. */
|
|
88
|
+
bind<S>(project: () => S): SnapshotStore<S>;
|
|
89
|
+
/** Read the card-level state: what the Host serves, and what a save would do. */
|
|
90
|
+
shell(): CardShell;
|
|
91
|
+
/** Read one field's state from the effective section and its staged draft. */
|
|
92
|
+
field(field: string): FieldState;
|
|
93
|
+
/** The actions the card's slot registration injects. */
|
|
94
|
+
actions(): CardActions;
|
|
95
|
+
/**
|
|
96
|
+
* Write every staged edit, then re-seed from what the Host accepted.
|
|
97
|
+
* @returns settlement after every write and the read-back.
|
|
98
|
+
*/
|
|
99
|
+
save(): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Every staged edit a save would write. An entry whose draft is not a value
|
|
102
|
+
* its field accepts carries no write: the form is still dirty, and the save
|
|
103
|
+
* refuses rather than dropping the edit. A staged edit that matches the
|
|
104
|
+
* effective section is not a write at all.
|
|
105
|
+
* @returns the planned writes, in the order the fields were staged.
|
|
106
|
+
*/
|
|
107
|
+
private plan;
|
|
108
|
+
private clear;
|
|
109
|
+
private store;
|
|
110
|
+
private stage;
|
|
111
|
+
private specOf;
|
|
112
|
+
private snapshotOf;
|
|
113
|
+
private sectionValue;
|
|
114
|
+
private baseValue;
|
|
115
|
+
private userLayer;
|
|
116
|
+
private stored;
|
|
117
|
+
private publish;
|
|
118
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidebar entry injection.
|
|
3
|
+
*
|
|
4
|
+
* dsh's sidebar shell exposes no slot an external plugin can register into
|
|
5
|
+
* (`sidebar.workspaces` / `sidebar.settings` are single-occupant and already
|
|
6
|
+
* taken), so — following the skin precedent of DOM-level extension — the
|
|
7
|
+
* entry row is injected between the shell's New Session button and the
|
|
8
|
+
* workspace browser. The injection self-heals: a MutationObserver watches the
|
|
9
|
+
* sidebar root and re-inserts the row whenever a React re-render displaces it
|
|
10
|
+
* (re-insertion happens in the same frame, before paint, so no flicker).
|
|
11
|
+
*
|
|
12
|
+
* The row is plain DOM (no React tree) so it can never disturb the shell's
|
|
13
|
+
* reconciliation; the board view it toggles is a separate React root mounted
|
|
14
|
+
* in the center column (see board-mount.ts).
|
|
15
|
+
*/
|
|
16
|
+
import type { BoardController } from '../core/controller.ts';
|
|
17
|
+
/** Stable data attribute identifying the injected entry row. */
|
|
18
|
+
export declare const ENTRY_SELECTOR = "[data-dsh-taskboard-entry]";
|
|
19
|
+
/**
|
|
20
|
+
* Mount the sidebar entry, waiting for the shell to render and self-healing
|
|
21
|
+
* on later React re-renders.
|
|
22
|
+
* @param controller - the board controller the entry toggles.
|
|
23
|
+
* @returns disposer removing the entry and its observers.
|
|
24
|
+
*/
|
|
25
|
+
export declare function mountSidebarEntry(controller: BoardController): () => void;
|