kantban-cli 0.1.51 → 0.1.54
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-X2CJ3ZAI.js → chunk-3A4B7CUH.js} +215 -25
- package/dist/chunk-3A4B7CUH.js.map +1 -0
- package/dist/{cron-OCKARAAM.js → cron-VZMNM2XT.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/lib/gate-proxy-server.js +6 -3
- package/dist/lib/gate-proxy-server.js.map +1 -1
- package/dist/{pipeline-6J64Z7VH.js → pipeline-KKUWLU3L.js} +76 -194
- package/dist/pipeline-KKUWLU3L.js.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-X2CJ3ZAI.js.map +0 -1
- package/dist/pipeline-6J64Z7VH.js.map +0 -1
- /package/dist/{cron-OCKARAAM.js.map → cron-VZMNM2XT.js.map} +0 -0
|
@@ -7,14 +7,20 @@ import {
|
|
|
7
7
|
classifyTrajectory,
|
|
8
8
|
cleanupGateProxyConfigs,
|
|
9
9
|
cleanupMcpConfig,
|
|
10
|
+
cleanupWorktree,
|
|
10
11
|
composeStuckDetectionPrompt,
|
|
12
|
+
defaultWorktreeRoot,
|
|
11
13
|
detectBranchMerged,
|
|
14
|
+
ensureWorktreeRemote,
|
|
12
15
|
generateGateProxyMcpConfig,
|
|
13
16
|
generateMcpConfig,
|
|
17
|
+
generateWorktreeName,
|
|
18
|
+
mergeWorktreeBranch,
|
|
14
19
|
parseJsonFromLlmOutput,
|
|
15
20
|
parseStuckDetectionResponse,
|
|
16
|
-
reapOrphanedMcpConfigDirs
|
|
17
|
-
|
|
21
|
+
reapOrphanedMcpConfigDirs,
|
|
22
|
+
renderWorktreePath
|
|
23
|
+
} from "./chunk-3A4B7CUH.js";
|
|
18
24
|
import {
|
|
19
25
|
LoopCheckpointSchema,
|
|
20
26
|
VerdictSchema,
|
|
@@ -34,8 +40,8 @@ import {
|
|
|
34
40
|
// src/commands/pipeline.ts
|
|
35
41
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync3, unlinkSync as unlinkSync3, existsSync as existsSync3, appendFileSync as appendFileSync2, promises as fsPromises } from "fs";
|
|
36
42
|
import { execFile } from "child_process";
|
|
37
|
-
import { homedir as
|
|
38
|
-
import { join as
|
|
43
|
+
import { homedir as homedir2 } from "os";
|
|
44
|
+
import { join as join3, dirname as dirname2, resolve, sep } from "path";
|
|
39
45
|
import { promisify } from "util";
|
|
40
46
|
|
|
41
47
|
// src/lib/harness-signal.ts
|
|
@@ -58,150 +64,6 @@ function resolveToolRestrictions(builtinTools, allowedTools, disallowedTools) {
|
|
|
58
64
|
};
|
|
59
65
|
}
|
|
60
66
|
|
|
61
|
-
// src/lib/worktree.ts
|
|
62
|
-
import { execFile as defaultExecFile, execFileSync } from "child_process";
|
|
63
|
-
import { homedir } from "os";
|
|
64
|
-
import { join } from "path";
|
|
65
|
-
function generateWorktreeName(ticketNumber, columnName) {
|
|
66
|
-
const slug = columnSlug(columnName);
|
|
67
|
-
return `kantban-${ticketNumber}-${slug}`;
|
|
68
|
-
}
|
|
69
|
-
function columnSlug(columnName) {
|
|
70
|
-
return columnName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
71
|
-
}
|
|
72
|
-
function renderWorktreePath(ticketNumber, columnName, pathPattern, options) {
|
|
73
|
-
const slug = columnSlug(columnName);
|
|
74
|
-
const worktreeName = generateWorktreeName(ticketNumber, columnName);
|
|
75
|
-
if (pathPattern) {
|
|
76
|
-
return pathPattern.replace(/\{ticket_number\}/g, String(ticketNumber)).replace(/\{column_slug\}/g, slug).replace(/\{worktree_name\}/g, worktreeName);
|
|
77
|
-
}
|
|
78
|
-
return join(options.defaultRoot, options.boardId, slug, String(ticketNumber));
|
|
79
|
-
}
|
|
80
|
-
function defaultWorktreeRoot() {
|
|
81
|
-
return join(homedir(), ".kantban", "worktrees");
|
|
82
|
-
}
|
|
83
|
-
function isPlausibleRemoteUrl(url) {
|
|
84
|
-
return url.includes("/") || url.includes("@") || url.includes("://");
|
|
85
|
-
}
|
|
86
|
-
function ensureWorktreeRemote(worktreePath) {
|
|
87
|
-
try {
|
|
88
|
-
const remotes = normalizeEol(execFileSync("git", ["-C", worktreePath, "remote"], {
|
|
89
|
-
stdio: "pipe",
|
|
90
|
-
encoding: "utf-8"
|
|
91
|
-
})).trim();
|
|
92
|
-
if (remotes.split("\n").includes("origin")) {
|
|
93
|
-
const currentUrl = normalizeEol(execFileSync("git", ["-C", worktreePath, "remote", "get-url", "origin"], {
|
|
94
|
-
stdio: "pipe",
|
|
95
|
-
encoding: "utf-8"
|
|
96
|
-
})).trim();
|
|
97
|
-
if (isPlausibleRemoteUrl(currentUrl)) return;
|
|
98
|
-
console.error(`[worktree] Invalid origin URL in ${worktreePath}: "${currentUrl}" \u2014 fixing`);
|
|
99
|
-
execFileSync("git", ["-C", worktreePath, "remote", "remove", "origin"], {
|
|
100
|
-
stdio: "pipe"
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
const originUrl = normalizeEol(execFileSync("git", ["remote", "get-url", "origin"], {
|
|
104
|
-
stdio: "pipe",
|
|
105
|
-
encoding: "utf-8"
|
|
106
|
-
})).trim();
|
|
107
|
-
if (originUrl && isPlausibleRemoteUrl(originUrl)) {
|
|
108
|
-
execFileSync("git", ["-C", worktreePath, "remote", "add", "origin", originUrl], {
|
|
109
|
-
stdio: "pipe"
|
|
110
|
-
});
|
|
111
|
-
console.error(`[worktree] Added missing origin remote to ${worktreePath}: ${originUrl}`);
|
|
112
|
-
} else {
|
|
113
|
-
console.error(`[worktree] WARNING: main repo origin URL is also invalid: "${originUrl}"`);
|
|
114
|
-
}
|
|
115
|
-
} catch (err) {
|
|
116
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
117
|
-
console.error(`[worktree] Failed to ensure remote for ${worktreePath}: ${msg}`);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
async function cleanupWorktree(worktreeName, exec = defaultExecFile) {
|
|
121
|
-
let target = worktreeName;
|
|
122
|
-
try {
|
|
123
|
-
const path = await findWorktreeForBranch(exec, worktreeName);
|
|
124
|
-
if (!path) return true;
|
|
125
|
-
target = path;
|
|
126
|
-
} catch {
|
|
127
|
-
return true;
|
|
128
|
-
}
|
|
129
|
-
return new Promise((resolve2) => {
|
|
130
|
-
exec("git", ["worktree", "remove", "--force", target], (err) => {
|
|
131
|
-
if (err) {
|
|
132
|
-
console.error(`[worktree] cleanup failed for ${worktreeName} (${target}): ${err.message}`);
|
|
133
|
-
resolve2(false);
|
|
134
|
-
} else {
|
|
135
|
-
resolve2(true);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
function execPromise(exec, cmd, args) {
|
|
141
|
-
return new Promise((resolve2, reject) => {
|
|
142
|
-
exec(cmd, args, (err, stdout, stderr) => {
|
|
143
|
-
if (err) reject(Object.assign(err, { stdout, stderr }));
|
|
144
|
-
else resolve2({ stdout, stderr });
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
async function findWorktreeForBranch(exec, branch) {
|
|
149
|
-
try {
|
|
150
|
-
const { stdout } = await execPromise(exec, "git", ["worktree", "list", "--porcelain"]);
|
|
151
|
-
const targetRef = `refs/heads/${branch}`;
|
|
152
|
-
let currentPath = null;
|
|
153
|
-
for (const line of normalizeEol(stdout).split("\n")) {
|
|
154
|
-
if (line.startsWith("worktree ")) currentPath = line.slice("worktree ".length);
|
|
155
|
-
if (line.startsWith("branch ") && line.slice("branch ".length) === targetRef && currentPath) {
|
|
156
|
-
return currentPath;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
return null;
|
|
160
|
-
} catch {
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
async function mergeWorktreeBranch(worktreeName, integrationBranch, exec = defaultExecFile) {
|
|
165
|
-
try {
|
|
166
|
-
try {
|
|
167
|
-
await execPromise(exec, "git", ["rev-parse", "--verify", worktreeName]);
|
|
168
|
-
} catch {
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
await execPromise(exec, "git", ["branch", integrationBranch, "HEAD"]).catch(() => {
|
|
172
|
-
});
|
|
173
|
-
const checkedOutPath = await findWorktreeForBranch(exec, integrationBranch);
|
|
174
|
-
if (checkedOutPath) {
|
|
175
|
-
await execPromise(exec, "git", ["-C", checkedOutPath, "merge", "--no-edit", worktreeName]);
|
|
176
|
-
console.error(`[worktree] merged ${worktreeName} \u2192 ${integrationBranch}`);
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
const { stdout: baseOut } = await execPromise(exec, "git", ["merge-base", integrationBranch, worktreeName]);
|
|
180
|
-
const mergeBase = baseOut.trim();
|
|
181
|
-
const { stdout: integrationSha } = await execPromise(exec, "git", ["rev-parse", integrationBranch]);
|
|
182
|
-
if (integrationSha.trim() === mergeBase) {
|
|
183
|
-
const { stdout: worktreeSha } = await execPromise(exec, "git", ["rev-parse", worktreeName]);
|
|
184
|
-
await execPromise(exec, "git", ["update-ref", `refs/heads/${integrationBranch}`, worktreeSha.trim()]);
|
|
185
|
-
console.error(`[worktree] fast-forward merged ${worktreeName} \u2192 ${integrationBranch}`);
|
|
186
|
-
return true;
|
|
187
|
-
}
|
|
188
|
-
const tmpWorktree = `merge-tmp-${Date.now()}`;
|
|
189
|
-
try {
|
|
190
|
-
await execPromise(exec, "git", ["worktree", "add", tmpWorktree, integrationBranch]);
|
|
191
|
-
await execPromise(exec, "git", ["-C", tmpWorktree, "merge", "--no-edit", worktreeName]);
|
|
192
|
-
console.error(`[worktree] merged ${worktreeName} \u2192 ${integrationBranch}`);
|
|
193
|
-
} finally {
|
|
194
|
-
await execPromise(exec, "git", ["worktree", "remove", "--force", tmpWorktree]).catch(() => {
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
return true;
|
|
198
|
-
} catch (err) {
|
|
199
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
200
|
-
console.error(`[worktree] merge failed for ${worktreeName} \u2192 ${integrationBranch}: ${msg}`);
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
67
|
// src/lib/constraint-evaluator.ts
|
|
206
68
|
function resolveColumn(board, columnId, subjectRef) {
|
|
207
69
|
const ref = subjectRef ?? "self";
|
|
@@ -2780,7 +2642,7 @@ var PipelineWsClient = class _PipelineWsClient {
|
|
|
2780
2642
|
|
|
2781
2643
|
// src/lib/logger.ts
|
|
2782
2644
|
import { mkdirSync, writeFileSync, appendFileSync, readdirSync, rmSync, statSync, renameSync } from "fs";
|
|
2783
|
-
import { join
|
|
2645
|
+
import { join } from "path";
|
|
2784
2646
|
var MAX_LOG_BYTES = 5 * 1024 * 1024;
|
|
2785
2647
|
var MAX_ROTATED_FILES = 3;
|
|
2786
2648
|
var ROTATION_CHECK_INTERVAL = 100;
|
|
@@ -2788,11 +2650,11 @@ var PipelineLogger = class {
|
|
|
2788
2650
|
boardDir;
|
|
2789
2651
|
writeCount = 0;
|
|
2790
2652
|
constructor(baseDir, boardId) {
|
|
2791
|
-
this.boardDir =
|
|
2653
|
+
this.boardDir = join(baseDir, boardId);
|
|
2792
2654
|
mkdirSync(this.boardDir, { recursive: true });
|
|
2793
2655
|
}
|
|
2794
2656
|
orchestrator(message) {
|
|
2795
|
-
const logPath =
|
|
2657
|
+
const logPath = join(this.boardDir, "orchestrator.log");
|
|
2796
2658
|
const entry = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
2797
2659
|
`;
|
|
2798
2660
|
appendFileSync(logPath, entry);
|
|
@@ -2824,10 +2686,10 @@ var PipelineLogger = class {
|
|
|
2824
2686
|
}
|
|
2825
2687
|
}
|
|
2826
2688
|
iteration(ticketNumber, iterationNum, data) {
|
|
2827
|
-
const ticketDir =
|
|
2689
|
+
const ticketDir = join(this.boardDir, ticketNumber);
|
|
2828
2690
|
mkdirSync(ticketDir, { recursive: true });
|
|
2829
2691
|
const padded = String(iterationNum).padStart(3, "0");
|
|
2830
|
-
const logPath =
|
|
2692
|
+
const logPath = join(ticketDir, `iteration-${padded}.log`);
|
|
2831
2693
|
const entry = {
|
|
2832
2694
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2833
2695
|
iteration: iterationNum,
|
|
@@ -2846,7 +2708,7 @@ var PipelineLogger = class {
|
|
|
2846
2708
|
try {
|
|
2847
2709
|
const entries = readdirSync(this.boardDir, { withFileTypes: true });
|
|
2848
2710
|
for (const entry of entries) {
|
|
2849
|
-
const fullPath =
|
|
2711
|
+
const fullPath = join(this.boardDir, entry.name);
|
|
2850
2712
|
if (entry.isDirectory() && entry.name !== ".") {
|
|
2851
2713
|
try {
|
|
2852
2714
|
const stat = statSync(fullPath);
|
|
@@ -3483,7 +3345,7 @@ var ProviderRegistry = class {
|
|
|
3483
3345
|
};
|
|
3484
3346
|
|
|
3485
3347
|
// src/providers/codex-provider.ts
|
|
3486
|
-
import { spawn as spawn2, execFileSync
|
|
3348
|
+
import { spawn as spawn2, execFileSync } from "child_process";
|
|
3487
3349
|
import { existsSync, rmSync as rmSync2 } from "fs";
|
|
3488
3350
|
|
|
3489
3351
|
// src/providers/codex-jsonl-parser.ts
|
|
@@ -3624,12 +3486,12 @@ var CodexProvider = class {
|
|
|
3624
3486
|
const branch = request.branch ?? request.workingDirectory;
|
|
3625
3487
|
if (!existsSync(request.workingDirectory)) {
|
|
3626
3488
|
try {
|
|
3627
|
-
|
|
3489
|
+
execFileSync("git", ["worktree", "add", "-b", branch, request.workingDirectory, "HEAD"], {
|
|
3628
3490
|
stdio: "pipe"
|
|
3629
3491
|
});
|
|
3630
3492
|
} catch {
|
|
3631
3493
|
try {
|
|
3632
|
-
|
|
3494
|
+
execFileSync("git", ["worktree", "add", request.workingDirectory, branch], {
|
|
3633
3495
|
stdio: "pipe"
|
|
3634
3496
|
});
|
|
3635
3497
|
} catch (err) {
|
|
@@ -3639,18 +3501,18 @@ var CodexProvider = class {
|
|
|
3639
3501
|
}
|
|
3640
3502
|
} else {
|
|
3641
3503
|
try {
|
|
3642
|
-
|
|
3504
|
+
execFileSync("git", ["-C", request.workingDirectory, "rev-parse", "--git-dir"], {
|
|
3643
3505
|
stdio: "pipe"
|
|
3644
3506
|
});
|
|
3645
3507
|
} catch {
|
|
3646
3508
|
try {
|
|
3647
3509
|
rmSync2(request.workingDirectory, { recursive: true, force: true });
|
|
3648
|
-
|
|
3510
|
+
execFileSync("git", ["worktree", "add", "-b", branch, request.workingDirectory, "HEAD"], {
|
|
3649
3511
|
stdio: "pipe"
|
|
3650
3512
|
});
|
|
3651
3513
|
} catch {
|
|
3652
3514
|
try {
|
|
3653
|
-
|
|
3515
|
+
execFileSync("git", ["worktree", "add", request.workingDirectory, branch], {
|
|
3654
3516
|
stdio: "pipe"
|
|
3655
3517
|
});
|
|
3656
3518
|
} catch (err) {
|
|
@@ -3670,6 +3532,12 @@ var CodexProvider = class {
|
|
|
3670
3532
|
const child = spawn2(cmd, resolvedArgs, {
|
|
3671
3533
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3672
3534
|
env: { ...process.env, ...env },
|
|
3535
|
+
// Run the agent process *inside* its worktree, not the orchestrator's
|
|
3536
|
+
// launch dir. Codex's `-C` arg alone is not enough: without an explicit
|
|
3537
|
+
// cwd the process inherits the orchestrator's cwd (the main checkout),
|
|
3538
|
+
// and any shell command that resolves to process.cwd rather than `-C`
|
|
3539
|
+
// corrupts the shared repo (detached HEAD, stray writes).
|
|
3540
|
+
...request.workingDirectory ? { cwd: request.workingDirectory } : {},
|
|
3673
3541
|
...prefixArgs.length > 0 ? {} : crossSpawnOptions()
|
|
3674
3542
|
});
|
|
3675
3543
|
const parser = new CodexJsonlParser();
|
|
@@ -3786,10 +3654,10 @@ var CodexProvider = class {
|
|
|
3786
3654
|
};
|
|
3787
3655
|
|
|
3788
3656
|
// src/providers/gemini-provider.ts
|
|
3789
|
-
import { spawn as spawn3, execFileSync as
|
|
3657
|
+
import { spawn as spawn3, execFileSync as execFileSync2 } from "child_process";
|
|
3790
3658
|
import { existsSync as existsSync2, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, rmSync as rmSync3 } from "fs";
|
|
3791
|
-
import { join as
|
|
3792
|
-
import { homedir
|
|
3659
|
+
import { join as join2, dirname } from "path";
|
|
3660
|
+
import { homedir } from "os";
|
|
3793
3661
|
import { fileURLToPath } from "url";
|
|
3794
3662
|
import { readFileSync as readFileSync2 } from "fs";
|
|
3795
3663
|
|
|
@@ -3952,13 +3820,13 @@ function resolveHookScriptPath() {
|
|
|
3952
3820
|
try {
|
|
3953
3821
|
const thisDir = dirname(fileURLToPath(import.meta.url));
|
|
3954
3822
|
const candidates = [
|
|
3955
|
-
|
|
3823
|
+
join2(thisDir, "lib", "gemini-hooks.mjs"),
|
|
3956
3824
|
// dist/lib/ (flat bundle)
|
|
3957
|
-
|
|
3825
|
+
join2(thisDir, "..", "lib", "gemini-hooks.mjs"),
|
|
3958
3826
|
// dist/../lib/ (nested)
|
|
3959
|
-
|
|
3827
|
+
join2(thisDir, "..", "src", "lib", "gemini-hooks.mjs"),
|
|
3960
3828
|
// source from dist/
|
|
3961
|
-
|
|
3829
|
+
join2(thisDir, "..", "..", "src", "lib", "gemini-hooks.mjs")
|
|
3962
3830
|
// source from dist/providers/
|
|
3963
3831
|
];
|
|
3964
3832
|
for (const p of candidates) {
|
|
@@ -3998,12 +3866,12 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
3998
3866
|
if (request.workingDirectory) {
|
|
3999
3867
|
if (!existsSync2(request.workingDirectory)) {
|
|
4000
3868
|
try {
|
|
4001
|
-
|
|
3869
|
+
execFileSync2("git", ["worktree", "add", "-b", request.workingDirectory, request.workingDirectory, "HEAD"], {
|
|
4002
3870
|
stdio: "pipe"
|
|
4003
3871
|
});
|
|
4004
3872
|
} catch {
|
|
4005
3873
|
try {
|
|
4006
|
-
|
|
3874
|
+
execFileSync2("git", ["worktree", "add", request.workingDirectory, request.workingDirectory], {
|
|
4007
3875
|
stdio: "pipe"
|
|
4008
3876
|
});
|
|
4009
3877
|
} catch {
|
|
@@ -4012,18 +3880,18 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
4012
3880
|
}
|
|
4013
3881
|
} else {
|
|
4014
3882
|
try {
|
|
4015
|
-
|
|
3883
|
+
execFileSync2("git", ["-C", request.workingDirectory, "rev-parse", "--git-dir"], {
|
|
4016
3884
|
stdio: "pipe"
|
|
4017
3885
|
});
|
|
4018
3886
|
} catch {
|
|
4019
3887
|
try {
|
|
4020
3888
|
rmSync3(request.workingDirectory, { recursive: true, force: true });
|
|
4021
|
-
|
|
3889
|
+
execFileSync2("git", ["worktree", "add", "-b", request.workingDirectory, request.workingDirectory, "HEAD"], {
|
|
4022
3890
|
stdio: "pipe"
|
|
4023
3891
|
});
|
|
4024
3892
|
} catch {
|
|
4025
3893
|
try {
|
|
4026
|
-
|
|
3894
|
+
execFileSync2("git", ["worktree", "add", request.workingDirectory, request.workingDirectory], {
|
|
4027
3895
|
stdio: "pipe"
|
|
4028
3896
|
});
|
|
4029
3897
|
} catch {
|
|
@@ -4152,9 +4020,9 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
4152
4020
|
}
|
|
4153
4021
|
writeGeminiSettings(request, degraded) {
|
|
4154
4022
|
try {
|
|
4155
|
-
const baseDir =
|
|
4156
|
-
const dir =
|
|
4157
|
-
const geminiDir =
|
|
4023
|
+
const baseDir = join2(homedir(), ".kantban", "pipelines", "gemini-tmp");
|
|
4024
|
+
const dir = join2(baseDir, `session-${Date.now()}`);
|
|
4025
|
+
const geminiDir = join2(dir, ".gemini");
|
|
4158
4026
|
mkdirSync2(geminiDir, { recursive: true, mode: 448 });
|
|
4159
4027
|
const settings = {};
|
|
4160
4028
|
if (request.mcpConfig && Object.keys(request.mcpConfig.servers).length > 0) {
|
|
@@ -4178,20 +4046,20 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
4178
4046
|
hookConfig.disallowedTools = tr.disallowedTools ? translateToolNames(tr.disallowedTools) : null;
|
|
4179
4047
|
if (tr.tools !== void 0) hookConfig.builtinToolsMode = tr.tools;
|
|
4180
4048
|
const ext = IS_WINDOWS ? ".cmd" : ".sh";
|
|
4181
|
-
const wrapperPath =
|
|
4182
|
-
writeFileSync3(wrapperPath, this.generateHookWrapper(hookPath, "BeforeToolSelection",
|
|
4049
|
+
const wrapperPath = join2(dir, `.kantban-hook-before-tool${ext}`);
|
|
4050
|
+
writeFileSync3(wrapperPath, this.generateHookWrapper(hookPath, "BeforeToolSelection", join2(dir, ".kantban-hook-config.json")), { mode: 493 });
|
|
4183
4051
|
hooks.BeforeToolSelection = [{ matcher: "*", hooks: [{ type: "command", command: wrapperPath, timeout: 3e4 }] }];
|
|
4184
4052
|
}
|
|
4185
4053
|
if (request.maxTurns && request.mcpConfig) {
|
|
4186
4054
|
hookConfig.maxTurns = request.maxTurns;
|
|
4187
|
-
hookConfig.turnFile =
|
|
4055
|
+
hookConfig.turnFile = join2(dir, ".kantban-turn-counter");
|
|
4188
4056
|
const ext = IS_WINDOWS ? ".cmd" : ".sh";
|
|
4189
|
-
const wrapperPath =
|
|
4190
|
-
writeFileSync3(wrapperPath, this.generateHookWrapper(hookPath, "AfterAgent",
|
|
4057
|
+
const wrapperPath = join2(dir, `.kantban-hook-after-agent${ext}`);
|
|
4058
|
+
writeFileSync3(wrapperPath, this.generateHookWrapper(hookPath, "AfterAgent", join2(dir, ".kantban-hook-config.json")), { mode: 493 });
|
|
4191
4059
|
hooks.AfterAgent = [{ matcher: "*", hooks: [{ type: "command", command: wrapperPath, timeout: 3e4 }] }];
|
|
4192
4060
|
}
|
|
4193
4061
|
if (Object.keys(hookConfig).length > 0) {
|
|
4194
|
-
writeFileSync3(
|
|
4062
|
+
writeFileSync3(join2(dir, ".kantban-hook-config.json"), JSON.stringify(hookConfig), { mode: 384 });
|
|
4195
4063
|
}
|
|
4196
4064
|
if (Object.keys(hooks).length > 0) {
|
|
4197
4065
|
settings.hooks = hooks;
|
|
@@ -4204,7 +4072,7 @@ var GeminiProvider = class _GeminiProvider {
|
|
|
4204
4072
|
process.stderr.write(`[gemini] Hook script not found \u2014 tool scoping and turn limits unavailable
|
|
4205
4073
|
`);
|
|
4206
4074
|
}
|
|
4207
|
-
writeFileSync3(
|
|
4075
|
+
writeFileSync3(join2(geminiDir, "settings.json"), JSON.stringify(settings, null, 2), { mode: 384 });
|
|
4208
4076
|
return dir;
|
|
4209
4077
|
} catch (err) {
|
|
4210
4078
|
process.stderr.write(`[gemini] Failed to write settings.json: ${err}
|
|
@@ -4270,11 +4138,11 @@ node "${hookScript}" "${event}" "${configFile}" < "$STDIN_FILE"
|
|
|
4270
4138
|
}
|
|
4271
4139
|
copySettingsToDir(settingsDir, targetDir) {
|
|
4272
4140
|
try {
|
|
4273
|
-
const sourceFile =
|
|
4274
|
-
const targetGeminiDir =
|
|
4141
|
+
const sourceFile = join2(settingsDir, ".gemini", "settings.json");
|
|
4142
|
+
const targetGeminiDir = join2(targetDir, ".gemini");
|
|
4275
4143
|
mkdirSync2(targetGeminiDir, { recursive: true, mode: 448 });
|
|
4276
4144
|
const content = readFileSync2(sourceFile, "utf-8");
|
|
4277
|
-
writeFileSync3(
|
|
4145
|
+
writeFileSync3(join2(targetGeminiDir, "settings.json"), content, { mode: 384 });
|
|
4278
4146
|
} catch {
|
|
4279
4147
|
}
|
|
4280
4148
|
}
|
|
@@ -4414,10 +4282,10 @@ Flags:
|
|
|
4414
4282
|
return { boardId, once, dryRun, columnFilter, maxIterations, maxBudget, model, provider, concurrency, logRetention, yes };
|
|
4415
4283
|
}
|
|
4416
4284
|
function pidDir(boardId) {
|
|
4417
|
-
return
|
|
4285
|
+
return join3(homedir2(), ".kantban", "pipelines", boardId);
|
|
4418
4286
|
}
|
|
4419
4287
|
function pidFilePath(boardId) {
|
|
4420
|
-
return
|
|
4288
|
+
return join3(pidDir(boardId), "orchestrator.pid");
|
|
4421
4289
|
}
|
|
4422
4290
|
function writePidFile(boardId) {
|
|
4423
4291
|
const dir = pidDir(boardId);
|
|
@@ -4431,7 +4299,7 @@ function removePidFile(boardId) {
|
|
|
4431
4299
|
}
|
|
4432
4300
|
}
|
|
4433
4301
|
function childManifestPath(boardId) {
|
|
4434
|
-
return
|
|
4302
|
+
return join3(pidDir(boardId), "children.pid");
|
|
4435
4303
|
}
|
|
4436
4304
|
function readChildManifest(boardId) {
|
|
4437
4305
|
try {
|
|
@@ -4476,7 +4344,7 @@ function cleanupOrphanedProcesses(boardId) {
|
|
|
4476
4344
|
console.log(`Killed ${String(manifestPids.length)} orphaned child process(es) from manifest`);
|
|
4477
4345
|
removeChildManifest(boardId);
|
|
4478
4346
|
}
|
|
4479
|
-
const staleReaperPath =
|
|
4347
|
+
const staleReaperPath = join3(pidDir(boardId), "reaper.pid");
|
|
4480
4348
|
try {
|
|
4481
4349
|
if (existsSync3(staleReaperPath)) {
|
|
4482
4350
|
const reaperPid = parseInt(readFileSync3(staleReaperPath, "utf-8").trim(), 10);
|
|
@@ -4535,7 +4403,7 @@ async function runPipeline(client, args) {
|
|
|
4535
4403
|
return;
|
|
4536
4404
|
}
|
|
4537
4405
|
}
|
|
4538
|
-
const gateFilePath =
|
|
4406
|
+
const gateFilePath = join3(process.cwd(), "pipeline.gates.yaml");
|
|
4539
4407
|
let gateConfig;
|
|
4540
4408
|
if (!existsSync3(gateFilePath)) {
|
|
4541
4409
|
console.error(`Error: pipeline.gates.yaml not found in ${process.cwd()}`);
|
|
@@ -4572,7 +4440,7 @@ async function runPipeline(client, args) {
|
|
|
4572
4440
|
...opts.provider ? { intelligence_provider: opts.provider } : {}
|
|
4573
4441
|
};
|
|
4574
4442
|
const intelligenceProvider = registry.resolveForIntelligence(boardProviderConfig);
|
|
4575
|
-
const logBaseDir =
|
|
4443
|
+
const logBaseDir = join3(homedir2(), ".kantban", "pipelines");
|
|
4576
4444
|
const logger = new PipelineLogger(logBaseDir, opts.boardId);
|
|
4577
4445
|
logger.pruneOldLogs(opts.logRetention);
|
|
4578
4446
|
let runMemory = null;
|
|
@@ -4636,7 +4504,21 @@ async function runPipeline(client, args) {
|
|
|
4636
4504
|
effectiveConfig.model = registry.resolveModel(columnProvider, effectiveConfig.model);
|
|
4637
4505
|
}
|
|
4638
4506
|
const { gates: columnGates } = resolveGatesForColumn(gateConfig, resolvedColumnName);
|
|
4639
|
-
const gateCwd = effectiveConfig.worktreePath ?? (effectiveConfig.worktreeName ?
|
|
4507
|
+
const gateCwd = effectiveConfig.worktreePath ?? (effectiveConfig.worktreeName ? join3(process.cwd(), effectiveConfig.worktreeName) : process.cwd());
|
|
4508
|
+
if (effectiveConfig.worktreePath || effectiveConfig.worktreeName) {
|
|
4509
|
+
const primaryRepoRoot = await getPrimaryRepoRoot();
|
|
4510
|
+
const resolvedGate = resolve(gateCwd);
|
|
4511
|
+
const insideRepo = resolvedGate === primaryRepoRoot || resolvedGate.startsWith(primaryRepoRoot + sep) || primaryRepoRoot.startsWith(resolvedGate + sep);
|
|
4512
|
+
if (insideRepo) {
|
|
4513
|
+
const errMsg = `[fatal] dispatch refused: gate cwd "${resolvedGate}" is inside the primary repo "${primaryRepoRoot}" \u2014 refusing to run gates against the shared checkout. Fix agent_config.worktree.path_pattern.`;
|
|
4514
|
+
logger.orchestrator(errMsg);
|
|
4515
|
+
await deps.createComment(
|
|
4516
|
+
ticketId,
|
|
4517
|
+
`[dispatch] failed: gate cwd would be the primary repo ("${resolvedGate}"). Fix worktree.path_pattern; the orchestrator will retry.`
|
|
4518
|
+
);
|
|
4519
|
+
return { reason: "error", iterations: 0, gutterCount: 0, lastError: errMsg };
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4640
4522
|
const effectiveMcpConfigPath = columnGates.length > 0 ? generateGateProxyMcpConfig(
|
|
4641
4523
|
client.baseUrl,
|
|
4642
4524
|
client.token,
|
|
@@ -5145,7 +5027,7 @@ Received ${signal}. Shutting down gracefully...`);
|
|
|
5145
5027
|
cleanupOrphanedProcesses(opts.boardId);
|
|
5146
5028
|
writePidFile(opts.boardId);
|
|
5147
5029
|
logger.orchestrator(`PID file written: ${String(process.pid)}`);
|
|
5148
|
-
const reaperPidPath =
|
|
5030
|
+
const reaperPidPath = join3(pidDir(opts.boardId), "reaper.pid");
|
|
5149
5031
|
const reaperProcess = spawnReaper({
|
|
5150
5032
|
orchestratorPid: process.pid,
|
|
5151
5033
|
manifestPath: childManifestPath(opts.boardId),
|
|
@@ -5335,4 +5217,4 @@ export {
|
|
|
5335
5217
|
runPipeline,
|
|
5336
5218
|
stopPipeline
|
|
5337
5219
|
};
|
|
5338
|
-
//# sourceMappingURL=pipeline-
|
|
5220
|
+
//# sourceMappingURL=pipeline-KKUWLU3L.js.map
|