@fonlan/dsh-task-kanban 0.1.1 → 0.2.0
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/lib/client.js +90 -54
- package/lib/client.js.map +1 -1
- package/lib/index.js +78 -5
- package/lib/types/server/runner.d.ts +21 -0
- package/package.json +1 -1
- package/src/client/board.css +46 -10
- package/src/client/board.tsx +65 -22
- package/src/client/locales.ts +8 -2
- package/src/server/runner.ts +100 -5
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useCallback","useMemo","useRef","useRef","IconChecklistOutline14","useState"],"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 `skill.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 `skill.list` unary RPC over the same-origin HTTP\n * bridge (the exact wire shape DSH's chat input uses for its /-autocomplete).\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/skill.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: 'skill.list',\n payload: { 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\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}","import { useSyncExternalStore } from 'react'\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\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 state.boardDisposer = ctx.slots.register({ name: 'conversation', priority: -1, locale: 'task-kanban' } as never, root as never)\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 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 maxParallelWorkers: '全局并行 worker 数',\n defaultModel: '默认模型',\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 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 Settings',\n maxParallelWorkers: 'Global parallel workers',\n defaultModel: 'Default model',\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 } 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}\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 const currentSessionId = sessionState?.current\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 </div>\n <div className=\"kb-board-actions\">\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 api.settingsGet()\n .then((s) => {\n if (alive && s.defaultModel !== '') {\n setModel(s.defaultModel)\n }\n })\n .catch(() => undefined)\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 <li key={phase.id} className={'kb-plan-phase' + (i === card.currentPhase && card.status === 'running' ? ' kb-plan-phase-current' : '')}>\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-goal\">{phase.goal}</div>\n <PhaseSessions phaseIndex={i} card={card} t={t} onOpenSession={onOpenSession} />\n </li>\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\nfunction PhaseSessions({ phaseIndex, card, t, onOpenSession }: {\n phaseIndex: number\n card: KanbanCard\n t: (key: string) => string\n onOpenSession: (sessionId: string) => void\n}): JSX.Element | null {\n const attempts = card.sessions.phases.filter((a) => a.phaseIndex === phaseIndex)\n if (attempts.length === 0) return null\n return (\n <div className=\"kb-session-links\">\n {attempts.map((a) => (\n <span key={a.sessionId} className=\"kb-session-attempt\">\n <button type=\"button\" className=\"kb-btn kb-btn-small\" onClick={() => onOpenSession(a.sessionId)}>\n {t('openSession')} · {a.sessionId.slice(0, 13)}\n </button>\n {a.summary !== undefined && <span className=\"kb-session-summary\">{a.summary}</span>}\n </span>\n ))}\n </div>\n )\n}","import { useEffect, useRef, useState } from 'react'\nimport { IconChecklistOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { api } from './api'\nimport { toggleBoard, useBoardOpen } from './kanban-state'\nimport type { KanbanSettingsShape } 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/** Plugin settings section: global parallel workers + default model. */\nexport function KanbanSettingsSection({ t }: SettingsSectionProps): JSX.Element {\n const tr = t ?? ((key: string) => key)\n const [settings, setSettings] = useState<KanbanSettingsShape>({ maxParallelWorkers: 1, defaultModel: '' })\n const [models, setModels] = useState<Array<{ provider: string; id: string; name?: string }>>([])\n const [saved, setSaved] = useState(false)\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 return () => { alive = false }\n }, [])\n\n const commit = 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 return (\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 <label className=\"kb-field kb-field-row\">\n <span>{tr('defaultModel')}</span>\n <select\n className=\"kb-input\"\n value={settings.defaultModel}\n onChange={(e) => { void commit({ defaultModel: e.target.value }) }}\n >\n <option value=\"\">—</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 {saved && <div className=\"kb-settings-saved\">{tr('saved')}</div>}\n </div>\n )\n}","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\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-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/** 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 ctx.slots.inject('settings.section', () =>\n ctx.slots.register({\n name: 'settings.section',\n id: 'task-kanban',\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":["useSyncExternalStore","useState","useCallback","useMemo","useRef","useRef","IconChecklistOutline14","useState"],"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 `skill.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 `skill.list` unary RPC over the same-origin HTTP\n * bridge (the exact wire shape DSH's chat input uses for its /-autocomplete).\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/skill.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: 'skill.list',\n payload: { 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\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}","import { useSyncExternalStore } from 'react'\nimport type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\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 state.boardDisposer = ctx.slots.register({ name: 'conversation', priority: -1, locale: 'task-kanban' } as never, root as never)\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 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 maxParallelWorkers: '全局并行 worker 数',\n defaultModel: '默认模型',\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 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 maxParallelWorkers: 'Global parallel workers',\n defaultModel: 'Default model',\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}\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 const currentSessionId = sessionState?.current\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 api.settingsGet()\n .then((s) => {\n if (alive && s.defaultModel !== '') {\n setModel(s.defaultModel)\n }\n })\n .catch(() => undefined)\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 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} 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/** Open-session buttons for one phase's attempts (retries append more). */\nfunction PhaseSessions({ attempts, t, onOpenSession }: {\n attempts: PhaseAttempt[]\n t: (key: string) => 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\" onClick={() => onOpenSession(a.sessionId)}>\n {t('openSession')} · {a.sessionId.slice(0, 13)}\n </button>\n ))}\n </div>\n )\n}","import { useEffect, useRef, useState } from 'react'\nimport { IconChecklistOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { api } from './api'\nimport { toggleBoard, useBoardOpen } from './kanban-state'\nimport type { KanbanSettingsShape } 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/** Plugin settings section: global parallel workers + default model. */\nexport function KanbanSettingsSection({ t }: SettingsSectionProps): JSX.Element {\n const tr = t ?? ((key: string) => key)\n const [settings, setSettings] = useState<KanbanSettingsShape>({ maxParallelWorkers: 1, defaultModel: '' })\n const [models, setModels] = useState<Array<{ provider: string; id: string; name?: string }>>([])\n const [saved, setSaved] = useState(false)\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 return () => { alive = false }\n }, [])\n\n const commit = 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 return (\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 <label className=\"kb-field kb-field-row\">\n <span>{tr('defaultModel')}</span>\n <select\n className=\"kb-input\"\n value={settings.defaultModel}\n onChange={(e) => { void commit({ defaultModel: e.target.value }) }}\n >\n <option value=\"\">—</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 {saved && <div className=\"kb-settings-saved\">{tr('saved')}</div>}\n </div>\n )\n}","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\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-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/** 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 ctx.slots.inject('settings.section', () =>\n ctx.slots.register({\n name: 'settings.section',\n id: 'task-kanban',\n order: 200,\n label: () => t('settingsTitle'),\n locale: LOCALE_NS,\n }, KanbanSettingsSection as never),\n )\n}"],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -611,6 +611,11 @@ var KanbanRunner = class {
|
|
|
611
611
|
merging = /* @__PURE__ */ new Set();
|
|
612
612
|
/** Retained agent handles (kept so ended sessions stay in the store/UI). */
|
|
613
613
|
handles = /* @__PURE__ */ new Map();
|
|
614
|
+
/** Whether startup recovery + session indexing ran (deferred until workspaces exist). */
|
|
615
|
+
recovered = false;
|
|
616
|
+
/** Agents that already got their scoped kanban tools (event idempotency). */
|
|
617
|
+
toolScopedAgents = /* @__PURE__ */ new WeakSet();
|
|
618
|
+
agentStartOff;
|
|
614
619
|
constructor(ctx, store, settings) {
|
|
615
620
|
this.ctx = ctx;
|
|
616
621
|
this.store = store;
|
|
@@ -623,9 +628,17 @@ var KanbanRunner = class {
|
|
|
623
628
|
this.pumpTimer = setInterval(() => {
|
|
624
629
|
this.pump();
|
|
625
630
|
}, 2500);
|
|
631
|
+
this.agentStartOff = this.ctx.on("agent/session-start", (payload) => {
|
|
632
|
+
this.onAgentSessionStart(payload.agent);
|
|
633
|
+
});
|
|
626
634
|
}
|
|
627
635
|
stop() {
|
|
628
636
|
if (this.pumpTimer !== void 0) clearInterval(this.pumpTimer);
|
|
637
|
+
this.pumpTimer = void 0;
|
|
638
|
+
if (this.agentStartOff !== void 0) {
|
|
639
|
+
this.agentStartOff();
|
|
640
|
+
this.agentStartOff = void 0;
|
|
641
|
+
}
|
|
629
642
|
}
|
|
630
643
|
newSessionId() {
|
|
631
644
|
return `session-${randomUUID()}`;
|
|
@@ -703,6 +716,52 @@ var KanbanRunner = class {
|
|
|
703
716
|
}
|
|
704
717
|
}
|
|
705
718
|
}
|
|
719
|
+
/**
|
|
720
|
+
* Rebuild sessionId → cardId from the task store. Runs once the workspace
|
|
721
|
+
* registry is available (see pump), so kanban sessions resumed after a
|
|
722
|
+
* restart still resolve their card.
|
|
723
|
+
*/
|
|
724
|
+
async indexSessions() {
|
|
725
|
+
for (const ws of await this.workspaceList()) {
|
|
726
|
+
const cards = await this.store.list(ws.path);
|
|
727
|
+
for (const card of cards) this.mapCardSessions(card.id, card);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
mapCardSessions(cardId, card) {
|
|
731
|
+
for (const sid of card.sessions.refinement) this.sessionCards.set(sid, cardId);
|
|
732
|
+
for (const attempt of card.sessions.phases) this.sessionCards.set(attempt.sessionId, cardId);
|
|
733
|
+
for (const sid of card.sessions.merge) this.sessionCards.set(sid, cardId);
|
|
734
|
+
}
|
|
735
|
+
/** Fallback lookup when a session starts before indexSessions ran. */
|
|
736
|
+
async lookupCardOfSession(sessionId) {
|
|
737
|
+
for (const ws of await this.workspaceList()) {
|
|
738
|
+
const cards = await this.store.list(ws.path);
|
|
739
|
+
for (const card of cards) if (card.sessions.refinement.includes(sessionId) || card.sessions.phases.some((a) => a.sessionId === sessionId) || card.sessions.merge.includes(sessionId)) {
|
|
740
|
+
this.mapCardSessions(card.id, card);
|
|
741
|
+
return card.id;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* The single place kanban tools get registered. `agent/session-start` fires
|
|
747
|
+
* for BOTH `agents.create` (startup) and `agents.resume` (host re-open after
|
|
748
|
+
* a restart), so a resumed refinement/phase/merge session keeps its scoped
|
|
749
|
+
* tools. Idempotent per agent object; non-kanban sessions are skipped.
|
|
750
|
+
*/
|
|
751
|
+
async onAgentSessionStart(agent) {
|
|
752
|
+
if (agent === void 0 || agent.id === void 0 || agent.ctx === void 0) return;
|
|
753
|
+
if (this.toolScopedAgents.has(agent)) return;
|
|
754
|
+
let cardId = this.sessionCards.get(agent.id);
|
|
755
|
+
if (cardId === void 0) cardId = await this.lookupCardOfSession(agent.id);
|
|
756
|
+
if (cardId === void 0) return;
|
|
757
|
+
this.sessionCards.set(agent.id, cardId);
|
|
758
|
+
try {
|
|
759
|
+
registerKanbanTools(agent.ctx, this.toolResolver());
|
|
760
|
+
this.toolScopedAgents.add(agent);
|
|
761
|
+
} catch (error) {
|
|
762
|
+
console.error("[task-kanban] register kanban tools for " + agent.id + " failed:", String(error));
|
|
763
|
+
}
|
|
764
|
+
}
|
|
706
765
|
async listCards(workspacePath) {
|
|
707
766
|
return this.store.list(workspacePath);
|
|
708
767
|
}
|
|
@@ -859,6 +918,21 @@ var KanbanRunner = class {
|
|
|
859
918
|
return this.settings.get().maxParallelWorkers;
|
|
860
919
|
}
|
|
861
920
|
async pump() {
|
|
921
|
+
if (!this.recovered) {
|
|
922
|
+
if ((await this.workspaceList()).length > 0) {
|
|
923
|
+
this.recovered = true;
|
|
924
|
+
try {
|
|
925
|
+
await this.recoverInterrupted();
|
|
926
|
+
} catch (error) {
|
|
927
|
+
console.error("[task-kanban] recoverInterrupted failed:", String(error));
|
|
928
|
+
}
|
|
929
|
+
try {
|
|
930
|
+
await this.indexSessions();
|
|
931
|
+
} catch (error) {
|
|
932
|
+
console.error("[task-kanban] indexSessions failed:", String(error));
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
862
936
|
if (this.slots >= this.maxParallel()) return;
|
|
863
937
|
const workspaces = await this.workspaceList();
|
|
864
938
|
for (const ws of workspaces) {
|
|
@@ -911,7 +985,7 @@ var KanbanRunner = class {
|
|
|
911
985
|
c.sessions.refinement.push(sessionId);
|
|
912
986
|
}, wsPath);
|
|
913
987
|
try {
|
|
914
|
-
const handle = await this.createAgent(sessionId, wsPath, route
|
|
988
|
+
const handle = await this.createAgent(sessionId, wsPath, route);
|
|
915
989
|
this.keepHandle(cardId, handle);
|
|
916
990
|
await this.attachRefinementSession(wsPath, sessionId);
|
|
917
991
|
const skill = card.skill !== void 0 ? await loadCardSkill(this.ctx, card.skill, wsPath, handle.agent) : void 0;
|
|
@@ -1015,7 +1089,7 @@ var KanbanRunner = class {
|
|
|
1015
1089
|
dispose
|
|
1016
1090
|
};
|
|
1017
1091
|
}
|
|
1018
|
-
async createAgent(sessionId, cwd, route
|
|
1092
|
+
async createAgent(sessionId, cwd, route) {
|
|
1019
1093
|
const agentOptions = route.provider !== void 0 && route.model !== void 0 && route.model !== "" ? {
|
|
1020
1094
|
provider: route.provider,
|
|
1021
1095
|
model: route.model
|
|
@@ -1028,7 +1102,6 @@ var KanbanRunner = class {
|
|
|
1028
1102
|
const agentPresets = agentCtx.get("agentPresets");
|
|
1029
1103
|
if (agentPresets !== void 0) await agentPresets.mount(agentCtx, "standard");
|
|
1030
1104
|
else throw new Error("@fonlan/dsh-task-kanban: agent-presets service is not mounted");
|
|
1031
|
-
registerKanbanTools(agentCtx, resolver);
|
|
1032
1105
|
}
|
|
1033
1106
|
});
|
|
1034
1107
|
}
|
|
@@ -1181,7 +1254,7 @@ var KanbanRunner = class {
|
|
|
1181
1254
|
}, wsPath);
|
|
1182
1255
|
const route = await this.modelRoute(cardId, wsPath);
|
|
1183
1256
|
try {
|
|
1184
|
-
const handle = await this.createAgent(sessionId, workdir, route
|
|
1257
|
+
const handle = await this.createAgent(sessionId, workdir, route);
|
|
1185
1258
|
this.keepHandle(cardId, handle);
|
|
1186
1259
|
entry.cancel = () => handle.agent.cancel({ kind: "user" });
|
|
1187
1260
|
handle.agent.followup(this.asUserMessage(phasePrompt({
|
|
@@ -1475,7 +1548,7 @@ var KanbanRunner = class {
|
|
|
1475
1548
|
}, wsPath);
|
|
1476
1549
|
const route = await this.modelRoute(cardId, wsPath);
|
|
1477
1550
|
try {
|
|
1478
|
-
const handle = await this.createAgent(sessionId, workdir, route
|
|
1551
|
+
const handle = await this.createAgent(sessionId, workdir, route);
|
|
1479
1552
|
this.keepHandle(cardId, handle);
|
|
1480
1553
|
handle.agent.followup(this.asUserMessage(mergePrompt(workdir, conflicts)));
|
|
1481
1554
|
await handle.agent.whenIdle();
|
|
@@ -17,6 +17,11 @@ export declare class KanbanRunner implements KanbanToolResolver {
|
|
|
17
17
|
private merging;
|
|
18
18
|
/** Retained agent handles (kept so ended sessions stay in the store/UI). */
|
|
19
19
|
private handles;
|
|
20
|
+
/** Whether startup recovery + session indexing ran (deferred until workspaces exist). */
|
|
21
|
+
private recovered;
|
|
22
|
+
/** Agents that already got their scoped kanban tools (event idempotency). */
|
|
23
|
+
private toolScopedAgents;
|
|
24
|
+
private agentStartOff;
|
|
20
25
|
constructor(ctx: Context, store: TaskStore, settings: KanbanSettingsFace);
|
|
21
26
|
register(ctx: Context): void;
|
|
22
27
|
start(): void;
|
|
@@ -30,6 +35,22 @@ export declare class KanbanRunner implements KanbanToolResolver {
|
|
|
30
35
|
mergeResolved(sessionId: string): Promise<void>;
|
|
31
36
|
private toolResolver;
|
|
32
37
|
recoverInterrupted(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Rebuild sessionId → cardId from the task store. Runs once the workspace
|
|
40
|
+
* registry is available (see pump), so kanban sessions resumed after a
|
|
41
|
+
* restart still resolve their card.
|
|
42
|
+
*/
|
|
43
|
+
private indexSessions;
|
|
44
|
+
private mapCardSessions;
|
|
45
|
+
/** Fallback lookup when a session starts before indexSessions ran. */
|
|
46
|
+
private lookupCardOfSession;
|
|
47
|
+
/**
|
|
48
|
+
* The single place kanban tools get registered. `agent/session-start` fires
|
|
49
|
+
* for BOTH `agents.create` (startup) and `agents.resume` (host re-open after
|
|
50
|
+
* a restart), so a resumed refinement/phase/merge session keeps its scoped
|
|
51
|
+
* tools. Idempotent per agent object; non-kanban sessions are skipped.
|
|
52
|
+
*/
|
|
53
|
+
private onAgentSessionStart;
|
|
33
54
|
listCards(workspacePath: string): Promise<KanbanCard[]>;
|
|
34
55
|
createTask(input: {
|
|
35
56
|
workspacePath: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fonlan/dsh-task-kanban",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "DSH web plugin: a task kanban that refines requirements into phased plans, auto-executes them in git worktrees (one session per phase), and auto-merges into the main branch on completion.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|