@tmddev/tmd 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.
Files changed (53) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +424 -0
  3. package/bin/tmd.js +3 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.js +92 -0
  6. package/dist/commands/act.d.ts +3 -0
  7. package/dist/commands/act.js +210 -0
  8. package/dist/commands/check.d.ts +3 -0
  9. package/dist/commands/check.js +183 -0
  10. package/dist/commands/do.d.ts +3 -0
  11. package/dist/commands/do.js +310 -0
  12. package/dist/commands/list.d.ts +3 -0
  13. package/dist/commands/list.js +56 -0
  14. package/dist/commands/plan.d.ts +3 -0
  15. package/dist/commands/plan.js +89 -0
  16. package/dist/commands/show.d.ts +2 -0
  17. package/dist/commands/show.js +69 -0
  18. package/dist/commands/skills.d.ts +3 -0
  19. package/dist/commands/skills.js +243 -0
  20. package/dist/types.d.ts +79 -0
  21. package/dist/types.js +5 -0
  22. package/dist/utils/act-processing.d.ts +64 -0
  23. package/dist/utils/act-processing.js +222 -0
  24. package/dist/utils/analysis.d.ts +34 -0
  25. package/dist/utils/analysis.js +159 -0
  26. package/dist/utils/comparison.d.ts +34 -0
  27. package/dist/utils/comparison.js +217 -0
  28. package/dist/utils/language-validator.d.ts +11 -0
  29. package/dist/utils/language-validator.js +39 -0
  30. package/dist/utils/openspec.d.ts +5 -0
  31. package/dist/utils/openspec.js +91 -0
  32. package/dist/utils/paths.d.ts +10 -0
  33. package/dist/utils/paths.js +33 -0
  34. package/dist/utils/skills.d.ts +3 -0
  35. package/dist/utils/skills.js +248 -0
  36. package/dist/utils/skillssh.d.ts +12 -0
  37. package/dist/utils/skillssh.js +135 -0
  38. package/dist/utils/standardization.d.ts +26 -0
  39. package/dist/utils/standardization.js +106 -0
  40. package/dist/utils/task-chain.d.ts +35 -0
  41. package/dist/utils/task-chain.js +146 -0
  42. package/dist/utils/task-id.d.ts +5 -0
  43. package/dist/utils/task-id.js +15 -0
  44. package/dist/utils/task-status.d.ts +6 -0
  45. package/dist/utils/task-status.js +61 -0
  46. package/dist/utils/task-validator.d.ts +42 -0
  47. package/dist/utils/task-validator.js +178 -0
  48. package/dist/utils/tasks.d.ts +27 -0
  49. package/dist/utils/tasks.js +125 -0
  50. package/dist/utils/templates.d.ts +12 -0
  51. package/dist/utils/templates.js +143 -0
  52. package/package.json +84 -0
  53. package/scripts/postinstall.js +92 -0
