kantban-cli 0.1.10 → 0.1.12

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.
@@ -2,7 +2,7 @@ import {
2
2
  RalphLoop,
3
3
  cleanupMcpConfig,
4
4
  generateMcpConfig
5
- } from "./chunk-ZCUIGFSP.js";
5
+ } from "./chunk-MTPUHYZV.js";
6
6
 
7
7
  // src/commands/cron.ts
8
8
  import { execFile } from "child_process";
@@ -109,4 +109,4 @@ async function runCron(client, args) {
109
109
  export {
110
110
  runCron
111
111
  };
112
- //# sourceMappingURL=cron-OKQP6QDF.js.map
112
+ //# sourceMappingURL=cron-QKX2LAAY.js.map
package/dist/index.js CHANGED
@@ -163,16 +163,16 @@ async function main() {
163
163
  }
164
164
  case "pipeline": {
165
165
  if (args[0] === "stop") {
166
- const { stopPipeline } = await import("./pipeline-HTGCXNPL.js");
166
+ const { stopPipeline } = await import("./pipeline-SFXKDLMA.js");
167
167
  await stopPipeline(args.slice(1));
168
168
  } else {
169
- const { runPipeline } = await import("./pipeline-HTGCXNPL.js");
169
+ const { runPipeline } = await import("./pipeline-SFXKDLMA.js");
170
170
  await runPipeline(client, args);
171
171
  }
172
172
  break;
173
173
  }
174
174
  case "cron": {
175
- const { runCron } = await import("./cron-OKQP6QDF.js");
175
+ const { runCron } = await import("./cron-QKX2LAAY.js");
176
176
  await runCron(client, args);
177
177
  break;
178
178
  }
@@ -13,7 +13,7 @@ import {
13
13
  parseStuckDetectionResponse,
14
14
  parseTimeout,
15
15
  resolveGatesForColumn
16
- } from "./chunk-ZCUIGFSP.js";
16
+ } from "./chunk-MTPUHYZV.js";
17
17
 
18
18
  // src/commands/pipeline.ts
19
19
  import { spawn as spawn2, execSync } from "child_process";
@@ -53,6 +53,65 @@ async function cleanupWorktree(worktreeName, exec = defaultExecFile) {
53
53
  });
54
54
  });
55
55
  }
56
+ function execPromise(exec, cmd, args) {
57
+ return new Promise((resolve, reject) => {
58
+ exec(cmd, args, (err, stdout, stderr) => {
59
+ if (err) reject(Object.assign(err, { stdout, stderr }));
60
+ else resolve({ stdout, stderr });
61
+ });
62
+ });
63
+ }
64
+ async function findWorktreeForBranch(exec, branch) {
65
+ try {
66
+ const { stdout } = await execPromise(exec, "git", ["worktree", "list", "--porcelain"]);
67
+ const targetRef = `refs/heads/${branch}`;
68
+ let currentPath = null;
69
+ for (const line of stdout.split("\n")) {
70
+ if (line.startsWith("worktree ")) currentPath = line.slice("worktree ".length);
71
+ if (line.startsWith("branch ") && line.slice("branch ".length) === targetRef && currentPath) {
72
+ return currentPath;
73
+ }
74
+ }
75
+ return null;
76
+ } catch {
77
+ return null;
78
+ }
79
+ }
80
+ async function mergeWorktreeBranch(worktreeName, integrationBranch, exec = defaultExecFile) {
81
+ try {
82
+ await execPromise(exec, "git", ["branch", integrationBranch, "HEAD"]).catch(() => {
83
+ });
84
+ const checkedOutPath = await findWorktreeForBranch(exec, integrationBranch);
85
+ if (checkedOutPath) {
86
+ await execPromise(exec, "git", ["-C", checkedOutPath, "merge", "--no-edit", worktreeName]);
87
+ console.error(`[worktree] merged ${worktreeName} \u2192 ${integrationBranch}`);
88
+ return true;
89
+ }
90
+ const { stdout: baseOut } = await execPromise(exec, "git", ["merge-base", integrationBranch, worktreeName]);
91
+ const mergeBase = baseOut.trim();
92
+ const { stdout: integrationSha } = await execPromise(exec, "git", ["rev-parse", integrationBranch]);
93
+ if (integrationSha.trim() === mergeBase) {
94
+ const { stdout: worktreeSha } = await execPromise(exec, "git", ["rev-parse", worktreeName]);
95
+ await execPromise(exec, "git", ["update-ref", `refs/heads/${integrationBranch}`, worktreeSha.trim()]);
96
+ console.error(`[worktree] fast-forward merged ${worktreeName} \u2192 ${integrationBranch}`);
97
+ return true;
98
+ }
99
+ const tmpWorktree = `merge-tmp-${Date.now()}`;
100
+ try {
101
+ await execPromise(exec, "git", ["worktree", "add", tmpWorktree, integrationBranch]);
102
+ await execPromise(exec, "git", ["-C", tmpWorktree, "merge", "--no-edit", worktreeName]);
103
+ console.error(`[worktree] merged ${worktreeName} \u2192 ${integrationBranch}`);
104
+ } finally {
105
+ await execPromise(exec, "git", ["worktree", "remove", "--force", tmpWorktree]).catch(() => {
106
+ });
107
+ }
108
+ return true;
109
+ } catch (err) {
110
+ const msg = err instanceof Error ? err.message : String(err);
111
+ console.error(`[worktree] merge failed for ${worktreeName} \u2192 ${integrationBranch}: ${msg}`);
112
+ return false;
113
+ }
114
+ }
56
115
 
