@bicorne/task-flow 0.1.0
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/LICENSE +21 -0
- package/README.md +252 -0
- package/SKILL.md +250 -0
- package/assets/.harnessrc +10 -0
- package/assets/PHASE-task.json.example +50 -0
- package/assets/design.md +69 -0
- package/assets/hooks.json +15 -0
- package/assets/product-requirement.md +82 -0
- package/assets/schema.json +127 -0
- package/assets/tasks.md +26 -0
- package/dist/commands/analyze.d.ts +32 -0
- package/dist/commands/analyze.js +338 -0
- package/dist/commands/archive.d.ts +11 -0
- package/dist/commands/archive.js +53 -0
- package/dist/commands/design.d.ts +38 -0
- package/dist/commands/design.js +492 -0
- package/dist/commands/extract.d.ts +31 -0
- package/dist/commands/extract.js +477 -0
- package/dist/commands/init.d.ts +24 -0
- package/dist/commands/init.js +165 -0
- package/dist/commands/merge/index.d.ts +17 -0
- package/dist/commands/merge/index.js +322 -0
- package/dist/commands/merge/merger.d.ts +18 -0
- package/dist/commands/merge/merger.js +151 -0
- package/dist/commands/merge/types.d.ts +67 -0
- package/dist/commands/merge/types.js +6 -0
- package/dist/commands/merge/validators.d.ts +14 -0
- package/dist/commands/merge/validators.js +147 -0
- package/dist/commands/merge.d.ts +7 -0
- package/dist/commands/merge.js +15 -0
- package/dist/commands/start.d.ts +32 -0
- package/dist/commands/start.js +265 -0
- package/dist/commands/status.d.ts +15 -0
- package/dist/commands/status.js +143 -0
- package/dist/commands/sync.d.ts +11 -0
- package/dist/commands/sync.js +58 -0
- package/dist/commands/tasks-gen/doc-parser.d.ts +7 -0
- package/dist/commands/tasks-gen/doc-parser.js +259 -0
- package/dist/commands/tasks-gen/generators.d.ts +33 -0
- package/dist/commands/tasks-gen/generators.js +141 -0
- package/dist/commands/tasks-gen/index.d.ts +30 -0
- package/dist/commands/tasks-gen/index.js +345 -0
- package/dist/commands/tasks-gen/parsers.d.ts +29 -0
- package/dist/commands/tasks-gen/parsers.js +272 -0
- package/dist/commands/tasks-gen/templates.d.ts +8 -0
- package/dist/commands/tasks-gen/templates.js +37 -0
- package/dist/commands/tasks-gen/types.d.ts +71 -0
- package/dist/commands/tasks-gen/types.js +17 -0
- package/dist/commands/tasks-gen/validators.d.ts +14 -0
- package/dist/commands/tasks-gen/validators.js +54 -0
- package/dist/commands/tasks.d.ts +9 -0
- package/dist/commands/tasks.js +22 -0
- package/dist/commands/worktree.d.ts +28 -0
- package/dist/commands/worktree.js +275 -0
- package/dist/hooks/check-prd-exists.d.ts +20 -0
- package/dist/hooks/check-prd-exists.js +61 -0
- package/dist/hooks/check-worktree-conflict.d.ts +34 -0
- package/dist/hooks/check-worktree-conflict.js +107 -0
- package/dist/hooks/hook-runner/executor.d.ts +18 -0
- package/dist/hooks/hook-runner/executor.js +143 -0
- package/dist/hooks/hook-runner/index.d.ts +64 -0
- package/dist/hooks/hook-runner/index.js +220 -0
- package/dist/hooks/hook-runner/loader.d.ts +23 -0
- package/dist/hooks/hook-runner/loader.js +126 -0
- package/dist/hooks/hook-runner/types.d.ts +59 -0
- package/dist/hooks/hook-runner/types.js +6 -0
- package/dist/hooks/hook-runner.d.ts +9 -0
- package/dist/hooks/hook-runner.js +30 -0
- package/dist/hooks/phase-complete-detector.d.ts +35 -0
- package/dist/hooks/phase-complete-detector.js +203 -0
- package/dist/hooks/phase-gate-validator.d.ts +76 -0
- package/dist/hooks/phase-gate-validator.js +407 -0
- package/dist/hooks/save-checkpoint.d.ts +43 -0
- package/dist/hooks/save-checkpoint.js +144 -0
- package/dist/hooks/start-mcp-servers.d.ts +50 -0
- package/dist/hooks/start-mcp-servers.js +75 -0
- package/dist/hooks/stop-mcp-servers.d.ts +40 -0
- package/dist/hooks/stop-mcp-servers.js +58 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +238 -0
- package/dist/lib/archive.d.ts +31 -0
- package/dist/lib/archive.js +226 -0
- package/dist/lib/config.d.ts +93 -0
- package/dist/lib/config.js +251 -0
- package/dist/lib/constants.d.ts +222 -0
- package/dist/lib/constants.js +247 -0
- package/dist/lib/interactive.d.ts +31 -0
- package/dist/lib/interactive.js +166 -0
- package/dist/lib/mcp-client.d.ts +156 -0
- package/dist/lib/mcp-client.js +370 -0
- package/dist/lib/state.d.ts +119 -0
- package/dist/lib/state.js +293 -0
- package/dist/slash/executor.d.ts +22 -0
- package/dist/slash/executor.js +259 -0
- package/dist/slash/index.d.ts +11 -0
- package/dist/slash/index.js +45 -0
- package/dist/slash/parser.d.ts +24 -0
- package/dist/slash/parser.js +101 -0
- package/dist/slash/registry.d.ts +22 -0
- package/dist/slash/registry.js +155 -0
- package/dist/spec/openspec-to-task/builders.d.ts +107 -0
- package/dist/spec/openspec-to-task/builders.js +138 -0
- package/dist/spec/openspec-to-task/index.d.ts +20 -0
- package/dist/spec/openspec-to-task/index.js +182 -0
- package/dist/spec/openspec-to-task/parsers.d.ts +65 -0
- package/dist/spec/openspec-to-task/parsers.js +232 -0
- package/dist/spec/openspec-to-task/types.d.ts +49 -0
- package/dist/spec/openspec-to-task/types.js +6 -0
- package/dist/spec/sync-openspec-to-task.d.ts +7 -0
- package/dist/spec/sync-openspec-to-task.js +21 -0
- package/dist/spec/sync-task-to-openspec.d.ts +27 -0
- package/dist/spec/sync-task-to-openspec.js +288 -0
- package/dist/types/ai-context.d.ts +108 -0
- package/dist/types/ai-context.js +9 -0
- package/package.json +66 -0
- package/references/AI-CONVERSATION-TUTORIAL.md +270 -0
- package/references/CLI-TUTORIAL.md +447 -0
- package/references/GIT-WORKTREE-SOP.md +109 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* commands/merge/index.ts
|
|
4
|
+
* Merge completed worktree back to main
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.mergeTask = mergeTask;
|
|
41
|
+
exports.main = main;
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const readline = __importStar(require("readline"));
|
|
46
|
+
const config_1 = require("../../lib/config");
|
|
47
|
+
const state_1 = require("../../lib/state");
|
|
48
|
+
const validators_1 = require("./validators");
|
|
49
|
+
const merger_1 = require("./merger");
|
|
50
|
+
/**
|
|
51
|
+
* Parse CLI arguments
|
|
52
|
+
*/
|
|
53
|
+
function parseArgs(argv) {
|
|
54
|
+
const args = {};
|
|
55
|
+
for (let i = 2; i < argv.length; i += 1) {
|
|
56
|
+
const token = argv[i] || '';
|
|
57
|
+
if (!token.startsWith('--')) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const key = token.slice(2);
|
|
61
|
+
const next = argv[i + 1] || '';
|
|
62
|
+
if (!next || next.startsWith('--')) {
|
|
63
|
+
args[key] = true;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
args[key] = next;
|
|
67
|
+
i += 1;
|
|
68
|
+
}
|
|
69
|
+
return args;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Extract merge setting from task file
|
|
73
|
+
*/
|
|
74
|
+
function extractTaskMergeSetting(file, key) {
|
|
75
|
+
try {
|
|
76
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
77
|
+
const lines = content.split('\n');
|
|
78
|
+
let inMergeStrategy = false;
|
|
79
|
+
for (const line of lines) {
|
|
80
|
+
if (/^mergeStrategy:/.test(line)) {
|
|
81
|
+
inMergeStrategy = true;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (inMergeStrategy) {
|
|
85
|
+
if (/^[^\s]/.test(line)) {
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
const match = line.match(new RegExp(`^\\s+${key}:\\s*(.+)$`));
|
|
89
|
+
if (match) {
|
|
90
|
+
return match?.[1]?.trim() || null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// ignore
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get merge configuration from task file
|
|
102
|
+
*/
|
|
103
|
+
function getMergeConfig(taskPath, options) {
|
|
104
|
+
const mergeType = extractTaskMergeSetting(taskPath, 'type') || 'squash';
|
|
105
|
+
let deleteBranch = extractTaskMergeSetting(taskPath, 'deleteBranch') !== 'false';
|
|
106
|
+
let deleteWorktree = extractTaskMergeSetting(taskPath, 'deleteWorktree') !== 'false';
|
|
107
|
+
if (options.deleteBranch === true) {
|
|
108
|
+
deleteBranch = true;
|
|
109
|
+
}
|
|
110
|
+
if (options.deleteWorktree === true) {
|
|
111
|
+
deleteWorktree = true;
|
|
112
|
+
}
|
|
113
|
+
return { mergeType, deleteBranch, deleteWorktree };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Print merge summary
|
|
117
|
+
*/
|
|
118
|
+
function printMergeSummary(params) {
|
|
119
|
+
console.log('');
|
|
120
|
+
console.log('╔════════════════════════════════════════════════════════╗');
|
|
121
|
+
console.log('║ Task Flow Merge Summary ║');
|
|
122
|
+
console.log('╚════════════════════════════════════════════════════════╝');
|
|
123
|
+
console.log('');
|
|
124
|
+
console.log(`Task ID: ${params.taskId}`);
|
|
125
|
+
console.log(`Branch: ${params.branch}`);
|
|
126
|
+
console.log(`Worktree: ${params.worktreeName}`);
|
|
127
|
+
console.log(`Merge Type: ${params.mergeType}`);
|
|
128
|
+
console.log(`Delete Branch: ${params.deleteBranch}`);
|
|
129
|
+
console.log(`Delete Worktree: ${params.deleteWorktree}`);
|
|
130
|
+
console.log(`Dry Run: ${params.dryRun || false}`);
|
|
131
|
+
console.log('');
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Update task state after merge
|
|
135
|
+
*/
|
|
136
|
+
function updateTaskStateAfterMerge(config, taskId) {
|
|
137
|
+
(0, state_1.clearCurrentTask)(config);
|
|
138
|
+
(0, state_1.addTaskToHistory)({
|
|
139
|
+
taskId,
|
|
140
|
+
status: 'completed',
|
|
141
|
+
completedAt: new Date().toISOString(),
|
|
142
|
+
}, config);
|
|
143
|
+
const archiveScript = path.resolve(__dirname, '../../lib/archive.js');
|
|
144
|
+
(0, child_process_1.spawnSync)(process.execPath, [
|
|
145
|
+
archiveScript,
|
|
146
|
+
'--cwd', config.projectRoot,
|
|
147
|
+
'--task-id', taskId,
|
|
148
|
+
'--event', 'task_merged',
|
|
149
|
+
'--status', 'completed',
|
|
150
|
+
'--phase', 'merge',
|
|
151
|
+
'--phase-completed', 'review',
|
|
152
|
+
'--review-conclusion', 'PASS',
|
|
153
|
+
'--completed-at', new Date().toISOString(),
|
|
154
|
+
], { stdio: 'inherit' });
|
|
155
|
+
const syncScript = path.resolve(__dirname, '../../spec/sync-task-to-openspec.js');
|
|
156
|
+
(0, child_process_1.spawnSync)(process.execPath, [
|
|
157
|
+
syncScript,
|
|
158
|
+
'--cwd', config.projectRoot,
|
|
159
|
+
'--task-id', taskId,
|
|
160
|
+
], { stdio: 'inherit' });
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Execute merge operation
|
|
164
|
+
*/
|
|
165
|
+
async function executeMerge(config, taskId, branch, worktree, mergeType, deleteBranch, deleteWorktree, dryRun) {
|
|
166
|
+
console.log('[MERGE] Pulling latest changes...');
|
|
167
|
+
try {
|
|
168
|
+
const pullResult = (0, child_process_1.spawnSync)('git', ['pull', 'origin', 'main'], { stdio: 'inherit' });
|
|
169
|
+
if (pullResult.status !== 0) {
|
|
170
|
+
console.warn('[MERGE] Pull failed, continuing anyway...');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
console.warn('[MERGE] Pull failed, continuing anyway...');
|
|
175
|
+
}
|
|
176
|
+
console.log(`[MERGE] Merging branch: ${branch}`);
|
|
177
|
+
if (!(0, merger_1.performMerge)(branch, mergeType, dryRun)) {
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
reason: 'merge-failed',
|
|
181
|
+
message: 'Merge failed',
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
(0, merger_1.cleanupWorktreeAndBranch)(config, worktree, branch, deleteWorktree, deleteBranch);
|
|
185
|
+
updateTaskStateAfterMerge(config, taskId);
|
|
186
|
+
return {
|
|
187
|
+
success: true,
|
|
188
|
+
taskId,
|
|
189
|
+
branch,
|
|
190
|
+
worktreeName: worktree.name,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Merge task
|
|
195
|
+
*/
|
|
196
|
+
function mergeTask(options = {}) {
|
|
197
|
+
const config = (0, config_1.loadConfig)({ cwd: options.cwd });
|
|
198
|
+
const state = (0, state_1.loadState)(config);
|
|
199
|
+
const taskId = options.taskId || state.currentTask;
|
|
200
|
+
if (!taskId) {
|
|
201
|
+
return {
|
|
202
|
+
success: false,
|
|
203
|
+
reason: 'missing-task-id',
|
|
204
|
+
message: 'No current task in state.json. Please specify task-id.',
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
const taskPath = path.resolve(config.tasksDirAbs, `${taskId}.json`);
|
|
208
|
+
if (!fs.existsSync(taskPath)) {
|
|
209
|
+
return {
|
|
210
|
+
success: false,
|
|
211
|
+
reason: 'missing-task-file',
|
|
212
|
+
message: `Task file not found: ${taskPath}`,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const mergeConfig = getMergeConfig(taskPath, options);
|
|
216
|
+
const reviewPath = path.resolve(config.reportsDirAbs, `${taskId}-review.md`);
|
|
217
|
+
const reviewValidation = (0, validators_1.validateReview)(reviewPath, options.skipReviewCheck);
|
|
218
|
+
if (!reviewValidation.valid) {
|
|
219
|
+
return {
|
|
220
|
+
success: false,
|
|
221
|
+
reason: reviewValidation.reason,
|
|
222
|
+
message: reviewValidation.message,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
const worktreeValidation = (0, validators_1.validateWorktreeAndBranch)(state, taskId);
|
|
226
|
+
if (!worktreeValidation.valid) {
|
|
227
|
+
return {
|
|
228
|
+
success: false,
|
|
229
|
+
reason: worktreeValidation.reason,
|
|
230
|
+
message: worktreeValidation.message,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const { worktree, branch } = worktreeValidation;
|
|
234
|
+
printMergeSummary({
|
|
235
|
+
taskId,
|
|
236
|
+
branch: branch,
|
|
237
|
+
worktreeName: worktree.name,
|
|
238
|
+
mergeType: mergeConfig.mergeType,
|
|
239
|
+
deleteBranch: mergeConfig.deleteBranch,
|
|
240
|
+
deleteWorktree: mergeConfig.deleteWorktree,
|
|
241
|
+
dryRun: options.dryRun,
|
|
242
|
+
});
|
|
243
|
+
if (!options.dryRun) {
|
|
244
|
+
const rl = readline.createInterface({
|
|
245
|
+
input: process.stdin,
|
|
246
|
+
output: process.stdout,
|
|
247
|
+
});
|
|
248
|
+
return new Promise((resolve) => {
|
|
249
|
+
rl.question('Proceed with merge? (y/N) ', (answer) => {
|
|
250
|
+
rl.close();
|
|
251
|
+
if (!/^[Yy]$/.test(answer)) {
|
|
252
|
+
resolve({
|
|
253
|
+
success: false,
|
|
254
|
+
reason: 'cancelled',
|
|
255
|
+
message: 'Merge cancelled',
|
|
256
|
+
});
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
executeMerge(config, taskId, branch, worktree, mergeConfig.mergeType, mergeConfig.deleteBranch, mergeConfig.deleteWorktree, options.dryRun).then(resolve);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
success: true,
|
|
265
|
+
taskId,
|
|
266
|
+
branch,
|
|
267
|
+
worktreeName: worktree.name,
|
|
268
|
+
dryRun: true,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Main entry point
|
|
273
|
+
*/
|
|
274
|
+
function main() {
|
|
275
|
+
const args = parseArgs(process.argv);
|
|
276
|
+
const positionalArgs = Array.isArray(args._) ? args._ : [];
|
|
277
|
+
const result = mergeTask({
|
|
278
|
+
cwd: args.cwd,
|
|
279
|
+
taskId: positionalArgs[0] || args['task-id'],
|
|
280
|
+
skipReviewCheck: args['skip-review-check'] === true,
|
|
281
|
+
deleteBranch: args['no-delete-branch'] !== true,
|
|
282
|
+
deleteWorktree: args['no-delete-worktree'] !== true,
|
|
283
|
+
dryRun: args['dry-run'] === true,
|
|
284
|
+
});
|
|
285
|
+
if (result instanceof Promise) {
|
|
286
|
+
result.then((res) => {
|
|
287
|
+
if (!res.success) {
|
|
288
|
+
console.error(`[MERGE] ${res.message}`);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
console.log('');
|
|
292
|
+
console.log('[MERGE] Merge completed successfully!');
|
|
293
|
+
console.log(` Task: ${res.taskId}`);
|
|
294
|
+
console.log(` Status: completed`);
|
|
295
|
+
console.log('');
|
|
296
|
+
process.exit(0);
|
|
297
|
+
}).catch((error) => {
|
|
298
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
299
|
+
console.error('[MERGE] Error:', errorMessage);
|
|
300
|
+
process.exit(1);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
if (!result.success) {
|
|
305
|
+
console.error(`[MERGE] ${result.message}`);
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
308
|
+
if (result.dryRun) {
|
|
309
|
+
console.log('[MERGE] Dry run completed. No changes made.');
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
console.log('[MERGE] Merge completed successfully!');
|
|
313
|
+
}
|
|
314
|
+
process.exit(0);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (require.main === module) {
|
|
318
|
+
main();
|
|
319
|
+
}
|
|
320
|
+
exports.default = {
|
|
321
|
+
mergeTask,
|
|
322
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commands/merge/merger.ts
|
|
3
|
+
* Merge execution utilities
|
|
4
|
+
*/
|
|
5
|
+
import { Config } from '../../lib/config';
|
|
6
|
+
import { WorktreeInfo } from '../../lib/state';
|
|
7
|
+
/**
|
|
8
|
+
* Handle merge conflicts
|
|
9
|
+
*/
|
|
10
|
+
export declare function handleMergeConflict(): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Perform the actual merge
|
|
13
|
+
*/
|
|
14
|
+
export declare function performMerge(branch: string, mergeType: string, dryRun?: boolean): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Cleanup worktree and branch
|
|
17
|
+
*/
|
|
18
|
+
export declare function cleanupWorktreeAndBranch(config: Config, worktree: WorktreeInfo, branch: string, deleteWorktree: boolean, deleteBranch: boolean): void;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* commands/merge/merger.ts
|
|
4
|
+
* Merge execution utilities
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.handleMergeConflict = handleMergeConflict;
|
|
41
|
+
exports.performMerge = performMerge;
|
|
42
|
+
exports.cleanupWorktreeAndBranch = cleanupWorktreeAndBranch;
|
|
43
|
+
const child_process_1 = require("child_process");
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
/**
|
|
47
|
+
* Handle merge conflicts
|
|
48
|
+
*/
|
|
49
|
+
function handleMergeConflict() {
|
|
50
|
+
try {
|
|
51
|
+
const conflicted = (0, child_process_1.execSync)('git diff --name-only --diff-filter=U', { encoding: 'utf8' });
|
|
52
|
+
if (conflicted.trim()) {
|
|
53
|
+
console.error('[MERGE] Merge conflicts detected:');
|
|
54
|
+
console.error(conflicted);
|
|
55
|
+
(0, child_process_1.execSync)('git merge --abort 2>/dev/null || git reset --merge 2>/dev/null || true');
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// no conflicts
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Perform the actual merge
|
|
66
|
+
*/
|
|
67
|
+
function performMerge(branch, mergeType, dryRun) {
|
|
68
|
+
if (dryRun) {
|
|
69
|
+
console.log(`[DRY-RUN] Would merge ${branch} using ${mergeType}`);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
if (mergeType === 'squash') {
|
|
74
|
+
const squashResult = (0, child_process_1.spawnSync)('git', ['merge', '--squash', branch], { stdio: 'inherit' });
|
|
75
|
+
if (squashResult.status !== 0) {
|
|
76
|
+
console.error('[MERGE] Squash merge failed');
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
if (handleMergeConflict()) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const commitResult = (0, child_process_1.spawnSync)('git', ['commit', '-m', `feat: merged from harness worktree ${branch}`], { stdio: 'inherit' });
|
|
84
|
+
if (commitResult.status !== 0) {
|
|
85
|
+
console.warn('[MERGE] No changes to commit');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
console.warn('[MERGE] No changes to commit');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (mergeType === 'merge') {
|
|
93
|
+
const mergeResult = (0, child_process_1.spawnSync)('git', ['merge', '--no-ff', branch, '-m', `feat: merged from harness worktree ${branch}`], { stdio: 'inherit' });
|
|
94
|
+
if (mergeResult.status !== 0) {
|
|
95
|
+
console.error('[MERGE] Merge failed');
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
if (handleMergeConflict()) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (mergeType === 'rebase') {
|
|
103
|
+
console.error('[MERGE] Rebase strategy requires worktree rebase - use manual merge for now');
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
console.error(`[MERGE] Unsupported merge strategy: ${mergeType}`);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
114
|
+
console.error('[MERGE] Merge failed:', errorMessage);
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Cleanup worktree and branch
|
|
120
|
+
*/
|
|
121
|
+
function cleanupWorktreeAndBranch(config, worktree, branch, deleteWorktree, deleteBranch) {
|
|
122
|
+
if (deleteWorktree && worktree.path) {
|
|
123
|
+
const worktreePath = path.resolve(config.projectRoot, worktree.path);
|
|
124
|
+
if (fs.existsSync(worktreePath)) {
|
|
125
|
+
console.log(`[MERGE] Removing worktree: ${worktree.name}`);
|
|
126
|
+
try {
|
|
127
|
+
const result = (0, child_process_1.spawnSync)('git', ['worktree', 'remove', worktreePath, '--force'], { stdio: 'inherit' });
|
|
128
|
+
if (result.status !== 0) {
|
|
129
|
+
console.warn('[MERGE] Failed to remove worktree');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
134
|
+
console.warn('[MERGE] Failed to remove worktree:', errorMessage);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (deleteBranch) {
|
|
139
|
+
console.log(`[MERGE] Deleting branch: ${branch}`);
|
|
140
|
+
try {
|
|
141
|
+
const result = (0, child_process_1.spawnSync)('git', ['branch', '-D', branch], { stdio: 'inherit' });
|
|
142
|
+
if (result.status !== 0) {
|
|
143
|
+
console.warn('[MERGE] Failed to delete branch');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
148
|
+
console.warn('[MERGE] Failed to delete branch:', errorMessage);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commands/merge/types.ts
|
|
3
|
+
* Type definitions for merge command
|
|
4
|
+
*/
|
|
5
|
+
import { WorktreeInfo } from '../../lib/state';
|
|
6
|
+
/**
|
|
7
|
+
* Merge command options
|
|
8
|
+
*/
|
|
9
|
+
export interface MergeOptions {
|
|
10
|
+
cwd?: string;
|
|
11
|
+
taskId?: string;
|
|
12
|
+
skipReviewCheck?: boolean;
|
|
13
|
+
deleteBranch?: boolean;
|
|
14
|
+
deleteWorktree?: boolean;
|
|
15
|
+
dryRun?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Merge command result
|
|
19
|
+
*/
|
|
20
|
+
export interface MergeResult {
|
|
21
|
+
success: boolean;
|
|
22
|
+
reason?: string;
|
|
23
|
+
message?: string;
|
|
24
|
+
taskId?: string;
|
|
25
|
+
branch?: string;
|
|
26
|
+
worktreeName?: string;
|
|
27
|
+
dryRun?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Merge configuration
|
|
31
|
+
*/
|
|
32
|
+
export interface MergeConfig {
|
|
33
|
+
mergeType: string;
|
|
34
|
+
deleteBranch: boolean;
|
|
35
|
+
deleteWorktree: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validation context for review
|
|
39
|
+
*/
|
|
40
|
+
export interface ReviewValidation {
|
|
41
|
+
valid: boolean;
|
|
42
|
+
reason?: string;
|
|
43
|
+
message?: string;
|
|
44
|
+
conclusion?: string | null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validation context for worktree and branch
|
|
48
|
+
*/
|
|
49
|
+
export interface WorktreeValidation {
|
|
50
|
+
valid: boolean;
|
|
51
|
+
reason?: string;
|
|
52
|
+
message?: string;
|
|
53
|
+
worktree?: WorktreeInfo;
|
|
54
|
+
branch?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Merge summary parameters
|
|
58
|
+
*/
|
|
59
|
+
export interface MergeSummaryParams {
|
|
60
|
+
taskId: string;
|
|
61
|
+
branch: string;
|
|
62
|
+
worktreeName: string;
|
|
63
|
+
mergeType: string;
|
|
64
|
+
deleteBranch: boolean;
|
|
65
|
+
deleteWorktree: boolean;
|
|
66
|
+
dryRun?: boolean;
|
|
67
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commands/merge/validators.ts
|
|
3
|
+
* Validation utilities for merge command
|
|
4
|
+
*/
|
|
5
|
+
import { State } from '../../lib/state';
|
|
6
|
+
import { ReviewValidation, WorktreeValidation } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Validate review report
|
|
9
|
+
*/
|
|
10
|
+
export declare function validateReview(reviewPath: string, skipReviewCheck?: boolean): ReviewValidation;
|
|
11
|
+
/**
|
|
12
|
+
* Validate worktree and branch
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateWorktreeAndBranch(state: State, taskId: string): WorktreeValidation;
|