@fonlan/dsh-task-kanban 0.2.6 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/lib/client.js +146 -221
- package/lib/client.js.map +1 -1
- package/lib/index.js +65 -41
- package/lib/types/index.d.ts +23 -3
- package/lib/types/server/runner.d.ts +6 -5
- package/lib/types/server/settings.d.ts +34 -26
- package/package.json +39 -39
- package/src/client/board.css +0 -107
- package/src/client/board.tsx +5 -9
- package/src/client/icons.tsx +74 -0
- package/src/client/index.tsx +27 -11
- package/src/client/kanban-state.ts +79 -107
- package/src/client/sections.tsx +10 -136
- package/src/index.ts +7 -5
- package/src/server/runner.ts +33 -18
- package/src/server/settings.ts +69 -36
package/src/server/settings.ts
CHANGED
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* User-facing plugin settings (global parallel worker count, per-session-type
|
|
3
|
-
* model/effort/preset defaults),
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* model/effort/preset defaults), carried by this bundle's entry config: dsh
|
|
4
|
+
* >= 0.1.7 owns plugin settings as entry config (the plugin's `Config`
|
|
5
|
+
* schema), so the face reads the config it was applied with and persists
|
|
6
|
+
* updates through `settings.update`.
|
|
7
7
|
*/
|
|
8
8
|
import type { Context } from '@deepseek-ai/cordis'
|
|
9
9
|
import z from '@deepseek-ai/schemastery'
|
|
10
10
|
import type { KanbanSessionKind, KanbanSettingsShape } from '../shared/card.js'
|
|
11
|
-
import type {} from '@deepseek-ai/dsh-settings'
|
|
12
11
|
|
|
13
12
|
export const KANBAN_SETTINGS_NS = 'task-kanban'
|
|
14
13
|
|
|
14
|
+
/**
|
|
15
|
+
* The entry config schema. Deliberately UNANNOTATED: schemastery >= 3.18.3
|
|
16
|
+
* added a third `Mode` type parameter, so `.default().volatile()` fields have
|
|
17
|
+
* output type `Volatile<T>` and an explicit `z<KanbanSettingsShape>` no longer
|
|
18
|
+
* compiles (the schema's `meta.default` then carries `Volatile<number>`, which
|
|
19
|
+
* is not a `number`). The plain `KanbanSettingsShape` interface stays the
|
|
20
|
+
* plugin-facing shape: `registerSettings` unwraps the live cells below.
|
|
21
|
+
*/
|
|
15
22
|
export const KanbanSettingsSchema = z.object({
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
// Volatile: the settings plane (settings page / settings.update) only
|
|
24
|
+
// writes volatile-marked fields on dsh >= 0.1.7.
|
|
25
|
+
maxParallelWorkers: z.natural().min(1).default(1).volatile(),
|
|
26
|
+
refinementModel: z.string().default('').volatile(),
|
|
27
|
+
refinementProvider: z.string().default('').volatile(),
|
|
28
|
+
refinementReasoningEffort: z.string().default('').volatile(),
|
|
29
|
+
refinementPreset: z.string().default('').volatile(),
|
|
30
|
+
phaseModel: z.string().default('').volatile(),
|
|
31
|
+
phaseProvider: z.string().default('').volatile(),
|
|
32
|
+
phaseReasoningEffort: z.string().default('').volatile(),
|
|
33
|
+
phasePreset: z.string().default('').volatile(),
|
|
25
34
|
})
|
|
26
35
|
|
|
27
36
|
/** The per-session-type default slice a session kind resolves. */
|
|
@@ -47,38 +56,59 @@ export interface KanbanSettingsFace {
|
|
|
47
56
|
|
|
48
57
|
/** Structural settings-service subset; the real service resolves the schema. */
|
|
49
58
|
interface SettingsServiceLike {
|
|
50
|
-
register(ns: unknown, schema: unknown): unknown
|
|
51
59
|
update(ns: unknown, patch: Record<string, unknown>, expectedRevision?: number): Promise<unknown>
|
|
52
60
|
}
|
|
53
61
|
|
|
54
|
-
|
|
62
|
+
/** One config field as the loader hands it over: a stable volatile reference. */
|
|
63
|
+
interface VolatileField<T> {
|
|
64
|
+
get(): T | undefined
|
|
65
|
+
}
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
phaseReasoningEffort: '',
|
|
66
|
-
phasePreset: '',
|
|
67
|
+
/**
|
|
68
|
+
* Dereference one config field. `Config` fields marked `.volatile()` are handed
|
|
69
|
+
* to the plugin as references (`{ get() }`) instead of plain values, so reading
|
|
70
|
+
* them raw yields the reference object — which serializes to `{}` and makes
|
|
71
|
+
* every setting look empty. Non-volatile (plain) configs keep working as-is.
|
|
72
|
+
*/
|
|
73
|
+
function fieldValue<T>(value: unknown, fallback: T): T {
|
|
74
|
+
if (value !== null && typeof value === 'object' && typeof (value as VolatileField<T>).get === 'function') {
|
|
75
|
+
return (value as VolatileField<T>).get() ?? fallback
|
|
67
76
|
}
|
|
77
|
+
return (value as T | undefined) ?? fallback
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const EMPTY_DEFAULTS: KanbanSessionDefaults = { model: '', provider: '', reasoningEffort: '', preset: '' }
|
|
81
|
+
|
|
82
|
+
export function registerSettings(ctx: Context, config: KanbanSettingsShape): KanbanSettingsFace {
|
|
83
|
+
const fields = (config ?? {}) as unknown as Record<string, unknown>
|
|
84
|
+
// Read the references on EVERY access: the settings plane updates them in
|
|
85
|
+
// place (a volatile-only config change does not restart this entry).
|
|
86
|
+
const snapshot = (): KanbanSettingsShape => ({
|
|
87
|
+
maxParallelWorkers: fieldValue(fields.maxParallelWorkers, 1),
|
|
88
|
+
refinementModel: fieldValue(fields.refinementModel, ''),
|
|
89
|
+
refinementProvider: fieldValue(fields.refinementProvider, ''),
|
|
90
|
+
refinementReasoningEffort: fieldValue(fields.refinementReasoningEffort, ''),
|
|
91
|
+
refinementPreset: fieldValue(fields.refinementPreset, ''),
|
|
92
|
+
phaseModel: fieldValue(fields.phaseModel, ''),
|
|
93
|
+
phaseProvider: fieldValue(fields.phaseProvider, ''),
|
|
94
|
+
phaseReasoningEffort: fieldValue(fields.phaseReasoningEffort, ''),
|
|
95
|
+
phasePreset: fieldValue(fields.phasePreset, ''),
|
|
96
|
+
})
|
|
97
|
+
// Optimistic overlay: `settings.update` persists through the profile document
|
|
98
|
+
// and refreshes the references asynchronously, so the write's own caller must
|
|
99
|
+
// still observe the patch it just sent.
|
|
100
|
+
let pending: Partial<KanbanSettingsShape> = {}
|
|
101
|
+
const current = (): KanbanSettingsShape => ({ ...snapshot(), ...pending })
|
|
68
102
|
let service: SettingsServiceLike | undefined
|
|
103
|
+
// Optional settings service: without one the settings still resolve from
|
|
104
|
+
// the entry config; edits just cannot persist.
|
|
69
105
|
ctx.inject(['settings'], (sctx) => {
|
|
70
|
-
service = sctx
|
|
71
|
-
const scope = service.register(KANBAN_SETTINGS_NS, KanbanSettingsSchema) as {
|
|
72
|
-
get(): KanbanSettingsShape
|
|
73
|
-
watch(callback: (next: KanbanSettingsShape) => void): () => void
|
|
74
|
-
}
|
|
75
|
-
current = scope.get()
|
|
76
|
-
scope.watch((next) => { current = next })
|
|
106
|
+
service = (sctx as unknown as { settings?: SettingsServiceLike }).settings
|
|
77
107
|
})
|
|
78
108
|
return {
|
|
79
|
-
get: () => current,
|
|
109
|
+
get: () => current(),
|
|
80
110
|
sessionDefaults: (kind) => {
|
|
81
|
-
const s = current
|
|
111
|
+
const s = current()
|
|
82
112
|
switch (kind) {
|
|
83
113
|
case 'refine':
|
|
84
114
|
return { model: s.refinementModel, provider: s.refinementProvider, reasoningEffort: s.refinementReasoningEffort, preset: s.refinementPreset }
|
|
@@ -108,7 +138,10 @@ export function registerSettings(ctx: Context): KanbanSettingsFace {
|
|
|
108
138
|
if (service === undefined) {
|
|
109
139
|
throw new Error('@fonlan/dsh-task-kanban: settings service is not available in this profile')
|
|
110
140
|
}
|
|
141
|
+
// The settings plane keys plugin settings by PROFILE ENTRY id (the id in
|
|
142
|
+
// cordis.patch.yml), which is what this plugin ships.
|
|
111
143
|
await service.update(KANBAN_SETTINGS_NS, patch as Record<string, unknown>)
|
|
144
|
+
pending = { ...pending, ...patch }
|
|
112
145
|
},
|
|
113
146
|
}
|
|
114
147
|
}
|