@fonlan/dsh-task-kanban 0.2.7 → 0.2.9

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 CHANGED
@@ -174,59 +174,39 @@ window.__ModuleLoader__.load({
174
174
  function getClient() {
175
175
  return getState().client;
176
176
  }
177
- /** The shell's panel face, when this runtime provides it. */
178
- function layoutOf(ctx) {
179
- if (ctx === null) return null;
180
- try {
181
- const layout = ctx.layout;
182
- return typeof layout?.selectPanel === "function" ? layout : null;
183
- } catch {
184
- return null;
185
- }
186
- }
187
- /** Hand the center column back to the Conversation. */
188
- function leaveKanbanPanel(ctx = getClient()) {
189
- try {
190
- layoutOf(ctx)?.selectPanel(null);
191
- } catch (error) {
192
- console.error("[@fonlan/dsh-task-kanban] cannot leave the kanban panel:", error);
193
- }
194
- }
195
177
  /**
196
- * Route session navigation through the panel selection: opening any session
197
- * while the board is the active panel first returns the center column to the
198
- * Conversation, so the session view renders.
178
+ * Open one session — or a durable direct-parent subagent address — in the
179
+ * center column, leaving the kanban panel.
199
180
  *
200
- * Every sidebar path that selects a session funnels through `sessions.open`
201
- * (session rows, search results, fork results, New Session) or
202
- * `sessions.openSubagent` (catalog children) — including re-clicking the
203
- * already-current session, which never changes `list.current` and therefore
204
- * cannot be caught by a list-store subscription. Wrapping the two entry points
205
- * covers all of them in one place.
181
+ * Navigation is a view-owner concern, not a session-controller one: `ctx.sessions`
182
+ * (`ISessions`) exposes retention (`retain`/`using`/`retainInfo`), creation,
183
+ * fork, search and catalog reads, and has no `open`/`openSubagent` at all
184
+ * ("navigation belongs to view owners"). The view owner the shell itself uses is
185
+ * `ctx.uiWorkspace.openSession(target)` (dsh-client-ui-workspace): it retains the
186
+ * session AND reveals the Conversation panel as ONE navigation action. Routing
187
+ * every open through it therefore replaces the old wrapper around
188
+ * `sessions.open`/`openSubagent`, which existed only to hand the center column
189
+ * back when a sidebar click selected a session while the board was showing.
206
190
  *
207
- * The wrapper is idempotent: a `kbBound` marker on the wrapper prevents a
208
- * second bind (plugin re-apply / HMR) from stacking another layer.
191
+ * @param target - session id (or subagent address) to show.
192
+ * @returns whether the runtime provided the navigation face; `false` means the
193
+ * session could not be shown (a client without ui-workspace).
209
194
  */
210
- function bindSessionNavigation(ctx) {
211
- const sessions = ctx.sessions;
212
- if (sessions === void 0) return;
213
- const open = sessions.open;
214
- if (typeof open === "function" && open.kbBound !== true) {
215
- const bound = ((id) => {
216
- leaveKanbanPanel(ctx);
217
- return open.call(sessions, id);
218
- });
219
- bound.kbBound = true;
220
- sessions.open = bound;
195
+ function openSessionView(target, ctx = getClient()) {
196
+ if (ctx === null) return false;
197
+ let uiWorkspace;
198
+ try {
199
+ uiWorkspace = ctx.uiWorkspace;
200
+ } catch {
201
+ return false;
221
202
  }
222
- const openSubagent = sessions.openSubagent;
223
- if (typeof openSubagent === "function" && openSubagent.kbBound !== true) {
224
- const bound = ((address) => {
225
- leaveKanbanPanel(ctx);
226
- return openSubagent.call(sessions, address);
227
- });
228
- bound.kbBound = true;
229
- sessions.openSubagent = bound;
203
+ if (typeof uiWorkspace?.openSession !== "function") return false;
204
+ try {
205
+ uiWorkspace.openSession(target);
206
+ return true;
207
+ } catch (error) {
208
+ console.error("[@fonlan/dsh-task-kanban] cannot open the session view:", error);
209
+ return false;
230
210
  }
231
211
  }
232
212
  //#endregion
@@ -529,14 +509,7 @@ window.__ModuleLoader__.load({
529
509
  t
530
510
  ]);
531
511
  const openSession = (0, react.useCallback)((sessionId) => {
532
- const ctx = getClient();
533
- leaveKanbanPanel(ctx);
534
- if (ctx === null) return;
535
- try {
536
- ctx.sessions.open(sessionId);
537
- } catch {
538
- showToast(t("sessionNotListed"));
539
- }
512
+ if (!openSessionView(sessionId)) showToast(t("sessionNotListed"));
540
513
  }, [showToast, t]);
541
514
  if (items.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
542
515
  className: "kb-board kb-empty",
@@ -1484,7 +1457,6 @@ window.__ModuleLoader__.load({
1484
1457
  /** Client plugin body. */
1485
1458
  function apply(ctx) {
1486
1459
  setClient(ctx);
1487
- bindSessionNavigation(ctx);
1488
1460
  const t = ctx.locale.bind(LOCALE_NS);
1489
1461
  ctx.effect(() => {
1490
1462
  const off = ctx.locale.register(LOCALE_NS, {
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useState","useCallback","useMemo","useRef","primitives","useState","useCallback","useRef"],"sources":["../../../src/shared/lanes.ts","../../../src/client/api.ts","../../../src/client/kanban-state.ts","../../../src/client/locales.ts","../../../src/client/board.tsx","../../../src/client/icons.tsx","../../../src/client/sections.tsx","../../../src/client/index.tsx"],"sourcesContent":["/**\n * Lane mapping and drag rules (shared by the board UI and tests).\n */\nimport type { KanbanCard, Lane } from './card.js'\n\n/** Which lane a card renders in, based on status + error stage. */\nexport function laneOf(card: KanbanCard): Lane {\n if (card.status === 'error') {\n if (card.error?.stage !== undefined) return card.error.stage\n const kind = card.error?.kind\n if (kind === 'phase_failed' || kind === 'no_base_branch' || kind === 'worktree_failed') return 'running'\n if (kind === 'merge_failed') return 'completed'\n return 'demand'\n }\n switch (card.status) {\n case 'draft':\n case 'refining':\n case 'planned':\n return 'demand'\n case 'queued':\n return 'queue'\n case 'running':\n return 'running'\n case 'completed':\n case 'merging':\n return 'completed'\n case 'merged':\n return 'merged'\n }\n}\n\n/** Lanes a drop onto `to` may come from. */\nexport const DROP_RULES: Record<Lane, Lane[]> = {\n demand: ['queue'],\n queue: ['demand', 'running'],\n running: [],\n completed: [],\n merged: [],\n}\n\nexport function canDrop(from: Lane, to: Lane): boolean {\n return DROP_RULES[to].includes(from)\n}\n","import type { KanbanCard, KanbanSettingsShape, Lane, ModelOption } from '../shared/card'\n\nexport class KanbanApiError extends Error {\n constructor(readonly code: string, message: string) {\n super(message)\n }\n}\n\nasync function call<T>(method: string, payload: Record<string, unknown> = {}): Promise<T> {\n let response: Response\n try {\n response = await fetch(`/plugins/@fonlan/dsh-task-kanban/api/${method}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n } catch (error) {\n throw new KanbanApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed: { ok?: boolean; value?: unknown; error?: { code?: string; message?: string } } | null\n = await response.json().catch(() => null)\n if (!response.ok || parsed === null || parsed.ok !== true || parsed.value === undefined) {\n throw new KanbanApiError(\n parsed?.error?.code ?? 'http',\n parsed?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.value as T\n}\n\n/** One row of the host `skills/list` catalog (same shape DSH's chat autocomplete uses). */\nexport interface SkillOption {\n name: string\n description: string\n whenToUse?: string\n modelInvocable: boolean\n}\n\n/**\n * Call the host gateway's `skills/list` unary RPC over the same-origin HTTP\n * bridge (the exact wire shape DSH's chat input uses for its /-autocomplete).\n *\n * DSH ≥0.1.5 addresses Remote endpoints as the canonical `<namespace>/<method>`\n * pair — `/api/skills/list` with the method `skills/list` — and carries named\n * wire arguments inside a single `args` field, so the request body is\n * `{ args: { request: { sessionId } } }` (the descriptor's parameter wire name\n * is `request`). The older dotted `skill.list` endpoint no longer exists and\n * answers HTTP 404.\n *\n * The requested `sessionId` scopes the catalog to that session's agent\n * preset, which is where the filesystem skill roots are registered.\n */\nexport async function gatewaySkillList(sessionId: string): Promise<SkillOption[]> {\n let response: Response\n try {\n response = await fetch('/api/skills/list', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n type: 'client-request',\n rpcId: `task-kanban-${Math.random().toString(36).slice(2)}`,\n method: 'skills/list',\n payload: { args: { request: { sessionId } } },\n }),\n })\n } catch (error) {\n throw new KanbanApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed: { type?: string; result?: { ok?: boolean; value?: { skills?: SkillOption[] }; error?: { code?: string; message?: string } } } | null\n = await response.json().catch(() => null)\n if (!response.ok || parsed === null || parsed.type !== 'server-response' || parsed.result?.ok !== true) {\n throw new KanbanApiError(\n parsed?.result?.error?.code ?? 'http',\n parsed?.result?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.result.value?.skills ?? []\n}\n\n/** One row of the host `agentPresets.list()` roster. */\nexport interface PresetOption {\n id: string\n name?: string\n description?: string\n}\n\n/** Reasoning efforts of one provider/model route (`reasoning.options`). */\nexport interface ReasoningOptions {\n efforts: Array<{ id: string; name: string; description?: string }>\n defaultEffort?: string\n /** Client-side marker: the fetch failed; the stored effort must be kept. */\n failed?: boolean\n}\n\nexport const api = {\n list: (workspacePath: string) => call<KanbanCard[]>('list', { workspacePath }),\n create: (workspacePath: string, requirement: string, model: string, provider?: string, skill?: string) =>\n call<KanbanCard>('create', { workspacePath, requirement, model, provider, ...(skill !== undefined && skill !== '' ? { skill } : {}) }),\n move: (cardId: string, toLane: Lane) => call<{ ok: boolean; message?: string }>('move', { cardId, toLane }),\n stop: (cardId: string) => call<{ ok: boolean; message?: string }>('stop', { cardId }),\n retry: (cardId: string) => call<{ ok: boolean; message?: string }>('retry', { cardId }),\n remove: (cardId: string) => call<{ ok: boolean; message?: string }>('remove', { cardId }),\n settingsGet: () => call<KanbanSettingsShape>('settings.get'),\n settingsSet: (patch: Partial<KanbanSettingsShape>) => call<KanbanSettingsShape>('settings.set', patch),\n models: () => call<ModelOption[]>('models.list'),\n presets: () => call<PresetOption[]>('presets.list'),\n reasoningOptions: (provider: string, model: string) =>\n call<ReasoningOptions>('reasoning.options', { provider, model }),\n}\n","import type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\n\n/**\n * Panel id shared by this plugin's main-panel key (`main`) and its sidebar\n * entry (`sidebar.panellist`): the shell selects the panel by this id, so the\n * two registrations must agree.\n */\nexport const KANBAN_PANEL_ID = 'task-kanban'\n\n/**\n * Structural view of the client shell's panel-navigation face (`ctx.layout`).\n * Declared locally (no value import) so the plugin keeps working on a runtime\n * whose layout types differ.\n */\ninterface LayoutLike {\n selectPanel(panelId: string | null): void\n}\n\n/**\n * HMR-safe owner context, keyed on the global symbol registry.\n *\n * The client-hmr hot swap re-evaluates this module (a fresh `lib/client.js`\n * bundle) WITHOUT reloading the page; a module-level cell would then be\n * duplicated per evaluation and an old copy's helper would read a stale owner.\n * `Symbol.for` makes every bundle copy share one cell.\n */\nconst STATE_KEY = Symbol.for('@fonlan/dsh-task-kanban/state')\n\ninterface KanbanState {\n client: ClientContext | null\n}\n\nfunction getState(): KanbanState {\n const g = globalThis as unknown as Record<symbol, KanbanState | undefined>\n let state = g[STATE_KEY]\n if (state === undefined) {\n state = { client: null }\n g[STATE_KEY] = state\n }\n return state\n}\n\nexport function setClient(ctx: ClientContext | null): void {\n getState().client = ctx\n}\nexport function getClient(): ClientContext | null {\n return getState().client\n}\n\n/** The shell's panel face, when this runtime provides it. */\nfunction layoutOf(ctx: ClientContext | null): LayoutLike | null {\n if (ctx === null) return null\n try {\n const layout = (ctx as unknown as { layout?: LayoutLike }).layout\n return typeof layout?.selectPanel === 'function' ? layout : null\n } catch {\n return null\n }\n}\n\n/** Select the kanban panel. The sidebar's own entry does this; kept for in-app callers. */\nexport function showKanbanPanel(ctx: ClientContext | null = getClient()): void {\n try {\n layoutOf(ctx)?.selectPanel(KANBAN_PANEL_ID)\n } catch (error) {\n console.error('[@fonlan/dsh-task-kanban] cannot select the kanban panel:', error)\n }\n}\n\n/** Hand the center column back to the Conversation. */\nexport function leaveKanbanPanel(ctx: ClientContext | null = getClient()): void {\n try {\n layoutOf(ctx)?.selectPanel(null)\n } catch (error) {\n console.error('[@fonlan/dsh-task-kanban] cannot leave the kanban panel:', error)\n }\n}\n\n/**\n * Route session navigation through the panel selection: opening any session\n * while the board is the active panel first returns the center column to the\n * Conversation, so the session view renders.\n *\n * Every sidebar path that selects a session funnels through `sessions.open`\n * (session rows, search results, fork results, New Session) or\n * `sessions.openSubagent` (catalog children) — including re-clicking the\n * already-current session, which never changes `list.current` and therefore\n * cannot be caught by a list-store subscription. Wrapping the two entry points\n * covers all of them in one place.\n *\n * The wrapper is idempotent: a `kbBound` marker on the wrapper prevents a\n * second bind (plugin re-apply / HMR) from stacking another layer.\n */\nexport function bindSessionNavigation(ctx: ClientContext): void {\n const sessions = ctx.sessions\n if (sessions === undefined) return\n\n const open = sessions.open\n if (typeof open === 'function' && (open as unknown as { kbBound?: boolean }).kbBound !== true) {\n const bound = ((id: Parameters<typeof open>[0]) => {\n leaveKanbanPanel(ctx)\n return open.call(sessions, id)\n }) as typeof open\n ;(bound as unknown as { kbBound?: boolean }).kbBound = true\n sessions.open = bound\n }\n\n const openSubagent = sessions.openSubagent\n if (typeof openSubagent === 'function' && (openSubagent as unknown as { kbBound?: boolean }).kbBound !== true) {\n const bound = ((address: Parameters<typeof openSubagent>[0]) => {\n leaveKanbanPanel(ctx)\n return openSubagent.call(sessions, address)\n }) as typeof openSubagent\n ;(bound as unknown as { kbBound?: boolean }).kbBound = true\n sessions.openSubagent = bound\n }\n}\n","// Locale namespace = the plugin's cordis id (kebab). DSH flat namespace keys\n// (settings + locale) use the internal id `task-kanban`; the scoped npm package\n// name is reserved for package-bound identifiers (exported `name`, module-loader\n// id, the /plugins/<pkg>/… route base).\nexport const LOCALE_NS = 'task-kanban'\n\nexport const zh = {\n kanban: '任务看板',\n openBoard: '打开任务看板',\n closeBoard: '返回对话',\n newTask: '新建任务',\n requirement: '需求',\n project: '所属项目',\n model: '模型',\n cancel: '取消',\n close: '关闭',\n addAndRefine: '添加并细化',\n laneDemand: '需求',\n laneQueue: '队列',\n laneRunning: '运行中',\n laneCompleted: '已完成',\n laneMerged: '已合并',\n statusDraft: '未细化',\n statusRefining: '细化中',\n statusPlanned: '已规划',\n statusQueued: '排队中',\n statusRunning: '实现中',\n statusCompleted: '已完成',\n statusMerging: '合并中',\n statusMerged: '已合并',\n statusError: '出错',\n phaseProgress: '{current}/{total}',\n retry: '重试',\n stop: '停止',\n delete: '删除',\n deleteConfirm: '确定删除该任务?其 worktree 会被清理。',\n openSession: '打开会话',\n plan: '实现方案',\n summary: '摘要',\n phases: '阶段',\n phaseGoal: '目标',\n phaseSessions: '会话',\n phaseConclusion: '结论',\n phaseNum: 'phase {n}',\n error: '错误',\n requirementLabel: '需求文本',\n requirementPlaceholder: '描述你要实现的需求……',\n skillGestureHint: '开头输入 /skill-name 可指定细化时使用的 Skill(如 /grill-me)',\n skillHint: '细化时将使用 Skill「{skill}」,并可与该会话交流打磨需求',\n skillMenuUserOnly: '仅用户可调',\n skillBadge: '细化 Skill:/{skill}',\n modelPlaceholder: '(使用默认模型)',\n noWorkspace: '没有可用工作区,请先在侧边栏添加',\n refresh: '刷新',\n settingsTitle: '任务看板',\n sectionSub: '全局并行 worker 数与各会话类型的默认模型、推理强度、Agent 预设',\n maxParallelWorkers: '全局并行 worker 数',\n settingsRefineGroup: '细化需求会话默认',\n settingsPhaseGroup: 'Phase 实现会话默认',\n reasoningEffort: '推理强度',\n agentPreset: 'Agent 预设',\n defaultOption: '(默认)',\n saved: '已保存',\n loadError: '加载任务失败',\n noPlan: '该卡片还没有实现计划,请先点击\"添加并细化\"',\n dragNoPlan: '还没有实现计划的卡片不能进入队列',\n actionFailed: '操作失败:{message}',\n sessionNotListed: '该会话不在当前列表,可能来自其他工作区',\n interrupted: '已中断',\n noBaseBranch: '项目没有 main/master 分支',\n worktreeFailed: 'worktree 创建失败',\n refineFailed: '细化失败',\n phaseFailed: '阶段执行失败',\n mergeFailed: '合并失败',\n createFailed: '创建失败',\n refinementLabel: '需求细化',\n mergeLabel: '合并',\n commitLabel: '提交',\n}\n\nexport const en = {\n kanban: 'Task Kanban',\n openBoard: 'Open Task Kanban',\n closeBoard: 'Back to chat',\n newTask: 'New Task',\n requirement: 'Requirement',\n project: 'Project',\n model: 'Model',\n cancel: 'Cancel',\n close: 'Close',\n addAndRefine: 'Add & Refine',\n laneDemand: 'Demands',\n laneQueue: 'Queue',\n laneRunning: 'Running',\n laneCompleted: 'Completed',\n laneMerged: 'Merged',\n statusDraft: 'Unrefined',\n statusRefining: 'Refining',\n statusPlanned: 'Planned',\n statusQueued: 'Queued',\n statusRunning: 'Running',\n statusCompleted: 'Completed',\n statusMerging: 'Merging',\n statusMerged: 'Merged',\n statusError: 'Error',\n phaseProgress: '{current}/{total}',\n retry: 'Retry',\n stop: 'Stop',\n delete: 'Delete',\n deleteConfirm: 'Delete this task? Its worktree will be cleaned up.',\n openSession: 'Open session',\n plan: 'Plan',\n summary: 'Summary',\n phases: 'Phases',\n phaseGoal: 'Goal',\n phaseSessions: 'Sessions',\n phaseConclusion: 'Conclusion',\n phaseNum: 'Phase {n}',\n error: 'Error',\n requirementLabel: 'Requirement',\n requirementPlaceholder: 'Describe what you want to build…',\n skillGestureHint: 'Start with /skill-name to choose the refinement skill (e.g. /grill-me)',\n skillHint: 'Refinement will use Skill “{skill}” — talk to this session to refine the requirement',\n skillMenuUserOnly: 'User-only',\n skillBadge: 'Refine skill: /{skill}',\n modelPlaceholder: '(use default model)',\n noWorkspace: 'No workspaces available — add one in the sidebar first',\n refresh: 'Refresh',\n settingsTitle: 'Task Kanban',\n sectionSub: 'Global parallel workers and per-session-type defaults for model, reasoning effort, and agent preset',\n maxParallelWorkers: 'Global parallel workers',\n settingsRefineGroup: 'Refinement session defaults',\n settingsPhaseGroup: 'Phase implementation defaults',\n reasoningEffort: 'Reasoning effort',\n agentPreset: 'Agent preset',\n defaultOption: '(default)',\n saved: 'Saved',\n loadError: 'Failed to load tasks',\n noPlan: 'This card has no plan yet — click \"Add & Refine\" first',\n dragNoPlan: 'Cards without a plan cannot enter the queue',\n actionFailed: 'Action failed: {message}',\n sessionNotListed: 'Session is not listed here; it may belong to another workspace',\n interrupted: 'Interrupted',\n noBaseBranch: 'Project has no main/master branch',\n worktreeFailed: 'Worktree creation failed',\n refineFailed: 'Refinement failed',\n phaseFailed: 'Phase failed',\n mergeFailed: 'Merge failed',\n createFailed: 'Creation failed',\n refinementLabel: 'Refinement',\n mergeLabel: 'Merge',\n commitLabel: 'Commit',\n}","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { KanbanCard, Lane, PhaseAttempt, PlanPhase } from '../shared/card'\nimport { DROP_RULES, laneOf } from '../shared/lanes'\nimport { api, gatewaySkillList, type SkillOption } from './api'\nimport { getClient, leaveKanbanPanel } from './kanban-state'\nimport { en, zh } from './locales'\nimport './board.css'\n\ninterface BoardProps {\n t?: (key: string, params?: Record<string, unknown>) => string\n useWorkspaces?: (selector: (state: unknown) => unknown) => unknown\n useSessions?: (selector: (state: unknown) => unknown) => unknown\n}\n\n/** Session-list snapshot shape the standard `useSessions` feed carries. */\ninterface SessionListStateLike {\n current?: string\n /** Listed session ids (the feed's own order). */\n ids?: string[]\n}\n\nfunction firstLine(text: string): string {\n return text.split('\\n').find((l) => l.trim() !== '')?.trim() ?? ''\n}\n\n/** The leading `/skill-name` gesture at the start of the requirement input. */\nconst SKILL_GESTURE = /^\\s*\\/([a-z0-9]+(?:-[a-z0-9]+)*)(?=\\s|$)/\n\n/** Extract a leading `/skill-name` token plus the cleaned remainder. */\nfunction parseSkillGesture(raw: string): { skill?: string; requirement: string } {\n const m = SKILL_GESTURE.exec(raw)\n if (m === null) return { requirement: raw.trim() }\n return { skill: m[1], requirement: raw.slice(m[0].length).trim() }\n}\n\nfunction statusLabel(card: KanbanCard, t: (key: string) => string): string {\n if (card.status === 'error') {\n switch (card.error?.kind) {\n case 'interrupted': return t('interrupted')\n case 'no_base_branch': return t('noBaseBranch')\n case 'worktree_failed': return t('worktreeFailed')\n case 'refine_failed': return t('refineFailed')\n case 'phase_failed': return t('phaseFailed')\n case 'merge_failed': return t('mergeFailed')\n default: return t('createFailed')\n }\n }\n switch (card.status) {\n case 'draft': return t('statusDraft')\n case 'refining': return t('statusRefining')\n case 'planned': return t('statusPlanned')\n case 'queued': return t('statusQueued')\n case 'running': return t('statusRunning')\n case 'completed': return t('statusCompleted')\n case 'merging': return t('statusMerging')\n case 'merged': return t('statusMerged')\n }\n}\n\ninterface WorkspaceRow {\n workspaceId: string\n path: string\n title: string\n}\n\nconst LANE_ORDER: Array<{ key: Lane; labelKey: string }> = [\n { key: 'demand', labelKey: 'laneDemand' },\n { key: 'queue', labelKey: 'laneQueue' },\n { key: 'running', labelKey: 'laneRunning' },\n { key: 'completed', labelKey: 'laneCompleted' },\n { key: 'merged', labelKey: 'laneMerged' },\n]\n\nconst WS_STORAGE_KEY = '@fonlan/dsh-task-kanban:workspace'\n\nexport function BoardRoot(props: BoardProps): JSX.Element {\n const t = props.t ?? ((key: string, params?: Record<string, unknown>) => {\n const dict = (zh as Record<string, string>)[key] ?? (en as Record<string, string>)[key]\n if (dict === undefined || params === undefined) return dict ?? key\n return dict.replace(/\\{(\\w+)\\}/g, (m, name: string) => (params[name] as string) ?? m)\n })\n const useWorkspaces = props.useWorkspaces\n const wsState = useWorkspaces !== undefined ? (useWorkspaces((s: unknown) => s) as { items?: WorkspaceRow[] } | undefined) : undefined\n const items: WorkspaceRow[] = wsState?.items ?? []\n const useSessions = props.useSessions\n const sessionState = useSessions !== undefined ? (useSessions((s: unknown) => s) as SessionListStateLike | undefined) : undefined\n // The skill catalog is addressed by session (`skills/list`), so the /-menu\n // needs one. With no selection (fresh browser, board opened straight from the\n // footer) fall back to the most recent listed session: any session resolves a\n // preset scope, whereas no session silently leaves the menu empty.\n const currentSessionId = sessionState?.current ?? sessionState?.ids?.[0]\n\n const [selectedPath, setSelectedPath] = useState<string>(() => {\n try {\n return localStorage.getItem(WS_STORAGE_KEY) ?? ''\n } catch {\n return ''\n }\n })\n const [cards, setCards] = useState<KanbanCard[]>([])\n const [toast, setToast] = useState<string | null>(null)\n const [detailId, setDetailId] = useState<string | null>(null)\n const [newTaskOpen, setNewTaskOpen] = useState(false)\n\n useEffect(() => {\n if (selectedPath === '' && items.length > 0) {\n setSelectedPath(items[0].path)\n }\n }, [selectedPath, items])\n\n const showToast = useCallback((message: string) => {\n setToast(message)\n window.setTimeout(() => setToast(null), 3500)\n }, [])\n\n const refresh = useCallback(async () => {\n if (selectedPath === '') return\n try {\n setCards(await api.list(selectedPath))\n } catch (error) {\n showToast(error instanceof Error ? error.message : String(error))\n }\n }, [selectedPath, showToast])\n\n useEffect(() => {\n void refresh()\n const timer = window.setInterval(() => { void refresh() }, 2500)\n return () => window.clearInterval(timer)\n }, [refresh])\n\n const byLane = useMemo(() => {\n const map: Record<Lane, KanbanCard[]> = { demand: [], queue: [], running: [], completed: [], merged: [] }\n for (const card of cards) map[laneOf(card)].push(card)\n for (const lane of LANE_ORDER) map[lane.key].sort((a, b) => a.createdAt - b.createdAt)\n return map\n }, [cards])\n\n const handleDrop = useCallback(async (target: Lane, event: React.DragEvent) => {\n event.preventDefault()\n const cardId = event.dataTransfer.getData('text/plain')\n if (cardId === '') return\n const card = cards.find((c) => c.id === cardId)\n if (card === undefined) return\n if (target === 'queue' && card.status !== 'running' && card.plan === undefined) {\n showToast(t('dragNoPlan'))\n return\n }\n try {\n const result = await api.move(cardId, target)\n if (!result.ok) {\n showToast(t('actionFailed', { message: result.message ?? '' }))\n }\n void refresh()\n } catch (error) {\n showToast(error instanceof Error ? error.message : String(error))\n }\n }, [cards, refresh, showToast, t])\n\n const openSession = useCallback((sessionId: string) => {\n const ctx = getClient()\n // Return the center column to the Conversation first: `sessions.open` is\n // wrapped by bindSessionNavigation as well, but a runtime without that\n // binding must still leave the board before the session renders.\n leaveKanbanPanel(ctx)\n if (ctx === null) return\n try {\n ;(ctx.sessions as { open(id: string): void }).open(sessionId)\n } catch {\n showToast(t('sessionNotListed'))\n }\n }, [showToast, t])\n\n if (items.length === 0) {\n return (\n <div className=\"kb-board kb-empty\">\n <div className=\"kb-empty-text\">{t('noWorkspace')}</div>\n </div>\n )\n }\n\n return (\n <div className=\"kb-board\">\n <div className=\"kb-board-header\">\n <div className=\"kb-board-title\">\n <select\n className=\"kb-ws-select\"\n value={selectedPath}\n onChange={(e) => {\n setSelectedPath(e.target.value)\n try {\n localStorage.setItem(WS_STORAGE_KEY, e.target.value)\n } catch {\n // storage unavailable\n }\n }}\n >\n {items.map((w) => (\n <option key={w.workspaceId} value={w.path}>{w.title}</option>\n ))}\n </select>\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" onClick={() => setNewTaskOpen(true)}>{t('newTask')}</button>\n </div>\n </div>\n\n <div className=\"kb-lanes\">\n {LANE_ORDER.map((lane) => (\n <div\n key={lane.key}\n className={'kb-lane' + (DROP_RULES[lane.key].length > 0 ? ' kb-lane-drop' : '')}\n onDragOver={(e) => {\n if (DROP_RULES[lane.key].length > 0) e.preventDefault()\n }}\n onDrop={(e) => { void handleDrop(lane.key, e) }}\n >\n <div className=\"kb-lane-head\">\n <span className=\"kb-lane-title\">{t(lane.labelKey)}</span>\n <span className=\"kb-lane-count\">{byLane[lane.key].length}</span>\n </div>\n <div className=\"kb-lane-body\">\n {byLane[lane.key].map((card) => (\n <CardView\n key={card.id}\n card={card}\n t={t}\n onToggle={() => setDetailId(detailId === card.id ? null : card.id)}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n\n {toast !== null && <div className=\"kb-toast\">{toast}</div>}\n\n {newTaskOpen && (\n <NewTaskModal\n t={t}\n workspaces={items}\n selectedPath={selectedPath}\n sessionId={currentSessionId}\n onClose={() => setNewTaskOpen(false)}\n onCreated={() => {\n setNewTaskOpen(false)\n void refresh()\n }}\n onError={(message) => showToast(message)}\n />\n )}\n\n {detailId !== null && (\n <DetailPanel\n card={cards.find((c) => c.id === detailId) ?? null}\n t={t}\n onClose={() => setDetailId(null)}\n onChanged={() => {\n setDetailId(null)\n void refresh()\n }}\n onToast={showToast}\n onOpenSession={openSession}\n />\n )}\n </div>\n )\n}\n\ninterface CardViewProps {\n card: KanbanCard\n t: (key: string, params?: Record<string, unknown>) => string\n onToggle: () => void\n}\n\nfunction CardView({ card, t, onToggle }: CardViewProps): JSX.Element {\n const draggable = card.status === 'planned' || card.status === 'queued' || card.status === 'running'\n const title = card.plan !== undefined && card.plan.title !== '' ? card.plan.title : firstLine(card.requirement)\n const badge = statusLabel(card, t)\n const phaseInfo = card.status === 'running' || card.status === 'error'\n ? card.currentPhase < card.phaseCount ? t('phaseProgress', { current: card.currentPhase + 1, total: card.phaseCount }) : ''\n : ''\n return (\n <div\n className={'kb-card' + (card.status === 'error' ? ' kb-card-error' : '') + (card.status === 'running' ? ' kb-card-running' : '')}\n draggable={draggable}\n onDragStart={(e) => {\n e.dataTransfer.setData('text/plain', card.id)\n e.dataTransfer.effectAllowed = 'move'\n }}\n onClick={onToggle}\n >\n <div className=\"kb-card-title\">{title}</div>\n <div className=\"kb-card-meta\">\n <span className=\"kb-card-badge\">{badge}</span>\n {phaseInfo !== '' && <span className=\"kb-card-phase\">{phaseInfo}</span>}\n {card.skill !== undefined && card.skill !== '' && <span className=\"kb-card-skill\">/ {card.skill}</span>}\n {card.model !== '' && <span className=\"kb-card-model\">{card.model}</span>}\n </div>\n {card.status === 'error' && card.error !== undefined && (\n <div className=\"kb-card-error-text\">{card.error.message}</div>\n )}\n {card.status === 'running' && card.gitMode === true && (\n <div className=\"kb-card-worktree\">{card.worktreePath ?? ''}</div>\n )}\n </div>\n )\n}\n\ninterface NewTaskModalProps {\n t: (key: string, params?: Record<string, unknown>) => string\n workspaces: WorkspaceRow[]\n selectedPath: string\n /** Current session id, scoping the host skill.list catalog lookup. */\n sessionId?: string\n onClose: () => void\n onCreated: () => void\n onError: (message: string) => void\n}\n\n/** An in-progress leading `/query` token (menu-open state). */\nconst SKILL_MENU_RE = /^\\s*\\/([a-z0-9-]*)$/\n\nfunction NewTaskModal({ t, workspaces, selectedPath, sessionId, onClose, onCreated, onError }: NewTaskModalProps): JSX.Element {\n const [requirement, setRequirement] = useState('')\n const [project, setProject] = useState(selectedPath)\n const [model, setModel] = useState('')\n const [modelProvider, setModelProvider] = useState('')\n const [models, setModels] = useState<Array<{ provider: string; id: string; name?: string }>>([])\n const [skills, setSkills] = useState<SkillOption[]>([])\n const [menuQuery, setMenuQuery] = useState<string | null>(null)\n const [menuIndex, setMenuIndex] = useState(0)\n const [busy, setBusy] = useState(false)\n const textareaRef = useRef<HTMLTextAreaElement | null>(null)\n\n useEffect(() => {\n let alive = true\n api.models()\n .then((list) => { if (alive) setModels(list) })\n .catch(() => { if (alive) setModels([]) })\n return () => { alive = false }\n }, [])\n\n // Load the host skill catalog once (scoped to the current session), the\n // same feed DSH's chat input uses for its /-autocomplete.\n useEffect(() => {\n if (sessionId === undefined) return\n let alive = true\n gatewaySkillList(sessionId)\n .then((list) => { if (alive) setSkills(list) })\n .catch(() => { if (alive) setSkills([]) })\n return () => { alive = false }\n }, [sessionId])\n\n const matches = skills.filter((s) => s.name.startsWith(menuQuery ?? ''))\n const menuVisible = menuQuery !== null && matches.length > 0\n const selected = menuVisible ? matches[Math.min(menuIndex, matches.length - 1)] : undefined\n\n /** Re-evaluate the leading-token menu state from the current value + caret. */\n const syncMenu = (value: string, caret: number): void => {\n const head = value.slice(0, caret)\n const m = SKILL_MENU_RE.exec(head)\n if (m !== null) {\n setMenuQuery(m[1])\n setMenuIndex(0)\n return\n }\n setMenuQuery(null)\n }\n\n const selectSkill = (name: string): void => {\n const el = textareaRef.current\n const caret = el?.selectionStart ?? requirement.length\n const head = requirement.slice(0, caret)\n const m = SKILL_MENU_RE.exec(head)\n // Replace the leading `/query` token with `/name `.\n const inserted = `/${name} `\n const newValue = m !== null ? inserted + requirement.slice(caret) : inserted + requirement\n setRequirement(newValue)\n setMenuQuery(null)\n requestAnimationFrame(() => {\n const next = textareaRef.current\n if (next !== null) {\n next.focus()\n const pos = inserted.length\n next.setSelectionRange(pos, pos)\n }\n })\n }\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>): void => {\n if (!menuVisible) return\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setMenuIndex((i) => (i + 1) % matches.length)\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n setMenuIndex((i) => (i - 1 + matches.length) % matches.length)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n if (selected !== undefined) selectSkill(selected.name)\n } else if (e.key === 'Escape') {\n e.preventDefault()\n setMenuQuery(null)\n } else if (e.key === 'Tab') {\n e.preventDefault()\n if (selected !== undefined) selectSkill(selected.name)\n }\n }\n\n const submit = async (): Promise<void> => {\n if (requirement.trim() === '') {\n onError(t('requirementLabel') + ' ' + t('error'))\n return\n }\n if (project === '') {\n onError(t('noWorkspace'))\n return\n }\n const parsed = parseSkillGesture(requirement)\n setBusy(true)\n try {\n await api.create(project, parsed.requirement, model, modelProvider, parsed.skill)\n onCreated()\n } catch (error) {\n onError(error instanceof Error ? error.message : String(error))\n setBusy(false)\n }\n }\n\n const activeSkill = parseSkillGesture(requirement).skill\n\n return (\n <div className=\"kb-modal-backdrop\" onClick={busy ? undefined : onClose}>\n <div className=\"kb-modal\" onClick={(e) => e.stopPropagation()}>\n <div className=\"kb-modal-title\">{t('newTask')}</div>\n <label className=\"kb-field\">\n <span>{t('requirementLabel')}</span>\n <div className=\"kb-skill-menu-wrap\">\n <textarea\n ref={textareaRef}\n className=\"kb-input kb-textarea\"\n value={requirement}\n placeholder={t('requirementPlaceholder')}\n onChange={(e) => {\n const value = e.target.value\n setRequirement(value)\n syncMenu(value, e.target.selectionStart ?? value.length)\n }}\n onKeyDown={onKeyDown}\n />\n {menuVisible && (\n <ul className=\"kb-skill-menu\" role=\"listbox\">\n {matches.map((s, i) => (\n <li\n key={s.name}\n role=\"option\"\n aria-selected={i === menuIndex}\n className={'kb-skill-menu-item' + (i === menuIndex ? ' kb-skill-menu-item-active' : '')}\n onMouseDown={(e) => { e.preventDefault(); selectSkill(s.name) }}\n onMouseEnter={() => setMenuIndex(i)}\n >\n <span className=\"kb-skill-menu-name\">/{s.name}</span>\n <span className=\"kb-skill-menu-desc\">\n {s.modelInvocable ? s.description : `${t('skillMenuUserOnly')} · ${s.description}`}\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n {activeSkill !== undefined ? (\n <span className=\"kb-field-hint kb-field-hint-skill\">{t('skillHint', { skill: activeSkill })}</span>\n ) : (\n <span className=\"kb-field-hint\">{t('skillGestureHint')}</span>\n )}\n </label>\n <label className=\"kb-field\">\n <span>{t('project')}</span>\n <select className=\"kb-input\" value={project} onChange={(e) => setProject(e.target.value)}>\n {workspaces.map((w) => (\n <option key={w.workspaceId} value={w.path}>{w.title}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field\">\n <span>{t('model')}</span>\n <select\n className=\"kb-input\"\n value={model}\n onChange={(e) => {\n const id = e.target.value\n setModel(id)\n const found = models.find((m) => m.id === id)\n setModelProvider(found?.provider ?? '')\n }}\n >\n <option value=\"\">{t('modelPlaceholder')}</option>\n {models.map((m) => (\n <option key={m.provider + '/' + m.id} value={m.id}>{m.name ?? m.id}</option>\n ))}\n </select>\n </label>\n <div className=\"kb-modal-actions\">\n <button type=\"button\" className=\"kb-btn\" onClick={onClose} disabled={busy}>{t('cancel')}</button>\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" onClick={() => { void submit() }} disabled={busy}>\n {t('addAndRefine')}\n </button>\n </div>\n </div>\n </div>\n )\n}\n\ninterface DetailPanelProps {\n card: KanbanCard | null\n t: (key: string, params?: Record<string, unknown>) => string\n onClose: () => void\n onChanged: () => void\n onToast: (message: string) => void\n onOpenSession: (sessionId: string) => void\n}\n\nfunction DetailPanel({ card, t, onClose, onChanged, onToast, onOpenSession }: DetailPanelProps): JSX.Element | null {\n const [busy, setBusy] = useState(false)\n if (card === null) return null\n\n const act = async (fn: () => Promise<unknown>): Promise<void> => {\n setBusy(true)\n try {\n await fn()\n onChanged()\n } catch (error) {\n onToast(error instanceof Error ? error.message : String(error))\n setBusy(false)\n }\n }\n\n const remove = async (): Promise<void> => {\n if (!window.confirm(t('deleteConfirm'))) return\n await act(() => api.remove(card!.id))\n }\n\n return (\n <div className=\"kb-detail-panel\">\n <div className=\"kb-detail-panel-head\">\n <div className=\"kb-modal-title\">\n {card.plan !== undefined && card.plan.title !== '' ? card.plan.title : firstLine(card.requirement)}\n <span className={'kb-detail-status kb-status-' + card.status}>{statusLabel(card, t)}</span>\n </div>\n <button type=\"button\" className=\"kb-detail-close\" aria-label={t('close')} title={t('close')} onClick={onClose}>✕</button>\n </div>\n\n <div className=\"kb-detail-panel-body\">\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('requirement')}</div>\n {card.skill !== undefined && card.skill !== '' && (\n <div className=\"kb-detail-skill\">{t('skillBadge', { skill: card.skill })}</div>\n )}\n <div className=\"kb-detail-text\">{card.requirement}</div>\n </div>\n\n {card.plan !== undefined && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('plan')}</div>\n <div className=\"kb-detail-plan\">\n <div className=\"kb-plan-summary\">{card.plan.summary}</div>\n <ol className=\"kb-plan-phases\">\n {card.plan.phases.map((phase, i) => (\n <PhaseCard\n key={phase.id}\n phase={phase}\n phaseIndex={i}\n card={card}\n t={t}\n onOpenSession={onOpenSession}\n />\n ))}\n </ol>\n </div>\n </div>\n )}\n\n {card.sessions.refinement.length > 0 && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('refinementLabel')}</div>\n <div className=\"kb-session-links\">\n {card.sessions.refinement.map((sid) => (\n <button key={sid} type=\"button\" className=\"kb-btn kb-btn-small\" onClick={() => onOpenSession(sid)}>\n {t('openSession')} · {sid.slice(0, 13)}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {card.status === 'error' && card.error !== undefined && (\n <div className=\"kb-detail-section kb-detail-error\">\n <div className=\"kb-detail-label\">{t('error')}</div>\n <div className=\"kb-detail-text\">{card.error.message}</div>\n </div>\n )}\n\n {card.merge?.mergeCommit !== undefined && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('mergeLabel')}</div>\n <div className=\"kb-detail-text\">{t('commitLabel')} {card.merge.mergeCommit.slice(0, 12)}</div>\n </div>\n )}\n\n <div className=\"kb-modal-actions\">\n {card.status === 'error' && (\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" disabled={busy} onClick={() => { void act(() => api.retry(card!.id)) }}>\n {t('retry')}\n </button>\n )}\n {(card.status === 'running' || card.status === 'merging') && (\n <button type=\"button\" className=\"kb-btn\" disabled={busy} onClick={() => { void act(() => api.stop(card!.id)) }}>\n {t('stop')}\n </button>\n )}\n {card.status !== 'running' && card.status !== 'refining' && card.status !== 'merging' && (\n <button type=\"button\" className=\"kb-btn kb-btn-danger\" disabled={busy} onClick={() => { void remove() }}>\n {t('delete')}\n </button>\n )}\n <button type=\"button\" className=\"kb-btn\" onClick={onClose}>{t('cancel')}</button>\n </div>\n </div>\n </div>\n )\n}\n\n/** One plan phase rendered as a card with goal / sessions / conclusion sections. */\nfunction PhaseCard({ phase, phaseIndex, card, t, onOpenSession }: {\n phase: PlanPhase\n phaseIndex: number\n card: KanbanCard\n t: (key: string, params?: Record<string, unknown>) => string\n onOpenSession: (sessionId: string) => void\n}): JSX.Element {\n const attempts = card.sessions.phases.filter((a) => a.phaseIndex === phaseIndex)\n const summaries = attempts\n .filter((a) => a.summary !== undefined && a.summary.trim() !== '')\n .map((a) => a.summary as string)\n const isCurrent = phaseIndex === card.currentPhase && card.status === 'running'\n // A phase with at least one concluded attempt counts as completed.\n const isCompleted = summaries.length > 0\n const cls = 'kb-plan-phase'\n + (isCurrent ? ' kb-plan-phase-current' : '')\n + (isCompleted ? ' kb-plan-phase-completed' : '')\n const planTitle = card.plan?.title ?? ''\n return (\n <li className={cls}>\n <div className=\"kb-plan-phase-head\">\n <span className=\"kb-plan-phase-title\">{phase.title}</span>\n <span className=\"kb-plan-phase-id\">{phase.id}</span>\n </div>\n <div className=\"kb-plan-phase-body\">\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseGoal')}</div>\n <div className=\"kb-plan-phase-goal\">{phase.goal}</div>\n </div>\n {attempts.length > 0 && (\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseSessions')}</div>\n <PhaseSessions attempts={attempts} planTitle={planTitle} phaseIndex={phaseIndex} t={t} onOpenSession={onOpenSession} />\n </div>\n )}\n {summaries.length > 0 && (\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseConclusion')}</div>\n <div className=\"kb-plan-phase-conclusion\">\n {summaries.map((s, idx) => (\n <div key={idx} className=\"kb-plan-phase-conclusion-item\">{s}</div>\n ))}\n </div>\n </div>\n )}\n </div>\n </li>\n )\n}\n\n/**\n * Open-session buttons for one phase's attempts (retries append more). The\n * button labels the session with the deterministic \"{plan title} · phase N\"\n * format (the requested fallback when the host never auto-generated a title);\n * the full session id stays available as the native tooltip.\n */\nfunction PhaseSessions({ attempts, planTitle, phaseIndex, t, onOpenSession }: {\n attempts: PhaseAttempt[]\n planTitle: string\n phaseIndex: number\n t: (key: string, params?: Record<string, unknown>) => string\n onOpenSession: (sessionId: string) => void\n}): JSX.Element {\n return (\n <div className=\"kb-plan-phase-sessions\">\n {attempts.map((a) => (\n <button key={a.sessionId} type=\"button\" className=\"kb-btn kb-btn-small\" title={a.sessionId} onClick={() => onOpenSession(a.sessionId)}>\n {t('openSession')} · {planTitle !== '' ? `${planTitle} · ${t('phaseNum', { n: phaseIndex + 1 })}` : a.sessionId.slice(0, 13)}\n </button>\n ))}\n </div>\n )\n}","import * as primitives from '@deepseek-ai/dsh-client-ui-primitives'\n\n/** Props every shell icon accepts: square edge in px, color rides currentColor. */\nexport interface IconProps {\n size?: number\n className?: string\n}\n\n/** One shell icon component. */\nexport type IconComponent = (props: IconProps) => JSX.Element\n\n/** The runtime export table, read by capability instead of by one hard-coded name. */\nconst table = primitives as unknown as Record<string, IconComponent | undefined>\n\n/** First name the runtime actually provides (a missing export is `undefined`). */\nfunction firstDefined(...names: string[]): IconComponent | undefined {\n for (const name of names) {\n let candidate: IconComponent | undefined\n try {\n candidate = table[name]\n } catch {\n // Some module namespaces reject unknown names instead of yielding\n // `undefined`; a rename must never throw on its way to the fallback.\n continue\n }\n if (typeof candidate === 'function') return candidate\n }\n return undefined\n}\n\n/**\n * Self-contained 16×16 checklist glyph (the 0.1.7 artwork) used when the shell\n * primitives expose none of the names above: the footer entry must render\n * something even on a runtime whose icon exports we do not know.\n */\nfunction ChecklistFallback({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg\n width={size}\n height={size}\n className={className}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n strokeWidth={1}\n >\n <path d=\"M3.75 6.25C4.7165 6.25 5.5 5.4665 5.5 4.5C5.5 3.5335 4.7165 2.75 3.75 2.75C2.7835 2.75 2 3.5335 2 4.5C2 5.4665 2.7835 6.25 3.75 6.25Z\" stroke=\"currentColor\" />\n <path d=\"M7.5 4.5H13.5\" stroke=\"currentColor\" />\n <path d=\"M3.75 13.25C4.7165 13.25 5.5 12.4665 5.5 11.5C5.5 10.5335 4.7165 9.75 3.75 9.75C2.7835 9.75 2 10.5335 2 11.5C2 12.4665 2.7835 13.25 3.75 13.25Z\" stroke=\"currentColor\" />\n <path d=\"M7.5 11.5H13.5\" stroke=\"currentColor\" />\n </svg>\n )\n}\n\n/**\n * The checklist icon used by the sidebar panel row entry.\n *\n * DSH 0.1.7 renamed every size-suffixed shell icon (`IconChecklistOutline14`)\n * into stroke-weight variants (`…Regular` 1px / `…Medium` 1.3px) inside\n * `@deepseek-ai/dsh-client-ui-primitives`. A stale named import resolves to\n * `undefined` and React then throws \"Element type is invalid\" while rendering\n * the slot entry — the entry is dropped and the button silently disappears\n * (exactly what upgrading to 0.1.7 did to this plugin). Resolve the name at\n * runtime, newest first, so the next rename degrades to another shipped\n * variant instead of taking the button down with it.\n */\nexport const ChecklistIcon: IconComponent =\n firstDefined(\n 'IconChecklistOutlineRegular',\n 'IconChecklistOutlineMedium',\n 'IconChecklistOutline',\n 'IconChecklistOutline14',\n ) ?? ChecklistFallback\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport { ChecklistIcon } from './icons'\nimport { api, type PresetOption, type ReasoningOptions } from './api'\nimport type { KanbanSettingsShape, ModelOption } from '../shared/card'\n\n/**\n * Sidebar panel-row glyph for the board (`sidebar.panellist`).\n *\n * The shell owns the row: it renders the button, its label, tooltip and active\n * state, and calls `layout.selectPanel(id)` on click. The entry contributes\n * only the glyph, so this component must stay purely presentational.\n */\nexport function KanbanPanelIcon({ size }: { size: number }): JSX.Element {\n return <ChecklistIcon size={size} />\n}\n\ninterface SettingsSectionProps {\n t?: (key: string) => string\n}\n\n/** Fallback shape while settings load (server always resolves the full set). */\nconst EMPTY_SETTINGS: KanbanSettingsShape = {\n maxParallelWorkers: 1,\n refinementModel: '',\n refinementProvider: '',\n refinementReasoningEffort: '',\n refinementPreset: '',\n phaseModel: '',\n phaseProvider: '',\n phaseReasoningEffort: '',\n phasePreset: '',\n}\n\n/** The setting field names of one session-type group. */\nconst GROUP_FIELDS = {\n refinement: {\n model: 'refinementModel',\n provider: 'refinementProvider',\n effort: 'refinementReasoningEffort',\n preset: 'refinementPreset',\n },\n phase: {\n model: 'phaseModel',\n provider: 'phaseProvider',\n effort: 'phaseReasoningEffort',\n preset: 'phasePreset',\n },\n} as const\n\ntype SessionGroupKey = keyof typeof GROUP_FIELDS\n\ninterface SessionDefaultsGroupProps {\n kind: SessionGroupKey\n settings: KanbanSettingsShape\n models: ModelOption[]\n presets: PresetOption[]\n /** Reasoning efforts already fetched, keyed `provider/model`. */\n efforts: Record<string, ReasoningOptions>\n tr: (key: string) => string\n onCommit: (patch: Partial<KanbanSettingsShape>) => Promise<void>\n loadEfforts: (provider: string, model: string) => void\n}\n\n/** Model / reasoning effort / agent preset defaults for one session type. */\nfunction SessionDefaultsGroup({ kind, settings, models, presets, efforts, tr, onCommit, loadEfforts }: SessionDefaultsGroupProps): JSX.Element {\n const fields = GROUP_FIELDS[kind]\n const model = settings[fields.model]\n const provider = settings[fields.provider]\n const effort = settings[fields.effort]\n const preset = settings[fields.preset]\n const effortKey = model !== '' && provider !== '' ? `${provider}/${model}` : ''\n const effortOptions = effortKey !== '' ? (efforts[effortKey]?.efforts ?? []) : []\n\n const handleModel = (id: string): void => {\n const found = models.find((m) => m.id === id)\n const nextProvider = found?.provider ?? ''\n void onCommit({ [fields.model]: id, [fields.provider]: nextProvider } as Partial<KanbanSettingsShape>)\n if (id !== '' && nextProvider !== '') loadEfforts(nextProvider, id)\n }\n\n return (\n <div className=\"kb-settings-group\">\n <div className=\"kb-settings-group-title\">{tr(kind === 'refinement' ? 'settingsRefineGroup' : 'settingsPhaseGroup')}</div>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('model')}</span>\n <select className=\"kb-input\" value={model} onChange={(e) => handleModel(e.target.value)}>\n <option value=\"\">{tr('defaultOption')}</option>\n {models.map((m) => (\n <option key={m.provider + '/' + m.id} value={m.id}>{m.name ?? m.id}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('reasoningEffort')}</span>\n <select\n className=\"kb-input\"\n value={effort}\n disabled={model === ''}\n onChange={(e) => void onCommit({ [fields.effort]: e.target.value } as Partial<KanbanSettingsShape>)}\n >\n <option value=\"\">{tr('defaultOption')}</option>\n {effortOptions.map((o) => (\n <option key={o.id} value={o.id}>{o.name}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('agentPreset')}</span>\n <select\n className=\"kb-input\"\n value={preset}\n onChange={(e) => void onCommit({ [fields.preset]: e.target.value } as Partial<KanbanSettingsShape>)}\n >\n <option value=\"\">{tr('defaultOption')}</option>\n {presets.map((p) => (\n <option key={p.id} value={p.id}>{p.name ?? p.id}</option>\n ))}\n </select>\n </label>\n </div>\n )\n}\n\n/** Plugin settings page (设置 -> 侧栏「任务看板」): workers + default model + per-session-type defaults. */\nexport function KanbanSettingsSection({ t }: SettingsSectionProps): JSX.Element {\n const tr = t ?? ((key: string) => key)\n const [settings, setSettings] = useState<KanbanSettingsShape>(EMPTY_SETTINGS)\n const [models, setModels] = useState<ModelOption[]>([])\n const [presets, setPresets] = useState<PresetOption[]>([])\n const [efforts, setEfforts] = useState<Record<string, ReasoningOptions>>({})\n const [saved, setSaved] = useState(false)\n\n const commit = useCallback(async (patch: Partial<KanbanSettingsShape>): Promise<void> => {\n try {\n const next = await api.settingsSet(patch)\n setSettings(next)\n setSaved(true)\n window.setTimeout(() => setSaved(false), 1500)\n } catch {\n // keep the previous value\n }\n }, [])\n\n // Refs so async callbacks (effort fetch) read the freshest settings/commit.\n const settingsRef = useRef(settings)\n settingsRef.current = settings\n const commitRef = useRef(commit)\n commitRef.current = commit\n\n useEffect(() => {\n let alive = true\n api.settingsGet()\n .then((s) => { if (alive) setSettings(s) })\n .catch(() => undefined)\n api.models()\n .then((list) => { if (alive) setModels(list) })\n .catch(() => undefined)\n api.presets()\n .then((list) => { if (alive) setPresets(list) })\n .catch(() => undefined)\n return () => { alive = false }\n }, [])\n\n /** Reasoning routes already requested (dedupe across mount + model changes). */\n const effortFetched = useRef<Set<string>>(new Set())\n\n /**\n * Fetch the reasoning efforts of one model route (once per route). A failed\n * fetch is marked `failed` so the stored effort is preserved (see the reset\n * effect below) instead of being wiped by a transient error.\n */\n const loadEfforts = useCallback((provider: string, model: string): void => {\n const key = `${provider}/${model}`\n if (effortFetched.current.has(key)) return\n effortFetched.current.add(key)\n api.reasoningOptions(provider, model)\n .then((opts) => setEfforts((prev) => ({ ...prev, [key]: opts })))\n .catch(() => setEfforts((prev) => ({ ...prev, [key]: { efforts: [], failed: true } })))\n }, [])\n\n // Fetch efforts for the models already configured in settings, so the\n // effort selects show their levels (and validate the stored effort) as soon\n // as settings load — the fetch previously ran only on model change.\n useEffect(() => {\n for (const kind of ['refinement', 'phase'] as const) {\n const fields = GROUP_FIELDS[kind]\n const model = settings[fields.model]\n const provider = settings[fields.provider]\n if (model !== '' && provider !== '') loadEfforts(provider, model)\n }\n }, [settings.refinementModel, settings.refinementProvider, settings.phaseModel, settings.phaseProvider, loadEfforts])\n\n // When the efforts of the selected model arrive, drop a stored effort the\n // model no longer offers (e.g. the user switched the model). A failed fetch\n // (`failed: true`) keeps the stored effort: the model may just be\n // temporarily unresolvable, and wiping the user's choice would be worse.\n useEffect(() => {\n const s = settingsRef.current\n for (const kind of ['refinement', 'phase'] as const) {\n const fields = GROUP_FIELDS[kind]\n const model = s[fields.model]\n const provider = s[fields.provider]\n const effort = s[fields.effort]\n if (effort === '' || model === '' || provider === '') continue\n const opts = efforts[`${provider}/${model}`]\n if (opts === undefined || opts.failed === true) continue\n if (!opts.efforts.some((o) => o.id === effort)) {\n void commitRef.current({ [fields.effort]: '' } as Partial<KanbanSettingsShape>)\n }\n }\n }, [efforts])\n\n return (\n <div className=\"kb-page\">\n <header className=\"kb-page-head\">\n <h3 className=\"kb-page-title\">{tr('settingsTitle')}</h3>\n <p className=\"kb-page-sub\">{tr('sectionSub')}</p>\n </header>\n <div className=\"kb-settings\">\n <label className=\"kb-field kb-field-row\">\n <span>{tr('maxParallelWorkers')}</span>\n <input\n className=\"kb-input kb-input-number\"\n type=\"number\"\n min={1}\n step={1}\n value={settings.maxParallelWorkers}\n onChange={(e) => {\n const value = Math.max(1, Math.floor(Number(e.target.value) || 1))\n setSettings((s) => ({ ...s, maxParallelWorkers: value }))\n void commit({ maxParallelWorkers: value })\n }}\n />\n </label>\n <SessionDefaultsGroup\n kind=\"refinement\"\n settings={settings}\n models={models}\n presets={presets}\n efforts={efforts}\n tr={tr}\n onCommit={commit}\n loadEfforts={loadEfforts}\n />\n <SessionDefaultsGroup\n kind=\"phase\"\n settings={settings}\n models={models}\n presets={presets}\n efforts={efforts}\n tr={tr}\n onCommit={commit}\n loadEfforts={loadEfforts}\n />\n {saved && <div className=\"kb-settings-saved\">{tr('saved')}</div>}\n </div>\n </div>\n )\n}","import type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { BoardRoot } from './board'\nimport { KanbanPanelIcon, KanbanSettingsSection } from './sections'\nimport { LOCALE_NS, zh, en } from './locales'\nimport { KANBAN_PANEL_ID, setClient, bindSessionNavigation } from './kanban-state'\n\n/** The settings sidebar entry this plugin's page owns (must stay stable). */\nconst SETTINGS_SECTION_ID = 'task-kanban'\n\n/** Services required before mounting (provided by the client runtime). */\nexport const inject = ['slots', 'sessions', 'workspaces', 'locale']\n\n/** Client plugin body. */\nexport function apply(ctx: ClientContext): void {\n setClient(ctx)\n // Selecting a session while the board is open must return to the Conversation.\n bindSessionNavigation(ctx)\n\n // Live translate bound to the active locale (labels re-read it per call).\n const t = ctx.locale.bind(LOCALE_NS)\n ctx.effect(() => {\n const off = ctx.locale.register(LOCALE_NS, { zh, en })\n return () => off()\n }, 'task-kanban: dictionaries')\n\n // The board is a GLOBAL MAIN PANEL: the shell renders one `main` entry per\n // selected panel id, so keying it (instead of replacing `main.conversation`)\n // keeps the Conversation mounted and selectable beside the board, and the\n // sidebar's own panel row owns the button that selects it (the\n // `sidebar.panellist` entry below). Nothing of this plugin sits in the\n // sidebar foot any more, so the Settings trigger can never be squeezed.\n ctx.slots.inject('main', () =>\n ctx.slots.register({\n name: 'main',\n key: KANBAN_PANEL_ID,\n locale: LOCALE_NS,\n } as never, BoardRoot as never),\n )\n\n // Sidebar panel row: the shell renders the row (label, tooltip, active state)\n // and calls `layout.selectPanel(id)` on click; the entry supplies the glyph.\n ctx.slots.inject('sidebar.panellist', () =>\n ctx.slots.register({\n name: 'sidebar.panellist',\n id: KANBAN_PANEL_ID,\n order: 20,\n label: () => t('kanban'),\n locale: LOCALE_NS,\n }, KanbanPanelIcon as never),\n )\n\n // The plugin's own settings page (设置 -> 侧栏「任务看板」) rides the\n // task-kanban settings namespace and registers into the settings.section\n // list slot, which gives it one entry in the settings sidebar and renders\n // its content into the panel's content column.\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register({\n name: 'settings.section',\n id: SETTINGS_SECTION_ID,\n order: 200,\n label: () => t('settingsTitle'),\n locale: LOCALE_NS,\n }, KanbanSettingsSection as never),\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["useState","useCallback","useMemo","useRef","primitives","useState","useCallback","useRef"],"sources":["../../../src/shared/lanes.ts","../../../src/client/api.ts","../../../src/client/kanban-state.ts","../../../src/client/locales.ts","../../../src/client/board.tsx","../../../src/client/icons.tsx","../../../src/client/sections.tsx","../../../src/client/index.tsx"],"sourcesContent":["/**\n * Lane mapping and drag rules (shared by the board UI and tests).\n */\nimport type { KanbanCard, Lane } from './card.js'\n\n/** Which lane a card renders in, based on status + error stage. */\nexport function laneOf(card: KanbanCard): Lane {\n if (card.status === 'error') {\n if (card.error?.stage !== undefined) return card.error.stage\n const kind = card.error?.kind\n if (kind === 'phase_failed' || kind === 'no_base_branch' || kind === 'worktree_failed') return 'running'\n if (kind === 'merge_failed') return 'completed'\n return 'demand'\n }\n switch (card.status) {\n case 'draft':\n case 'refining':\n case 'planned':\n return 'demand'\n case 'queued':\n return 'queue'\n case 'running':\n return 'running'\n case 'completed':\n case 'merging':\n return 'completed'\n case 'merged':\n return 'merged'\n }\n}\n\n/** Lanes a drop onto `to` may come from. */\nexport const DROP_RULES: Record<Lane, Lane[]> = {\n demand: ['queue'],\n queue: ['demand', 'running'],\n running: [],\n completed: [],\n merged: [],\n}\n\nexport function canDrop(from: Lane, to: Lane): boolean {\n return DROP_RULES[to].includes(from)\n}\n","import type { KanbanCard, KanbanSettingsShape, Lane, ModelOption } from '../shared/card'\n\nexport class KanbanApiError extends Error {\n constructor(readonly code: string, message: string) {\n super(message)\n }\n}\n\nasync function call<T>(method: string, payload: Record<string, unknown> = {}): Promise<T> {\n let response: Response\n try {\n response = await fetch(`/plugins/@fonlan/dsh-task-kanban/api/${method}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n })\n } catch (error) {\n throw new KanbanApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed: { ok?: boolean; value?: unknown; error?: { code?: string; message?: string } } | null\n = await response.json().catch(() => null)\n if (!response.ok || parsed === null || parsed.ok !== true || parsed.value === undefined) {\n throw new KanbanApiError(\n parsed?.error?.code ?? 'http',\n parsed?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.value as T\n}\n\n/** One row of the host `skills/list` catalog (same shape DSH's chat autocomplete uses). */\nexport interface SkillOption {\n name: string\n description: string\n whenToUse?: string\n modelInvocable: boolean\n}\n\n/**\n * Call the host gateway's `skills/list` unary RPC over the same-origin HTTP\n * bridge (the exact wire shape DSH's chat input uses for its /-autocomplete).\n *\n * DSH ≥0.1.5 addresses Remote endpoints as the canonical `<namespace>/<method>`\n * pair — `/api/skills/list` with the method `skills/list` — and carries named\n * wire arguments inside a single `args` field, so the request body is\n * `{ args: { request: { sessionId } } }` (the descriptor's parameter wire name\n * is `request`). The older dotted `skill.list` endpoint no longer exists and\n * answers HTTP 404.\n *\n * The requested `sessionId` scopes the catalog to that session's agent\n * preset, which is where the filesystem skill roots are registered.\n */\nexport async function gatewaySkillList(sessionId: string): Promise<SkillOption[]> {\n let response: Response\n try {\n response = await fetch('/api/skills/list', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n type: 'client-request',\n rpcId: `task-kanban-${Math.random().toString(36).slice(2)}`,\n method: 'skills/list',\n payload: { args: { request: { sessionId } } },\n }),\n })\n } catch (error) {\n throw new KanbanApiError('network', error instanceof Error ? error.message : String(error))\n }\n const parsed: { type?: string; result?: { ok?: boolean; value?: { skills?: SkillOption[] }; error?: { code?: string; message?: string } } } | null\n = await response.json().catch(() => null)\n if (!response.ok || parsed === null || parsed.type !== 'server-response' || parsed.result?.ok !== true) {\n throw new KanbanApiError(\n parsed?.result?.error?.code ?? 'http',\n parsed?.result?.error?.message ?? `HTTP ${response.status}`,\n )\n }\n return parsed.result.value?.skills ?? []\n}\n\n/** One row of the host `agentPresets.list()` roster. */\nexport interface PresetOption {\n id: string\n name?: string\n description?: string\n}\n\n/** Reasoning efforts of one provider/model route (`reasoning.options`). */\nexport interface ReasoningOptions {\n efforts: Array<{ id: string; name: string; description?: string }>\n defaultEffort?: string\n /** Client-side marker: the fetch failed; the stored effort must be kept. */\n failed?: boolean\n}\n\nexport const api = {\n list: (workspacePath: string) => call<KanbanCard[]>('list', { workspacePath }),\n create: (workspacePath: string, requirement: string, model: string, provider?: string, skill?: string) =>\n call<KanbanCard>('create', { workspacePath, requirement, model, provider, ...(skill !== undefined && skill !== '' ? { skill } : {}) }),\n move: (cardId: string, toLane: Lane) => call<{ ok: boolean; message?: string }>('move', { cardId, toLane }),\n stop: (cardId: string) => call<{ ok: boolean; message?: string }>('stop', { cardId }),\n retry: (cardId: string) => call<{ ok: boolean; message?: string }>('retry', { cardId }),\n remove: (cardId: string) => call<{ ok: boolean; message?: string }>('remove', { cardId }),\n settingsGet: () => call<KanbanSettingsShape>('settings.get'),\n settingsSet: (patch: Partial<KanbanSettingsShape>) => call<KanbanSettingsShape>('settings.set', patch),\n models: () => call<ModelOption[]>('models.list'),\n presets: () => call<PresetOption[]>('presets.list'),\n reasoningOptions: (provider: string, model: string) =>\n call<ReasoningOptions>('reasoning.options', { provider, model }),\n}\n","import type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\n\n/**\n * Panel id shared by this plugin's main-panel key (`main`) and its sidebar\n * entry (`sidebar.panellist`): the shell selects the panel by this id, so the\n * two registrations must agree.\n */\nexport const KANBAN_PANEL_ID = 'task-kanban'\n\n/**\n * Structural view of the client shell's panel-navigation face (`ctx.layout`).\n * Declared locally (no value import) so the plugin keeps working on a runtime\n * whose layout types differ.\n */\ninterface LayoutLike {\n selectPanel(panelId: string | null): void\n}\n\n/**\n * Structural view of the client shell's workspace-navigation face\n * (`ctx.uiWorkspace`, dsh-client-ui-workspace). Declared locally (no value\n * import) so the plugin keeps working on a runtime whose workspace types differ.\n */\ninterface UiWorkspaceLike {\n /** Select a Session (id, or a direct-parent subagent address) and show it. */\n openSession(target: string): void\n}\n\n/**\n * HMR-safe owner context, keyed on the global symbol registry.\n *\n * The client-hmr hot swap re-evaluates this module (a fresh `lib/client.js`\n * bundle) WITHOUT reloading the page; a module-level cell would then be\n * duplicated per evaluation and an old copy's helper would read a stale owner.\n * `Symbol.for` makes every bundle copy share one cell.\n */\nconst STATE_KEY = Symbol.for('@fonlan/dsh-task-kanban/state')\n\ninterface KanbanState {\n client: ClientContext | null\n}\n\nfunction getState(): KanbanState {\n const g = globalThis as unknown as Record<symbol, KanbanState | undefined>\n let state = g[STATE_KEY]\n if (state === undefined) {\n state = { client: null }\n g[STATE_KEY] = state\n }\n return state\n}\n\nexport function setClient(ctx: ClientContext | null): void {\n getState().client = ctx\n}\nexport function getClient(): ClientContext | null {\n return getState().client\n}\n\n/** The shell's panel face, when this runtime provides it. */\nfunction layoutOf(ctx: ClientContext | null): LayoutLike | null {\n if (ctx === null) return null\n try {\n const layout = (ctx as unknown as { layout?: LayoutLike }).layout\n return typeof layout?.selectPanel === 'function' ? layout : null\n } catch {\n return null\n }\n}\n\n/** Select the kanban panel. The sidebar's own entry does this; kept for in-app callers. */\nexport function showKanbanPanel(ctx: ClientContext | null = getClient()): void {\n try {\n layoutOf(ctx)?.selectPanel(KANBAN_PANEL_ID)\n } catch (error) {\n console.error('[@fonlan/dsh-task-kanban] cannot select the kanban panel:', error)\n }\n}\n\n/** Hand the center column back to the Conversation. */\nexport function leaveKanbanPanel(ctx: ClientContext | null = getClient()): void {\n try {\n layoutOf(ctx)?.selectPanel(null)\n } catch (error) {\n console.error('[@fonlan/dsh-task-kanban] cannot leave the kanban panel:', error)\n }\n}\n\n/**\n * Open one session — or a durable direct-parent subagent address — in the\n * center column, leaving the kanban panel.\n *\n * Navigation is a view-owner concern, not a session-controller one: `ctx.sessions`\n * (`ISessions`) exposes retention (`retain`/`using`/`retainInfo`), creation,\n * fork, search and catalog reads, and has no `open`/`openSubagent` at all\n * (\"navigation belongs to view owners\"). The view owner the shell itself uses is\n * `ctx.uiWorkspace.openSession(target)` (dsh-client-ui-workspace): it retains the\n * session AND reveals the Conversation panel as ONE navigation action. Routing\n * every open through it therefore replaces the old wrapper around\n * `sessions.open`/`openSubagent`, which existed only to hand the center column\n * back when a sidebar click selected a session while the board was showing.\n *\n * @param target - session id (or subagent address) to show.\n * @returns whether the runtime provided the navigation face; `false` means the\n * session could not be shown (a client without ui-workspace).\n */\nexport function openSessionView(target: string, ctx: ClientContext | null = getClient()): boolean {\n if (ctx === null) return false\n let uiWorkspace: UiWorkspaceLike | undefined\n try {\n uiWorkspace = (ctx as unknown as { uiWorkspace?: UiWorkspaceLike }).uiWorkspace\n } catch {\n return false\n }\n if (typeof uiWorkspace?.openSession !== 'function') return false\n try {\n uiWorkspace.openSession(target)\n return true\n } catch (error) {\n console.error('[@fonlan/dsh-task-kanban] cannot open the session view:', error)\n return false\n }\n}\n","// Locale namespace = the plugin's cordis id (kebab). DSH flat namespace keys\n// (settings + locale) use the internal id `task-kanban`; the scoped npm package\n// name is reserved for package-bound identifiers (exported `name`, module-loader\n// id, the /plugins/<pkg>/… route base).\nexport const LOCALE_NS = 'task-kanban'\n\nexport const zh = {\n kanban: '任务看板',\n openBoard: '打开任务看板',\n closeBoard: '返回对话',\n newTask: '新建任务',\n requirement: '需求',\n project: '所属项目',\n model: '模型',\n cancel: '取消',\n close: '关闭',\n addAndRefine: '添加并细化',\n laneDemand: '需求',\n laneQueue: '队列',\n laneRunning: '运行中',\n laneCompleted: '已完成',\n laneMerged: '已合并',\n statusDraft: '未细化',\n statusRefining: '细化中',\n statusPlanned: '已规划',\n statusQueued: '排队中',\n statusRunning: '实现中',\n statusCompleted: '已完成',\n statusMerging: '合并中',\n statusMerged: '已合并',\n statusError: '出错',\n phaseProgress: '{current}/{total}',\n retry: '重试',\n stop: '停止',\n delete: '删除',\n deleteConfirm: '确定删除该任务?其 worktree 会被清理。',\n openSession: '打开会话',\n plan: '实现方案',\n summary: '摘要',\n phases: '阶段',\n phaseGoal: '目标',\n phaseSessions: '会话',\n phaseConclusion: '结论',\n phaseNum: 'phase {n}',\n error: '错误',\n requirementLabel: '需求文本',\n requirementPlaceholder: '描述你要实现的需求……',\n skillGestureHint: '开头输入 /skill-name 可指定细化时使用的 Skill(如 /grill-me)',\n skillHint: '细化时将使用 Skill「{skill}」,并可与该会话交流打磨需求',\n skillMenuUserOnly: '仅用户可调',\n skillBadge: '细化 Skill:/{skill}',\n modelPlaceholder: '(使用默认模型)',\n noWorkspace: '没有可用工作区,请先在侧边栏添加',\n refresh: '刷新',\n settingsTitle: '任务看板',\n sectionSub: '全局并行 worker 数与各会话类型的默认模型、推理强度、Agent 预设',\n maxParallelWorkers: '全局并行 worker 数',\n settingsRefineGroup: '细化需求会话默认',\n settingsPhaseGroup: 'Phase 实现会话默认',\n reasoningEffort: '推理强度',\n agentPreset: 'Agent 预设',\n defaultOption: '(默认)',\n saved: '已保存',\n loadError: '加载任务失败',\n noPlan: '该卡片还没有实现计划,请先点击\"添加并细化\"',\n dragNoPlan: '还没有实现计划的卡片不能进入队列',\n actionFailed: '操作失败:{message}',\n sessionNotListed: '该会话不在当前列表,可能来自其他工作区',\n interrupted: '已中断',\n noBaseBranch: '项目没有 main/master 分支',\n worktreeFailed: 'worktree 创建失败',\n refineFailed: '细化失败',\n phaseFailed: '阶段执行失败',\n mergeFailed: '合并失败',\n createFailed: '创建失败',\n refinementLabel: '需求细化',\n mergeLabel: '合并',\n commitLabel: '提交',\n}\n\nexport const en = {\n kanban: 'Task Kanban',\n openBoard: 'Open Task Kanban',\n closeBoard: 'Back to chat',\n newTask: 'New Task',\n requirement: 'Requirement',\n project: 'Project',\n model: 'Model',\n cancel: 'Cancel',\n close: 'Close',\n addAndRefine: 'Add & Refine',\n laneDemand: 'Demands',\n laneQueue: 'Queue',\n laneRunning: 'Running',\n laneCompleted: 'Completed',\n laneMerged: 'Merged',\n statusDraft: 'Unrefined',\n statusRefining: 'Refining',\n statusPlanned: 'Planned',\n statusQueued: 'Queued',\n statusRunning: 'Running',\n statusCompleted: 'Completed',\n statusMerging: 'Merging',\n statusMerged: 'Merged',\n statusError: 'Error',\n phaseProgress: '{current}/{total}',\n retry: 'Retry',\n stop: 'Stop',\n delete: 'Delete',\n deleteConfirm: 'Delete this task? Its worktree will be cleaned up.',\n openSession: 'Open session',\n plan: 'Plan',\n summary: 'Summary',\n phases: 'Phases',\n phaseGoal: 'Goal',\n phaseSessions: 'Sessions',\n phaseConclusion: 'Conclusion',\n phaseNum: 'Phase {n}',\n error: 'Error',\n requirementLabel: 'Requirement',\n requirementPlaceholder: 'Describe what you want to build…',\n skillGestureHint: 'Start with /skill-name to choose the refinement skill (e.g. /grill-me)',\n skillHint: 'Refinement will use Skill “{skill}” — talk to this session to refine the requirement',\n skillMenuUserOnly: 'User-only',\n skillBadge: 'Refine skill: /{skill}',\n modelPlaceholder: '(use default model)',\n noWorkspace: 'No workspaces available — add one in the sidebar first',\n refresh: 'Refresh',\n settingsTitle: 'Task Kanban',\n sectionSub: 'Global parallel workers and per-session-type defaults for model, reasoning effort, and agent preset',\n maxParallelWorkers: 'Global parallel workers',\n settingsRefineGroup: 'Refinement session defaults',\n settingsPhaseGroup: 'Phase implementation defaults',\n reasoningEffort: 'Reasoning effort',\n agentPreset: 'Agent preset',\n defaultOption: '(default)',\n saved: 'Saved',\n loadError: 'Failed to load tasks',\n noPlan: 'This card has no plan yet — click \"Add & Refine\" first',\n dragNoPlan: 'Cards without a plan cannot enter the queue',\n actionFailed: 'Action failed: {message}',\n sessionNotListed: 'Session is not listed here; it may belong to another workspace',\n interrupted: 'Interrupted',\n noBaseBranch: 'Project has no main/master branch',\n worktreeFailed: 'Worktree creation failed',\n refineFailed: 'Refinement failed',\n phaseFailed: 'Phase failed',\n mergeFailed: 'Merge failed',\n createFailed: 'Creation failed',\n refinementLabel: 'Refinement',\n mergeLabel: 'Merge',\n commitLabel: 'Commit',\n}","import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type { KanbanCard, Lane, PhaseAttempt, PlanPhase } from '../shared/card'\nimport { DROP_RULES, laneOf } from '../shared/lanes'\nimport { api, gatewaySkillList, type SkillOption } from './api'\nimport { openSessionView } from './kanban-state'\nimport { en, zh } from './locales'\nimport './board.css'\n\ninterface BoardProps {\n t?: (key: string, params?: Record<string, unknown>) => string\n useWorkspaces?: (selector: (state: unknown) => unknown) => unknown\n useSessions?: (selector: (state: unknown) => unknown) => unknown\n}\n\n/** Session-list snapshot shape the standard `useSessions` feed carries. */\ninterface SessionListStateLike {\n current?: string\n /** Listed session ids (the feed's own order). */\n ids?: string[]\n}\n\nfunction firstLine(text: string): string {\n return text.split('\\n').find((l) => l.trim() !== '')?.trim() ?? ''\n}\n\n/** The leading `/skill-name` gesture at the start of the requirement input. */\nconst SKILL_GESTURE = /^\\s*\\/([a-z0-9]+(?:-[a-z0-9]+)*)(?=\\s|$)/\n\n/** Extract a leading `/skill-name` token plus the cleaned remainder. */\nfunction parseSkillGesture(raw: string): { skill?: string; requirement: string } {\n const m = SKILL_GESTURE.exec(raw)\n if (m === null) return { requirement: raw.trim() }\n return { skill: m[1], requirement: raw.slice(m[0].length).trim() }\n}\n\nfunction statusLabel(card: KanbanCard, t: (key: string) => string): string {\n if (card.status === 'error') {\n switch (card.error?.kind) {\n case 'interrupted': return t('interrupted')\n case 'no_base_branch': return t('noBaseBranch')\n case 'worktree_failed': return t('worktreeFailed')\n case 'refine_failed': return t('refineFailed')\n case 'phase_failed': return t('phaseFailed')\n case 'merge_failed': return t('mergeFailed')\n default: return t('createFailed')\n }\n }\n switch (card.status) {\n case 'draft': return t('statusDraft')\n case 'refining': return t('statusRefining')\n case 'planned': return t('statusPlanned')\n case 'queued': return t('statusQueued')\n case 'running': return t('statusRunning')\n case 'completed': return t('statusCompleted')\n case 'merging': return t('statusMerging')\n case 'merged': return t('statusMerged')\n }\n}\n\ninterface WorkspaceRow {\n workspaceId: string\n path: string\n title: string\n}\n\nconst LANE_ORDER: Array<{ key: Lane; labelKey: string }> = [\n { key: 'demand', labelKey: 'laneDemand' },\n { key: 'queue', labelKey: 'laneQueue' },\n { key: 'running', labelKey: 'laneRunning' },\n { key: 'completed', labelKey: 'laneCompleted' },\n { key: 'merged', labelKey: 'laneMerged' },\n]\n\nconst WS_STORAGE_KEY = '@fonlan/dsh-task-kanban:workspace'\n\nexport function BoardRoot(props: BoardProps): JSX.Element {\n const t = props.t ?? ((key: string, params?: Record<string, unknown>) => {\n const dict = (zh as Record<string, string>)[key] ?? (en as Record<string, string>)[key]\n if (dict === undefined || params === undefined) return dict ?? key\n return dict.replace(/\\{(\\w+)\\}/g, (m, name: string) => (params[name] as string) ?? m)\n })\n const useWorkspaces = props.useWorkspaces\n const wsState = useWorkspaces !== undefined ? (useWorkspaces((s: unknown) => s) as { items?: WorkspaceRow[] } | undefined) : undefined\n const items: WorkspaceRow[] = wsState?.items ?? []\n const useSessions = props.useSessions\n const sessionState = useSessions !== undefined ? (useSessions((s: unknown) => s) as SessionListStateLike | undefined) : undefined\n // The skill catalog is addressed by session (`skills/list`), so the /-menu\n // needs one. With no selection (fresh browser, board opened straight from the\n // footer) fall back to the most recent listed session: any session resolves a\n // preset scope, whereas no session silently leaves the menu empty.\n const currentSessionId = sessionState?.current ?? sessionState?.ids?.[0]\n\n const [selectedPath, setSelectedPath] = useState<string>(() => {\n try {\n return localStorage.getItem(WS_STORAGE_KEY) ?? ''\n } catch {\n return ''\n }\n })\n const [cards, setCards] = useState<KanbanCard[]>([])\n const [toast, setToast] = useState<string | null>(null)\n const [detailId, setDetailId] = useState<string | null>(null)\n const [newTaskOpen, setNewTaskOpen] = useState(false)\n\n useEffect(() => {\n if (selectedPath === '' && items.length > 0) {\n setSelectedPath(items[0].path)\n }\n }, [selectedPath, items])\n\n const showToast = useCallback((message: string) => {\n setToast(message)\n window.setTimeout(() => setToast(null), 3500)\n }, [])\n\n const refresh = useCallback(async () => {\n if (selectedPath === '') return\n try {\n setCards(await api.list(selectedPath))\n } catch (error) {\n showToast(error instanceof Error ? error.message : String(error))\n }\n }, [selectedPath, showToast])\n\n useEffect(() => {\n void refresh()\n const timer = window.setInterval(() => { void refresh() }, 2500)\n return () => window.clearInterval(timer)\n }, [refresh])\n\n const byLane = useMemo(() => {\n const map: Record<Lane, KanbanCard[]> = { demand: [], queue: [], running: [], completed: [], merged: [] }\n for (const card of cards) map[laneOf(card)].push(card)\n for (const lane of LANE_ORDER) map[lane.key].sort((a, b) => a.createdAt - b.createdAt)\n return map\n }, [cards])\n\n const handleDrop = useCallback(async (target: Lane, event: React.DragEvent) => {\n event.preventDefault()\n const cardId = event.dataTransfer.getData('text/plain')\n if (cardId === '') return\n const card = cards.find((c) => c.id === cardId)\n if (card === undefined) return\n if (target === 'queue' && card.status !== 'running' && card.plan === undefined) {\n showToast(t('dragNoPlan'))\n return\n }\n try {\n const result = await api.move(cardId, target)\n if (!result.ok) {\n showToast(t('actionFailed', { message: result.message ?? '' }))\n }\n void refresh()\n } catch (error) {\n showToast(error instanceof Error ? error.message : String(error))\n }\n }, [cards, refresh, showToast, t])\n\n const openSession = useCallback((sessionId: string) => {\n // The shell's view owner retains the session and reveals the Conversation\n // in one action, so the board itself needs no panel teardown; a runtime\n // without that face cannot show the session at all.\n if (!openSessionView(sessionId)) showToast(t('sessionNotListed'))\n }, [showToast, t])\n\n if (items.length === 0) {\n return (\n <div className=\"kb-board kb-empty\">\n <div className=\"kb-empty-text\">{t('noWorkspace')}</div>\n </div>\n )\n }\n\n return (\n <div className=\"kb-board\">\n <div className=\"kb-board-header\">\n <div className=\"kb-board-title\">\n <select\n className=\"kb-ws-select\"\n value={selectedPath}\n onChange={(e) => {\n setSelectedPath(e.target.value)\n try {\n localStorage.setItem(WS_STORAGE_KEY, e.target.value)\n } catch {\n // storage unavailable\n }\n }}\n >\n {items.map((w) => (\n <option key={w.workspaceId} value={w.path}>{w.title}</option>\n ))}\n </select>\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" onClick={() => setNewTaskOpen(true)}>{t('newTask')}</button>\n </div>\n </div>\n\n <div className=\"kb-lanes\">\n {LANE_ORDER.map((lane) => (\n <div\n key={lane.key}\n className={'kb-lane' + (DROP_RULES[lane.key].length > 0 ? ' kb-lane-drop' : '')}\n onDragOver={(e) => {\n if (DROP_RULES[lane.key].length > 0) e.preventDefault()\n }}\n onDrop={(e) => { void handleDrop(lane.key, e) }}\n >\n <div className=\"kb-lane-head\">\n <span className=\"kb-lane-title\">{t(lane.labelKey)}</span>\n <span className=\"kb-lane-count\">{byLane[lane.key].length}</span>\n </div>\n <div className=\"kb-lane-body\">\n {byLane[lane.key].map((card) => (\n <CardView\n key={card.id}\n card={card}\n t={t}\n onToggle={() => setDetailId(detailId === card.id ? null : card.id)}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n\n {toast !== null && <div className=\"kb-toast\">{toast}</div>}\n\n {newTaskOpen && (\n <NewTaskModal\n t={t}\n workspaces={items}\n selectedPath={selectedPath}\n sessionId={currentSessionId}\n onClose={() => setNewTaskOpen(false)}\n onCreated={() => {\n setNewTaskOpen(false)\n void refresh()\n }}\n onError={(message) => showToast(message)}\n />\n )}\n\n {detailId !== null && (\n <DetailPanel\n card={cards.find((c) => c.id === detailId) ?? null}\n t={t}\n onClose={() => setDetailId(null)}\n onChanged={() => {\n setDetailId(null)\n void refresh()\n }}\n onToast={showToast}\n onOpenSession={openSession}\n />\n )}\n </div>\n )\n}\n\ninterface CardViewProps {\n card: KanbanCard\n t: (key: string, params?: Record<string, unknown>) => string\n onToggle: () => void\n}\n\nfunction CardView({ card, t, onToggle }: CardViewProps): JSX.Element {\n const draggable = card.status === 'planned' || card.status === 'queued' || card.status === 'running'\n const title = card.plan !== undefined && card.plan.title !== '' ? card.plan.title : firstLine(card.requirement)\n const badge = statusLabel(card, t)\n const phaseInfo = card.status === 'running' || card.status === 'error'\n ? card.currentPhase < card.phaseCount ? t('phaseProgress', { current: card.currentPhase + 1, total: card.phaseCount }) : ''\n : ''\n return (\n <div\n className={'kb-card' + (card.status === 'error' ? ' kb-card-error' : '') + (card.status === 'running' ? ' kb-card-running' : '')}\n draggable={draggable}\n onDragStart={(e) => {\n e.dataTransfer.setData('text/plain', card.id)\n e.dataTransfer.effectAllowed = 'move'\n }}\n onClick={onToggle}\n >\n <div className=\"kb-card-title\">{title}</div>\n <div className=\"kb-card-meta\">\n <span className=\"kb-card-badge\">{badge}</span>\n {phaseInfo !== '' && <span className=\"kb-card-phase\">{phaseInfo}</span>}\n {card.skill !== undefined && card.skill !== '' && <span className=\"kb-card-skill\">/ {card.skill}</span>}\n {card.model !== '' && <span className=\"kb-card-model\">{card.model}</span>}\n </div>\n {card.status === 'error' && card.error !== undefined && (\n <div className=\"kb-card-error-text\">{card.error.message}</div>\n )}\n {card.status === 'running' && card.gitMode === true && (\n <div className=\"kb-card-worktree\">{card.worktreePath ?? ''}</div>\n )}\n </div>\n )\n}\n\ninterface NewTaskModalProps {\n t: (key: string, params?: Record<string, unknown>) => string\n workspaces: WorkspaceRow[]\n selectedPath: string\n /** Current session id, scoping the host skill.list catalog lookup. */\n sessionId?: string\n onClose: () => void\n onCreated: () => void\n onError: (message: string) => void\n}\n\n/** An in-progress leading `/query` token (menu-open state). */\nconst SKILL_MENU_RE = /^\\s*\\/([a-z0-9-]*)$/\n\nfunction NewTaskModal({ t, workspaces, selectedPath, sessionId, onClose, onCreated, onError }: NewTaskModalProps): JSX.Element {\n const [requirement, setRequirement] = useState('')\n const [project, setProject] = useState(selectedPath)\n const [model, setModel] = useState('')\n const [modelProvider, setModelProvider] = useState('')\n const [models, setModels] = useState<Array<{ provider: string; id: string; name?: string }>>([])\n const [skills, setSkills] = useState<SkillOption[]>([])\n const [menuQuery, setMenuQuery] = useState<string | null>(null)\n const [menuIndex, setMenuIndex] = useState(0)\n const [busy, setBusy] = useState(false)\n const textareaRef = useRef<HTMLTextAreaElement | null>(null)\n\n useEffect(() => {\n let alive = true\n api.models()\n .then((list) => { if (alive) setModels(list) })\n .catch(() => { if (alive) setModels([]) })\n return () => { alive = false }\n }, [])\n\n // Load the host skill catalog once (scoped to the current session), the\n // same feed DSH's chat input uses for its /-autocomplete.\n useEffect(() => {\n if (sessionId === undefined) return\n let alive = true\n gatewaySkillList(sessionId)\n .then((list) => { if (alive) setSkills(list) })\n .catch(() => { if (alive) setSkills([]) })\n return () => { alive = false }\n }, [sessionId])\n\n const matches = skills.filter((s) => s.name.startsWith(menuQuery ?? ''))\n const menuVisible = menuQuery !== null && matches.length > 0\n const selected = menuVisible ? matches[Math.min(menuIndex, matches.length - 1)] : undefined\n\n /** Re-evaluate the leading-token menu state from the current value + caret. */\n const syncMenu = (value: string, caret: number): void => {\n const head = value.slice(0, caret)\n const m = SKILL_MENU_RE.exec(head)\n if (m !== null) {\n setMenuQuery(m[1])\n setMenuIndex(0)\n return\n }\n setMenuQuery(null)\n }\n\n const selectSkill = (name: string): void => {\n const el = textareaRef.current\n const caret = el?.selectionStart ?? requirement.length\n const head = requirement.slice(0, caret)\n const m = SKILL_MENU_RE.exec(head)\n // Replace the leading `/query` token with `/name `.\n const inserted = `/${name} `\n const newValue = m !== null ? inserted + requirement.slice(caret) : inserted + requirement\n setRequirement(newValue)\n setMenuQuery(null)\n requestAnimationFrame(() => {\n const next = textareaRef.current\n if (next !== null) {\n next.focus()\n const pos = inserted.length\n next.setSelectionRange(pos, pos)\n }\n })\n }\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>): void => {\n if (!menuVisible) return\n if (e.key === 'ArrowDown') {\n e.preventDefault()\n setMenuIndex((i) => (i + 1) % matches.length)\n } else if (e.key === 'ArrowUp') {\n e.preventDefault()\n setMenuIndex((i) => (i - 1 + matches.length) % matches.length)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n if (selected !== undefined) selectSkill(selected.name)\n } else if (e.key === 'Escape') {\n e.preventDefault()\n setMenuQuery(null)\n } else if (e.key === 'Tab') {\n e.preventDefault()\n if (selected !== undefined) selectSkill(selected.name)\n }\n }\n\n const submit = async (): Promise<void> => {\n if (requirement.trim() === '') {\n onError(t('requirementLabel') + ' ' + t('error'))\n return\n }\n if (project === '') {\n onError(t('noWorkspace'))\n return\n }\n const parsed = parseSkillGesture(requirement)\n setBusy(true)\n try {\n await api.create(project, parsed.requirement, model, modelProvider, parsed.skill)\n onCreated()\n } catch (error) {\n onError(error instanceof Error ? error.message : String(error))\n setBusy(false)\n }\n }\n\n const activeSkill = parseSkillGesture(requirement).skill\n\n return (\n <div className=\"kb-modal-backdrop\" onClick={busy ? undefined : onClose}>\n <div className=\"kb-modal\" onClick={(e) => e.stopPropagation()}>\n <div className=\"kb-modal-title\">{t('newTask')}</div>\n <label className=\"kb-field\">\n <span>{t('requirementLabel')}</span>\n <div className=\"kb-skill-menu-wrap\">\n <textarea\n ref={textareaRef}\n className=\"kb-input kb-textarea\"\n value={requirement}\n placeholder={t('requirementPlaceholder')}\n onChange={(e) => {\n const value = e.target.value\n setRequirement(value)\n syncMenu(value, e.target.selectionStart ?? value.length)\n }}\n onKeyDown={onKeyDown}\n />\n {menuVisible && (\n <ul className=\"kb-skill-menu\" role=\"listbox\">\n {matches.map((s, i) => (\n <li\n key={s.name}\n role=\"option\"\n aria-selected={i === menuIndex}\n className={'kb-skill-menu-item' + (i === menuIndex ? ' kb-skill-menu-item-active' : '')}\n onMouseDown={(e) => { e.preventDefault(); selectSkill(s.name) }}\n onMouseEnter={() => setMenuIndex(i)}\n >\n <span className=\"kb-skill-menu-name\">/{s.name}</span>\n <span className=\"kb-skill-menu-desc\">\n {s.modelInvocable ? s.description : `${t('skillMenuUserOnly')} · ${s.description}`}\n </span>\n </li>\n ))}\n </ul>\n )}\n </div>\n {activeSkill !== undefined ? (\n <span className=\"kb-field-hint kb-field-hint-skill\">{t('skillHint', { skill: activeSkill })}</span>\n ) : (\n <span className=\"kb-field-hint\">{t('skillGestureHint')}</span>\n )}\n </label>\n <label className=\"kb-field\">\n <span>{t('project')}</span>\n <select className=\"kb-input\" value={project} onChange={(e) => setProject(e.target.value)}>\n {workspaces.map((w) => (\n <option key={w.workspaceId} value={w.path}>{w.title}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field\">\n <span>{t('model')}</span>\n <select\n className=\"kb-input\"\n value={model}\n onChange={(e) => {\n const id = e.target.value\n setModel(id)\n const found = models.find((m) => m.id === id)\n setModelProvider(found?.provider ?? '')\n }}\n >\n <option value=\"\">{t('modelPlaceholder')}</option>\n {models.map((m) => (\n <option key={m.provider + '/' + m.id} value={m.id}>{m.name ?? m.id}</option>\n ))}\n </select>\n </label>\n <div className=\"kb-modal-actions\">\n <button type=\"button\" className=\"kb-btn\" onClick={onClose} disabled={busy}>{t('cancel')}</button>\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" onClick={() => { void submit() }} disabled={busy}>\n {t('addAndRefine')}\n </button>\n </div>\n </div>\n </div>\n )\n}\n\ninterface DetailPanelProps {\n card: KanbanCard | null\n t: (key: string, params?: Record<string, unknown>) => string\n onClose: () => void\n onChanged: () => void\n onToast: (message: string) => void\n onOpenSession: (sessionId: string) => void\n}\n\nfunction DetailPanel({ card, t, onClose, onChanged, onToast, onOpenSession }: DetailPanelProps): JSX.Element | null {\n const [busy, setBusy] = useState(false)\n if (card === null) return null\n\n const act = async (fn: () => Promise<unknown>): Promise<void> => {\n setBusy(true)\n try {\n await fn()\n onChanged()\n } catch (error) {\n onToast(error instanceof Error ? error.message : String(error))\n setBusy(false)\n }\n }\n\n const remove = async (): Promise<void> => {\n if (!window.confirm(t('deleteConfirm'))) return\n await act(() => api.remove(card!.id))\n }\n\n return (\n <div className=\"kb-detail-panel\">\n <div className=\"kb-detail-panel-head\">\n <div className=\"kb-modal-title\">\n {card.plan !== undefined && card.plan.title !== '' ? card.plan.title : firstLine(card.requirement)}\n <span className={'kb-detail-status kb-status-' + card.status}>{statusLabel(card, t)}</span>\n </div>\n <button type=\"button\" className=\"kb-detail-close\" aria-label={t('close')} title={t('close')} onClick={onClose}>✕</button>\n </div>\n\n <div className=\"kb-detail-panel-body\">\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('requirement')}</div>\n {card.skill !== undefined && card.skill !== '' && (\n <div className=\"kb-detail-skill\">{t('skillBadge', { skill: card.skill })}</div>\n )}\n <div className=\"kb-detail-text\">{card.requirement}</div>\n </div>\n\n {card.plan !== undefined && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('plan')}</div>\n <div className=\"kb-detail-plan\">\n <div className=\"kb-plan-summary\">{card.plan.summary}</div>\n <ol className=\"kb-plan-phases\">\n {card.plan.phases.map((phase, i) => (\n <PhaseCard\n key={phase.id}\n phase={phase}\n phaseIndex={i}\n card={card}\n t={t}\n onOpenSession={onOpenSession}\n />\n ))}\n </ol>\n </div>\n </div>\n )}\n\n {card.sessions.refinement.length > 0 && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('refinementLabel')}</div>\n <div className=\"kb-session-links\">\n {card.sessions.refinement.map((sid) => (\n <button key={sid} type=\"button\" className=\"kb-btn kb-btn-small\" onClick={() => onOpenSession(sid)}>\n {t('openSession')} · {sid.slice(0, 13)}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {card.status === 'error' && card.error !== undefined && (\n <div className=\"kb-detail-section kb-detail-error\">\n <div className=\"kb-detail-label\">{t('error')}</div>\n <div className=\"kb-detail-text\">{card.error.message}</div>\n </div>\n )}\n\n {card.merge?.mergeCommit !== undefined && (\n <div className=\"kb-detail-section\">\n <div className=\"kb-detail-label\">{t('mergeLabel')}</div>\n <div className=\"kb-detail-text\">{t('commitLabel')} {card.merge.mergeCommit.slice(0, 12)}</div>\n </div>\n )}\n\n <div className=\"kb-modal-actions\">\n {card.status === 'error' && (\n <button type=\"button\" className=\"kb-btn kb-btn-primary\" disabled={busy} onClick={() => { void act(() => api.retry(card!.id)) }}>\n {t('retry')}\n </button>\n )}\n {(card.status === 'running' || card.status === 'merging') && (\n <button type=\"button\" className=\"kb-btn\" disabled={busy} onClick={() => { void act(() => api.stop(card!.id)) }}>\n {t('stop')}\n </button>\n )}\n {card.status !== 'running' && card.status !== 'refining' && card.status !== 'merging' && (\n <button type=\"button\" className=\"kb-btn kb-btn-danger\" disabled={busy} onClick={() => { void remove() }}>\n {t('delete')}\n </button>\n )}\n <button type=\"button\" className=\"kb-btn\" onClick={onClose}>{t('cancel')}</button>\n </div>\n </div>\n </div>\n )\n}\n\n/** One plan phase rendered as a card with goal / sessions / conclusion sections. */\nfunction PhaseCard({ phase, phaseIndex, card, t, onOpenSession }: {\n phase: PlanPhase\n phaseIndex: number\n card: KanbanCard\n t: (key: string, params?: Record<string, unknown>) => string\n onOpenSession: (sessionId: string) => void\n}): JSX.Element {\n const attempts = card.sessions.phases.filter((a) => a.phaseIndex === phaseIndex)\n const summaries = attempts\n .filter((a) => a.summary !== undefined && a.summary.trim() !== '')\n .map((a) => a.summary as string)\n const isCurrent = phaseIndex === card.currentPhase && card.status === 'running'\n // A phase with at least one concluded attempt counts as completed.\n const isCompleted = summaries.length > 0\n const cls = 'kb-plan-phase'\n + (isCurrent ? ' kb-plan-phase-current' : '')\n + (isCompleted ? ' kb-plan-phase-completed' : '')\n const planTitle = card.plan?.title ?? ''\n return (\n <li className={cls}>\n <div className=\"kb-plan-phase-head\">\n <span className=\"kb-plan-phase-title\">{phase.title}</span>\n <span className=\"kb-plan-phase-id\">{phase.id}</span>\n </div>\n <div className=\"kb-plan-phase-body\">\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseGoal')}</div>\n <div className=\"kb-plan-phase-goal\">{phase.goal}</div>\n </div>\n {attempts.length > 0 && (\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseSessions')}</div>\n <PhaseSessions attempts={attempts} planTitle={planTitle} phaseIndex={phaseIndex} t={t} onOpenSession={onOpenSession} />\n </div>\n )}\n {summaries.length > 0 && (\n <div className=\"kb-plan-phase-section\">\n <div className=\"kb-plan-phase-section-title\">{t('phaseConclusion')}</div>\n <div className=\"kb-plan-phase-conclusion\">\n {summaries.map((s, idx) => (\n <div key={idx} className=\"kb-plan-phase-conclusion-item\">{s}</div>\n ))}\n </div>\n </div>\n )}\n </div>\n </li>\n )\n}\n\n/**\n * Open-session buttons for one phase's attempts (retries append more). The\n * button labels the session with the deterministic \"{plan title} · phase N\"\n * format (the requested fallback when the host never auto-generated a title);\n * the full session id stays available as the native tooltip.\n */\nfunction PhaseSessions({ attempts, planTitle, phaseIndex, t, onOpenSession }: {\n attempts: PhaseAttempt[]\n planTitle: string\n phaseIndex: number\n t: (key: string, params?: Record<string, unknown>) => string\n onOpenSession: (sessionId: string) => void\n}): JSX.Element {\n return (\n <div className=\"kb-plan-phase-sessions\">\n {attempts.map((a) => (\n <button key={a.sessionId} type=\"button\" className=\"kb-btn kb-btn-small\" title={a.sessionId} onClick={() => onOpenSession(a.sessionId)}>\n {t('openSession')} · {planTitle !== '' ? `${planTitle} · ${t('phaseNum', { n: phaseIndex + 1 })}` : a.sessionId.slice(0, 13)}\n </button>\n ))}\n </div>\n )\n}","import * as primitives from '@deepseek-ai/dsh-client-ui-primitives'\n\n/** Props every shell icon accepts: square edge in px, color rides currentColor. */\nexport interface IconProps {\n size?: number\n className?: string\n}\n\n/** One shell icon component. */\nexport type IconComponent = (props: IconProps) => JSX.Element\n\n/** The runtime export table, read by capability instead of by one hard-coded name. */\nconst table = primitives as unknown as Record<string, IconComponent | undefined>\n\n/** First name the runtime actually provides (a missing export is `undefined`). */\nfunction firstDefined(...names: string[]): IconComponent | undefined {\n for (const name of names) {\n let candidate: IconComponent | undefined\n try {\n candidate = table[name]\n } catch {\n // Some module namespaces reject unknown names instead of yielding\n // `undefined`; a rename must never throw on its way to the fallback.\n continue\n }\n if (typeof candidate === 'function') return candidate\n }\n return undefined\n}\n\n/**\n * Self-contained 16×16 checklist glyph (the 0.1.7 artwork) used when the shell\n * primitives expose none of the names above: the footer entry must render\n * something even on a runtime whose icon exports we do not know.\n */\nfunction ChecklistFallback({ size = 14, className }: IconProps): JSX.Element {\n return (\n <svg\n width={size}\n height={size}\n className={className}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n strokeWidth={1}\n >\n <path d=\"M3.75 6.25C4.7165 6.25 5.5 5.4665 5.5 4.5C5.5 3.5335 4.7165 2.75 3.75 2.75C2.7835 2.75 2 3.5335 2 4.5C2 5.4665 2.7835 6.25 3.75 6.25Z\" stroke=\"currentColor\" />\n <path d=\"M7.5 4.5H13.5\" stroke=\"currentColor\" />\n <path d=\"M3.75 13.25C4.7165 13.25 5.5 12.4665 5.5 11.5C5.5 10.5335 4.7165 9.75 3.75 9.75C2.7835 9.75 2 10.5335 2 11.5C2 12.4665 2.7835 13.25 3.75 13.25Z\" stroke=\"currentColor\" />\n <path d=\"M7.5 11.5H13.5\" stroke=\"currentColor\" />\n </svg>\n )\n}\n\n/**\n * The checklist icon used by the sidebar panel row entry.\n *\n * DSH 0.1.7 renamed every size-suffixed shell icon (`IconChecklistOutline14`)\n * into stroke-weight variants (`…Regular` 1px / `…Medium` 1.3px) inside\n * `@deepseek-ai/dsh-client-ui-primitives`. A stale named import resolves to\n * `undefined` and React then throws \"Element type is invalid\" while rendering\n * the slot entry — the entry is dropped and the button silently disappears\n * (exactly what upgrading to 0.1.7 did to this plugin). Resolve the name at\n * runtime, newest first, so the next rename degrades to another shipped\n * variant instead of taking the button down with it.\n */\nexport const ChecklistIcon: IconComponent =\n firstDefined(\n 'IconChecklistOutlineRegular',\n 'IconChecklistOutlineMedium',\n 'IconChecklistOutline',\n 'IconChecklistOutline14',\n ) ?? ChecklistFallback\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport { ChecklistIcon } from './icons'\nimport { api, type PresetOption, type ReasoningOptions } from './api'\nimport type { KanbanSettingsShape, ModelOption } from '../shared/card'\n\n/**\n * Sidebar panel-row glyph for the board (`sidebar.panellist`).\n *\n * The shell owns the row: it renders the button, its label, tooltip and active\n * state, and calls `layout.selectPanel(id)` on click. The entry contributes\n * only the glyph, so this component must stay purely presentational.\n */\nexport function KanbanPanelIcon({ size }: { size: number }): JSX.Element {\n return <ChecklistIcon size={size} />\n}\n\ninterface SettingsSectionProps {\n t?: (key: string) => string\n}\n\n/** Fallback shape while settings load (server always resolves the full set). */\nconst EMPTY_SETTINGS: KanbanSettingsShape = {\n maxParallelWorkers: 1,\n refinementModel: '',\n refinementProvider: '',\n refinementReasoningEffort: '',\n refinementPreset: '',\n phaseModel: '',\n phaseProvider: '',\n phaseReasoningEffort: '',\n phasePreset: '',\n}\n\n/** The setting field names of one session-type group. */\nconst GROUP_FIELDS = {\n refinement: {\n model: 'refinementModel',\n provider: 'refinementProvider',\n effort: 'refinementReasoningEffort',\n preset: 'refinementPreset',\n },\n phase: {\n model: 'phaseModel',\n provider: 'phaseProvider',\n effort: 'phaseReasoningEffort',\n preset: 'phasePreset',\n },\n} as const\n\ntype SessionGroupKey = keyof typeof GROUP_FIELDS\n\ninterface SessionDefaultsGroupProps {\n kind: SessionGroupKey\n settings: KanbanSettingsShape\n models: ModelOption[]\n presets: PresetOption[]\n /** Reasoning efforts already fetched, keyed `provider/model`. */\n efforts: Record<string, ReasoningOptions>\n tr: (key: string) => string\n onCommit: (patch: Partial<KanbanSettingsShape>) => Promise<void>\n loadEfforts: (provider: string, model: string) => void\n}\n\n/** Model / reasoning effort / agent preset defaults for one session type. */\nfunction SessionDefaultsGroup({ kind, settings, models, presets, efforts, tr, onCommit, loadEfforts }: SessionDefaultsGroupProps): JSX.Element {\n const fields = GROUP_FIELDS[kind]\n const model = settings[fields.model]\n const provider = settings[fields.provider]\n const effort = settings[fields.effort]\n const preset = settings[fields.preset]\n const effortKey = model !== '' && provider !== '' ? `${provider}/${model}` : ''\n const effortOptions = effortKey !== '' ? (efforts[effortKey]?.efforts ?? []) : []\n\n const handleModel = (id: string): void => {\n const found = models.find((m) => m.id === id)\n const nextProvider = found?.provider ?? ''\n void onCommit({ [fields.model]: id, [fields.provider]: nextProvider } as Partial<KanbanSettingsShape>)\n if (id !== '' && nextProvider !== '') loadEfforts(nextProvider, id)\n }\n\n return (\n <div className=\"kb-settings-group\">\n <div className=\"kb-settings-group-title\">{tr(kind === 'refinement' ? 'settingsRefineGroup' : 'settingsPhaseGroup')}</div>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('model')}</span>\n <select className=\"kb-input\" value={model} onChange={(e) => handleModel(e.target.value)}>\n <option value=\"\">{tr('defaultOption')}</option>\n {models.map((m) => (\n <option key={m.provider + '/' + m.id} value={m.id}>{m.name ?? m.id}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('reasoningEffort')}</span>\n <select\n className=\"kb-input\"\n value={effort}\n disabled={model === ''}\n onChange={(e) => void onCommit({ [fields.effort]: e.target.value } as Partial<KanbanSettingsShape>)}\n >\n <option value=\"\">{tr('defaultOption')}</option>\n {effortOptions.map((o) => (\n <option key={o.id} value={o.id}>{o.name}</option>\n ))}\n </select>\n </label>\n <label className=\"kb-field kb-field-row\">\n <span>{tr('agentPreset')}</span>\n <select\n className=\"kb-input\"\n value={preset}\n onChange={(e) => void onCommit({ [fields.preset]: e.target.value } as Partial<KanbanSettingsShape>)}\n >\n <option value=\"\">{tr('defaultOption')}</option>\n {presets.map((p) => (\n <option key={p.id} value={p.id}>{p.name ?? p.id}</option>\n ))}\n </select>\n </label>\n </div>\n )\n}\n\n/** Plugin settings page (设置 -> 侧栏「任务看板」): workers + default model + per-session-type defaults. */\nexport function KanbanSettingsSection({ t }: SettingsSectionProps): JSX.Element {\n const tr = t ?? ((key: string) => key)\n const [settings, setSettings] = useState<KanbanSettingsShape>(EMPTY_SETTINGS)\n const [models, setModels] = useState<ModelOption[]>([])\n const [presets, setPresets] = useState<PresetOption[]>([])\n const [efforts, setEfforts] = useState<Record<string, ReasoningOptions>>({})\n const [saved, setSaved] = useState(false)\n\n const commit = useCallback(async (patch: Partial<KanbanSettingsShape>): Promise<void> => {\n try {\n const next = await api.settingsSet(patch)\n setSettings(next)\n setSaved(true)\n window.setTimeout(() => setSaved(false), 1500)\n } catch {\n // keep the previous value\n }\n }, [])\n\n // Refs so async callbacks (effort fetch) read the freshest settings/commit.\n const settingsRef = useRef(settings)\n settingsRef.current = settings\n const commitRef = useRef(commit)\n commitRef.current = commit\n\n useEffect(() => {\n let alive = true\n api.settingsGet()\n .then((s) => { if (alive) setSettings(s) })\n .catch(() => undefined)\n api.models()\n .then((list) => { if (alive) setModels(list) })\n .catch(() => undefined)\n api.presets()\n .then((list) => { if (alive) setPresets(list) })\n .catch(() => undefined)\n return () => { alive = false }\n }, [])\n\n /** Reasoning routes already requested (dedupe across mount + model changes). */\n const effortFetched = useRef<Set<string>>(new Set())\n\n /**\n * Fetch the reasoning efforts of one model route (once per route). A failed\n * fetch is marked `failed` so the stored effort is preserved (see the reset\n * effect below) instead of being wiped by a transient error.\n */\n const loadEfforts = useCallback((provider: string, model: string): void => {\n const key = `${provider}/${model}`\n if (effortFetched.current.has(key)) return\n effortFetched.current.add(key)\n api.reasoningOptions(provider, model)\n .then((opts) => setEfforts((prev) => ({ ...prev, [key]: opts })))\n .catch(() => setEfforts((prev) => ({ ...prev, [key]: { efforts: [], failed: true } })))\n }, [])\n\n // Fetch efforts for the models already configured in settings, so the\n // effort selects show their levels (and validate the stored effort) as soon\n // as settings load — the fetch previously ran only on model change.\n useEffect(() => {\n for (const kind of ['refinement', 'phase'] as const) {\n const fields = GROUP_FIELDS[kind]\n const model = settings[fields.model]\n const provider = settings[fields.provider]\n if (model !== '' && provider !== '') loadEfforts(provider, model)\n }\n }, [settings.refinementModel, settings.refinementProvider, settings.phaseModel, settings.phaseProvider, loadEfforts])\n\n // When the efforts of the selected model arrive, drop a stored effort the\n // model no longer offers (e.g. the user switched the model). A failed fetch\n // (`failed: true`) keeps the stored effort: the model may just be\n // temporarily unresolvable, and wiping the user's choice would be worse.\n useEffect(() => {\n const s = settingsRef.current\n for (const kind of ['refinement', 'phase'] as const) {\n const fields = GROUP_FIELDS[kind]\n const model = s[fields.model]\n const provider = s[fields.provider]\n const effort = s[fields.effort]\n if (effort === '' || model === '' || provider === '') continue\n const opts = efforts[`${provider}/${model}`]\n if (opts === undefined || opts.failed === true) continue\n if (!opts.efforts.some((o) => o.id === effort)) {\n void commitRef.current({ [fields.effort]: '' } as Partial<KanbanSettingsShape>)\n }\n }\n }, [efforts])\n\n return (\n <div className=\"kb-page\">\n <header className=\"kb-page-head\">\n <h3 className=\"kb-page-title\">{tr('settingsTitle')}</h3>\n <p className=\"kb-page-sub\">{tr('sectionSub')}</p>\n </header>\n <div className=\"kb-settings\">\n <label className=\"kb-field kb-field-row\">\n <span>{tr('maxParallelWorkers')}</span>\n <input\n className=\"kb-input kb-input-number\"\n type=\"number\"\n min={1}\n step={1}\n value={settings.maxParallelWorkers}\n onChange={(e) => {\n const value = Math.max(1, Math.floor(Number(e.target.value) || 1))\n setSettings((s) => ({ ...s, maxParallelWorkers: value }))\n void commit({ maxParallelWorkers: value })\n }}\n />\n </label>\n <SessionDefaultsGroup\n kind=\"refinement\"\n settings={settings}\n models={models}\n presets={presets}\n efforts={efforts}\n tr={tr}\n onCommit={commit}\n loadEfforts={loadEfforts}\n />\n <SessionDefaultsGroup\n kind=\"phase\"\n settings={settings}\n models={models}\n presets={presets}\n efforts={efforts}\n tr={tr}\n onCommit={commit}\n loadEfforts={loadEfforts}\n />\n {saved && <div className=\"kb-settings-saved\">{tr('saved')}</div>}\n </div>\n </div>\n )\n}","import type { Context } from '@deepseek-ai/cordis'\ntype ClientContext = Context\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { BoardRoot } from './board'\nimport { KanbanPanelIcon, KanbanSettingsSection } from './sections'\nimport { LOCALE_NS, zh, en } from './locales'\nimport { KANBAN_PANEL_ID, setClient } from './kanban-state'\n\n/** The settings sidebar entry this plugin's page owns (must stay stable). */\nconst SETTINGS_SECTION_ID = 'task-kanban'\n\n/** Services required before mounting (provided by the client runtime). */\nexport const inject = ['slots', 'sessions', 'workspaces', 'locale']\n\n/** Client plugin body. */\nexport function apply(ctx: ClientContext): void {\n setClient(ctx)\n // Session opening goes through the shell's own view owner\n // (`ctx.uiWorkspace.openSession`, see kanban-state.ts), which already returns\n // the center column to the Conversation — no wrapper to install here.\n\n // Live translate bound to the active locale (labels re-read it per call).\n const t = ctx.locale.bind(LOCALE_NS)\n ctx.effect(() => {\n const off = ctx.locale.register(LOCALE_NS, { zh, en })\n return () => off()\n }, 'task-kanban: dictionaries')\n\n // The board is a GLOBAL MAIN PANEL: the shell renders one `main` entry per\n // selected panel id, so keying it (instead of replacing `main.conversation`)\n // keeps the Conversation mounted and selectable beside the board, and the\n // sidebar's own panel row owns the button that selects it (the\n // `sidebar.panellist` entry below). Nothing of this plugin sits in the\n // sidebar foot any more, so the Settings trigger can never be squeezed.\n ctx.slots.inject('main', () =>\n ctx.slots.register({\n name: 'main',\n key: KANBAN_PANEL_ID,\n locale: LOCALE_NS,\n } as never, BoardRoot as never),\n )\n\n // Sidebar panel row: the shell renders the row (label, tooltip, active state)\n // and calls `layout.selectPanel(id)` on click; the entry supplies the glyph.\n ctx.slots.inject('sidebar.panellist', () =>\n ctx.slots.register({\n name: 'sidebar.panellist',\n id: KANBAN_PANEL_ID,\n order: 20,\n label: () => t('kanban'),\n locale: LOCALE_NS,\n }, KanbanPanelIcon as never),\n )\n\n // The plugin's own settings page (设置 -> 侧栏「任务看板」) rides the\n // task-kanban settings namespace and registers into the settings.section\n // list slot, which gives it one entry in the settings sidebar and renders\n // its content into the panel's content column.\n ctx.slots.inject('settings.section', () =>\n ctx.slots.register({\n name: 'settings.section',\n id: SETTINGS_SECTION_ID,\n order: 200,\n label: () => t('settingsTitle'),\n locale: LOCALE_NS,\n }, KanbanSettingsSection as never),\n )\n}\n"],"mappings":"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"}
package/lib/index.js CHANGED
@@ -10,6 +10,14 @@ import { isSkillName, isUserInvocable, renderSkillContent } from "@deepseek-ai/d
10
10
  import { defineTool } from "@deepseek-ai/dsh-tools";
11
11
  //#region src/server/settings.ts
12
12
  const KANBAN_SETTINGS_NS = "task-kanban";
13
+ /**
14
+ * The entry config schema. Deliberately UNANNOTATED: schemastery >= 3.18.3
15
+ * added a third `Mode` type parameter, so `.default().volatile()` fields have
16
+ * output type `Volatile<T>` and an explicit `z<KanbanSettingsShape>` no longer
17
+ * compiles (the schema's `meta.default` then carries `Volatile<number>`, which
18
+ * is not a `number`). The plain `KanbanSettingsShape` interface stays the
19
+ * plugin-facing shape: `registerSettings` unwraps the live cells below.
20
+ */
13
21
  const KanbanSettingsSchema = z.object({
14
22
  maxParallelWorkers: z.natural().min(1).default(1).volatile(),
15
23
  refinementModel: z.string().default("").volatile(),
@@ -668,7 +676,7 @@ var KanbanRunner = class {
668
676
  recovered = false;
669
677
  /** Agents that already got their scoped kanban tools (event idempotency). */
670
678
  toolScopedAgents = /* @__PURE__ */ new WeakSet();
671
- agentStartOff;
679
+ agentCreatedOff;
672
680
  constructor(ctx, store, settings) {
673
681
  this.ctx = ctx;
674
682
  this.store = store;
@@ -681,16 +689,16 @@ var KanbanRunner = class {
681
689
  this.pumpTimer = setInterval(() => {
682
690
  this.pump();
683
691
  }, 2500);
684
- this.agentStartOff = this.ctx.on("agent/session-start", (payload) => {
685
- this.onAgentSessionStart(payload.agent);
692
+ this.agentCreatedOff = this.ctx.on("agent/created", (payload) => {
693
+ this.onAgentCreated(payload.agent);
686
694
  });
687
695
  }
688
696
  stop() {
689
697
  if (this.pumpTimer !== void 0) clearInterval(this.pumpTimer);
690
698
  this.pumpTimer = void 0;
691
- if (this.agentStartOff !== void 0) {
692
- this.agentStartOff();
693
- this.agentStartOff = void 0;
699
+ if (this.agentCreatedOff !== void 0) {
700
+ this.agentCreatedOff();
701
+ this.agentCreatedOff = void 0;
694
702
  }
695
703
  }
696
704
  newSessionId() {
@@ -796,12 +804,13 @@ var KanbanRunner = class {
796
804
  }
797
805
  }
798
806
  /**
799
- * The single place kanban tools get registered. `agent/session-start` fires
800
- * for BOTH `agents.create` (startup) and `agents.resume` (host re-open after
801
- * a restart), so a resumed refinement/phase/merge session keeps its scoped
807
+ * The single place kanban tools get registered. Subscribed to
808
+ * `agent/created`, which fires for BOTH `agents.create` (startup) and
809
+ * `agents.resume` (host re-open after a restart) and carries the path in its
810
+ * `source`, so a resumed refinement/phase/merge session keeps its scoped
802
811
  * tools. Idempotent per agent object; non-kanban sessions are skipped.
803
812
  */
804
- async onAgentSessionStart(agent) {
813
+ async onAgentCreated(agent) {
805
814
  if (agent === void 0 || agent.id === void 0 || agent.ctx === void 0) return;
806
815
  if (this.toolScopedAgents.has(agent)) return;
807
816
  let cardId = this.sessionCards.get(agent.id);
@@ -10,5 +10,25 @@ import type { Context } from '@deepseek-ai/cordis';
10
10
  import type { KanbanSettingsShape } from './shared/card.js';
11
11
  export declare const name = "@fonlan/dsh-task-kanban";
12
12
  export declare const inject: string[];
13
- export declare const Config: import("@deepseek-ai/schemastery").default<KanbanSettingsShape>;
13
+ export declare const Config: import("@deepseek-ai/schemastery").default<Schemastery.ObjectS<NoInfer<{
14
+ maxParallelWorkers: import("@deepseek-ai/schemastery").default<number, number, "volatile-defined">;
15
+ refinementModel: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
16
+ refinementProvider: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
17
+ refinementReasoningEffort: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
18
+ refinementPreset: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
19
+ phaseModel: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
20
+ phaseProvider: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
21
+ phaseReasoningEffort: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
22
+ phasePreset: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
23
+ }>>, Schemastery.ObjectT<NoInfer<{
24
+ maxParallelWorkers: import("@deepseek-ai/schemastery").default<number, number, "volatile-defined">;
25
+ refinementModel: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
26
+ refinementProvider: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
27
+ refinementReasoningEffort: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
28
+ refinementPreset: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
29
+ phaseModel: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
30
+ phaseProvider: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
31
+ phaseReasoningEffort: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
32
+ phasePreset: import("@deepseek-ai/schemastery").default<string, string, "volatile-defined">;
33
+ }>>, "plain">;
14
34
  export declare function apply(ctx: Context, config: KanbanSettingsShape): void;
@@ -21,7 +21,7 @@ export declare class KanbanRunner implements KanbanToolResolver {
21
21
  private recovered;
22
22
  /** Agents that already got their scoped kanban tools (event idempotency). */
23
23
  private toolScopedAgents;
24
- private agentStartOff;
24
+ private agentCreatedOff;
25
25
  constructor(ctx: Context, store: TaskStore, settings: KanbanSettingsFace);
26
26
  register(ctx: Context): void;
27
27
  start(): void;
@@ -45,12 +45,13 @@ export declare class KanbanRunner implements KanbanToolResolver {
45
45
  /** Fallback lookup when a session starts before indexSessions ran. */
46
46
  private lookupCardOfSession;
47
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
48
+ * The single place kanban tools get registered. Subscribed to
49
+ * `agent/created`, which fires for BOTH `agents.create` (startup) and
50
+ * `agents.resume` (host re-open after a restart) and carries the path in its
51
+ * `source`, so a resumed refinement/phase/merge session keeps its scoped
51
52
  * tools. Idempotent per agent object; non-kanban sessions are skipped.
52
53
  */
53
- private onAgentSessionStart;
54
+ private onAgentCreated;
54
55
  listCards(workspacePath: string): Promise<KanbanCard[]>;
55
56
  createTask(input: {
56
57
  workspacePath: string;
@@ -9,7 +9,35 @@ import type { Context } from '@deepseek-ai/cordis';
9
9
  import z from '@deepseek-ai/schemastery';
10
10
  import type { KanbanSessionKind, KanbanSettingsShape } from '../shared/card.js';
11
11
  export declare const KANBAN_SETTINGS_NS = "task-kanban";
12
- export declare const KanbanSettingsSchema: z<KanbanSettingsShape>;
12
+ /**
13
+ * The entry config schema. Deliberately UNANNOTATED: schemastery >= 3.18.3
14
+ * added a third `Mode` type parameter, so `.default().volatile()` fields have
15
+ * output type `Volatile<T>` and an explicit `z<KanbanSettingsShape>` no longer
16
+ * compiles (the schema's `meta.default` then carries `Volatile<number>`, which
17
+ * is not a `number`). The plain `KanbanSettingsShape` interface stays the
18
+ * plugin-facing shape: `registerSettings` unwraps the live cells below.
19
+ */
20
+ export declare const KanbanSettingsSchema: z<Schemastery.ObjectS<NoInfer<{
21
+ maxParallelWorkers: z<number, number, "volatile-defined">;
22
+ refinementModel: z<string, string, "volatile-defined">;
23
+ refinementProvider: z<string, string, "volatile-defined">;
24
+ refinementReasoningEffort: z<string, string, "volatile-defined">;
25
+ refinementPreset: z<string, string, "volatile-defined">;
26
+ phaseModel: z<string, string, "volatile-defined">;
27
+ phaseProvider: z<string, string, "volatile-defined">;
28
+ phaseReasoningEffort: z<string, string, "volatile-defined">;
29
+ phasePreset: z<string, string, "volatile-defined">;
30
+ }>>, Schemastery.ObjectT<NoInfer<{
31
+ maxParallelWorkers: z<number, number, "volatile-defined">;
32
+ refinementModel: z<string, string, "volatile-defined">;
33
+ refinementProvider: z<string, string, "volatile-defined">;
34
+ refinementReasoningEffort: z<string, string, "volatile-defined">;
35
+ refinementPreset: z<string, string, "volatile-defined">;
36
+ phaseModel: z<string, string, "volatile-defined">;
37
+ phaseProvider: z<string, string, "volatile-defined">;
38
+ phaseReasoningEffort: z<string, string, "volatile-defined">;
39
+ phasePreset: z<string, string, "volatile-defined">;
40
+ }>>, "plain">;
13
41
  /** The per-session-type default slice a session kind resolves. */
14
42
  export interface KanbanSessionDefaults {
15
43
  model: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fonlan/dsh-task-kanban",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
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": {
@@ -78,49 +78,50 @@
78
78
  },
79
79
  "peerDependencies": {
80
80
  "@deepseek-ai/cordis": "^4.0.2",
81
- "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
82
- "@deepseek-ai/dsh-agent-presets": "^0.1.5-rc.2",
83
- "@deepseek-ai/dsh-api-session-controller": "^0.1.5-rc.2",
84
- "@deepseek-ai/dsh-client-locale": "^0.1.5-rc.2",
85
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-rc.2",
86
- "@deepseek-ai/dsh-client-ui-layout": "^0.1.5-rc.2",
87
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.2",
88
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-rc.2",
89
- "@deepseek-ai/dsh-client-ui-session": "^0.1.5-rc.2",
90
- "@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.5-rc.2",
91
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-rc.2",
92
- "@deepseek-ai/dsh-client-ui-workspace": "^0.1.5-rc.2",
93
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
94
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
95
- "@deepseek-ai/dsh-settings": "^0.1.5-rc.2",
96
- "@deepseek-ai/dsh-skill": "^0.1.5-rc.2",
97
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
81
+ "@deepseek-ai/dsh-agent": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
82
+ "@deepseek-ai/dsh-agent-preset-registry": "^0.1.7-rc.1 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
83
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
84
+ "@deepseek-ai/dsh-client-locale": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
85
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
86
+ "@deepseek-ai/dsh-client-ui-layout": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
87
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
88
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
89
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
90
+ "@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
91
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
92
+ "@deepseek-ai/dsh-client-ui-workspace": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
93
+ "@deepseek-ai/dsh-llm": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
94
+ "@deepseek-ai/dsh-session": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
95
+ "@deepseek-ai/dsh-settings": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
96
+ "@deepseek-ai/dsh-skill": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
97
+ "@deepseek-ai/dsh-tools": "^0.1.5-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
98
98
  "@deepseek-ai/schemastery": "^3.18.2",
99
99
  "react": "^18.2.0",
100
100
  "react-dom": "^18.2.0"
101
101
  },
102
102
  "devDependencies": {
103
- "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
104
- "@deepseek-ai/dsh-agent-presets": "^0.1.5-rc.2",
105
- "@deepseek-ai/dsh-api-session-controller": "^0.1.5-rc.2",
106
- "@deepseek-ai/dsh-client-locale": "^0.1.5-rc.2",
107
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-rc.2",
108
- "@deepseek-ai/dsh-client-ui-layout": "^0.1.5-rc.2",
109
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.2",
110
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-rc.2",
111
- "@deepseek-ai/dsh-client-ui-session": "^0.1.5-rc.2",
112
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.5-rc.2",
113
- "@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.5-rc.2",
114
- "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.5-rc.2",
115
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-rc.2",
116
- "@deepseek-ai/dsh-client-ui-workspace": "^0.1.5-rc.2",
117
- "@deepseek-ai/dsh-host-webserver": "^0.1.5-rc.2",
118
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
119
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
120
- "@deepseek-ai/dsh-settings": "^0.1.5-rc.2",
121
- "@deepseek-ai/dsh-skill": "^0.1.5-rc.2",
122
- "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
123
- "@deepseek-ai/schemastery": "^3.18.3",
103
+ "@deepseek-ai/dsh-agent": "0.2.1-alpha.1",
104
+ "@deepseek-ai/dsh-agent-preset": "0.2.1-alpha.1",
105
+ "@deepseek-ai/dsh-agent-preset-registry": "0.2.1-alpha.1",
106
+ "@deepseek-ai/dsh-api-session-controller": "0.2.1-alpha.1",
107
+ "@deepseek-ai/dsh-client-locale": "0.2.1-alpha.1",
108
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.1-alpha.1",
109
+ "@deepseek-ai/dsh-client-ui-layout": "0.2.1-alpha.1",
110
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-alpha.1",
111
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.1-alpha.1",
112
+ "@deepseek-ai/dsh-client-ui-session": "0.2.1-alpha.1",
113
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.1-alpha.1",
114
+ "@deepseek-ai/dsh-client-ui-settings-plugins": "0.2.1-alpha.1",
115
+ "@deepseek-ai/dsh-client-ui-sidebar": "0.2.1-alpha.1",
116
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.1-alpha.1",
117
+ "@deepseek-ai/dsh-client-ui-workspace": "0.2.1-alpha.1",
118
+ "@deepseek-ai/dsh-host-webserver": "0.2.1-alpha.1",
119
+ "@deepseek-ai/dsh-llm": "0.2.1-alpha.1",
120
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.1",
121
+ "@deepseek-ai/dsh-settings": "0.2.1-alpha.1",
122
+ "@deepseek-ai/dsh-skill": "0.2.1-alpha.1",
123
+ "@deepseek-ai/dsh-tools": "0.2.1-alpha.1",
124
+ "@deepseek-ai/schemastery": "3.18.5-alpha.1",
124
125
  "@types/node": "^22.0.0",
125
126
  "@types/react": "~18.3.1",
126
127
  "@types/react-dom": "~18.3.0",
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
2
2
  import type { KanbanCard, Lane, PhaseAttempt, PlanPhase } from '../shared/card'
3
3
  import { DROP_RULES, laneOf } from '../shared/lanes'
4
4
  import { api, gatewaySkillList, type SkillOption } from './api'
5
- import { getClient, leaveKanbanPanel } from './kanban-state'
5
+ import { openSessionView } from './kanban-state'
6
6
  import { en, zh } from './locales'
7
7
  import './board.css'
8
8
 
@@ -157,17 +157,10 @@ export function BoardRoot(props: BoardProps): JSX.Element {
157
157
  }, [cards, refresh, showToast, t])
158
158
 
159
159
  const openSession = useCallback((sessionId: string) => {
160
- const ctx = getClient()
161
- // Return the center column to the Conversation first: `sessions.open` is
162
- // wrapped by bindSessionNavigation as well, but a runtime without that
163
- // binding must still leave the board before the session renders.
164
- leaveKanbanPanel(ctx)
165
- if (ctx === null) return
166
- try {
167
- ;(ctx.sessions as { open(id: string): void }).open(sessionId)
168
- } catch {
169
- showToast(t('sessionNotListed'))
170
- }
160
+ // The shell's view owner retains the session and reveals the Conversation
161
+ // in one action, so the board itself needs no panel teardown; a runtime
162
+ // without that face cannot show the session at all.
163
+ if (!openSessionView(sessionId)) showToast(t('sessionNotListed'))
171
164
  }, [showToast, t])
172
165
 
173
166
  if (items.length === 0) {
@@ -8,7 +8,7 @@ import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
8
8
  import { BoardRoot } from './board'
9
9
  import { KanbanPanelIcon, KanbanSettingsSection } from './sections'
10
10
  import { LOCALE_NS, zh, en } from './locales'
11
- import { KANBAN_PANEL_ID, setClient, bindSessionNavigation } from './kanban-state'
11
+ import { KANBAN_PANEL_ID, setClient } from './kanban-state'
12
12
 
13
13
  /** The settings sidebar entry this plugin's page owns (must stay stable). */
14
14
  const SETTINGS_SECTION_ID = 'task-kanban'
@@ -19,8 +19,9 @@ export const inject = ['slots', 'sessions', 'workspaces', 'locale']
19
19
  /** Client plugin body. */
20
20
  export function apply(ctx: ClientContext): void {
21
21
  setClient(ctx)
22
- // Selecting a session while the board is open must return to the Conversation.
23
- bindSessionNavigation(ctx)
22
+ // Session opening goes through the shell's own view owner
23
+ // (`ctx.uiWorkspace.openSession`, see kanban-state.ts), which already returns
24
+ // the center column to the Conversation — no wrapper to install here.
24
25
 
25
26
  // Live translate bound to the active locale (labels re-read it per call).
26
27
  const t = ctx.locale.bind(LOCALE_NS)
@@ -17,6 +17,16 @@ interface LayoutLike {
17
17
  selectPanel(panelId: string | null): void
18
18
  }
19
19
 
20
+ /**
21
+ * Structural view of the client shell's workspace-navigation face
22
+ * (`ctx.uiWorkspace`, dsh-client-ui-workspace). Declared locally (no value
23
+ * import) so the plugin keeps working on a runtime whose workspace types differ.
24
+ */
25
+ interface UiWorkspaceLike {
26
+ /** Select a Session (id, or a direct-parent subagent address) and show it. */
27
+ openSession(target: string): void
28
+ }
29
+
20
30
  /**
21
31
  * HMR-safe owner context, keyed on the global symbol registry.
22
32
  *
@@ -78,41 +88,37 @@ export function leaveKanbanPanel(ctx: ClientContext | null = getClient()): void
78
88
  }
79
89
 
80
90
  /**
81
- * Route session navigation through the panel selection: opening any session
82
- * while the board is the active panel first returns the center column to the
83
- * Conversation, so the session view renders.
91
+ * Open one session — or a durable direct-parent subagent address — in the
92
+ * center column, leaving the kanban panel.
84
93
  *
85
- * Every sidebar path that selects a session funnels through `sessions.open`
86
- * (session rows, search results, fork results, New Session) or
87
- * `sessions.openSubagent` (catalog children) — including re-clicking the
88
- * already-current session, which never changes `list.current` and therefore
89
- * cannot be caught by a list-store subscription. Wrapping the two entry points
90
- * covers all of them in one place.
94
+ * Navigation is a view-owner concern, not a session-controller one: `ctx.sessions`
95
+ * (`ISessions`) exposes retention (`retain`/`using`/`retainInfo`), creation,
96
+ * fork, search and catalog reads, and has no `open`/`openSubagent` at all
97
+ * ("navigation belongs to view owners"). The view owner the shell itself uses is
98
+ * `ctx.uiWorkspace.openSession(target)` (dsh-client-ui-workspace): it retains the
99
+ * session AND reveals the Conversation panel as ONE navigation action. Routing
100
+ * every open through it therefore replaces the old wrapper around
101
+ * `sessions.open`/`openSubagent`, which existed only to hand the center column
102
+ * back when a sidebar click selected a session while the board was showing.
91
103
  *
92
- * The wrapper is idempotent: a `kbBound` marker on the wrapper prevents a
93
- * second bind (plugin re-apply / HMR) from stacking another layer.
104
+ * @param target - session id (or subagent address) to show.
105
+ * @returns whether the runtime provided the navigation face; `false` means the
106
+ * session could not be shown (a client without ui-workspace).
94
107
  */
95
- export function bindSessionNavigation(ctx: ClientContext): void {
96
- const sessions = ctx.sessions
97
- if (sessions === undefined) return
98
-
99
- const open = sessions.open
100
- if (typeof open === 'function' && (open as unknown as { kbBound?: boolean }).kbBound !== true) {
101
- const bound = ((id: Parameters<typeof open>[0]) => {
102
- leaveKanbanPanel(ctx)
103
- return open.call(sessions, id)
104
- }) as typeof open
105
- ;(bound as unknown as { kbBound?: boolean }).kbBound = true
106
- sessions.open = bound
108
+ export function openSessionView(target: string, ctx: ClientContext | null = getClient()): boolean {
109
+ if (ctx === null) return false
110
+ let uiWorkspace: UiWorkspaceLike | undefined
111
+ try {
112
+ uiWorkspace = (ctx as unknown as { uiWorkspace?: UiWorkspaceLike }).uiWorkspace
113
+ } catch {
114
+ return false
107
115
  }
108
-
109
- const openSubagent = sessions.openSubagent
110
- if (typeof openSubagent === 'function' && (openSubagent as unknown as { kbBound?: boolean }).kbBound !== true) {
111
- const bound = ((address: Parameters<typeof openSubagent>[0]) => {
112
- leaveKanbanPanel(ctx)
113
- return openSubagent.call(sessions, address)
114
- }) as typeof openSubagent
115
- ;(bound as unknown as { kbBound?: boolean }).kbBound = true
116
- sessions.openSubagent = bound
116
+ if (typeof uiWorkspace?.openSession !== 'function') return false
117
+ try {
118
+ uiWorkspace.openSession(target)
119
+ return true
120
+ } catch (error) {
121
+ console.error('[@fonlan/dsh-task-kanban] cannot open the session view:', error)
122
+ return false
117
123
  }
118
124
  }
@@ -19,7 +19,14 @@ import { currentBranch, detectBaseRef, hasStashMessage, isGitRepo, isTreeDirty,
19
19
  import { interactiveRefinementPrompt, mergePrompt, phasePrompt, refinementPrompt } from './prompts.js'
20
20
  import { loadCardSkill, parseSkillGesture, skillInvocationMessage } from './skills.js'
21
21
  import { registerKanbanTools, type KanbanToolResolver } from './tools.js'
22
- import type {} from '@deepseek-ai/dsh-agent-presets'
22
+ // Declaration-merge only (erased at runtime): loads the `agentPresets` service
23
+ // augmentation for `ctx.get('agentPresets')` below. The 0.1.x name
24
+ // `@deepseek-ai/dsh-agent-presets` stopped shipping after 0.1.5-rc.3 and does
25
+ // not exist at 0.2.0-rc.1; `@deepseek-ai/dsh-agent-preset` ships on both live
26
+ // runtimes and carries the same `agentPresets` Context augmentation (it depends
27
+ // on `@deepseek-ai/dsh-agent-preset-registry`, which owns the service and the
28
+ // augmentation).
29
+ import type {} from '@deepseek-ai/dsh-agent-preset'
23
30
 
24
31
  const WORKTREES_REL = ['.dsh', 'worktrees']
25
32
 
@@ -59,7 +66,7 @@ export class KanbanRunner implements KanbanToolResolver {
59
66
  private recovered = false
60
67
  /** Agents that already got their scoped kanban tools (event idempotency). */
61
68
  private toolScopedAgents = new WeakSet<object>()
62
- private agentStartOff: (() => void) | undefined
69
+ private agentCreatedOff: (() => void) | undefined
63
70
 
64
71
  constructor(ctx: Context, store: TaskStore, settings: KanbanSettingsFace) {
65
72
  this.ctx = ctx
@@ -73,21 +80,28 @@ export class KanbanRunner implements KanbanToolResolver {
73
80
 
74
81
  start(): void {
75
82
  this.pumpTimer = setInterval(() => { void this.pump() }, 2500)
76
- // `agent/session-start` fires for BOTH agents.create (startup) and
77
- // agents.resume (host re-open after a restart). Kanban tools are scoped
78
- // per agent, so a resumed refinement/phase/merge session would otherwise
79
- // lose them — register there instead of only in createAgent's setup.
80
- this.agentStartOff = this.ctx.on('agent/session-start', (payload: { agent?: { id?: string; ctx?: Context } }) => {
81
- void this.onAgentSessionStart(payload.agent)
83
+ // `agent/created` is the lifecycle edge for an agent that entered the
84
+ // registry — dsh announces every creation path through it, including
85
+ // `agents.resume` (the factory re-opens a persisted session's agent after a
86
+ // host restart), and its `source` records which path that was. The previous
87
+ // subscription used `agent/session-start`, which existed in dsh 0.1.5 only
88
+ // and was already gone by 0.1.7 — so resumed refinement/phase/merge
89
+ // sessions silently lost their scoped kanban tools. `agent/created` exists
90
+ // in 0.1.7-rc.2 and 0.2.0-rc.1 with the same `{ agent, source }` payload.
91
+ // It dispatches as a serial listener, so this callback must not reject:
92
+ // tool registration is best-effort and a lookup failure must not fail the
93
+ // host's agent creation (hence the floating promise).
94
+ this.agentCreatedOff = this.ctx.on('agent/created', (payload: { agent?: { id?: string; ctx?: Context } }): undefined => {
95
+ void this.onAgentCreated(payload.agent)
82
96
  })
83
97
  }
84
98
 
85
99
  stop(): void {
86
100
  if (this.pumpTimer !== undefined) clearInterval(this.pumpTimer)
87
101
  this.pumpTimer = undefined
88
- if (this.agentStartOff !== undefined) {
89
- this.agentStartOff()
90
- this.agentStartOff = undefined
102
+ if (this.agentCreatedOff !== undefined) {
103
+ this.agentCreatedOff()
104
+ this.agentCreatedOff = undefined
91
105
  }
92
106
  }
93
107
 
@@ -217,12 +231,13 @@ export class KanbanRunner implements KanbanToolResolver {
217
231
  }
218
232
 
219
233
  /**
220
- * The single place kanban tools get registered. `agent/session-start` fires
221
- * for BOTH `agents.create` (startup) and `agents.resume` (host re-open after
222
- * a restart), so a resumed refinement/phase/merge session keeps its scoped
234
+ * The single place kanban tools get registered. Subscribed to
235
+ * `agent/created`, which fires for BOTH `agents.create` (startup) and
236
+ * `agents.resume` (host re-open after a restart) and carries the path in its
237
+ * `source`, so a resumed refinement/phase/merge session keeps its scoped
223
238
  * tools. Idempotent per agent object; non-kanban sessions are skipped.
224
239
  */
225
- private async onAgentSessionStart(agent: { id?: string; ctx?: Context } | undefined): Promise<void> {
240
+ private async onAgentCreated(agent: { id?: string; ctx?: Context } | undefined): Promise<void> {
226
241
  if (agent === undefined || agent.id === undefined || agent.ctx === undefined) return
227
242
  if (this.toolScopedAgents.has(agent)) return
228
243
  let cardId = this.sessionCards.get(agent.id)
@@ -611,9 +626,9 @@ export class KanbanRunner implements KanbanToolResolver {
611
626
  sessionId,
612
627
  meta: { cwd, ...(presetId !== undefined ? { agentPreset: presetId } : {}) },
613
628
  ...(agentOptions !== undefined ? { agentOptions } : {}),
614
- // Kanban tools are NOT registered here: `agent/session-start` (see
615
- // start()) fires for both create and resume, keeping them available
616
- // even when the host re-opens a persisted kanban session.
629
+ // Kanban tools are NOT registered here: `agent/created` (see start())
630
+ // fires for both create and resume, keeping them available even when the
631
+ // host re-opens a persisted kanban session.
617
632
  setup: async (agentCtx) => {
618
633
  const agentPresets = agentCtx.get('agentPresets') as
619
634
  | { mount(agentCtx: unknown, id?: string): Promise<unknown> }
@@ -11,7 +11,15 @@ import type { KanbanSessionKind, KanbanSettingsShape } from '../shared/card.js'
11
11
 
12
12
  export const KANBAN_SETTINGS_NS = 'task-kanban'
13
13
 
14
- export const KanbanSettingsSchema: z<KanbanSettingsShape> = z.object({
14
+ /**
15
+ * The entry config schema. Deliberately UNANNOTATED: schemastery >= 3.18.3
16
+ * added a third `Mode` type parameter, so `.default().volatile()` fields have
17
+ * output type `Volatile<T>` and an explicit `z<KanbanSettingsShape>` no longer
18
+ * compiles (the schema's `meta.default` then carries `Volatile<number>`, which
19
+ * is not a `number`). The plain `KanbanSettingsShape` interface stays the
20
+ * plugin-facing shape: `registerSettings` unwraps the live cells below.
21
+ */
22
+ export const KanbanSettingsSchema = z.object({
15
23
  // Volatile: the settings plane (settings page / settings.update) only
16
24
  // writes volatile-marked fields on dsh >= 0.1.7.
17
25
  maxParallelWorkers: z.natural().min(1).default(1).volatile(),