kantban-cli 0.1.34 → 0.1.36
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-4VT3TGJ5.js +68 -0
- package/dist/chunk-4VT3TGJ5.js.map +1 -0
- package/dist/{chunk-ZTQJMXJM.js → chunk-DAFLEMLK.js} +1 -1
- package/dist/chunk-DAFLEMLK.js.map +1 -0
- package/dist/{chunk-2P25AHSD.js → chunk-GCDCGOWL.js} +12 -7
- package/dist/chunk-GCDCGOWL.js.map +1 -0
- package/dist/{chunk-7HJZFR7Y.js → chunk-YFBFQAFI.js} +17 -13
- package/dist/chunk-YFBFQAFI.js.map +1 -0
- package/dist/{cron-RG4VCGME.js → cron-HKGLRBVM.js} +4 -3
- package/dist/{cron-RG4VCGME.js.map → cron-HKGLRBVM.js.map} +1 -1
- package/dist/index.js +4 -4
- package/dist/lib/gate-proxy-server.js +3 -2
- package/dist/lib/gate-proxy-server.js.map +1 -1
- package/dist/{pipeline-L4HFDBM4.js → pipeline-N7Z43P6P.js} +78 -55
- package/dist/pipeline-N7Z43P6P.js.map +1 -0
- package/dist/{work-2V33NZAT.js → work-RECDDPXT.js} +7 -2
- package/dist/work-RECDDPXT.js.map +1 -0
- package/package.json +4 -3
- package/dist/chunk-2P25AHSD.js.map +0 -1
- package/dist/chunk-7HJZFR7Y.js.map +0 -1
- package/dist/chunk-ZTQJMXJM.js.map +0 -1
- package/dist/pipeline-L4HFDBM4.js.map +0 -1
- package/dist/work-2V33NZAT.js.map +0 -1
|
@@ -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-GCDCGOWL.js";
|
|
4
4
|
import {
|
|
5
5
|
ClaudeProvider,
|
|
6
6
|
RalphLoop,
|
|
@@ -12,14 +12,20 @@ import {
|
|
|
12
12
|
generateMcpConfig,
|
|
13
13
|
parseJsonFromLlmOutput,
|
|
14
14
|
parseStuckDetectionResponse
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-YFBFQAFI.js";
|
|
16
16
|
import {
|
|
17
17
|
LoopCheckpointSchema,
|
|
18
18
|
VerdictSchema,
|
|
19
19
|
parseGateConfig,
|
|
20
20
|
parseTimeout,
|
|
21
21
|
resolveGatesForColumn
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-DAFLEMLK.js";
|
|
23
|
+
import {
|
|
24
|
+
IS_WINDOWS,
|
|
25
|
+
crossSpawnOptions,
|
|
26
|
+
killProcessTree,
|
|
27
|
+
normalizeEol
|
|
28
|
+
} from "./chunk-4VT3TGJ5.js";
|
|
23
29
|
|
|
24
30
|
// src/commands/pipeline.ts
|
|
25
31
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync3, unlinkSync as unlinkSync3, existsSync as existsSync3, appendFileSync as appendFileSync2 } from "fs";
|
|
@@ -51,25 +57,25 @@ function isPlausibleRemoteUrl(url) {
|
|
|
51
57
|
}
|
|
52
58
|
function ensureWorktreeRemote(worktreePath) {
|
|
53
59
|
try {
|
|
54
|
-
const remotes = execFileSync("git", ["-C", worktreePath, "remote"], {
|
|
60
|
+
const remotes = normalizeEol(execFileSync("git", ["-C", worktreePath, "remote"], {
|
|
55
61
|
stdio: "pipe",
|
|
56
62
|
encoding: "utf-8"
|
|
57
|
-
}).trim();
|
|
63
|
+
})).trim();
|
|
58
64
|
if (remotes.split("\n").includes("origin")) {
|
|
59
|
-
const currentUrl = execFileSync("git", ["-C", worktreePath, "remote", "get-url", "origin"], {
|
|
65
|
+
const currentUrl = normalizeEol(execFileSync("git", ["-C", worktreePath, "remote", "get-url", "origin"], {
|
|
60
66
|
stdio: "pipe",
|
|
61
67
|
encoding: "utf-8"
|
|
62
|
-
}).trim();
|
|
68
|
+
})).trim();
|
|
63
69
|
if (isPlausibleRemoteUrl(currentUrl)) return;
|
|
64
70
|
console.error(`[worktree] Invalid origin URL in ${worktreePath}: "${currentUrl}" \u2014 fixing`);
|
|
65
71
|
execFileSync("git", ["-C", worktreePath, "remote", "remove", "origin"], {
|
|
66
72
|
stdio: "pipe"
|
|
67
73
|
});
|
|
68
74
|
}
|
|
69
|
-
const originUrl = execFileSync("git", ["remote", "get-url", "origin"], {
|
|
75
|
+
const originUrl = normalizeEol(execFileSync("git", ["remote", "get-url", "origin"], {
|
|
70
76
|
stdio: "pipe",
|
|
71
77
|
encoding: "utf-8"
|
|
72
|
-
}).trim();
|
|
78
|
+
})).trim();
|
|
73
79
|
if (originUrl && isPlausibleRemoteUrl(originUrl)) {
|
|
74
80
|
execFileSync("git", ["-C", worktreePath, "remote", "add", "origin", originUrl], {
|
|
75
81
|
stdio: "pipe"
|
|
@@ -114,7 +120,7 @@ async function findWorktreeForBranch(exec, branch) {
|
|
|
114
120
|
const { stdout } = await execPromise(exec, "git", ["worktree", "list", "--porcelain"]);
|
|
115
121
|
const targetRef = `refs/heads/${branch}`;
|
|
116
122
|
let currentPath = null;
|
|
117
|
-
for (const line of stdout.split("\n")) {
|
|
123
|
+
for (const line of normalizeEol(stdout).split("\n")) {
|
|
118
124
|
if (line.startsWith("worktree ")) currentPath = line.slice("worktree ".length);
|
|
119
125
|
if (line.startsWith("branch ") && line.slice("branch ".length) === targetRef && currentPath) {
|
|
120
126
|
return currentPath;
|
|
@@ -2116,7 +2122,7 @@ var RunMemory = class {
|
|
|
2116
2122
|
}
|
|
2117
2123
|
try {
|
|
2118
2124
|
const content = await this.deps.getDocument(this._documentId);
|
|
2119
|
-
const lines = content.split("\n");
|
|
2125
|
+
const lines = normalizeEol(content).split("\n");
|
|
2120
2126
|
if (lines.length > DEFAULT_COMPACTION_THRESHOLD) {
|
|
2121
2127
|
const truncated = lines.slice(-DEFAULT_COMPACTION_THRESHOLD);
|
|
2122
2128
|
return "[Run memory truncated \u2014 compaction needed]\n" + truncated.join("\n");
|
|
@@ -2137,7 +2143,7 @@ var RunMemory = class {
|
|
|
2137
2143
|
try {
|
|
2138
2144
|
const content = await this.deps.getDocument(this._documentId);
|
|
2139
2145
|
if (!content) return false;
|
|
2140
|
-
return content.split("\n").length > threshold;
|
|
2146
|
+
return normalizeEol(content).split("\n").length > threshold;
|
|
2141
2147
|
} catch {
|
|
2142
2148
|
return false;
|
|
2143
2149
|
}
|
|
@@ -2768,13 +2774,16 @@ function isAlive(pid) {
|
|
|
2768
2774
|
function readManifest() {
|
|
2769
2775
|
try {
|
|
2770
2776
|
return fs.readFileSync(MANIFEST_PATH, 'utf-8')
|
|
2771
|
-
.split(
|
|
2777
|
+
.split(/\\r?\\n/)
|
|
2772
2778
|
.map(l => parseInt(l.trim(), 10))
|
|
2773
2779
|
.filter(p => !isNaN(p) && p > 0);
|
|
2774
2780
|
} catch { return []; }
|
|
2775
2781
|
}
|
|
2776
2782
|
|
|
2777
2783
|
function killPid(pid, signal) {
|
|
2784
|
+
if (process.platform === 'win32') {
|
|
2785
|
+
try { require('child_process').execFileSync('taskkill', ['/pid', String(pid), '/t', '/f'], { stdio: 'pipe' }); return; } catch { /* fall through */ }
|
|
2786
|
+
}
|
|
2778
2787
|
try { process.kill(pid, signal); } catch { /* already dead */ }
|
|
2779
2788
|
}
|
|
2780
2789
|
|
|
@@ -2782,14 +2791,14 @@ function cleanup() {
|
|
|
2782
2791
|
const pids = readManifest();
|
|
2783
2792
|
for (const pid of pids) {
|
|
2784
2793
|
killPid(pid, 'SIGTERM');
|
|
2785
|
-
try { process.kill(-pid, 'SIGTERM'); } catch { /* ignore */ }
|
|
2794
|
+
if (process.platform !== 'win32') { try { process.kill(-pid, 'SIGTERM'); } catch { /* ignore */ } }
|
|
2786
2795
|
}
|
|
2787
2796
|
|
|
2788
2797
|
setTimeout(() => {
|
|
2789
2798
|
for (const pid of pids) {
|
|
2790
2799
|
if (isAlive(pid)) {
|
|
2791
2800
|
killPid(pid, 'SIGKILL');
|
|
2792
|
-
try { process.kill(-pid, 'SIGKILL'); } catch { /* ignore */ }
|
|
2801
|
+
if (process.platform !== 'win32') { try { process.kill(-pid, 'SIGKILL'); } catch { /* ignore */ } }
|
|
2793
2802
|
}
|
|
2794
2803
|
}
|
|
2795
2804
|
|
|
@@ -2833,7 +2842,8 @@ function spawnReaper(config) {
|
|
|
2833
2842
|
const script = buildReaperScript(config);
|
|
2834
2843
|
const child = spawn(process.execPath, ["-e", script], {
|
|
2835
2844
|
detached: true,
|
|
2836
|
-
stdio: "ignore"
|
|
2845
|
+
stdio: "ignore",
|
|
2846
|
+
windowsHide: true
|
|
2837
2847
|
});
|
|
2838
2848
|
child.unref();
|
|
2839
2849
|
if (child.pid) {
|
|
@@ -2844,7 +2854,7 @@ function spawnReaper(config) {
|
|
|
2844
2854
|
function killReaper(reaperPidPath) {
|
|
2845
2855
|
try {
|
|
2846
2856
|
const pid = parseInt(
|
|
2847
|
-
readFileSync(reaperPidPath, "utf-8").trim(),
|
|
2857
|
+
readFileSync(reaperPidPath, "utf-8").replace(/\r\n/g, "\n").trim(),
|
|
2848
2858
|
10
|
|
2849
2859
|
);
|
|
2850
2860
|
if (pid && !isNaN(pid)) {
|
|
@@ -3153,7 +3163,7 @@ var ProviderRegistry = class {
|
|
|
3153
3163
|
|
|
3154
3164
|
// src/providers/codex-provider.ts
|
|
3155
3165
|
import { spawn as spawn2, execFileSync as execFileSync2 } from "child_process";
|
|
3156
|
-
import { existsSync } from "fs";
|
|
3166
|
+
import { existsSync, rmSync as rmSync2 } from "fs";
|
|
3157
3167
|
|
|
3158
3168
|
// src/providers/codex-jsonl-parser.ts
|
|
3159
3169
|
var CodexJsonlParser = class {
|
|
@@ -3311,7 +3321,7 @@ var CodexProvider = class {
|
|
|
3311
3321
|
});
|
|
3312
3322
|
} catch {
|
|
3313
3323
|
try {
|
|
3314
|
-
|
|
3324
|
+
rmSync2(request.workingDirectory, { recursive: true, force: true });
|
|
3315
3325
|
execFileSync2("git", ["worktree", "add", "-b", request.workingDirectory, request.workingDirectory, "HEAD"], {
|
|
3316
3326
|
stdio: "pipe"
|
|
3317
3327
|
});
|
|
@@ -3333,7 +3343,8 @@ var CodexProvider = class {
|
|
|
3333
3343
|
return new Promise((resolve) => {
|
|
3334
3344
|
const child = spawn2("codex", args, {
|
|
3335
3345
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3336
|
-
env: { ...process.env, ...env }
|
|
3346
|
+
env: { ...process.env, ...env },
|
|
3347
|
+
...crossSpawnOptions()
|
|
3337
3348
|
});
|
|
3338
3349
|
const parser = new CodexJsonlParser();
|
|
3339
3350
|
parser.onEvent = (event) => request.onStreamEvent?.(event);
|
|
@@ -3359,10 +3370,7 @@ var CodexProvider = class {
|
|
|
3359
3370
|
} catch {
|
|
3360
3371
|
}
|
|
3361
3372
|
killTimer = setTimeout(() => {
|
|
3362
|
-
|
|
3363
|
-
child.kill("SIGKILL");
|
|
3364
|
-
} catch {
|
|
3365
|
-
}
|
|
3373
|
+
if (child.pid) killProcessTree(child.pid, "SIGKILL");
|
|
3366
3374
|
}, 5e3);
|
|
3367
3375
|
}, CODEX_TIMEOUT_MS);
|
|
3368
3376
|
let resolved = false;
|
|
@@ -3451,7 +3459,7 @@ var CodexProvider = class {
|
|
|
3451
3459
|
|
|
3452
3460
|
// src/providers/gemini-provider.ts
|
|
3453
3461
|
import { spawn as spawn3, execFileSync as execFileSync3 } from "child_process";
|
|
3454
|
-
import { existsSync as existsSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
3462
|
+
import { existsSync as existsSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, rmSync as rmSync3 } from "fs";
|
|
3455
3463
|
import { join as join2, dirname } from "path";
|
|
3456
3464
|
import { homedir } from "os";
|
|
3457
3465
|
import { fileURLToPath } from "url";
|
|
@@ -3649,7 +3657,8 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
3649
3657
|
supportedModels: [
|
|
3650
3658
|
{ id: "gemini-2.5-flash-lite", displayName: "Flash Lite", tier: "fast" },
|
|
3651
3659
|
{ id: "gemini-2.5-flash", displayName: "Flash", tier: "default" },
|
|
3652
|
-
{ id: "gemini-2.5-pro", displayName: "Pro 2.5", tier: "thorough" }
|
|
3660
|
+
{ id: "gemini-2.5-pro", displayName: "Pro 2.5", tier: "thorough" },
|
|
3661
|
+
{ id: "gemini-3.1-pro-preview", displayName: "Pro 3.1", tier: "thorough" }
|
|
3653
3662
|
],
|
|
3654
3663
|
streamFormat: "jsonl"
|
|
3655
3664
|
};
|
|
@@ -3680,7 +3689,7 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
3680
3689
|
});
|
|
3681
3690
|
} catch {
|
|
3682
3691
|
try {
|
|
3683
|
-
|
|
3692
|
+
rmSync3(request.workingDirectory, { recursive: true, force: true });
|
|
3684
3693
|
execFileSync3("git", ["worktree", "add", "-b", request.workingDirectory, request.workingDirectory, "HEAD"], {
|
|
3685
3694
|
stdio: "pipe"
|
|
3686
3695
|
});
|
|
@@ -3707,25 +3716,31 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
3707
3716
|
return new Promise((resolve) => {
|
|
3708
3717
|
const child = spawn3("gemini", args, {
|
|
3709
3718
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3710
|
-
cwd: cwd || void 0
|
|
3719
|
+
cwd: cwd || void 0,
|
|
3720
|
+
...crossSpawnOptions()
|
|
3711
3721
|
});
|
|
3712
3722
|
const parser = new GeminiJsonlParser();
|
|
3713
3723
|
parser.onEvent = (event) => request.onStreamEvent?.(event);
|
|
3714
3724
|
parser.onError = (err) => process.stderr.write(`[gemini-jsonl] ${err.message}
|
|
3715
3725
|
`);
|
|
3716
3726
|
let stderr = "";
|
|
3727
|
+
let lastStderrLine = "";
|
|
3717
3728
|
let gotStdout = false;
|
|
3718
3729
|
child.stdout?.on("data", (chunk) => {
|
|
3719
3730
|
gotStdout = true;
|
|
3720
3731
|
parser.feed(chunk.toString());
|
|
3721
3732
|
});
|
|
3722
3733
|
child.stderr?.on("data", (chunk) => {
|
|
3723
|
-
|
|
3734
|
+
const text = chunk.toString();
|
|
3735
|
+
stderr += text;
|
|
3736
|
+
const lines = normalizeEol(text).split("\n").filter((l) => l.trim());
|
|
3737
|
+
if (lines.length) lastStderrLine = lines[lines.length - 1];
|
|
3724
3738
|
});
|
|
3725
3739
|
child.stdin?.end();
|
|
3726
3740
|
const startupTimer = setTimeout(() => {
|
|
3727
3741
|
if (!gotStdout) {
|
|
3728
|
-
|
|
3742
|
+
const hint = stderr.includes("429") || stderr.includes("RESOURCE_EXHAUSTED") ? "model is rate-limited (429)" : stderr.includes("Attempt") ? "retrying API errors" : "model may be unavailable";
|
|
3743
|
+
process.stderr.write(`[gemini] No output after ${GEMINI_STARTUP_TIMEOUT_MS / 1e3}s \u2014 ${hint}. Last stderr: ${lastStderrLine.slice(0, 200)}
|
|
3729
3744
|
`);
|
|
3730
3745
|
try {
|
|
3731
3746
|
child.kill("SIGTERM");
|
|
@@ -3748,10 +3763,7 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
3748
3763
|
} catch {
|
|
3749
3764
|
}
|
|
3750
3765
|
killTimer = setTimeout(() => {
|
|
3751
|
-
|
|
3752
|
-
child.kill("SIGKILL");
|
|
3753
|
-
} catch {
|
|
3754
|
-
}
|
|
3766
|
+
if (child.pid) killProcessTree(child.pid, "SIGKILL");
|
|
3755
3767
|
}, 5e3);
|
|
3756
3768
|
}, GEMINI_TIMEOUT_MS);
|
|
3757
3769
|
let resolved = false;
|
|
@@ -3835,14 +3847,16 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
3835
3847
|
hookConfig.allowedTools = tr.allowedTools ? translateToolNames(tr.allowedTools) : null;
|
|
3836
3848
|
hookConfig.disallowedTools = tr.disallowedTools ? translateToolNames(tr.disallowedTools) : null;
|
|
3837
3849
|
if (tr.tools !== void 0) hookConfig.builtinToolsMode = tr.tools;
|
|
3838
|
-
const
|
|
3850
|
+
const ext = IS_WINDOWS ? ".cmd" : ".sh";
|
|
3851
|
+
const wrapperPath = join2(dir, `.kantban-hook-before-tool${ext}`);
|
|
3839
3852
|
writeFileSync3(wrapperPath, this.generateHookWrapper(hookPath, "BeforeToolSelection", join2(dir, ".kantban-hook-config.json")), { mode: 493 });
|
|
3840
3853
|
hooks.BeforeToolSelection = [{ matcher: "*", hooks: [{ type: "command", command: wrapperPath, timeout: 3e4 }] }];
|
|
3841
3854
|
}
|
|
3842
3855
|
if (request.maxTurns && request.mcpConfig) {
|
|
3843
3856
|
hookConfig.maxTurns = request.maxTurns;
|
|
3844
3857
|
hookConfig.turnFile = join2(dir, ".kantban-turn-counter");
|
|
3845
|
-
const
|
|
3858
|
+
const ext = IS_WINDOWS ? ".cmd" : ".sh";
|
|
3859
|
+
const wrapperPath = join2(dir, `.kantban-hook-after-agent${ext}`);
|
|
3846
3860
|
writeFileSync3(wrapperPath, this.generateHookWrapper(hookPath, "AfterAgent", join2(dir, ".kantban-hook-config.json")), { mode: 493 });
|
|
3847
3861
|
hooks.AfterAgent = [{ matcher: "*", hooks: [{ type: "command", command: wrapperPath, timeout: 3e4 }] }];
|
|
3848
3862
|
}
|
|
@@ -3875,6 +3889,18 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
3875
3889
|
/** Generate a per-session bash wrapper that invokes the Node hook script.
|
|
3876
3890
|
* Gemini CLI ignores `args` in hook definitions, so we embed all arguments. */
|
|
3877
3891
|
generateHookWrapper(hookScript, event, configFile) {
|
|
3892
|
+
if (IS_WINDOWS) {
|
|
3893
|
+
return [
|
|
3894
|
+
"@echo off",
|
|
3895
|
+
'set "STDIN_FILE=%TEMP%\\kantban-hook-%RANDOM%%RANDOM%.tmp"',
|
|
3896
|
+
'findstr "^" > "%STDIN_FILE%"',
|
|
3897
|
+
`node "${hookScript}" "${event}" "${configFile}" < "%STDIN_FILE%"`,
|
|
3898
|
+
'set "EXIT_CODE=%ERRORLEVEL%"',
|
|
3899
|
+
'del /f /q "%STDIN_FILE%" >nul 2>&1',
|
|
3900
|
+
"exit /b %EXIT_CODE%",
|
|
3901
|
+
""
|
|
3902
|
+
].join("\r\n");
|
|
3903
|
+
}
|
|
3878
3904
|
return `#!/bin/bash
|
|
3879
3905
|
# KantBan pipeline hook wrapper \u2014 Gemini CLI does not pass args, so we embed them.
|
|
3880
3906
|
STDIN_FILE=$(mktemp)
|
|
@@ -3888,7 +3914,7 @@ node "${hookScript}" "${event}" "${configFile}" < "$STDIN_FILE"
|
|
|
3888
3914
|
* which contains lines like "YOLO mode is enabled..." and "Loaded cached credentials."
|
|
3889
3915
|
* that corrupt JSON parsing in downstream consumers (advisor, light-call). */
|
|
3890
3916
|
static stripCliPreamble(text) {
|
|
3891
|
-
const lines = text.split("\n");
|
|
3917
|
+
const lines = normalizeEol(text).split("\n");
|
|
3892
3918
|
const jsonStart = lines.findIndex((line) => {
|
|
3893
3919
|
const trimmed = line.trim();
|
|
3894
3920
|
return trimmed.startsWith("{") || trimmed.startsWith("[");
|
|
@@ -4051,7 +4077,7 @@ function childManifestPath(boardId) {
|
|
|
4051
4077
|
}
|
|
4052
4078
|
function readChildManifest(boardId) {
|
|
4053
4079
|
try {
|
|
4054
|
-
const contents = readFileSync3(childManifestPath(boardId), "utf-8");
|
|
4080
|
+
const contents = normalizeEol(readFileSync3(childManifestPath(boardId), "utf-8"));
|
|
4055
4081
|
return contents.split("\n").map((l) => l.trim()).filter((l) => l !== "").map(Number).filter((n) => !isNaN(n) && n > 0);
|
|
4056
4082
|
} catch {
|
|
4057
4083
|
return [];
|
|
@@ -4071,7 +4097,7 @@ function cleanupOrphanedProcesses(boardId) {
|
|
|
4071
4097
|
if (stalePid && stalePid !== process.pid) {
|
|
4072
4098
|
try {
|
|
4073
4099
|
process.kill(stalePid, 0);
|
|
4074
|
-
|
|
4100
|
+
killProcessTree(stalePid, "SIGTERM");
|
|
4075
4101
|
console.log(`Killed stale orchestrator (PID ${String(stalePid)})`);
|
|
4076
4102
|
} catch {
|
|
4077
4103
|
}
|
|
@@ -4085,7 +4111,7 @@ function cleanupOrphanedProcesses(boardId) {
|
|
|
4085
4111
|
for (const pid of manifestPids) {
|
|
4086
4112
|
try {
|
|
4087
4113
|
process.kill(pid, 0);
|
|
4088
|
-
|
|
4114
|
+
killProcessTree(pid, "SIGTERM");
|
|
4089
4115
|
} catch {
|
|
4090
4116
|
}
|
|
4091
4117
|
}
|
|
@@ -4099,7 +4125,7 @@ function cleanupOrphanedProcesses(boardId) {
|
|
|
4099
4125
|
if (reaperPid && !isNaN(reaperPid)) {
|
|
4100
4126
|
try {
|
|
4101
4127
|
process.kill(reaperPid, 0);
|
|
4102
|
-
|
|
4128
|
+
killProcessTree(reaperPid, "SIGTERM");
|
|
4103
4129
|
console.log(`Killed stale reaper (PID ${String(reaperPid)})`);
|
|
4104
4130
|
} catch {
|
|
4105
4131
|
}
|
|
@@ -4251,7 +4277,7 @@ async function runPipeline(client, args) {
|
|
|
4251
4277
|
// Run memory enrichment — inject accumulated discoveries into each iteration prompt
|
|
4252
4278
|
fetchRunMemoryContent: mem ? async () => {
|
|
4253
4279
|
const content = await mem.getContent();
|
|
4254
|
-
const lines = content.split("\n");
|
|
4280
|
+
const lines = normalizeEol(content).split("\n");
|
|
4255
4281
|
if (lines.length > 500) {
|
|
4256
4282
|
return lines.slice(-500).join("\n");
|
|
4257
4283
|
}
|
|
@@ -4665,12 +4691,14 @@ Received ${signal}. Shutting down gracefully...`);
|
|
|
4665
4691
|
process.exit(1);
|
|
4666
4692
|
});
|
|
4667
4693
|
});
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4694
|
+
if (!IS_WINDOWS) {
|
|
4695
|
+
process.on("SIGHUP", () => {
|
|
4696
|
+
shutdown("SIGHUP").catch((err) => {
|
|
4697
|
+
console.error("Error during shutdown:", err);
|
|
4698
|
+
process.exit(1);
|
|
4699
|
+
});
|
|
4672
4700
|
});
|
|
4673
|
-
}
|
|
4701
|
+
}
|
|
4674
4702
|
cleanupOrphanedProcesses(opts.boardId);
|
|
4675
4703
|
writePidFile(opts.boardId);
|
|
4676
4704
|
logger.orchestrator(`PID file written: ${String(process.pid)}`);
|
|
@@ -4849,13 +4877,8 @@ async function stopPipeline(args) {
|
|
|
4849
4877
|
return;
|
|
4850
4878
|
}
|
|
4851
4879
|
try {
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
console.log(`Sent SIGTERM to pipeline process group (pgid ${String(pid)}) for board ${boardId}.`);
|
|
4855
|
-
} catch {
|
|
4856
|
-
process.kill(pid, "SIGTERM");
|
|
4857
|
-
console.log(`Sent SIGTERM to pipeline process ${String(pid)} for board ${boardId}.`);
|
|
4858
|
-
}
|
|
4880
|
+
killProcessTree(pid, "SIGTERM");
|
|
4881
|
+
console.log(`Sent SIGTERM to pipeline process ${String(pid)} for board ${boardId}.`);
|
|
4859
4882
|
} catch (err) {
|
|
4860
4883
|
const message = err instanceof Error ? err.message : String(err);
|
|
4861
4884
|
console.error(`Failed to stop pipeline (PID ${String(pid)}): ${message}`);
|
|
@@ -4868,4 +4891,4 @@ export {
|
|
|
4868
4891
|
runPipeline,
|
|
4869
4892
|
stopPipeline
|
|
4870
4893
|
};
|
|
4871
|
-
//# sourceMappingURL=pipeline-
|
|
4894
|
+
//# sourceMappingURL=pipeline-N7Z43P6P.js.map
|