@linxin666/dsh-client-ui-task-board 0.3.24 → 0.4.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/icon.svg +3 -0
- package/lib/client.js +154 -115
- package/lib/client.js.map +1 -1
- package/lib/index.js +109 -898
- package/lib/types/client/PluginSettingsCard.d.ts +4 -0
- package/lib/types/client/TaskBoardSettingsCard.d.ts +5 -5
- package/lib/types/client/index.d.ts +43 -10
- package/lib/types/client/main-session.d.ts +32 -0
- package/lib/types/client/plugin-card-seat.d.ts +23 -16
- package/lib/types/client/settings-form.d.ts +17 -17
- package/lib/types/client/sidebar-entry-core.d.ts +0 -32
- package/lib/types/core/controller.d.ts +10 -8
- package/lib/types/http.d.ts +18 -1
- package/lib/types/index.d.ts +72 -17
- package/package.json +30 -25
- package/src/client/PluginSettingsCard.tsx +7 -2
- package/src/client/TaskBoardSettingsCard.tsx +7 -5
- package/src/client/board.module.css +31 -12
- package/src/client/index.ts +112 -23
- package/src/client/main-session.ts +43 -0
- package/src/client/plugin-card-seat.ts +24 -17
- package/src/client/settings-form.ts +34 -31
- package/src/client/sidebar-entry-core.ts +10 -94
- package/src/client/sidebar-entry.ts +2 -2
- package/src/core/controller.ts +12 -8
- package/src/http.ts +23 -1
- package/src/index.ts +97 -52
|
@@ -47,6 +47,10 @@ export interface PluginSettingsCardProps<TKey extends string = string> {
|
|
|
47
47
|
* edits, so the footer would sit there permanently disabled.
|
|
48
48
|
*/
|
|
49
49
|
hideFooter?: boolean;
|
|
50
|
+
/** Render children even when the settings namespace is not exposed by the host. */
|
|
51
|
+
renderChildrenWhenNotExposed?: boolean;
|
|
52
|
+
/** Hide the 'not exposed' warning banner when the settings namespace is not exposed. */
|
|
53
|
+
hideNotExposedNotice?: boolean;
|
|
50
54
|
/** The plugin's controls. */
|
|
51
55
|
children: ReactNode;
|
|
52
56
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
7
7
|
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
8
|
-
import type {
|
|
8
|
+
import type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
9
9
|
import { type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts';
|
|
10
10
|
/** The task-board fields this card edits (the namespace's full schema). */
|
|
11
11
|
export interface TaskBoardSettings {
|
|
@@ -32,12 +32,12 @@ export interface TaskBoardSettingsCardFace extends CardActions {
|
|
|
32
32
|
taskBoardSettingsCard: SnapshotStore<TaskBoardSettingsCardState>;
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
-
/** Bridges the `task-board`
|
|
35
|
+
/** Bridges the `task-board` settings form onto the card's staged form. */
|
|
36
36
|
export declare class TaskBoardSettingsCardController {
|
|
37
37
|
private readonly form;
|
|
38
38
|
private readonly store;
|
|
39
|
-
/** @param scope - the bound
|
|
40
|
-
constructor(scope:
|
|
39
|
+
/** @param scope - the bound configuration form for the `task-board` namespace. */
|
|
40
|
+
constructor(scope: ConfigForm<TaskBoardSettings>);
|
|
41
41
|
private projection;
|
|
42
42
|
/**
|
|
43
43
|
* Build the face the card's slot registration injects.
|
|
@@ -45,7 +45,7 @@ export declare class TaskBoardSettingsCardController {
|
|
|
45
45
|
*/
|
|
46
46
|
inject(): TaskBoardSettingsCardFace;
|
|
47
47
|
/**
|
|
48
|
-
* Release the card's
|
|
48
|
+
* Release the card's form subscription and bound stores; the slot
|
|
49
49
|
* disposer calls this on teardown.
|
|
50
50
|
*/
|
|
51
51
|
dispose(): void;
|
|
@@ -9,8 +9,30 @@
|
|
|
9
9
|
* plugin must not take the GUI down.
|
|
10
10
|
*/
|
|
11
11
|
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
12
|
-
import type {
|
|
12
|
+
import type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
13
|
+
import { type TaskBoardSettings } from './TaskBoardSettingsCard.tsx';
|
|
13
14
|
import { type TaskBoardKey } from './locales.ts';
|
|
15
|
+
/** Domain-owned description of one settings namespace a family card binds. */
|
|
16
|
+
export interface SettingsFormSpec<T> {
|
|
17
|
+
/** Settings namespace the card edits. */
|
|
18
|
+
namespace: string;
|
|
19
|
+
/**
|
|
20
|
+
* Narrow one wire section; undefined keeps the last accepted value. The
|
|
21
|
+
* shared form already resolves the namespace's own serialized wire schema,
|
|
22
|
+
* so a decoder exists only to narrow beyond that schema.
|
|
23
|
+
*/
|
|
24
|
+
decode?: (section: unknown) => T | undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The family settings binder published by dsh-web-settings. Its `bind` resolves
|
|
28
|
+
* a family namespace to the profile entry id that owns it and hands back the
|
|
29
|
+
* shared configuration form, so it is the only seat that can reach this card's
|
|
30
|
+
* form on a Host whose row id is not the namespace.
|
|
31
|
+
*/
|
|
32
|
+
export interface SettingsFormBinder {
|
|
33
|
+
/** Bind one family settings namespace. */
|
|
34
|
+
bind<T>(spec: SettingsFormSpec<T>): ConfigForm<T>;
|
|
35
|
+
}
|
|
14
36
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
15
37
|
interface LocaleNamespaceMap {
|
|
16
38
|
/** Task-board surface copy. */
|
|
@@ -19,9 +41,9 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
19
41
|
interface SlotMap {
|
|
20
42
|
/**
|
|
21
43
|
* The child slot the Web UI plugin group declares; this card registers
|
|
22
|
-
* into the group
|
|
23
|
-
* Spelled here with the same shape so this
|
|
24
|
-
* depending on the sibling UI package.
|
|
44
|
+
* into the group's list seat rather than the official
|
|
45
|
+
* bundle-configuration seat. Spelled here with the same shape so this
|
|
46
|
+
* package can register without depending on the sibling UI package.
|
|
25
47
|
*/
|
|
26
48
|
'web-ui.plugin.item': {
|
|
27
49
|
kind: 'list';
|
|
@@ -38,13 +60,11 @@ export interface SettingsPluginItemOwnerProps {
|
|
|
38
60
|
declare module '@deepseek-ai/cordis' {
|
|
39
61
|
interface Context {
|
|
40
62
|
/**
|
|
41
|
-
* Optional
|
|
42
|
-
*
|
|
43
|
-
*
|
|
63
|
+
* Optional family settings binder provided by dsh-web-settings; absent
|
|
64
|
+
* when that group plugin is not installed, so callers fall back to the
|
|
65
|
+
* shared configuration forms service.
|
|
44
66
|
*/
|
|
45
|
-
webUiSettings?:
|
|
46
|
-
bind<S>(spec: SettingsScopeSpec<S>): SettingsScope<S>;
|
|
47
|
-
};
|
|
67
|
+
webUiSettings?: SettingsFormBinder;
|
|
48
68
|
}
|
|
49
69
|
}
|
|
50
70
|
/**
|
|
@@ -61,3 +81,16 @@ export declare const inject: string[];
|
|
|
61
81
|
* @param ctx - client root context (services: sessions, workspaces).
|
|
62
82
|
*/
|
|
63
83
|
export declare function apply(ctx: ClientContext): void;
|
|
84
|
+
/**
|
|
85
|
+
* Bind the settings form this card stages over.
|
|
86
|
+
*
|
|
87
|
+
* The family binder (`ctx.get('webUiSettings')`, published by dsh-web-settings)
|
|
88
|
+
* comes first: it is what traces this package's family namespace onto the
|
|
89
|
+
* profile entry id the Host serves the form under, and it keeps the loopback
|
|
90
|
+
* bridge as its own fallback. A page without that group falls back to the
|
|
91
|
+
* shared configuration forms service bound directly at one of this package's
|
|
92
|
+
* own profile entry ids.
|
|
93
|
+
* @param ctx - client root context.
|
|
94
|
+
* @returns the form the settings card reads and writes.
|
|
95
|
+
*/
|
|
96
|
+
export declare function bindSettingsForm(ctx: ClientContext): ConfigForm<TaskBoardSettings>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main-view Session derivation for the multi-instance Client Session model.
|
|
3
|
+
*
|
|
4
|
+
* The Client Session Controller carries no global "current" selection: view
|
|
5
|
+
* selection belongs to the workspace UI, which owns the main-area reference and
|
|
6
|
+
* publishes it through the catalog's per-source ownership counts
|
|
7
|
+
* (`SessionSummary.retainedBy.mainView`). A plugin that needs the Session the
|
|
8
|
+
* main view shows derives it from that marker instead of the removed
|
|
9
|
+
* `SessionListState.current` field.
|
|
10
|
+
*
|
|
11
|
+
* The marker describes view ownership, not authority. It is the right input for
|
|
12
|
+
* presentation and for deciding which view a navigation targets; it is not a
|
|
13
|
+
* business fallback, because source counts never imply visibility or success.
|
|
14
|
+
* @module dsh-web/shared/main-session
|
|
15
|
+
*/
|
|
16
|
+
/** The catalog row subset this helper reads (a `SessionSummary` projection). */
|
|
17
|
+
export interface MainViewOwnedRow<Id extends string = string> {
|
|
18
|
+
/** Catalog row identity. */
|
|
19
|
+
readonly id: Id;
|
|
20
|
+
/** Per-source local ownership counts; absent rows are never owned. */
|
|
21
|
+
readonly retainedBy?: Readonly<Partial<Record<string, number>>> | undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the Session the main view currently shows.
|
|
25
|
+
*
|
|
26
|
+
* Reads the catalog's rows rather than a per-id retain-info source: ownership
|
|
27
|
+
* counts ride the list snapshot, so this neither allocates observers nor opens
|
|
28
|
+
* history, and a subscription to the list still fires when the selection moves.
|
|
29
|
+
* @param byId - the session catalog's rows (`SessionListState.byId`), when available.
|
|
30
|
+
* @returns the main-view session id, or undefined when the main view shows none.
|
|
31
|
+
*/
|
|
32
|
+
export declare function mainViewSessionId<Id extends string>(byId: Readonly<Record<Id, MainViewOwnedRow<Id> | undefined>> | undefined | null): Id | undefined;
|
|
@@ -6,22 +6,24 @@
|
|
|
6
6
|
*
|
|
7
7
|
* - `web-ui.plugin.item` — the list seat declared by the dsh-web-settings
|
|
8
8
|
* group section (this family's own first-level "Web UI plugins" section);
|
|
9
|
-
* - `
|
|
10
|
-
*
|
|
9
|
+
* - `plugins.bundle.config` — the official keyed seat of the harness's plugin
|
|
10
|
+
* manager page, keyed by the bundle's package name and rendered on that
|
|
11
|
+
* bundle's page. alpha.2 removed the `settings.plugin.item` keyed seat of the
|
|
12
|
+
* `ui-settings-plugins` tab that this helper used before, so a card keyed by
|
|
13
|
+
* its settings namespace has no seat to land in any more.
|
|
11
14
|
*
|
|
12
|
-
* SEAT SELECTION IS NOT A DECLARATION PROBE. The official
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* heading and zero cards.
|
|
15
|
+
* SEAT SELECTION IS NOT A DECLARATION PROBE. The official plugin surface
|
|
16
|
+
* belongs to the harness bundle and declares its seats before any external
|
|
17
|
+
* plugin's `apply()` runs, so "is the official seat declared?" answers yes even
|
|
18
|
+
* in the deployment whose whole point is the family group. Choosing on that
|
|
19
|
+
* probe sends every family card to the official page and leaves the group's own
|
|
20
|
+
* section permanently empty — the family of reports where the section renders
|
|
21
|
+
* its heading and zero cards.
|
|
20
22
|
*
|
|
21
23
|
* The signal that actually distinguishes the two deployments is whether
|
|
22
24
|
* dsh-web-settings is loaded: it is the package that owns the group section and
|
|
23
25
|
* it publishes the `webUiSettings` service during `apply()`, which every
|
|
24
|
-
* family plugin already reads for its settings
|
|
26
|
+
* family plugin already reads for its settings form. Group loaded -> the family
|
|
25
27
|
* seat; group absent -> the official seat.
|
|
26
28
|
*
|
|
27
29
|
* The decision is re-evaluated on every `slots/changed` because the group may
|
|
@@ -37,8 +39,8 @@
|
|
|
37
39
|
*/
|
|
38
40
|
/** The family list seat key. */
|
|
39
41
|
export declare const FAMILY_PLUGIN_CARD_SEAT = "web-ui.plugin.item";
|
|
40
|
-
/** The official keyed plugin-card seat key. */
|
|
41
|
-
export declare const OFFICIAL_PLUGIN_CARD_SEAT = "
|
|
42
|
+
/** The official keyed plugin-card seat key (the alpha.2 bundle-configuration seat). */
|
|
43
|
+
export declare const OFFICIAL_PLUGIN_CARD_SEAT = "plugins.bundle.config";
|
|
42
44
|
/** The service dsh-web-settings publishes while it is loaded. */
|
|
43
45
|
export declare const FAMILY_GROUP_SERVICE = "webUiSettings";
|
|
44
46
|
/** The slot-registry member this helper uses (structurally satisfied by ctx.slots). */
|
|
@@ -54,15 +56,20 @@ export interface PluginCardContext {
|
|
|
54
56
|
/** Event subscription seat; absent on an event-less test double. */
|
|
55
57
|
on?(event: string, listener: (...args: never[]) => void): unknown;
|
|
56
58
|
}
|
|
57
|
-
/** Owner share of a
|
|
59
|
+
/** Owner share of a family list-seat card (that seat supplies nothing). */
|
|
58
60
|
export interface SettingsPluginItemOwnerProps {
|
|
59
61
|
/** Marker field: card owner props are intentionally empty. */
|
|
60
62
|
children?: never;
|
|
61
63
|
}
|
|
62
64
|
/** One family plugin's card contribution. */
|
|
63
65
|
export interface PluginCardSeat {
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Npm package name of the bundle this card configures; the official keyed
|
|
68
|
+
* seat dispatches on it. Every family package ships its own bundle patch, so
|
|
69
|
+
* a standalone install lists that package as the bundle whose page renders
|
|
70
|
+
* this card.
|
|
71
|
+
*/
|
|
72
|
+
bundle: string;
|
|
66
73
|
/** Family list-seat entry id. */
|
|
67
74
|
id: string;
|
|
68
75
|
/** Family list-seat sort order. */
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* each plugin's client bundle; mirrors the official ui-plugin-config
|
|
7
7
|
* card-store pattern.
|
|
8
8
|
*/
|
|
9
|
-
import type {
|
|
9
|
+
import type { ConfigForm } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
10
10
|
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
11
11
|
/** The write one field's staged text performs when the card is saved. */
|
|
12
12
|
export type FieldWrite = {
|
|
@@ -86,7 +86,7 @@ export interface CardActions {
|
|
|
86
86
|
/** Drop every staged edit. */
|
|
87
87
|
discard: () => void;
|
|
88
88
|
}
|
|
89
|
-
/** One durable write inside the save's atomic
|
|
89
|
+
/** One durable write inside the save's atomic form mutation. */
|
|
90
90
|
export interface BatchedWrite {
|
|
91
91
|
/** Field this entry writes. */
|
|
92
92
|
field: string;
|
|
@@ -130,20 +130,20 @@ export declare class CardForm<T> {
|
|
|
130
130
|
private readonly specs;
|
|
131
131
|
private readonly staged;
|
|
132
132
|
private readonly listeners;
|
|
133
|
-
/** The
|
|
134
|
-
private readonly
|
|
133
|
+
/** The form subscription installed in the constructor; released by dispose(). */
|
|
134
|
+
private readonly disposeForm;
|
|
135
135
|
private disposed;
|
|
136
136
|
private saving;
|
|
137
137
|
private failed;
|
|
138
138
|
private failedReason;
|
|
139
|
-
/** @param scope - the bound
|
|
140
|
-
constructor(scope:
|
|
139
|
+
/** @param scope - the bound configuration form for this card's namespace. */
|
|
140
|
+
constructor(scope: ConfigForm<T>, specs: FieldSpec[]);
|
|
141
141
|
/**
|
|
142
|
-
* Release the
|
|
142
|
+
* Release the form subscription and every bound store listener. The card
|
|
143
143
|
* must call this on teardown; later calls are no-ops.
|
|
144
144
|
*/
|
|
145
145
|
dispose(): void;
|
|
146
|
-
/** Publish a projection of this form, rebuilt whenever the
|
|
146
|
+
/** Publish a projection of this form, rebuilt whenever the form or a draft changes. */
|
|
147
147
|
bind<S>(project: () => S): SnapshotStore<S>;
|
|
148
148
|
/** Read the card-level state: what the Host serves, and what a save would do. */
|
|
149
149
|
shell(): CardShell;
|
|
@@ -152,19 +152,19 @@ export declare class CardForm<T> {
|
|
|
152
152
|
/** The actions the card's slot registration injects. */
|
|
153
153
|
actions(): CardActions;
|
|
154
154
|
/**
|
|
155
|
-
* Write every staged edit in one atomic
|
|
155
|
+
* Write every staged edit in one atomic form mutation, then re-seed from
|
|
156
156
|
* what the Host accepted.
|
|
157
157
|
*
|
|
158
158
|
* The whole batch rides one mutate, so cross-field validate hooks
|
|
159
159
|
* (baseURL+model) judge it as a unit: the Host either applies every write
|
|
160
|
-
* or refuses the batch. The
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* settled snapshot back
|
|
164
|
-
* fails the whole save. A
|
|
165
|
-
*
|
|
166
|
-
* message. A save that did not land keeps its drafts, so
|
|
167
|
-
* correct them instead of retyping.
|
|
160
|
+
* or refuses the batch. The form contract answers a refusal or a skipped
|
|
161
|
+
* write with `false` (it recovers with a fresh Host view instead of
|
|
162
|
+
* throwing), so the outcome is judged twice: the answer itself, and then the
|
|
163
|
+
* settled snapshot read back one planned write at a time. One missed write
|
|
164
|
+
* fails the whole save. A transport that rejects instead (the dsh-web bridge
|
|
165
|
+
* controller on a dead connection) reports through the same failure path
|
|
166
|
+
* with its rejection message. A save that did not land keeps its drafts, so
|
|
167
|
+
* the user can correct them instead of retyping.
|
|
168
168
|
* @returns settlement after the mutation and the read-back.
|
|
169
169
|
*/
|
|
170
170
|
save(): Promise<void>;
|
|
@@ -1,29 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One trailing action button seated at the entry row's right edge (e.g. a
|
|
3
|
-
* refresh command or a collapse chevron). Rows with actions switch from the
|
|
4
|
-
* classic single-button structure to a container with a main button plus the
|
|
5
|
-
* action buttons (nested interactive elements are invalid HTML); rows without
|
|
6
|
-
* actions keep the classic structure untouched.
|
|
7
|
-
*/
|
|
8
|
-
export interface SidebarEntryAction {
|
|
9
|
-
/** Stable id stamped as data-dsh-entry-action="<id>" (CSS hooks and tests). */
|
|
10
|
-
id: string;
|
|
11
|
-
/** Inline icon markup while the row is active (always, when inactiveIcon is unset). */
|
|
12
|
-
icon: string;
|
|
13
|
-
/**
|
|
14
|
-
* Optional icon while the row is inactive. Setting it makes the action a
|
|
15
|
-
* state mirror (a collapse chevron): the core swaps the icon and stamps
|
|
16
|
-
* aria-expanded on every active-state change. Requires the active bridge.
|
|
17
|
-
*/
|
|
18
|
-
inactiveIcon?: string;
|
|
19
|
-
/** Localized accessible label (aria-label + title); receives the active state. */
|
|
20
|
-
label(active: boolean): string;
|
|
21
|
-
/**
|
|
22
|
-
* Click handler; receives the button so the caller can drive transient
|
|
23
|
-
* affordances (a refresh cooldown) without a re-render.
|
|
24
|
-
*/
|
|
25
|
-
onClick(button: HTMLButtonElement): void;
|
|
26
|
-
}
|
|
27
1
|
/** Per-package configuration for one sidebar entry row. */
|
|
28
2
|
export interface SidebarEntryOptions {
|
|
29
3
|
/** Full attribute name identifying the injected row (idempotency key), e.g. 'data-dsh-ssh-entry'. */
|
|
@@ -57,12 +31,6 @@ export interface SidebarEntryOptions {
|
|
|
57
31
|
};
|
|
58
32
|
/** Click action (open/toggle the owning panel). */
|
|
59
33
|
onToggle(): void;
|
|
60
|
-
/**
|
|
61
|
-
* Optional trailing action buttons at the row's right edge. Requires the
|
|
62
|
-
* package CSS to seat entryMain / entryAction; empty keeps the classic
|
|
63
|
-
* single-button row.
|
|
64
|
-
*/
|
|
65
|
-
actions?: readonly SidebarEntryAction[];
|
|
66
34
|
/** Family-block position: 'before' inserts ahead of sibling plugin rows, 'after' behind them. */
|
|
67
35
|
position: 'before' | 'after';
|
|
68
36
|
/**
|
|
@@ -30,16 +30,18 @@ export interface TaskBoardTransport {
|
|
|
30
30
|
*/
|
|
31
31
|
parseDraft?(request: TaskBoardParseRequest, signal?: AbortSignal): Promise<TaskBoardParseDraft>;
|
|
32
32
|
}
|
|
33
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* The sessions face the controller needs for navigation awareness. The Client
|
|
35
|
+
* Session Controller carries no global selection since 0.1.6-alpha.2, so the
|
|
36
|
+
* wiring resolves the main-view Session once and exposes it as current().
|
|
37
|
+
*/
|
|
34
38
|
export interface SessionsControllerFace {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
subscribe(fn: () => void): () => void;
|
|
40
|
-
};
|
|
41
|
-
/** Select a session as current (navigates the conversation view). */
|
|
39
|
+
/** The Session the main view currently shows, when any. */
|
|
40
|
+
current(): string | undefined;
|
|
41
|
+
/** Navigate the main view to a Session. */
|
|
42
42
|
open(id: string): void;
|
|
43
|
+
/** Subscribe to catalog changes; selection ownership rides the same snapshot. */
|
|
44
|
+
subscribe(fn: () => void): () => void;
|
|
43
45
|
}
|
|
44
46
|
/** Controller dependencies (all swappable in tests). */
|
|
45
47
|
export interface ControllerDeps {
|
package/lib/types/http.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared JSON body/response helpers for the host route families: one strict
|
|
3
3
|
* bounded body reader, one lenient bounded body reader, one JSON object
|
|
4
|
-
* narrow,
|
|
4
|
+
* narrow, one JSON writer, and the outbound request-init helper that keeps a
|
|
5
|
+
* host fetch body decodable (withIdentityEncoding). Previously the readers
|
|
6
|
+
* were copy-pasted across the
|
|
5
7
|
* package route files (routes.ts, update-routes.ts, mobile-api.ts, and each
|
|
6
8
|
* family's route module) with drifting contracts: body caps ranging 4 KiB to
|
|
7
9
|
* 1 MiB and four distinct overflow behaviors (reject, undefined, null, throw).
|
|
@@ -34,6 +36,21 @@ export declare function readJsonBody(req: IncomingMessage, opts?: {
|
|
|
34
36
|
}): Promise<unknown | null>;
|
|
35
37
|
/** Narrow a value to a JSON object, or undefined when it is not one. */
|
|
36
38
|
export declare function asJsonObject(value: unknown): Record<string, unknown> | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Request init that asks a remote origin for an uncompressed body.
|
|
41
|
+
*
|
|
42
|
+
* The DSH host boots `@deepseek-ai/dsh-http-proxy`, whose top-level import of
|
|
43
|
+
* the npm `undici` copy replaces the legacy `undici.globalDispatcher.1` slot
|
|
44
|
+
* Node's built-in `fetch()` reads. That cross-major wrapper drops the
|
|
45
|
+
* `content-encoding` header and automatic decompression, so a plain fetch
|
|
46
|
+
* resolves to raw gzip/brotli/zstd bytes — compressed noise no JSON or text
|
|
47
|
+
* consumer can read. Every host fetch that parses a remote body must request
|
|
48
|
+
* identity encoding. Caller headers survive; `accept-encoding` is forced to
|
|
49
|
+
* `identity` because a caller value has no decoder behind it in this host.
|
|
50
|
+
* @param init - the caller's request init (signal, headers, method, ...).
|
|
51
|
+
* @returns a copy with `accept-encoding: identity` merged in.
|
|
52
|
+
*/
|
|
53
|
+
export declare function withIdentityEncoding(init?: RequestInit): RequestInit;
|
|
37
54
|
/**
|
|
38
55
|
* Write one JSON response. Default headers are the family defaults
|
|
39
56
|
* (content-type and referrer-policy); caller headers are appended or
|
package/lib/types/index.d.ts
CHANGED
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* execution reconciliation, and optional idle-sleep inhibitor. The browser is
|
|
6
6
|
* a same-origin asynchronous view over that service.
|
|
7
7
|
*/
|
|
8
|
-
import type { Context } from '@deepseek-ai/cordis';
|
|
9
|
-
import
|
|
10
|
-
import z from 'schemastery';
|
|
8
|
+
import type { Context, Volatile } from '@deepseek-ai/cordis';
|
|
9
|
+
import z from '@deepseek-ai/schemastery';
|
|
11
10
|
import type { LlmRuntime } from '@deepseek-ai/dsh-llm';
|
|
12
11
|
import { type TaskPermission } from './core/tasks.ts';
|
|
13
12
|
/** Default environment variable holding the authenticated proxy token. */
|
|
@@ -16,24 +15,30 @@ export declare const inject: string[];
|
|
|
16
15
|
/** Model-facing announcement: plugin presence, capabilities, and limits. */
|
|
17
16
|
export declare const TASK_BOARD_GUIDANCE = "\u672C\u673A\u5DF2\u5B89\u88C5 dsh-task-board \u63D2\u4EF6\uFF08DSH Web GUI \u7684\u4EFB\u52A1\u770B\u677F\uFF09\uFF1A\u4FA7\u8FB9\u680F\u300C\u4EFB\u52A1\u770B\u677F\u300D\u5165\u53E3\uFF1B\u5728 dsh-web \u63D2\u4EF6\u5168\u5BB6\u6876\u4ED3\u5E93\uFF08packages/dsh-task-board\uFF09\u7EDF\u4E00\u7EF4\u62A4\uFF0C\u7ECF\u805A\u5408\u5305 web-ui-all \u4E00\u952E\u5B89\u88C5\u3002\u80FD\u529B\uFF1A\u591A\u5217\u770B\u677F\u7BA1\u7406\u4EFB\u52A1\uFF1BHost \u6743\u5A01\u8D26\u672C\uFF1B\u5173\u95ED\u6D4F\u89C8\u5668\u540E\u4ECD\u7531 Host \u6267\u884C\u548C\u7ED3\u7B97\uFF1B\u4EFB\u52A1\u53EF\u9489\u4F4F\u5DE5\u4F5C\u533A\u3001agent \u9884\u8BBE\u548C\u6743\u9650\uFF1B\u652F\u6301 Host \u672C\u5730\u65F6\u533A\u7684 5 \u6BB5 cron\uFF0C\u9519\u8FC7\u7684\u89E6\u53D1\u70B9\u4E0D\u8865\u8DD1\uFF1B\u53EF\u9009\u4E14\u9ED8\u8BA4\u5173\u95ED\u7684\u7A7A\u95F2\u7CFB\u7EDF\u7761\u7720\u4FDD\u62A4\u5141\u8BB8\u5C4F\u5E55\u7184\u706D\uFF0C\u4F46\u4E0D\u627F\u8BFA\u62E6\u622A\u5408\u76D6\u3001\u624B\u52A8\u7761\u7720\u3001\u4F11\u7720\u3001\u5173\u673A\u6216\u5524\u9192\u5DF2\u7761\u7720\u673A\u5668\u3002\u6267\u884C\u6D88\u8017 API \u989D\u5EA6\u3002\u7528\u6237\u63D0\u5230\u300C\u4EFB\u52A1\u770B\u677F / \u770B\u677F / \u5B9A\u65F6\u4EFB\u52A1\u300D\u65F6\u5373\u6307\u672C\u63D2\u4EF6\uFF0C\u8BF7\u636E\u6B64\u534F\u4F5C\u3002\u82E5\u4F60\u540C\u65F6\u7528 todo_write \u7EF4\u62A4\u4F1A\u8BDD\u9876\u90E8\u7684\u53EF\u89C1\u8BA1\u5212\u5217\u8868\uFF0C\u6700\u7EC8\u56DE\u590D\u524D\u5FC5\u987B\u518D\u6B21\u8C03\u7528 todo_write \u6536\u5C3E\uFF1A\u6CA1\u6709\u5269\u4F59\u5DE5\u4F5C\u65F6\u4E0D\u8981\u4FDD\u7559 in_progress\uFF0C\u5DF2\u5B8C\u6210\u7684\u6700\u540E\u4E00\u6B65\u8981\u6807\u4E3A completed\u3002";
|
|
18
17
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* Plugin config, validated by the same-named schemastery schema.
|
|
19
|
+
*
|
|
20
|
+
* This schema IS the board's settings page: the 0.1.7 Host serves one
|
|
21
|
+
* configuration form per profile entry from the entry's own Config, so the
|
|
22
|
+
* three fields the browser card edits are marked volatile — the Loader commits
|
|
23
|
+
* an edit into the running fiber's references without remounting the row (no
|
|
24
|
+
* settings document of the plugin's own exists any more).
|
|
22
25
|
*/
|
|
23
|
-
export declare const TASK_BOARD_SETTINGS_NAMESPACE: SettingsNamespace;
|
|
24
|
-
/** Plugin config, validated by the same-named schemastery schema. */
|
|
25
26
|
export interface Config {
|
|
26
27
|
/**
|
|
27
28
|
* When true (default), a system-prompt section announces the board to every
|
|
28
29
|
* agent. Set false to keep the board silent in prompts; agents then learn
|
|
29
30
|
* about it only when the user mentions it.
|
|
30
31
|
*/
|
|
31
|
-
announceToAgent?: boolean
|
|
32
|
+
announceToAgent?: Volatile<boolean>;
|
|
32
33
|
/** Master switch for the plugin (browser half + host announcement). */
|
|
33
|
-
enabled?: boolean
|
|
34
|
+
enabled?: Volatile<boolean>;
|
|
34
35
|
/** Prevent idle system sleep while sessions run or schedules are armed. */
|
|
35
|
-
preventIdleSleep?: boolean
|
|
36
|
-
/**
|
|
36
|
+
preventIdleSleep?: Volatile<boolean>;
|
|
37
|
+
/**
|
|
38
|
+
* Canonical reverse-proxy Host authorities admitted with a server-side
|
|
39
|
+
* token. Deployment-level, so it stays an ordinary field: editing it reloads
|
|
40
|
+
* the row, which re-registers the routes with the new proxy access.
|
|
41
|
+
*/
|
|
37
42
|
trustedProxyHosts?: string[];
|
|
38
43
|
/** Environment variable whose value the authenticated proxy injects upstream. */
|
|
39
44
|
proxyTokenEnv?: string;
|
|
@@ -44,7 +49,52 @@ export interface Config {
|
|
|
44
49
|
*/
|
|
45
50
|
sessionDefaultPermission?: TaskPermission;
|
|
46
51
|
}
|
|
47
|
-
|
|
52
|
+
/**
|
|
53
|
+
* The schema is left to inference rather than annotated with `z<Config>`: a
|
|
54
|
+
* volatile field's parsed output is a `Volatile` reference while its accepted
|
|
55
|
+
* input stays the plain value, so the two sides no longer share one shape and
|
|
56
|
+
* the annotation would reject the schema the Host must be given.
|
|
57
|
+
*/
|
|
58
|
+
export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
59
|
+
announceToAgent: z<boolean, boolean, "volatile-defined">;
|
|
60
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
61
|
+
preventIdleSleep: z<boolean, boolean, "volatile-defined">;
|
|
62
|
+
trustedProxyHosts: z<string[], string[], "defined">;
|
|
63
|
+
proxyTokenEnv: z<string, string, "defined">;
|
|
64
|
+
sessionDefaultPermission: z<"read-only" | "workspace-write" | "danger-full-access", "read-only" | "workspace-write" | "danger-full-access", "defined">;
|
|
65
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
66
|
+
announceToAgent: z<boolean, boolean, "volatile-defined">;
|
|
67
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
68
|
+
preventIdleSleep: z<boolean, boolean, "volatile-defined">;
|
|
69
|
+
trustedProxyHosts: z<string[], string[], "defined">;
|
|
70
|
+
proxyTokenEnv: z<string, string, "defined">;
|
|
71
|
+
sessionDefaultPermission: z<"read-only" | "workspace-write" | "danger-full-access", "read-only" | "workspace-write" | "danger-full-access", "defined">;
|
|
72
|
+
}>>, "plain">;
|
|
73
|
+
declare module '@deepseek-ai/cordis' {
|
|
74
|
+
interface Events {
|
|
75
|
+
/**
|
|
76
|
+
* Volatile config values were committed into the running fiber without a
|
|
77
|
+
* remount; dispatched to the owning fiber only. Spelled here because the
|
|
78
|
+
* Loader package is not a dependency of this plugin, with the Loader's own
|
|
79
|
+
* shape so the two declarations merge when a Host program carries both.
|
|
80
|
+
* @param paths - changed config paths as key arrays; every value is committed before dispatch.
|
|
81
|
+
* @mode emit
|
|
82
|
+
*/
|
|
83
|
+
'loader/volatile-update'(paths: readonly (readonly string[])[]): void;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Read one config field's current value.
|
|
88
|
+
*
|
|
89
|
+
* The Loader hands schema-volatile fields as stable references it commits in
|
|
90
|
+
* place, so a live value must be read at use time rather than captured when
|
|
91
|
+
* the plugin activates; a plain value (a programmatic mount, or a field the
|
|
92
|
+
* schema does not mark volatile) is returned as it stands.
|
|
93
|
+
* @param field - the config field as the Loader handed it.
|
|
94
|
+
* @param fallback - value to use when the field is absent.
|
|
95
|
+
* @returns the effective field value.
|
|
96
|
+
*/
|
|
97
|
+
export declare function readConfigField<T>(field: Volatile<T> | T | undefined, fallback: T): T;
|
|
48
98
|
/** Resolve proxy access without ever placing the token value in plugin config. */
|
|
49
99
|
export declare function resolveProxyAccess(config: Config | undefined, env?: NodeJS.ProcessEnv): {
|
|
50
100
|
trustedProxyHosts: string[];
|
|
@@ -59,10 +109,15 @@ export declare function resolveProxyAccess(config: Config | undefined, env?: Nod
|
|
|
59
109
|
*/
|
|
60
110
|
export declare function resolveLlmRuntime(ctx: Context): LlmRuntime | undefined;
|
|
61
111
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
112
|
+
* Activate the board's host half: ledger, routes, cron scheduler, power
|
|
113
|
+
* inhibitor, and the model-facing announcement.
|
|
114
|
+
*
|
|
115
|
+
* The effective settings are the config the Host hands this row. The three
|
|
116
|
+
* fields the browser card edits are schema-volatile, so the Loader commits an
|
|
117
|
+
* edit into the running fiber's references instead of remounting the row —
|
|
118
|
+
* `sync` therefore reads them at use time and follows
|
|
119
|
+
* `loader/volatile-update`, the event the Loader emits once it has committed
|
|
120
|
+
* them. Every other field reloads the row, which re-runs this activation.
|
|
66
121
|
* @param ctx - the plugin context (systemPrompt injected).
|
|
67
122
|
* @param config - resolved plugin config (schema defaults applied by the loader).
|
|
68
123
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linxin666/dsh-client-ui-task-board",
|
|
3
3
|
"description": "Host-authoritative task board for the DSH Web GUI with real session execution, Host cron scheduling, and optional cross-platform idle-sleep protection; mounted without DSH source changes.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.1",
|
|
5
|
+
"icon": "icon.svg",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "lib/index.js",
|
|
7
8
|
"types": "lib/types/index.d.ts",
|
|
@@ -23,7 +24,7 @@
|
|
|
23
24
|
},
|
|
24
25
|
"dsh": {
|
|
25
26
|
"engines": {
|
|
26
|
-
"dsh": ">=0.1.
|
|
27
|
+
"dsh": ">=0.1.7-rc.1"
|
|
27
28
|
},
|
|
28
29
|
"bundle": {
|
|
29
30
|
"patch": "./cordis.patch.yml"
|
|
@@ -35,46 +36,49 @@
|
|
|
35
36
|
"@deepseek-ai/dsh-client-ui-renderer",
|
|
36
37
|
"@deepseek-ai/dsh-api-session-controller",
|
|
37
38
|
"@deepseek-ai/dsh-api-workspace-controller",
|
|
38
|
-
"@deepseek-ai/dsh-api-remotes"
|
|
39
|
+
"@deepseek-ai/dsh-api-remotes",
|
|
40
|
+
"@deepseek-ai/dsh-client-ui-workspace"
|
|
39
41
|
],
|
|
40
42
|
"platform": "web"
|
|
41
43
|
}
|
|
42
44
|
},
|
|
43
45
|
"peerDependencies": {
|
|
46
|
+
"@deepseek-ai/dsh": ">=0.1.7-rc.1",
|
|
44
47
|
"react": "^18.2.0"
|
|
45
48
|
},
|
|
46
49
|
"dependencies": {
|
|
47
|
-
"schemastery": "^3.18.
|
|
50
|
+
"@deepseek-ai/schemastery": "^3.18.4"
|
|
48
51
|
},
|
|
49
52
|
"devDependencies": {
|
|
50
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
51
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
52
|
-
"@deepseek-ai/dsh-agent-
|
|
53
|
-
"@deepseek-ai/dsh-api-gateway": "^0.1.
|
|
54
|
-
"@deepseek-ai/dsh-api-remotes": "^0.1.
|
|
55
|
-
"@deepseek-ai/dsh-
|
|
56
|
-
"@deepseek-ai/dsh-api-
|
|
57
|
-
"@deepseek-ai/dsh-
|
|
58
|
-
"@deepseek-ai/dsh-client-
|
|
59
|
-
"@deepseek-ai/dsh-client-
|
|
60
|
-
"@deepseek-ai/dsh-client-
|
|
61
|
-
"@deepseek-ai/dsh-client-ui-
|
|
62
|
-
"@deepseek-ai/dsh-client-ui-
|
|
63
|
-
"@deepseek-ai/dsh-client-ui-
|
|
64
|
-
"@deepseek-ai/dsh-commands": "^0.1.
|
|
65
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.
|
|
66
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
67
|
-
"@deepseek-ai/dsh-system-prompt": "^0.1.
|
|
53
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
54
|
+
"@deepseek-ai/dsh-agent": "^0.1.7-rc.1",
|
|
55
|
+
"@deepseek-ai/dsh-agent-preset-registry": "^0.1.7-rc.1",
|
|
56
|
+
"@deepseek-ai/dsh-api-gateway": "^0.1.7-rc.1",
|
|
57
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.7-rc.1",
|
|
58
|
+
"@deepseek-ai/dsh-api-session-controller": "^0.1.7-rc.1",
|
|
59
|
+
"@deepseek-ai/dsh-api-workspace-controller": "^0.1.7-rc.1",
|
|
60
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.7-rc.1",
|
|
61
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.7-rc.1",
|
|
62
|
+
"@deepseek-ai/dsh-client-store": "^0.1.7-rc.1",
|
|
63
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.7-rc.1",
|
|
64
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.7-rc.1",
|
|
65
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.7-rc.1",
|
|
66
|
+
"@deepseek-ai/dsh-client-ui-workspace": "^0.1.7-rc.1",
|
|
67
|
+
"@deepseek-ai/dsh-commands": "^0.1.7-rc.1",
|
|
68
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.7-rc.1",
|
|
69
|
+
"@deepseek-ai/dsh-settings": "^0.1.7-rc.1",
|
|
70
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.7-rc.1",
|
|
71
|
+
"@deepseek-ai/dsh-workspace": "^0.1.7-rc.1",
|
|
68
72
|
"@types/node": "^22.20.0",
|
|
69
73
|
"@types/react": "~18.3.1",
|
|
70
74
|
"@types/react-dom": "^18.3.5",
|
|
71
|
-
"@vitest/coverage-v8": "^
|
|
75
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
72
76
|
"jsdom": "^25.0.0",
|
|
73
77
|
"react": "^18.3.1",
|
|
74
78
|
"react-dom": "^18.3.1",
|
|
75
79
|
"tsdown": "0.22.2",
|
|
76
80
|
"typescript": "~5.7.2",
|
|
77
|
-
"vitest": "^
|
|
81
|
+
"vitest": "^4.1.11"
|
|
78
82
|
},
|
|
79
83
|
"files": [
|
|
80
84
|
"lib/**/*.js",
|
|
@@ -82,7 +86,8 @@
|
|
|
82
86
|
"lib/**/*.d.ts",
|
|
83
87
|
"lib/**/*.d.ts.map",
|
|
84
88
|
"src",
|
|
85
|
-
"cordis.patch.yml"
|
|
89
|
+
"cordis.patch.yml",
|
|
90
|
+
"icon.svg"
|
|
86
91
|
],
|
|
87
92
|
"license": "Apache-2.0",
|
|
88
93
|
"repository": {
|