@alpacachen/dsh-kanban 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +40 -21
- package/lib/client.js +6 -6
- package/package.json +19 -3
package/index.js
CHANGED
|
@@ -51,6 +51,15 @@ export const LEGACY_VERSION = 0
|
|
|
51
51
|
// 活动日志:追加式只读记录,随看板一起落盘;超过上限丢弃最旧事件,防止日志无界增长。
|
|
52
52
|
const ACTIVITY_LIMIT = 5000
|
|
53
53
|
|
|
54
|
+
// 输入长度上限:与工具 schema 描述、客户端编辑器(CardDialog)保持一致。
|
|
55
|
+
// 超长输入在写入前被截断,并通过看板 warnings 通道发出一次性警告(见 clampText),
|
|
56
|
+
// 因此 agent 与用户都能感知到内容被裁剪,而不是静默丢失。
|
|
57
|
+
export const TITLE_LIMIT = 120
|
|
58
|
+
export const NOTE_LIMIT = 2000
|
|
59
|
+
export const LABEL_LIMIT = 20
|
|
60
|
+
export const COLUMN_TITLE_LIMIT = 40
|
|
61
|
+
export const COMMENT_LIMIT = 2000
|
|
62
|
+
|
|
54
63
|
const isObj = (v) => typeof v === 'object' && v !== null && !Array.isArray(v)
|
|
55
64
|
const strField = (v, fb) => (typeof v === 'string' && v ? v : fb)
|
|
56
65
|
const normColor = (v) => (typeof v === 'string' && /^#[0-9a-fA-F]{6}$/.test(v) ? v.toLowerCase() : '#94a3b8')
|
|
@@ -526,6 +535,16 @@ export function apply(ctx) {
|
|
|
526
535
|
|
|
527
536
|
// ---- 校验 / 查找 / 序列化 ----
|
|
528
537
|
const str = (v, fb) => (typeof v === 'string' ? v : fb)
|
|
538
|
+
|
|
539
|
+
// 截断辅助:把输入裁到 limit 以内;一旦实际发生截断,就经看板 warnings 通道
|
|
540
|
+
// 发出一次性警告(同时写入宿主日志),避免内容被静默丢弃。
|
|
541
|
+
const clampText = (value, limit, field, board) => {
|
|
542
|
+
const s = str(value, '')
|
|
543
|
+
if (s.length <= limit) return s
|
|
544
|
+
warn(board, field + ' truncated to ' + limit + ' characters')
|
|
545
|
+
return s.slice(0, limit)
|
|
546
|
+
}
|
|
547
|
+
|
|
529
548
|
const PRIORITIES = ['high', 'medium', 'low']
|
|
530
549
|
const normPriority = (v) => (typeof v === 'string' && PRIORITIES.includes(v) ? v : undefined)
|
|
531
550
|
const normColor = (v) => (typeof v === 'string' && /^#[0-9a-fA-F]{6}$/.test(v) ? v.toLowerCase() : undefined)
|
|
@@ -611,13 +630,13 @@ export function apply(ctx) {
|
|
|
611
630
|
case 'addCard': {
|
|
612
631
|
const col = findColumn(board, str(a.columnId, '')) || board.columns[0]
|
|
613
632
|
if (!col) return result({ error: 'No list available' })
|
|
614
|
-
const label = typeof a.label === 'string' ? a.label
|
|
633
|
+
const label = typeof a.label === 'string' ? clampText(a.label, LABEL_LIMIT, 'Label', board) : undefined
|
|
615
634
|
if (label && !findLabel(board, label)) return result({ error: 'Label not found: ' + label })
|
|
616
635
|
const card = {
|
|
617
636
|
id: nextId('k'),
|
|
618
637
|
columnId: col.id,
|
|
619
|
-
title:
|
|
620
|
-
note:
|
|
638
|
+
title: clampText(a.title, TITLE_LIMIT, 'Title', board) || 'Untitled card',
|
|
639
|
+
note: clampText(a.note, NOTE_LIMIT, 'Note', board),
|
|
621
640
|
label,
|
|
622
641
|
priority: normPriority(a.priority),
|
|
623
642
|
createdAt: new Date().toISOString(),
|
|
@@ -643,7 +662,7 @@ export function apply(ctx) {
|
|
|
643
662
|
case 'updateCard': {
|
|
644
663
|
const card = findCard(board, str(a.id, ''))
|
|
645
664
|
if (card) {
|
|
646
|
-
const nextLabel = typeof a.label === 'string' ? a.label
|
|
665
|
+
const nextLabel = typeof a.label === 'string' ? clampText(a.label, LABEL_LIMIT, 'Label', board) : undefined
|
|
647
666
|
if (nextLabel && !findLabel(board, nextLabel)) return result({ error: 'Label not found: ' + nextLabel })
|
|
648
667
|
const before = {
|
|
649
668
|
title: card.title,
|
|
@@ -651,8 +670,8 @@ export function apply(ctx) {
|
|
|
651
670
|
label: card.label ?? null,
|
|
652
671
|
priority: card.priority ?? null,
|
|
653
672
|
}
|
|
654
|
-
if (typeof a.title === 'string') card.title = a.title
|
|
655
|
-
if (typeof a.note === 'string') card.note = a.note
|
|
673
|
+
if (typeof a.title === 'string') card.title = clampText(a.title, TITLE_LIMIT, 'Title', board) || card.title
|
|
674
|
+
if (typeof a.note === 'string') card.note = clampText(a.note, NOTE_LIMIT, 'Note', board)
|
|
656
675
|
if (typeof a.label === 'string') card.label = nextLabel || undefined
|
|
657
676
|
if (typeof a.priority === 'string') card.priority = normPriority(a.priority)
|
|
658
677
|
const after = {
|
|
@@ -685,7 +704,7 @@ export function apply(ctx) {
|
|
|
685
704
|
if (!card) return result({ error: 'Card not found: ' + str(a.id, '') })
|
|
686
705
|
const content = str(a.content, '').trim()
|
|
687
706
|
if (!content) return result({ error: 'Comment content required' })
|
|
688
|
-
if (content.length >
|
|
707
|
+
if (content.length > COMMENT_LIMIT) return result({ error: 'Comment exceeds ' + COMMENT_LIMIT + ' characters' })
|
|
689
708
|
const comment = {
|
|
690
709
|
id: nextId('m'),
|
|
691
710
|
content,
|
|
@@ -731,7 +750,7 @@ export function apply(ctx) {
|
|
|
731
750
|
}
|
|
732
751
|
|
|
733
752
|
case 'addColumn': {
|
|
734
|
-
const title =
|
|
753
|
+
const title = clampText(a.title, COLUMN_TITLE_LIMIT, 'List title', board) || 'New list'
|
|
735
754
|
board.columns.push({ id: nextId('c'), title })
|
|
736
755
|
record(board, { cardId: null, type: 'column_added', source: actor, meta: { column: title } })
|
|
737
756
|
await save(workspace, session)
|
|
@@ -742,7 +761,7 @@ export function apply(ctx) {
|
|
|
742
761
|
const col = findColumn(board, str(a.id, ''))
|
|
743
762
|
if (col && typeof a.title === 'string') {
|
|
744
763
|
const before = col.title
|
|
745
|
-
col.title = a.title
|
|
764
|
+
col.title = clampText(a.title, COLUMN_TITLE_LIMIT, 'List title', board) || col.title
|
|
746
765
|
if (col.title !== before) {
|
|
747
766
|
record(board, { cardId: null, type: 'column_renamed', source: actor, field: 'title', from: before, to: col.title, meta: { column: col.title } })
|
|
748
767
|
}
|
|
@@ -784,7 +803,7 @@ export function apply(ctx) {
|
|
|
784
803
|
}
|
|
785
804
|
|
|
786
805
|
case 'addLabel': {
|
|
787
|
-
const name =
|
|
806
|
+
const name = clampText(a.name, LABEL_LIMIT, 'Label name', board)
|
|
788
807
|
if (!name) return result({ error: 'Label name required' })
|
|
789
808
|
if (findLabel(board, name)) return result({ error: 'Label already exists' })
|
|
790
809
|
board.labels.push({ name, color: normColor(a.color) || '#94a3b8' })
|
|
@@ -797,7 +816,7 @@ export function apply(ctx) {
|
|
|
797
816
|
const name = str(a.name, '')
|
|
798
817
|
const label = findLabel(board, name)
|
|
799
818
|
if (!label) return result({ error: 'Label not found' })
|
|
800
|
-
const newName =
|
|
819
|
+
const newName = clampText(a.newName, LABEL_LIMIT, 'Label name', board)
|
|
801
820
|
if (newName && newName !== name) {
|
|
802
821
|
if (findLabel(board, newName)) return result({ error: 'Label name already exists' })
|
|
803
822
|
label.name = newName
|
|
@@ -1186,10 +1205,10 @@ export function apply(ctx) {
|
|
|
1186
1205
|
parameters: {
|
|
1187
1206
|
type: 'object',
|
|
1188
1207
|
properties: {
|
|
1189
|
-
title: { type: 'string', description:
|
|
1208
|
+
title: { type: 'string', description: `Card title (task name, concise and actionable; max ${TITLE_LIMIT} chars)` },
|
|
1190
1209
|
columnId: { type: 'string', description: 'Target list id; defaults to the first list (Todo)' },
|
|
1191
|
-
note: { type: 'string', description:
|
|
1192
|
-
label: { type: 'string', description:
|
|
1210
|
+
note: { type: 'string', description: `Note: background, acceptance criteria or breakdown details (optional; max ${NOTE_LIMIT} chars)` },
|
|
1211
|
+
label: { type: 'string', description: `Label name (optional; max ${LABEL_LIMIT} chars): e.g. New Feature, bug, Feedback` },
|
|
1193
1212
|
priority: { type: 'string', enum: ['high', 'medium', 'low'], description: 'Priority (optional): high=P0 / medium=P1 / low=P2' },
|
|
1194
1213
|
},
|
|
1195
1214
|
required: ['title'],
|
|
@@ -1206,9 +1225,9 @@ export function apply(ctx) {
|
|
|
1206
1225
|
type: 'object',
|
|
1207
1226
|
properties: {
|
|
1208
1227
|
id: { type: 'string', description: 'Card id' },
|
|
1209
|
-
title: { type: 'string', description:
|
|
1210
|
-
note: { type: 'string', description:
|
|
1211
|
-
label: { type: 'string', description:
|
|
1228
|
+
title: { type: 'string', description: `New title (optional; max ${TITLE_LIMIT} chars)` },
|
|
1229
|
+
note: { type: 'string', description: `New note (optional; max ${NOTE_LIMIT} chars)` },
|
|
1230
|
+
label: { type: 'string', description: `New label name (optional; max ${LABEL_LIMIT} chars); pass empty string to clear` },
|
|
1212
1231
|
priority: { type: 'string', enum: ['high', 'medium', 'low', ''], description: 'New priority (optional): high=P0 / medium=P1 / low=P2; pass empty string to clear' },
|
|
1213
1232
|
},
|
|
1214
1233
|
required: ['id'],
|
|
@@ -1253,7 +1272,7 @@ export function apply(ctx) {
|
|
|
1253
1272
|
description: 'Add a list (column) to the board. Use when a new workflow stage (e.g. Review, Blocked) is needed.',
|
|
1254
1273
|
parameters: {
|
|
1255
1274
|
type: 'object',
|
|
1256
|
-
properties: { title: { type: 'string', description:
|
|
1275
|
+
properties: { title: { type: 'string', description: `List name (max ${COLUMN_TITLE_LIMIT} chars)` } },
|
|
1257
1276
|
required: ['title'],
|
|
1258
1277
|
},
|
|
1259
1278
|
output: output(renderBoard),
|
|
@@ -1268,7 +1287,7 @@ export function apply(ctx) {
|
|
|
1268
1287
|
type: 'object',
|
|
1269
1288
|
properties: {
|
|
1270
1289
|
id: { type: 'string', description: 'List id' },
|
|
1271
|
-
title: { type: 'string', description:
|
|
1290
|
+
title: { type: 'string', description: `New name (max ${COLUMN_TITLE_LIMIT} chars)` },
|
|
1272
1291
|
},
|
|
1273
1292
|
required: ['id', 'title'],
|
|
1274
1293
|
},
|
|
@@ -1312,7 +1331,7 @@ export function apply(ctx) {
|
|
|
1312
1331
|
parameters: {
|
|
1313
1332
|
type: 'object',
|
|
1314
1333
|
properties: {
|
|
1315
|
-
name: { type: 'string', description:
|
|
1334
|
+
name: { type: 'string', description: `Label name (unique, max ${LABEL_LIMIT} chars; e.g. Urgent, Refactor)` },
|
|
1316
1335
|
color: { type: 'string', description: 'Label color (optional): #rrggbb hex; defaults to gray' },
|
|
1317
1336
|
},
|
|
1318
1337
|
required: ['name'],
|
|
@@ -1329,7 +1348,7 @@ export function apply(ctx) {
|
|
|
1329
1348
|
type: 'object',
|
|
1330
1349
|
properties: {
|
|
1331
1350
|
name: { type: 'string', description: 'Current label name' },
|
|
1332
|
-
newName: { type: 'string', description:
|
|
1351
|
+
newName: { type: 'string', description: `New name (optional; max ${LABEL_LIMIT} chars)` },
|
|
1333
1352
|
color: { type: 'string', description: 'New color (optional): #rrggbb hex' },
|
|
1334
1353
|
},
|
|
1335
1354
|
required: ['name'],
|