@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,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config.ts
|
|
3
|
+
* Configuration loader for task-flow
|
|
4
|
+
*
|
|
5
|
+
* Loads configuration from:
|
|
6
|
+
* 1. Environment variables (highest priority)
|
|
7
|
+
* 2. Config file (.harnessrc)
|
|
8
|
+
* 3. Default values (lowest priority)
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Default configuration values
|
|
12
|
+
*/
|
|
13
|
+
export declare const DEFAULTS: Config;
|
|
14
|
+
/**
|
|
15
|
+
* Configuration object interface
|
|
16
|
+
*/
|
|
17
|
+
export interface Config {
|
|
18
|
+
harnessRoot?: string;
|
|
19
|
+
worktreesDir?: string;
|
|
20
|
+
tasksDir?: string;
|
|
21
|
+
snapshotsDir?: string;
|
|
22
|
+
archiveDir?: string;
|
|
23
|
+
reportsDir?: string;
|
|
24
|
+
plansDir?: string;
|
|
25
|
+
specRoot?: string;
|
|
26
|
+
configFile?: string;
|
|
27
|
+
harnessRootAbs?: string;
|
|
28
|
+
worktreesDirAbs?: string;
|
|
29
|
+
tasksDirAbs?: string;
|
|
30
|
+
snapshotsDirAbs?: string;
|
|
31
|
+
archiveDirAbs?: string;
|
|
32
|
+
reportsDirAbs?: string;
|
|
33
|
+
plansDirAbs?: string;
|
|
34
|
+
specRootAbs?: string;
|
|
35
|
+
projectRoot?: string;
|
|
36
|
+
configPath?: string;
|
|
37
|
+
configSources?: {
|
|
38
|
+
defaults: typeof DEFAULTS;
|
|
39
|
+
file: Record<string, unknown>;
|
|
40
|
+
env: Record<string, string>;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Find config file starting from cwd and walking up
|
|
45
|
+
* @param cwd - Current working directory
|
|
46
|
+
* @returns Path to config file or null
|
|
47
|
+
*/
|
|
48
|
+
export declare function findConfigFile(cwd: string): string | null;
|
|
49
|
+
/**
|
|
50
|
+
* Load config from file
|
|
51
|
+
* @param configPath - Path to config file
|
|
52
|
+
* @returns Config object
|
|
53
|
+
*/
|
|
54
|
+
export declare function loadConfigFile(configPath: string | null): Record<string, unknown>;
|
|
55
|
+
/**
|
|
56
|
+
* Load config from environment variables
|
|
57
|
+
* @returns Config object
|
|
58
|
+
*/
|
|
59
|
+
export declare function loadEnvConfig(): Record<string, string>;
|
|
60
|
+
/**
|
|
61
|
+
* Resolve absolute path relative to project root
|
|
62
|
+
* @param basePath - Base path (can be relative or absolute)
|
|
63
|
+
* @param projectRoot - Project root directory
|
|
64
|
+
* @returns Resolved absolute path
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolvePath(basePath: string | undefined, projectRoot: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Load and merge all configuration sources
|
|
69
|
+
* @param options - Options
|
|
70
|
+
* @param options.cwd - Current working directory
|
|
71
|
+
* @param options.configFile - Explicit config file path
|
|
72
|
+
* @returns Merged configuration
|
|
73
|
+
*/
|
|
74
|
+
export declare function loadConfig(options?: {
|
|
75
|
+
cwd?: string;
|
|
76
|
+
configFile?: string;
|
|
77
|
+
}): Config;
|
|
78
|
+
/**
|
|
79
|
+
* Get a specific config value
|
|
80
|
+
* @param key - Config key
|
|
81
|
+
* @param defaultValue - Default value if not found
|
|
82
|
+
* @param options - Options
|
|
83
|
+
* @returns Config value
|
|
84
|
+
*/
|
|
85
|
+
export declare function getConfig<T = string>(key: string, defaultValue: T, options?: {
|
|
86
|
+
cwd?: string;
|
|
87
|
+
configFile?: string;
|
|
88
|
+
}): T;
|
|
89
|
+
/**
|
|
90
|
+
* Ensure all harness directories exist
|
|
91
|
+
* @param config - Config object
|
|
92
|
+
*/
|
|
93
|
+
export declare function ensureDirectories(config: Config): void;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* config.ts
|
|
4
|
+
* Configuration loader for task-flow
|
|
5
|
+
*
|
|
6
|
+
* Loads configuration from:
|
|
7
|
+
* 1. Environment variables (highest priority)
|
|
8
|
+
* 2. Config file (.harnessrc)
|
|
9
|
+
* 3. Default values (lowest priority)
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.DEFAULTS = void 0;
|
|
46
|
+
exports.findConfigFile = findConfigFile;
|
|
47
|
+
exports.loadConfigFile = loadConfigFile;
|
|
48
|
+
exports.loadEnvConfig = loadEnvConfig;
|
|
49
|
+
exports.resolvePath = resolvePath;
|
|
50
|
+
exports.loadConfig = loadConfig;
|
|
51
|
+
exports.getConfig = getConfig;
|
|
52
|
+
exports.ensureDirectories = ensureDirectories;
|
|
53
|
+
const fs = __importStar(require("fs"));
|
|
54
|
+
const path = __importStar(require("path"));
|
|
55
|
+
/**
|
|
56
|
+
* Default configuration values
|
|
57
|
+
*/
|
|
58
|
+
exports.DEFAULTS = {
|
|
59
|
+
harnessRoot: '.harness',
|
|
60
|
+
worktreesDir: '.worktrees',
|
|
61
|
+
tasksDir: 'tasks',
|
|
62
|
+
snapshotsDir: 'snapshots',
|
|
63
|
+
archiveDir: 'archive',
|
|
64
|
+
reportsDir: 'reports',
|
|
65
|
+
plansDir: 'plans',
|
|
66
|
+
specRoot: 'spec',
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Environment variable mappings
|
|
70
|
+
*/
|
|
71
|
+
const ENV_MAPPING = {
|
|
72
|
+
HARNESS_ROOT: 'harnessRoot',
|
|
73
|
+
HARNESS_WORKTREES_DIR: 'worktreesDir',
|
|
74
|
+
HARNESS_TASKS_DIR: 'tasksDir',
|
|
75
|
+
HARNESS_SNAPSHOTS_DIR: 'snapshotsDir',
|
|
76
|
+
HARNESS_ARCHIVE_DIR: 'archiveDir',
|
|
77
|
+
HARNESS_REPORTS_DIR: 'reportsDir',
|
|
78
|
+
HARNESS_PLANS_DIR: 'plansDir',
|
|
79
|
+
HARNESS_SPEC_ROOT: 'specRoot',
|
|
80
|
+
HARNESS_CONFIG_FILE: 'configFile',
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Find config file starting from cwd and walking up
|
|
84
|
+
* @param cwd - Current working directory
|
|
85
|
+
* @returns Path to config file or null
|
|
86
|
+
*/
|
|
87
|
+
function findConfigFile(cwd) {
|
|
88
|
+
const configNames = ['.harnessrc', '.harnessrc.json', 'harness.config.json'];
|
|
89
|
+
let current = cwd;
|
|
90
|
+
while (current !== path.dirname(current)) {
|
|
91
|
+
for (const configName of configNames) {
|
|
92
|
+
const configPath = path.resolve(current, configName);
|
|
93
|
+
if (fs.existsSync(configPath)) {
|
|
94
|
+
return configPath;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
current = path.dirname(current);
|
|
98
|
+
}
|
|
99
|
+
// Check cwd for config file even if not found walking up
|
|
100
|
+
for (const configName of configNames) {
|
|
101
|
+
const configPath = path.resolve(cwd, configName);
|
|
102
|
+
if (fs.existsSync(configPath)) {
|
|
103
|
+
return configPath;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Load config from file
|
|
110
|
+
* @param configPath - Path to config file
|
|
111
|
+
* @returns Config object
|
|
112
|
+
*/
|
|
113
|
+
function loadConfigFile(configPath) {
|
|
114
|
+
if (!configPath || !fs.existsSync(configPath)) {
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
119
|
+
// Support both JSON and JSONC (with comments)
|
|
120
|
+
const cleaned = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
|
|
121
|
+
return JSON.parse(cleaned);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
125
|
+
console.warn(`[CONFIG] Failed to load config file: ${configPath}`, errorMessage);
|
|
126
|
+
return {};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Load config from environment variables
|
|
131
|
+
* @returns Config object
|
|
132
|
+
*/
|
|
133
|
+
function loadEnvConfig() {
|
|
134
|
+
const config = {};
|
|
135
|
+
for (const [envVar, configKey] of Object.entries(ENV_MAPPING)) {
|
|
136
|
+
const envValue = process.env[envVar];
|
|
137
|
+
if (envValue) {
|
|
138
|
+
config[configKey] = envValue;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return config;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Resolve absolute path relative to project root
|
|
145
|
+
* @param basePath - Base path (can be relative or absolute)
|
|
146
|
+
* @param projectRoot - Project root directory
|
|
147
|
+
* @returns Resolved absolute path
|
|
148
|
+
*/
|
|
149
|
+
function resolvePath(basePath, projectRoot) {
|
|
150
|
+
if (!basePath) {
|
|
151
|
+
return projectRoot;
|
|
152
|
+
}
|
|
153
|
+
if (path.isAbsolute(basePath)) {
|
|
154
|
+
return basePath;
|
|
155
|
+
}
|
|
156
|
+
return path.resolve(projectRoot, basePath);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Load and merge all configuration sources
|
|
160
|
+
* @param options - Options
|
|
161
|
+
* @param options.cwd - Current working directory
|
|
162
|
+
* @param options.configFile - Explicit config file path
|
|
163
|
+
* @returns Merged configuration
|
|
164
|
+
*/
|
|
165
|
+
function loadConfig(options = {}) {
|
|
166
|
+
const cwd = path.resolve(options.cwd || process.cwd());
|
|
167
|
+
// Find config file
|
|
168
|
+
const configPath = options.configFile || findConfigFile(cwd);
|
|
169
|
+
// Determine project root
|
|
170
|
+
let projectRoot = cwd;
|
|
171
|
+
if (configPath) {
|
|
172
|
+
projectRoot = path.dirname(configPath);
|
|
173
|
+
// Walk up to find actual project root (where .git is)
|
|
174
|
+
let current = projectRoot;
|
|
175
|
+
while (current !== path.dirname(current)) {
|
|
176
|
+
if (fs.existsSync(path.resolve(current, '.git'))) {
|
|
177
|
+
projectRoot = current;
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
current = path.dirname(current);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Load from all sources
|
|
184
|
+
const fileConfig = configPath ? loadConfigFile(configPath) : {};
|
|
185
|
+
const envConfig = loadEnvConfig();
|
|
186
|
+
// Merge configurations (priority: env > file > defaults)
|
|
187
|
+
const config = {
|
|
188
|
+
...exports.DEFAULTS,
|
|
189
|
+
...fileConfig,
|
|
190
|
+
...envConfig,
|
|
191
|
+
};
|
|
192
|
+
// Resolve all paths to absolute
|
|
193
|
+
const pathKeys = ['harnessRoot', 'worktreesDir', 'tasksDir', 'snapshotsDir', 'archiveDir', 'reportsDir', 'plansDir', 'specRoot'];
|
|
194
|
+
for (const key of pathKeys) {
|
|
195
|
+
const value = config[key];
|
|
196
|
+
if (typeof value === 'string') {
|
|
197
|
+
const absKey = `${key}Abs`;
|
|
198
|
+
config[absKey] = resolvePath(value, projectRoot);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Add derived paths
|
|
202
|
+
config.harnessRootAbs = resolvePath(config.harnessRoot, projectRoot);
|
|
203
|
+
config.tasksDirAbs = resolvePath(config.tasksDir, config.harnessRootAbs);
|
|
204
|
+
config.snapshotsDirAbs = resolvePath(config.snapshotsDir, config.harnessRootAbs);
|
|
205
|
+
config.archiveDirAbs = resolvePath(config.archiveDir, config.harnessRootAbs);
|
|
206
|
+
config.reportsDirAbs = resolvePath(config.reportsDir, config.harnessRootAbs);
|
|
207
|
+
config.plansDirAbs = resolvePath(config.plansDir, config.harnessRootAbs);
|
|
208
|
+
config.worktreesDirAbs = resolvePath(config.worktreesDir, projectRoot);
|
|
209
|
+
config.specRootAbs = resolvePath(config.specRoot, projectRoot);
|
|
210
|
+
// Add metadata
|
|
211
|
+
config.projectRoot = projectRoot;
|
|
212
|
+
config.configPath = configPath || undefined;
|
|
213
|
+
config.configSources = {
|
|
214
|
+
defaults: exports.DEFAULTS,
|
|
215
|
+
file: fileConfig,
|
|
216
|
+
env: envConfig,
|
|
217
|
+
};
|
|
218
|
+
return config;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Get a specific config value
|
|
222
|
+
* @param key - Config key
|
|
223
|
+
* @param defaultValue - Default value if not found
|
|
224
|
+
* @param options - Options
|
|
225
|
+
* @returns Config value
|
|
226
|
+
*/
|
|
227
|
+
function getConfig(key, defaultValue, options = {}) {
|
|
228
|
+
const config = loadConfig(options);
|
|
229
|
+
const value = config[key] || config[`${key}Abs`] || defaultValue;
|
|
230
|
+
return value;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Ensure all harness directories exist
|
|
234
|
+
* @param config - Config object
|
|
235
|
+
*/
|
|
236
|
+
function ensureDirectories(config) {
|
|
237
|
+
const dirs = [
|
|
238
|
+
config.harnessRootAbs,
|
|
239
|
+
config.tasksDirAbs,
|
|
240
|
+
config.snapshotsDirAbs,
|
|
241
|
+
config.archiveDirAbs,
|
|
242
|
+
config.reportsDirAbs,
|
|
243
|
+
config.plansDirAbs,
|
|
244
|
+
config.worktreesDirAbs,
|
|
245
|
+
];
|
|
246
|
+
for (const dir of dirs) {
|
|
247
|
+
if (dir) {
|
|
248
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/constants.ts
|
|
3
|
+
* Shared constants and magic strings for task-flow
|
|
4
|
+
*
|
|
5
|
+
* Centralizes all magic strings, status values, phase names, and error codes
|
|
6
|
+
* to ensure consistency across the codebase.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Phase names
|
|
10
|
+
*/
|
|
11
|
+
export declare const PHASE: {
|
|
12
|
+
readonly PLANNING: "planning";
|
|
13
|
+
readonly IMPLEMENTATION: "implementation";
|
|
14
|
+
readonly REVIEW: "review";
|
|
15
|
+
readonly MERGE: "merge";
|
|
16
|
+
};
|
|
17
|
+
export type Phase = typeof PHASE[keyof typeof PHASE];
|
|
18
|
+
/**
|
|
19
|
+
* Status values
|
|
20
|
+
*/
|
|
21
|
+
export declare const STATUS: {
|
|
22
|
+
readonly PENDING: "pending";
|
|
23
|
+
readonly RUNNING: "running";
|
|
24
|
+
readonly COMPLETED: "completed";
|
|
25
|
+
readonly BLOCKED: "blocked";
|
|
26
|
+
readonly FAILED: "failed";
|
|
27
|
+
readonly SKIPPED: "skipped";
|
|
28
|
+
readonly ACTIVE: "active";
|
|
29
|
+
};
|
|
30
|
+
export type Status = typeof STATUS[keyof typeof STATUS];
|
|
31
|
+
/**
|
|
32
|
+
* Review conclusions
|
|
33
|
+
*/
|
|
34
|
+
export declare const REVIEW_CONCLUSION: {
|
|
35
|
+
readonly PASS: "PASS";
|
|
36
|
+
readonly NEEDS_WORK: "NEEDS_WORK";
|
|
37
|
+
readonly FAIL: "FAIL";
|
|
38
|
+
};
|
|
39
|
+
export type ReviewConclusion = typeof REVIEW_CONCLUSION[keyof typeof REVIEW_CONCLUSION];
|
|
40
|
+
/**
|
|
41
|
+
* Validation status values
|
|
42
|
+
*/
|
|
43
|
+
export declare const VALIDATION_STATUS: {
|
|
44
|
+
readonly PASS: "pass";
|
|
45
|
+
readonly PASSED: "passed";
|
|
46
|
+
readonly SUCCESS: "success";
|
|
47
|
+
readonly OK: "ok";
|
|
48
|
+
readonly TRUE: "true";
|
|
49
|
+
readonly FAIL: "fail";
|
|
50
|
+
readonly FAILED: "failed";
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Validated status values (for passed validations)
|
|
54
|
+
*/
|
|
55
|
+
export declare const VALIDATED_STATUSES: readonly ["pass", "passed", "success", "ok", "true"];
|
|
56
|
+
/**
|
|
57
|
+
* Merge strategy types
|
|
58
|
+
*/
|
|
59
|
+
export declare const MERGE_TYPE: {
|
|
60
|
+
readonly SQUASH: "squash";
|
|
61
|
+
readonly MERGE: "merge";
|
|
62
|
+
readonly REBASE: "rebase";
|
|
63
|
+
};
|
|
64
|
+
export type MergeType = typeof MERGE_TYPE[keyof typeof MERGE_TYPE];
|
|
65
|
+
/**
|
|
66
|
+
* Default merge configuration
|
|
67
|
+
*/
|
|
68
|
+
export declare const DEFAULT_MERGE_CONFIG: {
|
|
69
|
+
readonly type: "squash";
|
|
70
|
+
readonly deleteBranch: true;
|
|
71
|
+
readonly deleteWorktree: true;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Allowed commands for CLI execution (security whitelist)
|
|
75
|
+
*/
|
|
76
|
+
export declare const ALLOWED_COMMANDS: readonly ["git", "node", "pnpm", "npm", "yarn", "tsc", "eslint", "prettier", "jest", "vitest", "mocha", "tsx", "ts-node"];
|
|
77
|
+
export type AllowedCommand = typeof ALLOWED_COMMANDS[number];
|
|
78
|
+
/**
|
|
79
|
+
* Check if a command is allowed
|
|
80
|
+
* @param cmd - Command to check
|
|
81
|
+
* @returns True if command is allowed
|
|
82
|
+
*/
|
|
83
|
+
export declare function isAllowedCommand(cmd: string): cmd is AllowedCommand;
|
|
84
|
+
/**
|
|
85
|
+
* File patterns
|
|
86
|
+
*/
|
|
87
|
+
export declare const FILE_PATTERNS: {
|
|
88
|
+
readonly TASK_JSON: RegExp;
|
|
89
|
+
readonly SNAPSHOT_JSON: RegExp;
|
|
90
|
+
readonly REVIEW_MD: RegExp;
|
|
91
|
+
readonly PROPOSAL_MD: RegExp;
|
|
92
|
+
readonly DESIGN_MD: RegExp;
|
|
93
|
+
readonly TASKS_MD: RegExp;
|
|
94
|
+
readonly EXECUTION_JSON: RegExp;
|
|
95
|
+
readonly MANIFEST_JSON: RegExp;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Directory names
|
|
99
|
+
*/
|
|
100
|
+
export declare const DIR_NAMES: {
|
|
101
|
+
readonly HARNESS: ".harness";
|
|
102
|
+
readonly SPEC: "spec";
|
|
103
|
+
readonly CHANGES: "changes";
|
|
104
|
+
readonly TASKS: "tasks";
|
|
105
|
+
readonly SNAPSHOTS: "snapshots";
|
|
106
|
+
readonly REPORTS: "reports";
|
|
107
|
+
readonly ARCHIVE: "archive";
|
|
108
|
+
readonly WORKTREES: ".worktrees";
|
|
109
|
+
readonly SKILLS: "skills";
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* State file names
|
|
113
|
+
*/
|
|
114
|
+
export declare const STATE_FILES: {
|
|
115
|
+
readonly STATE: "state.json";
|
|
116
|
+
readonly CONFIG: ".harnessrc";
|
|
117
|
+
readonly HOOKS: "hooks.json";
|
|
118
|
+
readonly MCP: "mcp.json";
|
|
119
|
+
readonly SKILLS: "skills.json";
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Hook names
|
|
123
|
+
*/
|
|
124
|
+
export declare const HOOK_NAMES: {
|
|
125
|
+
readonly PRE_DESIGN: "pre-design";
|
|
126
|
+
readonly POST_DESIGN: "post-design";
|
|
127
|
+
readonly PRE_TASKS: "pre-tasks";
|
|
128
|
+
readonly POST_TASKS: "post-tasks";
|
|
129
|
+
readonly PRE_WORKTREE: "pre-worktree";
|
|
130
|
+
readonly POST_WORKTREE: "post-worktree";
|
|
131
|
+
readonly PRE_SNAPSHOT: "pre-snapshot";
|
|
132
|
+
readonly POST_SNAPSHOT: "post-snapshot";
|
|
133
|
+
readonly PRE_REVIEW: "pre-review";
|
|
134
|
+
readonly POST_REVIEW: "post-review";
|
|
135
|
+
readonly PRE_MERGE: "pre-merge";
|
|
136
|
+
readonly POST_MERGE: "post-merge";
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* Gate validation names
|
|
140
|
+
*/
|
|
141
|
+
export declare const GATE_VALIDATIONS: {
|
|
142
|
+
readonly BUILD_PASSES: "build-passes";
|
|
143
|
+
readonly TESTS_PASS: "tests-pass";
|
|
144
|
+
readonly TYPECHECK_PASSES: "typecheck-passes";
|
|
145
|
+
readonly LINT_PASSES: "lint-passes";
|
|
146
|
+
readonly SECURITY_CHECK: "security-check";
|
|
147
|
+
readonly COVERAGE_GE_80: "coverage-ge-80";
|
|
148
|
+
readonly REVIEW_CONCLUSION: "review-conclusion";
|
|
149
|
+
readonly PLANNING_READY: "planning-ready";
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Validation aliases (maps validation name to alternative names)
|
|
153
|
+
*/
|
|
154
|
+
export declare const VALIDATION_ALIASES: Record<string, string[]>;
|
|
155
|
+
/**
|
|
156
|
+
* Agent types
|
|
157
|
+
*/
|
|
158
|
+
export declare const AGENT_TYPES: {
|
|
159
|
+
readonly CLAUDE_CODE: "claude-code";
|
|
160
|
+
readonly TRAE: "trae";
|
|
161
|
+
readonly QODER: "qoder";
|
|
162
|
+
};
|
|
163
|
+
export type AgentType = typeof AGENT_TYPES[keyof typeof AGENT_TYPES];
|
|
164
|
+
/**
|
|
165
|
+
* Skill formats
|
|
166
|
+
*/
|
|
167
|
+
export declare const SKILL_FORMAT: {
|
|
168
|
+
readonly COPY_SKILL_MD: "copy-skill-md";
|
|
169
|
+
readonly COPY_DIRECTORY: "copy-directory";
|
|
170
|
+
readonly SYMLINK: "symlink";
|
|
171
|
+
};
|
|
172
|
+
export type SkillFormat = typeof SKILL_FORMAT[keyof typeof SKILL_FORMAT];
|
|
173
|
+
/**
|
|
174
|
+
* Event types for archiving
|
|
175
|
+
*/
|
|
176
|
+
export declare const EVENT_TYPES: {
|
|
177
|
+
readonly TASK_STARTED: "task_started";
|
|
178
|
+
readonly PHASE_STARTED: "phase_started";
|
|
179
|
+
readonly PHASE_COMPLETED: "phase_completed";
|
|
180
|
+
readonly SNAPSHOT_CREATED: "snapshot_created";
|
|
181
|
+
readonly REVIEW_COMPLETED: "review_completed";
|
|
182
|
+
readonly TASK_MERGED: "task_merged";
|
|
183
|
+
readonly TASK_COMPLETED: "task_completed";
|
|
184
|
+
readonly GATE_BLOCKED: "gate_blocked";
|
|
185
|
+
};
|
|
186
|
+
export type EventType = typeof EVENT_TYPES[keyof typeof EVENT_TYPES];
|
|
187
|
+
/**
|
|
188
|
+
* Error codes
|
|
189
|
+
*/
|
|
190
|
+
export declare const ERROR_CODES: {
|
|
191
|
+
readonly MISSING_CHANGE: "missing-change";
|
|
192
|
+
readonly INVALID_CHANGE: "invalid-change";
|
|
193
|
+
readonly MISSING_TASK_ID: "missing-task-id";
|
|
194
|
+
readonly INVALID_TASK_ID: "invalid-task-id";
|
|
195
|
+
readonly MISSING_TASK_FILE: "missing-task-file";
|
|
196
|
+
readonly MISSING_SPEC: "missing-spec";
|
|
197
|
+
readonly MISSING_METADATA: "missing-metadata";
|
|
198
|
+
readonly ALREADY_EXISTS: "already-exists";
|
|
199
|
+
readonly NOT_FOUND: "not-found";
|
|
200
|
+
readonly VALIDATION_FAILED: "validation-failed";
|
|
201
|
+
readonly GATE_BLOCKED: "gate-blocked";
|
|
202
|
+
readonly MERGE_FAILED: "merge-failed";
|
|
203
|
+
readonly WORKTREE_CONFLICT: "worktree-conflict";
|
|
204
|
+
readonly REVIEW_NOT_PASSED: "review-not-passed";
|
|
205
|
+
readonly MISSING_REVIEW: "missing-review";
|
|
206
|
+
readonly MISSING_WORKTREE: "missing-worktree";
|
|
207
|
+
readonly MISSING_BRANCH: "missing-branch";
|
|
208
|
+
readonly DIRTY_WORKTREE: "dirty-worktree";
|
|
209
|
+
readonly CANCELLED: "cancelled";
|
|
210
|
+
readonly SYNC_FAILED: "sync-failed";
|
|
211
|
+
readonly UNKNOWN_ERROR: "unknown-error";
|
|
212
|
+
};
|
|
213
|
+
export type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES];
|
|
214
|
+
/**
|
|
215
|
+
* Default values
|
|
216
|
+
*/
|
|
217
|
+
export declare const DEFAULTS: {
|
|
218
|
+
readonly TIMEOUT: 300000;
|
|
219
|
+
readonly FORCE_KILL_TIMEOUT: 5000;
|
|
220
|
+
readonly MAX_HISTORY_ENTRIES: 100;
|
|
221
|
+
readonly MAX_WORKTREES: 10;
|
|
222
|
+
};
|