@inspecto-dev/cli 0.3.4 → 0.3.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 +7 -7
- package/.turbo/turbo-test.log +205 -7275
- package/CHANGELOG.md +14 -0
- package/dist/bin.js +32 -1
- package/dist/{chunk-2MOEVONN.js → chunk-7ABJRH3F.js} +1232 -145
- package/dist/index.d.ts +62 -4
- package/dist/index.js +7 -1
- package/package.json +2 -2
- package/src/bin.ts +45 -0
- package/src/commands/dev-config.ts +109 -0
- package/src/commands/doctor.ts +162 -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 +1 -1
- package/src/commands/onboard.ts +72 -21
- package/src/detect/build-tool.ts +14 -5
- 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 +137 -3
- package/src/onboarding/nextjs-guidance.ts +257 -0
- package/src/onboarding/nuxt-guidance.ts +129 -0
- package/src/onboarding/planner.ts +257 -6
- package/src/onboarding/session.ts +117 -27
- package/src/onboarding/target-resolution.ts +3 -3
- package/src/onboarding/umi-guidance.ts +139 -0
- package/src/types.ts +51 -3
- package/tests/apply.test.ts +319 -0
- package/tests/dev-config.test.ts +73 -0
- package/tests/doctor.test.ts +89 -0
- package/tests/init.test.ts +17 -0
- package/tests/instructions.test.ts +10 -6
- package/tests/integration-host-ide.test.ts +20 -0
- package/tests/integration-install.test.ts +65 -0
- package/tests/nextjs-guidance.test.ts +128 -0
- package/tests/nuxt-guidance.test.ts +67 -0
- package/tests/onboard.test.ts +416 -0
- package/tests/plan.test.ts +181 -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
|
@@ -61,7 +61,7 @@ interface OnboardingTargetCandidate {
|
|
|
61
61
|
automaticInjection: boolean;
|
|
62
62
|
}
|
|
63
63
|
interface OnboardingTargetResolution {
|
|
64
|
-
status: 'resolved' | 'needs_selection';
|
|
64
|
+
status: 'resolved' | 'needs_selection' | 'guided';
|
|
65
65
|
selected?: OnboardingTargetCandidate;
|
|
66
66
|
candidates: OnboardingTargetCandidate[];
|
|
67
67
|
reason: string;
|
|
@@ -74,6 +74,13 @@ interface OnboardingSummary {
|
|
|
74
74
|
risks: string[];
|
|
75
75
|
manualFollowUp: string[];
|
|
76
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
|
+
}
|
|
77
84
|
interface OnboardingConfirmation {
|
|
78
85
|
required: boolean;
|
|
79
86
|
reason?: string;
|
|
@@ -104,6 +111,15 @@ interface OnboardingVerification {
|
|
|
104
111
|
devCommand?: string;
|
|
105
112
|
message: string;
|
|
106
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
|
+
}
|
|
107
123
|
interface ResolvedOnboardingSession {
|
|
108
124
|
status: OnboardStatus;
|
|
109
125
|
target: OnboardingTargetResolution;
|
|
@@ -118,6 +134,14 @@ interface ResolvedOnboardingSession {
|
|
|
118
134
|
supported: boolean;
|
|
119
135
|
} | null;
|
|
120
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;
|
|
121
145
|
}
|
|
122
146
|
interface OnboardCommandResult {
|
|
123
147
|
status: OnboardStatus;
|
|
@@ -128,6 +152,14 @@ interface OnboardCommandResult {
|
|
|
128
152
|
verification?: OnboardingVerification;
|
|
129
153
|
result?: OnboardingExecutionResult;
|
|
130
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;
|
|
131
163
|
}
|
|
132
164
|
/** Machine-readable detection output for skill-first onboarding */
|
|
133
165
|
interface DetectionResult {
|
|
@@ -155,9 +187,9 @@ interface PlanResult {
|
|
|
155
187
|
status: CommandStatus;
|
|
156
188
|
warnings: CommandMessage[];
|
|
157
189
|
blockers: CommandMessage[];
|
|
158
|
-
strategy: 'supported' | 'manual' | 'unsupported';
|
|
190
|
+
strategy: 'supported' | 'guided' | 'manual' | 'unsupported';
|
|
159
191
|
actions: Array<{
|
|
160
|
-
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';
|
|
161
193
|
target: string;
|
|
162
194
|
description: string;
|
|
163
195
|
}>;
|
|
@@ -167,6 +199,13 @@ interface PlanResult {
|
|
|
167
199
|
shared: boolean;
|
|
168
200
|
extension: boolean;
|
|
169
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[];
|
|
170
209
|
}
|
|
171
210
|
/** A single doctor diagnostic check/result */
|
|
172
211
|
interface DoctorDiagnostic {
|
|
@@ -244,6 +283,24 @@ declare function apply(options?: ApplyCommandOptions): Promise<ApplyCommandResul
|
|
|
244
283
|
|
|
245
284
|
declare function detect(json?: boolean): Promise<DetectionResult>;
|
|
246
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
|
+
|
|
247
304
|
declare function init(options: InitOptions): Promise<void>;
|
|
248
305
|
|
|
249
306
|
interface DoctorCommandOptions {
|
|
@@ -257,6 +314,7 @@ interface IntegrationAutomationOptions {
|
|
|
257
314
|
inspectoVsix?: string;
|
|
258
315
|
preview?: boolean;
|
|
259
316
|
silent?: boolean;
|
|
317
|
+
ignoreProjectArtifacts?: boolean;
|
|
260
318
|
}
|
|
261
319
|
interface IntegrationAutomationDetails {
|
|
262
320
|
hostIde?: {
|
|
@@ -349,4 +407,4 @@ declare function reportCommandError(error: unknown, options?: ReportCommandError
|
|
|
349
407
|
|
|
350
408
|
type Framework = 'react' | 'vue';
|
|
351
409
|
|
|
352
|
-
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.6",
|
|
4
4
|
"description": "CLI tools for Inspecto onboarding and lifecycle management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"inspecto",
|
|
@@ -20,7 +20,7 @@
|
|
|
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.6"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^20.19.39",
|
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 })
|
|
@@ -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'),
|
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 = {
|
|
@@ -12,6 +12,7 @@ export type HostIdeSource = 'explicit' | 'config' | 'env' | 'artifact' | 'ambigu
|
|
|
12
12
|
export interface ResolveIntegrationHostIdeOptions {
|
|
13
13
|
explicitIde?: string
|
|
14
14
|
cwd?: string
|
|
15
|
+
ignoreProjectArtifacts?: boolean
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export interface ResolvedIntegrationHostIde {
|
|
@@ -51,7 +52,7 @@ export async function resolveIntegrationHostIde(
|
|
|
51
52
|
const envCandidates = detectEnvHostIdes()
|
|
52
53
|
if (envCandidates.length === 1) {
|
|
53
54
|
return {
|
|
54
|
-
ide: envCandidates[0]
|
|
55
|
+
ide: envCandidates[0]!,
|
|
55
56
|
confidence: 'high',
|
|
56
57
|
source: 'env',
|
|
57
58
|
candidates: envCandidates,
|
|
@@ -67,22 +68,24 @@ export async function resolveIntegrationHostIde(
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
if (!options.ignoreProjectArtifacts) {
|
|
72
|
+
const artifactCandidates = await detectArtifactHostIdes(cwd)
|
|
73
|
+
if (artifactCandidates.length === 1) {
|
|
74
|
+
return {
|
|
75
|
+
ide: artifactCandidates[0]!,
|
|
76
|
+
confidence: 'medium',
|
|
77
|
+
source: 'artifact',
|
|
78
|
+
candidates: artifactCandidates,
|
|
79
|
+
}
|
|
77
80
|
}
|
|
78
|
-
}
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
if (artifactCandidates.length > 1) {
|
|
83
|
+
return {
|
|
84
|
+
ide: null,
|
|
85
|
+
confidence: 'low',
|
|
86
|
+
source: 'ambiguous',
|
|
87
|
+
candidates: artifactCandidates,
|
|
88
|
+
}
|
|
86
89
|
}
|
|
87
90
|
}
|
|
88
91
|
|
|
@@ -266,7 +266,7 @@ export async function installIntegration(
|
|
|
266
266
|
|
|
267
267
|
const automationResult = await runIntegrationAutomation(
|
|
268
268
|
assistant,
|
|
269
|
-
{ ...options, silent },
|
|
269
|
+
{ ...options, silent, ignoreProjectArtifacts: true },
|
|
270
270
|
process.cwd(),
|
|
271
271
|
)
|
|
272
272
|
const result: IntegrationInstallResult = {
|