@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,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* slash/parser.ts
|
|
4
|
+
* Parse slash command strings like /tf:propose or /taskflow:apply
|
|
5
|
+
*
|
|
6
|
+
* Format: /<namespace>:<command> [args...]
|
|
7
|
+
* Examples:
|
|
8
|
+
* /tf:propose add-dark-mode
|
|
9
|
+
* /taskflow:apply
|
|
10
|
+
* /tf:archive --task-id my-feature
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.VALID_NAMESPACES = exports.DEFAULT_NAMESPACE = void 0;
|
|
14
|
+
exports.parseSlashCommand = parseSlashCommand;
|
|
15
|
+
exports.isSlashCommand = isSlashCommand;
|
|
16
|
+
exports.formatSlashCommand = formatSlashCommand;
|
|
17
|
+
const DEFAULT_NAMESPACE = 'tf';
|
|
18
|
+
exports.DEFAULT_NAMESPACE = DEFAULT_NAMESPACE;
|
|
19
|
+
const VALID_NAMESPACES = ['tf', 'taskflow'];
|
|
20
|
+
exports.VALID_NAMESPACES = VALID_NAMESPACES;
|
|
21
|
+
function isValidNamespace(ns) {
|
|
22
|
+
return VALID_NAMESPACES.includes(ns);
|
|
23
|
+
}
|
|
24
|
+
function parseSlashCommand(input) {
|
|
25
|
+
const trimmed = input.trim();
|
|
26
|
+
if (!trimmed.startsWith('/')) {
|
|
27
|
+
return {
|
|
28
|
+
valid: false,
|
|
29
|
+
namespace: '',
|
|
30
|
+
command: '',
|
|
31
|
+
args: [],
|
|
32
|
+
raw: trimmed,
|
|
33
|
+
error: `Slash command must start with "/". Got: "${trimmed}"`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const withoutSlash = trimmed.slice(1);
|
|
37
|
+
const colonIndex = withoutSlash.indexOf(':');
|
|
38
|
+
if (colonIndex === -1) {
|
|
39
|
+
return {
|
|
40
|
+
valid: false,
|
|
41
|
+
namespace: '',
|
|
42
|
+
command: '',
|
|
43
|
+
args: [],
|
|
44
|
+
raw: trimmed,
|
|
45
|
+
error: `Slash command must contain ":" separator. Format: /<namespace>:<command>. Got: "${trimmed}"`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const namespace = withoutSlash.slice(0, colonIndex);
|
|
49
|
+
const remainder = withoutSlash.slice(colonIndex + 1);
|
|
50
|
+
if (!namespace) {
|
|
51
|
+
return {
|
|
52
|
+
valid: false,
|
|
53
|
+
namespace: '',
|
|
54
|
+
command: '',
|
|
55
|
+
args: [],
|
|
56
|
+
raw: trimmed,
|
|
57
|
+
error: `Missing namespace before ":". Format: /<namespace>:<command>. Got: "${trimmed}"`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (!isValidNamespace(namespace)) {
|
|
61
|
+
return {
|
|
62
|
+
valid: false,
|
|
63
|
+
namespace,
|
|
64
|
+
command: '',
|
|
65
|
+
args: [],
|
|
66
|
+
raw: trimmed,
|
|
67
|
+
error: `Unknown namespace "${namespace}". Valid namespaces: ${VALID_NAMESPACES.join(', ')}`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const tokens = remainder.split(/\s+/).filter(Boolean);
|
|
71
|
+
const command = tokens[0] || '';
|
|
72
|
+
if (!command) {
|
|
73
|
+
return {
|
|
74
|
+
valid: false,
|
|
75
|
+
namespace,
|
|
76
|
+
command: '',
|
|
77
|
+
args: [],
|
|
78
|
+
raw: trimmed,
|
|
79
|
+
error: `Missing command after "${namespace}:". Format: /${namespace}:<command>. Got: "${trimmed}"`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const args = tokens.slice(1);
|
|
83
|
+
return {
|
|
84
|
+
valid: true,
|
|
85
|
+
namespace,
|
|
86
|
+
command,
|
|
87
|
+
args,
|
|
88
|
+
raw: trimmed,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function isSlashCommand(input) {
|
|
92
|
+
const trimmed = input.trim();
|
|
93
|
+
if (!trimmed.startsWith('/')) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
const withoutSlash = trimmed.slice(1);
|
|
97
|
+
return withoutSlash.includes(':');
|
|
98
|
+
}
|
|
99
|
+
function formatSlashCommand(namespace, command) {
|
|
100
|
+
return `/${namespace}:${command}`;
|
|
101
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* slash/registry.ts
|
|
3
|
+
* Slash command registry — defines all available slash commands,
|
|
4
|
+
* their argument schemas, and whether they are composite (multi-step).
|
|
5
|
+
*/
|
|
6
|
+
export type CommandCategory = 'single' | 'composite';
|
|
7
|
+
export interface SlashCommandDef {
|
|
8
|
+
name: string;
|
|
9
|
+
description: string;
|
|
10
|
+
category: CommandCategory;
|
|
11
|
+
requiresChange: boolean;
|
|
12
|
+
requiresTaskId: boolean;
|
|
13
|
+
steps?: string[];
|
|
14
|
+
usage: string;
|
|
15
|
+
example: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function getCommand(name: string): SlashCommandDef | undefined;
|
|
18
|
+
export declare function getAllCommands(): SlashCommandDef[];
|
|
19
|
+
export declare function getCompositeCommands(): SlashCommandDef[];
|
|
20
|
+
export declare function getSingleCommands(): SlashCommandDef[];
|
|
21
|
+
export declare function hasCommand(name: string): boolean;
|
|
22
|
+
export declare function printSlashHelp(): string;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* slash/registry.ts
|
|
4
|
+
* Slash command registry — defines all available slash commands,
|
|
5
|
+
* their argument schemas, and whether they are composite (multi-step).
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.getCommand = getCommand;
|
|
9
|
+
exports.getAllCommands = getAllCommands;
|
|
10
|
+
exports.getCompositeCommands = getCompositeCommands;
|
|
11
|
+
exports.getSingleCommands = getSingleCommands;
|
|
12
|
+
exports.hasCommand = hasCommand;
|
|
13
|
+
exports.printSlashHelp = printSlashHelp;
|
|
14
|
+
const COMMANDS = {
|
|
15
|
+
propose: {
|
|
16
|
+
name: 'propose',
|
|
17
|
+
description: 'Create a full change proposal (extract → design → tasks)',
|
|
18
|
+
category: 'composite',
|
|
19
|
+
requiresChange: true,
|
|
20
|
+
requiresTaskId: false,
|
|
21
|
+
steps: ['extract', 'design', 'tasks'],
|
|
22
|
+
usage: '/tf:propose <change-name>',
|
|
23
|
+
example: '/tf:propose add-dark-mode',
|
|
24
|
+
},
|
|
25
|
+
apply: {
|
|
26
|
+
name: 'apply',
|
|
27
|
+
description: 'Apply a change by creating worktree and starting implementation',
|
|
28
|
+
category: 'composite',
|
|
29
|
+
requiresChange: true,
|
|
30
|
+
requiresTaskId: false,
|
|
31
|
+
steps: ['worktree'],
|
|
32
|
+
usage: '/tf:apply <change-name>',
|
|
33
|
+
example: '/tf:apply add-dark-mode',
|
|
34
|
+
},
|
|
35
|
+
archive: {
|
|
36
|
+
name: 'archive',
|
|
37
|
+
description: 'Archive a completed change (archive → sync)',
|
|
38
|
+
category: 'composite',
|
|
39
|
+
requiresChange: false,
|
|
40
|
+
requiresTaskId: true,
|
|
41
|
+
steps: ['archive', 'sync'],
|
|
42
|
+
usage: '/tf:archive --task-id <task-id>',
|
|
43
|
+
example: '/tf:archive --task-id add-dark-mode',
|
|
44
|
+
},
|
|
45
|
+
init: {
|
|
46
|
+
name: 'init',
|
|
47
|
+
description: 'Initialize task flow in current project',
|
|
48
|
+
category: 'single',
|
|
49
|
+
requiresChange: false,
|
|
50
|
+
requiresTaskId: false,
|
|
51
|
+
usage: '/tf:init',
|
|
52
|
+
example: '/tf:init',
|
|
53
|
+
},
|
|
54
|
+
status: {
|
|
55
|
+
name: 'status',
|
|
56
|
+
description: 'Show current task and phase status',
|
|
57
|
+
category: 'single',
|
|
58
|
+
requiresChange: false,
|
|
59
|
+
requiresTaskId: false,
|
|
60
|
+
usage: '/tf:status',
|
|
61
|
+
example: '/tf:status',
|
|
62
|
+
},
|
|
63
|
+
extract: {
|
|
64
|
+
name: 'extract',
|
|
65
|
+
description: 'Extract project requirements and generate PRD document',
|
|
66
|
+
category: 'single',
|
|
67
|
+
requiresChange: true,
|
|
68
|
+
requiresTaskId: false,
|
|
69
|
+
usage: '/tf:extract <change-name>',
|
|
70
|
+
example: '/tf:extract add-dark-mode',
|
|
71
|
+
},
|
|
72
|
+
design: {
|
|
73
|
+
name: 'design',
|
|
74
|
+
description: 'Generate technical specification from PRD',
|
|
75
|
+
category: 'single',
|
|
76
|
+
requiresChange: true,
|
|
77
|
+
requiresTaskId: false,
|
|
78
|
+
usage: '/tf:design <change-name>',
|
|
79
|
+
example: '/tf:design add-dark-mode',
|
|
80
|
+
},
|
|
81
|
+
tasks: {
|
|
82
|
+
name: 'tasks',
|
|
83
|
+
description: 'Generate PHASE-*.json task files from PRD and design',
|
|
84
|
+
category: 'single',
|
|
85
|
+
requiresChange: true,
|
|
86
|
+
requiresTaskId: false,
|
|
87
|
+
usage: '/tf:tasks <change-name>',
|
|
88
|
+
example: '/tf:tasks add-dark-mode',
|
|
89
|
+
},
|
|
90
|
+
worktree: {
|
|
91
|
+
name: 'worktree',
|
|
92
|
+
description: 'Create isolated git worktree for task execution',
|
|
93
|
+
category: 'single',
|
|
94
|
+
requiresChange: true,
|
|
95
|
+
requiresTaskId: false,
|
|
96
|
+
usage: '/tf:worktree <change-name>',
|
|
97
|
+
example: '/tf:worktree add-dark-mode',
|
|
98
|
+
},
|
|
99
|
+
merge: {
|
|
100
|
+
name: 'merge',
|
|
101
|
+
description: 'Merge completed worktree back to main branch',
|
|
102
|
+
category: 'single',
|
|
103
|
+
requiresChange: false,
|
|
104
|
+
requiresTaskId: true,
|
|
105
|
+
usage: '/tf:merge <task-id>',
|
|
106
|
+
example: '/tf:merge add-dark-mode',
|
|
107
|
+
},
|
|
108
|
+
sync: {
|
|
109
|
+
name: 'sync',
|
|
110
|
+
description: 'Sync task execution status to spec',
|
|
111
|
+
category: 'single',
|
|
112
|
+
requiresChange: false,
|
|
113
|
+
requiresTaskId: true,
|
|
114
|
+
usage: '/tf:sync --task-id <task-id>',
|
|
115
|
+
example: '/tf:sync --task-id add-dark-mode',
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
function getCommand(name) {
|
|
119
|
+
return COMMANDS[name];
|
|
120
|
+
}
|
|
121
|
+
function getAllCommands() {
|
|
122
|
+
return Object.values(COMMANDS);
|
|
123
|
+
}
|
|
124
|
+
function getCompositeCommands() {
|
|
125
|
+
return Object.values(COMMANDS).filter((cmd) => cmd.category === 'composite');
|
|
126
|
+
}
|
|
127
|
+
function getSingleCommands() {
|
|
128
|
+
return Object.values(COMMANDS).filter((cmd) => cmd.category === 'single');
|
|
129
|
+
}
|
|
130
|
+
function hasCommand(name) {
|
|
131
|
+
return name in COMMANDS;
|
|
132
|
+
}
|
|
133
|
+
function printSlashHelp() {
|
|
134
|
+
const lines = [
|
|
135
|
+
'',
|
|
136
|
+
'Slash Commands:',
|
|
137
|
+
'',
|
|
138
|
+
' Composite (multi-step):',
|
|
139
|
+
];
|
|
140
|
+
for (const cmd of getCompositeCommands()) {
|
|
141
|
+
lines.push(` ${cmd.usage.padEnd(40)} ${cmd.description}`);
|
|
142
|
+
}
|
|
143
|
+
lines.push('');
|
|
144
|
+
lines.push(' Single:');
|
|
145
|
+
for (const cmd of getSingleCommands()) {
|
|
146
|
+
lines.push(` ${cmd.usage.padEnd(40)} ${cmd.description}`);
|
|
147
|
+
}
|
|
148
|
+
lines.push('');
|
|
149
|
+
lines.push(' Examples:');
|
|
150
|
+
lines.push(' /tf:propose add-dark-mode → extract + design + tasks');
|
|
151
|
+
lines.push(' /tf:apply add-dark-mode → create worktree');
|
|
152
|
+
lines.push(' /tf:archive --task-id feat → archive + sync');
|
|
153
|
+
lines.push('');
|
|
154
|
+
return lines.join('\n');
|
|
155
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec/openspec-to-task/builders.ts
|
|
3
|
+
* Task object builders for Spec to task sync
|
|
4
|
+
*/
|
|
5
|
+
import { Config } from '../../lib/config';
|
|
6
|
+
/**
|
|
7
|
+
* Build task output paths config
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildTaskOutputs(config: Config | undefined, taskId: string): {
|
|
10
|
+
task: string;
|
|
11
|
+
snapshot: string;
|
|
12
|
+
report: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Build task object
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildTaskObject(params: {
|
|
18
|
+
taskId: string;
|
|
19
|
+
type: string;
|
|
20
|
+
title: string;
|
|
21
|
+
priority: string;
|
|
22
|
+
description: string;
|
|
23
|
+
files: string[];
|
|
24
|
+
worktree: string;
|
|
25
|
+
implementationValidations: string[];
|
|
26
|
+
reviewValidations: string[];
|
|
27
|
+
changeName: string;
|
|
28
|
+
manifestPath: string;
|
|
29
|
+
executionPath: string;
|
|
30
|
+
mergeStrategy: {
|
|
31
|
+
type: string;
|
|
32
|
+
deleteBranch: boolean;
|
|
33
|
+
deleteWorktree: boolean;
|
|
34
|
+
};
|
|
35
|
+
planningSummary: string;
|
|
36
|
+
implementationSteps: string[];
|
|
37
|
+
outputs: {
|
|
38
|
+
task: string;
|
|
39
|
+
snapshot: string;
|
|
40
|
+
report: string;
|
|
41
|
+
};
|
|
42
|
+
}): Record<string, unknown>;
|
|
43
|
+
/**
|
|
44
|
+
* Build task JSON string
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildTaskJson(params: {
|
|
47
|
+
taskId: string;
|
|
48
|
+
type: string;
|
|
49
|
+
title: string;
|
|
50
|
+
priority: string;
|
|
51
|
+
description: string;
|
|
52
|
+
files: string[];
|
|
53
|
+
worktree: string;
|
|
54
|
+
implementationValidations: string[];
|
|
55
|
+
reviewValidations: string[];
|
|
56
|
+
changeName: string;
|
|
57
|
+
manifestPath: string;
|
|
58
|
+
executionPath: string;
|
|
59
|
+
mergeStrategy: {
|
|
60
|
+
type: string;
|
|
61
|
+
deleteBranch: boolean;
|
|
62
|
+
deleteWorktree: boolean;
|
|
63
|
+
};
|
|
64
|
+
planningSummary: string;
|
|
65
|
+
implementationSteps: string[];
|
|
66
|
+
config?: Config;
|
|
67
|
+
}): string;
|
|
68
|
+
/**
|
|
69
|
+
* Build sync parameters from options and config
|
|
70
|
+
*/
|
|
71
|
+
export declare function buildSyncParams(options: {
|
|
72
|
+
taskId?: string;
|
|
73
|
+
type?: string;
|
|
74
|
+
priority?: string;
|
|
75
|
+
worktree?: string;
|
|
76
|
+
}, config: Config, changeName: string, _changeDir: string, proposalContent: string, _designContent: string, tasksContent: string, manifest: {
|
|
77
|
+
taskId?: string;
|
|
78
|
+
type?: string;
|
|
79
|
+
priority?: string;
|
|
80
|
+
title?: string;
|
|
81
|
+
files?: string[];
|
|
82
|
+
worktree?: string;
|
|
83
|
+
implementationValidation?: string[];
|
|
84
|
+
reviewValidation?: string[];
|
|
85
|
+
mergeStrategy?: {
|
|
86
|
+
type?: string;
|
|
87
|
+
deleteBranch?: boolean;
|
|
88
|
+
deleteWorktree?: boolean;
|
|
89
|
+
};
|
|
90
|
+
}, _manifestPath: string, _executionPath: string): {
|
|
91
|
+
taskId: string;
|
|
92
|
+
type: string;
|
|
93
|
+
title: string;
|
|
94
|
+
priority: string;
|
|
95
|
+
description: string;
|
|
96
|
+
files: string[];
|
|
97
|
+
worktree: string;
|
|
98
|
+
implementationValidations: string[];
|
|
99
|
+
reviewValidations: string[];
|
|
100
|
+
mergeStrategy: {
|
|
101
|
+
type: string;
|
|
102
|
+
deleteBranch: boolean;
|
|
103
|
+
deleteWorktree: boolean;
|
|
104
|
+
};
|
|
105
|
+
planningSummary: string;
|
|
106
|
+
implementationSteps: string[];
|
|
107
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* spec/openspec-to-task/builders.ts
|
|
4
|
+
* Task object builders for Spec to task sync
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.buildTaskOutputs = buildTaskOutputs;
|
|
8
|
+
exports.buildTaskObject = buildTaskObject;
|
|
9
|
+
exports.buildTaskJson = buildTaskJson;
|
|
10
|
+
exports.buildSyncParams = buildSyncParams;
|
|
11
|
+
const parsers_1 = require("./parsers");
|
|
12
|
+
/**
|
|
13
|
+
* Build task output paths config
|
|
14
|
+
*/
|
|
15
|
+
function buildTaskOutputs(config, taskId) {
|
|
16
|
+
const tasksDir = config?.tasksDir || 'tasks';
|
|
17
|
+
const snapshotsDir = config?.snapshotsDir || 'snapshots';
|
|
18
|
+
const reportsDir = config?.reportsDir || 'reports';
|
|
19
|
+
return {
|
|
20
|
+
task: `${tasksDir}/${taskId}.json`,
|
|
21
|
+
snapshot: `${snapshotsDir}/${taskId}-impl.json`,
|
|
22
|
+
report: `${reportsDir}/${taskId}-review.md`,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build task object
|
|
27
|
+
*/
|
|
28
|
+
function buildTaskObject(params) {
|
|
29
|
+
const { taskId, type, title, priority, description, files, worktree, implementationValidations, reviewValidations, changeName, manifestPath, executionPath, mergeStrategy, planningSummary, implementationSteps, outputs, } = params;
|
|
30
|
+
return {
|
|
31
|
+
id: taskId,
|
|
32
|
+
type,
|
|
33
|
+
title,
|
|
34
|
+
priority,
|
|
35
|
+
phase: 1,
|
|
36
|
+
dependencies: [],
|
|
37
|
+
docs_to_read: [
|
|
38
|
+
`spec/changes/${changeName}/product-requirement.md`,
|
|
39
|
+
`spec/changes/${changeName}/design.md`,
|
|
40
|
+
`spec/changes/${changeName}/tasks.md`,
|
|
41
|
+
],
|
|
42
|
+
spec: {
|
|
43
|
+
description: description || `从 Spec 变更 ${changeName} 同步生成。`,
|
|
44
|
+
files: files || [],
|
|
45
|
+
context: [],
|
|
46
|
+
},
|
|
47
|
+
acceptance_criteria: [
|
|
48
|
+
'validation-passes',
|
|
49
|
+
'review-pass',
|
|
50
|
+
],
|
|
51
|
+
implementation: {
|
|
52
|
+
steps: implementationSteps.map((step) => ({
|
|
53
|
+
step,
|
|
54
|
+
details: '',
|
|
55
|
+
})),
|
|
56
|
+
notes: planningSummary || '',
|
|
57
|
+
},
|
|
58
|
+
validation: {
|
|
59
|
+
commands: implementationValidations || [],
|
|
60
|
+
manual_checks: reviewValidations || [],
|
|
61
|
+
},
|
|
62
|
+
status: 'pending',
|
|
63
|
+
metadata: {
|
|
64
|
+
change: changeName,
|
|
65
|
+
manifest: manifestPath,
|
|
66
|
+
execution: executionPath,
|
|
67
|
+
worktree,
|
|
68
|
+
mergeStrategy: {
|
|
69
|
+
type: mergeStrategy.type || 'squash',
|
|
70
|
+
deleteBranch: mergeStrategy.deleteBranch ?? true,
|
|
71
|
+
deleteWorktree: mergeStrategy.deleteWorktree ?? true,
|
|
72
|
+
},
|
|
73
|
+
outputs,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Build task JSON string
|
|
79
|
+
*/
|
|
80
|
+
function buildTaskJson(params) {
|
|
81
|
+
const outputs = buildTaskOutputs(params.config, params.taskId);
|
|
82
|
+
const taskObject = buildTaskObject({ ...params, outputs });
|
|
83
|
+
return JSON.stringify(taskObject, null, 2);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Build sync parameters from options and config
|
|
87
|
+
*/
|
|
88
|
+
function buildSyncParams(options, config, changeName, _changeDir, proposalContent, _designContent, tasksContent, manifest, _manifestPath, _executionPath) {
|
|
89
|
+
const checklistItems = (0, parsers_1.extractChecklistItems)(tasksContent);
|
|
90
|
+
const taskId = (0, parsers_1.toTaskId)(options.taskId || manifest.taskId || changeName);
|
|
91
|
+
const type = String(options.type || manifest.type || 'feat');
|
|
92
|
+
const priority = String(options.priority || manifest.priority || 'medium');
|
|
93
|
+
const title = String(manifest.title || (0, parsers_1.extractTitle)(changeName, proposalContent));
|
|
94
|
+
const description = [
|
|
95
|
+
`从 Spec 变更 ${changeName} 同步生成。`,
|
|
96
|
+
'',
|
|
97
|
+
proposalContent ? proposalContent.split(/\r?\n/).slice(0, 20).join('\n') : '请参考 Spec proposal/design/tasks 文档补全细节。',
|
|
98
|
+
].join('\n');
|
|
99
|
+
const fileCandidates = (0, parsers_1.uniqueArray)([
|
|
100
|
+
...(Array.isArray(manifest.files) ? manifest.files : []),
|
|
101
|
+
...(0, parsers_1.extractFileCandidates)([proposalContent, _designContent, tasksContent]),
|
|
102
|
+
]);
|
|
103
|
+
const files = fileCandidates.length > 0 ? fileCandidates : [`${config.tasksDir}/README.md`];
|
|
104
|
+
const worktree = String(options.worktree || manifest.worktree || (0, parsers_1.toWorktreeName)(type, taskId));
|
|
105
|
+
const implementationValidations = (0, parsers_1.uniqueArray)(Array.isArray(manifest.implementationValidation) && manifest.implementationValidation.length > 0
|
|
106
|
+
? manifest.implementationValidation
|
|
107
|
+
: (0, parsers_1.inferImplementationValidations)(checklistItems));
|
|
108
|
+
const reviewValidations = (0, parsers_1.uniqueArray)(Array.isArray(manifest.reviewValidation) && manifest.reviewValidation.length > 0
|
|
109
|
+
? manifest.reviewValidation
|
|
110
|
+
: (0, parsers_1.inferReviewValidations)(checklistItems));
|
|
111
|
+
const mergeStrategy = {
|
|
112
|
+
type: String(manifest.mergeStrategy?.type || 'squash'),
|
|
113
|
+
deleteBranch: (0, parsers_1.normalizeBoolean)(manifest.mergeStrategy?.deleteBranch, true),
|
|
114
|
+
deleteWorktree: (0, parsers_1.normalizeBoolean)(manifest.mergeStrategy?.deleteWorktree, true),
|
|
115
|
+
};
|
|
116
|
+
const implementationSteps = checklistItems.length > 0
|
|
117
|
+
? checklistItems
|
|
118
|
+
: [
|
|
119
|
+
'读取 Spec 规格并补全任务分解',
|
|
120
|
+
'完成实现并执行构建、测试、类型检查与 lint',
|
|
121
|
+
'输出审查报告并给出结论',
|
|
122
|
+
];
|
|
123
|
+
const planningSummary = `从 Spec 变更 ${changeName} 同步生成,基于 proposal、design、tasks 与 harness manifest 收敛出的执行规划。`;
|
|
124
|
+
return {
|
|
125
|
+
taskId,
|
|
126
|
+
type,
|
|
127
|
+
title,
|
|
128
|
+
priority,
|
|
129
|
+
description,
|
|
130
|
+
files,
|
|
131
|
+
worktree,
|
|
132
|
+
implementationValidations,
|
|
133
|
+
reviewValidations,
|
|
134
|
+
mergeStrategy,
|
|
135
|
+
planningSummary,
|
|
136
|
+
implementationSteps,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* spec/openspec-to-task/index.ts
|
|
3
|
+
* Sync Spec change to harness task definition
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node sync-openspec-to-task.js --change <change-name> [options]
|
|
7
|
+
*/
|
|
8
|
+
import { SyncOptions, SyncResult } from './types';
|
|
9
|
+
/**
|
|
10
|
+
* Sync Spec to task
|
|
11
|
+
*/
|
|
12
|
+
export declare function syncSpecToTask(options?: SyncOptions): SyncResult;
|
|
13
|
+
/**
|
|
14
|
+
* Main entry point
|
|
15
|
+
*/
|
|
16
|
+
export declare function main(): void;
|
|
17
|
+
declare const _default: {
|
|
18
|
+
syncSpecToTask: typeof syncSpecToTask;
|
|
19
|
+
};
|
|
20
|
+
export default _default;
|