@alpacachen/dsh-kanban 1.5.1 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ A collaborative kanban board where you and your AI agent plan, organize, and shi
11
11
  [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
12
12
  ![License](https://img.shields.io/badge/license-MIT-22c55e)
13
13
 
14
- [简体中文](README.zh.md) · **English**
14
+ [Simplified Chinese](README.zh.md) · **English**
15
15
 
16
16
  </div>
17
17
 
package/cordis.patch.yml CHANGED
@@ -1,6 +1,6 @@
1
- # dsh-kanban bundle patch:把看板插件行插入 profile 组合。
2
- # 安装后该行通过包名 @alpacachen/dsh-kanban 解析(Node profile node_modules 找到本包)。
3
- # 层顺序:@deepseek-ai/dsh-base bundle profile 自己的 cordis.patch.yml 用户 --patch 覆盖。
1
+ # Insert the kanban plugin into the profile composition.
2
+ # Node resolves @alpacachen/dsh-kanban from the profile node_modules after installation.
3
+ # Layer order: @deepseek-ai/dsh-base -> this bundle -> profile cordis.patch.yml -> user --patch overrides.
4
4
  - insert:
5
5
  - id: dsh-kanban
6
6
  name: "@alpacachen/dsh-kanban"
package/index.js CHANGED
@@ -1,59 +1,59 @@
1
1
  /**
2
- * dsh-kanban DSH bundle 宿主插件(标准 Cordis 函数插件)
2
+ * dsh-kanban: DSH bundle host plugin (standard Cordis function plugin).
3
3
  *
4
- * 挂载方式:package.json `dsh.bundle.patch` 指向 cordis.patch.yml
5
- * 该补丁层把本插件行插入 profile 组合,Loader 按包名 dsh-kanban 解析本文件。
4
+ * package.json points dsh.bundle.patch to cordis.patch.yml, which inserts this
5
+ * plugin into the profile composition. The loader resolves its package entry.
6
6
  *
7
- * 职责:
8
- * - 按工作区(项目)隔离:boards workspaceId 为键,每个工作区一块独立看板
9
- * - 磁盘持久化:经 ctx.fs 写入 <workspace.path>/.dsh-kanban.json
10
- * - 模型工具:经 ctx.tools.register 注册 15 kanban_* 工具
11
- * - 浏览器数据层:经 ctx.get('webServer') 注册 /api/kanban 前缀路由
7
+ * Responsibilities:
8
+ * - Workspace isolation: boards are keyed by workspaceId, one board per workspace.
9
+ * - Persistence: ctx.fs writes <workspace.path>/.dsh-kanban.json.
10
+ * - Agent tools: ctx.tools.register exposes 15 kanban_* tools.
11
+ * - Browser API: ctx.get('webServer') registers routes under /api/kanban.
12
12
  *
13
- * 数据模型(每工作区,磁盘文件带 schemaVersion):
13
+ * Per-workspace data model (disk files include schemaVersion):
14
14
  * schemaVersion: 3
15
15
  * columns: [{ id, title }]
16
- * labels: [{ name, color }] —— 标签与颜色绑定,name 为唯一键
16
+ * labels: [{ name, color }] // name is the unique key and binds the color
17
17
  * cards: [{ id, columnId, title, note, label, priority, createdAt, createdBy,
18
18
  * comments: [{ id, content, source, createdAt }] }]
19
- * activities: [{ id, ts, cardId, type, source, field?, from?, to?, meta? }] —— 追加式活动日志
19
+ * activities: [{ id, ts, cardId, type, source, field?, from?, to?, meta? }] // append-only log
20
20
  *
21
- * 数据安全:
22
- * - schemaVersion 的历史文件按 v0 处理,首次打开自动升级(见 MIGRATIONS
23
- * - 升级/损坏/版本超前均先备份原文件(.bak-vN / .corrupt-<ts> / .unsupported-vN
24
- * - 启动时全量体检所有看板文件,损坏文件备份后不影响看板可用性
21
+ * Data safety:
22
+ * - Files without schemaVersion are v0 and migrate on first access (see MIGRATIONS).
23
+ * - Back up originals before migration or recovery: .bak-vN / .corrupt-<ts> / .unsupported-vN.
24
+ * - Check all workspace boards at startup; back up corrupt files and keep boards usable.
25
25
  */
26
26
  export const name = 'dsh-kanban'
27
27
 
28
28
  export const inject = ['tools']
29
29
 
30
30
  // ---------------------------------------------------------------------------
31
- // 持久化格式版本与迁移
31
+ // Persistence format version and migrations.
32
32
  //
33
- // 磁盘文件结构:
33
+ // On-disk structure:
34
34
  // { schemaVersion, columns, labels, cards }
35
35
  //
36
- // 版本约定:
37
- // v1 —— 首个带版本声明的格式,等价于 1.0.x ~ 1.2.x 时代无版本声明的三数组格式
38
- // (columns/labels/cards),并补齐了卡片的规范字段(note/label/priority)。
39
- // LEGACY_VERSION(0) —— 历史文件没有 schemaVersion 字段,一律归入 v0 处理。
36
+ // Version conventions:
37
+ // v1: first versioned format, matching the unversioned columns/labels/cards arrays
38
+ // used in 1.0.x through 1.2.x, with normalized note/label/priority card fields.
39
+ // LEGACY_VERSION (0): files without schemaVersion.
40
40
  //
41
- // 新增/删除字段的流程:
42
- // 1) SCHEMA_VERSION 自增
43
- // 2) MIGRATIONS 里以"旧版本号为键"注册 v(n)v(n+1) 迁移函数
44
- // 3) 迁移函数是纯函数,输出必须带 schemaVersion: n+1migrateBoard 会校验)
45
- // 旧文件在首次打开时自动沿迁移链升级,升级前原文件先备份。
41
+ // Adding or removing fields:
42
+ // 1) Increment SCHEMA_VERSION.
43
+ // 2) Register a v(n) -> v(n+1) function in MIGRATIONS, keyed by the old version.
44
+ // 3) Return schemaVersion: n+1 from the pure migration (checked by migrateBoard).
45
+ // Back up old files before following the migration chain on first access.
46
46
  // ---------------------------------------------------------------------------
47
47
 
48
48
  export const SCHEMA_VERSION = 3
49
49
  export const LEGACY_VERSION = 0
50
50
 
51
- // 活动日志:追加式只读记录,随看板一起落盘;超过上限丢弃最旧事件,防止日志无界增长。
51
+ // Append-only activity log persisted with the board; drop oldest events above the limit.
52
52
  const ACTIVITY_LIMIT = 5000
53
53
 
54
- // 输入长度上限:与工具 schema 描述、客户端编辑器(CardDialog)保持一致。
55
- // 超长输入在写入前被截断,并通过看板 warnings 通道发出一次性警告(见 clampText),
56
- // 因此 agent 与用户都能感知到内容被裁剪,而不是静默丢失。
54
+ // Input limits must match tool schemas and the CardDialog editor.
55
+ // clampText truncates oversized input before writing and emits a one-time board warning
56
+ // so both agents and users know when content was shortened.
57
57
  export const TITLE_LIMIT = 120
58
58
  export const NOTE_LIMIT = 2000
59
59
  export const LABEL_LIMIT = 20
@@ -64,7 +64,7 @@ const isObj = (v) => typeof v === 'object' && v !== null && !Array.isArray(v)
64
64
  const strField = (v, fb) => (typeof v === 'string' && v ? v : fb)
65
65
  const normColor = (v) => (typeof v === 'string' && /^#[0-9a-fA-F]{6}$/.test(v) ? v.toLowerCase() : '#94a3b8')
66
66
 
67
- // v1 的规范实体形状(仅补缺省值,不改动合法数据)
67
+ // Canonical v1 entity shapes: fill missing defaults without changing valid data.
68
68
  const normColumn = (c) =>
69
69
  isObj(c) ? { id: strField(c.id, ''), title: strField(c.title, 'Untitled') } : null
70
70
  const normLabel = (l) =>
@@ -82,12 +82,12 @@ const normCard = (c) =>
82
82
  : null
83
83
 
84
84
  /**
85
- * 逐版本迁移注册表:key = 旧版本号,value = (旧数据) => 新数据。
86
- * 输出必须设置 schemaVersion = key + 1migrateBoard 会逐级校验。
85
+ * Migration registry: key = old version, value = (old data) => new data.
86
+ * Each result must set schemaVersion = key + 1; migrateBoard validates every step.
87
87
  */
88
88
  export const MIGRATIONS = {
89
89
  0: (data) => {
90
- // v0 v1:历史无版本文件 —— 声明版本 + 规范化实体字段
90
+ // v0 -> v1: declare the version and normalize legacy entity fields.
91
91
  const src = isObj(data) ? data : {}
92
92
  const pick = (arr) => (Array.isArray(arr) ? arr : [])
93
93
  return {
@@ -98,7 +98,7 @@ export const MIGRATIONS = {
98
98
  }
99
99
  },
100
100
  1: (data) => {
101
- // v1 v2:新增追加式活动日志 activities;卡片补 createdAt/createdBy(历史数据为 null
101
+ // v1 -> v2: add activities and card createdAt/createdBy (null for legacy cards).
102
102
  const src = isObj(data) ? data : {}
103
103
  const pick = (arr) => (Array.isArray(arr) ? arr : [])
104
104
  return {
@@ -115,7 +115,7 @@ export const MIGRATIONS = {
115
115
  }
116
116
  },
117
117
  2: (data) => {
118
- // v2 v3:卡片新增评论数组;历史卡片默认没有评论
118
+ // v2 -> v3: add comments; legacy cards start with an empty array.
119
119
  const src = isObj(data) ? data : {}
120
120
  const pick = (arr) => (Array.isArray(arr) ? arr : [])
121
121
  return {
@@ -131,8 +131,8 @@ export const MIGRATIONS = {
131
131
  }
132
132
 
133
133
  /**
134
- * 沿迁移链把数据从 fromVersion 逐级升级到 SCHEMA_VERSION
135
- * 任一步缺失或产出无效都会抛错(由调用方备份并降级处理)。
134
+ * Migrate from fromVersion to SCHEMA_VERSION one step at a time.
135
+ * Throw for missing steps or invalid output; the caller handles backup and fallback.
136
136
  */
137
137
  export function migrateBoard(data, fromVersion) {
138
138
  let out = data
@@ -152,8 +152,8 @@ export function migrateBoard(data, fromVersion) {
152
152
  }
153
153
 
154
154
  /**
155
- * 结构校验(迁移后的最终形态)。
156
- * 返回 { ok, errors }errors 非空时文件应视为损坏处理。
155
+ * Validate the final migrated structure.
156
+ * Return { ok, errors }; nonempty errors mark the file as invalid.
157
157
  */
158
158
  export function validateBoard(data) {
159
159
  const errors = []
@@ -241,16 +241,16 @@ export function validateBoard(data) {
241
241
  }
242
242
 
243
243
  /**
244
- * 解析并升级一段看板文件文本(纯函数,不触磁盘)。
244
+ * Parse and migrate board JSON without accessing disk.
245
245
  *
246
- * 返回:
247
- * { ok: true, kind: 'ok', data, migrated, fromVersion, warnings } —— data 为可用的最新版
248
- * { ok: false, kind: 'corrupt'|'invalid'|'unsupported', warnings } —— 需要调用方备份原文件
246
+ * Results:
247
+ * { ok: true, kind: 'ok', data, migrated, fromVersion, warnings }: usable current data
248
+ * { ok: false, kind: 'corrupt'|'invalid'|'unsupported', warnings }: back up the original
249
249
  *
250
- * kind 语义:
251
- * corrupt —— JSON 无法解析
252
- * invalid —— 结构校验失败 / 迁移失败
253
- * unsupported —— schemaVersion 高于当前插件支持(文件来自更新版本插件)
250
+ * Failure kinds:
251
+ * corrupt: JSON parsing failed
252
+ * invalid: validation or migration failed
253
+ * unsupported: schemaVersion exceeds this plugin version
254
254
  */
255
255
  export function parseBoardText(text) {
256
256
  const warnings = []
@@ -334,12 +334,12 @@ export function apply(ctx) {
334
334
  const getWorkspaceRegistry = () => ctx.get('workspaceRegistry')
335
335
 
336
336
  const boards = new Map() // workspaceId -> { columns, labels, cards }
337
- const boardLoads = new Map() // workspaceId -> Promise<board>,防止冷启动发布半初始化状态
338
- const workspaceQueues = new Map() // workspaceId -> Promise,串行化完整 mutation 临界区
339
- const fileTargets = new Map() // workspaceId -> FsTarget;解析失败不缓存,允许后续重试
340
- let seq = 0 // 全局自增,用于生成 cN(列)/ kN(卡)唯一 id
337
+ const boardLoads = new Map() // workspaceId -> Promise<board>; publish only fully initialized boards
338
+ const workspaceQueues = new Map() // workspaceId -> Promise; serialize the entire mutation
339
+ const fileTargets = new Map() // workspaceId -> FsTarget; retry failed resolution instead of caching it
340
+ let seq = 0 // Global sequence for unique cN (column) and kN (card) ids.
341
341
 
342
- // ---- id 生成 ----
342
+ // ---- ID generation ----
343
343
  const nextId = (prefix) => prefix + (++seq)
344
344
  const bumpSeq = (id) => {
345
345
  if (typeof id !== 'string') return
@@ -347,7 +347,7 @@ export function apply(ctx) {
347
347
  if (Number.isFinite(n) && n > seq) seq = n
348
348
  }
349
349
 
350
- // ---- 默认看板 ----
350
+ // ---- Default board ----
351
351
  const DEFAULT_COLUMNS = ['Todo', 'In Progress', 'Review', 'Done']
352
352
  const DEFAULT_LABELS = [
353
353
  { name: 'New Feature', color: '#38bdf8' },
@@ -355,7 +355,7 @@ export function apply(ctx) {
355
355
  { name: 'Feedback', color: '#34d399' },
356
356
  ]
357
357
 
358
- // ---- 持久化定位 ----
358
+ // ---- Persistence target resolution ----
359
359
  const BOARD_FILE = '.dsh-kanban.json'
360
360
  const workspaceKey = (workspace) => String(workspace.id || workspace.path)
361
361
  const writePolicyFor = (workspace, session) => {
@@ -373,7 +373,7 @@ export function apply(ctx) {
373
373
  return await fs.resolve(BOARD_FILE, { cwd: workspace.path })
374
374
  } catch (err) {
375
375
  console.log(
376
- 'dsh-kanban: 解析工作区看板文件失败 ' + workspaceKey(workspace) + '' + ((err && err.message) || err),
376
+ 'dsh-kanban: Failed to resolve workspace board file ' + workspaceKey(workspace) + ': ' + ((err && err.message) || err),
377
377
  )
378
378
  return null
379
379
  }
@@ -387,9 +387,9 @@ export function apply(ctx) {
387
387
  }
388
388
  const persistedFlag = (workspace) => fileTargets.has(workspaceKey(workspace))
389
389
 
390
- // ---- 看板读写 ----
390
+ // ---- Board reads and writes ----
391
391
 
392
- // 备份原文件为 .dsh-kanban.json.<suffix>(复制而非移动,保证原文件在写回前始终存在)
392
+ // Copy to .dsh-kanban.json.<suffix>, keeping the original until the replacement is written.
393
393
  const backupFile = async (workspace, suffix, session) => {
394
394
  const fs = getFs()
395
395
  const target = await targetOf(workspace)
@@ -401,12 +401,12 @@ export function apply(ctx) {
401
401
  await fs.writeText(backupTarget, text, undefined, undefined, writePolicyFor(workspace, session))
402
402
  return backupTarget
403
403
  } catch (err) {
404
- console.log('dsh-kanban: 备份失败 ' + key + ' (' + suffix + ')' + ((err && err.message) || err))
404
+ console.log('dsh-kanban: Backup failed ' + key + ' (' + suffix + '): ' + ((err && err.message) || err))
405
405
  return null
406
406
  }
407
407
  }
408
408
 
409
- // 记录一次性警告:进入看板 warnings 队列 + 写宿主日志
409
+ // Queue a one-time board warning and write it to the host log.
410
410
  const warn = (board, message) => {
411
411
  if (Array.isArray(board.warnings)) board.warnings.push(message)
412
412
  console.log('dsh-kanban: ' + message)
@@ -420,7 +420,7 @@ export function apply(ctx) {
420
420
 
421
421
  const isNotFound = (err) => err && (err.code === 'ENOENT' || err.code === 'FS_NOT_FOUND' || err.message === 'ENOENT')
422
422
 
423
- // 首次访问缓存初始化 Promise;完成读取、迁移和默认值建立后才发布 board。
423
+ // Cache initialization promises; publish only after reads, migrations and defaults finish.
424
424
  const boardOf = async (workspace, session) => {
425
425
  const key = workspaceKey(workspace)
426
426
  const existing = boards.get(key)
@@ -472,7 +472,7 @@ export function apply(ctx) {
472
472
  }
473
473
  }
474
474
  } catch (err) {
475
- console.log('dsh-kanban: 读取看板失败 ' + key + '' + ((err && err.message) || err))
475
+ console.log('dsh-kanban: Failed to read board ' + key + ': ' + ((err && err.message) || err))
476
476
  if (!isNotFound(err)) {
477
477
  board.readOnlyReason = 'Board could not be read; changes are disabled to protect the existing file.'
478
478
  warn(board, board.readOnlyReason)
@@ -528,16 +528,16 @@ export function apply(ctx) {
528
528
  writePolicyFor(workspace, session),
529
529
  )
530
530
  } catch (err) {
531
- console.log('dsh-kanban: 保存失败 ' + key + '' + ((err && err.message) || err))
531
+ console.log('dsh-kanban: Save failed ' + key + ': ' + ((err && err.message) || err))
532
532
  throw err
533
533
  }
534
534
  }
535
535
 
536
- // ---- 校验 / 查找 / 序列化 ----
536
+ // ---- Validation, lookup and serialization ----
537
537
  const str = (v, fb) => (typeof v === 'string' ? v : fb)
538
538
 
539
- // 截断辅助:把输入裁到 limit 以内;一旦实际发生截断,就经看板 warnings 通道
540
- // 发出一次性警告(同时写入宿主日志),避免内容被静默丢弃。
539
+ // Clamp input to its limit and warn through the board warnings queue and host log
540
+ // whenever truncation occurs, so content is never silently discarded.
541
541
  const clampText = (value, limit, field, board) => {
542
542
  const s = str(value, '')
543
543
  if (s.length <= limit) return s
@@ -592,7 +592,7 @@ export function apply(ctx) {
592
592
  })),
593
593
  })
594
594
 
595
- // 追加一条活动事件(只读日志,随看板一起落盘)
595
+ // Append a read-only activity event, persisted with the board.
596
596
  const record = (board, ev) => {
597
597
  if (!Array.isArray(board.activities)) board.activities = []
598
598
  board.activities.push({
@@ -605,7 +605,7 @@ export function apply(ctx) {
605
605
  }
606
606
  }
607
607
 
608
- // ---- 核心数据操作:工具与浏览器 HTTP 共用同一份逻辑 ----
608
+ // ---- Core operations shared by agent tools and browser HTTP ----
609
609
  const READ_METHODS = new Set(['get', 'getCard'])
610
610
  const dispatchUnlocked = async (workspace, method, args, source, session) => {
611
611
  const board = await boardOf(workspace, session)
@@ -881,7 +881,7 @@ export function apply(ctx) {
881
881
  return run
882
882
  }
883
883
 
884
- // ---- 工具执行上下文 / 浏览器 workspaceId -> 工作区 ----
884
+ // ---- Tool execution context and browser workspaceId resolution ----
885
885
  const workspaceOfExec = async (exec) => {
886
886
  const agent = exec && exec.agent
887
887
  const session = agent && agent.session
@@ -893,10 +893,10 @@ export function apply(ctx) {
893
893
  const workspace = await registry.resolveByPath(cwd)
894
894
  if (workspace) return workspace
895
895
  } catch (err) {
896
- console.log('dsh-kanban: 解析工作区失败:' + ((err && err.message) || err))
896
+ console.log('dsh-kanban: Failed to resolve workspace: ' + ((err && err.message) || err))
897
897
  }
898
898
  }
899
- // 未登记到 WorkspaceRegistry 的会话仍以自身 cwd 作为工作区根目录。
899
+ // Unregistered sessions use their own cwd as the workspace root.
900
900
  return { id: 'cwd:' + cwd, path: cwd, title: cwd }
901
901
  }
902
902
  const workspaceOfId = (id) => {
@@ -934,7 +934,7 @@ export function apply(ctx) {
934
934
  }
935
935
  }
936
936
 
937
- // ---- 浏览器数据层:经官方 webServer 扩展点注册 /api/kanban ----
937
+ // ---- Browser API through the official webServer extension ----
938
938
  const MAX_HTTP_BODY = 1024 * 1024
939
939
  const sendJson = (res, status, value) => {
940
940
  res.writeHead(status, { 'content-type': 'application/json; charset=utf-8' })
@@ -984,9 +984,9 @@ export function apply(ctx) {
984
984
  const dispose = webServer.register({ kind: 'prefix', path: '/api/kanban', handler: httpHandler })
985
985
  routeState.dispose = typeof dispose === 'function' ? dispose : null
986
986
  routeState.registered = true
987
- console.log('dsh-kanban: /api/kanban 路由已注册')
987
+ console.log('dsh-kanban: /api/kanban route registered')
988
988
  } catch (err) {
989
- console.log('dsh-kanban: 路由注册失败:' + ((err && err.message) || err))
989
+ console.log('dsh-kanban: Route registration failed: ' + ((err && err.message) || err))
990
990
  }
991
991
  }
992
992
  registerRoute()
@@ -1005,7 +1005,7 @@ export function apply(ctx) {
1005
1005
  }
1006
1006
  }
1007
1007
 
1008
- // ---- 启动校验:逐个工作区体检 .dsh-kanban.json(只读 + 备份损坏文件)----
1008
+ // ---- Startup checks: read each workspace board and back up corrupt files ----
1009
1009
  const startupState = { done: false }
1010
1010
  const maybeStartupCheck = () => {
1011
1011
  if (startupState.done) return
@@ -1035,49 +1035,49 @@ export function apply(ctx) {
1035
1035
  if (parsed.ok) {
1036
1036
  if (parsed.migrated) {
1037
1037
  pendingUpgrade++
1038
- console.log('dsh-kanban: 启动校验 ' + key + 'schemaVersion ' + parsed.fromVersion + ',首次打开时将自动升级')
1038
+ console.log('dsh-kanban: Startup check ' + key + ': schemaVersion ' + parsed.fromVersion + '; will migrate on first access')
1039
1039
  } else {
1040
1040
  ok++
1041
1041
  }
1042
1042
  } else if (parsed.kind === 'unsupported') {
1043
1043
  unsupported++
1044
- console.log('dsh-kanban: 启动校验 ' + key + ':文件由更新版本插件写入(schemaVersion ' + parsed.version + '')
1044
+ console.log('dsh-kanban: Startup check ' + key + ': file written by a newer plugin (schemaVersion ' + parsed.version + ')')
1045
1045
  } else {
1046
1046
  corrupt++
1047
1047
  const suffix = 'corrupt-' + timestamp()
1048
1048
  const backupTarget = await fs.resolve(BOARD_FILE + '.' + suffix, { cwd: workspace.path })
1049
1049
  await fs.writeText(backupTarget, text, undefined, undefined, writePolicyFor(workspace))
1050
- console.log('dsh-kanban: 启动校验 ' + key + ':数据文件损坏(' + parsed.kind + '),已备份为 ' + BOARD_FILE + '.' + suffix)
1050
+ console.log('dsh-kanban: Startup check ' + key + ': corrupt data file (' + parsed.kind + '); backed up to ' + BOARD_FILE + '.' + suffix)
1051
1051
  }
1052
1052
  } catch (err) {
1053
1053
  if (!err || (err.code !== 'ENOENT' && err.message !== 'ENOENT')) {
1054
- console.log('dsh-kanban: 启动校验 ' + key + ':检查失败 ' + ((err && err.message) || err))
1054
+ console.log('dsh-kanban: Startup check ' + key + ': check failed ' + ((err && err.message) || err))
1055
1055
  }
1056
1056
  }
1057
1057
  }
1058
1058
  if (found === 0) {
1059
- console.log('dsh-kanban: 启动校验完成,未发现看板数据文件')
1059
+ console.log('dsh-kanban: Startup check complete: no board data files found')
1060
1060
  return
1061
1061
  }
1062
1062
  console.log(
1063
- 'dsh-kanban: 启动校验完成:共 ' +
1063
+ 'dsh-kanban: Startup check complete: total ' +
1064
1064
  found +
1065
- ' 个看板文件,正常 ' +
1065
+ ' board files, valid ' +
1066
1066
  ok +
1067
- ',损坏并已备份 ' +
1067
+ ', corrupt and backed up ' +
1068
1068
  corrupt +
1069
- ',待自动升级 ' +
1069
+ ', pending migration ' +
1070
1070
  pendingUpgrade +
1071
- ',版本超前 ' +
1071
+ ', unsupported version ' +
1072
1072
  unsupported,
1073
1073
  )
1074
1074
  } catch (err) {
1075
- console.log('dsh-kanban: 启动校验失败:' + ((err && err.message) || err))
1075
+ console.log('dsh-kanban: Startup check failed: ' + ((err && err.message) || err))
1076
1076
  }
1077
1077
  }
1078
1078
  maybeStartupCheck()
1079
1079
 
1080
- // ---- 工具注册 ----
1080
+ // ---- Tool registration ----
1081
1081
  const resultSchema = {
1082
1082
  type: 'object',
1083
1083
  properties: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alpacachen/dsh-kanban",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "A kanban board plugin for DeepSeek Harness: a 'Board' tab, card comments and 15 kanban_* AI tools, with per-workspace isolation and disk persistence.",
5
5
  "type": "module",
6
6
  "main": "index.js",