@inspecto-dev/cli 0.3.3 → 0.3.5
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 +7 -7
- package/.turbo/turbo-test.log +10594 -4044
- package/CHANGELOG.md +28 -0
- package/dist/bin.js +36 -2
- package/dist/{chunk-LJOKPCPD.js → chunk-7ABJRH3F.js} +1701 -182
- package/dist/index.d.ts +69 -4
- package/dist/index.js +7 -1
- package/package.json +3 -3
- package/src/bin.ts +49 -1
- package/src/commands/dev-config.ts +109 -0
- package/src/commands/doctor.ts +189 -9
- package/src/commands/init.ts +10 -3
- package/src/commands/integration-automation.ts +2 -0
- package/src/commands/integration-host-ide.ts +18 -15
- package/src/commands/integration-install.ts +100 -5
- package/src/commands/onboard.ts +80 -15
- package/src/detect/build-tool.ts +212 -15
- package/src/detect/framework.ts +3 -0
- package/src/detect/package-manager.ts +1 -1
- package/src/index.ts +1 -0
- package/src/inject/gitignore.ts +13 -2
- package/src/instructions.ts +33 -7
- package/src/onboarding/apply.ts +255 -28
- package/src/onboarding/nextjs-guidance.ts +257 -0
- package/src/onboarding/nuxt-guidance.ts +129 -0
- package/src/onboarding/planner.ts +337 -10
- package/src/onboarding/session.ts +127 -31
- package/src/onboarding/target-resolution.ts +79 -3
- package/src/onboarding/umi-guidance.ts +139 -0
- package/src/types.ts +58 -3
- package/tests/apply.test.ts +553 -0
- package/tests/build-tool.test.ts +199 -0
- package/tests/dev-config.test.ts +73 -0
- package/tests/doctor.test.ts +130 -0
- package/tests/init.test.ts +17 -0
- package/tests/install-wrapper.test.ts +56 -0
- package/tests/instructions.test.ts +10 -6
- package/tests/integration-host-ide.test.ts +20 -0
- package/tests/integration-install.test.ts +193 -0
- package/tests/nextjs-guidance.test.ts +128 -0
- package/tests/nuxt-guidance.test.ts +67 -0
- package/tests/onboard.test.ts +511 -0
- package/tests/plan.test.ts +283 -21
- package/tests/runner-script.test.ts +120 -1
- package/tests/session-resolve.test.ts +116 -0
- package/tests/session.test.ts +120 -0
package/dist/index.d.ts
CHANGED
|
@@ -49,17 +49,24 @@ interface OnboardingContext {
|
|
|
49
49
|
providers: OnboardingProvider[];
|
|
50
50
|
}
|
|
51
51
|
interface OnboardingTargetCandidate {
|
|
52
|
+
id?: string;
|
|
53
|
+
candidateId?: string;
|
|
52
54
|
packagePath: string;
|
|
53
55
|
configPath: string;
|
|
56
|
+
label?: string;
|
|
54
57
|
buildTool: BuildTool;
|
|
58
|
+
isLegacyRspack?: boolean;
|
|
59
|
+
isLegacyWebpack?: boolean;
|
|
55
60
|
frameworks: string[];
|
|
56
61
|
automaticInjection: boolean;
|
|
57
62
|
}
|
|
58
63
|
interface OnboardingTargetResolution {
|
|
59
|
-
status: 'resolved' | 'needs_selection';
|
|
64
|
+
status: 'resolved' | 'needs_selection' | 'guided';
|
|
60
65
|
selected?: OnboardingTargetCandidate;
|
|
61
66
|
candidates: OnboardingTargetCandidate[];
|
|
62
67
|
reason: string;
|
|
68
|
+
selectionPurpose?: string;
|
|
69
|
+
selectionInstructions?: string;
|
|
63
70
|
}
|
|
64
71
|
interface OnboardingSummary {
|
|
65
72
|
headline: string;
|
|
@@ -67,6 +74,13 @@ interface OnboardingSummary {
|
|
|
67
74
|
risks: string[];
|
|
68
75
|
manualFollowUp: string[];
|
|
69
76
|
}
|
|
77
|
+
interface OnboardingPatchPlan {
|
|
78
|
+
path: string;
|
|
79
|
+
status: 'planned' | 'manual_patch_required';
|
|
80
|
+
reason: string;
|
|
81
|
+
snippet: string;
|
|
82
|
+
confidence: 'high' | 'medium' | 'low';
|
|
83
|
+
}
|
|
70
84
|
interface OnboardingConfirmation {
|
|
71
85
|
required: boolean;
|
|
72
86
|
reason?: string;
|
|
@@ -97,6 +111,15 @@ interface OnboardingVerification {
|
|
|
97
111
|
devCommand?: string;
|
|
98
112
|
message: string;
|
|
99
113
|
}
|
|
114
|
+
interface OnboardingAssistantHandoff {
|
|
115
|
+
framework?: string;
|
|
116
|
+
metaFramework?: string;
|
|
117
|
+
routerMode?: 'app' | 'pages' | 'mixed' | 'unknown';
|
|
118
|
+
autoApplied?: string[];
|
|
119
|
+
pendingSteps?: string[];
|
|
120
|
+
assistantPrompt?: string;
|
|
121
|
+
patches?: OnboardingPatchPlan[];
|
|
122
|
+
}
|
|
100
123
|
interface ResolvedOnboardingSession {
|
|
101
124
|
status: OnboardStatus;
|
|
102
125
|
target: OnboardingTargetResolution;
|
|
@@ -111,6 +134,14 @@ interface ResolvedOnboardingSession {
|
|
|
111
134
|
supported: boolean;
|
|
112
135
|
} | null;
|
|
113
136
|
providerDefault?: string;
|
|
137
|
+
framework?: string;
|
|
138
|
+
metaFramework?: string;
|
|
139
|
+
routerMode?: 'app' | 'pages' | 'mixed' | 'unknown';
|
|
140
|
+
autoApplied?: string[];
|
|
141
|
+
pendingSteps?: string[];
|
|
142
|
+
assistantPrompt?: string;
|
|
143
|
+
patches?: OnboardingPatchPlan[];
|
|
144
|
+
handoff?: OnboardingAssistantHandoff;
|
|
114
145
|
}
|
|
115
146
|
interface OnboardCommandResult {
|
|
116
147
|
status: OnboardStatus;
|
|
@@ -121,6 +152,14 @@ interface OnboardCommandResult {
|
|
|
121
152
|
verification?: OnboardingVerification;
|
|
122
153
|
result?: OnboardingExecutionResult;
|
|
123
154
|
diagnostics?: OnboardingDiagnostics;
|
|
155
|
+
framework?: string;
|
|
156
|
+
metaFramework?: string;
|
|
157
|
+
routerMode?: 'app' | 'pages' | 'mixed' | 'unknown';
|
|
158
|
+
autoApplied?: string[];
|
|
159
|
+
pendingSteps?: string[];
|
|
160
|
+
assistantPrompt?: string;
|
|
161
|
+
patches?: OnboardingPatchPlan[];
|
|
162
|
+
handoff?: OnboardingAssistantHandoff;
|
|
124
163
|
}
|
|
125
164
|
/** Machine-readable detection output for skill-first onboarding */
|
|
126
165
|
interface DetectionResult {
|
|
@@ -148,9 +187,9 @@ interface PlanResult {
|
|
|
148
187
|
status: CommandStatus;
|
|
149
188
|
warnings: CommandMessage[];
|
|
150
189
|
blockers: CommandMessage[];
|
|
151
|
-
strategy: 'supported' | 'manual' | 'unsupported';
|
|
190
|
+
strategy: 'supported' | 'guided' | 'manual' | 'unsupported';
|
|
152
191
|
actions: Array<{
|
|
153
|
-
type: 'install_dependency' | 'modify_file' | 'install_extension' | 'manual_step';
|
|
192
|
+
type: 'install_dependency' | 'modify_file' | 'install_extension' | 'manual_step' | 'generate_patch_plan' | 'generate_file' | 'manual_confirmation';
|
|
154
193
|
target: string;
|
|
155
194
|
description: string;
|
|
156
195
|
}>;
|
|
@@ -160,6 +199,13 @@ interface PlanResult {
|
|
|
160
199
|
shared: boolean;
|
|
161
200
|
extension: boolean;
|
|
162
201
|
};
|
|
202
|
+
framework?: string;
|
|
203
|
+
metaFramework?: string;
|
|
204
|
+
routerMode?: 'app' | 'pages' | 'mixed' | 'unknown';
|
|
205
|
+
autoApplied?: string[];
|
|
206
|
+
pendingSteps?: string[];
|
|
207
|
+
assistantPrompt?: string;
|
|
208
|
+
patches?: OnboardingPatchPlan[];
|
|
163
209
|
}
|
|
164
210
|
/** A single doctor diagnostic check/result */
|
|
165
211
|
interface DoctorDiagnostic {
|
|
@@ -237,6 +283,24 @@ declare function apply(options?: ApplyCommandOptions): Promise<ApplyCommandResul
|
|
|
237
283
|
|
|
238
284
|
declare function detect(json?: boolean): Promise<DetectionResult>;
|
|
239
285
|
|
|
286
|
+
interface InspectoDevConfig {
|
|
287
|
+
cliBin?: string;
|
|
288
|
+
devRepo?: string;
|
|
289
|
+
}
|
|
290
|
+
interface DevConfigCommandResult {
|
|
291
|
+
status: 'ok';
|
|
292
|
+
configPath: string;
|
|
293
|
+
config: InspectoDevConfig;
|
|
294
|
+
}
|
|
295
|
+
interface DevLinkOptions {
|
|
296
|
+
cliBin?: string;
|
|
297
|
+
devRepo?: string;
|
|
298
|
+
json?: boolean;
|
|
299
|
+
}
|
|
300
|
+
declare function devLink(options: DevLinkOptions): Promise<DevConfigCommandResult>;
|
|
301
|
+
declare function devStatus(json?: boolean): Promise<DevConfigCommandResult>;
|
|
302
|
+
declare function devUnlink(json?: boolean): Promise<DevConfigCommandResult>;
|
|
303
|
+
|
|
240
304
|
declare function init(options: InitOptions): Promise<void>;
|
|
241
305
|
|
|
242
306
|
interface DoctorCommandOptions {
|
|
@@ -250,6 +314,7 @@ interface IntegrationAutomationOptions {
|
|
|
250
314
|
inspectoVsix?: string;
|
|
251
315
|
preview?: boolean;
|
|
252
316
|
silent?: boolean;
|
|
317
|
+
ignoreProjectArtifacts?: boolean;
|
|
253
318
|
}
|
|
254
319
|
interface IntegrationAutomationDetails {
|
|
255
320
|
hostIde?: {
|
|
@@ -342,4 +407,4 @@ declare function reportCommandError(error: unknown, options?: ReportCommandError
|
|
|
342
407
|
|
|
343
408
|
type Framework = 'react' | 'vue';
|
|
344
409
|
|
|
345
|
-
export { type BuildTool, type DoctorDiagnostic, type DoctorResult, type Framework, type InitOptions, type InstallLock, type OnboardCommandResult, type OnboardStatus, type PackageManager, type ResolvedOnboardingSession, apply, collectDoctorResult, detect, doctor, init, integrationDoctor, onboard, plan, reportCommandError, teardown, writeCommandOutput };
|
|
410
|
+
export { type BuildTool, type DoctorDiagnostic, type DoctorResult, type Framework, type InitOptions, type InstallLock, type OnboardCommandResult, type OnboardStatus, type PackageManager, type ResolvedOnboardingSession, apply, collectDoctorResult, detect, devLink, devStatus, devUnlink, doctor, init, integrationDoctor, onboard, plan, reportCommandError, teardown, writeCommandOutput };
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,9 @@ import {
|
|
|
2
2
|
apply,
|
|
3
3
|
collectDoctorResult,
|
|
4
4
|
detect,
|
|
5
|
+
devLink,
|
|
6
|
+
devStatus,
|
|
7
|
+
devUnlink,
|
|
5
8
|
doctor,
|
|
6
9
|
init,
|
|
7
10
|
integrationDoctor,
|
|
@@ -10,11 +13,14 @@ import {
|
|
|
10
13
|
reportCommandError,
|
|
11
14
|
teardown,
|
|
12
15
|
writeCommandOutput
|
|
13
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-7ABJRH3F.js";
|
|
14
17
|
export {
|
|
15
18
|
apply,
|
|
16
19
|
collectDoctorResult,
|
|
17
20
|
detect,
|
|
21
|
+
devLink,
|
|
22
|
+
devStatus,
|
|
23
|
+
devUnlink,
|
|
18
24
|
doctor,
|
|
19
25
|
init,
|
|
20
26
|
integrationDoctor,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inspecto-dev/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "CLI tools for Inspecto onboarding and lifecycle management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"inspecto",
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"ora": "^9.3.0",
|
|
21
21
|
"picocolors": "^1.0.0",
|
|
22
22
|
"prompts": "^2.4.2",
|
|
23
|
-
"@inspecto-dev/types": "0.3.
|
|
23
|
+
"@inspecto-dev/types": "0.3.5"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@types/node": "^20.
|
|
26
|
+
"@types/node": "^20.19.39",
|
|
27
27
|
"@types/prompts": "^2.4.9",
|
|
28
28
|
"tsup": "^8.0.2",
|
|
29
29
|
"typescript": "^5.4.5",
|
package/src/bin.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
8
8
|
import { createRequire } from 'node:module'
|
|
9
9
|
import { apply } from './commands/apply.js'
|
|
10
10
|
import { detect } from './commands/detect.js'
|
|
11
|
+
import { devLink, devStatus, devUnlink } from './commands/dev-config.js'
|
|
11
12
|
import { init } from './commands/init.js'
|
|
12
13
|
import { doctor } from './commands/doctor.js'
|
|
13
14
|
import { onboard } from './commands/onboard.js'
|
|
@@ -69,6 +70,11 @@ interface IntegrationCommandOptions extends JsonCommandOptions {
|
|
|
69
70
|
force?: boolean
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
interface DevCommandOptions extends JsonCommandOptions {
|
|
74
|
+
cliBin?: string
|
|
75
|
+
repo?: string
|
|
76
|
+
}
|
|
77
|
+
|
|
72
78
|
const integrationScopes = ['project', 'user'] as const
|
|
73
79
|
const integrationModes = ['skills', 'instructions', 'agents', 'rules'] as const
|
|
74
80
|
|
|
@@ -83,6 +89,45 @@ function exitWithError(error: unknown, options: JsonCommandOptions = {}): never
|
|
|
83
89
|
export function createCli(_argv: readonly string[] = process.argv): CAC {
|
|
84
90
|
const cli: CAC = cac('inspecto')
|
|
85
91
|
|
|
92
|
+
cli
|
|
93
|
+
.command('dev <subcommand>', 'Manage project-local Inspecto development overrides')
|
|
94
|
+
.option('--cli-bin <path>', 'Point this project at a local CLI dist/bin.js')
|
|
95
|
+
.option('--repo <path>', 'Point this project at a local Inspecto repository root')
|
|
96
|
+
.option('--json', 'Print machine-readable JSON output', { default: false })
|
|
97
|
+
.option('--debug', 'Enable debug mode to show full error traces', { default: false })
|
|
98
|
+
.action(async (subcommand: string, options: DevCommandOptions) => {
|
|
99
|
+
try {
|
|
100
|
+
if (subcommand === 'link') {
|
|
101
|
+
if (!options.cliBin && !options.repo) {
|
|
102
|
+
throw new Error('The `dev link` subcommand requires --cli-bin <path> or --repo <path>.')
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
await devLink({
|
|
106
|
+
...(options.cliBin ? { cliBin: options.cliBin } : {}),
|
|
107
|
+
...(options.repo ? { devRepo: options.repo } : {}),
|
|
108
|
+
json: options.json ?? false,
|
|
109
|
+
})
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (subcommand === 'status') {
|
|
114
|
+
await devStatus(options.json ?? false)
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (subcommand === 'unlink') {
|
|
119
|
+
await devUnlink(options.json ?? false)
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
throw new Error(
|
|
124
|
+
'Usage:\n inspecto dev link [--cli-bin <path>] [--repo <path>]\n inspecto dev status [--json]\n inspecto dev unlink [--json]',
|
|
125
|
+
)
|
|
126
|
+
} catch (error) {
|
|
127
|
+
exitWithError(error, options)
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
|
|
86
131
|
cli
|
|
87
132
|
.command('init', 'Set up Inspecto in your project')
|
|
88
133
|
.option('--shared', 'Share .inspecto/settings.json with your team via Git', { default: false })
|
|
@@ -128,7 +173,10 @@ export function createCli(_argv: readonly string[] = process.argv): CAC {
|
|
|
128
173
|
cli
|
|
129
174
|
.command('onboard', 'Run assistant-oriented Inspecto onboarding in one structured flow')
|
|
130
175
|
.option('--json', 'Print machine-readable JSON output', { default: false })
|
|
131
|
-
.option(
|
|
176
|
+
.option(
|
|
177
|
+
'--target <candidateIdOrPath>',
|
|
178
|
+
'Select the build target to onboard using a returned candidateId or compatible config path',
|
|
179
|
+
)
|
|
132
180
|
.option('--yes', 'Accept a lightweight confirmation gate automatically', { default: false })
|
|
133
181
|
.option('--shared', 'Write shared Inspecto settings instead of local-only settings')
|
|
134
182
|
.option('--skip-install', 'Skip npm dependency installation')
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { readJSON, removeFile, writeJSON } from '../utils/fs.js'
|
|
3
|
+
import { updateGitignore } from '../inject/gitignore.js'
|
|
4
|
+
import { log } from '../utils/logger.js'
|
|
5
|
+
import { writeCommandOutput } from '../utils/output.js'
|
|
6
|
+
|
|
7
|
+
export interface InspectoDevConfig {
|
|
8
|
+
cliBin?: string
|
|
9
|
+
devRepo?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface DevConfigCommandResult {
|
|
13
|
+
status: 'ok'
|
|
14
|
+
configPath: string
|
|
15
|
+
config: InspectoDevConfig
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface DevLinkOptions {
|
|
19
|
+
cliBin?: string
|
|
20
|
+
devRepo?: string
|
|
21
|
+
json?: boolean
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const DEV_CONFIG_PATH = path.join('.inspecto', 'dev.json')
|
|
25
|
+
|
|
26
|
+
function absoluteDevConfigPath(root: string): string {
|
|
27
|
+
return path.join(root, DEV_CONFIG_PATH)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function printDevConfigResult(result: DevConfigCommandResult): void {
|
|
31
|
+
log.header('Inspecto Dev')
|
|
32
|
+
log.info(`Config: ${result.configPath}`)
|
|
33
|
+
if (result.config.cliBin) {
|
|
34
|
+
log.hint(`cliBin: ${result.config.cliBin}`)
|
|
35
|
+
}
|
|
36
|
+
if (result.config.devRepo) {
|
|
37
|
+
log.hint(`devRepo: ${result.config.devRepo}`)
|
|
38
|
+
}
|
|
39
|
+
if (!result.config.cliBin && !result.config.devRepo) {
|
|
40
|
+
log.hint('No local dev overrides are configured.')
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function readExistingConfig(root: string): Promise<InspectoDevConfig> {
|
|
45
|
+
const configPath = absoluteDevConfigPath(root)
|
|
46
|
+
const config = await readJSON<InspectoDevConfig>(configPath)
|
|
47
|
+
if (!config || typeof config !== 'object') {
|
|
48
|
+
return {}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return config
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function devLink(options: DevLinkOptions): Promise<DevConfigCommandResult> {
|
|
55
|
+
const root = process.cwd()
|
|
56
|
+
const configPath = absoluteDevConfigPath(root)
|
|
57
|
+
const existing = await readExistingConfig(root)
|
|
58
|
+
const nextConfig: InspectoDevConfig = {
|
|
59
|
+
...existing,
|
|
60
|
+
...(options.cliBin ? { cliBin: options.cliBin } : {}),
|
|
61
|
+
...(options.devRepo ? { devRepo: options.devRepo } : {}),
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
await writeJSON(configPath, nextConfig)
|
|
65
|
+
await updateGitignore(root, false, false, true)
|
|
66
|
+
|
|
67
|
+
return writeCommandOutput(
|
|
68
|
+
{
|
|
69
|
+
status: 'ok',
|
|
70
|
+
configPath,
|
|
71
|
+
config: nextConfig,
|
|
72
|
+
},
|
|
73
|
+
options.json ?? false,
|
|
74
|
+
printDevConfigResult,
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function devStatus(json = false): Promise<DevConfigCommandResult> {
|
|
79
|
+
const root = process.cwd()
|
|
80
|
+
const configPath = absoluteDevConfigPath(root)
|
|
81
|
+
const config = await readExistingConfig(root)
|
|
82
|
+
|
|
83
|
+
return writeCommandOutput(
|
|
84
|
+
{
|
|
85
|
+
status: 'ok',
|
|
86
|
+
configPath,
|
|
87
|
+
config,
|
|
88
|
+
},
|
|
89
|
+
json,
|
|
90
|
+
printDevConfigResult,
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function devUnlink(json = false): Promise<DevConfigCommandResult> {
|
|
95
|
+
const root = process.cwd()
|
|
96
|
+
const configPath = absoluteDevConfigPath(root)
|
|
97
|
+
|
|
98
|
+
await removeFile(configPath)
|
|
99
|
+
|
|
100
|
+
return writeCommandOutput(
|
|
101
|
+
{
|
|
102
|
+
status: 'ok',
|
|
103
|
+
configPath,
|
|
104
|
+
config: {},
|
|
105
|
+
},
|
|
106
|
+
json,
|
|
107
|
+
printDevConfigResult,
|
|
108
|
+
)
|
|
109
|
+
}
|
package/src/commands/doctor.ts
CHANGED
|
@@ -10,8 +10,15 @@ import { detectFrameworks } from '../detect/framework.js'
|
|
|
10
10
|
import { detectIDE } from '../detect/ide.js'
|
|
11
11
|
import { detectProviders } from '../detect/provider.js'
|
|
12
12
|
import { isExtensionInstalled } from '../inject/extension.js'
|
|
13
|
+
import { createPlanResult } from '../onboarding/planner.js'
|
|
13
14
|
import { writeCommandOutput } from '../utils/output.js'
|
|
14
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
CommandStatus,
|
|
17
|
+
DoctorDiagnostic,
|
|
18
|
+
DoctorResult,
|
|
19
|
+
OnboardingContext,
|
|
20
|
+
PlanResult,
|
|
21
|
+
} from '../types.js'
|
|
15
22
|
|
|
16
23
|
export interface DoctorCommandOptions {
|
|
17
24
|
json?: boolean
|
|
@@ -39,6 +46,113 @@ function doctorStatus(errors: number, warnings: number): CommandStatus {
|
|
|
39
46
|
return 'ok'
|
|
40
47
|
}
|
|
41
48
|
|
|
49
|
+
function isGuidedMetaFramework(buildTool: string): boolean {
|
|
50
|
+
return buildTool === 'Next.js' || buildTool === 'Nuxt'
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function buildDoctorOnboardingContext(input: {
|
|
54
|
+
root: string
|
|
55
|
+
packageManager: NonNullable<DoctorResult['project']['packageManager']>
|
|
56
|
+
buildTools: Awaited<ReturnType<typeof detectBuildTools>>
|
|
57
|
+
frameworks: Awaited<ReturnType<typeof detectFrameworks>>
|
|
58
|
+
ides: Awaited<ReturnType<typeof detectIDE>>
|
|
59
|
+
providers: Awaited<ReturnType<typeof detectProviders>>
|
|
60
|
+
}): OnboardingContext {
|
|
61
|
+
return {
|
|
62
|
+
root: input.root,
|
|
63
|
+
packageManager: input.packageManager,
|
|
64
|
+
buildTools: input.buildTools,
|
|
65
|
+
frameworks: {
|
|
66
|
+
supported: input.frameworks.supported,
|
|
67
|
+
unsupported: input.frameworks.unsupported.map(item => item.name),
|
|
68
|
+
},
|
|
69
|
+
ides: input.ides.detected.map(({ ide, supported }) => ({ ide, supported })),
|
|
70
|
+
providers: input.providers.detected.map(({ id, label, supported, preferredMode }) => ({
|
|
71
|
+
id,
|
|
72
|
+
label,
|
|
73
|
+
supported,
|
|
74
|
+
preferredMode,
|
|
75
|
+
})),
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isConfigPatchReason(reason: string): boolean {
|
|
80
|
+
return reason.startsWith('next_config_') || reason.startsWith('nuxt_config_')
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isNextWebpackDevPatchReason(reason: string): boolean {
|
|
84
|
+
return reason === 'next_dev_script_requires_webpack'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function collectGuidedPatchDiagnostics(
|
|
88
|
+
root: string,
|
|
89
|
+
plan: PlanResult,
|
|
90
|
+
): Promise<DoctorDiagnostic[]> {
|
|
91
|
+
if (plan.strategy !== 'guided' || !plan.patches?.length) {
|
|
92
|
+
return []
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const diagnostics: DoctorDiagnostic[] = []
|
|
96
|
+
|
|
97
|
+
for (const patch of plan.patches) {
|
|
98
|
+
if (isConfigPatchReason(patch.reason)) {
|
|
99
|
+
const content = await readFile(path.join(root, patch.path))
|
|
100
|
+
if (content?.includes('@inspecto-dev/plugin')) {
|
|
101
|
+
diagnostics.push(
|
|
102
|
+
createDiagnostic(
|
|
103
|
+
'guided-config-patch-detected',
|
|
104
|
+
'ok',
|
|
105
|
+
`Guided config patch appears to be applied in ${patch.path}`,
|
|
106
|
+
[],
|
|
107
|
+
{ path: patch.path, reason: patch.reason },
|
|
108
|
+
),
|
|
109
|
+
)
|
|
110
|
+
} else {
|
|
111
|
+
diagnostics.push(
|
|
112
|
+
createDiagnostic(
|
|
113
|
+
'guided-config-patch-pending',
|
|
114
|
+
'warning',
|
|
115
|
+
`Guided config patch still needs review in ${patch.path}`,
|
|
116
|
+
['Run `inspecto onboard --json` to review the generated patch details.'],
|
|
117
|
+
{ path: patch.path, reason: patch.reason },
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (isNextWebpackDevPatchReason(patch.reason)) {
|
|
125
|
+
const packageJson = await readJSON<{ scripts?: Record<string, string> }>(
|
|
126
|
+
path.join(root, 'package.json'),
|
|
127
|
+
)
|
|
128
|
+
const devScript = packageJson?.scripts?.dev ?? ''
|
|
129
|
+
if (/next\s+dev\b/.test(devScript) && /--webpack\b/.test(devScript)) {
|
|
130
|
+
diagnostics.push(
|
|
131
|
+
createDiagnostic(
|
|
132
|
+
'guided-dev-script-configured',
|
|
133
|
+
'ok',
|
|
134
|
+
'Next.js dev script is configured for webpack mode',
|
|
135
|
+
[],
|
|
136
|
+
{ script: devScript },
|
|
137
|
+
),
|
|
138
|
+
)
|
|
139
|
+
} else {
|
|
140
|
+
diagnostics.push(
|
|
141
|
+
createDiagnostic(
|
|
142
|
+
'guided-dev-script-pending',
|
|
143
|
+
'warning',
|
|
144
|
+
'Next.js dev script still needs webpack mode for Inspecto validation',
|
|
145
|
+
['Update the `dev` script to `next dev --webpack` before browser validation.'],
|
|
146
|
+
{ script: devScript },
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return diagnostics
|
|
154
|
+
}
|
|
155
|
+
|
|
42
156
|
function printDoctorResult(result: DoctorResult): void {
|
|
43
157
|
log.header('Inspecto Doctor')
|
|
44
158
|
|
|
@@ -99,6 +213,15 @@ export async function collectDoctorResult(root = process.cwd()): Promise<DoctorR
|
|
|
99
213
|
detectBuildTools(root),
|
|
100
214
|
isExtensionInstalled(),
|
|
101
215
|
])
|
|
216
|
+
const onboardingContext = buildDoctorOnboardingContext({
|
|
217
|
+
root,
|
|
218
|
+
packageManager: pm,
|
|
219
|
+
buildTools: buildResult,
|
|
220
|
+
frameworks: frameworkResult,
|
|
221
|
+
ides: ideProbe,
|
|
222
|
+
providers: providerProbe,
|
|
223
|
+
})
|
|
224
|
+
const onboardingPlan = createPlanResult(onboardingContext)
|
|
102
225
|
|
|
103
226
|
// Check 2: IDE
|
|
104
227
|
if (ideProbe.detected.length === 0) {
|
|
@@ -229,15 +352,45 @@ export async function collectDoctorResult(root = process.cwd()): Promise<DoctorR
|
|
|
229
352
|
)
|
|
230
353
|
}
|
|
231
354
|
} else if (buildResult.unsupported.length > 0) {
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
`build-tool-unsupported`,
|
|
236
|
-
'warning',
|
|
237
|
-
`Build tool: ${names} (not supported in v1)`,
|
|
238
|
-
['current version supports: Vite, Webpack, Rspack, esbuild, Rollup'],
|
|
239
|
-
),
|
|
355
|
+
const guidedBuildTools = buildResult.unsupported.filter(isGuidedMetaFramework)
|
|
356
|
+
const trulyUnsupportedBuildTools = buildResult.unsupported.filter(
|
|
357
|
+
buildTool => !isGuidedMetaFramework(buildTool),
|
|
240
358
|
)
|
|
359
|
+
|
|
360
|
+
if (guidedBuildTools.length > 0) {
|
|
361
|
+
checks.push(
|
|
362
|
+
createDiagnostic(
|
|
363
|
+
'build-tool-guided',
|
|
364
|
+
'warning',
|
|
365
|
+
`Build tool: ${guidedBuildTools.join(', ')} (guided onboarding available)`,
|
|
366
|
+
[
|
|
367
|
+
'Run `inspecto onboard --json` to generate the remaining patch plan and assistant handoff.',
|
|
368
|
+
...(onboardingPlan.pendingSteps ?? []),
|
|
369
|
+
],
|
|
370
|
+
{
|
|
371
|
+
metaFrameworks: guidedBuildTools,
|
|
372
|
+
...(onboardingPlan.pendingSteps ? { pendingSteps: onboardingPlan.pendingSteps } : {}),
|
|
373
|
+
...(onboardingPlan.assistantPrompt
|
|
374
|
+
? { assistantPrompt: onboardingPlan.assistantPrompt }
|
|
375
|
+
: {}),
|
|
376
|
+
...(onboardingPlan.patches ? { patchCount: onboardingPlan.patches.length } : {}),
|
|
377
|
+
},
|
|
378
|
+
),
|
|
379
|
+
)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
checks.push(...(await collectGuidedPatchDiagnostics(root, onboardingPlan)))
|
|
383
|
+
|
|
384
|
+
if (trulyUnsupportedBuildTools.length > 0) {
|
|
385
|
+
checks.push(
|
|
386
|
+
createDiagnostic(
|
|
387
|
+
'build-tool-unsupported',
|
|
388
|
+
'warning',
|
|
389
|
+
`Build tool: ${trulyUnsupportedBuildTools.join(', ')} (not supported in v1)`,
|
|
390
|
+
['current version supports: Vite, Webpack, Rspack, esbuild, Rollup'],
|
|
391
|
+
),
|
|
392
|
+
)
|
|
393
|
+
}
|
|
241
394
|
} else {
|
|
242
395
|
checks.push(
|
|
243
396
|
createDiagnostic('build-tool-missing', 'warning', 'No recognized build config found'),
|
|
@@ -282,6 +435,33 @@ export async function collectDoctorResult(root = process.cwd()): Promise<DoctorR
|
|
|
282
435
|
const settings = await readJSON(targetPath)
|
|
283
436
|
if (settings) {
|
|
284
437
|
checks.push(createDiagnostic('settings-valid', 'ok', `.inspecto/${fileName} valid`))
|
|
438
|
+
|
|
439
|
+
const configuredIde =
|
|
440
|
+
typeof (settings as Record<string, unknown>).ide === 'string'
|
|
441
|
+
? ((settings as Record<string, unknown>).ide as string)
|
|
442
|
+
: undefined
|
|
443
|
+
const detectedIdeCandidates = ideProbe.detected.map(item => item.ide)
|
|
444
|
+
if (
|
|
445
|
+
configuredIde &&
|
|
446
|
+
detectedIdeCandidates.length > 0 &&
|
|
447
|
+
!detectedIdeCandidates.includes(configuredIde)
|
|
448
|
+
) {
|
|
449
|
+
checks.push(
|
|
450
|
+
createDiagnostic(
|
|
451
|
+
'settings-ide-mismatch',
|
|
452
|
+
'warning',
|
|
453
|
+
`.inspecto/${fileName} sets ide=${configuredIde}, but the current environment looks like ${detectedIdeCandidates.join(', ')}. Inspecto will use the configured IDE from ${fileName}.`,
|
|
454
|
+
[
|
|
455
|
+
`Update .inspecto/${fileName} if you want Inspecto to target the currently detected IDE instead.`,
|
|
456
|
+
],
|
|
457
|
+
{
|
|
458
|
+
configuredIde,
|
|
459
|
+
detectedIdeCandidates,
|
|
460
|
+
precedence: `configured ide from ${fileName}`,
|
|
461
|
+
},
|
|
462
|
+
),
|
|
463
|
+
)
|
|
464
|
+
}
|
|
285
465
|
} else {
|
|
286
466
|
checks.push(
|
|
287
467
|
createDiagnostic(
|
package/src/commands/init.ts
CHANGED
|
@@ -24,7 +24,11 @@ import {
|
|
|
24
24
|
promptMonorepoPackageChoice,
|
|
25
25
|
promptUnsupportedFrameworkContinue,
|
|
26
26
|
} from '../prompts.js'
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
printNextJsManualInstructions,
|
|
29
|
+
printNuxtManualInstructions,
|
|
30
|
+
printUmiManualInstructions,
|
|
31
|
+
} from '../instructions.js'
|
|
28
32
|
|
|
29
33
|
export async function init(options: InitOptions): Promise<void> {
|
|
30
34
|
const repoRoot = process.cwd()
|
|
@@ -175,8 +179,8 @@ export async function init(options: InitOptions): Promise<void> {
|
|
|
175
179
|
if (buildResult.unsupported.length > 0) {
|
|
176
180
|
const names = buildResult.unsupported.join(', ')
|
|
177
181
|
manualConfigRequiredFor = buildResult.unsupported[0] || ''
|
|
178
|
-
log.warn(`Detected ${names} —
|
|
179
|
-
log.hint('
|
|
182
|
+
log.warn(`Detected ${names} — guided onboarding is available in the current version`)
|
|
183
|
+
log.hint('Inspecto can prepare the remaining patch plan and assistant handoff for this stack.')
|
|
180
184
|
|
|
181
185
|
if (buildResult.unsupported.includes('Next.js')) {
|
|
182
186
|
printNextJsManualInstructions()
|
|
@@ -184,6 +188,9 @@ export async function init(options: InitOptions): Promise<void> {
|
|
|
184
188
|
if (buildResult.unsupported.includes('Nuxt')) {
|
|
185
189
|
printNuxtManualInstructions()
|
|
186
190
|
}
|
|
191
|
+
if (buildResult.unsupported.includes('Umi')) {
|
|
192
|
+
printUmiManualInstructions()
|
|
193
|
+
}
|
|
187
194
|
}
|
|
188
195
|
if (buildResult.supported.length === 0 && buildResult.unsupported.length === 0) {
|
|
189
196
|
log.warn('No recognized build tool detected')
|
|
@@ -24,6 +24,7 @@ interface IntegrationAutomationOptions {
|
|
|
24
24
|
inspectoVsix?: string
|
|
25
25
|
preview?: boolean
|
|
26
26
|
silent?: boolean
|
|
27
|
+
ignoreProjectArtifacts?: boolean
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
interface IntegrationAutomationDetails {
|
|
@@ -93,6 +94,7 @@ export async function runIntegrationAutomation(
|
|
|
93
94
|
const resolvedHostIde = await resolveIntegrationHostIde({
|
|
94
95
|
...(options.ide ? { explicitIde: options.ide } : {}),
|
|
95
96
|
...(cwd ? { cwd } : {}),
|
|
97
|
+
...(options.ignoreProjectArtifacts ? { ignoreProjectArtifacts: true } : {}),
|
|
96
98
|
})
|
|
97
99
|
|
|
98
100
|
const details: IntegrationAutomationDetails = {
|