kanban-lite 1.0.39 → 1.0.41
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/dist/cli.js +1779 -1473
- package/dist/extension.js +1483 -1257
- package/dist/mcp-server.js +1207 -953
- package/dist/sdk/index.cjs +1156 -774
- package/dist/sdk/index.mjs +1156 -774
- package/dist/sdk/sdk/KanbanSDK.d.ts +58 -20
- package/dist/sdk/sdk/modules/attachments.d.ts +18 -0
- package/dist/sdk/sdk/modules/boards.d.ts +49 -0
- package/dist/sdk/sdk/modules/cards.d.ts +47 -0
- package/dist/sdk/sdk/modules/columns.d.ts +30 -0
- package/dist/sdk/sdk/modules/comments.d.ts +18 -0
- package/dist/sdk/sdk/modules/context.d.ts +35 -0
- package/dist/sdk/sdk/modules/labels.d.ts +26 -0
- package/dist/sdk/sdk/modules/logs.d.ts +42 -0
- package/dist/sdk/sdk/modules/migration.d.ts +9 -0
- package/dist/sdk/sdk/modules/settings.d.ts +14 -0
- package/dist/sdk/sdk/webhooks.d.ts +61 -0
- package/package.json +1 -1
- package/src/cli/index.ts +45 -60
- package/src/extension/KanbanPanel.ts +10 -27
- package/src/mcp-server/index.ts +17 -34
- package/src/sdk/KanbanSDK.ts +132 -828
- package/src/sdk/modules/attachments.ts +60 -0
- package/src/sdk/modules/boards.ts +258 -0
- package/src/sdk/modules/cards.ts +323 -0
- package/src/sdk/modules/columns.ts +135 -0
- package/src/sdk/modules/comments.ts +96 -0
- package/src/sdk/modules/context.ts +40 -0
- package/src/sdk/modules/labels.ts +82 -0
- package/src/sdk/modules/logs.ts +195 -0
- package/src/sdk/modules/migration.ts +81 -0
- package/src/sdk/modules/settings.ts +31 -0
- package/src/sdk/webhooks.ts +192 -0
- package/src/standalone/__tests__/server.integration.test.ts +30 -28
- package/src/standalone/server.ts +43 -42
- package/src/standalone/webhooks.ts +2 -223
package/dist/cli.js
CHANGED
|
@@ -33,221 +33,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
33
|
mod
|
|
34
34
|
));
|
|
35
35
|
|
|
36
|
-
// node_modules/.pnpm/fractional-indexing@3.2.0/node_modules/fractional-indexing/src/index.js
|
|
37
|
-
function midpoint(a, b, digits) {
|
|
38
|
-
const zero = digits[0];
|
|
39
|
-
if (b != null && a >= b) {
|
|
40
|
-
throw new Error(a + " >= " + b);
|
|
41
|
-
}
|
|
42
|
-
if (a.slice(-1) === zero || b && b.slice(-1) === zero) {
|
|
43
|
-
throw new Error("trailing zero");
|
|
44
|
-
}
|
|
45
|
-
if (b) {
|
|
46
|
-
let n = 0;
|
|
47
|
-
while ((a[n] || zero) === b[n]) {
|
|
48
|
-
n++;
|
|
49
|
-
}
|
|
50
|
-
if (n > 0) {
|
|
51
|
-
return b.slice(0, n) + midpoint(a.slice(n), b.slice(n), digits);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
const digitA = a ? digits.indexOf(a[0]) : 0;
|
|
55
|
-
const digitB = b != null ? digits.indexOf(b[0]) : digits.length;
|
|
56
|
-
if (digitB - digitA > 1) {
|
|
57
|
-
const midDigit = Math.round(0.5 * (digitA + digitB));
|
|
58
|
-
return digits[midDigit];
|
|
59
|
-
} else {
|
|
60
|
-
if (b && b.length > 1) {
|
|
61
|
-
return b.slice(0, 1);
|
|
62
|
-
} else {
|
|
63
|
-
return digits[digitA] + midpoint(a.slice(1), null, digits);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function validateInteger(int4) {
|
|
68
|
-
if (int4.length !== getIntegerLength(int4[0])) {
|
|
69
|
-
throw new Error("invalid integer part of order key: " + int4);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function getIntegerLength(head) {
|
|
73
|
-
if (head >= "a" && head <= "z") {
|
|
74
|
-
return head.charCodeAt(0) - "a".charCodeAt(0) + 2;
|
|
75
|
-
} else if (head >= "A" && head <= "Z") {
|
|
76
|
-
return "Z".charCodeAt(0) - head.charCodeAt(0) + 2;
|
|
77
|
-
} else {
|
|
78
|
-
throw new Error("invalid order key head: " + head);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
function getIntegerPart(key) {
|
|
82
|
-
const integerPartLength = getIntegerLength(key[0]);
|
|
83
|
-
if (integerPartLength > key.length) {
|
|
84
|
-
throw new Error("invalid order key: " + key);
|
|
85
|
-
}
|
|
86
|
-
return key.slice(0, integerPartLength);
|
|
87
|
-
}
|
|
88
|
-
function validateOrderKey(key, digits) {
|
|
89
|
-
if (key === "A" + digits[0].repeat(26)) {
|
|
90
|
-
throw new Error("invalid order key: " + key);
|
|
91
|
-
}
|
|
92
|
-
const i = getIntegerPart(key);
|
|
93
|
-
const f = key.slice(i.length);
|
|
94
|
-
if (f.slice(-1) === digits[0]) {
|
|
95
|
-
throw new Error("invalid order key: " + key);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
function incrementInteger(x, digits) {
|
|
99
|
-
validateInteger(x);
|
|
100
|
-
const [head, ...digs] = x.split("");
|
|
101
|
-
let carry = true;
|
|
102
|
-
for (let i = digs.length - 1; carry && i >= 0; i--) {
|
|
103
|
-
const d = digits.indexOf(digs[i]) + 1;
|
|
104
|
-
if (d === digits.length) {
|
|
105
|
-
digs[i] = digits[0];
|
|
106
|
-
} else {
|
|
107
|
-
digs[i] = digits[d];
|
|
108
|
-
carry = false;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if (carry) {
|
|
112
|
-
if (head === "Z") {
|
|
113
|
-
return "a" + digits[0];
|
|
114
|
-
}
|
|
115
|
-
if (head === "z") {
|
|
116
|
-
return null;
|
|
117
|
-
}
|
|
118
|
-
const h = String.fromCharCode(head.charCodeAt(0) + 1);
|
|
119
|
-
if (h > "a") {
|
|
120
|
-
digs.push(digits[0]);
|
|
121
|
-
} else {
|
|
122
|
-
digs.pop();
|
|
123
|
-
}
|
|
124
|
-
return h + digs.join("");
|
|
125
|
-
} else {
|
|
126
|
-
return head + digs.join("");
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
function decrementInteger(x, digits) {
|
|
130
|
-
validateInteger(x);
|
|
131
|
-
const [head, ...digs] = x.split("");
|
|
132
|
-
let borrow = true;
|
|
133
|
-
for (let i = digs.length - 1; borrow && i >= 0; i--) {
|
|
134
|
-
const d = digits.indexOf(digs[i]) - 1;
|
|
135
|
-
if (d === -1) {
|
|
136
|
-
digs[i] = digits.slice(-1);
|
|
137
|
-
} else {
|
|
138
|
-
digs[i] = digits[d];
|
|
139
|
-
borrow = false;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
if (borrow) {
|
|
143
|
-
if (head === "a") {
|
|
144
|
-
return "Z" + digits.slice(-1);
|
|
145
|
-
}
|
|
146
|
-
if (head === "A") {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
const h = String.fromCharCode(head.charCodeAt(0) - 1);
|
|
150
|
-
if (h < "Z") {
|
|
151
|
-
digs.push(digits.slice(-1));
|
|
152
|
-
} else {
|
|
153
|
-
digs.pop();
|
|
154
|
-
}
|
|
155
|
-
return h + digs.join("");
|
|
156
|
-
} else {
|
|
157
|
-
return head + digs.join("");
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
function generateKeyBetween(a, b, digits = BASE_62_DIGITS) {
|
|
161
|
-
if (a != null) {
|
|
162
|
-
validateOrderKey(a, digits);
|
|
163
|
-
}
|
|
164
|
-
if (b != null) {
|
|
165
|
-
validateOrderKey(b, digits);
|
|
166
|
-
}
|
|
167
|
-
if (a != null && b != null && a >= b) {
|
|
168
|
-
throw new Error(a + " >= " + b);
|
|
169
|
-
}
|
|
170
|
-
if (a == null) {
|
|
171
|
-
if (b == null) {
|
|
172
|
-
return "a" + digits[0];
|
|
173
|
-
}
|
|
174
|
-
const ib2 = getIntegerPart(b);
|
|
175
|
-
const fb2 = b.slice(ib2.length);
|
|
176
|
-
if (ib2 === "A" + digits[0].repeat(26)) {
|
|
177
|
-
return ib2 + midpoint("", fb2, digits);
|
|
178
|
-
}
|
|
179
|
-
if (ib2 < b) {
|
|
180
|
-
return ib2;
|
|
181
|
-
}
|
|
182
|
-
const res = decrementInteger(ib2, digits);
|
|
183
|
-
if (res == null) {
|
|
184
|
-
throw new Error("cannot decrement any more");
|
|
185
|
-
}
|
|
186
|
-
return res;
|
|
187
|
-
}
|
|
188
|
-
if (b == null) {
|
|
189
|
-
const ia2 = getIntegerPart(a);
|
|
190
|
-
const fa2 = a.slice(ia2.length);
|
|
191
|
-
const i2 = incrementInteger(ia2, digits);
|
|
192
|
-
return i2 == null ? ia2 + midpoint(fa2, null, digits) : i2;
|
|
193
|
-
}
|
|
194
|
-
const ia = getIntegerPart(a);
|
|
195
|
-
const fa = a.slice(ia.length);
|
|
196
|
-
const ib = getIntegerPart(b);
|
|
197
|
-
const fb = b.slice(ib.length);
|
|
198
|
-
if (ia === ib) {
|
|
199
|
-
return ia + midpoint(fa, fb, digits);
|
|
200
|
-
}
|
|
201
|
-
const i = incrementInteger(ia, digits);
|
|
202
|
-
if (i == null) {
|
|
203
|
-
throw new Error("cannot increment any more");
|
|
204
|
-
}
|
|
205
|
-
if (i < b) {
|
|
206
|
-
return i;
|
|
207
|
-
}
|
|
208
|
-
return ia + midpoint(fa, null, digits);
|
|
209
|
-
}
|
|
210
|
-
function generateNKeysBetween(a, b, n, digits = BASE_62_DIGITS) {
|
|
211
|
-
if (n === 0) {
|
|
212
|
-
return [];
|
|
213
|
-
}
|
|
214
|
-
if (n === 1) {
|
|
215
|
-
return [generateKeyBetween(a, b, digits)];
|
|
216
|
-
}
|
|
217
|
-
if (b == null) {
|
|
218
|
-
let c2 = generateKeyBetween(a, b, digits);
|
|
219
|
-
const result = [c2];
|
|
220
|
-
for (let i = 0; i < n - 1; i++) {
|
|
221
|
-
c2 = generateKeyBetween(c2, b, digits);
|
|
222
|
-
result.push(c2);
|
|
223
|
-
}
|
|
224
|
-
return result;
|
|
225
|
-
}
|
|
226
|
-
if (a == null) {
|
|
227
|
-
let c2 = generateKeyBetween(a, b, digits);
|
|
228
|
-
const result = [c2];
|
|
229
|
-
for (let i = 0; i < n - 1; i++) {
|
|
230
|
-
c2 = generateKeyBetween(a, c2, digits);
|
|
231
|
-
result.push(c2);
|
|
232
|
-
}
|
|
233
|
-
result.reverse();
|
|
234
|
-
return result;
|
|
235
|
-
}
|
|
236
|
-
const mid = Math.floor(n / 2);
|
|
237
|
-
const c = generateKeyBetween(a, b, digits);
|
|
238
|
-
return [
|
|
239
|
-
...generateNKeysBetween(a, c, mid, digits),
|
|
240
|
-
c,
|
|
241
|
-
...generateNKeysBetween(c, b, n - mid - 1, digits)
|
|
242
|
-
];
|
|
243
|
-
}
|
|
244
|
-
var BASE_62_DIGITS;
|
|
245
|
-
var init_src = __esm({
|
|
246
|
-
"node_modules/.pnpm/fractional-indexing@3.2.0/node_modules/fractional-indexing/src/index.js"() {
|
|
247
|
-
BASE_62_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
36
|
// src/shared/types.ts
|
|
252
37
|
function getTitleFromContent(content) {
|
|
253
38
|
const match = content.match(/^#\s+(.+)$/m);
|
|
@@ -3224,11 +3009,11 @@ var init_js_yaml = __esm({
|
|
|
3224
3009
|
|
|
3225
3010
|
// src/sdk/parser.ts
|
|
3226
3011
|
function extractIdFromFilename(filePath) {
|
|
3227
|
-
const
|
|
3228
|
-
const numericMatch =
|
|
3012
|
+
const basename10 = path3.basename(filePath, ".md");
|
|
3013
|
+
const numericMatch = basename10.match(/^(\d+)-/);
|
|
3229
3014
|
if (numericMatch)
|
|
3230
3015
|
return numericMatch[1];
|
|
3231
|
-
return
|
|
3016
|
+
return basename10;
|
|
3232
3017
|
}
|
|
3233
3018
|
function parseCommentBlock(header, body) {
|
|
3234
3019
|
const getValue = (key) => {
|
|
@@ -3611,21 +3396,21 @@ var require_file_uri_to_path = __commonJS({
|
|
|
3611
3396
|
var rest = decodeURI(uri.substring(7));
|
|
3612
3397
|
var firstSlash = rest.indexOf("/");
|
|
3613
3398
|
var host = rest.substring(0, firstSlash);
|
|
3614
|
-
var
|
|
3399
|
+
var path17 = rest.substring(firstSlash + 1);
|
|
3615
3400
|
if ("localhost" == host)
|
|
3616
3401
|
host = "";
|
|
3617
3402
|
if (host) {
|
|
3618
3403
|
host = sep2 + sep2 + host;
|
|
3619
3404
|
}
|
|
3620
|
-
|
|
3405
|
+
path17 = path17.replace(/^(.+)\|/, "$1:");
|
|
3621
3406
|
if (sep2 == "\\") {
|
|
3622
|
-
|
|
3407
|
+
path17 = path17.replace(/\//g, "\\");
|
|
3623
3408
|
}
|
|
3624
|
-
if (/^.+\:/.test(
|
|
3409
|
+
if (/^.+\:/.test(path17)) {
|
|
3625
3410
|
} else {
|
|
3626
|
-
|
|
3411
|
+
path17 = sep2 + path17;
|
|
3627
3412
|
}
|
|
3628
|
-
return host +
|
|
3413
|
+
return host + path17;
|
|
3629
3414
|
}
|
|
3630
3415
|
}
|
|
3631
3416
|
});
|
|
@@ -3633,19 +3418,19 @@ var require_file_uri_to_path = __commonJS({
|
|
|
3633
3418
|
// node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js
|
|
3634
3419
|
var require_bindings = __commonJS({
|
|
3635
3420
|
"node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js"(exports2, module2) {
|
|
3636
|
-
var
|
|
3637
|
-
var
|
|
3421
|
+
var fs16 = require("fs");
|
|
3422
|
+
var path17 = require("path");
|
|
3638
3423
|
var fileURLToPath2 = require_file_uri_to_path();
|
|
3639
|
-
var
|
|
3640
|
-
var
|
|
3641
|
-
var exists =
|
|
3424
|
+
var join16 = path17.join;
|
|
3425
|
+
var dirname12 = path17.dirname;
|
|
3426
|
+
var exists = fs16.accessSync && function(path18) {
|
|
3642
3427
|
try {
|
|
3643
|
-
|
|
3428
|
+
fs16.accessSync(path18);
|
|
3644
3429
|
} catch (e) {
|
|
3645
3430
|
return false;
|
|
3646
3431
|
}
|
|
3647
3432
|
return true;
|
|
3648
|
-
} ||
|
|
3433
|
+
} || fs16.existsSync || path17.existsSync;
|
|
3649
3434
|
var defaults = {
|
|
3650
3435
|
arrow: process.env.NODE_BINDINGS_ARROW || " \u2192 ",
|
|
3651
3436
|
compiled: process.env.NODE_BINDINGS_COMPILED_DIR || "compiled",
|
|
@@ -3691,13 +3476,13 @@ var require_bindings = __commonJS({
|
|
|
3691
3476
|
if (!opts.module_root) {
|
|
3692
3477
|
opts.module_root = exports2.getRoot(exports2.getFileName());
|
|
3693
3478
|
}
|
|
3694
|
-
if (
|
|
3479
|
+
if (path17.extname(opts.bindings) != ".node") {
|
|
3695
3480
|
opts.bindings += ".node";
|
|
3696
3481
|
}
|
|
3697
3482
|
var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
|
|
3698
3483
|
var tries = [], i = 0, l = opts.try.length, n, b, err;
|
|
3699
3484
|
for (; i < l; i++) {
|
|
3700
|
-
n =
|
|
3485
|
+
n = join16.apply(
|
|
3701
3486
|
null,
|
|
3702
3487
|
opts.try[i].map(function(p) {
|
|
3703
3488
|
return opts[p] || p;
|
|
@@ -3753,12 +3538,12 @@ var require_bindings = __commonJS({
|
|
|
3753
3538
|
return fileName;
|
|
3754
3539
|
};
|
|
3755
3540
|
exports2.getRoot = function getRoot(file3) {
|
|
3756
|
-
var dir =
|
|
3541
|
+
var dir = dirname12(file3), prev;
|
|
3757
3542
|
while (true) {
|
|
3758
3543
|
if (dir === ".") {
|
|
3759
3544
|
dir = process.cwd();
|
|
3760
3545
|
}
|
|
3761
|
-
if (exists(
|
|
3546
|
+
if (exists(join16(dir, "package.json")) || exists(join16(dir, "node_modules"))) {
|
|
3762
3547
|
return dir;
|
|
3763
3548
|
}
|
|
3764
3549
|
if (prev === dir) {
|
|
@@ -3767,7 +3552,7 @@ var require_bindings = __commonJS({
|
|
|
3767
3552
|
);
|
|
3768
3553
|
}
|
|
3769
3554
|
prev = dir;
|
|
3770
|
-
dir =
|
|
3555
|
+
dir = join16(dir, "..");
|
|
3771
3556
|
}
|
|
3772
3557
|
};
|
|
3773
3558
|
}
|
|
@@ -3934,11 +3719,11 @@ var require_pragma = __commonJS({
|
|
|
3934
3719
|
var require_backup = __commonJS({
|
|
3935
3720
|
"node_modules/.pnpm/better-sqlite3@12.6.2/node_modules/better-sqlite3/lib/methods/backup.js"(exports2, module2) {
|
|
3936
3721
|
"use strict";
|
|
3937
|
-
var
|
|
3938
|
-
var
|
|
3722
|
+
var fs16 = require("fs");
|
|
3723
|
+
var path17 = require("path");
|
|
3939
3724
|
var { promisify: promisify6 } = require("util");
|
|
3940
3725
|
var { cppdb } = require_util();
|
|
3941
|
-
var fsAccess = promisify6(
|
|
3726
|
+
var fsAccess = promisify6(fs16.access);
|
|
3942
3727
|
module2.exports = async function backup(filename, options) {
|
|
3943
3728
|
if (options == null)
|
|
3944
3729
|
options = {};
|
|
@@ -3959,7 +3744,7 @@ var require_backup = __commonJS({
|
|
|
3959
3744
|
throw new TypeError('The "attached" option cannot be an empty string');
|
|
3960
3745
|
if (handler != null && typeof handler !== "function")
|
|
3961
3746
|
throw new TypeError('Expected the "progress" option to be a function');
|
|
3962
|
-
await fsAccess(
|
|
3747
|
+
await fsAccess(path17.dirname(filename)).catch(() => {
|
|
3963
3748
|
throw new TypeError("Cannot save backup because the directory does not exist");
|
|
3964
3749
|
});
|
|
3965
3750
|
const isNewFile = await fsAccess(filename).then(() => false, () => true);
|
|
@@ -4289,8 +4074,8 @@ var require_inspect = __commonJS({
|
|
|
4289
4074
|
var require_database = __commonJS({
|
|
4290
4075
|
"node_modules/.pnpm/better-sqlite3@12.6.2/node_modules/better-sqlite3/lib/database.js"(exports2, module2) {
|
|
4291
4076
|
"use strict";
|
|
4292
|
-
var
|
|
4293
|
-
var
|
|
4077
|
+
var fs16 = require("fs");
|
|
4078
|
+
var path17 = require("path");
|
|
4294
4079
|
var util2 = require_util();
|
|
4295
4080
|
var SqliteError = require_sqlite_error();
|
|
4296
4081
|
var DEFAULT_ADDON;
|
|
@@ -4337,7 +4122,7 @@ var require_database = __commonJS({
|
|
|
4337
4122
|
addon = DEFAULT_ADDON || (DEFAULT_ADDON = require_bindings()("better_sqlite3.node"));
|
|
4338
4123
|
} else if (typeof nativeBinding === "string") {
|
|
4339
4124
|
const requireFunc = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : require;
|
|
4340
|
-
addon = requireFunc(
|
|
4125
|
+
addon = requireFunc(path17.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
|
|
4341
4126
|
} else {
|
|
4342
4127
|
addon = nativeBinding;
|
|
4343
4128
|
}
|
|
@@ -4345,7 +4130,7 @@ var require_database = __commonJS({
|
|
|
4345
4130
|
addon.setErrorConstructor(SqliteError);
|
|
4346
4131
|
addon.isInitialized = true;
|
|
4347
4132
|
}
|
|
4348
|
-
if (!anonymous && !filename.startsWith("file:") && !
|
|
4133
|
+
if (!anonymous && !filename.startsWith("file:") && !fs16.existsSync(path17.dirname(filename))) {
|
|
4349
4134
|
throw new TypeError("Cannot open database because the directory does not exist");
|
|
4350
4135
|
}
|
|
4351
4136
|
Object.defineProperties(this, {
|
|
@@ -4617,7 +4402,7 @@ CREATE INDEX IF NOT EXISTS idx_comments_card ON comments (card_id, board_i
|
|
|
4617
4402
|
default_status = excluded.default_status,
|
|
4618
4403
|
default_priority = excluded.default_priority
|
|
4619
4404
|
`);
|
|
4620
|
-
const
|
|
4405
|
+
const deleteBoard2 = this.db.prepare("DELETE FROM boards WHERE id = ?");
|
|
4621
4406
|
const existingBoardIds = this.db.prepare("SELECT id FROM boards").all().map((r) => r.id);
|
|
4622
4407
|
const newBoardIds = new Set(Object.keys(config3.boards));
|
|
4623
4408
|
const doWrite = this.db.transaction(() => {
|
|
@@ -4634,7 +4419,7 @@ CREATE INDEX IF NOT EXISTS idx_comments_card ON comments (card_id, board_i
|
|
|
4634
4419
|
}
|
|
4635
4420
|
for (const id of existingBoardIds) {
|
|
4636
4421
|
if (!newBoardIds.has(id))
|
|
4637
|
-
|
|
4422
|
+
deleteBoard2.run(id);
|
|
4638
4423
|
}
|
|
4639
4424
|
this.db.prepare("DELETE FROM labels").run();
|
|
4640
4425
|
const insertLabel = this.db.prepare("INSERT INTO labels (name, color, group_name) VALUES (?, ?, ?)");
|
|
@@ -4866,9 +4651,9 @@ function createStorageEngine(kanbanDir, options = {}) {
|
|
|
4866
4651
|
}
|
|
4867
4652
|
function readBootstrapConfig(workspaceRoot) {
|
|
4868
4653
|
try {
|
|
4869
|
-
const
|
|
4654
|
+
const fs16 = require("fs");
|
|
4870
4655
|
const configFile = path7.join(workspaceRoot, ".kanban.json");
|
|
4871
|
-
const raw = JSON.parse(
|
|
4656
|
+
const raw = JSON.parse(fs16.readFileSync(configFile, "utf-8"));
|
|
4872
4657
|
return {
|
|
4873
4658
|
storageEngine: raw.storageEngine,
|
|
4874
4659
|
sqlitePath: raw.sqlitePath
|
|
@@ -4889,6 +4674,339 @@ var init_storage = __esm({
|
|
|
4889
4674
|
}
|
|
4890
4675
|
});
|
|
4891
4676
|
|
|
4677
|
+
// src/sdk/webhooks.ts
|
|
4678
|
+
function fireWebhooks(workspaceRoot, event, data) {
|
|
4679
|
+
const config3 = readConfig(workspaceRoot);
|
|
4680
|
+
const webhooks = config3.webhooks || [];
|
|
4681
|
+
const matching = webhooks.filter(
|
|
4682
|
+
(w) => w.active && (w.events.includes("*") || w.events.includes(event))
|
|
4683
|
+
);
|
|
4684
|
+
if (matching.length === 0)
|
|
4685
|
+
return;
|
|
4686
|
+
const payload = JSON.stringify({
|
|
4687
|
+
event,
|
|
4688
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4689
|
+
data
|
|
4690
|
+
});
|
|
4691
|
+
for (const webhook of matching) {
|
|
4692
|
+
deliverWebhook(webhook, event, payload).catch((err) => {
|
|
4693
|
+
console.error(`Webhook delivery failed for ${webhook.id} (${webhook.url}):`, err.message || err);
|
|
4694
|
+
});
|
|
4695
|
+
}
|
|
4696
|
+
}
|
|
4697
|
+
async function deliverWebhook(webhook, event, payload) {
|
|
4698
|
+
const url3 = new URL(webhook.url);
|
|
4699
|
+
const isHttps = url3.protocol === "https:";
|
|
4700
|
+
const transport = isHttps ? https : http;
|
|
4701
|
+
const headers = {
|
|
4702
|
+
"Content-Type": "application/json",
|
|
4703
|
+
"Content-Length": Buffer.byteLength(payload).toString(),
|
|
4704
|
+
"X-Webhook-Event": event
|
|
4705
|
+
};
|
|
4706
|
+
if (webhook.secret) {
|
|
4707
|
+
const signature = crypto.createHmac("sha256", webhook.secret).update(payload).digest("hex");
|
|
4708
|
+
headers["X-Webhook-Signature"] = `sha256=${signature}`;
|
|
4709
|
+
}
|
|
4710
|
+
return new Promise((resolve9, reject) => {
|
|
4711
|
+
const req = transport.request(
|
|
4712
|
+
{
|
|
4713
|
+
hostname: url3.hostname,
|
|
4714
|
+
port: url3.port || (isHttps ? 443 : 80),
|
|
4715
|
+
path: url3.pathname + url3.search,
|
|
4716
|
+
method: "POST",
|
|
4717
|
+
headers,
|
|
4718
|
+
timeout: 1e4
|
|
4719
|
+
},
|
|
4720
|
+
(res) => {
|
|
4721
|
+
res.resume();
|
|
4722
|
+
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
4723
|
+
resolve9();
|
|
4724
|
+
} else {
|
|
4725
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
4726
|
+
}
|
|
4727
|
+
}
|
|
4728
|
+
);
|
|
4729
|
+
req.on("error", reject);
|
|
4730
|
+
req.on("timeout", () => {
|
|
4731
|
+
req.destroy();
|
|
4732
|
+
reject(new Error("Timeout"));
|
|
4733
|
+
});
|
|
4734
|
+
req.write(payload);
|
|
4735
|
+
req.end();
|
|
4736
|
+
});
|
|
4737
|
+
}
|
|
4738
|
+
function loadWebhooks(workspaceRoot) {
|
|
4739
|
+
const config3 = readConfig(workspaceRoot);
|
|
4740
|
+
return config3.webhooks || [];
|
|
4741
|
+
}
|
|
4742
|
+
function saveWebhooks(workspaceRoot, webhooks) {
|
|
4743
|
+
const config3 = readConfig(workspaceRoot);
|
|
4744
|
+
config3.webhooks = webhooks;
|
|
4745
|
+
writeConfig(workspaceRoot, config3);
|
|
4746
|
+
}
|
|
4747
|
+
function createWebhook(workspaceRoot, webhookConfig) {
|
|
4748
|
+
const webhooks = loadWebhooks(workspaceRoot);
|
|
4749
|
+
const webhook = {
|
|
4750
|
+
id: "wh_" + crypto.randomBytes(8).toString("hex"),
|
|
4751
|
+
url: webhookConfig.url,
|
|
4752
|
+
events: webhookConfig.events,
|
|
4753
|
+
secret: webhookConfig.secret,
|
|
4754
|
+
active: true
|
|
4755
|
+
};
|
|
4756
|
+
webhooks.push(webhook);
|
|
4757
|
+
saveWebhooks(workspaceRoot, webhooks);
|
|
4758
|
+
return webhook;
|
|
4759
|
+
}
|
|
4760
|
+
function deleteWebhook(workspaceRoot, id) {
|
|
4761
|
+
const webhooks = loadWebhooks(workspaceRoot);
|
|
4762
|
+
const filtered = webhooks.filter((w) => w.id !== id);
|
|
4763
|
+
if (filtered.length === webhooks.length)
|
|
4764
|
+
return false;
|
|
4765
|
+
saveWebhooks(workspaceRoot, filtered);
|
|
4766
|
+
return true;
|
|
4767
|
+
}
|
|
4768
|
+
function updateWebhook(workspaceRoot, id, updates) {
|
|
4769
|
+
const webhooks = loadWebhooks(workspaceRoot);
|
|
4770
|
+
const webhook = webhooks.find((w) => w.id === id);
|
|
4771
|
+
if (!webhook)
|
|
4772
|
+
return null;
|
|
4773
|
+
if (updates.url !== void 0)
|
|
4774
|
+
webhook.url = updates.url;
|
|
4775
|
+
if (updates.events !== void 0)
|
|
4776
|
+
webhook.events = updates.events;
|
|
4777
|
+
if (updates.secret !== void 0)
|
|
4778
|
+
webhook.secret = updates.secret;
|
|
4779
|
+
if (updates.active !== void 0)
|
|
4780
|
+
webhook.active = updates.active;
|
|
4781
|
+
saveWebhooks(workspaceRoot, webhooks);
|
|
4782
|
+
return webhook;
|
|
4783
|
+
}
|
|
4784
|
+
var crypto, http, https;
|
|
4785
|
+
var init_webhooks = __esm({
|
|
4786
|
+
"src/sdk/webhooks.ts"() {
|
|
4787
|
+
"use strict";
|
|
4788
|
+
crypto = __toESM(require("crypto"));
|
|
4789
|
+
http = __toESM(require("http"));
|
|
4790
|
+
https = __toESM(require("https"));
|
|
4791
|
+
init_config();
|
|
4792
|
+
}
|
|
4793
|
+
});
|
|
4794
|
+
|
|
4795
|
+
// node_modules/.pnpm/fractional-indexing@3.2.0/node_modules/fractional-indexing/src/index.js
|
|
4796
|
+
function midpoint(a, b, digits) {
|
|
4797
|
+
const zero = digits[0];
|
|
4798
|
+
if (b != null && a >= b) {
|
|
4799
|
+
throw new Error(a + " >= " + b);
|
|
4800
|
+
}
|
|
4801
|
+
if (a.slice(-1) === zero || b && b.slice(-1) === zero) {
|
|
4802
|
+
throw new Error("trailing zero");
|
|
4803
|
+
}
|
|
4804
|
+
if (b) {
|
|
4805
|
+
let n = 0;
|
|
4806
|
+
while ((a[n] || zero) === b[n]) {
|
|
4807
|
+
n++;
|
|
4808
|
+
}
|
|
4809
|
+
if (n > 0) {
|
|
4810
|
+
return b.slice(0, n) + midpoint(a.slice(n), b.slice(n), digits);
|
|
4811
|
+
}
|
|
4812
|
+
}
|
|
4813
|
+
const digitA = a ? digits.indexOf(a[0]) : 0;
|
|
4814
|
+
const digitB = b != null ? digits.indexOf(b[0]) : digits.length;
|
|
4815
|
+
if (digitB - digitA > 1) {
|
|
4816
|
+
const midDigit = Math.round(0.5 * (digitA + digitB));
|
|
4817
|
+
return digits[midDigit];
|
|
4818
|
+
} else {
|
|
4819
|
+
if (b && b.length > 1) {
|
|
4820
|
+
return b.slice(0, 1);
|
|
4821
|
+
} else {
|
|
4822
|
+
return digits[digitA] + midpoint(a.slice(1), null, digits);
|
|
4823
|
+
}
|
|
4824
|
+
}
|
|
4825
|
+
}
|
|
4826
|
+
function validateInteger(int4) {
|
|
4827
|
+
if (int4.length !== getIntegerLength(int4[0])) {
|
|
4828
|
+
throw new Error("invalid integer part of order key: " + int4);
|
|
4829
|
+
}
|
|
4830
|
+
}
|
|
4831
|
+
function getIntegerLength(head) {
|
|
4832
|
+
if (head >= "a" && head <= "z") {
|
|
4833
|
+
return head.charCodeAt(0) - "a".charCodeAt(0) + 2;
|
|
4834
|
+
} else if (head >= "A" && head <= "Z") {
|
|
4835
|
+
return "Z".charCodeAt(0) - head.charCodeAt(0) + 2;
|
|
4836
|
+
} else {
|
|
4837
|
+
throw new Error("invalid order key head: " + head);
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4840
|
+
function getIntegerPart(key) {
|
|
4841
|
+
const integerPartLength = getIntegerLength(key[0]);
|
|
4842
|
+
if (integerPartLength > key.length) {
|
|
4843
|
+
throw new Error("invalid order key: " + key);
|
|
4844
|
+
}
|
|
4845
|
+
return key.slice(0, integerPartLength);
|
|
4846
|
+
}
|
|
4847
|
+
function validateOrderKey(key, digits) {
|
|
4848
|
+
if (key === "A" + digits[0].repeat(26)) {
|
|
4849
|
+
throw new Error("invalid order key: " + key);
|
|
4850
|
+
}
|
|
4851
|
+
const i = getIntegerPart(key);
|
|
4852
|
+
const f = key.slice(i.length);
|
|
4853
|
+
if (f.slice(-1) === digits[0]) {
|
|
4854
|
+
throw new Error("invalid order key: " + key);
|
|
4855
|
+
}
|
|
4856
|
+
}
|
|
4857
|
+
function incrementInteger(x, digits) {
|
|
4858
|
+
validateInteger(x);
|
|
4859
|
+
const [head, ...digs] = x.split("");
|
|
4860
|
+
let carry = true;
|
|
4861
|
+
for (let i = digs.length - 1; carry && i >= 0; i--) {
|
|
4862
|
+
const d = digits.indexOf(digs[i]) + 1;
|
|
4863
|
+
if (d === digits.length) {
|
|
4864
|
+
digs[i] = digits[0];
|
|
4865
|
+
} else {
|
|
4866
|
+
digs[i] = digits[d];
|
|
4867
|
+
carry = false;
|
|
4868
|
+
}
|
|
4869
|
+
}
|
|
4870
|
+
if (carry) {
|
|
4871
|
+
if (head === "Z") {
|
|
4872
|
+
return "a" + digits[0];
|
|
4873
|
+
}
|
|
4874
|
+
if (head === "z") {
|
|
4875
|
+
return null;
|
|
4876
|
+
}
|
|
4877
|
+
const h = String.fromCharCode(head.charCodeAt(0) + 1);
|
|
4878
|
+
if (h > "a") {
|
|
4879
|
+
digs.push(digits[0]);
|
|
4880
|
+
} else {
|
|
4881
|
+
digs.pop();
|
|
4882
|
+
}
|
|
4883
|
+
return h + digs.join("");
|
|
4884
|
+
} else {
|
|
4885
|
+
return head + digs.join("");
|
|
4886
|
+
}
|
|
4887
|
+
}
|
|
4888
|
+
function decrementInteger(x, digits) {
|
|
4889
|
+
validateInteger(x);
|
|
4890
|
+
const [head, ...digs] = x.split("");
|
|
4891
|
+
let borrow = true;
|
|
4892
|
+
for (let i = digs.length - 1; borrow && i >= 0; i--) {
|
|
4893
|
+
const d = digits.indexOf(digs[i]) - 1;
|
|
4894
|
+
if (d === -1) {
|
|
4895
|
+
digs[i] = digits.slice(-1);
|
|
4896
|
+
} else {
|
|
4897
|
+
digs[i] = digits[d];
|
|
4898
|
+
borrow = false;
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4901
|
+
if (borrow) {
|
|
4902
|
+
if (head === "a") {
|
|
4903
|
+
return "Z" + digits.slice(-1);
|
|
4904
|
+
}
|
|
4905
|
+
if (head === "A") {
|
|
4906
|
+
return null;
|
|
4907
|
+
}
|
|
4908
|
+
const h = String.fromCharCode(head.charCodeAt(0) - 1);
|
|
4909
|
+
if (h < "Z") {
|
|
4910
|
+
digs.push(digits.slice(-1));
|
|
4911
|
+
} else {
|
|
4912
|
+
digs.pop();
|
|
4913
|
+
}
|
|
4914
|
+
return h + digs.join("");
|
|
4915
|
+
} else {
|
|
4916
|
+
return head + digs.join("");
|
|
4917
|
+
}
|
|
4918
|
+
}
|
|
4919
|
+
function generateKeyBetween(a, b, digits = BASE_62_DIGITS) {
|
|
4920
|
+
if (a != null) {
|
|
4921
|
+
validateOrderKey(a, digits);
|
|
4922
|
+
}
|
|
4923
|
+
if (b != null) {
|
|
4924
|
+
validateOrderKey(b, digits);
|
|
4925
|
+
}
|
|
4926
|
+
if (a != null && b != null && a >= b) {
|
|
4927
|
+
throw new Error(a + " >= " + b);
|
|
4928
|
+
}
|
|
4929
|
+
if (a == null) {
|
|
4930
|
+
if (b == null) {
|
|
4931
|
+
return "a" + digits[0];
|
|
4932
|
+
}
|
|
4933
|
+
const ib2 = getIntegerPart(b);
|
|
4934
|
+
const fb2 = b.slice(ib2.length);
|
|
4935
|
+
if (ib2 === "A" + digits[0].repeat(26)) {
|
|
4936
|
+
return ib2 + midpoint("", fb2, digits);
|
|
4937
|
+
}
|
|
4938
|
+
if (ib2 < b) {
|
|
4939
|
+
return ib2;
|
|
4940
|
+
}
|
|
4941
|
+
const res = decrementInteger(ib2, digits);
|
|
4942
|
+
if (res == null) {
|
|
4943
|
+
throw new Error("cannot decrement any more");
|
|
4944
|
+
}
|
|
4945
|
+
return res;
|
|
4946
|
+
}
|
|
4947
|
+
if (b == null) {
|
|
4948
|
+
const ia2 = getIntegerPart(a);
|
|
4949
|
+
const fa2 = a.slice(ia2.length);
|
|
4950
|
+
const i2 = incrementInteger(ia2, digits);
|
|
4951
|
+
return i2 == null ? ia2 + midpoint(fa2, null, digits) : i2;
|
|
4952
|
+
}
|
|
4953
|
+
const ia = getIntegerPart(a);
|
|
4954
|
+
const fa = a.slice(ia.length);
|
|
4955
|
+
const ib = getIntegerPart(b);
|
|
4956
|
+
const fb = b.slice(ib.length);
|
|
4957
|
+
if (ia === ib) {
|
|
4958
|
+
return ia + midpoint(fa, fb, digits);
|
|
4959
|
+
}
|
|
4960
|
+
const i = incrementInteger(ia, digits);
|
|
4961
|
+
if (i == null) {
|
|
4962
|
+
throw new Error("cannot increment any more");
|
|
4963
|
+
}
|
|
4964
|
+
if (i < b) {
|
|
4965
|
+
return i;
|
|
4966
|
+
}
|
|
4967
|
+
return ia + midpoint(fa, null, digits);
|
|
4968
|
+
}
|
|
4969
|
+
function generateNKeysBetween(a, b, n, digits = BASE_62_DIGITS) {
|
|
4970
|
+
if (n === 0) {
|
|
4971
|
+
return [];
|
|
4972
|
+
}
|
|
4973
|
+
if (n === 1) {
|
|
4974
|
+
return [generateKeyBetween(a, b, digits)];
|
|
4975
|
+
}
|
|
4976
|
+
if (b == null) {
|
|
4977
|
+
let c2 = generateKeyBetween(a, b, digits);
|
|
4978
|
+
const result = [c2];
|
|
4979
|
+
for (let i = 0; i < n - 1; i++) {
|
|
4980
|
+
c2 = generateKeyBetween(c2, b, digits);
|
|
4981
|
+
result.push(c2);
|
|
4982
|
+
}
|
|
4983
|
+
return result;
|
|
4984
|
+
}
|
|
4985
|
+
if (a == null) {
|
|
4986
|
+
let c2 = generateKeyBetween(a, b, digits);
|
|
4987
|
+
const result = [c2];
|
|
4988
|
+
for (let i = 0; i < n - 1; i++) {
|
|
4989
|
+
c2 = generateKeyBetween(a, c2, digits);
|
|
4990
|
+
result.push(c2);
|
|
4991
|
+
}
|
|
4992
|
+
result.reverse();
|
|
4993
|
+
return result;
|
|
4994
|
+
}
|
|
4995
|
+
const mid = Math.floor(n / 2);
|
|
4996
|
+
const c = generateKeyBetween(a, b, digits);
|
|
4997
|
+
return [
|
|
4998
|
+
...generateNKeysBetween(a, c, mid, digits),
|
|
4999
|
+
c,
|
|
5000
|
+
...generateNKeysBetween(c, b, n - mid - 1, digits)
|
|
5001
|
+
];
|
|
5002
|
+
}
|
|
5003
|
+
var BASE_62_DIGITS;
|
|
5004
|
+
var init_src = __esm({
|
|
5005
|
+
"node_modules/.pnpm/fractional-indexing@3.2.0/node_modules/fractional-indexing/src/index.js"() {
|
|
5006
|
+
BASE_62_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
5007
|
+
}
|
|
5008
|
+
});
|
|
5009
|
+
|
|
4892
5010
|
// src/sdk/types.ts
|
|
4893
5011
|
function sanitizeCard(card) {
|
|
4894
5012
|
const { filePath: _, ...rest } = card;
|
|
@@ -4903,15 +5021,210 @@ var init_types2 = __esm({
|
|
|
4903
5021
|
}
|
|
4904
5022
|
});
|
|
4905
5023
|
|
|
5024
|
+
// src/sdk/modules/boards.ts
|
|
5025
|
+
function listBoards(ctx) {
|
|
5026
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5027
|
+
return Object.entries(config3.boards).map(([id, board]) => ({
|
|
5028
|
+
id,
|
|
5029
|
+
name: board.name,
|
|
5030
|
+
description: board.description,
|
|
5031
|
+
columns: board.columns,
|
|
5032
|
+
actions: board.actions
|
|
5033
|
+
}));
|
|
5034
|
+
}
|
|
5035
|
+
function createBoard(ctx, id, name, options) {
|
|
5036
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5037
|
+
if (!id) {
|
|
5038
|
+
const base = generateSlug(name) || "board";
|
|
5039
|
+
let uniqueId = base;
|
|
5040
|
+
let counter = 1;
|
|
5041
|
+
while (config3.boards[uniqueId]) {
|
|
5042
|
+
uniqueId = `${base}-${counter++}`;
|
|
5043
|
+
}
|
|
5044
|
+
id = uniqueId;
|
|
5045
|
+
}
|
|
5046
|
+
if (config3.boards[id]) {
|
|
5047
|
+
throw new Error(`Board already exists: ${id}`);
|
|
5048
|
+
}
|
|
5049
|
+
const columns = options?.columns || [...config3.boards[config3.defaultBoard]?.columns || [
|
|
5050
|
+
{ id: "backlog", name: "Backlog", color: "#6b7280" },
|
|
5051
|
+
{ id: "todo", name: "To Do", color: "#3b82f6" },
|
|
5052
|
+
{ id: "in-progress", name: "In Progress", color: "#f59e0b" },
|
|
5053
|
+
{ id: "review", name: "Review", color: "#8b5cf6" },
|
|
5054
|
+
{ id: "done", name: "Done", color: "#22c55e" }
|
|
5055
|
+
]];
|
|
5056
|
+
config3.boards[id] = {
|
|
5057
|
+
name,
|
|
5058
|
+
description: options?.description,
|
|
5059
|
+
columns,
|
|
5060
|
+
nextCardId: 1,
|
|
5061
|
+
defaultStatus: options?.defaultStatus || columns[0]?.id || "backlog",
|
|
5062
|
+
defaultPriority: options?.defaultPriority || config3.defaultPriority
|
|
5063
|
+
};
|
|
5064
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5065
|
+
const boardInfo = { id, name, description: options?.description };
|
|
5066
|
+
ctx.emitEvent("board.created", boardInfo);
|
|
5067
|
+
return boardInfo;
|
|
5068
|
+
}
|
|
5069
|
+
async function deleteBoard(ctx, boardId) {
|
|
5070
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5071
|
+
if (!config3.boards[boardId]) {
|
|
5072
|
+
throw new Error(`Board not found: ${boardId}`);
|
|
5073
|
+
}
|
|
5074
|
+
if (config3.defaultBoard === boardId) {
|
|
5075
|
+
throw new Error(`Cannot delete the default board: ${boardId}`);
|
|
5076
|
+
}
|
|
5077
|
+
const cards = await ctx.listCards(void 0, boardId);
|
|
5078
|
+
if (cards.length > 0) {
|
|
5079
|
+
throw new Error(`Cannot delete board "${boardId}": ${cards.length} card(s) still exist`);
|
|
5080
|
+
}
|
|
5081
|
+
const boardDir = ctx._boardDir(boardId);
|
|
5082
|
+
await ctx._storage.deleteBoardData(boardDir, boardId);
|
|
5083
|
+
delete config3.boards[boardId];
|
|
5084
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5085
|
+
ctx.emitEvent("board.deleted", { id: boardId });
|
|
5086
|
+
}
|
|
5087
|
+
function getBoard(ctx, boardId) {
|
|
5088
|
+
return getBoardConfig(ctx.workspaceRoot, boardId);
|
|
5089
|
+
}
|
|
5090
|
+
function updateBoard(ctx, boardId, updates) {
|
|
5091
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5092
|
+
const board = config3.boards[boardId];
|
|
5093
|
+
if (!board) {
|
|
5094
|
+
throw new Error(`Board not found: ${boardId}`);
|
|
5095
|
+
}
|
|
5096
|
+
if (updates.name !== void 0)
|
|
5097
|
+
board.name = updates.name;
|
|
5098
|
+
if (updates.description !== void 0)
|
|
5099
|
+
board.description = updates.description;
|
|
5100
|
+
if (updates.columns !== void 0)
|
|
5101
|
+
board.columns = updates.columns;
|
|
5102
|
+
if (updates.defaultStatus !== void 0)
|
|
5103
|
+
board.defaultStatus = updates.defaultStatus;
|
|
5104
|
+
if (updates.defaultPriority !== void 0)
|
|
5105
|
+
board.defaultPriority = updates.defaultPriority;
|
|
5106
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5107
|
+
ctx.emitEvent("board.updated", { id: boardId, ...board });
|
|
5108
|
+
return board;
|
|
5109
|
+
}
|
|
5110
|
+
function getBoardActions(ctx, boardId) {
|
|
5111
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5112
|
+
const resolvedId = boardId || config3.defaultBoard;
|
|
5113
|
+
const board = config3.boards[resolvedId];
|
|
5114
|
+
if (!board)
|
|
5115
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
5116
|
+
return board.actions ?? {};
|
|
5117
|
+
}
|
|
5118
|
+
function addBoardAction(ctx, boardId, key, title) {
|
|
5119
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5120
|
+
const board = config3.boards[boardId];
|
|
5121
|
+
if (!board)
|
|
5122
|
+
throw new Error(`Board not found: ${boardId}`);
|
|
5123
|
+
board.actions ??= {};
|
|
5124
|
+
board.actions[key] = title;
|
|
5125
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5126
|
+
ctx.emitEvent("board.updated", { id: boardId, ...board });
|
|
5127
|
+
return board.actions;
|
|
5128
|
+
}
|
|
5129
|
+
function removeBoardAction(ctx, boardId, key) {
|
|
5130
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5131
|
+
const board = config3.boards[boardId];
|
|
5132
|
+
if (!board)
|
|
5133
|
+
throw new Error(`Board not found: ${boardId}`);
|
|
5134
|
+
if (!board.actions || !(key in board.actions)) {
|
|
5135
|
+
throw new Error(`Action "${key}" not found on board "${boardId}"`);
|
|
5136
|
+
}
|
|
5137
|
+
delete board.actions[key];
|
|
5138
|
+
if (Object.keys(board.actions).length === 0)
|
|
5139
|
+
delete board.actions;
|
|
5140
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5141
|
+
ctx.emitEvent("board.updated", { id: boardId, ...board });
|
|
5142
|
+
return board.actions ?? {};
|
|
5143
|
+
}
|
|
5144
|
+
async function triggerBoardAction(ctx, boardId, actionKey) {
|
|
5145
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5146
|
+
const resolvedId = boardId || config3.defaultBoard;
|
|
5147
|
+
const board = config3.boards[resolvedId];
|
|
5148
|
+
if (!board)
|
|
5149
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
5150
|
+
const actions = board.actions ?? {};
|
|
5151
|
+
if (!(actionKey in actions)) {
|
|
5152
|
+
throw new Error(`Action "${actionKey}" not defined on board "${resolvedId}"`);
|
|
5153
|
+
}
|
|
5154
|
+
const actionTitle = actions[actionKey];
|
|
5155
|
+
ctx.emitEvent("board.action", { boardId: resolvedId, action: actionKey, title: actionTitle });
|
|
5156
|
+
}
|
|
5157
|
+
async function transferCard(ctx, cardId, fromBoardId, toBoardId, targetStatus) {
|
|
5158
|
+
const toBoardDir = ctx._boardDir(toBoardId);
|
|
5159
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5160
|
+
if (!config3.boards[fromBoardId])
|
|
5161
|
+
throw new Error(`Board not found: ${fromBoardId}`);
|
|
5162
|
+
if (!config3.boards[toBoardId])
|
|
5163
|
+
throw new Error(`Board not found: ${toBoardId}`);
|
|
5164
|
+
const card = await ctx.getCard(cardId, fromBoardId);
|
|
5165
|
+
if (!card)
|
|
5166
|
+
throw new Error(`Card not found: ${cardId} in board ${fromBoardId}`);
|
|
5167
|
+
const previousStatus = card.status;
|
|
5168
|
+
const toBoard = config3.boards[toBoardId];
|
|
5169
|
+
const newStatus = targetStatus || toBoard.defaultStatus || toBoard.columns[0]?.id || "backlog";
|
|
5170
|
+
await ctx._storage.ensureBoardDirs(toBoardDir, [newStatus]);
|
|
5171
|
+
const srcAttachDir = ctx._storage.getCardDir(card);
|
|
5172
|
+
await ctx._storage.deleteCard(card);
|
|
5173
|
+
card.status = newStatus;
|
|
5174
|
+
card.boardId = toBoardId;
|
|
5175
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5176
|
+
card.completedAt = ctx._isCompletedStatus(newStatus, toBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
5177
|
+
if (ctx._storage.type === "markdown") {
|
|
5178
|
+
card.filePath = path8.join(toBoardDir, newStatus, path8.basename(card.filePath));
|
|
5179
|
+
} else {
|
|
5180
|
+
card.filePath = "";
|
|
5181
|
+
}
|
|
5182
|
+
const targetCards = await ctx.listCards(void 0, toBoardId);
|
|
5183
|
+
const cardsInStatus = targetCards.filter((c) => c.status === newStatus && c.id !== cardId).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
5184
|
+
const lastOrder = cardsInStatus.length > 0 ? cardsInStatus[cardsInStatus.length - 1].order : null;
|
|
5185
|
+
card.order = generateKeyBetween(lastOrder, null);
|
|
5186
|
+
await ctx._storage.writeCard(card);
|
|
5187
|
+
if (card.attachments.length > 0) {
|
|
5188
|
+
const dstAttachDir = ctx._storage.getCardDir(card);
|
|
5189
|
+
if (srcAttachDir !== dstAttachDir) {
|
|
5190
|
+
await fs6.mkdir(dstAttachDir, { recursive: true });
|
|
5191
|
+
await Promise.all(
|
|
5192
|
+
card.attachments.map(async (filename) => {
|
|
5193
|
+
const src = path8.join(srcAttachDir, filename);
|
|
5194
|
+
const dst = path8.join(dstAttachDir, filename);
|
|
5195
|
+
await fs6.rename(src, dst).catch(() => {
|
|
5196
|
+
});
|
|
5197
|
+
})
|
|
5198
|
+
);
|
|
5199
|
+
}
|
|
5200
|
+
}
|
|
5201
|
+
ctx.emitEvent("task.moved", { ...sanitizeCard(card), previousStatus, fromBoard: fromBoardId, toBoard: toBoardId });
|
|
5202
|
+
await ctx.addLog(card.id, `Status changed: \`${previousStatus}\` \u2192 \`${newStatus}\``, { source: "system" }, toBoardId).catch(() => {
|
|
5203
|
+
});
|
|
5204
|
+
return card;
|
|
5205
|
+
}
|
|
5206
|
+
var path8, fs6;
|
|
5207
|
+
var init_boards = __esm({
|
|
5208
|
+
"src/sdk/modules/boards.ts"() {
|
|
5209
|
+
"use strict";
|
|
5210
|
+
path8 = __toESM(require("path"));
|
|
5211
|
+
fs6 = __toESM(require("fs/promises"));
|
|
5212
|
+
init_src();
|
|
5213
|
+
init_types();
|
|
5214
|
+
init_config();
|
|
5215
|
+
init_types2();
|
|
5216
|
+
}
|
|
5217
|
+
});
|
|
5218
|
+
|
|
4906
5219
|
// src/sdk/metaUtils.ts
|
|
4907
|
-
function getNestedValue(obj,
|
|
4908
|
-
return
|
|
5220
|
+
function getNestedValue(obj, path17) {
|
|
5221
|
+
return path17.split(".").reduce((curr, key) => curr != null && typeof curr === "object" ? curr[key] : void 0, obj);
|
|
4909
5222
|
}
|
|
4910
5223
|
function matchesMetaFilter(metadata, filter) {
|
|
4911
5224
|
if (!metadata)
|
|
4912
5225
|
return false;
|
|
4913
|
-
for (const [
|
|
4914
|
-
const value = getNestedValue(metadata,
|
|
5226
|
+
for (const [path17, needle] of Object.entries(filter)) {
|
|
5227
|
+
const value = getNestedValue(metadata, path17);
|
|
4915
5228
|
if (value == null)
|
|
4916
5229
|
return false;
|
|
4917
5230
|
if (!String(value).toLowerCase().includes(needle.toLowerCase()))
|
|
@@ -4925,20 +5238,769 @@ var init_metaUtils = __esm({
|
|
|
4925
5238
|
}
|
|
4926
5239
|
});
|
|
4927
5240
|
|
|
4928
|
-
// src/sdk/
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
5241
|
+
// src/sdk/modules/cards.ts
|
|
5242
|
+
async function listCards(ctx, columns, boardId, metaFilter, sort) {
|
|
5243
|
+
await ctx._ensureMigrated();
|
|
5244
|
+
const boardDir = ctx._boardDir(boardId);
|
|
5245
|
+
const resolvedBoardId = ctx._resolveBoardId(boardId);
|
|
5246
|
+
await ctx._storage.ensureBoardDirs(boardDir, columns);
|
|
5247
|
+
const cards = await ctx._storage.scanCards(boardDir, resolvedBoardId);
|
|
5248
|
+
const hasLegacyOrder = cards.some((c) => /^\d+$/.test(c.order));
|
|
5249
|
+
if (hasLegacyOrder) {
|
|
5250
|
+
const byStatus = /* @__PURE__ */ new Map();
|
|
5251
|
+
for (const c of cards) {
|
|
5252
|
+
const list = byStatus.get(c.status) || [];
|
|
5253
|
+
list.push(c);
|
|
5254
|
+
byStatus.set(c.status, list);
|
|
5255
|
+
}
|
|
5256
|
+
for (const columnCards of byStatus.values()) {
|
|
5257
|
+
columnCards.sort((a, b) => parseInt(a.order) - parseInt(b.order));
|
|
5258
|
+
const keys = generateNKeysBetween(null, null, columnCards.length);
|
|
5259
|
+
for (let i = 0; i < columnCards.length; i++) {
|
|
5260
|
+
columnCards[i].order = keys[i];
|
|
5261
|
+
await ctx._storage.writeCard(columnCards[i]);
|
|
5262
|
+
}
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
const numericIds = cards.map((c) => parseInt(c.id, 10)).filter((n) => !Number.isNaN(n));
|
|
5266
|
+
if (numericIds.length > 0) {
|
|
5267
|
+
syncCardIdCounter(ctx.workspaceRoot, resolvedBoardId, numericIds);
|
|
5268
|
+
}
|
|
5269
|
+
const filtered = metaFilter && Object.keys(metaFilter).length > 0 ? cards.filter((c) => matchesMetaFilter(c.metadata, metaFilter)) : cards;
|
|
5270
|
+
if (sort) {
|
|
5271
|
+
const [field, dir] = sort.split(":");
|
|
5272
|
+
return filtered.sort((a, b) => {
|
|
5273
|
+
const aVal = field === "created" ? a.created : a.modified;
|
|
5274
|
+
const bVal = field === "created" ? b.created : b.modified;
|
|
5275
|
+
return dir === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
|
|
5276
|
+
});
|
|
5277
|
+
}
|
|
5278
|
+
return filtered.sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
5279
|
+
}
|
|
5280
|
+
async function getCard(ctx, cardId, boardId) {
|
|
5281
|
+
const cards = await listCards(ctx, void 0, boardId);
|
|
5282
|
+
return cards.find((c) => c.id === cardId) || null;
|
|
5283
|
+
}
|
|
5284
|
+
async function createCard(ctx, data) {
|
|
5285
|
+
await ctx._ensureMigrated();
|
|
5286
|
+
const resolvedBoardId = ctx._resolveBoardId(data.boardId);
|
|
5287
|
+
const boardDir = ctx._boardDir(resolvedBoardId);
|
|
5288
|
+
await ctx._storage.ensureBoardDirs(boardDir);
|
|
5289
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5290
|
+
const board = config3.boards[resolvedBoardId];
|
|
5291
|
+
const status = data.status || board?.defaultStatus || config3.defaultStatus || "backlog";
|
|
5292
|
+
const priority = data.priority || board?.defaultPriority || config3.defaultPriority || "medium";
|
|
5293
|
+
const title = getTitleFromContent(data.content);
|
|
5294
|
+
const numericId = allocateCardId(ctx.workspaceRoot, resolvedBoardId);
|
|
5295
|
+
const filename = generateCardFilename(numericId, title);
|
|
5296
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5297
|
+
const cards = await listCards(ctx, void 0, resolvedBoardId);
|
|
5298
|
+
const cardsInStatus = cards.filter((c) => c.status === status).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
5299
|
+
const lastOrder = cardsInStatus.length > 0 ? cardsInStatus[cardsInStatus.length - 1].order : null;
|
|
5300
|
+
const card = {
|
|
5301
|
+
version: CARD_FORMAT_VERSION,
|
|
5302
|
+
id: String(numericId),
|
|
5303
|
+
boardId: resolvedBoardId,
|
|
5304
|
+
status,
|
|
5305
|
+
priority,
|
|
5306
|
+
assignee: data.assignee ?? null,
|
|
5307
|
+
dueDate: data.dueDate ?? null,
|
|
5308
|
+
created: now,
|
|
5309
|
+
modified: now,
|
|
5310
|
+
completedAt: ctx._isCompletedStatus(status, resolvedBoardId) ? now : null,
|
|
5311
|
+
labels: data.labels || [],
|
|
5312
|
+
attachments: data.attachments || [],
|
|
5313
|
+
comments: [],
|
|
5314
|
+
order: generateKeyBetween(lastOrder, null),
|
|
5315
|
+
content: data.content,
|
|
5316
|
+
...data.metadata && Object.keys(data.metadata).length > 0 ? { metadata: data.metadata } : {},
|
|
5317
|
+
...data.actions && (Array.isArray(data.actions) ? data.actions.length > 0 : Object.keys(data.actions).length > 0) ? { actions: data.actions } : {},
|
|
5318
|
+
filePath: ctx._storage.type === "markdown" ? getCardFilePath(boardDir, status, filename) : ""
|
|
5319
|
+
};
|
|
5320
|
+
await ctx._storage.writeCard(card);
|
|
5321
|
+
ctx.emitEvent("task.created", sanitizeCard(card));
|
|
5322
|
+
return card;
|
|
5323
|
+
}
|
|
5324
|
+
async function updateCard(ctx, cardId, updates, boardId) {
|
|
5325
|
+
const card = await getCard(ctx, cardId, boardId);
|
|
5326
|
+
if (!card)
|
|
5327
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5328
|
+
const resolvedBoardId = card.boardId || ctx._resolveBoardId(boardId);
|
|
5329
|
+
const boardDir = ctx._boardDir(resolvedBoardId);
|
|
5330
|
+
const oldStatus = card.status;
|
|
5331
|
+
const oldTitle = getTitleFromContent(card.content);
|
|
5332
|
+
const { filePath: _fp, id: _id, boardId: _bid, ...safeUpdates } = updates;
|
|
5333
|
+
Object.assign(card, safeUpdates);
|
|
5334
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5335
|
+
if (oldStatus !== card.status) {
|
|
5336
|
+
card.completedAt = ctx._isCompletedStatus(card.status, resolvedBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
5337
|
+
}
|
|
5338
|
+
await ctx._storage.writeCard(card);
|
|
5339
|
+
const newTitle = getTitleFromContent(card.content);
|
|
5340
|
+
const numericId = extractNumericId(card.id);
|
|
5341
|
+
if (numericId !== null && newTitle !== oldTitle) {
|
|
5342
|
+
const newFilename = generateCardFilename(numericId, newTitle);
|
|
5343
|
+
const newPath = await ctx._storage.renameCard(card, newFilename);
|
|
5344
|
+
if (newPath)
|
|
5345
|
+
card.filePath = newPath;
|
|
5346
|
+
}
|
|
5347
|
+
if (oldStatus !== card.status) {
|
|
5348
|
+
const newPath = await ctx._storage.moveCard(card, boardDir, card.status);
|
|
5349
|
+
if (newPath)
|
|
5350
|
+
card.filePath = newPath;
|
|
5351
|
+
}
|
|
5352
|
+
ctx.emitEvent("task.updated", sanitizeCard(card));
|
|
5353
|
+
if (oldStatus !== card.status) {
|
|
5354
|
+
await ctx.addLog(card.id, `Status changed: \`${oldStatus}\` \u2192 \`${card.status}\``, { source: "system" }, resolvedBoardId).catch(() => {
|
|
5355
|
+
});
|
|
5356
|
+
}
|
|
5357
|
+
return card;
|
|
5358
|
+
}
|
|
5359
|
+
async function triggerAction(ctx, cardId, action, boardId) {
|
|
5360
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5361
|
+
const { actionWebhookUrl } = config3;
|
|
5362
|
+
if (!actionWebhookUrl) {
|
|
5363
|
+
throw new Error("No action webhook URL configured. Set actionWebhookUrl in .kanban.json");
|
|
5364
|
+
}
|
|
5365
|
+
const card = await getCard(ctx, cardId, boardId);
|
|
5366
|
+
if (!card)
|
|
5367
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5368
|
+
const resolvedBoardId = card.boardId || ctx._resolveBoardId(boardId);
|
|
5369
|
+
const payload = {
|
|
5370
|
+
action,
|
|
5371
|
+
board: resolvedBoardId,
|
|
5372
|
+
list: card.status,
|
|
5373
|
+
card: sanitizeCard(card)
|
|
5374
|
+
};
|
|
5375
|
+
const response = await fetch(actionWebhookUrl, {
|
|
5376
|
+
method: "POST",
|
|
5377
|
+
headers: { "Content-Type": "application/json" },
|
|
5378
|
+
body: JSON.stringify(payload)
|
|
5379
|
+
});
|
|
5380
|
+
if (!response.ok) {
|
|
5381
|
+
throw new Error(`Action webhook responded with ${response.status}: ${response.statusText}`);
|
|
5382
|
+
}
|
|
5383
|
+
await ctx.addLog(cardId, `Action triggered: \`${action}\``, { source: "system" }, resolvedBoardId).catch(() => {
|
|
5384
|
+
});
|
|
5385
|
+
}
|
|
5386
|
+
async function moveCard(ctx, cardId, newStatus, position, boardId) {
|
|
5387
|
+
const cards = await listCards(ctx, void 0, boardId);
|
|
5388
|
+
const card = cards.find((c) => c.id === cardId);
|
|
5389
|
+
if (!card)
|
|
5390
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5391
|
+
const resolvedBoardId = card.boardId || ctx._resolveBoardId(boardId);
|
|
5392
|
+
const boardDir = ctx._boardDir(resolvedBoardId);
|
|
5393
|
+
const oldStatus = card.status;
|
|
5394
|
+
card.status = newStatus;
|
|
5395
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5396
|
+
if (oldStatus !== newStatus) {
|
|
5397
|
+
card.completedAt = ctx._isCompletedStatus(newStatus, resolvedBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
5398
|
+
}
|
|
5399
|
+
const targetColumnCards = cards.filter((c) => c.status === newStatus && c.id !== cardId).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
5400
|
+
const pos = position !== void 0 ? Math.max(0, Math.min(position, targetColumnCards.length)) : targetColumnCards.length;
|
|
5401
|
+
const before = pos > 0 ? targetColumnCards[pos - 1].order : null;
|
|
5402
|
+
const after = pos < targetColumnCards.length ? targetColumnCards[pos].order : null;
|
|
5403
|
+
card.order = generateKeyBetween(before, after);
|
|
5404
|
+
await ctx._storage.writeCard(card);
|
|
5405
|
+
if (oldStatus !== newStatus) {
|
|
5406
|
+
const newPath = await ctx._storage.moveCard(card, boardDir, newStatus);
|
|
5407
|
+
if (newPath)
|
|
5408
|
+
card.filePath = newPath;
|
|
5409
|
+
}
|
|
5410
|
+
ctx.emitEvent("task.moved", { ...sanitizeCard(card), previousStatus: oldStatus });
|
|
5411
|
+
if (oldStatus !== newStatus) {
|
|
5412
|
+
await ctx.addLog(card.id, `Status changed: \`${oldStatus}\` \u2192 \`${newStatus}\``, { source: "system" }, resolvedBoardId).catch(() => {
|
|
5413
|
+
});
|
|
5414
|
+
}
|
|
5415
|
+
return card;
|
|
5416
|
+
}
|
|
5417
|
+
async function deleteCard(ctx, cardId, boardId) {
|
|
5418
|
+
const card = await getCard(ctx, cardId, boardId);
|
|
5419
|
+
if (!card)
|
|
5420
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5421
|
+
if (card.status === DELETED_STATUS_ID)
|
|
5422
|
+
return;
|
|
5423
|
+
await updateCard(ctx, cardId, { status: DELETED_STATUS_ID }, boardId);
|
|
5424
|
+
}
|
|
5425
|
+
async function permanentlyDeleteCard(ctx, cardId, boardId) {
|
|
5426
|
+
const card = await getCard(ctx, cardId, boardId);
|
|
5427
|
+
if (!card)
|
|
5428
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5429
|
+
const snapshot = sanitizeCard(card);
|
|
5430
|
+
await ctx._storage.deleteCard(card);
|
|
5431
|
+
ctx.emitEvent("task.deleted", snapshot);
|
|
5432
|
+
}
|
|
5433
|
+
async function getCardsByStatus(ctx, status, boardId) {
|
|
5434
|
+
const cards = await listCards(ctx, void 0, boardId);
|
|
5435
|
+
return cards.filter((c) => c.status === status);
|
|
5436
|
+
}
|
|
5437
|
+
async function getUniqueAssignees(ctx, boardId) {
|
|
5438
|
+
const cards = await listCards(ctx, void 0, boardId);
|
|
5439
|
+
const assignees = /* @__PURE__ */ new Set();
|
|
5440
|
+
for (const c of cards) {
|
|
5441
|
+
if (c.assignee)
|
|
5442
|
+
assignees.add(c.assignee);
|
|
5443
|
+
}
|
|
5444
|
+
return [...assignees].sort();
|
|
5445
|
+
}
|
|
5446
|
+
async function getUniqueLabels(ctx, boardId) {
|
|
5447
|
+
const cards = await listCards(ctx, void 0, boardId);
|
|
5448
|
+
const labels = /* @__PURE__ */ new Set();
|
|
5449
|
+
for (const c of cards) {
|
|
5450
|
+
for (const l of c.labels)
|
|
5451
|
+
labels.add(l);
|
|
5452
|
+
}
|
|
5453
|
+
return [...labels].sort();
|
|
5454
|
+
}
|
|
5455
|
+
var init_cards = __esm({
|
|
5456
|
+
"src/sdk/modules/cards.ts"() {
|
|
4932
5457
|
"use strict";
|
|
4933
|
-
path8 = __toESM(require("path"));
|
|
4934
|
-
fs6 = __toESM(require("fs/promises"));
|
|
4935
5458
|
init_src();
|
|
4936
5459
|
init_types();
|
|
4937
5460
|
init_config();
|
|
4938
5461
|
init_fileUtils();
|
|
5462
|
+
init_metaUtils();
|
|
4939
5463
|
init_types2();
|
|
5464
|
+
}
|
|
5465
|
+
});
|
|
5466
|
+
|
|
5467
|
+
// src/sdk/modules/labels.ts
|
|
5468
|
+
function getLabels(ctx) {
|
|
5469
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5470
|
+
return config3.labels || {};
|
|
5471
|
+
}
|
|
5472
|
+
function setLabel(ctx, name, definition) {
|
|
5473
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5474
|
+
if (!config3.labels)
|
|
5475
|
+
config3.labels = {};
|
|
5476
|
+
config3.labels[name] = definition;
|
|
5477
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5478
|
+
}
|
|
5479
|
+
async function deleteLabel(ctx, name) {
|
|
5480
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5481
|
+
if (config3.labels) {
|
|
5482
|
+
delete config3.labels[name];
|
|
5483
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5484
|
+
}
|
|
5485
|
+
const cards = await ctx.listCards();
|
|
5486
|
+
for (const card of cards) {
|
|
5487
|
+
if (card.labels.includes(name)) {
|
|
5488
|
+
await ctx.updateCard(card.id, { labels: card.labels.filter((l) => l !== name) });
|
|
5489
|
+
}
|
|
5490
|
+
}
|
|
5491
|
+
}
|
|
5492
|
+
async function renameLabel(ctx, oldName, newName) {
|
|
5493
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5494
|
+
if (config3.labels && config3.labels[oldName]) {
|
|
5495
|
+
config3.labels[newName] = config3.labels[oldName];
|
|
5496
|
+
delete config3.labels[oldName];
|
|
5497
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5498
|
+
}
|
|
5499
|
+
const cards = await ctx.listCards();
|
|
5500
|
+
for (const card of cards) {
|
|
5501
|
+
if (card.labels.includes(oldName)) {
|
|
5502
|
+
const newLabels = card.labels.map((l) => l === oldName ? newName : l);
|
|
5503
|
+
await ctx.updateCard(card.id, { labels: newLabels });
|
|
5504
|
+
}
|
|
5505
|
+
}
|
|
5506
|
+
}
|
|
5507
|
+
function getLabelsInGroup(ctx, group) {
|
|
5508
|
+
const labels = getLabels(ctx);
|
|
5509
|
+
return Object.entries(labels).filter(([, def]) => def.group === group).map(([name]) => name).sort();
|
|
5510
|
+
}
|
|
5511
|
+
async function filterCardsByLabelGroup(ctx, group, boardId) {
|
|
5512
|
+
const groupLabels = getLabelsInGroup(ctx, group);
|
|
5513
|
+
if (groupLabels.length === 0)
|
|
5514
|
+
return [];
|
|
5515
|
+
const cards = await ctx.listCards(void 0, boardId);
|
|
5516
|
+
return cards.filter((c) => c.labels.some((l) => groupLabels.includes(l)));
|
|
5517
|
+
}
|
|
5518
|
+
var init_labels = __esm({
|
|
5519
|
+
"src/sdk/modules/labels.ts"() {
|
|
5520
|
+
"use strict";
|
|
5521
|
+
init_config();
|
|
5522
|
+
}
|
|
5523
|
+
});
|
|
5524
|
+
|
|
5525
|
+
// src/sdk/modules/attachments.ts
|
|
5526
|
+
async function addAttachment(ctx, cardId, sourcePath, boardId) {
|
|
5527
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5528
|
+
if (!card)
|
|
5529
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5530
|
+
const fileName = path9.basename(sourcePath);
|
|
5531
|
+
await ctx._storage.copyAttachment(sourcePath, card);
|
|
5532
|
+
if (!card.attachments.includes(fileName)) {
|
|
5533
|
+
card.attachments.push(fileName);
|
|
5534
|
+
}
|
|
5535
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5536
|
+
await ctx._storage.writeCard(card);
|
|
5537
|
+
ctx.emitEvent("attachment.added", { cardId, attachment: fileName });
|
|
5538
|
+
return card;
|
|
5539
|
+
}
|
|
5540
|
+
async function removeAttachment(ctx, cardId, attachment, boardId) {
|
|
5541
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5542
|
+
if (!card)
|
|
5543
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5544
|
+
card.attachments = card.attachments.filter((a) => a !== attachment);
|
|
5545
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5546
|
+
await ctx._storage.writeCard(card);
|
|
5547
|
+
ctx.emitEvent("attachment.removed", { cardId, attachment });
|
|
5548
|
+
return card;
|
|
5549
|
+
}
|
|
5550
|
+
async function listAttachments(ctx, cardId, boardId) {
|
|
5551
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5552
|
+
if (!card)
|
|
5553
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5554
|
+
return card.attachments;
|
|
5555
|
+
}
|
|
5556
|
+
async function getAttachmentDir(ctx, cardId, boardId) {
|
|
5557
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5558
|
+
if (!card)
|
|
5559
|
+
return null;
|
|
5560
|
+
return ctx._storage.getCardDir(card);
|
|
5561
|
+
}
|
|
5562
|
+
var path9;
|
|
5563
|
+
var init_attachments = __esm({
|
|
5564
|
+
"src/sdk/modules/attachments.ts"() {
|
|
5565
|
+
"use strict";
|
|
5566
|
+
path9 = __toESM(require("path"));
|
|
5567
|
+
}
|
|
5568
|
+
});
|
|
5569
|
+
|
|
5570
|
+
// src/sdk/modules/comments.ts
|
|
5571
|
+
async function listComments(ctx, cardId, boardId) {
|
|
5572
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5573
|
+
if (!card)
|
|
5574
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5575
|
+
return card.comments || [];
|
|
5576
|
+
}
|
|
5577
|
+
async function addComment(ctx, cardId, author, content, boardId) {
|
|
5578
|
+
if (!content?.trim())
|
|
5579
|
+
throw new Error("Comment content cannot be empty");
|
|
5580
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5581
|
+
if (!card)
|
|
5582
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5583
|
+
if (!card.comments)
|
|
5584
|
+
card.comments = [];
|
|
5585
|
+
const maxId = card.comments.reduce((max, c) => {
|
|
5586
|
+
const num = parseInt(c.id.replace("c", ""), 10);
|
|
5587
|
+
return Number.isNaN(num) ? max : Math.max(max, num);
|
|
5588
|
+
}, 0);
|
|
5589
|
+
const comment = {
|
|
5590
|
+
id: `c${maxId + 1}`,
|
|
5591
|
+
author,
|
|
5592
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5593
|
+
content
|
|
5594
|
+
};
|
|
5595
|
+
card.comments.push(comment);
|
|
5596
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5597
|
+
await ctx._storage.writeCard(card);
|
|
5598
|
+
ctx.emitEvent("comment.created", { ...comment, cardId });
|
|
5599
|
+
return card;
|
|
5600
|
+
}
|
|
5601
|
+
async function updateComment(ctx, cardId, commentId, content, boardId) {
|
|
5602
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5603
|
+
if (!card)
|
|
5604
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5605
|
+
const comment = (card.comments || []).find((c) => c.id === commentId);
|
|
5606
|
+
if (!comment)
|
|
5607
|
+
throw new Error(`Comment not found: ${commentId}`);
|
|
5608
|
+
comment.content = content;
|
|
5609
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5610
|
+
await ctx._storage.writeCard(card);
|
|
5611
|
+
ctx.emitEvent("comment.updated", { ...comment, cardId });
|
|
5612
|
+
return card;
|
|
5613
|
+
}
|
|
5614
|
+
async function deleteComment(ctx, cardId, commentId, boardId) {
|
|
5615
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5616
|
+
if (!card)
|
|
5617
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5618
|
+
const comment = (card.comments || []).find((c) => c.id === commentId);
|
|
5619
|
+
card.comments = (card.comments || []).filter((c) => c.id !== commentId);
|
|
5620
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5621
|
+
await ctx._storage.writeCard(card);
|
|
5622
|
+
if (comment) {
|
|
5623
|
+
ctx.emitEvent("comment.deleted", { ...comment, cardId });
|
|
5624
|
+
}
|
|
5625
|
+
return card;
|
|
5626
|
+
}
|
|
5627
|
+
var init_comments = __esm({
|
|
5628
|
+
"src/sdk/modules/comments.ts"() {
|
|
5629
|
+
"use strict";
|
|
5630
|
+
}
|
|
5631
|
+
});
|
|
5632
|
+
|
|
5633
|
+
// src/sdk/modules/logs.ts
|
|
5634
|
+
function parseLogLine(line) {
|
|
5635
|
+
const trimmed = line.trim();
|
|
5636
|
+
if (!trimmed)
|
|
5637
|
+
return null;
|
|
5638
|
+
const match = trimmed.match(/^(\S+)\s+\[([^\]]+)\]\s+(.+)$/);
|
|
5639
|
+
if (!match)
|
|
5640
|
+
return null;
|
|
5641
|
+
const [, timestamp2, source, rest] = match;
|
|
5642
|
+
const jsonMatch = rest.match(/^(.*?)\s+(\{.+\})\s*$/);
|
|
5643
|
+
if (jsonMatch) {
|
|
5644
|
+
try {
|
|
5645
|
+
const obj = JSON.parse(jsonMatch[2]);
|
|
5646
|
+
return { timestamp: timestamp2, source, text: jsonMatch[1], object: obj };
|
|
5647
|
+
} catch {
|
|
5648
|
+
}
|
|
5649
|
+
}
|
|
5650
|
+
return { timestamp: timestamp2, source, text: rest };
|
|
5651
|
+
}
|
|
5652
|
+
function serializeLogEntry(entry) {
|
|
5653
|
+
let line = `${entry.timestamp} [${entry.source}] ${entry.text}`;
|
|
5654
|
+
if (entry.object && Object.keys(entry.object).length > 0) {
|
|
5655
|
+
line += ` ${JSON.stringify(entry.object)}`;
|
|
5656
|
+
}
|
|
5657
|
+
return line;
|
|
5658
|
+
}
|
|
5659
|
+
async function getLogFilePath(ctx, cardId, boardId) {
|
|
5660
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5661
|
+
if (!card)
|
|
5662
|
+
return null;
|
|
5663
|
+
const dir = ctx._storage.getCardDir(card);
|
|
5664
|
+
return path10.join(dir, `${card.id}.log`);
|
|
5665
|
+
}
|
|
5666
|
+
async function listLogs(ctx, cardId, boardId) {
|
|
5667
|
+
const logPath = await getLogFilePath(ctx, cardId, boardId);
|
|
5668
|
+
if (!logPath)
|
|
5669
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5670
|
+
try {
|
|
5671
|
+
const content = await fs7.readFile(logPath, "utf-8");
|
|
5672
|
+
const entries = [];
|
|
5673
|
+
for (const line of content.split("\n")) {
|
|
5674
|
+
const entry = parseLogLine(line);
|
|
5675
|
+
if (entry)
|
|
5676
|
+
entries.push(entry);
|
|
5677
|
+
}
|
|
5678
|
+
return entries;
|
|
5679
|
+
} catch {
|
|
5680
|
+
return [];
|
|
5681
|
+
}
|
|
5682
|
+
}
|
|
5683
|
+
async function addLog(ctx, cardId, text, options, boardId) {
|
|
5684
|
+
if (!text?.trim())
|
|
5685
|
+
throw new Error("Log text cannot be empty");
|
|
5686
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5687
|
+
if (!card)
|
|
5688
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5689
|
+
const entry = {
|
|
5690
|
+
timestamp: options?.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
5691
|
+
source: options?.source || "default",
|
|
5692
|
+
text: text.trim(),
|
|
5693
|
+
...options?.object && Object.keys(options.object).length > 0 ? { object: options.object } : {}
|
|
5694
|
+
};
|
|
5695
|
+
const dir = ctx._storage.getCardDir(card);
|
|
5696
|
+
const logFileName = `${card.id}.log`;
|
|
5697
|
+
const logPath = path10.join(dir, logFileName);
|
|
5698
|
+
await fs7.mkdir(dir, { recursive: true });
|
|
5699
|
+
const line = serializeLogEntry(entry) + "\n";
|
|
5700
|
+
await fs7.appendFile(logPath, line, "utf-8");
|
|
5701
|
+
if (!card.attachments.includes(logFileName)) {
|
|
5702
|
+
card.attachments.push(logFileName);
|
|
5703
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5704
|
+
await ctx._storage.writeCard(card);
|
|
5705
|
+
}
|
|
5706
|
+
ctx.emitEvent("log.added", { cardId, entry });
|
|
5707
|
+
return entry;
|
|
5708
|
+
}
|
|
5709
|
+
async function clearLogs(ctx, cardId, boardId) {
|
|
5710
|
+
const card = await ctx.getCard(cardId, boardId);
|
|
5711
|
+
if (!card)
|
|
5712
|
+
throw new Error(`Card not found: ${cardId}`);
|
|
5713
|
+
const logFileName = `${card.id}.log`;
|
|
5714
|
+
const dir = ctx._storage.getCardDir(card);
|
|
5715
|
+
const logPath = path10.join(dir, logFileName);
|
|
5716
|
+
try {
|
|
5717
|
+
await fs7.unlink(logPath);
|
|
5718
|
+
} catch {
|
|
5719
|
+
}
|
|
5720
|
+
if (card.attachments.includes(logFileName)) {
|
|
5721
|
+
card.attachments = card.attachments.filter((a) => a !== logFileName);
|
|
5722
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5723
|
+
await ctx._storage.writeCard(card);
|
|
5724
|
+
}
|
|
5725
|
+
ctx.emitEvent("log.cleared", { cardId });
|
|
5726
|
+
}
|
|
5727
|
+
function getBoardLogFilePath(ctx, boardId) {
|
|
5728
|
+
return path10.join(ctx._boardDir(boardId), "board.log");
|
|
5729
|
+
}
|
|
5730
|
+
async function listBoardLogs(ctx, boardId) {
|
|
5731
|
+
const logPath = getBoardLogFilePath(ctx, boardId);
|
|
5732
|
+
let content;
|
|
5733
|
+
try {
|
|
5734
|
+
content = await fs7.readFile(logPath, "utf-8");
|
|
5735
|
+
} catch {
|
|
5736
|
+
return [];
|
|
5737
|
+
}
|
|
5738
|
+
const entries = [];
|
|
5739
|
+
for (const line of content.split("\n")) {
|
|
5740
|
+
const trimmed = line.trim();
|
|
5741
|
+
if (!trimmed)
|
|
5742
|
+
continue;
|
|
5743
|
+
const entry = parseLogLine(trimmed);
|
|
5744
|
+
if (entry)
|
|
5745
|
+
entries.push(entry);
|
|
5746
|
+
}
|
|
5747
|
+
return entries;
|
|
5748
|
+
}
|
|
5749
|
+
async function addBoardLog(ctx, text, options, boardId) {
|
|
5750
|
+
const entry = {
|
|
5751
|
+
timestamp: options?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
5752
|
+
source: options?.source ?? "sdk",
|
|
5753
|
+
text,
|
|
5754
|
+
...options?.object ? { object: options.object } : {}
|
|
5755
|
+
};
|
|
5756
|
+
const logPath = getBoardLogFilePath(ctx, boardId);
|
|
5757
|
+
await fs7.mkdir(path10.dirname(logPath), { recursive: true });
|
|
5758
|
+
const line = serializeLogEntry(entry) + "\n";
|
|
5759
|
+
await fs7.appendFile(logPath, line, "utf-8");
|
|
5760
|
+
ctx.emitEvent("board.log.added", { boardId, entry });
|
|
5761
|
+
return entry;
|
|
5762
|
+
}
|
|
5763
|
+
async function clearBoardLogs(ctx, boardId) {
|
|
5764
|
+
const logPath = getBoardLogFilePath(ctx, boardId);
|
|
5765
|
+
try {
|
|
5766
|
+
await fs7.unlink(logPath);
|
|
5767
|
+
} catch {
|
|
5768
|
+
}
|
|
5769
|
+
ctx.emitEvent("board.log.cleared", { boardId });
|
|
5770
|
+
}
|
|
5771
|
+
var path10, fs7;
|
|
5772
|
+
var init_logs = __esm({
|
|
5773
|
+
"src/sdk/modules/logs.ts"() {
|
|
5774
|
+
"use strict";
|
|
5775
|
+
path10 = __toESM(require("path"));
|
|
5776
|
+
fs7 = __toESM(require("fs/promises"));
|
|
5777
|
+
}
|
|
5778
|
+
});
|
|
5779
|
+
|
|
5780
|
+
// src/sdk/modules/columns.ts
|
|
5781
|
+
function listColumns(ctx, boardId) {
|
|
5782
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5783
|
+
const resolvedId = boardId || config3.defaultBoard;
|
|
5784
|
+
const board = config3.boards[resolvedId];
|
|
5785
|
+
return board?.columns || [];
|
|
5786
|
+
}
|
|
5787
|
+
function addColumn(ctx, column, boardId) {
|
|
5788
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5789
|
+
const resolvedId = boardId || config3.defaultBoard;
|
|
5790
|
+
const board = config3.boards[resolvedId];
|
|
5791
|
+
if (!board)
|
|
5792
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
5793
|
+
if (!column.id) {
|
|
5794
|
+
const base = generateSlug(column.name) || "column";
|
|
5795
|
+
let uniqueId = base;
|
|
5796
|
+
let counter = 1;
|
|
5797
|
+
while (board.columns.some((c) => c.id === uniqueId)) {
|
|
5798
|
+
uniqueId = `${base}-${counter++}`;
|
|
5799
|
+
}
|
|
5800
|
+
column = { ...column, id: uniqueId };
|
|
5801
|
+
}
|
|
5802
|
+
if (column.id === DELETED_STATUS_ID)
|
|
5803
|
+
throw new Error(`"${DELETED_STATUS_ID}" is a reserved column ID`);
|
|
5804
|
+
if (board.columns.some((c) => c.id === column.id)) {
|
|
5805
|
+
throw new Error(`Column already exists: ${column.id}`);
|
|
5806
|
+
}
|
|
5807
|
+
board.columns.push(column);
|
|
5808
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5809
|
+
ctx.emitEvent("column.created", column);
|
|
5810
|
+
return board.columns;
|
|
5811
|
+
}
|
|
5812
|
+
function updateColumn(ctx, columnId, updates, boardId) {
|
|
5813
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5814
|
+
const resolvedId = boardId || config3.defaultBoard;
|
|
5815
|
+
const board = config3.boards[resolvedId];
|
|
5816
|
+
if (!board)
|
|
5817
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
5818
|
+
const col = board.columns.find((c) => c.id === columnId);
|
|
5819
|
+
if (!col)
|
|
5820
|
+
throw new Error(`Column not found: ${columnId}`);
|
|
5821
|
+
if (updates.name !== void 0)
|
|
5822
|
+
col.name = updates.name;
|
|
5823
|
+
if (updates.color !== void 0)
|
|
5824
|
+
col.color = updates.color;
|
|
5825
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5826
|
+
ctx.emitEvent("column.updated", col);
|
|
5827
|
+
return board.columns;
|
|
5828
|
+
}
|
|
5829
|
+
async function removeColumn(ctx, columnId, boardId) {
|
|
5830
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5831
|
+
const resolvedId = boardId || config3.defaultBoard;
|
|
5832
|
+
const board = config3.boards[resolvedId];
|
|
5833
|
+
if (!board)
|
|
5834
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
5835
|
+
if (columnId === DELETED_STATUS_ID)
|
|
5836
|
+
throw new Error(`Cannot remove the reserved "${DELETED_STATUS_ID}" column`);
|
|
5837
|
+
const idx = board.columns.findIndex((c) => c.id === columnId);
|
|
5838
|
+
if (idx === -1)
|
|
5839
|
+
throw new Error(`Column not found: ${columnId}`);
|
|
5840
|
+
const cards = await ctx.listCards(void 0, resolvedId);
|
|
5841
|
+
const cardsInColumn = cards.filter((c) => c.status === columnId);
|
|
5842
|
+
if (cardsInColumn.length > 0) {
|
|
5843
|
+
throw new Error(`Cannot remove column "${columnId}": ${cardsInColumn.length} card(s) still in this column`);
|
|
5844
|
+
}
|
|
5845
|
+
const removed = board.columns[idx];
|
|
5846
|
+
board.columns.splice(idx, 1);
|
|
5847
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5848
|
+
ctx.emitEvent("column.deleted", removed);
|
|
5849
|
+
return board.columns;
|
|
5850
|
+
}
|
|
5851
|
+
async function cleanupColumn(ctx, columnId, boardId) {
|
|
5852
|
+
if (columnId === DELETED_STATUS_ID)
|
|
5853
|
+
return 0;
|
|
5854
|
+
const cards = await ctx.listCards(void 0, boardId);
|
|
5855
|
+
const cardsToMove = cards.filter((c) => c.status === columnId);
|
|
5856
|
+
for (const card of cardsToMove) {
|
|
5857
|
+
await ctx.moveCard(card.id, DELETED_STATUS_ID, 0, boardId);
|
|
5858
|
+
}
|
|
5859
|
+
return cardsToMove.length;
|
|
5860
|
+
}
|
|
5861
|
+
async function purgeDeletedCards(ctx, boardId) {
|
|
5862
|
+
const cards = await ctx.listCards(void 0, boardId);
|
|
5863
|
+
const deleted = cards.filter((c) => c.status === DELETED_STATUS_ID);
|
|
5864
|
+
for (const card of deleted) {
|
|
5865
|
+
await ctx.permanentlyDeleteCard(card.id, boardId);
|
|
5866
|
+
}
|
|
5867
|
+
return deleted.length;
|
|
5868
|
+
}
|
|
5869
|
+
function reorderColumns(ctx, columnIds, boardId) {
|
|
5870
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5871
|
+
const resolvedId = boardId || config3.defaultBoard;
|
|
5872
|
+
const board = config3.boards[resolvedId];
|
|
5873
|
+
if (!board)
|
|
5874
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
5875
|
+
const colMap = new Map(board.columns.map((c) => [c.id, c]));
|
|
5876
|
+
for (const id of columnIds) {
|
|
5877
|
+
if (!colMap.has(id))
|
|
5878
|
+
throw new Error(`Column not found: ${id}`);
|
|
5879
|
+
}
|
|
5880
|
+
if (columnIds.length !== board.columns.length) {
|
|
5881
|
+
throw new Error("Must include all column IDs when reordering");
|
|
5882
|
+
}
|
|
5883
|
+
board.columns = columnIds.map((id) => colMap.get(id));
|
|
5884
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5885
|
+
return board.columns;
|
|
5886
|
+
}
|
|
5887
|
+
var init_columns = __esm({
|
|
5888
|
+
"src/sdk/modules/columns.ts"() {
|
|
5889
|
+
"use strict";
|
|
5890
|
+
init_config();
|
|
5891
|
+
init_types();
|
|
5892
|
+
}
|
|
5893
|
+
});
|
|
5894
|
+
|
|
5895
|
+
// src/sdk/modules/settings.ts
|
|
5896
|
+
function getSettings(ctx) {
|
|
5897
|
+
return configToSettings(readConfig(ctx.workspaceRoot));
|
|
5898
|
+
}
|
|
5899
|
+
function updateSettings(ctx, settings) {
|
|
5900
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5901
|
+
writeConfig(ctx.workspaceRoot, settingsToConfig(config3, settings));
|
|
5902
|
+
ctx.emitEvent("settings.updated", settings);
|
|
5903
|
+
}
|
|
5904
|
+
function setDefaultBoard(ctx, boardId) {
|
|
5905
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5906
|
+
if (!config3.boards[boardId])
|
|
5907
|
+
throw new Error(`Board not found: ${boardId}`);
|
|
5908
|
+
config3.defaultBoard = boardId;
|
|
5909
|
+
writeConfig(ctx.workspaceRoot, config3);
|
|
5910
|
+
}
|
|
5911
|
+
var init_settings = __esm({
|
|
5912
|
+
"src/sdk/modules/settings.ts"() {
|
|
5913
|
+
"use strict";
|
|
5914
|
+
init_config();
|
|
5915
|
+
}
|
|
5916
|
+
});
|
|
5917
|
+
|
|
5918
|
+
// src/sdk/modules/migration.ts
|
|
5919
|
+
async function migrateToSqlite(ctx, dbPath) {
|
|
5920
|
+
if (ctx._storage.type === "sqlite") {
|
|
5921
|
+
throw new Error("Storage engine is already sqlite");
|
|
5922
|
+
}
|
|
5923
|
+
await ctx._ensureMigrated();
|
|
5924
|
+
const resolvedDbPath = dbPath ?? ".kanban/kanban.db";
|
|
5925
|
+
const absDbPath = path11.resolve(ctx.workspaceRoot, resolvedDbPath);
|
|
5926
|
+
const { SqliteStorageEngine: SqliteStorageEngine2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
5927
|
+
const sqliteEngine = new SqliteStorageEngine2(ctx._storage.kanbanDir, absDbPath);
|
|
5928
|
+
await sqliteEngine.init();
|
|
5929
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5930
|
+
const boardIds = Object.keys(config3.boards);
|
|
5931
|
+
let count = 0;
|
|
5932
|
+
for (const boardId of boardIds) {
|
|
5933
|
+
const boardDir = path11.join(ctx._storage.kanbanDir, "boards", boardId);
|
|
5934
|
+
const cards = await ctx._storage.scanCards(boardDir, boardId);
|
|
5935
|
+
for (const card of cards) {
|
|
5936
|
+
await sqliteEngine.writeCard({ ...card, filePath: "" });
|
|
5937
|
+
count++;
|
|
5938
|
+
}
|
|
5939
|
+
}
|
|
5940
|
+
sqliteEngine.close();
|
|
5941
|
+
writeConfig(ctx.workspaceRoot, { ...config3, storageEngine: "sqlite", sqlitePath: resolvedDbPath });
|
|
5942
|
+
ctx.emitEvent("storage.migrated", { from: "markdown", to: "sqlite", count });
|
|
5943
|
+
return count;
|
|
5944
|
+
}
|
|
5945
|
+
async function migrateToMarkdown(ctx) {
|
|
5946
|
+
if (ctx._storage.type === "markdown") {
|
|
5947
|
+
throw new Error("Storage engine is already markdown");
|
|
5948
|
+
}
|
|
5949
|
+
await ctx._ensureMigrated();
|
|
5950
|
+
const { MarkdownStorageEngine: MarkdownStorageEngine2 } = await Promise.resolve().then(() => (init_markdown(), markdown_exports));
|
|
5951
|
+
const mdEngine = new MarkdownStorageEngine2(ctx._storage.kanbanDir);
|
|
5952
|
+
await mdEngine.init();
|
|
5953
|
+
const config3 = readConfig(ctx.workspaceRoot);
|
|
5954
|
+
const boardIds = Object.keys(config3.boards);
|
|
5955
|
+
let count = 0;
|
|
5956
|
+
for (const boardId of boardIds) {
|
|
5957
|
+
const boardDir = path11.join(ctx._storage.kanbanDir, "boards", boardId);
|
|
5958
|
+
const cards = await ctx._storage.scanCards(boardDir, boardId);
|
|
5959
|
+
for (const card of cards) {
|
|
5960
|
+
const numericId = Number(card.id) || 0;
|
|
5961
|
+
const title = getTitleFromContent(card.content) || card.id;
|
|
5962
|
+
const filename = generateCardFilename(numericId, title);
|
|
5963
|
+
const filePath = getCardFilePath(boardDir, card.status, filename);
|
|
5964
|
+
await mdEngine.writeCard({ ...card, filePath });
|
|
5965
|
+
count++;
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5968
|
+
mdEngine.close();
|
|
5969
|
+
const { storageEngine: _se, sqlitePath: _sp, ...restConfig } = config3;
|
|
5970
|
+
writeConfig(ctx.workspaceRoot, restConfig);
|
|
5971
|
+
ctx.emitEvent("storage.migrated", { from: "sqlite", to: "markdown", count });
|
|
5972
|
+
return count;
|
|
5973
|
+
}
|
|
5974
|
+
var path11;
|
|
5975
|
+
var init_migration2 = __esm({
|
|
5976
|
+
"src/sdk/modules/migration.ts"() {
|
|
5977
|
+
"use strict";
|
|
5978
|
+
path11 = __toESM(require("path"));
|
|
5979
|
+
init_config();
|
|
5980
|
+
init_types();
|
|
5981
|
+
init_fileUtils();
|
|
5982
|
+
}
|
|
5983
|
+
});
|
|
5984
|
+
|
|
5985
|
+
// src/sdk/KanbanSDK.ts
|
|
5986
|
+
var path12, KanbanSDK;
|
|
5987
|
+
var init_KanbanSDK = __esm({
|
|
5988
|
+
"src/sdk/KanbanSDK.ts"() {
|
|
5989
|
+
"use strict";
|
|
5990
|
+
path12 = __toESM(require("path"));
|
|
5991
|
+
init_types();
|
|
5992
|
+
init_config();
|
|
4940
5993
|
init_storage();
|
|
4941
|
-
|
|
5994
|
+
init_webhooks();
|
|
5995
|
+
init_boards();
|
|
5996
|
+
init_cards();
|
|
5997
|
+
init_labels();
|
|
5998
|
+
init_attachments();
|
|
5999
|
+
init_comments();
|
|
6000
|
+
init_logs();
|
|
6001
|
+
init_columns();
|
|
6002
|
+
init_settings();
|
|
6003
|
+
init_migration2();
|
|
4942
6004
|
KanbanSDK = class {
|
|
4943
6005
|
/**
|
|
4944
6006
|
* Creates a new KanbanSDK instance.
|
|
@@ -4990,6 +6052,7 @@ var init_KanbanSDK = __esm({
|
|
|
4990
6052
|
* Emits an event to the registered handler, if one exists.
|
|
4991
6053
|
* Called internally after every successful mutating operation.
|
|
4992
6054
|
*/
|
|
6055
|
+
/** @internal */
|
|
4993
6056
|
emitEvent(event, data) {
|
|
4994
6057
|
if (this._onEvent) {
|
|
4995
6058
|
try {
|
|
@@ -4997,6 +6060,8 @@ var init_KanbanSDK = __esm({
|
|
|
4997
6060
|
} catch (err) {
|
|
4998
6061
|
console.error(`SDK event handler error for ${event}:`, err);
|
|
4999
6062
|
}
|
|
6063
|
+
} else {
|
|
6064
|
+
fireWebhooks(this.workspaceRoot, event, data);
|
|
5000
6065
|
}
|
|
5001
6066
|
}
|
|
5002
6067
|
/**
|
|
@@ -5013,17 +6078,20 @@ var init_KanbanSDK = __esm({
|
|
|
5013
6078
|
* ```
|
|
5014
6079
|
*/
|
|
5015
6080
|
get workspaceRoot() {
|
|
5016
|
-
return
|
|
6081
|
+
return path12.dirname(this.kanbanDir);
|
|
5017
6082
|
}
|
|
5018
6083
|
// --- Board resolution helpers ---
|
|
6084
|
+
/** @internal */
|
|
5019
6085
|
_resolveBoardId(boardId) {
|
|
5020
6086
|
const config3 = readConfig(this.workspaceRoot);
|
|
5021
6087
|
return boardId || config3.defaultBoard;
|
|
5022
6088
|
}
|
|
6089
|
+
/** @internal */
|
|
5023
6090
|
_boardDir(boardId) {
|
|
5024
6091
|
const resolvedId = this._resolveBoardId(boardId);
|
|
5025
|
-
return
|
|
6092
|
+
return path12.join(this.kanbanDir, "boards", resolvedId);
|
|
5026
6093
|
}
|
|
6094
|
+
/** @internal */
|
|
5027
6095
|
_isCompletedStatus(status, boardId) {
|
|
5028
6096
|
const config3 = readConfig(this.workspaceRoot);
|
|
5029
6097
|
const resolvedId = boardId || config3.defaultBoard;
|
|
@@ -5032,6 +6100,7 @@ var init_KanbanSDK = __esm({
|
|
|
5032
6100
|
return status === "done";
|
|
5033
6101
|
return board.columns[board.columns.length - 1].id === status;
|
|
5034
6102
|
}
|
|
6103
|
+
/** @internal */
|
|
5035
6104
|
async _ensureMigrated() {
|
|
5036
6105
|
if (this._migrated)
|
|
5037
6106
|
return;
|
|
@@ -5073,14 +6142,7 @@ var init_KanbanSDK = __esm({
|
|
|
5073
6142
|
* ```
|
|
5074
6143
|
*/
|
|
5075
6144
|
listBoards() {
|
|
5076
|
-
|
|
5077
|
-
return Object.entries(config3.boards).map(([id, board]) => ({
|
|
5078
|
-
id,
|
|
5079
|
-
name: board.name,
|
|
5080
|
-
description: board.description,
|
|
5081
|
-
columns: board.columns,
|
|
5082
|
-
actions: board.actions
|
|
5083
|
-
}));
|
|
6145
|
+
return listBoards(this);
|
|
5084
6146
|
}
|
|
5085
6147
|
/**
|
|
5086
6148
|
* Creates a new board with the given ID and name.
|
|
@@ -5108,29 +6170,7 @@ var init_KanbanSDK = __esm({
|
|
|
5108
6170
|
* ```
|
|
5109
6171
|
*/
|
|
5110
6172
|
createBoard(id, name, options) {
|
|
5111
|
-
|
|
5112
|
-
if (config3.boards[id]) {
|
|
5113
|
-
throw new Error(`Board already exists: ${id}`);
|
|
5114
|
-
}
|
|
5115
|
-
const columns = options?.columns || [...config3.boards[config3.defaultBoard]?.columns || [
|
|
5116
|
-
{ id: "backlog", name: "Backlog", color: "#6b7280" },
|
|
5117
|
-
{ id: "todo", name: "To Do", color: "#3b82f6" },
|
|
5118
|
-
{ id: "in-progress", name: "In Progress", color: "#f59e0b" },
|
|
5119
|
-
{ id: "review", name: "Review", color: "#8b5cf6" },
|
|
5120
|
-
{ id: "done", name: "Done", color: "#22c55e" }
|
|
5121
|
-
]];
|
|
5122
|
-
config3.boards[id] = {
|
|
5123
|
-
name,
|
|
5124
|
-
description: options?.description,
|
|
5125
|
-
columns,
|
|
5126
|
-
nextCardId: 1,
|
|
5127
|
-
defaultStatus: options?.defaultStatus || columns[0]?.id || "backlog",
|
|
5128
|
-
defaultPriority: options?.defaultPriority || config3.defaultPriority
|
|
5129
|
-
};
|
|
5130
|
-
writeConfig(this.workspaceRoot, config3);
|
|
5131
|
-
const boardInfo = { id, name, description: options?.description };
|
|
5132
|
-
this.emitEvent("board.created", boardInfo);
|
|
5133
|
-
return boardInfo;
|
|
6173
|
+
return createBoard(this, id, name, options);
|
|
5134
6174
|
}
|
|
5135
6175
|
/**
|
|
5136
6176
|
* Deletes a board and its directory from the filesystem.
|
|
@@ -5151,22 +6191,7 @@ var init_KanbanSDK = __esm({
|
|
|
5151
6191
|
* ```
|
|
5152
6192
|
*/
|
|
5153
6193
|
async deleteBoard(boardId) {
|
|
5154
|
-
|
|
5155
|
-
if (!config3.boards[boardId]) {
|
|
5156
|
-
throw new Error(`Board not found: ${boardId}`);
|
|
5157
|
-
}
|
|
5158
|
-
if (config3.defaultBoard === boardId) {
|
|
5159
|
-
throw new Error(`Cannot delete the default board: ${boardId}`);
|
|
5160
|
-
}
|
|
5161
|
-
const cards = await this.listCards(void 0, boardId);
|
|
5162
|
-
if (cards.length > 0) {
|
|
5163
|
-
throw new Error(`Cannot delete board "${boardId}": ${cards.length} card(s) still exist`);
|
|
5164
|
-
}
|
|
5165
|
-
const boardDir = this._boardDir(boardId);
|
|
5166
|
-
await this._storage.deleteBoardData(boardDir, boardId);
|
|
5167
|
-
delete config3.boards[boardId];
|
|
5168
|
-
writeConfig(this.workspaceRoot, config3);
|
|
5169
|
-
this.emitEvent("board.deleted", { id: boardId });
|
|
6194
|
+
return deleteBoard(this, boardId);
|
|
5170
6195
|
}
|
|
5171
6196
|
/**
|
|
5172
6197
|
* Retrieves the full configuration for a specific board.
|
|
@@ -5182,7 +6207,7 @@ var init_KanbanSDK = __esm({
|
|
|
5182
6207
|
* ```
|
|
5183
6208
|
*/
|
|
5184
6209
|
getBoard(boardId) {
|
|
5185
|
-
return
|
|
6210
|
+
return getBoard(this, boardId);
|
|
5186
6211
|
}
|
|
5187
6212
|
/**
|
|
5188
6213
|
* Updates properties of an existing board.
|
|
@@ -5209,24 +6234,7 @@ var init_KanbanSDK = __esm({
|
|
|
5209
6234
|
* ```
|
|
5210
6235
|
*/
|
|
5211
6236
|
updateBoard(boardId, updates) {
|
|
5212
|
-
|
|
5213
|
-
const board = config3.boards[boardId];
|
|
5214
|
-
if (!board) {
|
|
5215
|
-
throw new Error(`Board not found: ${boardId}`);
|
|
5216
|
-
}
|
|
5217
|
-
if (updates.name !== void 0)
|
|
5218
|
-
board.name = updates.name;
|
|
5219
|
-
if (updates.description !== void 0)
|
|
5220
|
-
board.description = updates.description;
|
|
5221
|
-
if (updates.columns !== void 0)
|
|
5222
|
-
board.columns = updates.columns;
|
|
5223
|
-
if (updates.defaultStatus !== void 0)
|
|
5224
|
-
board.defaultStatus = updates.defaultStatus;
|
|
5225
|
-
if (updates.defaultPriority !== void 0)
|
|
5226
|
-
board.defaultPriority = updates.defaultPriority;
|
|
5227
|
-
writeConfig(this.workspaceRoot, config3);
|
|
5228
|
-
this.emitEvent("board.updated", { id: boardId, ...board });
|
|
5229
|
-
return board;
|
|
6237
|
+
return updateBoard(this, boardId, updates);
|
|
5230
6238
|
}
|
|
5231
6239
|
/**
|
|
5232
6240
|
* Returns the named actions defined on a board.
|
|
@@ -5236,12 +6244,7 @@ var init_KanbanSDK = __esm({
|
|
|
5236
6244
|
* @throws {Error} If the board does not exist.
|
|
5237
6245
|
*/
|
|
5238
6246
|
getBoardActions(boardId) {
|
|
5239
|
-
|
|
5240
|
-
const resolvedId = boardId || config3.defaultBoard;
|
|
5241
|
-
const board = config3.boards[resolvedId];
|
|
5242
|
-
if (!board)
|
|
5243
|
-
throw new Error(`Board not found: ${resolvedId}`);
|
|
5244
|
-
return board.actions ?? {};
|
|
6247
|
+
return getBoardActions(this, boardId);
|
|
5245
6248
|
}
|
|
5246
6249
|
/**
|
|
5247
6250
|
* Adds or updates a named action on a board.
|
|
@@ -5253,15 +6256,7 @@ var init_KanbanSDK = __esm({
|
|
|
5253
6256
|
* @throws {Error} If the board does not exist.
|
|
5254
6257
|
*/
|
|
5255
6258
|
addBoardAction(boardId, key, title) {
|
|
5256
|
-
|
|
5257
|
-
const board = config3.boards[boardId];
|
|
5258
|
-
if (!board)
|
|
5259
|
-
throw new Error(`Board not found: ${boardId}`);
|
|
5260
|
-
board.actions ??= {};
|
|
5261
|
-
board.actions[key] = title;
|
|
5262
|
-
writeConfig(this.workspaceRoot, config3);
|
|
5263
|
-
this.emitEvent("board.updated", { id: boardId, ...board });
|
|
5264
|
-
return board.actions;
|
|
6259
|
+
return addBoardAction(this, boardId, key, title);
|
|
5265
6260
|
}
|
|
5266
6261
|
/**
|
|
5267
6262
|
* Removes a named action from a board.
|
|
@@ -5273,19 +6268,7 @@ var init_KanbanSDK = __esm({
|
|
|
5273
6268
|
* @throws {Error} If the action key is not found on the board.
|
|
5274
6269
|
*/
|
|
5275
6270
|
removeBoardAction(boardId, key) {
|
|
5276
|
-
|
|
5277
|
-
const board = config3.boards[boardId];
|
|
5278
|
-
if (!board)
|
|
5279
|
-
throw new Error(`Board not found: ${boardId}`);
|
|
5280
|
-
if (!board.actions || !(key in board.actions)) {
|
|
5281
|
-
throw new Error(`Action "${key}" not found on board "${boardId}"`);
|
|
5282
|
-
}
|
|
5283
|
-
delete board.actions[key];
|
|
5284
|
-
if (Object.keys(board.actions).length === 0)
|
|
5285
|
-
delete board.actions;
|
|
5286
|
-
writeConfig(this.workspaceRoot, config3);
|
|
5287
|
-
this.emitEvent("board.updated", { id: boardId, ...board });
|
|
5288
|
-
return board.actions ?? {};
|
|
6271
|
+
return removeBoardAction(this, boardId, key);
|
|
5289
6272
|
}
|
|
5290
6273
|
/**
|
|
5291
6274
|
* Fires the `board.action` webhook event for a named board action.
|
|
@@ -5296,17 +6279,7 @@ var init_KanbanSDK = __esm({
|
|
|
5296
6279
|
* @throws {Error} If the action key is not defined on the board.
|
|
5297
6280
|
*/
|
|
5298
6281
|
async triggerBoardAction(boardId, actionKey) {
|
|
5299
|
-
|
|
5300
|
-
const resolvedId = boardId || config3.defaultBoard;
|
|
5301
|
-
const board = config3.boards[resolvedId];
|
|
5302
|
-
if (!board)
|
|
5303
|
-
throw new Error(`Board not found: ${resolvedId}`);
|
|
5304
|
-
const actions = board.actions ?? {};
|
|
5305
|
-
if (!(actionKey in actions)) {
|
|
5306
|
-
throw new Error(`Action "${actionKey}" not defined on board "${resolvedId}"`);
|
|
5307
|
-
}
|
|
5308
|
-
const actionTitle = actions[actionKey];
|
|
5309
|
-
this.emitEvent("board.action", { boardId: resolvedId, action: actionKey, title: actionTitle });
|
|
6282
|
+
return triggerBoardAction(this, boardId, actionKey);
|
|
5310
6283
|
}
|
|
5311
6284
|
/**
|
|
5312
6285
|
* Transfers a card from one board to another.
|
|
@@ -5334,55 +6307,7 @@ var init_KanbanSDK = __esm({
|
|
|
5334
6307
|
* ```
|
|
5335
6308
|
*/
|
|
5336
6309
|
async transferCard(cardId, fromBoardId, toBoardId, targetStatus) {
|
|
5337
|
-
|
|
5338
|
-
const config3 = readConfig(this.workspaceRoot);
|
|
5339
|
-
if (!config3.boards[fromBoardId])
|
|
5340
|
-
throw new Error(`Board not found: ${fromBoardId}`);
|
|
5341
|
-
if (!config3.boards[toBoardId])
|
|
5342
|
-
throw new Error(`Board not found: ${toBoardId}`);
|
|
5343
|
-
const card = await this.getCard(cardId, fromBoardId);
|
|
5344
|
-
if (!card)
|
|
5345
|
-
throw new Error(`Card not found: ${cardId} in board ${fromBoardId}`);
|
|
5346
|
-
const previousStatus = card.status;
|
|
5347
|
-
const toBoard = config3.boards[toBoardId];
|
|
5348
|
-
const newStatus = targetStatus || toBoard.defaultStatus || toBoard.columns[0]?.id || "backlog";
|
|
5349
|
-
await this._storage.ensureBoardDirs(toBoardDir, [newStatus]);
|
|
5350
|
-
const srcAttachDir = this._storage.getCardDir(card);
|
|
5351
|
-
await this._storage.deleteCard(card);
|
|
5352
|
-
card.status = newStatus;
|
|
5353
|
-
card.boardId = toBoardId;
|
|
5354
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5355
|
-
card.completedAt = this._isCompletedStatus(newStatus, toBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
5356
|
-
if (this._storage.type === "markdown") {
|
|
5357
|
-
card.filePath = path8.join(toBoardDir, newStatus, path8.basename(card.filePath));
|
|
5358
|
-
} else {
|
|
5359
|
-
card.filePath = "";
|
|
5360
|
-
}
|
|
5361
|
-
const targetCards = await this.listCards(void 0, toBoardId);
|
|
5362
|
-
const cardsInStatus = targetCards.filter((c) => c.status === newStatus && c.id !== cardId).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
5363
|
-
const lastOrder = cardsInStatus.length > 0 ? cardsInStatus[cardsInStatus.length - 1].order : null;
|
|
5364
|
-
card.order = generateKeyBetween(lastOrder, null);
|
|
5365
|
-
await this._storage.writeCard(card);
|
|
5366
|
-
if (card.attachments.length > 0) {
|
|
5367
|
-
const dstAttachDir = this._storage.getCardDir(card);
|
|
5368
|
-
if (srcAttachDir !== dstAttachDir) {
|
|
5369
|
-
await fs6.mkdir(dstAttachDir, { recursive: true });
|
|
5370
|
-
await Promise.all(
|
|
5371
|
-
card.attachments.map(async (filename) => {
|
|
5372
|
-
const src = path8.join(srcAttachDir, filename);
|
|
5373
|
-
const dst = path8.join(dstAttachDir, filename);
|
|
5374
|
-
await fs6.rename(src, dst).catch(() => {
|
|
5375
|
-
});
|
|
5376
|
-
})
|
|
5377
|
-
);
|
|
5378
|
-
}
|
|
5379
|
-
}
|
|
5380
|
-
this.emitEvent("task.moved", { ...sanitizeCard(card), previousStatus, fromBoard: fromBoardId, toBoard: toBoardId });
|
|
5381
|
-
if (previousStatus !== newStatus) {
|
|
5382
|
-
await this.addLog(card.id, `Status changed: \`${previousStatus}\` \u2192 \`${newStatus}\``, { source: "system" }, toBoardId).catch(() => {
|
|
5383
|
-
});
|
|
5384
|
-
}
|
|
5385
|
-
return card;
|
|
6310
|
+
return transferCard(this, cardId, fromBoardId, toBoardId, targetStatus);
|
|
5386
6311
|
}
|
|
5387
6312
|
// --- Card CRUD ---
|
|
5388
6313
|
/**
|
|
@@ -5426,42 +6351,7 @@ var init_KanbanSDK = __esm({
|
|
|
5426
6351
|
* ```
|
|
5427
6352
|
*/
|
|
5428
6353
|
async listCards(columns, boardId, metaFilter, sort) {
|
|
5429
|
-
|
|
5430
|
-
const boardDir = this._boardDir(boardId);
|
|
5431
|
-
const resolvedBoardId = this._resolveBoardId(boardId);
|
|
5432
|
-
await this._storage.ensureBoardDirs(boardDir, columns);
|
|
5433
|
-
const cards = await this._storage.scanCards(boardDir, resolvedBoardId);
|
|
5434
|
-
const hasLegacyOrder = cards.some((c) => /^\d+$/.test(c.order));
|
|
5435
|
-
if (hasLegacyOrder) {
|
|
5436
|
-
const byStatus = /* @__PURE__ */ new Map();
|
|
5437
|
-
for (const c of cards) {
|
|
5438
|
-
const list = byStatus.get(c.status) || [];
|
|
5439
|
-
list.push(c);
|
|
5440
|
-
byStatus.set(c.status, list);
|
|
5441
|
-
}
|
|
5442
|
-
for (const columnCards of byStatus.values()) {
|
|
5443
|
-
columnCards.sort((a, b) => parseInt(a.order) - parseInt(b.order));
|
|
5444
|
-
const keys = generateNKeysBetween(null, null, columnCards.length);
|
|
5445
|
-
for (let i = 0; i < columnCards.length; i++) {
|
|
5446
|
-
columnCards[i].order = keys[i];
|
|
5447
|
-
await this._storage.writeCard(columnCards[i]);
|
|
5448
|
-
}
|
|
5449
|
-
}
|
|
5450
|
-
}
|
|
5451
|
-
const numericIds = cards.map((c) => parseInt(c.id, 10)).filter((n) => !Number.isNaN(n));
|
|
5452
|
-
if (numericIds.length > 0) {
|
|
5453
|
-
syncCardIdCounter(this.workspaceRoot, resolvedBoardId, numericIds);
|
|
5454
|
-
}
|
|
5455
|
-
const filtered = metaFilter && Object.keys(metaFilter).length > 0 ? cards.filter((c) => matchesMetaFilter(c.metadata, metaFilter)) : cards;
|
|
5456
|
-
if (sort) {
|
|
5457
|
-
const [field, dir] = sort.split(":");
|
|
5458
|
-
return filtered.sort((a, b) => {
|
|
5459
|
-
const aVal = field === "created" ? a.created : a.modified;
|
|
5460
|
-
const bVal = field === "created" ? b.created : b.modified;
|
|
5461
|
-
return dir === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
|
|
5462
|
-
});
|
|
5463
|
-
}
|
|
5464
|
-
return filtered.sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
6354
|
+
return listCards(this, columns, boardId, metaFilter, sort);
|
|
5465
6355
|
}
|
|
5466
6356
|
/**
|
|
5467
6357
|
* Retrieves a single card by its ID.
|
|
@@ -5482,8 +6372,7 @@ var init_KanbanSDK = __esm({
|
|
|
5482
6372
|
* ```
|
|
5483
6373
|
*/
|
|
5484
6374
|
async getCard(cardId, boardId) {
|
|
5485
|
-
|
|
5486
|
-
return cards.find((c) => c.id === cardId) || null;
|
|
6375
|
+
return getCard(this, cardId, boardId);
|
|
5487
6376
|
}
|
|
5488
6377
|
/**
|
|
5489
6378
|
* Creates a new card on a board.
|
|
@@ -5518,44 +6407,7 @@ var init_KanbanSDK = __esm({
|
|
|
5518
6407
|
* ```
|
|
5519
6408
|
*/
|
|
5520
6409
|
async createCard(data) {
|
|
5521
|
-
|
|
5522
|
-
const resolvedBoardId = this._resolveBoardId(data.boardId);
|
|
5523
|
-
const boardDir = this._boardDir(resolvedBoardId);
|
|
5524
|
-
await this._storage.ensureBoardDirs(boardDir);
|
|
5525
|
-
const config3 = readConfig(this.workspaceRoot);
|
|
5526
|
-
const board = config3.boards[resolvedBoardId];
|
|
5527
|
-
const status = data.status || board?.defaultStatus || config3.defaultStatus || "backlog";
|
|
5528
|
-
const priority = data.priority || board?.defaultPriority || config3.defaultPriority || "medium";
|
|
5529
|
-
const title = getTitleFromContent(data.content);
|
|
5530
|
-
const numericId = allocateCardId(this.workspaceRoot, resolvedBoardId);
|
|
5531
|
-
const filename = generateCardFilename(numericId, title);
|
|
5532
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5533
|
-
const cards = await this.listCards(void 0, resolvedBoardId);
|
|
5534
|
-
const cardsInStatus = cards.filter((c) => c.status === status).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
5535
|
-
const lastOrder = cardsInStatus.length > 0 ? cardsInStatus[cardsInStatus.length - 1].order : null;
|
|
5536
|
-
const card = {
|
|
5537
|
-
version: CARD_FORMAT_VERSION,
|
|
5538
|
-
id: String(numericId),
|
|
5539
|
-
boardId: resolvedBoardId,
|
|
5540
|
-
status,
|
|
5541
|
-
priority,
|
|
5542
|
-
assignee: data.assignee ?? null,
|
|
5543
|
-
dueDate: data.dueDate ?? null,
|
|
5544
|
-
created: now,
|
|
5545
|
-
modified: now,
|
|
5546
|
-
completedAt: this._isCompletedStatus(status, resolvedBoardId) ? now : null,
|
|
5547
|
-
labels: data.labels || [],
|
|
5548
|
-
attachments: data.attachments || [],
|
|
5549
|
-
comments: [],
|
|
5550
|
-
order: generateKeyBetween(lastOrder, null),
|
|
5551
|
-
content: data.content,
|
|
5552
|
-
...data.metadata && Object.keys(data.metadata).length > 0 ? { metadata: data.metadata } : {},
|
|
5553
|
-
...data.actions && (Array.isArray(data.actions) ? data.actions.length > 0 : Object.keys(data.actions).length > 0) ? { actions: data.actions } : {},
|
|
5554
|
-
filePath: this._storage.type === "markdown" ? getCardFilePath(boardDir, status, filename) : ""
|
|
5555
|
-
};
|
|
5556
|
-
await this._storage.writeCard(card);
|
|
5557
|
-
this.emitEvent("task.created", sanitizeCard(card));
|
|
5558
|
-
return card;
|
|
6410
|
+
return createCard(this, data);
|
|
5559
6411
|
}
|
|
5560
6412
|
/**
|
|
5561
6413
|
* Updates an existing card's properties.
|
|
@@ -5582,39 +6434,7 @@ var init_KanbanSDK = __esm({
|
|
|
5582
6434
|
* ```
|
|
5583
6435
|
*/
|
|
5584
6436
|
async updateCard(cardId, updates, boardId) {
|
|
5585
|
-
|
|
5586
|
-
if (!card)
|
|
5587
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
5588
|
-
const resolvedBoardId = card.boardId || this._resolveBoardId(boardId);
|
|
5589
|
-
const boardDir = this._boardDir(resolvedBoardId);
|
|
5590
|
-
const oldStatus = card.status;
|
|
5591
|
-
const oldTitle = getTitleFromContent(card.content);
|
|
5592
|
-
const { filePath: _fp, id: _id, boardId: _bid, ...safeUpdates } = updates;
|
|
5593
|
-
Object.assign(card, safeUpdates);
|
|
5594
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5595
|
-
if (oldStatus !== card.status) {
|
|
5596
|
-
card.completedAt = this._isCompletedStatus(card.status, resolvedBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
5597
|
-
}
|
|
5598
|
-
await this._storage.writeCard(card);
|
|
5599
|
-
const newTitle = getTitleFromContent(card.content);
|
|
5600
|
-
const numericId = extractNumericId(card.id);
|
|
5601
|
-
if (numericId !== null && newTitle !== oldTitle) {
|
|
5602
|
-
const newFilename = generateCardFilename(numericId, newTitle);
|
|
5603
|
-
const newPath = await this._storage.renameCard(card, newFilename);
|
|
5604
|
-
if (newPath)
|
|
5605
|
-
card.filePath = newPath;
|
|
5606
|
-
}
|
|
5607
|
-
if (oldStatus !== card.status) {
|
|
5608
|
-
const newPath = await this._storage.moveCard(card, boardDir, card.status);
|
|
5609
|
-
if (newPath)
|
|
5610
|
-
card.filePath = newPath;
|
|
5611
|
-
}
|
|
5612
|
-
this.emitEvent("task.updated", sanitizeCard(card));
|
|
5613
|
-
if (oldStatus !== card.status) {
|
|
5614
|
-
await this.addLog(card.id, `Status changed: \`${oldStatus}\` \u2192 \`${card.status}\``, { source: "system" }, resolvedBoardId).catch(() => {
|
|
5615
|
-
});
|
|
5616
|
-
}
|
|
5617
|
-
return card;
|
|
6437
|
+
return updateCard(this, cardId, updates, boardId);
|
|
5618
6438
|
}
|
|
5619
6439
|
/**
|
|
5620
6440
|
* Triggers a named action for a card by POSTing to the global `actionWebhookUrl`
|
|
@@ -5640,31 +6460,7 @@ var init_KanbanSDK = __esm({
|
|
|
5640
6460
|
* ```
|
|
5641
6461
|
*/
|
|
5642
6462
|
async triggerAction(cardId, action, boardId) {
|
|
5643
|
-
|
|
5644
|
-
const { actionWebhookUrl } = config3;
|
|
5645
|
-
if (!actionWebhookUrl) {
|
|
5646
|
-
throw new Error("No action webhook URL configured. Set actionWebhookUrl in .kanban.json");
|
|
5647
|
-
}
|
|
5648
|
-
const card = await this.getCard(cardId, boardId);
|
|
5649
|
-
if (!card)
|
|
5650
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
5651
|
-
const resolvedBoardId = card.boardId || this._resolveBoardId(boardId);
|
|
5652
|
-
const payload = {
|
|
5653
|
-
action,
|
|
5654
|
-
board: resolvedBoardId,
|
|
5655
|
-
list: card.status,
|
|
5656
|
-
card: sanitizeCard(card)
|
|
5657
|
-
};
|
|
5658
|
-
const response = await fetch(actionWebhookUrl, {
|
|
5659
|
-
method: "POST",
|
|
5660
|
-
headers: { "Content-Type": "application/json" },
|
|
5661
|
-
body: JSON.stringify(payload)
|
|
5662
|
-
});
|
|
5663
|
-
if (!response.ok) {
|
|
5664
|
-
throw new Error(`Action webhook responded with ${response.status}: ${response.statusText}`);
|
|
5665
|
-
}
|
|
5666
|
-
await this.addLog(cardId, `Action triggered: \`${action}\``, { source: "system" }, resolvedBoardId).catch(() => {
|
|
5667
|
-
});
|
|
6463
|
+
return triggerAction(this, cardId, action, boardId);
|
|
5668
6464
|
}
|
|
5669
6465
|
/**
|
|
5670
6466
|
* Moves a card to a different status column and/or position within that column.
|
|
@@ -5691,35 +6487,7 @@ var init_KanbanSDK = __esm({
|
|
|
5691
6487
|
* ```
|
|
5692
6488
|
*/
|
|
5693
6489
|
async moveCard(cardId, newStatus, position, boardId) {
|
|
5694
|
-
|
|
5695
|
-
const card = cards.find((c) => c.id === cardId);
|
|
5696
|
-
if (!card)
|
|
5697
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
5698
|
-
const resolvedBoardId = card.boardId || this._resolveBoardId(boardId);
|
|
5699
|
-
const boardDir = this._boardDir(resolvedBoardId);
|
|
5700
|
-
const oldStatus = card.status;
|
|
5701
|
-
card.status = newStatus;
|
|
5702
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
5703
|
-
if (oldStatus !== newStatus) {
|
|
5704
|
-
card.completedAt = this._isCompletedStatus(newStatus, resolvedBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
5705
|
-
}
|
|
5706
|
-
const targetColumnCards = cards.filter((c) => c.status === newStatus && c.id !== cardId).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
5707
|
-
const pos = position !== void 0 ? Math.max(0, Math.min(position, targetColumnCards.length)) : targetColumnCards.length;
|
|
5708
|
-
const before = pos > 0 ? targetColumnCards[pos - 1].order : null;
|
|
5709
|
-
const after = pos < targetColumnCards.length ? targetColumnCards[pos].order : null;
|
|
5710
|
-
card.order = generateKeyBetween(before, after);
|
|
5711
|
-
await this._storage.writeCard(card);
|
|
5712
|
-
if (oldStatus !== newStatus) {
|
|
5713
|
-
const newPath = await this._storage.moveCard(card, boardDir, newStatus);
|
|
5714
|
-
if (newPath)
|
|
5715
|
-
card.filePath = newPath;
|
|
5716
|
-
}
|
|
5717
|
-
this.emitEvent("task.moved", { ...sanitizeCard(card), previousStatus: oldStatus });
|
|
5718
|
-
if (oldStatus !== newStatus) {
|
|
5719
|
-
await this.addLog(card.id, `Status changed: \`${oldStatus}\` \u2192 \`${newStatus}\``, { source: "system" }, resolvedBoardId).catch(() => {
|
|
5720
|
-
});
|
|
5721
|
-
}
|
|
5722
|
-
return card;
|
|
6490
|
+
return moveCard(this, cardId, newStatus, position, boardId);
|
|
5723
6491
|
}
|
|
5724
6492
|
/**
|
|
5725
6493
|
* Soft-deletes a card by moving it to the `deleted` status column.
|
|
@@ -5736,12 +6504,7 @@ var init_KanbanSDK = __esm({
|
|
|
5736
6504
|
* ```
|
|
5737
6505
|
*/
|
|
5738
6506
|
async deleteCard(cardId, boardId) {
|
|
5739
|
-
|
|
5740
|
-
if (!card)
|
|
5741
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
5742
|
-
if (card.status === DELETED_STATUS_ID)
|
|
5743
|
-
return;
|
|
5744
|
-
await this.updateCard(cardId, { status: DELETED_STATUS_ID }, boardId);
|
|
6507
|
+
return deleteCard(this, cardId, boardId);
|
|
5745
6508
|
}
|
|
5746
6509
|
/**
|
|
5747
6510
|
* Permanently deletes a card's markdown file from disk.
|
|
@@ -5758,12 +6521,7 @@ var init_KanbanSDK = __esm({
|
|
|
5758
6521
|
* ```
|
|
5759
6522
|
*/
|
|
5760
6523
|
async permanentlyDeleteCard(cardId, boardId) {
|
|
5761
|
-
|
|
5762
|
-
if (!card)
|
|
5763
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
5764
|
-
const snapshot = sanitizeCard(card);
|
|
5765
|
-
await this._storage.deleteCard(card);
|
|
5766
|
-
this.emitEvent("task.deleted", snapshot);
|
|
6524
|
+
return permanentlyDeleteCard(this, cardId, boardId);
|
|
5767
6525
|
}
|
|
5768
6526
|
/**
|
|
5769
6527
|
* Returns all cards in a specific status column.
|
|
@@ -5782,8 +6540,7 @@ var init_KanbanSDK = __esm({
|
|
|
5782
6540
|
* ```
|
|
5783
6541
|
*/
|
|
5784
6542
|
async getCardsByStatus(status, boardId) {
|
|
5785
|
-
|
|
5786
|
-
return cards.filter((c) => c.status === status);
|
|
6543
|
+
return getCardsByStatus(this, status, boardId);
|
|
5787
6544
|
}
|
|
5788
6545
|
/**
|
|
5789
6546
|
* Returns a sorted list of unique assignee names across all cards on a board.
|
|
@@ -5800,13 +6557,7 @@ var init_KanbanSDK = __esm({
|
|
|
5800
6557
|
* ```
|
|
5801
6558
|
*/
|
|
5802
6559
|
async getUniqueAssignees(boardId) {
|
|
5803
|
-
|
|
5804
|
-
const assignees = /* @__PURE__ */ new Set();
|
|
5805
|
-
for (const c of cards) {
|
|
5806
|
-
if (c.assignee)
|
|
5807
|
-
assignees.add(c.assignee);
|
|
5808
|
-
}
|
|
5809
|
-
return [...assignees].sort();
|
|
6560
|
+
return getUniqueAssignees(this, boardId);
|
|
5810
6561
|
}
|
|
5811
6562
|
/**
|
|
5812
6563
|
* Returns a sorted list of unique labels across all cards on a board.
|
|
@@ -5821,13 +6572,7 @@ var init_KanbanSDK = __esm({
|
|
|
5821
6572
|
* ```
|
|
5822
6573
|
*/
|
|
5823
6574
|
async getUniqueLabels(boardId) {
|
|
5824
|
-
|
|
5825
|
-
const labels = /* @__PURE__ */ new Set();
|
|
5826
|
-
for (const c of cards) {
|
|
5827
|
-
for (const l of c.labels)
|
|
5828
|
-
labels.add(l);
|
|
5829
|
-
}
|
|
5830
|
-
return [...labels].sort();
|
|
6575
|
+
return getUniqueLabels(this, boardId);
|
|
5831
6576
|
}
|
|
5832
6577
|
// --- Label definition management ---
|
|
5833
6578
|
/**
|
|
@@ -5845,8 +6590,7 @@ var init_KanbanSDK = __esm({
|
|
|
5845
6590
|
* ```
|
|
5846
6591
|
*/
|
|
5847
6592
|
getLabels() {
|
|
5848
|
-
|
|
5849
|
-
return config3.labels || {};
|
|
6593
|
+
return getLabels(this);
|
|
5850
6594
|
}
|
|
5851
6595
|
/**
|
|
5852
6596
|
* Creates or updates a label definition in the workspace configuration.
|
|
@@ -5864,11 +6608,7 @@ var init_KanbanSDK = __esm({
|
|
|
5864
6608
|
* ```
|
|
5865
6609
|
*/
|
|
5866
6610
|
setLabel(name, definition) {
|
|
5867
|
-
|
|
5868
|
-
if (!config3.labels)
|
|
5869
|
-
config3.labels = {};
|
|
5870
|
-
config3.labels[name] = definition;
|
|
5871
|
-
writeConfig(this.workspaceRoot, config3);
|
|
6611
|
+
setLabel(this, name, definition);
|
|
5872
6612
|
}
|
|
5873
6613
|
/**
|
|
5874
6614
|
* Removes a label definition from the workspace configuration and cascades
|
|
@@ -5882,17 +6622,7 @@ var init_KanbanSDK = __esm({
|
|
|
5882
6622
|
* ```
|
|
5883
6623
|
*/
|
|
5884
6624
|
async deleteLabel(name) {
|
|
5885
|
-
|
|
5886
|
-
if (config3.labels) {
|
|
5887
|
-
delete config3.labels[name];
|
|
5888
|
-
writeConfig(this.workspaceRoot, config3);
|
|
5889
|
-
}
|
|
5890
|
-
const cards = await this.listCards();
|
|
5891
|
-
for (const card of cards) {
|
|
5892
|
-
if (card.labels.includes(name)) {
|
|
5893
|
-
await this.updateCard(card.id, { labels: card.labels.filter((l) => l !== name) });
|
|
5894
|
-
}
|
|
5895
|
-
}
|
|
6625
|
+
return deleteLabel(this, name);
|
|
5896
6626
|
}
|
|
5897
6627
|
/**
|
|
5898
6628
|
* Renames a label in the configuration and cascades the change to all cards.
|
|
@@ -5911,19 +6641,7 @@ var init_KanbanSDK = __esm({
|
|
|
5911
6641
|
* ```
|
|
5912
6642
|
*/
|
|
5913
6643
|
async renameLabel(oldName, newName) {
|
|
5914
|
-
|
|
5915
|
-
if (config3.labels && config3.labels[oldName]) {
|
|
5916
|
-
config3.labels[newName] = config3.labels[oldName];
|
|
5917
|
-
delete config3.labels[oldName];
|
|
5918
|
-
writeConfig(this.workspaceRoot, config3);
|
|
5919
|
-
}
|
|
5920
|
-
const cards = await this.listCards();
|
|
5921
|
-
for (const card of cards) {
|
|
5922
|
-
if (card.labels.includes(oldName)) {
|
|
5923
|
-
const newLabels = card.labels.map((l) => l === oldName ? newName : l);
|
|
5924
|
-
await this.updateCard(card.id, { labels: newLabels });
|
|
5925
|
-
}
|
|
5926
|
-
}
|
|
6644
|
+
return renameLabel(this, oldName, newName);
|
|
5927
6645
|
}
|
|
5928
6646
|
/**
|
|
5929
6647
|
* Returns a sorted list of label names that belong to the given group.
|
|
@@ -5944,8 +6662,7 @@ var init_KanbanSDK = __esm({
|
|
|
5944
6662
|
* ```
|
|
5945
6663
|
*/
|
|
5946
6664
|
getLabelsInGroup(group) {
|
|
5947
|
-
|
|
5948
|
-
return Object.entries(labels).filter(([, def]) => def.group === group).map(([name]) => name).sort();
|
|
6665
|
+
return getLabelsInGroup(this, group);
|
|
5949
6666
|
}
|
|
5950
6667
|
/**
|
|
5951
6668
|
* Returns all cards that have at least one label belonging to the given group.
|
|
@@ -5964,11 +6681,7 @@ var init_KanbanSDK = __esm({
|
|
|
5964
6681
|
* ```
|
|
5965
6682
|
*/
|
|
5966
6683
|
async filterCardsByLabelGroup(group, boardId) {
|
|
5967
|
-
|
|
5968
|
-
if (groupLabels.length === 0)
|
|
5969
|
-
return [];
|
|
5970
|
-
const cards = await this.listCards(void 0, boardId);
|
|
5971
|
-
return cards.filter((c) => c.labels.some((l) => groupLabels.includes(l)));
|
|
6684
|
+
return filterCardsByLabelGroup(this, group, boardId);
|
|
5972
6685
|
}
|
|
5973
6686
|
// --- Attachment management ---
|
|
5974
6687
|
/**
|
|
@@ -5991,18 +6704,7 @@ var init_KanbanSDK = __esm({
|
|
|
5991
6704
|
* ```
|
|
5992
6705
|
*/
|
|
5993
6706
|
async addAttachment(cardId, sourcePath, boardId) {
|
|
5994
|
-
|
|
5995
|
-
if (!card)
|
|
5996
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
5997
|
-
const fileName = path8.basename(sourcePath);
|
|
5998
|
-
await this._storage.copyAttachment(sourcePath, card);
|
|
5999
|
-
if (!card.attachments.includes(fileName)) {
|
|
6000
|
-
card.attachments.push(fileName);
|
|
6001
|
-
}
|
|
6002
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
6003
|
-
await this._storage.writeCard(card);
|
|
6004
|
-
this.emitEvent("attachment.added", { cardId, attachment: fileName });
|
|
6005
|
-
return card;
|
|
6707
|
+
return addAttachment(this, cardId, sourcePath, boardId);
|
|
6006
6708
|
}
|
|
6007
6709
|
/**
|
|
6008
6710
|
* Removes an attachment reference from a card's metadata.
|
|
@@ -6022,14 +6724,7 @@ var init_KanbanSDK = __esm({
|
|
|
6022
6724
|
* ```
|
|
6023
6725
|
*/
|
|
6024
6726
|
async removeAttachment(cardId, attachment, boardId) {
|
|
6025
|
-
|
|
6026
|
-
if (!card)
|
|
6027
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
6028
|
-
card.attachments = card.attachments.filter((a) => a !== attachment);
|
|
6029
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
6030
|
-
await this._storage.writeCard(card);
|
|
6031
|
-
this.emitEvent("attachment.removed", { cardId, attachment });
|
|
6032
|
-
return card;
|
|
6727
|
+
return removeAttachment(this, cardId, attachment, boardId);
|
|
6033
6728
|
}
|
|
6034
6729
|
/**
|
|
6035
6730
|
* Lists all attachment filenames for a card.
|
|
@@ -6046,10 +6741,7 @@ var init_KanbanSDK = __esm({
|
|
|
6046
6741
|
* ```
|
|
6047
6742
|
*/
|
|
6048
6743
|
async listAttachments(cardId, boardId) {
|
|
6049
|
-
|
|
6050
|
-
if (!card)
|
|
6051
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
6052
|
-
return card.attachments;
|
|
6744
|
+
return listAttachments(this, cardId, boardId);
|
|
6053
6745
|
}
|
|
6054
6746
|
/**
|
|
6055
6747
|
* Returns the absolute path to the attachment directory for a card.
|
|
@@ -6068,10 +6760,7 @@ var init_KanbanSDK = __esm({
|
|
|
6068
6760
|
* ```
|
|
6069
6761
|
*/
|
|
6070
6762
|
async getAttachmentDir(cardId, boardId) {
|
|
6071
|
-
|
|
6072
|
-
if (!card)
|
|
6073
|
-
return null;
|
|
6074
|
-
return this._storage.getCardDir(card);
|
|
6763
|
+
return getAttachmentDir(this, cardId, boardId);
|
|
6075
6764
|
}
|
|
6076
6765
|
// --- Comment management ---
|
|
6077
6766
|
/**
|
|
@@ -6091,10 +6780,7 @@ var init_KanbanSDK = __esm({
|
|
|
6091
6780
|
* ```
|
|
6092
6781
|
*/
|
|
6093
6782
|
async listComments(cardId, boardId) {
|
|
6094
|
-
|
|
6095
|
-
if (!card)
|
|
6096
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
6097
|
-
return card.comments || [];
|
|
6783
|
+
return listComments(this, cardId, boardId);
|
|
6098
6784
|
}
|
|
6099
6785
|
/**
|
|
6100
6786
|
* Adds a comment to a card.
|
|
@@ -6116,28 +6802,7 @@ var init_KanbanSDK = __esm({
|
|
|
6116
6802
|
* ```
|
|
6117
6803
|
*/
|
|
6118
6804
|
async addComment(cardId, author, content, boardId) {
|
|
6119
|
-
|
|
6120
|
-
throw new Error("Comment content cannot be empty");
|
|
6121
|
-
const card = await this.getCard(cardId, boardId);
|
|
6122
|
-
if (!card)
|
|
6123
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
6124
|
-
if (!card.comments)
|
|
6125
|
-
card.comments = [];
|
|
6126
|
-
const maxId = card.comments.reduce((max, c) => {
|
|
6127
|
-
const num = parseInt(c.id.replace("c", ""), 10);
|
|
6128
|
-
return Number.isNaN(num) ? max : Math.max(max, num);
|
|
6129
|
-
}, 0);
|
|
6130
|
-
const comment = {
|
|
6131
|
-
id: `c${maxId + 1}`,
|
|
6132
|
-
author,
|
|
6133
|
-
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6134
|
-
content
|
|
6135
|
-
};
|
|
6136
|
-
card.comments.push(comment);
|
|
6137
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
6138
|
-
await this._storage.writeCard(card);
|
|
6139
|
-
this.emitEvent("comment.created", { ...comment, cardId });
|
|
6140
|
-
return card;
|
|
6805
|
+
return addComment(this, cardId, author, content, boardId);
|
|
6141
6806
|
}
|
|
6142
6807
|
/**
|
|
6143
6808
|
* Updates the content of an existing comment on a card.
|
|
@@ -6156,17 +6821,7 @@ var init_KanbanSDK = __esm({
|
|
|
6156
6821
|
* ```
|
|
6157
6822
|
*/
|
|
6158
6823
|
async updateComment(cardId, commentId, content, boardId) {
|
|
6159
|
-
|
|
6160
|
-
if (!card)
|
|
6161
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
6162
|
-
const comment = (card.comments || []).find((c) => c.id === commentId);
|
|
6163
|
-
if (!comment)
|
|
6164
|
-
throw new Error(`Comment not found: ${commentId}`);
|
|
6165
|
-
comment.content = content;
|
|
6166
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
6167
|
-
await this._storage.writeCard(card);
|
|
6168
|
-
this.emitEvent("comment.updated", { ...comment, cardId });
|
|
6169
|
-
return card;
|
|
6824
|
+
return updateComment(this, cardId, commentId, content, boardId);
|
|
6170
6825
|
}
|
|
6171
6826
|
/**
|
|
6172
6827
|
* Deletes a comment from a card.
|
|
@@ -6183,17 +6838,7 @@ var init_KanbanSDK = __esm({
|
|
|
6183
6838
|
* ```
|
|
6184
6839
|
*/
|
|
6185
6840
|
async deleteComment(cardId, commentId, boardId) {
|
|
6186
|
-
|
|
6187
|
-
if (!card)
|
|
6188
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
6189
|
-
const comment = (card.comments || []).find((c) => c.id === commentId);
|
|
6190
|
-
card.comments = (card.comments || []).filter((c) => c.id !== commentId);
|
|
6191
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
6192
|
-
await this._storage.writeCard(card);
|
|
6193
|
-
if (comment) {
|
|
6194
|
-
this.emitEvent("comment.deleted", { ...comment, cardId });
|
|
6195
|
-
}
|
|
6196
|
-
return card;
|
|
6841
|
+
return deleteComment(this, cardId, commentId, boardId);
|
|
6197
6842
|
}
|
|
6198
6843
|
// --- Log management ---
|
|
6199
6844
|
/**
|
|
@@ -6207,44 +6852,7 @@ var init_KanbanSDK = __esm({
|
|
|
6207
6852
|
* @returns A promise resolving to the log file path, or `null` if the card is not found.
|
|
6208
6853
|
*/
|
|
6209
6854
|
async getLogFilePath(cardId, boardId) {
|
|
6210
|
-
|
|
6211
|
-
if (!card)
|
|
6212
|
-
return null;
|
|
6213
|
-
const dir = this._storage.getCardDir(card);
|
|
6214
|
-
return path8.join(dir, `${card.id}.log`);
|
|
6215
|
-
}
|
|
6216
|
-
/**
|
|
6217
|
-
* Parses a single log line into a {@link LogEntry}.
|
|
6218
|
-
*
|
|
6219
|
-
* Expected format: `timestamp [source] text {json}`
|
|
6220
|
-
*/
|
|
6221
|
-
_parseLogLine(line) {
|
|
6222
|
-
const trimmed = line.trim();
|
|
6223
|
-
if (!trimmed)
|
|
6224
|
-
return null;
|
|
6225
|
-
const match = trimmed.match(/^(\S+)\s+\[([^\]]+)\]\s+(.+)$/);
|
|
6226
|
-
if (!match)
|
|
6227
|
-
return null;
|
|
6228
|
-
const [, timestamp2, source, rest] = match;
|
|
6229
|
-
const jsonMatch = rest.match(/^(.*?)\s+(\{.+\})\s*$/);
|
|
6230
|
-
if (jsonMatch) {
|
|
6231
|
-
try {
|
|
6232
|
-
const obj = JSON.parse(jsonMatch[2]);
|
|
6233
|
-
return { timestamp: timestamp2, source, text: jsonMatch[1], object: obj };
|
|
6234
|
-
} catch {
|
|
6235
|
-
}
|
|
6236
|
-
}
|
|
6237
|
-
return { timestamp: timestamp2, source, text: rest };
|
|
6238
|
-
}
|
|
6239
|
-
/**
|
|
6240
|
-
* Serializes a {@link LogEntry} into a single log line.
|
|
6241
|
-
*/
|
|
6242
|
-
_serializeLogEntry(entry) {
|
|
6243
|
-
let line = `${entry.timestamp} [${entry.source}] ${entry.text}`;
|
|
6244
|
-
if (entry.object && Object.keys(entry.object).length > 0) {
|
|
6245
|
-
line += ` ${JSON.stringify(entry.object)}`;
|
|
6246
|
-
}
|
|
6247
|
-
return line;
|
|
6855
|
+
return getLogFilePath(this, cardId, boardId);
|
|
6248
6856
|
}
|
|
6249
6857
|
/**
|
|
6250
6858
|
* Lists all log entries for a card.
|
|
@@ -6266,21 +6874,7 @@ var init_KanbanSDK = __esm({
|
|
|
6266
6874
|
* ```
|
|
6267
6875
|
*/
|
|
6268
6876
|
async listLogs(cardId, boardId) {
|
|
6269
|
-
|
|
6270
|
-
if (!logPath)
|
|
6271
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
6272
|
-
try {
|
|
6273
|
-
const content = await fs6.readFile(logPath, "utf-8");
|
|
6274
|
-
const entries = [];
|
|
6275
|
-
for (const line of content.split("\n")) {
|
|
6276
|
-
const entry = this._parseLogLine(line);
|
|
6277
|
-
if (entry)
|
|
6278
|
-
entries.push(entry);
|
|
6279
|
-
}
|
|
6280
|
-
return entries;
|
|
6281
|
-
} catch {
|
|
6282
|
-
return [];
|
|
6283
|
-
}
|
|
6877
|
+
return listLogs(this, cardId, boardId);
|
|
6284
6878
|
}
|
|
6285
6879
|
/**
|
|
6286
6880
|
* Adds a log entry to a card.
|
|
@@ -6310,30 +6904,7 @@ var init_KanbanSDK = __esm({
|
|
|
6310
6904
|
* ```
|
|
6311
6905
|
*/
|
|
6312
6906
|
async addLog(cardId, text, options, boardId) {
|
|
6313
|
-
|
|
6314
|
-
throw new Error("Log text cannot be empty");
|
|
6315
|
-
const card = await this.getCard(cardId, boardId);
|
|
6316
|
-
if (!card)
|
|
6317
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
6318
|
-
const entry = {
|
|
6319
|
-
timestamp: options?.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
6320
|
-
source: options?.source || "default",
|
|
6321
|
-
text: text.trim(),
|
|
6322
|
-
...options?.object && Object.keys(options.object).length > 0 ? { object: options.object } : {}
|
|
6323
|
-
};
|
|
6324
|
-
const dir = this._storage.getCardDir(card);
|
|
6325
|
-
const logFileName = `${card.id}.log`;
|
|
6326
|
-
const logPath = path8.join(dir, logFileName);
|
|
6327
|
-
await fs6.mkdir(dir, { recursive: true });
|
|
6328
|
-
const line = this._serializeLogEntry(entry) + "\n";
|
|
6329
|
-
await fs6.appendFile(logPath, line, "utf-8");
|
|
6330
|
-
if (!card.attachments.includes(logFileName)) {
|
|
6331
|
-
card.attachments.push(logFileName);
|
|
6332
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
6333
|
-
await this._storage.writeCard(card);
|
|
6334
|
-
}
|
|
6335
|
-
this.emitEvent("log.added", { cardId, entry });
|
|
6336
|
-
return entry;
|
|
6907
|
+
return addLog(this, cardId, text, options, boardId);
|
|
6337
6908
|
}
|
|
6338
6909
|
/**
|
|
6339
6910
|
* Clears all log entries for a card by deleting the `.log` file.
|
|
@@ -6352,22 +6923,7 @@ var init_KanbanSDK = __esm({
|
|
|
6352
6923
|
* ```
|
|
6353
6924
|
*/
|
|
6354
6925
|
async clearLogs(cardId, boardId) {
|
|
6355
|
-
|
|
6356
|
-
if (!card)
|
|
6357
|
-
throw new Error(`Card not found: ${cardId}`);
|
|
6358
|
-
const logFileName = `${card.id}.log`;
|
|
6359
|
-
const dir = this._storage.getCardDir(card);
|
|
6360
|
-
const logPath = path8.join(dir, logFileName);
|
|
6361
|
-
try {
|
|
6362
|
-
await fs6.unlink(logPath);
|
|
6363
|
-
} catch {
|
|
6364
|
-
}
|
|
6365
|
-
if (card.attachments.includes(logFileName)) {
|
|
6366
|
-
card.attachments = card.attachments.filter((a) => a !== logFileName);
|
|
6367
|
-
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
6368
|
-
await this._storage.writeCard(card);
|
|
6369
|
-
}
|
|
6370
|
-
this.emitEvent("log.cleared", { cardId });
|
|
6926
|
+
return clearLogs(this, cardId, boardId);
|
|
6371
6927
|
}
|
|
6372
6928
|
// --- Board-level log management ---
|
|
6373
6929
|
/**
|
|
@@ -6386,7 +6942,7 @@ var init_KanbanSDK = __esm({
|
|
|
6386
6942
|
* ```
|
|
6387
6943
|
*/
|
|
6388
6944
|
getBoardLogFilePath(boardId) {
|
|
6389
|
-
return
|
|
6945
|
+
return getBoardLogFilePath(this, boardId);
|
|
6390
6946
|
}
|
|
6391
6947
|
/**
|
|
6392
6948
|
* Lists all log entries from the board-level log file.
|
|
@@ -6403,23 +6959,7 @@ var init_KanbanSDK = __esm({
|
|
|
6403
6959
|
* ```
|
|
6404
6960
|
*/
|
|
6405
6961
|
async listBoardLogs(boardId) {
|
|
6406
|
-
|
|
6407
|
-
let content;
|
|
6408
|
-
try {
|
|
6409
|
-
content = await fs6.readFile(logPath, "utf-8");
|
|
6410
|
-
} catch {
|
|
6411
|
-
return [];
|
|
6412
|
-
}
|
|
6413
|
-
const entries = [];
|
|
6414
|
-
for (const line of content.split("\n")) {
|
|
6415
|
-
const trimmed = line.trim();
|
|
6416
|
-
if (!trimmed)
|
|
6417
|
-
continue;
|
|
6418
|
-
const entry = this._parseLogLine(trimmed);
|
|
6419
|
-
if (entry)
|
|
6420
|
-
entries.push(entry);
|
|
6421
|
-
}
|
|
6422
|
-
return entries;
|
|
6962
|
+
return listBoardLogs(this, boardId);
|
|
6423
6963
|
}
|
|
6424
6964
|
/**
|
|
6425
6965
|
* Appends a new log entry to the board-level log file.
|
|
@@ -6437,18 +6977,7 @@ var init_KanbanSDK = __esm({
|
|
|
6437
6977
|
* ```
|
|
6438
6978
|
*/
|
|
6439
6979
|
async addBoardLog(text, options, boardId) {
|
|
6440
|
-
|
|
6441
|
-
timestamp: options?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
6442
|
-
source: options?.source ?? "sdk",
|
|
6443
|
-
text,
|
|
6444
|
-
...options?.object ? { object: options.object } : {}
|
|
6445
|
-
};
|
|
6446
|
-
const logPath = this.getBoardLogFilePath(boardId);
|
|
6447
|
-
await fs6.mkdir(path8.dirname(logPath), { recursive: true });
|
|
6448
|
-
const line = this._serializeLogEntry(entry) + "\n";
|
|
6449
|
-
await fs6.appendFile(logPath, line, "utf-8");
|
|
6450
|
-
this.emitEvent("board.log.added", { boardId, entry });
|
|
6451
|
-
return entry;
|
|
6980
|
+
return addBoardLog(this, text, options, boardId);
|
|
6452
6981
|
}
|
|
6453
6982
|
/**
|
|
6454
6983
|
* Clears all log entries for a board by deleting the board-level `board.log` file.
|
|
@@ -6465,12 +6994,7 @@ var init_KanbanSDK = __esm({
|
|
|
6465
6994
|
* ```
|
|
6466
6995
|
*/
|
|
6467
6996
|
async clearBoardLogs(boardId) {
|
|
6468
|
-
|
|
6469
|
-
try {
|
|
6470
|
-
await fs6.unlink(logPath);
|
|
6471
|
-
} catch {
|
|
6472
|
-
}
|
|
6473
|
-
this.emitEvent("board.log.cleared", { boardId });
|
|
6997
|
+
return clearBoardLogs(this, boardId);
|
|
6474
6998
|
}
|
|
6475
6999
|
// --- Column management (board-scoped) ---
|
|
6476
7000
|
/**
|
|
@@ -6486,10 +7010,7 @@ var init_KanbanSDK = __esm({
|
|
|
6486
7010
|
* ```
|
|
6487
7011
|
*/
|
|
6488
7012
|
listColumns(boardId) {
|
|
6489
|
-
|
|
6490
|
-
const resolvedId = boardId || config3.defaultBoard;
|
|
6491
|
-
const board = config3.boards[resolvedId];
|
|
6492
|
-
return board?.columns || [];
|
|
7013
|
+
return listColumns(this, boardId);
|
|
6493
7014
|
}
|
|
6494
7015
|
/**
|
|
6495
7016
|
* Adds a new column to a board.
|
|
@@ -6515,20 +7036,7 @@ var init_KanbanSDK = __esm({
|
|
|
6515
7036
|
* ```
|
|
6516
7037
|
*/
|
|
6517
7038
|
addColumn(column, boardId) {
|
|
6518
|
-
|
|
6519
|
-
const resolvedId = boardId || config3.defaultBoard;
|
|
6520
|
-
const board = config3.boards[resolvedId];
|
|
6521
|
-
if (!board)
|
|
6522
|
-
throw new Error(`Board not found: ${resolvedId}`);
|
|
6523
|
-
if (column.id === DELETED_STATUS_ID)
|
|
6524
|
-
throw new Error(`"${DELETED_STATUS_ID}" is a reserved column ID`);
|
|
6525
|
-
if (board.columns.some((c) => c.id === column.id)) {
|
|
6526
|
-
throw new Error(`Column already exists: ${column.id}`);
|
|
6527
|
-
}
|
|
6528
|
-
board.columns.push(column);
|
|
6529
|
-
writeConfig(this.workspaceRoot, config3);
|
|
6530
|
-
this.emitEvent("column.created", column);
|
|
6531
|
-
return board.columns;
|
|
7039
|
+
return addColumn(this, column, boardId);
|
|
6532
7040
|
}
|
|
6533
7041
|
/**
|
|
6534
7042
|
* Updates the properties of an existing column.
|
|
@@ -6554,21 +7062,7 @@ var init_KanbanSDK = __esm({
|
|
|
6554
7062
|
* ```
|
|
6555
7063
|
*/
|
|
6556
7064
|
updateColumn(columnId, updates, boardId) {
|
|
6557
|
-
|
|
6558
|
-
const resolvedId = boardId || config3.defaultBoard;
|
|
6559
|
-
const board = config3.boards[resolvedId];
|
|
6560
|
-
if (!board)
|
|
6561
|
-
throw new Error(`Board not found: ${resolvedId}`);
|
|
6562
|
-
const col = board.columns.find((c) => c.id === columnId);
|
|
6563
|
-
if (!col)
|
|
6564
|
-
throw new Error(`Column not found: ${columnId}`);
|
|
6565
|
-
if (updates.name !== void 0)
|
|
6566
|
-
col.name = updates.name;
|
|
6567
|
-
if (updates.color !== void 0)
|
|
6568
|
-
col.color = updates.color;
|
|
6569
|
-
writeConfig(this.workspaceRoot, config3);
|
|
6570
|
-
this.emitEvent("column.updated", col);
|
|
6571
|
-
return board.columns;
|
|
7065
|
+
return updateColumn(this, columnId, updates, boardId);
|
|
6572
7066
|
}
|
|
6573
7067
|
/**
|
|
6574
7068
|
* Removes a column from a board.
|
|
@@ -6590,26 +7084,7 @@ var init_KanbanSDK = __esm({
|
|
|
6590
7084
|
* ```
|
|
6591
7085
|
*/
|
|
6592
7086
|
async removeColumn(columnId, boardId) {
|
|
6593
|
-
|
|
6594
|
-
const resolvedId = boardId || config3.defaultBoard;
|
|
6595
|
-
const board = config3.boards[resolvedId];
|
|
6596
|
-
if (!board)
|
|
6597
|
-
throw new Error(`Board not found: ${resolvedId}`);
|
|
6598
|
-
if (columnId === DELETED_STATUS_ID)
|
|
6599
|
-
throw new Error(`Cannot remove the reserved "${DELETED_STATUS_ID}" column`);
|
|
6600
|
-
const idx = board.columns.findIndex((c) => c.id === columnId);
|
|
6601
|
-
if (idx === -1)
|
|
6602
|
-
throw new Error(`Column not found: ${columnId}`);
|
|
6603
|
-
const cards = await this.listCards(void 0, resolvedId);
|
|
6604
|
-
const cardsInColumn = cards.filter((c) => c.status === columnId);
|
|
6605
|
-
if (cardsInColumn.length > 0) {
|
|
6606
|
-
throw new Error(`Cannot remove column "${columnId}": ${cardsInColumn.length} card(s) still in this column`);
|
|
6607
|
-
}
|
|
6608
|
-
const removed = board.columns[idx];
|
|
6609
|
-
board.columns.splice(idx, 1);
|
|
6610
|
-
writeConfig(this.workspaceRoot, config3);
|
|
6611
|
-
this.emitEvent("column.deleted", removed);
|
|
6612
|
-
return board.columns;
|
|
7087
|
+
return removeColumn(this, columnId, boardId);
|
|
6613
7088
|
}
|
|
6614
7089
|
/**
|
|
6615
7090
|
* Moves all cards in the specified column to the `deleted` (soft-delete) column.
|
|
@@ -6630,14 +7105,7 @@ var init_KanbanSDK = __esm({
|
|
|
6630
7105
|
* ```
|
|
6631
7106
|
*/
|
|
6632
7107
|
async cleanupColumn(columnId, boardId) {
|
|
6633
|
-
|
|
6634
|
-
return 0;
|
|
6635
|
-
const cards = await this.listCards(void 0, boardId);
|
|
6636
|
-
const cardsToMove = cards.filter((c) => c.status === columnId);
|
|
6637
|
-
for (const card of cardsToMove) {
|
|
6638
|
-
await this.moveCard(card.id, DELETED_STATUS_ID, 0, boardId);
|
|
6639
|
-
}
|
|
6640
|
-
return cardsToMove.length;
|
|
7108
|
+
return cleanupColumn(this, columnId, boardId);
|
|
6641
7109
|
}
|
|
6642
7110
|
/**
|
|
6643
7111
|
* Permanently deletes all cards currently in the `deleted` column.
|
|
@@ -6655,12 +7123,7 @@ var init_KanbanSDK = __esm({
|
|
|
6655
7123
|
* ```
|
|
6656
7124
|
*/
|
|
6657
7125
|
async purgeDeletedCards(boardId) {
|
|
6658
|
-
|
|
6659
|
-
const deleted = cards.filter((c) => c.status === DELETED_STATUS_ID);
|
|
6660
|
-
for (const card of deleted) {
|
|
6661
|
-
await this.permanentlyDeleteCard(card.id, boardId);
|
|
6662
|
-
}
|
|
6663
|
-
return deleted.length;
|
|
7126
|
+
return purgeDeletedCards(this, boardId);
|
|
6664
7127
|
}
|
|
6665
7128
|
/**
|
|
6666
7129
|
* Reorders the columns of a board.
|
|
@@ -6684,22 +7147,7 @@ var init_KanbanSDK = __esm({
|
|
|
6684
7147
|
* ```
|
|
6685
7148
|
*/
|
|
6686
7149
|
reorderColumns(columnIds, boardId) {
|
|
6687
|
-
|
|
6688
|
-
const resolvedId = boardId || config3.defaultBoard;
|
|
6689
|
-
const board = config3.boards[resolvedId];
|
|
6690
|
-
if (!board)
|
|
6691
|
-
throw new Error(`Board not found: ${resolvedId}`);
|
|
6692
|
-
const colMap = new Map(board.columns.map((c) => [c.id, c]));
|
|
6693
|
-
for (const id of columnIds) {
|
|
6694
|
-
if (!colMap.has(id))
|
|
6695
|
-
throw new Error(`Column not found: ${id}`);
|
|
6696
|
-
}
|
|
6697
|
-
if (columnIds.length !== board.columns.length) {
|
|
6698
|
-
throw new Error("Must include all column IDs when reordering");
|
|
6699
|
-
}
|
|
6700
|
-
board.columns = columnIds.map((id) => colMap.get(id));
|
|
6701
|
-
writeConfig(this.workspaceRoot, config3);
|
|
6702
|
-
return board.columns;
|
|
7150
|
+
return reorderColumns(this, columnIds, boardId);
|
|
6703
7151
|
}
|
|
6704
7152
|
// --- Settings management (global) ---
|
|
6705
7153
|
/**
|
|
@@ -6717,7 +7165,7 @@ var init_KanbanSDK = __esm({
|
|
|
6717
7165
|
* ```
|
|
6718
7166
|
*/
|
|
6719
7167
|
getSettings() {
|
|
6720
|
-
return
|
|
7168
|
+
return getSettings(this);
|
|
6721
7169
|
}
|
|
6722
7170
|
/**
|
|
6723
7171
|
* Updates the global card display settings for the workspace.
|
|
@@ -6738,9 +7186,7 @@ var init_KanbanSDK = __esm({
|
|
|
6738
7186
|
* ```
|
|
6739
7187
|
*/
|
|
6740
7188
|
updateSettings(settings) {
|
|
6741
|
-
|
|
6742
|
-
writeConfig(this.workspaceRoot, settingsToConfig(config3, settings));
|
|
6743
|
-
this.emitEvent("settings.updated", settings);
|
|
7189
|
+
updateSettings(this, settings);
|
|
6744
7190
|
}
|
|
6745
7191
|
// ---------------------------------------------------------------------------
|
|
6746
7192
|
// Storage migration
|
|
@@ -6768,30 +7214,7 @@ var init_KanbanSDK = __esm({
|
|
|
6768
7214
|
* ```
|
|
6769
7215
|
*/
|
|
6770
7216
|
async migrateToSqlite(dbPath) {
|
|
6771
|
-
|
|
6772
|
-
throw new Error("Storage engine is already sqlite");
|
|
6773
|
-
}
|
|
6774
|
-
await this._ensureMigrated();
|
|
6775
|
-
const resolvedDbPath = dbPath ?? ".kanban/kanban.db";
|
|
6776
|
-
const absDbPath = path8.resolve(this.workspaceRoot, resolvedDbPath);
|
|
6777
|
-
const { SqliteStorageEngine: SqliteStorageEngine2 } = await Promise.resolve().then(() => (init_sqlite(), sqlite_exports));
|
|
6778
|
-
const sqliteEngine = new SqliteStorageEngine2(this._storage.kanbanDir, absDbPath);
|
|
6779
|
-
await sqliteEngine.init();
|
|
6780
|
-
const config3 = readConfig(this.workspaceRoot);
|
|
6781
|
-
const boardIds = Object.keys(config3.boards);
|
|
6782
|
-
let count = 0;
|
|
6783
|
-
for (const boardId of boardIds) {
|
|
6784
|
-
const boardDir = path8.join(this._storage.kanbanDir, "boards", boardId);
|
|
6785
|
-
const cards = await this._storage.scanCards(boardDir, boardId);
|
|
6786
|
-
for (const card of cards) {
|
|
6787
|
-
await sqliteEngine.writeCard({ ...card, filePath: "" });
|
|
6788
|
-
count++;
|
|
6789
|
-
}
|
|
6790
|
-
}
|
|
6791
|
-
sqliteEngine.close();
|
|
6792
|
-
writeConfig(this.workspaceRoot, { ...config3, storageEngine: "sqlite", sqlitePath: resolvedDbPath });
|
|
6793
|
-
this.emitEvent("storage.migrated", { from: "markdown", to: "sqlite", count });
|
|
6794
|
-
return count;
|
|
7217
|
+
return migrateToSqlite(this, dbPath);
|
|
6795
7218
|
}
|
|
6796
7219
|
/**
|
|
6797
7220
|
* Migrates all card data from the current SQLite engine back to markdown files.
|
|
@@ -6814,152 +7237,59 @@ var init_KanbanSDK = __esm({
|
|
|
6814
7237
|
* ```
|
|
6815
7238
|
*/
|
|
6816
7239
|
async migrateToMarkdown() {
|
|
6817
|
-
|
|
6818
|
-
throw new Error("Storage engine is already markdown");
|
|
6819
|
-
}
|
|
6820
|
-
await this._ensureMigrated();
|
|
6821
|
-
const { MarkdownStorageEngine: MarkdownStorageEngine2 } = await Promise.resolve().then(() => (init_markdown(), markdown_exports));
|
|
6822
|
-
const mdEngine = new MarkdownStorageEngine2(this._storage.kanbanDir);
|
|
6823
|
-
await mdEngine.init();
|
|
6824
|
-
const config3 = readConfig(this.workspaceRoot);
|
|
6825
|
-
const boardIds = Object.keys(config3.boards);
|
|
6826
|
-
let count = 0;
|
|
6827
|
-
for (const boardId of boardIds) {
|
|
6828
|
-
const boardDir = path8.join(this._storage.kanbanDir, "boards", boardId);
|
|
6829
|
-
const cards = await this._storage.scanCards(boardDir, boardId);
|
|
6830
|
-
for (const card of cards) {
|
|
6831
|
-
const numericId = Number(card.id) || 0;
|
|
6832
|
-
const title = getTitleFromContent(card.content) || card.id;
|
|
6833
|
-
const filename = generateCardFilename(numericId, title);
|
|
6834
|
-
const filePath = getCardFilePath(boardDir, card.status, filename);
|
|
6835
|
-
await mdEngine.writeCard({ ...card, filePath });
|
|
6836
|
-
count++;
|
|
6837
|
-
}
|
|
6838
|
-
}
|
|
6839
|
-
mdEngine.close();
|
|
6840
|
-
const { storageEngine: _se, sqlitePath: _sp, ...restConfig } = config3;
|
|
6841
|
-
writeConfig(this.workspaceRoot, restConfig);
|
|
6842
|
-
this.emitEvent("storage.migrated", { from: "sqlite", to: "markdown", count });
|
|
6843
|
-
return count;
|
|
7240
|
+
return migrateToMarkdown(this);
|
|
6844
7241
|
}
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
}
|
|
6859
|
-
function createWebhook(workspaceRoot, webhookConfig) {
|
|
6860
|
-
const webhooks = loadWebhooks(workspaceRoot);
|
|
6861
|
-
const webhook = {
|
|
6862
|
-
id: "wh_" + crypto.randomBytes(8).toString("hex"),
|
|
6863
|
-
url: webhookConfig.url,
|
|
6864
|
-
events: webhookConfig.events,
|
|
6865
|
-
secret: webhookConfig.secret,
|
|
6866
|
-
active: true
|
|
6867
|
-
};
|
|
6868
|
-
webhooks.push(webhook);
|
|
6869
|
-
saveWebhooks(workspaceRoot, webhooks);
|
|
6870
|
-
return webhook;
|
|
6871
|
-
}
|
|
6872
|
-
function deleteWebhook(workspaceRoot, id) {
|
|
6873
|
-
const webhooks = loadWebhooks(workspaceRoot);
|
|
6874
|
-
const filtered = webhooks.filter((w) => w.id !== id);
|
|
6875
|
-
if (filtered.length === webhooks.length)
|
|
6876
|
-
return false;
|
|
6877
|
-
saveWebhooks(workspaceRoot, filtered);
|
|
6878
|
-
return true;
|
|
6879
|
-
}
|
|
6880
|
-
function updateWebhook(workspaceRoot, id, updates) {
|
|
6881
|
-
const webhooks = loadWebhooks(workspaceRoot);
|
|
6882
|
-
const webhook = webhooks.find((w) => w.id === id);
|
|
6883
|
-
if (!webhook)
|
|
6884
|
-
return null;
|
|
6885
|
-
if (updates.url !== void 0)
|
|
6886
|
-
webhook.url = updates.url;
|
|
6887
|
-
if (updates.events !== void 0)
|
|
6888
|
-
webhook.events = updates.events;
|
|
6889
|
-
if (updates.secret !== void 0)
|
|
6890
|
-
webhook.secret = updates.secret;
|
|
6891
|
-
if (updates.active !== void 0)
|
|
6892
|
-
webhook.active = updates.active;
|
|
6893
|
-
saveWebhooks(workspaceRoot, webhooks);
|
|
6894
|
-
return webhook;
|
|
6895
|
-
}
|
|
6896
|
-
function fireWebhooks(workspaceRoot, event, data) {
|
|
6897
|
-
const webhooks = loadWebhooks(workspaceRoot);
|
|
6898
|
-
const matching = webhooks.filter(
|
|
6899
|
-
(w) => w.active && (w.events.includes("*") || w.events.includes(event))
|
|
6900
|
-
);
|
|
6901
|
-
if (matching.length === 0)
|
|
6902
|
-
return;
|
|
6903
|
-
const payload = JSON.stringify({
|
|
6904
|
-
event,
|
|
6905
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6906
|
-
data
|
|
6907
|
-
});
|
|
6908
|
-
for (const webhook of matching) {
|
|
6909
|
-
deliverWebhook(webhook, event, payload).catch((err) => {
|
|
6910
|
-
console.error(`Webhook delivery failed for ${webhook.id} (${webhook.url}):`, err.message || err);
|
|
6911
|
-
});
|
|
6912
|
-
}
|
|
6913
|
-
}
|
|
6914
|
-
async function deliverWebhook(webhook, event, payload) {
|
|
6915
|
-
const url3 = new URL(webhook.url);
|
|
6916
|
-
const isHttps = url3.protocol === "https:";
|
|
6917
|
-
const transport = isHttps ? https : http;
|
|
6918
|
-
const headers = {
|
|
6919
|
-
"Content-Type": "application/json",
|
|
6920
|
-
"Content-Length": Buffer.byteLength(payload).toString(),
|
|
6921
|
-
"X-Webhook-Event": event
|
|
6922
|
-
};
|
|
6923
|
-
if (webhook.secret) {
|
|
6924
|
-
const signature = crypto.createHmac("sha256", webhook.secret).update(payload).digest("hex");
|
|
6925
|
-
headers["X-Webhook-Signature"] = `sha256=${signature}`;
|
|
6926
|
-
}
|
|
6927
|
-
return new Promise((resolve9, reject) => {
|
|
6928
|
-
const req = transport.request(
|
|
6929
|
-
{
|
|
6930
|
-
hostname: url3.hostname,
|
|
6931
|
-
port: url3.port || (isHttps ? 443 : 80),
|
|
6932
|
-
path: url3.pathname + url3.search,
|
|
6933
|
-
method: "POST",
|
|
6934
|
-
headers,
|
|
6935
|
-
timeout: 1e4
|
|
6936
|
-
},
|
|
6937
|
-
(res) => {
|
|
6938
|
-
res.resume();
|
|
6939
|
-
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
6940
|
-
resolve9();
|
|
6941
|
-
} else {
|
|
6942
|
-
reject(new Error(`HTTP ${res.statusCode}`));
|
|
6943
|
-
}
|
|
7242
|
+
/**
|
|
7243
|
+
* Sets the default board for the workspace.
|
|
7244
|
+
*
|
|
7245
|
+
* @param boardId - The ID of the board to set as the default.
|
|
7246
|
+
* @throws {Error} If the board does not exist.
|
|
7247
|
+
*
|
|
7248
|
+
* @example
|
|
7249
|
+
* ```ts
|
|
7250
|
+
* sdk.setDefaultBoard('sprint-2')
|
|
7251
|
+
* ```
|
|
7252
|
+
*/
|
|
7253
|
+
setDefaultBoard(boardId) {
|
|
7254
|
+
setDefaultBoard(this, boardId);
|
|
6944
7255
|
}
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
7256
|
+
/**
|
|
7257
|
+
* Lists all registered webhooks.
|
|
7258
|
+
*
|
|
7259
|
+
* @returns Array of {@link Webhook} objects.
|
|
7260
|
+
*/
|
|
7261
|
+
listWebhooks() {
|
|
7262
|
+
return loadWebhooks(this.workspaceRoot);
|
|
7263
|
+
}
|
|
7264
|
+
/**
|
|
7265
|
+
* Creates and persists a new webhook.
|
|
7266
|
+
*
|
|
7267
|
+
* @param webhookConfig - The webhook configuration.
|
|
7268
|
+
* @returns The newly created {@link Webhook}.
|
|
7269
|
+
*/
|
|
7270
|
+
createWebhook(webhookConfig) {
|
|
7271
|
+
return createWebhook(this.workspaceRoot, webhookConfig);
|
|
7272
|
+
}
|
|
7273
|
+
/**
|
|
7274
|
+
* Deletes a webhook by its ID.
|
|
7275
|
+
*
|
|
7276
|
+
* @param id - The webhook ID to delete.
|
|
7277
|
+
* @returns `true` if deleted, `false` if not found.
|
|
7278
|
+
*/
|
|
7279
|
+
deleteWebhook(id) {
|
|
7280
|
+
return deleteWebhook(this.workspaceRoot, id);
|
|
7281
|
+
}
|
|
7282
|
+
/**
|
|
7283
|
+
* Updates an existing webhook's configuration.
|
|
7284
|
+
*
|
|
7285
|
+
* @param id - The webhook ID to update.
|
|
7286
|
+
* @param updates - Partial webhook fields to merge.
|
|
7287
|
+
* @returns The updated {@link Webhook}, or `null` if not found.
|
|
7288
|
+
*/
|
|
7289
|
+
updateWebhook(id, updates) {
|
|
7290
|
+
return updateWebhook(this.workspaceRoot, id, updates);
|
|
7291
|
+
}
|
|
7292
|
+
};
|
|
6963
7293
|
}
|
|
6964
7294
|
});
|
|
6965
7295
|
|
|
@@ -7368,8 +7698,8 @@ var init_parseUtil = __esm({
|
|
|
7368
7698
|
init_errors();
|
|
7369
7699
|
init_en();
|
|
7370
7700
|
makeIssue = (params) => {
|
|
7371
|
-
const { data, path:
|
|
7372
|
-
const fullPath = [...
|
|
7701
|
+
const { data, path: path17, errorMaps, issueData } = params;
|
|
7702
|
+
const fullPath = [...path17, ...issueData.path || []];
|
|
7373
7703
|
const fullIssue = {
|
|
7374
7704
|
...issueData,
|
|
7375
7705
|
path: fullPath
|
|
@@ -7649,11 +7979,11 @@ var init_types3 = __esm({
|
|
|
7649
7979
|
init_parseUtil();
|
|
7650
7980
|
init_util();
|
|
7651
7981
|
ParseInputLazyPath = class {
|
|
7652
|
-
constructor(parent, value,
|
|
7982
|
+
constructor(parent, value, path17, key) {
|
|
7653
7983
|
this._cachedPath = [];
|
|
7654
7984
|
this.parent = parent;
|
|
7655
7985
|
this.data = value;
|
|
7656
|
-
this._path =
|
|
7986
|
+
this._path = path17;
|
|
7657
7987
|
this._key = key;
|
|
7658
7988
|
}
|
|
7659
7989
|
get path() {
|
|
@@ -11159,10 +11489,10 @@ function mergeDefs(...defs) {
|
|
|
11159
11489
|
function cloneDef(schema2) {
|
|
11160
11490
|
return mergeDefs(schema2._zod.def);
|
|
11161
11491
|
}
|
|
11162
|
-
function getElementAtPath(obj,
|
|
11163
|
-
if (!
|
|
11492
|
+
function getElementAtPath(obj, path17) {
|
|
11493
|
+
if (!path17)
|
|
11164
11494
|
return obj;
|
|
11165
|
-
return
|
|
11495
|
+
return path17.reduce((acc, key) => acc?.[key], obj);
|
|
11166
11496
|
}
|
|
11167
11497
|
function promiseAllObject(promisesObj) {
|
|
11168
11498
|
const keys = Object.keys(promisesObj);
|
|
@@ -11474,11 +11804,11 @@ function aborted(x, startIndex = 0) {
|
|
|
11474
11804
|
}
|
|
11475
11805
|
return false;
|
|
11476
11806
|
}
|
|
11477
|
-
function prefixIssues(
|
|
11807
|
+
function prefixIssues(path17, issues) {
|
|
11478
11808
|
return issues.map((iss) => {
|
|
11479
11809
|
var _a3;
|
|
11480
11810
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
11481
|
-
iss.path.unshift(
|
|
11811
|
+
iss.path.unshift(path17);
|
|
11482
11812
|
return iss;
|
|
11483
11813
|
});
|
|
11484
11814
|
}
|
|
@@ -25968,8 +26298,8 @@ var require_utils = __commonJS({
|
|
|
25968
26298
|
}
|
|
25969
26299
|
return ind;
|
|
25970
26300
|
}
|
|
25971
|
-
function removeDotSegments(
|
|
25972
|
-
let input =
|
|
26301
|
+
function removeDotSegments(path17) {
|
|
26302
|
+
let input = path17;
|
|
25973
26303
|
const output = [];
|
|
25974
26304
|
let nextSlash = -1;
|
|
25975
26305
|
let len = 0;
|
|
@@ -26168,8 +26498,8 @@ var require_schemes = __commonJS({
|
|
|
26168
26498
|
wsComponent.secure = void 0;
|
|
26169
26499
|
}
|
|
26170
26500
|
if (wsComponent.resourceName) {
|
|
26171
|
-
const [
|
|
26172
|
-
wsComponent.path =
|
|
26501
|
+
const [path17, query] = wsComponent.resourceName.split("?");
|
|
26502
|
+
wsComponent.path = path17 && path17 !== "/" ? path17 : void 0;
|
|
26173
26503
|
wsComponent.query = query;
|
|
26174
26504
|
wsComponent.resourceName = void 0;
|
|
26175
26505
|
}
|
|
@@ -29532,12 +29862,12 @@ var require_dist = __commonJS({
|
|
|
29532
29862
|
throw new Error(`Unknown format "${name}"`);
|
|
29533
29863
|
return f;
|
|
29534
29864
|
};
|
|
29535
|
-
function addFormats(ajv, list,
|
|
29865
|
+
function addFormats(ajv, list, fs16, exportName) {
|
|
29536
29866
|
var _a3;
|
|
29537
29867
|
var _b;
|
|
29538
29868
|
(_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
29539
29869
|
for (const f of list)
|
|
29540
|
-
ajv.addFormat(f,
|
|
29870
|
+
ajv.addFormat(f, fs16[f]);
|
|
29541
29871
|
}
|
|
29542
29872
|
module2.exports = exports2 = formatsPlugin;
|
|
29543
29873
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -31394,10 +31724,10 @@ function mergeDefs2(...defs) {
|
|
|
31394
31724
|
function cloneDef2(schema2) {
|
|
31395
31725
|
return mergeDefs2(schema2._zod.def);
|
|
31396
31726
|
}
|
|
31397
|
-
function getElementAtPath2(obj,
|
|
31398
|
-
if (!
|
|
31727
|
+
function getElementAtPath2(obj, path17) {
|
|
31728
|
+
if (!path17)
|
|
31399
31729
|
return obj;
|
|
31400
|
-
return
|
|
31730
|
+
return path17.reduce((acc, key) => acc?.[key], obj);
|
|
31401
31731
|
}
|
|
31402
31732
|
function promiseAllObject2(promisesObj) {
|
|
31403
31733
|
const keys = Object.keys(promisesObj);
|
|
@@ -31709,11 +32039,11 @@ function aborted2(x, startIndex = 0) {
|
|
|
31709
32039
|
}
|
|
31710
32040
|
return false;
|
|
31711
32041
|
}
|
|
31712
|
-
function prefixIssues2(
|
|
32042
|
+
function prefixIssues2(path17, issues) {
|
|
31713
32043
|
return issues.map((iss) => {
|
|
31714
32044
|
var _a3;
|
|
31715
32045
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
31716
|
-
iss.path.unshift(
|
|
32046
|
+
iss.path.unshift(path17);
|
|
31717
32047
|
return iss;
|
|
31718
32048
|
});
|
|
31719
32049
|
}
|
|
@@ -31955,7 +32285,7 @@ function formatError3(error49, mapper = (issue3) => issue3.message) {
|
|
|
31955
32285
|
}
|
|
31956
32286
|
function treeifyError2(error49, mapper = (issue3) => issue3.message) {
|
|
31957
32287
|
const result = { errors: [] };
|
|
31958
|
-
const processError = (error50,
|
|
32288
|
+
const processError = (error50, path17 = []) => {
|
|
31959
32289
|
var _a3, _b;
|
|
31960
32290
|
for (const issue3 of error50.issues) {
|
|
31961
32291
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
@@ -31965,7 +32295,7 @@ function treeifyError2(error49, mapper = (issue3) => issue3.message) {
|
|
|
31965
32295
|
} else if (issue3.code === "invalid_element") {
|
|
31966
32296
|
processError({ issues: issue3.issues }, issue3.path);
|
|
31967
32297
|
} else {
|
|
31968
|
-
const fullpath = [...
|
|
32298
|
+
const fullpath = [...path17, ...issue3.path];
|
|
31969
32299
|
if (fullpath.length === 0) {
|
|
31970
32300
|
result.errors.push(mapper(issue3));
|
|
31971
32301
|
continue;
|
|
@@ -31997,8 +32327,8 @@ function treeifyError2(error49, mapper = (issue3) => issue3.message) {
|
|
|
31997
32327
|
}
|
|
31998
32328
|
function toDotPath(_path) {
|
|
31999
32329
|
const segs = [];
|
|
32000
|
-
const
|
|
32001
|
-
for (const seg of
|
|
32330
|
+
const path17 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
32331
|
+
for (const seg of path17) {
|
|
32002
32332
|
if (typeof seg === "number")
|
|
32003
32333
|
segs.push(`[${seg}]`);
|
|
32004
32334
|
else if (typeof seg === "symbol")
|
|
@@ -44691,13 +45021,13 @@ function resolveRef(ref, ctx) {
|
|
|
44691
45021
|
if (!ref.startsWith("#")) {
|
|
44692
45022
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
44693
45023
|
}
|
|
44694
|
-
const
|
|
44695
|
-
if (
|
|
45024
|
+
const path17 = ref.slice(1).split("/").filter(Boolean);
|
|
45025
|
+
if (path17.length === 0) {
|
|
44696
45026
|
return ctx.rootSchema;
|
|
44697
45027
|
}
|
|
44698
45028
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
44699
|
-
if (
|
|
44700
|
-
const key =
|
|
45029
|
+
if (path17[0] === defsKey) {
|
|
45030
|
+
const key = path17[1];
|
|
44701
45031
|
if (!key || !ctx.defs[key]) {
|
|
44702
45032
|
throw new Error(`Reference not found: ${ref}`);
|
|
44703
45033
|
}
|
|
@@ -45462,16 +45792,16 @@ async function findWorkspaceRoot(startDir) {
|
|
|
45462
45792
|
let dir = startDir;
|
|
45463
45793
|
while (true) {
|
|
45464
45794
|
try {
|
|
45465
|
-
await
|
|
45795
|
+
await fs8.access(path13.join(dir, ".git"));
|
|
45466
45796
|
return dir;
|
|
45467
45797
|
} catch {
|
|
45468
45798
|
}
|
|
45469
45799
|
try {
|
|
45470
|
-
await
|
|
45800
|
+
await fs8.access(path13.join(dir, "package.json"));
|
|
45471
45801
|
return dir;
|
|
45472
45802
|
} catch {
|
|
45473
45803
|
}
|
|
45474
|
-
const parent =
|
|
45804
|
+
const parent = path13.dirname(dir);
|
|
45475
45805
|
if (parent === dir)
|
|
45476
45806
|
return startDir;
|
|
45477
45807
|
dir = parent;
|
|
@@ -45480,25 +45810,18 @@ async function findWorkspaceRoot(startDir) {
|
|
|
45480
45810
|
async function resolveKanbanDir() {
|
|
45481
45811
|
const dirIndex = process.argv.indexOf("--dir");
|
|
45482
45812
|
if (dirIndex !== -1 && process.argv[dirIndex + 1]) {
|
|
45483
|
-
return
|
|
45813
|
+
return path13.resolve(process.argv[dirIndex + 1]);
|
|
45484
45814
|
}
|
|
45485
45815
|
const envDir = process.env.KANBAN_DIR || process.env.KANBAN_FEATURES_DIR;
|
|
45486
45816
|
if (envDir) {
|
|
45487
|
-
return
|
|
45817
|
+
return path13.resolve(envDir);
|
|
45488
45818
|
}
|
|
45489
45819
|
const root = await findWorkspaceRoot(process.cwd());
|
|
45490
|
-
return
|
|
45491
|
-
}
|
|
45492
|
-
function getTitleFromContent2(content) {
|
|
45493
|
-
const match = content.match(/^#\s+(.+)$/m);
|
|
45494
|
-
if (match)
|
|
45495
|
-
return match[1].trim();
|
|
45496
|
-
const firstLine = content.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
|
|
45497
|
-
return firstLine || "Untitled";
|
|
45820
|
+
return path13.join(root, ".kanban");
|
|
45498
45821
|
}
|
|
45499
45822
|
async function main() {
|
|
45500
45823
|
const kanbanDir = await resolveKanbanDir();
|
|
45501
|
-
const workspaceRoot =
|
|
45824
|
+
const workspaceRoot = path13.dirname(kanbanDir);
|
|
45502
45825
|
const sdk = new KanbanSDK(kanbanDir, {
|
|
45503
45826
|
onEvent: (event, data) => fireWebhooks(workspaceRoot, event, data)
|
|
45504
45827
|
});
|
|
@@ -45571,7 +45894,12 @@ async function main() {
|
|
|
45571
45894
|
sort: external_exports4.enum(["created:asc", "created:desc", "modified:asc", "modified:desc"]).optional().describe("Sort order: created:asc, created:desc, modified:asc, or modified:desc. Defaults to board order.")
|
|
45572
45895
|
},
|
|
45573
45896
|
async ({ boardId, status, priority, assignee, label, labelGroup, includeDeleted, metaFilter, sort }) => {
|
|
45574
|
-
let cards = await sdk.listCards(
|
|
45897
|
+
let cards = await sdk.listCards(
|
|
45898
|
+
void 0,
|
|
45899
|
+
boardId,
|
|
45900
|
+
metaFilter && Object.keys(metaFilter).length > 0 ? metaFilter : void 0,
|
|
45901
|
+
sort || void 0
|
|
45902
|
+
);
|
|
45575
45903
|
if (!includeDeleted)
|
|
45576
45904
|
cards = cards.filter((c) => c.status !== DELETED_STATUS_ID);
|
|
45577
45905
|
if (status)
|
|
@@ -45586,19 +45914,9 @@ async function main() {
|
|
|
45586
45914
|
const groupLabels = sdk.getLabelsInGroup(labelGroup);
|
|
45587
45915
|
cards = cards.filter((c) => c.labels.some((l) => groupLabels.includes(l)));
|
|
45588
45916
|
}
|
|
45589
|
-
if (metaFilter && Object.keys(metaFilter).length > 0)
|
|
45590
|
-
cards = cards.filter((c) => matchesMetaFilter(c.metadata, metaFilter));
|
|
45591
|
-
if (sort) {
|
|
45592
|
-
const [field, dir] = sort.split(":");
|
|
45593
|
-
cards = [...cards].sort((a, b) => {
|
|
45594
|
-
const aVal = field === "created" ? a.created : a.modified;
|
|
45595
|
-
const bVal = field === "created" ? b.created : b.modified;
|
|
45596
|
-
return dir === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
|
|
45597
|
-
});
|
|
45598
|
-
}
|
|
45599
45917
|
const summary = cards.map((c) => ({
|
|
45600
45918
|
id: c.id,
|
|
45601
|
-
title:
|
|
45919
|
+
title: getTitleFromContent(c.content),
|
|
45602
45920
|
status: c.status,
|
|
45603
45921
|
priority: c.priority,
|
|
45604
45922
|
assignee: c.assignee,
|
|
@@ -46506,8 +46824,7 @@ async function main() {
|
|
|
46506
46824
|
"Get the current kanban board display settings.",
|
|
46507
46825
|
{},
|
|
46508
46826
|
async () => {
|
|
46509
|
-
const
|
|
46510
|
-
const settings = configToSettings(config3);
|
|
46827
|
+
const settings = sdk.getSettings();
|
|
46511
46828
|
return {
|
|
46512
46829
|
content: [{
|
|
46513
46830
|
type: "text",
|
|
@@ -46531,20 +46848,18 @@ async function main() {
|
|
|
46531
46848
|
defaultStatus: external_exports4.string().optional().describe("Default status for new cards")
|
|
46532
46849
|
},
|
|
46533
46850
|
async (updates) => {
|
|
46534
|
-
const
|
|
46535
|
-
const settings = configToSettings(config3);
|
|
46851
|
+
const settings = sdk.getSettings();
|
|
46536
46852
|
const merged = { ...settings };
|
|
46537
46853
|
for (const [key, value] of Object.entries(updates)) {
|
|
46538
46854
|
if (value !== void 0) {
|
|
46539
46855
|
merged[key] = value;
|
|
46540
46856
|
}
|
|
46541
46857
|
}
|
|
46542
|
-
|
|
46543
|
-
const updated = configToSettings(readConfig(workspaceRoot));
|
|
46858
|
+
sdk.updateSettings(merged);
|
|
46544
46859
|
return {
|
|
46545
46860
|
content: [{
|
|
46546
46861
|
type: "text",
|
|
46547
|
-
text: JSON.stringify(
|
|
46862
|
+
text: JSON.stringify(sdk.getSettings(), null, 2)
|
|
46548
46863
|
}]
|
|
46549
46864
|
};
|
|
46550
46865
|
}
|
|
@@ -46554,7 +46869,7 @@ async function main() {
|
|
|
46554
46869
|
"List all registered webhooks.",
|
|
46555
46870
|
{},
|
|
46556
46871
|
async () => {
|
|
46557
|
-
const webhooks =
|
|
46872
|
+
const webhooks = sdk.listWebhooks();
|
|
46558
46873
|
return {
|
|
46559
46874
|
content: [{
|
|
46560
46875
|
type: "text",
|
|
@@ -46572,7 +46887,7 @@ async function main() {
|
|
|
46572
46887
|
secret: external_exports4.string().optional().describe("Optional HMAC-SHA256 signing secret")
|
|
46573
46888
|
},
|
|
46574
46889
|
async ({ url: url3, events, secret }) => {
|
|
46575
|
-
const webhook = createWebhook(
|
|
46890
|
+
const webhook = sdk.createWebhook({
|
|
46576
46891
|
url: url3,
|
|
46577
46892
|
events: events || ["*"],
|
|
46578
46893
|
secret
|
|
@@ -46592,7 +46907,7 @@ async function main() {
|
|
|
46592
46907
|
webhookId: external_exports4.string().describe('Webhook ID (e.g. "wh_abc123")')
|
|
46593
46908
|
},
|
|
46594
46909
|
async ({ webhookId }) => {
|
|
46595
|
-
const removed = deleteWebhook(
|
|
46910
|
+
const removed = sdk.deleteWebhook(webhookId);
|
|
46596
46911
|
if (!removed) {
|
|
46597
46912
|
return {
|
|
46598
46913
|
content: [{ type: "text", text: `Webhook not found: ${webhookId}` }],
|
|
@@ -46627,7 +46942,7 @@ async function main() {
|
|
|
46627
46942
|
updates.secret = secret;
|
|
46628
46943
|
if (active !== void 0)
|
|
46629
46944
|
updates.active = active;
|
|
46630
|
-
const updated = updateWebhook(
|
|
46945
|
+
const updated = sdk.updateWebhook(webhookId, updates);
|
|
46631
46946
|
if (!updated) {
|
|
46632
46947
|
return {
|
|
46633
46948
|
content: [{ type: "text", text: `Webhook not found: ${webhookId}` }],
|
|
@@ -46726,12 +47041,12 @@ async function main() {
|
|
|
46726
47041
|
const transport = new StdioServerTransport();
|
|
46727
47042
|
await server.connect(transport);
|
|
46728
47043
|
}
|
|
46729
|
-
var
|
|
47044
|
+
var path13, fs8;
|
|
46730
47045
|
var init_mcp_server2 = __esm({
|
|
46731
47046
|
"src/mcp-server/index.ts"() {
|
|
46732
47047
|
"use strict";
|
|
46733
|
-
|
|
46734
|
-
|
|
47048
|
+
path13 = __toESM(require("path"));
|
|
47049
|
+
fs8 = __toESM(require("fs/promises"));
|
|
46735
47050
|
init_mcp();
|
|
46736
47051
|
init_stdio2();
|
|
46737
47052
|
init_zod2();
|
|
@@ -46739,7 +47054,6 @@ var init_mcp_server2 = __esm({
|
|
|
46739
47054
|
init_types();
|
|
46740
47055
|
init_config();
|
|
46741
47056
|
init_webhooks();
|
|
46742
|
-
init_metaUtils();
|
|
46743
47057
|
main().catch((err) => {
|
|
46744
47058
|
console.error(`MCP Server error: ${err.message}`);
|
|
46745
47059
|
process.exit(1);
|
|
@@ -50557,7 +50871,7 @@ var init_esm2 = __esm({
|
|
|
50557
50871
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
50558
50872
|
const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
|
|
50559
50873
|
if (wantBigintFsStats) {
|
|
50560
|
-
this._stat = (
|
|
50874
|
+
this._stat = (path17) => statMethod(path17, { bigint: true });
|
|
50561
50875
|
} else {
|
|
50562
50876
|
this._stat = statMethod;
|
|
50563
50877
|
}
|
|
@@ -50582,8 +50896,8 @@ var init_esm2 = __esm({
|
|
|
50582
50896
|
const par = this.parent;
|
|
50583
50897
|
const fil = par && par.files;
|
|
50584
50898
|
if (fil && fil.length > 0) {
|
|
50585
|
-
const { path:
|
|
50586
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
50899
|
+
const { path: path17, depth } = par;
|
|
50900
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path17));
|
|
50587
50901
|
const awaited = await Promise.all(slice);
|
|
50588
50902
|
for (const entry of awaited) {
|
|
50589
50903
|
if (!entry)
|
|
@@ -50623,21 +50937,21 @@ var init_esm2 = __esm({
|
|
|
50623
50937
|
this.reading = false;
|
|
50624
50938
|
}
|
|
50625
50939
|
}
|
|
50626
|
-
async _exploreDir(
|
|
50940
|
+
async _exploreDir(path17, depth) {
|
|
50627
50941
|
let files;
|
|
50628
50942
|
try {
|
|
50629
|
-
files = await (0, import_promises.readdir)(
|
|
50943
|
+
files = await (0, import_promises.readdir)(path17, this._rdOptions);
|
|
50630
50944
|
} catch (error49) {
|
|
50631
50945
|
this._onError(error49);
|
|
50632
50946
|
}
|
|
50633
|
-
return { files, depth, path:
|
|
50947
|
+
return { files, depth, path: path17 };
|
|
50634
50948
|
}
|
|
50635
|
-
async _formatEntry(dirent,
|
|
50949
|
+
async _formatEntry(dirent, path17) {
|
|
50636
50950
|
let entry;
|
|
50637
|
-
const
|
|
50951
|
+
const basename10 = this._isDirent ? dirent.name : dirent;
|
|
50638
50952
|
try {
|
|
50639
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(
|
|
50640
|
-
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename:
|
|
50953
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path17, basename10));
|
|
50954
|
+
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename10 };
|
|
50641
50955
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
50642
50956
|
} catch (err) {
|
|
50643
50957
|
this._onError(err);
|
|
@@ -50693,16 +51007,16 @@ var init_esm2 = __esm({
|
|
|
50693
51007
|
});
|
|
50694
51008
|
|
|
50695
51009
|
// node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/handler.js
|
|
50696
|
-
function createFsWatchInstance(
|
|
51010
|
+
function createFsWatchInstance(path17, options, listener, errHandler, emitRaw) {
|
|
50697
51011
|
const handleEvent = (rawEvent, evPath) => {
|
|
50698
|
-
listener(
|
|
50699
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
50700
|
-
if (evPath &&
|
|
50701
|
-
fsWatchBroadcast(sysPath.resolve(
|
|
51012
|
+
listener(path17);
|
|
51013
|
+
emitRaw(rawEvent, evPath, { watchedPath: path17 });
|
|
51014
|
+
if (evPath && path17 !== evPath) {
|
|
51015
|
+
fsWatchBroadcast(sysPath.resolve(path17, evPath), KEY_LISTENERS, sysPath.join(path17, evPath));
|
|
50702
51016
|
}
|
|
50703
51017
|
};
|
|
50704
51018
|
try {
|
|
50705
|
-
return (0, import_fs.watch)(
|
|
51019
|
+
return (0, import_fs.watch)(path17, {
|
|
50706
51020
|
persistent: options.persistent
|
|
50707
51021
|
}, handleEvent);
|
|
50708
51022
|
} catch (error49) {
|
|
@@ -51050,12 +51364,12 @@ var init_handler = __esm({
|
|
|
51050
51364
|
listener(val1, val2, val3);
|
|
51051
51365
|
});
|
|
51052
51366
|
};
|
|
51053
|
-
setFsWatchListener = (
|
|
51367
|
+
setFsWatchListener = (path17, fullPath, options, handlers) => {
|
|
51054
51368
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
51055
51369
|
let cont = FsWatchInstances.get(fullPath);
|
|
51056
51370
|
let watcher;
|
|
51057
51371
|
if (!options.persistent) {
|
|
51058
|
-
watcher = createFsWatchInstance(
|
|
51372
|
+
watcher = createFsWatchInstance(path17, options, listener, errHandler, rawEmitter);
|
|
51059
51373
|
if (!watcher)
|
|
51060
51374
|
return;
|
|
51061
51375
|
return watcher.close.bind(watcher);
|
|
@@ -51066,7 +51380,7 @@ var init_handler = __esm({
|
|
|
51066
51380
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
51067
51381
|
} else {
|
|
51068
51382
|
watcher = createFsWatchInstance(
|
|
51069
|
-
|
|
51383
|
+
path17,
|
|
51070
51384
|
options,
|
|
51071
51385
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
51072
51386
|
errHandler,
|
|
@@ -51081,7 +51395,7 @@ var init_handler = __esm({
|
|
|
51081
51395
|
cont.watcherUnusable = true;
|
|
51082
51396
|
if (isWindows && error49.code === "EPERM") {
|
|
51083
51397
|
try {
|
|
51084
|
-
const fd = await (0, import_promises2.open)(
|
|
51398
|
+
const fd = await (0, import_promises2.open)(path17, "r");
|
|
51085
51399
|
await fd.close();
|
|
51086
51400
|
broadcastErr(error49);
|
|
51087
51401
|
} catch (err) {
|
|
@@ -51112,7 +51426,7 @@ var init_handler = __esm({
|
|
|
51112
51426
|
};
|
|
51113
51427
|
};
|
|
51114
51428
|
FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
51115
|
-
setFsWatchFileListener = (
|
|
51429
|
+
setFsWatchFileListener = (path17, fullPath, options, handlers) => {
|
|
51116
51430
|
const { listener, rawEmitter } = handlers;
|
|
51117
51431
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
51118
51432
|
const copts = cont && cont.options;
|
|
@@ -51134,7 +51448,7 @@ var init_handler = __esm({
|
|
|
51134
51448
|
});
|
|
51135
51449
|
const currmtime = curr.mtimeMs;
|
|
51136
51450
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
51137
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
51451
|
+
foreach(cont.listeners, (listener2) => listener2(path17, curr));
|
|
51138
51452
|
}
|
|
51139
51453
|
})
|
|
51140
51454
|
};
|
|
@@ -51162,13 +51476,13 @@ var init_handler = __esm({
|
|
|
51162
51476
|
* @param listener on fs change
|
|
51163
51477
|
* @returns closer for the watcher instance
|
|
51164
51478
|
*/
|
|
51165
|
-
_watchWithNodeFs(
|
|
51479
|
+
_watchWithNodeFs(path17, listener) {
|
|
51166
51480
|
const opts = this.fsw.options;
|
|
51167
|
-
const directory = sysPath.dirname(
|
|
51168
|
-
const
|
|
51481
|
+
const directory = sysPath.dirname(path17);
|
|
51482
|
+
const basename10 = sysPath.basename(path17);
|
|
51169
51483
|
const parent = this.fsw._getWatchedDir(directory);
|
|
51170
|
-
parent.add(
|
|
51171
|
-
const absolutePath = sysPath.resolve(
|
|
51484
|
+
parent.add(basename10);
|
|
51485
|
+
const absolutePath = sysPath.resolve(path17);
|
|
51172
51486
|
const options = {
|
|
51173
51487
|
persistent: opts.persistent
|
|
51174
51488
|
};
|
|
@@ -51177,13 +51491,13 @@ var init_handler = __esm({
|
|
|
51177
51491
|
let closer;
|
|
51178
51492
|
if (opts.usePolling) {
|
|
51179
51493
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
51180
|
-
options.interval = enableBin && isBinaryPath(
|
|
51181
|
-
closer = setFsWatchFileListener(
|
|
51494
|
+
options.interval = enableBin && isBinaryPath(basename10) ? opts.binaryInterval : opts.interval;
|
|
51495
|
+
closer = setFsWatchFileListener(path17, absolutePath, options, {
|
|
51182
51496
|
listener,
|
|
51183
51497
|
rawEmitter: this.fsw._emitRaw
|
|
51184
51498
|
});
|
|
51185
51499
|
} else {
|
|
51186
|
-
closer = setFsWatchListener(
|
|
51500
|
+
closer = setFsWatchListener(path17, absolutePath, options, {
|
|
51187
51501
|
listener,
|
|
51188
51502
|
errHandler: this._boundHandleError,
|
|
51189
51503
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -51199,13 +51513,13 @@ var init_handler = __esm({
|
|
|
51199
51513
|
if (this.fsw.closed) {
|
|
51200
51514
|
return;
|
|
51201
51515
|
}
|
|
51202
|
-
const
|
|
51203
|
-
const
|
|
51204
|
-
const parent = this.fsw._getWatchedDir(
|
|
51516
|
+
const dirname12 = sysPath.dirname(file3);
|
|
51517
|
+
const basename10 = sysPath.basename(file3);
|
|
51518
|
+
const parent = this.fsw._getWatchedDir(dirname12);
|
|
51205
51519
|
let prevStats = stats;
|
|
51206
|
-
if (parent.has(
|
|
51520
|
+
if (parent.has(basename10))
|
|
51207
51521
|
return;
|
|
51208
|
-
const listener = async (
|
|
51522
|
+
const listener = async (path17, newStats) => {
|
|
51209
51523
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file3, 5))
|
|
51210
51524
|
return;
|
|
51211
51525
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -51219,18 +51533,18 @@ var init_handler = __esm({
|
|
|
51219
51533
|
this.fsw._emit(EV.CHANGE, file3, newStats2);
|
|
51220
51534
|
}
|
|
51221
51535
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
51222
|
-
this.fsw._closeFile(
|
|
51536
|
+
this.fsw._closeFile(path17);
|
|
51223
51537
|
prevStats = newStats2;
|
|
51224
51538
|
const closer2 = this._watchWithNodeFs(file3, listener);
|
|
51225
51539
|
if (closer2)
|
|
51226
|
-
this.fsw._addPathCloser(
|
|
51540
|
+
this.fsw._addPathCloser(path17, closer2);
|
|
51227
51541
|
} else {
|
|
51228
51542
|
prevStats = newStats2;
|
|
51229
51543
|
}
|
|
51230
51544
|
} catch (error49) {
|
|
51231
|
-
this.fsw._remove(
|
|
51545
|
+
this.fsw._remove(dirname12, basename10);
|
|
51232
51546
|
}
|
|
51233
|
-
} else if (parent.has(
|
|
51547
|
+
} else if (parent.has(basename10)) {
|
|
51234
51548
|
const at = newStats.atimeMs;
|
|
51235
51549
|
const mt = newStats.mtimeMs;
|
|
51236
51550
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -51255,7 +51569,7 @@ var init_handler = __esm({
|
|
|
51255
51569
|
* @param item basename of this item
|
|
51256
51570
|
* @returns true if no more processing is needed for this entry.
|
|
51257
51571
|
*/
|
|
51258
|
-
async _handleSymlink(entry, directory,
|
|
51572
|
+
async _handleSymlink(entry, directory, path17, item) {
|
|
51259
51573
|
if (this.fsw.closed) {
|
|
51260
51574
|
return;
|
|
51261
51575
|
}
|
|
@@ -51265,7 +51579,7 @@ var init_handler = __esm({
|
|
|
51265
51579
|
this.fsw._incrReadyCount();
|
|
51266
51580
|
let linkPath;
|
|
51267
51581
|
try {
|
|
51268
|
-
linkPath = await (0, import_promises2.realpath)(
|
|
51582
|
+
linkPath = await (0, import_promises2.realpath)(path17);
|
|
51269
51583
|
} catch (e) {
|
|
51270
51584
|
this.fsw._emitReady();
|
|
51271
51585
|
return true;
|
|
@@ -51275,12 +51589,12 @@ var init_handler = __esm({
|
|
|
51275
51589
|
if (dir.has(item)) {
|
|
51276
51590
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
51277
51591
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
51278
|
-
this.fsw._emit(EV.CHANGE,
|
|
51592
|
+
this.fsw._emit(EV.CHANGE, path17, entry.stats);
|
|
51279
51593
|
}
|
|
51280
51594
|
} else {
|
|
51281
51595
|
dir.add(item);
|
|
51282
51596
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
51283
|
-
this.fsw._emit(EV.ADD,
|
|
51597
|
+
this.fsw._emit(EV.ADD, path17, entry.stats);
|
|
51284
51598
|
}
|
|
51285
51599
|
this.fsw._emitReady();
|
|
51286
51600
|
return true;
|
|
@@ -51309,9 +51623,9 @@ var init_handler = __esm({
|
|
|
51309
51623
|
return;
|
|
51310
51624
|
}
|
|
51311
51625
|
const item = entry.path;
|
|
51312
|
-
let
|
|
51626
|
+
let path17 = sysPath.join(directory, item);
|
|
51313
51627
|
current.add(item);
|
|
51314
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
51628
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path17, item)) {
|
|
51315
51629
|
return;
|
|
51316
51630
|
}
|
|
51317
51631
|
if (this.fsw.closed) {
|
|
@@ -51320,8 +51634,8 @@ var init_handler = __esm({
|
|
|
51320
51634
|
}
|
|
51321
51635
|
if (item === target || !target && !previous.has(item)) {
|
|
51322
51636
|
this.fsw._incrReadyCount();
|
|
51323
|
-
|
|
51324
|
-
this._addToNodeFs(
|
|
51637
|
+
path17 = sysPath.join(dir, sysPath.relative(dir, path17));
|
|
51638
|
+
this._addToNodeFs(path17, initialAdd, wh, depth + 1);
|
|
51325
51639
|
}
|
|
51326
51640
|
}).on(EV.ERROR, this._boundHandleError);
|
|
51327
51641
|
return new Promise((resolve9, reject) => {
|
|
@@ -51390,13 +51704,13 @@ var init_handler = __esm({
|
|
|
51390
51704
|
* @param depth Child path actually targeted for watch
|
|
51391
51705
|
* @param target Child path actually targeted for watch
|
|
51392
51706
|
*/
|
|
51393
|
-
async _addToNodeFs(
|
|
51707
|
+
async _addToNodeFs(path17, initialAdd, priorWh, depth, target) {
|
|
51394
51708
|
const ready = this.fsw._emitReady;
|
|
51395
|
-
if (this.fsw._isIgnored(
|
|
51709
|
+
if (this.fsw._isIgnored(path17) || this.fsw.closed) {
|
|
51396
51710
|
ready();
|
|
51397
51711
|
return false;
|
|
51398
51712
|
}
|
|
51399
|
-
const wh = this.fsw._getWatchHelpers(
|
|
51713
|
+
const wh = this.fsw._getWatchHelpers(path17);
|
|
51400
51714
|
if (priorWh) {
|
|
51401
51715
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
51402
51716
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -51412,8 +51726,8 @@ var init_handler = __esm({
|
|
|
51412
51726
|
const follow = this.fsw.options.followSymlinks;
|
|
51413
51727
|
let closer;
|
|
51414
51728
|
if (stats.isDirectory()) {
|
|
51415
|
-
const absPath = sysPath.resolve(
|
|
51416
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
51729
|
+
const absPath = sysPath.resolve(path17);
|
|
51730
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path17) : path17;
|
|
51417
51731
|
if (this.fsw.closed)
|
|
51418
51732
|
return;
|
|
51419
51733
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -51423,29 +51737,29 @@ var init_handler = __esm({
|
|
|
51423
51737
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
51424
51738
|
}
|
|
51425
51739
|
} else if (stats.isSymbolicLink()) {
|
|
51426
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
51740
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path17) : path17;
|
|
51427
51741
|
if (this.fsw.closed)
|
|
51428
51742
|
return;
|
|
51429
51743
|
const parent = sysPath.dirname(wh.watchPath);
|
|
51430
51744
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
51431
51745
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
51432
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
51746
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path17, wh, targetPath);
|
|
51433
51747
|
if (this.fsw.closed)
|
|
51434
51748
|
return;
|
|
51435
51749
|
if (targetPath !== void 0) {
|
|
51436
|
-
this.fsw._symlinkPaths.set(sysPath.resolve(
|
|
51750
|
+
this.fsw._symlinkPaths.set(sysPath.resolve(path17), targetPath);
|
|
51437
51751
|
}
|
|
51438
51752
|
} else {
|
|
51439
51753
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
51440
51754
|
}
|
|
51441
51755
|
ready();
|
|
51442
51756
|
if (closer)
|
|
51443
|
-
this.fsw._addPathCloser(
|
|
51757
|
+
this.fsw._addPathCloser(path17, closer);
|
|
51444
51758
|
return false;
|
|
51445
51759
|
} catch (error49) {
|
|
51446
51760
|
if (this.fsw._handleError(error49)) {
|
|
51447
51761
|
ready();
|
|
51448
|
-
return
|
|
51762
|
+
return path17;
|
|
51449
51763
|
}
|
|
51450
51764
|
}
|
|
51451
51765
|
}
|
|
@@ -51480,26 +51794,26 @@ function createPattern(matcher) {
|
|
|
51480
51794
|
}
|
|
51481
51795
|
return () => false;
|
|
51482
51796
|
}
|
|
51483
|
-
function normalizePath(
|
|
51484
|
-
if (typeof
|
|
51797
|
+
function normalizePath(path17) {
|
|
51798
|
+
if (typeof path17 !== "string")
|
|
51485
51799
|
throw new Error("string expected");
|
|
51486
|
-
|
|
51487
|
-
|
|
51800
|
+
path17 = sysPath2.normalize(path17);
|
|
51801
|
+
path17 = path17.replace(/\\/g, "/");
|
|
51488
51802
|
let prepend = false;
|
|
51489
|
-
if (
|
|
51803
|
+
if (path17.startsWith("//"))
|
|
51490
51804
|
prepend = true;
|
|
51491
51805
|
const DOUBLE_SLASH_RE2 = /\/\//;
|
|
51492
|
-
while (
|
|
51493
|
-
|
|
51806
|
+
while (path17.match(DOUBLE_SLASH_RE2))
|
|
51807
|
+
path17 = path17.replace(DOUBLE_SLASH_RE2, "/");
|
|
51494
51808
|
if (prepend)
|
|
51495
|
-
|
|
51496
|
-
return
|
|
51809
|
+
path17 = "/" + path17;
|
|
51810
|
+
return path17;
|
|
51497
51811
|
}
|
|
51498
51812
|
function matchPatterns(patterns, testString, stats) {
|
|
51499
|
-
const
|
|
51813
|
+
const path17 = normalizePath(testString);
|
|
51500
51814
|
for (let index = 0; index < patterns.length; index++) {
|
|
51501
51815
|
const pattern = patterns[index];
|
|
51502
|
-
if (pattern(
|
|
51816
|
+
if (pattern(path17, stats)) {
|
|
51503
51817
|
return true;
|
|
51504
51818
|
}
|
|
51505
51819
|
}
|
|
@@ -51563,19 +51877,19 @@ var init_esm3 = __esm({
|
|
|
51563
51877
|
}
|
|
51564
51878
|
return str2;
|
|
51565
51879
|
};
|
|
51566
|
-
normalizePathToUnix = (
|
|
51567
|
-
normalizeIgnored = (cwd = "") => (
|
|
51568
|
-
if (typeof
|
|
51569
|
-
return normalizePathToUnix(sysPath2.isAbsolute(
|
|
51880
|
+
normalizePathToUnix = (path17) => toUnix(sysPath2.normalize(toUnix(path17)));
|
|
51881
|
+
normalizeIgnored = (cwd = "") => (path17) => {
|
|
51882
|
+
if (typeof path17 === "string") {
|
|
51883
|
+
return normalizePathToUnix(sysPath2.isAbsolute(path17) ? path17 : sysPath2.join(cwd, path17));
|
|
51570
51884
|
} else {
|
|
51571
|
-
return
|
|
51885
|
+
return path17;
|
|
51572
51886
|
}
|
|
51573
51887
|
};
|
|
51574
|
-
getAbsolutePath = (
|
|
51575
|
-
if (sysPath2.isAbsolute(
|
|
51576
|
-
return
|
|
51888
|
+
getAbsolutePath = (path17, cwd) => {
|
|
51889
|
+
if (sysPath2.isAbsolute(path17)) {
|
|
51890
|
+
return path17;
|
|
51577
51891
|
}
|
|
51578
|
-
return sysPath2.join(cwd,
|
|
51892
|
+
return sysPath2.join(cwd, path17);
|
|
51579
51893
|
};
|
|
51580
51894
|
EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
51581
51895
|
DirEntry = class {
|
|
@@ -51630,10 +51944,10 @@ var init_esm3 = __esm({
|
|
|
51630
51944
|
STAT_METHOD_F = "stat";
|
|
51631
51945
|
STAT_METHOD_L = "lstat";
|
|
51632
51946
|
WatchHelper = class {
|
|
51633
|
-
constructor(
|
|
51947
|
+
constructor(path17, follow, fsw) {
|
|
51634
51948
|
this.fsw = fsw;
|
|
51635
|
-
const watchPath =
|
|
51636
|
-
this.path =
|
|
51949
|
+
const watchPath = path17;
|
|
51950
|
+
this.path = path17 = path17.replace(REPLACER_RE, "");
|
|
51637
51951
|
this.watchPath = watchPath;
|
|
51638
51952
|
this.fullWatchPath = sysPath2.resolve(watchPath);
|
|
51639
51953
|
this.dirParts = [];
|
|
@@ -51755,20 +52069,20 @@ var init_esm3 = __esm({
|
|
|
51755
52069
|
this._closePromise = void 0;
|
|
51756
52070
|
let paths = unifyPaths(paths_);
|
|
51757
52071
|
if (cwd) {
|
|
51758
|
-
paths = paths.map((
|
|
51759
|
-
const absPath = getAbsolutePath(
|
|
52072
|
+
paths = paths.map((path17) => {
|
|
52073
|
+
const absPath = getAbsolutePath(path17, cwd);
|
|
51760
52074
|
return absPath;
|
|
51761
52075
|
});
|
|
51762
52076
|
}
|
|
51763
|
-
paths.forEach((
|
|
51764
|
-
this._removeIgnoredPath(
|
|
52077
|
+
paths.forEach((path17) => {
|
|
52078
|
+
this._removeIgnoredPath(path17);
|
|
51765
52079
|
});
|
|
51766
52080
|
this._userIgnored = void 0;
|
|
51767
52081
|
if (!this._readyCount)
|
|
51768
52082
|
this._readyCount = 0;
|
|
51769
52083
|
this._readyCount += paths.length;
|
|
51770
|
-
Promise.all(paths.map(async (
|
|
51771
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
52084
|
+
Promise.all(paths.map(async (path17) => {
|
|
52085
|
+
const res = await this._nodeFsHandler._addToNodeFs(path17, !_internal, void 0, 0, _origAdd);
|
|
51772
52086
|
if (res)
|
|
51773
52087
|
this._emitReady();
|
|
51774
52088
|
return res;
|
|
@@ -51790,17 +52104,17 @@ var init_esm3 = __esm({
|
|
|
51790
52104
|
return this;
|
|
51791
52105
|
const paths = unifyPaths(paths_);
|
|
51792
52106
|
const { cwd } = this.options;
|
|
51793
|
-
paths.forEach((
|
|
51794
|
-
if (!sysPath2.isAbsolute(
|
|
52107
|
+
paths.forEach((path17) => {
|
|
52108
|
+
if (!sysPath2.isAbsolute(path17) && !this._closers.has(path17)) {
|
|
51795
52109
|
if (cwd)
|
|
51796
|
-
|
|
51797
|
-
|
|
52110
|
+
path17 = sysPath2.join(cwd, path17);
|
|
52111
|
+
path17 = sysPath2.resolve(path17);
|
|
51798
52112
|
}
|
|
51799
|
-
this._closePath(
|
|
51800
|
-
this._addIgnoredPath(
|
|
51801
|
-
if (this._watched.has(
|
|
52113
|
+
this._closePath(path17);
|
|
52114
|
+
this._addIgnoredPath(path17);
|
|
52115
|
+
if (this._watched.has(path17)) {
|
|
51802
52116
|
this._addIgnoredPath({
|
|
51803
|
-
path:
|
|
52117
|
+
path: path17,
|
|
51804
52118
|
recursive: true
|
|
51805
52119
|
});
|
|
51806
52120
|
}
|
|
@@ -51864,38 +52178,38 @@ var init_esm3 = __esm({
|
|
|
51864
52178
|
* @param stats arguments to be passed with event
|
|
51865
52179
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
51866
52180
|
*/
|
|
51867
|
-
async _emit(event,
|
|
52181
|
+
async _emit(event, path17, stats) {
|
|
51868
52182
|
if (this.closed)
|
|
51869
52183
|
return;
|
|
51870
52184
|
const opts = this.options;
|
|
51871
52185
|
if (isWindows)
|
|
51872
|
-
|
|
52186
|
+
path17 = sysPath2.normalize(path17);
|
|
51873
52187
|
if (opts.cwd)
|
|
51874
|
-
|
|
51875
|
-
const args = [
|
|
52188
|
+
path17 = sysPath2.relative(opts.cwd, path17);
|
|
52189
|
+
const args = [path17];
|
|
51876
52190
|
if (stats != null)
|
|
51877
52191
|
args.push(stats);
|
|
51878
52192
|
const awf = opts.awaitWriteFinish;
|
|
51879
52193
|
let pw;
|
|
51880
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
52194
|
+
if (awf && (pw = this._pendingWrites.get(path17))) {
|
|
51881
52195
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
51882
52196
|
return this;
|
|
51883
52197
|
}
|
|
51884
52198
|
if (opts.atomic) {
|
|
51885
52199
|
if (event === EVENTS.UNLINK) {
|
|
51886
|
-
this._pendingUnlinks.set(
|
|
52200
|
+
this._pendingUnlinks.set(path17, [event, ...args]);
|
|
51887
52201
|
setTimeout(() => {
|
|
51888
|
-
this._pendingUnlinks.forEach((entry,
|
|
52202
|
+
this._pendingUnlinks.forEach((entry, path18) => {
|
|
51889
52203
|
this.emit(...entry);
|
|
51890
52204
|
this.emit(EVENTS.ALL, ...entry);
|
|
51891
|
-
this._pendingUnlinks.delete(
|
|
52205
|
+
this._pendingUnlinks.delete(path18);
|
|
51892
52206
|
});
|
|
51893
52207
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
51894
52208
|
return this;
|
|
51895
52209
|
}
|
|
51896
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
52210
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path17)) {
|
|
51897
52211
|
event = EVENTS.CHANGE;
|
|
51898
|
-
this._pendingUnlinks.delete(
|
|
52212
|
+
this._pendingUnlinks.delete(path17);
|
|
51899
52213
|
}
|
|
51900
52214
|
}
|
|
51901
52215
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -51913,16 +52227,16 @@ var init_esm3 = __esm({
|
|
|
51913
52227
|
this.emitWithAll(event, args);
|
|
51914
52228
|
}
|
|
51915
52229
|
};
|
|
51916
|
-
this._awaitWriteFinish(
|
|
52230
|
+
this._awaitWriteFinish(path17, awf.stabilityThreshold, event, awfEmit);
|
|
51917
52231
|
return this;
|
|
51918
52232
|
}
|
|
51919
52233
|
if (event === EVENTS.CHANGE) {
|
|
51920
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
52234
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path17, 50);
|
|
51921
52235
|
if (isThrottled)
|
|
51922
52236
|
return this;
|
|
51923
52237
|
}
|
|
51924
52238
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
51925
|
-
const fullPath = opts.cwd ? sysPath2.join(opts.cwd,
|
|
52239
|
+
const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path17) : path17;
|
|
51926
52240
|
let stats2;
|
|
51927
52241
|
try {
|
|
51928
52242
|
stats2 = await (0, import_promises3.stat)(fullPath);
|
|
@@ -51953,23 +52267,23 @@ var init_esm3 = __esm({
|
|
|
51953
52267
|
* @param timeout duration of time to suppress duplicate actions
|
|
51954
52268
|
* @returns tracking object or false if action should be suppressed
|
|
51955
52269
|
*/
|
|
51956
|
-
_throttle(actionType,
|
|
52270
|
+
_throttle(actionType, path17, timeout) {
|
|
51957
52271
|
if (!this._throttled.has(actionType)) {
|
|
51958
52272
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
51959
52273
|
}
|
|
51960
52274
|
const action = this._throttled.get(actionType);
|
|
51961
52275
|
if (!action)
|
|
51962
52276
|
throw new Error("invalid throttle");
|
|
51963
|
-
const actionPath = action.get(
|
|
52277
|
+
const actionPath = action.get(path17);
|
|
51964
52278
|
if (actionPath) {
|
|
51965
52279
|
actionPath.count++;
|
|
51966
52280
|
return false;
|
|
51967
52281
|
}
|
|
51968
52282
|
let timeoutObject;
|
|
51969
52283
|
const clear = () => {
|
|
51970
|
-
const item = action.get(
|
|
52284
|
+
const item = action.get(path17);
|
|
51971
52285
|
const count = item ? item.count : 0;
|
|
51972
|
-
action.delete(
|
|
52286
|
+
action.delete(path17);
|
|
51973
52287
|
clearTimeout(timeoutObject);
|
|
51974
52288
|
if (item)
|
|
51975
52289
|
clearTimeout(item.timeoutObject);
|
|
@@ -51977,7 +52291,7 @@ var init_esm3 = __esm({
|
|
|
51977
52291
|
};
|
|
51978
52292
|
timeoutObject = setTimeout(clear, timeout);
|
|
51979
52293
|
const thr = { timeoutObject, clear, count: 0 };
|
|
51980
|
-
action.set(
|
|
52294
|
+
action.set(path17, thr);
|
|
51981
52295
|
return thr;
|
|
51982
52296
|
}
|
|
51983
52297
|
_incrReadyCount() {
|
|
@@ -51991,44 +52305,44 @@ var init_esm3 = __esm({
|
|
|
51991
52305
|
* @param event
|
|
51992
52306
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
51993
52307
|
*/
|
|
51994
|
-
_awaitWriteFinish(
|
|
52308
|
+
_awaitWriteFinish(path17, threshold, event, awfEmit) {
|
|
51995
52309
|
const awf = this.options.awaitWriteFinish;
|
|
51996
52310
|
if (typeof awf !== "object")
|
|
51997
52311
|
return;
|
|
51998
52312
|
const pollInterval = awf.pollInterval;
|
|
51999
52313
|
let timeoutHandler;
|
|
52000
|
-
let fullPath =
|
|
52001
|
-
if (this.options.cwd && !sysPath2.isAbsolute(
|
|
52002
|
-
fullPath = sysPath2.join(this.options.cwd,
|
|
52314
|
+
let fullPath = path17;
|
|
52315
|
+
if (this.options.cwd && !sysPath2.isAbsolute(path17)) {
|
|
52316
|
+
fullPath = sysPath2.join(this.options.cwd, path17);
|
|
52003
52317
|
}
|
|
52004
52318
|
const now = /* @__PURE__ */ new Date();
|
|
52005
52319
|
const writes = this._pendingWrites;
|
|
52006
52320
|
function awaitWriteFinishFn(prevStat) {
|
|
52007
52321
|
(0, import_fs2.stat)(fullPath, (err, curStat) => {
|
|
52008
|
-
if (err || !writes.has(
|
|
52322
|
+
if (err || !writes.has(path17)) {
|
|
52009
52323
|
if (err && err.code !== "ENOENT")
|
|
52010
52324
|
awfEmit(err);
|
|
52011
52325
|
return;
|
|
52012
52326
|
}
|
|
52013
52327
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
52014
52328
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
52015
|
-
writes.get(
|
|
52329
|
+
writes.get(path17).lastChange = now2;
|
|
52016
52330
|
}
|
|
52017
|
-
const pw = writes.get(
|
|
52331
|
+
const pw = writes.get(path17);
|
|
52018
52332
|
const df = now2 - pw.lastChange;
|
|
52019
52333
|
if (df >= threshold) {
|
|
52020
|
-
writes.delete(
|
|
52334
|
+
writes.delete(path17);
|
|
52021
52335
|
awfEmit(void 0, curStat);
|
|
52022
52336
|
} else {
|
|
52023
52337
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
52024
52338
|
}
|
|
52025
52339
|
});
|
|
52026
52340
|
}
|
|
52027
|
-
if (!writes.has(
|
|
52028
|
-
writes.set(
|
|
52341
|
+
if (!writes.has(path17)) {
|
|
52342
|
+
writes.set(path17, {
|
|
52029
52343
|
lastChange: now,
|
|
52030
52344
|
cancelWait: () => {
|
|
52031
|
-
writes.delete(
|
|
52345
|
+
writes.delete(path17);
|
|
52032
52346
|
clearTimeout(timeoutHandler);
|
|
52033
52347
|
return event;
|
|
52034
52348
|
}
|
|
@@ -52039,8 +52353,8 @@ var init_esm3 = __esm({
|
|
|
52039
52353
|
/**
|
|
52040
52354
|
* Determines whether user has asked to ignore this path.
|
|
52041
52355
|
*/
|
|
52042
|
-
_isIgnored(
|
|
52043
|
-
if (this.options.atomic && DOT_RE.test(
|
|
52356
|
+
_isIgnored(path17, stats) {
|
|
52357
|
+
if (this.options.atomic && DOT_RE.test(path17))
|
|
52044
52358
|
return true;
|
|
52045
52359
|
if (!this._userIgnored) {
|
|
52046
52360
|
const { cwd } = this.options;
|
|
@@ -52050,17 +52364,17 @@ var init_esm3 = __esm({
|
|
|
52050
52364
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
52051
52365
|
this._userIgnored = anymatch(list, void 0);
|
|
52052
52366
|
}
|
|
52053
|
-
return this._userIgnored(
|
|
52367
|
+
return this._userIgnored(path17, stats);
|
|
52054
52368
|
}
|
|
52055
|
-
_isntIgnored(
|
|
52056
|
-
return !this._isIgnored(
|
|
52369
|
+
_isntIgnored(path17, stat4) {
|
|
52370
|
+
return !this._isIgnored(path17, stat4);
|
|
52057
52371
|
}
|
|
52058
52372
|
/**
|
|
52059
52373
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
52060
52374
|
* @param path file or directory pattern being watched
|
|
52061
52375
|
*/
|
|
52062
|
-
_getWatchHelpers(
|
|
52063
|
-
return new WatchHelper(
|
|
52376
|
+
_getWatchHelpers(path17) {
|
|
52377
|
+
return new WatchHelper(path17, this.options.followSymlinks, this);
|
|
52064
52378
|
}
|
|
52065
52379
|
// Directory helpers
|
|
52066
52380
|
// -----------------
|
|
@@ -52092,63 +52406,63 @@ var init_esm3 = __esm({
|
|
|
52092
52406
|
* @param item base path of item/directory
|
|
52093
52407
|
*/
|
|
52094
52408
|
_remove(directory, item, isDirectory) {
|
|
52095
|
-
const
|
|
52096
|
-
const fullPath = sysPath2.resolve(
|
|
52097
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
52098
|
-
if (!this._throttle("remove",
|
|
52409
|
+
const path17 = sysPath2.join(directory, item);
|
|
52410
|
+
const fullPath = sysPath2.resolve(path17);
|
|
52411
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path17) || this._watched.has(fullPath);
|
|
52412
|
+
if (!this._throttle("remove", path17, 100))
|
|
52099
52413
|
return;
|
|
52100
52414
|
if (!isDirectory && this._watched.size === 1) {
|
|
52101
52415
|
this.add(directory, item, true);
|
|
52102
52416
|
}
|
|
52103
|
-
const wp = this._getWatchedDir(
|
|
52417
|
+
const wp = this._getWatchedDir(path17);
|
|
52104
52418
|
const nestedDirectoryChildren = wp.getChildren();
|
|
52105
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
52419
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path17, nested));
|
|
52106
52420
|
const parent = this._getWatchedDir(directory);
|
|
52107
52421
|
const wasTracked = parent.has(item);
|
|
52108
52422
|
parent.remove(item);
|
|
52109
52423
|
if (this._symlinkPaths.has(fullPath)) {
|
|
52110
52424
|
this._symlinkPaths.delete(fullPath);
|
|
52111
52425
|
}
|
|
52112
|
-
let relPath =
|
|
52426
|
+
let relPath = path17;
|
|
52113
52427
|
if (this.options.cwd)
|
|
52114
|
-
relPath = sysPath2.relative(this.options.cwd,
|
|
52428
|
+
relPath = sysPath2.relative(this.options.cwd, path17);
|
|
52115
52429
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
52116
52430
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
52117
52431
|
if (event === EVENTS.ADD)
|
|
52118
52432
|
return;
|
|
52119
52433
|
}
|
|
52120
|
-
this._watched.delete(
|
|
52434
|
+
this._watched.delete(path17);
|
|
52121
52435
|
this._watched.delete(fullPath);
|
|
52122
52436
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
52123
|
-
if (wasTracked && !this._isIgnored(
|
|
52124
|
-
this._emit(eventName,
|
|
52125
|
-
this._closePath(
|
|
52437
|
+
if (wasTracked && !this._isIgnored(path17))
|
|
52438
|
+
this._emit(eventName, path17);
|
|
52439
|
+
this._closePath(path17);
|
|
52126
52440
|
}
|
|
52127
52441
|
/**
|
|
52128
52442
|
* Closes all watchers for a path
|
|
52129
52443
|
*/
|
|
52130
|
-
_closePath(
|
|
52131
|
-
this._closeFile(
|
|
52132
|
-
const dir = sysPath2.dirname(
|
|
52133
|
-
this._getWatchedDir(dir).remove(sysPath2.basename(
|
|
52444
|
+
_closePath(path17) {
|
|
52445
|
+
this._closeFile(path17);
|
|
52446
|
+
const dir = sysPath2.dirname(path17);
|
|
52447
|
+
this._getWatchedDir(dir).remove(sysPath2.basename(path17));
|
|
52134
52448
|
}
|
|
52135
52449
|
/**
|
|
52136
52450
|
* Closes only file-specific watchers
|
|
52137
52451
|
*/
|
|
52138
|
-
_closeFile(
|
|
52139
|
-
const closers = this._closers.get(
|
|
52452
|
+
_closeFile(path17) {
|
|
52453
|
+
const closers = this._closers.get(path17);
|
|
52140
52454
|
if (!closers)
|
|
52141
52455
|
return;
|
|
52142
52456
|
closers.forEach((closer) => closer());
|
|
52143
|
-
this._closers.delete(
|
|
52457
|
+
this._closers.delete(path17);
|
|
52144
52458
|
}
|
|
52145
|
-
_addPathCloser(
|
|
52459
|
+
_addPathCloser(path17, closer) {
|
|
52146
52460
|
if (!closer)
|
|
52147
52461
|
return;
|
|
52148
|
-
let list = this._closers.get(
|
|
52462
|
+
let list = this._closers.get(path17);
|
|
52149
52463
|
if (!list) {
|
|
52150
52464
|
list = [];
|
|
52151
|
-
this._closers.set(
|
|
52465
|
+
this._closers.set(path17, list);
|
|
52152
52466
|
}
|
|
52153
52467
|
list.push(closer);
|
|
52154
52468
|
}
|
|
@@ -52174,13 +52488,21 @@ var init_esm3 = __esm({
|
|
|
52174
52488
|
}
|
|
52175
52489
|
});
|
|
52176
52490
|
|
|
52491
|
+
// src/standalone/webhooks.ts
|
|
52492
|
+
var init_webhooks2 = __esm({
|
|
52493
|
+
"src/standalone/webhooks.ts"() {
|
|
52494
|
+
"use strict";
|
|
52495
|
+
init_webhooks();
|
|
52496
|
+
}
|
|
52497
|
+
});
|
|
52498
|
+
|
|
52177
52499
|
// src/standalone/server.ts
|
|
52178
52500
|
var server_exports = {};
|
|
52179
52501
|
__export(server_exports, {
|
|
52180
52502
|
startServer: () => startServer
|
|
52181
52503
|
});
|
|
52182
52504
|
function startServer(kanbanDir, port, webviewDir) {
|
|
52183
|
-
const absoluteKanbanDir =
|
|
52505
|
+
const absoluteKanbanDir = path14.resolve(kanbanDir);
|
|
52184
52506
|
let cards = [];
|
|
52185
52507
|
let migrating = false;
|
|
52186
52508
|
let currentEditingCardId = null;
|
|
@@ -52197,15 +52519,15 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
52197
52519
|
}
|
|
52198
52520
|
if (tempFilePath) {
|
|
52199
52521
|
try {
|
|
52200
|
-
|
|
52522
|
+
fs9.unlinkSync(tempFilePath);
|
|
52201
52523
|
} catch {
|
|
52202
52524
|
}
|
|
52203
52525
|
tempFilePath = void 0;
|
|
52204
52526
|
}
|
|
52205
52527
|
tempFileCardId = void 0;
|
|
52206
52528
|
}
|
|
52207
|
-
const resolvedWebviewDir = webviewDir ||
|
|
52208
|
-
const workspaceRoot =
|
|
52529
|
+
const resolvedWebviewDir = webviewDir || path14.join(__dirname, "standalone-webview");
|
|
52530
|
+
const workspaceRoot = path14.dirname(absoluteKanbanDir);
|
|
52209
52531
|
const sdk = new KanbanSDK(absoluteKanbanDir, {
|
|
52210
52532
|
onEvent: (event, data) => {
|
|
52211
52533
|
fireWebhooks(workspaceRoot, event, data);
|
|
@@ -52413,15 +52735,8 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
52413
52735
|
}
|
|
52414
52736
|
}
|
|
52415
52737
|
function doAddColumn(name, color) {
|
|
52416
|
-
const
|
|
52417
|
-
const
|
|
52418
|
-
let uniqueId = id;
|
|
52419
|
-
let counter = 1;
|
|
52420
|
-
while (existingColumns.some((c) => c.id === uniqueId)) {
|
|
52421
|
-
uniqueId = `${id}-${counter++}`;
|
|
52422
|
-
}
|
|
52423
|
-
const column = { id: uniqueId, name, color };
|
|
52424
|
-
sdk.addColumn(column, currentBoardId);
|
|
52738
|
+
const columns = sdk.addColumn({ id: "", name, color }, currentBoardId);
|
|
52739
|
+
const column = columns[columns.length - 1];
|
|
52425
52740
|
broadcast(buildInitMessage());
|
|
52426
52741
|
return column;
|
|
52427
52742
|
}
|
|
@@ -52473,11 +52788,11 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
52473
52788
|
if (!card)
|
|
52474
52789
|
return false;
|
|
52475
52790
|
const cardDir = sdk.storageEngine.getCardDir(card);
|
|
52476
|
-
|
|
52477
|
-
|
|
52791
|
+
fs9.mkdirSync(cardDir, { recursive: true });
|
|
52792
|
+
fs9.writeFileSync(path14.join(cardDir, filename), fileData);
|
|
52478
52793
|
migrating = true;
|
|
52479
52794
|
try {
|
|
52480
|
-
const updated = await sdk.addAttachment(cardId,
|
|
52795
|
+
const updated = await sdk.addAttachment(cardId, path14.join(cardDir, filename), currentBoardId);
|
|
52481
52796
|
lastWrittenContent = serializeCard(updated);
|
|
52482
52797
|
await loadCards();
|
|
52483
52798
|
} finally {
|
|
@@ -52880,10 +53195,9 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
52880
53195
|
break;
|
|
52881
53196
|
case "createBoard": {
|
|
52882
53197
|
const boardName = msg.name;
|
|
52883
|
-
const boardId = generateSlug(boardName) || "board";
|
|
52884
53198
|
try {
|
|
52885
|
-
sdk.createBoard(
|
|
52886
|
-
currentBoardId =
|
|
53199
|
+
const createdBoard = sdk.createBoard("", boardName);
|
|
53200
|
+
currentBoardId = createdBoard.id;
|
|
52887
53201
|
migrating = true;
|
|
52888
53202
|
try {
|
|
52889
53203
|
await loadCards();
|
|
@@ -53027,13 +53341,15 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53027
53341
|
const { boardId } = params;
|
|
53028
53342
|
const body = await readBody(req);
|
|
53029
53343
|
const actions = body.actions;
|
|
53030
|
-
const
|
|
53031
|
-
const
|
|
53032
|
-
|
|
53033
|
-
|
|
53034
|
-
|
|
53035
|
-
|
|
53036
|
-
|
|
53344
|
+
const existing = sdk.getBoardActions(boardId);
|
|
53345
|
+
for (const key of Object.keys(existing)) {
|
|
53346
|
+
if (!(key in actions))
|
|
53347
|
+
sdk.removeBoardAction(boardId, key);
|
|
53348
|
+
}
|
|
53349
|
+
for (const [key, title] of Object.entries(actions)) {
|
|
53350
|
+
sdk.addBoardAction(boardId, key, title);
|
|
53351
|
+
}
|
|
53352
|
+
return jsonOk(res, sdk.getBoardActions(boardId));
|
|
53037
53353
|
} catch (err) {
|
|
53038
53354
|
return jsonError(res, 400, String(err));
|
|
53039
53355
|
}
|
|
@@ -53092,7 +53408,18 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53092
53408
|
try {
|
|
53093
53409
|
const { boardId } = params;
|
|
53094
53410
|
const boardColumns = sdk.listColumns(boardId);
|
|
53095
|
-
const
|
|
53411
|
+
const metaFilter = {};
|
|
53412
|
+
for (const [param, value] of url3.searchParams.entries()) {
|
|
53413
|
+
if (param.startsWith("meta."))
|
|
53414
|
+
metaFilter[param.slice(5)] = value;
|
|
53415
|
+
}
|
|
53416
|
+
const sortParam = url3.searchParams.get("sort");
|
|
53417
|
+
const boardTasks = await sdk.listCards(
|
|
53418
|
+
boardColumns.map((c) => c.id),
|
|
53419
|
+
boardId,
|
|
53420
|
+
Object.keys(metaFilter).length > 0 ? metaFilter : void 0,
|
|
53421
|
+
sortParam || void 0
|
|
53422
|
+
);
|
|
53096
53423
|
let result = boardTasks.map(sanitizeCard);
|
|
53097
53424
|
if (url3.searchParams.get("includeDeleted") !== "true") {
|
|
53098
53425
|
result = result.filter((f) => f.status !== "deleted");
|
|
@@ -53114,14 +53441,6 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53114
53441
|
const groupLabels = sdk.getLabelsInGroup(labelGroup);
|
|
53115
53442
|
result = result.filter((f) => f.labels.some((l) => groupLabels.includes(l)));
|
|
53116
53443
|
}
|
|
53117
|
-
const metaFilter = {};
|
|
53118
|
-
for (const [param, value] of url3.searchParams.entries()) {
|
|
53119
|
-
if (param.startsWith("meta."))
|
|
53120
|
-
metaFilter[param.slice(5)] = value;
|
|
53121
|
-
}
|
|
53122
|
-
if (Object.keys(metaFilter).length > 0)
|
|
53123
|
-
result = result.filter((f) => matchesMetaFilter(f.metadata, metaFilter));
|
|
53124
|
-
result = applySortParam(result, url3.searchParams.get("sort"));
|
|
53125
53444
|
return jsonOk(res, result);
|
|
53126
53445
|
} catch (err) {
|
|
53127
53446
|
return jsonError(res, 400, String(err));
|
|
@@ -53239,6 +53558,12 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53239
53558
|
}
|
|
53240
53559
|
params = route("GET", "/api/tasks");
|
|
53241
53560
|
if (params) {
|
|
53561
|
+
const metaFilter2 = {};
|
|
53562
|
+
for (const [param, value] of url3.searchParams.entries()) {
|
|
53563
|
+
if (param.startsWith("meta."))
|
|
53564
|
+
metaFilter2[param.slice(5)] = value;
|
|
53565
|
+
}
|
|
53566
|
+
const sortParam2 = url3.searchParams.get("sort");
|
|
53242
53567
|
await loadCards();
|
|
53243
53568
|
let result = cards.map(sanitizeCard);
|
|
53244
53569
|
if (url3.searchParams.get("includeDeleted") !== "true") {
|
|
@@ -53261,14 +53586,9 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53261
53586
|
const groupLabels = sdk.getLabelsInGroup(labelGroup);
|
|
53262
53587
|
result = result.filter((f) => f.labels.some((l) => groupLabels.includes(l)));
|
|
53263
53588
|
}
|
|
53264
|
-
|
|
53265
|
-
|
|
53266
|
-
|
|
53267
|
-
metaFilter[param.slice(5)] = value;
|
|
53268
|
-
}
|
|
53269
|
-
if (Object.keys(metaFilter).length > 0)
|
|
53270
|
-
result = result.filter((f) => matchesMetaFilter(f.metadata, metaFilter));
|
|
53271
|
-
result = applySortParam(result, url3.searchParams.get("sort"));
|
|
53589
|
+
if (Object.keys(metaFilter2).length > 0)
|
|
53590
|
+
result = result.filter((f) => matchesMetaFilter(f.metadata, metaFilter2));
|
|
53591
|
+
result = applySortParam(result, sortParam2);
|
|
53272
53592
|
return jsonOk(res, result);
|
|
53273
53593
|
}
|
|
53274
53594
|
params = route("POST", "/api/tasks");
|
|
@@ -53388,7 +53708,7 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53388
53708
|
const rawPath = url3.searchParams.get("path") ?? "";
|
|
53389
53709
|
if (!rawPath)
|
|
53390
53710
|
return jsonError(res, 400, "path is required");
|
|
53391
|
-
const resolved = /^([/~]|[A-Za-z]:[/\\])/.test(rawPath) ? rawPath.replace(/^~/, process.env.HOME ?? os.homedir()) :
|
|
53711
|
+
const resolved = /^([/~]|[A-Za-z]:[/\\])/.test(rawPath) ? rawPath.replace(/^~/, process.env.HOME ?? os.homedir()) : path14.resolve(workspaceRoot, rawPath);
|
|
53392
53712
|
return jsonOk(res, { path: resolved });
|
|
53393
53713
|
}
|
|
53394
53714
|
params = route("GET", "/api/card-file");
|
|
@@ -53407,16 +53727,16 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53407
53727
|
if (tempFileCardId === cardId && tempFilePath) {
|
|
53408
53728
|
tempFileWriting = true;
|
|
53409
53729
|
try {
|
|
53410
|
-
|
|
53730
|
+
fs9.writeFileSync(tempFilePath, serializeCard(openCard), "utf-8");
|
|
53411
53731
|
} finally {
|
|
53412
53732
|
tempFileWriting = false;
|
|
53413
53733
|
}
|
|
53414
53734
|
return jsonOk(res, { path: tempFilePath });
|
|
53415
53735
|
}
|
|
53416
|
-
const tmpPath =
|
|
53736
|
+
const tmpPath = path14.join(os.tmpdir(), `kanban-card-${openCard.id}.md`);
|
|
53417
53737
|
tempFileWriting = true;
|
|
53418
53738
|
try {
|
|
53419
|
-
|
|
53739
|
+
fs9.writeFileSync(tmpPath, serializeCard(openCard), "utf-8");
|
|
53420
53740
|
} finally {
|
|
53421
53741
|
tempFileWriting = false;
|
|
53422
53742
|
}
|
|
@@ -53435,7 +53755,7 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53435
53755
|
if (!cid || !fp)
|
|
53436
53756
|
return;
|
|
53437
53757
|
try {
|
|
53438
|
-
const raw =
|
|
53758
|
+
const raw = fs9.readFileSync(fp, "utf-8");
|
|
53439
53759
|
const parsed = parseCardFile(raw, `${cid}.md`);
|
|
53440
53760
|
if (!parsed)
|
|
53441
53761
|
return;
|
|
@@ -53475,15 +53795,15 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53475
53795
|
if (!card)
|
|
53476
53796
|
return jsonError(res, 404, "Task not found");
|
|
53477
53797
|
const cardDir = sdk.storageEngine.getCardDir(card);
|
|
53478
|
-
const attachmentPath =
|
|
53798
|
+
const attachmentPath = path14.resolve(cardDir, attachName);
|
|
53479
53799
|
if (!attachmentPath.startsWith(absoluteKanbanDir)) {
|
|
53480
53800
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
53481
53801
|
res.end("Forbidden");
|
|
53482
53802
|
return;
|
|
53483
53803
|
}
|
|
53484
|
-
const ext2 =
|
|
53804
|
+
const ext2 = path14.extname(attachName);
|
|
53485
53805
|
const contentType2 = MIME_TYPES[ext2] || "application/octet-stream";
|
|
53486
|
-
|
|
53806
|
+
fs9.readFile(attachmentPath, (err, data) => {
|
|
53487
53807
|
if (err) {
|
|
53488
53808
|
res.writeHead(404);
|
|
53489
53809
|
res.end("File not found");
|
|
@@ -53687,7 +54007,7 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53687
54007
|
}
|
|
53688
54008
|
params = route("GET", "/api/webhooks");
|
|
53689
54009
|
if (params) {
|
|
53690
|
-
return jsonOk(res,
|
|
54010
|
+
return jsonOk(res, sdk.listWebhooks());
|
|
53691
54011
|
}
|
|
53692
54012
|
params = route("POST", "/api/webhooks");
|
|
53693
54013
|
if (params) {
|
|
@@ -53701,7 +54021,7 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53701
54021
|
if (!events || !Array.isArray(events) || events.length === 0) {
|
|
53702
54022
|
return jsonError(res, 400, "events array is required");
|
|
53703
54023
|
}
|
|
53704
|
-
const webhook = createWebhook(
|
|
54024
|
+
const webhook = sdk.createWebhook({ url: webhookUrl, events, secret });
|
|
53705
54025
|
return jsonOk(res, webhook, 201);
|
|
53706
54026
|
} catch (err) {
|
|
53707
54027
|
return jsonError(res, 400, String(err));
|
|
@@ -53712,7 +54032,7 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53712
54032
|
try {
|
|
53713
54033
|
const { id } = params;
|
|
53714
54034
|
const body = await readBody(req);
|
|
53715
|
-
const webhook = updateWebhook(
|
|
54035
|
+
const webhook = sdk.updateWebhook(id, body);
|
|
53716
54036
|
if (!webhook)
|
|
53717
54037
|
return jsonError(res, 404, "Webhook not found");
|
|
53718
54038
|
return jsonOk(res, webhook);
|
|
@@ -53723,7 +54043,7 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53723
54043
|
params = route("DELETE", "/api/webhooks/:id");
|
|
53724
54044
|
if (params) {
|
|
53725
54045
|
const { id } = params;
|
|
53726
|
-
const ok = deleteWebhook(
|
|
54046
|
+
const ok = sdk.deleteWebhook(id);
|
|
53727
54047
|
if (!ok)
|
|
53728
54048
|
return jsonError(res, 404, "Webhook not found");
|
|
53729
54049
|
return jsonOk(res, { deleted: true });
|
|
@@ -53866,15 +54186,15 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53866
54186
|
return;
|
|
53867
54187
|
}
|
|
53868
54188
|
const cardDir = sdk.storageEngine.getCardDir(card);
|
|
53869
|
-
const attachmentPath =
|
|
54189
|
+
const attachmentPath = path14.resolve(cardDir, filename);
|
|
53870
54190
|
if (!attachmentPath.startsWith(absoluteKanbanDir)) {
|
|
53871
54191
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
53872
54192
|
res.end("Forbidden");
|
|
53873
54193
|
return;
|
|
53874
54194
|
}
|
|
53875
|
-
const ext2 =
|
|
54195
|
+
const ext2 = path14.extname(filename);
|
|
53876
54196
|
const contentType2 = MIME_TYPES[ext2] || "application/octet-stream";
|
|
53877
|
-
|
|
54197
|
+
fs9.readFile(attachmentPath, (err, data) => {
|
|
53878
54198
|
if (err) {
|
|
53879
54199
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
53880
54200
|
res.end("File not found");
|
|
@@ -53888,15 +54208,15 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53888
54208
|
if (pathname.startsWith("/api/")) {
|
|
53889
54209
|
return jsonError(res, 404, "Not found");
|
|
53890
54210
|
}
|
|
53891
|
-
const filePath =
|
|
53892
|
-
if (!
|
|
54211
|
+
const filePath = path14.join(resolvedWebviewDir, pathname === "/" ? "index.html" : pathname);
|
|
54212
|
+
if (!path14.extname(filePath)) {
|
|
53893
54213
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
53894
54214
|
res.end(indexHtml);
|
|
53895
54215
|
return;
|
|
53896
54216
|
}
|
|
53897
|
-
const ext =
|
|
54217
|
+
const ext = path14.extname(filePath);
|
|
53898
54218
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
53899
|
-
|
|
54219
|
+
fs9.readFile(filePath, (err, data) => {
|
|
53900
54220
|
if (err) {
|
|
53901
54221
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
53902
54222
|
res.end(indexHtml);
|
|
@@ -53918,7 +54238,7 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53918
54238
|
});
|
|
53919
54239
|
});
|
|
53920
54240
|
let debounceTimer;
|
|
53921
|
-
|
|
54241
|
+
fs9.mkdirSync(absoluteKanbanDir, { recursive: true });
|
|
53922
54242
|
const handleFileChange = (changedPath) => {
|
|
53923
54243
|
if (changedPath && !changedPath.endsWith(".md"))
|
|
53924
54244
|
return;
|
|
@@ -53964,13 +54284,17 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53964
54284
|
}, 100);
|
|
53965
54285
|
};
|
|
53966
54286
|
if (sdk.storageEngine.type === "markdown") {
|
|
54287
|
+
let watcherReady = false;
|
|
53967
54288
|
const watcher = esm_default.watch(absoluteKanbanDir, {
|
|
53968
54289
|
ignoreInitial: true,
|
|
53969
54290
|
awaitWriteFinish: { stabilityThreshold: 100 }
|
|
53970
54291
|
});
|
|
53971
|
-
watcher.on("
|
|
53972
|
-
|
|
53973
|
-
|
|
54292
|
+
watcher.on("ready", () => {
|
|
54293
|
+
watcherReady = true;
|
|
54294
|
+
});
|
|
54295
|
+
watcher.on("change", (p) => watcherReady && handleFileChange(p));
|
|
54296
|
+
watcher.on("add", (p) => watcherReady && handleFileChange(p));
|
|
54297
|
+
watcher.on("unlink", (p) => watcherReady && handleFileChange(p));
|
|
53974
54298
|
server.on("close", () => {
|
|
53975
54299
|
watcher.close();
|
|
53976
54300
|
wss.close();
|
|
@@ -53988,22 +54312,21 @@ function startServer(kanbanDir, port, webviewDir) {
|
|
|
53988
54312
|
});
|
|
53989
54313
|
return server;
|
|
53990
54314
|
}
|
|
53991
|
-
var http2,
|
|
54315
|
+
var http2, fs9, os, path14, MIME_TYPES;
|
|
53992
54316
|
var init_server3 = __esm({
|
|
53993
54317
|
"src/standalone/server.ts"() {
|
|
53994
54318
|
"use strict";
|
|
53995
54319
|
http2 = __toESM(require("http"));
|
|
53996
|
-
|
|
54320
|
+
fs9 = __toESM(require("fs"));
|
|
53997
54321
|
os = __toESM(require("os"));
|
|
53998
|
-
|
|
54322
|
+
path14 = __toESM(require("path"));
|
|
53999
54323
|
init_wrapper();
|
|
54000
54324
|
init_esm3();
|
|
54001
|
-
init_types();
|
|
54002
54325
|
init_KanbanSDK();
|
|
54003
54326
|
init_parser();
|
|
54004
54327
|
init_config();
|
|
54005
54328
|
init_types2();
|
|
54006
|
-
|
|
54329
|
+
init_webhooks2();
|
|
54007
54330
|
init_metaUtils();
|
|
54008
54331
|
MIME_TYPES = {
|
|
54009
54332
|
".html": "text/html",
|
|
@@ -54617,12 +54940,11 @@ var init_open = __esm({
|
|
|
54617
54940
|
});
|
|
54618
54941
|
|
|
54619
54942
|
// src/cli/index.ts
|
|
54620
|
-
var
|
|
54621
|
-
var
|
|
54943
|
+
var path16 = __toESM(require("path"));
|
|
54944
|
+
var fs15 = __toESM(require("fs/promises"));
|
|
54622
54945
|
init_KanbanSDK();
|
|
54623
|
-
|
|
54946
|
+
init_types();
|
|
54624
54947
|
init_config();
|
|
54625
|
-
init_metaUtils();
|
|
54626
54948
|
var VALID_PRIORITIES = ["critical", "high", "medium", "low"];
|
|
54627
54949
|
function parseArgs(argv) {
|
|
54628
54950
|
const args = argv.slice(2);
|
|
@@ -54665,16 +54987,16 @@ async function findWorkspaceRoot2(startDir) {
|
|
|
54665
54987
|
let dir = startDir;
|
|
54666
54988
|
while (true) {
|
|
54667
54989
|
try {
|
|
54668
|
-
await
|
|
54990
|
+
await fs15.access(path16.join(dir, ".git"));
|
|
54669
54991
|
return dir;
|
|
54670
54992
|
} catch {
|
|
54671
54993
|
}
|
|
54672
54994
|
try {
|
|
54673
|
-
await
|
|
54995
|
+
await fs15.access(path16.join(dir, "package.json"));
|
|
54674
54996
|
return dir;
|
|
54675
54997
|
} catch {
|
|
54676
54998
|
}
|
|
54677
|
-
const parent =
|
|
54999
|
+
const parent = path16.dirname(dir);
|
|
54678
55000
|
if (parent === dir)
|
|
54679
55001
|
return startDir;
|
|
54680
55002
|
dir = parent;
|
|
@@ -54682,10 +55004,10 @@ async function findWorkspaceRoot2(startDir) {
|
|
|
54682
55004
|
}
|
|
54683
55005
|
async function resolveKanbanDir2(flags) {
|
|
54684
55006
|
if (typeof flags.dir === "string") {
|
|
54685
|
-
return
|
|
55007
|
+
return path16.resolve(flags.dir);
|
|
54686
55008
|
}
|
|
54687
55009
|
const root = await findWorkspaceRoot2(process.cwd());
|
|
54688
|
-
return
|
|
55010
|
+
return path16.join(root, ".kanban");
|
|
54689
55011
|
}
|
|
54690
55012
|
var bold = (s) => `\x1B[1m${s}\x1B[0m`;
|
|
54691
55013
|
var dim = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
@@ -54724,21 +55046,14 @@ function colorPriority(priority) {
|
|
|
54724
55046
|
return priority;
|
|
54725
55047
|
}
|
|
54726
55048
|
}
|
|
54727
|
-
function getTitleFromContent3(content) {
|
|
54728
|
-
const match = content.match(/^#\s+(.+)$/m);
|
|
54729
|
-
if (match)
|
|
54730
|
-
return match[1].trim();
|
|
54731
|
-
const firstLine = content.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
|
|
54732
|
-
return firstLine || "Untitled";
|
|
54733
|
-
}
|
|
54734
55049
|
function formatCardRow(c) {
|
|
54735
|
-
const title =
|
|
55050
|
+
const title = getTitleFromContent(c.content);
|
|
54736
55051
|
const truncTitle = title.length > 40 ? title.slice(0, 37) + "..." : title;
|
|
54737
55052
|
const assignee = c.assignee || "-";
|
|
54738
55053
|
return ` ${bold(c.id.slice(0, 30).padEnd(30))} ${colorStatus(c.status.padEnd(12))} ${colorPriority(c.priority.padEnd(8))} ${assignee.padEnd(12)} ${truncTitle}`;
|
|
54739
55054
|
}
|
|
54740
55055
|
function formatCardDetail(c) {
|
|
54741
|
-
const title =
|
|
55056
|
+
const title = getTitleFromContent(c.content);
|
|
54742
55057
|
const lines = [
|
|
54743
55058
|
`${bold(title)}`,
|
|
54744
55059
|
"",
|
|
@@ -54769,7 +55084,29 @@ function formatCardDetail(c) {
|
|
|
54769
55084
|
}
|
|
54770
55085
|
async function cmdList(sdk, flags) {
|
|
54771
55086
|
const boardId = getBoardId(flags);
|
|
54772
|
-
|
|
55087
|
+
const metaFilter = Array.isArray(flags.meta) ? (() => {
|
|
55088
|
+
const mf = {};
|
|
55089
|
+
for (const entry of flags.meta) {
|
|
55090
|
+
const eq = entry.indexOf("=");
|
|
55091
|
+
if (eq < 1) {
|
|
55092
|
+
console.error(red(`Invalid --meta format: "${entry}". Expected key=value`));
|
|
55093
|
+
process.exit(1);
|
|
55094
|
+
}
|
|
55095
|
+
mf[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
55096
|
+
}
|
|
55097
|
+
return Object.keys(mf).length > 0 ? mf : void 0;
|
|
55098
|
+
})() : void 0;
|
|
55099
|
+
const VALID_SORTS = ["created:asc", "created:desc", "modified:asc", "modified:desc"];
|
|
55100
|
+
let sortOpt;
|
|
55101
|
+
if (typeof flags.sort === "string") {
|
|
55102
|
+
const sort = flags.sort;
|
|
55103
|
+
if (!VALID_SORTS.includes(sort)) {
|
|
55104
|
+
console.error(red(`Invalid --sort value: "${sort}". Must be one of: ${VALID_SORTS.join(", ")}`));
|
|
55105
|
+
process.exit(1);
|
|
55106
|
+
}
|
|
55107
|
+
sortOpt = sort;
|
|
55108
|
+
}
|
|
55109
|
+
let cards = await sdk.listCards(void 0, boardId, metaFilter, sortOpt);
|
|
54773
55110
|
if (!flags["include-deleted"]) {
|
|
54774
55111
|
cards = cards.filter((c) => c.status !== "deleted");
|
|
54775
55112
|
}
|
|
@@ -54789,32 +55126,6 @@ async function cmdList(sdk, flags) {
|
|
|
54789
55126
|
const groupLabels = sdk.getLabelsInGroup(flags["label-group"]);
|
|
54790
55127
|
cards = cards.filter((c) => c.labels.some((l) => groupLabels.includes(l)));
|
|
54791
55128
|
}
|
|
54792
|
-
if (Array.isArray(flags.meta)) {
|
|
54793
|
-
const metaFilter = {};
|
|
54794
|
-
for (const entry of flags.meta) {
|
|
54795
|
-
const eq = entry.indexOf("=");
|
|
54796
|
-
if (eq < 1) {
|
|
54797
|
-
console.error(red(`Invalid --meta format: "${entry}". Expected key=value`));
|
|
54798
|
-
process.exit(1);
|
|
54799
|
-
}
|
|
54800
|
-
metaFilter[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
54801
|
-
}
|
|
54802
|
-
cards = cards.filter((c) => matchesMetaFilter(c.metadata, metaFilter));
|
|
54803
|
-
}
|
|
54804
|
-
const VALID_SORTS = ["created:asc", "created:desc", "modified:asc", "modified:desc"];
|
|
54805
|
-
if (typeof flags.sort === "string") {
|
|
54806
|
-
const sort = flags.sort;
|
|
54807
|
-
if (!VALID_SORTS.includes(sort)) {
|
|
54808
|
-
console.error(red(`Invalid --sort value: "${sort}". Must be one of: ${VALID_SORTS.join(", ")}`));
|
|
54809
|
-
process.exit(1);
|
|
54810
|
-
}
|
|
54811
|
-
const [field, dir] = sort.split(":");
|
|
54812
|
-
cards = [...cards].sort((a, b) => {
|
|
54813
|
-
const aVal = field === "created" ? a.created : a.modified;
|
|
54814
|
-
const bVal = field === "created" ? b.created : b.modified;
|
|
54815
|
-
return dir === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
|
|
54816
|
-
});
|
|
54817
|
-
}
|
|
54818
55129
|
if (flags.json) {
|
|
54819
55130
|
console.log(JSON.stringify(cards, null, 2));
|
|
54820
55131
|
return;
|
|
@@ -55068,17 +55379,16 @@ async function cmdBoards(sdk, positional, flags, workspaceRoot) {
|
|
|
55068
55379
|
case "default": {
|
|
55069
55380
|
const boardId = positional[1];
|
|
55070
55381
|
if (!boardId) {
|
|
55071
|
-
const
|
|
55072
|
-
console.log(
|
|
55382
|
+
const config3 = readConfig(workspaceRoot);
|
|
55383
|
+
console.log(config3.defaultBoard);
|
|
55073
55384
|
break;
|
|
55074
55385
|
}
|
|
55075
|
-
|
|
55076
|
-
|
|
55077
|
-
|
|
55386
|
+
try {
|
|
55387
|
+
sdk.setDefaultBoard(boardId);
|
|
55388
|
+
} catch (err) {
|
|
55389
|
+
console.error(red(String(err)));
|
|
55078
55390
|
process.exit(1);
|
|
55079
55391
|
}
|
|
55080
|
-
config3.defaultBoard = boardId;
|
|
55081
|
-
writeConfig(workspaceRoot, config3);
|
|
55082
55392
|
console.log(green(`Default board set to: ${boardId}`));
|
|
55083
55393
|
break;
|
|
55084
55394
|
}
|
|
@@ -55214,7 +55524,7 @@ async function cmdAttach(sdk, positional, flags) {
|
|
|
55214
55524
|
}
|
|
55215
55525
|
const resolvedId = await resolveCardId(sdk, cardId, boardId);
|
|
55216
55526
|
const updated = await sdk.addAttachment(resolvedId, filePath, boardId);
|
|
55217
|
-
console.log(green(`Attached to ${updated.id}: ${
|
|
55527
|
+
console.log(green(`Attached to ${updated.id}: ${path16.basename(filePath)}`));
|
|
55218
55528
|
break;
|
|
55219
55529
|
}
|
|
55220
55530
|
case "remove":
|
|
@@ -55682,11 +55992,11 @@ async function cmdAction(sdk, positional, flags) {
|
|
|
55682
55992
|
process.exit(1);
|
|
55683
55993
|
}
|
|
55684
55994
|
}
|
|
55685
|
-
async function cmdWebhooks(positional, flags,
|
|
55995
|
+
async function cmdWebhooks(positional, flags, sdk) {
|
|
55686
55996
|
const subcommand = positional[0] || "list";
|
|
55687
55997
|
switch (subcommand) {
|
|
55688
55998
|
case "list": {
|
|
55689
|
-
const webhooks =
|
|
55999
|
+
const webhooks = sdk.listWebhooks();
|
|
55690
56000
|
if (flags.json) {
|
|
55691
56001
|
console.log(JSON.stringify(webhooks, null, 2));
|
|
55692
56002
|
} else if (webhooks.length === 0) {
|
|
@@ -55710,7 +56020,7 @@ async function cmdWebhooks(positional, flags, workspaceRoot) {
|
|
|
55710
56020
|
}
|
|
55711
56021
|
const events = typeof flags.events === "string" ? flags.events.split(",").map((e) => e.trim()) : ["*"];
|
|
55712
56022
|
const secret = typeof flags.secret === "string" ? flags.secret : void 0;
|
|
55713
|
-
const webhook = createWebhook(
|
|
56023
|
+
const webhook = sdk.createWebhook({ url: url3, events, secret });
|
|
55714
56024
|
if (flags.json) {
|
|
55715
56025
|
console.log(JSON.stringify(webhook, null, 2));
|
|
55716
56026
|
} else {
|
|
@@ -55729,7 +56039,7 @@ async function cmdWebhooks(positional, flags, workspaceRoot) {
|
|
|
55729
56039
|
console.error(red("Usage: kl webhooks remove <id>"));
|
|
55730
56040
|
process.exit(1);
|
|
55731
56041
|
}
|
|
55732
|
-
const removed = deleteWebhook(
|
|
56042
|
+
const removed = sdk.deleteWebhook(webhookId);
|
|
55733
56043
|
if (removed) {
|
|
55734
56044
|
console.log(green(`Removed webhook: ${webhookId}`));
|
|
55735
56045
|
} else {
|
|
@@ -55753,7 +56063,7 @@ async function cmdWebhooks(positional, flags, workspaceRoot) {
|
|
|
55753
56063
|
updates.secret = flags.secret;
|
|
55754
56064
|
if (typeof flags.active === "string")
|
|
55755
56065
|
updates.active = flags.active === "true";
|
|
55756
|
-
const updated = updateWebhook(
|
|
56066
|
+
const updated = sdk.updateWebhook(webhookId, updates);
|
|
55757
56067
|
if (!updated) {
|
|
55758
56068
|
console.error(red(`Webhook not found: ${webhookId}`));
|
|
55759
56069
|
process.exit(1);
|
|
@@ -55785,13 +56095,12 @@ var SETTINGS_KEYS = [
|
|
|
55785
56095
|
"defaultPriority",
|
|
55786
56096
|
"defaultStatus"
|
|
55787
56097
|
];
|
|
55788
|
-
async function cmdSettings(positional, flags,
|
|
56098
|
+
async function cmdSettings(positional, flags, sdk) {
|
|
55789
56099
|
const subcommand = positional[0] || "show";
|
|
55790
56100
|
switch (subcommand) {
|
|
55791
56101
|
case "show":
|
|
55792
56102
|
case "list": {
|
|
55793
|
-
const
|
|
55794
|
-
const settings = configToSettings(config3);
|
|
56103
|
+
const settings = sdk.getSettings();
|
|
55795
56104
|
if (flags.json) {
|
|
55796
56105
|
console.log(JSON.stringify(settings, null, 2));
|
|
55797
56106
|
} else {
|
|
@@ -55805,8 +56114,7 @@ async function cmdSettings(positional, flags, workspaceRoot) {
|
|
|
55805
56114
|
}
|
|
55806
56115
|
case "update":
|
|
55807
56116
|
case "set": {
|
|
55808
|
-
const
|
|
55809
|
-
const settings = configToSettings(config3);
|
|
56117
|
+
const settings = sdk.getSettings();
|
|
55810
56118
|
let changed = false;
|
|
55811
56119
|
const settingsAny = settings;
|
|
55812
56120
|
for (const key of SETTINGS_KEYS) {
|
|
@@ -55827,10 +56135,10 @@ async function cmdSettings(positional, flags, workspaceRoot) {
|
|
|
55827
56135
|
console.error(`Available: ${SETTINGS_KEYS.join(", ")}`);
|
|
55828
56136
|
process.exit(1);
|
|
55829
56137
|
}
|
|
55830
|
-
|
|
56138
|
+
sdk.updateSettings(settings);
|
|
55831
56139
|
console.log(green("Settings updated."));
|
|
55832
56140
|
if (flags.json) {
|
|
55833
|
-
console.log(JSON.stringify(
|
|
56141
|
+
console.log(JSON.stringify(sdk.getSettings(), null, 2));
|
|
55834
56142
|
}
|
|
55835
56143
|
break;
|
|
55836
56144
|
}
|
|
@@ -55842,7 +56150,7 @@ async function cmdSettings(positional, flags, workspaceRoot) {
|
|
|
55842
56150
|
}
|
|
55843
56151
|
async function cmdMcp(flags) {
|
|
55844
56152
|
if (typeof flags.dir === "string") {
|
|
55845
|
-
process.env.KANBAN_DIR =
|
|
56153
|
+
process.env.KANBAN_DIR = path16.resolve(flags.dir);
|
|
55846
56154
|
}
|
|
55847
56155
|
await Promise.resolve().then(() => (init_mcp_server2(), mcp_server_exports));
|
|
55848
56156
|
}
|
|
@@ -55895,10 +56203,10 @@ async function findPackageRoot() {
|
|
|
55895
56203
|
let dir = __dirname;
|
|
55896
56204
|
while (true) {
|
|
55897
56205
|
try {
|
|
55898
|
-
await
|
|
56206
|
+
await fs15.access(path16.join(dir, "package.json"));
|
|
55899
56207
|
return dir;
|
|
55900
56208
|
} catch {
|
|
55901
|
-
const parent =
|
|
56209
|
+
const parent = path16.dirname(dir);
|
|
55902
56210
|
if (parent === dir)
|
|
55903
56211
|
return __dirname;
|
|
55904
56212
|
dir = parent;
|
|
@@ -55913,9 +56221,9 @@ async function showDocHelp(topic) {
|
|
|
55913
56221
|
process.exit(1);
|
|
55914
56222
|
}
|
|
55915
56223
|
const pkgRoot = await findPackageRoot();
|
|
55916
|
-
const docPath =
|
|
56224
|
+
const docPath = path16.join(pkgRoot, relativePath);
|
|
55917
56225
|
try {
|
|
55918
|
-
const content = await
|
|
56226
|
+
const content = await fs15.readFile(docPath, "utf-8");
|
|
55919
56227
|
console.log(formatMarkdownForTerminal(content));
|
|
55920
56228
|
} catch {
|
|
55921
56229
|
console.error(red(`Documentation not found: ${docPath}`));
|
|
@@ -56091,7 +56399,7 @@ async function main2() {
|
|
|
56091
56399
|
const { command, positional, flags } = parseArgs(process.argv);
|
|
56092
56400
|
if (command === "version" || flags.version) {
|
|
56093
56401
|
const pkgRoot = await findPackageRoot();
|
|
56094
|
-
const pkg = JSON.parse(await
|
|
56402
|
+
const pkg = JSON.parse(await fs15.readFile(path16.join(pkgRoot, "package.json"), "utf-8"));
|
|
56095
56403
|
console.log(pkg.version);
|
|
56096
56404
|
return;
|
|
56097
56405
|
}
|
|
@@ -56113,10 +56421,8 @@ async function main2() {
|
|
|
56113
56421
|
return;
|
|
56114
56422
|
}
|
|
56115
56423
|
const kanbanDir = await resolveKanbanDir2(flags);
|
|
56116
|
-
const workspaceRoot =
|
|
56117
|
-
const sdk = new KanbanSDK(kanbanDir
|
|
56118
|
-
onEvent: (event, data) => fireWebhooks(workspaceRoot, event, data)
|
|
56119
|
-
});
|
|
56424
|
+
const workspaceRoot = path16.dirname(kanbanDir);
|
|
56425
|
+
const sdk = new KanbanSDK(kanbanDir);
|
|
56120
56426
|
switch (command) {
|
|
56121
56427
|
case "list":
|
|
56122
56428
|
case "ls":
|
|
@@ -56187,10 +56493,10 @@ async function main2() {
|
|
|
56187
56493
|
case "webhooks":
|
|
56188
56494
|
case "webhook":
|
|
56189
56495
|
case "wh":
|
|
56190
|
-
await cmdWebhooks(positional, flags,
|
|
56496
|
+
await cmdWebhooks(positional, flags, sdk);
|
|
56191
56497
|
break;
|
|
56192
56498
|
case "settings":
|
|
56193
|
-
await cmdSettings(positional, flags,
|
|
56499
|
+
await cmdSettings(positional, flags, sdk);
|
|
56194
56500
|
break;
|
|
56195
56501
|
case "pwd":
|
|
56196
56502
|
if (flags.json) {
|