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.
Files changed (27) hide show
  1. package/dist/{chunk-AF72765A.js → chunk-2CY5OPZN.js} +2 -2
  2. package/dist/{chunk-UNSNCYTR.js → chunk-5ZU2OOES.js} +19 -8
  3. package/dist/chunk-5ZU2OOES.js.map +1 -0
  4. package/dist/{chunk-MIL7SIPJ.js → chunk-MKKHLFA5.js} +2 -2
  5. package/dist/{context-IRTNYVN6.js → context-7YDNTI3P.js} +1 -3
  6. package/dist/{context-IRTNYVN6.js.map → context-7YDNTI3P.js.map} +1 -1
  7. package/dist/{cron-PS2IEPH2.js → cron-3R2UWFO7.js} +3 -4
  8. package/dist/{cron-PS2IEPH2.js.map → cron-3R2UWFO7.js.map} +1 -1
  9. package/dist/index.js +6 -7
  10. package/dist/index.js.map +1 -1
  11. package/dist/lib/gate-proxy-server.js +2 -3
  12. package/dist/lib/gate-proxy-server.js.map +1 -1
  13. package/dist/{pipeline-76ZTI4IN.js → pipeline-IAKINX5A.js} +7 -8
  14. package/dist/pipeline-IAKINX5A.js.map +1 -0
  15. package/dist/{pipeline-init-QDHBJGWY.js → pipeline-init-IGZZOOLK.js} +1 -3
  16. package/dist/{pipeline-init-QDHBJGWY.js.map → pipeline-init-IGZZOOLK.js.map} +1 -1
  17. package/dist/{status-3B3BSJBJ.js → status-4GFXMVIM.js} +1 -3
  18. package/dist/{status-3B3BSJBJ.js.map → status-4GFXMVIM.js.map} +1 -1
  19. package/dist/{work-HZVJJG4A.js → work-45GILGKD.js} +2 -3
  20. package/dist/{work-HZVJJG4A.js.map → work-45GILGKD.js.map} +1 -1
  21. package/package.json +1 -1
  22. package/dist/chunk-DGUM43GV.js +0 -11
  23. package/dist/chunk-DGUM43GV.js.map +0 -1
  24. package/dist/chunk-UNSNCYTR.js.map +0 -1
  25. package/dist/pipeline-76ZTI4IN.js.map +0 -1
  26. /package/dist/{chunk-AF72765A.js.map → chunk-2CY5OPZN.js.map} +0 -0
  27. /package/dist/{chunk-MIL7SIPJ.js.map → chunk-MKKHLFA5.js.map} +0 -0
@@ -1,5 +1,3 @@
1
- import "./chunk-DGUM43GV.js";
2
-
3
1
  // src/commands/pipeline-init.ts
4
2
  import { existsSync, readFileSync, writeFileSync } from "fs";
5
3
  import { join } from "path";
