@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.
- package/LICENSE +201 -0
- package/README.md +424 -0
- package/bin/tmd.js +3 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +92 -0
- package/dist/commands/act.d.ts +3 -0
- package/dist/commands/act.js +210 -0
- package/dist/commands/check.d.ts +3 -0
- package/dist/commands/check.js +183 -0
- package/dist/commands/do.d.ts +3 -0
- package/dist/commands/do.js +310 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.js +56 -0
- package/dist/commands/plan.d.ts +3 -0
- package/dist/commands/plan.js +89 -0
- package/dist/commands/show.d.ts +2 -0
- package/dist/commands/show.js +69 -0
- package/dist/commands/skills.d.ts +3 -0
- package/dist/commands/skills.js +243 -0
- package/dist/types.d.ts +79 -0
- package/dist/types.js +5 -0
- package/dist/utils/act-processing.d.ts +64 -0
- package/dist/utils/act-processing.js +222 -0
- package/dist/utils/analysis.d.ts +34 -0
- package/dist/utils/analysis.js +159 -0
- package/dist/utils/comparison.d.ts +34 -0
- package/dist/utils/comparison.js +217 -0
- package/dist/utils/language-validator.d.ts +11 -0
- package/dist/utils/language-validator.js +39 -0
- package/dist/utils/openspec.d.ts +5 -0
- package/dist/utils/openspec.js +91 -0
- package/dist/utils/paths.d.ts +10 -0
- package/dist/utils/paths.js +33 -0
- package/dist/utils/skills.d.ts +3 -0
- package/dist/utils/skills.js +248 -0
- package/dist/utils/skillssh.d.ts +12 -0
- package/dist/utils/skillssh.js +135 -0
- package/dist/utils/standardization.d.ts +26 -0
- package/dist/utils/standardization.js +106 -0
- package/dist/utils/task-chain.d.ts +35 -0
- package/dist/utils/task-chain.js +146 -0
- package/dist/utils/task-id.d.ts +5 -0
- package/dist/utils/task-id.js +15 -0
- package/dist/utils/task-status.d.ts +6 -0
- package/dist/utils/task-status.js +61 -0
- package/dist/utils/task-validator.d.ts +42 -0
- package/dist/utils/task-validator.js +178 -0
- package/dist/utils/tasks.d.ts +27 -0
- package/dist/utils/tasks.js +125 -0
- package/dist/utils/templates.d.ts +12 -0
- package/dist/utils/templates.js +143 -0
- package/package.json +84 -0
- package/scripts/postinstall.js +92 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'fs';
|
|
2
|
+
import { getSkillsDir, getSkillDir } from '../utils/paths.js';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import yaml from 'js-yaml';
|
|
6
|
+
import { addSkillFromSkillssh } from '../utils/skillssh.js';
|
|
7
|
+
export function skillsCommand(action, name, options) {
|
|
8
|
+
const skillsDir = getSkillsDir();
|
|
9
|
+
if (!action || action === 'list') {
|
|
10
|
+
listSkills(skillsDir);
|
|
11
|
+
}
|
|
12
|
+
else if (action === 'search') {
|
|
13
|
+
searchSkills(skillsDir, name ?? '');
|
|
14
|
+
}
|
|
15
|
+
else if (action === 'show') {
|
|
16
|
+
if (!name) {
|
|
17
|
+
console.error(chalk.red('✗ Skill name required'));
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
showSkill(name, skillsDir);
|
|
21
|
+
}
|
|
22
|
+
else if (action === 'invoke') {
|
|
23
|
+
if (!name) {
|
|
24
|
+
console.error(chalk.red('✗ Skill name required'));
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
void invokeSkill(name, options?.input, skillsDir);
|
|
28
|
+
}
|
|
29
|
+
else if (action === 'add') {
|
|
30
|
+
if (!name) {
|
|
31
|
+
console.error(chalk.red('✗ Repository required (format: owner/repo)'));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
void addSkill(name);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.error(chalk.red(`✗ Unknown action: ${action}`));
|
|
38
|
+
console.log(chalk.gray('Available actions: list, search, show, invoke, add'));
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function addSkill(ownerRepo) {
|
|
43
|
+
console.log(chalk.blue(`\nAdding skill from skills.sh: ${ownerRepo}`));
|
|
44
|
+
console.log('─'.repeat(60));
|
|
45
|
+
const result = await addSkillFromSkillssh(ownerRepo);
|
|
46
|
+
if (result.success) {
|
|
47
|
+
const skillName = result.skillName ?? 'unknown';
|
|
48
|
+
const skillDir = result.skillDir ?? 'unknown';
|
|
49
|
+
console.log(chalk.green(`✓ Skill added: ${skillName}`));
|
|
50
|
+
console.log(chalk.gray(` Location: ${skillDir}`));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const error = result.error ?? 'Unknown error';
|
|
54
|
+
console.error(chalk.red(`✗ ${error}`));
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function listSkills(skillsDir) {
|
|
59
|
+
if (!existsSync(skillsDir)) {
|
|
60
|
+
console.log(chalk.yellow('No skills found. Create one with: tmd plan "description" --skill'));
|
|
61
|
+
console.log(chalk.gray('Or add from skills.sh: tmd skills add <owner/repo>'));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const skills = readdirSync(skillsDir, { withFileTypes: true })
|
|
65
|
+
.filter(dirent => dirent.isDirectory())
|
|
66
|
+
.map(dirent => dirent.name);
|
|
67
|
+
if (skills.length === 0) {
|
|
68
|
+
console.log(chalk.yellow('No skills found. Create one with: tmd plan "description" --skill'));
|
|
69
|
+
console.log(chalk.gray('Or add from skills.sh: tmd skills add <owner/repo>'));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
console.log(chalk.bold('\nAvailable Skills:'));
|
|
73
|
+
console.log('─'.repeat(60));
|
|
74
|
+
for (const skillName of skills) {
|
|
75
|
+
const skillDir = getSkillDir(skillName);
|
|
76
|
+
const metadataPath = join(skillDir, 'metadata.yaml');
|
|
77
|
+
if (existsSync(metadataPath)) {
|
|
78
|
+
try {
|
|
79
|
+
const metadata = yaml.load(readFileSync(metadataPath, 'utf-8'));
|
|
80
|
+
const description = metadata.description ?? 'No description';
|
|
81
|
+
const sourceTag = metadata.source === 'skillssh' ? chalk.magenta(' [skills.sh]') : '';
|
|
82
|
+
const repoInfo = metadata.repo ? chalk.gray(` (${metadata.repo})`) : '';
|
|
83
|
+
console.log(` ${chalk.cyan(skillName)}${sourceTag}${repoInfo}`);
|
|
84
|
+
console.log(` ${chalk.gray(description)}`);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
console.log(` ${chalk.cyan(skillName)}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.log(` ${chalk.cyan(skillName)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
console.log('─'.repeat(60));
|
|
95
|
+
console.log(chalk.gray(`Total: ${String(skills.length)} skill(s)`));
|
|
96
|
+
}
|
|
97
|
+
function searchSkills(skillsDir, query) {
|
|
98
|
+
if (!existsSync(skillsDir)) {
|
|
99
|
+
console.log(chalk.yellow('No skills found'));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const skills = readdirSync(skillsDir, { withFileTypes: true })
|
|
103
|
+
.filter(dirent => dirent.isDirectory())
|
|
104
|
+
.map(dirent => dirent.name);
|
|
105
|
+
const results = skills.filter(skillName => {
|
|
106
|
+
const skillDir = getSkillDir(skillName);
|
|
107
|
+
const metadataPath = join(skillDir, 'metadata.yaml');
|
|
108
|
+
const skillPath = join(skillDir, 'skill.md');
|
|
109
|
+
if (existsSync(metadataPath)) {
|
|
110
|
+
try {
|
|
111
|
+
const metadata = yaml.load(readFileSync(metadataPath, 'utf-8'));
|
|
112
|
+
const text = `${skillName} ${metadata.description ?? ''} ${metadata.tags?.join(' ') ?? ''}`.toLowerCase();
|
|
113
|
+
return text.includes(query.toLowerCase());
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return skillName.toLowerCase().includes(query.toLowerCase());
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (existsSync(skillPath)) {
|
|
120
|
+
const content = readFileSync(skillPath, 'utf-8').toLowerCase();
|
|
121
|
+
return content.includes(query.toLowerCase());
|
|
122
|
+
}
|
|
123
|
+
return skillName.toLowerCase().includes(query.toLowerCase());
|
|
124
|
+
});
|
|
125
|
+
if (results.length === 0) {
|
|
126
|
+
console.log(chalk.yellow(`No skills found matching: ${query}`));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
console.log(chalk.bold(`\nSearch Results for "${query}":`));
|
|
130
|
+
console.log('─'.repeat(60));
|
|
131
|
+
for (const skillName of results) {
|
|
132
|
+
console.log(` ${chalk.cyan(skillName)}`);
|
|
133
|
+
}
|
|
134
|
+
console.log('─'.repeat(60));
|
|
135
|
+
console.log(chalk.gray(`Found: ${String(results.length)} skill(s)`));
|
|
136
|
+
}
|
|
137
|
+
function showSkill(skillName, _skillsDir) {
|
|
138
|
+
const skillDir = getSkillDir(skillName);
|
|
139
|
+
if (!existsSync(skillDir)) {
|
|
140
|
+
console.error(chalk.red(`✗ Skill not found: ${skillName}`));
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
console.log(chalk.bold(`\nSkill: ${chalk.cyan(skillName)}`));
|
|
144
|
+
console.log('─'.repeat(60));
|
|
145
|
+
// Read skill.md
|
|
146
|
+
const skillPath = join(skillDir, 'skill.md');
|
|
147
|
+
if (existsSync(skillPath)) {
|
|
148
|
+
const content = readFileSync(skillPath, 'utf-8');
|
|
149
|
+
console.log(chalk.bold('\nDescription:'));
|
|
150
|
+
console.log(content);
|
|
151
|
+
}
|
|
152
|
+
// Read metadata.yaml
|
|
153
|
+
const metadataPath = join(skillDir, 'metadata.yaml');
|
|
154
|
+
if (existsSync(metadataPath)) {
|
|
155
|
+
try {
|
|
156
|
+
const metadata = yaml.load(readFileSync(metadataPath, 'utf-8'));
|
|
157
|
+
console.log(chalk.bold('\nMetadata:'));
|
|
158
|
+
console.log(` Version: ${metadata.version ?? 'N/A'}`);
|
|
159
|
+
if (metadata.source === 'skillssh') {
|
|
160
|
+
console.log(` Source: ${chalk.magenta('skills.sh')}`);
|
|
161
|
+
console.log(` Repository: ${metadata.repo ?? 'N/A'}`);
|
|
162
|
+
if (metadata.importedAt) {
|
|
163
|
+
console.log(` Imported: ${metadata.importedAt}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (metadata.tags && metadata.tags.length > 0) {
|
|
167
|
+
console.log(` Tags: ${metadata.tags.join(', ')}`);
|
|
168
|
+
}
|
|
169
|
+
if (metadata.interface) {
|
|
170
|
+
console.log(chalk.bold('\nInterface:'));
|
|
171
|
+
if (metadata.interface.input && metadata.interface.input.length > 0) {
|
|
172
|
+
console.log(' Input:');
|
|
173
|
+
metadata.interface.input.forEach((input) => {
|
|
174
|
+
console.log(` - ${input.name} (${input.type})${input.required ? ' [required]' : ''}`);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (metadata.interface.output && Object.keys(metadata.interface.output).length > 0) {
|
|
178
|
+
console.log(' Output:');
|
|
179
|
+
Object.entries(metadata.interface.output).forEach(([key, value]) => {
|
|
180
|
+
console.log(` - ${key}: ${String(value)}`);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
console.log(chalk.yellow(' Could not parse metadata'));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
console.log('─'.repeat(60));
|
|
190
|
+
}
|
|
191
|
+
async function invokeSkill(skillName, inputParams, _skillsDir) {
|
|
192
|
+
const skillDir = getSkillDir(skillName);
|
|
193
|
+
if (!existsSync(skillDir)) {
|
|
194
|
+
console.error(chalk.red(`✗ Skill not found: ${skillName}`));
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
console.log(chalk.bold(`\nInvoking skill: ${chalk.cyan(skillName)}`));
|
|
198
|
+
console.log('─'.repeat(60));
|
|
199
|
+
// Parse input parameters
|
|
200
|
+
const params = {};
|
|
201
|
+
if (inputParams) {
|
|
202
|
+
inputParams.split(',').forEach(param => {
|
|
203
|
+
const [key, value] = param.split('=').map(s => s.trim());
|
|
204
|
+
if (key && value) {
|
|
205
|
+
params[key] = value;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
// Load skill metadata to validate inputs
|
|
210
|
+
const metadataPath = join(skillDir, 'metadata.yaml');
|
|
211
|
+
if (existsSync(metadataPath)) {
|
|
212
|
+
try {
|
|
213
|
+
const metadata = yaml.load(readFileSync(metadataPath, 'utf-8'));
|
|
214
|
+
if (metadata.interface?.input) {
|
|
215
|
+
console.log(chalk.bold('\nInput Parameters:'));
|
|
216
|
+
metadata.interface.input.forEach((input) => {
|
|
217
|
+
const value = params[input.name] ?? (input.required ? chalk.red('MISSING') : 'not provided');
|
|
218
|
+
const valueStr = typeof value === 'string' ? value : String(value);
|
|
219
|
+
console.log(` ${input.name}: ${valueStr}`);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// Ignore metadata parsing errors
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Execute skill in isolated context
|
|
228
|
+
console.log(chalk.bold('\nExecution Context:'));
|
|
229
|
+
console.log(chalk.gray(' Isolated execution context'));
|
|
230
|
+
console.log(chalk.gray(' Cross-agent invocation'));
|
|
231
|
+
// Import and use executeSkill function
|
|
232
|
+
const { executeSkill } = await import('../utils/skills.js');
|
|
233
|
+
try {
|
|
234
|
+
await executeSkill(skillName, `invoke-${String(Date.now())}`);
|
|
235
|
+
console.log(chalk.green('\n✓ Skill invocation completed'));
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
239
|
+
console.error(chalk.red(`\n✗ Skill invocation failed: ${errorMessage}`));
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=skills.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for TMD CLI
|
|
3
|
+
*/
|
|
4
|
+
export interface PlanCommandOptions {
|
|
5
|
+
openspec?: boolean;
|
|
6
|
+
skill?: boolean;
|
|
7
|
+
useSkill?: string;
|
|
8
|
+
validateTasks?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface DoCommandOptions {
|
|
11
|
+
data?: string;
|
|
12
|
+
skill?: string;
|
|
13
|
+
list?: boolean;
|
|
14
|
+
task?: number;
|
|
15
|
+
parallel?: boolean;
|
|
16
|
+
maxConcurrency?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface CheckCommandOptions {
|
|
19
|
+
compare?: boolean;
|
|
20
|
+
validateSkill?: boolean;
|
|
21
|
+
analyze?: boolean;
|
|
22
|
+
recommend?: boolean;
|
|
23
|
+
manual?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface ActCommandOptions {
|
|
26
|
+
standardize?: boolean;
|
|
27
|
+
complete?: boolean;
|
|
28
|
+
carryForward?: boolean;
|
|
29
|
+
manual?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface ListCommandOptions {
|
|
32
|
+
status?: string;
|
|
33
|
+
phase?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface SkillsCommandOptions {
|
|
36
|
+
input?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface TaskMetadata {
|
|
39
|
+
status?: string;
|
|
40
|
+
lastUpdated?: string;
|
|
41
|
+
completed?: boolean;
|
|
42
|
+
completedAt?: string;
|
|
43
|
+
openspecChange?: string;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
export interface SkillMetadata {
|
|
47
|
+
name: string;
|
|
48
|
+
version?: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
tags?: string[];
|
|
51
|
+
source?: 'skillssh' | 'local';
|
|
52
|
+
repo?: string;
|
|
53
|
+
importedAt?: string;
|
|
54
|
+
createdFrom?: string;
|
|
55
|
+
interface?: SkillInterface;
|
|
56
|
+
}
|
|
57
|
+
export interface SkillInterface {
|
|
58
|
+
input?: SkillInput[];
|
|
59
|
+
output?: Record<string, unknown>;
|
|
60
|
+
}
|
|
61
|
+
export interface SkillInput {
|
|
62
|
+
name: string;
|
|
63
|
+
type: string;
|
|
64
|
+
required?: boolean;
|
|
65
|
+
description?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface SkillSteps {
|
|
68
|
+
steps?: SkillStep[];
|
|
69
|
+
}
|
|
70
|
+
export interface SkillStep {
|
|
71
|
+
type?: string;
|
|
72
|
+
description?: string;
|
|
73
|
+
operation?: string;
|
|
74
|
+
script?: string;
|
|
75
|
+
endpoint?: string;
|
|
76
|
+
depends?: string[] | number[];
|
|
77
|
+
[key: string]: unknown;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export interface Success {
|
|
2
|
+
goal: string;
|
|
3
|
+
type: 'met' | 'over-achieved';
|
|
4
|
+
description: string;
|
|
5
|
+
practice?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface Failure {
|
|
8
|
+
goal: string;
|
|
9
|
+
deviation: string;
|
|
10
|
+
severity: 'critical' | 'major' | 'minor';
|
|
11
|
+
rootCause?: string;
|
|
12
|
+
lesson?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface UnresolvedIssue {
|
|
15
|
+
goal: string;
|
|
16
|
+
description: string;
|
|
17
|
+
priority: 'high' | 'medium' | 'low';
|
|
18
|
+
reason: string;
|
|
19
|
+
linkToDeviation?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Parse evaluation results from evaluation.md
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseEvaluationResults(evaluationPath: string): {
|
|
25
|
+
metGoals: string[];
|
|
26
|
+
unmetGoals: string[];
|
|
27
|
+
overAchievedGoals: string[];
|
|
28
|
+
partialGoals: string[];
|
|
29
|
+
summary?: {
|
|
30
|
+
totalGoals: number;
|
|
31
|
+
metGoals: number;
|
|
32
|
+
unmetGoals: number;
|
|
33
|
+
successRate: number;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Parse deviation analysis from deviation.md
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseDeviationAnalysis(deviationPath: string): {
|
|
40
|
+
deviations: Array<{
|
|
41
|
+
description: string;
|
|
42
|
+
type: string;
|
|
43
|
+
severity: string;
|
|
44
|
+
status: string;
|
|
45
|
+
}>;
|
|
46
|
+
rootCauses: Array<{
|
|
47
|
+
category: string;
|
|
48
|
+
description: string;
|
|
49
|
+
evidence: string[];
|
|
50
|
+
}>;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Identify successes from evaluation results
|
|
54
|
+
*/
|
|
55
|
+
export declare function identifySuccesses(evaluationResults: ReturnType<typeof parseEvaluationResults>): Success[];
|
|
56
|
+
/**
|
|
57
|
+
* Identify failures from deviations and root causes
|
|
58
|
+
*/
|
|
59
|
+
export declare function identifyFailures(deviationAnalysis: ReturnType<typeof parseDeviationAnalysis>, evaluationResults: ReturnType<typeof parseEvaluationResults>): Failure[];
|
|
60
|
+
/**
|
|
61
|
+
* Identify unresolved issues for next cycle
|
|
62
|
+
*/
|
|
63
|
+
export declare function identifyUnresolvedIssues(evaluationResults: ReturnType<typeof parseEvaluationResults>, deviationAnalysis: ReturnType<typeof parseDeviationAnalysis>): UnresolvedIssue[];
|
|
64
|
+
//# sourceMappingURL=act-processing.d.ts.map
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'fs';
|
|
2
|
+
/**
|
|
3
|
+
* Parse evaluation results from evaluation.md
|
|
4
|
+
*/
|
|
5
|
+
export function parseEvaluationResults(evaluationPath) {
|
|
6
|
+
if (!existsSync(evaluationPath)) {
|
|
7
|
+
return {
|
|
8
|
+
metGoals: [],
|
|
9
|
+
unmetGoals: [],
|
|
10
|
+
overAchievedGoals: [],
|
|
11
|
+
partialGoals: []
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const content = readFileSync(evaluationPath, 'utf-8');
|
|
15
|
+
const metGoals = [];
|
|
16
|
+
const unmetGoals = [];
|
|
17
|
+
const overAchievedGoals = [];
|
|
18
|
+
const partialGoals = [];
|
|
19
|
+
// Parse comparison table
|
|
20
|
+
const tableMatch = content.match(/## Comparison with Plan[\s\S]*?\|[-\s|]+\|([\s\S]*?)(?=\n##|$)/);
|
|
21
|
+
if (tableMatch?.[1]) {
|
|
22
|
+
const rows = tableMatch[1].trim().split('\n');
|
|
23
|
+
for (const row of rows) {
|
|
24
|
+
if (!row.trim() || !row.includes('|'))
|
|
25
|
+
continue;
|
|
26
|
+
const cells = row.split('|').map(c => c.trim()).filter(c => c);
|
|
27
|
+
if (cells.length >= 4 && cells[0] && cells[3]) {
|
|
28
|
+
const goal = cells[0];
|
|
29
|
+
const status = cells[3].toLowerCase();
|
|
30
|
+
if (status.includes('met') || status.includes('✅')) {
|
|
31
|
+
metGoals.push(goal);
|
|
32
|
+
}
|
|
33
|
+
else if (status.includes('over') || status.includes('📈')) {
|
|
34
|
+
overAchievedGoals.push(goal);
|
|
35
|
+
}
|
|
36
|
+
else if (status.includes('partial') || status.includes('⚠️')) {
|
|
37
|
+
partialGoals.push(goal);
|
|
38
|
+
}
|
|
39
|
+
else if (status.includes('unmet') || status.includes('❌')) {
|
|
40
|
+
unmetGoals.push(goal);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Parse summary statistics
|
|
46
|
+
let summary;
|
|
47
|
+
const totalMatch = content.match(/Total goals:\s*(\d+)/i);
|
|
48
|
+
const metMatch = content.match(/Goals met:\s*(\d+)/i);
|
|
49
|
+
const unmetMatch = content.match(/Goals unmet:\s*(\d+)/i);
|
|
50
|
+
const rateMatch = content.match(/Success rate:\s*(\d+)%/i);
|
|
51
|
+
if (totalMatch?.[1] && metMatch?.[1]) {
|
|
52
|
+
summary = {
|
|
53
|
+
totalGoals: parseInt(totalMatch[1], 10),
|
|
54
|
+
metGoals: parseInt(metMatch[1], 10),
|
|
55
|
+
unmetGoals: unmetMatch?.[1] ? parseInt(unmetMatch[1], 10) : 0,
|
|
56
|
+
successRate: rateMatch?.[1] ? parseInt(rateMatch[1], 10) : 0
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
metGoals,
|
|
61
|
+
unmetGoals,
|
|
62
|
+
overAchievedGoals,
|
|
63
|
+
partialGoals,
|
|
64
|
+
...(summary ? { summary } : {})
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parse deviation analysis from deviation.md
|
|
69
|
+
*/
|
|
70
|
+
export function parseDeviationAnalysis(deviationPath) {
|
|
71
|
+
if (!existsSync(deviationPath)) {
|
|
72
|
+
return {
|
|
73
|
+
deviations: [],
|
|
74
|
+
rootCauses: []
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const content = readFileSync(deviationPath, 'utf-8');
|
|
78
|
+
const deviations = [];
|
|
79
|
+
const rootCauses = [];
|
|
80
|
+
// Parse deviations
|
|
81
|
+
const deviationSection = content.match(/## Deviations Identified[\s\S]*?(?=\n##|$)/);
|
|
82
|
+
if (deviationSection?.[0]) {
|
|
83
|
+
const deviationBlocks = deviationSection[0].split(/### /).slice(1);
|
|
84
|
+
for (const block of deviationBlocks) {
|
|
85
|
+
const descMatch = block.match(/^([^\n]+)/);
|
|
86
|
+
const typeMatch = block.match(/\*\*Type\*\*:\s*([^\n]+)/);
|
|
87
|
+
const severityMatch = block.match(/\*\*Severity\*\*:\s*([^\n]+)/);
|
|
88
|
+
const statusMatch = block.match(/\*\*Status\*\*:\s*([^\n]+)/);
|
|
89
|
+
if (descMatch?.[1]) {
|
|
90
|
+
deviations.push({
|
|
91
|
+
description: descMatch[1].trim(),
|
|
92
|
+
type: typeMatch?.[1] ? typeMatch[1].trim() : 'unknown',
|
|
93
|
+
severity: severityMatch?.[1] ? severityMatch[1].trim() : 'minor',
|
|
94
|
+
status: statusMatch?.[1] ? statusMatch[1].trim() : 'unknown'
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Parse root causes
|
|
100
|
+
const rootCauseSection = content.match(/## Root Cause Analysis[\s\S]*?(?=\n##|$)/);
|
|
101
|
+
if (rootCauseSection?.[0]) {
|
|
102
|
+
const causeBlocks = rootCauseSection[0].split(/### /).slice(1);
|
|
103
|
+
for (const block of causeBlocks) {
|
|
104
|
+
const categoryMatch = block.match(/^([^\n]+)/);
|
|
105
|
+
const descMatch = block.match(/\n\n([^\n]+(?:\n[^\n]+)*?)(?=\n\*\*|$)/);
|
|
106
|
+
const evidenceMatch = block.match(/\*\*Evidence\*\*:([\s\S]*?)(?=\n\n|$)/);
|
|
107
|
+
if (categoryMatch?.[1]) {
|
|
108
|
+
const category = categoryMatch[1].trim();
|
|
109
|
+
const description = descMatch?.[1] ? descMatch[1].trim() : '';
|
|
110
|
+
const evidence = [];
|
|
111
|
+
if (evidenceMatch?.[1]) {
|
|
112
|
+
const evidenceLines = evidenceMatch[1].split('\n').filter(l => l.trim().startsWith('-'));
|
|
113
|
+
for (const line of evidenceLines) {
|
|
114
|
+
const ev = line.replace(/^-\s*/, '').trim();
|
|
115
|
+
if (ev)
|
|
116
|
+
evidence.push(ev);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
rootCauses.push({
|
|
120
|
+
category,
|
|
121
|
+
description,
|
|
122
|
+
evidence
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return { deviations, rootCauses };
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Identify successes from evaluation results
|
|
131
|
+
*/
|
|
132
|
+
export function identifySuccesses(evaluationResults) {
|
|
133
|
+
const successes = [];
|
|
134
|
+
// Met goals as successes
|
|
135
|
+
for (const goal of evaluationResults.metGoals) {
|
|
136
|
+
successes.push({
|
|
137
|
+
goal,
|
|
138
|
+
type: 'met',
|
|
139
|
+
description: `Successfully achieved goal: ${goal}`
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// Over-achieved goals as successes
|
|
143
|
+
for (const goal of evaluationResults.overAchievedGoals) {
|
|
144
|
+
successes.push({
|
|
145
|
+
goal,
|
|
146
|
+
type: 'over-achieved',
|
|
147
|
+
description: `Exceeded expectations for goal: ${goal}`
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return successes;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Identify failures from deviations and root causes
|
|
154
|
+
*/
|
|
155
|
+
export function identifyFailures(deviationAnalysis, evaluationResults) {
|
|
156
|
+
const failures = [];
|
|
157
|
+
// From unmet goals
|
|
158
|
+
for (const goal of evaluationResults.unmetGoals) {
|
|
159
|
+
failures.push({
|
|
160
|
+
goal,
|
|
161
|
+
deviation: `Goal not achieved: ${goal}`,
|
|
162
|
+
severity: 'major',
|
|
163
|
+
lesson: `Failed to achieve goal: ${goal}. Review execution approach and identify improvements.`
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// From deviations
|
|
167
|
+
for (const deviation of deviationAnalysis.deviations) {
|
|
168
|
+
failures.push({
|
|
169
|
+
goal: deviation.description,
|
|
170
|
+
deviation: deviation.description,
|
|
171
|
+
severity: deviation.severity,
|
|
172
|
+
lesson: `Deviation identified: ${deviation.description}. Type: ${deviation.type}, Severity: ${deviation.severity}.`
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
// Link root causes to failures
|
|
176
|
+
for (const rootCause of deviationAnalysis.rootCauses) {
|
|
177
|
+
// Try to match root cause with failures
|
|
178
|
+
for (const failure of failures) {
|
|
179
|
+
if (failure.lesson?.toLowerCase().includes(rootCause.category.toLowerCase())) {
|
|
180
|
+
failure.rootCause = rootCause.description;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return failures;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Identify unresolved issues for next cycle
|
|
188
|
+
*/
|
|
189
|
+
export function identifyUnresolvedIssues(evaluationResults, deviationAnalysis) {
|
|
190
|
+
const issues = [];
|
|
191
|
+
// Unmet goals that need next cycle
|
|
192
|
+
for (const goal of evaluationResults.unmetGoals) {
|
|
193
|
+
issues.push({
|
|
194
|
+
goal,
|
|
195
|
+
description: `Address unmet goal: ${goal}`,
|
|
196
|
+
priority: 'high',
|
|
197
|
+
reason: 'Goal was not achieved in current cycle and requires attention in next cycle'
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// Partial goals that need continuation
|
|
201
|
+
for (const goal of evaluationResults.partialGoals) {
|
|
202
|
+
issues.push({
|
|
203
|
+
goal,
|
|
204
|
+
description: `Continue work on partially achieved goal: ${goal}`,
|
|
205
|
+
priority: 'medium',
|
|
206
|
+
reason: 'Goal was partially achieved and needs continuation in next cycle'
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
// Critical deviations that need resolution
|
|
210
|
+
const criticalDeviations = deviationAnalysis.deviations.filter(d => d.severity === 'critical');
|
|
211
|
+
for (const deviation of criticalDeviations) {
|
|
212
|
+
issues.push({
|
|
213
|
+
goal: deviation.description,
|
|
214
|
+
description: `Resolve critical deviation: ${deviation.description}`,
|
|
215
|
+
priority: 'high',
|
|
216
|
+
reason: `Critical deviation identified: ${deviation.type}`,
|
|
217
|
+
linkToDeviation: deviation.description
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return issues;
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=act-processing.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ComparisonResult } from './comparison.js';
|
|
2
|
+
export type DeviationType = 'timing' | 'scope' | 'quality' | 'resources';
|
|
3
|
+
export type DeviationSeverity = 'critical' | 'major' | 'minor';
|
|
4
|
+
export interface Deviation {
|
|
5
|
+
comparison: ComparisonResult;
|
|
6
|
+
type: DeviationType;
|
|
7
|
+
severity: DeviationSeverity;
|
|
8
|
+
description: string;
|
|
9
|
+
}
|
|
10
|
+
export interface RootCause {
|
|
11
|
+
category: 'planning' | 'execution' | 'external' | 'resources';
|
|
12
|
+
description: string;
|
|
13
|
+
evidence: string[];
|
|
14
|
+
confidence: 'high' | 'medium' | 'low';
|
|
15
|
+
}
|
|
16
|
+
export interface Recommendation {
|
|
17
|
+
priority: 'high' | 'medium' | 'low';
|
|
18
|
+
category: 'corrective' | 'preventive' | 'plan-modification';
|
|
19
|
+
action: string;
|
|
20
|
+
description: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Identify deviations from comparison results
|
|
24
|
+
*/
|
|
25
|
+
export declare function identifyDeviations(comparisons: ComparisonResult[]): Deviation[];
|
|
26
|
+
/**
|
|
27
|
+
* Analyze root causes of deviations
|
|
28
|
+
*/
|
|
29
|
+
export declare function analyzeRootCauses(deviations: Deviation[]): RootCause[];
|
|
30
|
+
/**
|
|
31
|
+
* Recommend adjustments based on analysis
|
|
32
|
+
*/
|
|
33
|
+
export declare function recommendAdjustments(deviations: Deviation[], rootCauses: RootCause[]): Recommendation[];
|
|
34
|
+
//# sourceMappingURL=analysis.d.ts.map
|