@linxin666/dsh-client-ui-task-board 0.4.4 → 0.4.6
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.i18n.yaml +2 -2
- package/README.md +59 -20
- package/README.zh.md +59 -20
- package/lib/client.js +6208 -624
- package/lib/client.js.map +1 -1
- package/lib/index.js +4774 -493
- package/lib/types/client/PluginSettingsCard.d.ts +7 -0
- package/lib/types/client/TaskBoardSettingsCard.d.ts +31 -3
- package/lib/types/client/board/ClampedMarkdown.d.ts +3 -0
- package/lib/types/client/board/ConfirmDialog.d.ts +4 -1
- package/lib/types/client/board/EditTaskModal.d.ts +5 -2
- package/lib/types/client/board/LinkSubtaskModal.d.ts +5 -2
- package/lib/types/client/board/NewTaskModal.d.ts +4 -1
- package/lib/types/client/board/TagManagerModal.d.ts +26 -0
- package/lib/types/client/board/TaskBoard.d.ts +10 -1
- package/lib/types/client/board/TaskCard.d.ts +14 -1
- package/lib/types/client/board/TaskDetail.d.ts +3 -1
- package/lib/types/client/board/TaskForm.d.ts +4 -1
- package/lib/types/client/board/VerificationReport.d.ts +23 -0
- package/lib/types/client/board/card-view.d.ts +113 -0
- package/lib/types/client/board/icons.d.ts +32 -0
- package/lib/types/client/board/overlay.d.ts +69 -0
- package/lib/types/client/board/status-key.d.ts +15 -0
- package/lib/types/client/board/task-markdown.d.ts +19 -0
- package/lib/types/client/index.d.ts +23 -5
- package/lib/types/client/locales.d.ts +168 -1
- package/lib/types/client/native-panel.d.ts +6 -20
- package/lib/types/client/plugin-card-seat.d.ts +5 -0
- package/lib/types/client/schedule-zone.d.ts +50 -0
- package/lib/types/client/seats.d.ts +18 -0
- package/lib/types/client/service.d.ts +32 -0
- package/lib/types/client/settings-form.d.ts +16 -0
- package/lib/types/core/controller.d.ts +46 -11
- package/lib/types/core/extension.d.ts +283 -0
- package/lib/types/core/handover.d.ts +13 -1
- package/lib/types/core/issue-form.d.ts +16 -0
- package/lib/types/core/poll-cadence.d.ts +31 -0
- package/lib/types/core/tasks.d.ts +228 -17
- package/lib/types/core/use-cases/task-schedule.d.ts +68 -10
- package/lib/types/core/use-cases/task-tag.d.ts +48 -0
- package/lib/types/core/use-cases/task-update.d.ts +5 -3
- package/lib/types/core/verification-budget.d.ts +52 -0
- package/lib/types/core/verification.d.ts +753 -0
- package/lib/types/core/workspace-target.d.ts +41 -0
- package/lib/types/host/agent-tools.d.ts +1 -1
- package/lib/types/host/extension-registry.d.ts +111 -0
- package/lib/types/host/llm-dispatch.d.ts +63 -0
- package/lib/types/host/verification-gate.d.ts +95 -0
- package/lib/types/host/verification-runner.d.ts +139 -0
- package/lib/types/host/workspace-evidence.d.ts +53 -0
- package/lib/types/host-ledger.d.ts +133 -14
- package/lib/types/host-runner.d.ts +55 -10
- package/lib/types/host-service.d.ts +205 -11
- package/lib/types/index.d.ts +134 -26
- package/lib/types/protocol.d.ts +92 -10
- package/lib/types/tool-surface.d.ts +71 -0
- package/package.json +28 -31
- package/src/client/PluginSettingsCard.tsx +9 -0
- package/src/client/TaskBoardSettingsCard.tsx +378 -66
- package/src/client/board/ClampedMarkdown.tsx +69 -0
- package/src/client/board/ConfirmDialog.tsx +7 -3
- package/src/client/board/EditTaskModal.tsx +5 -2
- package/src/client/board/LinkSubtaskModal.tsx +12 -7
- package/src/client/board/NewTaskModal.tsx +168 -21
- package/src/client/board/TagManagerModal.tsx +235 -0
- package/src/client/board/TaskBoard.tsx +259 -103
- package/src/client/board/TaskCard.tsx +214 -81
- package/src/client/board/TaskDetail.tsx +289 -43
- package/src/client/board/TaskForm.tsx +13 -3
- package/src/client/board/VerificationReport.tsx +322 -0
- package/src/client/board/card-view.ts +220 -0
- package/src/client/board/icons.tsx +89 -0
- package/src/client/board/overlay.tsx +189 -0
- package/src/client/board/status-key.ts +30 -0
- package/src/client/board/task-markdown.module.css +137 -0
- package/src/client/board/task-markdown.tsx +106 -0
- package/src/client/board-settings.module.css +66 -0
- package/src/client/board.module.css +488 -63
- package/src/client/index.ts +82 -51
- package/src/client/locales.ts +343 -6
- package/src/client/native-panel.tsx +18 -2
- package/src/client/plugin-card-seat.ts +7 -0
- package/src/client/schedule-zone.ts +100 -2
- package/src/client/seats.tsx +58 -0
- package/src/client/service.ts +94 -0
- package/src/client/settings-card.module.css +31 -5
- package/src/client/settings-form.ts +27 -1
- package/src/core/controller.ts +105 -10
- package/src/core/extension.ts +376 -0
- package/src/core/freeze-snapshot.ts +2 -2
- package/src/core/handover.ts +16 -1
- package/src/core/issue-form.ts +19 -0
- package/src/core/poll-cadence.ts +41 -0
- package/src/core/store.ts +80 -15
- package/src/core/tasks.ts +293 -45
- package/src/core/use-cases/task-create.ts +30 -9
- package/src/core/use-cases/task-parent.ts +3 -2
- package/src/core/use-cases/task-schedule.ts +190 -25
- package/src/core/use-cases/task-tag.ts +110 -0
- package/src/core/use-cases/task-update.ts +13 -7
- package/src/core/verification-budget.ts +115 -0
- package/src/core/verification.ts +1594 -0
- package/src/core/workspace-target.ts +59 -0
- package/src/host/agent-tools.ts +125 -38
- package/src/host/extension-registry.ts +509 -0
- package/src/host/llm-dispatch.ts +87 -0
- package/src/host/verification-gate.ts +487 -0
- package/src/host/verification-runner.ts +702 -0
- package/src/host/workspace-evidence.ts +176 -0
- package/src/host-ai.ts +15 -9
- package/src/host-ledger.ts +468 -71
- package/src/host-routes.ts +15 -2
- package/src/host-runner.ts +106 -24
- package/src/host-service.ts +546 -40
- package/src/index.ts +305 -21
- package/src/protocol.ts +226 -28
- package/src/tool-surface.ts +95 -0
- package/lib/invariant.js +0 -6
- package/lib/types/invariant.d.ts +0 -3
- package/src/invariant.ts +0 -4
package/src/client/index.ts
CHANGED
|
@@ -35,6 +35,14 @@ import { HttpTaskBoardHostTransport } from './host-api.ts'
|
|
|
35
35
|
import { reportDailyHeartbeat } from './telemetry.ts'
|
|
36
36
|
import { installPluginCard } from './plugin-card-seat.ts'
|
|
37
37
|
import { createServedEntryForm } from './settings-entry-form.ts'
|
|
38
|
+
import { TaskBoardClientService } from './service.ts'
|
|
39
|
+
import {
|
|
40
|
+
TASK_BOARD_SERVICE_NAME,
|
|
41
|
+
type TaskBoardCardDecorationProps,
|
|
42
|
+
type TaskBoardDetailSectionProps,
|
|
43
|
+
type TaskBoardHostFace,
|
|
44
|
+
type TaskBoardSettingsSectionProps,
|
|
45
|
+
} from '../core/extension.ts'
|
|
38
46
|
|
|
39
47
|
/** Locale namespace this plugin owns. */
|
|
40
48
|
const NS = 'task-board'
|
|
@@ -95,6 +103,13 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
95
103
|
* package can register without depending on the sibling UI package.
|
|
96
104
|
*/
|
|
97
105
|
'web-ui.plugin.item': { kind: 'list'; scope: 'root'; owner: SettingsPluginItemOwnerProps }
|
|
106
|
+
|
|
107
|
+
/** Provider task-detail section; the board declares and renders it. */
|
|
108
|
+
'task-board.detail.section': { kind: 'list'; scope: 'root'; owner: TaskBoardDetailSectionProps }
|
|
109
|
+
/** Provider settings section; the board declares and renders it. */
|
|
110
|
+
'task-board.settings.section': { kind: 'list'; scope: 'root'; owner: TaskBoardSettingsSectionProps }
|
|
111
|
+
/** Provider card decoration; the board declares and renders it. */
|
|
112
|
+
'task-board.card.decoration': { kind: 'list'; scope: 'root'; owner: TaskBoardCardDecorationProps }
|
|
98
113
|
}
|
|
99
114
|
}
|
|
100
115
|
|
|
@@ -118,15 +133,17 @@ declare module '@deepseek-ai/cordis' {
|
|
|
118
133
|
|
|
119
134
|
/**
|
|
120
135
|
* Required services (fiber inject waiting — the runtime must be up first).
|
|
121
|
-
* The generated remote
|
|
122
|
-
* `remote.agentPresets`
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* connection RPC face.
|
|
136
|
+
* The generated remote namespaces are not all hard injects: `remote.session`
|
|
137
|
+
* is one, while `remote.agentPresets` is reached through a scoped inject at
|
|
138
|
+
* use time (see mountUi), because the namespace mounts with the official
|
|
139
|
+
* api-remotes assembly applied beside this entry rather than before it.
|
|
126
140
|
*/
|
|
127
141
|
export const inject = ['slots', 'sessions', 'workspaces', 'connection', 'configForms', 'locale', 'remote', 'remote.session', 'uiWorkspace', 'layout']
|
|
128
142
|
|
|
129
|
-
/**
|
|
143
|
+
/** The generated Remote namespace the mode picker reads its roster from. */
|
|
144
|
+
type PresetRemote = ClientRemote['agentPresets']
|
|
145
|
+
|
|
146
|
+
/** One agent-preset row the mode picker consumes. */
|
|
130
147
|
interface PresetRosterRow {
|
|
131
148
|
id: string
|
|
132
149
|
name?: string
|
|
@@ -137,41 +154,17 @@ interface PresetRosterRow {
|
|
|
137
154
|
}
|
|
138
155
|
|
|
139
156
|
/**
|
|
140
|
-
* Read the agent-preset roster through
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
157
|
+
* Read the agent-preset roster through the generated api-remotes face. The
|
|
158
|
+
* caller passes the namespace resolved inside its scoped inject, so a host
|
|
159
|
+
* that serves no such namespace never reaches here; a host that serves it
|
|
160
|
+
* answers `ok: false` instead, which leaves the picker options untouched.
|
|
161
|
+
* @param remote - the `remote.agentPresets` namespace.
|
|
162
|
+
* @returns the roster, or a failed read the caller ignores.
|
|
146
163
|
*/
|
|
147
|
-
async function readPresetRoster(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// The cordis `remote` proxy throws on a property that was never injected
|
|
152
|
-
// ("cannot get property X without inject") rather than returning undefined,
|
|
153
|
-
// so the probe must guard the access — a hard read would abort mounting on
|
|
154
|
-
// hosts below the 0.1.2-alpha.2 cohort instead of degrading to the legacy
|
|
155
|
-
// connection RPC face below.
|
|
156
|
-
let remotes: ClientRemote['agentPresets'] | undefined
|
|
157
|
-
try {
|
|
158
|
-
remotes = (remote as Partial<ClientRemote>).agentPresets
|
|
159
|
-
} catch {
|
|
160
|
-
remotes = undefined
|
|
161
|
-
}
|
|
162
|
-
if (remotes !== undefined) {
|
|
163
|
-
const response = await remotes.list()
|
|
164
|
-
if (!response.ok) return { ok: false, presets: [] }
|
|
165
|
-
return { ok: true, presets: response.value.presets }
|
|
166
|
-
}
|
|
167
|
-
const connection = ctx.get('connection') as unknown as {
|
|
168
|
-
api?: { agentPresets?: { list(request: Record<string, never>): Promise<{ result: { ok: boolean; value?: { presets?: readonly PresetRosterRow[] } } }> } }
|
|
169
|
-
}
|
|
170
|
-
const legacy = connection.api?.agentPresets
|
|
171
|
-
if (legacy === undefined) return undefined
|
|
172
|
-
const response = await legacy.list({})
|
|
173
|
-
if (!response.result.ok || response.result.value === undefined) return { ok: false, presets: [] }
|
|
174
|
-
return { ok: true, presets: response.result.value.presets ?? [] }
|
|
164
|
+
async function readPresetRoster(remote: PresetRemote): Promise<{ ok: boolean; presets: readonly PresetRosterRow[] }> {
|
|
165
|
+
const response = await remote.list()
|
|
166
|
+
if (!response.ok) return { ok: false, presets: [] }
|
|
167
|
+
return { ok: true, presets: response.value.presets }
|
|
175
168
|
}
|
|
176
169
|
|
|
177
170
|
/**
|
|
@@ -211,12 +204,26 @@ export function apply(ctx: ClientContext): void {
|
|
|
211
204
|
// namespace, contributed to whichever plugin-card seat this host declares
|
|
212
205
|
// (the family group's list seat, or the official bundle-configuration seat).
|
|
213
206
|
const settingsForm = bindSettingsForm(ctx)
|
|
214
|
-
|
|
207
|
+
// The board's browser-half extension service. It is provided before any
|
|
208
|
+
// controller exists (the UI mounts only once the settings form settles), so
|
|
209
|
+
// providers can subscribe and register visibility immediately.
|
|
210
|
+
const clientService = new TaskBoardClientService()
|
|
211
|
+
// A capture-only test context implements no service registry; the board's
|
|
212
|
+
// own surfaces still mount.
|
|
213
|
+
if (typeof (ctx as { provide?: unknown }).provide === 'function') {
|
|
214
|
+
;(ctx.provide as unknown as (name: string, value: unknown) => void)(TASK_BOARD_SERVICE_NAME, clientService as unknown as TaskBoardHostFace)
|
|
215
|
+
}
|
|
216
|
+
ctx.effect(() => () => { clientService.detach() }, 'task-board: extension service')
|
|
217
|
+
|
|
218
|
+
const settingsCard = new TaskBoardSettingsCardController(settingsForm, request => clientService.dispatch(request))
|
|
215
219
|
installPluginCard(ctx, {
|
|
216
220
|
bundle: '@linxin666/dsh-client-ui-task-board',
|
|
217
221
|
id: 'task-board',
|
|
218
222
|
order: 110,
|
|
219
223
|
locale: NS,
|
|
224
|
+
// The board's own settings card declares the provider settings seat; the
|
|
225
|
+
// provider registers into it and this card renders it.
|
|
226
|
+
children: { 'task-board.settings.section': { kind: 'list', scope: 'root' } },
|
|
220
227
|
inject: () => settingsCard.inject(),
|
|
221
228
|
component: TaskBoardSettingsCard,
|
|
222
229
|
})
|
|
@@ -263,6 +270,9 @@ export function apply(ctx: ClientContext): void {
|
|
|
263
270
|
},
|
|
264
271
|
})
|
|
265
272
|
controller.start()
|
|
273
|
+
// The extension service follows the live controller: providers observe the
|
|
274
|
+
// board mirror and dispatch through it while the board runs.
|
|
275
|
+
clientService.attach(controller)
|
|
266
276
|
|
|
267
277
|
const disposers: Array<() => void> = []
|
|
268
278
|
|
|
@@ -289,10 +299,10 @@ export function apply(ctx: ClientContext): void {
|
|
|
289
299
|
const created = await workspaces.create({ path })
|
|
290
300
|
return { workspaceId: created.workspaceId }
|
|
291
301
|
})
|
|
292
|
-
const pushPresetOptions = async (): Promise<void> => {
|
|
302
|
+
const pushPresetOptions = async (presetRemote: PresetRemote): Promise<void> => {
|
|
293
303
|
try {
|
|
294
|
-
const roster = await readPresetRoster(
|
|
295
|
-
if (
|
|
304
|
+
const roster = await readPresetRoster(presetRemote)
|
|
305
|
+
if (!roster.ok) return
|
|
296
306
|
controller.setExecutionOptions({
|
|
297
307
|
presets: roster.presets.map(preset => ({
|
|
298
308
|
id: preset.id,
|
|
@@ -308,6 +318,25 @@ export function apply(ctx: ClientContext): void {
|
|
|
308
318
|
console.error('[dsh-task-board] agent preset roster read failed', error)
|
|
309
319
|
}
|
|
310
320
|
}
|
|
321
|
+
// The roster namespace mounts with the official api-remotes assembly,
|
|
322
|
+
// which the page applies beside this entry: at mount time the namespace is
|
|
323
|
+
// usually still absent, and reading it through `remote.agentPresets`
|
|
324
|
+
// before it lands throws ("cannot get property ... without inject"), so a
|
|
325
|
+
// one-shot probe leaves the mode picker with nothing but "inherit" for the
|
|
326
|
+
// page lifetime. A hard inject is no better — it would pend the whole
|
|
327
|
+
// board on a deployment that never mounts the namespace. The scoped inject
|
|
328
|
+
// runs the feed exactly when the namespace exists and re-runs it if the
|
|
329
|
+
// namespace is replaced; the reconnect read inside covers a deployment
|
|
330
|
+
// change behind the same namespace.
|
|
331
|
+
const presetRosterFeed = ctx.inject(['remote.agentPresets'], (inner) => {
|
|
332
|
+
const presetRemote = inner.get('remote.agentPresets') as PresetRemote | undefined
|
|
333
|
+
if (presetRemote === undefined) return
|
|
334
|
+
void pushPresetOptions(presetRemote)
|
|
335
|
+
// Subscribed inside the injected scope, so a namespace that goes away
|
|
336
|
+
// takes its listener with it instead of leaving one per remount.
|
|
337
|
+
return inner.on('connection/reset', () => { void pushPresetOptions(presetRemote) })
|
|
338
|
+
})
|
|
339
|
+
disposers.push(() => { void presetRosterFeed.dispose() })
|
|
311
340
|
const pushModelOptions = async (): Promise<void> => {
|
|
312
341
|
try {
|
|
313
342
|
let models: Array<{ id: string; name?: string; provider?: string }> = []
|
|
@@ -372,12 +401,8 @@ export function apply(ctx: ClientContext): void {
|
|
|
372
401
|
console.error('[dsh-task-board] model options read failed', error)
|
|
373
402
|
}
|
|
374
403
|
}
|
|
375
|
-
void pushPresetOptions()
|
|
376
404
|
void pushModelOptions()
|
|
377
|
-
disposers.push(ctx.on('connection/reset', () => {
|
|
378
|
-
void pushPresetOptions()
|
|
379
|
-
void pushModelOptions()
|
|
380
|
-
}))
|
|
405
|
+
disposers.push(ctx.on('connection/reset', () => { void pushModelOptions() }))
|
|
381
406
|
// Native panel surfaces: one sidebar row and one center-column page, both
|
|
382
407
|
// through the official slot seats the shell itself renders. The layout's
|
|
383
408
|
// panel selection is reconciled back into the controller so the board's own
|
|
@@ -400,6 +425,7 @@ export function apply(ctx: ClientContext): void {
|
|
|
400
425
|
|
|
401
426
|
uiDisposer = () => {
|
|
402
427
|
for (const dispose of disposers.splice(0)) dispose()
|
|
428
|
+
clientService.detach()
|
|
403
429
|
controller.dispose()
|
|
404
430
|
uiDisposer = undefined
|
|
405
431
|
}
|
|
@@ -409,8 +435,13 @@ export function apply(ctx: ClientContext): void {
|
|
|
409
435
|
const enabled = snapshot.status === 'ready'
|
|
410
436
|
? snapshot.value?.enabled ?? true
|
|
411
437
|
: snapshot.status === 'unavailable'
|
|
412
|
-
if (enabled)
|
|
413
|
-
|
|
438
|
+
if (enabled) {
|
|
439
|
+
mountUi()
|
|
440
|
+
clientService.setEnabled(true)
|
|
441
|
+
} else {
|
|
442
|
+
clientService.setEnabled(false)
|
|
443
|
+
uiDisposer?.()
|
|
444
|
+
}
|
|
414
445
|
}
|
|
415
446
|
const unsubscribeSettings = settingsForm.subscribe(syncEnabled)
|
|
416
447
|
// The mounted surfaces and the settings subscription belong to this fiber.
|