@@ -102,4 +100,4 @@ Next steps:`);
102
100
  export {
103
101
  runPipelineInit
104
102
  };
105
- //# sourceMappingURL=pipeline-init-QDHBJGWY.js.map
103
+ //# sourceMappingURL=pipeline-init-IGZZOOLK.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/pipeline-init.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst GATE_FILE = 'pipeline.gates.yaml';\n\ninterface ProjectDetection {\n type: string;\n testCommand: string;\n typecheckCommand: string;\n lintCommand: string;\n buildCommand: string;\n}\n\nfunction detectProjectType(cwd: string): ProjectDetection {\n if (existsSync(join(cwd, 'package.json'))) {\n const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8')) as {\n scripts?: Record<string, string>;\n };\n const scripts = pkg.scripts ?? {};\n const pm = existsSync(join(cwd, 'pnpm-lock.yaml')) ? 'pnpm'\n : existsSync(join(cwd, 'yarn.lock')) ? 'yarn' : 'npm';\n return {\n type: 'node',\n testCommand: scripts.test ? `${pm} test` : `${pm} vitest run`,\n typecheckCommand: scripts.typecheck ? `${pm} typecheck` : `${pm} tsc --noEmit`,\n lintCommand: scripts.lint ? `${pm} lint` : `${pm} eslint .`,\n buildCommand: scripts.build ? `${pm} build` : 'echo \"no build configured\"',\n };\n }\n if (existsSync(join(cwd, 'Cargo.toml'))) {\n return { type: 'rust', testCommand: 'cargo test', typecheckCommand: 'cargo check', lintCommand: 'cargo clippy', buildCommand: 'cargo build' };\n }\n if (existsSync(join(cwd, 'pyproject.toml')) || existsSync(join(cwd, 'setup.py'))) {\n return { type: 'python', testCommand: 'pytest', typecheckCommand: 'mypy .', lintCommand: 'ruff check .', buildCommand: 'echo \"no build configured\"' };\n }\n if (existsSync(join(cwd, 'go.mod'))) {\n return { type: 'go', testCommand: 'go test ./...', typecheckCommand: 'go vet ./...', lintCommand: 'golangci-lint run', buildCommand: 'go build ./...' };\n }\n return { type: 'unknown', testCommand: 'echo \"configure your test command\"', typecheckCommand: 'echo \"configure your typecheck command\"', lintCommand: 'echo \"configure your lint command\"', buildCommand: 'echo \"configure your build command\"' };\n}\n\n/** YAML-safe single-quoting: escapes internal single quotes by doubling them */\nfunction yamlQuote(s: string): string {\n return `'${s.replace(/'/g, \"''\")}'`;\n}\n\nfunction generateGateFile(detection: ProjectDetection): string {\n return `# pipeline.gates.yaml — Gate definitions for KantBan pipeline\n# Detected project type: ${detection.type}\n#\n# Gates are shell commands that produce pass/fail results.\n# Required gates block ticket movement. Advisory gates show output but don't block.\n\ndefault:\n - name: typecheck\n run: ${yamlQuote(detection.typecheckCommand)}\n required: true\n timeout: 60s\n\n - name: tests\n run: ${yamlQuote(detection.testCommand)}\n required: true\n timeout: 120s\n\n - name: lint\n run: ${yamlQuote(detection.lintCommand)}\n required: false # advisory — output shown but doesn't block\n\n# Column-specific overrides — matched by column name (case-insensitive)\n# columns:\n# implementation:\n# extend: true # inherit default gates, add more\n# gates:\n# - name: build\n# run: ${yamlQuote(detection.buildCommand)}\n# required: true\n# timeout: 120s\n#\n# qa:\n# extend: false # replace default gates entirely\n# gates:\n# - name: e2e\n# run: \"echo 'configure your e2e test command'\"\n# required: true\n# timeout: 300s\n\nsettings:\n # cwd: .\n env:\n CI: \"true\"\n total_timeout: 300s\n budget:\n max_input_tokens: 5000000\n max_output_tokens: 1500000\n warn_pct: 75\n`;\n}\n\nexport async function runPipelineInit(): Promise<void> {\n const cwd = process.cwd();\n const filePath = join(cwd, GATE_FILE);\n\n if (existsSync(filePath)) {\n console.error(`Error: ${GATE_FILE} already exists in ${cwd}`);\n console.error('Edit the existing file or delete it to regenerate.');\n process.exit(1);\n }\n\n const detection = detectProjectType(cwd);\n const content = generateGateFile(detection);\n writeFileSync(filePath, content);\n\n console.log(`Created ${GATE_FILE} (detected: ${detection.type} project)`);\n console.log(`\\nNext steps:`);\n console.log(` 1. Review and customize the gate file`);\n console.log(` 2. Run: kantban pipeline <board-id>`);\n}\n"],"mappings":";;;AAAA,SAAS,YAAY,cAAc,qBAAqB;AACxD,SAAS,YAAY;AAErB,IAAM,YAAY;AAUlB,SAAS,kBAAkB,KAA+B;AACxD,MAAI,WAAW,KAAK,KAAK,cAAc,CAAC,GAAG;AACzC,UAAM,MAAM,KAAK,MAAM,aAAa,KAAK,KAAK,cAAc,GAAG,OAAO,CAAC;AAGvE,UAAM,UAAU,IAAI,WAAW,CAAC;AAChC,UAAM,KAAK,WAAW,KAAK,KAAK,gBAAgB,CAAC,IAAI,SACjD,WAAW,KAAK,KAAK,WAAW,CAAC,IAAI,SAAS;AAClD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa,QAAQ,OAAO,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,MAChD,kBAAkB,QAAQ,YAAY,GAAG,EAAE,eAAe,GAAG,EAAE;AAAA,MAC/D,aAAa,QAAQ,OAAO,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,MAChD,cAAc,QAAQ,QAAQ,GAAG,EAAE,WAAW;AAAA,IAChD;AAAA,EACF;AACA,MAAI,WAAW,KAAK,KAAK,YAAY,CAAC,GAAG;AACvC,WAAO,EAAE,MAAM,QAAQ,aAAa,cAAc,kBAAkB,eAAe,aAAa,gBAAgB,cAAc,cAAc;AAAA,EAC9I;AACA,MAAI,WAAW,KAAK,KAAK,gBAAgB,CAAC,KAAK,WAAW,KAAK,KAAK,UAAU,CAAC,GAAG;AAChF,WAAO,EAAE,MAAM,UAAU,aAAa,UAAU,kBAAkB,UAAU,aAAa,gBAAgB,cAAc,6BAA6B;AAAA,EACtJ;AACA,MAAI,WAAW,KAAK,KAAK,QAAQ,CAAC,GAAG;AACnC,WAAO,EAAE,MAAM,MAAM,aAAa,iBAAiB,kBAAkB,gBAAgB,aAAa,qBAAqB,cAAc,iBAAiB;AAAA,EACxJ;AACA,SAAO,EAAE,MAAM,WAAW,aAAa,sCAAsC,kBAAkB,2CAA2C,aAAa,sCAAsC,cAAc,sCAAsC;AACnP;AAGA,SAAS,UAAU,GAAmB;AACpC,SAAO,IAAI,EAAE,QAAQ,MAAM,IAAI,CAAC;AAClC;AAEA,SAAS,iBAAiB,WAAqC;AAC7D,SAAO;AAAA,2BACkB,UAAU,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAO9B,UAAU,UAAU,gBAAgB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,WAKrC,UAAU,UAAU,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,WAKhC,UAAU,UAAU,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAS1B,UAAU,UAAU,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBlD;AAEA,eAAsB,kBAAiC;AACrD,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,WAAW,KAAK,KAAK,SAAS;AAEpC,MAAI,WAAW,QAAQ,GAAG;AACxB,YAAQ,MAAM,UAAU,SAAS,sBAAsB,GAAG,EAAE;AAC5D,YAAQ,MAAM,oDAAoD;AAClE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,kBAAkB,GAAG;AACvC,QAAM,UAAU,iBAAiB,SAAS;AAC1C,gBAAc,UAAU,OAAO;AAE/B,UAAQ,IAAI,WAAW,SAAS,eAAe,UAAU,IAAI,WAAW;AACxE,UAAQ,IAAI;AAAA,YAAe;AAC3B,UAAQ,IAAI,yCAAyC;AACrD,UAAQ,IAAI,uCAAuC;AACrD;","names":[]}
1
+ {"version":3,"sources":["../src/commands/pipeline-init.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst GATE_FILE = 'pipeline.gates.yaml';\n\ninterface ProjectDetection {\n type: string;\n testCommand: string;\n typecheckCommand: string;\n lintCommand: string;\n buildCommand: string;\n}\n\nfunction detectProjectType(cwd: string): ProjectDetection {\n if (existsSync(join(cwd, 'package.json'))) {\n const pkg = JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8')) as {\n scripts?: Record<string, string>;\n };\n const scripts = pkg.scripts ?? {};\n const pm = existsSync(join(cwd, 'pnpm-lock.yaml')) ? 'pnpm'\n : existsSync(join(cwd, 'yarn.lock')) ? 'yarn' : 'npm';\n return {\n type: 'node',\n testCommand: scripts.test ? `${pm} test` : `${pm} vitest run`,\n typecheckCommand: scripts.typecheck ? `${pm} typecheck` : `${pm} tsc --noEmit`,\n lintCommand: scripts.lint ? `${pm} lint` : `${pm} eslint .`,\n buildCommand: scripts.build ? `${pm} build` : 'echo \"no build configured\"',\n };\n }\n if (existsSync(join(cwd, 'Cargo.toml'))) {\n return { type: 'rust', testCommand: 'cargo test', typecheckCommand: 'cargo check', lintCommand: 'cargo clippy', buildCommand: 'cargo build' };\n }\n if (existsSync(join(cwd, 'pyproject.toml')) || existsSync(join(cwd, 'setup.py'))) {\n return { type: 'python', testCommand: 'pytest', typecheckCommand: 'mypy .', lintCommand: 'ruff check .', buildCommand: 'echo \"no build configured\"' };\n }\n if (existsSync(join(cwd, 'go.mod'))) {\n return { type: 'go', testCommand: 'go test ./...', typecheckCommand: 'go vet ./...', lintCommand: 'golangci-lint run', buildCommand: 'go build ./...' };\n }\n return { type: 'unknown', testCommand: 'echo \"configure your test command\"', typecheckCommand: 'echo \"configure your typecheck command\"', lintCommand: 'echo \"configure your lint command\"', buildCommand: 'echo \"configure your build command\"' };\n}\n\n/** YAML-safe single-quoting: escapes internal single quotes by doubling them */\nfunction yamlQuote(s: string): string {\n return `'${s.replace(/'/g, \"''\")}'`;\n}\n\nfunction generateGateFile(detection: ProjectDetection): string {\n return `# pipeline.gates.yaml — Gate definitions for KantBan pipeline\n# Detected project type: ${detection.type}\n#\n# Gates are shell commands that produce pass/fail results.\n# Required gates block ticket movement. Advisory gates show output but don't block.\n\ndefault:\n - name: typecheck\n run: ${yamlQuote(detection.typecheckCommand)}\n required: true\n timeout: 60s\n\n - name: tests\n run: ${yamlQuote(detection.testCommand)}\n required: true\n timeout: 120s\n\n - name: lint\n run: ${yamlQuote(detection.lintCommand)}\n required: false # advisory — output shown but doesn't block\n\n# Column-specific overrides — matched by column name (case-insensitive)\n# columns:\n# implementation:\n# extend: true # inherit default gates, add more\n# gates:\n# - name: build\n# run: ${yamlQuote(detection.buildCommand)}\n# required: true\n# timeout: 120s\n#\n# qa:\n# extend: false # replace default gates entirely\n# gates:\n# - name: e2e\n# run: \"echo 'configure your e2e test command'\"\n# required: true\n# timeout: 300s\n\nsettings:\n # cwd: .\n env:\n CI: \"true\"\n total_timeout: 300s\n budget:\n max_input_tokens: 5000000\n max_output_tokens: 1500000\n warn_pct: 75\n`;\n}\n\nexport async function runPipelineInit(): Promise<void> {\n const cwd = process.cwd();\n const filePath = join(cwd, GATE_FILE);\n\n if (existsSync(filePath)) {\n console.error(`Error: ${GATE_FILE} already exists in ${cwd}`);\n console.error('Edit the existing file or delete it to regenerate.');\n process.exit(1);\n }\n\n const detection = detectProjectType(cwd);\n const content = generateGateFile(detection);\n writeFileSync(filePath, content);\n\n console.log(`Created ${GATE_FILE} (detected: ${detection.type} project)`);\n console.log(`\\nNext steps:`);\n console.log(` 1. Review and customize the gate file`);\n console.log(` 2. Run: kantban pipeline <board-id>`);\n}\n"],"mappings":";AAAA,SAAS,YAAY,cAAc,qBAAqB;AACxD,SAAS,YAAY;AAErB,IAAM,YAAY;AAUlB,SAAS,kBAAkB,KAA+B;AACxD,MAAI,WAAW,KAAK,KAAK,cAAc,CAAC,GAAG;AACzC,UAAM,MAAM,KAAK,MAAM,aAAa,KAAK,KAAK,cAAc,GAAG,OAAO,CAAC;AAGvE,UAAM,UAAU,IAAI,WAAW,CAAC;AAChC,UAAM,KAAK,WAAW,KAAK,KAAK,gBAAgB,CAAC,IAAI,SACjD,WAAW,KAAK,KAAK,WAAW,CAAC,IAAI,SAAS;AAClD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa,QAAQ,OAAO,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,MAChD,kBAAkB,QAAQ,YAAY,GAAG,EAAE,eAAe,GAAG,EAAE;AAAA,MAC/D,aAAa,QAAQ,OAAO,GAAG,EAAE,UAAU,GAAG,EAAE;AAAA,MAChD,cAAc,QAAQ,QAAQ,GAAG,EAAE,WAAW;AAAA,IAChD;AAAA,EACF;AACA,MAAI,WAAW,KAAK,KAAK,YAAY,CAAC,GAAG;AACvC,WAAO,EAAE,MAAM,QAAQ,aAAa,cAAc,kBAAkB,eAAe,aAAa,gBAAgB,cAAc,cAAc;AAAA,EAC9I;AACA,MAAI,WAAW,KAAK,KAAK,gBAAgB,CAAC,KAAK,WAAW,KAAK,KAAK,UAAU,CAAC,GAAG;AAChF,WAAO,EAAE,MAAM,UAAU,aAAa,UAAU,kBAAkB,UAAU,aAAa,gBAAgB,cAAc,6BAA6B;AAAA,EACtJ;AACA,MAAI,WAAW,KAAK,KAAK,QAAQ,CAAC,GAAG;AACnC,WAAO,EAAE,MAAM,MAAM,aAAa,iBAAiB,kBAAkB,gBAAgB,aAAa,qBAAqB,cAAc,iBAAiB;AAAA,EACxJ;AACA,SAAO,EAAE,MAAM,WAAW,aAAa,sCAAsC,kBAAkB,2CAA2C,aAAa,sCAAsC,cAAc,sCAAsC;AACnP;AAGA,SAAS,UAAU,GAAmB;AACpC,SAAO,IAAI,EAAE,QAAQ,MAAM,IAAI,CAAC;AAClC;AAEA,SAAS,iBAAiB,WAAqC;AAC7D,SAAO;AAAA,2BACkB,UAAU,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAO9B,UAAU,UAAU,gBAAgB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,WAKrC,UAAU,UAAU,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,WAKhC,UAAU,UAAU,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAS1B,UAAU,UAAU,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBlD;AAEA,eAAsB,kBAAiC;AACrD,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,WAAW,KAAK,KAAK,SAAS;AAEpC,MAAI,WAAW,QAAQ,GAAG;AACxB,YAAQ,MAAM,UAAU,SAAS,sBAAsB,GAAG,EAAE;AAC5D,YAAQ,MAAM,oDAAoD;AAClE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,kBAAkB,GAAG;AACvC,QAAM,UAAU,iBAAiB,SAAS;AAC1C,gBAAc,UAAU,OAAO;AAE/B,UAAQ,IAAI,WAAW,SAAS,eAAe,UAAU,IAAI,WAAW;AACxE,UAAQ,IAAI;AAAA,YAAe;AAC3B,UAAQ,IAAI,yCAAyC;AACrD,UAAQ,IAAI,uCAAuC;AACrD;","names":[]}
@@ -1,5 +1,3 @@
1
- import "./chunk-DGUM43GV.js";
2
-
3
1
  // src/commands/status.ts
