@inspecto-dev/cli 0.2.0-alpha.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.
@@ -0,0 +1,40 @@
1
+ /** Package manager detection result */
2
+ type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm';
3
+ /** Supported build tools (v1) */
4
+ type BuildTool = 'vite' | 'webpack' | 'rspack' | 'rsbuild' | 'esbuild' | 'rollup';
5
+ /** Options passed to `inspecto init` */
6
+ interface InitOptions {
7
+ shared: boolean;
8
+ skipInstall: boolean;
9
+ dryRun: boolean;
10
+ prefer?: string;
11
+ noExtension: boolean;
12
+ packages?: string[];
13
+ }
14
+ /** A single mutation recorded in install.lock */
15
+ interface Mutation {
16
+ type: 'file_modified' | 'file_created' | 'dependency_added' | 'extension_installed';
17
+ path?: string;
18
+ backup?: string;
19
+ name?: string;
20
+ id?: string;
21
+ dev?: boolean;
22
+ description?: string;
23
+ manual_action_required?: boolean;
24
+ }
25
+ /** Structure of .inspecto/install.lock */
26
+ interface InstallLock {
27
+ version: string;
28
+ created_at: string;
29
+ mutations: Mutation[];
30
+ }
31
+
32
+ declare function init(options: InitOptions): Promise<void>;
33
+
34
+ declare function doctor(): Promise<void>;
35
+
36
+ declare function teardown(): Promise<void>;
37
+
38
+ type Framework = 'react' | 'vue';
39
+
40
+ export { type BuildTool, type Framework, type InitOptions, type InstallLock, type PackageManager, doctor, init, teardown };
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import {
2
+ doctor,
3
+ init,
4
+ teardown
5
+ } from "./chunk-4RR7PTRN.js";
6
+ export {
7
+ doctor,
8
+ init,
9
+ teardown
10
+ };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@inspecto-dev/cli",
3
+ "version": "0.2.0-alpha.0",
4
+ "description": "CLI tools for Inspecto onboarding and lifecycle management",
5
+ "keywords": [
6
+ "inspecto",
7
+ "cli",
8
+ "ai",
9
+ "devtools",
10
+ "scaffold",
11
+ "init"
12
+ ],
13
+ "type": "module",
14
+ "bin": {
15
+ "inspecto": "./bin/inspecto.js"
16
+ },
17
+ "dependencies": {
18
+ "cac": "^6.7.14",
19
+ "picocolors": "^1.0.0",
20
+ "prompts": "^2.4.2",
21
+ "@inspecto-dev/types": "0.2.0-alpha.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.0.0",
25
+ "@types/prompts": "^2.4.9",
26
+ "tsup": "^8.0.2",
27
+ "typescript": "^5.4.5",
28
+ "vitest": "^1.6.0"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "scripts": {
34
+ "build": "tsup",
35
+ "dev": "tsup --watch",
36
+ "test": "vitest run --passWithNoTests"
37
+ }
38
+ }
package/src/bin.ts ADDED
@@ -0,0 +1,89 @@
1
+ // ============================================================
2
+ // src/bin.ts — CLI entry point
3
+ //
4
+ // v1 scope: VS Code | React + Vue | Vite + Webpack + Rspack + esbuild + Rollup
5
+ // ============================================================
6
+ import { parseArgs } from 'node:util'
7
+ import { init } from './commands/init.js'
8
+ import { doctor } from './commands/doctor.js'
9
+ import { teardown } from './commands/teardown.js'
10
+ import { log } from './utils/logger.js'
11
+
12
+ const HELP = `
13
+ ✦ Inspecto CLI (v1)
14
+
15
+ Supported: VS Code | React + Vue | Vite + Webpack + Rspack + esbuild + Rollup
16
+
17
+ Usage:
18
+ inspecto init Set up Inspecto in your project
19
+ inspecto doctor Diagnose your Inspecto installation
20
+ inspecto teardown Remove Inspecto from your project
21
+
22
+ Init Options:
23
+ --shared Share .inspecto/settings.json with your team via Git
24
+ --skip-install Skip npm dependency installation
25
+ --dry-run Preview changes without modifying files
26
+ --prefer <tool> Set default AI tool (e.g. github-copilot, claude-code)
27
+ --no-extension Skip VS Code extension installation
28
+ --packages <names> (Monorepo) Comma-separated list of packages to inject
29
+
30
+ Examples:
31
+ npx inspecto init
32
+ npx inspecto init --shared --prefer github-copilot
33
+ npx inspecto init --dry-run
34
+ npx inspecto doctor
35
+ npx inspecto teardown
36
+ `
37
+
38
+ async function main() {
39
+ const args = process.argv.slice(2)
40
+ const command = args[0]
41
+
42
+ if (!command || command === '--help' || command === '-h') {
43
+ console.log(HELP)
44
+ process.exit(0)
45
+ }
46
+
47
+ try {
48
+ switch (command) {
49
+ case 'init': {
50
+ const { values } = parseArgs({
51
+ args: args.slice(1),
52
+ options: {
53
+ shared: { type: 'boolean', default: false },
54
+ 'skip-install': { type: 'boolean', default: false },
55
+ 'dry-run': { type: 'boolean', default: false },
56
+ prefer: { type: 'string' },
57
+ 'no-extension': { type: 'boolean', default: false },
58
+ packages: { type: 'string' },
59
+ },
60
+ strict: true,
61
+ })
62
+ await init({
63
+ shared: values.shared ?? false,
64
+ skipInstall: values['skip-install'] ?? false,
65
+ dryRun: values['dry-run'] ?? false,
66
+ ...(values.prefer && { prefer: values.prefer }),
67
+ noExtension: values['no-extension'] ?? false,
68
+ ...(values.packages && { packages: values.packages.split(',').map(s => s.trim()) }),
69
+ })
70
+ break
71
+ }
72
+ case 'doctor':
73
+ await doctor()
74
+ break
75
+ case 'teardown':
76
+ await teardown()
77
+ break
78
+ default:
79
+ log.error(`Unknown command: ${command}`)
80
+ console.log(HELP)
81
+ process.exit(1)
82
+ }
83
+ } catch (err) {
84
+ log.error(err instanceof Error ? err.message : String(err))
85
+ process.exit(1)
86
+ }
87
+ }
88
+
89
+ main()
@@ -0,0 +1,185 @@
1
+ // ============================================================
2
+ // src/commands/doctor.ts — Installation diagnostics (v1)
3
+ // ============================================================
4
+ import path from 'node:path'
5
+ import { log } from '../utils/logger.js'
6
+ import { exists, readJSON, readFile } from '../utils/fs.js'
7
+ import { detectPackageManager, getInstallCommand } from '../detect/package-manager.js'
8
+ import { detectBuildTools } from '../detect/build-tool.js'
9
+ import { detectFrameworks } from '../detect/framework.js'
10
+ import { detectIDE } from '../detect/ide.js'
11
+ import { detectAITools } from '../detect/ai-tool.js'
12
+ import { isExtensionInstalled } from '../inject/extension.js'
13
+
14
+ interface DiagResult {
15
+ errors: number
16
+ warnings: number
17
+ }
18
+
19
+ export async function doctor(): Promise<void> {
20
+ const root = process.cwd()
21
+ const result: DiagResult = { errors: 0, warnings: 0 }
22
+
23
+ log.header('Inspecto Doctor')
24
+
25
+ // Check 1: package.json exists
26
+ if (!(await exists(path.join(root, 'package.json')))) {
27
+ log.error('No package.json found')
28
+ log.hint('Run this command from your project root')
29
+ return
30
+ }
31
+
32
+ // Check 2: IDE
33
+ const ideProbe = await detectIDE(root)
34
+ if (ideProbe.detected.length === 0) {
35
+ log.warn('IDE: not detected')
36
+ result.warnings++
37
+ } else {
38
+ // If we have at least one supported IDE, it's a pass
39
+ const hasSupported = ideProbe.detected.some(d => d.supported)
40
+ if (hasSupported) {
41
+ log.success(
42
+ `IDE: ${ideProbe.detected
43
+ .filter(d => d.supported)
44
+ .map(d => d.ide)
45
+ .join(', ')}`,
46
+ )
47
+ } else {
48
+ const names = ideProbe.detected.map(d => d.ide).join(', ')
49
+ log.warn(`IDE: ${names} (not supported in v1, VS Code only)`)
50
+ result.warnings++
51
+ }
52
+ }
53
+
54
+ // Check 3: Supported framework
55
+ const frameworkResult = await detectFrameworks(root)
56
+ if (frameworkResult.supported.length > 0) {
57
+ log.success(`Framework: ${frameworkResult.supported.join(', ')}`)
58
+ } else if (frameworkResult.unsupported.length > 0) {
59
+ const names = frameworkResult.unsupported.map(f => f.name).join(', ')
60
+ log.warn(`Framework: ${names} (not supported in v1, React/Vue only)`)
61
+ result.warnings++
62
+ } else {
63
+ log.warn('Framework: not detected (React / Vue expected)')
64
+ result.warnings++
65
+ }
66
+
67
+ // Check 3.5: AI Tools
68
+ const aiProbe = await detectAITools(root)
69
+ if (aiProbe.detected.length === 0) {
70
+ log.warn('AI Tool: none detected')
71
+ log.hint('Inspecto works best with Claude Code, Trae CLI, or GitHub Copilot')
72
+ result.warnings++
73
+ } else {
74
+ const aiNames = aiProbe.detected
75
+ .map(d => {
76
+ const modeLabels = d.toolModes.map(mode =>
77
+ mode === 'plugin' ? 'VS Code Extension' : 'Terminal CLI',
78
+ )
79
+ return `${d.label} (${modeLabels.join(' & ')})`
80
+ })
81
+ .join(', ')
82
+ log.success(`AI Tool: ${aiNames}`)
83
+ }
84
+
85
+ // Check 4: @inspecto-dev/plugin installed
86
+ const pluginPath = path.join(root, 'node_modules', '@inspecto', 'plugin')
87
+ if (await exists(pluginPath)) {
88
+ const pkgJson = await readJSON<{ version?: string }>(path.join(pluginPath, 'package.json'))
89
+ const version = pkgJson?.version ?? 'unknown'
90
+ log.success(`@inspecto-dev/plugin@${version} installed`)
91
+ } else {
92
+ log.error('@inspecto-dev/plugin not installed')
93
+ const pm = await detectPackageManager(root)
94
+ log.hint(`Fix: ${getInstallCommand(pm, '@inspecto-dev/plugin')}`)
95
+ result.errors++
96
+ }
97
+
98
+ // Check 5: Plugin injected in build config
99
+ const buildResult = await detectBuildTools(root)
100
+ if (buildResult.supported.length > 0) {
101
+ let injected = false
102
+ for (const bt of buildResult.supported) {
103
+ const content = await readFile(path.join(root, bt.configPath))
104
+ if (content && content.includes('@inspecto-dev/plugin')) {
105
+ log.success(`Plugin injected in ${bt.configPath}`)
106
+ injected = true
107
+ break
108
+ }
109
+ }
110
+ if (!injected) {
111
+ log.error('Plugin not injected in any build config')
112
+ log.hint('Fix: npx inspecto init')
113
+ result.errors++
114
+ }
115
+ } else if (buildResult.unsupported.length > 0) {
116
+ const names = buildResult.unsupported.join(', ')
117
+ log.warn(`Build tool: ${names} (not supported in v1)`)
118
+ log.hint('v1 supports: Vite, Webpack, Rspack, esbuild, Rollup')
119
+ result.warnings++
120
+ } else {
121
+ log.warn('No recognized build config found')
122
+ result.warnings++
123
+ }
124
+
125
+ // Check 6: VS Code extension
126
+ const extInstalled = await isExtensionInstalled()
127
+ if (extInstalled) {
128
+ log.success('VS Code extension detected')
129
+ } else {
130
+ const hasSupported = ideProbe.detected.some(d => d.supported)
131
+ if (ideProbe.detected.length > 0 && !hasSupported) {
132
+ log.warn('VS Code extension not applicable (non-VS Code IDE)')
133
+ } else {
134
+ log.error('VS Code extension not found')
135
+ log.hint('Fix: code --install-extension inspecto.inspecto')
136
+ log.hint('Or: https://marketplace.visualstudio.com/items?itemName=inspecto.inspecto')
137
+ result.errors++
138
+ }
139
+ }
140
+
141
+ // Check 7: settings.json
142
+ const settingsPath = path.join(root, '.inspecto', 'settings.json')
143
+ if (await exists(settingsPath)) {
144
+ const settings = await readJSON(settingsPath)
145
+ if (settings) {
146
+ log.success('.inspecto/settings.json valid')
147
+ } else {
148
+ log.error('.inspecto/settings.json has invalid JSON')
149
+ log.hint(
150
+ 'Fix: Manually correct the syntax errors, or delete the file and re-run npx inspecto init',
151
+ )
152
+ result.errors++
153
+ }
154
+ } else {
155
+ log.warn('.inspecto/settings.json not found (using defaults)')
156
+ log.hint('Optional: npx inspecto init')
157
+ result.warnings++
158
+ }
159
+
160
+ // Check 8: .gitignore status
161
+ const gitignoreContent = await readFile(path.join(root, '.gitignore'))
162
+ if (gitignoreContent) {
163
+ const hasLockIgnore =
164
+ gitignoreContent.includes('.inspecto/install.lock') || gitignoreContent.includes('.inspecto/')
165
+ if (!hasLockIgnore) {
166
+ log.warn('.inspecto/install.lock not in .gitignore')
167
+ log.hint('install.lock contains local machine state and should not be committed')
168
+ result.warnings++
169
+ }
170
+ }
171
+
172
+ // Summary
173
+ log.blank()
174
+ if (result.errors === 0 && result.warnings === 0) {
175
+ log.success('All checks passed. Hold Alt + Click to start!')
176
+ } else {
177
+ const parts: string[] = []
178
+ if (result.errors > 0) parts.push(`${result.errors} error(s)`)
179
+ if (result.warnings > 0) parts.push(`${result.warnings} warning(s)`)
180
+ console.log(
181
+ ` ${parts.join(', ')}. ${result.errors > 0 ? 'Fix the errors above to get started.' : ''}`,
182
+ )
183
+ }
184
+ log.blank()
185
+ }