kanban-lite 1.0.9 → 1.0.13
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 +1015 -407
- package/dist/extension.js +897 -347
- package/dist/mcp-server.js +550 -189
- package/dist/sdk/index.cjs +1223 -0
- package/dist/sdk/index.mjs +1168 -0
- package/dist/sdk/sdk/KanbanSDK.d.ts +39 -21
- package/dist/sdk/sdk/index.d.ts +4 -3
- package/dist/sdk/sdk/migration.d.ts +6 -0
- package/dist/sdk/sdk/types.d.ts +3 -5
- package/dist/sdk/shared/config.d.ts +23 -10
- package/dist/sdk/shared/types.d.ts +18 -4
- package/dist/standalone-webview/index.js +27 -27
- package/dist/standalone-webview/index.js.map +1 -1
- package/dist/standalone-webview/style.css +1 -1
- package/dist/standalone.js +831 -328
- package/dist/webview/index.js +45 -45
- package/dist/webview/index.js.map +1 -1
- package/dist/webview/style.css +1 -1
- package/package.json +4 -3
- package/src/cli/index.ts +217 -95
- package/src/extension/KanbanPanel.ts +49 -22
- package/src/mcp-server/index.ts +138 -62
- package/src/sdk/KanbanSDK.ts +283 -77
- package/src/sdk/__tests__/KanbanSDK.test.ts +5 -5
- package/src/sdk/__tests__/migration.test.ts +269 -0
- package/src/sdk/__tests__/multi-board.test.ts +449 -0
- package/src/sdk/index.ts +4 -3
- package/src/sdk/migration.ts +52 -0
- package/src/sdk/types.ts +3 -6
- package/src/shared/config.ts +144 -22
- package/src/shared/types.ts +14 -5
- package/src/standalone/__tests__/server.integration.test.ts +38 -37
- package/src/standalone/server.ts +239 -21
- package/src/webview/App.tsx +17 -7
- package/src/webview/components/Toolbar.tsx +99 -3
- package/src/webview/store/index.ts +11 -3
- package/.kanban/backlog/1-test1.md +0 -30
- package/.kanban.json +0 -42
package/dist/extension.js
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __commonJS = (cb, mod) => function __require() {
|
|
9
12
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
13
|
};
|
|
@@ -30,6 +33,47 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
33
|
));
|
|
31
34
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
35
|
|
|
36
|
+
// src/shared/types.ts
|
|
37
|
+
var types_exports = {};
|
|
38
|
+
__export(types_exports, {
|
|
39
|
+
DEFAULT_COLUMNS: () => DEFAULT_COLUMNS,
|
|
40
|
+
extractNumericId: () => extractNumericId,
|
|
41
|
+
generateFeatureFilename: () => generateFeatureFilename,
|
|
42
|
+
generateSlug: () => generateSlug,
|
|
43
|
+
getTitleFromContent: () => getTitleFromContent
|
|
44
|
+
});
|
|
45
|
+
function getTitleFromContent(content) {
|
|
46
|
+
const match = content.match(/^#\s+(.+)$/m);
|
|
47
|
+
if (match)
|
|
48
|
+
return match[1].trim();
|
|
49
|
+
const firstLine = content.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
|
|
50
|
+
return firstLine || "Untitled";
|
|
51
|
+
}
|
|
52
|
+
function generateSlug(title) {
|
|
53
|
+
return title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 50) || "feature";
|
|
54
|
+
}
|
|
55
|
+
function generateFeatureFilename(id, title) {
|
|
56
|
+
const slug = generateSlug(title);
|
|
57
|
+
return `${id}-${slug}`;
|
|
58
|
+
}
|
|
59
|
+
function extractNumericId(filenameOrId) {
|
|
60
|
+
const match = filenameOrId.match(/^(\d+)(?:-|$)/);
|
|
61
|
+
return match ? parseInt(match[1], 10) : null;
|
|
62
|
+
}
|
|
63
|
+
var DEFAULT_COLUMNS;
|
|
64
|
+
var init_types = __esm({
|
|
65
|
+
"src/shared/types.ts"() {
|
|
66
|
+
"use strict";
|
|
67
|
+
DEFAULT_COLUMNS = [
|
|
68
|
+
{ id: "backlog", name: "Backlog", color: "#6b7280" },
|
|
69
|
+
{ id: "todo", name: "To Do", color: "#3b82f6" },
|
|
70
|
+
{ id: "in-progress", name: "In Progress", color: "#f59e0b" },
|
|
71
|
+
{ id: "review", name: "Review", color: "#8b5cf6" },
|
|
72
|
+
{ id: "done", name: "Done", color: "#22c55e" }
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
33
77
|
// node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js
|
|
34
78
|
var require_constants = __commonJS({
|
|
35
79
|
"node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js"(exports2, module2) {
|
|
@@ -3747,25 +3791,30 @@ __export(extension_exports, {
|
|
|
3747
3791
|
});
|
|
3748
3792
|
module.exports = __toCommonJS(extension_exports);
|
|
3749
3793
|
var net = __toESM(require("node:net"));
|
|
3750
|
-
var
|
|
3794
|
+
var path10 = __toESM(require("node:path"));
|
|
3751
3795
|
var vscode3 = __toESM(require("vscode"));
|
|
3752
3796
|
|
|
3753
3797
|
// src/shared/config.ts
|
|
3754
3798
|
var fs = __toESM(require("fs"));
|
|
3755
3799
|
var path = __toESM(require("path"));
|
|
3800
|
+
init_types();
|
|
3801
|
+
var DEFAULT_BOARD_CONFIG = {
|
|
3802
|
+
name: "Default",
|
|
3803
|
+
columns: [...DEFAULT_COLUMNS],
|
|
3804
|
+
nextCardId: 1,
|
|
3805
|
+
defaultStatus: "backlog",
|
|
3806
|
+
defaultPriority: "medium"
|
|
3807
|
+
};
|
|
3756
3808
|
var DEFAULT_CONFIG = {
|
|
3809
|
+
version: 2,
|
|
3810
|
+
boards: {
|
|
3811
|
+
default: { ...DEFAULT_BOARD_CONFIG, columns: [...DEFAULT_COLUMNS] }
|
|
3812
|
+
},
|
|
3813
|
+
defaultBoard: "default",
|
|
3757
3814
|
featuresDirectory: ".kanban",
|
|
3815
|
+
aiAgent: "claude",
|
|
3758
3816
|
defaultPriority: "medium",
|
|
3759
3817
|
defaultStatus: "backlog",
|
|
3760
|
-
columns: [
|
|
3761
|
-
{ id: "backlog", name: "Backlog", color: "#6b7280" },
|
|
3762
|
-
{ id: "todo", name: "To Do", color: "#3b82f6" },
|
|
3763
|
-
{ id: "in-progress", name: "In Progress", color: "#f59e0b" },
|
|
3764
|
-
{ id: "review", name: "Review", color: "#8b5cf6" },
|
|
3765
|
-
{ id: "done", name: "Done", color: "#22c55e" }
|
|
3766
|
-
],
|
|
3767
|
-
aiAgent: "claude",
|
|
3768
|
-
nextCardId: 1,
|
|
3769
3818
|
showPriorityBadges: true,
|
|
3770
3819
|
showAssignee: true,
|
|
3771
3820
|
showDueDate: true,
|
|
@@ -3779,12 +3828,65 @@ var CONFIG_FILENAME = ".kanban.json";
|
|
|
3779
3828
|
function configPath(workspaceRoot) {
|
|
3780
3829
|
return path.join(workspaceRoot, CONFIG_FILENAME);
|
|
3781
3830
|
}
|
|
3831
|
+
function migrateConfigV1ToV2(raw) {
|
|
3832
|
+
const v1Defaults = {
|
|
3833
|
+
featuresDirectory: ".kanban",
|
|
3834
|
+
defaultPriority: "medium",
|
|
3835
|
+
defaultStatus: "backlog",
|
|
3836
|
+
columns: [...DEFAULT_COLUMNS],
|
|
3837
|
+
aiAgent: "claude",
|
|
3838
|
+
nextCardId: 1,
|
|
3839
|
+
showPriorityBadges: true,
|
|
3840
|
+
showAssignee: true,
|
|
3841
|
+
showDueDate: true,
|
|
3842
|
+
showLabels: true,
|
|
3843
|
+
showBuildWithAI: true,
|
|
3844
|
+
showFileName: false,
|
|
3845
|
+
compactMode: false,
|
|
3846
|
+
markdownEditorMode: false
|
|
3847
|
+
};
|
|
3848
|
+
const v1 = { ...v1Defaults, ...raw };
|
|
3849
|
+
return {
|
|
3850
|
+
version: 2,
|
|
3851
|
+
boards: {
|
|
3852
|
+
default: {
|
|
3853
|
+
name: "Default",
|
|
3854
|
+
columns: v1.columns,
|
|
3855
|
+
nextCardId: v1.nextCardId,
|
|
3856
|
+
defaultStatus: v1.defaultStatus,
|
|
3857
|
+
defaultPriority: v1.defaultPriority
|
|
3858
|
+
}
|
|
3859
|
+
},
|
|
3860
|
+
defaultBoard: "default",
|
|
3861
|
+
featuresDirectory: v1.featuresDirectory,
|
|
3862
|
+
aiAgent: v1.aiAgent,
|
|
3863
|
+
defaultPriority: v1.defaultPriority,
|
|
3864
|
+
defaultStatus: v1.defaultStatus,
|
|
3865
|
+
showPriorityBadges: v1.showPriorityBadges,
|
|
3866
|
+
showAssignee: v1.showAssignee,
|
|
3867
|
+
showDueDate: v1.showDueDate,
|
|
3868
|
+
showLabels: v1.showLabels,
|
|
3869
|
+
showBuildWithAI: v1.showBuildWithAI,
|
|
3870
|
+
showFileName: v1.showFileName,
|
|
3871
|
+
compactMode: v1.compactMode,
|
|
3872
|
+
markdownEditorMode: v1.markdownEditorMode
|
|
3873
|
+
};
|
|
3874
|
+
}
|
|
3782
3875
|
function readConfig(workspaceRoot) {
|
|
3783
3876
|
const filePath = configPath(workspaceRoot);
|
|
3784
|
-
const defaults = { ...DEFAULT_CONFIG, columns: [...
|
|
3877
|
+
const defaults = { ...DEFAULT_CONFIG, boards: { default: { ...DEFAULT_BOARD_CONFIG, columns: [...DEFAULT_COLUMNS] } } };
|
|
3785
3878
|
try {
|
|
3786
3879
|
const raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
3787
|
-
|
|
3880
|
+
if (!raw.version || raw.version === 1) {
|
|
3881
|
+
const v2 = migrateConfigV1ToV2(raw);
|
|
3882
|
+
writeConfig(workspaceRoot, v2);
|
|
3883
|
+
return v2;
|
|
3884
|
+
}
|
|
3885
|
+
const config = { ...defaults, ...raw };
|
|
3886
|
+
if (!config.boards || Object.keys(config.boards).length === 0) {
|
|
3887
|
+
config.boards = defaults.boards;
|
|
3888
|
+
}
|
|
3889
|
+
return config;
|
|
3788
3890
|
} catch {
|
|
3789
3891
|
return defaults;
|
|
3790
3892
|
}
|
|
@@ -3793,19 +3895,39 @@ function writeConfig(workspaceRoot, config) {
|
|
|
3793
3895
|
const filePath = configPath(workspaceRoot);
|
|
3794
3896
|
fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
3795
3897
|
}
|
|
3796
|
-
function
|
|
3898
|
+
function getBoardConfig(workspaceRoot, boardId) {
|
|
3797
3899
|
const config = readConfig(workspaceRoot);
|
|
3798
|
-
const
|
|
3799
|
-
|
|
3900
|
+
const resolvedId = boardId || config.defaultBoard;
|
|
3901
|
+
const board = config.boards[resolvedId];
|
|
3902
|
+
if (!board) {
|
|
3903
|
+
throw new Error(`Board '${resolvedId}' not found`);
|
|
3904
|
+
}
|
|
3905
|
+
return board;
|
|
3906
|
+
}
|
|
3907
|
+
function allocateCardId(workspaceRoot, boardId) {
|
|
3908
|
+
const config = readConfig(workspaceRoot);
|
|
3909
|
+
const resolvedId = boardId || config.defaultBoard;
|
|
3910
|
+
const board = config.boards[resolvedId];
|
|
3911
|
+
if (!board) {
|
|
3912
|
+
throw new Error(`Board '${resolvedId}' not found`);
|
|
3913
|
+
}
|
|
3914
|
+
const id = board.nextCardId;
|
|
3915
|
+
board.nextCardId = id + 1;
|
|
3916
|
+
writeConfig(workspaceRoot, config);
|
|
3800
3917
|
return id;
|
|
3801
3918
|
}
|
|
3802
|
-
function syncCardIdCounter(workspaceRoot, existingIds) {
|
|
3919
|
+
function syncCardIdCounter(workspaceRoot, boardId, existingIds) {
|
|
3803
3920
|
if (existingIds.length === 0)
|
|
3804
3921
|
return;
|
|
3805
3922
|
const maxId = Math.max(...existingIds);
|
|
3806
3923
|
const config = readConfig(workspaceRoot);
|
|
3807
|
-
|
|
3808
|
-
|
|
3924
|
+
const resolvedId = boardId || config.defaultBoard;
|
|
3925
|
+
const board = config.boards[resolvedId];
|
|
3926
|
+
if (!board)
|
|
3927
|
+
return;
|
|
3928
|
+
if (board.nextCardId <= maxId) {
|
|
3929
|
+
board.nextCardId = maxId + 1;
|
|
3930
|
+
writeConfig(workspaceRoot, config);
|
|
3809
3931
|
}
|
|
3810
3932
|
}
|
|
3811
3933
|
function configToSettings(config) {
|
|
@@ -3837,8 +3959,8 @@ function settingsToConfig(config, settings) {
|
|
|
3837
3959
|
}
|
|
3838
3960
|
|
|
3839
3961
|
// src/sdk/KanbanSDK.ts
|
|
3840
|
-
var
|
|
3841
|
-
var
|
|
3962
|
+
var fs4 = __toESM(require("fs/promises"));
|
|
3963
|
+
var path5 = __toESM(require("path"));
|
|
3842
3964
|
|
|
3843
3965
|
// node_modules/.pnpm/fractional-indexing@3.2.0/node_modules/fractional-indexing/src/index.js
|
|
3844
3966
|
var BASE_62_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
@@ -4050,25 +4172,8 @@ function generateNKeysBetween(a, b, n, digits = BASE_62_DIGITS) {
|
|
|
4050
4172
|
];
|
|
4051
4173
|
}
|
|
4052
4174
|
|
|
4053
|
-
// src/
|
|
4054
|
-
|
|
4055
|
-
const match = content.match(/^#\s+(.+)$/m);
|
|
4056
|
-
if (match)
|
|
4057
|
-
return match[1].trim();
|
|
4058
|
-
const firstLine = content.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
|
|
4059
|
-
return firstLine || "Untitled";
|
|
4060
|
-
}
|
|
4061
|
-
function generateSlug(title) {
|
|
4062
|
-
return title.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 50) || "feature";
|
|
4063
|
-
}
|
|
4064
|
-
function generateFeatureFilename(id, title) {
|
|
4065
|
-
const slug = generateSlug(title);
|
|
4066
|
-
return `${id}-${slug}`;
|
|
4067
|
-
}
|
|
4068
|
-
function extractNumericId(filenameOrId) {
|
|
4069
|
-
const match = filenameOrId.match(/^(\d+)(?:-|$)/);
|
|
4070
|
-
return match ? parseInt(match[1], 10) : null;
|
|
4071
|
-
}
|
|
4175
|
+
// src/sdk/KanbanSDK.ts
|
|
4176
|
+
init_types();
|
|
4072
4177
|
|
|
4073
4178
|
// src/sdk/parser.ts
|
|
4074
4179
|
var path2 = __toESM(require("path"));
|
|
@@ -4257,30 +4362,203 @@ async function fileExists(filePath) {
|
|
|
4257
4362
|
}
|
|
4258
4363
|
}
|
|
4259
4364
|
|
|
4365
|
+
// src/sdk/migration.ts
|
|
4366
|
+
var fs3 = __toESM(require("fs/promises"));
|
|
4367
|
+
var path4 = __toESM(require("path"));
|
|
4368
|
+
async function migrateFileSystemToMultiBoard(featuresDir) {
|
|
4369
|
+
const boardsDir = path4.join(featuresDir, "boards");
|
|
4370
|
+
const defaultBoardDir = path4.join(boardsDir, "default");
|
|
4371
|
+
try {
|
|
4372
|
+
await fs3.access(boardsDir);
|
|
4373
|
+
return;
|
|
4374
|
+
} catch {
|
|
4375
|
+
}
|
|
4376
|
+
await fs3.mkdir(defaultBoardDir, { recursive: true });
|
|
4377
|
+
let entries;
|
|
4378
|
+
try {
|
|
4379
|
+
entries = await fs3.readdir(featuresDir, { withFileTypes: true });
|
|
4380
|
+
} catch {
|
|
4381
|
+
return;
|
|
4382
|
+
}
|
|
4383
|
+
for (const entry of entries) {
|
|
4384
|
+
if (!entry.isDirectory())
|
|
4385
|
+
continue;
|
|
4386
|
+
if (entry.name === "boards" || entry.name.startsWith("."))
|
|
4387
|
+
continue;
|
|
4388
|
+
const src = path4.join(featuresDir, entry.name);
|
|
4389
|
+
const dest = path4.join(defaultBoardDir, entry.name);
|
|
4390
|
+
await fs3.rename(src, dest);
|
|
4391
|
+
}
|
|
4392
|
+
const rootMdFiles = entries.filter((e) => e.isFile() && e.name.endsWith(".md"));
|
|
4393
|
+
if (rootMdFiles.length > 0) {
|
|
4394
|
+
const backlogDir = path4.join(defaultBoardDir, "backlog");
|
|
4395
|
+
await fs3.mkdir(backlogDir, { recursive: true });
|
|
4396
|
+
for (const file of rootMdFiles) {
|
|
4397
|
+
await fs3.rename(
|
|
4398
|
+
path4.join(featuresDir, file.name),
|
|
4399
|
+
path4.join(backlogDir, file.name)
|
|
4400
|
+
);
|
|
4401
|
+
}
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4404
|
+
|
|
4260
4405
|
// src/sdk/KanbanSDK.ts
|
|
4261
4406
|
var KanbanSDK = class {
|
|
4262
4407
|
constructor(featuresDir) {
|
|
4263
4408
|
this.featuresDir = featuresDir;
|
|
4409
|
+
this._migrated = false;
|
|
4264
4410
|
}
|
|
4265
4411
|
get workspaceRoot() {
|
|
4266
|
-
return
|
|
4412
|
+
return path5.dirname(this.featuresDir);
|
|
4413
|
+
}
|
|
4414
|
+
// --- Board resolution helpers ---
|
|
4415
|
+
_resolveBoardId(boardId) {
|
|
4416
|
+
const config = readConfig(this.workspaceRoot);
|
|
4417
|
+
return boardId || config.defaultBoard;
|
|
4418
|
+
}
|
|
4419
|
+
_boardDir(boardId) {
|
|
4420
|
+
const resolvedId = this._resolveBoardId(boardId);
|
|
4421
|
+
return path5.join(this.featuresDir, "boards", resolvedId);
|
|
4422
|
+
}
|
|
4423
|
+
_isCompletedStatus(status, boardId) {
|
|
4424
|
+
const config = readConfig(this.workspaceRoot);
|
|
4425
|
+
const resolvedId = boardId || config.defaultBoard;
|
|
4426
|
+
const board = config.boards[resolvedId];
|
|
4427
|
+
if (!board || board.columns.length === 0)
|
|
4428
|
+
return status === "done";
|
|
4429
|
+
return board.columns[board.columns.length - 1].id === status;
|
|
4430
|
+
}
|
|
4431
|
+
async _ensureMigrated() {
|
|
4432
|
+
if (this._migrated)
|
|
4433
|
+
return;
|
|
4434
|
+
await migrateFileSystemToMultiBoard(this.featuresDir);
|
|
4435
|
+
this._migrated = true;
|
|
4267
4436
|
}
|
|
4268
4437
|
async init() {
|
|
4269
|
-
await
|
|
4438
|
+
await this._ensureMigrated();
|
|
4439
|
+
const boardDir = this._boardDir();
|
|
4440
|
+
await ensureDirectories(boardDir);
|
|
4441
|
+
}
|
|
4442
|
+
// --- Board management ---
|
|
4443
|
+
listBoards() {
|
|
4444
|
+
const config = readConfig(this.workspaceRoot);
|
|
4445
|
+
return Object.entries(config.boards).map(([id, board]) => ({
|
|
4446
|
+
id,
|
|
4447
|
+
name: board.name,
|
|
4448
|
+
description: board.description
|
|
4449
|
+
}));
|
|
4450
|
+
}
|
|
4451
|
+
createBoard(id, name, options) {
|
|
4452
|
+
const config = readConfig(this.workspaceRoot);
|
|
4453
|
+
if (config.boards[id]) {
|
|
4454
|
+
throw new Error(`Board already exists: ${id}`);
|
|
4455
|
+
}
|
|
4456
|
+
const columns = options?.columns || [...config.boards[config.defaultBoard]?.columns || [
|
|
4457
|
+
{ id: "backlog", name: "Backlog", color: "#6b7280" },
|
|
4458
|
+
{ id: "todo", name: "To Do", color: "#3b82f6" },
|
|
4459
|
+
{ id: "in-progress", name: "In Progress", color: "#f59e0b" },
|
|
4460
|
+
{ id: "review", name: "Review", color: "#8b5cf6" },
|
|
4461
|
+
{ id: "done", name: "Done", color: "#22c55e" }
|
|
4462
|
+
]];
|
|
4463
|
+
config.boards[id] = {
|
|
4464
|
+
name,
|
|
4465
|
+
description: options?.description,
|
|
4466
|
+
columns,
|
|
4467
|
+
nextCardId: 1,
|
|
4468
|
+
defaultStatus: options?.defaultStatus || columns[0]?.id || "backlog",
|
|
4469
|
+
defaultPriority: options?.defaultPriority || config.defaultPriority
|
|
4470
|
+
};
|
|
4471
|
+
writeConfig(this.workspaceRoot, config);
|
|
4472
|
+
return { id, name, description: options?.description };
|
|
4473
|
+
}
|
|
4474
|
+
async deleteBoard(boardId) {
|
|
4475
|
+
const config = readConfig(this.workspaceRoot);
|
|
4476
|
+
if (!config.boards[boardId]) {
|
|
4477
|
+
throw new Error(`Board not found: ${boardId}`);
|
|
4478
|
+
}
|
|
4479
|
+
if (config.defaultBoard === boardId) {
|
|
4480
|
+
throw new Error(`Cannot delete the default board: ${boardId}`);
|
|
4481
|
+
}
|
|
4482
|
+
const cards = await this.listCards(void 0, boardId);
|
|
4483
|
+
if (cards.length > 0) {
|
|
4484
|
+
throw new Error(`Cannot delete board "${boardId}": ${cards.length} card(s) still exist`);
|
|
4485
|
+
}
|
|
4486
|
+
const boardDir = this._boardDir(boardId);
|
|
4487
|
+
try {
|
|
4488
|
+
await fs4.rm(boardDir, { recursive: true });
|
|
4489
|
+
} catch {
|
|
4490
|
+
}
|
|
4491
|
+
delete config.boards[boardId];
|
|
4492
|
+
writeConfig(this.workspaceRoot, config);
|
|
4493
|
+
}
|
|
4494
|
+
getBoard(boardId) {
|
|
4495
|
+
return getBoardConfig(this.workspaceRoot, boardId);
|
|
4496
|
+
}
|
|
4497
|
+
updateBoard(boardId, updates) {
|
|
4498
|
+
const config = readConfig(this.workspaceRoot);
|
|
4499
|
+
const board = config.boards[boardId];
|
|
4500
|
+
if (!board) {
|
|
4501
|
+
throw new Error(`Board not found: ${boardId}`);
|
|
4502
|
+
}
|
|
4503
|
+
if (updates.name !== void 0)
|
|
4504
|
+
board.name = updates.name;
|
|
4505
|
+
if (updates.description !== void 0)
|
|
4506
|
+
board.description = updates.description;
|
|
4507
|
+
if (updates.columns !== void 0)
|
|
4508
|
+
board.columns = updates.columns;
|
|
4509
|
+
if (updates.defaultStatus !== void 0)
|
|
4510
|
+
board.defaultStatus = updates.defaultStatus;
|
|
4511
|
+
if (updates.defaultPriority !== void 0)
|
|
4512
|
+
board.defaultPriority = updates.defaultPriority;
|
|
4513
|
+
writeConfig(this.workspaceRoot, config);
|
|
4514
|
+
return board;
|
|
4515
|
+
}
|
|
4516
|
+
async transferCard(cardId, fromBoardId, toBoardId, targetStatus) {
|
|
4517
|
+
const toBoardDir = this._boardDir(toBoardId);
|
|
4518
|
+
const config = readConfig(this.workspaceRoot);
|
|
4519
|
+
if (!config.boards[fromBoardId])
|
|
4520
|
+
throw new Error(`Board not found: ${fromBoardId}`);
|
|
4521
|
+
if (!config.boards[toBoardId])
|
|
4522
|
+
throw new Error(`Board not found: ${toBoardId}`);
|
|
4523
|
+
const card = await this.getCard(cardId, fromBoardId);
|
|
4524
|
+
if (!card)
|
|
4525
|
+
throw new Error(`Card not found: ${cardId} in board ${fromBoardId}`);
|
|
4526
|
+
const toBoard = config.boards[toBoardId];
|
|
4527
|
+
const newStatus = targetStatus || toBoard.defaultStatus || toBoard.columns[0]?.id || "backlog";
|
|
4528
|
+
const targetDir = path5.join(toBoardDir, newStatus);
|
|
4529
|
+
await fs4.mkdir(targetDir, { recursive: true });
|
|
4530
|
+
const oldPath = card.filePath;
|
|
4531
|
+
const filename = path5.basename(oldPath);
|
|
4532
|
+
const newPath = path5.join(targetDir, filename);
|
|
4533
|
+
await fs4.rename(oldPath, newPath);
|
|
4534
|
+
card.status = newStatus;
|
|
4535
|
+
card.boardId = toBoardId;
|
|
4536
|
+
card.filePath = newPath;
|
|
4537
|
+
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
4538
|
+
card.completedAt = this._isCompletedStatus(newStatus, toBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
4539
|
+
const targetCards = await this.listCards(void 0, toBoardId);
|
|
4540
|
+
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);
|
|
4541
|
+
const lastOrder = cardsInStatus.length > 0 ? cardsInStatus[cardsInStatus.length - 1].order : null;
|
|
4542
|
+
card.order = generateKeyBetween(lastOrder, null);
|
|
4543
|
+
await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
|
|
4544
|
+
return card;
|
|
4270
4545
|
}
|
|
4271
4546
|
// --- Card CRUD ---
|
|
4272
|
-
async listCards(columns) {
|
|
4273
|
-
await
|
|
4547
|
+
async listCards(columns, boardId) {
|
|
4548
|
+
await this._ensureMigrated();
|
|
4549
|
+
const boardDir = this._boardDir(boardId);
|
|
4550
|
+
const resolvedBoardId = this._resolveBoardId(boardId);
|
|
4551
|
+
await ensureDirectories(boardDir);
|
|
4274
4552
|
if (columns) {
|
|
4275
|
-
await ensureStatusSubfolders(
|
|
4553
|
+
await ensureStatusSubfolders(boardDir, columns);
|
|
4276
4554
|
}
|
|
4277
4555
|
try {
|
|
4278
|
-
const rootFiles = await this._readMdFiles(
|
|
4556
|
+
const rootFiles = await this._readMdFiles(boardDir);
|
|
4279
4557
|
for (const filePath of rootFiles) {
|
|
4280
4558
|
try {
|
|
4281
4559
|
const card = await this._loadCard(filePath);
|
|
4282
4560
|
if (card) {
|
|
4283
|
-
await moveFeatureFile(filePath,
|
|
4561
|
+
await moveFeatureFile(filePath, boardDir, card.status, card.attachments);
|
|
4284
4562
|
}
|
|
4285
4563
|
} catch {
|
|
4286
4564
|
}
|
|
@@ -4288,26 +4566,33 @@ var KanbanSDK = class {
|
|
|
4288
4566
|
} catch {
|
|
4289
4567
|
}
|
|
4290
4568
|
const cards = [];
|
|
4291
|
-
|
|
4569
|
+
let entries;
|
|
4570
|
+
try {
|
|
4571
|
+
entries = await fs4.readdir(boardDir, { withFileTypes: true });
|
|
4572
|
+
} catch {
|
|
4573
|
+
return [];
|
|
4574
|
+
}
|
|
4292
4575
|
for (const entry of entries) {
|
|
4293
4576
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
4294
4577
|
continue;
|
|
4295
|
-
const subdir =
|
|
4578
|
+
const subdir = path5.join(boardDir, entry.name);
|
|
4296
4579
|
try {
|
|
4297
4580
|
const mdFiles = await this._readMdFiles(subdir);
|
|
4298
4581
|
for (const filePath of mdFiles) {
|
|
4299
4582
|
const card = await this._loadCard(filePath);
|
|
4300
|
-
if (card)
|
|
4583
|
+
if (card) {
|
|
4584
|
+
card.boardId = resolvedBoardId;
|
|
4301
4585
|
cards.push(card);
|
|
4586
|
+
}
|
|
4302
4587
|
}
|
|
4303
4588
|
} catch {
|
|
4304
4589
|
}
|
|
4305
4590
|
}
|
|
4306
4591
|
for (const card of cards) {
|
|
4307
|
-
const pathStatus = getStatusFromPath(card.filePath,
|
|
4592
|
+
const pathStatus = getStatusFromPath(card.filePath, boardDir);
|
|
4308
4593
|
if (pathStatus !== null && pathStatus !== card.status) {
|
|
4309
4594
|
try {
|
|
4310
|
-
card.filePath = await moveFeatureFile(card.filePath,
|
|
4595
|
+
card.filePath = await moveFeatureFile(card.filePath, boardDir, card.status, card.attachments);
|
|
4311
4596
|
} catch {
|
|
4312
4597
|
}
|
|
4313
4598
|
}
|
|
@@ -4325,65 +4610,72 @@ var KanbanSDK = class {
|
|
|
4325
4610
|
const keys = generateNKeysBetween(null, null, columnCards.length);
|
|
4326
4611
|
for (let i = 0; i < columnCards.length; i++) {
|
|
4327
4612
|
columnCards[i].order = keys[i];
|
|
4328
|
-
await
|
|
4613
|
+
await fs4.writeFile(columnCards[i].filePath, serializeFeature(columnCards[i]), "utf-8");
|
|
4329
4614
|
}
|
|
4330
4615
|
}
|
|
4331
4616
|
}
|
|
4332
4617
|
const numericIds = cards.map((c) => parseInt(c.id, 10)).filter((n) => !Number.isNaN(n));
|
|
4333
4618
|
if (numericIds.length > 0) {
|
|
4334
|
-
syncCardIdCounter(
|
|
4619
|
+
syncCardIdCounter(this.workspaceRoot, resolvedBoardId, numericIds);
|
|
4335
4620
|
}
|
|
4336
4621
|
return cards.sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
4337
4622
|
}
|
|
4338
|
-
async getCard(cardId) {
|
|
4339
|
-
const cards = await this.listCards();
|
|
4623
|
+
async getCard(cardId, boardId) {
|
|
4624
|
+
const cards = await this.listCards(void 0, boardId);
|
|
4340
4625
|
return cards.find((c) => c.id === cardId) || null;
|
|
4341
4626
|
}
|
|
4342
4627
|
async createCard(data) {
|
|
4343
|
-
await
|
|
4344
|
-
const
|
|
4345
|
-
const
|
|
4628
|
+
await this._ensureMigrated();
|
|
4629
|
+
const resolvedBoardId = this._resolveBoardId(data.boardId);
|
|
4630
|
+
const boardDir = this._boardDir(resolvedBoardId);
|
|
4631
|
+
await ensureDirectories(boardDir);
|
|
4632
|
+
const config = readConfig(this.workspaceRoot);
|
|
4633
|
+
const board = config.boards[resolvedBoardId];
|
|
4634
|
+
const status = data.status || board?.defaultStatus || config.defaultStatus || "backlog";
|
|
4635
|
+
const priority = data.priority || board?.defaultPriority || config.defaultPriority || "medium";
|
|
4346
4636
|
const title = getTitleFromContent(data.content);
|
|
4347
|
-
const
|
|
4348
|
-
const numericId = allocateCardId(workspaceRoot);
|
|
4637
|
+
const numericId = allocateCardId(this.workspaceRoot, resolvedBoardId);
|
|
4349
4638
|
const filename = generateFeatureFilename(numericId, title);
|
|
4350
4639
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4351
|
-
const cards = await this.listCards();
|
|
4640
|
+
const cards = await this.listCards(void 0, resolvedBoardId);
|
|
4352
4641
|
const cardsInStatus = cards.filter((c) => c.status === status).sort((a, b) => a.order < b.order ? -1 : a.order > b.order ? 1 : 0);
|
|
4353
4642
|
const lastOrder = cardsInStatus.length > 0 ? cardsInStatus[cardsInStatus.length - 1].order : null;
|
|
4354
4643
|
const card = {
|
|
4355
4644
|
id: String(numericId),
|
|
4645
|
+
boardId: resolvedBoardId,
|
|
4356
4646
|
status,
|
|
4357
4647
|
priority,
|
|
4358
4648
|
assignee: data.assignee ?? null,
|
|
4359
4649
|
dueDate: data.dueDate ?? null,
|
|
4360
4650
|
created: now,
|
|
4361
4651
|
modified: now,
|
|
4362
|
-
completedAt: status
|
|
4652
|
+
completedAt: this._isCompletedStatus(status, resolvedBoardId) ? now : null,
|
|
4363
4653
|
labels: data.labels || [],
|
|
4364
4654
|
attachments: data.attachments || [],
|
|
4365
4655
|
comments: [],
|
|
4366
4656
|
order: generateKeyBetween(lastOrder, null),
|
|
4367
4657
|
content: data.content,
|
|
4368
|
-
filePath: getFeatureFilePath(
|
|
4658
|
+
filePath: getFeatureFilePath(boardDir, status, filename)
|
|
4369
4659
|
};
|
|
4370
|
-
await
|
|
4371
|
-
await
|
|
4660
|
+
await fs4.mkdir(path5.dirname(card.filePath), { recursive: true });
|
|
4661
|
+
await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
|
|
4372
4662
|
return card;
|
|
4373
4663
|
}
|
|
4374
|
-
async updateCard(cardId, updates) {
|
|
4375
|
-
const card = await this.getCard(cardId);
|
|
4664
|
+
async updateCard(cardId, updates, boardId) {
|
|
4665
|
+
const card = await this.getCard(cardId, boardId);
|
|
4376
4666
|
if (!card)
|
|
4377
4667
|
throw new Error(`Card not found: ${cardId}`);
|
|
4668
|
+
const resolvedBoardId = card.boardId || this._resolveBoardId(boardId);
|
|
4669
|
+
const boardDir = this._boardDir(resolvedBoardId);
|
|
4378
4670
|
const oldStatus = card.status;
|
|
4379
4671
|
const oldTitle = getTitleFromContent(card.content);
|
|
4380
|
-
const { filePath: _fp, id: _id, ...safeUpdates } = updates;
|
|
4672
|
+
const { filePath: _fp, id: _id, boardId: _bid, ...safeUpdates } = updates;
|
|
4381
4673
|
Object.assign(card, safeUpdates);
|
|
4382
4674
|
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
4383
4675
|
if (oldStatus !== card.status) {
|
|
4384
|
-
card.completedAt = card.status
|
|
4676
|
+
card.completedAt = this._isCompletedStatus(card.status, resolvedBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
4385
4677
|
}
|
|
4386
|
-
await
|
|
4678
|
+
await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
|
|
4387
4679
|
const newTitle = getTitleFromContent(card.content);
|
|
4388
4680
|
const numericId = extractNumericId(card.id);
|
|
4389
4681
|
if (numericId !== null && newTitle !== oldTitle) {
|
|
@@ -4391,46 +4683,48 @@ var KanbanSDK = class {
|
|
|
4391
4683
|
card.filePath = await renameFeatureFile(card.filePath, newFilename);
|
|
4392
4684
|
}
|
|
4393
4685
|
if (oldStatus !== card.status) {
|
|
4394
|
-
const newPath = await moveFeatureFile(card.filePath,
|
|
4686
|
+
const newPath = await moveFeatureFile(card.filePath, boardDir, card.status, card.attachments);
|
|
4395
4687
|
card.filePath = newPath;
|
|
4396
4688
|
}
|
|
4397
4689
|
return card;
|
|
4398
4690
|
}
|
|
4399
|
-
async moveCard(cardId, newStatus, position) {
|
|
4400
|
-
const cards = await this.listCards();
|
|
4691
|
+
async moveCard(cardId, newStatus, position, boardId) {
|
|
4692
|
+
const cards = await this.listCards(void 0, boardId);
|
|
4401
4693
|
const card = cards.find((c) => c.id === cardId);
|
|
4402
4694
|
if (!card)
|
|
4403
4695
|
throw new Error(`Card not found: ${cardId}`);
|
|
4696
|
+
const resolvedBoardId = card.boardId || this._resolveBoardId(boardId);
|
|
4697
|
+
const boardDir = this._boardDir(resolvedBoardId);
|
|
4404
4698
|
const oldStatus = card.status;
|
|
4405
4699
|
card.status = newStatus;
|
|
4406
4700
|
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
4407
4701
|
if (oldStatus !== newStatus) {
|
|
4408
|
-
card.completedAt = newStatus
|
|
4702
|
+
card.completedAt = this._isCompletedStatus(newStatus, resolvedBoardId) ? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
4409
4703
|
}
|
|
4410
4704
|
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);
|
|
4411
4705
|
const pos = position !== void 0 ? Math.max(0, Math.min(position, targetColumnCards.length)) : targetColumnCards.length;
|
|
4412
4706
|
const before = pos > 0 ? targetColumnCards[pos - 1].order : null;
|
|
4413
4707
|
const after = pos < targetColumnCards.length ? targetColumnCards[pos].order : null;
|
|
4414
4708
|
card.order = generateKeyBetween(before, after);
|
|
4415
|
-
await
|
|
4709
|
+
await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
|
|
4416
4710
|
if (oldStatus !== newStatus) {
|
|
4417
|
-
const newPath = await moveFeatureFile(card.filePath,
|
|
4711
|
+
const newPath = await moveFeatureFile(card.filePath, boardDir, newStatus, card.attachments);
|
|
4418
4712
|
card.filePath = newPath;
|
|
4419
4713
|
}
|
|
4420
4714
|
return card;
|
|
4421
4715
|
}
|
|
4422
|
-
async deleteCard(cardId) {
|
|
4423
|
-
const card = await this.getCard(cardId);
|
|
4716
|
+
async deleteCard(cardId, boardId) {
|
|
4717
|
+
const card = await this.getCard(cardId, boardId);
|
|
4424
4718
|
if (!card)
|
|
4425
4719
|
throw new Error(`Card not found: ${cardId}`);
|
|
4426
|
-
await
|
|
4720
|
+
await fs4.unlink(card.filePath);
|
|
4427
4721
|
}
|
|
4428
|
-
async getCardsByStatus(status) {
|
|
4429
|
-
const cards = await this.listCards();
|
|
4722
|
+
async getCardsByStatus(status, boardId) {
|
|
4723
|
+
const cards = await this.listCards(void 0, boardId);
|
|
4430
4724
|
return cards.filter((c) => c.status === status);
|
|
4431
4725
|
}
|
|
4432
|
-
async getUniqueAssignees() {
|
|
4433
|
-
const cards = await this.listCards();
|
|
4726
|
+
async getUniqueAssignees(boardId) {
|
|
4727
|
+
const cards = await this.listCards(void 0, boardId);
|
|
4434
4728
|
const assignees = /* @__PURE__ */ new Set();
|
|
4435
4729
|
for (const c of cards) {
|
|
4436
4730
|
if (c.assignee)
|
|
@@ -4438,8 +4732,8 @@ var KanbanSDK = class {
|
|
|
4438
4732
|
}
|
|
4439
4733
|
return [...assignees].sort();
|
|
4440
4734
|
}
|
|
4441
|
-
async getUniqueLabels() {
|
|
4442
|
-
const cards = await this.listCards();
|
|
4735
|
+
async getUniqueLabels(boardId) {
|
|
4736
|
+
const cards = await this.listCards(void 0, boardId);
|
|
4443
4737
|
const labels = /* @__PURE__ */ new Set();
|
|
4444
4738
|
for (const c of cards) {
|
|
4445
4739
|
for (const l of c.labels)
|
|
@@ -4448,48 +4742,48 @@ var KanbanSDK = class {
|
|
|
4448
4742
|
return [...labels].sort();
|
|
4449
4743
|
}
|
|
4450
4744
|
// --- Attachment management ---
|
|
4451
|
-
async addAttachment(cardId, sourcePath) {
|
|
4452
|
-
const card = await this.getCard(cardId);
|
|
4745
|
+
async addAttachment(cardId, sourcePath, boardId) {
|
|
4746
|
+
const card = await this.getCard(cardId, boardId);
|
|
4453
4747
|
if (!card)
|
|
4454
4748
|
throw new Error(`Card not found: ${cardId}`);
|
|
4455
|
-
const fileName =
|
|
4456
|
-
const cardDir =
|
|
4457
|
-
const destPath =
|
|
4458
|
-
const sourceDir =
|
|
4749
|
+
const fileName = path5.basename(sourcePath);
|
|
4750
|
+
const cardDir = path5.dirname(card.filePath);
|
|
4751
|
+
const destPath = path5.join(cardDir, fileName);
|
|
4752
|
+
const sourceDir = path5.dirname(path5.resolve(sourcePath));
|
|
4459
4753
|
if (sourceDir !== cardDir) {
|
|
4460
|
-
await
|
|
4754
|
+
await fs4.copyFile(path5.resolve(sourcePath), destPath);
|
|
4461
4755
|
}
|
|
4462
4756
|
if (!card.attachments.includes(fileName)) {
|
|
4463
4757
|
card.attachments.push(fileName);
|
|
4464
4758
|
}
|
|
4465
4759
|
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
4466
|
-
await
|
|
4760
|
+
await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
|
|
4467
4761
|
return card;
|
|
4468
4762
|
}
|
|
4469
|
-
async removeAttachment(cardId, attachment) {
|
|
4470
|
-
const card = await this.getCard(cardId);
|
|
4763
|
+
async removeAttachment(cardId, attachment, boardId) {
|
|
4764
|
+
const card = await this.getCard(cardId, boardId);
|
|
4471
4765
|
if (!card)
|
|
4472
4766
|
throw new Error(`Card not found: ${cardId}`);
|
|
4473
4767
|
card.attachments = card.attachments.filter((a) => a !== attachment);
|
|
4474
4768
|
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
4475
|
-
await
|
|
4769
|
+
await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
|
|
4476
4770
|
return card;
|
|
4477
4771
|
}
|
|
4478
|
-
async listAttachments(cardId) {
|
|
4479
|
-
const card = await this.getCard(cardId);
|
|
4772
|
+
async listAttachments(cardId, boardId) {
|
|
4773
|
+
const card = await this.getCard(cardId, boardId);
|
|
4480
4774
|
if (!card)
|
|
4481
4775
|
throw new Error(`Card not found: ${cardId}`);
|
|
4482
4776
|
return card.attachments;
|
|
4483
4777
|
}
|
|
4484
4778
|
// --- Comment management ---
|
|
4485
|
-
async listComments(cardId) {
|
|
4486
|
-
const card = await this.getCard(cardId);
|
|
4779
|
+
async listComments(cardId, boardId) {
|
|
4780
|
+
const card = await this.getCard(cardId, boardId);
|
|
4487
4781
|
if (!card)
|
|
4488
4782
|
throw new Error(`Card not found: ${cardId}`);
|
|
4489
4783
|
return card.comments || [];
|
|
4490
4784
|
}
|
|
4491
|
-
async addComment(cardId, author, content) {
|
|
4492
|
-
const card = await this.getCard(cardId);
|
|
4785
|
+
async addComment(cardId, author, content, boardId) {
|
|
4786
|
+
const card = await this.getCard(cardId, boardId);
|
|
4493
4787
|
if (!card)
|
|
4494
4788
|
throw new Error(`Card not found: ${cardId}`);
|
|
4495
4789
|
if (!card.comments)
|
|
@@ -4506,11 +4800,11 @@ var KanbanSDK = class {
|
|
|
4506
4800
|
};
|
|
4507
4801
|
card.comments.push(comment);
|
|
4508
4802
|
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
4509
|
-
await
|
|
4803
|
+
await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
|
|
4510
4804
|
return card;
|
|
4511
4805
|
}
|
|
4512
|
-
async updateComment(cardId, commentId, content) {
|
|
4513
|
-
const card = await this.getCard(cardId);
|
|
4806
|
+
async updateComment(cardId, commentId, content, boardId) {
|
|
4807
|
+
const card = await this.getCard(cardId, boardId);
|
|
4514
4808
|
if (!card)
|
|
4515
4809
|
throw new Error(`Card not found: ${cardId}`);
|
|
4516
4810
|
const comment = (card.comments || []).find((c) => c.id === commentId);
|
|
@@ -4518,34 +4812,45 @@ var KanbanSDK = class {
|
|
|
4518
4812
|
throw new Error(`Comment not found: ${commentId}`);
|
|
4519
4813
|
comment.content = content;
|
|
4520
4814
|
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
4521
|
-
await
|
|
4815
|
+
await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
|
|
4522
4816
|
return card;
|
|
4523
4817
|
}
|
|
4524
|
-
async deleteComment(cardId, commentId) {
|
|
4525
|
-
const card = await this.getCard(cardId);
|
|
4818
|
+
async deleteComment(cardId, commentId, boardId) {
|
|
4819
|
+
const card = await this.getCard(cardId, boardId);
|
|
4526
4820
|
if (!card)
|
|
4527
4821
|
throw new Error(`Card not found: ${cardId}`);
|
|
4528
4822
|
card.comments = (card.comments || []).filter((c) => c.id !== commentId);
|
|
4529
4823
|
card.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
4530
|
-
await
|
|
4824
|
+
await fs4.writeFile(card.filePath, serializeFeature(card), "utf-8");
|
|
4531
4825
|
return card;
|
|
4532
4826
|
}
|
|
4533
|
-
// --- Column management ---
|
|
4534
|
-
listColumns() {
|
|
4535
|
-
|
|
4827
|
+
// --- Column management (board-scoped) ---
|
|
4828
|
+
listColumns(boardId) {
|
|
4829
|
+
const config = readConfig(this.workspaceRoot);
|
|
4830
|
+
const resolvedId = boardId || config.defaultBoard;
|
|
4831
|
+
const board = config.boards[resolvedId];
|
|
4832
|
+
return board?.columns || [];
|
|
4536
4833
|
}
|
|
4537
|
-
addColumn(column) {
|
|
4834
|
+
addColumn(column, boardId) {
|
|
4538
4835
|
const config = readConfig(this.workspaceRoot);
|
|
4539
|
-
|
|
4836
|
+
const resolvedId = boardId || config.defaultBoard;
|
|
4837
|
+
const board = config.boards[resolvedId];
|
|
4838
|
+
if (!board)
|
|
4839
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
4840
|
+
if (board.columns.some((c) => c.id === column.id)) {
|
|
4540
4841
|
throw new Error(`Column already exists: ${column.id}`);
|
|
4541
4842
|
}
|
|
4542
|
-
|
|
4843
|
+
board.columns.push(column);
|
|
4543
4844
|
writeConfig(this.workspaceRoot, config);
|
|
4544
|
-
return
|
|
4845
|
+
return board.columns;
|
|
4545
4846
|
}
|
|
4546
|
-
updateColumn(columnId, updates) {
|
|
4847
|
+
updateColumn(columnId, updates, boardId) {
|
|
4547
4848
|
const config = readConfig(this.workspaceRoot);
|
|
4548
|
-
const
|
|
4849
|
+
const resolvedId = boardId || config.defaultBoard;
|
|
4850
|
+
const board = config.boards[resolvedId];
|
|
4851
|
+
if (!board)
|
|
4852
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
4853
|
+
const col = board.columns.find((c) => c.id === columnId);
|
|
4549
4854
|
if (!col)
|
|
4550
4855
|
throw new Error(`Column not found: ${columnId}`);
|
|
4551
4856
|
if (updates.name !== void 0)
|
|
@@ -4553,37 +4858,45 @@ var KanbanSDK = class {
|
|
|
4553
4858
|
if (updates.color !== void 0)
|
|
4554
4859
|
col.color = updates.color;
|
|
4555
4860
|
writeConfig(this.workspaceRoot, config);
|
|
4556
|
-
return
|
|
4861
|
+
return board.columns;
|
|
4557
4862
|
}
|
|
4558
|
-
async removeColumn(columnId) {
|
|
4863
|
+
async removeColumn(columnId, boardId) {
|
|
4559
4864
|
const config = readConfig(this.workspaceRoot);
|
|
4560
|
-
const
|
|
4865
|
+
const resolvedId = boardId || config.defaultBoard;
|
|
4866
|
+
const board = config.boards[resolvedId];
|
|
4867
|
+
if (!board)
|
|
4868
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
4869
|
+
const idx = board.columns.findIndex((c) => c.id === columnId);
|
|
4561
4870
|
if (idx === -1)
|
|
4562
4871
|
throw new Error(`Column not found: ${columnId}`);
|
|
4563
|
-
const cards = await this.listCards();
|
|
4872
|
+
const cards = await this.listCards(void 0, resolvedId);
|
|
4564
4873
|
const cardsInColumn = cards.filter((c) => c.status === columnId);
|
|
4565
4874
|
if (cardsInColumn.length > 0) {
|
|
4566
4875
|
throw new Error(`Cannot remove column "${columnId}": ${cardsInColumn.length} card(s) still in this column`);
|
|
4567
4876
|
}
|
|
4568
|
-
|
|
4877
|
+
board.columns.splice(idx, 1);
|
|
4569
4878
|
writeConfig(this.workspaceRoot, config);
|
|
4570
|
-
return
|
|
4879
|
+
return board.columns;
|
|
4571
4880
|
}
|
|
4572
|
-
reorderColumns(columnIds) {
|
|
4881
|
+
reorderColumns(columnIds, boardId) {
|
|
4573
4882
|
const config = readConfig(this.workspaceRoot);
|
|
4574
|
-
const
|
|
4883
|
+
const resolvedId = boardId || config.defaultBoard;
|
|
4884
|
+
const board = config.boards[resolvedId];
|
|
4885
|
+
if (!board)
|
|
4886
|
+
throw new Error(`Board not found: ${resolvedId}`);
|
|
4887
|
+
const colMap = new Map(board.columns.map((c) => [c.id, c]));
|
|
4575
4888
|
for (const id of columnIds) {
|
|
4576
4889
|
if (!colMap.has(id))
|
|
4577
4890
|
throw new Error(`Column not found: ${id}`);
|
|
4578
4891
|
}
|
|
4579
|
-
if (columnIds.length !==
|
|
4892
|
+
if (columnIds.length !== board.columns.length) {
|
|
4580
4893
|
throw new Error("Must include all column IDs when reordering");
|
|
4581
4894
|
}
|
|
4582
|
-
|
|
4895
|
+
board.columns = columnIds.map((id) => colMap.get(id));
|
|
4583
4896
|
writeConfig(this.workspaceRoot, config);
|
|
4584
|
-
return
|
|
4897
|
+
return board.columns;
|
|
4585
4898
|
}
|
|
4586
|
-
// --- Settings management ---
|
|
4899
|
+
// --- Settings management (global) ---
|
|
4587
4900
|
getSettings() {
|
|
4588
4901
|
return configToSettings(readConfig(this.workspaceRoot));
|
|
4589
4902
|
}
|
|
@@ -4593,19 +4906,19 @@ var KanbanSDK = class {
|
|
|
4593
4906
|
}
|
|
4594
4907
|
// --- Private helpers ---
|
|
4595
4908
|
async _readMdFiles(dir) {
|
|
4596
|
-
const entries = await
|
|
4597
|
-
return entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) =>
|
|
4909
|
+
const entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
4910
|
+
return entries.filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => path5.join(dir, e.name));
|
|
4598
4911
|
}
|
|
4599
4912
|
async _loadCard(filePath) {
|
|
4600
|
-
const content = await
|
|
4913
|
+
const content = await fs4.readFile(filePath, "utf-8");
|
|
4601
4914
|
return parseFeatureFile(content, filePath);
|
|
4602
4915
|
}
|
|
4603
4916
|
};
|
|
4604
4917
|
|
|
4605
4918
|
// src/standalone/server.ts
|
|
4606
4919
|
var http2 = __toESM(require("http"));
|
|
4607
|
-
var
|
|
4608
|
-
var
|
|
4920
|
+
var fs6 = __toESM(require("fs"));
|
|
4921
|
+
var path7 = __toESM(require("path"));
|
|
4609
4922
|
|
|
4610
4923
|
// node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
|
|
4611
4924
|
var import_stream = __toESM(require_stream(), 1);
|
|
@@ -4690,7 +5003,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
4690
5003
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
4691
5004
|
const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
|
|
4692
5005
|
if (wantBigintFsStats) {
|
|
4693
|
-
this._stat = (
|
|
5006
|
+
this._stat = (path11) => statMethod(path11, { bigint: true });
|
|
4694
5007
|
} else {
|
|
4695
5008
|
this._stat = statMethod;
|
|
4696
5009
|
}
|
|
@@ -4715,8 +5028,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
4715
5028
|
const par = this.parent;
|
|
4716
5029
|
const fil = par && par.files;
|
|
4717
5030
|
if (fil && fil.length > 0) {
|
|
4718
|
-
const { path:
|
|
4719
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
5031
|
+
const { path: path11, depth } = par;
|
|
5032
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path11));
|
|
4720
5033
|
const awaited = await Promise.all(slice);
|
|
4721
5034
|
for (const entry of awaited) {
|
|
4722
5035
|
if (!entry)
|
|
@@ -4756,20 +5069,20 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
4756
5069
|
this.reading = false;
|
|
4757
5070
|
}
|
|
4758
5071
|
}
|
|
4759
|
-
async _exploreDir(
|
|
5072
|
+
async _exploreDir(path11, depth) {
|
|
4760
5073
|
let files;
|
|
4761
5074
|
try {
|
|
4762
|
-
files = await (0, import_promises.readdir)(
|
|
5075
|
+
files = await (0, import_promises.readdir)(path11, this._rdOptions);
|
|
4763
5076
|
} catch (error) {
|
|
4764
5077
|
this._onError(error);
|
|
4765
5078
|
}
|
|
4766
|
-
return { files, depth, path:
|
|
5079
|
+
return { files, depth, path: path11 };
|
|
4767
5080
|
}
|
|
4768
|
-
async _formatEntry(dirent,
|
|
5081
|
+
async _formatEntry(dirent, path11) {
|
|
4769
5082
|
let entry;
|
|
4770
5083
|
const basename6 = this._isDirent ? dirent.name : dirent;
|
|
4771
5084
|
try {
|
|
4772
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(
|
|
5085
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path11, basename6));
|
|
4773
5086
|
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename6 };
|
|
4774
5087
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
4775
5088
|
} catch (err) {
|
|
@@ -5169,16 +5482,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
5169
5482
|
};
|
|
5170
5483
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
5171
5484
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
5172
|
-
function createFsWatchInstance(
|
|
5485
|
+
function createFsWatchInstance(path11, options, listener, errHandler, emitRaw) {
|
|
5173
5486
|
const handleEvent = (rawEvent, evPath) => {
|
|
5174
|
-
listener(
|
|
5175
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
5176
|
-
if (evPath &&
|
|
5177
|
-
fsWatchBroadcast(sysPath.resolve(
|
|
5487
|
+
listener(path11);
|
|
5488
|
+
emitRaw(rawEvent, evPath, { watchedPath: path11 });
|
|
5489
|
+
if (evPath && path11 !== evPath) {
|
|
5490
|
+
fsWatchBroadcast(sysPath.resolve(path11, evPath), KEY_LISTENERS, sysPath.join(path11, evPath));
|
|
5178
5491
|
}
|
|
5179
5492
|
};
|
|
5180
5493
|
try {
|
|
5181
|
-
return (0, import_fs.watch)(
|
|
5494
|
+
return (0, import_fs.watch)(path11, {
|
|
5182
5495
|
persistent: options.persistent
|
|
5183
5496
|
}, handleEvent);
|
|
5184
5497
|
} catch (error) {
|
|
@@ -5194,12 +5507,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
5194
5507
|
listener(val1, val2, val3);
|
|
5195
5508
|
});
|
|
5196
5509
|
};
|
|
5197
|
-
var setFsWatchListener = (
|
|
5510
|
+
var setFsWatchListener = (path11, fullPath, options, handlers) => {
|
|
5198
5511
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
5199
5512
|
let cont = FsWatchInstances.get(fullPath);
|
|
5200
5513
|
let watcher;
|
|
5201
5514
|
if (!options.persistent) {
|
|
5202
|
-
watcher = createFsWatchInstance(
|
|
5515
|
+
watcher = createFsWatchInstance(path11, options, listener, errHandler, rawEmitter);
|
|
5203
5516
|
if (!watcher)
|
|
5204
5517
|
return;
|
|
5205
5518
|
return watcher.close.bind(watcher);
|
|
@@ -5210,7 +5523,7 @@ var setFsWatchListener = (path10, fullPath, options, handlers) => {
|
|
|
5210
5523
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
5211
5524
|
} else {
|
|
5212
5525
|
watcher = createFsWatchInstance(
|
|
5213
|
-
|
|
5526
|
+
path11,
|
|
5214
5527
|
options,
|
|
5215
5528
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
5216
5529
|
errHandler,
|
|
@@ -5225,7 +5538,7 @@ var setFsWatchListener = (path10, fullPath, options, handlers) => {
|
|
|
5225
5538
|
cont.watcherUnusable = true;
|
|
5226
5539
|
if (isWindows && error.code === "EPERM") {
|
|
5227
5540
|
try {
|
|
5228
|
-
const fd = await (0, import_promises2.open)(
|
|
5541
|
+
const fd = await (0, import_promises2.open)(path11, "r");
|
|
5229
5542
|
await fd.close();
|
|
5230
5543
|
broadcastErr(error);
|
|
5231
5544
|
} catch (err) {
|
|
@@ -5256,7 +5569,7 @@ var setFsWatchListener = (path10, fullPath, options, handlers) => {
|
|
|
5256
5569
|
};
|
|
5257
5570
|
};
|
|
5258
5571
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
5259
|
-
var setFsWatchFileListener = (
|
|
5572
|
+
var setFsWatchFileListener = (path11, fullPath, options, handlers) => {
|
|
5260
5573
|
const { listener, rawEmitter } = handlers;
|
|
5261
5574
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
5262
5575
|
const copts = cont && cont.options;
|
|
@@ -5278,7 +5591,7 @@ var setFsWatchFileListener = (path10, fullPath, options, handlers) => {
|
|
|
5278
5591
|
});
|
|
5279
5592
|
const currmtime = curr.mtimeMs;
|
|
5280
5593
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
5281
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
5594
|
+
foreach(cont.listeners, (listener2) => listener2(path11, curr));
|
|
5282
5595
|
}
|
|
5283
5596
|
})
|
|
5284
5597
|
};
|
|
@@ -5306,13 +5619,13 @@ var NodeFsHandler = class {
|
|
|
5306
5619
|
* @param listener on fs change
|
|
5307
5620
|
* @returns closer for the watcher instance
|
|
5308
5621
|
*/
|
|
5309
|
-
_watchWithNodeFs(
|
|
5622
|
+
_watchWithNodeFs(path11, listener) {
|
|
5310
5623
|
const opts = this.fsw.options;
|
|
5311
|
-
const directory = sysPath.dirname(
|
|
5312
|
-
const basename6 = sysPath.basename(
|
|
5624
|
+
const directory = sysPath.dirname(path11);
|
|
5625
|
+
const basename6 = sysPath.basename(path11);
|
|
5313
5626
|
const parent = this.fsw._getWatchedDir(directory);
|
|
5314
5627
|
parent.add(basename6);
|
|
5315
|
-
const absolutePath = sysPath.resolve(
|
|
5628
|
+
const absolutePath = sysPath.resolve(path11);
|
|
5316
5629
|
const options = {
|
|
5317
5630
|
persistent: opts.persistent
|
|
5318
5631
|
};
|
|
@@ -5322,12 +5635,12 @@ var NodeFsHandler = class {
|
|
|
5322
5635
|
if (opts.usePolling) {
|
|
5323
5636
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
5324
5637
|
options.interval = enableBin && isBinaryPath(basename6) ? opts.binaryInterval : opts.interval;
|
|
5325
|
-
closer = setFsWatchFileListener(
|
|
5638
|
+
closer = setFsWatchFileListener(path11, absolutePath, options, {
|
|
5326
5639
|
listener,
|
|
5327
5640
|
rawEmitter: this.fsw._emitRaw
|
|
5328
5641
|
});
|
|
5329
5642
|
} else {
|
|
5330
|
-
closer = setFsWatchListener(
|
|
5643
|
+
closer = setFsWatchListener(path11, absolutePath, options, {
|
|
5331
5644
|
listener,
|
|
5332
5645
|
errHandler: this._boundHandleError,
|
|
5333
5646
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -5349,7 +5662,7 @@ var NodeFsHandler = class {
|
|
|
5349
5662
|
let prevStats = stats;
|
|
5350
5663
|
if (parent.has(basename6))
|
|
5351
5664
|
return;
|
|
5352
|
-
const listener = async (
|
|
5665
|
+
const listener = async (path11, newStats) => {
|
|
5353
5666
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
5354
5667
|
return;
|
|
5355
5668
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -5363,11 +5676,11 @@ var NodeFsHandler = class {
|
|
|
5363
5676
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
5364
5677
|
}
|
|
5365
5678
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
5366
|
-
this.fsw._closeFile(
|
|
5679
|
+
this.fsw._closeFile(path11);
|
|
5367
5680
|
prevStats = newStats2;
|
|
5368
5681
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
5369
5682
|
if (closer2)
|
|
5370
|
-
this.fsw._addPathCloser(
|
|
5683
|
+
this.fsw._addPathCloser(path11, closer2);
|
|
5371
5684
|
} else {
|
|
5372
5685
|
prevStats = newStats2;
|
|
5373
5686
|
}
|
|
@@ -5399,7 +5712,7 @@ var NodeFsHandler = class {
|
|
|
5399
5712
|
* @param item basename of this item
|
|
5400
5713
|
* @returns true if no more processing is needed for this entry.
|
|
5401
5714
|
*/
|
|
5402
|
-
async _handleSymlink(entry, directory,
|
|
5715
|
+
async _handleSymlink(entry, directory, path11, item) {
|
|
5403
5716
|
if (this.fsw.closed) {
|
|
5404
5717
|
return;
|
|
5405
5718
|
}
|
|
@@ -5409,7 +5722,7 @@ var NodeFsHandler = class {
|
|
|
5409
5722
|
this.fsw._incrReadyCount();
|
|
5410
5723
|
let linkPath;
|
|
5411
5724
|
try {
|
|
5412
|
-
linkPath = await (0, import_promises2.realpath)(
|
|
5725
|
+
linkPath = await (0, import_promises2.realpath)(path11);
|
|
5413
5726
|
} catch (e) {
|
|
5414
5727
|
this.fsw._emitReady();
|
|
5415
5728
|
return true;
|
|
@@ -5419,12 +5732,12 @@ var NodeFsHandler = class {
|
|
|
5419
5732
|
if (dir.has(item)) {
|
|
5420
5733
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
5421
5734
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
5422
|
-
this.fsw._emit(EV.CHANGE,
|
|
5735
|
+
this.fsw._emit(EV.CHANGE, path11, entry.stats);
|
|
5423
5736
|
}
|
|
5424
5737
|
} else {
|
|
5425
5738
|
dir.add(item);
|
|
5426
5739
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
5427
|
-
this.fsw._emit(EV.ADD,
|
|
5740
|
+
this.fsw._emit(EV.ADD, path11, entry.stats);
|
|
5428
5741
|
}
|
|
5429
5742
|
this.fsw._emitReady();
|
|
5430
5743
|
return true;
|
|
@@ -5453,9 +5766,9 @@ var NodeFsHandler = class {
|
|
|
5453
5766
|
return;
|
|
5454
5767
|
}
|
|
5455
5768
|
const item = entry.path;
|
|
5456
|
-
let
|
|
5769
|
+
let path11 = sysPath.join(directory, item);
|
|
5457
5770
|
current.add(item);
|
|
5458
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
5771
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path11, item)) {
|
|
5459
5772
|
return;
|
|
5460
5773
|
}
|
|
5461
5774
|
if (this.fsw.closed) {
|
|
@@ -5464,8 +5777,8 @@ var NodeFsHandler = class {
|
|
|
5464
5777
|
}
|
|
5465
5778
|
if (item === target || !target && !previous.has(item)) {
|
|
5466
5779
|
this.fsw._incrReadyCount();
|
|
5467
|
-
|
|
5468
|
-
this._addToNodeFs(
|
|
5780
|
+
path11 = sysPath.join(dir, sysPath.relative(dir, path11));
|
|
5781
|
+
this._addToNodeFs(path11, initialAdd, wh, depth + 1);
|
|
5469
5782
|
}
|
|
5470
5783
|
}).on(EV.ERROR, this._boundHandleError);
|
|
5471
5784
|
return new Promise((resolve6, reject) => {
|
|
@@ -5534,13 +5847,13 @@ var NodeFsHandler = class {
|
|
|
5534
5847
|
* @param depth Child path actually targeted for watch
|
|
5535
5848
|
* @param target Child path actually targeted for watch
|
|
5536
5849
|
*/
|
|
5537
|
-
async _addToNodeFs(
|
|
5850
|
+
async _addToNodeFs(path11, initialAdd, priorWh, depth, target) {
|
|
5538
5851
|
const ready = this.fsw._emitReady;
|
|
5539
|
-
if (this.fsw._isIgnored(
|
|
5852
|
+
if (this.fsw._isIgnored(path11) || this.fsw.closed) {
|
|
5540
5853
|
ready();
|
|
5541
5854
|
return false;
|
|
5542
5855
|
}
|
|
5543
|
-
const wh = this.fsw._getWatchHelpers(
|
|
5856
|
+
const wh = this.fsw._getWatchHelpers(path11);
|
|
5544
5857
|
if (priorWh) {
|
|
5545
5858
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
5546
5859
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -5556,8 +5869,8 @@ var NodeFsHandler = class {
|
|
|
5556
5869
|
const follow = this.fsw.options.followSymlinks;
|
|
5557
5870
|
let closer;
|
|
5558
5871
|
if (stats.isDirectory()) {
|
|
5559
|
-
const absPath = sysPath.resolve(
|
|
5560
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
5872
|
+
const absPath = sysPath.resolve(path11);
|
|
5873
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path11) : path11;
|
|
5561
5874
|
if (this.fsw.closed)
|
|
5562
5875
|
return;
|
|
5563
5876
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -5567,29 +5880,29 @@ var NodeFsHandler = class {
|
|
|
5567
5880
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
5568
5881
|
}
|
|
5569
5882
|
} else if (stats.isSymbolicLink()) {
|
|
5570
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
5883
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path11) : path11;
|
|
5571
5884
|
if (this.fsw.closed)
|
|
5572
5885
|
return;
|
|
5573
5886
|
const parent = sysPath.dirname(wh.watchPath);
|
|
5574
5887
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
5575
5888
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
5576
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
5889
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path11, wh, targetPath);
|
|
5577
5890
|
if (this.fsw.closed)
|
|
5578
5891
|
return;
|
|
5579
5892
|
if (targetPath !== void 0) {
|
|
5580
|
-
this.fsw._symlinkPaths.set(sysPath.resolve(
|
|
5893
|
+
this.fsw._symlinkPaths.set(sysPath.resolve(path11), targetPath);
|
|
5581
5894
|
}
|
|
5582
5895
|
} else {
|
|
5583
5896
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
5584
5897
|
}
|
|
5585
5898
|
ready();
|
|
5586
5899
|
if (closer)
|
|
5587
|
-
this.fsw._addPathCloser(
|
|
5900
|
+
this.fsw._addPathCloser(path11, closer);
|
|
5588
5901
|
return false;
|
|
5589
5902
|
} catch (error) {
|
|
5590
5903
|
if (this.fsw._handleError(error)) {
|
|
5591
5904
|
ready();
|
|
5592
|
-
return
|
|
5905
|
+
return path11;
|
|
5593
5906
|
}
|
|
5594
5907
|
}
|
|
5595
5908
|
}
|
|
@@ -5632,26 +5945,26 @@ function createPattern(matcher) {
|
|
|
5632
5945
|
}
|
|
5633
5946
|
return () => false;
|
|
5634
5947
|
}
|
|
5635
|
-
function normalizePath(
|
|
5636
|
-
if (typeof
|
|
5948
|
+
function normalizePath(path11) {
|
|
5949
|
+
if (typeof path11 !== "string")
|
|
5637
5950
|
throw new Error("string expected");
|
|
5638
|
-
|
|
5639
|
-
|
|
5951
|
+
path11 = sysPath2.normalize(path11);
|
|
5952
|
+
path11 = path11.replace(/\\/g, "/");
|
|
5640
5953
|
let prepend = false;
|
|
5641
|
-
if (
|
|
5954
|
+
if (path11.startsWith("//"))
|
|
5642
5955
|
prepend = true;
|
|
5643
5956
|
const DOUBLE_SLASH_RE2 = /\/\//;
|
|
5644
|
-
while (
|
|
5645
|
-
|
|
5957
|
+
while (path11.match(DOUBLE_SLASH_RE2))
|
|
5958
|
+
path11 = path11.replace(DOUBLE_SLASH_RE2, "/");
|
|
5646
5959
|
if (prepend)
|
|
5647
|
-
|
|
5648
|
-
return
|
|
5960
|
+
path11 = "/" + path11;
|
|
5961
|
+
return path11;
|
|
5649
5962
|
}
|
|
5650
5963
|
function matchPatterns(patterns, testString, stats) {
|
|
5651
|
-
const
|
|
5964
|
+
const path11 = normalizePath(testString);
|
|
5652
5965
|
for (let index = 0; index < patterns.length; index++) {
|
|
5653
5966
|
const pattern = patterns[index];
|
|
5654
|
-
if (pattern(
|
|
5967
|
+
if (pattern(path11, stats)) {
|
|
5655
5968
|
return true;
|
|
5656
5969
|
}
|
|
5657
5970
|
}
|
|
@@ -5691,19 +6004,19 @@ var toUnix = (string) => {
|
|
|
5691
6004
|
}
|
|
5692
6005
|
return str;
|
|
5693
6006
|
};
|
|
5694
|
-
var normalizePathToUnix = (
|
|
5695
|
-
var normalizeIgnored = (cwd = "") => (
|
|
5696
|
-
if (typeof
|
|
5697
|
-
return normalizePathToUnix(sysPath2.isAbsolute(
|
|
6007
|
+
var normalizePathToUnix = (path11) => toUnix(sysPath2.normalize(toUnix(path11)));
|
|
6008
|
+
var normalizeIgnored = (cwd = "") => (path11) => {
|
|
6009
|
+
if (typeof path11 === "string") {
|
|
6010
|
+
return normalizePathToUnix(sysPath2.isAbsolute(path11) ? path11 : sysPath2.join(cwd, path11));
|
|
5698
6011
|
} else {
|
|
5699
|
-
return
|
|
6012
|
+
return path11;
|
|
5700
6013
|
}
|
|
5701
6014
|
};
|
|
5702
|
-
var getAbsolutePath = (
|
|
5703
|
-
if (sysPath2.isAbsolute(
|
|
5704
|
-
return
|
|
6015
|
+
var getAbsolutePath = (path11, cwd) => {
|
|
6016
|
+
if (sysPath2.isAbsolute(path11)) {
|
|
6017
|
+
return path11;
|
|
5705
6018
|
}
|
|
5706
|
-
return sysPath2.join(cwd,
|
|
6019
|
+
return sysPath2.join(cwd, path11);
|
|
5707
6020
|
};
|
|
5708
6021
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
5709
6022
|
var DirEntry = class {
|
|
@@ -5758,10 +6071,10 @@ var DirEntry = class {
|
|
|
5758
6071
|
var STAT_METHOD_F = "stat";
|
|
5759
6072
|
var STAT_METHOD_L = "lstat";
|
|
5760
6073
|
var WatchHelper = class {
|
|
5761
|
-
constructor(
|
|
6074
|
+
constructor(path11, follow, fsw) {
|
|
5762
6075
|
this.fsw = fsw;
|
|
5763
|
-
const watchPath =
|
|
5764
|
-
this.path =
|
|
6076
|
+
const watchPath = path11;
|
|
6077
|
+
this.path = path11 = path11.replace(REPLACER_RE, "");
|
|
5765
6078
|
this.watchPath = watchPath;
|
|
5766
6079
|
this.fullWatchPath = sysPath2.resolve(watchPath);
|
|
5767
6080
|
this.dirParts = [];
|
|
@@ -5883,20 +6196,20 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
5883
6196
|
this._closePromise = void 0;
|
|
5884
6197
|
let paths = unifyPaths(paths_);
|
|
5885
6198
|
if (cwd) {
|
|
5886
|
-
paths = paths.map((
|
|
5887
|
-
const absPath = getAbsolutePath(
|
|
6199
|
+
paths = paths.map((path11) => {
|
|
6200
|
+
const absPath = getAbsolutePath(path11, cwd);
|
|
5888
6201
|
return absPath;
|
|
5889
6202
|
});
|
|
5890
6203
|
}
|
|
5891
|
-
paths.forEach((
|
|
5892
|
-
this._removeIgnoredPath(
|
|
6204
|
+
paths.forEach((path11) => {
|
|
6205
|
+
this._removeIgnoredPath(path11);
|
|
5893
6206
|
});
|
|
5894
6207
|
this._userIgnored = void 0;
|
|
5895
6208
|
if (!this._readyCount)
|
|
5896
6209
|
this._readyCount = 0;
|
|
5897
6210
|
this._readyCount += paths.length;
|
|
5898
|
-
Promise.all(paths.map(async (
|
|
5899
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
6211
|
+
Promise.all(paths.map(async (path11) => {
|
|
6212
|
+
const res = await this._nodeFsHandler._addToNodeFs(path11, !_internal, void 0, 0, _origAdd);
|
|
5900
6213
|
if (res)
|
|
5901
6214
|
this._emitReady();
|
|
5902
6215
|
return res;
|
|
@@ -5918,17 +6231,17 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
5918
6231
|
return this;
|
|
5919
6232
|
const paths = unifyPaths(paths_);
|
|
5920
6233
|
const { cwd } = this.options;
|
|
5921
|
-
paths.forEach((
|
|
5922
|
-
if (!sysPath2.isAbsolute(
|
|
6234
|
+
paths.forEach((path11) => {
|
|
6235
|
+
if (!sysPath2.isAbsolute(path11) && !this._closers.has(path11)) {
|
|
5923
6236
|
if (cwd)
|
|
5924
|
-
|
|
5925
|
-
|
|
6237
|
+
path11 = sysPath2.join(cwd, path11);
|
|
6238
|
+
path11 = sysPath2.resolve(path11);
|
|
5926
6239
|
}
|
|
5927
|
-
this._closePath(
|
|
5928
|
-
this._addIgnoredPath(
|
|
5929
|
-
if (this._watched.has(
|
|
6240
|
+
this._closePath(path11);
|
|
6241
|
+
this._addIgnoredPath(path11);
|
|
6242
|
+
if (this._watched.has(path11)) {
|
|
5930
6243
|
this._addIgnoredPath({
|
|
5931
|
-
path:
|
|
6244
|
+
path: path11,
|
|
5932
6245
|
recursive: true
|
|
5933
6246
|
});
|
|
5934
6247
|
}
|
|
@@ -5992,38 +6305,38 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
5992
6305
|
* @param stats arguments to be passed with event
|
|
5993
6306
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
5994
6307
|
*/
|
|
5995
|
-
async _emit(event,
|
|
6308
|
+
async _emit(event, path11, stats) {
|
|
5996
6309
|
if (this.closed)
|
|
5997
6310
|
return;
|
|
5998
6311
|
const opts = this.options;
|
|
5999
6312
|
if (isWindows)
|
|
6000
|
-
|
|
6313
|
+
path11 = sysPath2.normalize(path11);
|
|
6001
6314
|
if (opts.cwd)
|
|
6002
|
-
|
|
6003
|
-
const args = [
|
|
6315
|
+
path11 = sysPath2.relative(opts.cwd, path11);
|
|
6316
|
+
const args = [path11];
|
|
6004
6317
|
if (stats != null)
|
|
6005
6318
|
args.push(stats);
|
|
6006
6319
|
const awf = opts.awaitWriteFinish;
|
|
6007
6320
|
let pw;
|
|
6008
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
6321
|
+
if (awf && (pw = this._pendingWrites.get(path11))) {
|
|
6009
6322
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
6010
6323
|
return this;
|
|
6011
6324
|
}
|
|
6012
6325
|
if (opts.atomic) {
|
|
6013
6326
|
if (event === EVENTS.UNLINK) {
|
|
6014
|
-
this._pendingUnlinks.set(
|
|
6327
|
+
this._pendingUnlinks.set(path11, [event, ...args]);
|
|
6015
6328
|
setTimeout(() => {
|
|
6016
|
-
this._pendingUnlinks.forEach((entry,
|
|
6329
|
+
this._pendingUnlinks.forEach((entry, path12) => {
|
|
6017
6330
|
this.emit(...entry);
|
|
6018
6331
|
this.emit(EVENTS.ALL, ...entry);
|
|
6019
|
-
this._pendingUnlinks.delete(
|
|
6332
|
+
this._pendingUnlinks.delete(path12);
|
|
6020
6333
|
});
|
|
6021
6334
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
6022
6335
|
return this;
|
|
6023
6336
|
}
|
|
6024
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
6337
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path11)) {
|
|
6025
6338
|
event = EVENTS.CHANGE;
|
|
6026
|
-
this._pendingUnlinks.delete(
|
|
6339
|
+
this._pendingUnlinks.delete(path11);
|
|
6027
6340
|
}
|
|
6028
6341
|
}
|
|
6029
6342
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -6041,16 +6354,16 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
6041
6354
|
this.emitWithAll(event, args);
|
|
6042
6355
|
}
|
|
6043
6356
|
};
|
|
6044
|
-
this._awaitWriteFinish(
|
|
6357
|
+
this._awaitWriteFinish(path11, awf.stabilityThreshold, event, awfEmit);
|
|
6045
6358
|
return this;
|
|
6046
6359
|
}
|
|
6047
6360
|
if (event === EVENTS.CHANGE) {
|
|
6048
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
6361
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path11, 50);
|
|
6049
6362
|
if (isThrottled)
|
|
6050
6363
|
return this;
|
|
6051
6364
|
}
|
|
6052
6365
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
6053
|
-
const fullPath = opts.cwd ? sysPath2.join(opts.cwd,
|
|
6366
|
+
const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path11) : path11;
|
|
6054
6367
|
let stats2;
|
|
6055
6368
|
try {
|
|
6056
6369
|
stats2 = await (0, import_promises3.stat)(fullPath);
|
|
@@ -6081,23 +6394,23 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
6081
6394
|
* @param timeout duration of time to suppress duplicate actions
|
|
6082
6395
|
* @returns tracking object or false if action should be suppressed
|
|
6083
6396
|
*/
|
|
6084
|
-
_throttle(actionType,
|
|
6397
|
+
_throttle(actionType, path11, timeout) {
|
|
6085
6398
|
if (!this._throttled.has(actionType)) {
|
|
6086
6399
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
6087
6400
|
}
|
|
6088
6401
|
const action = this._throttled.get(actionType);
|
|
6089
6402
|
if (!action)
|
|
6090
6403
|
throw new Error("invalid throttle");
|
|
6091
|
-
const actionPath = action.get(
|
|
6404
|
+
const actionPath = action.get(path11);
|
|
6092
6405
|
if (actionPath) {
|
|
6093
6406
|
actionPath.count++;
|
|
6094
6407
|
return false;
|
|
6095
6408
|
}
|
|
6096
6409
|
let timeoutObject;
|
|
6097
6410
|
const clear = () => {
|
|
6098
|
-
const item = action.get(
|
|
6411
|
+
const item = action.get(path11);
|
|
6099
6412
|
const count = item ? item.count : 0;
|
|
6100
|
-
action.delete(
|
|
6413
|
+
action.delete(path11);
|
|
6101
6414
|
clearTimeout(timeoutObject);
|
|
6102
6415
|
if (item)
|
|
6103
6416
|
clearTimeout(item.timeoutObject);
|
|
@@ -6105,7 +6418,7 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
6105
6418
|
};
|
|
6106
6419
|
timeoutObject = setTimeout(clear, timeout);
|
|
6107
6420
|
const thr = { timeoutObject, clear, count: 0 };
|
|
6108
|
-
action.set(
|
|
6421
|
+
action.set(path11, thr);
|
|
6109
6422
|
return thr;
|
|
6110
6423
|
}
|
|
6111
6424
|
_incrReadyCount() {
|
|
@@ -6119,44 +6432,44 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
6119
6432
|
* @param event
|
|
6120
6433
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
6121
6434
|
*/
|
|
6122
|
-
_awaitWriteFinish(
|
|
6435
|
+
_awaitWriteFinish(path11, threshold, event, awfEmit) {
|
|
6123
6436
|
const awf = this.options.awaitWriteFinish;
|
|
6124
6437
|
if (typeof awf !== "object")
|
|
6125
6438
|
return;
|
|
6126
6439
|
const pollInterval = awf.pollInterval;
|
|
6127
6440
|
let timeoutHandler;
|
|
6128
|
-
let fullPath =
|
|
6129
|
-
if (this.options.cwd && !sysPath2.isAbsolute(
|
|
6130
|
-
fullPath = sysPath2.join(this.options.cwd,
|
|
6441
|
+
let fullPath = path11;
|
|
6442
|
+
if (this.options.cwd && !sysPath2.isAbsolute(path11)) {
|
|
6443
|
+
fullPath = sysPath2.join(this.options.cwd, path11);
|
|
6131
6444
|
}
|
|
6132
6445
|
const now = /* @__PURE__ */ new Date();
|
|
6133
6446
|
const writes = this._pendingWrites;
|
|
6134
6447
|
function awaitWriteFinishFn(prevStat) {
|
|
6135
6448
|
(0, import_fs2.stat)(fullPath, (err, curStat) => {
|
|
6136
|
-
if (err || !writes.has(
|
|
6449
|
+
if (err || !writes.has(path11)) {
|
|
6137
6450
|
if (err && err.code !== "ENOENT")
|
|
6138
6451
|
awfEmit(err);
|
|
6139
6452
|
return;
|
|
6140
6453
|
}
|
|
6141
6454
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
6142
6455
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
6143
|
-
writes.get(
|
|
6456
|
+
writes.get(path11).lastChange = now2;
|
|
6144
6457
|
}
|
|
6145
|
-
const pw = writes.get(
|
|
6458
|
+
const pw = writes.get(path11);
|
|
6146
6459
|
const df = now2 - pw.lastChange;
|
|
6147
6460
|
if (df >= threshold) {
|
|
6148
|
-
writes.delete(
|
|
6461
|
+
writes.delete(path11);
|
|
6149
6462
|
awfEmit(void 0, curStat);
|
|
6150
6463
|
} else {
|
|
6151
6464
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
6152
6465
|
}
|
|
6153
6466
|
});
|
|
6154
6467
|
}
|
|
6155
|
-
if (!writes.has(
|
|
6156
|
-
writes.set(
|
|
6468
|
+
if (!writes.has(path11)) {
|
|
6469
|
+
writes.set(path11, {
|
|
6157
6470
|
lastChange: now,
|
|
6158
6471
|
cancelWait: () => {
|
|
6159
|
-
writes.delete(
|
|
6472
|
+
writes.delete(path11);
|
|
6160
6473
|
clearTimeout(timeoutHandler);
|
|
6161
6474
|
return event;
|
|
6162
6475
|
}
|
|
@@ -6167,8 +6480,8 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
6167
6480
|
/**
|
|
6168
6481
|
* Determines whether user has asked to ignore this path.
|
|
6169
6482
|
*/
|
|
6170
|
-
_isIgnored(
|
|
6171
|
-
if (this.options.atomic && DOT_RE.test(
|
|
6483
|
+
_isIgnored(path11, stats) {
|
|
6484
|
+
if (this.options.atomic && DOT_RE.test(path11))
|
|
6172
6485
|
return true;
|
|
6173
6486
|
if (!this._userIgnored) {
|
|
6174
6487
|
const { cwd } = this.options;
|
|
@@ -6178,17 +6491,17 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
6178
6491
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
6179
6492
|
this._userIgnored = anymatch(list, void 0);
|
|
6180
6493
|
}
|
|
6181
|
-
return this._userIgnored(
|
|
6494
|
+
return this._userIgnored(path11, stats);
|
|
6182
6495
|
}
|
|
6183
|
-
_isntIgnored(
|
|
6184
|
-
return !this._isIgnored(
|
|
6496
|
+
_isntIgnored(path11, stat4) {
|
|
6497
|
+
return !this._isIgnored(path11, stat4);
|
|
6185
6498
|
}
|
|
6186
6499
|
/**
|
|
6187
6500
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
6188
6501
|
* @param path file or directory pattern being watched
|
|
6189
6502
|
*/
|
|
6190
|
-
_getWatchHelpers(
|
|
6191
|
-
return new WatchHelper(
|
|
6503
|
+
_getWatchHelpers(path11) {
|
|
6504
|
+
return new WatchHelper(path11, this.options.followSymlinks, this);
|
|
6192
6505
|
}
|
|
6193
6506
|
// Directory helpers
|
|
6194
6507
|
// -----------------
|
|
@@ -6220,63 +6533,63 @@ var FSWatcher = class extends import_events.EventEmitter {
|
|
|
6220
6533
|
* @param item base path of item/directory
|
|
6221
6534
|
*/
|
|
6222
6535
|
_remove(directory, item, isDirectory) {
|
|
6223
|
-
const
|
|
6224
|
-
const fullPath = sysPath2.resolve(
|
|
6225
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
6226
|
-
if (!this._throttle("remove",
|
|
6536
|
+
const path11 = sysPath2.join(directory, item);
|
|
6537
|
+
const fullPath = sysPath2.resolve(path11);
|
|
6538
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path11) || this._watched.has(fullPath);
|
|
6539
|
+
if (!this._throttle("remove", path11, 100))
|
|
6227
6540
|
return;
|
|
6228
6541
|
if (!isDirectory && this._watched.size === 1) {
|
|
6229
6542
|
this.add(directory, item, true);
|
|
6230
6543
|
}
|
|
6231
|
-
const wp = this._getWatchedDir(
|
|
6544
|
+
const wp = this._getWatchedDir(path11);
|
|
6232
6545
|
const nestedDirectoryChildren = wp.getChildren();
|
|
6233
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
6546
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path11, nested));
|
|
6234
6547
|
const parent = this._getWatchedDir(directory);
|
|
6235
6548
|
const wasTracked = parent.has(item);
|
|
6236
6549
|
parent.remove(item);
|
|
6237
6550
|
if (this._symlinkPaths.has(fullPath)) {
|
|
6238
6551
|
this._symlinkPaths.delete(fullPath);
|
|
6239
6552
|
}
|
|
6240
|
-
let relPath =
|
|
6553
|
+
let relPath = path11;
|
|
6241
6554
|
if (this.options.cwd)
|
|
6242
|
-
relPath = sysPath2.relative(this.options.cwd,
|
|
6555
|
+
relPath = sysPath2.relative(this.options.cwd, path11);
|
|
6243
6556
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
6244
6557
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
6245
6558
|
if (event === EVENTS.ADD)
|
|
6246
6559
|
return;
|
|
6247
6560
|
}
|
|
6248
|
-
this._watched.delete(
|
|
6561
|
+
this._watched.delete(path11);
|
|
6249
6562
|
this._watched.delete(fullPath);
|
|
6250
6563
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
6251
|
-
if (wasTracked && !this._isIgnored(
|
|
6252
|
-
this._emit(eventName,
|
|
6253
|
-
this._closePath(
|
|
6564
|
+
if (wasTracked && !this._isIgnored(path11))
|
|
6565
|
+
this._emit(eventName, path11);
|
|
6566
|
+
this._closePath(path11);
|
|
6254
6567
|
}
|
|
6255
6568
|
/**
|
|
6256
6569
|
* Closes all watchers for a path
|
|
6257
6570
|
*/
|
|
6258
|
-
_closePath(
|
|
6259
|
-
this._closeFile(
|
|
6260
|
-
const dir = sysPath2.dirname(
|
|
6261
|
-
this._getWatchedDir(dir).remove(sysPath2.basename(
|
|
6571
|
+
_closePath(path11) {
|
|
6572
|
+
this._closeFile(path11);
|
|
6573
|
+
const dir = sysPath2.dirname(path11);
|
|
6574
|
+
this._getWatchedDir(dir).remove(sysPath2.basename(path11));
|
|
6262
6575
|
}
|
|
6263
6576
|
/**
|
|
6264
6577
|
* Closes only file-specific watchers
|
|
6265
6578
|
*/
|
|
6266
|
-
_closeFile(
|
|
6267
|
-
const closers = this._closers.get(
|
|
6579
|
+
_closeFile(path11) {
|
|
6580
|
+
const closers = this._closers.get(path11);
|
|
6268
6581
|
if (!closers)
|
|
6269
6582
|
return;
|
|
6270
6583
|
closers.forEach((closer) => closer());
|
|
6271
|
-
this._closers.delete(
|
|
6584
|
+
this._closers.delete(path11);
|
|
6272
6585
|
}
|
|
6273
|
-
_addPathCloser(
|
|
6586
|
+
_addPathCloser(path11, closer) {
|
|
6274
6587
|
if (!closer)
|
|
6275
6588
|
return;
|
|
6276
|
-
let list = this._closers.get(
|
|
6589
|
+
let list = this._closers.get(path11);
|
|
6277
6590
|
if (!list) {
|
|
6278
6591
|
list = [];
|
|
6279
|
-
this._closers.set(
|
|
6592
|
+
this._closers.set(path11, list);
|
|
6280
6593
|
}
|
|
6281
6594
|
list.push(closer);
|
|
6282
6595
|
}
|
|
@@ -6305,19 +6618,22 @@ function watch(paths, options = {}) {
|
|
|
6305
6618
|
}
|
|
6306
6619
|
var esm_default = { watch, FSWatcher };
|
|
6307
6620
|
|
|
6621
|
+
// src/standalone/server.ts
|
|
6622
|
+
init_types();
|
|
6623
|
+
|
|
6308
6624
|
// src/standalone/webhooks.ts
|
|
6309
|
-
var
|
|
6310
|
-
var
|
|
6625
|
+
var fs5 = __toESM(require("fs"));
|
|
6626
|
+
var path6 = __toESM(require("path"));
|
|
6311
6627
|
var http = __toESM(require("http"));
|
|
6312
6628
|
var https = __toESM(require("https"));
|
|
6313
6629
|
var crypto = __toESM(require("crypto"));
|
|
6314
6630
|
var WEBHOOKS_FILENAME = ".kanban-webhooks.json";
|
|
6315
6631
|
function webhooksPath(workspaceRoot) {
|
|
6316
|
-
return
|
|
6632
|
+
return path6.join(workspaceRoot, WEBHOOKS_FILENAME);
|
|
6317
6633
|
}
|
|
6318
6634
|
function loadWebhooks(workspaceRoot) {
|
|
6319
6635
|
try {
|
|
6320
|
-
const raw =
|
|
6636
|
+
const raw = fs5.readFileSync(webhooksPath(workspaceRoot), "utf-8");
|
|
6321
6637
|
const data = JSON.parse(raw);
|
|
6322
6638
|
return Array.isArray(data) ? data : [];
|
|
6323
6639
|
} catch {
|
|
@@ -6325,7 +6641,7 @@ function loadWebhooks(workspaceRoot) {
|
|
|
6325
6641
|
}
|
|
6326
6642
|
}
|
|
6327
6643
|
function saveWebhooks(workspaceRoot, webhooks) {
|
|
6328
|
-
|
|
6644
|
+
fs5.writeFileSync(webhooksPath(workspaceRoot), JSON.stringify(webhooks, null, 2) + "\n", "utf-8");
|
|
6329
6645
|
}
|
|
6330
6646
|
function createWebhook(workspaceRoot, config) {
|
|
6331
6647
|
const webhooks = loadWebhooks(workspaceRoot);
|
|
@@ -6420,13 +6736,14 @@ var MIME_TYPES = {
|
|
|
6420
6736
|
".map": "application/json"
|
|
6421
6737
|
};
|
|
6422
6738
|
function startServer(featuresDir, port, webviewDir) {
|
|
6423
|
-
const absoluteFeaturesDir =
|
|
6739
|
+
const absoluteFeaturesDir = path7.resolve(featuresDir);
|
|
6424
6740
|
let features = [];
|
|
6425
6741
|
let migrating = false;
|
|
6426
6742
|
let currentEditingFeatureId = null;
|
|
6427
6743
|
let lastWrittenContent = "";
|
|
6428
|
-
|
|
6429
|
-
const
|
|
6744
|
+
let currentBoardId;
|
|
6745
|
+
const resolvedWebviewDir = webviewDir || path7.join(__dirname, "standalone-webview");
|
|
6746
|
+
const workspaceRoot = path7.dirname(absoluteFeaturesDir);
|
|
6430
6747
|
const sdk = new KanbanSDK(absoluteFeaturesDir);
|
|
6431
6748
|
function sanitizeFeature(feature) {
|
|
6432
6749
|
const { filePath: _, ...rest } = feature;
|
|
@@ -6492,17 +6809,20 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6492
6809
|
</body>
|
|
6493
6810
|
</html>`;
|
|
6494
6811
|
async function loadFeatures() {
|
|
6495
|
-
features = await sdk.listCards(sdk.listColumns().map((c) => c.id));
|
|
6812
|
+
features = await sdk.listCards(sdk.listColumns(currentBoardId).map((c) => c.id), currentBoardId);
|
|
6496
6813
|
}
|
|
6497
6814
|
function buildInitMessage() {
|
|
6815
|
+
const config = readConfig(workspaceRoot);
|
|
6498
6816
|
const settings = sdk.getSettings();
|
|
6499
6817
|
settings.showBuildWithAI = false;
|
|
6500
6818
|
settings.markdownEditorMode = false;
|
|
6501
6819
|
return {
|
|
6502
6820
|
type: "init",
|
|
6503
6821
|
features,
|
|
6504
|
-
columns: sdk.listColumns(),
|
|
6505
|
-
settings
|
|
6822
|
+
columns: sdk.listColumns(currentBoardId),
|
|
6823
|
+
settings,
|
|
6824
|
+
boards: sdk.listBoards(),
|
|
6825
|
+
currentBoard: currentBoardId || config.defaultBoard
|
|
6506
6826
|
};
|
|
6507
6827
|
}
|
|
6508
6828
|
function broadcast(message) {
|
|
@@ -6522,7 +6842,8 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6522
6842
|
priority: data.priority,
|
|
6523
6843
|
assignee: data.assignee,
|
|
6524
6844
|
dueDate: data.dueDate,
|
|
6525
|
-
labels: data.labels
|
|
6845
|
+
labels: data.labels,
|
|
6846
|
+
boardId: currentBoardId
|
|
6526
6847
|
});
|
|
6527
6848
|
await loadFeatures();
|
|
6528
6849
|
broadcast(buildInitMessage());
|
|
@@ -6539,7 +6860,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6539
6860
|
const oldStatus = feature.status;
|
|
6540
6861
|
migrating = true;
|
|
6541
6862
|
try {
|
|
6542
|
-
const updated = await sdk.moveCard(featureId, newStatus, newOrder);
|
|
6863
|
+
const updated = await sdk.moveCard(featureId, newStatus, newOrder, currentBoardId);
|
|
6543
6864
|
await loadFeatures();
|
|
6544
6865
|
broadcast(buildInitMessage());
|
|
6545
6866
|
fireWebhooks(workspaceRoot, "task.moved", {
|
|
@@ -6557,7 +6878,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6557
6878
|
return null;
|
|
6558
6879
|
migrating = true;
|
|
6559
6880
|
try {
|
|
6560
|
-
const updated = await sdk.updateCard(featureId, updates);
|
|
6881
|
+
const updated = await sdk.updateCard(featureId, updates, currentBoardId);
|
|
6561
6882
|
lastWrittenContent = serializeFeature(updated);
|
|
6562
6883
|
await loadFeatures();
|
|
6563
6884
|
broadcast(buildInitMessage());
|
|
@@ -6573,7 +6894,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6573
6894
|
return false;
|
|
6574
6895
|
try {
|
|
6575
6896
|
const deleted = sanitizeFeature(feature);
|
|
6576
|
-
await sdk.deleteCard(featureId);
|
|
6897
|
+
await sdk.deleteCard(featureId, currentBoardId);
|
|
6577
6898
|
await loadFeatures();
|
|
6578
6899
|
broadcast(buildInitMessage());
|
|
6579
6900
|
fireWebhooks(workspaceRoot, "task.deleted", deleted);
|
|
@@ -6584,7 +6905,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6584
6905
|
}
|
|
6585
6906
|
}
|
|
6586
6907
|
function doAddColumn(name, color) {
|
|
6587
|
-
const existingColumns = sdk.listColumns();
|
|
6908
|
+
const existingColumns = sdk.listColumns(currentBoardId);
|
|
6588
6909
|
const id = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
6589
6910
|
let uniqueId = id;
|
|
6590
6911
|
let counter = 1;
|
|
@@ -6592,14 +6913,14 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6592
6913
|
uniqueId = `${id}-${counter++}`;
|
|
6593
6914
|
}
|
|
6594
6915
|
const column = { id: uniqueId, name, color };
|
|
6595
|
-
sdk.addColumn(column);
|
|
6916
|
+
sdk.addColumn(column, currentBoardId);
|
|
6596
6917
|
broadcast(buildInitMessage());
|
|
6597
6918
|
fireWebhooks(workspaceRoot, "column.created", column);
|
|
6598
6919
|
return column;
|
|
6599
6920
|
}
|
|
6600
6921
|
function doEditColumn(columnId, updates) {
|
|
6601
6922
|
try {
|
|
6602
|
-
const columns = sdk.updateColumn(columnId, { name: updates.name, color: updates.color });
|
|
6923
|
+
const columns = sdk.updateColumn(columnId, { name: updates.name, color: updates.color }, currentBoardId);
|
|
6603
6924
|
const updated = columns.find((c) => c.id === columnId) ?? null;
|
|
6604
6925
|
broadcast(buildInitMessage());
|
|
6605
6926
|
if (updated)
|
|
@@ -6611,13 +6932,13 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6611
6932
|
}
|
|
6612
6933
|
async function doRemoveColumn(columnId) {
|
|
6613
6934
|
try {
|
|
6614
|
-
const columns = sdk.listColumns();
|
|
6935
|
+
const columns = sdk.listColumns(currentBoardId);
|
|
6615
6936
|
if (columns.length <= 1)
|
|
6616
6937
|
return { removed: false, error: "Cannot remove last column" };
|
|
6617
6938
|
const col = columns.find((c) => c.id === columnId);
|
|
6618
6939
|
if (!col)
|
|
6619
6940
|
return { removed: false, error: "Column not found" };
|
|
6620
|
-
await sdk.removeColumn(columnId);
|
|
6941
|
+
await sdk.removeColumn(columnId, currentBoardId);
|
|
6621
6942
|
broadcast(buildInitMessage());
|
|
6622
6943
|
fireWebhooks(workspaceRoot, "column.deleted", col);
|
|
6623
6944
|
return { removed: true };
|
|
@@ -6633,11 +6954,11 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6633
6954
|
const feature = features.find((f) => f.id === featureId);
|
|
6634
6955
|
if (!feature)
|
|
6635
6956
|
return false;
|
|
6636
|
-
const featureDir =
|
|
6637
|
-
|
|
6957
|
+
const featureDir = path7.dirname(feature.filePath);
|
|
6958
|
+
fs6.writeFileSync(path7.join(featureDir, filename), fileData);
|
|
6638
6959
|
migrating = true;
|
|
6639
6960
|
try {
|
|
6640
|
-
const updated = await sdk.addAttachment(featureId,
|
|
6961
|
+
const updated = await sdk.addAttachment(featureId, path7.join(featureDir, filename), currentBoardId);
|
|
6641
6962
|
lastWrittenContent = serializeFeature(updated);
|
|
6642
6963
|
await loadFeatures();
|
|
6643
6964
|
} finally {
|
|
@@ -6651,7 +6972,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6651
6972
|
return null;
|
|
6652
6973
|
migrating = true;
|
|
6653
6974
|
try {
|
|
6654
|
-
const updated = await sdk.removeAttachment(featureId, attachment);
|
|
6975
|
+
const updated = await sdk.removeAttachment(featureId, attachment, currentBoardId);
|
|
6655
6976
|
lastWrittenContent = serializeFeature(updated);
|
|
6656
6977
|
await loadFeatures();
|
|
6657
6978
|
broadcast(buildInitMessage());
|
|
@@ -6663,7 +6984,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6663
6984
|
async function doAddComment(featureId, author, content) {
|
|
6664
6985
|
migrating = true;
|
|
6665
6986
|
try {
|
|
6666
|
-
const updated = await sdk.addComment(featureId, author, content);
|
|
6987
|
+
const updated = await sdk.addComment(featureId, author, content, currentBoardId);
|
|
6667
6988
|
lastWrittenContent = serializeFeature(updated);
|
|
6668
6989
|
const comment = updated.comments[updated.comments.length - 1];
|
|
6669
6990
|
await loadFeatures();
|
|
@@ -6679,7 +7000,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6679
7000
|
async function doUpdateComment(featureId, commentId, content) {
|
|
6680
7001
|
migrating = true;
|
|
6681
7002
|
try {
|
|
6682
|
-
const updated = await sdk.updateComment(featureId, commentId, content);
|
|
7003
|
+
const updated = await sdk.updateComment(featureId, commentId, content, currentBoardId);
|
|
6683
7004
|
lastWrittenContent = serializeFeature(updated);
|
|
6684
7005
|
const comment = (updated.comments || []).find((c) => c.id === commentId);
|
|
6685
7006
|
await loadFeatures();
|
|
@@ -6702,7 +7023,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6702
7023
|
return false;
|
|
6703
7024
|
migrating = true;
|
|
6704
7025
|
try {
|
|
6705
|
-
const updated = await sdk.deleteComment(featureId, commentId);
|
|
7026
|
+
const updated = await sdk.deleteComment(featureId, commentId, currentBoardId);
|
|
6706
7027
|
lastWrittenContent = serializeFeature(updated);
|
|
6707
7028
|
await loadFeatures();
|
|
6708
7029
|
broadcast(buildInitMessage());
|
|
@@ -6887,6 +7208,34 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6887
7208
|
}
|
|
6888
7209
|
break;
|
|
6889
7210
|
}
|
|
7211
|
+
case "switchBoard":
|
|
7212
|
+
currentBoardId = msg.boardId;
|
|
7213
|
+
migrating = true;
|
|
7214
|
+
try {
|
|
7215
|
+
await loadFeatures();
|
|
7216
|
+
broadcast(buildInitMessage());
|
|
7217
|
+
} finally {
|
|
7218
|
+
migrating = false;
|
|
7219
|
+
}
|
|
7220
|
+
break;
|
|
7221
|
+
case "createBoard": {
|
|
7222
|
+
const boardName = msg.name;
|
|
7223
|
+
const boardId = generateSlug(boardName) || "board";
|
|
7224
|
+
try {
|
|
7225
|
+
sdk.createBoard(boardId, boardName);
|
|
7226
|
+
currentBoardId = boardId;
|
|
7227
|
+
migrating = true;
|
|
7228
|
+
try {
|
|
7229
|
+
await loadFeatures();
|
|
7230
|
+
broadcast(buildInitMessage());
|
|
7231
|
+
} finally {
|
|
7232
|
+
migrating = false;
|
|
7233
|
+
}
|
|
7234
|
+
} catch (err) {
|
|
7235
|
+
console.error("Failed to create board:", err);
|
|
7236
|
+
}
|
|
7237
|
+
break;
|
|
7238
|
+
}
|
|
6890
7239
|
case "openFile":
|
|
6891
7240
|
case "focusMenuBar":
|
|
6892
7241
|
case "startWithAI":
|
|
@@ -6910,7 +7259,178 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
6910
7259
|
return;
|
|
6911
7260
|
}
|
|
6912
7261
|
const route = (expectedMethod, pattern) => matchRoute(expectedMethod, method, pathname, pattern);
|
|
6913
|
-
let params = route("GET", "/api/
|
|
7262
|
+
let params = route("GET", "/api/boards");
|
|
7263
|
+
if (params) {
|
|
7264
|
+
return jsonOk(res, sdk.listBoards());
|
|
7265
|
+
}
|
|
7266
|
+
params = route("POST", "/api/boards");
|
|
7267
|
+
if (params) {
|
|
7268
|
+
try {
|
|
7269
|
+
const body = await readBody(req);
|
|
7270
|
+
const id = body.id;
|
|
7271
|
+
const name = body.name;
|
|
7272
|
+
if (!id)
|
|
7273
|
+
return jsonError(res, 400, "id is required");
|
|
7274
|
+
if (!name)
|
|
7275
|
+
return jsonError(res, 400, "name is required");
|
|
7276
|
+
const board = sdk.createBoard(id, name, {
|
|
7277
|
+
description: body.description,
|
|
7278
|
+
columns: body.columns
|
|
7279
|
+
});
|
|
7280
|
+
return jsonOk(res, board, 201);
|
|
7281
|
+
} catch (err) {
|
|
7282
|
+
return jsonError(res, 400, String(err));
|
|
7283
|
+
}
|
|
7284
|
+
}
|
|
7285
|
+
params = route("GET", "/api/boards/:boardId");
|
|
7286
|
+
if (params) {
|
|
7287
|
+
try {
|
|
7288
|
+
const { boardId } = params;
|
|
7289
|
+
const board = sdk.getBoard(boardId);
|
|
7290
|
+
return jsonOk(res, board);
|
|
7291
|
+
} catch (err) {
|
|
7292
|
+
return jsonError(res, 404, String(err));
|
|
7293
|
+
}
|
|
7294
|
+
}
|
|
7295
|
+
params = route("PUT", "/api/boards/:boardId");
|
|
7296
|
+
if (params) {
|
|
7297
|
+
try {
|
|
7298
|
+
const { boardId } = params;
|
|
7299
|
+
const body = await readBody(req);
|
|
7300
|
+
const board = sdk.updateBoard(boardId, body);
|
|
7301
|
+
return jsonOk(res, board);
|
|
7302
|
+
} catch (err) {
|
|
7303
|
+
return jsonError(res, 400, String(err));
|
|
7304
|
+
}
|
|
7305
|
+
}
|
|
7306
|
+
params = route("DELETE", "/api/boards/:boardId");
|
|
7307
|
+
if (params) {
|
|
7308
|
+
try {
|
|
7309
|
+
const { boardId } = params;
|
|
7310
|
+
await sdk.deleteBoard(boardId);
|
|
7311
|
+
return jsonOk(res, { deleted: true });
|
|
7312
|
+
} catch (err) {
|
|
7313
|
+
return jsonError(res, 400, String(err));
|
|
7314
|
+
}
|
|
7315
|
+
}
|
|
7316
|
+
params = route("POST", "/api/boards/:boardId/tasks/:id/transfer");
|
|
7317
|
+
if (params) {
|
|
7318
|
+
try {
|
|
7319
|
+
const { boardId, id } = params;
|
|
7320
|
+
const body = await readBody(req);
|
|
7321
|
+
const config = readConfig(workspaceRoot);
|
|
7322
|
+
const fromBoard = currentBoardId || config.defaultBoard;
|
|
7323
|
+
const targetStatus = body.targetStatus;
|
|
7324
|
+
const card = await sdk.transferCard(id, fromBoard, boardId, targetStatus);
|
|
7325
|
+
return jsonOk(res, sanitizeFeature(card));
|
|
7326
|
+
} catch (err) {
|
|
7327
|
+
return jsonError(res, 400, String(err));
|
|
7328
|
+
}
|
|
7329
|
+
}
|
|
7330
|
+
params = route("GET", "/api/boards/:boardId/tasks");
|
|
7331
|
+
if (params) {
|
|
7332
|
+
try {
|
|
7333
|
+
const { boardId } = params;
|
|
7334
|
+
const boardColumns = sdk.listColumns(boardId);
|
|
7335
|
+
const boardTasks = await sdk.listCards(boardColumns.map((c) => c.id), boardId);
|
|
7336
|
+
let result = boardTasks.map(sanitizeFeature);
|
|
7337
|
+
const status = url.searchParams.get("status");
|
|
7338
|
+
if (status)
|
|
7339
|
+
result = result.filter((f) => f.status === status);
|
|
7340
|
+
const priority = url.searchParams.get("priority");
|
|
7341
|
+
if (priority)
|
|
7342
|
+
result = result.filter((f) => f.priority === priority);
|
|
7343
|
+
const assignee = url.searchParams.get("assignee");
|
|
7344
|
+
if (assignee)
|
|
7345
|
+
result = result.filter((f) => f.assignee === assignee);
|
|
7346
|
+
const label = url.searchParams.get("label");
|
|
7347
|
+
if (label)
|
|
7348
|
+
result = result.filter((f) => f.labels.includes(label));
|
|
7349
|
+
return jsonOk(res, result);
|
|
7350
|
+
} catch (err) {
|
|
7351
|
+
return jsonError(res, 400, String(err));
|
|
7352
|
+
}
|
|
7353
|
+
}
|
|
7354
|
+
params = route("POST", "/api/boards/:boardId/tasks");
|
|
7355
|
+
if (params) {
|
|
7356
|
+
try {
|
|
7357
|
+
const { boardId } = params;
|
|
7358
|
+
const body = await readBody(req);
|
|
7359
|
+
const content = body.content || "";
|
|
7360
|
+
if (!content)
|
|
7361
|
+
return jsonError(res, 400, "content is required");
|
|
7362
|
+
const feature = await sdk.createCard({
|
|
7363
|
+
content,
|
|
7364
|
+
status: body.status || "backlog",
|
|
7365
|
+
priority: body.priority || "medium",
|
|
7366
|
+
assignee: body.assignee || null,
|
|
7367
|
+
dueDate: body.dueDate || null,
|
|
7368
|
+
labels: body.labels || [],
|
|
7369
|
+
boardId
|
|
7370
|
+
});
|
|
7371
|
+
return jsonOk(res, sanitizeFeature(feature), 201);
|
|
7372
|
+
} catch (err) {
|
|
7373
|
+
return jsonError(res, 400, String(err));
|
|
7374
|
+
}
|
|
7375
|
+
}
|
|
7376
|
+
params = route("GET", "/api/boards/:boardId/tasks/:id");
|
|
7377
|
+
if (params) {
|
|
7378
|
+
try {
|
|
7379
|
+
const { boardId, id } = params;
|
|
7380
|
+
const card = await sdk.getCard(id, boardId);
|
|
7381
|
+
if (!card)
|
|
7382
|
+
return jsonError(res, 404, "Task not found");
|
|
7383
|
+
return jsonOk(res, sanitizeFeature(card));
|
|
7384
|
+
} catch (err) {
|
|
7385
|
+
return jsonError(res, 400, String(err));
|
|
7386
|
+
}
|
|
7387
|
+
}
|
|
7388
|
+
params = route("PUT", "/api/boards/:boardId/tasks/:id");
|
|
7389
|
+
if (params) {
|
|
7390
|
+
try {
|
|
7391
|
+
const { boardId, id } = params;
|
|
7392
|
+
const body = await readBody(req);
|
|
7393
|
+
const feature = await sdk.updateCard(id, body, boardId);
|
|
7394
|
+
return jsonOk(res, sanitizeFeature(feature));
|
|
7395
|
+
} catch (err) {
|
|
7396
|
+
return jsonError(res, 400, String(err));
|
|
7397
|
+
}
|
|
7398
|
+
}
|
|
7399
|
+
params = route("PATCH", "/api/boards/:boardId/tasks/:id/move");
|
|
7400
|
+
if (params) {
|
|
7401
|
+
try {
|
|
7402
|
+
const { boardId, id } = params;
|
|
7403
|
+
const body = await readBody(req);
|
|
7404
|
+
const newStatus = body.status;
|
|
7405
|
+
const position = body.position ?? 0;
|
|
7406
|
+
if (!newStatus)
|
|
7407
|
+
return jsonError(res, 400, "status is required");
|
|
7408
|
+
const feature = await sdk.moveCard(id, newStatus, position, boardId);
|
|
7409
|
+
return jsonOk(res, sanitizeFeature(feature));
|
|
7410
|
+
} catch (err) {
|
|
7411
|
+
return jsonError(res, 400, String(err));
|
|
7412
|
+
}
|
|
7413
|
+
}
|
|
7414
|
+
params = route("DELETE", "/api/boards/:boardId/tasks/:id");
|
|
7415
|
+
if (params) {
|
|
7416
|
+
try {
|
|
7417
|
+
const { boardId, id } = params;
|
|
7418
|
+
await sdk.deleteCard(id, boardId);
|
|
7419
|
+
return jsonOk(res, { deleted: true });
|
|
7420
|
+
} catch (err) {
|
|
7421
|
+
return jsonError(res, 400, String(err));
|
|
7422
|
+
}
|
|
7423
|
+
}
|
|
7424
|
+
params = route("GET", "/api/boards/:boardId/columns");
|
|
7425
|
+
if (params) {
|
|
7426
|
+
try {
|
|
7427
|
+
const { boardId } = params;
|
|
7428
|
+
return jsonOk(res, sdk.listColumns(boardId));
|
|
7429
|
+
} catch (err) {
|
|
7430
|
+
return jsonError(res, 400, String(err));
|
|
7431
|
+
}
|
|
7432
|
+
}
|
|
7433
|
+
params = route("GET", "/api/tasks");
|
|
6914
7434
|
if (params) {
|
|
6915
7435
|
await loadFeatures();
|
|
6916
7436
|
let result = features.map(sanitizeFeature);
|
|
@@ -7021,16 +7541,16 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
7021
7541
|
const feature = features.find((f) => f.id === id);
|
|
7022
7542
|
if (!feature)
|
|
7023
7543
|
return jsonError(res, 404, "Task not found");
|
|
7024
|
-
const featureDir =
|
|
7025
|
-
const attachmentPath =
|
|
7544
|
+
const featureDir = path7.dirname(feature.filePath);
|
|
7545
|
+
const attachmentPath = path7.resolve(featureDir, attachName);
|
|
7026
7546
|
if (!attachmentPath.startsWith(absoluteFeaturesDir)) {
|
|
7027
7547
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
7028
7548
|
res.end("Forbidden");
|
|
7029
7549
|
return;
|
|
7030
7550
|
}
|
|
7031
|
-
const ext2 =
|
|
7551
|
+
const ext2 = path7.extname(attachName);
|
|
7032
7552
|
const contentType2 = MIME_TYPES[ext2] || "application/octet-stream";
|
|
7033
|
-
|
|
7553
|
+
fs6.readFile(attachmentPath, (err, data) => {
|
|
7034
7554
|
if (err) {
|
|
7035
7555
|
res.writeHead(404);
|
|
7036
7556
|
res.end("File not found");
|
|
@@ -7106,7 +7626,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
7106
7626
|
}
|
|
7107
7627
|
params = route("GET", "/api/columns");
|
|
7108
7628
|
if (params) {
|
|
7109
|
-
return jsonOk(res, sdk.listColumns());
|
|
7629
|
+
return jsonOk(res, sdk.listColumns(currentBoardId));
|
|
7110
7630
|
}
|
|
7111
7631
|
params = route("POST", "/api/columns");
|
|
7112
7632
|
if (params) {
|
|
@@ -7245,16 +7765,16 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
7245
7765
|
res.end("Feature not found");
|
|
7246
7766
|
return;
|
|
7247
7767
|
}
|
|
7248
|
-
const featureDir =
|
|
7249
|
-
const attachmentPath =
|
|
7768
|
+
const featureDir = path7.dirname(feature.filePath);
|
|
7769
|
+
const attachmentPath = path7.resolve(featureDir, filename);
|
|
7250
7770
|
if (!attachmentPath.startsWith(absoluteFeaturesDir)) {
|
|
7251
7771
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
7252
7772
|
res.end("Forbidden");
|
|
7253
7773
|
return;
|
|
7254
7774
|
}
|
|
7255
|
-
const ext2 =
|
|
7775
|
+
const ext2 = path7.extname(filename);
|
|
7256
7776
|
const contentType2 = MIME_TYPES[ext2] || "application/octet-stream";
|
|
7257
|
-
|
|
7777
|
+
fs6.readFile(attachmentPath, (err, data) => {
|
|
7258
7778
|
if (err) {
|
|
7259
7779
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
7260
7780
|
res.end("File not found");
|
|
@@ -7268,15 +7788,15 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
7268
7788
|
if (pathname.startsWith("/api/")) {
|
|
7269
7789
|
return jsonError(res, 404, "Not found");
|
|
7270
7790
|
}
|
|
7271
|
-
const filePath =
|
|
7272
|
-
if (!
|
|
7791
|
+
const filePath = path7.join(resolvedWebviewDir, pathname === "/" ? "index.html" : pathname);
|
|
7792
|
+
if (!path7.extname(filePath)) {
|
|
7273
7793
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
7274
7794
|
res.end(indexHtml);
|
|
7275
7795
|
return;
|
|
7276
7796
|
}
|
|
7277
|
-
const ext =
|
|
7797
|
+
const ext = path7.extname(filePath);
|
|
7278
7798
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
7279
|
-
|
|
7799
|
+
fs6.readFile(filePath, (err, data) => {
|
|
7280
7800
|
if (err) {
|
|
7281
7801
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
7282
7802
|
res.end(indexHtml);
|
|
@@ -7298,7 +7818,7 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
7298
7818
|
});
|
|
7299
7819
|
});
|
|
7300
7820
|
let debounceTimer;
|
|
7301
|
-
|
|
7821
|
+
fs6.mkdirSync(absoluteFeaturesDir, { recursive: true });
|
|
7302
7822
|
const watcher = esm_default.watch(absoluteFeaturesDir, {
|
|
7303
7823
|
ignoreInitial: true,
|
|
7304
7824
|
awaitWriteFinish: { stabilityThreshold: 100 }
|
|
@@ -7361,12 +7881,14 @@ function startServer(featuresDir, port, webviewDir) {
|
|
|
7361
7881
|
|
|
7362
7882
|
// src/extension/KanbanPanel.ts
|
|
7363
7883
|
var vscode = __toESM(require("vscode"));
|
|
7364
|
-
var
|
|
7884
|
+
var path8 = __toESM(require("path"));
|
|
7885
|
+
init_types();
|
|
7365
7886
|
var KanbanPanel = class _KanbanPanel {
|
|
7366
7887
|
constructor(panel, extensionUri, context) {
|
|
7367
7888
|
this._features = [];
|
|
7368
7889
|
this._disposables = [];
|
|
7369
7890
|
this._currentEditingFeatureId = null;
|
|
7891
|
+
this._currentBoardId = void 0;
|
|
7370
7892
|
this._lastWrittenContent = "";
|
|
7371
7893
|
this._migrating = false;
|
|
7372
7894
|
this._onDisposeCallbacks = [];
|
|
@@ -7479,6 +8001,26 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7479
8001
|
case "removeColumn":
|
|
7480
8002
|
await this._removeColumn(message.columnId);
|
|
7481
8003
|
break;
|
|
8004
|
+
case "switchBoard":
|
|
8005
|
+
this._currentBoardId = message.boardId;
|
|
8006
|
+
await this._loadFeatures();
|
|
8007
|
+
this._sendFeaturesToWebview();
|
|
8008
|
+
break;
|
|
8009
|
+
case "createBoard": {
|
|
8010
|
+
if (!this._sdk)
|
|
8011
|
+
break;
|
|
8012
|
+
const { generateSlug: generateSlug2 } = await Promise.resolve().then(() => (init_types(), types_exports));
|
|
8013
|
+
const boardId = generateSlug2(message.name) || "board";
|
|
8014
|
+
try {
|
|
8015
|
+
this._sdk.createBoard(boardId, message.name);
|
|
8016
|
+
this._currentBoardId = boardId;
|
|
8017
|
+
await this._loadFeatures();
|
|
8018
|
+
this._sendFeaturesToWebview();
|
|
8019
|
+
} catch (err) {
|
|
8020
|
+
vscode.window.showErrorMessage(`Failed to create board: ${err}`);
|
|
8021
|
+
}
|
|
8022
|
+
break;
|
|
8023
|
+
}
|
|
7482
8024
|
case "toggleTheme":
|
|
7483
8025
|
await vscode.commands.executeCommand("workbench.action.toggleLightDarkThemes");
|
|
7484
8026
|
break;
|
|
@@ -7528,7 +8070,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7528
8070
|
const featuresDir = this._getWorkspaceFeaturesDir();
|
|
7529
8071
|
if (!featuresDir)
|
|
7530
8072
|
return;
|
|
7531
|
-
const pattern = new vscode.RelativePattern(featuresDir, "
|
|
8073
|
+
const pattern = new vscode.RelativePattern(featuresDir, "boards/**/*.md");
|
|
7532
8074
|
this._fileWatcher = vscode.workspace.createFileSystemWatcher(pattern);
|
|
7533
8075
|
let debounceTimer;
|
|
7534
8076
|
const handleFileChange = (uri) => {
|
|
@@ -7642,7 +8184,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7642
8184
|
if (!root)
|
|
7643
8185
|
return null;
|
|
7644
8186
|
const config = readConfig(root);
|
|
7645
|
-
return
|
|
8187
|
+
return path8.join(root, config.featuresDirectory);
|
|
7646
8188
|
}
|
|
7647
8189
|
_getSDK() {
|
|
7648
8190
|
const featuresDir = this._getWorkspaceFeaturesDir();
|
|
@@ -7662,7 +8204,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7662
8204
|
try {
|
|
7663
8205
|
this._migrating = true;
|
|
7664
8206
|
const columns = this._getColumns().map((c) => c.id);
|
|
7665
|
-
this._features = await sdk.listCards(columns);
|
|
8207
|
+
this._features = await sdk.listCards(columns, this._currentBoardId);
|
|
7666
8208
|
} catch {
|
|
7667
8209
|
this._features = [];
|
|
7668
8210
|
} finally {
|
|
@@ -7695,7 +8237,8 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7695
8237
|
priority: data.priority,
|
|
7696
8238
|
assignee: data.assignee ?? void 0,
|
|
7697
8239
|
dueDate: data.dueDate ?? void 0,
|
|
7698
|
-
labels: data.labels
|
|
8240
|
+
labels: data.labels,
|
|
8241
|
+
boardId: this._currentBoardId
|
|
7699
8242
|
});
|
|
7700
8243
|
this._features.push(feature);
|
|
7701
8244
|
this._sendFeaturesToWebview();
|
|
@@ -7709,7 +8252,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7709
8252
|
return;
|
|
7710
8253
|
this._migrating = true;
|
|
7711
8254
|
try {
|
|
7712
|
-
const updated = await sdk.moveCard(featureId, newStatus, newOrder);
|
|
8255
|
+
const updated = await sdk.moveCard(featureId, newStatus, newOrder, this._currentBoardId);
|
|
7713
8256
|
const idx = this._features.findIndex((f) => f.id === featureId);
|
|
7714
8257
|
if (idx !== -1)
|
|
7715
8258
|
this._features[idx] = updated;
|
|
@@ -7723,7 +8266,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7723
8266
|
if (!sdk)
|
|
7724
8267
|
return;
|
|
7725
8268
|
try {
|
|
7726
|
-
await sdk.deleteCard(featureId);
|
|
8269
|
+
await sdk.deleteCard(featureId, this._currentBoardId);
|
|
7727
8270
|
this._features = this._features.filter((f) => f.id !== featureId);
|
|
7728
8271
|
this._sendFeaturesToWebview();
|
|
7729
8272
|
} catch (err) {
|
|
@@ -7736,7 +8279,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7736
8279
|
return;
|
|
7737
8280
|
this._migrating = true;
|
|
7738
8281
|
try {
|
|
7739
|
-
const updated = await sdk.updateCard(featureId, updates);
|
|
8282
|
+
const updated = await sdk.updateCard(featureId, updates, this._currentBoardId);
|
|
7740
8283
|
const idx = this._features.findIndex((f) => f.id === featureId);
|
|
7741
8284
|
if (idx !== -1)
|
|
7742
8285
|
this._features[idx] = updated;
|
|
@@ -7794,7 +8337,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7794
8337
|
dueDate: frontmatter.dueDate,
|
|
7795
8338
|
labels: frontmatter.labels,
|
|
7796
8339
|
attachments: frontmatter.attachments
|
|
7797
|
-
});
|
|
8340
|
+
}, this._currentBoardId);
|
|
7798
8341
|
this._lastWrittenContent = serializeFeature(updated);
|
|
7799
8342
|
const idx = this._features.findIndex((f) => f.id === featureId);
|
|
7800
8343
|
if (idx !== -1)
|
|
@@ -7820,7 +8363,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7820
8363
|
try {
|
|
7821
8364
|
let updated = feature;
|
|
7822
8365
|
for (const uri of uris) {
|
|
7823
|
-
updated = await sdk.addAttachment(featureId, uri.fsPath);
|
|
8366
|
+
updated = await sdk.addAttachment(featureId, uri.fsPath, this._currentBoardId);
|
|
7824
8367
|
}
|
|
7825
8368
|
const idx = this._features.findIndex((f) => f.id === featureId);
|
|
7826
8369
|
if (idx !== -1)
|
|
@@ -7837,8 +8380,8 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7837
8380
|
const feature = this._features.find((f) => f.id === featureId);
|
|
7838
8381
|
if (!feature)
|
|
7839
8382
|
return;
|
|
7840
|
-
const featureDir =
|
|
7841
|
-
const attachmentPath =
|
|
8383
|
+
const featureDir = path8.dirname(feature.filePath);
|
|
8384
|
+
const attachmentPath = path8.resolve(featureDir, attachment);
|
|
7842
8385
|
try {
|
|
7843
8386
|
await vscode.workspace.fs.stat(vscode.Uri.file(attachmentPath));
|
|
7844
8387
|
const doc = await vscode.workspace.openTextDocument(vscode.Uri.file(attachmentPath));
|
|
@@ -7853,7 +8396,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7853
8396
|
return;
|
|
7854
8397
|
this._migrating = true;
|
|
7855
8398
|
try {
|
|
7856
|
-
const updated = await sdk.removeAttachment(featureId, attachment);
|
|
8399
|
+
const updated = await sdk.removeAttachment(featureId, attachment, this._currentBoardId);
|
|
7857
8400
|
const idx = this._features.findIndex((f) => f.id === featureId);
|
|
7858
8401
|
if (idx !== -1)
|
|
7859
8402
|
this._features[idx] = updated;
|
|
@@ -7871,7 +8414,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7871
8414
|
return;
|
|
7872
8415
|
this._migrating = true;
|
|
7873
8416
|
try {
|
|
7874
|
-
const updated = await sdk.addComment(featureId, author, content);
|
|
8417
|
+
const updated = await sdk.addComment(featureId, author, content, this._currentBoardId);
|
|
7875
8418
|
const idx = this._features.findIndex((f) => f.id === featureId);
|
|
7876
8419
|
if (idx !== -1)
|
|
7877
8420
|
this._features[idx] = updated;
|
|
@@ -7889,7 +8432,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7889
8432
|
return;
|
|
7890
8433
|
this._migrating = true;
|
|
7891
8434
|
try {
|
|
7892
|
-
const updated = await sdk.updateComment(featureId, commentId, content);
|
|
8435
|
+
const updated = await sdk.updateComment(featureId, commentId, content, this._currentBoardId);
|
|
7893
8436
|
const idx = this._features.findIndex((f) => f.id === featureId);
|
|
7894
8437
|
if (idx !== -1)
|
|
7895
8438
|
this._features[idx] = updated;
|
|
@@ -7907,7 +8450,7 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7907
8450
|
return;
|
|
7908
8451
|
this._migrating = true;
|
|
7909
8452
|
try {
|
|
7910
|
-
const updated = await sdk.deleteComment(featureId, commentId);
|
|
8453
|
+
const updated = await sdk.deleteComment(featureId, commentId, this._currentBoardId);
|
|
7911
8454
|
const idx = this._features.findIndex((f) => f.id === featureId);
|
|
7912
8455
|
if (idx !== -1)
|
|
7913
8456
|
this._features[idx] = updated;
|
|
@@ -7983,13 +8526,17 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7983
8526
|
_getColumns() {
|
|
7984
8527
|
const sdk = this._getSDK();
|
|
7985
8528
|
if (!sdk)
|
|
7986
|
-
return [...DEFAULT_CONFIG.columns];
|
|
7987
|
-
return sdk.listColumns();
|
|
8529
|
+
return [...DEFAULT_CONFIG.boards.default.columns];
|
|
8530
|
+
return sdk.listColumns(this._currentBoardId);
|
|
7988
8531
|
}
|
|
7989
8532
|
_sendFeaturesToWebview() {
|
|
7990
8533
|
const sdk = this._getSDK();
|
|
7991
|
-
const columns = sdk ? sdk.listColumns() : [...DEFAULT_CONFIG.columns];
|
|
8534
|
+
const columns = sdk ? sdk.listColumns(this._currentBoardId) : [...DEFAULT_CONFIG.boards.default.columns];
|
|
7992
8535
|
const settings = sdk ? sdk.getSettings() : configToSettings(DEFAULT_CONFIG);
|
|
8536
|
+
const boards = sdk ? sdk.listBoards() : [];
|
|
8537
|
+
const root = this._getWorkspaceRoot();
|
|
8538
|
+
const config = root ? readConfig(root) : DEFAULT_CONFIG;
|
|
8539
|
+
const currentBoard = this._currentBoardId || config.defaultBoard;
|
|
7993
8540
|
const aiDisabled = vscode.workspace.getConfiguration("chat").get("disableAIFeatures", false);
|
|
7994
8541
|
if (aiDisabled) {
|
|
7995
8542
|
settings.showBuildWithAI = false;
|
|
@@ -7998,7 +8545,9 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
7998
8545
|
type: "init",
|
|
7999
8546
|
features: this._features,
|
|
8000
8547
|
columns,
|
|
8001
|
-
settings
|
|
8548
|
+
settings,
|
|
8549
|
+
boards,
|
|
8550
|
+
currentBoard
|
|
8002
8551
|
});
|
|
8003
8552
|
}
|
|
8004
8553
|
_addColumn(column) {
|
|
@@ -8012,14 +8561,14 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
8012
8561
|
while (existing.some((c) => c.id === uniqueId)) {
|
|
8013
8562
|
uniqueId = `${id}-${counter++}`;
|
|
8014
8563
|
}
|
|
8015
|
-
sdk.addColumn({ id: uniqueId, name: column.name, color: column.color });
|
|
8564
|
+
sdk.addColumn({ id: uniqueId, name: column.name, color: column.color }, this._currentBoardId);
|
|
8016
8565
|
this._sendFeaturesToWebview();
|
|
8017
8566
|
}
|
|
8018
8567
|
_editColumn(columnId, updates) {
|
|
8019
8568
|
const sdk = this._getSDK();
|
|
8020
8569
|
if (!sdk)
|
|
8021
8570
|
return;
|
|
8022
|
-
sdk.updateColumn(columnId, updates);
|
|
8571
|
+
sdk.updateColumn(columnId, updates, this._currentBoardId);
|
|
8023
8572
|
this._sendFeaturesToWebview();
|
|
8024
8573
|
}
|
|
8025
8574
|
_removeColumn(columnId) {
|
|
@@ -8036,14 +8585,15 @@ var KanbanPanel = class _KanbanPanel {
|
|
|
8036
8585
|
vscode.window.showWarningMessage("Cannot remove the last list.");
|
|
8037
8586
|
return;
|
|
8038
8587
|
}
|
|
8039
|
-
sdk.removeColumn(columnId);
|
|
8588
|
+
sdk.removeColumn(columnId, this._currentBoardId);
|
|
8040
8589
|
this._sendFeaturesToWebview();
|
|
8041
8590
|
}
|
|
8042
8591
|
};
|
|
8043
8592
|
|
|
8044
8593
|
// src/extension/SidebarViewProvider.ts
|
|
8045
8594
|
var vscode2 = __toESM(require("vscode"));
|
|
8046
|
-
var
|
|
8595
|
+
var path9 = __toESM(require("path"));
|
|
8596
|
+
init_types();
|
|
8047
8597
|
var SidebarViewProvider = class {
|
|
8048
8598
|
constructor(_extensionUri, _context) {
|
|
8049
8599
|
this._extensionUri = _extensionUri;
|
|
@@ -8161,7 +8711,7 @@ var SidebarViewProvider = class {
|
|
|
8161
8711
|
return null;
|
|
8162
8712
|
const root = workspaceFolders[0].uri.fsPath;
|
|
8163
8713
|
const config = readConfig(root);
|
|
8164
|
-
return
|
|
8714
|
+
return path9.join(root, config.featuresDirectory);
|
|
8165
8715
|
}
|
|
8166
8716
|
_getColumns() {
|
|
8167
8717
|
const featuresDir = this._getFeaturesDir();
|
|
@@ -8518,7 +9068,7 @@ async function createFeatureFromPrompts() {
|
|
|
8518
9068
|
});
|
|
8519
9069
|
const root = workspaceFolders[0].uri.fsPath;
|
|
8520
9070
|
const kanbanConfig = readConfig(root);
|
|
8521
|
-
const featuresDir =
|
|
9071
|
+
const featuresDir = path10.join(root, kanbanConfig.featuresDirectory);
|
|
8522
9072
|
const sdk = new KanbanSDK(featuresDir);
|
|
8523
9073
|
const content = `# ${title}${description ? "\n\n" + description : ""}`;
|
|
8524
9074
|
const feature = await sdk.createCard({ content, status, priority });
|
|
@@ -8554,8 +9104,8 @@ function activate(context) {
|
|
|
8554
9104
|
if (workspaceFolders) {
|
|
8555
9105
|
const root = workspaceFolders[0].uri.fsPath;
|
|
8556
9106
|
const kanbanConfig = readConfig(root);
|
|
8557
|
-
const featuresDir =
|
|
8558
|
-
const webviewDir =
|
|
9107
|
+
const featuresDir = path10.join(root, kanbanConfig.featuresDirectory);
|
|
9108
|
+
const webviewDir = path10.join(context.extensionPath, "dist", "standalone-webview");
|
|
8559
9109
|
findFreePort(3464).then((port) => {
|
|
8560
9110
|
standaloneServer = startServer(featuresDir, port, webviewDir);
|
|
8561
9111
|
standaloneServer.on("error", () => {
|