@inspecto-dev/cli 0.2.0-alpha.4 → 0.2.0-alpha.6
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/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-test.log +16 -21
- package/CHANGELOG.md +12 -0
- package/README.md +58 -11
- package/bin/inspecto.js +5 -1
- package/dist/bin.d.ts +5 -1
- package/dist/bin.js +89 -50
- package/dist/{chunk-EUCQCD3Y.js → chunk-PDDFPQJS.js} +1954 -1053
- package/dist/index.d.ts +128 -2
- package/dist/index.js +15 -3
- package/package.json +2 -1
- package/src/bin.ts +139 -67
- package/src/commands/apply.ts +114 -0
- package/src/commands/detect.ts +59 -0
- package/src/commands/doctor.ts +225 -72
- package/src/commands/init.ts +106 -183
- package/src/commands/plan.ts +41 -0
- package/src/detect/build-tool.ts +107 -3
- package/src/index.ts +13 -2
- package/src/inject/ast-injector.ts +20 -9
- package/src/inject/extension.ts +3 -1
- package/src/inject/strategies/vite.ts +2 -1
- package/src/instructions.ts +60 -46
- package/src/onboarding/apply.ts +325 -0
- package/src/onboarding/context.ts +36 -0
- package/src/onboarding/planner.ts +278 -0
- package/src/prompts.ts +54 -11
- package/src/types.ts +95 -0
- package/src/utils/fs.ts +2 -1
- package/src/utils/logger.ts +9 -0
- package/src/utils/output.ts +40 -0
- package/tests/apply.test.ts +537 -0
- package/tests/ast-injector.test.ts +50 -0
- package/tests/build-tool.test.ts +3 -5
- package/tests/detect.test.ts +94 -0
- package/tests/doctor.test.ts +224 -0
- package/tests/init.test.ts +333 -0
- package/tests/instructions.test.ts +61 -0
- package/tests/logger.test.ts +100 -0
- package/tests/plan.test.ts +713 -0
- package/tests/workspace-build-tool.test.ts +75 -0
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,94 @@
|
|
|
2
2
|
type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm';
|
|
3
3
|
/** Supported build tools (v1) */
|
|
4
4
|
type BuildTool = 'vite' | 'webpack' | 'rspack' | 'rsbuild' | 'esbuild' | 'rollup';
|
|
5
|
+
/** Machine-readable status for onboarding commands */
|
|
6
|
+
type CommandStatus = 'ok' | 'warning' | 'blocked' | 'error';
|
|
7
|
+
/** Structured message emitted by onboarding commands */
|
|
8
|
+
interface CommandMessage {
|
|
9
|
+
code: string;
|
|
10
|
+
message: string;
|
|
11
|
+
}
|
|
12
|
+
interface OnboardingProvider {
|
|
13
|
+
id: string;
|
|
14
|
+
label: string;
|
|
15
|
+
supported: boolean;
|
|
16
|
+
preferredMode: 'cli' | 'extension';
|
|
17
|
+
}
|
|
18
|
+
/** Detected build tool with its config path */
|
|
19
|
+
interface BuildToolDetection {
|
|
20
|
+
tool: BuildTool;
|
|
21
|
+
configPath: string;
|
|
22
|
+
/** Human-readable label like "Vite (vite.config.ts)" */
|
|
23
|
+
label: string;
|
|
24
|
+
/** Whether this is a legacy rspack version (< 0.4.0) */
|
|
25
|
+
isLegacyRspack?: boolean;
|
|
26
|
+
/** Whether this is Webpack 4.x */
|
|
27
|
+
isLegacyWebpack?: boolean;
|
|
28
|
+
/** Relative package path when using --packages */
|
|
29
|
+
packagePath?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Machine-readable detection output for skill-first onboarding */
|
|
32
|
+
interface DetectionResult {
|
|
33
|
+
status: CommandStatus;
|
|
34
|
+
warnings: CommandMessage[];
|
|
35
|
+
blockers: CommandMessage[];
|
|
36
|
+
project: {
|
|
37
|
+
root: string;
|
|
38
|
+
packageManager: PackageManager;
|
|
39
|
+
};
|
|
40
|
+
environment: {
|
|
41
|
+
frameworks: string[];
|
|
42
|
+
unsupportedFrameworks: string[];
|
|
43
|
+
buildTools: BuildToolDetection[];
|
|
44
|
+
unsupportedBuildTools: string[];
|
|
45
|
+
ides: Array<{
|
|
46
|
+
ide: string;
|
|
47
|
+
supported: boolean;
|
|
48
|
+
}>;
|
|
49
|
+
providers: OnboardingProvider[];
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Machine-readable onboarding plan output */
|
|
53
|
+
interface PlanResult {
|
|
54
|
+
status: CommandStatus;
|
|
55
|
+
warnings: CommandMessage[];
|
|
56
|
+
blockers: CommandMessage[];
|
|
57
|
+
strategy: 'supported' | 'manual' | 'unsupported';
|
|
58
|
+
actions: Array<{
|
|
59
|
+
type: 'install_dependency' | 'modify_file' | 'install_extension' | 'manual_step';
|
|
60
|
+
target: string;
|
|
61
|
+
description: string;
|
|
62
|
+
}>;
|
|
63
|
+
defaults: {
|
|
64
|
+
provider?: string;
|
|
65
|
+
ide?: string;
|
|
66
|
+
shared: boolean;
|
|
67
|
+
extension: boolean;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** A single doctor diagnostic check/result */
|
|
71
|
+
interface DoctorDiagnostic {
|
|
72
|
+
code: string;
|
|
73
|
+
status: 'ok' | 'warning' | 'error';
|
|
74
|
+
message: string;
|
|
75
|
+
hints: string[];
|
|
76
|
+
details?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
/** Machine-readable diagnostics output for `inspecto doctor` */
|
|
79
|
+
interface DoctorResult {
|
|
80
|
+
status: CommandStatus;
|
|
81
|
+
summary: {
|
|
82
|
+
errors: number;
|
|
83
|
+
warnings: number;
|
|
84
|
+
};
|
|
85
|
+
project: {
|
|
86
|
+
root: string;
|
|
87
|
+
packageManager?: PackageManager;
|
|
88
|
+
};
|
|
89
|
+
errors: DoctorDiagnostic[];
|
|
90
|
+
warnings: DoctorDiagnostic[];
|
|
91
|
+
checks: DoctorDiagnostic[];
|
|
92
|
+
}
|
|
5
93
|
/** Options passed to `inspecto init` */
|
|
6
94
|
interface InitOptions {
|
|
7
95
|
shared: boolean;
|
|
@@ -30,12 +118,50 @@ interface InstallLock {
|
|
|
30
118
|
mutations: Mutation[];
|
|
31
119
|
}
|
|
32
120
|
|
|
121
|
+
interface ApplyOnboardingResult {
|
|
122
|
+
status: CommandStatus;
|
|
123
|
+
mutations: Mutation[];
|
|
124
|
+
postInstall: {
|
|
125
|
+
installFailed: boolean;
|
|
126
|
+
injectionFailed: boolean;
|
|
127
|
+
manualExtensionInstallNeeded: boolean;
|
|
128
|
+
nextSteps: string[];
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
interface ApplyCommandOptions {
|
|
133
|
+
json?: boolean;
|
|
134
|
+
shared?: boolean;
|
|
135
|
+
skipInstall?: boolean;
|
|
136
|
+
dryRun?: boolean;
|
|
137
|
+
noExtension?: boolean;
|
|
138
|
+
}
|
|
139
|
+
interface ApplyCommandResult extends ApplyOnboardingResult {
|
|
140
|
+
plan: PlanResult;
|
|
141
|
+
}
|
|
142
|
+
declare function apply(options?: ApplyCommandOptions): Promise<ApplyCommandResult>;
|
|
143
|
+
|
|
144
|
+
declare function detect(json?: boolean): Promise<DetectionResult>;
|
|
145
|
+
|
|
33
146
|
declare function init(options: InitOptions): Promise<void>;
|
|
34
147
|
|
|
35
|
-
|
|
148
|
+
interface DoctorCommandOptions {
|
|
149
|
+
json?: boolean;
|
|
150
|
+
}
|
|
151
|
+
declare function collectDoctorResult(root?: string): Promise<DoctorResult>;
|
|
152
|
+
declare function doctor(options?: DoctorCommandOptions | boolean): Promise<DoctorResult>;
|
|
153
|
+
|
|
154
|
+
declare function plan(json?: boolean): Promise<PlanResult>;
|
|
36
155
|
|
|
37
156
|
declare function teardown(): Promise<void>;
|
|
38
157
|
|
|
158
|
+
interface ReportCommandErrorOptions {
|
|
159
|
+
debug?: boolean;
|
|
160
|
+
json?: boolean;
|
|
161
|
+
}
|
|
162
|
+
declare function writeCommandOutput<T>(result: T, json: boolean, renderText: (value: T) => void): T;
|
|
163
|
+
declare function reportCommandError(error: unknown, options?: ReportCommandErrorOptions): void;
|
|
164
|
+
|
|
39
165
|
type Framework = 'react' | 'vue';
|
|
40
166
|
|
|
41
|
-
export { type BuildTool, type Framework, type InitOptions, type InstallLock, type PackageManager, doctor, init, teardown };
|
|
167
|
+
export { type BuildTool, type DoctorDiagnostic, type DoctorResult, type Framework, type InitOptions, type InstallLock, type PackageManager, apply, collectDoctorResult, detect, doctor, init, plan, reportCommandError, teardown, writeCommandOutput };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
+
apply,
|
|
3
|
+
collectDoctorResult,
|
|
4
|
+
detect,
|
|
2
5
|
doctor,
|
|
3
6
|
init,
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
plan,
|
|
8
|
+
reportCommandError,
|
|
9
|
+
teardown,
|
|
10
|
+
writeCommandOutput
|
|
11
|
+
} from "./chunk-PDDFPQJS.js";
|
|
6
12
|
export {
|
|
13
|
+
apply,
|
|
14
|
+
collectDoctorResult,
|
|
15
|
+
detect,
|
|
7
16
|
doctor,
|
|
8
17
|
init,
|
|
9
|
-
|
|
18
|
+
plan,
|
|
19
|
+
reportCommandError,
|
|
20
|
+
teardown,
|
|
21
|
+
writeCommandOutput
|
|
10
22
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inspecto-dev/cli",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.6",
|
|
4
4
|
"description": "CLI tools for Inspecto onboarding and lifecycle management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"inspecto",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"cac": "^6.7.14",
|
|
19
19
|
"magicast": "^0.5.2",
|
|
20
|
+
"ora": "^9.3.0",
|
|
20
21
|
"picocolors": "^1.0.0",
|
|
21
22
|
"prompts": "^2.4.2",
|
|
22
23
|
"@inspecto-dev/types": "0.2.0-alpha.4"
|
package/src/bin.ts
CHANGED
|
@@ -4,22 +4,27 @@
|
|
|
4
4
|
// v1 scope: VS Code | React + Vue | Vite + Webpack + Rspack + esbuild + Rollup
|
|
5
5
|
// ============================================================
|
|
6
6
|
import { cac, type CAC } from 'cac'
|
|
7
|
+
import { fileURLToPath } from 'node:url'
|
|
7
8
|
import { createRequire } from 'node:module'
|
|
9
|
+
import { apply } from './commands/apply.js'
|
|
10
|
+
import { detect } from './commands/detect.js'
|
|
8
11
|
import { init } from './commands/init.js'
|
|
9
12
|
import { doctor } from './commands/doctor.js'
|
|
13
|
+
import { plan } from './commands/plan.js'
|
|
10
14
|
import { teardown } from './commands/teardown.js'
|
|
11
|
-
import {
|
|
15
|
+
import { reportCommandError } from './utils/output.js'
|
|
12
16
|
|
|
13
17
|
const require = createRequire(import.meta.url)
|
|
14
18
|
const { version } = require('../package.json')
|
|
15
19
|
|
|
16
|
-
// cac object
|
|
17
|
-
const cli: CAC = cac('inspecto')
|
|
18
|
-
|
|
19
20
|
interface GlobalOptions {
|
|
20
21
|
debug?: boolean
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
interface JsonCommandOptions extends GlobalOptions {
|
|
25
|
+
json?: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
23
28
|
interface InitCommandOptions extends GlobalOptions {
|
|
24
29
|
shared?: boolean
|
|
25
30
|
skipInstall?: boolean
|
|
@@ -30,74 +35,141 @@ interface InitCommandOptions extends GlobalOptions {
|
|
|
30
35
|
force?: boolean
|
|
31
36
|
}
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
await init({
|
|
46
|
-
shared: options.shared ?? false,
|
|
47
|
-
skipInstall: options.skipInstall ?? false,
|
|
48
|
-
dryRun: options.dryRun ?? false,
|
|
49
|
-
...(options.provider && { provider: options.provider }), // Changed from prefer to provider
|
|
50
|
-
noExtension: options.noExtension ?? false,
|
|
51
|
-
...(options.packages && {
|
|
52
|
-
packages: options.packages.split(',').map((s: string) => s.trim()),
|
|
53
|
-
}),
|
|
54
|
-
force: options.force ?? false,
|
|
55
|
-
})
|
|
56
|
-
} catch (err) {
|
|
57
|
-
log.error(err instanceof Error ? err.message : String(err))
|
|
58
|
-
if (options.debug && err instanceof Error && err.stack) {
|
|
59
|
-
console.error(err.stack)
|
|
60
|
-
}
|
|
61
|
-
process.exit(1)
|
|
62
|
-
}
|
|
38
|
+
interface ApplyCommandOptions extends JsonCommandOptions {
|
|
39
|
+
shared?: boolean
|
|
40
|
+
skipInstall?: boolean
|
|
41
|
+
dryRun?: boolean
|
|
42
|
+
extension?: boolean
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function exitWithError(error: unknown, options: JsonCommandOptions = {}): never {
|
|
46
|
+
reportCommandError(error, {
|
|
47
|
+
debug: options.debug ?? false,
|
|
48
|
+
json: options.json ?? false,
|
|
63
49
|
})
|
|
50
|
+
process.exit(1)
|
|
51
|
+
}
|
|
64
52
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
53
|
+
export function createCli(_argv: readonly string[] = process.argv): CAC {
|
|
54
|
+
const cli: CAC = cac('inspecto')
|
|
55
|
+
|
|
56
|
+
cli
|
|
57
|
+
.command('init', 'Set up Inspecto in your project')
|
|
58
|
+
.option('--shared', 'Share .inspecto/settings.json with your team via Git', { default: false })
|
|
59
|
+
.option('--skip-install', 'Skip npm dependency installation', { default: false })
|
|
60
|
+
.option('--dry-run', 'Preview changes without modifying files', { default: false })
|
|
61
|
+
.option('--provider <provider>', 'Set default provider (e.g. copilot, claude-code)')
|
|
62
|
+
.option('--no-extension', 'Skip VS Code extension installation', { default: false })
|
|
63
|
+
.option('--packages <names>', '(Monorepo) Comma-separated list of packages to inject')
|
|
64
|
+
.option('--force', 'Force initialization even if environment is unsupported', {
|
|
65
|
+
default: false,
|
|
66
|
+
})
|
|
67
|
+
.option('--debug', 'Enable debug mode to show full error traces', { default: false })
|
|
68
|
+
.action(async (options: InitCommandOptions) => {
|
|
69
|
+
try {
|
|
70
|
+
await init({
|
|
71
|
+
shared: options.shared ?? false,
|
|
72
|
+
skipInstall: options.skipInstall ?? false,
|
|
73
|
+
dryRun: options.dryRun ?? false,
|
|
74
|
+
...(options.provider && { provider: options.provider }),
|
|
75
|
+
noExtension: options.noExtension ?? false,
|
|
76
|
+
...(options.packages && {
|
|
77
|
+
packages: options.packages.split(',').map((s: string) => s.trim()),
|
|
78
|
+
}),
|
|
79
|
+
force: options.force ?? false,
|
|
80
|
+
})
|
|
81
|
+
} catch (error) {
|
|
82
|
+
exitWithError(error, options)
|
|
75
83
|
}
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
})
|
|
84
|
+
})
|
|
79
85
|
|
|
80
|
-
cli
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
console.error(err.stack)
|
|
86
|
+
cli
|
|
87
|
+
.command('doctor', 'Diagnose your Inspecto installation')
|
|
88
|
+
.option('--json', 'Print machine-readable JSON output', { default: false })
|
|
89
|
+
.option('--debug', 'Enable debug mode to show full error traces', { default: false })
|
|
90
|
+
.action(async (options: JsonCommandOptions) => {
|
|
91
|
+
try {
|
|
92
|
+
await doctor({ json: options.json ?? false })
|
|
93
|
+
} catch (error) {
|
|
94
|
+
exitWithError(error, options)
|
|
90
95
|
}
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
})
|
|
96
|
+
})
|
|
94
97
|
|
|
95
|
-
cli
|
|
96
|
-
|
|
98
|
+
cli
|
|
99
|
+
.command('detect', 'Detect whether the current project can be onboarded automatically')
|
|
100
|
+
.option('--json', 'Print machine-readable JSON output', { default: false })
|
|
101
|
+
.option('--debug', 'Enable debug mode to show full error traces', { default: false })
|
|
102
|
+
.action(async (options: JsonCommandOptions) => {
|
|
103
|
+
try {
|
|
104
|
+
await detect(options.json ?? false)
|
|
105
|
+
} catch (error) {
|
|
106
|
+
exitWithError(error, options)
|
|
107
|
+
}
|
|
108
|
+
})
|
|
97
109
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
cli
|
|
111
|
+
.command('plan', 'Preview the onboarding plan for the current project')
|
|
112
|
+
.option('--json', 'Print machine-readable JSON output', { default: false })
|
|
113
|
+
.option('--debug', 'Enable debug mode to show full error traces', { default: false })
|
|
114
|
+
.action(async (options: JsonCommandOptions) => {
|
|
115
|
+
try {
|
|
116
|
+
await plan(options.json ?? false)
|
|
117
|
+
} catch (error) {
|
|
118
|
+
exitWithError(error, options)
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
cli
|
|
123
|
+
.command('apply', 'Apply the onboarding plan to the current project')
|
|
124
|
+
.option('--json', 'Print machine-readable JSON output', { default: false })
|
|
125
|
+
.option('--shared', 'Write shared Inspecto settings instead of local-only settings')
|
|
126
|
+
.option('--skip-install', 'Skip npm dependency installation')
|
|
127
|
+
.option('--dry-run', 'Preview changes without modifying files')
|
|
128
|
+
.option('--no-extension', 'Skip IDE extension installation')
|
|
129
|
+
.option('--debug', 'Enable debug mode to show full error traces', { default: false })
|
|
130
|
+
.action(async (options: ApplyCommandOptions) => {
|
|
131
|
+
try {
|
|
132
|
+
await apply({
|
|
133
|
+
json: options.json ?? false,
|
|
134
|
+
...(options.shared !== undefined && { shared: options.shared }),
|
|
135
|
+
...(options.skipInstall !== undefined && { skipInstall: options.skipInstall }),
|
|
136
|
+
...(options.dryRun !== undefined && { dryRun: options.dryRun }),
|
|
137
|
+
...(options.extension === false && { noExtension: true }),
|
|
138
|
+
})
|
|
139
|
+
} catch (error) {
|
|
140
|
+
exitWithError(error, options)
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
cli
|
|
145
|
+
.command('teardown', 'Remove Inspecto from your project')
|
|
146
|
+
.option('--debug', 'Enable debug mode to show full error traces', { default: false })
|
|
147
|
+
.action(async (options: GlobalOptions) => {
|
|
148
|
+
try {
|
|
149
|
+
await teardown()
|
|
150
|
+
} catch (error) {
|
|
151
|
+
exitWithError(error, options)
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
cli.help()
|
|
156
|
+
cli.version(version)
|
|
157
|
+
|
|
158
|
+
return cli
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function runCli(argv: readonly string[] = process.argv): Promise<void> {
|
|
162
|
+
const cli = createCli(argv)
|
|
163
|
+
const parsedArgv = [...argv]
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
await cli.parse(parsedArgv)
|
|
167
|
+
} catch (error) {
|
|
168
|
+
exitWithError(error, { json: argv.includes('--json') })
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const entryPath = process.argv[1]
|
|
173
|
+
if (entryPath && fileURLToPath(import.meta.url) === entryPath) {
|
|
174
|
+
void runCli()
|
|
103
175
|
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { applyOnboardingPlan, type ApplyOnboardingResult } from '../onboarding/apply.js'
|
|
2
|
+
import { buildOnboardingContext } from '../onboarding/context.js'
|
|
3
|
+
import { createPlanResult } from '../onboarding/planner.js'
|
|
4
|
+
import { log } from '../utils/logger.js'
|
|
5
|
+
import { writeCommandOutput } from '../utils/output.js'
|
|
6
|
+
import type { PlanResult } from '../types.js'
|
|
7
|
+
|
|
8
|
+
export interface ApplyCommandOptions {
|
|
9
|
+
json?: boolean
|
|
10
|
+
shared?: boolean
|
|
11
|
+
skipInstall?: boolean
|
|
12
|
+
dryRun?: boolean
|
|
13
|
+
noExtension?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ApplyCommandResult extends ApplyOnboardingResult {
|
|
17
|
+
plan: PlanResult
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getProviderDefault(
|
|
21
|
+
providerId?: string,
|
|
22
|
+
preferredMode?: 'cli' | 'extension',
|
|
23
|
+
): string | undefined {
|
|
24
|
+
if (!providerId) return undefined
|
|
25
|
+
const mode = preferredMode ?? (providerId === 'coco' ? 'cli' : 'extension')
|
|
26
|
+
return `${providerId}.${mode}`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function statusRank(status: ApplyCommandResult['status']): number {
|
|
30
|
+
switch (status) {
|
|
31
|
+
case 'error':
|
|
32
|
+
return 3
|
|
33
|
+
case 'blocked':
|
|
34
|
+
return 2
|
|
35
|
+
case 'warning':
|
|
36
|
+
return 1
|
|
37
|
+
case 'ok':
|
|
38
|
+
default:
|
|
39
|
+
return 0
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function mergeStatus(
|
|
44
|
+
planStatus: PlanResult['status'],
|
|
45
|
+
applyStatus: ApplyOnboardingResult['status'],
|
|
46
|
+
): ApplyCommandResult['status'] {
|
|
47
|
+
return statusRank(planStatus) >= statusRank(applyStatus) ? planStatus : applyStatus
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function printApplyResult(result: ApplyCommandResult): void {
|
|
51
|
+
const manualSteps = result.postInstall.nextSteps.filter(
|
|
52
|
+
step => !result.plan.blockers.some(blocker => blocker.message === step),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
log.header('Inspecto Apply')
|
|
56
|
+
log.info(`Status: ${result.status}`)
|
|
57
|
+
log.info(`Strategy: ${result.plan.strategy}`)
|
|
58
|
+
|
|
59
|
+
for (const blocker of result.plan.blockers) {
|
|
60
|
+
log.error(blocker.message)
|
|
61
|
+
}
|
|
62
|
+
for (const warning of result.plan.warnings) {
|
|
63
|
+
log.warn(warning.message)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (manualSteps.length > 0 || result.plan.blockers.length > 0) {
|
|
67
|
+
log.blank()
|
|
68
|
+
log.warn('──────── Manual Steps Required ────────')
|
|
69
|
+
manualSteps.forEach(step => log.error(step))
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (result.plan.warnings.length > 0) {
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
log.ready('Ready! Hold Alt + Click any element to inspect.')
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function apply(options: ApplyCommandOptions = {}): Promise<ApplyCommandResult> {
|
|
81
|
+
const root = process.cwd()
|
|
82
|
+
const context = await buildOnboardingContext(root)
|
|
83
|
+
const plan = createPlanResult(context)
|
|
84
|
+
const selectedProvider =
|
|
85
|
+
context.providers.find(provider => provider.id === plan.defaults.provider) ?? null
|
|
86
|
+
const selectedIDE =
|
|
87
|
+
context.ides.find(ide => ide.ide === plan.defaults.ide) ??
|
|
88
|
+
context.ides.find(ide => ide.supported) ??
|
|
89
|
+
null
|
|
90
|
+
|
|
91
|
+
const applyResult = await applyOnboardingPlan({
|
|
92
|
+
repoRoot: root,
|
|
93
|
+
projectRoot: root,
|
|
94
|
+
packageManager: context.packageManager,
|
|
95
|
+
supportedBuildTargets: context.buildTools.supported,
|
|
96
|
+
options: {
|
|
97
|
+
shared: options.shared ?? plan.defaults.shared,
|
|
98
|
+
skipInstall: options.skipInstall ?? false,
|
|
99
|
+
dryRun: options.dryRun ?? false,
|
|
100
|
+
noExtension: options.noExtension ?? !plan.defaults.extension,
|
|
101
|
+
quiet: options.json ?? false,
|
|
102
|
+
},
|
|
103
|
+
selectedIDE,
|
|
104
|
+
providerDefault: getProviderDefault(plan.defaults.provider, selectedProvider?.preferredMode),
|
|
105
|
+
plan,
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
const result: ApplyCommandResult = {
|
|
109
|
+
...applyResult,
|
|
110
|
+
status: mergeStatus(plan.status, applyResult.status),
|
|
111
|
+
plan,
|
|
112
|
+
}
|
|
113
|
+
return writeCommandOutput(result, options.json ?? false, printApplyResult)
|
|
114
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { log } from '../utils/logger.js'
|
|
2
|
+
import { writeCommandOutput } from '../utils/output.js'
|
|
3
|
+
import { createDetectionResult } from '../onboarding/planner.js'
|
|
4
|
+
import type { DetectionResult } from '../types.js'
|
|
5
|
+
|
|
6
|
+
function printDetectionResult(result: DetectionResult): void {
|
|
7
|
+
const suppressedCodes = new Set([
|
|
8
|
+
'unsupported-build-tool',
|
|
9
|
+
'unsupported-build-tool-present',
|
|
10
|
+
'unsupported-framework',
|
|
11
|
+
'unsupported-framework-present',
|
|
12
|
+
])
|
|
13
|
+
|
|
14
|
+
log.header('Inspecto Detect')
|
|
15
|
+
log.info(`Status: ${result.status}`)
|
|
16
|
+
log.info(`Root: ${result.project.root}`)
|
|
17
|
+
log.info(`Package manager: ${result.project.packageManager}`)
|
|
18
|
+
|
|
19
|
+
if (result.environment.frameworks.length > 0) {
|
|
20
|
+
log.success(`Supported frameworks: ${result.environment.frameworks.join(', ')}`)
|
|
21
|
+
}
|
|
22
|
+
if (result.environment.unsupportedFrameworks.length > 0) {
|
|
23
|
+
log.warn(`Unsupported frameworks: ${result.environment.unsupportedFrameworks.join(', ')}`)
|
|
24
|
+
}
|
|
25
|
+
if (result.environment.buildTools.length > 0) {
|
|
26
|
+
log.success(
|
|
27
|
+
`Supported build tools: ${result.environment.buildTools.map(tool => tool.label).join(', ')}`,
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
if (result.environment.unsupportedBuildTools.length > 0) {
|
|
31
|
+
log.warn(`Unsupported build tools: ${result.environment.unsupportedBuildTools.join(', ')}`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const supportedIdes = result.environment.ides.filter(ide => ide.supported).map(ide => ide.ide)
|
|
35
|
+
if (supportedIdes.length > 0) {
|
|
36
|
+
log.success(`Supported IDEs: ${supportedIdes.join(', ')}`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const supportedProviders = result.environment.providers
|
|
40
|
+
.filter(provider => provider.supported)
|
|
41
|
+
.map(provider => provider.label)
|
|
42
|
+
if (supportedProviders.length > 0) {
|
|
43
|
+
log.success(`Supported providers: ${supportedProviders.join(', ')}`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (const blocker of result.blockers) {
|
|
47
|
+
if (suppressedCodes.has(blocker.code)) continue
|
|
48
|
+
log.error(blocker.message)
|
|
49
|
+
}
|
|
50
|
+
for (const warning of result.warnings) {
|
|
51
|
+
if (suppressedCodes.has(warning.code)) continue
|
|
52
|
+
log.warn(warning.message)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function detect(json = false): Promise<DetectionResult> {
|
|
57
|
+
const result = await createDetectionResult(process.cwd())
|
|
58
|
+
return writeCommandOutput(result, json, printDetectionResult)
|
|
59
|
+
}
|