@linxin666/dsh-client-ui-task-board 0.4.0 → 0.4.2
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 +24 -0
- package/README.zh.md +24 -0
- package/lib/client.js +917 -81
- package/lib/client.js.map +1 -1
- package/lib/index.js +1774 -1420
- package/lib/types/client/TaskBoardSettingsCard.d.ts +4 -0
- package/lib/types/client/board/LinkSubtaskModal.d.ts +11 -0
- package/lib/types/client/board/NewTaskModal.d.ts +7 -1
- package/lib/types/client/board/TaskCard.d.ts +11 -1
- package/lib/types/client/locales.d.ts +33 -0
- package/lib/types/core/controller.d.ts +30 -1
- package/lib/types/core/subtask.d.ts +122 -0
- package/lib/types/core/tasks.d.ts +46 -3
- package/lib/types/core/use-cases/task-archive.d.ts +10 -13
- package/lib/types/core/use-cases/task-create.d.ts +13 -4
- package/lib/types/core/use-cases/task-delete.d.ts +7 -1
- package/lib/types/core/use-cases/task-parent.d.ts +21 -0
- package/lib/types/core/use-cases/task-update.d.ts +1 -1
- package/lib/types/host/agent-tools.d.ts +27 -0
- package/lib/types/host-ledger.d.ts +88 -4
- package/lib/types/host-runner.d.ts +39 -1
- package/lib/types/host-service.d.ts +47 -0
- package/lib/types/index.d.ts +83 -5
- package/lib/types/protocol.d.ts +14 -0
- package/package.json +23 -21
- package/src/client/TaskBoardSettingsCard.tsx +48 -3
- package/src/client/board/LinkSubtaskModal.tsx +82 -0
- package/src/client/board/NewTaskModal.tsx +40 -6
- package/src/client/board/TaskBoard.tsx +88 -8
- package/src/client/board/TaskCard.tsx +52 -2
- package/src/client/board/TaskDetail.tsx +124 -1
- package/src/client/board.module.css +96 -0
- package/src/client/host-api.ts +14 -4
- package/src/client/index.ts +11 -1
- package/src/client/locales.ts +70 -2
- package/src/core/controller.ts +69 -8
- package/src/core/store.ts +15 -0
- package/src/core/subtask.ts +286 -0
- package/src/core/tasks.ts +50 -2
- package/src/core/use-cases/task-archive.ts +46 -12
- package/src/core/use-cases/task-create.ts +42 -7
- package/src/core/use-cases/task-delete.ts +11 -1
- package/src/core/use-cases/task-parent.ts +64 -0
- package/src/core/use-cases/task-update.ts +3 -1
- package/src/host/agent-tools.ts +643 -0
- package/src/host-ledger.ts +323 -45
- package/src/host-runner.ts +141 -12
- package/src/host-service.ts +127 -10
- package/src/index.ts +181 -9
- package/src/protocol.ts +26 -2
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parent-link use case: attach an existing on-board task under another as a
|
|
3
|
+
* subtask, or detach it back to the root. The lineage gate is the same one
|
|
4
|
+
* creation uses (unknown or archived parent, self, cycle, depth), so the two
|
|
5
|
+
* ways into the tree cannot disagree. Pure ledger transition.
|
|
6
|
+
*/
|
|
7
|
+
import { DEFAULT_SUBTASK_DEPTH, checkParentLink, normalizeSubtaskDepth, type ParentLinkRejection } from '../subtask.ts'
|
|
8
|
+
import type { TaskRecord } from '../tasks.ts'
|
|
9
|
+
|
|
10
|
+
/** Result of a parent-link transition. */
|
|
11
|
+
export interface SetParentResult {
|
|
12
|
+
/** The next ledger; the input reference when refused. */
|
|
13
|
+
tasks: readonly TaskRecord[]
|
|
14
|
+
/** Whether the link (or the detachment) was stored. */
|
|
15
|
+
applied: boolean
|
|
16
|
+
/** User-facing refusal reason; absent when applied. */
|
|
17
|
+
error?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Host error text per refusal reason (the wire carries the same strings). */
|
|
21
|
+
const REJECTION_TEXT: Record<ParentLinkRejection, string> = {
|
|
22
|
+
'unknown-task': 'task not found',
|
|
23
|
+
'unknown-parent': 'parent task not found',
|
|
24
|
+
'archived-parent': 'parent task is archived',
|
|
25
|
+
'self-parent': 'a task cannot be its own parent',
|
|
26
|
+
'cycle': 'a task cannot be attached under its own subtask',
|
|
27
|
+
'depth-exceeded': 'subtask depth limit exceeded',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Attach or detach one task. A null (or blank) parent detaches, which is always
|
|
32
|
+
* allowed for a known on-board task; attaching validates the whole chain so a
|
|
33
|
+
* cyclic or too-deep ledger can never be stored.
|
|
34
|
+
* @param tasks - current ledger.
|
|
35
|
+
* @param id - the task being moved.
|
|
36
|
+
* @param parentId - the new parent, or null to detach.
|
|
37
|
+
* @param now - clock instant (ms epoch).
|
|
38
|
+
* @param maxSubtaskDepth - deployment subtask depth limit.
|
|
39
|
+
*/
|
|
40
|
+
export function applySetParent(
|
|
41
|
+
tasks: readonly TaskRecord[],
|
|
42
|
+
id: string,
|
|
43
|
+
parentId: string | null,
|
|
44
|
+
now: number,
|
|
45
|
+
maxSubtaskDepth: number = DEFAULT_SUBTASK_DEPTH,
|
|
46
|
+
): SetParentResult {
|
|
47
|
+
const task = tasks.find(candidate => candidate.id === id)
|
|
48
|
+
if (task === undefined) return { tasks, applied: false, error: REJECTION_TEXT['unknown-task'] }
|
|
49
|
+
if (task.archivedAt !== undefined) return { tasks, applied: false, error: 'archived task is read-only' }
|
|
50
|
+
// A task with an open execution may be a participant of a running cascade.
|
|
51
|
+
// Moving it would break that group's parent walk and leave the parent card
|
|
52
|
+
// in the running column forever, so the link is frozen until it settles.
|
|
53
|
+
if (task.status === 'running' || task.executions.some(execution => execution.endedAt === undefined)) {
|
|
54
|
+
return { tasks, applied: false, error: 'running task cannot be re-parented' }
|
|
55
|
+
}
|
|
56
|
+
const check = checkParentLink(tasks, id, parentId, normalizeSubtaskDepth(maxSubtaskDepth))
|
|
57
|
+
if (!check.ok) return { tasks, applied: false, error: REJECTION_TEXT[check.reason ?? 'unknown-task'] }
|
|
58
|
+
const nextParentId = parentId === null || parentId === '' ? undefined : parentId
|
|
59
|
+
if (nextParentId === task.parentId) return { tasks: [...tasks], applied: true }
|
|
60
|
+
return {
|
|
61
|
+
tasks: tasks.map(candidate => candidate.id === id ? { ...candidate, parentId: nextParentId, updatedAt: now } : candidate),
|
|
62
|
+
applied: true,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -16,7 +16,7 @@ import type { TaskHandoverInput } from '../handover.ts'
|
|
|
16
16
|
* Editable fields on a task (the update patch surface). `freeze` replaces the
|
|
17
17
|
* continuation-card snapshot (restamping frozenAt); an explicit null clears it.
|
|
18
18
|
*/
|
|
19
|
-
export type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission' | 'model' | 'reuseSession'>> & {
|
|
19
|
+
export type TaskUpdatePatch = Partial<Pick<TaskRecord, 'title' | 'description' | 'prompt' | 'workspaceId' | 'mode' | 'permission' | 'model' | 'reuseSession' | 'teamRun'>> & {
|
|
20
20
|
freeze?: FreezeSnapshot & { redacted?: boolean } | null
|
|
21
21
|
/** Replaces the handover bundle (restamping bundledAt); an explicit null clears it. */
|
|
22
22
|
handover?: TaskHandoverInput | null
|
|
@@ -106,6 +106,8 @@ export function applyUpdateTask(
|
|
|
106
106
|
// Session reuse is a boolean opt-in; false (or an explicit null from a
|
|
107
107
|
// caller that needs to clear it) returns the task to one session per run.
|
|
108
108
|
if ('reuseSession' in patch) next.reuseSession = patch.reuseSession === true ? true : undefined
|
|
109
|
+
// Team execution is a boolean opt-in with the same clear-by-false rule.
|
|
110
|
+
if ('teamRun' in patch) next.teamRun = patch.teamRun === true ? true : undefined
|
|
109
111
|
if (workspaceId !== undefined || 'workspaceId' in patch) next.workspaceId = workspaceId
|
|
110
112
|
if (mode !== undefined || 'mode' in patch) next.mode = mode
|
|
111
113
|
if (permission !== undefined || 'permission' in patch) next.permission = permission
|