57
116
  // src/lib/constraint-evaluator.ts
58
117
  function resolveColumn(board, columnId, subjectRef) {
@@ -457,6 +516,7 @@ var PipelineOrchestrator = class {
457
516
  worktreeEnabled: cfg?.worktree?.enabled,
458
517
  worktreeOnMove: cfg?.worktree?.on_move,
459
518
  worktreeOnDone: cfg?.worktree?.on_done,
519
+ worktreeIntegrationBranch: cfg?.worktree?.integration_branch,
460
520
  invocationTier: cfg?.invocation_tier,
461
521
  lookaheadColumnId: cfg?.lookahead_column_id,
462
522
  runMemory: cfg?.run_memory,
@@ -1597,18 +1657,28 @@ ${findingsText}`)
1597
1657
  );
1598
1658
  }
1599
1659
  const isTerminal = result.reason === "moved" || result.reason === "max_iterations" || result.reason === "error" || result.reason === "stalled" || result.reason === "stopped" || result.reason === "deleted";
1600
- if (isTerminal && colConfig?.worktreeOnDone === "cleanup" && this.deps.cleanupWorktree) {
1660
+ if (isTerminal && colConfig) {
1601
1661
  const colScope2 = this.columnScopes.get(columnId);
1602
1662
  const ticket2 = colScope2?.tickets.find((t) => t.id === ticketId);
1603
1663
  if (ticket2) {
1604
1664
  const worktreeName = generateWorktreeName(ticket2.ticket_number, colConfig.name);
1605
- void this.deps.cleanupWorktree(worktreeName).then((success) => {
1606
- if (!success) {
1607
- console.error(` [warn] Worktree cleanup failed for ${worktreeName} \u2014 may need manual removal`);
1608
- }
1609
- }).catch((err) => {
1610
- console.error(` [warn] Worktree cleanup error for ${worktreeName}: ${err instanceof Error ? err.message : String(err)}`);
1611
- });
1665
+ if (colConfig.worktreeOnDone === "merge" && colConfig.worktreeIntegrationBranch && this.deps.mergeWorktree) {
1666
+ void this.deps.mergeWorktree(worktreeName, colConfig.worktreeIntegrationBranch).then((success) => {
1667
+ if (!success) {
1668
+ console.error(` [warn] Worktree merge failed for ${worktreeName} \u2192 ${colConfig.worktreeIntegrationBranch} \u2014 may need manual resolution`);
1669
+ }
1670
+ }).catch((err) => {
1671
+ console.error(` [warn] Worktree merge error for ${worktreeName}: ${err instanceof Error ? err.message : String(err)}`);
1672
+ });
1673
+ } else if (colConfig.worktreeOnDone === "cleanup" && this.deps.cleanupWorktree) {
1674
+ void this.deps.cleanupWorktree(worktreeName).then((success) => {
1675
+ if (!success) {
1676
+ console.error(` [warn] Worktree cleanup failed for ${worktreeName} \u2014 may need manual removal`);
1677
+ }
1678
+ }).catch((err) => {
1679
+ console.error(` [warn] Worktree cleanup error for ${worktreeName}: ${err instanceof Error ? err.message : String(err)}`);
1680
+ });
1681
+ }
1612
1682
  }
1613
1683
  }
1614
1684
  this.deps.gateSnapshotStore?.clear(ticketId);
@@ -3643,6 +3713,7 @@ async function runPipeline(client, args) {
3643
3713
  moveTicketToColumn: async (ticketId, columnId, handoff) => {
3644
3714
  await client.patch(`/projects/${projectId}/tickets/${ticketId}/move`, {
3645
3715
  column_id: columnId,
3716
+ position: 0,
3646
3717
  handoff
3647
3718
  });
3648
3719
  },
@@ -3663,6 +3734,7 @@ async function runPipeline(client, args) {
3663
3734
  // Run memory append — closure captures runMemory by reference (set after initialization)
3664
3735
  appendRunMemory: (section, content) => runMemory ? runMemory.append(section, content) : Promise.resolve(),
3665
3736
  cleanupWorktree: (name) => cleanupWorktree(name),
3737
+ mergeWorktree: (name, integrationBranch) => mergeWorktreeBranch(name, integrationBranch),
3666
3738
  // Pipeline event emission — wsClient captured by reference (set later before any loops run)
3667
3739
  emitPipelineEvent: (event) => {
3668
3740
  wsClient?.send(event);
@@ -4046,4 +4118,4 @@ export {
4046
4118
  runPipeline,
4047
4119
  stopPipeline
4048
4120
  };
4049
- //# sourceMappingURL=pipeline-HTGCXNPL.js.map
4121
+ //# sourceMappingURL=pipeline-SFXKDLMA.js.map