algomath-extract 1.0.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 (90) hide show
  1. package/README.md +260 -0
  2. package/bin/algo-extract.js +143 -0
  3. package/bin/algo-generate.js +102 -0
  4. package/bin/algo-help.js +136 -0
  5. package/bin/algo-list.js +56 -0
  6. package/bin/algo-run.js +141 -0
  7. package/bin/algo-status.js +88 -0
  8. package/bin/algo-verify.js +189 -0
  9. package/bin/install.js +349 -0
  10. package/package.json +57 -0
  11. package/requirements.txt +20 -0
  12. package/src/__pycache__/intent.cpython-313.pyc +0 -0
  13. package/src/cli/__pycache__/commands.cpython-313.pyc +0 -0
  14. package/src/cli/cli_entry.py +106 -0
  15. package/src/cli/commands.py +339 -0
  16. package/src/execution/__init__.py +74 -0
  17. package/src/execution/__pycache__/__init__.cpython-313.pyc +0 -0
  18. package/src/execution/__pycache__/display.cpython-313.pyc +0 -0
  19. package/src/execution/__pycache__/errors.cpython-313.pyc +0 -0
  20. package/src/execution/__pycache__/executor.cpython-313.pyc +0 -0
  21. package/src/execution/__pycache__/sandbox.cpython-313.pyc +0 -0
  22. package/src/execution/display.py +261 -0
  23. package/src/execution/errors.py +158 -0
  24. package/src/execution/executor.py +253 -0
  25. package/src/execution/sandbox.py +333 -0
  26. package/src/extraction/__init__.py +102 -0
  27. package/src/extraction/__pycache__/__init__.cpython-313.pyc +0 -0
  28. package/src/extraction/__pycache__/boundaries.cpython-313.pyc +0 -0
  29. package/src/extraction/__pycache__/errors.cpython-313.pyc +0 -0
  30. package/src/extraction/__pycache__/llm_extraction.cpython-313.pyc +0 -0
  31. package/src/extraction/__pycache__/notation.cpython-313.pyc +0 -0
  32. package/src/extraction/__pycache__/parser.cpython-313.pyc +0 -0
  33. package/src/extraction/__pycache__/pdf_processor.cpython-313.pyc +0 -0
  34. package/src/extraction/__pycache__/prompts.cpython-313.pyc +0 -0
  35. package/src/extraction/__pycache__/review.cpython-313.pyc +0 -0
  36. package/src/extraction/__pycache__/schema.cpython-313.pyc +0 -0
  37. package/src/extraction/__pycache__/validation.cpython-313.pyc +0 -0
  38. package/src/extraction/boundaries.py +281 -0
  39. package/src/extraction/errors.py +156 -0
  40. package/src/extraction/llm_extraction.py +225 -0
  41. package/src/extraction/notation.py +240 -0
  42. package/src/extraction/parser.py +402 -0
  43. package/src/extraction/pdf_processor.py +281 -0
  44. package/src/extraction/prompts.py +90 -0
  45. package/src/extraction/review.py +298 -0
  46. package/src/extraction/schema.py +173 -0
  47. package/src/extraction/validation.py +202 -0
  48. package/src/generation/__init__.py +79 -0
  49. package/src/generation/__pycache__/__init__.cpython-313.pyc +0 -0
  50. package/src/generation/__pycache__/code_generator.cpython-313.pyc +0 -0
  51. package/src/generation/__pycache__/errors.cpython-313.pyc +0 -0
  52. package/src/generation/__pycache__/hybrid.cpython-313.pyc +0 -0
  53. package/src/generation/__pycache__/llm_generator.cpython-313.pyc +0 -0
  54. package/src/generation/__pycache__/persistence.cpython-313.pyc +0 -0
  55. package/src/generation/__pycache__/prompts.cpython-313.pyc +0 -0
  56. package/src/generation/__pycache__/review.cpython-313.pyc +0 -0
  57. package/src/generation/__pycache__/templates.cpython-313.pyc +0 -0
  58. package/src/generation/__pycache__/types.cpython-313.pyc +0 -0
  59. package/src/generation/__pycache__/validation.cpython-313.pyc +0 -0
  60. package/src/generation/code_generator.py +375 -0
  61. package/src/generation/errors.py +84 -0
  62. package/src/generation/hybrid.py +210 -0
  63. package/src/generation/llm_generator.py +223 -0
  64. package/src/generation/persistence.py +221 -0
  65. package/src/generation/prompts.py +202 -0
  66. package/src/generation/review.py +254 -0
  67. package/src/generation/templates.py +208 -0
  68. package/src/generation/types.py +196 -0
  69. package/src/generation/validation.py +278 -0
  70. package/src/intent.py +323 -0
  71. package/src/verification/__init__.py +63 -0
  72. package/src/verification/__pycache__/__init__.cpython-313.pyc +0 -0
  73. package/src/verification/__pycache__/checker.cpython-313.pyc +0 -0
  74. package/src/verification/__pycache__/comparison.cpython-313.pyc +0 -0
  75. package/src/verification/__pycache__/explainer.cpython-313.pyc +0 -0
  76. package/src/verification/__pycache__/static_analysis.cpython-313.pyc +0 -0
  77. package/src/verification/checker.py +220 -0
  78. package/src/verification/comparison.py +492 -0
  79. package/src/verification/explainer.py +414 -0
  80. package/src/verification/static_analysis.py +540 -0
  81. package/src/workflows/__init__.py +21 -0
  82. package/src/workflows/__pycache__/__init__.cpython-313.pyc +0 -0
  83. package/src/workflows/__pycache__/extract.cpython-313.pyc +0 -0
  84. package/src/workflows/__pycache__/generate.cpython-313.pyc +0 -0
  85. package/src/workflows/__pycache__/run.cpython-313.pyc +0 -0
  86. package/src/workflows/__pycache__/verify.cpython-313.pyc +0 -0
  87. package/src/workflows/extract.py +181 -0
  88. package/src/workflows/generate.py +155 -0
  89. package/src/workflows/run.py +187 -0
  90. package/src/workflows/verify.py +334 -0
