kanban-lite 1.2.2 → 1.2.4
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 +257 -90
- package/dist/extension.js +245 -78
- package/dist/mcp-server.js +117 -33
- package/dist/sdk/index.cjs +117 -32
- package/dist/sdk/index.mjs +117 -32
- package/dist/sdk/sdk/KanbanSDK.d.ts +27 -10
- package/dist/sdk/sdk/modules/cards.d.ts +11 -2
- package/dist/sdk/sdk/plugins/index.d.ts +7 -0
- package/dist/sdk/sdk/types.d.ts +12 -27
- package/dist/sdk/shared/config.d.ts +17 -1
- package/dist/standalone-webview/index.js +38 -38
- package/dist/standalone-webview/index.js.map +1 -1
- package/dist/standalone.js +307 -125
- package/package.json +1 -1
- package/src/cli/index.test.ts +157 -0
- package/src/cli/index.ts +1 -1
- package/src/mcp-server/index.test.ts +76 -0
- package/src/mcp-server/index.ts +1 -1
- package/src/sdk/KanbanSDK.d.ts +26 -10
- package/src/sdk/KanbanSDK.ts +37 -11
- package/src/sdk/__tests__/KanbanSDK.test.ts +79 -24
- package/src/sdk/integrationCatalog.ts +1 -0
- package/src/sdk/modules/cards.ts +13 -24
- package/src/sdk/plugins/index.d.ts +7 -0
- package/src/sdk/plugins/index.ts +17 -2
- package/src/sdk/types.d.ts +10 -26
- package/src/sdk/types.ts +11 -24
- package/src/sdk/webhooks.ts +19 -2
- package/src/shared/config.ts +130 -2
- package/src/standalone/__tests__/server.integration.test.ts +81 -2
- package/src/standalone/internal/runtime.ts +11 -6
- package/src/standalone/internal/websocket.ts +13 -3
- package/src/standalone/server.ts +67 -9
- package/src/standalone/watcherSetup.ts +9 -0
- package/src/webview/standalone-shim.ts +2 -1
- package/tmp/screenshots-workspace/.kanban/.active-card.json +5 -0
- package/tmp/screenshots-workspace/.kanban/boards/default/deleted/1-dddd.md +17 -0
- package/tmp/screenshots-workspace/.kanban/boards/default/deleted/attachments/1.log +1 -0
- package/tmp/screenshots-workspace/.kanban.json +59 -0
package/dist/extension.js
CHANGED
|
@@ -22970,7 +22970,7 @@ var require_thread_stream = __commonJS({
|
|
|
22970
22970
|
var { version } = require_package();
|
|
22971
22971
|
var { EventEmitter: EventEmitter3 } = require("events");
|
|
22972
22972
|
var { Worker } = require("worker_threads");
|
|
22973
|
-
var { join:
|
|
22973
|
+
var { join: join24 } = require("path");
|
|
22974
22974
|
var { pathToFileURL } = require("url");
|
|
22975
22975
|
var { wait } = require_wait();
|
|
22976
22976
|
var {
|
|
@@ -23006,7 +23006,7 @@ var require_thread_stream = __commonJS({
|
|
|
23006
23006
|
function createWorker(stream, opts) {
|
|
23007
23007
|
const { filename, workerData } = opts;
|
|
23008
23008
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
23009
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
23009
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join24(__dirname, "lib", "worker.js");
|
|
23010
23010
|
const worker = new Worker(toExecute, {
|
|
23011
23011
|
...opts.workerOpts,
|
|
23012
23012
|
trackUnmanagedFds: false,
|
|
@@ -23397,7 +23397,7 @@ var require_transport = __commonJS({
|
|
|
23397
23397
|
var { createRequire: createRequire2 } = require("module");
|
|
23398
23398
|
var { existsSync: existsSync4 } = require("node:fs");
|
|
23399
23399
|
var getCallers = require_caller();
|
|
23400
|
-
var { join:
|
|
23400
|
+
var { join: join24, isAbsolute: isAbsolute2, sep: sep2 } = require("node:path");
|
|
23401
23401
|
var { fileURLToPath } = require("node:url");
|
|
23402
23402
|
var sleep = require_atomic_sleep();
|
|
23403
23403
|
var onExit = require_on_exit_leak_free();
|
|
@@ -23550,7 +23550,7 @@ var require_transport = __commonJS({
|
|
|
23550
23550
|
throw new Error("only one of target or targets can be specified");
|
|
23551
23551
|
}
|
|
23552
23552
|
if (targets) {
|
|
23553
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
23553
|
+
target = bundlerOverrides["pino-worker"] || join24(__dirname, "worker.js");
|
|
23554
23554
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
23555
23555
|
return {
|
|
23556
23556
|
...dest,
|
|
@@ -23568,7 +23568,7 @@ var require_transport = __commonJS({
|
|
|
23568
23568
|
});
|
|
23569
23569
|
});
|
|
23570
23570
|
} else if (pipeline) {
|
|
23571
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
23571
|
+
target = bundlerOverrides["pino-worker"] || join24(__dirname, "worker.js");
|
|
23572
23572
|
options.pipelines = [pipeline.map((dest) => {
|
|
23573
23573
|
return {
|
|
23574
23574
|
...dest,
|
|
@@ -23591,7 +23591,7 @@ var require_transport = __commonJS({
|
|
|
23591
23591
|
return origin;
|
|
23592
23592
|
}
|
|
23593
23593
|
if (origin === "pino/file") {
|
|
23594
|
-
return
|
|
23594
|
+
return join24(__dirname, "..", "file.js");
|
|
23595
23595
|
}
|
|
23596
23596
|
let fixTarget2;
|
|
23597
23597
|
for (const filePath of callers) {
|
|
@@ -24581,7 +24581,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
24581
24581
|
return circularValue;
|
|
24582
24582
|
}
|
|
24583
24583
|
let res = "";
|
|
24584
|
-
let
|
|
24584
|
+
let join24 = ",";
|
|
24585
24585
|
const originalIndentation = indentation;
|
|
24586
24586
|
if (Array.isArray(value)) {
|
|
24587
24587
|
if (value.length === 0) {
|
|
@@ -24595,7 +24595,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
24595
24595
|
indentation += spacer;
|
|
24596
24596
|
res += `
|
|
24597
24597
|
${indentation}`;
|
|
24598
|
-
|
|
24598
|
+
join24 = `,
|
|
24599
24599
|
${indentation}`;
|
|
24600
24600
|
}
|
|
24601
24601
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -24603,13 +24603,13 @@ ${indentation}`;
|
|
|
24603
24603
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
24604
24604
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
24605
24605
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
24606
|
-
res +=
|
|
24606
|
+
res += join24;
|
|
24607
24607
|
}
|
|
24608
24608
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
24609
24609
|
res += tmp !== void 0 ? tmp : "null";
|
|
24610
24610
|
if (value.length - 1 > maximumBreadth) {
|
|
24611
24611
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
24612
|
-
res += `${
|
|
24612
|
+
res += `${join24}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
24613
24613
|
}
|
|
24614
24614
|
if (spacer !== "") {
|
|
24615
24615
|
res += `
|
|
@@ -24630,7 +24630,7 @@ ${originalIndentation}`;
|
|
|
24630
24630
|
let separator = "";
|
|
24631
24631
|
if (spacer !== "") {
|
|
24632
24632
|
indentation += spacer;
|
|
24633
|
-
|
|
24633
|
+
join24 = `,
|
|
24634
24634
|
${indentation}`;
|
|
24635
24635
|
whitespace = " ";
|
|
24636
24636
|
}
|
|
@@ -24644,13 +24644,13 @@ ${indentation}`;
|
|
|
24644
24644
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
24645
24645
|
if (tmp !== void 0) {
|
|
24646
24646
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
24647
|
-
separator =
|
|
24647
|
+
separator = join24;
|
|
24648
24648
|
}
|
|
24649
24649
|
}
|
|
24650
24650
|
if (keyLength > maximumBreadth) {
|
|
24651
24651
|
const removedKeys = keyLength - maximumBreadth;
|
|
24652
24652
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
24653
|
-
separator =
|
|
24653
|
+
separator = join24;
|
|
24654
24654
|
}
|
|
24655
24655
|
if (spacer !== "" && separator.length > 1) {
|
|
24656
24656
|
res = `
|
|
@@ -24690,7 +24690,7 @@ ${originalIndentation}`;
|
|
|
24690
24690
|
}
|
|
24691
24691
|
const originalIndentation = indentation;
|
|
24692
24692
|
let res = "";
|
|
24693
|
-
let
|
|
24693
|
+
let join24 = ",";
|
|
24694
24694
|
if (Array.isArray(value)) {
|
|
24695
24695
|
if (value.length === 0) {
|
|
24696
24696
|
return "[]";
|
|
@@ -24703,7 +24703,7 @@ ${originalIndentation}`;
|
|
|
24703
24703
|
indentation += spacer;
|
|
24704
24704
|
res += `
|
|
24705
24705
|
${indentation}`;
|
|
24706
|
-
|
|
24706
|
+
join24 = `,
|
|
24707
24707
|
${indentation}`;
|
|
24708
24708
|
}
|
|
24709
24709
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -24711,13 +24711,13 @@ ${indentation}`;
|
|
|
24711
24711
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
24712
24712
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
24713
24713
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
24714
|
-
res +=
|
|
24714
|
+
res += join24;
|
|
24715
24715
|
}
|
|
24716
24716
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
24717
24717
|
res += tmp !== void 0 ? tmp : "null";
|
|
24718
24718
|
if (value.length - 1 > maximumBreadth) {
|
|
24719
24719
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
24720
|
-
res += `${
|
|
24720
|
+
res += `${join24}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
24721
24721
|
}
|
|
24722
24722
|
if (spacer !== "") {
|
|
24723
24723
|
res += `
|
|
@@ -24730,7 +24730,7 @@ ${originalIndentation}`;
|
|
|
24730
24730
|
let whitespace = "";
|
|
24731
24731
|
if (spacer !== "") {
|
|
24732
24732
|
indentation += spacer;
|
|
24733
|
-
|
|
24733
|
+
join24 = `,
|
|
24734
24734
|
${indentation}`;
|
|
24735
24735
|
whitespace = " ";
|
|
24736
24736
|
}
|
|
@@ -24739,7 +24739,7 @@ ${indentation}`;
|
|
|
24739
24739
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
24740
24740
|
if (tmp !== void 0) {
|
|
24741
24741
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
24742
|
-
separator =
|
|
24742
|
+
separator = join24;
|
|
24743
24743
|
}
|
|
24744
24744
|
}
|
|
24745
24745
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -24796,20 +24796,20 @@ ${originalIndentation}`;
|
|
|
24796
24796
|
indentation += spacer;
|
|
24797
24797
|
let res2 = `
|
|
24798
24798
|
${indentation}`;
|
|
24799
|
-
const
|
|
24799
|
+
const join25 = `,
|
|
24800
24800
|
${indentation}`;
|
|
24801
24801
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
24802
24802
|
let i = 0;
|
|
24803
24803
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
24804
24804
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
24805
24805
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
24806
|
-
res2 +=
|
|
24806
|
+
res2 += join25;
|
|
24807
24807
|
}
|
|
24808
24808
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
24809
24809
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
24810
24810
|
if (value.length - 1 > maximumBreadth) {
|
|
24811
24811
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
24812
|
-
res2 += `${
|
|
24812
|
+
res2 += `${join25}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
24813
24813
|
}
|
|
24814
24814
|
res2 += `
|
|
24815
24815
|
${originalIndentation}`;
|
|
@@ -24825,16 +24825,16 @@ ${originalIndentation}`;
|
|
|
24825
24825
|
return '"[Object]"';
|
|
24826
24826
|
}
|
|
24827
24827
|
indentation += spacer;
|
|
24828
|
-
const
|
|
24828
|
+
const join24 = `,
|
|
24829
24829
|
${indentation}`;
|
|
24830
24830
|
let res = "";
|
|
24831
24831
|
let separator = "";
|
|
24832
24832
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
24833
24833
|
if (isTypedArrayWithEntries(value)) {
|
|
24834
|
-
res += stringifyTypedArray(value,
|
|
24834
|
+
res += stringifyTypedArray(value, join24, maximumBreadth);
|
|
24835
24835
|
keys = keys.slice(value.length);
|
|
24836
24836
|
maximumPropertiesToStringify -= value.length;
|
|
24837
|
-
separator =
|
|
24837
|
+
separator = join24;
|
|
24838
24838
|
}
|
|
24839
24839
|
if (deterministic) {
|
|
24840
24840
|
keys = sort(keys, comparator);
|
|
@@ -24845,13 +24845,13 @@ ${indentation}`;
|
|
|
24845
24845
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
24846
24846
|
if (tmp !== void 0) {
|
|
24847
24847
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
24848
|
-
separator =
|
|
24848
|
+
separator = join24;
|
|
24849
24849
|
}
|
|
24850
24850
|
}
|
|
24851
24851
|
if (keyLength > maximumBreadth) {
|
|
24852
24852
|
const removedKeys = keyLength - maximumBreadth;
|
|
24853
24853
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
24854
|
-
separator =
|
|
24854
|
+
separator = join24;
|
|
24855
24855
|
}
|
|
24856
24856
|
if (separator !== "") {
|
|
24857
24857
|
res = `
|
|
@@ -59636,7 +59636,7 @@ var require_send = __commonJS({
|
|
|
59636
59636
|
var { parseTokenList } = require_parseTokenList();
|
|
59637
59637
|
var { createHttpError } = require_createHttpError();
|
|
59638
59638
|
var extname5 = path24.extname;
|
|
59639
|
-
var
|
|
59639
|
+
var join24 = path24.join;
|
|
59640
59640
|
var normalize2 = path24.normalize;
|
|
59641
59641
|
var resolve10 = path24.resolve;
|
|
59642
59642
|
var sep2 = path24.sep;
|
|
@@ -59723,7 +59723,7 @@ var require_send = __commonJS({
|
|
|
59723
59723
|
return { statusCode: 403 };
|
|
59724
59724
|
}
|
|
59725
59725
|
parts = path25.split(sep2);
|
|
59726
|
-
path25 = normalize2(
|
|
59726
|
+
path25 = normalize2(join24(root, path25));
|
|
59727
59727
|
} else {
|
|
59728
59728
|
if (UP_PATH_REGEXP.test(path25)) {
|
|
59729
59729
|
debug('malicious path "%s"', path25);
|
|
@@ -60007,7 +60007,7 @@ var require_send = __commonJS({
|
|
|
60007
60007
|
let err;
|
|
60008
60008
|
for (let i = 0; i < options.index.length; i++) {
|
|
60009
60009
|
const index = options.index[i];
|
|
60010
|
-
const p =
|
|
60010
|
+
const p = join24(path25, index);
|
|
60011
60011
|
const { error, stat: stat4 } = await tryStat(p);
|
|
60012
60012
|
if (error) {
|
|
60013
60013
|
err = error;
|
|
@@ -65329,11 +65329,87 @@ function migrateConfigV1ToV2(raw) {
|
|
|
65329
65329
|
}
|
|
65330
65330
|
return v2;
|
|
65331
65331
|
}
|
|
65332
|
+
function loadDotEnv(dir) {
|
|
65333
|
+
const envPath = path.join(dir, ".env");
|
|
65334
|
+
let content;
|
|
65335
|
+
try {
|
|
65336
|
+
content = fs.readFileSync(envPath, "utf-8");
|
|
65337
|
+
} catch {
|
|
65338
|
+
return;
|
|
65339
|
+
}
|
|
65340
|
+
for (const line of content.split("\n")) {
|
|
65341
|
+
const trimmed = line.trim();
|
|
65342
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
65343
|
+
continue;
|
|
65344
|
+
const eqIdx = trimmed.indexOf("=");
|
|
65345
|
+
if (eqIdx < 1)
|
|
65346
|
+
continue;
|
|
65347
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
65348
|
+
let val = trimmed.slice(eqIdx + 1).trim();
|
|
65349
|
+
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
65350
|
+
val = val.slice(1, -1);
|
|
65351
|
+
}
|
|
65352
|
+
if (process.env[key] === void 0) {
|
|
65353
|
+
process.env[key] = val;
|
|
65354
|
+
}
|
|
65355
|
+
}
|
|
65356
|
+
}
|
|
65357
|
+
function resolveConfigEnvVars(node, configFileName, nodePath = "") {
|
|
65358
|
+
const isFormDefaultDataPath = /^\.forms\.(?:[^.]+|"[^"]+")\.data(?:$|[.\[])/.test(nodePath);
|
|
65359
|
+
if (isFormDefaultDataPath) {
|
|
65360
|
+
return node;
|
|
65361
|
+
}
|
|
65362
|
+
if (typeof node === "string") {
|
|
65363
|
+
return node.replace(/\$\{([^}]+)\}/g, (_match, varName) => {
|
|
65364
|
+
const envValue = process.env[varName];
|
|
65365
|
+
if (envValue === void 0) {
|
|
65366
|
+
throw new Error(
|
|
65367
|
+
`missing ${varName} in ${configFileName}: ${nodePath} "${node}"`
|
|
65368
|
+
);
|
|
65369
|
+
}
|
|
65370
|
+
return envValue;
|
|
65371
|
+
});
|
|
65372
|
+
}
|
|
65373
|
+
if (Array.isArray(node)) {
|
|
65374
|
+
for (let i = 0; i < node.length; i++) {
|
|
65375
|
+
node[i] = resolveConfigEnvVars(node[i], configFileName, `${nodePath}[${i}]`);
|
|
65376
|
+
}
|
|
65377
|
+
return node;
|
|
65378
|
+
}
|
|
65379
|
+
if (node !== null && typeof node === "object") {
|
|
65380
|
+
const obj = node;
|
|
65381
|
+
for (const key of Object.keys(obj)) {
|
|
65382
|
+
const jsonKey = /[^a-zA-Z0-9_]/.test(key) ? `"${key}"` : key;
|
|
65383
|
+
const childPath = nodePath ? `${nodePath}.${jsonKey}` : `.${jsonKey}`;
|
|
65384
|
+
obj[key] = resolveConfigEnvVars(obj[key], configFileName, childPath);
|
|
65385
|
+
}
|
|
65386
|
+
return obj;
|
|
65387
|
+
}
|
|
65388
|
+
return node;
|
|
65389
|
+
}
|
|
65332
65390
|
function readConfig(workspaceRoot) {
|
|
65333
65391
|
const filePath = configPath(workspaceRoot);
|
|
65334
65392
|
const defaults = { ...DEFAULT_CONFIG, boards: { default: { ...DEFAULT_BOARD_CONFIG, columns: [...DEFAULT_COLUMNS] } } };
|
|
65393
|
+
let raw;
|
|
65394
|
+
try {
|
|
65395
|
+
raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
65396
|
+
} catch {
|
|
65397
|
+
return defaults;
|
|
65398
|
+
}
|
|
65399
|
+
loadDotEnv(workspaceRoot);
|
|
65400
|
+
try {
|
|
65401
|
+
resolveConfigEnvVars(raw, CONFIG_FILENAME);
|
|
65402
|
+
} catch (err) {
|
|
65403
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
65404
|
+
process.stderr.write(`
|
|
65405
|
+
Configuration error: ${msg}
|
|
65406
|
+
|
|
65407
|
+
Set the missing environment variable before starting the server.
|
|
65408
|
+
|
|
65409
|
+
`);
|
|
65410
|
+
process.exit(1);
|
|
65411
|
+
}
|
|
65335
65412
|
try {
|
|
65336
|
-
const raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
65337
65413
|
const isV1 = raw.version === 1 || !raw.version && !(typeof raw.boards === "object" && raw.boards !== null && !Array.isArray(raw.boards));
|
|
65338
65414
|
if (isV1) {
|
|
65339
65415
|
const v2 = migrateConfigV1ToV2(raw);
|
|
@@ -68937,7 +69013,7 @@ function resolveAuthIdentityPlugin(ref) {
|
|
|
68937
69013
|
if (ref.provider === "rbac")
|
|
68938
69014
|
return RBAC_IDENTITY_PLUGIN;
|
|
68939
69015
|
const packageName = AUTH_PROVIDER_ALIASES.get(ref.provider) ?? ref.provider;
|
|
68940
|
-
return loadExternalAuthIdentityPlugin(packageName, ref.provider);
|
|
69016
|
+
return loadExternalAuthIdentityPlugin(packageName, ref.provider, ref.options);
|
|
68941
69017
|
}
|
|
68942
69018
|
function resolveAuthPolicyPlugin(ref) {
|
|
68943
69019
|
if (ref.provider === "noop")
|
|
@@ -69163,8 +69239,13 @@ function selectAuthPolicyPlugin(mod, providerId) {
|
|
|
69163
69239
|
return direct;
|
|
69164
69240
|
return null;
|
|
69165
69241
|
}
|
|
69166
|
-
function loadExternalAuthIdentityPlugin(packageName, providerId) {
|
|
69242
|
+
function loadExternalAuthIdentityPlugin(packageName, providerId, options) {
|
|
69167
69243
|
const mod = loadExternalModule(packageName);
|
|
69244
|
+
if (options !== void 0 && typeof mod.createAuthIdentityPlugin === "function") {
|
|
69245
|
+
const created = mod.createAuthIdentityPlugin(options);
|
|
69246
|
+
if (isValidAuthIdentityPlugin(created, providerId))
|
|
69247
|
+
return created;
|
|
69248
|
+
}
|
|
69168
69249
|
const plugin = selectAuthIdentityPlugin(mod, providerId);
|
|
69169
69250
|
if (!plugin) {
|
|
69170
69251
|
throw new Error(
|
|
@@ -72167,29 +72248,10 @@ async function updateCard(ctx, { cardId, updates, boardId }) {
|
|
|
72167
72248
|
return card;
|
|
72168
72249
|
}
|
|
72169
72250
|
async function triggerAction(ctx, { cardId, action, boardId }) {
|
|
72170
|
-
const config = readConfig(ctx.workspaceRoot);
|
|
72171
|
-
const { actionWebhookUrl } = config;
|
|
72172
|
-
if (!actionWebhookUrl) {
|
|
72173
|
-
throw new Error("No action webhook URL configured. Set actionWebhookUrl in .kanban.json");
|
|
72174
|
-
}
|
|
72175
72251
|
const card = await getCard(ctx, { cardId, boardId });
|
|
72176
72252
|
if (!card)
|
|
72177
72253
|
throw new Error(`Card not found: ${cardId}`);
|
|
72178
72254
|
const resolvedBoardId = card.boardId || ctx._resolveBoardId(boardId);
|
|
72179
|
-
const payload = {
|
|
72180
|
-
action,
|
|
72181
|
-
board: resolvedBoardId,
|
|
72182
|
-
list: card.status,
|
|
72183
|
-
card: sanitizeCard(card)
|
|
72184
|
-
};
|
|
72185
|
-
const response = await fetch(actionWebhookUrl, {
|
|
72186
|
-
method: "POST",
|
|
72187
|
-
headers: { "Content-Type": "application/json" },
|
|
72188
|
-
body: JSON.stringify(payload)
|
|
72189
|
-
});
|
|
72190
|
-
if (!response.ok) {
|
|
72191
|
-
throw new Error(`Action webhook responded with ${response.status}: ${response.statusText}`);
|
|
72192
|
-
}
|
|
72193
72255
|
await appendActivityLog(ctx, {
|
|
72194
72256
|
cardId,
|
|
72195
72257
|
boardId: resolvedBoardId,
|
|
@@ -72200,6 +72262,12 @@ async function triggerAction(ctx, { cardId, action, boardId }) {
|
|
|
72200
72262
|
}
|
|
72201
72263
|
}).catch(() => {
|
|
72202
72264
|
});
|
|
72265
|
+
return {
|
|
72266
|
+
action,
|
|
72267
|
+
board: resolvedBoardId,
|
|
72268
|
+
list: card.status,
|
|
72269
|
+
card: sanitizeCard(card)
|
|
72270
|
+
};
|
|
72203
72271
|
}
|
|
72204
72272
|
async function submitForm(ctx, input) {
|
|
72205
72273
|
const card = await getCard(ctx, { cardId: input.cardId, boardId: input.boardId });
|
|
@@ -73616,6 +73684,25 @@ var KanbanSDK = class _KanbanSDK {
|
|
|
73616
73684
|
get workspaceRoot() {
|
|
73617
73685
|
return path14.dirname(this.kanbanDir);
|
|
73618
73686
|
}
|
|
73687
|
+
/**
|
|
73688
|
+
* Returns a cloned read-only snapshot of the current workspace config.
|
|
73689
|
+
*
|
|
73690
|
+
* The returned snapshot is created from a fresh config read and deep-cloned
|
|
73691
|
+
* before being returned, so callers receive an isolated view of the current
|
|
73692
|
+
* `.kanban.json` state rather than a live mutable runtime object. Mutating the
|
|
73693
|
+
* returned snapshot does not update persisted config or affect this SDK instance.
|
|
73694
|
+
*
|
|
73695
|
+
* @returns A cloned read-only snapshot of the current {@link KanbanConfig}.
|
|
73696
|
+
*
|
|
73697
|
+
* @example
|
|
73698
|
+
* ```ts
|
|
73699
|
+
* const config = sdk.getConfigSnapshot()
|
|
73700
|
+
* console.log(config.defaultBoard)
|
|
73701
|
+
* ```
|
|
73702
|
+
*/
|
|
73703
|
+
getConfigSnapshot() {
|
|
73704
|
+
return structuredClone(readConfig(this.workspaceRoot));
|
|
73705
|
+
}
|
|
73619
73706
|
// --- Board resolution helpers ---
|
|
73620
73707
|
/** @internal */
|
|
73621
73708
|
_resolveBoardId(boardId) {
|
|
@@ -74082,21 +74169,17 @@ var KanbanSDK = class _KanbanSDK {
|
|
|
74082
74169
|
return result;
|
|
74083
74170
|
}
|
|
74084
74171
|
/**
|
|
74085
|
-
* Triggers a named action for a card
|
|
74086
|
-
* configured in `.kanban.json`.
|
|
74172
|
+
* Triggers a named action for a card.
|
|
74087
74173
|
*
|
|
74088
|
-
*
|
|
74089
|
-
*
|
|
74090
|
-
*
|
|
74091
|
-
* ```
|
|
74174
|
+
* Validates the card, appends an activity log entry, and emits the
|
|
74175
|
+
* `card.action.triggered` after-event so registered webhooks receive
|
|
74176
|
+
* the action payload automatically.
|
|
74092
74177
|
*
|
|
74093
74178
|
* @param cardId - The ID of the card to trigger the action for.
|
|
74094
74179
|
* @param action - The action name string (e.g. `'retry'`, `'sendEmail'`).
|
|
74095
74180
|
* @param boardId - Optional board ID. Defaults to the workspace's default board.
|
|
74096
|
-
* @returns A promise
|
|
74097
|
-
* @throws {Error} If no `actionWebhookUrl` is configured in `.kanban.json`.
|
|
74181
|
+
* @returns A promise that resolves when the action has been processed.
|
|
74098
74182
|
* @throws {Error} If the card is not found.
|
|
74099
|
-
* @throws {Error} If the webhook responds with a non-2xx status.
|
|
74100
74183
|
*
|
|
74101
74184
|
* @example
|
|
74102
74185
|
* ```ts
|
|
@@ -74106,7 +74189,8 @@ var KanbanSDK = class _KanbanSDK {
|
|
|
74106
74189
|
*/
|
|
74107
74190
|
async triggerAction(cardId, action, boardId) {
|
|
74108
74191
|
const mergedInput = await this._runBeforeEvent("card.action.trigger", { cardId, action, boardId }, void 0, boardId);
|
|
74109
|
-
|
|
74192
|
+
const payload = await triggerAction(this, mergedInput);
|
|
74193
|
+
this._runAfterEvent("card.action.triggered", payload, void 0, payload.board);
|
|
74110
74194
|
}
|
|
74111
74195
|
/**
|
|
74112
74196
|
* Moves a card to a different status column and/or position within that column.
|
|
@@ -78318,6 +78402,13 @@ function setupWatcher(ctx, server) {
|
|
|
78318
78402
|
ctx.wss.close();
|
|
78319
78403
|
});
|
|
78320
78404
|
}
|
|
78405
|
+
const configFilePath = path16.join(ctx.workspaceRoot, ".kanban.json");
|
|
78406
|
+
const configWatcher = esm_default.watch(configFilePath, {
|
|
78407
|
+
ignoreInitial: true,
|
|
78408
|
+
awaitWriteFinish: { stabilityThreshold: 100 }
|
|
78409
|
+
});
|
|
78410
|
+
configWatcher.on("change", () => handleFileChange(ctx, debounceRef));
|
|
78411
|
+
server.on("close", () => configWatcher.close());
|
|
78321
78412
|
}
|
|
78322
78413
|
|
|
78323
78414
|
// src/standalone/httpUtils.ts
|
|
@@ -78494,20 +78585,24 @@ async function handleCardFileRoute(request) {
|
|
|
78494
78585
|
var http = __toESM(require("http"));
|
|
78495
78586
|
var fs12 = __toESM(require("fs"));
|
|
78496
78587
|
var path18 = __toESM(require("path"));
|
|
78497
|
-
|
|
78588
|
+
function getIndexHtml(basePath = "") {
|
|
78589
|
+
return `<!DOCTYPE html>
|
|
78498
78590
|
<html lang="en">
|
|
78499
78591
|
<head>
|
|
78500
78592
|
<meta charset="UTF-8">
|
|
78501
78593
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
78502
|
-
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
78503
|
-
<link href="/style.css" rel="stylesheet">
|
|
78594
|
+
<link rel="icon" type="image/svg+xml" href="${basePath}/favicon.svg">
|
|
78595
|
+
<link href="${basePath}/style.css" rel="stylesheet">
|
|
78504
78596
|
<title>Kanban Board</title>
|
|
78597
|
+
<script>window.__KB_BASE__ = ${JSON.stringify(basePath)}</script>
|
|
78505
78598
|
</head>
|
|
78506
78599
|
<body>
|
|
78507
78600
|
<div id="root"></div>
|
|
78508
|
-
<script type="module" src="/index.js"></script>
|
|
78601
|
+
<script type="module" src="${basePath}/index.js"></script>
|
|
78509
78602
|
</body>
|
|
78510
78603
|
</html>`;
|
|
78604
|
+
}
|
|
78605
|
+
var indexHtml = getIndexHtml();
|
|
78511
78606
|
function resolveStandaloneWebviewDir(webviewDir) {
|
|
78512
78607
|
if (webviewDir)
|
|
78513
78608
|
return webviewDir;
|
|
@@ -78521,12 +78616,12 @@ function resolveStandaloneWebviewDir(webviewDir) {
|
|
|
78521
78616
|
}
|
|
78522
78617
|
return candidates[0];
|
|
78523
78618
|
}
|
|
78524
|
-
function createStandaloneRuntime(kanbanDir, webviewDir, httpServer) {
|
|
78619
|
+
function createStandaloneRuntime(kanbanDir, webviewDir, httpServer, basePath) {
|
|
78525
78620
|
const absoluteKanbanDir = path18.resolve(kanbanDir);
|
|
78526
78621
|
const workspaceRoot = path18.dirname(absoluteKanbanDir);
|
|
78527
78622
|
const resolvedWebviewDir = resolveStandaloneWebviewDir(webviewDir);
|
|
78528
78623
|
const server = httpServer ?? http.createServer();
|
|
78529
|
-
const wss = new import_websocket_server.default({ server, path: "/ws" });
|
|
78624
|
+
const wss = new import_websocket_server.default({ server, path: (basePath || "") + "/ws" });
|
|
78530
78625
|
const ctx = {};
|
|
78531
78626
|
const sdk = new KanbanSDK(absoluteKanbanDir, {
|
|
78532
78627
|
onEvent: (event, data) => {
|
|
@@ -80574,9 +80669,14 @@ async function handleMessage(ctx, ws, message, authContext) {
|
|
|
80574
80669
|
}
|
|
80575
80670
|
|
|
80576
80671
|
// src/standalone/internal/websocket.ts
|
|
80577
|
-
function attachWebSocketHandlers(ctx) {
|
|
80578
|
-
ctx.wss.on("connection", (ws, req) => {
|
|
80579
|
-
|
|
80672
|
+
function attachWebSocketHandlers(ctx, resolveAuthContext) {
|
|
80673
|
+
ctx.wss.on("connection", async (ws, req) => {
|
|
80674
|
+
let authContext;
|
|
80675
|
+
try {
|
|
80676
|
+
authContext = resolveAuthContext ? await resolveAuthContext(req) : extractAuthContext(req);
|
|
80677
|
+
} catch {
|
|
80678
|
+
authContext = extractAuthContext(req);
|
|
80679
|
+
}
|
|
80580
80680
|
setClientEditingCard(ctx, ws, null);
|
|
80581
80681
|
ws.on("message", (data) => {
|
|
80582
80682
|
let message;
|
|
@@ -80743,6 +80843,7 @@ function isPageRequest(method, pathname) {
|
|
|
80743
80843
|
function collectStandaloneHttpHandlers(requestType, ctx) {
|
|
80744
80844
|
const plugins = ctx.sdk.capabilities?.standaloneHttpPlugins ?? [];
|
|
80745
80845
|
const registrationOptions = {
|
|
80846
|
+
sdk: ctx.sdk,
|
|
80746
80847
|
workspaceRoot: ctx.workspaceRoot,
|
|
80747
80848
|
kanbanDir: ctx.absoluteKanbanDir,
|
|
80748
80849
|
capabilities: ctx.sdk.capabilities?.providers ?? {
|
|
@@ -80800,10 +80901,13 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
80800
80901
|
const swaggerUiStaticDir = resolveSwaggerUiStaticDir();
|
|
80801
80902
|
const swaggerUiLogoPath = swaggerUiStaticDir ? path20.join(swaggerUiStaticDir, "logo.svg") : void 0;
|
|
80802
80903
|
const swaggerUiLogo = swaggerUiLogoPath && fs15.existsSync(swaggerUiLogoPath) ? { type: "image/svg+xml", content: fs15.readFileSync(swaggerUiLogoPath) } : null;
|
|
80803
|
-
const
|
|
80904
|
+
const workspaceRoot = path20.dirname(path20.resolve(kanbanDir));
|
|
80905
|
+
const config = readConfig(workspaceRoot);
|
|
80906
|
+
const rawBase = config.basePath ?? "";
|
|
80907
|
+
const basePath = rawBase ? (rawBase.startsWith("/") ? rawBase : "/" + rawBase).replace(/\/+$/, "") : "";
|
|
80908
|
+
const runtime = createStandaloneRuntime(kanbanDir, webviewDir, fastify.server, basePath);
|
|
80804
80909
|
const { ctx, resolvedWebviewDir } = runtime;
|
|
80805
|
-
|
|
80806
|
-
let resolvedIndexHtml = indexHtml;
|
|
80910
|
+
let resolvedIndexHtml = getIndexHtml(basePath);
|
|
80807
80911
|
let customHead = config.customHeadHtml || "";
|
|
80808
80912
|
if (config.customHeadHtmlFile) {
|
|
80809
80913
|
try {
|
|
@@ -80813,14 +80917,14 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
80813
80917
|
}
|
|
80814
80918
|
}
|
|
80815
80919
|
if (customHead) {
|
|
80816
|
-
resolvedIndexHtml =
|
|
80920
|
+
resolvedIndexHtml = resolvedIndexHtml.replace("</head>", `${customHead}
|
|
80817
80921
|
</head>`);
|
|
80818
80922
|
}
|
|
80819
80923
|
const standaloneHttpPlugins = ctx.sdk.capabilities?.standaloneHttpPlugins ?? [];
|
|
80820
80924
|
const standaloneOpenApiSpec = buildStandaloneOpenApiSpec(standaloneHttpPlugins);
|
|
80821
80925
|
fastify.register(import_swagger.default, { openapi: standaloneOpenApiSpec });
|
|
80822
80926
|
fastify.register(import_swagger_ui.default, {
|
|
80823
|
-
routePrefix:
|
|
80927
|
+
routePrefix: `${basePath}/api/docs`,
|
|
80824
80928
|
uiConfig: { docExpansion: "list", deepLinking: false },
|
|
80825
80929
|
logo: swaggerUiLogo,
|
|
80826
80930
|
...swaggerUiStaticDir ? { baseDir: swaggerUiStaticDir } : {}
|
|
@@ -80852,6 +80956,14 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
80852
80956
|
if (request.body instanceof Buffer && request.body.length > 0) {
|
|
80853
80957
|
req._rawBody = request.body;
|
|
80854
80958
|
}
|
|
80959
|
+
if (basePath) {
|
|
80960
|
+
const rawUrl = req.url ?? "/";
|
|
80961
|
+
if (rawUrl === basePath) {
|
|
80962
|
+
req.url = "/";
|
|
80963
|
+
} else if (rawUrl.startsWith(basePath + "/") || rawUrl.startsWith(basePath + "?")) {
|
|
80964
|
+
req.url = rawUrl.slice(basePath.length);
|
|
80965
|
+
}
|
|
80966
|
+
}
|
|
80855
80967
|
const requestContext = createRequestContext(ctx, req, reply.raw, resolvedWebviewDir, resolvedIndexHtml);
|
|
80856
80968
|
await dispatchRequest(requestContext, middlewareHandlers);
|
|
80857
80969
|
if (!reply.sent && !reply.raw.writableEnded) {
|
|
@@ -80859,7 +80971,62 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
80859
80971
|
}
|
|
80860
80972
|
reply.hijack();
|
|
80861
80973
|
});
|
|
80862
|
-
|
|
80974
|
+
const resolveWsAuthContext = async (req) => {
|
|
80975
|
+
const silentRes = /* @__PURE__ */ (() => {
|
|
80976
|
+
const r = {
|
|
80977
|
+
writableEnded: false,
|
|
80978
|
+
writeHead() {
|
|
80979
|
+
return r;
|
|
80980
|
+
},
|
|
80981
|
+
setHeader() {
|
|
80982
|
+
return r;
|
|
80983
|
+
},
|
|
80984
|
+
removeHeader() {
|
|
80985
|
+
},
|
|
80986
|
+
getHeader() {
|
|
80987
|
+
return void 0;
|
|
80988
|
+
},
|
|
80989
|
+
getHeaders() {
|
|
80990
|
+
return {};
|
|
80991
|
+
},
|
|
80992
|
+
end(..._args) {
|
|
80993
|
+
r.writableEnded = true;
|
|
80994
|
+
return r;
|
|
80995
|
+
},
|
|
80996
|
+
write() {
|
|
80997
|
+
return false;
|
|
80998
|
+
}
|
|
80999
|
+
};
|
|
81000
|
+
return r;
|
|
81001
|
+
})();
|
|
81002
|
+
const reqWithBody = req;
|
|
81003
|
+
const wsUrl = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
81004
|
+
const requestContext = {
|
|
81005
|
+
ctx,
|
|
81006
|
+
sdk: ctx.sdk,
|
|
81007
|
+
workspaceRoot: ctx.workspaceRoot,
|
|
81008
|
+
kanbanDir: ctx.absoluteKanbanDir,
|
|
81009
|
+
req: reqWithBody,
|
|
81010
|
+
res: silentRes,
|
|
81011
|
+
url: wsUrl,
|
|
81012
|
+
pathname: wsUrl.pathname,
|
|
81013
|
+
method: "GET",
|
|
81014
|
+
resolvedWebviewDir,
|
|
81015
|
+
indexHtml: resolvedIndexHtml,
|
|
81016
|
+
route: createRouteMatcher("GET", wsUrl.pathname, matchRoute),
|
|
81017
|
+
isApiRequest: false,
|
|
81018
|
+
isPageRequest: false,
|
|
81019
|
+
getAuthContext: () => getRequestAuthContext(req),
|
|
81020
|
+
setAuthContext: (auth) => setRequestAuthContext(req, auth),
|
|
81021
|
+
mergeAuthContext: (auth) => mergeRequestAuthContext(req, auth)
|
|
81022
|
+
};
|
|
81023
|
+
for (const handler of middlewareHandlers) {
|
|
81024
|
+
if (await handler(requestContext))
|
|
81025
|
+
break;
|
|
81026
|
+
}
|
|
81027
|
+
return extractAuthContext(req);
|
|
81028
|
+
};
|
|
81029
|
+
attachWebSocketHandlers(ctx, resolveWsAuthContext);
|
|
80863
81030
|
setupStandaloneLifecycle(ctx, fastify.server);
|
|
80864
81031
|
const effectiveConfigPath = resolvedConfigPath ?? configPath(path20.dirname(ctx.absoluteKanbanDir));
|
|
80865
81032
|
fastify.listen({ port, host: "0.0.0.0" }, (err) => {
|
|
@@ -80867,7 +81034,7 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
80867
81034
|
console.error("Failed to start server:", err);
|
|
80868
81035
|
process.exit(1);
|
|
80869
81036
|
}
|
|
80870
|
-
console.log(`Kanban board running at http://localhost:${port}`);
|
|
81037
|
+
console.log(`Kanban board running at http://localhost:${port}${basePath}`);
|
|
80871
81038
|
console.log(`API available at http://localhost:${port}/api`);
|
|
80872
81039
|
console.log(`Kanban config: ${effectiveConfigPath}`);
|
|
80873
81040
|
console.log(`Kanban directory: ${ctx.absoluteKanbanDir}`);
|