@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,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* hooks/hook-runner/loader.ts
|
|
4
|
+
* Hook loading 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.getDefaultHooksPath = getDefaultHooksPath;
|
|
41
|
+
exports.loadHooksConfig = loadHooksConfig;
|
|
42
|
+
exports.loadHookScriptAsync = loadHookScriptAsync;
|
|
43
|
+
exports.loadHookScript = loadHookScript;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const config_1 = require("../../lib/config");
|
|
47
|
+
/**
|
|
48
|
+
* Default hooks config
|
|
49
|
+
*/
|
|
50
|
+
const DEFAULT_HOOKS_CONFIG = {
|
|
51
|
+
hooks: {},
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Get default hooks path
|
|
55
|
+
*/
|
|
56
|
+
function getDefaultHooksPath(config) {
|
|
57
|
+
return path.resolve(config.harnessRootAbs, 'hooks.json');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Load hooks config from file
|
|
61
|
+
*/
|
|
62
|
+
function loadHooksConfig(config) {
|
|
63
|
+
const cfg = config || (0, config_1.loadConfig)();
|
|
64
|
+
const hooksPath = getDefaultHooksPath(cfg);
|
|
65
|
+
if (!fs.existsSync(hooksPath)) {
|
|
66
|
+
return { ...DEFAULT_HOOKS_CONFIG, configPath: hooksPath };
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const content = fs.readFileSync(hooksPath, 'utf8');
|
|
70
|
+
const parsed = JSON.parse(content);
|
|
71
|
+
return {
|
|
72
|
+
...DEFAULT_HOOKS_CONFIG,
|
|
73
|
+
...parsed,
|
|
74
|
+
configPath: hooksPath,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.warn('[HOOK-RUNNER] Failed to load hooks config:', error instanceof Error ? error.message : 'Unknown error');
|
|
79
|
+
return { ...DEFAULT_HOOKS_CONFIG, configPath: hooksPath };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Load hook script with dynamic import to avoid require.cache issues
|
|
84
|
+
*/
|
|
85
|
+
async function loadHookScriptAsync(scriptPath, config) {
|
|
86
|
+
const cfg = config || (0, config_1.loadConfig)();
|
|
87
|
+
const absolutePath = path.isAbsolute(scriptPath)
|
|
88
|
+
? scriptPath
|
|
89
|
+
: path.resolve(cfg.projectRoot, scriptPath);
|
|
90
|
+
if (!fs.existsSync(absolutePath)) {
|
|
91
|
+
console.warn('[HOOK-RUNNER] Hook script not found:', absolutePath);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const fileUrl = `file://${absolutePath}?t=${Date.now()}`;
|
|
96
|
+
const hookModule = await Promise.resolve(`${fileUrl}`).then(s => __importStar(require(s)));
|
|
97
|
+
return hookModule.default || hookModule;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.error('[HOOK-RUNNER] Failed to load hook script:', absolutePath, error instanceof Error ? error.message : 'Unknown error');
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Load hook script (legacy sync version)
|
|
106
|
+
* @deprecated Use loadHookScriptAsync instead
|
|
107
|
+
*/
|
|
108
|
+
function loadHookScript(scriptPath, config) {
|
|
109
|
+
const cfg = config || (0, config_1.loadConfig)();
|
|
110
|
+
const absolutePath = path.isAbsolute(scriptPath)
|
|
111
|
+
? scriptPath
|
|
112
|
+
: path.resolve(cfg.projectRoot, scriptPath);
|
|
113
|
+
if (!fs.existsSync(absolutePath)) {
|
|
114
|
+
console.warn('[HOOK-RUNNER] Hook script not found:', absolutePath);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
119
|
+
const hookModule = require(absolutePath);
|
|
120
|
+
return hookModule;
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
console.error('[HOOK-RUNNER] Failed to load hook script:', absolutePath, error instanceof Error ? error.message : 'Unknown error');
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hooks/hook-runner/types.ts
|
|
3
|
+
* Type definitions for hook runner
|
|
4
|
+
*/
|
|
5
|
+
import { Config } from '../../lib/config';
|
|
6
|
+
/**
|
|
7
|
+
* Hook lifecycle information
|
|
8
|
+
*/
|
|
9
|
+
export interface HookLifecycle {
|
|
10
|
+
phase: string;
|
|
11
|
+
timing: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Hook configuration
|
|
15
|
+
*/
|
|
16
|
+
export interface HookConfig {
|
|
17
|
+
name: string;
|
|
18
|
+
script: string;
|
|
19
|
+
enabled?: boolean;
|
|
20
|
+
timeout?: number;
|
|
21
|
+
hookName?: string;
|
|
22
|
+
lifecycle?: HookLifecycle;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Hook execution context
|
|
26
|
+
*/
|
|
27
|
+
export interface HookContext {
|
|
28
|
+
config?: Config;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Hook execution result
|
|
33
|
+
*/
|
|
34
|
+
export interface HookResult {
|
|
35
|
+
name?: string;
|
|
36
|
+
success: boolean;
|
|
37
|
+
result?: unknown;
|
|
38
|
+
error?: string;
|
|
39
|
+
script?: string;
|
|
40
|
+
stack?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Hook execution engine result
|
|
44
|
+
*/
|
|
45
|
+
export interface HookExecutionResult {
|
|
46
|
+
success: boolean;
|
|
47
|
+
executed: number;
|
|
48
|
+
results: HookResult[];
|
|
49
|
+
message?: string;
|
|
50
|
+
hookName?: string;
|
|
51
|
+
hookNames?: string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Loaded hooks config
|
|
55
|
+
*/
|
|
56
|
+
export interface LoadedHooksConfig {
|
|
57
|
+
hooks: Record<string, HookConfig[]>;
|
|
58
|
+
configPath: string;
|
|
59
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hooks/hook-runner.ts
|
|
3
|
+
* Backward-compatible re-export from hook-runner/ module
|
|
4
|
+
* @deprecated Import from './hook-runner/index' directly
|
|
5
|
+
*/
|
|
6
|
+
export { runHook, runHookSync, runHookChain, getHookLifecycle, getHooksForPhase, validateHookConfig, createHookConfig, HOOK_LIFECYCLE, default, } from './hook-runner/index';
|
|
7
|
+
export { HookLifecycle, HookConfig, HookContext, HookResult, HookExecutionResult, LoadedHooksConfig, } from './hook-runner/types';
|
|
8
|
+
export { getDefaultHooksPath, loadHooksConfig, loadHookScript, loadHookScriptAsync, } from './hook-runner/loader';
|
|
9
|
+
export { executeHookFunction, executeSingleHookAsync, executeSingleHookSync, } from './hook-runner/executor';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* hooks/hook-runner.ts
|
|
4
|
+
* Backward-compatible re-export from hook-runner/ module
|
|
5
|
+
* @deprecated Import from './hook-runner/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.executeSingleHookSync = exports.executeSingleHookAsync = exports.executeHookFunction = exports.loadHookScriptAsync = exports.loadHookScript = exports.loadHooksConfig = exports.getDefaultHooksPath = exports.default = exports.HOOK_LIFECYCLE = exports.createHookConfig = exports.validateHookConfig = exports.getHooksForPhase = exports.getHookLifecycle = exports.runHookChain = exports.runHookSync = exports.runHook = void 0;
|
|
12
|
+
var index_1 = require("./hook-runner/index");
|
|
13
|
+
Object.defineProperty(exports, "runHook", { enumerable: true, get: function () { return index_1.runHook; } });
|
|
14
|
+
Object.defineProperty(exports, "runHookSync", { enumerable: true, get: function () { return index_1.runHookSync; } });
|
|
15
|
+
Object.defineProperty(exports, "runHookChain", { enumerable: true, get: function () { return index_1.runHookChain; } });
|
|
16
|
+
Object.defineProperty(exports, "getHookLifecycle", { enumerable: true, get: function () { return index_1.getHookLifecycle; } });
|
|
17
|
+
Object.defineProperty(exports, "getHooksForPhase", { enumerable: true, get: function () { return index_1.getHooksForPhase; } });
|
|
18
|
+
Object.defineProperty(exports, "validateHookConfig", { enumerable: true, get: function () { return index_1.validateHookConfig; } });
|
|
19
|
+
Object.defineProperty(exports, "createHookConfig", { enumerable: true, get: function () { return index_1.createHookConfig; } });
|
|
20
|
+
Object.defineProperty(exports, "HOOK_LIFECYCLE", { enumerable: true, get: function () { return index_1.HOOK_LIFECYCLE; } });
|
|
21
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(index_1).default; } });
|
|
22
|
+
var loader_1 = require("./hook-runner/loader");
|
|
23
|
+
Object.defineProperty(exports, "getDefaultHooksPath", { enumerable: true, get: function () { return loader_1.getDefaultHooksPath; } });
|
|
24
|
+
Object.defineProperty(exports, "loadHooksConfig", { enumerable: true, get: function () { return loader_1.loadHooksConfig; } });
|
|
25
|
+
Object.defineProperty(exports, "loadHookScript", { enumerable: true, get: function () { return loader_1.loadHookScript; } });
|
|
26
|
+
Object.defineProperty(exports, "loadHookScriptAsync", { enumerable: true, get: function () { return loader_1.loadHookScriptAsync; } });
|
|
27
|
+
var executor_1 = require("./hook-runner/executor");
|
|
28
|
+
Object.defineProperty(exports, "executeHookFunction", { enumerable: true, get: function () { return executor_1.executeHookFunction; } });
|
|
29
|
+
Object.defineProperty(exports, "executeSingleHookAsync", { enumerable: true, get: function () { return executor_1.executeSingleHookAsync; } });
|
|
30
|
+
Object.defineProperty(exports, "executeSingleHookSync", { enumerable: true, get: function () { return executor_1.executeSingleHookSync; } });
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hooks/phase-complete-detector.ts
|
|
3
|
+
* Detect phase completion and update state
|
|
4
|
+
*/
|
|
5
|
+
import { Config } from '../lib/config';
|
|
6
|
+
import { State } from '../lib/state';
|
|
7
|
+
import { GateResult } from './phase-gate-validator';
|
|
8
|
+
export interface DetectOptions {
|
|
9
|
+
filePath: string;
|
|
10
|
+
config: Config;
|
|
11
|
+
state: State;
|
|
12
|
+
}
|
|
13
|
+
export interface DetectResult {
|
|
14
|
+
detected: boolean;
|
|
15
|
+
reason?: string;
|
|
16
|
+
blocked?: boolean;
|
|
17
|
+
gateResult?: GateResult;
|
|
18
|
+
phaseCompleted?: string;
|
|
19
|
+
newPhase?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Update task JSON phase status with error handling
|
|
23
|
+
*/
|
|
24
|
+
export declare function updateTaskJsonPhaseStatus(taskPath: string, phaseName: string, status: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Detect phase completion
|
|
27
|
+
* @param options - Options
|
|
28
|
+
* @returns Detection result
|
|
29
|
+
*/
|
|
30
|
+
export declare function detectPhaseCompletion(options: DetectOptions): DetectResult;
|
|
31
|
+
declare const _default: {
|
|
32
|
+
detectPhaseCompletion: typeof detectPhaseCompletion;
|
|
33
|
+
updateTaskJsonPhaseStatus: typeof updateTaskJsonPhaseStatus;
|
|
34
|
+
};
|
|
35
|
+
export default _default;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* hooks/phase-complete-detector.ts
|
|
4
|
+
* Detect phase completion and update state
|
|
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.updateTaskJsonPhaseStatus = updateTaskJsonPhaseStatus;
|
|
41
|
+
exports.detectPhaseCompletion = detectPhaseCompletion;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const config_1 = require("../lib/config");
|
|
45
|
+
const state_1 = require("../lib/state");
|
|
46
|
+
const archive_1 = require("../lib/archive");
|
|
47
|
+
const phase_gate_validator_1 = require("./phase-gate-validator");
|
|
48
|
+
const sync_task_to_openspec_1 = require("../spec/sync-task-to-openspec");
|
|
49
|
+
/**
|
|
50
|
+
* Update task JSON phase status with error handling
|
|
51
|
+
*/
|
|
52
|
+
function updateTaskJsonPhaseStatus(taskPath, phaseName, status) {
|
|
53
|
+
if (!fs.existsSync(taskPath)) {
|
|
54
|
+
console.warn(`[PHASE-DETECTOR] Task file not found: ${taskPath}`);
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const content = fs.readFileSync(taskPath, 'utf8');
|
|
59
|
+
const taskJson = JSON.parse(content);
|
|
60
|
+
taskJson.status = status;
|
|
61
|
+
fs.writeFileSync(taskPath, JSON.stringify(taskJson, null, 2), 'utf8');
|
|
62
|
+
console.log(`[PHASE-DETECTOR] Updated task JSON: ${phaseName} phase -> ${status}`);
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
console.error(`[PHASE-DETECTOR] Error updating task JSON: ${e.message}`);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Log gate blocked warnings with type-safe access
|
|
72
|
+
*/
|
|
73
|
+
function logGateBlockedWarnings(gateResult) {
|
|
74
|
+
if (!gateResult) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.warn(`[PHASE-DETECTOR] Phase blocked: ${gateResult.reason}`);
|
|
78
|
+
const missingValidations = Array.isArray(gateResult.missingValidations)
|
|
79
|
+
? gateResult.missingValidations
|
|
80
|
+
: [];
|
|
81
|
+
if (missingValidations.length > 0) {
|
|
82
|
+
console.warn(`[PHASE-DETECTOR] Missing: ${missingValidations.join(', ')}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Detect phase completion
|
|
87
|
+
* @param options - Options
|
|
88
|
+
* @returns Detection result
|
|
89
|
+
*/
|
|
90
|
+
function detectPhaseCompletion(options) {
|
|
91
|
+
const { filePath, config, state } = options;
|
|
92
|
+
if (!filePath.includes('.harness/')) {
|
|
93
|
+
return { detected: false, reason: 'not-harness-file' };
|
|
94
|
+
}
|
|
95
|
+
const taskId = state.currentTask;
|
|
96
|
+
if (!taskId) {
|
|
97
|
+
return { detected: false, reason: 'no-current-task' };
|
|
98
|
+
}
|
|
99
|
+
const gateResult = (0, phase_gate_validator_1.assessTransitionGate)({ taskId, filePath, state, config });
|
|
100
|
+
if (gateResult.skipped) {
|
|
101
|
+
return { detected: false, reason: 'gate-skipped' };
|
|
102
|
+
}
|
|
103
|
+
if (!gateResult.allowed) {
|
|
104
|
+
// Update state with blocked gate info
|
|
105
|
+
(0, state_1.updateState)({
|
|
106
|
+
lastGateBlockedAt: new Date().toISOString(),
|
|
107
|
+
lastGateBlockedReason: gateResult.reason,
|
|
108
|
+
lastGateBlockedPhase: gateResult.phaseCompleted || null,
|
|
109
|
+
lastMissingValidations: gateResult.missingValidations || [],
|
|
110
|
+
}, config);
|
|
111
|
+
// Archive task state
|
|
112
|
+
(0, archive_1.archiveTaskState)({
|
|
113
|
+
cwd: config.projectRoot,
|
|
114
|
+
taskId,
|
|
115
|
+
eventType: 'gate_blocked',
|
|
116
|
+
status: state.status || 'running',
|
|
117
|
+
phase: state.currentPhase || undefined,
|
|
118
|
+
phaseCompleted: gateResult.phaseCompleted || state.phaseCompleted || undefined,
|
|
119
|
+
reviewConclusion: state.reviewConclusion || undefined,
|
|
120
|
+
reason: gateResult.reason,
|
|
121
|
+
});
|
|
122
|
+
// Sync to Spec
|
|
123
|
+
(0, sync_task_to_openspec_1.syncTaskToSpec)({ cwd: config.projectRoot, taskId });
|
|
124
|
+
return {
|
|
125
|
+
detected: true,
|
|
126
|
+
blocked: true,
|
|
127
|
+
gateResult,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
// Phase transition allowed
|
|
131
|
+
const newPhase = gateResult.nextPhase;
|
|
132
|
+
const phaseCompleted = gateResult.phaseCompleted;
|
|
133
|
+
// Update state
|
|
134
|
+
(0, state_1.updateState)({
|
|
135
|
+
currentPhase: newPhase,
|
|
136
|
+
phaseCompleted,
|
|
137
|
+
reviewConclusion: gateResult.reviewConclusion || state.reviewConclusion || null,
|
|
138
|
+
lastGateBlockedAt: null,
|
|
139
|
+
lastGateBlockedReason: null,
|
|
140
|
+
lastGateBlockedPhase: null,
|
|
141
|
+
lastMissingValidations: [],
|
|
142
|
+
}, config);
|
|
143
|
+
// Update task JSON phase statuses
|
|
144
|
+
const taskPath = path.resolve(config.tasksDirAbs, `${taskId}.json`);
|
|
145
|
+
if (phaseCompleted) {
|
|
146
|
+
updateTaskJsonPhaseStatus(taskPath, phaseCompleted, 'completed');
|
|
147
|
+
}
|
|
148
|
+
if (newPhase && newPhase !== 'merge') {
|
|
149
|
+
updateTaskJsonPhaseStatus(taskPath, newPhase, 'in_progress');
|
|
150
|
+
}
|
|
151
|
+
// Archive task state
|
|
152
|
+
(0, archive_1.archiveTaskState)({
|
|
153
|
+
cwd: config.projectRoot,
|
|
154
|
+
taskId,
|
|
155
|
+
eventType: 'phase_transition',
|
|
156
|
+
status: state.status || 'running',
|
|
157
|
+
phase: newPhase || undefined,
|
|
158
|
+
phaseCompleted: phaseCompleted || undefined,
|
|
159
|
+
reviewConclusion: gateResult.reviewConclusion || undefined,
|
|
160
|
+
});
|
|
161
|
+
// Sync to Spec
|
|
162
|
+
(0, sync_task_to_openspec_1.syncTaskToSpec)({ cwd: config.projectRoot, taskId });
|
|
163
|
+
return {
|
|
164
|
+
detected: true,
|
|
165
|
+
blocked: false,
|
|
166
|
+
phaseCompleted,
|
|
167
|
+
newPhase,
|
|
168
|
+
gateResult,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Main entry point for hook usage
|
|
173
|
+
*/
|
|
174
|
+
function main() {
|
|
175
|
+
const input = JSON.parse(process.argv[2] || '{}');
|
|
176
|
+
const filePath = input.tool_input?.file_path || input.tool_input?.path || '';
|
|
177
|
+
const config = (0, config_1.loadConfig)();
|
|
178
|
+
const state = (0, state_1.loadState)(config);
|
|
179
|
+
if (!state?.currentTask) {
|
|
180
|
+
process.exit(0);
|
|
181
|
+
}
|
|
182
|
+
const result = detectPhaseCompletion({ filePath, config, state });
|
|
183
|
+
if (!result.detected || result.reason) {
|
|
184
|
+
process.exit(0);
|
|
185
|
+
}
|
|
186
|
+
if (result.blocked) {
|
|
187
|
+
logGateBlockedWarnings(result.gateResult);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
console.log(`[PHASE-DETECTOR] Phase transition: ${result.phaseCompleted} -> ${result.newPhase}`);
|
|
191
|
+
if (result.gateResult?.reviewConclusion) {
|
|
192
|
+
console.log(`[PHASE-DETECTOR] Review conclusion: ${result.gateResult.reviewConclusion}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
process.exit(0);
|
|
196
|
+
}
|
|
197
|
+
if (require.main === module) {
|
|
198
|
+
main();
|
|
199
|
+
}
|
|
200
|
+
exports.default = {
|
|
201
|
+
detectPhaseCompletion,
|
|
202
|
+
updateTaskJsonPhaseStatus,
|
|
203
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hooks/phase-gate-validator.ts
|
|
3
|
+
* Validate phase transition gates
|
|
4
|
+
*/
|
|
5
|
+
import { Config } from '../lib/config';
|
|
6
|
+
import { State } from '../lib/state';
|
|
7
|
+
export interface TaskJson {
|
|
8
|
+
status?: string;
|
|
9
|
+
validation?: {
|
|
10
|
+
commands?: string[];
|
|
11
|
+
manual_checks?: string[];
|
|
12
|
+
};
|
|
13
|
+
implementation?: {
|
|
14
|
+
notes?: string;
|
|
15
|
+
steps?: Array<string | {
|
|
16
|
+
step?: string;
|
|
17
|
+
}>;
|
|
18
|
+
};
|
|
19
|
+
metadata?: {
|
|
20
|
+
outputs?: {
|
|
21
|
+
task?: string;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface GateResult {
|
|
26
|
+
allowed: boolean;
|
|
27
|
+
skipped: boolean;
|
|
28
|
+
phaseCompleted?: string;
|
|
29
|
+
nextPhase?: string;
|
|
30
|
+
reason?: string;
|
|
31
|
+
missingValidations?: string[];
|
|
32
|
+
details?: string[];
|
|
33
|
+
validations?: string[];
|
|
34
|
+
reviewConclusion?: string | null;
|
|
35
|
+
}
|
|
36
|
+
export interface GateOptions {
|
|
37
|
+
taskId: string;
|
|
38
|
+
filePath: string;
|
|
39
|
+
state: State;
|
|
40
|
+
config: Config;
|
|
41
|
+
}
|
|
42
|
+
export declare function normalizePath(inputPath: string | undefined, projectRoot: string): string;
|
|
43
|
+
export declare function normalizeValidationName(name: string): string;
|
|
44
|
+
export declare function getValidationAliases(validationName: string): string[];
|
|
45
|
+
export declare function isPassedStatus(status: string | undefined): boolean;
|
|
46
|
+
export declare function parseReviewConclusion(content: string): string | null;
|
|
47
|
+
export declare function parseReviewValidationMap(content: string): Record<string, string>;
|
|
48
|
+
export declare function parseReviewReport(content: string): {
|
|
49
|
+
conclusion: string | null;
|
|
50
|
+
validationMap: Record<string, string>;
|
|
51
|
+
};
|
|
52
|
+
export declare function deriveTransitionFromFilePath(filePath: string, config: Config): {
|
|
53
|
+
phaseCompleted: string;
|
|
54
|
+
nextPhase: string;
|
|
55
|
+
relativePath: string;
|
|
56
|
+
} | null;
|
|
57
|
+
export declare function getTaskFilePath(config: Config, taskId: string): string;
|
|
58
|
+
export declare function readTaskJson(config: Config, taskId: string): TaskJson | null;
|
|
59
|
+
export declare function getValidationItems(taskJson: TaskJson | null, phaseName: string): string[];
|
|
60
|
+
export declare function getPlanningSummary(taskJson: TaskJson | null): string;
|
|
61
|
+
export declare function getPlanningList(taskJson: TaskJson | null, key: string): string[];
|
|
62
|
+
export declare function getSnapshotValidationMap(snapshotPath: string): Record<string, boolean>;
|
|
63
|
+
export declare function hasValidationPassed(validationName: string, snapshotValidationMap: Record<string, boolean | string>): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Assess transition gate
|
|
66
|
+
* @param options - Options
|
|
67
|
+
* @returns Gate assessment result
|
|
68
|
+
*/
|
|
69
|
+
export declare function assessTransitionGate(options: GateOptions): GateResult;
|
|
70
|
+
declare const _default: {
|
|
71
|
+
assessTransitionGate: typeof assessTransitionGate;
|
|
72
|
+
deriveTransitionFromFilePath: typeof deriveTransitionFromFilePath;
|
|
73
|
+
parseReviewConclusion: typeof parseReviewConclusion;
|
|
74
|
+
parseReviewReport: typeof parseReviewReport;
|
|
75
|
+
};
|
|
76
|
+
export default _default;
|