package/bin/install.js ADDED
@@ -0,0 +1,349 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * AlgoMath Installer
5
+ *
6
+ * Usage: npx algomath@latest
7
+ *
8
+ * Installs AlgoMath to opencode (and optionally other runtimes)
9
+ */
10
+
11
+ const { execSync } = require('child_process');
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const os = require('os');
15
+
16
+ // Check if running with flags
17
+ const args = process.argv.slice(2);
18
+ const isOpencode = args.includes('--opencode') || args.includes('--all');
19
+ const isClaude = args.includes('--claude') || args.includes('--all');
20
+ const isGlobal = args.includes('--global') || args.includes('-g');
21
+ const isLocal = args.includes('--local') || args.includes('-l');
22
+ const skipPrompts = isOpencode || isClaude || isGlobal || isLocal;
23
+
24
+ async function main() {
25
+ console.log('\n╔════════════════════════════════════════════════════╗');
26
+ console.log('║ AlgoMath Framework Installer ║');
27
+ console.log('║ Mathematical Algorithm Extraction & Code ║');
28
+ console.log('╚════════════════════════════════════════════════════╝\n');
29
+
30
+ try {
31
+ // Step 1: Check Python
32
+ console.log('Step 1: Checking Python installation...');
33
+ const pythonOk = await checkPython();
34
+ if (!pythonOk) {
35
+ console.error('\n❌ Python 3.11+ is required but not found.');
36
+ console.log('\nPlease install Python 3.11 or later:');
37
+ console.log(' macOS: brew install python@3.11');
38
+ console.log(' Ubuntu: sudo apt install python3.11');
39
+ console.log(' Windows: python.org/downloads\n');
40
+ process.exit(1);
41
+ }
42
+ console.log('✓ Python 3.11+ detected\n');
43
+
44
+ // Step 2: Determine installation targets
45
+ let targets = [];
46
+ let location = 'global';
47
+
48
+ if (skipPrompts) {
49
+ // Non-interactive mode
50
+ if (isOpencode) targets.push('opencode');
51
+ if (isClaude) targets.push('claude');
52
+ if (isLocal) location = 'local';
53
+ } else {
54
+ // Interactive mode
55
+ targets = await promptForRuntimes();
56
+ location = await promptForLocation();
57
+ }
58
+
59
+ if (targets.length === 0) {
60
+ console.log('No runtimes selected. Exiting.');
61
+ process.exit(0);
62
+ }
63
+
64
+ // Step 3: Install Python dependencies
65
+ console.log('Step 2: Installing Python dependencies...');
66
+ await installPythonDependencies();
67
+ console.log('✓ Python dependencies installed\n');
68
+
69
+ // Step 4: Install to each runtime
70
+ console.log('Step 3: Installing AlgoMath commands...');
71
+ for (const target of targets) {
72
+ await installToRuntime(target, location);
73
+ }
74
+
75
+ // Step 5: Display completion
76
+ console.log('\n╔════════════════════════════════════════════════════╗');
77
+ console.log('║ Installation Complete! ✓ ║');
78
+ console.log('╚════════════════════════════════════════════════════╝\n');
79
+
80
+ console.log('AlgoMath is now ready to use.\n');
81
+ console.log('Try these commands:');
82
+ console.log(' /algo-extract <file.pdf> - Extract algorithm from PDF');
83
+ console.log(' /algo-generate - Generate Python code');
84
+ console.log(' /algo-run - Execute the code');
85
+ console.log(' /algo-verify - Verify results');
86
+ console.log(' /algo-help - Show all commands\n');
87
+
88
+ if (location === 'global') {
89
+ console.log('Installed globally - available in all projects.\n');
90
+ } else {
91
+ console.log('Installed locally - available in this project only.\n');
92
+ }
93
+
94
+ } catch (error) {
95
+ console.error('\n❌ Installation failed:', error.message);
96
+ console.error(error.stack);
97
+ process.exit(1);
98
+ }
99
+ }
100
+
101
+ function findPython() {
102
+ const candidates = ['python3', 'python'];
103
+ for (const cmd of candidates) {
104
+ try {
105
+ const version = execSync(`${cmd} --version`, { encoding: 'utf8', stdio: 'pipe' });
106
+ const match = version.match(/Python 3\.(\d+)/);
107
+ if (match) {
108
+ const minor = parseInt(match[1]);
109
+ if (minor >= 11) {
110
+ return { cmd, minor };
111
+ }
112
+ }
113
+ } catch (e) {
114
+ // Try next candidate
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+
120
+ async function checkPython() {
121
+ const found = findPython();
122
+ return found !== null;
123
+ }
124
+
125
+ function findPip() {
126
+ const candidates = ['pip3', 'pip'];
127
+ for (const cmd of candidates) {
128
+ try {
129
+ execSync(`${cmd} --version`, { stdio: 'pipe' });
130
+ return cmd;
131
+ } catch (e) {
132
+ // Try next candidate
133
+ }
134
+ }
135
+ return null;
136
+ }
137
+
138
+ async function promptForRuntimes() {
139
+ // Simple prompt (in real version would use inquirer)
140
+ console.log('Select runtime(s):');
141
+ console.log(' 1. OpenCode (recommended)');
142
+ console.log(' 2. Claude Code');
143
+ console.log(' 3. Both');
144
+ console.log(' 4. Skip\n');
145
+
146
+ // For now, auto-select OpenCode
147
+ console.log('Auto-selecting: OpenCode\n');
148
+ return ['opencode'];
149
+ }
150
+
151
+ async function promptForLocation() {
152
+ console.log('Installation location:');
153
+ console.log(' 1. Global (~/.opencode/) - All projects');
154
+ console.log(' 2. Local (./.opencode/) - This project only\n');
155
+
156
+ // For now, auto-select global
157
+ console.log('Auto-selecting: Global\n');
158
+ return 'global';
159
+ }
160
+
161
+ function checkPythonDeps() {
162
+ const pythonInfo = findPython();
163
+ if (!pythonInfo) return false;
164
+
165
+ try {
166
+ execSync(`${pythonInfo.cmd} -c "import pdfplumber; import fitz; import pydantic"`, {
167
+ stdio: 'pipe'
168
+ });
169
+ return true;
170
+ } catch (e) {
171
+ return false;
172
+ }
173
+ }
174
+
175
+ async function installPythonDependencies() {
176
+ const requirementsPath = path.join(__dirname, '..', 'requirements.txt');
177
+
178
+ if (!fs.existsSync(requirementsPath)) {
179
+ console.log('Creating requirements.txt...');
180
+ const requirements = `# AlgoMath Dependencies
181
+ pdfplumber>=0.10.0
182
+ pymupdf>=1.23.0
183
+ pydantic>=2.0.0
184
+ typing-extensions>=4.0.0
185
+ `;
186
+ fs.writeFileSync(requirementsPath, requirements);
187
+ }
188
+
189
+ // Check if dependencies are already installed
190
+ if (checkPythonDeps()) {
191
+ console.log('✓ Python dependencies already installed\n');
192
+ return;
193
+ }
194
+
195
+ // Find python and try pip module first
196
+ const pythonInfo = findPython();
197
+ if (!pythonInfo) {
198
+ console.error('\n❌ Python 3.11+ is required but not found.');
199
+ process.exit(1);
200
+ }
201
+
202
+ const pythonCmd = pythonInfo.cmd;
203
+ let installCmd = null;
204
+
205
+ // Try python -m pip first (most reliable)
206
+ try {
207
+ execSync(`${pythonCmd} -m pip --version`, { stdio: 'pipe' });
208
+ installCmd = `${pythonCmd} -m pip`;
209
+ } catch (e) {
210
+ // Fall back to pip command
211
+ const pipCmd = findPip();
212
+ if (pipCmd) {
213
+ installCmd = pipCmd;
214
+ }
215
+ }
216
+
217
+ if (!installCmd) {
218
+ console.log('\n⚠️ pip is not available. Attempting to install without pip...');
219
+ console.log(' If you encounter issues, please install dependencies manually:');
220
+ console.log(' macOS: brew install python@3.11 && python3 -m ensurepip --upgrade');
221
+ console.log(' Ubuntu: sudo apt install python3-pip');
222
+ console.log(' NixOS: nix-shell -p python311 python311Packages.pip python311Packages.pdfplumber python311Packages.pymupdf python311Packages.pydantic\n');
223
+ return; // Don't fail, let the user handle dependencies manually
224
+ }
225
+
226
+ try {
227
+ execSync(`${installCmd} install -r "${requirementsPath}"`, {
228
+ stdio: 'inherit',
229
+ cwd: path.join(__dirname, '..')
230
+ });
231
+ } catch (e) {
232
+ console.log('\n⚠️ Failed to install Python dependencies automatically.');
233
+ console.log(' Please install them manually if you encounter issues.\n');
234
+ }
235
+ }
236
+
237
+ function isWritable(dir) {
238
+ try {
239
+ fs.accessSync(dir, fs.constants.W_OK);
240
+ return true;
241
+ } catch (e) {
242
+ return false;
243
+ }
244
+ }
245
+
246
+ async function installToRuntime(runtime, location) {
247
+ const homeDir = os.homedir();
248
+ const platform = os.platform();
249
+ let targetDir;
250
+
251
+ if (runtime === 'opencode') {
252
+ targetDir = location === 'global'
253
+ ? path.join(homeDir, '.config', 'opencode')
254
+ : path.join(process.cwd(), '.opencode');
255
+ } else if (runtime === 'claude') {
256
+ targetDir = location === 'global'
257
+ ? path.join(homeDir, '.claude')
258
+ : path.join(process.cwd(), '.claude');
259
+ } else {
260
+ throw new Error(`Unknown runtime: ${runtime}`);
261
+ }
262
+
263
+ // Check if we need elevated permissions
264
+ const needsElevated = !fs.existsSync(targetDir) || !isWritable(targetDir);
265
+ const isWindows = platform === 'win32';
266
+ const isMac = platform === 'darwin';
267
+
268
+ if (needsElevated) {
269
+ console.log(` Installing to ${runtime} requires elevated permissions...`);
270
+ if (isWindows) {
271
+ console.log(` Please run this installer as Administrator.`);
272
+ console.log(` Right-click Command Prompt/PowerShell and select 'Run as Administrator'.`);
273
+ process.exit(1);
274
+ } else {
275
+ console.log(` Running with sudo...`);
276
+ }
277
+ }
278
+
279
+ // Create directories
280
+ const commandDir = path.join(targetDir, 'command');
281
+ if (needsElevated && !isWindows) {
282
+ execSync(`sudo mkdir -p "${commandDir}"`, { stdio: 'inherit' });
283
+ // Ensure the directory is writable by the user for future updates
284
+ const parentDir = path.dirname(targetDir);
285
+ execSync(`sudo chown -R $(whoami) "${parentDir}"`, { stdio: 'inherit' });
286
+ } else {
287
+ fs.mkdirSync(commandDir, { recursive: true });
288
+ }
289
+
290
+ // Copy command files
291
+ const sourceDir = path.join(__dirname, '..', 'commands');
292
+ const files = fs.readdirSync(sourceDir).filter(f => f.endsWith('.md'));
293
+
294
+ for (const file of files) {
295
+ const source = path.join(sourceDir, file);
296
+ const dest = path.join(commandDir, file);
297
+ if (needsElevated && !isWindows) {
298
+ execSync(`sudo cp "${source}" "${dest}"`, { stdio: 'pipe' });
299
+ } else {
300
+ fs.copyFileSync(source, dest);
301
+ }
302
+ }
303
+
304
+ // Create opencode.json if it doesn't exist
305
+ const configPath = path.join(targetDir, 'opencode.json');
306
+ if (!fs.existsSync(configPath)) {
307
+ const config = {
308
+ "type": "commonjs",
309
+ "permissions": {
310
+ "allow": [
311
+ "Bash(python3:*)",
312
+ "Bash(pip3:*)",
313
+ "Read(*)",
314
+ "Write(*)",
315
+ "Glob(*)",
316
+ "Grep(*)",
317
+ "Bash(git:*)",
318
+ "Bash(cat:*)",
319
+ "Bash(ls:*)",
320
+ "Bash(mkdir:*)",
321
+ "Bash(rm:*)",
322
+ "Bash(cp:*)",
323
+ "Bash(mv:*)",
324
+ "Bash(date:*)",
325
+ "Bash(echo:*)",
326
+ "Bash(head:*)",
327
+ "Bash(tail:*)",
328
+ "Bash(wc:*)",
329
+ "Bash(sort:*)",
330
+ "Bash(grep:*)",
331
+ "Bash(find:*)"
332
+ ]
333
+ }
334
+ };
335
+ if (needsElevated && !isWindows) {
336
+ const tempConfig = path.join(os.tmpdir(), 'opencode-config.json');
337
+ fs.writeFileSync(tempConfig, JSON.stringify(config, null, 2));
338
+ execSync(`sudo cp "${tempConfig}" "${configPath}"`, { stdio: 'pipe' });
339
+ fs.unlinkSync(tempConfig);
340
+ } else {
341
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
342
+ }
343
+ }
344
+
345
+ console.log(` ✓ Installed to ${runtime} (${location})`);
346
+ }
347
+
348
+ // Run installer
349
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "algomath-extract",
3
+ "version": "1.0.0",
4
+ "description": "AlgoMath Framework - Transform AI assistants into reliable mathematical problem-solving environments",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "algomath": "bin/install.js",
8
+ "algoextract": "bin/algo-extract.js",
9
+ "algogenerate": "bin/algo-generate.js",
10
+ "algorun": "bin/algo-run.js",
11
+ "algoverify": "bin/algo-verify.js",
12
+ "algostatus": "bin/algo-status.js",
13
+ "algolist": "bin/algo-list.js",
14
+ "algohelp": "bin/algo-help.js"
15
+ },
16
+ "scripts": {
17
+ "postinstall": "node scripts/postinstall.js",
18
+ "test": "node scripts/test.js"
19
+ },
20
+ "keywords": [
21
+ "algorithm",
22
+ "mathematics",
23
+ "ai",
24
+ "code-generation",
25
+ "extraction",
26
+ "verification"
27
+ ],
28
+ "author": "AlgoMath Team",
29
+ "license": "MIT",
30
+ "engines": {
31
+ "node": ">=18.0.0"
32
+ },
33
+ "files": [
34
+ "bin/",
35
+ "scripts/",
36
+ "src/",
37
+ "requirements.txt",
38
+ "README.md"
39
+ ],
40
+ "dependencies": {
41
+ "commander": "^11.0.0",
42
+ "inquirer": "^9.2.0",
43
+ "chalk": "^5.3.0",
44
+ "ora": "^7.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "eslint": "^8.0.0"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "https://github.com/yourusername/algomath.git"
52
+ },
53
+ "bugs": {
54
+ "url": "https://github.com/yourusername/algomath/issues"
55
+ },
56
+ "homepage": "https://github.com/yourusername/algomath#readme"
57
+ }
@@ -0,0 +1,20 @@
1
+ # AlgoMath Python Dependencies
2
+
3
+ # PDF Processing
4
+ pdfplumber>=0.10.0
5
+ pymupdf>=1.23.0
6
+
7
+ # Data Validation
8
+ pydantic>=2.0.0
9
+
10
+ # Type Hints
11
+ typing-extensions>=4.0.0
12
+
13
+ # Testing (optional)
14
+ pytest>=7.0.0
15
+ pytest-cov>=4.0.0
16
+
17
+ # Development (optional)
18
+ black>=23.0.0
19
+ flake8>=6.0.0
20
+ mypy>=1.0.0
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ CLI Entry Point for AlgoMath
4
+
5
+ This module provides a command-line interface for the AlgoMath framework,
6
+ allowing Node.js to call Python functions via subprocess.
7
+ """
8
+
9
+ import sys
10
+ import json
11
+ import argparse
12
+ from pathlib import Path
13
+
14
+ # Add project root to Python path
15
+ project_root = Path(__file__).parent.parent.parent
16
+ sys.path.insert(0, str(project_root))
17
+
18
+ from src.cli.commands import (
19
+ extract_command,
20
+ generate_command,
21
+ run_command,
22
+ verify_command,
23
+ status_command,
24
+ list_command,
25
+ help_command
26
+ )
27
+
28
+
29
+ def main():
30
+ """Main entry point for CLI."""
31
+ parser = argparse.ArgumentParser(description='AlgoMath CLI')
32
+ subparsers = parser.add_subparsers(dest='command', help='Available commands')
33
+
34
+ # Extract command
35
+ extract_parser = subparsers.add_parser('extract', help='Extract algorithm from text')
36
+ extract_parser.add_argument('text', help='Mathematical text')
37
+ extract_parser.add_argument('--name', '-n', help='Algorithm name', default=None)
38
+
39
+ # Generate command
40
+ generate_parser = subparsers.add_parser('generate', help='Generate code from steps')
41
+
42
+ # Run command
43
+ run_parser = subparsers.add_parser('run', help='Execute generated code')
44
+ run_parser.add_argument('--skip', action='store_true', help='Skip execution')
45
+
46
+ # Verify command
47
+ verify_parser = subparsers.add_parser('verify', help='Verify execution results')
48
+ verify_parser.add_argument('--step', type=int, help='Explain specific step')
49
+ verify_parser.add_argument('--detailed', action='store_true', help='Show detailed explanation')
50
+ verify_parser.add_argument('--diagnostic', action='store_true', help='Run diagnostic mode')
51
+
52
+ # Status command
53
+ status_parser = subparsers.add_parser('status', help='Show current state')
54
+
55
+ # List command
56
+ list_parser = subparsers.add_parser('list', help='List saved algorithms')
57
+
58
+ # Help command
59
+ help_parser = subparsers.add_parser('help', help='Show help')
60
+
61
+ args = parser.parse_args()
62
+
63
+ if not args.command:
64
+ parser.print_help()
65
+ sys.exit(1)
66
+
67
+ try:
68
+ # Route to appropriate command
69
+ if args.command == 'extract':
70
+ result = extract_command(args.text, args.name)
71
+ elif args.command == 'generate':
72
+ result = generate_command()
73
+ elif args.command == 'run':
74
+ result = run_command(skip=args.skip)
75
+ elif args.command == 'verify':
76
+ result = verify_command(
77
+ step=args.step,
78
+ detailed=args.detailed,
79
+ diagnostic=args.diagnostic
80
+ )
81
+ elif args.command == 'status':
82
+ result = status_command()
83
+ elif args.command == 'list':
84
+ result = list_command()
85
+ elif args.command == 'help':
86
+ result = help_command()
87
+ else:
88
+ print(json.dumps({
89
+ 'status': 'error',
90
+ 'message': f'Unknown command: {args.command}'
91
+ }))
92
+ sys.exit(1)
93
+
94
+ # Output result as JSON for Node.js to parse
95
+ print(json.dumps(result))
96
+
97
+ except Exception as e:
98
+ print(json.dumps({
99
+ 'status': 'error',
100
+ 'message': str(e)
101
+ }))
102
+ sys.exit(1)
103
+
104
+
105
+ if __name__ == '__main__':
106
+ main()