spec-agent 1.0.3
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/README.md +256 -0
- package/bin/spec-agent.js +14 -0
- package/dist/commands/analyze.d.ts +16 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +283 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/clean.d.ts +9 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +109 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/dispatch.d.ts +12 -0
- package/dist/commands/dispatch.d.ts.map +1 -0
- package/dist/commands/dispatch.js +232 -0
- package/dist/commands/dispatch.js.map +1 -0
- package/dist/commands/doctor.d.ts +9 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +153 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/learn.d.ts +13 -0
- package/dist/commands/learn.d.ts.map +1 -0
- package/dist/commands/learn.js +234 -0
- package/dist/commands/learn.js.map +1 -0
- package/dist/commands/merge.d.ts +11 -0
- package/dist/commands/merge.d.ts.map +1 -0
- package/dist/commands/merge.js +335 -0
- package/dist/commands/merge.js.map +1 -0
- package/dist/commands/pipeline.d.ts +19 -0
- package/dist/commands/pipeline.d.ts.map +1 -0
- package/dist/commands/pipeline.js +266 -0
- package/dist/commands/pipeline.js.map +1 -0
- package/dist/commands/plan.d.ts +13 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +314 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/scan.d.ts +28 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +488 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/status.d.ts +8 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +146 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/services/document-parser.d.ts +49 -0
- package/dist/services/document-parser.d.ts.map +1 -0
- package/dist/services/document-parser.js +499 -0
- package/dist/services/document-parser.js.map +1 -0
- package/dist/services/llm.d.ts +61 -0
- package/dist/services/llm.d.ts.map +1 -0
- package/dist/services/llm.js +716 -0
- package/dist/services/llm.js.map +1 -0
- package/dist/types.d.ts +159 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/file.d.ts +10 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +96 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +55 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +48 -0
- package/scripts/publish-npm.js +174 -0
- package/spec-agent-implementation.md +750 -0
- package/src/commands/analyze.ts +322 -0
- package/src/commands/clean.ts +88 -0
- package/src/commands/dispatch.ts +250 -0
- package/src/commands/doctor.ts +136 -0
- package/src/commands/learn.ts +261 -0
- package/src/commands/merge.ts +377 -0
- package/src/commands/pipeline.ts +306 -0
- package/src/commands/plan.ts +331 -0
- package/src/commands/scan.ts +568 -0
- package/src/commands/status.ts +129 -0
- package/src/index.ts +137 -0
- package/src/services/document-parser.ts +548 -0
- package/src/services/llm.ts +857 -0
- package/src/types.ts +161 -0
- package/src/utils/file.ts +60 -0
- package/src/utils/logger.ts +58 -0
- package/tsconfig.json +19 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Core types for spec-agent
|
|
2
|
+
|
|
3
|
+
export interface Chunk {
|
|
4
|
+
id: number;
|
|
5
|
+
sourceFiles: string[];
|
|
6
|
+
size: number;
|
|
7
|
+
content?: string;
|
|
8
|
+
contentPath?: string;
|
|
9
|
+
startLine?: number;
|
|
10
|
+
endLine?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface Manifest {
|
|
14
|
+
version: string;
|
|
15
|
+
createdAt: string;
|
|
16
|
+
totalFiles: number;
|
|
17
|
+
totalSize: number;
|
|
18
|
+
chunkSize: number;
|
|
19
|
+
chunks: Chunk[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface Feature {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
priority: 'P0' | 'P1' | 'P2' | 'P3';
|
|
27
|
+
dependencies: string[];
|
|
28
|
+
sourceChunk: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface DataModel {
|
|
32
|
+
name: string;
|
|
33
|
+
fields: string[];
|
|
34
|
+
relationships: string[];
|
|
35
|
+
sourceChunk: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface Page {
|
|
39
|
+
name: string;
|
|
40
|
+
route: string;
|
|
41
|
+
components: string[];
|
|
42
|
+
description?: string;
|
|
43
|
+
sourceChunk: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface Api {
|
|
47
|
+
method: string;
|
|
48
|
+
path: string;
|
|
49
|
+
description: string;
|
|
50
|
+
request?: object;
|
|
51
|
+
response?: object;
|
|
52
|
+
sourceChunk: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ChunkSummary {
|
|
56
|
+
chunkId: number;
|
|
57
|
+
sourceFiles: string[];
|
|
58
|
+
size: string;
|
|
59
|
+
features: Feature[];
|
|
60
|
+
dataModels: DataModel[];
|
|
61
|
+
pages: Page[];
|
|
62
|
+
apis: Api[];
|
|
63
|
+
businessRules: string[];
|
|
64
|
+
extractedAt: string;
|
|
65
|
+
llmUsage?: {
|
|
66
|
+
promptTokens: number;
|
|
67
|
+
completionTokens: number;
|
|
68
|
+
totalTokens: number;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface DependencyGraph {
|
|
73
|
+
[featureId: string]: string[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SpecSummary {
|
|
77
|
+
version: string;
|
|
78
|
+
createdAt: string;
|
|
79
|
+
sourceChunks: number;
|
|
80
|
+
deduplicatedFeatures: number;
|
|
81
|
+
features: Feature[];
|
|
82
|
+
dataModels: DataModel[];
|
|
83
|
+
pages: Page[];
|
|
84
|
+
apis: Api[];
|
|
85
|
+
businessRules: string[];
|
|
86
|
+
dependencyGraph: DependencyGraph;
|
|
87
|
+
conflicts?: string[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface Task {
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
type: 'setup' | 'page' | 'component' | 'api' | 'feature' | 'test' | 'doc';
|
|
94
|
+
description?: string;
|
|
95
|
+
dependencies: string[];
|
|
96
|
+
priority: 'P0' | 'P1' | 'P2' | 'P3';
|
|
97
|
+
estimatedHours?: number;
|
|
98
|
+
assignedTo?: string;
|
|
99
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface ParallelGroup {
|
|
103
|
+
group: number;
|
|
104
|
+
tasks: Task[];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface TaskPlan {
|
|
108
|
+
version: string;
|
|
109
|
+
createdAt: string;
|
|
110
|
+
totalTasks: number;
|
|
111
|
+
parallelGroups: ParallelGroup[];
|
|
112
|
+
outputDir: string;
|
|
113
|
+
framework: string;
|
|
114
|
+
type: string;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface AgentAssignment {
|
|
118
|
+
agentId: string;
|
|
119
|
+
type: string;
|
|
120
|
+
assignedTasks: string[];
|
|
121
|
+
workload: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface AgentPool {
|
|
125
|
+
[agentType: string]: AgentAssignment[];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface DispatchPlan {
|
|
129
|
+
version: string;
|
|
130
|
+
createdAt: string;
|
|
131
|
+
totalTasks: number;
|
|
132
|
+
agentPools: AgentPool;
|
|
133
|
+
unassigned: string[];
|
|
134
|
+
dispatchPlanPath: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface LearnedPattern {
|
|
138
|
+
name: string;
|
|
139
|
+
rule: string;
|
|
140
|
+
context: string;
|
|
141
|
+
confidence: number;
|
|
142
|
+
learnedAt: string;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface Patterns {
|
|
146
|
+
version: string;
|
|
147
|
+
workspace: string;
|
|
148
|
+
patterns: LearnedPattern[];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface WorkspaceStatus {
|
|
152
|
+
workspace: string;
|
|
153
|
+
phases: {
|
|
154
|
+
scan: { completed: boolean; output?: string };
|
|
155
|
+
analyze: { completed: boolean; chunksAnalyzed?: number; totalChunks?: number };
|
|
156
|
+
merge: { completed: boolean; output?: string };
|
|
157
|
+
plan: { completed: boolean; output?: string };
|
|
158
|
+
dispatch: { completed: boolean; output?: string };
|
|
159
|
+
};
|
|
160
|
+
canResumeFrom?: string;
|
|
161
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as fs from 'fs-extra';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
|
|
5
|
+
export async function ensureDir(dirPath: string): Promise<void> {
|
|
6
|
+
await fs.ensureDir(dirPath);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function readJson<T>(filePath: string): Promise<T> {
|
|
10
|
+
return await fs.readJson(filePath);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function writeJson(filePath: string, data: unknown): Promise<void> {
|
|
14
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
15
|
+
await fs.writeJson(filePath, data, { spaces: 2 });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function fileExists(filePath: string): Promise<boolean> {
|
|
19
|
+
return await fs.pathExists(filePath);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function getFileSize(filePath: string): Promise<number> {
|
|
23
|
+
const stats = await fs.stat(filePath);
|
|
24
|
+
return stats.size;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function formatSize(bytes: number): string {
|
|
28
|
+
const units = ['B', 'KB', 'MB', 'GB'];
|
|
29
|
+
let size = bytes;
|
|
30
|
+
let unitIndex = 0;
|
|
31
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
32
|
+
size /= 1024;
|
|
33
|
+
unitIndex++;
|
|
34
|
+
}
|
|
35
|
+
return `${size.toFixed(1)}${units[unitIndex]}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function parseSize(sizeStr: string): number {
|
|
39
|
+
const match = sizeStr.match(/^(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)?$/i);
|
|
40
|
+
if (!match) {
|
|
41
|
+
throw new Error(`Invalid size format: ${sizeStr}`);
|
|
42
|
+
}
|
|
43
|
+
const value = parseFloat(match[1]);
|
|
44
|
+
const unit = (match[2] || 'b').toLowerCase();
|
|
45
|
+
const multipliers: Record<string, number> = {
|
|
46
|
+
b: 1,
|
|
47
|
+
kb: 1024,
|
|
48
|
+
mb: 1024 * 1024,
|
|
49
|
+
gb: 1024 * 1024 * 1024,
|
|
50
|
+
};
|
|
51
|
+
return value * multipliers[unit];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function findFiles(pattern: string, cwd?: string): Promise<string[]> {
|
|
55
|
+
return await glob(pattern, { cwd, absolute: true });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function readFileContent(filePath: string): Promise<string> {
|
|
59
|
+
return await fs.readFile(filePath, 'utf-8');
|
|
60
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
export class Logger {
|
|
4
|
+
private silent: boolean;
|
|
5
|
+
private verbose: boolean;
|
|
6
|
+
|
|
7
|
+
constructor(silent = false, verbose = false) {
|
|
8
|
+
this.silent = silent;
|
|
9
|
+
this.verbose = verbose;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
debug(message: string): void {
|
|
13
|
+
if (!this.silent && this.verbose) {
|
|
14
|
+
console.log(chalk.gray('◆'), chalk.gray(message));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
info(message: string): void {
|
|
19
|
+
if (!this.silent) {
|
|
20
|
+
console.log(chalk.blue('ℹ'), message);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
success(message: string): void {
|
|
25
|
+
if (!this.silent) {
|
|
26
|
+
console.log(chalk.green('✔'), message);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
warn(message: string): void {
|
|
31
|
+
if (!this.silent) {
|
|
32
|
+
console.log(chalk.yellow('⚠'), message);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
error(message: string): void {
|
|
37
|
+
if (!this.silent) {
|
|
38
|
+
console.error(chalk.red('✖'), message);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
progress(current: number, total: number, message: string): void {
|
|
43
|
+
if (!this.silent) {
|
|
44
|
+
const percent = Math.round((current / total) * 100);
|
|
45
|
+
const bar = '█'.repeat(Math.floor(percent / 5)) + '░'.repeat(20 - Math.floor(percent / 5));
|
|
46
|
+
process.stdout.write(`\r[${bar}] ${percent}% ${message}`);
|
|
47
|
+
if (current === total) {
|
|
48
|
+
process.stdout.write('\n');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
json(data: unknown): void {
|
|
54
|
+
if (!this.silent) {
|
|
55
|
+
console.log(JSON.stringify(data, null, 2));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|