@@ -0,0 +1,310 @@
1
+ import { existsSync, appendFileSync, readFileSync } from 'fs';
2
+ import { ensureDir, getDoDir, getPlanDir } from '../utils/paths.js';
3
+ import { executionTemplate, renderTemplate } from '../utils/templates.js';
4
+ import { updateTaskStatus as updatePhaseStatus } from '../utils/task-status.js';
5
+ import { executeSkill } from '../utils/skills.js';
6
+ import { extractTasks, updateTaskStatus, detectSkillReference } from '../utils/tasks.js';
7
+ import { executeConcurrently } from '../utils/task-chain.js';
8
+ import { writeFileSync } from 'fs';
9
+ import { join } from 'path';
10
+ import chalk from 'chalk';
11
+ function displayTasks(tasks, showProgress = true) {
12
+ if (tasks.length === 0) {
13
+ console.log(chalk.yellow(' No tasks found in plan.md'));
14
+ return;
15
+ }
16
+ const completed = tasks.filter(t => t.completed).length;
17
+ const total = tasks.length;
18
+ const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;
19
+ if (showProgress) {
20
+ console.log(chalk.blue(`\n Task Progress: ${String(completed)}/${String(total)} (${String(percentage)}%)`));
21
+ }
22
+ console.log(chalk.blue('\n Tasks:'));
23
+ for (const task of tasks) {
24
+ const checkbox = task.completed ? chalk.green('[x]') : chalk.gray('[ ]');
25
+ const index = chalk.dim(`[${String(task.index)}]`);
26
+ console.log(` ${checkbox} ${index} ${task.content}`);
27
+ // Show dependencies if present
28
+ if (task.dependencies && task.dependencies.length > 0) {
29
+ const deps = task.dependencies.map(d => `task-${String(d)}`).join(', ');
30
+ console.log(chalk.gray(` → depends: ${deps}`));
31
+ }
32
+ // Show skill reference if present
33
+ const skillRef = detectSkillReference(task.content);
34
+ if (skillRef) {
35
+ console.log(chalk.gray(` → skill: ${skillRef}`));
36
+ }
37
+ }
38
+ }
39
+ function recordTaskCompletion(doDir, taskIndex, taskContent) {
40
+ const executionPath = join(doDir, 'execution.md');
41
+ const timestamp = new Date().toISOString();
42
+ let executionContent = '';
43
+ if (existsSync(executionPath)) {
44
+ executionContent = readFileSync(executionPath, 'utf-8');
45
+ }
46
+ else {
47
+ executionContent = renderTemplate(executionTemplate, { taskId: '' });
48
+ }
49
+ // Append task completion record
50
+ const completionRecord = `\n## Task Completions\n\n- [${timestamp}] Task ${String(taskIndex)}: ${taskContent}\n`;
51
+ // Check if "Task Completions" section exists
52
+ if (executionContent.includes('## Task Completions')) {
53
+ // Append to existing section
54
+ executionContent = executionContent.replace(/(## Task Completions\n\n)/, `$1- [${timestamp}] Task ${String(taskIndex)}: ${taskContent}\n`);
55
+ }
56
+ else {
57
+ // Add new section before "## Issues Encountered" or at the end
58
+ if (executionContent.includes('## Issues Encountered')) {
59
+ executionContent = executionContent.replace(/(## Issues Encountered)/, `## Task Completions\n\n- [${timestamp}] Task ${String(taskIndex)}: ${taskContent}\n\n$1`);
60
+ }
61
+ else {
62
+ executionContent += completionRecord;
63
+ }
64
+ }
65
+ writeFileSync(executionPath, executionContent, 'utf-8');
66
+ }
67
+ function recordConcurrentExecution(doDir, results) {
68
+ const executionPath = join(doDir, 'execution.md');
69
+ const timestamp = new Date().toISOString();
70
+ let executionContent = '';
71
+ if (existsSync(executionPath)) {
72
+ executionContent = readFileSync(executionPath, 'utf-8');
73
+ }
74
+ else {
75
+ executionContent = renderTemplate(executionTemplate, { taskId: '' });
76
+ }
77
+ const successCount = results.filter(r => r.success).length;
78
+ const failCount = results.length - successCount;
79
+ const summary = `\n## Concurrent Execution Results\n\n- Execution started: ${timestamp}\n- Total tasks: ${String(results.length)}\n- Successful: ${String(successCount)}\n- Failed: ${String(failCount)}\n\n### Task Results\n\n`;
80
+ let resultsList = '';
81
+ for (const result of results) {
82
+ const status = result.success ? 'SUCCESS' : 'FAILED';
83
+ const errorInfo = result.error ? ` (${result.error})` : '';
84
+ resultsList += `- Task ${String(result.taskIndex)}: ${status} (${String(result.duration)}ms)${errorInfo}\n`;
85
+ }
86
+ const resultsSection = summary + resultsList;
87
+ // Check if "Concurrent Execution Results" section exists
88
+ if (executionContent.includes('## Concurrent Execution Results')) {
89
+ // Replace existing section
90
+ executionContent = executionContent.replace(/## Concurrent Execution Results[\s\S]*?(?=\n## |$)/, resultsSection.trim());
91
+ }
92
+ else {
93
+ // Add new section before "## Issues Encountered" or at the end
94
+ if (executionContent.includes('## Issues Encountered')) {
95
+ executionContent = executionContent.replace(/(## Issues Encountered)/, `${resultsSection}\n$1`);
96
+ }
97
+ else {
98
+ executionContent += resultsSection;
99
+ }
100
+ }
101
+ writeFileSync(executionPath, executionContent, 'utf-8');
102
+ }
103
+ function recordSkillExecution(doDir, skillName, success, error) {
104
+ const executionPath = join(doDir, 'execution.md');
105
+ const timestamp = new Date().toISOString();
106
+ let executionContent = '';
107
+ if (existsSync(executionPath)) {
108
+ executionContent = readFileSync(executionPath, 'utf-8');
109
+ }
110
+ else {
111
+ executionContent = renderTemplate(executionTemplate, { taskId: '' });
112
+ }
113
+ const status = success ? 'SUCCESS' : 'FAILED';
114
+ const skillRecord = `- [${timestamp}] Skill: ${skillName} - ${status}${error ? ` (${error})` : ''}\n`;
115
+ // Check if "Skill Executions" section exists
116
+ if (executionContent.includes('## Skill Executions')) {
117
+ // Append to existing section
118
+ executionContent = executionContent.replace(/(## Skill Executions\n\n)/, `$1${skillRecord}`);
119
+ }
120
+ else {
121
+ // Add new section before "## Issues Encountered" or at the end
122
+ const skillSection = `\n## Skill Executions\n\n${skillRecord}`;
123
+ if (executionContent.includes('## Issues Encountered')) {
124
+ executionContent = executionContent.replace(/(## Issues Encountered)/, `${skillSection}\n$1`);
125
+ }
126
+ else {
127
+ executionContent += skillSection;
128
+ }
129
+ }
130
+ writeFileSync(executionPath, executionContent, 'utf-8');
131
+ }
132
+ export async function doCommand(taskId, options) {
133
+ // Validate plan exists
134
+ const planPath = join(getPlanDir(taskId), 'plan.md');
135
+ if (!existsSync(planPath)) {
136
+ console.error(chalk.red(`āœ— Plan not found for task: ${taskId}`));
137
+ process.exit(1);
138
+ }
139
+ // Extract tasks from plan
140
+ const tasks = extractTasks(planPath);
141
+ // Handle --list option: show task status without modifying
142
+ if (options.list) {
143
+ console.log(chalk.blue(`\nTask Status for: ${taskId}`));
144
+ displayTasks(tasks, true);
145
+ return;
146
+ }
147
+ // Handle --task option: mark specific task as complete
148
+ if (options.task !== undefined) {
149
+ const taskIndex = options.task;
150
+ const task = tasks.find(t => t.index === taskIndex);
151
+ if (!task) {
152
+ console.error(chalk.red(`āœ— Task at index ${String(taskIndex)} not found`));
153
+ process.exit(1);
154
+ }
155
+ if (task.completed) {
156
+ console.log(chalk.yellow(` Task ${String(taskIndex)} is already completed`));
157
+ return;
158
+ }
159
+ const doDir = getDoDir(taskId);
160
+ ensureDir(doDir);
161
+ // Ensure execution.md exists
162
+ const executionPath = join(doDir, 'execution.md');
163
+ if (!existsSync(executionPath)) {
164
+ const executionContent = renderTemplate(executionTemplate, { taskId });
165
+ writeFileSync(executionPath, executionContent);
166
+ }
167
+ // If --skill option is provided, execute skill first and only mark complete if successful
168
+ // Otherwise, mark task as complete immediately
169
+ const hasSkillOption = !!options.skill;
170
+ const skillRef = detectSkillReference(task.content);
171
+ const shouldExecuteSkill = hasSkillOption || skillRef;
172
+ if (shouldExecuteSkill) {
173
+ try {
174
+ // Execute skill from --skill option if provided
175
+ if (options.skill) {
176
+ await executeSkill(options.skill, taskId, false); // Sequential for single task execution
177
+ recordSkillExecution(doDir, options.skill, true);
178
+ }
179
+ // Check for skill reference and execute if present
180
+ if (skillRef) {
181
+ console.log(chalk.blue(` Detected skill reference: ${skillRef}`));
182
+ await executeSkill(skillRef, taskId, false); // Sequential for single task execution
183
+ recordSkillExecution(doDir, skillRef, true);
184
+ }
185
+ // Only mark task as complete if skill execution succeeded
186
+ updateTaskStatus(planPath, taskIndex, true);
187
+ recordTaskCompletion(doDir, taskIndex, task.content);
188
+ console.log(chalk.green(`āœ“ Task ${String(taskIndex)} marked as complete`));
189
+ }
190
+ catch (error) {
191
+ const errorMessage = error instanceof Error ? error.message : String(error);
192
+ // Record failed skill execution
193
+ if (options.skill) {
194
+ recordSkillExecution(doDir, options.skill, false, errorMessage);
195
+ }
196
+ if (skillRef) {
197
+ recordSkillExecution(doDir, skillRef, false, errorMessage);
198
+ }
199
+ console.error(chalk.red(`āœ— Skill execution failed. Task ${String(taskIndex)} not marked as complete.`));
200
+ throw error;
201
+ }
202
+ }
203
+ else {
204
+ // No skill execution required, mark task as complete immediately
205
+ updateTaskStatus(planPath, taskIndex, true);
206
+ recordTaskCompletion(doDir, taskIndex, task.content);
207
+ console.log(chalk.green(`āœ“ Task ${String(taskIndex)} marked as complete`));
208
+ }
209
+ // Show updated task list
210
+ const updatedTasks = extractTasks(planPath);
211
+ displayTasks(updatedTasks, true);
212
+ return;
213
+ }
214
+ // Normal execution: start do phase
215
+ const doDir = getDoDir(taskId);
216
+ ensureDir(doDir);
217
+ // Create execution.md if it doesn't exist
218
+ const executionPath = join(doDir, 'execution.md');
219
+ if (!existsSync(executionPath)) {
220
+ const executionContent = renderTemplate(executionTemplate, { taskId });
221
+ writeFileSync(executionPath, executionContent);
222
+ }
223
+ // Create data.md if it doesn't exist
224
+ const dataPath = join(doDir, 'data.md');
225
+ if (!existsSync(dataPath)) {
226
+ writeFileSync(dataPath, '# Data Collection\n\n');
227
+ }
228
+ // Update task status
229
+ updatePhaseStatus(taskId, 'doing');
230
+ console.log(chalk.green(`āœ“ Started execution phase for task: ${taskId}`));
231
+ console.log(chalk.blue(` Directory: ${doDir}`));
232
+ // Display tasks with progress
233
+ displayTasks(tasks, true);
234
+ // Concurrent execution if enabled
235
+ if (options.parallel) {
236
+ const maxConcurrency = options.maxConcurrency ?? Infinity;
237
+ const incompleteTasks = tasks.filter(t => !t.completed);
238
+ if (incompleteTasks.length === 0) {
239
+ console.log(chalk.yellow(' All tasks already completed'));
240
+ }
241
+ else {
242
+ console.log(chalk.blue(`\n Executing ${String(incompleteTasks.length)} tasks concurrently (max: ${maxConcurrency === Infinity ? 'unlimited' : String(maxConcurrency)})...`));
243
+ try {
244
+ const results = await executeConcurrently(incompleteTasks, async (task) => {
245
+ const startTime = Date.now();
246
+ try {
247
+ // Execute task (mark as complete)
248
+ updateTaskStatus(planPath, task.index, true);
249
+ recordTaskCompletion(doDir, task.index, task.content);
250
+ // Execute skill if referenced (with parallel support)
251
+ const skillRef = detectSkillReference(task.content);
252
+ if (skillRef) {
253
+ await executeSkill(skillRef, taskId, options.parallel, options.maxConcurrency);
254
+ recordSkillExecution(doDir, skillRef, true);
255
+ }
256
+ const duration = Date.now() - startTime;
257
+ console.log(chalk.green(` āœ“ Task ${String(task.index)} completed (${String(duration)}ms)`));
258
+ return {
259
+ taskIndex: task.index,
260
+ success: true,
261
+ duration
262
+ };
263
+ }
264
+ catch (error) {
265
+ const duration = Date.now() - startTime;
266
+ const errorMessage = error instanceof Error ? error.message : String(error);
267
+ console.error(chalk.red(` āœ— Task ${String(task.index)} failed: ${errorMessage}`));
268
+ return {
269
+ taskIndex: task.index,
270
+ success: false,
271
+ error: errorMessage,
272
+ duration
273
+ };
274
+ }
275
+ }, maxConcurrency);
276
+ // Record concurrent execution results
277
+ recordConcurrentExecution(doDir, results);
278
+ // Display summary
279
+ const successCount = results.filter(r => r.success).length;
280
+ const failCount = results.length - successCount;
281
+ console.log(chalk.blue(`\n Execution Summary:`));
282
+ console.log(chalk.green(` Successful: ${String(successCount)}`));
283
+ if (failCount > 0) {
284
+ console.log(chalk.red(` Failed: ${String(failCount)}`));
285
+ }
286
+ // Show updated task list
287
+ const updatedTasks = extractTasks(planPath);
288
+ displayTasks(updatedTasks, true);
289
+ }
290
+ catch (error) {
291
+ const errorMessage = error instanceof Error ? error.message : String(error);
292
+ console.error(chalk.red(`āœ— Concurrent execution failed: ${errorMessage}`));
293
+ throw error;
294
+ }
295
+ }
296
+ }
297
+ // Data collection
298
+ if (options.data) {
299
+ const [key, value] = options.data.split('=');
300
+ const safeKey = key ?? '';
301
+ const safeValue = value ?? '';
302
+ appendFileSync(dataPath, `- ${safeKey}: ${safeValue}\n`);
303
+ console.log(chalk.green(` Recorded data: ${safeKey}=${safeValue}`));
304
+ }
305
+ // Skill execution
306
+ if (options.skill) {
307
+ await executeSkill(options.skill, taskId, options.parallel, options.maxConcurrency);
308
+ }
309
+ }
310
+ //# sourceMappingURL=do.js.map
@@ -0,0 +1,3 @@
1
+ import type { ListCommandOptions } from '../types.js';
2
+ export declare function listCommand(options: ListCommandOptions): void;
3
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1,56 @@
1
+ import { readdirSync, existsSync } from 'fs';
2
+ import { getTmdDir } from '../utils/paths.js';
3
+ import { getTaskStatus } from '../utils/task-status.js';
4
+ import { join } from 'path';
5
+ import chalk from 'chalk';
6
+ export function listCommand(options) {
7
+ const tmdDir = getTmdDir();
8
+ if (!existsSync(tmdDir)) {
9
+ console.log(chalk.yellow('No tasks found. Create one with: tmd plan "description"'));
10
+ return;
11
+ }
12
+ const planDir = join(tmdDir, 'plan');
13
+ if (!existsSync(planDir)) {
14
+ console.log(chalk.yellow('No tasks found. Create one with: tmd plan "description"'));
15
+ return;
16
+ }
17
+ let tasks = readdirSync(planDir, { withFileTypes: true })
18
+ .filter(dirent => dirent.isDirectory())
19
+ .map(dirent => dirent.name);
20
+ if (tasks.length === 0) {
21
+ console.log(chalk.yellow('No tasks found. Create one with: tmd plan "description"'));
22
+ return;
23
+ }
24
+ // Filter by status if provided
25
+ if (options.status) {
26
+ tasks = tasks.filter(taskId => getTaskStatus(taskId) === options.status);
27
+ }
28
+ // Filter by phase if provided
29
+ if (options.phase) {
30
+ tasks = tasks.filter(taskId => {
31
+ const status = getTaskStatus(taskId);
32
+ return status === options.phase ||
33
+ (options.phase === 'plan' && status === 'planning') ||
34
+ (options.phase === 'do' && status === 'doing') ||
35
+ (options.phase === 'check' && status === 'checking') ||
36
+ (options.phase === 'act' && status === 'acting');
37
+ });
38
+ }
39
+ if (tasks.length === 0) {
40
+ console.log(chalk.yellow('No tasks found matching the criteria'));
41
+ return;
42
+ }
43
+ console.log(chalk.bold('\nTasks:'));
44
+ console.log('─'.repeat(60));
45
+ for (const taskId of tasks) {
46
+ const status = getTaskStatus(taskId);
47
+ const statusColor = status === 'completed' ? chalk.green :
48
+ status === 'acting' ? chalk.blue :
49
+ status === 'checking' ? chalk.yellow :
50
+ status === 'doing' ? chalk.cyan : chalk.gray;
51
+ console.log(` ${chalk.cyan(taskId)} - ${statusColor(status)}`);
52
+ }
53
+ console.log('─'.repeat(60));
54
+ console.log(chalk.gray(`Total: ${String(tasks.length)} task(s)`));
55
+ }
56
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1,3 @@
1
+ import type { PlanCommandOptions } from '../types.js';
2
+ export declare function planCommand(description: string, options: PlanCommandOptions): void;
3
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1,89 @@
1
+ import { ensureDir, getPlanDir } from '../utils/paths.js';
2
+ import { generateTaskId } from '../utils/task-id.js';
3
+ import { planTemplate, resourcesTemplate, renderTemplate } from '../utils/templates.js';
4
+ import { updateTaskStatus } from '../utils/task-status.js';
5
+ import { createOpenSpecChange } from '../utils/openspec.js';
6
+ import { createSkill } from '../utils/skills.js';
7
+ import { extractTasks } from '../utils/tasks.js';
8
+ import { validateTasks } from '../utils/task-validator.js';
9
+ import { writeFileSync, existsSync } from 'fs';
10
+ import { join } from 'path';
11
+ import chalk from 'chalk';
12
+ export function planCommand(description, options) {
13
+ const taskId = generateTaskId(description);
14
+ const planDir = getPlanDir(taskId);
15
+ ensureDir(planDir);
16
+ // Create plan.md
17
+ const planContent = renderTemplate(planTemplate, { description });
18
+ writeFileSync(join(planDir, 'plan.md'), planContent);
19
+ // Create resources.md
20
+ const resourcesContent = renderTemplate(resourcesTemplate, { description });
21
+ writeFileSync(join(planDir, 'resources.md'), resourcesContent);
22
+ // Initialize task status
23
+ updateTaskStatus(taskId, 'planning');
24
+ console.log(chalk.green(`āœ“ Created plan for task: ${taskId}`));
25
+ console.log(chalk.blue(` Directory: ${planDir}`));
26
+ // OpenSpec integration
27
+ if (options.openspec) {
28
+ const changeId = createOpenSpecChange(description, taskId);
29
+ if (changeId) {
30
+ console.log(chalk.green(` Linked to OpenSpec change: ${changeId}`));
31
+ }
32
+ }
33
+ // Skill creation
34
+ if (options.skill) {
35
+ const skillName = createSkill(description, taskId);
36
+ if (skillName) {
37
+ console.log(chalk.green(` Created skill: ${skillName}`));
38
+ }
39
+ }
40
+ // Use existing skill
41
+ if (options.useSkill) {
42
+ console.log(chalk.blue(` Using skill: ${options.useSkill}`));
43
+ // TODO: Link skill to task
44
+ }
45
+ // Task validation
46
+ if (options.validateTasks) {
47
+ const planPath = join(planDir, 'plan.md');
48
+ if (existsSync(planPath)) {
49
+ const tasks = extractTasks(planPath);
50
+ if (tasks.length > 0) {
51
+ const taskDescriptions = tasks.map(t => t.content);
52
+ const validation = validateTasks(taskDescriptions);
53
+ console.log(chalk.blue('\nšŸ“‹ Task Size Validation:'));
54
+ console.log(chalk.blue(` Total tasks: ${String(validation.summary.total)}`));
55
+ console.log(chalk.green(` Valid (pee-break sized): ${String(validation.summary.valid)}`));
56
+ if (validation.summary.invalid > 0) {
57
+ console.log(chalk.yellow(` āš ļø Tasks that may exceed 10 minutes: ${String(validation.summary.invalid)}`));
58
+ console.log(chalk.yellow(` Large tasks: ${String(validation.summary.large)}\n`));
59
+ validation.results.forEach((result, index) => {
60
+ if (!result.isValid) {
61
+ const task = tasks[index];
62
+ if (task) {
63
+ console.log(chalk.yellow(` Task ${String(task.index + 1)}: "${task.content}"`));
64
+ console.log(chalk.yellow(` Estimated: ${String(result.estimate.estimatedMinutes)} minutes (${result.estimate.category})`));
65
+ if (result.warning) {
66
+ console.log(chalk.yellow(` āš ļø ${result.warning}`));
67
+ }
68
+ if (result.suggestions && result.suggestions.length > 0) {
69
+ console.log(chalk.blue(` šŸ’” Suggestions:`));
70
+ result.suggestions.slice(0, 3).forEach(suggestion => {
71
+ console.log(chalk.blue(` - ${suggestion}`));
72
+ });
73
+ }
74
+ console.log('');
75
+ }
76
+ }
77
+ });
78
+ }
79
+ else {
80
+ console.log(chalk.green(' āœ“ All tasks are pee-break sized (10 seconds to 10 minutes)\n'));
81
+ }
82
+ }
83
+ else {
84
+ console.log(chalk.blue(' No tasks found in plan.md yet'));
85
+ }
86
+ }
87
+ }
88
+ }
89
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1,2 @@
1
+ export declare function showCommand(taskId: string): Promise<void>;
2
+ //# sourceMappingURL=show.d.ts.map
@@ -0,0 +1,69 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { getPlanDir, getDoDir, getCheckDir, getActDir } from '../utils/paths.js';
3
+ import { join } from 'path';
4
+ import chalk from 'chalk';
5
+ export async function showCommand(taskId) {
6
+ const planDir = getPlanDir(taskId);
7
+ const planPath = join(planDir, 'plan.md');
8
+ if (!existsSync(planPath)) {
9
+ console.error(chalk.red(`āœ— Task not found: ${taskId}`));
10
+ process.exit(1);
11
+ }
12
+ console.log(chalk.bold(`\nTask: ${chalk.cyan(taskId)}`));
13
+ console.log('─'.repeat(60));
14
+ // Read plan
15
+ if (existsSync(planPath)) {
16
+ const planContent = readFileSync(planPath, 'utf-8');
17
+ const firstLine = planContent.split('\n')[0] ?? '';
18
+ console.log(chalk.bold('\nPlan:'));
19
+ console.log(` ${firstLine.replace('# Plan: ', '')}`);
20
+ }
21
+ // Check phase status
22
+ const phases = [];
23
+ if (existsSync(join(getPlanDir(taskId), 'plan.md'))) {
24
+ phases.push('Plan');
25
+ }
26
+ if (existsSync(join(getDoDir(taskId), 'execution.md'))) {
27
+ phases.push('Do');
28
+ }
29
+ if (existsSync(join(getCheckDir(taskId), 'evaluation.md'))) {
30
+ phases.push('Check');
31
+ }
32
+ if (existsSync(join(getActDir(taskId), 'improvement.md'))) {
33
+ phases.push('Act');
34
+ }
35
+ console.log(chalk.bold('\nCurrent Phase:'));
36
+ console.log(` ${phases[phases.length - 1] ?? 'Plan'}`);
37
+ console.log(chalk.bold('\nCompleted Phases:'));
38
+ phases.forEach(phase => {
39
+ console.log(` ${chalk.green('āœ“')} ${phase}`);
40
+ });
41
+ console.log(chalk.bold('\nDirectories:'));
42
+ console.log(` Plan: ${chalk.blue(getPlanDir(taskId))}`);
43
+ if (existsSync(getDoDir(taskId))) {
44
+ console.log(` Do: ${chalk.blue(getDoDir(taskId))}`);
45
+ }
46
+ if (existsSync(getCheckDir(taskId))) {
47
+ console.log(` Check: ${chalk.blue(getCheckDir(taskId))}`);
48
+ }
49
+ if (existsSync(getActDir(taskId))) {
50
+ console.log(` Act: ${chalk.blue(getActDir(taskId))}`);
51
+ }
52
+ // OpenSpec link
53
+ const { getTaskMetadata } = await import('../utils/task-status.js');
54
+ const metadata = getTaskMetadata(taskId);
55
+ console.log(chalk.bold('\nOpenSpec Change:'));
56
+ if (metadata.openspecChange) {
57
+ console.log(` ${chalk.cyan(metadata.openspecChange)}`);
58
+ }
59
+ else {
60
+ console.log(chalk.gray(' Not linked (use --openspec when creating plan)'));
61
+ }
62
+ // Task status
63
+ const { getTaskStatus } = await import('../utils/task-status.js');
64
+ const status = getTaskStatus(taskId);
65
+ console.log(chalk.bold('\nStatus:'));
66
+ console.log(` ${status}`);
67
+ console.log('─'.repeat(60));
68
+ }
69
+ //# sourceMappingURL=show.js.map
@@ -0,0 +1,3 @@
1
+ import type { SkillsCommandOptions } from '../types.js';
2
+ export declare function skillsCommand(action?: string, name?: string, options?: SkillsCommandOptions): void;
3
+ //# sourceMappingURL=skills.d.ts.map