kantban-cli 0.1.11 → 0.1.13

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-FKIFDPKK.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-7EFCWJUS.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-7LG74YA2.js");
166
+ const { stopPipeline } = await import("./pipeline-Z47VDJBI.js");
167
167
  await stopPipeline(args.slice(1));
168
168
  } else {
169
- const { runPipeline } = await import("./pipeline-7LG74YA2.js");
169
+ const { runPipeline } = await import("./pipeline-Z47VDJBI.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-7EFCWJUS.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-FKIFDPKK.js";
17
17
 
18
18
  // src/commands/pipeline.ts
19
19
  import { spawn as spawn2, execSync } from "child_process";
@@ -61,10 +61,32 @@ function execPromise(exec, cmd, args) {
61
61
  });
62
62
  });
63
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
+ }
64
80
  async function mergeWorktreeBranch(worktreeName, integrationBranch, exec = defaultExecFile) {
65
81
  try {
66
82
  await execPromise(exec, "git", ["branch", integrationBranch, "HEAD"]).catch(() => {
67
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
+ }
68
90
  const { stdout: baseOut } = await execPromise(exec, "git", ["merge-base", integrationBranch, worktreeName]);
69
91
  const mergeBase = baseOut.trim();
70
92
  const { stdout: integrationSha } = await execPromise(exec, "git", ["rev-parse", integrationBranch]);
@@ -734,13 +756,12 @@ var PipelineOrchestrator = class {
734
756
  for (const r of result.results) {
735
757
  if (!r.passed && !r.error) {
736
758
  const constraint = constraintMap.get(r.constraint_id);
737
- if (constraint?.notify && this.deps.createColumnSignal) {
738
- void this.deps.createColumnSignal(
739
- columnId,
740
- `Firing constraint "${r.name}" blocked column: resolved=${String(r.resolved_value)} ${r.threshold.operator} ${String(r.threshold.value)}`
741
- ).catch((err) => {
759
+ if (constraint?.notify && this.deps.upsertColumnSignal) {
760
+ const prefix = `Firing constraint "${r.name}" blocked`;
761
+ const body = `${prefix} column: resolved=${String(r.resolved_value)} ${r.threshold.operator} ${String(r.threshold.value)}`;
762
+ void this.deps.upsertColumnSignal(columnId, prefix, body).catch((err) => {
742
763
  const msg = err instanceof Error ? err.message : String(err);
743
- console.error(` [warn] Failed to create constraint signal: ${msg}`);
764
+ console.error(` [warn] Failed to upsert constraint signal: ${msg}`);
744
765
  });
745
766
  }
746
767
  }
@@ -1992,14 +2013,21 @@ var RunMemory = class {
1992
2013
  this._documentId = await this.deps.createDocument(content, title);
1993
2014
  }
1994
2015
  /**
1995
- * Get current document content. Returns '' if not initialized or on error.
2016
+ * Get current document content, truncated to last 500 lines.
2017
+ * Returns '' if not initialized or on error.
1996
2018
  */
1997
2019
  async getContent() {
1998
2020
  if (this._documentId === null) {
1999
2021
  return "";
2000
2022
  }
2001
2023
  try {
2002
- return await this.deps.getDocument(this._documentId);
2024
+ const content = await this.deps.getDocument(this._documentId);
2025
+ const lines = content.split("\n");
2026
+ if (lines.length > DEFAULT_COMPACTION_THRESHOLD) {
2027
+ const truncated = lines.slice(-DEFAULT_COMPACTION_THRESHOLD);
2028
+ return "[Run memory truncated \u2014 compaction needed]\n" + truncated.join("\n");
2029
+ }
2030
+ return content;
2003
2031
  } catch (err) {
2004
2032
  console.warn(`[run-memory] getContent failed: ${err instanceof Error ? err.message : String(err)}`);
2005
2033
  return "";
@@ -2007,12 +2035,18 @@ var RunMemory = class {
2007
2035
  }
2008
2036
  /**
2009
2037
  * Check if document exceeds line threshold (default 500).
2038
+ * Reads the raw document directly — getContent() truncates, so checking
2039
+ * truncated output would cap the visible line count and miss the real size.
2010
2040
  */
2011
2041
  async needsCompaction(threshold = DEFAULT_COMPACTION_THRESHOLD) {
2012
- const content = await this.getContent();
2013
- if (!content) return false;
2014
- const lineCount = content.split("\n").length;
2015
- return lineCount > threshold;
2042
+ if (this._documentId === null) return false;
2043
+ try {
2044
+ const content = await this.deps.getDocument(this._documentId);
2045
+ if (!content) return false;
2046
+ return content.split("\n").length > threshold;
2047
+ } catch {
2048
+ return false;
2049
+ }
2016
2050
  }
2017
2051
  /**
2018
2052
  * Append content under a specific section heading.
@@ -2709,6 +2743,12 @@ function computeDelta(previous, currentResults) {
2709
2743
  const currPassing = currentResults.filter((r) => r.passed).length;
2710
2744
  if (currPassing > prevPassing) return "improved";
2711
2745
  if (currPassing < prevPassing) return "regressed";
2746
+ const prevFailing = previous.results.filter((r) => !r.passed);
2747
+ const currFailing = currentResults.filter((r) => !r.passed);
2748
+ for (const curr of currFailing) {
2749
+ const prev = prevFailing.find((r) => r.name === curr.name);
2750
+ if (prev && prev.output !== curr.output) return "improved";
2751
+ }
2712
2752
  return "same";
2713
2753
  }
2714
2754
  var GateSnapshotStore = class {
@@ -2873,7 +2913,7 @@ var PipelineCostTracker = class {
2873
2913
  cc.tokens_out += inv.tokensOut;
2874
2914
  if (inv.type === "light") cc.light_calls++;
2875
2915
  if (inv.type === "heavy") cc.heavy_calls++;
2876
- if (inv.type === "advisor" || inv.type === "stuck_detection") cc.advisor_calls++;
2916
+ if (inv.type === "advisor" || inv.type === "stuck_detection" || inv.type === "replanner") cc.advisor_calls++;
2877
2917
  this.columnCosts.set(inv.columnId, cc);
2878
2918
  const mc = this.modelCosts.get(inv.model) ?? { tokens_in: 0, tokens_out: 0, calls: 0 };
2879
2919
  mc.tokens_in += inv.tokensIn;
@@ -3602,6 +3642,12 @@ async function runPipeline(client, args) {
3602
3642
  scopeId: columnId,
3603
3643
  content: body
3604
3644
  }),
3645
+ upsertColumnSignal: (columnId, contentPrefix, body) => client.put(`/projects/${projectId}/signals/upsert`, {
3646
+ scopeType: "column",
3647
+ scopeId: columnId,
3648
+ contentPrefix,
3649
+ content: body
3650
+ }),
3605
3651
  claimTicket: (ticketId) => client.claimTicket(projectId, ticketId),
3606
3652
  fetchBlockedTickets: (ticketId) => client.get(
3607
3653
  `/projects/${projectId}/tickets/${ticketId}/blocked-tickets`
@@ -3691,6 +3737,7 @@ async function runPipeline(client, args) {
3691
3737
  moveTicketToColumn: async (ticketId, columnId, handoff) => {
3692
3738
  await client.patch(`/projects/${projectId}/tickets/${ticketId}/move`, {
3693
3739
  column_id: columnId,
3740
+ position: 0,
3694
3741
  handoff
3695
3742
  });
3696
3743
  },
@@ -3729,7 +3776,7 @@ async function runPipeline(client, args) {
3729
3776
  tools: "",
3730
3777
  includeMcpConfig: false
3731
3778
  });
3732
- costTracker?.record({ ticketId: "replanner", columnId: "pipeline", model: "haiku", tokensIn, tokensOut, type: "orchestrator" });
3779
+ costTracker?.record({ ticketId: "replanner", columnId: "pipeline", model: "haiku", tokensIn, tokensOut, type: "replanner" });
3733
3780
  if (exitCode !== 0) throw new Error(`Replanner failed`);
3734
3781
  return parseReplannerResponse(output);
3735
3782
  }
@@ -4095,4 +4142,4 @@ export {
4095
4142
  runPipeline,
4096
4143
  stopPipeline
4097
4144
  };
4098
- //# sourceMappingURL=pipeline-7LG74YA2.js.map
4145
+ //# sourceMappingURL=pipeline-Z47VDJBI.js.map