clavix 2.4.3 → 2.5.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/dist/cli/commands/task-complete.d.ts +27 -0
- package/dist/cli/commands/task-complete.js +305 -0
- package/dist/core/config-manager.d.ts +149 -0
- package/dist/core/config-manager.js +267 -0
- package/dist/core/git-manager.d.ts +27 -1
- package/dist/core/git-manager.js +114 -10
- package/dist/core/task-manager.d.ts +31 -0
- package/dist/core/task-manager.js +142 -0
- package/dist/templates/slash-commands/_canonical/implement.md +86 -33
- package/package.json +1 -1
- /package/dist/{core 2/adapters → core/adapters 2}/agents-md-generator.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/agents-md-generator.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/amp-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/amp-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/augment-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/augment-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/base-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/base-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/claude-code-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/claude-code-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/cline-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/cline-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/codebuddy-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/codebuddy-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/codex-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/codex-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/copilot-instructions-generator.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/copilot-instructions-generator.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/crush-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/crush-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/cursor-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/cursor-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/droid-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/droid-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/gemini-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/gemini-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/kilocode-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/kilocode-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/octo-md-generator.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/octo-md-generator.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/opencode-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/opencode-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/qwen-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/qwen-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/roocode-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/roocode-adapter.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/warp-md-generator.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/warp-md-generator.js +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/windsurf-adapter.d.ts +0 -0
- /package/dist/{core 2/adapters → core/adapters 2}/windsurf-adapter.js +0 -0
- /package/dist/{core 2/agent-manager.js → core/agent-manager 2.js} +0 -0
- /package/dist/{core 2/agent-manager.d.ts → core/agent-manager.d 2.ts} +0 -0
- /package/dist/{core 2/archive-manager.js → core/archive-manager 2.js} +0 -0
- /package/dist/{core 2/archive-manager.d.ts → core/archive-manager.d 2.ts} +0 -0
- /package/dist/{core 2/conversation-analyzer.d.ts → core/conversation-analyzer.d 2.ts} +0 -0
- /package/dist/{core 2/doc-injector.js → core/doc-injector 2.js} +0 -0
- /package/dist/{core 2/doc-injector.d.ts → core/doc-injector.d 2.ts} +0 -0
- /package/dist/{core 2/git-manager.js → core/git-manager 2.js} +0 -0
- /package/dist/{core 2/git-manager.d.ts → core/git-manager.d 2.ts} +0 -0
- /package/dist/{core 2/prompt-optimizer.js → core/prompt-optimizer 2.js} +0 -0
- /package/dist/{core 2/prompt-optimizer.d.ts → core/prompt-optimizer.d 2.ts} +0 -0
- /package/dist/{core 2/question-engine.js → core/question-engine 2.js} +0 -0
- /package/dist/{core 2/question-engine.d.ts → core/question-engine.d 2.ts} +0 -0
- /package/dist/{core 2/session-manager.js → core/session-manager 2.js} +0 -0
- /package/dist/{core 2/session-manager.d.ts → core/session-manager.d 2.ts} +0 -0
- /package/dist/{core 2/task-manager.js → core/task-manager 2.js} +0 -0
- /package/dist/{core 2/task-manager.d.ts → core/task-manager.d 2.ts} +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class TaskComplete extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
taskId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
'no-git': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
config: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Find config file (auto-discover or use provided path)
|
|
16
|
+
*/
|
|
17
|
+
private findConfigFile;
|
|
18
|
+
/**
|
|
19
|
+
* Handle git commit based on strategy
|
|
20
|
+
*/
|
|
21
|
+
private handleGitCommit;
|
|
22
|
+
/**
|
|
23
|
+
* Show next incomplete task
|
|
24
|
+
*/
|
|
25
|
+
private showNextTask;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=task-complete.d.ts.map
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const core_1 = require("@oclif/core");
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const task_manager_1 = require("../../core/task-manager");
|
|
42
|
+
const config_manager_1 = require("../../core/config-manager");
|
|
43
|
+
const git_manager_1 = require("../../core/git-manager");
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const fs = __importStar(require("fs-extra"));
|
|
46
|
+
class TaskComplete extends core_1.Command {
|
|
47
|
+
async run() {
|
|
48
|
+
const { args, flags } = await this.parse(TaskComplete);
|
|
49
|
+
const taskId = args.taskId;
|
|
50
|
+
console.log(chalk_1.default.bold.cyan(`\nTask Completion: ${taskId}\n`));
|
|
51
|
+
try {
|
|
52
|
+
const taskManager = new task_manager_1.TaskManager();
|
|
53
|
+
const configManager = new config_manager_1.ConfigManager();
|
|
54
|
+
const gitManager = new git_manager_1.GitManager();
|
|
55
|
+
// Find config file
|
|
56
|
+
const configPath = await this.findConfigFile(flags.config);
|
|
57
|
+
console.log(chalk_1.default.dim(`Config: ${configPath}\n`));
|
|
58
|
+
// Read config
|
|
59
|
+
const config = await configManager.read(configPath);
|
|
60
|
+
const tasksPath = config.tasksPath;
|
|
61
|
+
// Read tasks
|
|
62
|
+
const phases = await taskManager.readTasksFile(tasksPath);
|
|
63
|
+
// Validate task exists
|
|
64
|
+
const task = taskManager.validateTaskExists(phases, taskId);
|
|
65
|
+
if (!task) {
|
|
66
|
+
// Smart recovery: List available tasks
|
|
67
|
+
console.log(chalk_1.default.red(`✗ Task ID "${taskId}" not found\n`));
|
|
68
|
+
console.log(chalk_1.default.yellow('Available task IDs:\n'));
|
|
69
|
+
phases.forEach(phase => {
|
|
70
|
+
console.log(chalk_1.default.bold(` ${phase.name}:`));
|
|
71
|
+
phase.tasks.forEach(t => {
|
|
72
|
+
const status = t.completed ? chalk_1.default.green('[x]') : chalk_1.default.gray('[ ]');
|
|
73
|
+
console.log(` ${status} ${chalk_1.default.cyan(t.id)} - ${t.description}`);
|
|
74
|
+
});
|
|
75
|
+
console.log();
|
|
76
|
+
});
|
|
77
|
+
this.error('Task not found. Please use one of the task IDs listed above.');
|
|
78
|
+
}
|
|
79
|
+
// Check if already completed
|
|
80
|
+
if (task.completed && !flags.force) {
|
|
81
|
+
console.log(chalk_1.default.yellow(`⚠ Task "${taskId}" is already marked as completed\n`));
|
|
82
|
+
// Check if it's in config too
|
|
83
|
+
const isInConfig = await configManager.isTaskCompleted(configPath, taskId);
|
|
84
|
+
if (isInConfig) {
|
|
85
|
+
console.log(chalk_1.default.dim('Task is tracked in config as completed.\n'));
|
|
86
|
+
}
|
|
87
|
+
console.log(chalk_1.default.gray('Use --force to re-mark this task as completed.\n'));
|
|
88
|
+
// Show next task
|
|
89
|
+
await this.showNextTask(taskManager, phases);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Mark task as completed with validation
|
|
93
|
+
console.log(chalk_1.default.dim('Marking task as completed...'));
|
|
94
|
+
const result = await taskManager.markTaskCompletedWithValidation(tasksPath, taskId);
|
|
95
|
+
if (!result.success) {
|
|
96
|
+
// Smart recovery: Show error and suggestions
|
|
97
|
+
console.log(chalk_1.default.red(`\n✗ Failed to mark task as completed\n`));
|
|
98
|
+
console.log(chalk_1.default.yellow(`Error: ${result.error}\n`));
|
|
99
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
100
|
+
console.log(chalk_1.default.yellow('Warnings:'));
|
|
101
|
+
result.warnings.forEach(warning => console.log(chalk_1.default.yellow(` • ${warning}`)));
|
|
102
|
+
console.log();
|
|
103
|
+
}
|
|
104
|
+
// Provide recovery suggestions
|
|
105
|
+
console.log(chalk_1.default.bold('Recovery Options:\n'));
|
|
106
|
+
console.log(chalk_1.default.gray(' 1. Check if tasks.md file is readable and writable'));
|
|
107
|
+
console.log(chalk_1.default.gray(' 2. Verify task ID matches exactly (run "clavix implement" to see current task)'));
|
|
108
|
+
console.log(chalk_1.default.gray(' 3. Try running with --force flag if task is already completed'));
|
|
109
|
+
console.log(chalk_1.default.gray(' 4. Check tasks.md.backup file if one was created\n'));
|
|
110
|
+
this.error('Task completion failed');
|
|
111
|
+
}
|
|
112
|
+
// Display warnings if any
|
|
113
|
+
if (result.warnings && result.warnings.length > 0) {
|
|
114
|
+
console.log(chalk_1.default.yellow('\nWarnings:'));
|
|
115
|
+
result.warnings.forEach(warning => console.log(chalk_1.default.yellow(` • ${warning}`)));
|
|
116
|
+
console.log();
|
|
117
|
+
}
|
|
118
|
+
// Success!
|
|
119
|
+
if (result.alreadyCompleted) {
|
|
120
|
+
console.log(chalk_1.default.green(`✓ Task was already completed (tracking updated)\n`));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.log(chalk_1.default.green(`✓ Task marked as completed\n`));
|
|
124
|
+
}
|
|
125
|
+
// Track completion in config
|
|
126
|
+
console.log(chalk_1.default.dim('Updating configuration...'));
|
|
127
|
+
await configManager.trackCompletion(configPath, taskId);
|
|
128
|
+
// Update stats
|
|
129
|
+
const updatedStats = taskManager.getTaskStats(phases);
|
|
130
|
+
await configManager.update(configPath, { stats: updatedStats });
|
|
131
|
+
console.log(chalk_1.default.green('✓ Configuration updated\n'));
|
|
132
|
+
// Show progress
|
|
133
|
+
console.log(chalk_1.default.bold('Progress:'));
|
|
134
|
+
console.log(chalk_1.default.cyan(` Completed: ${updatedStats.completed}/${updatedStats.total} tasks (${updatedStats.percentage.toFixed(0)}%)`));
|
|
135
|
+
console.log(chalk_1.default.cyan(` Remaining: ${updatedStats.remaining} tasks\n`));
|
|
136
|
+
// Create git commit if enabled
|
|
137
|
+
if (!flags['no-git'] && config.commitStrategy !== 'none') {
|
|
138
|
+
await this.handleGitCommit(gitManager, configManager, configPath, config.commitStrategy, task, phases);
|
|
139
|
+
}
|
|
140
|
+
// Show next task
|
|
141
|
+
await this.showNextTask(taskManager, phases);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
const errorMessage = error instanceof Error ? error.message : 'An unexpected error occurred';
|
|
145
|
+
console.log(chalk_1.default.red(`\n✗ Error: ${errorMessage}\n`));
|
|
146
|
+
this.error(errorMessage);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Find config file (auto-discover or use provided path)
|
|
151
|
+
*/
|
|
152
|
+
async findConfigFile(providedPath) {
|
|
153
|
+
if (providedPath) {
|
|
154
|
+
if (await fs.pathExists(providedPath)) {
|
|
155
|
+
return providedPath;
|
|
156
|
+
}
|
|
157
|
+
throw new Error(`Config file not found: ${providedPath}`);
|
|
158
|
+
}
|
|
159
|
+
// Auto-discover: Look for .clavix/outputs/*/.clavix-implement-config.json
|
|
160
|
+
const outputsDir = path.join(process.cwd(), '.clavix', 'outputs');
|
|
161
|
+
if (!(await fs.pathExists(outputsDir))) {
|
|
162
|
+
throw new Error('No .clavix/outputs directory found.\n\nHint: Run "clavix implement" first to initialize');
|
|
163
|
+
}
|
|
164
|
+
// Search for config files
|
|
165
|
+
const entries = await fs.readdir(outputsDir, { withFileTypes: true });
|
|
166
|
+
const configFiles = [];
|
|
167
|
+
for (const entry of entries) {
|
|
168
|
+
if (!entry.isDirectory() || entry.name === 'archive') {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const configPath = path.join(outputsDir, entry.name, '.clavix-implement-config.json');
|
|
172
|
+
if (await fs.pathExists(configPath)) {
|
|
173
|
+
configFiles.push(configPath);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (configFiles.length === 0) {
|
|
177
|
+
throw new Error('No config files found.\n\nHint: Run "clavix implement" first to initialize');
|
|
178
|
+
}
|
|
179
|
+
// Use most recent config
|
|
180
|
+
const configsWithStats = await Promise.all(configFiles.map(async (filePath) => {
|
|
181
|
+
const stat = await fs.stat(filePath);
|
|
182
|
+
return { path: filePath, mtime: stat.mtime };
|
|
183
|
+
}));
|
|
184
|
+
configsWithStats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
185
|
+
return configsWithStats[0].path;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Handle git commit based on strategy
|
|
189
|
+
*/
|
|
190
|
+
async handleGitCommit(gitManager, configManager, configPath, strategy, completedTask, phases) {
|
|
191
|
+
console.log(chalk_1.default.dim(`Checking git commit strategy (${strategy})...`));
|
|
192
|
+
const config = await configManager.read(configPath);
|
|
193
|
+
const completedCount = config.completedTaskIds?.length ?? 0;
|
|
194
|
+
let shouldCommit = false;
|
|
195
|
+
let commitMessage = '';
|
|
196
|
+
switch (strategy) {
|
|
197
|
+
case 'per-task':
|
|
198
|
+
shouldCommit = true;
|
|
199
|
+
commitMessage = `clavix: ${completedTask.description}`;
|
|
200
|
+
break;
|
|
201
|
+
case 'per-5-tasks':
|
|
202
|
+
shouldCommit = completedCount % 5 === 0;
|
|
203
|
+
if (shouldCommit) {
|
|
204
|
+
const last5 = config.completedTaskIds?.slice(-5) ?? [];
|
|
205
|
+
const taskDescriptions = phases
|
|
206
|
+
.flatMap(p => p.tasks)
|
|
207
|
+
.filter((t) => last5.includes(t.id))
|
|
208
|
+
.map((t) => t.description);
|
|
209
|
+
commitMessage = `clavix: Completed ${last5.length} tasks\n\nCompleted tasks:\n${taskDescriptions.map(d => `- ${d}`).join('\n')}`;
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
case 'per-phase':
|
|
213
|
+
// Check if current phase is complete
|
|
214
|
+
const currentPhase = phases.find(p => p.name === completedTask.phase);
|
|
215
|
+
if (currentPhase) {
|
|
216
|
+
const phaseComplete = currentPhase.tasks.every((t) => t.completed);
|
|
217
|
+
shouldCommit = phaseComplete;
|
|
218
|
+
if (shouldCommit) {
|
|
219
|
+
commitMessage = `clavix: Completed ${currentPhase.name}\n\nCompleted tasks:\n${currentPhase.tasks.map((t) => `- ${t.description}`).join('\n')}`;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
case 'none':
|
|
224
|
+
default:
|
|
225
|
+
shouldCommit = false;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
if (!shouldCommit) {
|
|
229
|
+
console.log(chalk_1.default.dim('No commit needed (strategy criteria not met)\n'));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
// Check git status
|
|
233
|
+
const gitStatus = await gitManager.validateGitSetup();
|
|
234
|
+
if (!gitStatus.isRepo) {
|
|
235
|
+
console.log(chalk_1.default.yellow('⚠ Not a git repository - skipping commit\n'));
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (!gitStatus.hasChanges) {
|
|
239
|
+
console.log(chalk_1.default.dim('No git changes to commit\n'));
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
// Create commit
|
|
243
|
+
console.log(chalk_1.default.dim('Creating git commit...'));
|
|
244
|
+
const fullMessage = `${commitMessage}\n\nGenerated by Clavix task-complete`;
|
|
245
|
+
const success = await gitManager.createCommit({
|
|
246
|
+
message: fullMessage,
|
|
247
|
+
description: completedTask.description,
|
|
248
|
+
projectName: path.basename(path.dirname(configPath)),
|
|
249
|
+
});
|
|
250
|
+
if (success) {
|
|
251
|
+
console.log(chalk_1.default.green('✓ Git commit created\n'));
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
console.log(chalk_1.default.yellow('⚠ Git commit failed (non-critical)\n'));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Show next incomplete task
|
|
259
|
+
*/
|
|
260
|
+
async showNextTask(taskManager, phases) {
|
|
261
|
+
const nextTask = taskManager.findFirstIncompleteTask(phases);
|
|
262
|
+
if (!nextTask) {
|
|
263
|
+
console.log(chalk_1.default.bold.green('🎉 All tasks completed!\n'));
|
|
264
|
+
console.log(chalk_1.default.gray('Great work! All implementation tasks are done.\n'));
|
|
265
|
+
console.log(chalk_1.default.dim('Hint: Run "clavix archive" to archive this project\n'));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
console.log(chalk_1.default.bold('Next Task:'));
|
|
269
|
+
console.log(chalk_1.default.bold.white(` ID: ${chalk_1.default.cyan(nextTask.id)}`));
|
|
270
|
+
console.log(chalk_1.default.bold.white(` ${nextTask.description}`));
|
|
271
|
+
if (nextTask.prdReference) {
|
|
272
|
+
console.log(chalk_1.default.dim(` Reference: ${nextTask.prdReference}`));
|
|
273
|
+
}
|
|
274
|
+
console.log(chalk_1.default.dim(` Phase: ${nextTask.phase}\n`));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
TaskComplete.description = 'Mark a task as completed with validation and optional git commit';
|
|
278
|
+
TaskComplete.examples = [
|
|
279
|
+
'<%= config.bin %> <%= command.id %> phase-1-auth-1',
|
|
280
|
+
'<%= config.bin %> <%= command.id %> phase-2-api-3 --no-git',
|
|
281
|
+
'<%= config.bin %> <%= command.id %> setup-1 --force',
|
|
282
|
+
];
|
|
283
|
+
TaskComplete.args = {
|
|
284
|
+
taskId: core_1.Args.string({
|
|
285
|
+
description: 'Task ID to mark as completed',
|
|
286
|
+
required: true,
|
|
287
|
+
}),
|
|
288
|
+
};
|
|
289
|
+
TaskComplete.flags = {
|
|
290
|
+
'no-git': core_1.Flags.boolean({
|
|
291
|
+
description: 'Skip git commit even if strategy is enabled',
|
|
292
|
+
default: false,
|
|
293
|
+
}),
|
|
294
|
+
force: core_1.Flags.boolean({
|
|
295
|
+
char: 'f',
|
|
296
|
+
description: 'Force completion even if already marked complete',
|
|
297
|
+
default: false,
|
|
298
|
+
}),
|
|
299
|
+
config: core_1.Flags.string({
|
|
300
|
+
char: 'c',
|
|
301
|
+
description: 'Path to config file (defaults to auto-discover)',
|
|
302
|
+
}),
|
|
303
|
+
};
|
|
304
|
+
exports.default = TaskComplete;
|
|
305
|
+
//# sourceMappingURL=task-complete.js.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigManager - Manages .clavix-implement-config.json
|
|
3
|
+
*
|
|
4
|
+
* This class handles:
|
|
5
|
+
* - Reading/writing implementation configuration
|
|
6
|
+
* - Tracking task completion state
|
|
7
|
+
* - Managing resume checkpoints
|
|
8
|
+
* - Storing git commit strategy preferences
|
|
9
|
+
*/
|
|
10
|
+
import { Task } from './task-manager';
|
|
11
|
+
import { CommitStrategy } from './git-manager';
|
|
12
|
+
/**
|
|
13
|
+
* Configuration for task implementation
|
|
14
|
+
*/
|
|
15
|
+
export interface ImplementConfig {
|
|
16
|
+
/** Git commit strategy */
|
|
17
|
+
commitStrategy: CommitStrategy;
|
|
18
|
+
/** Path to tasks.md file */
|
|
19
|
+
tasksPath: string;
|
|
20
|
+
/** Current task being worked on */
|
|
21
|
+
currentTask: Task;
|
|
22
|
+
/** Overall task statistics */
|
|
23
|
+
stats: {
|
|
24
|
+
total: number;
|
|
25
|
+
completed: number;
|
|
26
|
+
remaining: number;
|
|
27
|
+
percentage: number;
|
|
28
|
+
};
|
|
29
|
+
/** Timestamp when config was last updated */
|
|
30
|
+
timestamp: string;
|
|
31
|
+
/** ID of the last completed task */
|
|
32
|
+
lastCompletedTaskId?: string;
|
|
33
|
+
/** Array of all completed task IDs (for validation and resume) */
|
|
34
|
+
completedTaskIds?: string[];
|
|
35
|
+
/** Timestamps for each task completion (for tracking progress) */
|
|
36
|
+
completionTimestamps?: Record<string, string>;
|
|
37
|
+
/** Array of blocked task IDs with reasons */
|
|
38
|
+
blockedTasks?: Array<{
|
|
39
|
+
taskId: string;
|
|
40
|
+
reason: string;
|
|
41
|
+
timestamp: string;
|
|
42
|
+
}>;
|
|
43
|
+
/** Resume checkpoint for interrupted sessions */
|
|
44
|
+
resumeCheckpoint?: {
|
|
45
|
+
lastTaskId: string;
|
|
46
|
+
phaseProgress: Record<string, number>;
|
|
47
|
+
sessionStartTime: string;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Options for updating config
|
|
52
|
+
*/
|
|
53
|
+
export interface ConfigUpdateOptions {
|
|
54
|
+
/** Merge with existing config (true) or overwrite (false) */
|
|
55
|
+
merge?: boolean;
|
|
56
|
+
/** Validate config structure before writing */
|
|
57
|
+
validate?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* ConfigManager class
|
|
61
|
+
*
|
|
62
|
+
* Manages implementation configuration and task tracking state
|
|
63
|
+
*/
|
|
64
|
+
export declare class ConfigManager {
|
|
65
|
+
/**
|
|
66
|
+
* Read implementation config from file
|
|
67
|
+
* @param configPath - Path to config file (.clavix-implement-config.json)
|
|
68
|
+
* @returns Implementation configuration
|
|
69
|
+
*/
|
|
70
|
+
read(configPath: string): Promise<ImplementConfig>;
|
|
71
|
+
/**
|
|
72
|
+
* Write implementation config to file
|
|
73
|
+
* @param configPath - Path to config file
|
|
74
|
+
* @param config - Configuration to write
|
|
75
|
+
* @param options - Update options
|
|
76
|
+
*/
|
|
77
|
+
write(configPath: string, config: ImplementConfig, options?: ConfigUpdateOptions): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Update specific fields in config
|
|
80
|
+
* @param configPath - Path to config file
|
|
81
|
+
* @param updates - Partial config updates
|
|
82
|
+
*/
|
|
83
|
+
update(configPath: string, updates: Partial<ImplementConfig>): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Track a task completion
|
|
86
|
+
* @param configPath - Path to config file
|
|
87
|
+
* @param taskId - ID of completed task
|
|
88
|
+
*/
|
|
89
|
+
trackCompletion(configPath: string, taskId: string): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Add a blocked task
|
|
92
|
+
* @param configPath - Path to config file
|
|
93
|
+
* @param taskId - ID of blocked task
|
|
94
|
+
* @param reason - Reason for blocking
|
|
95
|
+
*/
|
|
96
|
+
addBlockedTask(configPath: string, taskId: string, reason: string): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Remove a blocked task (unblock)
|
|
99
|
+
* @param configPath - Path to config file
|
|
100
|
+
* @param taskId - ID of task to unblock
|
|
101
|
+
*/
|
|
102
|
+
removeBlockedTask(configPath: string, taskId: string): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Get current implementation state
|
|
105
|
+
* @param configPath - Path to config file
|
|
106
|
+
* @returns State summary
|
|
107
|
+
*/
|
|
108
|
+
getState(configPath: string): Promise<{
|
|
109
|
+
currentTaskId: string;
|
|
110
|
+
completedCount: number;
|
|
111
|
+
remainingCount: number;
|
|
112
|
+
blockedCount: number;
|
|
113
|
+
lastCompletedTaskId?: string;
|
|
114
|
+
lastCompletionTime?: string;
|
|
115
|
+
}>;
|
|
116
|
+
/**
|
|
117
|
+
* Check if a task has been completed
|
|
118
|
+
* @param configPath - Path to config file
|
|
119
|
+
* @param taskId - Task ID to check
|
|
120
|
+
* @returns true if task is in completed list
|
|
121
|
+
*/
|
|
122
|
+
isTaskCompleted(configPath: string, taskId: string): Promise<boolean>;
|
|
123
|
+
/**
|
|
124
|
+
* Validate config structure
|
|
125
|
+
* @param config - Configuration to validate
|
|
126
|
+
* @throws Error if config is invalid
|
|
127
|
+
*/
|
|
128
|
+
private validateConfig;
|
|
129
|
+
/**
|
|
130
|
+
* Migrate old config format to new format
|
|
131
|
+
* @param config - Old config format
|
|
132
|
+
* @returns Migrated config
|
|
133
|
+
*/
|
|
134
|
+
private migrateConfig;
|
|
135
|
+
/**
|
|
136
|
+
* Create a resume checkpoint
|
|
137
|
+
* @param configPath - Path to config file
|
|
138
|
+
* @param currentTaskId - Current task being worked on
|
|
139
|
+
* @param phaseProgress - Progress by phase (phase name -> completed count)
|
|
140
|
+
*/
|
|
141
|
+
createResumeCheckpoint(configPath: string, currentTaskId: string, phaseProgress: Record<string, number>): Promise<void>;
|
|
142
|
+
/**
|
|
143
|
+
* Get the config file path for a PRD directory
|
|
144
|
+
* @param prdPath - Path to PRD directory
|
|
145
|
+
* @returns Path to config file
|
|
146
|
+
*/
|
|
147
|
+
static getConfigPath(prdPath: string): string;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=config-manager.d.ts.map
|