@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,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* commands/merge/validators.ts
|
|
4
|
+
* Validation utilities for merge command
|
|
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.validateReview = validateReview;
|
|
41
|
+
exports.validateWorktreeAndBranch = validateWorktreeAndBranch;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const child_process_1 = require("child_process");
|
|
44
|
+
/**
|
|
45
|
+
* Parse review conclusion from file content
|
|
46
|
+
*/
|
|
47
|
+
function parseReviewConclusion(file) {
|
|
48
|
+
try {
|
|
49
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
50
|
+
const patterns = [
|
|
51
|
+
/^\s*(?:结论|Conclusion)\s*:\s*(PASS|NEEDS_WORK|FAIL)\s*$/m,
|
|
52
|
+
/^##\s*结论\s*:\s*(PASS|NEEDS_WORK|FAIL)\s*$/m,
|
|
53
|
+
/\*\*(PASS|NEEDS_WORK|FAIL)\*\*/,
|
|
54
|
+
];
|
|
55
|
+
for (const pattern of patterns) {
|
|
56
|
+
const match = content.match(pattern);
|
|
57
|
+
if (match) {
|
|
58
|
+
return match[1] || match[0];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// ignore
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validate review report
|
|
69
|
+
*/
|
|
70
|
+
function validateReview(reviewPath, skipReviewCheck) {
|
|
71
|
+
if (skipReviewCheck) {
|
|
72
|
+
return { valid: true };
|
|
73
|
+
}
|
|
74
|
+
if (!fs.existsSync(reviewPath)) {
|
|
75
|
+
return {
|
|
76
|
+
valid: false,
|
|
77
|
+
reason: 'missing-review',
|
|
78
|
+
message: `Review report not found: ${reviewPath}. Use --skip-review-check to override.`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const conclusion = parseReviewConclusion(reviewPath);
|
|
82
|
+
if (conclusion !== 'PASS') {
|
|
83
|
+
return {
|
|
84
|
+
valid: false,
|
|
85
|
+
reason: 'review-not-passed',
|
|
86
|
+
message: `Review conclusion is ${conclusion}, not PASS. Use --skip-review-check to override.`,
|
|
87
|
+
conclusion,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return { valid: true, conclusion };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Validate worktree and branch
|
|
94
|
+
*/
|
|
95
|
+
function validateWorktreeAndBranch(state, taskId) {
|
|
96
|
+
const worktree = (state.worktrees || []).find((wt) => wt?.task === taskId);
|
|
97
|
+
if (!worktree) {
|
|
98
|
+
return {
|
|
99
|
+
valid: false,
|
|
100
|
+
reason: 'missing-worktree',
|
|
101
|
+
message: 'Worktree info not found in state.json',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const branch = worktree.branch;
|
|
105
|
+
if (!branch) {
|
|
106
|
+
return {
|
|
107
|
+
valid: false,
|
|
108
|
+
reason: 'missing-branch-info',
|
|
109
|
+
message: 'Branch info not found in worktree state',
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const showRefResult = (0, child_process_1.spawnSync)('git', ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`], { stdio: 'ignore' });
|
|
114
|
+
if (showRefResult.status !== 0) {
|
|
115
|
+
return {
|
|
116
|
+
valid: false,
|
|
117
|
+
reason: 'missing-branch',
|
|
118
|
+
message: `Branch does not exist: ${branch}`,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return {
|
|
124
|
+
valid: false,
|
|
125
|
+
reason: 'missing-branch',
|
|
126
|
+
message: `Branch does not exist: ${branch}`,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const diffResult = (0, child_process_1.spawnSync)('git', ['diff-index', '--quiet', 'HEAD', '--'], { stdio: 'ignore' });
|
|
131
|
+
if (diffResult.status !== 0) {
|
|
132
|
+
return {
|
|
133
|
+
valid: false,
|
|
134
|
+
reason: 'dirty-worktree',
|
|
135
|
+
message: 'Main worktree has uncommitted changes',
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return {
|
|
141
|
+
valid: false,
|
|
142
|
+
reason: 'dirty-worktree',
|
|
143
|
+
message: 'Main worktree has uncommitted changes',
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return { valid: true, worktree, branch };
|
|
147
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commands/merge.ts
|
|
3
|
+
* Backward-compatible re-export from merge/ module
|
|
4
|
+
* @deprecated Import from './merge/index' directly
|
|
5
|
+
*/
|
|
6
|
+
export { mergeTask, main, default } from './merge/index';
|
|
7
|
+
export { MergeOptions, MergeResult, MergeConfig } from './merge/types';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* commands/merge.ts
|
|
4
|
+
* Backward-compatible re-export from merge/ module
|
|
5
|
+
* @deprecated Import from './merge/index' directly
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.default = exports.main = exports.mergeTask = void 0;
|
|
12
|
+
var index_1 = require("./merge/index");
|
|
13
|
+
Object.defineProperty(exports, "mergeTask", { enumerable: true, get: function () { return index_1.mergeTask; } });
|
|
14
|
+
Object.defineProperty(exports, "main", { enumerable: true, get: function () { return index_1.main; } });
|
|
15
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(index_1).default; } });
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* commands/start.ts
|
|
3
|
+
* Start a new task from Spec change
|
|
4
|
+
*/
|
|
5
|
+
export interface StartOptions {
|
|
6
|
+
cwd?: string;
|
|
7
|
+
change?: string;
|
|
8
|
+
type?: string;
|
|
9
|
+
priority?: string;
|
|
10
|
+
worktree?: string;
|
|
11
|
+
output?: string;
|
|
12
|
+
force?: boolean;
|
|
13
|
+
taskId?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface StartResult {
|
|
16
|
+
success: boolean;
|
|
17
|
+
reason?: string;
|
|
18
|
+
message?: string;
|
|
19
|
+
taskId?: string;
|
|
20
|
+
taskPath?: string;
|
|
21
|
+
worktreeName?: string;
|
|
22
|
+
branch?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Start a new task
|
|
26
|
+
*/
|
|
27
|
+
export declare function startTask(options?: StartOptions): StartResult;
|
|
28
|
+
export declare function main(): void;
|
|
29
|
+
declare const _default: {
|
|
30
|
+
startTask: typeof startTask;
|
|
31
|
+
};
|
|
32
|
+
export default _default;
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* commands/start.ts
|
|
4
|
+
* Start a new task from Spec change
|
|
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.startTask = startTask;
|
|
41
|
+
exports.main = main;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const child_process_1 = require("child_process");
|
|
45
|
+
const config_1 = require("../lib/config");
|
|
46
|
+
const state_1 = require("../lib/state");
|
|
47
|
+
const archive_1 = require("../lib/archive");
|
|
48
|
+
const sync_task_to_openspec_1 = require("../spec/sync-task-to-openspec");
|
|
49
|
+
function parseArgs(argv) {
|
|
50
|
+
const args = {};
|
|
51
|
+
for (let i = 2; i < argv.length; i += 1) {
|
|
52
|
+
const token = argv[i] || '';
|
|
53
|
+
if (!token.startsWith('--')) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const key = token.slice(2);
|
|
57
|
+
const next = argv[i + 1] || '';
|
|
58
|
+
if (!next || next.startsWith('--')) {
|
|
59
|
+
args[key] = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
args[key] = next;
|
|
63
|
+
i += 1;
|
|
64
|
+
}
|
|
65
|
+
return args;
|
|
66
|
+
}
|
|
67
|
+
function toTaskId(input) {
|
|
68
|
+
return String(input || '')
|
|
69
|
+
.trim()
|
|
70
|
+
.replace(/[^a-zA-Z0-9-_]/g, '-')
|
|
71
|
+
.replace(/-+/g, '-')
|
|
72
|
+
.replace(/^-|-$/g, '');
|
|
73
|
+
}
|
|
74
|
+
function toWorktreeName(type, taskId) {
|
|
75
|
+
return `harness-${type}-${taskId}`;
|
|
76
|
+
}
|
|
77
|
+
function getGitBranch(cwd) {
|
|
78
|
+
try {
|
|
79
|
+
return (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', { cwd, encoding: 'utf8' }).trim();
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return 'main';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function updateTaskPlanningStatus(taskPath) {
|
|
86
|
+
if (!fs.existsSync(taskPath)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const content = fs.readFileSync(taskPath, 'utf8');
|
|
90
|
+
const updated = content.replace(/(-\s*name:\s*planning\s*\n(?:[^\n]*\n)*?status:\s*)\S+/m, '$1in_progress');
|
|
91
|
+
fs.writeFileSync(taskPath, updated, 'utf8');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Start a new task
|
|
95
|
+
*/
|
|
96
|
+
function startTask(options = {}) {
|
|
97
|
+
const config = (0, config_1.loadConfig)({ cwd: options.cwd });
|
|
98
|
+
const change = String(options.change || '').trim();
|
|
99
|
+
if (!change) {
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
reason: 'missing-change',
|
|
103
|
+
message: 'Missing required argument: --change <change-name>',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const taskId = toTaskId(options.taskId || change);
|
|
107
|
+
if (!taskId) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
reason: 'invalid-task-id',
|
|
111
|
+
message: 'Invalid task id derived from change name',
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
// Ensure directories exist
|
|
115
|
+
(0, config_1.ensureDirectories)(config);
|
|
116
|
+
// Check if harness is initialized
|
|
117
|
+
const harnessRootAbs = config.harnessRootAbs;
|
|
118
|
+
if (!harnessRootAbs) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
reason: 'missing-harness-root',
|
|
122
|
+
message: 'Config missing harnessRootAbs',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const statePath = path.resolve(harnessRootAbs, 'state.json');
|
|
126
|
+
if (!fs.existsSync(statePath)) {
|
|
127
|
+
const initialState = (0, state_1.createInitialState)();
|
|
128
|
+
fs.mkdirSync(harnessRootAbs, { recursive: true });
|
|
129
|
+
try {
|
|
130
|
+
fs.writeFileSync(statePath, JSON.stringify(initialState, null, 2), 'utf8');
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
134
|
+
return {
|
|
135
|
+
success: false,
|
|
136
|
+
reason: 'file-write-error',
|
|
137
|
+
message: `Failed to initialize state: ${errorMessage}`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Run sync-spec-to-task script to generate task JSON
|
|
142
|
+
const syncScript = path.resolve(__dirname, '../spec/sync-openspec-to-task.js');
|
|
143
|
+
const syncArgs = [syncScript, '--change', change, '--task-id', taskId];
|
|
144
|
+
if (options.type) {
|
|
145
|
+
syncArgs.push('--type', String(options.type));
|
|
146
|
+
}
|
|
147
|
+
if (options.priority) {
|
|
148
|
+
syncArgs.push('--priority', String(options.priority));
|
|
149
|
+
}
|
|
150
|
+
if (options.worktree) {
|
|
151
|
+
syncArgs.push('--worktree', String(options.worktree));
|
|
152
|
+
}
|
|
153
|
+
if (options.output) {
|
|
154
|
+
syncArgs.push('--output', String(options.output));
|
|
155
|
+
}
|
|
156
|
+
if (options.force) {
|
|
157
|
+
syncArgs.push('--force');
|
|
158
|
+
}
|
|
159
|
+
const runSync = (0, child_process_1.spawnSync)(process.execPath, syncArgs, {
|
|
160
|
+
cwd: config.projectRoot,
|
|
161
|
+
stdio: 'inherit',
|
|
162
|
+
});
|
|
163
|
+
if (runSync.status !== 0) {
|
|
164
|
+
return {
|
|
165
|
+
success: false,
|
|
166
|
+
reason: 'sync-failed',
|
|
167
|
+
message: 'Failed to sync Spec to task',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// Get task file path
|
|
171
|
+
const tasksDirAbs = config.tasksDirAbs;
|
|
172
|
+
const projectRoot = config.projectRoot;
|
|
173
|
+
if (!tasksDirAbs || !projectRoot) {
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
reason: 'missing-config-paths',
|
|
177
|
+
message: 'Config missing tasksDirAbs or projectRoot',
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const taskOutputPath = path.resolve(projectRoot, String(options.output || path.relative(projectRoot, path.resolve(tasksDirAbs, `${taskId}.json`))));
|
|
181
|
+
// Update task JSON planning status
|
|
182
|
+
updateTaskPlanningStatus(taskOutputPath);
|
|
183
|
+
// Get git info
|
|
184
|
+
const now = new Date().toISOString();
|
|
185
|
+
const worktreeName = process.env.WORKTREE_NAME || toWorktreeName(options.type || 'feat', taskId);
|
|
186
|
+
const branch = getGitBranch(projectRoot);
|
|
187
|
+
// Update state
|
|
188
|
+
const state = (0, state_1.loadState)(config);
|
|
189
|
+
state.version = state.version || '1.0';
|
|
190
|
+
state.status = 'running';
|
|
191
|
+
state.currentPhase = 'planning';
|
|
192
|
+
state.currentTask = taskId;
|
|
193
|
+
state.currentSnapshot = null;
|
|
194
|
+
state.reviewConclusion = null;
|
|
195
|
+
state.phaseCompleted = null;
|
|
196
|
+
state.taskHistory = Array.isArray(state.taskHistory) ? state.taskHistory : [];
|
|
197
|
+
state.startedAt = state.startedAt || now;
|
|
198
|
+
state.updatedAt = now;
|
|
199
|
+
// Add worktree
|
|
200
|
+
const worktreeInfo = {
|
|
201
|
+
name: worktreeName,
|
|
202
|
+
path: '.',
|
|
203
|
+
branch,
|
|
204
|
+
status: 'active',
|
|
205
|
+
task: taskId,
|
|
206
|
+
startedAt: now,
|
|
207
|
+
lastActivity: now,
|
|
208
|
+
pendingChanges: [],
|
|
209
|
+
};
|
|
210
|
+
(0, state_1.upsertWorktree)(worktreeInfo, config);
|
|
211
|
+
// Save state to persist worktree info
|
|
212
|
+
(0, state_1.saveState)(state, config);
|
|
213
|
+
// Archive task state
|
|
214
|
+
(0, archive_1.archiveTaskState)({
|
|
215
|
+
cwd: projectRoot,
|
|
216
|
+
taskId,
|
|
217
|
+
eventType: 'task_started',
|
|
218
|
+
status: 'running',
|
|
219
|
+
phase: 'planning',
|
|
220
|
+
});
|
|
221
|
+
// Sync to Spec
|
|
222
|
+
(0, sync_task_to_openspec_1.syncTaskToSpec)({ cwd: projectRoot, taskId });
|
|
223
|
+
return {
|
|
224
|
+
success: true,
|
|
225
|
+
taskId,
|
|
226
|
+
taskPath: taskOutputPath,
|
|
227
|
+
worktreeName,
|
|
228
|
+
branch,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function main() {
|
|
232
|
+
const args = parseArgs(process.argv);
|
|
233
|
+
const result = startTask({
|
|
234
|
+
cwd: args.cwd,
|
|
235
|
+
change: args.change,
|
|
236
|
+
type: args.type,
|
|
237
|
+
priority: args.priority,
|
|
238
|
+
worktree: args.worktree,
|
|
239
|
+
output: args.output,
|
|
240
|
+
force: args.force === true,
|
|
241
|
+
});
|
|
242
|
+
if (!result.success) {
|
|
243
|
+
console.error(`[START] ${result.message}`);
|
|
244
|
+
process.exit(1);
|
|
245
|
+
}
|
|
246
|
+
console.log('');
|
|
247
|
+
console.log('[START] Task started successfully!');
|
|
248
|
+
console.log(` Task ID: ${result.taskId}`);
|
|
249
|
+
console.log(` Task File: ${result.taskPath}`);
|
|
250
|
+
console.log(` Worktree: ${result.worktreeName}`);
|
|
251
|
+
console.log(` Branch: ${result.branch}`);
|
|
252
|
+
console.log('');
|
|
253
|
+
console.log('Next steps:');
|
|
254
|
+
console.log(` 1. Edit product-requirement.md: spec/changes/${result.taskId}/product-requirement.md`);
|
|
255
|
+
console.log(` 2. Run: task-flow design --change ${result.taskId}`);
|
|
256
|
+
console.log(' 3. Check status: task-flow status');
|
|
257
|
+
console.log('');
|
|
258
|
+
process.exit(0);
|
|
259
|
+
}
|
|
260
|
+
if (require.main === module) {
|
|
261
|
+
main();
|
|
262
|
+
}
|
|
263
|
+
exports.default = {
|
|
264
|
+
startTask,
|
|
265
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* commands/status.ts
|
|
4
|
+
* Show current task and phase status
|
|
5
|
+
*/
|
|
6
|
+
export interface StatusOptions {
|
|
7
|
+
cwd?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function showStatus(options?: StatusOptions): void;
|
|
10
|
+
export declare function main(): void;
|
|
11
|
+
declare const _default: {
|
|
12
|
+
showStatus: typeof showStatus;
|
|
13
|
+
main: typeof main;
|
|
14
|
+
};
|
|
15
|
+
export default _default;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* commands/status.ts
|
|
5
|
+
* Show current task and phase status
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.showStatus = showStatus;
|
|
9
|
+
exports.main = main;
|
|
10
|
+
const config_1 = require("../lib/config");
|
|
11
|
+
const state_1 = require("../lib/state");
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
const args = {};
|
|
14
|
+
for (let i = 2; i < argv.length; i += 1) {
|
|
15
|
+
const token = argv[i] || '';
|
|
16
|
+
if (!token.startsWith('--')) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const key = token.slice(2);
|
|
20
|
+
const next = argv[i + 1];
|
|
21
|
+
if (!next || next.startsWith('--')) {
|
|
22
|
+
args[key] = true;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
args[key] = next;
|
|
26
|
+
i += 1;
|
|
27
|
+
}
|
|
28
|
+
return args;
|
|
29
|
+
}
|
|
30
|
+
function formatPhase(phase) {
|
|
31
|
+
if (!phase) {
|
|
32
|
+
return 'None';
|
|
33
|
+
}
|
|
34
|
+
const labels = {
|
|
35
|
+
planning: '📋 Planning',
|
|
36
|
+
implementation: '🔨 Implementation',
|
|
37
|
+
review: '🔍 Review',
|
|
38
|
+
merge: '🔀 Merge',
|
|
39
|
+
};
|
|
40
|
+
return labels[phase] || phase;
|
|
41
|
+
}
|
|
42
|
+
function formatStatus(status) {
|
|
43
|
+
const icons = {
|
|
44
|
+
initialized: '⚪',
|
|
45
|
+
running: '🟢',
|
|
46
|
+
paused: '🟡',
|
|
47
|
+
completed: '✅',
|
|
48
|
+
failed: '🔴',
|
|
49
|
+
blocked: '🚫',
|
|
50
|
+
};
|
|
51
|
+
return `${icons[status] || '⚪'} ${status}`;
|
|
52
|
+
}
|
|
53
|
+
function showStatus(options = {}) {
|
|
54
|
+
const config = (0, config_1.loadConfig)({ cwd: options.cwd });
|
|
55
|
+
const state = (0, state_1.loadState)(config);
|
|
56
|
+
console.log('');
|
|
57
|
+
console.log('╔════════════════════════════════════════════════════════╗');
|
|
58
|
+
console.log('║ Task Flow Status ║');
|
|
59
|
+
console.log('╚════════════════════════════════════════════════════════╝');
|
|
60
|
+
console.log('');
|
|
61
|
+
// Overall status
|
|
62
|
+
console.log(`Status: ${formatStatus(state.status)}`);
|
|
63
|
+
console.log('');
|
|
64
|
+
// Current task
|
|
65
|
+
if (state.currentTask) {
|
|
66
|
+
console.log(`Current Task: ${state.currentTask}`);
|
|
67
|
+
console.log(`Current Phase: ${formatPhase(state.currentPhase)}`);
|
|
68
|
+
console.log(`Phase Completed: ${formatPhase(state.phaseCompleted)}`);
|
|
69
|
+
if (state.reviewConclusion) {
|
|
70
|
+
const conclusionIcon = {
|
|
71
|
+
PASS: '✅',
|
|
72
|
+
NEEDS_WORK: '🔶',
|
|
73
|
+
FAIL: '❌',
|
|
74
|
+
};
|
|
75
|
+
console.log(`Review Conclusion: ${conclusionIcon[state.reviewConclusion] || '⚪'} ${state.reviewConclusion}`);
|
|
76
|
+
}
|
|
77
|
+
if (state.currentSnapshot) {
|
|
78
|
+
console.log(`Latest Snapshot: ${state.currentSnapshot}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.log('Current Task: None');
|
|
83
|
+
}
|
|
84
|
+
console.log('');
|
|
85
|
+
// Active worktrees
|
|
86
|
+
const activeWorktrees = (0, state_1.getActiveWorktrees)(config);
|
|
87
|
+
if (activeWorktrees.length > 0) {
|
|
88
|
+
console.log(`Worktrees (${activeWorktrees.length}):`);
|
|
89
|
+
for (const wt of activeWorktrees) {
|
|
90
|
+
console.log(` - ${wt.name}`);
|
|
91
|
+
console.log(` Branch: ${wt.branch}`);
|
|
92
|
+
console.log(` Task: ${wt.task}`);
|
|
93
|
+
console.log(` Agent: ${wt.agent}`);
|
|
94
|
+
console.log(` Last Activity: ${wt.lastActivity}`);
|
|
95
|
+
if (wt.pendingChanges && wt.pendingChanges.length > 0) {
|
|
96
|
+
console.log(` Pending Changes: ${wt.pendingChanges.join(', ')}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log('Worktrees: None');
|
|
102
|
+
}
|
|
103
|
+
console.log('');
|
|
104
|
+
// Recent task history
|
|
105
|
+
if (state.taskHistory && state.taskHistory.length > 0) {
|
|
106
|
+
console.log('Task History:');
|
|
107
|
+
const recent = state.taskHistory.slice(-5).reverse();
|
|
108
|
+
for (const task of recent) {
|
|
109
|
+
const icon = {
|
|
110
|
+
completed: '✅',
|
|
111
|
+
failed: '❌',
|
|
112
|
+
running: '🟢',
|
|
113
|
+
};
|
|
114
|
+
console.log(` ${icon[task.status] || '⚪'} ${task.taskId}: ${task.status} (${task.currentPhase || 'no phase'})`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
console.log('');
|
|
118
|
+
// Gate blocked info
|
|
119
|
+
if (state.lastGateBlockedReason) {
|
|
120
|
+
console.log('⚠️ Gate Blocked:');
|
|
121
|
+
console.log(` Phase: ${state.lastGateBlockedPhase || 'unknown'}`);
|
|
122
|
+
console.log(` Reason: ${state.lastGateBlockedReason}`);
|
|
123
|
+
if (state.lastMissingValidations && state.lastMissingValidations.length > 0) {
|
|
124
|
+
console.log(` Missing: ${state.lastMissingValidations.join(', ')}`);
|
|
125
|
+
}
|
|
126
|
+
console.log('');
|
|
127
|
+
}
|
|
128
|
+
console.log(`Started: ${state.startedAt}`);
|
|
129
|
+
console.log(`Updated: ${state.updatedAt}`);
|
|
130
|
+
console.log('');
|
|
131
|
+
}
|
|
132
|
+
function main() {
|
|
133
|
+
const args = parseArgs(process.argv);
|
|
134
|
+
showStatus({ cwd: args.cwd });
|
|
135
|
+
process.exit(0);
|
|
136
|
+
}
|
|
137
|
+
if (require.main === module) {
|
|
138
|
+
main();
|
|
139
|
+
}
|
|
140
|
+
exports.default = {
|
|
141
|
+
showStatus,
|
|
142
|
+
main,
|
|
143
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* commands/sync.ts
|
|
4
|
+
* Sync task execution status to Spec
|
|
5
|
+
*/
|
|
6
|
+
import { syncTaskToSpec } from '../spec/sync-task-to-openspec';
|
|
7
|
+
export declare function main(): void;
|
|
8
|
+
declare const _default: {
|
|
9
|
+
syncTaskToSpec: typeof syncTaskToSpec;
|
|
10
|
+
};
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* commands/sync.ts
|
|
5
|
+
* Sync task execution status to Spec
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.main = main;
|
|
9
|
+
const sync_task_to_openspec_1 = require("../spec/sync-task-to-openspec");
|
|
10
|
+
function parseArgs(argv) {
|
|
11
|
+
const args = {};
|
|
12
|
+
for (let i = 2; i < argv.length; i += 1) {
|
|
13
|
+
const token = argv[i] || '';
|
|
14
|
+
if (!token.startsWith('--')) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const key = token.slice(2);
|
|
18
|
+
const next = argv[i + 1] || '';
|
|
19
|
+
if (!next || next.startsWith('--')) {
|
|
20
|
+
args[key] = true;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
args[key] = next;
|
|
24
|
+
i += 1;
|
|
25
|
+
}
|
|
26
|
+
return args;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if result has executionPath property
|
|
30
|
+
*/
|
|
31
|
+
function hasExecutionPath(result) {
|
|
32
|
+
return !result.skipped && 'executionPath' in result;
|
|
33
|
+
}
|
|
34
|
+
function main() {
|
|
35
|
+
const args = parseArgs(process.argv);
|
|
36
|
+
const result = (0, sync_task_to_openspec_1.syncTaskToSpec)({
|
|
37
|
+
cwd: args.cwd,
|
|
38
|
+
taskId: args['task-id'],
|
|
39
|
+
});
|
|
40
|
+
if (result.skipped) {
|
|
41
|
+
console.log(`[SYNC] skipped: ${result.reason}`);
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
// Type-safe access to executionPath
|
|
45
|
+
if (hasExecutionPath(result)) {
|
|
46
|
+
console.log(`[SYNC] updated: ${result.executionPath}`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
console.log('[SYNC] task synced but no execution path available');
|
|
50
|
+
}
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
if (require.main === module) {
|
|
54
|
+
main();
|
|
55
|
+
}
|
|
56
|
+
exports.default = {
|
|
57
|
+
syncTaskToSpec: sync_task_to_openspec_1.syncTaskToSpec,
|
|
58
|
+
};
|