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/cli.js
CHANGED
|
@@ -173,11 +173,87 @@ function migrateConfigV1ToV2(raw) {
|
|
|
173
173
|
}
|
|
174
174
|
return v2;
|
|
175
175
|
}
|
|
176
|
+
function loadDotEnv(dir) {
|
|
177
|
+
const envPath = path.join(dir, ".env");
|
|
178
|
+
let content;
|
|
179
|
+
try {
|
|
180
|
+
content = fs.readFileSync(envPath, "utf-8");
|
|
181
|
+
} catch {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
for (const line of content.split("\n")) {
|
|
185
|
+
const trimmed = line.trim();
|
|
186
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
187
|
+
continue;
|
|
188
|
+
const eqIdx = trimmed.indexOf("=");
|
|
189
|
+
if (eqIdx < 1)
|
|
190
|
+
continue;
|
|
191
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
192
|
+
let val = trimmed.slice(eqIdx + 1).trim();
|
|
193
|
+
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
194
|
+
val = val.slice(1, -1);
|
|
195
|
+
}
|
|
196
|
+
if (process.env[key] === void 0) {
|
|
197
|
+
process.env[key] = val;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function resolveConfigEnvVars(node, configFileName, nodePath = "") {
|
|
202
|
+
const isFormDefaultDataPath = /^\.forms\.(?:[^.]+|"[^"]+")\.data(?:$|[.\[])/.test(nodePath);
|
|
203
|
+
if (isFormDefaultDataPath) {
|
|
204
|
+
return node;
|
|
205
|
+
}
|
|
206
|
+
if (typeof node === "string") {
|
|
207
|
+
return node.replace(/\$\{([^}]+)\}/g, (_match, varName) => {
|
|
208
|
+
const envValue = process.env[varName];
|
|
209
|
+
if (envValue === void 0) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
`missing ${varName} in ${configFileName}: ${nodePath} "${node}"`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return envValue;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
if (Array.isArray(node)) {
|
|
218
|
+
for (let i = 0; i < node.length; i++) {
|
|
219
|
+
node[i] = resolveConfigEnvVars(node[i], configFileName, `${nodePath}[${i}]`);
|
|
220
|
+
}
|
|
221
|
+
return node;
|
|
222
|
+
}
|
|
223
|
+
if (node !== null && typeof node === "object") {
|
|
224
|
+
const obj = node;
|
|
225
|
+
for (const key of Object.keys(obj)) {
|
|
226
|
+
const jsonKey = /[^a-zA-Z0-9_]/.test(key) ? `"${key}"` : key;
|
|
227
|
+
const childPath = nodePath ? `${nodePath}.${jsonKey}` : `.${jsonKey}`;
|
|
228
|
+
obj[key] = resolveConfigEnvVars(obj[key], configFileName, childPath);
|
|
229
|
+
}
|
|
230
|
+
return obj;
|
|
231
|
+
}
|
|
232
|
+
return node;
|
|
233
|
+
}
|
|
176
234
|
function readConfig(workspaceRoot) {
|
|
177
235
|
const filePath = configPath(workspaceRoot);
|
|
178
236
|
const defaults = { ...DEFAULT_CONFIG, boards: { default: { ...DEFAULT_BOARD_CONFIG, columns: [...DEFAULT_COLUMNS] } } };
|
|
237
|
+
let raw;
|
|
238
|
+
try {
|
|
239
|
+
raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
240
|
+
} catch {
|
|
241
|
+
return defaults;
|
|
242
|
+
}
|
|
243
|
+
loadDotEnv(workspaceRoot);
|
|
244
|
+
try {
|
|
245
|
+
resolveConfigEnvVars(raw, CONFIG_FILENAME);
|
|
246
|
+
} catch (err) {
|
|
247
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
248
|
+
process.stderr.write(`
|
|
249
|
+
Configuration error: ${msg}
|
|
250
|
+
|
|
251
|
+
Set the missing environment variable before starting the server.
|
|
252
|
+
|
|
253
|
+
`);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
179
256
|
try {
|
|
180
|
-
const raw = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
181
257
|
const isV1 = raw.version === 1 || !raw.version && !(typeof raw.boards === "object" && raw.boards !== null && !Array.isArray(raw.boards));
|
|
182
258
|
if (isV1) {
|
|
183
259
|
const v2 = migrateConfigV1ToV2(raw);
|
|
@@ -5315,7 +5391,7 @@ function resolveAuthIdentityPlugin(ref) {
|
|
|
5315
5391
|
if (ref.provider === "rbac")
|
|
5316
5392
|
return RBAC_IDENTITY_PLUGIN;
|
|
5317
5393
|
const packageName = AUTH_PROVIDER_ALIASES.get(ref.provider) ?? ref.provider;
|
|
5318
|
-
return loadExternalAuthIdentityPlugin(packageName, ref.provider);
|
|
5394
|
+
return loadExternalAuthIdentityPlugin(packageName, ref.provider, ref.options);
|
|
5319
5395
|
}
|
|
5320
5396
|
function resolveAuthPolicyPlugin(ref) {
|
|
5321
5397
|
if (ref.provider === "noop")
|
|
@@ -5447,8 +5523,13 @@ function selectAuthPolicyPlugin(mod, providerId) {
|
|
|
5447
5523
|
return direct;
|
|
5448
5524
|
return null;
|
|
5449
5525
|
}
|
|
5450
|
-
function loadExternalAuthIdentityPlugin(packageName, providerId) {
|
|
5526
|
+
function loadExternalAuthIdentityPlugin(packageName, providerId, options) {
|
|
5451
5527
|
const mod = loadExternalModule(packageName);
|
|
5528
|
+
if (options !== void 0 && typeof mod.createAuthIdentityPlugin === "function") {
|
|
5529
|
+
const created = mod.createAuthIdentityPlugin(options);
|
|
5530
|
+
if (isValidAuthIdentityPlugin(created, providerId))
|
|
5531
|
+
return created;
|
|
5532
|
+
}
|
|
5452
5533
|
const plugin = selectAuthIdentityPlugin(mod, providerId);
|
|
5453
5534
|
if (!plugin) {
|
|
5454
5535
|
throw new Error(
|
|
@@ -24633,29 +24714,10 @@ async function updateCard(ctx, { cardId, updates, boardId }) {
|
|
|
24633
24714
|
return card;
|
|
24634
24715
|
}
|
|
24635
24716
|
async function triggerAction(ctx, { cardId, action, boardId }) {
|
|
24636
|
-
const config3 = readConfig(ctx.workspaceRoot);
|
|
24637
|
-
const { actionWebhookUrl } = config3;
|
|
24638
|
-
if (!actionWebhookUrl) {
|
|
24639
|
-
throw new Error("No action webhook URL configured. Set actionWebhookUrl in .kanban.json");
|
|
24640
|
-
}
|
|
24641
24717
|
const card = await getCard(ctx, { cardId, boardId });
|
|
24642
24718
|
if (!card)
|
|
24643
24719
|
throw new Error(`Card not found: ${cardId}`);
|
|
24644
24720
|
const resolvedBoardId = card.boardId || ctx._resolveBoardId(boardId);
|
|
24645
|
-
const payload = {
|
|
24646
|
-
action,
|
|
24647
|
-
board: resolvedBoardId,
|
|
24648
|
-
list: card.status,
|
|
24649
|
-
card: sanitizeCard(card)
|
|
24650
|
-
};
|
|
24651
|
-
const response = await fetch(actionWebhookUrl, {
|
|
24652
|
-
method: "POST",
|
|
24653
|
-
headers: { "Content-Type": "application/json" },
|
|
24654
|
-
body: JSON.stringify(payload)
|
|
24655
|
-
});
|
|
24656
|
-
if (!response.ok) {
|
|
24657
|
-
throw new Error(`Action webhook responded with ${response.status}: ${response.statusText}`);
|
|
24658
|
-
}
|
|
24659
24721
|
await appendActivityLog(ctx, {
|
|
24660
24722
|
cardId,
|
|
24661
24723
|
boardId: resolvedBoardId,
|
|
@@ -24666,6 +24728,12 @@ async function triggerAction(ctx, { cardId, action, boardId }) {
|
|
|
24666
24728
|
}
|
|
24667
24729
|
}).catch(() => {
|
|
24668
24730
|
});
|
|
24731
|
+
return {
|
|
24732
|
+
action,
|
|
24733
|
+
board: resolvedBoardId,
|
|
24734
|
+
list: card.status,
|
|
24735
|
+
card: sanitizeCard(card)
|
|
24736
|
+
};
|
|
24669
24737
|
}
|
|
24670
24738
|
async function submitForm(ctx, input) {
|
|
24671
24739
|
const card = await getCard(ctx, { cardId: input.cardId, boardId: input.boardId });
|
|
@@ -26170,6 +26238,25 @@ var init_KanbanSDK = __esm({
|
|
|
26170
26238
|
get workspaceRoot() {
|
|
26171
26239
|
return path14.dirname(this.kanbanDir);
|
|
26172
26240
|
}
|
|
26241
|
+
/**
|
|
26242
|
+
* Returns a cloned read-only snapshot of the current workspace config.
|
|
26243
|
+
*
|
|
26244
|
+
* The returned snapshot is created from a fresh config read and deep-cloned
|
|
26245
|
+
* before being returned, so callers receive an isolated view of the current
|
|
26246
|
+
* `.kanban.json` state rather than a live mutable runtime object. Mutating the
|
|
26247
|
+
* returned snapshot does not update persisted config or affect this SDK instance.
|
|
26248
|
+
*
|
|
26249
|
+
* @returns A cloned read-only snapshot of the current {@link KanbanConfig}.
|
|
26250
|
+
*
|
|
26251
|
+
* @example
|
|
26252
|
+
* ```ts
|
|
26253
|
+
* const config = sdk.getConfigSnapshot()
|
|
26254
|
+
* console.log(config.defaultBoard)
|
|
26255
|
+
* ```
|
|
26256
|
+
*/
|
|
26257
|
+
getConfigSnapshot() {
|
|
26258
|
+
return structuredClone(readConfig(this.workspaceRoot));
|
|
26259
|
+
}
|
|
26173
26260
|
// --- Board resolution helpers ---
|
|
26174
26261
|
/** @internal */
|
|
26175
26262
|
_resolveBoardId(boardId) {
|
|
@@ -26636,21 +26723,17 @@ var init_KanbanSDK = __esm({
|
|
|
26636
26723
|
return result;
|
|
26637
26724
|
}
|
|
26638
26725
|
/**
|
|
26639
|
-
* Triggers a named action for a card
|
|
26640
|
-
* configured in `.kanban.json`.
|
|
26726
|
+
* Triggers a named action for a card.
|
|
26641
26727
|
*
|
|
26642
|
-
*
|
|
26643
|
-
*
|
|
26644
|
-
*
|
|
26645
|
-
* ```
|
|
26728
|
+
* Validates the card, appends an activity log entry, and emits the
|
|
26729
|
+
* `card.action.triggered` after-event so registered webhooks receive
|
|
26730
|
+
* the action payload automatically.
|
|
26646
26731
|
*
|
|
26647
26732
|
* @param cardId - The ID of the card to trigger the action for.
|
|
26648
26733
|
* @param action - The action name string (e.g. `'retry'`, `'sendEmail'`).
|
|
26649
26734
|
* @param boardId - Optional board ID. Defaults to the workspace's default board.
|
|
26650
|
-
* @returns A promise
|
|
26651
|
-
* @throws {Error} If no `actionWebhookUrl` is configured in `.kanban.json`.
|
|
26735
|
+
* @returns A promise that resolves when the action has been processed.
|
|
26652
26736
|
* @throws {Error} If the card is not found.
|
|
26653
|
-
* @throws {Error} If the webhook responds with a non-2xx status.
|
|
26654
26737
|
*
|
|
26655
26738
|
* @example
|
|
26656
26739
|
* ```ts
|
|
@@ -26660,7 +26743,8 @@ var init_KanbanSDK = __esm({
|
|
|
26660
26743
|
*/
|
|
26661
26744
|
async triggerAction(cardId, action, boardId) {
|
|
26662
26745
|
const mergedInput = await this._runBeforeEvent("card.action.trigger", { cardId, action, boardId }, void 0, boardId);
|
|
26663
|
-
|
|
26746
|
+
const payload = await triggerAction(this, mergedInput);
|
|
26747
|
+
this._runAfterEvent("card.action.triggered", payload, void 0, payload.board);
|
|
26664
26748
|
}
|
|
26665
26749
|
/**
|
|
26666
26750
|
* Moves a card to a different status column and/or position within that column.
|
|
@@ -60340,7 +60424,7 @@ async function main() {
|
|
|
60340
60424
|
);
|
|
60341
60425
|
server.tool(
|
|
60342
60426
|
"trigger_action",
|
|
60343
|
-
"Trigger a named action on a card. The action name must match one of the card's configured actions.
|
|
60427
|
+
"Trigger a named action on a card. The action name must match one of the card's configured actions. Emits a card.action.triggered event delivered to registered webhooks.",
|
|
60344
60428
|
{
|
|
60345
60429
|
card_id: external_exports4.string().describe("Card ID (partial match supported)"),
|
|
60346
60430
|
action: external_exports4.string().describe("Action name to trigger"),
|
|
@@ -66751,7 +66835,7 @@ var require_thread_stream = __commonJS({
|
|
|
66751
66835
|
var { version: version3 } = require_package();
|
|
66752
66836
|
var { EventEmitter: EventEmitter3 } = require("events");
|
|
66753
66837
|
var { Worker } = require("worker_threads");
|
|
66754
|
-
var { join:
|
|
66838
|
+
var { join: join22 } = require("path");
|
|
66755
66839
|
var { pathToFileURL } = require("url");
|
|
66756
66840
|
var { wait } = require_wait();
|
|
66757
66841
|
var {
|
|
@@ -66787,7 +66871,7 @@ var require_thread_stream = __commonJS({
|
|
|
66787
66871
|
function createWorker(stream, opts) {
|
|
66788
66872
|
const { filename, workerData } = opts;
|
|
66789
66873
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
66790
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
66874
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join22(__dirname, "lib", "worker.js");
|
|
66791
66875
|
const worker = new Worker(toExecute, {
|
|
66792
66876
|
...opts.workerOpts,
|
|
66793
66877
|
trackUnmanagedFds: false,
|
|
@@ -67178,7 +67262,7 @@ var require_transport = __commonJS({
|
|
|
67178
67262
|
var { createRequire: createRequire2 } = require("module");
|
|
67179
67263
|
var { existsSync: existsSync4 } = require("node:fs");
|
|
67180
67264
|
var getCallers = require_caller();
|
|
67181
|
-
var { join:
|
|
67265
|
+
var { join: join22, isAbsolute: isAbsolute2, sep: sep2 } = require("node:path");
|
|
67182
67266
|
var { fileURLToPath: fileURLToPath2 } = require("node:url");
|
|
67183
67267
|
var sleep = require_atomic_sleep();
|
|
67184
67268
|
var onExit = require_on_exit_leak_free();
|
|
@@ -67331,7 +67415,7 @@ var require_transport = __commonJS({
|
|
|
67331
67415
|
throw new Error("only one of target or targets can be specified");
|
|
67332
67416
|
}
|
|
67333
67417
|
if (targets) {
|
|
67334
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
67418
|
+
target = bundlerOverrides["pino-worker"] || join22(__dirname, "worker.js");
|
|
67335
67419
|
options.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
67336
67420
|
return {
|
|
67337
67421
|
...dest,
|
|
@@ -67349,7 +67433,7 @@ var require_transport = __commonJS({
|
|
|
67349
67433
|
});
|
|
67350
67434
|
});
|
|
67351
67435
|
} else if (pipeline) {
|
|
67352
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
67436
|
+
target = bundlerOverrides["pino-worker"] || join22(__dirname, "worker.js");
|
|
67353
67437
|
options.pipelines = [pipeline.map((dest) => {
|
|
67354
67438
|
return {
|
|
67355
67439
|
...dest,
|
|
@@ -67372,7 +67456,7 @@ var require_transport = __commonJS({
|
|
|
67372
67456
|
return origin;
|
|
67373
67457
|
}
|
|
67374
67458
|
if (origin === "pino/file") {
|
|
67375
|
-
return
|
|
67459
|
+
return join22(__dirname, "..", "file.js");
|
|
67376
67460
|
}
|
|
67377
67461
|
let fixTarget2;
|
|
67378
67462
|
for (const filePath of callers) {
|
|
@@ -68362,7 +68446,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
68362
68446
|
return circularValue;
|
|
68363
68447
|
}
|
|
68364
68448
|
let res = "";
|
|
68365
|
-
let
|
|
68449
|
+
let join22 = ",";
|
|
68366
68450
|
const originalIndentation = indentation;
|
|
68367
68451
|
if (Array.isArray(value)) {
|
|
68368
68452
|
if (value.length === 0) {
|
|
@@ -68376,7 +68460,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
68376
68460
|
indentation += spacer;
|
|
68377
68461
|
res += `
|
|
68378
68462
|
${indentation}`;
|
|
68379
|
-
|
|
68463
|
+
join22 = `,
|
|
68380
68464
|
${indentation}`;
|
|
68381
68465
|
}
|
|
68382
68466
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -68384,13 +68468,13 @@ ${indentation}`;
|
|
|
68384
68468
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
68385
68469
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
68386
68470
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
68387
|
-
res +=
|
|
68471
|
+
res += join22;
|
|
68388
68472
|
}
|
|
68389
68473
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
68390
68474
|
res += tmp !== void 0 ? tmp : "null";
|
|
68391
68475
|
if (value.length - 1 > maximumBreadth) {
|
|
68392
68476
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
68393
|
-
res += `${
|
|
68477
|
+
res += `${join22}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
68394
68478
|
}
|
|
68395
68479
|
if (spacer !== "") {
|
|
68396
68480
|
res += `
|
|
@@ -68411,7 +68495,7 @@ ${originalIndentation}`;
|
|
|
68411
68495
|
let separator = "";
|
|
68412
68496
|
if (spacer !== "") {
|
|
68413
68497
|
indentation += spacer;
|
|
68414
|
-
|
|
68498
|
+
join22 = `,
|
|
68415
68499
|
${indentation}`;
|
|
68416
68500
|
whitespace = " ";
|
|
68417
68501
|
}
|
|
@@ -68425,13 +68509,13 @@ ${indentation}`;
|
|
|
68425
68509
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
68426
68510
|
if (tmp !== void 0) {
|
|
68427
68511
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
68428
|
-
separator =
|
|
68512
|
+
separator = join22;
|
|
68429
68513
|
}
|
|
68430
68514
|
}
|
|
68431
68515
|
if (keyLength > maximumBreadth) {
|
|
68432
68516
|
const removedKeys = keyLength - maximumBreadth;
|
|
68433
68517
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
68434
|
-
separator =
|
|
68518
|
+
separator = join22;
|
|
68435
68519
|
}
|
|
68436
68520
|
if (spacer !== "" && separator.length > 1) {
|
|
68437
68521
|
res = `
|
|
@@ -68471,7 +68555,7 @@ ${originalIndentation}`;
|
|
|
68471
68555
|
}
|
|
68472
68556
|
const originalIndentation = indentation;
|
|
68473
68557
|
let res = "";
|
|
68474
|
-
let
|
|
68558
|
+
let join22 = ",";
|
|
68475
68559
|
if (Array.isArray(value)) {
|
|
68476
68560
|
if (value.length === 0) {
|
|
68477
68561
|
return "[]";
|
|
@@ -68484,7 +68568,7 @@ ${originalIndentation}`;
|
|
|
68484
68568
|
indentation += spacer;
|
|
68485
68569
|
res += `
|
|
68486
68570
|
${indentation}`;
|
|
68487
|
-
|
|
68571
|
+
join22 = `,
|
|
68488
68572
|
${indentation}`;
|
|
68489
68573
|
}
|
|
68490
68574
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -68492,13 +68576,13 @@ ${indentation}`;
|
|
|
68492
68576
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
68493
68577
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
68494
68578
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
68495
|
-
res +=
|
|
68579
|
+
res += join22;
|
|
68496
68580
|
}
|
|
68497
68581
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
68498
68582
|
res += tmp !== void 0 ? tmp : "null";
|
|
68499
68583
|
if (value.length - 1 > maximumBreadth) {
|
|
68500
68584
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
68501
|
-
res += `${
|
|
68585
|
+
res += `${join22}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
68502
68586
|
}
|
|
68503
68587
|
if (spacer !== "") {
|
|
68504
68588
|
res += `
|
|
@@ -68511,7 +68595,7 @@ ${originalIndentation}`;
|
|
|
68511
68595
|
let whitespace = "";
|
|
68512
68596
|
if (spacer !== "") {
|
|
68513
68597
|
indentation += spacer;
|
|
68514
|
-
|
|
68598
|
+
join22 = `,
|
|
68515
68599
|
${indentation}`;
|
|
68516
68600
|
whitespace = " ";
|
|
68517
68601
|
}
|
|
@@ -68520,7 +68604,7 @@ ${indentation}`;
|
|
|
68520
68604
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
68521
68605
|
if (tmp !== void 0) {
|
|
68522
68606
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
68523
|
-
separator =
|
|
68607
|
+
separator = join22;
|
|
68524
68608
|
}
|
|
68525
68609
|
}
|
|
68526
68610
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -68577,20 +68661,20 @@ ${originalIndentation}`;
|
|
|
68577
68661
|
indentation += spacer;
|
|
68578
68662
|
let res2 = `
|
|
68579
68663
|
${indentation}`;
|
|
68580
|
-
const
|
|
68664
|
+
const join23 = `,
|
|
68581
68665
|
${indentation}`;
|
|
68582
68666
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
68583
68667
|
let i = 0;
|
|
68584
68668
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
68585
68669
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
68586
68670
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
68587
|
-
res2 +=
|
|
68671
|
+
res2 += join23;
|
|
68588
68672
|
}
|
|
68589
68673
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
68590
68674
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
68591
68675
|
if (value.length - 1 > maximumBreadth) {
|
|
68592
68676
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
68593
|
-
res2 += `${
|
|
68677
|
+
res2 += `${join23}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
68594
68678
|
}
|
|
68595
68679
|
res2 += `
|
|
68596
68680
|
${originalIndentation}`;
|
|
@@ -68606,16 +68690,16 @@ ${originalIndentation}`;
|
|
|
68606
68690
|
return '"[Object]"';
|
|
68607
68691
|
}
|
|
68608
68692
|
indentation += spacer;
|
|
68609
|
-
const
|
|
68693
|
+
const join22 = `,
|
|
68610
68694
|
${indentation}`;
|
|
68611
68695
|
let res = "";
|
|
68612
68696
|
let separator = "";
|
|
68613
68697
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
68614
68698
|
if (isTypedArrayWithEntries(value)) {
|
|
68615
|
-
res += stringifyTypedArray(value,
|
|
68699
|
+
res += stringifyTypedArray(value, join22, maximumBreadth);
|
|
68616
68700
|
keys = keys.slice(value.length);
|
|
68617
68701
|
maximumPropertiesToStringify -= value.length;
|
|
68618
|
-
separator =
|
|
68702
|
+
separator = join22;
|
|
68619
68703
|
}
|
|
68620
68704
|
if (deterministic) {
|
|
68621
68705
|
keys = sort(keys, comparator);
|
|
@@ -68626,13 +68710,13 @@ ${indentation}`;
|
|
|
68626
68710
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
68627
68711
|
if (tmp !== void 0) {
|
|
68628
68712
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
68629
|
-
separator =
|
|
68713
|
+
separator = join22;
|
|
68630
68714
|
}
|
|
68631
68715
|
}
|
|
68632
68716
|
if (keyLength > maximumBreadth) {
|
|
68633
68717
|
const removedKeys = keyLength - maximumBreadth;
|
|
68634
68718
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
68635
|
-
separator =
|
|
68719
|
+
separator = join22;
|
|
68636
68720
|
}
|
|
68637
68721
|
if (separator !== "") {
|
|
68638
68722
|
res = `
|
|
@@ -103100,7 +103184,7 @@ var require_send = __commonJS({
|
|
|
103100
103184
|
var { parseTokenList } = require_parseTokenList();
|
|
103101
103185
|
var { createHttpError } = require_createHttpError();
|
|
103102
103186
|
var extname4 = path24.extname;
|
|
103103
|
-
var
|
|
103187
|
+
var join22 = path24.join;
|
|
103104
103188
|
var normalize2 = path24.normalize;
|
|
103105
103189
|
var resolve11 = path24.resolve;
|
|
103106
103190
|
var sep2 = path24.sep;
|
|
@@ -103187,7 +103271,7 @@ var require_send = __commonJS({
|
|
|
103187
103271
|
return { statusCode: 403 };
|
|
103188
103272
|
}
|
|
103189
103273
|
parts = path25.split(sep2);
|
|
103190
|
-
path25 = normalize2(
|
|
103274
|
+
path25 = normalize2(join22(root, path25));
|
|
103191
103275
|
} else {
|
|
103192
103276
|
if (UP_PATH_REGEXP.test(path25)) {
|
|
103193
103277
|
debug('malicious path "%s"', path25);
|
|
@@ -103471,7 +103555,7 @@ var require_send = __commonJS({
|
|
|
103471
103555
|
let err;
|
|
103472
103556
|
for (let i = 0; i < options.index.length; i++) {
|
|
103473
103557
|
const index = options.index[i];
|
|
103474
|
-
const p =
|
|
103558
|
+
const p = join22(path25, index);
|
|
103475
103559
|
const { error: error49, stat: stat4 } = await tryStat(p);
|
|
103476
103560
|
if (error49) {
|
|
103477
103561
|
err = error49;
|
|
@@ -111887,6 +111971,13 @@ function setupWatcher(ctx, server) {
|
|
|
111887
111971
|
ctx.wss.close();
|
|
111888
111972
|
});
|
|
111889
111973
|
}
|
|
111974
|
+
const configFilePath = path17.join(ctx.workspaceRoot, ".kanban.json");
|
|
111975
|
+
const configWatcher = esm_default.watch(configFilePath, {
|
|
111976
|
+
ignoreInitial: true,
|
|
111977
|
+
awaitWriteFinish: { stabilityThreshold: 100 }
|
|
111978
|
+
});
|
|
111979
|
+
configWatcher.on("change", () => handleFileChange(ctx, debounceRef));
|
|
111980
|
+
server.on("close", () => configWatcher.close());
|
|
111890
111981
|
}
|
|
111891
111982
|
var fs10, path17;
|
|
111892
111983
|
var init_watcherSetup = __esm({
|
|
@@ -112092,6 +112183,23 @@ var init_lifecycle = __esm({
|
|
|
112092
112183
|
});
|
|
112093
112184
|
|
|
112094
112185
|
// src/standalone/internal/runtime.ts
|
|
112186
|
+
function getIndexHtml(basePath = "") {
|
|
112187
|
+
return `<!DOCTYPE html>
|
|
112188
|
+
<html lang="en">
|
|
112189
|
+
<head>
|
|
112190
|
+
<meta charset="UTF-8">
|
|
112191
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
112192
|
+
<link rel="icon" type="image/svg+xml" href="${basePath}/favicon.svg">
|
|
112193
|
+
<link href="${basePath}/style.css" rel="stylesheet">
|
|
112194
|
+
<title>Kanban Board</title>
|
|
112195
|
+
<script>window.__KB_BASE__ = ${JSON.stringify(basePath)}</script>
|
|
112196
|
+
</head>
|
|
112197
|
+
<body>
|
|
112198
|
+
<div id="root"></div>
|
|
112199
|
+
<script type="module" src="${basePath}/index.js"></script>
|
|
112200
|
+
</body>
|
|
112201
|
+
</html>`;
|
|
112202
|
+
}
|
|
112095
112203
|
function resolveStandaloneWebviewDir(webviewDir) {
|
|
112096
112204
|
if (webviewDir)
|
|
112097
112205
|
return webviewDir;
|
|
@@ -112105,12 +112213,12 @@ function resolveStandaloneWebviewDir(webviewDir) {
|
|
|
112105
112213
|
}
|
|
112106
112214
|
return candidates[0];
|
|
112107
112215
|
}
|
|
112108
|
-
function createStandaloneRuntime(kanbanDir, webviewDir, httpServer) {
|
|
112216
|
+
function createStandaloneRuntime(kanbanDir, webviewDir, httpServer, basePath) {
|
|
112109
112217
|
const absoluteKanbanDir = path19.resolve(kanbanDir);
|
|
112110
112218
|
const workspaceRoot = path19.dirname(absoluteKanbanDir);
|
|
112111
112219
|
const resolvedWebviewDir = resolveStandaloneWebviewDir(webviewDir);
|
|
112112
112220
|
const server = httpServer ?? http.createServer();
|
|
112113
|
-
const wss = new import_websocket_server.default({ server, path: "/ws" });
|
|
112221
|
+
const wss = new import_websocket_server.default({ server, path: (basePath || "") + "/ws" });
|
|
112114
112222
|
const ctx = {};
|
|
112115
112223
|
const sdk = new KanbanSDK(absoluteKanbanDir, {
|
|
112116
112224
|
onEvent: (event, data) => {
|
|
@@ -112159,20 +112267,7 @@ var init_runtime = __esm({
|
|
|
112159
112267
|
init_wrapper();
|
|
112160
112268
|
init_KanbanSDK();
|
|
112161
112269
|
init_broadcastService();
|
|
112162
|
-
indexHtml =
|
|
112163
|
-
<html lang="en">
|
|
112164
|
-
<head>
|
|
112165
|
-
<meta charset="UTF-8">
|
|
112166
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
112167
|
-
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
112168
|
-
<link href="/style.css" rel="stylesheet">
|
|
112169
|
-
<title>Kanban Board</title>
|
|
112170
|
-
</head>
|
|
112171
|
-
<body>
|
|
112172
|
-
<div id="root"></div>
|
|
112173
|
-
<script type="module" src="/index.js"></script>
|
|
112174
|
-
</body>
|
|
112175
|
-
</html>`;
|
|
112270
|
+
indexHtml = getIndexHtml();
|
|
112176
112271
|
}
|
|
112177
112272
|
});
|
|
112178
112273
|
|
|
@@ -114246,9 +114341,14 @@ var init_messageHandlers = __esm({
|
|
|
114246
114341
|
});
|
|
114247
114342
|
|
|
114248
114343
|
// src/standalone/internal/websocket.ts
|
|
114249
|
-
function attachWebSocketHandlers(ctx) {
|
|
114250
|
-
ctx.wss.on("connection", (ws, req) => {
|
|
114251
|
-
|
|
114344
|
+
function attachWebSocketHandlers(ctx, resolveAuthContext) {
|
|
114345
|
+
ctx.wss.on("connection", async (ws, req) => {
|
|
114346
|
+
let authContext;
|
|
114347
|
+
try {
|
|
114348
|
+
authContext = resolveAuthContext ? await resolveAuthContext(req) : extractAuthContext(req);
|
|
114349
|
+
} catch {
|
|
114350
|
+
authContext = extractAuthContext(req);
|
|
114351
|
+
}
|
|
114252
114352
|
setClientEditingCard(ctx, ws, null);
|
|
114253
114353
|
ws.on("message", (data) => {
|
|
114254
114354
|
let message;
|
|
@@ -114323,6 +114423,7 @@ function isPageRequest(method, pathname) {
|
|
|
114323
114423
|
function collectStandaloneHttpHandlers(requestType, ctx) {
|
|
114324
114424
|
const plugins = ctx.sdk.capabilities?.standaloneHttpPlugins ?? [];
|
|
114325
114425
|
const registrationOptions = {
|
|
114426
|
+
sdk: ctx.sdk,
|
|
114326
114427
|
workspaceRoot: ctx.workspaceRoot,
|
|
114327
114428
|
kanbanDir: ctx.absoluteKanbanDir,
|
|
114328
114429
|
capabilities: ctx.sdk.capabilities?.providers ?? {
|
|
@@ -114380,10 +114481,13 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
114380
114481
|
const swaggerUiStaticDir = resolveSwaggerUiStaticDir();
|
|
114381
114482
|
const swaggerUiLogoPath = swaggerUiStaticDir ? path21.join(swaggerUiStaticDir, "logo.svg") : void 0;
|
|
114382
114483
|
const swaggerUiLogo = swaggerUiLogoPath && fs15.existsSync(swaggerUiLogoPath) ? { type: "image/svg+xml", content: fs15.readFileSync(swaggerUiLogoPath) } : null;
|
|
114383
|
-
const
|
|
114484
|
+
const workspaceRoot = path21.dirname(path21.resolve(kanbanDir));
|
|
114485
|
+
const config3 = readConfig(workspaceRoot);
|
|
114486
|
+
const rawBase = config3.basePath ?? "";
|
|
114487
|
+
const basePath = rawBase ? (rawBase.startsWith("/") ? rawBase : "/" + rawBase).replace(/\/+$/, "") : "";
|
|
114488
|
+
const runtime = createStandaloneRuntime(kanbanDir, webviewDir, fastify.server, basePath);
|
|
114384
114489
|
const { ctx, resolvedWebviewDir } = runtime;
|
|
114385
|
-
|
|
114386
|
-
let resolvedIndexHtml = indexHtml;
|
|
114490
|
+
let resolvedIndexHtml = getIndexHtml(basePath);
|
|
114387
114491
|
let customHead = config3.customHeadHtml || "";
|
|
114388
114492
|
if (config3.customHeadHtmlFile) {
|
|
114389
114493
|
try {
|
|
@@ -114393,14 +114497,14 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
114393
114497
|
}
|
|
114394
114498
|
}
|
|
114395
114499
|
if (customHead) {
|
|
114396
|
-
resolvedIndexHtml =
|
|
114500
|
+
resolvedIndexHtml = resolvedIndexHtml.replace("</head>", `${customHead}
|
|
114397
114501
|
</head>`);
|
|
114398
114502
|
}
|
|
114399
114503
|
const standaloneHttpPlugins = ctx.sdk.capabilities?.standaloneHttpPlugins ?? [];
|
|
114400
114504
|
const standaloneOpenApiSpec = buildStandaloneOpenApiSpec(standaloneHttpPlugins);
|
|
114401
114505
|
fastify.register(import_swagger.default, { openapi: standaloneOpenApiSpec });
|
|
114402
114506
|
fastify.register(import_swagger_ui.default, {
|
|
114403
|
-
routePrefix:
|
|
114507
|
+
routePrefix: `${basePath}/api/docs`,
|
|
114404
114508
|
uiConfig: { docExpansion: "list", deepLinking: false },
|
|
114405
114509
|
logo: swaggerUiLogo,
|
|
114406
114510
|
...swaggerUiStaticDir ? { baseDir: swaggerUiStaticDir } : {}
|
|
@@ -114432,6 +114536,14 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
114432
114536
|
if (request.body instanceof Buffer && request.body.length > 0) {
|
|
114433
114537
|
req._rawBody = request.body;
|
|
114434
114538
|
}
|
|
114539
|
+
if (basePath) {
|
|
114540
|
+
const rawUrl = req.url ?? "/";
|
|
114541
|
+
if (rawUrl === basePath) {
|
|
114542
|
+
req.url = "/";
|
|
114543
|
+
} else if (rawUrl.startsWith(basePath + "/") || rawUrl.startsWith(basePath + "?")) {
|
|
114544
|
+
req.url = rawUrl.slice(basePath.length);
|
|
114545
|
+
}
|
|
114546
|
+
}
|
|
114435
114547
|
const requestContext = createRequestContext(ctx, req, reply.raw, resolvedWebviewDir, resolvedIndexHtml);
|
|
114436
114548
|
await dispatchRequest(requestContext, middlewareHandlers);
|
|
114437
114549
|
if (!reply.sent && !reply.raw.writableEnded) {
|
|
@@ -114439,7 +114551,62 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
114439
114551
|
}
|
|
114440
114552
|
reply.hijack();
|
|
114441
114553
|
});
|
|
114442
|
-
|
|
114554
|
+
const resolveWsAuthContext = async (req) => {
|
|
114555
|
+
const silentRes = /* @__PURE__ */ (() => {
|
|
114556
|
+
const r = {
|
|
114557
|
+
writableEnded: false,
|
|
114558
|
+
writeHead() {
|
|
114559
|
+
return r;
|
|
114560
|
+
},
|
|
114561
|
+
setHeader() {
|
|
114562
|
+
return r;
|
|
114563
|
+
},
|
|
114564
|
+
removeHeader() {
|
|
114565
|
+
},
|
|
114566
|
+
getHeader() {
|
|
114567
|
+
return void 0;
|
|
114568
|
+
},
|
|
114569
|
+
getHeaders() {
|
|
114570
|
+
return {};
|
|
114571
|
+
},
|
|
114572
|
+
end(..._args) {
|
|
114573
|
+
r.writableEnded = true;
|
|
114574
|
+
return r;
|
|
114575
|
+
},
|
|
114576
|
+
write() {
|
|
114577
|
+
return false;
|
|
114578
|
+
}
|
|
114579
|
+
};
|
|
114580
|
+
return r;
|
|
114581
|
+
})();
|
|
114582
|
+
const reqWithBody = req;
|
|
114583
|
+
const wsUrl = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
114584
|
+
const requestContext = {
|
|
114585
|
+
ctx,
|
|
114586
|
+
sdk: ctx.sdk,
|
|
114587
|
+
workspaceRoot: ctx.workspaceRoot,
|
|
114588
|
+
kanbanDir: ctx.absoluteKanbanDir,
|
|
114589
|
+
req: reqWithBody,
|
|
114590
|
+
res: silentRes,
|
|
114591
|
+
url: wsUrl,
|
|
114592
|
+
pathname: wsUrl.pathname,
|
|
114593
|
+
method: "GET",
|
|
114594
|
+
resolvedWebviewDir,
|
|
114595
|
+
indexHtml: resolvedIndexHtml,
|
|
114596
|
+
route: createRouteMatcher("GET", wsUrl.pathname, matchRoute),
|
|
114597
|
+
isApiRequest: false,
|
|
114598
|
+
isPageRequest: false,
|
|
114599
|
+
getAuthContext: () => getRequestAuthContext(req),
|
|
114600
|
+
setAuthContext: (auth) => setRequestAuthContext(req, auth),
|
|
114601
|
+
mergeAuthContext: (auth) => mergeRequestAuthContext(req, auth)
|
|
114602
|
+
};
|
|
114603
|
+
for (const handler of middlewareHandlers) {
|
|
114604
|
+
if (await handler(requestContext))
|
|
114605
|
+
break;
|
|
114606
|
+
}
|
|
114607
|
+
return extractAuthContext(req);
|
|
114608
|
+
};
|
|
114609
|
+
attachWebSocketHandlers(ctx, resolveWsAuthContext);
|
|
114443
114610
|
setupStandaloneLifecycle(ctx, fastify.server);
|
|
114444
114611
|
const effectiveConfigPath = resolvedConfigPath ?? configPath(path21.dirname(ctx.absoluteKanbanDir));
|
|
114445
114612
|
fastify.listen({ port, host: "0.0.0.0" }, (err) => {
|
|
@@ -114447,7 +114614,7 @@ function startServer(kanbanDir, port, webviewDir, resolvedConfigPath) {
|
|
|
114447
114614
|
console.error("Failed to start server:", err);
|
|
114448
114615
|
process.exit(1);
|
|
114449
114616
|
}
|
|
114450
|
-
console.log(`Kanban board running at http://localhost:${port}`);
|
|
114617
|
+
console.log(`Kanban board running at http://localhost:${port}${basePath}`);
|
|
114451
114618
|
console.log(`API available at http://localhost:${port}/api`);
|
|
114452
114619
|
console.log(`Kanban config: ${effectiveConfigPath}`);
|
|
114453
114620
|
console.log(`Kanban directory: ${ctx.absoluteKanbanDir}`);
|
|
@@ -116869,7 +117036,7 @@ async function cmdAuth(sdk, positional, flags, cliPlugins, workspaceRoot) {
|
|
|
116869
117036
|
if (sub !== "status") {
|
|
116870
117037
|
const authPlugin = findCliPlugin(cliPlugins, "auth");
|
|
116871
117038
|
if (authPlugin) {
|
|
116872
|
-
await authPlugin
|
|
117039
|
+
await runCliPlugin(authPlugin, positional, flags, workspaceRoot, sdk);
|
|
116873
117040
|
return;
|
|
116874
117041
|
}
|
|
116875
117042
|
console.error(red(`Unknown auth sub-command: ${sub}`));
|