kantban-cli 0.1.37 → 0.1.38
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/{chunk-AF72765A.js → chunk-2CY5OPZN.js} +2 -2
- package/dist/{chunk-UNSNCYTR.js → chunk-5ZU2OOES.js} +19 -8
- package/dist/chunk-5ZU2OOES.js.map +1 -0
- package/dist/{chunk-MIL7SIPJ.js → chunk-MKKHLFA5.js} +2 -2
- package/dist/{context-IRTNYVN6.js → context-7YDNTI3P.js} +1 -3
- package/dist/{context-IRTNYVN6.js.map → context-7YDNTI3P.js.map} +1 -1
- package/dist/{cron-PS2IEPH2.js → cron-3R2UWFO7.js} +3 -4
- package/dist/{cron-PS2IEPH2.js.map → cron-3R2UWFO7.js.map} +1 -1
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -1
- package/dist/lib/gate-proxy-server.js +2 -3
- package/dist/lib/gate-proxy-server.js.map +1 -1
- package/dist/{pipeline-76ZTI4IN.js → pipeline-IAKINX5A.js} +7 -8
- package/dist/pipeline-IAKINX5A.js.map +1 -0
- package/dist/{pipeline-init-QDHBJGWY.js → pipeline-init-IGZZOOLK.js} +1 -3
- package/dist/{pipeline-init-QDHBJGWY.js.map → pipeline-init-IGZZOOLK.js.map} +1 -1
- package/dist/{status-3B3BSJBJ.js → status-4GFXMVIM.js} +1 -3
- package/dist/{status-3B3BSJBJ.js.map → status-4GFXMVIM.js.map} +1 -1
- package/dist/{work-HZVJJG4A.js → work-45GILGKD.js} +2 -3
- package/dist/{work-HZVJJG4A.js.map → work-45GILGKD.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-DGUM43GV.js +0 -11
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-UNSNCYTR.js.map +0 -1
- package/dist/pipeline-76ZTI4IN.js.map +0 -1
- /package/dist/{chunk-AF72765A.js.map → chunk-2CY5OPZN.js.map} +0 -0
- /package/dist/{chunk-MIL7SIPJ.js.map → chunk-MKKHLFA5.js.map} +0 -0
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
killProcessTree,
|
|
8
8
|
npxCommand,
|
|
9
9
|
resolveCommand
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-5ZU2OOES.js";
|
|
11
11
|
|
|
12
12
|
// src/lib/stuck-detector.ts
|
|
13
13
|
import { z } from "zod";
|
|
@@ -1186,4 +1186,4 @@ export {
|
|
|
1186
1186
|
cleanupGateProxyConfigs,
|
|
1187
1187
|
ClaudeProvider
|
|
1188
1188
|
};
|
|
1189
|
-
//# sourceMappingURL=chunk-
|
|
1189
|
+
//# sourceMappingURL=chunk-2CY5OPZN.js.map
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
__require
|
|
3
|
-
} from "./chunk-DGUM43GV.js";
|
|
4
|
-
|
|
5
1
|
// src/lib/platform.ts
|
|
6
2
|
import { platform } from "os";
|
|
7
3
|
import { execFileSync } from "child_process";
|
|
8
|
-
import { readFileSync } from "fs";
|
|
9
|
-
import { join, dirname } from "path";
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
import { join, dirname, delimiter } from "path";
|
|
10
6
|
var IS_WINDOWS = platform() === "win32";
|
|
11
7
|
function normalizeEol(text) {
|
|
12
8
|
return text.replace(/\r\n|\r/g, "\n");
|
|
@@ -50,10 +46,25 @@ function killProcessTree(pid, signal = "SIGTERM") {
|
|
|
50
46
|
function npxCommand() {
|
|
51
47
|
return IS_WINDOWS ? "npx.cmd" : "npx";
|
|
52
48
|
}
|
|
49
|
+
function whichSync(command) {
|
|
50
|
+
const pathEnv = process.env["PATH"] || process.env["Path"] || defaultPath();
|
|
51
|
+
const dirs = pathEnv.split(delimiter);
|
|
52
|
+
const extensions = IS_WINDOWS ? (process.env["PATHEXT"] || ".COM;.EXE;.BAT;.CMD").toLowerCase().split(";") : [""];
|
|
53
|
+
for (const dir of dirs) {
|
|
54
|
+
for (const ext of extensions) {
|
|
55
|
+
const candidate = join(dir, command + ext);
|
|
56
|
+
if (existsSync(candidate)) return candidate;
|
|
57
|
+
if (IS_WINDOWS) {
|
|
58
|
+
const candidateUpper = join(dir, command + ext.toUpperCase());
|
|
59
|
+
if (candidateUpper !== candidate && existsSync(candidateUpper)) return candidateUpper;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`not found: ${command}`);
|
|
64
|
+
}
|
|
53
65
|
function resolveCommand(command) {
|
|
54
66
|
if (!IS_WINDOWS) return [command, []];
|
|
55
67
|
try {
|
|
56
|
-
const whichSync = __require("which").sync;
|
|
57
68
|
const resolved = whichSync(command);
|
|
58
69
|
if (resolved.toLowerCase().endsWith(".exe")) return [resolved, []];
|
|
59
70
|
if (resolved.toLowerCase().endsWith(".cmd")) {
|
|
@@ -93,4 +104,4 @@ export {
|
|
|
93
104
|
resolveCommand,
|
|
94
105
|
defaultPath
|
|
95
106
|
};
|
|
96
|
-
//# sourceMappingURL=chunk-
|
|
107
|
+
//# sourceMappingURL=chunk-5ZU2OOES.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/platform.ts"],"sourcesContent":["import { platform } from 'node:os';\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync, existsSync } from 'node:fs';\nimport { join, dirname, delimiter } from 'node:path';\n\nexport const IS_WINDOWS = platform() === 'win32';\n\n/** Normalize line endings to Unix-style (\\n). Strips \\r\\n and bare \\r. */\nexport function normalizeEol(text: string): string {\n return text.replace(/\\r\\n|\\r/g, '\\n');\n}\n\n/** Returns [shellExecutable, argsPrefix] for running shell commands.\n * Unix: ['/bin/sh', ['-c']] Windows: [cmd.exe /c] or [pwsh -NoProfile -Command] */\nexport function shellArgs(): [string, string[]] {\n if (IS_WINDOWS) {\n const comspec = process.env.COMSPEC || 'cmd.exe';\n // Detect PowerShell — uses -Command instead of /c\n if (/pwsh|powershell/i.test(comspec)) {\n return [comspec, ['-NoProfile', '-Command']];\n }\n return [comspec, ['/c']];\n }\n return ['/bin/sh', ['-c']];\n}\n\n/** Returns spawn options with shell:true on Windows for .cmd/.bat resolution. */\nexport function crossSpawnOptions<T extends Record<string, unknown>>(opts?: T): T & { shell: boolean } {\n return { ...(opts ?? {} as T), shell: IS_WINDOWS } as T & { shell: boolean };\n}\n\n/** Kill a process and its children. On Unix, tries process group first.\n * On Windows, uses `taskkill /T` for tree kill. Never throws. */\nexport function killProcessTree(pid: number, signal: NodeJS.Signals = 'SIGTERM'): void {\n if (IS_WINDOWS) {\n // taskkill /T kills the process tree; /F forces termination\n try { execFileSync('taskkill', ['/pid', String(pid), '/t', '/f'], { stdio: 'pipe' }); return; } catch { /* fall through */ }\n try { process.kill(pid); } catch { /* already dead */ }\n return;\n }\n // Unix: try process group kill first\n try { process.kill(-pid, signal); return; } catch { /* fall through */ }\n try { process.kill(pid, signal); } catch { /* already dead */ }\n}\n\n/** Returns platform-appropriate npx command ('npx' on Unix, 'npx.cmd' on Windows). */\nexport function npxCommand(): string {\n return IS_WINDOWS ? 'npx.cmd' : 'npx';\n}\n\n/** Synchronously find a command on PATH, similar to `which.sync`.\n * On Windows, checks PATHEXT extensions (.COM, .EXE, .CMD, .BAT, etc.).\n * Returns the first match or throws if not found. */\nfunction whichSync(command: string): string {\n const pathEnv = process.env['PATH'] || process.env['Path'] || defaultPath();\n const dirs = pathEnv.split(delimiter);\n const extensions = IS_WINDOWS\n ? (process.env['PATHEXT'] || '.COM;.EXE;.BAT;.CMD').toLowerCase().split(';')\n : [''];\n\n for (const dir of dirs) {\n for (const ext of extensions) {\n const candidate = join(dir, command + ext);\n if (existsSync(candidate)) return candidate;\n // Also try with original casing on Windows (PATHEXT is case-insensitive)\n if (IS_WINDOWS) {\n const candidateUpper = join(dir, command + ext.toUpperCase());\n if (candidateUpper !== candidate && existsSync(candidateUpper)) return candidateUpper;\n }\n }\n }\n throw new Error(`not found: ${command}`);\n}\n\n/**\n * Resolve a CLI command to [executable, prefixArgs] for direct invocation\n * WITHOUT cmd.exe on Windows. This avoids the 8191-char command line limit\n * that cmd.exe imposes (CreateProcessW supports 32,767 chars).\n *\n * On Windows, npm-installed CLI tools are `.cmd` wrappers that invoke Node.js\n * with a specific script. This function parses the wrapper and returns\n * ['node', ['path/to/script.js', ...extraFlags]] so spawn() can call Node directly.\n *\n * On Unix (or if resolution fails), returns [command, []] unchanged.\n */\nexport function resolveCommand(command: string): [cmd: string, prefixArgs: string[]] {\n if (!IS_WINDOWS) return [command, []];\n\n try {\n // Find the command on PATH — inline implementation to avoid ESM/CJS\n // interop issues with the `which` package in bundled ESM context.\n const resolved = whichSync(command);\n\n // If it's an .exe, use it directly — no shell needed\n if (resolved.toLowerCase().endsWith('.exe')) return [resolved, []];\n\n // If it's a .cmd, parse out the node script invocation\n if (resolved.toLowerCase().endsWith('.cmd')) {\n const content = readFileSync(resolved, 'utf-8');\n // Match: \"%_prog%\" [optional-flags] \"%dp0%\\path\\to\\script.js\" %*\n // The .cmd files generated by npm have this exact pattern on the last non-empty line.\n for (const line of content.split(/\\r?\\n/)) {\n const m = line.match(/\"%_prog%\"\\s+(.*?)\"%dp0%\\\\(.+?)\"\\s+%[*]/);\n if (m) {\n const flags = m[1]!.trim().split(/\\s+/).filter(Boolean);\n const scriptPath = join(dirname(resolved), m[2]!);\n return [process.execPath, [...flags, scriptPath]];\n }\n }\n }\n } catch {\n // which not found, or parsing failed — fall through\n }\n\n // Fallback: use the command as-is (will need shell: true)\n return [command, []];\n}\n\n/** Returns platform-appropriate default PATH when process.env.PATH is undefined. */\nexport function defaultPath(): string {\n if (IS_WINDOWS) {\n return [\n process.env.SystemRoot ? `${process.env.SystemRoot}\\\\System32` : 'C:\\\\Windows\\\\System32',\n process.env.SystemRoot || 'C:\\\\Windows',\n 'C:\\\\Program Files\\\\nodejs',\n process.env.APPDATA ? `${process.env.APPDATA}\\\\npm` : '',\n ].filter(Boolean).join(';');\n }\n return '/usr/local/bin:/usr/bin:/bin';\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
normalizeEol,
|
|
6
6
|
shellArgs
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5ZU2OOES.js";
|
|
8
8
|
|
|
9
9
|
// src/lib/gate-runner.ts
|
|
10
10
|
import { execFile } from "child_process";
|
|
@@ -104,4 +104,4 @@ export {
|
|
|
104
104
|
formatGateErrors,
|
|
105
105
|
runGates
|
|
106
106
|
};
|
|
107
|
-
//# sourceMappingURL=chunk-
|
|
107
|
+
//# sourceMappingURL=chunk-MKKHLFA5.js.map
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import "./chunk-DGUM43GV.js";
|
|
2
|
-
|
|
3
1
|
// src/commands/context.ts
|
|
4
2
|
async function runContext(client, args) {
|
|
5
3
|
const [scopeType, scopeId] = args;
|
|
@@ -29,4 +27,4 @@ async function runContext(client, args) {
|
|
|
29
27
|
export {
|
|
30
28
|
runContext
|
|
31
29
|
};
|
|
32
|
-
//# sourceMappingURL=context-
|
|
30
|
+
//# sourceMappingURL=context-7YDNTI3P.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/context.ts"],"sourcesContent":["import type { KantBanCLIClient } from '../client.js';\n\nexport async function runContext(client: KantBanCLIClient, args: string[]): Promise<void> {\n const [scopeType, scopeId] = args;\n if (!scopeType || !scopeId) {\n console.error('Usage: kantban context <board|column|ticket> <id>');\n process.exit(1);\n }\n\n const projectId = process.env['KANTBAN_PROJECT_ID'];\n if (!projectId) {\n console.error('Error: KANTBAN_PROJECT_ID environment variable required for context command');\n process.exit(1);\n }\n\n const params: Record<string, string> = {};\n if (scopeType === 'board') params['boardId'] = scopeId;\n else if (scopeType === 'column') params['columnId'] = scopeId;\n else if (scopeType === 'ticket') params['ticketId'] = scopeId;\n else {\n console.error(`Unknown scope type: ${scopeType}. Use board, column, or ticket.`);\n process.exit(1);\n }\n\n const data = await client.get<Record<string, unknown>>(\n `/projects/${projectId}/pipeline-context`,\n params,\n );\n\n // Output as structured JSON to stdout for piping\n console.log(JSON.stringify(data, null, 2));\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/commands/context.ts"],"sourcesContent":["import type { KantBanCLIClient } from '../client.js';\n\nexport async function runContext(client: KantBanCLIClient, args: string[]): Promise<void> {\n const [scopeType, scopeId] = args;\n if (!scopeType || !scopeId) {\n console.error('Usage: kantban context <board|column|ticket> <id>');\n process.exit(1);\n }\n\n const projectId = process.env['KANTBAN_PROJECT_ID'];\n if (!projectId) {\n console.error('Error: KANTBAN_PROJECT_ID environment variable required for context command');\n process.exit(1);\n }\n\n const params: Record<string, string> = {};\n if (scopeType === 'board') params['boardId'] = scopeId;\n else if (scopeType === 'column') params['columnId'] = scopeId;\n else if (scopeType === 'ticket') params['ticketId'] = scopeId;\n else {\n console.error(`Unknown scope type: ${scopeType}. Use board, column, or ticket.`);\n process.exit(1);\n }\n\n const data = await client.get<Record<string, unknown>>(\n `/projects/${projectId}/pipeline-context`,\n params,\n );\n\n // Output as structured JSON to stdout for piping\n console.log(JSON.stringify(data, null, 2));\n}\n"],"mappings":";AAEA,eAAsB,WAAW,QAA0B,MAA+B;AACxF,QAAM,CAAC,WAAW,OAAO,IAAI;AAC7B,MAAI,CAAC,aAAa,CAAC,SAAS;AAC1B,YAAQ,MAAM,mDAAmD;AACjE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,QAAQ,IAAI,oBAAoB;AAClD,MAAI,CAAC,WAAW;AACd,YAAQ,MAAM,6EAA6E;AAC3F,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAiC,CAAC;AACxC,MAAI,cAAc,QAAS,QAAO,SAAS,IAAI;AAAA,WACtC,cAAc,SAAU,QAAO,UAAU,IAAI;AAAA,WAC7C,cAAc,SAAU,QAAO,UAAU,IAAI;AAAA,OACjD;AACH,YAAQ,MAAM,uBAAuB,SAAS,iCAAiC;AAC/E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,OAAO,MAAM,OAAO;AAAA,IACxB,aAAa,SAAS;AAAA,IACtB;AAAA,EACF;AAGA,UAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAC3C;","names":[]}
|
|
@@ -3,10 +3,9 @@ import {
|
|
|
3
3
|
RalphLoop,
|
|
4
4
|
cleanupMcpConfig,
|
|
5
5
|
generateMcpConfig
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-2CY5OPZN.js";
|
|
7
7
|
import "./chunk-DAFLEMLK.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-DGUM43GV.js";
|
|
8
|
+
import "./chunk-5ZU2OOES.js";
|
|
10
9
|
|
|
11
10
|
// src/commands/cron.ts
|
|
12
11
|
import { readFileSync } from "fs";
|
|
@@ -103,4 +102,4 @@ async function runCron(client, args) {
|
|
|
103
102
|
export {
|
|
104
103
|
runCron
|
|
105
104
|
};
|
|
106
|
-
//# sourceMappingURL=cron-
|
|
105
|
+
//# sourceMappingURL=cron-3R2UWFO7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/cron.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport type { KantBanCLIClient } from '../client.js';\nimport { generateMcpConfig, cleanupMcpConfig } from '../lib/mcp-config.js';\nimport { RalphLoop, type RalphLoopDeps, type LoopConfig } from '../lib/ralph-loop.js';\nimport type { ColumnContext, TicketContext } from '../lib/prompt-composer.js';\nimport type { TicketFingerprint } from '@kantban/types';\nimport { ClaudeProvider } from '../providers/claude-provider.js';\nimport type { McpConfig } from '../providers/types.js';\n\nfunction parseDuration(input: string): number {\n const match = input.match(/^(\\d+)(s|m|h)$/);\n if (!match) throw new Error(`Invalid duration: ${input}. Use format like 5m, 30s, 1h`);\n const value = Number(match[1]);\n const unit = match[2];\n switch (unit) {\n case 's': return value * 1000;\n case 'm': return value * 60 * 1000;\n case 'h': return value * 60 * 60 * 1000;\n default: throw new Error(`Unknown unit: ${unit}`);\n }\n}\n\nexport async function runCron(client: KantBanCLIClient, args: string[]): Promise<void> {\n const columnId = args[0];\n if (!columnId) {\n console.error('Usage: kantban cron <column-id> [--interval 5m]');\n process.exit(1);\n }\n\n // Parse interval\n let intervalMs = 5 * 60 * 1000; // default 5m\n const intervalIdx = args.indexOf('--interval');\n const intervalArg = intervalIdx !== -1 ? args[intervalIdx + 1] : undefined;\n if (intervalArg) {\n intervalMs = parseDuration(intervalArg);\n }\n\n // Resolve project ID\n const projectId = process.env['KANTBAN_PROJECT_ID'];\n if (!projectId) {\n console.error('Error: KANTBAN_PROJECT_ID required');\n process.exit(1);\n }\n\n // Generate MCP config (stable path keyed by column)\n const mcpConfigPath = generateMcpConfig(client.baseUrl, client.token, `cron-${columnId}`);\n\n // Create provider and read MCP config\n const provider = new ClaudeProvider();\n const raw = JSON.parse(readFileSync(mcpConfigPath, 'utf-8')) as { mcpServers: McpConfig['servers'] };\n const mcpConfig: McpConfig = { servers: raw.mcpServers };\n\n let stopped = false;\n\n // Graceful shutdown\n const shutdown = () => {\n stopped = true;\n cleanupMcpConfig(mcpConfigPath);\n console.log('\\nCron stopped.');\n process.exit(0);\n };\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n\n console.log(`Cron: column ${columnId}, interval ${String(intervalMs / 1000)}s`);\n console.log('Press Ctrl+C to stop.\\n');\n\n // Main cron tick\n const tick = async () => {\n if (stopped) return;\n\n try {\n // Fetch column scope\n const columnScope = await client.get<ColumnContext>(\n `/projects/${projectId}/pipeline-context`,\n { columnId },\n );\n\n const tickets = columnScope.tickets ?? [];\n if (tickets.length === 0) {\n console.log(`[${new Date().toLocaleTimeString('en-US', { hour12: false })}] No tickets in column. Sleeping...`);\n return;\n }\n\n console.log(`[${new Date().toLocaleTimeString('en-US', { hour12: false })}] Processing ${String(tickets.length)} ticket(s)...`);\n\n // Process each ticket sequentially (one iteration each for cron)\n for (const ticket of tickets) {\n if (stopped) break;\n\n const deps: RalphLoopDeps = {\n fetchTicketContext: (tid) => client.get<TicketContext>(\n `/projects/${projectId}/pipeline-context`, { ticketId: tid },\n ),\n fetchColumnContext: (cid) => client.get<ColumnContext>(\n `/projects/${projectId}/pipeline-context`, { columnId: cid },\n ),\n fetchFingerprint: (tid) => client.getFingerprint(projectId, tid) as Promise<TicketFingerprint>,\n provider,\n mcpConfig,\n projectId,\n };\n\n const config: LoopConfig = { maxIterations: 1, gutterThreshold: 1 };\n\n const loop = new RalphLoop(ticket.id, columnId, config, deps);\n const result = await loop.run();\n console.log(` ${String(ticket.ticket_number)}: ${result.reason} (${String(result.iterations)} iter)`);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`Cron tick error: ${message}`);\n }\n };\n\n // Run immediately, then on interval\n await tick();\n setInterval(() => void tick(), intervalMs);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/commands/cron.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport type { KantBanCLIClient } from '../client.js';\nimport { generateMcpConfig, cleanupMcpConfig } from '../lib/mcp-config.js';\nimport { RalphLoop, type RalphLoopDeps, type LoopConfig } from '../lib/ralph-loop.js';\nimport type { ColumnContext, TicketContext } from '../lib/prompt-composer.js';\nimport type { TicketFingerprint } from '@kantban/types';\nimport { ClaudeProvider } from '../providers/claude-provider.js';\nimport type { McpConfig } from '../providers/types.js';\n\nfunction parseDuration(input: string): number {\n const match = input.match(/^(\\d+)(s|m|h)$/);\n if (!match) throw new Error(`Invalid duration: ${input}. Use format like 5m, 30s, 1h`);\n const value = Number(match[1]);\n const unit = match[2];\n switch (unit) {\n case 's': return value * 1000;\n case 'm': return value * 60 * 1000;\n case 'h': return value * 60 * 60 * 1000;\n default: throw new Error(`Unknown unit: ${unit}`);\n }\n}\n\nexport async function runCron(client: KantBanCLIClient, args: string[]): Promise<void> {\n const columnId = args[0];\n if (!columnId) {\n console.error('Usage: kantban cron <column-id> [--interval 5m]');\n process.exit(1);\n }\n\n // Parse interval\n let intervalMs = 5 * 60 * 1000; // default 5m\n const intervalIdx = args.indexOf('--interval');\n const intervalArg = intervalIdx !== -1 ? args[intervalIdx + 1] : undefined;\n if (intervalArg) {\n intervalMs = parseDuration(intervalArg);\n }\n\n // Resolve project ID\n const projectId = process.env['KANTBAN_PROJECT_ID'];\n if (!projectId) {\n console.error('Error: KANTBAN_PROJECT_ID required');\n process.exit(1);\n }\n\n // Generate MCP config (stable path keyed by column)\n const mcpConfigPath = generateMcpConfig(client.baseUrl, client.token, `cron-${columnId}`);\n\n // Create provider and read MCP config\n const provider = new ClaudeProvider();\n const raw = JSON.parse(readFileSync(mcpConfigPath, 'utf-8')) as { mcpServers: McpConfig['servers'] };\n const mcpConfig: McpConfig = { servers: raw.mcpServers };\n\n let stopped = false;\n\n // Graceful shutdown\n const shutdown = () => {\n stopped = true;\n cleanupMcpConfig(mcpConfigPath);\n console.log('\\nCron stopped.');\n process.exit(0);\n };\n process.on('SIGTERM', shutdown);\n process.on('SIGINT', shutdown);\n\n console.log(`Cron: column ${columnId}, interval ${String(intervalMs / 1000)}s`);\n console.log('Press Ctrl+C to stop.\\n');\n\n // Main cron tick\n const tick = async () => {\n if (stopped) return;\n\n try {\n // Fetch column scope\n const columnScope = await client.get<ColumnContext>(\n `/projects/${projectId}/pipeline-context`,\n { columnId },\n );\n\n const tickets = columnScope.tickets ?? [];\n if (tickets.length === 0) {\n console.log(`[${new Date().toLocaleTimeString('en-US', { hour12: false })}] No tickets in column. Sleeping...`);\n return;\n }\n\n console.log(`[${new Date().toLocaleTimeString('en-US', { hour12: false })}] Processing ${String(tickets.length)} ticket(s)...`);\n\n // Process each ticket sequentially (one iteration each for cron)\n for (const ticket of tickets) {\n if (stopped) break;\n\n const deps: RalphLoopDeps = {\n fetchTicketContext: (tid) => client.get<TicketContext>(\n `/projects/${projectId}/pipeline-context`, { ticketId: tid },\n ),\n fetchColumnContext: (cid) => client.get<ColumnContext>(\n `/projects/${projectId}/pipeline-context`, { columnId: cid },\n ),\n fetchFingerprint: (tid) => client.getFingerprint(projectId, tid) as Promise<TicketFingerprint>,\n provider,\n mcpConfig,\n projectId,\n };\n\n const config: LoopConfig = { maxIterations: 1, gutterThreshold: 1 };\n\n const loop = new RalphLoop(ticket.id, columnId, config, deps);\n const result = await loop.run();\n console.log(` ${String(ticket.ticket_number)}: ${result.reason} (${String(result.iterations)} iter)`);\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`Cron tick error: ${message}`);\n }\n };\n\n // Run immediately, then on interval\n await tick();\n setInterval(() => void tick(), intervalMs);\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import {
|
|
3
3
|
KantBanCLIClient
|
|
4
4
|
} from "./chunk-CQP4B53A.js";
|
|
5
|
-
import "./chunk-DGUM43GV.js";
|
|
6
5
|
|
|
7
6
|
// src/index.ts
|
|
8
7
|
var apiToken = process.env["KANTBAN_API_TOKEN"];
|
|
@@ -16,32 +15,32 @@ var [command, ...args] = process.argv.slice(2);
|
|
|
16
15
|
async function main() {
|
|
17
16
|
switch (command) {
|
|
18
17
|
case "context": {
|
|
19
|
-
const { runContext } = await import("./context-
|
|
18
|
+
const { runContext } = await import("./context-7YDNTI3P.js");
|
|
20
19
|
await runContext(client, args);
|
|
21
20
|
break;
|
|
22
21
|
}
|
|
23
22
|
case "status": {
|
|
24
|
-
const { runStatus } = await import("./status-
|
|
23
|
+
const { runStatus } = await import("./status-4GFXMVIM.js");
|
|
25
24
|
await runStatus(client, args);
|
|
26
25
|
break;
|
|
27
26
|
}
|
|
28
27
|
case "work": {
|
|
29
|
-
const { runWork } = await import("./work-
|
|
28
|
+
const { runWork } = await import("./work-45GILGKD.js");
|
|
30
29
|
await runWork(client, args);
|
|
31
30
|
break;
|
|
32
31
|
}
|
|
33
32
|
case "pipeline": {
|
|
34
33
|
if (args[0] === "stop") {
|
|
35
|
-
const { stopPipeline } = await import("./pipeline-
|
|
34
|
+
const { stopPipeline } = await import("./pipeline-IAKINX5A.js");
|
|
36
35
|
await stopPipeline(args.slice(1));
|
|
37
36
|
} else {
|
|
38
|
-
const { runPipeline } = await import("./pipeline-
|
|
37
|
+
const { runPipeline } = await import("./pipeline-IAKINX5A.js");
|
|
39
38
|
await runPipeline(client, args);
|
|
40
39
|
}
|
|
41
40
|
break;
|
|
42
41
|
}
|
|
43
42
|
case "cron": {
|
|
44
|
-
const { runCron } = await import("./cron-
|
|
43
|
+
const { runCron } = await import("./cron-3R2UWFO7.js");
|
|
45
44
|
await runCron(client, args);
|
|
46
45
|
break;
|
|
47
46
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { KantBanCLIClient } from './client.js';\n\nconst apiToken = process.env['KANTBAN_API_TOKEN'];\nconst apiUrl = process.env['KANTBAN_API_URL'];\n\nif (!apiToken || !apiUrl) {\n console.error('Error: KANTBAN_API_TOKEN and KANTBAN_API_URL environment variables are required');\n process.exit(1);\n}\n\nconst client = new KantBanCLIClient(apiUrl, apiToken);\nconst [command, ...args] = process.argv.slice(2);\n\nasync function main() {\n switch (command) {\n case 'context': {\n const { runContext } = await import('./commands/context.js');\n await runContext(client, args);\n break;\n }\n case 'status': {\n const { runStatus } = await import('./commands/status.js');\n await runStatus(client, args);\n break;\n }\n case 'work': {\n const { runWork } = await import('./commands/work.js');\n await runWork(client, args);\n break;\n }\n case 'pipeline': {\n if (args[0] === 'stop') {\n const { stopPipeline } = await import('./commands/pipeline.js');\n await stopPipeline(args.slice(1));\n } else {\n const { runPipeline } = await import('./commands/pipeline.js');\n await runPipeline(client, args);\n }\n break;\n }\n case 'cron': {\n const { runCron } = await import('./commands/cron.js');\n await runCron(client, args);\n break;\n }\n default:\n console.log(`kantban CLI — Pipeline orchestration for KantBan\n\nUsage:\n kantban context <scope-type> <scope-id> Output scoped pipeline context to stdout\n kantban status <board-id> Pipeline health at a glance\n kantban work <ticket-id> Start a Claude session for a ticket\n kantban pipeline <board-id> Persistent pipeline orchestrator\n kantban pipeline stop <board-id> Stop running pipeline\n kantban cron <column-id> [--interval 5m] Run single column on a timer\n\nEnvironment:\n KANTBAN_API_TOKEN API token (required)\n KANTBAN_API_URL API URL (required)\n KANTBAN_PROJECT_ID Default project ID (optional)`);\n }\n}\n\nmain().catch((err: Error) => {\n console.error('Error:', err.message);\n process.exit(1);\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { KantBanCLIClient } from './client.js';\n\nconst apiToken = process.env['KANTBAN_API_TOKEN'];\nconst apiUrl = process.env['KANTBAN_API_URL'];\n\nif (!apiToken || !apiUrl) {\n console.error('Error: KANTBAN_API_TOKEN and KANTBAN_API_URL environment variables are required');\n process.exit(1);\n}\n\nconst client = new KantBanCLIClient(apiUrl, apiToken);\nconst [command, ...args] = process.argv.slice(2);\n\nasync function main() {\n switch (command) {\n case 'context': {\n const { runContext } = await import('./commands/context.js');\n await runContext(client, args);\n break;\n }\n case 'status': {\n const { runStatus } = await import('./commands/status.js');\n await runStatus(client, args);\n break;\n }\n case 'work': {\n const { runWork } = await import('./commands/work.js');\n await runWork(client, args);\n break;\n }\n case 'pipeline': {\n if (args[0] === 'stop') {\n const { stopPipeline } = await import('./commands/pipeline.js');\n await stopPipeline(args.slice(1));\n } else {\n const { runPipeline } = await import('./commands/pipeline.js');\n await runPipeline(client, args);\n }\n break;\n }\n case 'cron': {\n const { runCron } = await import('./commands/cron.js');\n await runCron(client, args);\n break;\n }\n default:\n console.log(`kantban CLI — Pipeline orchestration for KantBan\n\nUsage:\n kantban context <scope-type> <scope-id> Output scoped pipeline context to stdout\n kantban status <board-id> Pipeline health at a glance\n kantban work <ticket-id> Start a Claude session for a ticket\n kantban pipeline <board-id> Persistent pipeline orchestrator\n kantban pipeline stop <board-id> Stop running pipeline\n kantban cron <column-id> [--interval 5m] Run single column on a timer\n\nEnvironment:\n KANTBAN_API_TOKEN API token (required)\n KANTBAN_API_URL API URL (required)\n KANTBAN_PROJECT_ID Default project ID (optional)`);\n }\n}\n\nmain().catch((err: Error) => {\n console.error('Error:', err.message);\n process.exit(1);\n});\n"],"mappings":";;;;;;AAGA,IAAM,WAAW,QAAQ,IAAI,mBAAmB;AAChD,IAAM,SAAS,QAAQ,IAAI,iBAAiB;AAE5C,IAAI,CAAC,YAAY,CAAC,QAAQ;AACxB,UAAQ,MAAM,iFAAiF;AAC/F,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,SAAS,IAAI,iBAAiB,QAAQ,QAAQ;AACpD,IAAM,CAAC,SAAS,GAAG,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC;AAE/C,eAAe,OAAO;AACpB,UAAQ,SAAS;AAAA,IACf,KAAK,WAAW;AACd,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,uBAAuB;AAC3D,YAAM,WAAW,QAAQ,IAAI;AAC7B;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,YAAM,EAAE,UAAU,IAAI,MAAM,OAAO,sBAAsB;AACzD,YAAM,UAAU,QAAQ,IAAI;AAC5B;AAAA,IACF;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,oBAAoB;AACrD,YAAM,QAAQ,QAAQ,IAAI;AAC1B;AAAA,IACF;AAAA,IACA,KAAK,YAAY;AACf,UAAI,KAAK,CAAC,MAAM,QAAQ;AACtB,cAAM,EAAE,aAAa,IAAI,MAAM,OAAO,wBAAwB;AAC9D,cAAM,aAAa,KAAK,MAAM,CAAC,CAAC;AAAA,MAClC,OAAO;AACL,cAAM,EAAE,YAAY,IAAI,MAAM,OAAO,wBAAwB;AAC7D,cAAM,YAAY,QAAQ,IAAI;AAAA,MAChC;AACA;AAAA,IACF;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,oBAAoB;AACrD,YAAM,QAAQ,QAAQ,IAAI;AAC1B;AAAA,IACF;AAAA,IACA;AACE,cAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qDAamC;AAAA,EACnD;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,QAAe;AAC3B,UAAQ,MAAM,UAAU,IAAI,OAAO;AACnC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|
|
@@ -5,14 +5,13 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
formatGateErrors,
|
|
7
7
|
runGates
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-MKKHLFA5.js";
|
|
9
9
|
import {
|
|
10
10
|
parseGateConfig,
|
|
11
11
|
parseTimeout,
|
|
12
12
|
resolveGatesForColumn
|
|
13
13
|
} from "../chunk-DAFLEMLK.js";
|
|
14
|
-
import "../chunk-
|
|
15
|
-
import "../chunk-DGUM43GV.js";
|
|
14
|
+
import "../chunk-5ZU2OOES.js";
|
|
16
15
|
|
|
17
16
|
// src/lib/gate-proxy-server.ts
|
|
18
17
|
import { readFileSync } from "fs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/gate-proxy-server.ts","../../src/lib/gate-proxy.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * gate-proxy-server.ts — MCP stdio server for gate enforcement.\n *\n * Spawned by the pipeline orchestrator as a child process. Reads gate config\n * from env vars, instantiates GateProxy, and exposes three MCP tools over\n * JSON-RPC on stdin/stdout:\n *\n * - kantban_run_gates — Run column gates and report results\n * - kantban_move_ticket — Run gates then forward move to KantBan API\n * - kantban_complete_task — Run gates then forward complete to KantBan API\n *\n * Uses raw JSON-RPC (no @modelcontextprotocol/sdk dependency).\n */\n\nimport { readFileSync } from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport { parseGateConfig } from './gate-config.js';\nimport { runGates, formatGateErrors } from './gate-runner.js';\nimport { GateProxy } from './gate-proxy.js';\nimport { fetchWithRetry } from '../client.js';\nimport type { GateProxyDeps } from './gate-proxy.js';\n\n// ── UUID validation ──────────────────────────────────────────────────────\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nfunction validateUuid(value: unknown, name: string): string {\n if (typeof value !== 'string' || !UUID_RE.test(value)) {\n throw new Error(`Invalid ${name}: expected UUID, got \"${String(value)}\"`);\n }\n return value;\n}\n\n// ── env ──────────────────────────────────────────────────────────────────\n\nconst GATE_CONFIG_PATH = process.env['GATE_CONFIG_PATH'];\nconst COLUMN_ID = process.env['COLUMN_ID'];\nconst COLUMN_NAME = process.env['COLUMN_NAME'];\nconst PROJECT_ID = process.env['PROJECT_ID'];\nconst API_TOKEN = process.env['KANTBAN_API_TOKEN'];\nconst API_URL = process.env['KANTBAN_API_URL'];\n\nfunction requireEnv(name: string, value: string | undefined): string {\n if (!value) {\n process.stderr.write(`gate-proxy-server: missing required env var ${name}\\n`);\n process.exit(1);\n }\n return value;\n}\n\nconst gateConfigPath = requireEnv('GATE_CONFIG_PATH', GATE_CONFIG_PATH);\nconst columnId = requireEnv('COLUMN_ID', COLUMN_ID);\nconst columnName = requireEnv('COLUMN_NAME', COLUMN_NAME);\nconst projectId = requireEnv('PROJECT_ID', PROJECT_ID);\nconst apiToken = requireEnv('KANTBAN_API_TOKEN', API_TOKEN);\nconst apiUrl = requireEnv('KANTBAN_API_URL', API_URL);\n\n// ── gate config ──────────────────────────────────────────────────────────\n\nconst yamlContent = readFileSync(gateConfigPath, 'utf-8');\nconst gateConfig = parseGateConfig(yamlContent);\n\n// GATE_CWD overrides the YAML settings.cwd — set by the orchestrator to the\n// agent's worktree path so gates run against the agent's checked-out code,\n// not the root repo.\nconst GATE_CWD = process.env['GATE_CWD'];\nif (GATE_CWD) {\n if (!gateConfig.settings) gateConfig.settings = {};\n gateConfig.settings.cwd = GATE_CWD;\n}\n\n// ── API helpers ──────────────────────────────────────────────────────────\n\nfunction apiHeaders(): Record<string, string> {\n return {\n 'Authorization': `Bearer ${apiToken}`,\n 'Content-Type': 'application/json',\n 'X-KantBan-Via': 'cli-gate-proxy',\n };\n}\n\nasync function apiPost(path: string, body: Record<string, unknown>): Promise<unknown> {\n const url = new URL(path, apiUrl);\n const res = await fetchWithRetry(url.toString(), {\n method: 'POST',\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`API error ${res.status}: ${text}`);\n }\n const json = (await res.json()) as { success: boolean; data: unknown };\n if (!json.success) throw new Error('API responded with success: false');\n return json.data;\n}\n\nasync function apiPatch(path: string, body: Record<string, unknown>): Promise<unknown> {\n const url = new URL(path, apiUrl);\n const res = await fetchWithRetry(url.toString(), {\n method: 'PATCH',\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`API error ${res.status}: ${text}`);\n }\n const json = (await res.json()) as { success: boolean; data: unknown };\n if (!json.success) throw new Error('API responded with success: false');\n return json.data;\n}\n\nasync function apiGet(path: string, params?: Record<string, string>): Promise<unknown> {\n const url = new URL(path, apiUrl);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n url.searchParams.set(k, v);\n }\n }\n const res = await fetchWithRetry(url.toString(), {\n headers: apiHeaders(),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`API error ${res.status}: ${text}`);\n }\n const json = (await res.json()) as { success: boolean; data: unknown };\n if (!json.success) throw new Error('API responded with success: false');\n return json.data;\n}\n\n// ── GateProxy deps ──────────────────────────────────────────────────────\n\nconst deps: GateProxyDeps = {\n runGates,\n\n async forwardMoveTicket(args: Record<string, unknown>): Promise<unknown> {\n const ticketProjectId = validateUuid(args['projectId'], 'projectId');\n const ticketId = validateUuid(args['ticketId'], 'ticketId');\n const body = { ...args };\n delete body['projectId'];\n delete body['ticketId'];\n return apiPatch(`/projects/${ticketProjectId}/tickets/${ticketId}/move`, body);\n },\n\n async forwardCompleteTask(args: Record<string, unknown>): Promise<unknown> {\n const projectId = validateUuid(args['projectId'], 'projectId');\n const ticketId = validateUuid(args['ticketId'], 'ticketId');\n const body = { ...args };\n delete body['projectId'];\n delete body['ticketId'];\n return apiPost(`/projects/${projectId}/tickets/${ticketId}/complete`, body);\n },\n\n async getTicketGateWaivers(ticketId: string): Promise<string[]> {\n try {\n // Field values require both projectId and ticketId in the path.\n // projectId is injected as an env var (PROJECT_ID) at server startup.\n validateUuid(ticketId, 'ticketId');\n const data = (await apiGet(`/projects/${projectId}/tickets/${ticketId}/field-values`)) as\n Array<{ field_name: string; value: unknown }>;\n const waiver = data.find((fv) => fv.field_name === 'gate_waiver');\n if (!waiver) return [];\n if (Array.isArray(waiver.value)) {\n return waiver.value.filter((v): v is string => typeof v === 'string' && v.length > 0);\n }\n return [];\n } catch (err) {\n process.stderr.write(`gate-proxy-server: waiver fetch failed (running all gates): ${err instanceof Error ? err.message : String(err)}\\n`);\n return [];\n }\n },\n};\n\nconst proxy = new GateProxy(gateConfig, deps);\n\n// ── JSON-RPC types ──────────────────────────────────────────────────────\n\ninterface JsonRpcRequest {\n jsonrpc: '2.0';\n id: number | string;\n method: string;\n params?: Record<string, unknown>;\n}\n\ninterface JsonRpcResponse {\n jsonrpc: '2.0';\n id: number | string | null;\n result?: unknown;\n error?: { code: number; message: string; data?: unknown };\n}\n\n// ── Tool definitions ────────────────────────────────────────────────────\n\nconst TOOLS = [\n {\n name: 'kantban_run_gates',\n description:\n 'Run all configured gates for the current column and report results. ' +\n 'Use this to check gate status before attempting to move a ticket. ' +\n 'Pass ticketId to filter out waived gates for that ticket.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n ticketId: { type: 'string', description: 'Ticket ID (UUID) — filters out waived gates for this ticket' },\n },\n required: [] as string[],\n },\n },\n {\n name: 'kantban_move_ticket',\n description:\n 'Move a ticket to a different column. Gates are automatically enforced — ' +\n 'if any required gate fails, the move is blocked and failure details are returned.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n projectId: { type: 'string', description: 'Project ID (UUID)' },\n ticketId: { type: 'string', description: 'Ticket ID (UUID)' },\n columnId: { type: 'string', description: 'Target column ID (UUID)' },\n currentColumnName: { type: 'string', description: 'Current column name' },\n handoff: {\n type: 'object',\n description: 'Structured handoff data for the next pipeline stage',\n additionalProperties: true,\n },\n },\n required: ['projectId', 'ticketId', 'columnId'],\n },\n },\n {\n name: 'kantban_complete_task',\n description:\n 'Mark a ticket as complete. Gates are automatically enforced — ' +\n 'if any required gate fails, the completion is blocked and failure details are returned.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n projectId: { type: 'string', description: 'Project ID (UUID)' },\n ticketId: { type: 'string', description: 'Ticket ID (UUID)' },\n currentColumnName: { type: 'string', description: 'Current column name' },\n moveToColumn: { type: 'string', description: 'Column name to move the ticket to (e.g. \"Done\")' },\n completionComment: { type: 'string', description: 'Comment to add upon completion' },\n handoff: {\n type: 'object',\n description: 'Structured handoff data for the next pipeline stage',\n additionalProperties: true,\n },\n },\n required: ['projectId', 'ticketId'],\n },\n },\n];\n\n// ── Tool handlers ───────────────────────────────────────────────────────\n\nasync function handleToolCall(\n name: string,\n args: Record<string, unknown>,\n): Promise<{ content: Array<{ type: 'text'; text: string }>; isError?: boolean }> {\n try {\n switch (name) {\n case 'kantban_run_gates': {\n const ticketIdArg = args['ticketId'] as string | undefined;\n if (ticketIdArg) validateUuid(ticketIdArg, 'ticketId');\n const result = await proxy.handleRunGates(columnName, ticketIdArg);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n };\n }\n\n case 'kantban_move_ticket': {\n const moveProjectId = validateUuid(args['projectId'], 'projectId');\n const moveTicketId = validateUuid(args['ticketId'], 'ticketId');\n const moveColumnId = validateUuid(args['columnId'], 'columnId');\n const result = await proxy.handleMoveTicket({\n projectId: moveProjectId,\n ticketId: moveTicketId,\n columnId: moveColumnId,\n currentColumnName: (args['currentColumnName'] as string | undefined) ?? columnName,\n args: {\n ...(args['handoff'] !== undefined ? { handoff: args['handoff'] } : {}),\n ...(args['column_id'] !== undefined ? { column_id: args['column_id'] } : {}),\n },\n });\n const isError = result.error === 'GATE_FAILURE';\n if (isError && result.results) {\n process.stderr.write(`gate-proxy-server: move blocked\\n${formatGateErrors(result.results)}`);\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n ...(isError ? { isError: true } : {}),\n };\n }\n\n case 'kantban_complete_task': {\n const completeProjectId = validateUuid(args['projectId'], 'projectId');\n const completeTicketId = validateUuid(args['ticketId'], 'ticketId');\n const result = await proxy.handleCompleteTask({\n projectId: completeProjectId,\n ticketId: completeTicketId,\n currentColumnName: (args['currentColumnName'] as string | undefined) ?? columnName,\n args: {\n ...(args['moveToColumn'] !== undefined ? { moveToColumn: args['moveToColumn'] } : {}),\n ...(args['completionComment'] !== undefined ? { completionComment: args['completionComment'] } : {}),\n ...(args['handoff'] !== undefined ? { handoff: args['handoff'] } : {}),\n },\n });\n const isError = result.error === 'GATE_FAILURE';\n if (isError && result.results) {\n process.stderr.write(`gate-proxy-server: complete blocked\\n${formatGateErrors(result.results)}`);\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n ...(isError ? { isError: true } : {}),\n };\n }\n\n default:\n return {\n content: [{ type: 'text', text: `Unknown tool: ${name}` }],\n isError: true,\n };\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `Error: ${message}` }],\n isError: true,\n };\n }\n}\n\n// ── JSON-RPC dispatch ───────────────────────────────────────────────────\n\nfunction sendResponse(response: JsonRpcResponse): void {\n const json = JSON.stringify(response);\n process.stdout.write(json + '\\n');\n}\n\nasync function handleMessage(msg: JsonRpcRequest): Promise<void> {\n const { id, method, params } = msg;\n\n switch (method) {\n case 'initialize': {\n sendResponse({\n jsonrpc: '2.0',\n id,\n result: {\n protocolVersion: '2024-11-05',\n capabilities: { tools: {} },\n serverInfo: {\n name: 'kantban-gates',\n version: '0.1.0',\n },\n },\n });\n return;\n }\n\n case 'notifications/initialized': {\n // Client acknowledgement — no response needed for notifications\n return;\n }\n\n case 'tools/list': {\n sendResponse({\n jsonrpc: '2.0',\n id,\n result: { tools: TOOLS },\n });\n return;\n }\n\n case 'tools/call': {\n const toolName = params?.['name'] as string | undefined;\n const toolArgs = (params?.['arguments'] as Record<string, unknown> | undefined) ?? {};\n\n if (!toolName) {\n sendResponse({\n jsonrpc: '2.0',\n id,\n error: { code: -32602, message: 'Missing tool name' },\n });\n return;\n }\n\n const result = await handleToolCall(toolName, toolArgs);\n sendResponse({\n jsonrpc: '2.0',\n id,\n result,\n });\n return;\n }\n\n case 'ping': {\n sendResponse({ jsonrpc: '2.0', id, result: {} });\n return;\n }\n\n default: {\n // Unknown method — return method not found per JSON-RPC spec\n if (method.startsWith('notifications/')) {\n // Notifications don't get responses\n return;\n }\n sendResponse({\n jsonrpc: '2.0',\n id,\n error: { code: -32601, message: `Method not found: ${method}` },\n });\n }\n }\n}\n\n// ── stdin reader ────────────────────────────────────────────────────────\n\nconst rl = createInterface({ input: process.stdin });\n\n// Serialize message processing to prevent concurrent double-moves\nlet messageQueue: Promise<void> = Promise.resolve();\n\nrl.on('line', (line: string) => {\n const trimmed = line.trim();\n if (!trimmed) return;\n\n let msg: JsonRpcRequest;\n try {\n msg = JSON.parse(trimmed) as JsonRpcRequest;\n } catch {\n sendResponse({\n jsonrpc: '2.0',\n id: null as unknown as number,\n error: { code: -32700, message: 'Parse error' },\n });\n return;\n }\n\n messageQueue = messageQueue.then(() => handleMessage(msg)).catch((err) => {\n process.stderr.write(`gate-proxy-server: unhandled error in message handler: ${err instanceof Error ? err.message : String(err)}\\n`);\n });\n});\n\nrl.on('close', () => {\n process.exit(0);\n});\n\n// Suppress unhandled rejection crashes — log to stderr and continue\nprocess.on('unhandledRejection', (err) => {\n process.stderr.write(\n `gate-proxy-server: unhandled rejection: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n});\n\nprocess.stderr.write(`gate-proxy-server: started (column=\"${columnName}\", gates=${gateConfig.default.length})\\n`);\n","import { resolveGatesForColumn, parseTimeout } from './gate-config.js';\nimport { formatGateErrors } from './gate-runner.js';\nimport type { GateConfig, GateDefinition, GateResult } from '@kantban/types';\n\nexport interface GateProxyDeps {\n runGates: (gates: GateDefinition[], options?: { cwd?: string; env?: Record<string, string>; totalTimeoutMs?: number }) => Promise<GateResult[]>;\n forwardMoveTicket: (args: Record<string, unknown>) => Promise<unknown>;\n forwardCompleteTask: (args: Record<string, unknown>) => Promise<unknown>;\n getTicketGateWaivers: (ticketId: string) => Promise<string[]>;\n}\n\nexport interface RunGatesResult {\n passed: boolean;\n results: GateResult[];\n}\n\nexport interface MoveArgs {\n projectId: string;\n ticketId: string;\n columnId: string;\n currentColumnName: string;\n args: Record<string, unknown>;\n}\n\nexport interface CompleteArgs {\n projectId: string;\n ticketId: string;\n currentColumnName: string;\n args: Record<string, unknown>;\n}\n\nexport interface InterceptResult {\n error?: 'GATE_FAILURE';\n message?: string;\n formatted?: string;\n results?: GateResult[];\n hint?: string;\n forwardResult?: unknown;\n}\n\nexport class GateProxy {\n private config: GateConfig;\n private deps: GateProxyDeps;\n\n constructor(config: GateConfig, deps: GateProxyDeps) {\n this.config = config;\n this.deps = deps;\n }\n\n private buildRunOptions(): { cwd?: string; env?: Record<string, string>; totalTimeoutMs?: number } {\n const opts: { cwd?: string; env?: Record<string, string>; totalTimeoutMs?: number } = {};\n if (this.config.settings?.cwd !== undefined) opts.cwd = this.config.settings.cwd;\n if (this.config.settings?.env !== undefined) opts.env = this.config.settings.env;\n if (this.config.settings?.total_timeout !== undefined) {\n opts.totalTimeoutMs = parseTimeout(this.config.settings.total_timeout);\n }\n return opts;\n }\n\n async handleRunGates(columnName: string, ticketId?: string): Promise<RunGatesResult> {\n const allGates = resolveGatesForColumn(this.config, columnName);\n\n let gates = allGates;\n if (ticketId) {\n const waivers = await this.deps.getTicketGateWaivers(ticketId);\n const waiverSet = new Set(waivers);\n gates = allGates.filter((g) => !waiverSet.has(g.name));\n }\n\n const results = await this.deps.runGates(gates, this.buildRunOptions());\n return {\n passed: results.filter((r) => r.required).every((r) => r.passed),\n results,\n };\n }\n\n async handleMoveTicket(move: MoveArgs): Promise<InterceptResult> {\n const allGates = resolveGatesForColumn(this.config, move.currentColumnName);\n\n // Filter out waived gates\n const waivers = await this.deps.getTicketGateWaivers(move.ticketId);\n const waiverSet = new Set(waivers);\n const gates = allGates.filter((g) => !waiverSet.has(g.name));\n\n let results: GateResult[];\n try {\n results = await this.deps.runGates(gates, this.buildRunOptions());\n } catch (err) {\n return {\n error: 'GATE_FAILURE',\n message: `Gate evaluation error: ${err instanceof Error ? err.message : String(err)}`,\n hint: 'Fix the gate environment and retry',\n };\n }\n\n const requiredFailures = results.filter((r) => r.required && !r.passed);\n if (requiredFailures.length > 0) {\n return {\n error: 'GATE_FAILURE',\n message: `Cannot move ticket — ${requiredFailures.length} required gate(s) failed`,\n formatted: formatGateErrors(results.filter((r) => r.required)),\n results,\n hint: 'Fix the failing gate(s) and try move_ticket again',\n };\n }\n\n const forwardResult = await this.deps.forwardMoveTicket({\n ...move.args,\n projectId: move.projectId,\n ticketId: move.ticketId,\n column_id: move.columnId,\n });\n\n return { forwardResult };\n }\n\n async handleCompleteTask(complete: CompleteArgs): Promise<InterceptResult> {\n const allGates = resolveGatesForColumn(this.config, complete.currentColumnName);\n const waivers = await this.deps.getTicketGateWaivers(complete.ticketId);\n const waiverSet = new Set(waivers);\n const gates = allGates.filter((g) => !waiverSet.has(g.name));\n\n let results: GateResult[];\n try {\n results = await this.deps.runGates(gates, this.buildRunOptions());\n } catch (err) {\n return {\n error: 'GATE_FAILURE',\n message: `Gate evaluation error: ${err instanceof Error ? err.message : String(err)}`,\n hint: 'Fix the gate environment and retry',\n };\n }\n\n const requiredFailures = results.filter((r) => r.required && !r.passed);\n if (requiredFailures.length > 0) {\n return {\n error: 'GATE_FAILURE',\n message: `Cannot complete task — ${requiredFailures.length} required gate(s) failed`,\n formatted: formatGateErrors(results.filter((r) => r.required)),\n results,\n hint: 'Fix the failing gate(s) and try complete_task again',\n };\n }\n\n const forwardResult = await this.deps.forwardCompleteTask({\n ...complete.args,\n projectId: complete.projectId,\n ticketId: complete.ticketId,\n });\n\n return { forwardResult };\n }\n}\n"],"mappings":"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","names":["deps","columnName","projectId"]}
|
|
1
|
+
{"version":3,"sources":["../../src/lib/gate-proxy-server.ts","../../src/lib/gate-proxy.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * gate-proxy-server.ts — MCP stdio server for gate enforcement.\n *\n * Spawned by the pipeline orchestrator as a child process. Reads gate config\n * from env vars, instantiates GateProxy, and exposes three MCP tools over\n * JSON-RPC on stdin/stdout:\n *\n * - kantban_run_gates — Run column gates and report results\n * - kantban_move_ticket — Run gates then forward move to KantBan API\n * - kantban_complete_task — Run gates then forward complete to KantBan API\n *\n * Uses raw JSON-RPC (no @modelcontextprotocol/sdk dependency).\n */\n\nimport { readFileSync } from 'node:fs';\nimport { createInterface } from 'node:readline';\nimport { parseGateConfig } from './gate-config.js';\nimport { runGates, formatGateErrors } from './gate-runner.js';\nimport { GateProxy } from './gate-proxy.js';\nimport { fetchWithRetry } from '../client.js';\nimport type { GateProxyDeps } from './gate-proxy.js';\n\n// ── UUID validation ──────────────────────────────────────────────────────\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nfunction validateUuid(value: unknown, name: string): string {\n if (typeof value !== 'string' || !UUID_RE.test(value)) {\n throw new Error(`Invalid ${name}: expected UUID, got \"${String(value)}\"`);\n }\n return value;\n}\n\n// ── env ──────────────────────────────────────────────────────────────────\n\nconst GATE_CONFIG_PATH = process.env['GATE_CONFIG_PATH'];\nconst COLUMN_ID = process.env['COLUMN_ID'];\nconst COLUMN_NAME = process.env['COLUMN_NAME'];\nconst PROJECT_ID = process.env['PROJECT_ID'];\nconst API_TOKEN = process.env['KANTBAN_API_TOKEN'];\nconst API_URL = process.env['KANTBAN_API_URL'];\n\nfunction requireEnv(name: string, value: string | undefined): string {\n if (!value) {\n process.stderr.write(`gate-proxy-server: missing required env var ${name}\\n`);\n process.exit(1);\n }\n return value;\n}\n\nconst gateConfigPath = requireEnv('GATE_CONFIG_PATH', GATE_CONFIG_PATH);\nconst columnId = requireEnv('COLUMN_ID', COLUMN_ID);\nconst columnName = requireEnv('COLUMN_NAME', COLUMN_NAME);\nconst projectId = requireEnv('PROJECT_ID', PROJECT_ID);\nconst apiToken = requireEnv('KANTBAN_API_TOKEN', API_TOKEN);\nconst apiUrl = requireEnv('KANTBAN_API_URL', API_URL);\n\n// ── gate config ──────────────────────────────────────────────────────────\n\nconst yamlContent = readFileSync(gateConfigPath, 'utf-8');\nconst gateConfig = parseGateConfig(yamlContent);\n\n// GATE_CWD overrides the YAML settings.cwd — set by the orchestrator to the\n// agent's worktree path so gates run against the agent's checked-out code,\n// not the root repo.\nconst GATE_CWD = process.env['GATE_CWD'];\nif (GATE_CWD) {\n if (!gateConfig.settings) gateConfig.settings = {};\n gateConfig.settings.cwd = GATE_CWD;\n}\n\n// ── API helpers ──────────────────────────────────────────────────────────\n\nfunction apiHeaders(): Record<string, string> {\n return {\n 'Authorization': `Bearer ${apiToken}`,\n 'Content-Type': 'application/json',\n 'X-KantBan-Via': 'cli-gate-proxy',\n };\n}\n\nasync function apiPost(path: string, body: Record<string, unknown>): Promise<unknown> {\n const url = new URL(path, apiUrl);\n const res = await fetchWithRetry(url.toString(), {\n method: 'POST',\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`API error ${res.status}: ${text}`);\n }\n const json = (await res.json()) as { success: boolean; data: unknown };\n if (!json.success) throw new Error('API responded with success: false');\n return json.data;\n}\n\nasync function apiPatch(path: string, body: Record<string, unknown>): Promise<unknown> {\n const url = new URL(path, apiUrl);\n const res = await fetchWithRetry(url.toString(), {\n method: 'PATCH',\n headers: apiHeaders(),\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`API error ${res.status}: ${text}`);\n }\n const json = (await res.json()) as { success: boolean; data: unknown };\n if (!json.success) throw new Error('API responded with success: false');\n return json.data;\n}\n\nasync function apiGet(path: string, params?: Record<string, string>): Promise<unknown> {\n const url = new URL(path, apiUrl);\n if (params) {\n for (const [k, v] of Object.entries(params)) {\n url.searchParams.set(k, v);\n }\n }\n const res = await fetchWithRetry(url.toString(), {\n headers: apiHeaders(),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`API error ${res.status}: ${text}`);\n }\n const json = (await res.json()) as { success: boolean; data: unknown };\n if (!json.success) throw new Error('API responded with success: false');\n return json.data;\n}\n\n// ── GateProxy deps ──────────────────────────────────────────────────────\n\nconst deps: GateProxyDeps = {\n runGates,\n\n async forwardMoveTicket(args: Record<string, unknown>): Promise<unknown> {\n const ticketProjectId = validateUuid(args['projectId'], 'projectId');\n const ticketId = validateUuid(args['ticketId'], 'ticketId');\n const body = { ...args };\n delete body['projectId'];\n delete body['ticketId'];\n return apiPatch(`/projects/${ticketProjectId}/tickets/${ticketId}/move`, body);\n },\n\n async forwardCompleteTask(args: Record<string, unknown>): Promise<unknown> {\n const projectId = validateUuid(args['projectId'], 'projectId');\n const ticketId = validateUuid(args['ticketId'], 'ticketId');\n const body = { ...args };\n delete body['projectId'];\n delete body['ticketId'];\n return apiPost(`/projects/${projectId}/tickets/${ticketId}/complete`, body);\n },\n\n async getTicketGateWaivers(ticketId: string): Promise<string[]> {\n try {\n // Field values require both projectId and ticketId in the path.\n // projectId is injected as an env var (PROJECT_ID) at server startup.\n validateUuid(ticketId, 'ticketId');\n const data = (await apiGet(`/projects/${projectId}/tickets/${ticketId}/field-values`)) as\n Array<{ field_name: string; value: unknown }>;\n const waiver = data.find((fv) => fv.field_name === 'gate_waiver');\n if (!waiver) return [];\n if (Array.isArray(waiver.value)) {\n return waiver.value.filter((v): v is string => typeof v === 'string' && v.length > 0);\n }\n return [];\n } catch (err) {\n process.stderr.write(`gate-proxy-server: waiver fetch failed (running all gates): ${err instanceof Error ? err.message : String(err)}\\n`);\n return [];\n }\n },\n};\n\nconst proxy = new GateProxy(gateConfig, deps);\n\n// ── JSON-RPC types ──────────────────────────────────────────────────────\n\ninterface JsonRpcRequest {\n jsonrpc: '2.0';\n id: number | string;\n method: string;\n params?: Record<string, unknown>;\n}\n\ninterface JsonRpcResponse {\n jsonrpc: '2.0';\n id: number | string | null;\n result?: unknown;\n error?: { code: number; message: string; data?: unknown };\n}\n\n// ── Tool definitions ────────────────────────────────────────────────────\n\nconst TOOLS = [\n {\n name: 'kantban_run_gates',\n description:\n 'Run all configured gates for the current column and report results. ' +\n 'Use this to check gate status before attempting to move a ticket. ' +\n 'Pass ticketId to filter out waived gates for that ticket.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n ticketId: { type: 'string', description: 'Ticket ID (UUID) — filters out waived gates for this ticket' },\n },\n required: [] as string[],\n },\n },\n {\n name: 'kantban_move_ticket',\n description:\n 'Move a ticket to a different column. Gates are automatically enforced — ' +\n 'if any required gate fails, the move is blocked and failure details are returned.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n projectId: { type: 'string', description: 'Project ID (UUID)' },\n ticketId: { type: 'string', description: 'Ticket ID (UUID)' },\n columnId: { type: 'string', description: 'Target column ID (UUID)' },\n currentColumnName: { type: 'string', description: 'Current column name' },\n handoff: {\n type: 'object',\n description: 'Structured handoff data for the next pipeline stage',\n additionalProperties: true,\n },\n },\n required: ['projectId', 'ticketId', 'columnId'],\n },\n },\n {\n name: 'kantban_complete_task',\n description:\n 'Mark a ticket as complete. Gates are automatically enforced — ' +\n 'if any required gate fails, the completion is blocked and failure details are returned.',\n inputSchema: {\n type: 'object' as const,\n properties: {\n projectId: { type: 'string', description: 'Project ID (UUID)' },\n ticketId: { type: 'string', description: 'Ticket ID (UUID)' },\n currentColumnName: { type: 'string', description: 'Current column name' },\n moveToColumn: { type: 'string', description: 'Column name to move the ticket to (e.g. \"Done\")' },\n completionComment: { type: 'string', description: 'Comment to add upon completion' },\n handoff: {\n type: 'object',\n description: 'Structured handoff data for the next pipeline stage',\n additionalProperties: true,\n },\n },\n required: ['projectId', 'ticketId'],\n },\n },\n];\n\n// ── Tool handlers ───────────────────────────────────────────────────────\n\nasync function handleToolCall(\n name: string,\n args: Record<string, unknown>,\n): Promise<{ content: Array<{ type: 'text'; text: string }>; isError?: boolean }> {\n try {\n switch (name) {\n case 'kantban_run_gates': {\n const ticketIdArg = args['ticketId'] as string | undefined;\n if (ticketIdArg) validateUuid(ticketIdArg, 'ticketId');\n const result = await proxy.handleRunGates(columnName, ticketIdArg);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n };\n }\n\n case 'kantban_move_ticket': {\n const moveProjectId = validateUuid(args['projectId'], 'projectId');\n const moveTicketId = validateUuid(args['ticketId'], 'ticketId');\n const moveColumnId = validateUuid(args['columnId'], 'columnId');\n const result = await proxy.handleMoveTicket({\n projectId: moveProjectId,\n ticketId: moveTicketId,\n columnId: moveColumnId,\n currentColumnName: (args['currentColumnName'] as string | undefined) ?? columnName,\n args: {\n ...(args['handoff'] !== undefined ? { handoff: args['handoff'] } : {}),\n ...(args['column_id'] !== undefined ? { column_id: args['column_id'] } : {}),\n },\n });\n const isError = result.error === 'GATE_FAILURE';\n if (isError && result.results) {\n process.stderr.write(`gate-proxy-server: move blocked\\n${formatGateErrors(result.results)}`);\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n ...(isError ? { isError: true } : {}),\n };\n }\n\n case 'kantban_complete_task': {\n const completeProjectId = validateUuid(args['projectId'], 'projectId');\n const completeTicketId = validateUuid(args['ticketId'], 'ticketId');\n const result = await proxy.handleCompleteTask({\n projectId: completeProjectId,\n ticketId: completeTicketId,\n currentColumnName: (args['currentColumnName'] as string | undefined) ?? columnName,\n args: {\n ...(args['moveToColumn'] !== undefined ? { moveToColumn: args['moveToColumn'] } : {}),\n ...(args['completionComment'] !== undefined ? { completionComment: args['completionComment'] } : {}),\n ...(args['handoff'] !== undefined ? { handoff: args['handoff'] } : {}),\n },\n });\n const isError = result.error === 'GATE_FAILURE';\n if (isError && result.results) {\n process.stderr.write(`gate-proxy-server: complete blocked\\n${formatGateErrors(result.results)}`);\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n ...(isError ? { isError: true } : {}),\n };\n }\n\n default:\n return {\n content: [{ type: 'text', text: `Unknown tool: ${name}` }],\n isError: true,\n };\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [{ type: 'text', text: `Error: ${message}` }],\n isError: true,\n };\n }\n}\n\n// ── JSON-RPC dispatch ───────────────────────────────────────────────────\n\nfunction sendResponse(response: JsonRpcResponse): void {\n const json = JSON.stringify(response);\n process.stdout.write(json + '\\n');\n}\n\nasync function handleMessage(msg: JsonRpcRequest): Promise<void> {\n const { id, method, params } = msg;\n\n switch (method) {\n case 'initialize': {\n sendResponse({\n jsonrpc: '2.0',\n id,\n result: {\n protocolVersion: '2024-11-05',\n capabilities: { tools: {} },\n serverInfo: {\n name: 'kantban-gates',\n version: '0.1.0',\n },\n },\n });\n return;\n }\n\n case 'notifications/initialized': {\n // Client acknowledgement — no response needed for notifications\n return;\n }\n\n case 'tools/list': {\n sendResponse({\n jsonrpc: '2.0',\n id,\n result: { tools: TOOLS },\n });\n return;\n }\n\n case 'tools/call': {\n const toolName = params?.['name'] as string | undefined;\n const toolArgs = (params?.['arguments'] as Record<string, unknown> | undefined) ?? {};\n\n if (!toolName) {\n sendResponse({\n jsonrpc: '2.0',\n id,\n error: { code: -32602, message: 'Missing tool name' },\n });\n return;\n }\n\n const result = await handleToolCall(toolName, toolArgs);\n sendResponse({\n jsonrpc: '2.0',\n id,\n result,\n });\n return;\n }\n\n case 'ping': {\n sendResponse({ jsonrpc: '2.0', id, result: {} });\n return;\n }\n\n default: {\n // Unknown method — return method not found per JSON-RPC spec\n if (method.startsWith('notifications/')) {\n // Notifications don't get responses\n return;\n }\n sendResponse({\n jsonrpc: '2.0',\n id,\n error: { code: -32601, message: `Method not found: ${method}` },\n });\n }\n }\n}\n\n// ── stdin reader ────────────────────────────────────────────────────────\n\nconst rl = createInterface({ input: process.stdin });\n\n// Serialize message processing to prevent concurrent double-moves\nlet messageQueue: Promise<void> = Promise.resolve();\n\nrl.on('line', (line: string) => {\n const trimmed = line.trim();\n if (!trimmed) return;\n\n let msg: JsonRpcRequest;\n try {\n msg = JSON.parse(trimmed) as JsonRpcRequest;\n } catch {\n sendResponse({\n jsonrpc: '2.0',\n id: null as unknown as number,\n error: { code: -32700, message: 'Parse error' },\n });\n return;\n }\n\n messageQueue = messageQueue.then(() => handleMessage(msg)).catch((err) => {\n process.stderr.write(`gate-proxy-server: unhandled error in message handler: ${err instanceof Error ? err.message : String(err)}\\n`);\n });\n});\n\nrl.on('close', () => {\n process.exit(0);\n});\n\n// Suppress unhandled rejection crashes — log to stderr and continue\nprocess.on('unhandledRejection', (err) => {\n process.stderr.write(\n `gate-proxy-server: unhandled rejection: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n});\n\nprocess.stderr.write(`gate-proxy-server: started (column=\"${columnName}\", gates=${gateConfig.default.length})\\n`);\n","import { resolveGatesForColumn, parseTimeout } from './gate-config.js';\nimport { formatGateErrors } from './gate-runner.js';\nimport type { GateConfig, GateDefinition, GateResult } from '@kantban/types';\n\nexport interface GateProxyDeps {\n runGates: (gates: GateDefinition[], options?: { cwd?: string; env?: Record<string, string>; totalTimeoutMs?: number }) => Promise<GateResult[]>;\n forwardMoveTicket: (args: Record<string, unknown>) => Promise<unknown>;\n forwardCompleteTask: (args: Record<string, unknown>) => Promise<unknown>;\n getTicketGateWaivers: (ticketId: string) => Promise<string[]>;\n}\n\nexport interface RunGatesResult {\n passed: boolean;\n results: GateResult[];\n}\n\nexport interface MoveArgs {\n projectId: string;\n ticketId: string;\n columnId: string;\n currentColumnName: string;\n args: Record<string, unknown>;\n}\n\nexport interface CompleteArgs {\n projectId: string;\n ticketId: string;\n currentColumnName: string;\n args: Record<string, unknown>;\n}\n\nexport interface InterceptResult {\n error?: 'GATE_FAILURE';\n message?: string;\n formatted?: string;\n results?: GateResult[];\n hint?: string;\n forwardResult?: unknown;\n}\n\nexport class GateProxy {\n private config: GateConfig;\n private deps: GateProxyDeps;\n\n constructor(config: GateConfig, deps: GateProxyDeps) {\n this.config = config;\n this.deps = deps;\n }\n\n private buildRunOptions(): { cwd?: string; env?: Record<string, string>; totalTimeoutMs?: number } {\n const opts: { cwd?: string; env?: Record<string, string>; totalTimeoutMs?: number } = {};\n if (this.config.settings?.cwd !== undefined) opts.cwd = this.config.settings.cwd;\n if (this.config.settings?.env !== undefined) opts.env = this.config.settings.env;\n if (this.config.settings?.total_timeout !== undefined) {\n opts.totalTimeoutMs = parseTimeout(this.config.settings.total_timeout);\n }\n return opts;\n }\n\n async handleRunGates(columnName: string, ticketId?: string): Promise<RunGatesResult> {\n const allGates = resolveGatesForColumn(this.config, columnName);\n\n let gates = allGates;\n if (ticketId) {\n const waivers = await this.deps.getTicketGateWaivers(ticketId);\n const waiverSet = new Set(waivers);\n gates = allGates.filter((g) => !waiverSet.has(g.name));\n }\n\n const results = await this.deps.runGates(gates, this.buildRunOptions());\n return {\n passed: results.filter((r) => r.required).every((r) => r.passed),\n results,\n };\n }\n\n async handleMoveTicket(move: MoveArgs): Promise<InterceptResult> {\n const allGates = resolveGatesForColumn(this.config, move.currentColumnName);\n\n // Filter out waived gates\n const waivers = await this.deps.getTicketGateWaivers(move.ticketId);\n const waiverSet = new Set(waivers);\n const gates = allGates.filter((g) => !waiverSet.has(g.name));\n\n let results: GateResult[];\n try {\n results = await this.deps.runGates(gates, this.buildRunOptions());\n } catch (err) {\n return {\n error: 'GATE_FAILURE',\n message: `Gate evaluation error: ${err instanceof Error ? err.message : String(err)}`,\n hint: 'Fix the gate environment and retry',\n };\n }\n\n const requiredFailures = results.filter((r) => r.required && !r.passed);\n if (requiredFailures.length > 0) {\n return {\n error: 'GATE_FAILURE',\n message: `Cannot move ticket — ${requiredFailures.length} required gate(s) failed`,\n formatted: formatGateErrors(results.filter((r) => r.required)),\n results,\n hint: 'Fix the failing gate(s) and try move_ticket again',\n };\n }\n\n const forwardResult = await this.deps.forwardMoveTicket({\n ...move.args,\n projectId: move.projectId,\n ticketId: move.ticketId,\n column_id: move.columnId,\n });\n\n return { forwardResult };\n }\n\n async handleCompleteTask(complete: CompleteArgs): Promise<InterceptResult> {\n const allGates = resolveGatesForColumn(this.config, complete.currentColumnName);\n const waivers = await this.deps.getTicketGateWaivers(complete.ticketId);\n const waiverSet = new Set(waivers);\n const gates = allGates.filter((g) => !waiverSet.has(g.name));\n\n let results: GateResult[];\n try {\n results = await this.deps.runGates(gates, this.buildRunOptions());\n } catch (err) {\n return {\n error: 'GATE_FAILURE',\n message: `Gate evaluation error: ${err instanceof Error ? err.message : String(err)}`,\n hint: 'Fix the gate environment and retry',\n };\n }\n\n const requiredFailures = results.filter((r) => r.required && !r.passed);\n if (requiredFailures.length > 0) {\n return {\n error: 'GATE_FAILURE',\n message: `Cannot complete task — ${requiredFailures.length} required gate(s) failed`,\n formatted: formatGateErrors(results.filter((r) => r.required)),\n results,\n hint: 'Fix the failing gate(s) and try complete_task again',\n };\n }\n\n const forwardResult = await this.deps.forwardCompleteTask({\n ...complete.args,\n projectId: complete.projectId,\n ticketId: complete.ticketId,\n });\n\n return { forwardResult };\n }\n}\n"],"mappings":"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","names":["deps","columnName","projectId"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runGates
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MKKHLFA5.js";
|
|
4
4
|
import {
|
|
5
5
|
ClaudeProvider,
|
|
6
6
|
RalphLoop,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
generateMcpConfig,
|
|
13
13
|
parseJsonFromLlmOutput,
|
|
14
14
|
parseStuckDetectionResponse
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-2CY5OPZN.js";
|
|
16
16
|
import {
|
|
17
17
|
LoopCheckpointSchema,
|
|
18
18
|
VerdictSchema,
|
|
@@ -26,8 +26,7 @@ import {
|
|
|
26
26
|
killProcessTree,
|
|
27
27
|
normalizeEol,
|
|
28
28
|
resolveCommand
|
|
29
|
-
} from "./chunk-
|
|
30
|
-
import "./chunk-DGUM43GV.js";
|
|
29
|
+
} from "./chunk-5ZU2OOES.js";
|
|
31
30
|
|
|
32
31
|
// src/commands/pipeline.ts
|
|
33
32
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync3, unlinkSync as unlinkSync3, existsSync as existsSync3, appendFileSync as appendFileSync2 } from "fs";
|
|
@@ -4169,7 +4168,7 @@ function waitForConfirmation() {
|
|
|
4169
4168
|
}
|
|
4170
4169
|
async function runPipeline(client, args) {
|
|
4171
4170
|
if (args[0] === "init") {
|
|
4172
|
-
const { runPipelineInit } = await import("./pipeline-init-
|
|
4171
|
+
const { runPipelineInit } = await import("./pipeline-init-IGZZOOLK.js");
|
|
4173
4172
|
await runPipelineInit();
|
|
4174
4173
|
return;
|
|
4175
4174
|
}
|
|
@@ -4215,8 +4214,8 @@ async function runPipeline(client, args) {
|
|
|
4215
4214
|
}
|
|
4216
4215
|
const mcpConfigPath = generateMcpConfig(client.baseUrl, client.token, opts.boardId);
|
|
4217
4216
|
const boardProviderConfig = {
|
|
4218
|
-
default_provider: opts.provider
|
|
4219
|
-
intelligence_provider: opts.provider
|
|
4217
|
+
...opts.provider ? { default_provider: opts.provider } : {},
|
|
4218
|
+
...opts.provider ? { intelligence_provider: opts.provider } : {}
|
|
4220
4219
|
};
|
|
4221
4220
|
const intelligenceProvider = registry.resolveForIntelligence(boardProviderConfig);
|
|
4222
4221
|
const logBaseDir = join3(homedir2(), ".kantban", "pipelines");
|
|
@@ -4897,4 +4896,4 @@ export {
|
|
|
4897
4896
|
runPipeline,
|
|
4898
4897
|
stopPipeline
|
|
4899
4898
|
};
|
|
4900
|
-
//# sourceMappingURL=pipeline-
|
|
4899
|
+
//# sourceMappingURL=pipeline-IAKINX5A.js.map
|