@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/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();