@fonlan/dsh-task-kanban 0.2.6 → 0.2.7
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 +139 -186
- package/lib/client.js.map +1 -1
- package/lib/index.js +46 -31
- package/lib/types/index.d.ts +3 -3
- package/lib/types/server/settings.d.ts +6 -26
- package/package.json +25 -25
- package/src/client/board.css +0 -107
- package/src/client/board.tsx +5 -2
- package/src/client/icons.tsx +74 -0
- package/src/client/index.tsx +25 -10
- package/src/client/kanban-state.ts +49 -83
- package/src/client/sections.tsx +10 -136
- package/src/index.ts +7 -5
- package/src/server/settings.ts +62 -37
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useCallback","useMemo","useRef","useRef","IconChecklistOutline14","useState","useCallback"],"sources":["../../../src/shared/lanes.ts","../../../src/client/api.ts","../../../src/client/kanban-state.ts","../../../src/client/locales.ts","../../../src/client/board.tsx","../../../src/client/sections.tsx","../../../src/client/index.tsx"],"sourcesContent":["/**\n * Lane mapping and drag rules (shared by the board UI and tests).\n */\nimport type { KanbanCard, Lane } from './card.js'\n\n/** Which lane a card renders in, based on status + error stage. */\nexport function laneOf(card: KanbanCard): Lane {\n if (card.status === 'error') {\n if (card.error?.stage !== undefined) return card.error.stage\n const kind = card.error?.kind\n if (kind === 'phase_failed' || kind === 'no_base_branch' || kind === 'worktree_failed') return 'running'\n if (kind === 'merge_failed') return 'completed'\n return 'demand'\n }\n switch (card.status) {\n case 'draft':\n case 'refining':\n case 'planned':\n return 'demand'\n case 'queued':\n return 'queue'\n case 'running':\n return 'running'\n case 'completed':\n case 'merging':\n return 'completed'\n case 'merged':\n return 'merged'\n }\n}\n\n/** Lanes a drop onto `to` may come from. */\nexport const DROP_RULES: Record<Lane, Lane[]> = {\n demand: ['queue'],\n queue: ['demand', 'running'],\n running: [],\n completed: [],\n merged: [],\n}\n\nexport function canDrop(from: Lane, to: Lane): boolean {\n return DROP_RULES[to].includes(from)\n}\n","import type { KanbanCard, KanbanSettingsShape, Lane, ModelOption } from '../shared/card'\n\nexport class KanbanApiError extends Error {\n constructor(readonly code: string, message: string) {\n super(message)\n }\n}\n\nasync function call<T>(method: string, payload: Record<string, unknown> = {}): Promise<T> {\n let response: Response\n try {\n response = await fetch(`/plugins/@fonlan/dsh-task-kanban/api/${method}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n } catch (error) {\n throw new KanbanApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed: { ok?: boolean; value?: unknown; error?: { code?: string; message?: string } } | null\n = await response.json().catch(() => null)\n if (!response.ok || parsed === null || parsed.ok !== true || parsed.value === undefined) {\n throw new KanbanApiError(\n parsed?.error?.code ?? 'http',\n parsed?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.value as T\n}\n\n/** One row of the host `skills/list` catalog (same shape DSH's chat autocomplete uses). */\nexport interface SkillOption {\n name: string\n description: string\n whenToUse?: string\n modelInvocable: boolean\n}\n\n/**\n * Call the host gateway's `skills/list` unary RPC over the same-origin HTTP\n * bridge (the exact wire shape DSH's chat input uses for its /-autocomplete).\n *\n * DSH ≥0.1.5 addresses Remote endpoints as the canonical `<namespace>/<method>`\n * pair — `/api/skills/list` with the method `skills/list` — and carries named\n * wire arguments inside a single `args` field, so the request body is\n * `{ args: { request: { sessionId } } }` (the descriptor's parameter wire name\n * is `request`). The older dotted `skill.list` endpoint no longer exists and\n * answers HTTP 404.\n *\n * The requested `sessionId` scopes the catalog to that session's agent\n * preset, which is where the filesystem skill roots are registered.\n */\nexport async function gatewaySkillList(sessionId: string): Promise<SkillOption[]> {\n let response: Response\n try {\n response = await fetch('/api/skills/list', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n type: 'client-request',\n rpcId: `task-kanban-${Math.random().toString(36).slice(2)}`,\n method: 'skills/list',\n payload: { args: { request: { sessionId } } },\n }),\n })\n } catch (error) {\n throw new KanbanApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed: { type?: string; result?: { ok?: boolean; value?: { skills?: SkillOption[] }; error?: { code?: string; message?: string } } } | null\n = await response.json().catch(() => null)\n if (!response.ok || parsed === null || parsed.type !== 'server-response' || parsed.result?.ok !== true) {\n throw new KanbanApiError(\n parsed?.result?.error?.code ?? 'http',\n parsed?.result?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.result.value?.skills ?? []\n}\n\n/** One row of the host `agentPresets.list()` roster. */\nexport interface PresetOption {\n id: string\n name?: string\n description?: string\n}\n\n/** Reasoning efforts of one provider/model route (`reasoning.options`). */\nexport interface ReasoningOptions {\n efforts: Array<{ id: string; name: string; description?: string }>\n defaultEffort?: string\n /** Client-side marker: the fetch failed; the stored effort must be kept. */\n failed?: boolean\n}\n\nexport const api = {\n list: (workspacePath: string) => call<KanbanCard[]>('list', { workspacePath }),\n create: (workspacePath: string, requirement: string, model: string, provider?: string, skill?: string) =>\n call<KanbanCard>('create', { workspacePath, requirement, model, provider, ...(skill !== undefined && skill !== '' ? { skill } : {}) }),\n move: (cardId: string, toLane: Lane) => call<{ ok: boolean; message?: string }>('move', { cardId, toLane }),\n stop: (cardId: string) => call<{ ok: boolean; message?: string }>('stop', { cardId }),\n retry: (cardId: string) => call<{ ok: boolean; message?: string }>('retry', { cardId }),\n remove: (cardId: string) => call<{ ok: boolean; message?: string }>('remove', { cardId }),\n settingsGet: () => call<KanbanSettingsShape>('settings.get'),\n settingsSet: (patch: Partial<KanbanSettingsShape>) => call<KanbanSettingsShape>('settings.set', patch),\n models: () => call<ModelOption[]>('models.list'),\n presets: () => call<PresetOption[]>('presets.list'),\n reasoningOptions: (provider: string, model: string) =>\n call<ReasoningOptions>('reasoning.options', { provider, model }),\n}\n","import { useSyncExternalStore } from 'react'\nimport type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\n\n/**\n * HMR-safe shared state store keyed on the global symbol registry.\n *\n * The client-hmr hot swap re-evaluates this module (a fresh `lib/client.js`\n * bundle) WITHOUT reloading the page. A module-level singleton would then be\n * duplicated per evaluation: the session-navigation wrapper installed by the\n * OLD module copy keeps calling the OLD copy's `exitBoard`, which reads the\n * OLD copy's `boardOpen`/`boardDisposer` — while a board opened after the swap\n * writes the NEW copy's state cell. The wrapper would then no-op and clicking\n * a sidebar session would never leave the board.\n *\n * Keeping every field on one `globalThis`-backed record (via `Symbol.for`, so\n * all bundle copies resolve the same key) makes every copy read/write the same\n * state cell, so exit works regardless of which module copy performed the\n * enter.\n */\nconst STATE_KEY = Symbol.for('@fonlan/dsh-task-kanban/state')\n\ninterface KanbanState {\n client: ClientContext | null\n boardRoot: ((props: Record<string, unknown>) => React.ReactNode) | null\n boardDisposer: (() => void) | null\n boardOpen: boolean\n listeners: Set<() => void>\n}\n\nfunction getState(): KanbanState {\n const g = globalThis as unknown as Record<symbol, KanbanState | undefined>\n let state = g[STATE_KEY]\n if (state === undefined) {\n state = {\n client: null,\n boardRoot: null,\n boardDisposer: null,\n boardOpen: false,\n listeners: new Set(),\n }\n g[STATE_KEY] = state\n }\n return state\n}\n\nexport function setClient(ctx: ClientContext | null): void {\n getState().client = ctx\n}\nexport function getClient(): ClientContext | null {\n return getState().client\n}\n\nexport function setBoardRoot(component: (props: Record<string, unknown>) => React.ReactNode): void {\n getState().boardRoot = component\n}\nexport function getBoardRoot(): ((props: Record<string, unknown>) => React.ReactNode) | null {\n return getState().boardRoot\n}\n\nfunction notify(): void {\n for (const listener of getState().listeners) listener()\n}\nexport function isBoardOpen(): boolean {\n return getState().boardOpen\n}\nfunction subscribe(cb: () => void): () => void {\n const listeners = getState().listeners\n listeners.add(cb)\n return () => { listeners.delete(cb) }\n}\nexport function useBoardOpen(): boolean {\n return useSyncExternalStore(subscribe, isBoardOpen)\n}\n\nexport function enterBoard(): void {\n const state = getState()\n const ctx = state.client\n const root = state.boardRoot\n if (ctx === null || root === null || state.boardDisposer !== null) return\n try {\n // DSH 0.1.5 moved the replaceable shell from the legacy `conversation`\n // seat to `main.conversation`. Register through `inject` so the board\n // waits for that owner if the client plugin load order is reversed.\n state.boardDisposer = ctx.slots.inject('main.conversation', () =>\n ctx.slots.register({ name: 'main.conversation', priority: -1, locale: 'task-kanban' } as never, root as never),\n )\n state.boardOpen = true\n notify()\n } catch (error) {\n console.error('[@fonlan/dsh-task-kanban] cannot open the board:', error)\n }\n}\n\nexport function exitBoard(): void {\n const state = getState()\n if (state.boardDisposer !== null) {\n state.boardDisposer()\n state.boardDisposer = null\n }\n if (state.boardOpen) {\n state.boardOpen = false\n notify()\n }\n}\n\nexport function toggleBoard(): void {\n if (isBoardOpen()) exitBoard()\n else enterBoard()\n}\n\n/**\n * Route session navigation through the board: opening any session while the\n * board is open leaves the board first, so the conversation view can render\n * for the newly selected session.\n *\n * Every sidebar path that selects a session funnels through `sessions.open`\n * (session rows, search results, fork results, New Session) or\n * `sessions.openSubagent` (catalog children) — including re-clicking the\n * already-current session, which never changes `list.current` and therefore\n * cannot be caught by a list-store subscription. Wrapping the two entry\n * points covers all of them in one place.\n *\n * The wrapper is idempotent: a `kbBound` marker on the wrapper prevents a\n * second bind (plugin re-apply / HMR) from stacking another layer. Because the\n * wrapper's exit goes through the shared state store, a wrapper left over from\n * a previous (HMR-replaced) module copy still closes the board correctly.\n */\nexport function bindSessionNavigation(ctx: ClientContext): void {\n const sessions = ctx.sessions\n if (sessions === undefined) return\n\n const open = sessions.open\n if (typeof open === 'function' && (open as unknown as { kbBound?: boolean }).kbBound !== true) {\n const bound = ((id: Parameters<typeof open>[0]) => {\n exitBoard()\n return open.call(sessions, id)\n }) as typeof open\n ;(bound as unknown as { kbBound?: boolean }).kbBound = true\n sessions.open = bound\n }\n\n const openSubagent = sessions.openSubagent\n if (typeof openSubagent === 'function' && (openSubagent as unknown as { kbBound?: boolean }).kbBound !== true) {\n const bound = ((address: Parameters<typeof openSubagent>[0]) => {\n exitBoard()\n return openSubagent.call(sessions, address)\n }) as typeof openSubagent\n ;(bound as unknown as { kbBound?: boolean }).kbBound = true\n sessions.openSubagent = bound\n }\n}","// Locale namespace = the plugin's cordis id (kebab). DSH flat namespace keys\n// (settings + locale) use the internal id `task-kanban`; the scoped npm package\n// name is reserved for package-bound identifiers (exported `name`, module-loader\n// id, the /plugins/<pkg>/… route base).\nexport const LOCALE_NS = 'task-kanban'\n\nexport const zh = {\n kanban: '任务看板',\n openBoard: '打开任务看板',\n closeBoard: '返回对话',\n newTask: '新建任务',\n requirement: '需求',\n project: '所属项目',\n model: '模型',\n cancel: '取消',\n close: '关闭',\n addAndRefine: '添加并细化',\n laneDemand: '需求',\n laneQueue: '队列',\n laneRunning: '运行中',\n laneCompleted: '已完成',\n laneMerged: '已合并',\n statusDraft: '未细化',\n statusRefining: '细化中',\n statusPlanned: '已规划',\n statusQueued: '排队中',\n statusRunning: '实现中',\n statusCompleted: '已完成',\n statusMerging: '合并中',\n statusMerged: '已合并',\n statusError: '出错',\n phaseProgress: '{current}/{total}',\n retry: '重试',\n stop: '停止',\n delete: '删除',\n deleteConfirm: '确定删除该任务?其 worktree 会被清理。',\n openSession: '打开会话',\n plan: '实现方案',\n summary: '摘要',\n phases: '阶段',\n phaseGoal: '目标',\n phaseSessions: '会话',\n phaseConclusion: '结论',\n phaseNum: 'phase {n}',\n error: '错误',\n requirementLabel: '需求文本',\n requirementPlaceholder: '描述你要实现的需求……',\n skillGestureHint: '开头输入 /skill-name 可指定细化时使用的 Skill(如 /grill-me)',\n skillHint: '细化时将使用 Skill「{skill}」,并可与该会话交流打磨需求',\n skillMenuUserOnly: '仅用户可调',\n skillBadge: '细化 Skill:/{skill}',\n modelPlaceholder: '(使用默认模型)',\n noWorkspace: '没有可用工作区,请先在侧边栏添加',\n refresh: '刷新',\n settingsTitle: '任务看板',\n sectionSub: '全局并行 worker 数与各会话类型的默认模型、推理强度、Agent 预设',\n maxParallelWorkers: '全局并行 worker 数',\n settingsRefineGroup: '细化需求会话默认',\n settingsPhaseGroup: 'Phase 实现会话默认',\n reasoningEffort: '推理强度',\n agentPreset: 'Agent 预设',\n defaultOption: '(默认)',\n saved: '已保存',\n loadError: '加载任务失败',\n noPlan: '该卡片还没有实现计划,请先点击\"添加并细化\"',\n dragNoPlan: '还没有实现计划的卡片不能进入队列',\n actionFailed: '操作失败:{message}',\n sessionNotListed: '该会话不在当前列表,可能来自其他工作区',\n interrupted: '已中断',\n noBaseBranch: '项目没有 main/master 分支',\n worktreeFailed: 'worktree 创建失败',\n refineFailed: '细化失败',\n phaseFailed: '阶段执行失败',\n mergeFailed: '合并失败',\n createFailed: '创建失败',\n refinementLabel: '需求细化',\n mergeLabel: '合并',\n commitLabel: '提交',\n}\n\nexport const en = {\n kanban: 'Task Kanban',\n openBoard: 'Open Task Kanban',\n closeBoard: 'Back to chat',\n newTask: 'New Task',\n requirement: 'Requirement',\n project: 'Project',\n model: 'Model',\n cancel: 'Cancel',\n close: 'Close',\n addAndRefine: 'Add & Refine',\n laneDemand: 'Demands',\n laneQueue: 'Queue',\n laneRunning: 'Running',\n laneCompleted: 'Completed',\n laneMerged: 'Merged',\n statusDraft: 'Unrefined',\n statusRefining: 'Refining',\n statusPlanned: 'Planned',\n statusQueued: 'Queued',\n statusRunning: 'Running',\n statusCompleted: 'Completed',\n statusMerging: 'Merging',\n statusMerged: 'Merged',\n statusError: 'Error',\n phaseProgress: '{current}/{total}',\n retry: 'Retry',\n stop: 'Stop',\n delete: 'Delete',\n deleteConfirm: 'Delete this task? Its worktree will be cleaned up.',\n openSession: 'Open session',\n plan: 'Plan',\n summary: 'Summary',\n phases: 'Phases',\n phaseGoal: 'Goal',\n phaseSessions: 'Sessions',\n phaseConclusion: 'Conclusion',\n phaseNum: 'Phase {n}',\n error: 'Error',\n requirementLabel: 'Requirement',\n requirementPlaceholder: 'Describe what you want to build…',\n skillGestureHint: 'Start with /skill-name to choose the refinement skill (e.g. /grill-me)',\n skillHint: 'Refinement will use Skill “{skill}” — talk to this session to refine the requirement',\n skillMenuUserOnly: 'User-only',\n skillBadge: 'Refine skill: /{skill}',\n modelPlaceholder: '(use default model)',\n noWorkspace: 'No workspaces available — add one in the sidebar first',\n refresh: 'Refresh',\n settingsTitle: 'Task Kanban',\n sectionSub: 'Global parallel workers and per-session-type defaults for model, reasoning effort, and agent preset',\n maxParallelWorkers: 'Global parallel workers',\n settingsRefineGroup: 'Refinement session defaults',\n settingsPhaseGroup: 'Phase implementation defaults',\n reasoningEffort: 'Reasoning effort',\n agentPreset: 'Agent preset',\n defaultOption: '(default)',\n saved: 'Saved',\n loadError: 'Failed to load tasks',\n noPlan: 'This card has no plan yet — click \"Add & Refine\" first',\n dragNoPlan: 'Cards without a plan cannot enter the queue',\n actionFailed: 'Action failed: {message}',\n sessionNotListed: 'Session is not listed here; it may belong to another workspace',\n interrupted: 'Interrupted',\n noBaseBranch: 'Project has no main/master branch',\n worktreeFailed: 'Worktree creation failed',\n refineFailed: 'Refinement failed',\n phaseFailed: 'Phase failed',\n mergeFailed: 'Merge failed',\n createFailed: 'Creation failed',\n refinementLabel: 'Refinement',\n mergeLabel: 'Merge',\n commitLabel: 'Commit',\n}","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { KanbanCard, Lane, PhaseAttempt, PlanPhase } from '../shared/card'\nimport { DROP_RULES, laneOf } from '../shared/lanes'\nimport { api, gatewaySkillList, type SkillOption } from './api'\nimport { exitBoard, getClient } from './kanban-state'\nimport { en, zh } from './locales'\nimport './board.css'\n\ninterface BoardProps {\n t?: (key: string, params?: Record<string, unknown>) => string\n useWorkspaces?: (selector: (state: unknown) => unknown) => unknown\n useSessions?: (selector: (state: unknown) => unknown) => unknown\n}\n\n/** Session-list snapshot shape the standard `useSessions` feed carries. */\ninterface SessionListStateLike {\n current?: string\n /** Listed session ids (the feed's own order). */\n ids?: string[]\n}\n\nfunction firstLine(text: string): string {\n return text.split('\\n').find((l) => l.trim() !== '')?.trim() ?? ''\n}\n\n/** The leading `/skill-name` gesture at the start of the requirement input. */\nconst SKILL_GESTURE = /^\\s*\\/([a-z0-9]+(?:-[a-z0-9]+)*)(?=\\s|$)/\n\n/** Extract a leading `/skill-name` token plus the cleaned remainder. */\nfunction parseSkillGesture(raw: string): { skill?: string; requirement: string } {\n const m = SKILL_GESTURE.exec(raw)\n if (m === null) return { requirement: raw.trim() }\n return { skill: m[1], requirement: raw.slice(m[0].length).trim() }\n}\n\nfunction statusLabel(card: KanbanCard, t: (key: string) => string): string {\n if (card.status === 'error') {\n switch (card.error?.kind) {\n case 'interrupted': return t('interrupted')\n case 'no_base_branch': return t('noBaseBranch')\n case 'worktree_failed': return t('worktreeFailed')\n case 'refine_failed': return t('refineFailed')\n case 'phase_failed': return t('phaseFailed')\n case 'merge_failed': return t('mergeFailed')\n default: return t('createFailed')\n }\n }\n switch (card.status) {\n case 'draft': return t('statusDraft')\n case 'refining': return t('statusRefining')\n case 'planned': return t('statusPlanned')\n case 'queued': return t('statusQueued')\n case 'running': return t('statusRunning')\n case 'completed': return t('statusCompleted')\n case 'merging': return t('statusMerging')\n case 'merged': return t('statusMerged')\n }\n}\n\ninterface WorkspaceRow {\n workspaceId: string\n path: string\n title: string\n}\n\nconst LANE_ORDER: Array<{ key: Lane; labelKey: string }> = [\n { key: 'demand', labelKey: 'laneDemand' },\n { key: 'queue', labelKey: 'laneQueue' },\n { key: 'running', labelKey: 'laneRunning' },\n { key: 'completed', labelKey: 'laneCompleted' },\n { key: 'merged', labelKey: 'laneMerged' },\n]\n\nconst WS_STORAGE_KEY = '@fonlan/dsh-task-kanban:workspace'\n\nexport function BoardRoot(props: BoardProps): JSX.Element {\n const t = props.t ?? ((key: string, params?: Record<string, unknown>) => {\n const dict = (zh as Record<string, string>)[key] ?? (en as Record<string, string>)[key]\n if (dict === undefined || params === undefined) return dict ?? key\n return dict.replace(/\\{(\\w+)\\}/g, (m, name: string) => (params[name] as string) ?? m)\n })\n const useWorkspaces = props.useWorkspaces\n const wsState = useWorkspaces !== undefined ? (useWorkspaces((s: unknown) => s) as { items?: WorkspaceRow[] } | undefined) : undefined\n const items: WorkspaceRow[] = wsState?.items ?? []\n const useSessions = props.useSessions\n const sessionState = useSessions !== undefined ? (useSessions((s: unknown) => s) as SessionListStateLike | undefined) : undefined\n // The skill catalog is addressed by session (`skills/list`), so the /-menu\n // needs one. With no selection (fresh browser, board opened straight from the\n // footer) fall back to the most recent listed session: any session resolves a\n // preset scope, whereas no session silently leaves the menu empty.\n const currentSessionId = sessionState?.current ?? sessionState?.ids?.[0]\n\n const [selectedPath, setSelectedPath] = useState<string>(() => {\n try {\n return localStorage.getItem(WS_STORAGE_KEY) ?? ''\n } catch {\n return ''\n }\n })\n const [cards, setCards] = useState<KanbanCard[]>([])\n const [toast, setToast] = useState<string | null>(null)\n const [detailId, setDetailId] = useState<string | null>(null)\n const [newTaskOpen, setNewTaskOpen] = useState(false)\n\n useEffect(() => {\n if (selectedPath === '' && items.length > 0) {\n setSelectedPath(items[0].path)\n }\n }, [selectedPath, items])\n\n const showToast = useCallback((message: string) => {\n setToast(message)\n window.setTimeout(() => setToast(null), 3500)\n }, [])\n\n const refresh = useCallback(async () => {\n if (selectedPath === '') return\n try {\n setCards(await api.list(selectedPath))\n } catch (error) {\n showToast(error instanceof Error ? error.message : String(error))\n }\n }, [selectedPath, showToast])\n\n useEffect(() => {\n void refresh()\n const timer = window.setInterval(() => { void refresh() }, 2500)\n return () => window.clearInterval(timer)\n }, [refresh])\n\n const byLane = useMemo(() => {\n const map: Record<Lane, KanbanCard[]> = { demand: [], queue: [], running: [], completed: [], merged: [] }\n for (const card of cards) map[laneOf(card)].push(card)\n for (const lane of LANE_ORDER) map[lane.key].sort((a, b) => a.createdAt - b.createdAt)\n return map\n }, [cards])\n\n const handleDrop = useCallback(async (target: Lane, event: React.DragEvent) => {\n event.preventDefault()\n const cardId = event.dataTransfer.getData('text/plain')\n if (cardId === '') return\n const card = cards.find((c) => c.id === cardId)\n if (card === undefined) return\n if (target === 'queue' && card.status !== 'running' && card.plan === undefined) {\n showToast(t('dragNoPlan'))\n return\n }\n try {\n const result = await api.move(cardId, target)\n if (!result.ok) {\n showToast(t('actionFailed', { message: result.message ?? '' }))\n }\n void refresh()\n } catch (error) {\n showToast(error instanceof Error ? error.message : String(error))\n }\n }, [cards, refresh, showToast, t])\n\n const openSession = useCallback((sessionId: string) => {\n const ctx = getClient()\n exitBoard()\n if (ctx === null) return\n try {\n ;(ctx.sessions as { open(id: string): void }).open(sessionId)\n } catch {\n showToast(t('sessionNotListed'))\n }\n }, [showToast, t])\n\n if (items.length === 0) {\n return (\n <div className=\"kb-board kb-empty\">\n <div className=\"kb-empty-text\">{t('noWorkspace')}</div>\n </div>\n )\n }\n\n return (\n <div className=\"kb-board\">\n <div className=\"kb-board-header\">\n <div className=\"kb-board-title\">\n <select\n className=\"kb-ws-select\"\n value={selectedPath}\n onChange={(e) => {\n setSelectedPath(e.target.value)\n try {\n localStorage.setItem(WS_STORAGE_KEY, e.target.value)\n } catch {\n // storage unavailable\n }\n }}\n >\n {items.map((w) => (\n <option key={w.workspaceId} value={w.path}>{w.title}</option>\n ))}\n </select>\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" onClick={() => setNewTaskOpen(true)}>{t('newTask')}</button>\n </div>\n </div>\n\n <div className=\"kb-lanes\">\n {LANE_ORDER.map((lane) => (\n <div\n key={lane.key}\n className={'kb-lane' + (DROP_RULES[lane.key].length > 0 ? ' kb-lane-drop' : '')}\n onDragOver={(e) => {\n if (DROP_RULES[lane.key].length > 0) e.preventDefault()\n }}\n onDrop={(e) => { void handleDrop(lane.key, e) }}\n >\n <div className=\"kb-lane-head\">\n <span className=\"kb-lane-title\">{t(lane.labelKey)}</span>\n <span className=\"kb-lane-count\">{byLane[lane.key].length}</span>\n </div>\n <div className=\"kb-lane-body\">\n {byLane[lane.key].map((card) => (\n <CardView\n key={card.id}\n card={card}\n t={t}\n onToggle={() => setDetailId(detailId === card.id ? null : card.id)}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n\n {toast !== null && <div className=\"kb-toast\">{toast}</div>}\n\n {newTaskOpen && (\n <NewTaskModal\n t={t}\n workspaces={items}\n selectedPath={selectedPath}\n sessionId={currentSessionId}\n onClose={() => setNewTaskOpen(false)}\n onCreated={() => {\n setNewTaskOpen(false)\n void refresh()\n }}\n onError={(message) => showToast(message)}\n />\n )}\n\n {detailId !== null && (\n <DetailPanel\n card={cards.find((c) => c.id === detailId) ?? null}\n t={t}\n onClose={() => setDetailId(null)}\n onChanged={() => {\n setDetailId(null)\n void refresh()\n }}\n onToast={showToast}\n onOpenSession={openSession}\n />\n )}\n </div>\n )\n}\n\ninterface CardViewProps {\n card: KanbanCard\n t: (key: string, params?: Record<string, unknown>) => string\n onToggle: () => void\n}\n\nfunction CardView({ card, t, onToggle }: CardViewProps): JSX.Element {\n const draggable = card.status === 'planned' || card.status === 'queued' || card.status === 'running'\n const title = card.plan !== undefined && card.plan.title !== '' ? card.plan.title : firstLine(card.requirement)\n const badge = statusLabel(card, t)\n const phaseInfo = card.status === 'running' || card.status === 'error'\n ? card.currentPhase < card.phaseCount ? t('phaseProgress', { current: card.currentPhase + 1, total: card.phaseCount }) : ''\n : ''\n return (\n <div\n className={'kb-card' + (card.status === 'error' ? ' kb-card-error' : '') + (card.status === 'running' ? ' kb-card-running' : '')}\n draggable={draggable}\n onDragStart={(e) => {\n e.dataTransfer.setData('text/plain', card.id)\n e.dataTransfer.effectAllowed = 'move'\n }}\n onClick={onToggle}\n >\n <div className=\"kb-card-title\">{title}</div>\n <div className=\"kb-card-meta\">\n <span className=\"kb-card-badge\">{badge}</span>\n {phaseInfo !== '' && <span className=\"kb-card-phase\">{phaseInfo}</span>}\n {card.skill !== undefined && card.skill !== '' && <span className=\"kb-card-skill\">/ {card.skill}</span>}\n {card.model !== '' && <span className=\"kb-card-model\">{card.model}</span>}\n </div>\n {card.status === 'error' && card.error !== undefined && (\n <div className=\"kb-card-error-text\">{card.error.message}</div>\n )}\n {card.status === 'running' && card.gitMode === true && (\n <div className=\"kb-card-worktree\">{card.worktreePath ?? ''}</div>\n )}\n </div>\n )\n}\n\ninterface NewTaskModalProps {\n t: (key: string, params?: Record<string, unknown>) => string\n workspaces: WorkspaceRow[]\n selectedPath: string\n /** Current session id, scoping the host skill.list catalog lookup. */\n sessionId?: string\n onClose: () => void\n onCreated: () => void\n onError: (message: string) => void\n}\n\n/** An in-progress leading `/query` token (menu-open state). */\nconst SKILL_MENU_RE = /^\\s*\\/([a-z0-9-]*)$/\n\nfunction NewTaskModal({ t, workspaces, selectedPath, sessionId, onClose, onCreated, onError }: NewTaskModalProps): JSX.Element {\n const [requirement, setRequirement] = useState('')\n const [project, setProject] = useState(selectedPath)\n const [model, setModel] = useState('')\n const [modelProvider, setModelProvider] = useState('')\n const [models, setModels] = useState<Array<{ provider: string; id: string; name?: string }>>([])\n const [skills, setSkills] = useState<SkillOption[]>([])\n const [menuQuery, setMenuQuery] = useState<string | null>(null)\n const [menuIndex, setMenuIndex] = useState(0)\n const [busy, setBusy] = useState(false)\n const textareaRef = useRef<HTMLTextAreaElement | null>(null)\n\n useEffect(() => {\n let alive = true\n api.models()\n .then((list) => { if (alive) setModels(list) })\n .catch(() => { if (alive) setModels([]) })\n return () => { alive = false }\n }, [])\n\n // Load the host skill catalog once (scoped to the current session), the\n // same feed DSH's chat input uses for its /-autocomplete.\n useEffect(() => {\n if (sessionId === undefined) return\n let alive = true\n gatewaySkillList(sessionId)\n .then((list) => { if (alive) setSkills(list) })\n .catch(() => { if (alive) setSkills([]) })\n return () => { alive = false }\n }, [sessionId])\n\n const matches = skills.filter((s) => s.name.startsWith(menuQuery ?? ''))\n const menuVisible = menuQuery !== null && matches.length > 0\n const selected = menuVisible ? matches[Math.min(menuIndex, matches.length - 1)] : undefined\n\n /** Re-evaluate the leading-token menu state from the current value + caret. */\n const syncMenu = (value: string, caret: number): void => {\n const head = value.slice(0, caret)\n const m = SKILL_MENU_RE.exec(head)\n if (m !== null) {\n setMenuQuery(m[1])\n setMenuIndex(0)\n return\n }\n setMenuQuery(null)\n }\n\n const selectSkill = (name: string): void => {\n const el = textareaRef.current\n const caret = el?.selectionStart ?? requirement.length\n const head = requirement.slice(0, caret)\n const m = SKILL_MENU_RE.exec(head)\n // Replace the leading `/query` token with `/name `.\n const inserted = `/${name} `\n const newValue = m !== null ? inserted + requirement.slice(caret) : inserted + requirement\n setRequirement(newValue)\n setMenuQuery(null)\n requestAnimationFrame(() => {\n const next = textareaRef.current\n if (next !== null) {\n next.focus()\n const pos = inserted.length\n next.setSelectionRange(pos, pos)\n }\n })\n }\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>): void => {\n if (!menuVisible) return\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setMenuIndex((i) => (i + 1) % matches.length)\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n setMenuIndex((i) => (i - 1 + matches.length) % matches.length)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n if (selected !== undefined) selectSkill(selected.name)\n } else if (e.key === 'Escape') {\n e.preventDefault()\n setMenuQuery(null)\n } else if (e.key === 'Tab') {\n e.preventDefault()\n if (selected !== undefined) selectSkill(selected.name)\n }\n }\n\n const submit = async (): Promise<void> => {\n if (requirement.trim() === '') {\n onError(t('requirementLabel') + ' ' + t('error'))\n return\n }\n if (project === '') {\n onError(t('noWorkspace'))\n return\n }\n const parsed = parseSkillGesture(requirement)\n setBusy(true)\n try {\n await api.create(project, parsed.requirement, model, modelProvider, parsed.skill)\n onCreated()\n } catch (error) {\n onError(error instanceof Error ? error.message : String(error))\n setBusy(false)\n }\n }\n\n const activeSkill = parseSkillGesture(requirement).skill\n\n return (\n <div className=\"kb-modal-backdrop\" onClick={busy ? undefined : onClose}>\n <div className=\"kb-modal\" onClick={(e) => e.stopPropagation()}>\n <div className=\"kb-modal-title\">{t('newTask')}</div>\n <label className=\"kb-field\">\n <span>{t('requirementLabel')}</span>\n <div className=\"kb-skill-menu-wrap\">\n <textarea\n ref={textareaRef}\n className=\"kb-input kb-textarea\"\n value={requirement}\n placeholder={t('requirementPlaceholder')}\n onChange={(e) => {\n const value = e.target.value\n setRequirement(value)\n syncMenu(value, e.target.selectionStart ?? value.length)\n }}\n onKeyDown={onKeyDown}\n />\n {menuVisible && (\n <ul className=\"kb-skill-menu\" role=\"listbox\">\n {matches.map((s, i) => (\n <li\n key={s.name}\n role=\"option\"\n aria-selected={i === menuIndex}\n className={'kb-skill-menu-item' + (i === menuIndex ? ' kb-skill-menu-item-active' : '')}\n onMouseDown={(e) => { e.preventDefault(); selectSkill(s.name) }}\n onMouseEnter={() => setMenuIndex(i)}\n >\n <span className=\"kb-skill-menu-name\">/{s.name}</span>\n <span className=\"kb-skill-menu-desc\">\n {s.modelInvocable ? s.description : `${t('skillMenuUserOnly')} · ${s.description}`}\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n {activeSkill !== undefined ? (\n <span className=\"kb-field-hint kb-field-hint-skill\">{t('skillHint', { skill: activeSkill })}</span>\n ) : (\n <span className=\"kb-field-hint\">{t('skillGestureHint')}</span>\n )}\n </label>\n <label className=\"kb-field\">\n <span>{t('project')}</span>\n <select className=\"kb-input\" value={project} onChange={(e) => setProject(e.target.value)}>\n {workspaces.map((w) => (\n <option key={w.workspaceId} value={w.path}>{w.title}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field\">\n <span>{t('model')}</span>\n <select\n className=\"kb-input\"\n value={model}\n onChange={(e) => {\n const id = e.target.value\n setModel(id)\n const found = models.find((m) => m.id === id)\n setModelProvider(found?.provider ?? '')\n }}\n >\n <option value=\"\">{t('modelPlaceholder')}</option>\n {models.map((m) => (\n <option key={m.provider + '/' + m.id} value={m.id}>{m.name ?? m.id}</option>\n ))}\n </select>\n </label>\n <div className=\"kb-modal-actions\">\n <button type=\"button\" className=\"kb-btn\" onClick={onClose} disabled={busy}>{t('cancel')}</button>\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" onClick={() => { void submit() }} disabled={busy}>\n {t('addAndRefine')}\n </button>\n </div>\n </div>\n </div>\n )\n}\n\ninterface DetailPanelProps {\n card: KanbanCard | null\n t: (key: string, params?: Record<string, unknown>) => string\n onClose: () => void\n onChanged: () => void\n onToast: (message: string) => void\n onOpenSession: (sessionId: string) => void\n}\n\nfunction DetailPanel({ card, t, onClose, onChanged, onToast, onOpenSession }: DetailPanelProps): JSX.Element | null {\n const [busy, setBusy] = useState(false)\n if (card === null) return null\n\n const act = async (fn: () => Promise<unknown>): Promise<void> => {\n setBusy(true)\n try {\n await fn()\n onChanged()\n } catch (error) {\n onToast(error instanceof Error ? error.message : String(error))\n setBusy(false)\n }\n }\n\n const remove = async (): Promise<void> => {\n if (!window.confirm(t('deleteConfirm'))) return\n await act(() => api.remove(card!.id))\n }\n\n return (\n <div className=\"kb-detail-panel\">\n <div className=\"kb-detail-panel-head\">\n <div className=\"kb-modal-title\">\n {card.plan !== undefined && card.plan.title !== '' ? card.plan.title : firstLine(card.requirement)}\n <span className={'kb-detail-status kb-status-' + card.status}>{statusLabel(card, t)}</span>\n </div>\n <button type=\"button\" className=\"kb-detail-close\" aria-label={t('close')} title={t('close')} onClick={onClose}>✕</button>\n </div>\n\n <div className=\"kb-detail-panel-body\">\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('requirement')}</div>\n {card.skill !== undefined && card.skill !== '' && (\n <div className=\"kb-detail-skill\">{t('skillBadge', { skill: card.skill })}</div>\n )}\n <div className=\"kb-detail-text\">{card.requirement}</div>\n </div>\n\n {card.plan !== undefined && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('plan')}</div>\n <div className=\"kb-detail-plan\">\n <div className=\"kb-plan-summary\">{card.plan.summary}</div>\n <ol className=\"kb-plan-phases\">\n {card.plan.phases.map((phase, i) => (\n <PhaseCard\n key={phase.id}\n phase={phase}\n phaseIndex={i}\n card={card}\n t={t}\n onOpenSession={onOpenSession}\n />\n ))}\n </ol>\n </div>\n </div>\n )}\n\n {card.sessions.refinement.length > 0 && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('refinementLabel')}</div>\n <div className=\"kb-session-links\">\n {card.sessions.refinement.map((sid) => (\n <button key={sid} type=\"button\" className=\"kb-btn kb-btn-small\" onClick={() => onOpenSession(sid)}>\n {t('openSession')} · {sid.slice(0, 13)}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {card.status === 'error' && card.error !== undefined && (\n <div className=\"kb-detail-section kb-detail-error\">\n <div className=\"kb-detail-label\">{t('error')}</div>\n <div className=\"kb-detail-text\">{card.error.message}</div>\n </div>\n )}\n\n {card.merge?.mergeCommit !== undefined && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('mergeLabel')}</div>\n <div className=\"kb-detail-text\">{t('commitLabel')} {card.merge.mergeCommit.slice(0, 12)}</div>\n </div>\n )}\n\n <div className=\"kb-modal-actions\">\n {card.status === 'error' && (\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" disabled={busy} onClick={() => { void act(() => api.retry(card!.id)) }}>\n {t('retry')}\n </button>\n )}\n {(card.status === 'running' || card.status === 'merging') && (\n <button type=\"button\" className=\"kb-btn\" disabled={busy} onClick={() => { void act(() => api.stop(card!.id)) }}>\n {t('stop')}\n </button>\n )}\n {card.status !== 'running' && card.status !== 'refining' && card.status !== 'merging' && (\n <button type=\"button\" className=\"kb-btn kb-btn-danger\" disabled={busy} onClick={() => { void remove() }}>\n {t('delete')}\n </button>\n )}\n <button type=\"button\" className=\"kb-btn\" onClick={onClose}>{t('cancel')}</button>\n </div>\n </div>\n </div>\n )\n}\n\n/** One plan phase rendered as a card with goal / sessions / conclusion sections. */\nfunction PhaseCard({ phase, phaseIndex, card, t, onOpenSession }: {\n phase: PlanPhase\n phaseIndex: number\n card: KanbanCard\n t: (key: string, params?: Record<string, unknown>) => string\n onOpenSession: (sessionId: string) => void\n}): JSX.Element {\n const attempts = card.sessions.phases.filter((a) => a.phaseIndex === phaseIndex)\n const summaries = attempts\n .filter((a) => a.summary !== undefined && a.summary.trim() !== '')\n .map((a) => a.summary as string)\n const isCurrent = phaseIndex === card.currentPhase && card.status === 'running'\n // A phase with at least one concluded attempt counts as completed.\n const isCompleted = summaries.length > 0\n const cls = 'kb-plan-phase'\n + (isCurrent ? ' kb-plan-phase-current' : '')\n + (isCompleted ? ' kb-plan-phase-completed' : '')\n const planTitle = card.plan?.title ?? ''\n return (\n <li className={cls}>\n <div className=\"kb-plan-phase-head\">\n <span className=\"kb-plan-phase-title\">{phase.title}</span>\n <span className=\"kb-plan-phase-id\">{phase.id}</span>\n </div>\n <div className=\"kb-plan-phase-body\">\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseGoal')}</div>\n <div className=\"kb-plan-phase-goal\">{phase.goal}</div>\n </div>\n {attempts.length > 0 && (\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseSessions')}</div>\n <PhaseSessions attempts={attempts} planTitle={planTitle} phaseIndex={phaseIndex} t={t} onOpenSession={onOpenSession} />\n </div>\n )}\n {summaries.length > 0 && (\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseConclusion')}</div>\n <div className=\"kb-plan-phase-conclusion\">\n {summaries.map((s, idx) => (\n <div key={idx} className=\"kb-plan-phase-conclusion-item\">{s}</div>\n ))}\n </div>\n </div>\n )}\n </div>\n </li>\n )\n}\n\n/**\n * Open-session buttons for one phase's attempts (retries append more). The\n * button labels the session with the deterministic \"{plan title} · phase N\"\n * format (the requested fallback when the host never auto-generated a title);\n * the full session id stays available as the native tooltip.\n */\nfunction PhaseSessions({ attempts, planTitle, phaseIndex, t, onOpenSession }: {\n attempts: PhaseAttempt[]\n planTitle: string\n phaseIndex: number\n t: (key: string, params?: Record<string, unknown>) => string\n onOpenSession: (sessionId: string) => void\n}): JSX.Element {\n return (\n <div className=\"kb-plan-phase-sessions\">\n {attempts.map((a) => (\n <button key={a.sessionId} type=\"button\" className=\"kb-btn kb-btn-small\" title={a.sessionId} onClick={() => onOpenSession(a.sessionId)}>\n {t('openSession')} · {planTitle !== '' ? `${planTitle} · ${t('phaseNum', { n: phaseIndex + 1 })}` : a.sessionId.slice(0, 13)}\n </button>\n ))}\n </div>\n )\n}","import { useCallback, useEffect, useRef, useState } from 'react'\nimport { IconChecklistOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { api, type PresetOption, type ReasoningOptions } from './api'\nimport { toggleBoard, useBoardOpen } from './kanban-state'\nimport type { KanbanSettingsShape, ModelOption } from '../shared/card'\n\ninterface FooterActionProps {\n wide?: boolean\n t?: (key: string) => string\n}\n\n/** Sidebar footer entry: toggles the kanban board main view.\n * The shell renders footer actions on their own row ABOVE the settings row,\n * so the button is reparented into the settings area to sit on the same\n * line, right of the Settings trigger (see board.css .kb-settings-row). */\nexport function KanbanFooterButton({ wide, t }: FooterActionProps): JSX.Element {\n const open = useBoardOpen()\n const ref = useRef<HTMLButtonElement | null>(null)\n const label = t !== undefined ? t(open ? 'closeBoard' : 'openBoard') : 'Task Kanban'\n\n useEffect(() => {\n const btn = ref.current\n if (btn === null) return\n let foot: Element | null = null\n let disposed = false\n\n // Locate the sidebar foot area WITHOUT moving any DOM: it is the ancestor\n // of the button whose LAST child contains the settings trigger and which\n // is itself the last child of its parent (root > footArea > settingsArea).\n // The slot machinery wraps entries in an anonymous div, so the search\n // tolerates extra wrapper levels. Styling is pure CSS (see board.css\n // .kb-foot-row), so a failed lookup only leaves the button in its natural\n // slot row — it can never vanish.\n const findFoot = (): Element | null => {\n let el: Element | null = btn.parentElement\n while (el !== null && el !== document.body && el.parentElement !== null) {\n const last = el.lastElementChild\n const hasTrigger =\n last !== null &&\n (last.querySelector?.('button[aria-haspopup=\"dialog\"]') !== null ||\n last.querySelector?.('button[aria-haspopup=\"menu\"]') !== null)\n const isLastChild = el.parentElement.lastElementChild === el\n if (hasTrigger && isLastChild) return el\n el = el.parentElement\n }\n return null\n }\n\n const tryApply = (): boolean => {\n if (foot === null) {\n try {\n foot = findFoot()\n } catch {\n foot = null\n }\n }\n if (foot === null) return false\n try {\n foot.classList.add('kb-foot-row')\n foot.classList.toggle('kb-foot-rail', wide !== true)\n } catch {\n // element already gone; retry will re-locate\n }\n return true\n }\n\n let applied = false\n try {\n applied = tryApply()\n } catch (error) {\n console.error('[@fonlan/dsh-task-kanban] foot placement error:', error)\n }\n if (!applied) {\n // The settings entry may mount later than this entry (plugin load\n // order); retry on DOM mutations AND on a short interval until the\n // foot area is found (give up after 15s).\n const observer = new MutationObserver(() => {\n if (disposed) return\n if (tryApply()) observer.disconnect()\n })\n observer.observe(document.body, { childList: true, subtree: true })\n const timer = window.setInterval(() => {\n if (disposed) {\n window.clearInterval(timer)\n return\n }\n if (tryApply()) {\n observer.disconnect()\n window.clearInterval(timer)\n }\n }, 1000)\n window.setTimeout(() => {\n observer.disconnect()\n window.clearInterval(timer)\n if (foot === null) {\n // report the DOM chain so the next report carries evidence\n const chain: string[] = []\n let el: Element | null = btn.parentElement\n while (el !== null && chain.length < 8) {\n chain.push(el.tagName + '.' + String(el.className).slice(0, 60))\n el = el.parentElement\n }\n console.warn('[@fonlan/dsh-task-kanban] could not locate the sidebar foot area:', chain)\n }\n }, 15000)\n return () => {\n disposed = true\n observer.disconnect()\n window.clearInterval(timer)\n try {\n foot?.classList.remove('kb-foot-row')\n foot?.classList.remove('kb-foot-rail')\n } catch {\n // already gone\n }\n }\n }\n return () => {\n try {\n foot?.classList.remove('kb-foot-row')\n foot?.classList.remove('kb-foot-rail')\n } catch {\n // already gone\n }\n }\n }, [wide])\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={'kb-footer-action' + (wide === true ? ' kb-footer-action-wide' : '') + (open ? ' kb-footer-action-active' : '')}\n aria-label={label}\n title={label}\n onClick={() => toggleBoard()}\n >\n <IconChecklistOutline14 size={wide === true ? 16 : 18} />\n {wide === true && <span className=\"kb-footer-label\">{t !== undefined ? t('kanban') : 'Kanban'}</span>}\n </button>\n )\n}\n\ninterface SettingsSectionProps {\n t?: (key: string) => string\n}\n\n/** Fallback shape while settings load (server always resolves the full set). */\nconst EMPTY_SETTINGS: KanbanSettingsShape = {\n maxParallelWorkers: 1,\n refinementModel: '',\n refinementProvider: '',\n refinementReasoningEffort: '',\n refinementPreset: '',\n phaseModel: '',\n phaseProvider: '',\n phaseReasoningEffort: '',\n phasePreset: '',\n}\n\n/** The setting field names of one session-type group. */\nconst GROUP_FIELDS = {\n refinement: {\n model: 'refinementModel',\n provider: 'refinementProvider',\n effort: 'refinementReasoningEffort',\n preset: 'refinementPreset',\n },\n phase: {\n model: 'phaseModel',\n provider: 'phaseProvider',\n effort: 'phaseReasoningEffort',\n preset: 'phasePreset',\n },\n} as const\n\ntype SessionGroupKey = keyof typeof GROUP_FIELDS\n\ninterface SessionDefaultsGroupProps {\n kind: SessionGroupKey\n settings: KanbanSettingsShape\n models: ModelOption[]\n presets: PresetOption[]\n /** Reasoning efforts already fetched, keyed `provider/model`. */\n efforts: Record<string, ReasoningOptions>\n tr: (key: string) => string\n onCommit: (patch: Partial<KanbanSettingsShape>) => Promise<void>\n loadEfforts: (provider: string, model: string) => void\n}\n\n/** Model / reasoning effort / agent preset defaults for one session type. */\nfunction SessionDefaultsGroup({ kind, settings, models, presets, efforts, tr, onCommit, loadEfforts }: SessionDefaultsGroupProps): JSX.Element {\n const fields = GROUP_FIELDS[kind]\n const model = settings[fields.model]\n const provider = settings[fields.provider]\n const effort = settings[fields.effort]\n const preset = settings[fields.preset]\n const effortKey = model !== '' && provider !== '' ? `${provider}/${model}` : ''\n const effortOptions = effortKey !== '' ? (efforts[effortKey]?.efforts ?? []) : []\n\n const handleModel = (id: string): void => {\n const found = models.find((m) => m.id === id)\n const nextProvider = found?.provider ?? ''\n void onCommit({ [fields.model]: id, [fields.provider]: nextProvider } as Partial<KanbanSettingsShape>)\n if (id !== '' && nextProvider !== '') loadEfforts(nextProvider, id)\n }\n\n return (\n <div className=\"kb-settings-group\">\n <div className=\"kb-settings-group-title\">{tr(kind === 'refinement' ? 'settingsRefineGroup' : 'settingsPhaseGroup')}</div>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('model')}</span>\n <select className=\"kb-input\" value={model} onChange={(e) => handleModel(e.target.value)}>\n <option value=\"\">{tr('defaultOption')}</option>\n {models.map((m) => (\n <option key={m.provider + '/' + m.id} value={m.id}>{m.name ?? m.id}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('reasoningEffort')}</span>\n <select\n className=\"kb-input\"\n value={effort}\n disabled={model === ''}\n onChange={(e) => void onCommit({ [fields.effort]: e.target.value } as Partial<KanbanSettingsShape>)}\n >\n <option value=\"\">{tr('defaultOption')}</option>\n {effortOptions.map((o) => (\n <option key={o.id} value={o.id}>{o.name}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('agentPreset')}</span>\n <select\n className=\"kb-input\"\n value={preset}\n onChange={(e) => void onCommit({ [fields.preset]: e.target.value } as Partial<KanbanSettingsShape>)}\n >\n <option value=\"\">{tr('defaultOption')}</option>\n {presets.map((p) => (\n <option key={p.id} value={p.id}>{p.name ?? p.id}</option>\n ))}\n </select>\n </label>\n </div>\n )\n}\n\n/** Plugin settings page (设置 -> 侧栏「任务看板」): workers + default model + per-session-type defaults. */\nexport function KanbanSettingsSection({ t }: SettingsSectionProps): JSX.Element {\n const tr = t ?? ((key: string) => key)\n const [settings, setSettings] = useState<KanbanSettingsShape>(EMPTY_SETTINGS)\n const [models, setModels] = useState<ModelOption[]>([])\n const [presets, setPresets] = useState<PresetOption[]>([])\n const [efforts, setEfforts] = useState<Record<string, ReasoningOptions>>({})\n const [saved, setSaved] = useState(false)\n\n const commit = useCallback(async (patch: Partial<KanbanSettingsShape>): Promise<void> => {\n try {\n const next = await api.settingsSet(patch)\n setSettings(next)\n setSaved(true)\n window.setTimeout(() => setSaved(false), 1500)\n } catch {\n // keep the previous value\n }\n }, [])\n\n // Refs so async callbacks (effort fetch) read the freshest settings/commit.\n const settingsRef = useRef(settings)\n settingsRef.current = settings\n const commitRef = useRef(commit)\n commitRef.current = commit\n\n useEffect(() => {\n let alive = true\n api.settingsGet()\n .then((s) => { if (alive) setSettings(s) })\n .catch(() => undefined)\n api.models()\n .then((list) => { if (alive) setModels(list) })\n .catch(() => undefined)\n api.presets()\n .then((list) => { if (alive) setPresets(list) })\n .catch(() => undefined)\n return () => { alive = false }\n }, [])\n\n /** Reasoning routes already requested (dedupe across mount + model changes). */\n const effortFetched = useRef<Set<string>>(new Set())\n\n /**\n * Fetch the reasoning efforts of one model route (once per route). A failed\n * fetch is marked `failed` so the stored effort is preserved (see the reset\n * effect below) instead of being wiped by a transient error.\n */\n const loadEfforts = useCallback((provider: string, model: string): void => {\n const key = `${provider}/${model}`\n if (effortFetched.current.has(key)) return\n effortFetched.current.add(key)\n api.reasoningOptions(provider, model)\n .then((opts) => setEfforts((prev) => ({ ...prev, [key]: opts })))\n .catch(() => setEfforts((prev) => ({ ...prev, [key]: { efforts: [], failed: true } })))\n }, [])\n\n // Fetch efforts for the models already configured in settings, so the\n // effort selects show their levels (and validate the stored effort) as soon\n // as settings load — the fetch previously ran only on model change.\n useEffect(() => {\n for (const kind of ['refinement', 'phase'] as const) {\n const fields = GROUP_FIELDS[kind]\n const model = settings[fields.model]\n const provider = settings[fields.provider]\n if (model !== '' && provider !== '') loadEfforts(provider, model)\n }\n }, [settings.refinementModel, settings.refinementProvider, settings.phaseModel, settings.phaseProvider, loadEfforts])\n\n // When the efforts of the selected model arrive, drop a stored effort the\n // model no longer offers (e.g. the user switched the model). A failed fetch\n // (`failed: true`) keeps the stored effort: the model may just be\n // temporarily unresolvable, and wiping the user's choice would be worse.\n useEffect(() => {\n const s = settingsRef.current\n for (const kind of ['refinement', 'phase'] as const) {\n const fields = GROUP_FIELDS[kind]\n const model = s[fields.model]\n const provider = s[fields.provider]\n const effort = s[fields.effort]\n if (effort === '' || model === '' || provider === '') continue\n const opts = efforts[`${provider}/${model}`]\n if (opts === undefined || opts.failed === true) continue\n if (!opts.efforts.some((o) => o.id === effort)) {\n void commitRef.current({ [fields.effort]: '' } as Partial<KanbanSettingsShape>)\n }\n }\n }, [efforts])\n\n return (\n <div className=\"kb-page\">\n <header className=\"kb-page-head\">\n <h3 className=\"kb-page-title\">{tr('settingsTitle')}</h3>\n <p className=\"kb-page-sub\">{tr('sectionSub')}</p>\n </header>\n <div className=\"kb-settings\">\n <label className=\"kb-field kb-field-row\">\n <span>{tr('maxParallelWorkers')}</span>\n <input\n className=\"kb-input kb-input-number\"\n type=\"number\"\n min={1}\n step={1}\n value={settings.maxParallelWorkers}\n onChange={(e) => {\n const value = Math.max(1, Math.floor(Number(e.target.value) || 1))\n setSettings((s) => ({ ...s, maxParallelWorkers: value }))\n void commit({ maxParallelWorkers: value })\n }}\n />\n </label>\n <SessionDefaultsGroup\n kind=\"refinement\"\n settings={settings}\n models={models}\n presets={presets}\n efforts={efforts}\n tr={tr}\n onCommit={commit}\n loadEfforts={loadEfforts}\n />\n <SessionDefaultsGroup\n kind=\"phase\"\n settings={settings}\n models={models}\n presets={presets}\n efforts={efforts}\n tr={tr}\n onCommit={commit}\n loadEfforts={loadEfforts}\n />\n {saved && <div className=\"kb-settings-saved\">{tr('saved')}</div>}\n </div>\n </div>\n )\n}","import type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { BoardRoot } from './board'\nimport { KanbanFooterButton, KanbanSettingsSection } from './sections'\nimport { LOCALE_NS, zh, en } from './locales'\nimport { setClient, setBoardRoot, bindSessionNavigation } from './kanban-state'\n\n/** The settings sidebar entry this plugin's page owns (must stay stable). */\nconst SETTINGS_SECTION_ID = 'task-kanban'\n\n/** Services required before mounting (provided by the client runtime). */\nexport const inject = ['slots', 'sessions', 'workspaces', 'locale']\n\n/** Client plugin body. */\nexport function apply(ctx: ClientContext): void {\n setClient(ctx)\n setBoardRoot(BoardRoot as unknown as (props: Record<string, unknown>) => React.ReactNode)\n // Selecting a session while the board is open must leave the board first.\n bindSessionNavigation(ctx)\n\n // Live translate bound to the active locale (labels re-read it per call).\n const t = ctx.locale.bind(LOCALE_NS)\n ctx.effect(() => {\n const off = ctx.locale.register(LOCALE_NS, { zh, en })\n return () => off()\n }, 'task-kanban: dictionaries')\n\n ctx.slots.inject('sidebar.footer.action', () =>\n ctx.slots.register({\n name: 'sidebar.footer.action',\n id: 'task-kanban',\n order: 60,\n label: () => t('kanban'),\n locale: LOCALE_NS,\n }, KanbanFooterButton as never),\n )\n\n // The plugin's own settings page (设置 -> 侧栏「任务看板」) rides the\n // task-kanban settings namespace and registers into the settings.section\n // list slot, which gives it one entry in the settings sidebar and renders\n // its content into the panel's content column.\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register({\n name: 'settings.section',\n id: SETTINGS_SECTION_ID,\n order: 200,\n label: () => t('settingsTitle'),\n locale: LOCALE_NS,\n }, KanbanSettingsSection as never),\n )\n}"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","useCallback","useMemo","useRef","primitives","useState","useCallback","useRef"],"sources":["../../../src/shared/lanes.ts","../../../src/client/api.ts","../../../src/client/kanban-state.ts","../../../src/client/locales.ts","../../../src/client/board.tsx","../../../src/client/icons.tsx","../../../src/client/sections.tsx","../../../src/client/index.tsx"],"sourcesContent":["/**\n * Lane mapping and drag rules (shared by the board UI and tests).\n */\nimport type { KanbanCard, Lane } from './card.js'\n\n/** Which lane a card renders in, based on status + error stage. */\nexport function laneOf(card: KanbanCard): Lane {\n if (card.status === 'error') {\n if (card.error?.stage !== undefined) return card.error.stage\n const kind = card.error?.kind\n if (kind === 'phase_failed' || kind === 'no_base_branch' || kind === 'worktree_failed') return 'running'\n if (kind === 'merge_failed') return 'completed'\n return 'demand'\n }\n switch (card.status) {\n case 'draft':\n case 'refining':\n case 'planned':\n return 'demand'\n case 'queued':\n return 'queue'\n case 'running':\n return 'running'\n case 'completed':\n case 'merging':\n return 'completed'\n case 'merged':\n return 'merged'\n }\n}\n\n/** Lanes a drop onto `to` may come from. */\nexport const DROP_RULES: Record<Lane, Lane[]> = {\n demand: ['queue'],\n queue: ['demand', 'running'],\n running: [],\n completed: [],\n merged: [],\n}\n\nexport function canDrop(from: Lane, to: Lane): boolean {\n return DROP_RULES[to].includes(from)\n}\n","import type { KanbanCard, KanbanSettingsShape, Lane, ModelOption } from '../shared/card'\n\nexport class KanbanApiError extends Error {\n constructor(readonly code: string, message: string) {\n super(message)\n }\n}\n\nasync function call<T>(method: string, payload: Record<string, unknown> = {}): Promise<T> {\n let response: Response\n try {\n response = await fetch(`/plugins/@fonlan/dsh-task-kanban/api/${method}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n } catch (error) {\n throw new KanbanApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed: { ok?: boolean; value?: unknown; error?: { code?: string; message?: string } } | null\n = await response.json().catch(() => null)\n if (!response.ok || parsed === null || parsed.ok !== true || parsed.value === undefined) {\n throw new KanbanApiError(\n parsed?.error?.code ?? 'http',\n parsed?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.value as T\n}\n\n/** One row of the host `skills/list` catalog (same shape DSH's chat autocomplete uses). */\nexport interface SkillOption {\n name: string\n description: string\n whenToUse?: string\n modelInvocable: boolean\n}\n\n/**\n * Call the host gateway's `skills/list` unary RPC over the same-origin HTTP\n * bridge (the exact wire shape DSH's chat input uses for its /-autocomplete).\n *\n * DSH ≥0.1.5 addresses Remote endpoints as the canonical `<namespace>/<method>`\n * pair — `/api/skills/list` with the method `skills/list` — and carries named\n * wire arguments inside a single `args` field, so the request body is\n * `{ args: { request: { sessionId } } }` (the descriptor's parameter wire name\n * is `request`). The older dotted `skill.list` endpoint no longer exists and\n * answers HTTP 404.\n *\n * The requested `sessionId` scopes the catalog to that session's agent\n * preset, which is where the filesystem skill roots are registered.\n */\nexport async function gatewaySkillList(sessionId: string): Promise<SkillOption[]> {\n let response: Response\n try {\n response = await fetch('/api/skills/list', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n type: 'client-request',\n rpcId: `task-kanban-${Math.random().toString(36).slice(2)}`,\n method: 'skills/list',\n payload: { args: { request: { sessionId } } },\n }),\n })\n } catch (error) {\n throw new KanbanApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed: { type?: string; result?: { ok?: boolean; value?: { skills?: SkillOption[] }; error?: { code?: string; message?: string } } } | null\n = await response.json().catch(() => null)\n if (!response.ok || parsed === null || parsed.type !== 'server-response' || parsed.result?.ok !== true) {\n throw new KanbanApiError(\n parsed?.result?.error?.code ?? 'http',\n parsed?.result?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.result.value?.skills ?? []\n}\n\n/** One row of the host `agentPresets.list()` roster. */\nexport interface PresetOption {\n id: string\n name?: string\n description?: string\n}\n\n/** Reasoning efforts of one provider/model route (`reasoning.options`). */\nexport interface ReasoningOptions {\n efforts: Array<{ id: string; name: string; description?: string }>\n defaultEffort?: string\n /** Client-side marker: the fetch failed; the stored effort must be kept. */\n failed?: boolean\n}\n\nexport const api = {\n list: (workspacePath: string) => call<KanbanCard[]>('list', { workspacePath }),\n create: (workspacePath: string, requirement: string, model: string, provider?: string, skill?: string) =>\n call<KanbanCard>('create', { workspacePath, requirement, model, provider, ...(skill !== undefined && skill !== '' ? { skill } : {}) }),\n move: (cardId: string, toLane: Lane) => call<{ ok: boolean; message?: string }>('move', { cardId, toLane }),\n stop: (cardId: string) => call<{ ok: boolean; message?: string }>('stop', { cardId }),\n retry: (cardId: string) => call<{ ok: boolean; message?: string }>('retry', { cardId }),\n remove: (cardId: string) => call<{ ok: boolean; message?: string }>('remove', { cardId }),\n settingsGet: () => call<KanbanSettingsShape>('settings.get'),\n settingsSet: (patch: Partial<KanbanSettingsShape>) => call<KanbanSettingsShape>('settings.set', patch),\n models: () => call<ModelOption[]>('models.list'),\n presets: () => call<PresetOption[]>('presets.list'),\n reasoningOptions: (provider: string, model: string) =>\n call<ReasoningOptions>('reasoning.options', { provider, model }),\n}\n","import type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\n\n/**\n * Panel id shared by this plugin's main-panel key (`main`) and its sidebar\n * entry (`sidebar.panellist`): the shell selects the panel by this id, so the\n * two registrations must agree.\n */\nexport const KANBAN_PANEL_ID = 'task-kanban'\n\n/**\n * Structural view of the client shell's panel-navigation face (`ctx.layout`).\n * Declared locally (no value import) so the plugin keeps working on a runtime\n * whose layout types differ.\n */\ninterface LayoutLike {\n selectPanel(panelId: string | null): void\n}\n\n/**\n * HMR-safe owner context, keyed on the global symbol registry.\n *\n * The client-hmr hot swap re-evaluates this module (a fresh `lib/client.js`\n * bundle) WITHOUT reloading the page; a module-level cell would then be\n * duplicated per evaluation and an old copy's helper would read a stale owner.\n * `Symbol.for` makes every bundle copy share one cell.\n */\nconst STATE_KEY = Symbol.for('@fonlan/dsh-task-kanban/state')\n\ninterface KanbanState {\n client: ClientContext | null\n}\n\nfunction getState(): KanbanState {\n const g = globalThis as unknown as Record<symbol, KanbanState | undefined>\n let state = g[STATE_KEY]\n if (state === undefined) {\n state = { client: null }\n g[STATE_KEY] = state\n }\n return state\n}\n\nexport function setClient(ctx: ClientContext | null): void {\n getState().client = ctx\n}\nexport function getClient(): ClientContext | null {\n return getState().client\n}\n\n/** The shell's panel face, when this runtime provides it. */\nfunction layoutOf(ctx: ClientContext | null): LayoutLike | null {\n if (ctx === null) return null\n try {\n const layout = (ctx as unknown as { layout?: LayoutLike }).layout\n return typeof layout?.selectPanel === 'function' ? layout : null\n } catch {\n return null\n }\n}\n\n/** Select the kanban panel. The sidebar's own entry does this; kept for in-app callers. */\nexport function showKanbanPanel(ctx: ClientContext | null = getClient()): void {\n try {\n layoutOf(ctx)?.selectPanel(KANBAN_PANEL_ID)\n } catch (error) {\n console.error('[@fonlan/dsh-task-kanban] cannot select the kanban panel:', error)\n }\n}\n\n/** Hand the center column back to the Conversation. */\nexport function leaveKanbanPanel(ctx: ClientContext | null = getClient()): void {\n try {\n layoutOf(ctx)?.selectPanel(null)\n } catch (error) {\n console.error('[@fonlan/dsh-task-kanban] cannot leave the kanban panel:', error)\n }\n}\n\n/**\n * Route session navigation through the panel selection: opening any session\n * while the board is the active panel first returns the center column to the\n * Conversation, so the session view renders.\n *\n * Every sidebar path that selects a session funnels through `sessions.open`\n * (session rows, search results, fork results, New Session) or\n * `sessions.openSubagent` (catalog children) — including re-clicking the\n * already-current session, which never changes `list.current` and therefore\n * cannot be caught by a list-store subscription. Wrapping the two entry points\n * covers all of them in one place.\n *\n * The wrapper is idempotent: a `kbBound` marker on the wrapper prevents a\n * second bind (plugin re-apply / HMR) from stacking another layer.\n */\nexport function bindSessionNavigation(ctx: ClientContext): void {\n const sessions = ctx.sessions\n if (sessions === undefined) return\n\n const open = sessions.open\n if (typeof open === 'function' && (open as unknown as { kbBound?: boolean }).kbBound !== true) {\n const bound = ((id: Parameters<typeof open>[0]) => {\n leaveKanbanPanel(ctx)\n return open.call(sessions, id)\n }) as typeof open\n ;(bound as unknown as { kbBound?: boolean }).kbBound = true\n sessions.open = bound\n }\n\n const openSubagent = sessions.openSubagent\n if (typeof openSubagent === 'function' && (openSubagent as unknown as { kbBound?: boolean }).kbBound !== true) {\n const bound = ((address: Parameters<typeof openSubagent>[0]) => {\n leaveKanbanPanel(ctx)\n return openSubagent.call(sessions, address)\n }) as typeof openSubagent\n ;(bound as unknown as { kbBound?: boolean }).kbBound = true\n sessions.openSubagent = bound\n }\n}\n","// Locale namespace = the plugin's cordis id (kebab). DSH flat namespace keys\n// (settings + locale) use the internal id `task-kanban`; the scoped npm package\n// name is reserved for package-bound identifiers (exported `name`, module-loader\n// id, the /plugins/<pkg>/… route base).\nexport const LOCALE_NS = 'task-kanban'\n\nexport const zh = {\n kanban: '任务看板',\n openBoard: '打开任务看板',\n closeBoard: '返回对话',\n newTask: '新建任务',\n requirement: '需求',\n project: '所属项目',\n model: '模型',\n cancel: '取消',\n close: '关闭',\n addAndRefine: '添加并细化',\n laneDemand: '需求',\n laneQueue: '队列',\n laneRunning: '运行中',\n laneCompleted: '已完成',\n laneMerged: '已合并',\n statusDraft: '未细化',\n statusRefining: '细化中',\n statusPlanned: '已规划',\n statusQueued: '排队中',\n statusRunning: '实现中',\n statusCompleted: '已完成',\n statusMerging: '合并中',\n statusMerged: '已合并',\n statusError: '出错',\n phaseProgress: '{current}/{total}',\n retry: '重试',\n stop: '停止',\n delete: '删除',\n deleteConfirm: '确定删除该任务?其 worktree 会被清理。',\n openSession: '打开会话',\n plan: '实现方案',\n summary: '摘要',\n phases: '阶段',\n phaseGoal: '目标',\n phaseSessions: '会话',\n phaseConclusion: '结论',\n phaseNum: 'phase {n}',\n error: '错误',\n requirementLabel: '需求文本',\n requirementPlaceholder: '描述你要实现的需求……',\n skillGestureHint: '开头输入 /skill-name 可指定细化时使用的 Skill(如 /grill-me)',\n skillHint: '细化时将使用 Skill「{skill}」,并可与该会话交流打磨需求',\n skillMenuUserOnly: '仅用户可调',\n skillBadge: '细化 Skill:/{skill}',\n modelPlaceholder: '(使用默认模型)',\n noWorkspace: '没有可用工作区,请先在侧边栏添加',\n refresh: '刷新',\n settingsTitle: '任务看板',\n sectionSub: '全局并行 worker 数与各会话类型的默认模型、推理强度、Agent 预设',\n maxParallelWorkers: '全局并行 worker 数',\n settingsRefineGroup: '细化需求会话默认',\n settingsPhaseGroup: 'Phase 实现会话默认',\n reasoningEffort: '推理强度',\n agentPreset: 'Agent 预设',\n defaultOption: '(默认)',\n saved: '已保存',\n loadError: '加载任务失败',\n noPlan: '该卡片还没有实现计划,请先点击\"添加并细化\"',\n dragNoPlan: '还没有实现计划的卡片不能进入队列',\n actionFailed: '操作失败:{message}',\n sessionNotListed: '该会话不在当前列表,可能来自其他工作区',\n interrupted: '已中断',\n noBaseBranch: '项目没有 main/master 分支',\n worktreeFailed: 'worktree 创建失败',\n refineFailed: '细化失败',\n phaseFailed: '阶段执行失败',\n mergeFailed: '合并失败',\n createFailed: '创建失败',\n refinementLabel: '需求细化',\n mergeLabel: '合并',\n commitLabel: '提交',\n}\n\nexport const en = {\n kanban: 'Task Kanban',\n openBoard: 'Open Task Kanban',\n closeBoard: 'Back to chat',\n newTask: 'New Task',\n requirement: 'Requirement',\n project: 'Project',\n model: 'Model',\n cancel: 'Cancel',\n close: 'Close',\n addAndRefine: 'Add & Refine',\n laneDemand: 'Demands',\n laneQueue: 'Queue',\n laneRunning: 'Running',\n laneCompleted: 'Completed',\n laneMerged: 'Merged',\n statusDraft: 'Unrefined',\n statusRefining: 'Refining',\n statusPlanned: 'Planned',\n statusQueued: 'Queued',\n statusRunning: 'Running',\n statusCompleted: 'Completed',\n statusMerging: 'Merging',\n statusMerged: 'Merged',\n statusError: 'Error',\n phaseProgress: '{current}/{total}',\n retry: 'Retry',\n stop: 'Stop',\n delete: 'Delete',\n deleteConfirm: 'Delete this task? Its worktree will be cleaned up.',\n openSession: 'Open session',\n plan: 'Plan',\n summary: 'Summary',\n phases: 'Phases',\n phaseGoal: 'Goal',\n phaseSessions: 'Sessions',\n phaseConclusion: 'Conclusion',\n phaseNum: 'Phase {n}',\n error: 'Error',\n requirementLabel: 'Requirement',\n requirementPlaceholder: 'Describe what you want to build…',\n skillGestureHint: 'Start with /skill-name to choose the refinement skill (e.g. /grill-me)',\n skillHint: 'Refinement will use Skill “{skill}” — talk to this session to refine the requirement',\n skillMenuUserOnly: 'User-only',\n skillBadge: 'Refine skill: /{skill}',\n modelPlaceholder: '(use default model)',\n noWorkspace: 'No workspaces available — add one in the sidebar first',\n refresh: 'Refresh',\n settingsTitle: 'Task Kanban',\n sectionSub: 'Global parallel workers and per-session-type defaults for model, reasoning effort, and agent preset',\n maxParallelWorkers: 'Global parallel workers',\n settingsRefineGroup: 'Refinement session defaults',\n settingsPhaseGroup: 'Phase implementation defaults',\n reasoningEffort: 'Reasoning effort',\n agentPreset: 'Agent preset',\n defaultOption: '(default)',\n saved: 'Saved',\n loadError: 'Failed to load tasks',\n noPlan: 'This card has no plan yet — click \"Add & Refine\" first',\n dragNoPlan: 'Cards without a plan cannot enter the queue',\n actionFailed: 'Action failed: {message}',\n sessionNotListed: 'Session is not listed here; it may belong to another workspace',\n interrupted: 'Interrupted',\n noBaseBranch: 'Project has no main/master branch',\n worktreeFailed: 'Worktree creation failed',\n refineFailed: 'Refinement failed',\n phaseFailed: 'Phase failed',\n mergeFailed: 'Merge failed',\n createFailed: 'Creation failed',\n refinementLabel: 'Refinement',\n mergeLabel: 'Merge',\n commitLabel: 'Commit',\n}","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { KanbanCard, Lane, PhaseAttempt, PlanPhase } from '../shared/card'\nimport { DROP_RULES, laneOf } from '../shared/lanes'\nimport { api, gatewaySkillList, type SkillOption } from './api'\nimport { getClient, leaveKanbanPanel } from './kanban-state'\nimport { en, zh } from './locales'\nimport './board.css'\n\ninterface BoardProps {\n t?: (key: string, params?: Record<string, unknown>) => string\n useWorkspaces?: (selector: (state: unknown) => unknown) => unknown\n useSessions?: (selector: (state: unknown) => unknown) => unknown\n}\n\n/** Session-list snapshot shape the standard `useSessions` feed carries. */\ninterface SessionListStateLike {\n current?: string\n /** Listed session ids (the feed's own order). */\n ids?: string[]\n}\n\nfunction firstLine(text: string): string {\n return text.split('\\n').find((l) => l.trim() !== '')?.trim() ?? ''\n}\n\n/** The leading `/skill-name` gesture at the start of the requirement input. */\nconst SKILL_GESTURE = /^\\s*\\/([a-z0-9]+(?:-[a-z0-9]+)*)(?=\\s|$)/\n\n/** Extract a leading `/skill-name` token plus the cleaned remainder. */\nfunction parseSkillGesture(raw: string): { skill?: string; requirement: string } {\n const m = SKILL_GESTURE.exec(raw)\n if (m === null) return { requirement: raw.trim() }\n return { skill: m[1], requirement: raw.slice(m[0].length).trim() }\n}\n\nfunction statusLabel(card: KanbanCard, t: (key: string) => string): string {\n if (card.status === 'error') {\n switch (card.error?.kind) {\n case 'interrupted': return t('interrupted')\n case 'no_base_branch': return t('noBaseBranch')\n case 'worktree_failed': return t('worktreeFailed')\n case 'refine_failed': return t('refineFailed')\n case 'phase_failed': return t('phaseFailed')\n case 'merge_failed': return t('mergeFailed')\n default: return t('createFailed')\n }\n }\n switch (card.status) {\n case 'draft': return t('statusDraft')\n case 'refining': return t('statusRefining')\n case 'planned': return t('statusPlanned')\n case 'queued': return t('statusQueued')\n case 'running': return t('statusRunning')\n case 'completed': return t('statusCompleted')\n case 'merging': return t('statusMerging')\n case 'merged': return t('statusMerged')\n }\n}\n\ninterface WorkspaceRow {\n workspaceId: string\n path: string\n title: string\n}\n\nconst LANE_ORDER: Array<{ key: Lane; labelKey: string }> = [\n { key: 'demand', labelKey: 'laneDemand' },\n { key: 'queue', labelKey: 'laneQueue' },\n { key: 'running', labelKey: 'laneRunning' },\n { key: 'completed', labelKey: 'laneCompleted' },\n { key: 'merged', labelKey: 'laneMerged' },\n]\n\nconst WS_STORAGE_KEY = '@fonlan/dsh-task-kanban:workspace'\n\nexport function BoardRoot(props: BoardProps): JSX.Element {\n const t = props.t ?? ((key: string, params?: Record<string, unknown>) => {\n const dict = (zh as Record<string, string>)[key] ?? (en as Record<string, string>)[key]\n if (dict === undefined || params === undefined) return dict ?? key\n return dict.replace(/\\{(\\w+)\\}/g, (m, name: string) => (params[name] as string) ?? m)\n })\n const useWorkspaces = props.useWorkspaces\n const wsState = useWorkspaces !== undefined ? (useWorkspaces((s: unknown) => s) as { items?: WorkspaceRow[] } | undefined) : undefined\n const items: WorkspaceRow[] = wsState?.items ?? []\n const useSessions = props.useSessions\n const sessionState = useSessions !== undefined ? (useSessions((s: unknown) => s) as SessionListStateLike | undefined) : undefined\n // The skill catalog is addressed by session (`skills/list`), so the /-menu\n // needs one. With no selection (fresh browser, board opened straight from the\n // footer) fall back to the most recent listed session: any session resolves a\n // preset scope, whereas no session silently leaves the menu empty.\n const currentSessionId = sessionState?.current ?? sessionState?.ids?.[0]\n\n const [selectedPath, setSelectedPath] = useState<string>(() => {\n try {\n return localStorage.getItem(WS_STORAGE_KEY) ?? ''\n } catch {\n return ''\n }\n })\n const [cards, setCards] = useState<KanbanCard[]>([])\n const [toast, setToast] = useState<string | null>(null)\n const [detailId, setDetailId] = useState<string | null>(null)\n const [newTaskOpen, setNewTaskOpen] = useState(false)\n\n useEffect(() => {\n if (selectedPath === '' && items.length > 0) {\n setSelectedPath(items[0].path)\n }\n }, [selectedPath, items])\n\n const showToast = useCallback((message: string) => {\n setToast(message)\n window.setTimeout(() => setToast(null), 3500)\n }, [])\n\n const refresh = useCallback(async () => {\n if (selectedPath === '') return\n try {\n setCards(await api.list(selectedPath))\n } catch (error) {\n showToast(error instanceof Error ? error.message : String(error))\n }\n }, [selectedPath, showToast])\n\n useEffect(() => {\n void refresh()\n const timer = window.setInterval(() => { void refresh() }, 2500)\n return () => window.clearInterval(timer)\n }, [refresh])\n\n const byLane = useMemo(() => {\n const map: Record<Lane, KanbanCard[]> = { demand: [], queue: [], running: [], completed: [], merged: [] }\n for (const card of cards) map[laneOf(card)].push(card)\n for (const lane of LANE_ORDER) map[lane.key].sort((a, b) => a.createdAt - b.createdAt)\n return map\n }, [cards])\n\n const handleDrop = useCallback(async (target: Lane, event: React.DragEvent) => {\n event.preventDefault()\n const cardId = event.dataTransfer.getData('text/plain')\n if (cardId === '') return\n const card = cards.find((c) => c.id === cardId)\n if (card === undefined) return\n if (target === 'queue' && card.status !== 'running' && card.plan === undefined) {\n showToast(t('dragNoPlan'))\n return\n }\n try {\n const result = await api.move(cardId, target)\n if (!result.ok) {\n showToast(t('actionFailed', { message: result.message ?? '' }))\n }\n void refresh()\n } catch (error) {\n showToast(error instanceof Error ? error.message : String(error))\n }\n }, [cards, refresh, showToast, t])\n\n const openSession = useCallback((sessionId: string) => {\n const ctx = getClient()\n // Return the center column to the Conversation first: `sessions.open` is\n // wrapped by bindSessionNavigation as well, but a runtime without that\n // binding must still leave the board before the session renders.\n leaveKanbanPanel(ctx)\n if (ctx === null) return\n try {\n ;(ctx.sessions as { open(id: string): void }).open(sessionId)\n } catch {\n showToast(t('sessionNotListed'))\n }\n }, [showToast, t])\n\n if (items.length === 0) {\n return (\n <div className=\"kb-board kb-empty\">\n <div className=\"kb-empty-text\">{t('noWorkspace')}</div>\n </div>\n )\n }\n\n return (\n <div className=\"kb-board\">\n <div className=\"kb-board-header\">\n <div className=\"kb-board-title\">\n <select\n className=\"kb-ws-select\"\n value={selectedPath}\n onChange={(e) => {\n setSelectedPath(e.target.value)\n try {\n localStorage.setItem(WS_STORAGE_KEY, e.target.value)\n } catch {\n // storage unavailable\n }\n }}\n >\n {items.map((w) => (\n <option key={w.workspaceId} value={w.path}>{w.title}</option>\n ))}\n </select>\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" onClick={() => setNewTaskOpen(true)}>{t('newTask')}</button>\n </div>\n </div>\n\n <div className=\"kb-lanes\">\n {LANE_ORDER.map((lane) => (\n <div\n key={lane.key}\n className={'kb-lane' + (DROP_RULES[lane.key].length > 0 ? ' kb-lane-drop' : '')}\n onDragOver={(e) => {\n if (DROP_RULES[lane.key].length > 0) e.preventDefault()\n }}\n onDrop={(e) => { void handleDrop(lane.key, e) }}\n >\n <div className=\"kb-lane-head\">\n <span className=\"kb-lane-title\">{t(lane.labelKey)}</span>\n <span className=\"kb-lane-count\">{byLane[lane.key].length}</span>\n </div>\n <div className=\"kb-lane-body\">\n {byLane[lane.key].map((card) => (\n <CardView\n key={card.id}\n card={card}\n t={t}\n onToggle={() => setDetailId(detailId === card.id ? null : card.id)}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n\n {toast !== null && <div className=\"kb-toast\">{toast}</div>}\n\n {newTaskOpen && (\n <NewTaskModal\n t={t}\n workspaces={items}\n selectedPath={selectedPath}\n sessionId={currentSessionId}\n onClose={() => setNewTaskOpen(false)}\n onCreated={() => {\n setNewTaskOpen(false)\n void refresh()\n }}\n onError={(message) => showToast(message)}\n />\n )}\n\n {detailId !== null && (\n <DetailPanel\n card={cards.find((c) => c.id === detailId) ?? null}\n t={t}\n onClose={() => setDetailId(null)}\n onChanged={() => {\n setDetailId(null)\n void refresh()\n }}\n onToast={showToast}\n onOpenSession={openSession}\n />\n )}\n </div>\n )\n}\n\ninterface CardViewProps {\n card: KanbanCard\n t: (key: string, params?: Record<string, unknown>) => string\n onToggle: () => void\n}\n\nfunction CardView({ card, t, onToggle }: CardViewProps): JSX.Element {\n const draggable = card.status === 'planned' || card.status === 'queued' || card.status === 'running'\n const title = card.plan !== undefined && card.plan.title !== '' ? card.plan.title : firstLine(card.requirement)\n const badge = statusLabel(card, t)\n const phaseInfo = card.status === 'running' || card.status === 'error'\n ? card.currentPhase < card.phaseCount ? t('phaseProgress', { current: card.currentPhase + 1, total: card.phaseCount }) : ''\n : ''\n return (\n <div\n className={'kb-card' + (card.status === 'error' ? ' kb-card-error' : '') + (card.status === 'running' ? ' kb-card-running' : '')}\n draggable={draggable}\n onDragStart={(e) => {\n e.dataTransfer.setData('text/plain', card.id)\n e.dataTransfer.effectAllowed = 'move'\n }}\n onClick={onToggle}\n >\n <div className=\"kb-card-title\">{title}</div>\n <div className=\"kb-card-meta\">\n <span className=\"kb-card-badge\">{badge}</span>\n {phaseInfo !== '' && <span className=\"kb-card-phase\">{phaseInfo}</span>}\n {card.skill !== undefined && card.skill !== '' && <span className=\"kb-card-skill\">/ {card.skill}</span>}\n {card.model !== '' && <span className=\"kb-card-model\">{card.model}</span>}\n </div>\n {card.status === 'error' && card.error !== undefined && (\n <div className=\"kb-card-error-text\">{card.error.message}</div>\n )}\n {card.status === 'running' && card.gitMode === true && (\n <div className=\"kb-card-worktree\">{card.worktreePath ?? ''}</div>\n )}\n </div>\n )\n}\n\ninterface NewTaskModalProps {\n t: (key: string, params?: Record<string, unknown>) => string\n workspaces: WorkspaceRow[]\n selectedPath: string\n /** Current session id, scoping the host skill.list catalog lookup. */\n sessionId?: string\n onClose: () => void\n onCreated: () => void\n onError: (message: string) => void\n}\n\n/** An in-progress leading `/query` token (menu-open state). */\nconst SKILL_MENU_RE = /^\\s*\\/([a-z0-9-]*)$/\n\nfunction NewTaskModal({ t, workspaces, selectedPath, sessionId, onClose, onCreated, onError }: NewTaskModalProps): JSX.Element {\n const [requirement, setRequirement] = useState('')\n const [project, setProject] = useState(selectedPath)\n const [model, setModel] = useState('')\n const [modelProvider, setModelProvider] = useState('')\n const [models, setModels] = useState<Array<{ provider: string; id: string; name?: string }>>([])\n const [skills, setSkills] = useState<SkillOption[]>([])\n const [menuQuery, setMenuQuery] = useState<string | null>(null)\n const [menuIndex, setMenuIndex] = useState(0)\n const [busy, setBusy] = useState(false)\n const textareaRef = useRef<HTMLTextAreaElement | null>(null)\n\n useEffect(() => {\n let alive = true\n api.models()\n .then((list) => { if (alive) setModels(list) })\n .catch(() => { if (alive) setModels([]) })\n return () => { alive = false }\n }, [])\n\n // Load the host skill catalog once (scoped to the current session), the\n // same feed DSH's chat input uses for its /-autocomplete.\n useEffect(() => {\n if (sessionId === undefined) return\n let alive = true\n gatewaySkillList(sessionId)\n .then((list) => { if (alive) setSkills(list) })\n .catch(() => { if (alive) setSkills([]) })\n return () => { alive = false }\n }, [sessionId])\n\n const matches = skills.filter((s) => s.name.startsWith(menuQuery ?? ''))\n const menuVisible = menuQuery !== null && matches.length > 0\n const selected = menuVisible ? matches[Math.min(menuIndex, matches.length - 1)] : undefined\n\n /** Re-evaluate the leading-token menu state from the current value + caret. */\n const syncMenu = (value: string, caret: number): void => {\n const head = value.slice(0, caret)\n const m = SKILL_MENU_RE.exec(head)\n if (m !== null) {\n setMenuQuery(m[1])\n setMenuIndex(0)\n return\n }\n setMenuQuery(null)\n }\n\n const selectSkill = (name: string): void => {\n const el = textareaRef.current\n const caret = el?.selectionStart ?? requirement.length\n const head = requirement.slice(0, caret)\n const m = SKILL_MENU_RE.exec(head)\n // Replace the leading `/query` token with `/name `.\n const inserted = `/${name} `\n const newValue = m !== null ? inserted + requirement.slice(caret) : inserted + requirement\n setRequirement(newValue)\n setMenuQuery(null)\n requestAnimationFrame(() => {\n const next = textareaRef.current\n if (next !== null) {\n next.focus()\n const pos = inserted.length\n next.setSelectionRange(pos, pos)\n }\n })\n }\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>): void => {\n if (!menuVisible) return\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setMenuIndex((i) => (i + 1) % matches.length)\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n setMenuIndex((i) => (i - 1 + matches.length) % matches.length)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n if (selected !== undefined) selectSkill(selected.name)\n } else if (e.key === 'Escape') {\n e.preventDefault()\n setMenuQuery(null)\n } else if (e.key === 'Tab') {\n e.preventDefault()\n if (selected !== undefined) selectSkill(selected.name)\n }\n }\n\n const submit = async (): Promise<void> => {\n if (requirement.trim() === '') {\n onError(t('requirementLabel') + ' ' + t('error'))\n return\n }\n if (project === '') {\n onError(t('noWorkspace'))\n return\n }\n const parsed = parseSkillGesture(requirement)\n setBusy(true)\n try {\n await api.create(project, parsed.requirement, model, modelProvider, parsed.skill)\n onCreated()\n } catch (error) {\n onError(error instanceof Error ? error.message : String(error))\n setBusy(false)\n }\n }\n\n const activeSkill = parseSkillGesture(requirement).skill\n\n return (\n <div className=\"kb-modal-backdrop\" onClick={busy ? undefined : onClose}>\n <div className=\"kb-modal\" onClick={(e) => e.stopPropagation()}>\n <div className=\"kb-modal-title\">{t('newTask')}</div>\n <label className=\"kb-field\">\n <span>{t('requirementLabel')}</span>\n <div className=\"kb-skill-menu-wrap\">\n <textarea\n ref={textareaRef}\n className=\"kb-input kb-textarea\"\n value={requirement}\n placeholder={t('requirementPlaceholder')}\n onChange={(e) => {\n const value = e.target.value\n setRequirement(value)\n syncMenu(value, e.target.selectionStart ?? value.length)\n }}\n onKeyDown={onKeyDown}\n />\n {menuVisible && (\n <ul className=\"kb-skill-menu\" role=\"listbox\">\n {matches.map((s, i) => (\n <li\n key={s.name}\n role=\"option\"\n aria-selected={i === menuIndex}\n className={'kb-skill-menu-item' + (i === menuIndex ? ' kb-skill-menu-item-active' : '')}\n onMouseDown={(e) => { e.preventDefault(); selectSkill(s.name) }}\n onMouseEnter={() => setMenuIndex(i)}\n >\n <span className=\"kb-skill-menu-name\">/{s.name}</span>\n <span className=\"kb-skill-menu-desc\">\n {s.modelInvocable ? s.description : `${t('skillMenuUserOnly')} · ${s.description}`}\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n {activeSkill !== undefined ? (\n <span className=\"kb-field-hint kb-field-hint-skill\">{t('skillHint', { skill: activeSkill })}</span>\n ) : (\n <span className=\"kb-field-hint\">{t('skillGestureHint')}</span>\n )}\n </label>\n <label className=\"kb-field\">\n <span>{t('project')}</span>\n <select className=\"kb-input\" value={project} onChange={(e) => setProject(e.target.value)}>\n {workspaces.map((w) => (\n <option key={w.workspaceId} value={w.path}>{w.title}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field\">\n <span>{t('model')}</span>\n <select\n className=\"kb-input\"\n value={model}\n onChange={(e) => {\n const id = e.target.value\n setModel(id)\n const found = models.find((m) => m.id === id)\n setModelProvider(found?.provider ?? '')\n }}\n >\n <option value=\"\">{t('modelPlaceholder')}</option>\n {models.map((m) => (\n <option key={m.provider + '/' + m.id} value={m.id}>{m.name ?? m.id}</option>\n ))}\n </select>\n </label>\n <div className=\"kb-modal-actions\">\n <button type=\"button\" className=\"kb-btn\" onClick={onClose} disabled={busy}>{t('cancel')}</button>\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" onClick={() => { void submit() }} disabled={busy}>\n {t('addAndRefine')}\n </button>\n </div>\n </div>\n </div>\n )\n}\n\ninterface DetailPanelProps {\n card: KanbanCard | null\n t: (key: string, params?: Record<string, unknown>) => string\n onClose: () => void\n onChanged: () => void\n onToast: (message: string) => void\n onOpenSession: (sessionId: string) => void\n}\n\nfunction DetailPanel({ card, t, onClose, onChanged, onToast, onOpenSession }: DetailPanelProps): JSX.Element | null {\n const [busy, setBusy] = useState(false)\n if (card === null) return null\n\n const act = async (fn: () => Promise<unknown>): Promise<void> => {\n setBusy(true)\n try {\n await fn()\n onChanged()\n } catch (error) {\n onToast(error instanceof Error ? error.message : String(error))\n setBusy(false)\n }\n }\n\n const remove = async (): Promise<void> => {\n if (!window.confirm(t('deleteConfirm'))) return\n await act(() => api.remove(card!.id))\n }\n\n return (\n <div className=\"kb-detail-panel\">\n <div className=\"kb-detail-panel-head\">\n <div className=\"kb-modal-title\">\n {card.plan !== undefined && card.plan.title !== '' ? card.plan.title : firstLine(card.requirement)}\n <span className={'kb-detail-status kb-status-' + card.status}>{statusLabel(card, t)}</span>\n </div>\n <button type=\"button\" className=\"kb-detail-close\" aria-label={t('close')} title={t('close')} onClick={onClose}>✕</button>\n </div>\n\n <div className=\"kb-detail-panel-body\">\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('requirement')}</div>\n {card.skill !== undefined && card.skill !== '' && (\n <div className=\"kb-detail-skill\">{t('skillBadge', { skill: card.skill })}</div>\n )}\n <div className=\"kb-detail-text\">{card.requirement}</div>\n </div>\n\n {card.plan !== undefined && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('plan')}</div>\n <div className=\"kb-detail-plan\">\n <div className=\"kb-plan-summary\">{card.plan.summary}</div>\n <ol className=\"kb-plan-phases\">\n {card.plan.phases.map((phase, i) => (\n <PhaseCard\n key={phase.id}\n phase={phase}\n phaseIndex={i}\n card={card}\n t={t}\n onOpenSession={onOpenSession}\n />\n ))}\n </ol>\n </div>\n </div>\n )}\n\n {card.sessions.refinement.length > 0 && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('refinementLabel')}</div>\n <div className=\"kb-session-links\">\n {card.sessions.refinement.map((sid) => (\n <button key={sid} type=\"button\" className=\"kb-btn kb-btn-small\" onClick={() => onOpenSession(sid)}>\n {t('openSession')} · {sid.slice(0, 13)}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {card.status === 'error' && card.error !== undefined && (\n <div className=\"kb-detail-section kb-detail-error\">\n <div className=\"kb-detail-label\">{t('error')}</div>\n <div className=\"kb-detail-text\">{card.error.message}</div>\n </div>\n )}\n\n {card.merge?.mergeCommit !== undefined && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('mergeLabel')}</div>\n <div className=\"kb-detail-text\">{t('commitLabel')} {card.merge.mergeCommit.slice(0, 12)}</div>\n </div>\n )}\n\n <div className=\"kb-modal-actions\">\n {card.status === 'error' && (\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" disabled={busy} onClick={() => { void act(() => api.retry(card!.id)) }}>\n {t('retry')}\n </button>\n )}\n {(card.status === 'running' || card.status === 'merging') && (\n <button type=\"button\" className=\"kb-btn\" disabled={busy} onClick={() => { void act(() => api.stop(card!.id)) }}>\n {t('stop')}\n </button>\n )}\n {card.status !== 'running' && card.status !== 'refining' && card.status !== 'merging' && (\n <button type=\"button\" className=\"kb-btn kb-btn-danger\" disabled={busy} onClick={() => { void remove() }}>\n {t('delete')}\n </button>\n )}\n <button type=\"button\" className=\"kb-btn\" onClick={onClose}>{t('cancel')}</button>\n </div>\n </div>\n </div>\n )\n}\n\n/** One plan phase rendered as a card with goal / sessions / conclusion sections. */\nfunction PhaseCard({ phase, phaseIndex, card, t, onOpenSession }: {\n phase: PlanPhase\n phaseIndex: number\n card: KanbanCard\n t: (key: string, params?: Record<string, unknown>) => string\n onOpenSession: (sessionId: string) => void\n}): JSX.Element {\n const attempts = card.sessions.phases.filter((a) => a.phaseIndex === phaseIndex)\n const summaries = attempts\n .filter((a) => a.summary !== undefined && a.summary.trim() !== '')\n .map((a) => a.summary as string)\n const isCurrent = phaseIndex === card.currentPhase && card.status === 'running'\n // A phase with at least one concluded attempt counts as completed.\n const isCompleted = summaries.length > 0\n const cls = 'kb-plan-phase'\n + (isCurrent ? ' kb-plan-phase-current' : '')\n + (isCompleted ? ' kb-plan-phase-completed' : '')\n const planTitle = card.plan?.title ?? ''\n return (\n <li className={cls}>\n <div className=\"kb-plan-phase-head\">\n <span className=\"kb-plan-phase-title\">{phase.title}</span>\n <span className=\"kb-plan-phase-id\">{phase.id}</span>\n </div>\n <div className=\"kb-plan-phase-body\">\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseGoal')}</div>\n <div className=\"kb-plan-phase-goal\">{phase.goal}</div>\n </div>\n {attempts.length > 0 && (\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseSessions')}</div>\n <PhaseSessions attempts={attempts} planTitle={planTitle} phaseIndex={phaseIndex} t={t} onOpenSession={onOpenSession} />\n </div>\n )}\n {summaries.length > 0 && (\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseConclusion')}</div>\n <div className=\"kb-plan-phase-conclusion\">\n {summaries.map((s, idx) => (\n <div key={idx} className=\"kb-plan-phase-conclusion-item\">{s}</div>\n ))}\n </div>\n </div>\n )}\n </div>\n </li>\n )\n}\n\n/**\n * Open-session buttons for one phase's attempts (retries append more). The\n * button labels the session with the deterministic \"{plan title} · phase N\"\n * format (the requested fallback when the host never auto-generated a title);\n * the full session id stays available as the native tooltip.\n */\nfunction PhaseSessions({ attempts, planTitle, phaseIndex, t, onOpenSession }: {\n attempts: PhaseAttempt[]\n planTitle: string\n phaseIndex: number\n t: (key: string, params?: Record<string, unknown>) => string\n onOpenSession: (sessionId: string) => void\n}): JSX.Element {\n return (\n <div className=\"kb-plan-phase-sessions\">\n {attempts.map((a) => (\n <button key={a.sessionId} type=\"button\" className=\"kb-btn kb-btn-small\" title={a.sessionId} onClick={() => onOpenSession(a.sessionId)}>\n {t('openSession')} · {planTitle !== '' ? `${planTitle} · ${t('phaseNum', { n: phaseIndex + 1 })}` : a.sessionId.slice(0, 13)}\n </button>\n ))}\n </div>\n )\n}","import * as primitives from '@deepseek-ai/dsh-client-ui-primitives'\n\n/** Props every shell icon accepts: square edge in px, color rides currentColor. */\nexport interface IconProps {\n size?: number\n className?: string\n}\n\n/** One shell icon component. */\nexport type IconComponent = (props: IconProps) => JSX.Element\n\n/** The runtime export table, read by capability instead of by one hard-coded name. */\nconst table = primitives as unknown as Record<string, IconComponent | undefined>\n\n/** First name the runtime actually provides (a missing export is `undefined`). */\nfunction firstDefined(...names: string[]): IconComponent | undefined {\n for (const name of names) {\n let candidate: IconComponent | undefined\n try {\n candidate = table[name]\n } catch {\n // Some module namespaces reject unknown names instead of yielding\n // `undefined`; a rename must never throw on its way to the fallback.\n continue\n }\n if (typeof candidate === 'function') return candidate\n }\n return undefined\n}\n\n/**\n * Self-contained 16×16 checklist glyph (the 0.1.7 artwork) used when the shell\n * primitives expose none of the names above: the footer entry must render\n * something even on a runtime whose icon exports we do not know.\n */\nfunction ChecklistFallback({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg\n width={size}\n height={size}\n className={className}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n strokeWidth={1}\n >\n <path d=\"M3.75 6.25C4.7165 6.25 5.5 5.4665 5.5 4.5C5.5 3.5335 4.7165 2.75 3.75 2.75C2.7835 2.75 2 3.5335 2 4.5C2 5.4665 2.7835 6.25 3.75 6.25Z\" stroke=\"currentColor\" />\n <path d=\"M7.5 4.5H13.5\" stroke=\"currentColor\" />\n <path d=\"M3.75 13.25C4.7165 13.25 5.5 12.4665 5.5 11.5C5.5 10.5335 4.7165 9.75 3.75 9.75C2.7835 9.75 2 10.5335 2 11.5C2 12.4665 2.7835 13.25 3.75 13.25Z\" stroke=\"currentColor\" />\n <path d=\"M7.5 11.5H13.5\" stroke=\"currentColor\" />\n </svg>\n )\n}\n\n/**\n * The checklist icon used by the sidebar panel row entry.\n *\n * DSH 0.1.7 renamed every size-suffixed shell icon (`IconChecklistOutline14`)\n * into stroke-weight variants (`…Regular` 1px / `…Medium` 1.3px) inside\n * `@deepseek-ai/dsh-client-ui-primitives`. A stale named import resolves to\n * `undefined` and React then throws \"Element type is invalid\" while rendering\n * the slot entry — the entry is dropped and the button silently disappears\n * (exactly what upgrading to 0.1.7 did to this plugin). Resolve the name at\n * runtime, newest first, so the next rename degrades to another shipped\n * variant instead of taking the button down with it.\n */\nexport const ChecklistIcon: IconComponent =\n firstDefined(\n 'IconChecklistOutlineRegular',\n 'IconChecklistOutlineMedium',\n 'IconChecklistOutline',\n 'IconChecklistOutline14',\n ) ?? ChecklistFallback\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport { ChecklistIcon } from './icons'\nimport { api, type PresetOption, type ReasoningOptions } from './api'\nimport type { KanbanSettingsShape, ModelOption } from '../shared/card'\n\n/**\n * Sidebar panel-row glyph for the board (`sidebar.panellist`).\n *\n * The shell owns the row: it renders the button, its label, tooltip and active\n * state, and calls `layout.selectPanel(id)` on click. The entry contributes\n * only the glyph, so this component must stay purely presentational.\n */\nexport function KanbanPanelIcon({ size }: { size: number }): JSX.Element {\n return <ChecklistIcon size={size} />\n}\n\ninterface SettingsSectionProps {\n t?: (key: string) => string\n}\n\n/** Fallback shape while settings load (server always resolves the full set). */\nconst EMPTY_SETTINGS: KanbanSettingsShape = {\n maxParallelWorkers: 1,\n refinementModel: '',\n refinementProvider: '',\n refinementReasoningEffort: '',\n refinementPreset: '',\n phaseModel: '',\n phaseProvider: '',\n phaseReasoningEffort: '',\n phasePreset: '',\n}\n\n/** The setting field names of one session-type group. */\nconst GROUP_FIELDS = {\n refinement: {\n model: 'refinementModel',\n provider: 'refinementProvider',\n effort: 'refinementReasoningEffort',\n preset: 'refinementPreset',\n },\n phase: {\n model: 'phaseModel',\n provider: 'phaseProvider',\n effort: 'phaseReasoningEffort',\n preset: 'phasePreset',\n },\n} as const\n\ntype SessionGroupKey = keyof typeof GROUP_FIELDS\n\ninterface SessionDefaultsGroupProps {\n kind: SessionGroupKey\n settings: KanbanSettingsShape\n models: ModelOption[]\n presets: PresetOption[]\n /** Reasoning efforts already fetched, keyed `provider/model`. */\n efforts: Record<string, ReasoningOptions>\n tr: (key: string) => string\n onCommit: (patch: Partial<KanbanSettingsShape>) => Promise<void>\n loadEfforts: (provider: string, model: string) => void\n}\n\n/** Model / reasoning effort / agent preset defaults for one session type. */\nfunction SessionDefaultsGroup({ kind, settings, models, presets, efforts, tr, onCommit, loadEfforts }: SessionDefaultsGroupProps): JSX.Element {\n const fields = GROUP_FIELDS[kind]\n const model = settings[fields.model]\n const provider = settings[fields.provider]\n const effort = settings[fields.effort]\n const preset = settings[fields.preset]\n const effortKey = model !== '' && provider !== '' ? `${provider}/${model}` : ''\n const effortOptions = effortKey !== '' ? (efforts[effortKey]?.efforts ?? []) : []\n\n const handleModel = (id: string): void => {\n const found = models.find((m) => m.id === id)\n const nextProvider = found?.provider ?? ''\n void onCommit({ [fields.model]: id, [fields.provider]: nextProvider } as Partial<KanbanSettingsShape>)\n if (id !== '' && nextProvider !== '') loadEfforts(nextProvider, id)\n }\n\n return (\n <div className=\"kb-settings-group\">\n <div className=\"kb-settings-group-title\">{tr(kind === 'refinement' ? 'settingsRefineGroup' : 'settingsPhaseGroup')}</div>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('model')}</span>\n <select className=\"kb-input\" value={model} onChange={(e) => handleModel(e.target.value)}>\n <option value=\"\">{tr('defaultOption')}</option>\n {models.map((m) => (\n <option key={m.provider + '/' + m.id} value={m.id}>{m.name ?? m.id}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('reasoningEffort')}</span>\n <select\n className=\"kb-input\"\n value={effort}\n disabled={model === ''}\n onChange={(e) => void onCommit({ [fields.effort]: e.target.value } as Partial<KanbanSettingsShape>)}\n >\n <option value=\"\">{tr('defaultOption')}</option>\n {effortOptions.map((o) => (\n <option key={o.id} value={o.id}>{o.name}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('agentPreset')}</span>\n <select\n className=\"kb-input\"\n value={preset}\n onChange={(e) => void onCommit({ [fields.preset]: e.target.value } as Partial<KanbanSettingsShape>)}\n >\n <option value=\"\">{tr('defaultOption')}</option>\n {presets.map((p) => (\n <option key={p.id} value={p.id}>{p.name ?? p.id}</option>\n ))}\n </select>\n </label>\n </div>\n )\n}\n\n/** Plugin settings page (设置 -> 侧栏「任务看板」): workers + default model + per-session-type defaults. */\nexport function KanbanSettingsSection({ t }: SettingsSectionProps): JSX.Element {\n const tr = t ?? ((key: string) => key)\n const [settings, setSettings] = useState<KanbanSettingsShape>(EMPTY_SETTINGS)\n const [models, setModels] = useState<ModelOption[]>([])\n const [presets, setPresets] = useState<PresetOption[]>([])\n const [efforts, setEfforts] = useState<Record<string, ReasoningOptions>>({})\n const [saved, setSaved] = useState(false)\n\n const commit = useCallback(async (patch: Partial<KanbanSettingsShape>): Promise<void> => {\n try {\n const next = await api.settingsSet(patch)\n setSettings(next)\n setSaved(true)\n window.setTimeout(() => setSaved(false), 1500)\n } catch {\n // keep the previous value\n }\n }, [])\n\n // Refs so async callbacks (effort fetch) read the freshest settings/commit.\n const settingsRef = useRef(settings)\n settingsRef.current = settings\n const commitRef = useRef(commit)\n commitRef.current = commit\n\n useEffect(() => {\n let alive = true\n api.settingsGet()\n .then((s) => { if (alive) setSettings(s) })\n .catch(() => undefined)\n api.models()\n .then((list) => { if (alive) setModels(list) })\n .catch(() => undefined)\n api.presets()\n .then((list) => { if (alive) setPresets(list) })\n .catch(() => undefined)\n return () => { alive = false }\n }, [])\n\n /** Reasoning routes already requested (dedupe across mount + model changes). */\n const effortFetched = useRef<Set<string>>(new Set())\n\n /**\n * Fetch the reasoning efforts of one model route (once per route). A failed\n * fetch is marked `failed` so the stored effort is preserved (see the reset\n * effect below) instead of being wiped by a transient error.\n */\n const loadEfforts = useCallback((provider: string, model: string): void => {\n const key = `${provider}/${model}`\n if (effortFetched.current.has(key)) return\n effortFetched.current.add(key)\n api.reasoningOptions(provider, model)\n .then((opts) => setEfforts((prev) => ({ ...prev, [key]: opts })))\n .catch(() => setEfforts((prev) => ({ ...prev, [key]: { efforts: [], failed: true } })))\n }, [])\n\n // Fetch efforts for the models already configured in settings, so the\n // effort selects show their levels (and validate the stored effort) as soon\n // as settings load — the fetch previously ran only on model change.\n useEffect(() => {\n for (const kind of ['refinement', 'phase'] as const) {\n const fields = GROUP_FIELDS[kind]\n const model = settings[fields.model]\n const provider = settings[fields.provider]\n if (model !== '' && provider !== '') loadEfforts(provider, model)\n }\n }, [settings.refinementModel, settings.refinementProvider, settings.phaseModel, settings.phaseProvider, loadEfforts])\n\n // When the efforts of the selected model arrive, drop a stored effort the\n // model no longer offers (e.g. the user switched the model). A failed fetch\n // (`failed: true`) keeps the stored effort: the model may just be\n // temporarily unresolvable, and wiping the user's choice would be worse.\n useEffect(() => {\n const s = settingsRef.current\n for (const kind of ['refinement', 'phase'] as const) {\n const fields = GROUP_FIELDS[kind]\n const model = s[fields.model]\n const provider = s[fields.provider]\n const effort = s[fields.effort]\n if (effort === '' || model === '' || provider === '') continue\n const opts = efforts[`${provider}/${model}`]\n if (opts === undefined || opts.failed === true) continue\n if (!opts.efforts.some((o) => o.id === effort)) {\n void commitRef.current({ [fields.effort]: '' } as Partial<KanbanSettingsShape>)\n }\n }\n }, [efforts])\n\n return (\n <div className=\"kb-page\">\n <header className=\"kb-page-head\">\n <h3 className=\"kb-page-title\">{tr('settingsTitle')}</h3>\n <p className=\"kb-page-sub\">{tr('sectionSub')}</p>\n </header>\n <div className=\"kb-settings\">\n <label className=\"kb-field kb-field-row\">\n <span>{tr('maxParallelWorkers')}</span>\n <input\n className=\"kb-input kb-input-number\"\n type=\"number\"\n min={1}\n step={1}\n value={settings.maxParallelWorkers}\n onChange={(e) => {\n const value = Math.max(1, Math.floor(Number(e.target.value) || 1))\n setSettings((s) => ({ ...s, maxParallelWorkers: value }))\n void commit({ maxParallelWorkers: value })\n }}\n />\n </label>\n <SessionDefaultsGroup\n kind=\"refinement\"\n settings={settings}\n models={models}\n presets={presets}\n efforts={efforts}\n tr={tr}\n onCommit={commit}\n loadEfforts={loadEfforts}\n />\n <SessionDefaultsGroup\n kind=\"phase\"\n settings={settings}\n models={models}\n presets={presets}\n efforts={efforts}\n tr={tr}\n onCommit={commit}\n loadEfforts={loadEfforts}\n />\n {saved && <div className=\"kb-settings-saved\">{tr('saved')}</div>}\n </div>\n </div>\n )\n}","import type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { BoardRoot } from './board'\nimport { KanbanPanelIcon, KanbanSettingsSection } from './sections'\nimport { LOCALE_NS, zh, en } from './locales'\nimport { KANBAN_PANEL_ID, setClient, bindSessionNavigation } from './kanban-state'\n\n/** The settings sidebar entry this plugin's page owns (must stay stable). */\nconst SETTINGS_SECTION_ID = 'task-kanban'\n\n/** Services required before mounting (provided by the client runtime). */\nexport const inject = ['slots', 'sessions', 'workspaces', 'locale']\n\n/** Client plugin body. */\nexport function apply(ctx: ClientContext): void {\n setClient(ctx)\n // Selecting a session while the board is open must return to the Conversation.\n bindSessionNavigation(ctx)\n\n // Live translate bound to the active locale (labels re-read it per call).\n const t = ctx.locale.bind(LOCALE_NS)\n ctx.effect(() => {\n const off = ctx.locale.register(LOCALE_NS, { zh, en })\n return () => off()\n }, 'task-kanban: dictionaries')\n\n // The board is a GLOBAL MAIN PANEL: the shell renders one `main` entry per\n // selected panel id, so keying it (instead of replacing `main.conversation`)\n // keeps the Conversation mounted and selectable beside the board, and the\n // sidebar's own panel row owns the button that selects it (the\n // `sidebar.panellist` entry below). Nothing of this plugin sits in the\n // sidebar foot any more, so the Settings trigger can never be squeezed.\n ctx.slots.inject('main', () =>\n ctx.slots.register({\n name: 'main',\n key: KANBAN_PANEL_ID,\n locale: LOCALE_NS,\n } as never, BoardRoot as never),\n )\n\n // Sidebar panel row: the shell renders the row (label, tooltip, active state)\n // and calls `layout.selectPanel(id)` on click; the entry supplies the glyph.\n ctx.slots.inject('sidebar.panellist', () =>\n ctx.slots.register({\n name: 'sidebar.panellist',\n id: KANBAN_PANEL_ID,\n order: 20,\n label: () => t('kanban'),\n locale: LOCALE_NS,\n }, KanbanPanelIcon as never),\n )\n\n // The plugin's own settings page (设置 -> 侧栏「任务看板」) rides the\n // task-kanban settings namespace and registers into the settings.section\n // list slot, which gives it one entry in the settings sidebar and renders\n // its content into the panel's content column.\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register({\n name: 'settings.section',\n id: SETTINGS_SECTION_ID,\n order: 200,\n label: () => t('settingsTitle'),\n locale: LOCALE_NS,\n }, KanbanSettingsSection as never),\n )\n}\n"],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -11,47 +11,58 @@ import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
|
11
11
|
//#region src/server/settings.ts
|
|
12
12
|
const KANBAN_SETTINGS_NS = "task-kanban";
|
|
13
13
|
const KanbanSettingsSchema = z.object({
|
|
14
|
-
maxParallelWorkers: z.natural().min(1).default(1),
|
|
15
|
-
refinementModel: z.string().default(""),
|
|
16
|
-
refinementProvider: z.string().default(""),
|
|
17
|
-
refinementReasoningEffort: z.string().default(""),
|
|
18
|
-
refinementPreset: z.string().default(""),
|
|
19
|
-
phaseModel: z.string().default(""),
|
|
20
|
-
phaseProvider: z.string().default(""),
|
|
21
|
-
phaseReasoningEffort: z.string().default(""),
|
|
22
|
-
phasePreset: z.string().default("")
|
|
14
|
+
maxParallelWorkers: z.natural().min(1).default(1).volatile(),
|
|
15
|
+
refinementModel: z.string().default("").volatile(),
|
|
16
|
+
refinementProvider: z.string().default("").volatile(),
|
|
17
|
+
refinementReasoningEffort: z.string().default("").volatile(),
|
|
18
|
+
refinementPreset: z.string().default("").volatile(),
|
|
19
|
+
phaseModel: z.string().default("").volatile(),
|
|
20
|
+
phaseProvider: z.string().default("").volatile(),
|
|
21
|
+
phaseReasoningEffort: z.string().default("").volatile(),
|
|
22
|
+
phasePreset: z.string().default("").volatile()
|
|
23
23
|
});
|
|
24
|
+
/**
|
|
25
|
+
* Dereference one config field. `Config` fields marked `.volatile()` are handed
|
|
26
|
+
* to the plugin as references (`{ get() }`) instead of plain values, so reading
|
|
27
|
+
* them raw yields the reference object — which serializes to `{}` and makes
|
|
28
|
+
* every setting look empty. Non-volatile (plain) configs keep working as-is.
|
|
29
|
+
*/
|
|
30
|
+
function fieldValue(value, fallback) {
|
|
31
|
+
if (value !== null && typeof value === "object" && typeof value.get === "function") return value.get() ?? fallback;
|
|
32
|
+
return value ?? fallback;
|
|
33
|
+
}
|
|
24
34
|
const EMPTY_DEFAULTS = {
|
|
25
35
|
model: "",
|
|
26
36
|
provider: "",
|
|
27
37
|
reasoningEffort: "",
|
|
28
38
|
preset: ""
|
|
29
39
|
};
|
|
30
|
-
function registerSettings(ctx) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
function registerSettings(ctx, config) {
|
|
41
|
+
const fields = config ?? {};
|
|
42
|
+
const snapshot = () => ({
|
|
43
|
+
maxParallelWorkers: fieldValue(fields.maxParallelWorkers, 1),
|
|
44
|
+
refinementModel: fieldValue(fields.refinementModel, ""),
|
|
45
|
+
refinementProvider: fieldValue(fields.refinementProvider, ""),
|
|
46
|
+
refinementReasoningEffort: fieldValue(fields.refinementReasoningEffort, ""),
|
|
47
|
+
refinementPreset: fieldValue(fields.refinementPreset, ""),
|
|
48
|
+
phaseModel: fieldValue(fields.phaseModel, ""),
|
|
49
|
+
phaseProvider: fieldValue(fields.phaseProvider, ""),
|
|
50
|
+
phaseReasoningEffort: fieldValue(fields.phaseReasoningEffort, ""),
|
|
51
|
+
phasePreset: fieldValue(fields.phasePreset, "")
|
|
52
|
+
});
|
|
53
|
+
let pending = {};
|
|
54
|
+
const current = () => ({
|
|
55
|
+
...snapshot(),
|
|
56
|
+
...pending
|
|
57
|
+
});
|
|
42
58
|
let service;
|
|
43
59
|
ctx.inject(["settings"], (sctx) => {
|
|
44
60
|
service = sctx.settings;
|
|
45
|
-
const scope = service.register(KANBAN_SETTINGS_NS, KanbanSettingsSchema);
|
|
46
|
-
current = scope.get();
|
|
47
|
-
scope.watch((next) => {
|
|
48
|
-
current = next;
|
|
49
|
-
});
|
|
50
61
|
});
|
|
51
62
|
return {
|
|
52
|
-
get: () => current,
|
|
63
|
+
get: () => current(),
|
|
53
64
|
sessionDefaults: (kind) => {
|
|
54
|
-
const s = current;
|
|
65
|
+
const s = current();
|
|
55
66
|
switch (kind) {
|
|
56
67
|
case "refine": return {
|
|
57
68
|
model: s.refinementModel,
|
|
@@ -85,6 +96,10 @@ function registerSettings(ctx) {
|
|
|
85
96
|
update: async (patch) => {
|
|
86
97
|
if (service === void 0) throw new Error("@fonlan/dsh-task-kanban: settings service is not available in this profile");
|
|
87
98
|
await service.update(KANBAN_SETTINGS_NS, patch);
|
|
99
|
+
pending = {
|
|
100
|
+
...pending,
|
|
101
|
+
...patch
|
|
102
|
+
};
|
|
88
103
|
}
|
|
89
104
|
};
|
|
90
105
|
}
|
|
@@ -1901,9 +1916,9 @@ const inject = [
|
|
|
1901
1916
|
"agents",
|
|
1902
1917
|
"skills"
|
|
1903
1918
|
];
|
|
1904
|
-
const Config =
|
|
1905
|
-
function apply(ctx,
|
|
1906
|
-
const settings = registerSettings(ctx);
|
|
1919
|
+
const Config = KanbanSettingsSchema;
|
|
1920
|
+
function apply(ctx, config) {
|
|
1921
|
+
const settings = registerSettings(ctx, config);
|
|
1907
1922
|
const runner = new KanbanRunner(ctx, new TaskStore(), settings);
|
|
1908
1923
|
ctx.effect(() => {
|
|
1909
1924
|
runner.recoverInterrupted();
|
package/lib/types/index.d.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* serves the fenced JSON API the board UI calls.
|
|
8
8
|
*/
|
|
9
9
|
import type { Context } from '@deepseek-ai/cordis';
|
|
10
|
-
import
|
|
10
|
+
import type { KanbanSettingsShape } from './shared/card.js';
|
|
11
11
|
export declare const name = "@fonlan/dsh-task-kanban";
|
|
12
12
|
export declare const inject: string[];
|
|
13
|
-
export declare const Config:
|
|
14
|
-
export declare function apply(ctx: Context,
|
|
13
|
+
export declare const Config: import("@deepseek-ai/schemastery").default<KanbanSettingsShape>;
|
|
14
|
+
export declare function apply(ctx: Context, config: KanbanSettingsShape): void;
|