@openweave/weave-cli 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +116 -0
- package/package.json +45 -0
- package/src/cli.test.ts +722 -0
- package/src/cli.ts +155 -0
- package/src/commands/errors.ts +211 -0
- package/src/commands/init.ts +133 -0
- package/src/commands/migrate.ts +239 -0
- package/src/commands/milestones.ts +249 -0
- package/src/commands/orphans.ts +210 -0
- package/src/commands/query.ts +170 -0
- package/src/commands/save-node.ts +161 -0
- package/src/commands/skills.ts +230 -0
- package/src/commands/status.ts +122 -0
- package/src/commands/tools.ts +346 -0
- package/src/index.ts +12 -0
- package/src/types.ts +53 -0
- package/src/utils.ts +19 -0
package/src/cli.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { CLIArgs, CommandResult, CliCommand } from './types';
|
|
4
|
+
import { initCommand } from './commands/init';
|
|
5
|
+
import { statusCommand } from './commands/status';
|
|
6
|
+
import { milestonesCommand } from './commands/milestones';
|
|
7
|
+
import { queryCommand } from './commands/query';
|
|
8
|
+
import { orphansCommand } from './commands/orphans';
|
|
9
|
+
import { errorsCommand } from './commands/errors';
|
|
10
|
+
import { saveNodeCommand } from './commands/save-node';
|
|
11
|
+
import { migrateCommand } from './commands/migrate';
|
|
12
|
+
import { skillsCommand } from './commands/skills';
|
|
13
|
+
import { toolsCommand } from './commands/tools';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Weave CLI - Main Entry Point
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const commands: Record<string, CliCommand> = {
|
|
20
|
+
init: initCommand,
|
|
21
|
+
status: statusCommand,
|
|
22
|
+
milestones: milestonesCommand,
|
|
23
|
+
query: queryCommand,
|
|
24
|
+
orphans: orphansCommand,
|
|
25
|
+
errors: errorsCommand,
|
|
26
|
+
'save-node': saveNodeCommand,
|
|
27
|
+
migrate: migrateCommand,
|
|
28
|
+
skills: skillsCommand,
|
|
29
|
+
tools: toolsCommand,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function parseArgs(): CLIArgs {
|
|
33
|
+
const argv = process.argv.slice(2);
|
|
34
|
+
|
|
35
|
+
if (argv.length === 0) {
|
|
36
|
+
showHelp();
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const command = argv[0];
|
|
41
|
+
const args: string[] = [];
|
|
42
|
+
const flags: Record<string, string | boolean> = {};
|
|
43
|
+
|
|
44
|
+
for (let i = 1; i < argv.length; i++) {
|
|
45
|
+
const arg = argv[i];
|
|
46
|
+
|
|
47
|
+
if (arg.startsWith('--')) {
|
|
48
|
+
const parts = arg.substring(2).split('=');
|
|
49
|
+
const flagName = parts[0];
|
|
50
|
+
const flagValue = parts[1] !== undefined ? parts[1] : true;
|
|
51
|
+
flags[flagName] = flagValue;
|
|
52
|
+
} else if (arg.startsWith('-') && arg.length === 2) {
|
|
53
|
+
const flagName = arg.substring(1);
|
|
54
|
+
const nextArg = argv[i + 1];
|
|
55
|
+
if (nextArg && !nextArg.startsWith('-')) {
|
|
56
|
+
flags[flagName] = nextArg;
|
|
57
|
+
i++;
|
|
58
|
+
} else {
|
|
59
|
+
flags[flagName] = true;
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
args.push(arg);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { command, args, flags };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function showHelp(): void {
|
|
70
|
+
console.log(`
|
|
71
|
+
๐งต Weave CLI - AI Agent Knowledge Management
|
|
72
|
+
|
|
73
|
+
Usage: weave <command> [options]
|
|
74
|
+
|
|
75
|
+
Commands:
|
|
76
|
+
init <project> Initialize a new Weave project
|
|
77
|
+
status Show current project status
|
|
78
|
+
milestones List all milestones and tasks
|
|
79
|
+
query <term> Search the knowledge graph
|
|
80
|
+
orphans Analyze code for unused exports
|
|
81
|
+
errors Show error registry
|
|
82
|
+
save-node Manually add a node to the graph
|
|
83
|
+
skills Manage skill modules (list, enable, disable, info)
|
|
84
|
+
tools Manage external tool adapters (add, remove, list, info, test)
|
|
85
|
+
migrate Migrate data between storage providers
|
|
86
|
+
|
|
87
|
+
Global Options:
|
|
88
|
+
--help, -h Show this help message
|
|
89
|
+
--version, -v Show version number
|
|
90
|
+
--verbose Enable verbose output
|
|
91
|
+
--json Output as JSON
|
|
92
|
+
|
|
93
|
+
Examples:
|
|
94
|
+
weave init my-project
|
|
95
|
+
weave status --verbose
|
|
96
|
+
weave query "authentication"
|
|
97
|
+
weave orphans --severity=critical
|
|
98
|
+
weave save-node --label=MyClass --type=class
|
|
99
|
+
|
|
100
|
+
For command-specific help:
|
|
101
|
+
weave <command> --help
|
|
102
|
+
|
|
103
|
+
Documentation: https://github.com/openweave/openweave
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function showVersion(): void {
|
|
108
|
+
console.log('Weave CLI v1.0.0');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function main(): Promise<void> {
|
|
112
|
+
try {
|
|
113
|
+
const parsedArgs = parseArgs();
|
|
114
|
+
|
|
115
|
+
// Handle global flags
|
|
116
|
+
if (parsedArgs.flags.help || parsedArgs.flags.h) {
|
|
117
|
+
showHelp();
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (parsedArgs.flags.version || parsedArgs.flags.v) {
|
|
122
|
+
showVersion();
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const command = commands[parsedArgs.command];
|
|
127
|
+
|
|
128
|
+
if (!command) {
|
|
129
|
+
console.error(
|
|
130
|
+
`โ Unknown command: ${parsedArgs.command}\n`
|
|
131
|
+
);
|
|
132
|
+
console.log('Run "weave --help" for usage information.');
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const result: CommandResult = await command.execute(parsedArgs);
|
|
137
|
+
|
|
138
|
+
console.log(result.message);
|
|
139
|
+
|
|
140
|
+
if (!result.success) {
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error(
|
|
145
|
+
'โ CLI Error:',
|
|
146
|
+
error instanceof Error ? error.message : String(error)
|
|
147
|
+
);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
main().catch((error) => {
|
|
153
|
+
console.error('Fatal error:', error);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
});
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { CLIArgs, CommandResult, CliCommand } from '../types';
|
|
4
|
+
import { resolveProjectRoot } from '../utils';
|
|
5
|
+
|
|
6
|
+
interface ErrorEntry {
|
|
7
|
+
id: string;
|
|
8
|
+
error_type: string;
|
|
9
|
+
message: string;
|
|
10
|
+
file: string;
|
|
11
|
+
line: number;
|
|
12
|
+
timestamp: string;
|
|
13
|
+
severity: 'error' | 'warning' | 'info';
|
|
14
|
+
suppressed: boolean;
|
|
15
|
+
correction?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Errors Command - View error registry
|
|
20
|
+
*/
|
|
21
|
+
export class ErrorsCommand implements CliCommand {
|
|
22
|
+
name = 'errors';
|
|
23
|
+
description = 'Show error registry and suppression status';
|
|
24
|
+
usage = 'weave errors [--type=all] [--filter=active]';
|
|
25
|
+
flags = {
|
|
26
|
+
type: {
|
|
27
|
+
short: 't',
|
|
28
|
+
description:
|
|
29
|
+
'Filter by error type: all, runtime, syntax, type, semantic',
|
|
30
|
+
default: 'all',
|
|
31
|
+
},
|
|
32
|
+
filter: {
|
|
33
|
+
short: 'f',
|
|
34
|
+
description: 'Filter: all, active, suppressed (default: all)',
|
|
35
|
+
default: 'all',
|
|
36
|
+
},
|
|
37
|
+
json: {
|
|
38
|
+
short: 'j',
|
|
39
|
+
description: 'Output as JSON',
|
|
40
|
+
default: false,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
async execute(args: CLIArgs): Promise<CommandResult> {
|
|
45
|
+
try {
|
|
46
|
+
const projectRoot = resolveProjectRoot();
|
|
47
|
+
const weaveDir = join(projectRoot, '.weave');
|
|
48
|
+
|
|
49
|
+
if (!existsSync(weaveDir)) {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
message: 'Error: .weave directory not found',
|
|
53
|
+
error: 'Please run "weave init <project-name>" first',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Mock error registry
|
|
58
|
+
const mockErrors: ErrorEntry[] = [
|
|
59
|
+
{
|
|
60
|
+
id: 'e1',
|
|
61
|
+
error_type: 'runtime',
|
|
62
|
+
message: 'Null pointer exception in data processing',
|
|
63
|
+
file: 'src/processors/data.ts',
|
|
64
|
+
line: 142,
|
|
65
|
+
timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000)
|
|
66
|
+
.toISOString(),
|
|
67
|
+
severity: 'error',
|
|
68
|
+
suppressed: false,
|
|
69
|
+
correction:
|
|
70
|
+
'Added null check before accessing property. Fixed in commit abc123.',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: 'e2',
|
|
74
|
+
error_type: 'type',
|
|
75
|
+
message: 'Type mismatch: Expected string, got number',
|
|
76
|
+
file: 'src/types/config.ts',
|
|
77
|
+
line: 28,
|
|
78
|
+
timestamp: new Date(Date.now() - 1 * 60 * 60 * 1000)
|
|
79
|
+
.toISOString(),
|
|
80
|
+
severity: 'error',
|
|
81
|
+
suppressed: true,
|
|
82
|
+
correction: 'Type coercion applied. Investigate further.',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'e3',
|
|
86
|
+
error_type: 'syntax',
|
|
87
|
+
message: 'Missing semicolon',
|
|
88
|
+
file: 'src/index.ts',
|
|
89
|
+
line: 5,
|
|
90
|
+
timestamp: new Date(Date.now() - 3000).toISOString(),
|
|
91
|
+
severity: 'warning',
|
|
92
|
+
suppressed: false,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'e4',
|
|
96
|
+
error_type: 'semantic',
|
|
97
|
+
message: 'Unused import statement',
|
|
98
|
+
file: 'src/utils/helpers.ts',
|
|
99
|
+
line: 12,
|
|
100
|
+
timestamp: new Date(Date.now() - 5 * 60 * 60 * 1000)
|
|
101
|
+
.toISOString(),
|
|
102
|
+
severity: 'info',
|
|
103
|
+
suppressed: true,
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
|
|
107
|
+
const typeFilter = (args.flags.type as string) || 'all';
|
|
108
|
+
const filter = (args.flags.filter as string) || 'all';
|
|
109
|
+
|
|
110
|
+
let results = mockErrors;
|
|
111
|
+
|
|
112
|
+
if (typeFilter !== 'all') {
|
|
113
|
+
results = results.filter(
|
|
114
|
+
(e) => e.error_type === typeFilter.toLowerCase()
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (filter === 'active') {
|
|
119
|
+
results = results.filter((e) => !e.suppressed);
|
|
120
|
+
} else if (filter === 'suppressed') {
|
|
121
|
+
results = results.filter((e) => e.suppressed);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (args.flags.json) {
|
|
125
|
+
return {
|
|
126
|
+
success: true,
|
|
127
|
+
message: JSON.stringify(results, null, 2),
|
|
128
|
+
data: {
|
|
129
|
+
total: results.length,
|
|
130
|
+
active: results.filter((e) => !e.suppressed).length,
|
|
131
|
+
suppressed: results.filter((e) => e.suppressed).length,
|
|
132
|
+
errors: results,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let output = '\n๐ Error Registry\n';
|
|
138
|
+
output += '='.repeat(60) + '\n';
|
|
139
|
+
|
|
140
|
+
if (results.length === 0) {
|
|
141
|
+
output += 'โจ No errors to display!\n';
|
|
142
|
+
} else {
|
|
143
|
+
for (const error of results) {
|
|
144
|
+
output += this.formatError(error);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
output += '\n' + '='.repeat(60) + '\n';
|
|
149
|
+
output += `Active: ${results.filter((e) => !e.suppressed).length} | `;
|
|
150
|
+
output += `Suppressed: ${results.filter((e) => e.suppressed).length}\n`;
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
success: true,
|
|
154
|
+
message: output,
|
|
155
|
+
data: {
|
|
156
|
+
total: results.length,
|
|
157
|
+
active: results.filter((e) => !e.suppressed).length,
|
|
158
|
+
suppressed: results.filter((e) => e.suppressed).length,
|
|
159
|
+
errors: results,
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
} catch (error) {
|
|
163
|
+
return {
|
|
164
|
+
success: false,
|
|
165
|
+
message: 'Error reading error registry',
|
|
166
|
+
error: error instanceof Error ? error.message : String(error),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private formatError(error: ErrorEntry): string {
|
|
172
|
+
const statusIcon = error.suppressed ? '๐' : '๐ด';
|
|
173
|
+
const typeIcon = this.getTypeIcon(error.error_type);
|
|
174
|
+
const severityColor = this.getSeverityIcon(error.severity);
|
|
175
|
+
|
|
176
|
+
let output = `\n${statusIcon} ${typeIcon} [${error.error_type.toUpperCase()}] `;
|
|
177
|
+
output += `${severityColor} ${error.severity.toUpperCase()}\n`;
|
|
178
|
+
output += ` Message: ${error.message}\n`;
|
|
179
|
+
output += ` Location: ${error.file}:${error.line}\n`;
|
|
180
|
+
output += ` Time: ${new Date(error.timestamp).toLocaleString()}\n`;
|
|
181
|
+
output += ` ID: ${error.id}\n`;
|
|
182
|
+
|
|
183
|
+
if (error.correction) {
|
|
184
|
+
output += ` Fix: ${error.correction}\n`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return output;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private getTypeIcon(type: string): string {
|
|
191
|
+
const icons: Record<string, string> = {
|
|
192
|
+
runtime: 'โก',
|
|
193
|
+
type: '๐ค',
|
|
194
|
+
syntax: '๐',
|
|
195
|
+
semantic: '๐ง ',
|
|
196
|
+
default: 'โ',
|
|
197
|
+
};
|
|
198
|
+
return icons[type.toLowerCase()] || icons.default;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private getSeverityIcon(severity: string): string {
|
|
202
|
+
const icons: Record<string, string> = {
|
|
203
|
+
error: '๐ด',
|
|
204
|
+
warning: '๐ก',
|
|
205
|
+
info: '๐ต',
|
|
206
|
+
};
|
|
207
|
+
return icons[severity.toLowerCase()] || 'โ';
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export const errorsCommand = new ErrorsCommand();
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { CLIArgs, CommandResult, CliCommand, CLIConfig } from '../types';
|
|
4
|
+
import { resolveProjectRoot } from '../utils';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Init Command - Initialize a new Weave project
|
|
8
|
+
*/
|
|
9
|
+
export class InitCommand implements CliCommand {
|
|
10
|
+
name = 'init';
|
|
11
|
+
description = 'Initialize a new Weave project';
|
|
12
|
+
usage = 'weave init <project-name> [--root /path] [--include-tests]';
|
|
13
|
+
flags = {
|
|
14
|
+
root: {
|
|
15
|
+
short: 'r',
|
|
16
|
+
description: 'Project root directory',
|
|
17
|
+
default: '',
|
|
18
|
+
},
|
|
19
|
+
'include-tests': {
|
|
20
|
+
short: 't',
|
|
21
|
+
description: 'Include test files in analysis',
|
|
22
|
+
default: false,
|
|
23
|
+
},
|
|
24
|
+
verbose: {
|
|
25
|
+
short: 'v',
|
|
26
|
+
description: 'Verbose output',
|
|
27
|
+
default: false,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
async execute(args: CLIArgs): Promise<CommandResult> {
|
|
32
|
+
try {
|
|
33
|
+
const projectName = args.args[0];
|
|
34
|
+
if (!projectName) {
|
|
35
|
+
return {
|
|
36
|
+
success: false,
|
|
37
|
+
message: 'Error: Project name is required',
|
|
38
|
+
error: 'Usage: weave init <project-name>',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const projectRoot = resolveProjectRoot(args.flags.root as string | undefined);
|
|
43
|
+
const weaveDir = join(projectRoot, '.weave');
|
|
44
|
+
const graphDbPath = join(weaveDir, 'graph.json');
|
|
45
|
+
const roadmapPath = join(weaveDir, 'ROADMAP.md');
|
|
46
|
+
const configPath = join(weaveDir, 'config.json');
|
|
47
|
+
|
|
48
|
+
// Check if .weave directory already exists
|
|
49
|
+
if (existsSync(weaveDir)) {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
message: `Error: .weave directory already exists in ${projectRoot}`,
|
|
53
|
+
error: 'Project may already be initialized',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Create .weave directory structure
|
|
58
|
+
mkdirSync(weaveDir, { recursive: true });
|
|
59
|
+
|
|
60
|
+
// Create config file
|
|
61
|
+
const config: CLIConfig = {
|
|
62
|
+
project_name: projectName,
|
|
63
|
+
project_root: projectRoot,
|
|
64
|
+
knowledge_graph_path: graphDbPath,
|
|
65
|
+
roadmap_file: roadmapPath,
|
|
66
|
+
include_tests: (args.flags['include-tests'] as boolean) || false,
|
|
67
|
+
max_context_depth: 5,
|
|
68
|
+
verbose: (args.flags.verbose as boolean) || false,
|
|
69
|
+
debug: false,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
73
|
+
|
|
74
|
+
// Create empty graph database
|
|
75
|
+
const emptyGraph = {
|
|
76
|
+
created_at: new Date().toISOString(),
|
|
77
|
+
nodes: [],
|
|
78
|
+
edges: [],
|
|
79
|
+
sessions: {},
|
|
80
|
+
};
|
|
81
|
+
writeFileSync(graphDbPath, JSON.stringify(emptyGraph, null, 2));
|
|
82
|
+
|
|
83
|
+
// Create roadmap file
|
|
84
|
+
const roadmapContent = `# ${projectName} - Development Roadmap
|
|
85
|
+
|
|
86
|
+
## Project Overview
|
|
87
|
+
This roadmap tracks the development progress of ${projectName}.
|
|
88
|
+
|
|
89
|
+
**Initialized:** ${new Date().toLocaleDateString()}
|
|
90
|
+
|
|
91
|
+
## Milestones
|
|
92
|
+
|
|
93
|
+
### Phase 0: Planning
|
|
94
|
+
- [ ] Define project architecture
|
|
95
|
+
- [ ] Set up development environment
|
|
96
|
+
- [ ] Configure knowledge graph
|
|
97
|
+
|
|
98
|
+
`;
|
|
99
|
+
writeFileSync(roadmapPath, roadmapContent);
|
|
100
|
+
|
|
101
|
+
const successMessage = `โ
Project "${projectName}" initialized successfully!
|
|
102
|
+
|
|
103
|
+
๐ Created .weave directory in: ${projectRoot}
|
|
104
|
+
๐ Knowledge graph created: ${graphDbPath}
|
|
105
|
+
๐ Roadmap created: ${roadmapPath}
|
|
106
|
+
โ๏ธ Config saved: ${configPath}
|
|
107
|
+
|
|
108
|
+
Next steps:
|
|
109
|
+
โข Run 'weave status' to see project overview
|
|
110
|
+
โข Run 'weave orphans' to analyze code for unused exports
|
|
111
|
+
โข Run 'weave query <term>' to search the knowledge graph
|
|
112
|
+
`;
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
success: true,
|
|
116
|
+
message: successMessage,
|
|
117
|
+
data: {
|
|
118
|
+
project_name: projectName,
|
|
119
|
+
project_root: projectRoot,
|
|
120
|
+
weave_directory: weaveDir,
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
} catch (error) {
|
|
124
|
+
return {
|
|
125
|
+
success: false,
|
|
126
|
+
message: 'Error initializing project',
|
|
127
|
+
error: error instanceof Error ? error.message : String(error),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const initCommand = new InitCommand();
|