4
2
  import { readFileSync, existsSync, statSync, readdirSync } from "fs";
5
3
  import { homedir } from "os";
@@ -127,4 +125,4 @@ Warnings: ${stuckCount} stuck, ${wipCount} WIP violations`);
127
125
  export {
128
126
  runStatus
129
127
  };
130
- //# sourceMappingURL=status-3B3BSJBJ.js.map
128
+ //# sourceMappingURL=status-4GFXMVIM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/status.ts"],"sourcesContent":["import { readFileSync, existsSync, statSync, readdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { KantBanCLIClient } from '../client.js';\n\n// ---------------------------------------------------------------------------\n// Pipeline runtime info helper\n// ---------------------------------------------------------------------------\n\nfunction formatUptime(ms: number): string {\n const totalMinutes = Math.floor(ms / 60_000);\n const hours = Math.floor(totalMinutes / 60);\n const minutes = totalMinutes % 60;\n if (hours > 0) return `${String(hours)}h ${String(minutes)}m`;\n return `${String(minutes)}m`;\n}\n\nfunction isProcessRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction showPipelineInfo(boardId: string): void {\n const pipelineDir = join(homedir(), '.kantban', 'pipelines', boardId);\n const pidFile = join(pipelineDir, 'orchestrator.pid');\n\n if (!existsSync(pidFile)) {\n console.log('\\nPipeline: not running');\n return;\n }\n\n const pidContent = readFileSync(pidFile, 'utf8').trim();\n const pid = Number(pidContent);\n if (isNaN(pid) || pid <= 0) {\n console.log('\\nOrchestrator: not running (invalid PID file)');\n return;\n }\n\n if (!isProcessRunning(pid)) {\n console.log('\\nOrchestrator: not running (stale PID file)');\n return;\n }\n\n // Process is running — calculate uptime from PID file mtime\n const pidStat = statSync(pidFile);\n const uptimeMs = Date.now() - pidStat.mtimeMs;\n console.log(`\\nOrchestrator: running (PID: ${String(pid)}, uptime: ${formatUptime(uptimeMs)})`);\n\n // Scan for recent iteration logs to show active/recent loop info\n if (!existsSync(pipelineDir)) return;\n\n const entries = readdirSync(pipelineDir, { withFileTypes: true });\n const ticketDirs = entries.filter((e) => e.isDirectory());\n\n if (ticketDirs.length === 0) return;\n\n const recentLoops: Array<{ ticket: string; lastIteration: number; outcome: string; timestamp: string }> = [];\n\n for (const dir of ticketDirs) {\n const ticketDir = join(pipelineDir, dir.name);\n const files = readdirSync(ticketDir).filter((f) => f.startsWith('iteration-') && f.endsWith('.log'));\n if (files.length === 0) continue;\n\n // Get the latest iteration log\n files.sort();\n const latestFile = files[files.length - 1]!;\n const logPath = join(ticketDir, latestFile);\n\n try {\n const logContent = readFileSync(logPath, 'utf8');\n const logData = JSON.parse(logContent) as Record<string, unknown>;\n recentLoops.push({\n ticket: dir.name,\n lastIteration: Number(logData['iteration'] ?? 0),\n outcome: String(logData['outcome'] ?? 'unknown'),\n timestamp: String(logData['timestamp'] ?? ''),\n });\n } catch {\n // Skip malformed log files\n }\n }\n\n if (recentLoops.length > 0) {\n // Sort by timestamp descending to show most recent first\n recentLoops.sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n console.log(` Active/recent loops (${String(recentLoops.length)}):`);\n for (const loop of recentLoops.slice(0, 10)) {\n console.log(` ${loop.ticket} iter:${String(loop.lastIteration)} ${loop.outcome}`);\n }\n if (recentLoops.length > 10) {\n console.log(` ... and ${String(recentLoops.length - 10)} more`);\n }\n }\n}\n\nexport async function runStatus(client: KantBanCLIClient, args: string[]): Promise<void> {\n const [boardId] = args;\n if (!boardId) {\n console.error('Usage: kantban status <board-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 required');\n process.exit(1);\n }\n\n const data = await client.get<Record<string, unknown>>(\n `/projects/${projectId}/pipeline-context`,\n { boardId },\n );\n\n const columns = data['columns'] as Array<Record<string, unknown>> | undefined;\n const cb = data['circuit_breaker'] as Record<string, unknown> | undefined;\n const board = data['board'] as Record<string, unknown> | undefined;\n\n console.log(`Pipeline Status: ${board?.['name'] ?? 'Unknown Board'}`);\n console.log('\\u2500'.repeat(60));\n\n if (columns) {\n for (const col of columns) {\n const prompt = col['has_prompt'] ? '\\u{1F4C4}' : ' ';\n const name = String(col['name'] ?? '(unnamed)');\n const count = Number(col['ticket_count'] ?? 0);\n const goal = col['goal'] ? ` \\u2014 ${String(col['goal'])}` : '';\n console.log(`${prompt} ${name} (${count} tickets)${goal}`);\n }\n }\n\n if (cb?.['threshold']) {\n console.log(`\\nCircuit Breaker: threshold=${String(cb['threshold'])}`);\n }\n\n // Fetch bottleneck info\n const bottlenecks = await client.get<Record<string, unknown>>(\n `/projects/${projectId}/boards/${boardId}/bottlenecks`,\n );\n const stuckCount = (bottlenecks['stuck_tickets'] as unknown[] | undefined)?.length ?? 0;\n const wipCount = (bottlenecks['wip_violations'] as unknown[] | undefined)?.length ?? 0;\n\n if (stuckCount > 0 || wipCount > 0) {\n console.log(`\\nWarnings: ${stuckCount} stuck, ${wipCount} WIP violations`);\n } else {\n console.log('\\nAll clear.');\n }\n\n // Show pipeline orchestrator runtime info (non-fatal on error)\n try {\n showPipelineInfo(boardId);\n } catch {\n // Pipeline info is supplementary — don't break the status command\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/commands/status.ts"],"sourcesContent":["import { readFileSync, existsSync, statSync, readdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { KantBanCLIClient } from '../client.js';\n\n// ---------------------------------------------------------------------------\n// Pipeline runtime info helper\n// ---------------------------------------------------------------------------\n\nfunction formatUptime(ms: number): string {\n const totalMinutes = Math.floor(ms / 60_000);\n const hours = Math.floor(totalMinutes / 60);\n const minutes = totalMinutes % 60;\n if (hours > 0) return `${String(hours)}h ${String(minutes)}m`;\n return `${String(minutes)}m`;\n}\n\nfunction isProcessRunning(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction showPipelineInfo(boardId: string): void {\n const pipelineDir = join(homedir(), '.kantban', 'pipelines', boardId);\n const pidFile = join(pipelineDir, 'orchestrator.pid');\n\n if (!existsSync(pidFile)) {\n console.log('\\nPipeline: not running');\n return;\n }\n\n const pidContent = readFileSync(pidFile, 'utf8').trim();\n const pid = Number(pidContent);\n if (isNaN(pid) || pid <= 0) {\n console.log('\\nOrchestrator: not running (invalid PID file)');\n return;\n }\n\n if (!isProcessRunning(pid)) {\n console.log('\\nOrchestrator: not running (stale PID file)');\n return;\n }\n\n // Process is running — calculate uptime from PID file mtime\n const pidStat = statSync(pidFile);\n const uptimeMs = Date.now() - pidStat.mtimeMs;\n console.log(`\\nOrchestrator: running (PID: ${String(pid)}, uptime: ${formatUptime(uptimeMs)})`);\n\n // Scan for recent iteration logs to show active/recent loop info\n if (!existsSync(pipelineDir)) return;\n\n const entries = readdirSync(pipelineDir, { withFileTypes: true });\n const ticketDirs = entries.filter((e) => e.isDirectory());\n\n if (ticketDirs.length === 0) return;\n\n const recentLoops: Array<{ ticket: string; lastIteration: number; outcome: string; timestamp: string }> = [];\n\n for (const dir of ticketDirs) {\n const ticketDir = join(pipelineDir, dir.name);\n const files = readdirSync(ticketDir).filter((f) => f.startsWith('iteration-') && f.endsWith('.log'));\n if (files.length === 0) continue;\n\n // Get the latest iteration log\n files.sort();\n const latestFile = files[files.length - 1]!;\n const logPath = join(ticketDir, latestFile);\n\n try {\n const logContent = readFileSync(logPath, 'utf8');\n const logData = JSON.parse(logContent) as Record<string, unknown>;\n recentLoops.push({\n ticket: dir.name,\n lastIteration: Number(logData['iteration'] ?? 0),\n outcome: String(logData['outcome'] ?? 'unknown'),\n timestamp: String(logData['timestamp'] ?? ''),\n });\n } catch {\n // Skip malformed log files\n }\n }\n\n if (recentLoops.length > 0) {\n // Sort by timestamp descending to show most recent first\n recentLoops.sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n console.log(` Active/recent loops (${String(recentLoops.length)}):`);\n for (const loop of recentLoops.slice(0, 10)) {\n console.log(` ${loop.ticket} iter:${String(loop.lastIteration)} ${loop.outcome}`);\n }\n if (recentLoops.length > 10) {\n console.log(` ... and ${String(recentLoops.length - 10)} more`);\n }\n }\n}\n\nexport async function runStatus(client: KantBanCLIClient, args: string[]): Promise<void> {\n const [boardId] = args;\n if (!boardId) {\n console.error('Usage: kantban status <board-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 required');\n process.exit(1);\n }\n\n const data = await client.get<Record<string, unknown>>(\n `/projects/${projectId}/pipeline-context`,\n { boardId },\n );\n\n const columns = data['columns'] as Array<Record<string, unknown>> | undefined;\n const cb = data['circuit_breaker'] as Record<string, unknown> | undefined;\n const board = data['board'] as Record<string, unknown> | undefined;\n\n console.log(`Pipeline Status: ${board?.['name'] ?? 'Unknown Board'}`);\n console.log('\\u2500'.repeat(60));\n\n if (columns) {\n for (const col of columns) {\n const prompt = col['has_prompt'] ? '\\u{1F4C4}' : ' ';\n const name = String(col['name'] ?? '(unnamed)');\n const count = Number(col['ticket_count'] ?? 0);\n const goal = col['goal'] ? ` \\u2014 ${String(col['goal'])}` : '';\n console.log(`${prompt} ${name} (${count} tickets)${goal}`);\n }\n }\n\n if (cb?.['threshold']) {\n console.log(`\\nCircuit Breaker: threshold=${String(cb['threshold'])}`);\n }\n\n // Fetch bottleneck info\n const bottlenecks = await client.get<Record<string, unknown>>(\n `/projects/${projectId}/boards/${boardId}/bottlenecks`,\n );\n const stuckCount = (bottlenecks['stuck_tickets'] as unknown[] | undefined)?.length ?? 0;\n const wipCount = (bottlenecks['wip_violations'] as unknown[] | undefined)?.length ?? 0;\n\n if (stuckCount > 0 || wipCount > 0) {\n console.log(`\\nWarnings: ${stuckCount} stuck, ${wipCount} WIP violations`);\n } else {\n console.log('\\nAll clear.');\n }\n\n // Show pipeline orchestrator runtime info (non-fatal on error)\n try {\n showPipelineInfo(boardId);\n } catch {\n // Pipeline info is supplementary — don't break the status command\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,8 +1,7 @@
1
1
  import {
2
2
  crossSpawnOptions,
3
3
  resolveCommand
4
- } from "./chunk-UNSNCYTR.js";
5
- import "./chunk-DGUM43GV.js";
4
+ } from "./chunk-5ZU2OOES.js";
6
5
 
7
6
  // src/commands/work.ts
8
7
  import { spawn } from "child_process";
@@ -86,4 +85,4 @@ async function runWork(client, args) {
86
85
  export {
87
86
  runWork
88
87
  };
89
- //# sourceMappingURL=work-HZVJJG4A.js.map
88
+ //# sourceMappingURL=work-45GILGKD.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/work.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport type { KantBanCLIClient } from '../client.js';\nimport { crossSpawnOptions, resolveCommand } from '../lib/platform.js';\n\nfunction asRecord(val: unknown): Record<string, unknown> | undefined {\n return typeof val === 'object' && val !== null && !Array.isArray(val)\n ? (val as Record<string, unknown>)\n : undefined;\n}\n\nfunction asStringArray(val: unknown): string[] {\n return Array.isArray(val) ? val.map((v) => String(v)) : [];\n}\n\nexport async function runWork(client: KantBanCLIClient, args: string[]): Promise<void> {\n const [ticketId] = args;\n if (!ticketId) {\n console.error('Usage: kantban work <ticket-id> [--dry-run]');\n process.exit(1);\n }\n\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 // Fetch ticket-scope context\n const context = await client.get<Record<string, unknown>>(\n `/projects/${projectId}/pipeline-context`,\n { ticketId },\n );\n\n const ticket = asRecord(context['ticket']);\n const signals = asStringArray(context['signals']);\n const rules = context['transition_rules'] ? String(context['transition_rules']) : undefined;\n\n const title = String(ticket?.['title'] ?? 'Untitled');\n const description = ticket?.['description'] ? String(ticket['description']) : '';\n const ticketIdStr = String(ticket?.['id'] ?? ticketId);\n\n // Build prompt for Claude\n const promptLines = [\n `# Task: ${title}`,\n '',\n ];\n\n if (description) {\n promptLines.push(description, '');\n }\n\n if (signals.length > 0) {\n promptLines.push('## Signals');\n for (const s of signals) {\n promptLines.push(`- ${s}`);\n }\n promptLines.push('');\n }\n\n if (rules) {\n promptLines.push('## Transition Rules', rules, '');\n }\n\n const toolPrefix = context['tool_prefix'] ? String(context['tool_prefix']) : 'kantban_';\n promptLines.push(\n `## Tool Prefix: ${toolPrefix}`,\n `## Ticket ID: ${ticketIdStr}`,\n `## Project ID: ${projectId}`,\n );\n\n const prompt = promptLines.join('\\n');\n\n console.log(`Starting Claude session for: ${title}`);\n console.log(`Ticket: ${ticketIdStr}`);\n\n // Check for dry run\n const dryRun = args.includes('--dry-run');\n if (dryRun) {\n console.log('\\n--- Prompt (dry run) ---');\n console.log(prompt);\n return;\n }\n\n // Spawn Claude with the prompt — resolveCommand bypasses cmd.exe 8191-char limit\n const [cmd, prefixArgs] = resolveCommand('claude');\n const child = spawn(cmd, [...prefixArgs, '-p', prompt], {\n stdio: 'inherit',\n env: { ...process.env },\n ...(prefixArgs.length > 0 ? {} : crossSpawnOptions()),\n });\n\n await new Promise<void>((resolve) => {\n child.on('error', (err) => {\n console.error(`Failed to start claude: ${err.message}`);\n process.exitCode = 1;\n resolve();\n });\n child.on('exit', (code) => {\n process.exitCode = code ?? 0;\n resolve();\n });\n });\n}\n"],"mappings":";;;;;;;AAAA,SAAS,aAAa;AAItB,SAAS,SAAS,KAAmD;AACnE,SAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,CAAC,MAAM,QAAQ,GAAG,IAC/D,MACD;AACN;AAEA,SAAS,cAAc,KAAwB;AAC7C,SAAO,MAAM,QAAQ,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC;AAC3D;AAEA,eAAsB,QAAQ,QAA0B,MAA+B;AACrF,QAAM,CAAC,QAAQ,IAAI;AACnB,MAAI,CAAC,UAAU;AACb,YAAQ,MAAM,6CAA6C;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,QAAQ,IAAI,oBAAoB;AAClD,MAAI,CAAC,WAAW;AACd,YAAQ,MAAM,oCAAoC;AAClD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,UAAU,MAAM,OAAO;AAAA,IAC3B,aAAa,SAAS;AAAA,IACtB,EAAE,SAAS;AAAA,EACb;AAEA,QAAM,SAAS,SAAS,QAAQ,QAAQ,CAAC;AACzC,QAAM,UAAU,cAAc,QAAQ,SAAS,CAAC;AAChD,QAAM,QAAQ,QAAQ,kBAAkB,IAAI,OAAO,QAAQ,kBAAkB,CAAC,IAAI;AAElF,QAAM,QAAQ,OAAO,SAAS,OAAO,KAAK,UAAU;AACpD,QAAM,cAAc,SAAS,aAAa,IAAI,OAAO,OAAO,aAAa,CAAC,IAAI;AAC9E,QAAM,cAAc,OAAO,SAAS,IAAI,KAAK,QAAQ;AAGrD,QAAM,cAAc;AAAA,IAClB,WAAW,KAAK;AAAA,IAChB;AAAA,EACF;AAEA,MAAI,aAAa;AACf,gBAAY,KAAK,aAAa,EAAE;AAAA,EAClC;AAEA,MAAI,QAAQ,SAAS,GAAG;AACtB,gBAAY,KAAK,YAAY;AAC7B,eAAW,KAAK,SAAS;AACvB,kBAAY,KAAK,KAAK,CAAC,EAAE;AAAA,IAC3B;AACA,gBAAY,KAAK,EAAE;AAAA,EACrB;AAEA,MAAI,OAAO;AACT,gBAAY,KAAK,uBAAuB,OAAO,EAAE;AAAA,EACnD;AAEA,QAAM,aAAa,QAAQ,aAAa,IAAI,OAAO,QAAQ,aAAa,CAAC,IAAI;AAC7E,cAAY;AAAA,IACV,mBAAmB,UAAU;AAAA,IAC7B,iBAAiB,WAAW;AAAA,IAC5B,kBAAkB,SAAS;AAAA,EAC7B;AAEA,QAAM,SAAS,YAAY,KAAK,IAAI;AAEpC,UAAQ,IAAI,gCAAgC,KAAK,EAAE;AACnD,UAAQ,IAAI,WAAW,WAAW,EAAE;AAGpC,QAAM,SAAS,KAAK,SAAS,WAAW;AACxC,MAAI,QAAQ;AACV,YAAQ,IAAI,4BAA4B;AACxC,YAAQ,IAAI,MAAM;AAClB;AAAA,EACF;AAGA,QAAM,CAAC,KAAK,UAAU,IAAI,eAAe,QAAQ;AACjD,QAAM,QAAQ,MAAM,KAAK,CAAC,GAAG,YAAY,MAAM,MAAM,GAAG;AAAA,IACtD,OAAO;AAAA,IACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,IACtB,GAAI,WAAW,SAAS,IAAI,CAAC,IAAI,kBAAkB;AAAA,EACrD,CAAC;AAED,QAAM,IAAI,QAAc,CAAC,YAAY;AACnC,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,cAAQ,MAAM,2BAA2B,IAAI,OAAO,EAAE;AACtD,cAAQ,WAAW;AACnB,cAAQ;AAAA,IACV,CAAC;AACD,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,cAAQ,WAAW,QAAQ;AAC3B,cAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../src/commands/work.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport type { KantBanCLIClient } from '../client.js';\nimport { crossSpawnOptions, resolveCommand } from '../lib/platform.js';\n\nfunction asRecord(val: unknown): Record<string, unknown> | undefined {\n return typeof val === 'object' && val !== null && !Array.isArray(val)\n ? (val as Record<string, unknown>)\n : undefined;\n}\n\nfunction asStringArray(val: unknown): string[] {\n return Array.isArray(val) ? val.map((v) => String(v)) : [];\n}\n\nexport async function runWork(client: KantBanCLIClient, args: string[]): Promise<void> {\n const [ticketId] = args;\n if (!ticketId) {\n console.error('Usage: kantban work <ticket-id> [--dry-run]');\n process.exit(1);\n }\n\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 // Fetch ticket-scope context\n const context = await client.get<Record<string, unknown>>(\n `/projects/${projectId}/pipeline-context`,\n { ticketId },\n );\n\n const ticket = asRecord(context['ticket']);\n const signals = asStringArray(context['signals']);\n const rules = context['transition_rules'] ? String(context['transition_rules']) : undefined;\n\n const title = String(ticket?.['title'] ?? 'Untitled');\n const description = ticket?.['description'] ? String(ticket['description']) : '';\n const ticketIdStr = String(ticket?.['id'] ?? ticketId);\n\n // Build prompt for Claude\n const promptLines = [\n `# Task: ${title}`,\n '',\n ];\n\n if (description) {\n promptLines.push(description, '');\n }\n\n if (signals.length > 0) {\n promptLines.push('## Signals');\n for (const s of signals) {\n promptLines.push(`- ${s}`);\n }\n promptLines.push('');\n }\n\n if (rules) {\n promptLines.push('## Transition Rules', rules, '');\n }\n\n const toolPrefix = context['tool_prefix'] ? String(context['tool_prefix']) : 'kantban_';\n promptLines.push(\n `## Tool Prefix: ${toolPrefix}`,\n `## Ticket ID: ${ticketIdStr}`,\n `## Project ID: ${projectId}`,\n );\n\n const prompt = promptLines.join('\\n');\n\n console.log(`Starting Claude session for: ${title}`);\n console.log(`Ticket: ${ticketIdStr}`);\n\n // Check for dry run\n const dryRun = args.includes('--dry-run');\n if (dryRun) {\n console.log('\\n--- Prompt (dry run) ---');\n console.log(prompt);\n return;\n }\n\n // Spawn Claude with the prompt — resolveCommand bypasses cmd.exe 8191-char limit\n const [cmd, prefixArgs] = resolveCommand('claude');\n const child = spawn(cmd, [...prefixArgs, '-p', prompt], {\n stdio: 'inherit',\n env: { ...process.env },\n ...(prefixArgs.length > 0 ? {} : crossSpawnOptions()),\n });\n\n await new Promise<void>((resolve) => {\n child.on('error', (err) => {\n console.error(`Failed to start claude: ${err.message}`);\n process.exitCode = 1;\n resolve();\n });\n child.on('exit', (code) => {\n process.exitCode = code ?? 0;\n resolve();\n });\n });\n}\n"],"mappings":";;;;;;AAAA,SAAS,aAAa;AAItB,SAAS,SAAS,KAAmD;AACnE,SAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,CAAC,MAAM,QAAQ,GAAG,IAC/D,MACD;AACN;AAEA,SAAS,cAAc,KAAwB;AAC7C,SAAO,MAAM,QAAQ,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC;AAC3D;AAEA,eAAsB,QAAQ,QAA0B,MAA+B;AACrF,QAAM,CAAC,QAAQ,IAAI;AACnB,MAAI,CAAC,UAAU;AACb,YAAQ,MAAM,6CAA6C;AAC3D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,YAAY,QAAQ,IAAI,oBAAoB;AAClD,MAAI,CAAC,WAAW;AACd,YAAQ,MAAM,oCAAoC;AAClD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,UAAU,MAAM,OAAO;AAAA,IAC3B,aAAa,SAAS;AAAA,IACtB,EAAE,SAAS;AAAA,EACb;AAEA,QAAM,SAAS,SAAS,QAAQ,QAAQ,CAAC;AACzC,QAAM,UAAU,cAAc,QAAQ,SAAS,CAAC;AAChD,QAAM,QAAQ,QAAQ,kBAAkB,IAAI,OAAO,QAAQ,kBAAkB,CAAC,IAAI;AAElF,QAAM,QAAQ,OAAO,SAAS,OAAO,KAAK,UAAU;AACpD,QAAM,cAAc,SAAS,aAAa,IAAI,OAAO,OAAO,aAAa,CAAC,IAAI;AAC9E,QAAM,cAAc,OAAO,SAAS,IAAI,KAAK,QAAQ;AAGrD,QAAM,cAAc;AAAA,IAClB,WAAW,KAAK;AAAA,IAChB;AAAA,EACF;AAEA,MAAI,aAAa;AACf,gBAAY,KAAK,aAAa,EAAE;AAAA,EAClC;AAEA,MAAI,QAAQ,SAAS,GAAG;AACtB,gBAAY,KAAK,YAAY;AAC7B,eAAW,KAAK,SAAS;AACvB,kBAAY,KAAK,KAAK,CAAC,EAAE;AAAA,IAC3B;AACA,gBAAY,KAAK,EAAE;AAAA,EACrB;AAEA,MAAI,OAAO;AACT,gBAAY,KAAK,uBAAuB,OAAO,EAAE;AAAA,EACnD;AAEA,QAAM,aAAa,QAAQ,aAAa,IAAI,OAAO,QAAQ,aAAa,CAAC,IAAI;AAC7E,cAAY;AAAA,IACV,mBAAmB,UAAU;AAAA,IAC7B,iBAAiB,WAAW;AAAA,IAC5B,kBAAkB,SAAS;AAAA,EAC7B;AAEA,QAAM,SAAS,YAAY,KAAK,IAAI;AAEpC,UAAQ,IAAI,gCAAgC,KAAK,EAAE;AACnD,UAAQ,IAAI,WAAW,WAAW,EAAE;AAGpC,QAAM,SAAS,KAAK,SAAS,WAAW;AACxC,MAAI,QAAQ;AACV,YAAQ,IAAI,4BAA4B;AACxC,YAAQ,IAAI,MAAM;AAClB;AAAA,EACF;AAGA,QAAM,CAAC,KAAK,UAAU,IAAI,eAAe,QAAQ;AACjD,QAAM,QAAQ,MAAM,KAAK,CAAC,GAAG,YAAY,MAAM,MAAM,GAAG;AAAA,IACtD,OAAO;AAAA,IACP,KAAK,EAAE,GAAG,QAAQ,IAAI;AAAA,IACtB,GAAI,WAAW,SAAS,IAAI,CAAC,IAAI,kBAAkB;AAAA,EACrD,CAAC;AAED,QAAM,IAAI,QAAc,CAAC,YAAY;AACnC,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,cAAQ,MAAM,2BAA2B,IAAI,OAAO,EAAE;AACtD,cAAQ,WAAW;AACnB,cAAQ;AAAA,IACV,CAAC;AACD,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,cAAQ,WAAW,QAAQ;AAC3B,cAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kantban-cli",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "description": "CLI for KantBan pipeline orchestration — bridges KantBan boards to local Claude Code sessions",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -1,11 +0,0 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
- export {
9
- __require
10
- };
11
- //# sourceMappingURL=chunk-DGUM43GV.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/platform.ts"],"sourcesContent":["import { platform } from 'node:os';\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { join, dirname } 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/**\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 .cmd file on PATH\n const whichSync = require('which').sync as (cmd: string) => string;\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":";;;;;AAAA,SAAS,gBAAgB;AACzB,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,MAAM,eAAe;AAEvB,IAAM,aAAa,SAAS,MAAM;AAGlC,SAAS,aAAa,MAAsB;AACjD,SAAO,KAAK,QAAQ,YAAY,IAAI;AACtC;AAIO,SAAS,YAAgC;AAC9C,MAAI,YAAY;AACd,UAAM,UAAU,QAAQ,IAAI,WAAW;AAEvC,QAAI,mBAAmB,KAAK,OAAO,GAAG;AACpC,aAAO,CAAC,SAAS,CAAC,cAAc,UAAU,CAAC;AAAA,IAC7C;AACA,WAAO,CAAC,SAAS,CAAC,IAAI,CAAC;AAAA,EACzB;AACA,SAAO,CAAC,WAAW,CAAC,IAAI,CAAC;AAC3B;AAGO,SAAS,kBAAqD,MAAkC;AACrG,SAAO,EAAE,GAAI,QAAQ,CAAC,GAAS,OAAO,WAAW;AACnD;AAIO,SAAS,gBAAgB,KAAa,SAAyB,WAAiB;AACrF,MAAI,YAAY;AAEd,QAAI;AAAE,mBAAa,YAAY,CAAC,QAAQ,OAAO,GAAG,GAAG,MAAM,IAAI,GAAG,EAAE,OAAO,OAAO,CAAC;AAAG;AAAA,IAAQ,QAAQ;AAAA,IAAqB;AAC3H,QAAI;AAAE,cAAQ,KAAK,GAAG;AAAA,IAAG,QAAQ;AAAA,IAAqB;AACtD;AAAA,EACF;AAEA,MAAI;AAAE,YAAQ,KAAK,CAAC,KAAK,MAAM;AAAG;AAAA,EAAQ,QAAQ;AAAA,EAAqB;AACvE,MAAI;AAAE,YAAQ,KAAK,KAAK,MAAM;AAAA,EAAG,QAAQ;AAAA,EAAqB;AAChE;AAGO,SAAS,aAAqB;AACnC,SAAO,aAAa,YAAY;AAClC;AAaO,SAAS,eAAe,SAAsD;AACnF,MAAI,CAAC,WAAY,QAAO,CAAC,SAAS,CAAC,CAAC;AAEpC,MAAI;AAEF,UAAM,YAAY,UAAQ,OAAO,EAAE;AACnC,UAAM,WAAW,UAAU,OAAO;AAGlC,QAAI,SAAS,YAAY,EAAE,SAAS,MAAM,EAAG,QAAO,CAAC,UAAU,CAAC,CAAC;AAGjE,QAAI,SAAS,YAAY,EAAE,SAAS,MAAM,GAAG;AAC3C,YAAM,UAAU,aAAa,UAAU,OAAO;AAG9C,iBAAW,QAAQ,QAAQ,MAAM,OAAO,GAAG;AACzC,cAAM,IAAI,KAAK,MAAM,wCAAwC;AAC7D,YAAI,GAAG;AACL,gBAAM,QAAQ,EAAE,CAAC,EAAG,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;AACtD,gBAAM,aAAa,KAAK,QAAQ,QAAQ,GAAG,EAAE,CAAC,CAAE;AAChD,iBAAO,CAAC,QAAQ,UAAU,CAAC,GAAG,OAAO,UAAU,CAAC;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAGA,SAAO,CAAC,SAAS,CAAC,CAAC;AACrB;AAGO,SAAS,cAAsB;AACpC,MAAI,YAAY;AACd,WAAO;AAAA,MACL,QAAQ,IAAI,aAAa,GAAG,QAAQ,IAAI,UAAU,eAAe;AAAA,MACjE,QAAQ,IAAI,cAAc;AAAA,MAC1B;AAAA,MACA,QAAQ,IAAI,UAAU,GAAG,QAAQ,IAAI,OAAO,UAAU;AAAA,IACxD,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,EAC5B;AACA,SAAO;AACT;","names":[]}