@inspecto-dev/cli 0.3.6 → 0.3.8
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 +5 -5
- package/.turbo/turbo-test.log +6777 -205
- package/CHANGELOG.md +16 -0
- package/README.md +4 -2
- package/dist/bin.js +1 -1
- package/dist/{chunk-7ABJRH3F.js → chunk-B5JDHSP7.js} +166 -35
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/src/commands/integration-automation.ts +12 -4
- package/src/commands/integration-host-ide.ts +25 -6
- package/src/commands/integration-install.ts +48 -9
- package/src/detect/framework.ts +9 -6
- package/src/detect/ide.ts +42 -7
- package/src/detect/provider.ts +1 -1
- package/src/inject/extension.ts +30 -0
- package/src/inject/strategies/esbuild.ts +2 -2
- package/src/inject/strategies/rollup.ts +2 -2
- package/src/inject/strategies/rsbuild.ts +2 -2
- package/src/inject/strategies/rspack.ts +2 -2
- package/src/inject/strategies/vite.ts +2 -2
- package/src/inject/strategies/webpack.ts +2 -2
- package/src/integrations/capabilities.ts +38 -0
- package/tests/detect.test.ts +2 -2
- package/tests/extension-installer.test.ts +48 -0
- package/tests/framework.test.ts +27 -3
- package/tests/integration-automation.test.ts +1 -1
- package/tests/integration-host-ide.test.ts +54 -0
- package/tests/integration-install.test.ts +7 -7
- package/tests/plan.test.ts +16 -16
- package/tests/shared-capabilities.test.ts +4 -0
|
@@ -19,7 +19,15 @@ import {
|
|
|
19
19
|
const REPO_RAW_BASE = 'https://raw.githubusercontent.com/inspecto-dev/inspecto/main'
|
|
20
20
|
const TOTAL_STEPS = 6
|
|
21
21
|
|
|
22
|
-
type AssistantId =
|
|
22
|
+
type AssistantId =
|
|
23
|
+
| 'codex'
|
|
24
|
+
| 'claude-code'
|
|
25
|
+
| 'copilot'
|
|
26
|
+
| 'cursor'
|
|
27
|
+
| 'gemini'
|
|
28
|
+
| 'trae'
|
|
29
|
+
| 'coco'
|
|
30
|
+
| 'codebuddy'
|
|
23
31
|
type ClaudeScope = 'project' | 'user'
|
|
24
32
|
type CopilotMode = 'skills' | 'instructions' | 'agents'
|
|
25
33
|
type CursorMode = 'skills' | 'rules' | 'agents'
|
|
@@ -86,7 +94,7 @@ const INTEGRATION_MANIFESTS: IntegrationManifest[] = [
|
|
|
86
94
|
type: 'native-skill',
|
|
87
95
|
installTarget: '.agents/skills/',
|
|
88
96
|
preferredInstall:
|
|
89
|
-
'npx @inspecto-dev/cli integrations install codex --host-ide <vscode|cursor|trae|trae-cn>',
|
|
97
|
+
'npx @inspecto-dev/cli integrations install codex --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn>',
|
|
90
98
|
cliSupported: true,
|
|
91
99
|
},
|
|
92
100
|
{
|
|
@@ -94,7 +102,7 @@ const INTEGRATION_MANIFESTS: IntegrationManifest[] = [
|
|
|
94
102
|
type: 'native-skill',
|
|
95
103
|
installTarget: '.claude/skills/ or ~/.claude/skills/',
|
|
96
104
|
preferredInstall:
|
|
97
|
-
'npx @inspecto-dev/cli integrations install claude-code --scope project --host-ide <vscode|cursor|trae|trae-cn>',
|
|
105
|
+
'npx @inspecto-dev/cli integrations install claude-code --scope project --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn>',
|
|
98
106
|
cliSupported: true,
|
|
99
107
|
},
|
|
100
108
|
{
|
|
@@ -102,7 +110,7 @@ const INTEGRATION_MANIFESTS: IntegrationManifest[] = [
|
|
|
102
110
|
type: 'native-skill',
|
|
103
111
|
installTarget: '.github/skills/inspecto-onboarding/',
|
|
104
112
|
preferredInstall:
|
|
105
|
-
'npx @inspecto-dev/cli integrations install copilot --host-ide <vscode|cursor|trae|trae-cn>',
|
|
113
|
+
'npx @inspecto-dev/cli integrations install copilot --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn>',
|
|
106
114
|
cliSupported: true,
|
|
107
115
|
},
|
|
108
116
|
{
|
|
@@ -110,7 +118,7 @@ const INTEGRATION_MANIFESTS: IntegrationManifest[] = [
|
|
|
110
118
|
type: 'native-skill',
|
|
111
119
|
installTarget: '.cursor/skills/inspecto-onboarding/',
|
|
112
120
|
preferredInstall:
|
|
113
|
-
'npx @inspecto-dev/cli integrations install cursor --host-ide <vscode|cursor|trae|trae-cn>',
|
|
121
|
+
'npx @inspecto-dev/cli integrations install cursor --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn>',
|
|
114
122
|
cliSupported: true,
|
|
115
123
|
},
|
|
116
124
|
{
|
|
@@ -118,7 +126,7 @@ const INTEGRATION_MANIFESTS: IntegrationManifest[] = [
|
|
|
118
126
|
type: 'native-skill',
|
|
119
127
|
installTarget: '.gemini/skills/inspecto-onboarding/',
|
|
120
128
|
preferredInstall:
|
|
121
|
-
'npx @inspecto-dev/cli integrations install gemini --host-ide <vscode|cursor|trae|trae-cn>',
|
|
129
|
+
'npx @inspecto-dev/cli integrations install gemini --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn>',
|
|
122
130
|
cliSupported: true,
|
|
123
131
|
},
|
|
124
132
|
{
|
|
@@ -126,7 +134,7 @@ const INTEGRATION_MANIFESTS: IntegrationManifest[] = [
|
|
|
126
134
|
type: 'native-skill',
|
|
127
135
|
installTarget: '.trae/skills/inspecto-onboarding/',
|
|
128
136
|
preferredInstall:
|
|
129
|
-
'npx @inspecto-dev/cli integrations install trae --host-ide <vscode|cursor|trae|trae-cn>',
|
|
137
|
+
'npx @inspecto-dev/cli integrations install trae --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn>',
|
|
130
138
|
cliSupported: true,
|
|
131
139
|
},
|
|
132
140
|
{
|
|
@@ -134,7 +142,15 @@ const INTEGRATION_MANIFESTS: IntegrationManifest[] = [
|
|
|
134
142
|
type: 'native-skill',
|
|
135
143
|
installTarget: '.trae/skills/inspecto-onboarding/',
|
|
136
144
|
preferredInstall:
|
|
137
|
-
'npx @inspecto-dev/cli integrations install coco --host-ide <vscode|cursor|trae|trae-cn>',
|
|
145
|
+
'npx @inspecto-dev/cli integrations install coco --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn>',
|
|
146
|
+
cliSupported: true,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
assistant: 'codebuddy',
|
|
150
|
+
type: 'native-skill',
|
|
151
|
+
installTarget: '.codebuddy/skills/inspecto-onboarding/',
|
|
152
|
+
preferredInstall:
|
|
153
|
+
'npx @inspecto-dev/cli integrations install codebuddy --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn>',
|
|
138
154
|
cliSupported: true,
|
|
139
155
|
},
|
|
140
156
|
]
|
|
@@ -235,7 +251,7 @@ export async function installIntegration(
|
|
|
235
251
|
const message = `Installed ${getAssistantLabel(assistant)} integration assets. User-level installs only write integration assets and do not launch onboarding automatically.`
|
|
236
252
|
const nextStep = options.ide
|
|
237
253
|
? `Run the install command again from your target project root with --host-ide ${options.ide} when you want to launch onboarding automatically.`
|
|
238
|
-
: 'Run the install command again from your target project root with --host-ide <vscode|cursor|trae|trae-cn> when you want to launch onboarding automatically.'
|
|
254
|
+
: 'Run the install command again from your target project root with --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn> when you want to launch onboarding automatically.'
|
|
239
255
|
const result: IntegrationInstallResult = {
|
|
240
256
|
status: 'partial',
|
|
241
257
|
assistant,
|
|
@@ -486,6 +502,26 @@ function resolveInstallPlan(assistant: string, options: InstallIntegrationOption
|
|
|
486
502
|
successMessage: 'Installed Coco skill to .trae/skills/inspecto-onboarding/SKILL.md',
|
|
487
503
|
nextStep: 'Start a new Coco session.',
|
|
488
504
|
}
|
|
505
|
+
case 'codebuddy':
|
|
506
|
+
return {
|
|
507
|
+
assets: [
|
|
508
|
+
{
|
|
509
|
+
source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-codebuddy/SKILL.md`,
|
|
510
|
+
target: '.codebuddy/skills/inspecto-onboarding/SKILL.md',
|
|
511
|
+
localSource: 'skills/inspecto-onboarding-codebuddy/SKILL.md',
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-codebuddy/scripts/run-inspecto.sh`,
|
|
515
|
+
target: '.codebuddy/skills/inspecto-onboarding/scripts/run-inspecto.sh',
|
|
516
|
+
localSource: 'skills/inspecto-onboarding-codebuddy/scripts/run-inspecto.sh',
|
|
517
|
+
executable: true,
|
|
518
|
+
},
|
|
519
|
+
],
|
|
520
|
+
successMessage:
|
|
521
|
+
'Installed CodeBuddy skill to .codebuddy/skills/inspecto-onboarding/SKILL.md',
|
|
522
|
+
nextStep:
|
|
523
|
+
'Open a new CodeBuddy chat and verify the inspecto-onboarding skill is available.',
|
|
524
|
+
}
|
|
489
525
|
default:
|
|
490
526
|
throw new Error(`Unknown assistant: ${assistant}`)
|
|
491
527
|
}
|
|
@@ -515,6 +551,7 @@ function getAssistantLabel(assistant: string): string {
|
|
|
515
551
|
if (assistant === 'gemini') return 'Gemini'
|
|
516
552
|
if (assistant === 'trae') return 'Trae'
|
|
517
553
|
if (assistant === 'coco') return 'Coco'
|
|
554
|
+
if (assistant === 'codebuddy') return 'CodeBuddy'
|
|
518
555
|
return assistant
|
|
519
556
|
}
|
|
520
557
|
|
|
@@ -523,6 +560,8 @@ function formatHostIdeLabel(ide: string): string {
|
|
|
523
560
|
if (ide === 'cursor') return 'Cursor'
|
|
524
561
|
if (ide === 'trae') return 'Trae'
|
|
525
562
|
if (ide === 'trae-cn') return 'Trae CN'
|
|
563
|
+
if (ide === 'codebuddy') return 'CodeBuddy'
|
|
564
|
+
if (ide === 'codebuddy-cn') return 'CodeBuddy CN'
|
|
526
565
|
return ide
|
|
527
566
|
}
|
|
528
567
|
|
package/src/detect/framework.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// ============================================================
|
|
2
2
|
// src/detect/framework.ts — Frontend framework detection
|
|
3
3
|
//
|
|
4
|
-
// v1 supported: React / Vue
|
|
5
|
-
// Recognized but unsupported:
|
|
4
|
+
// v1 supported: React / Vue / Svelte / Solid / Astro
|
|
5
|
+
// Recognized but unsupported: Angular, Preact, Lit
|
|
6
6
|
// ============================================================
|
|
7
7
|
import path from 'node:path'
|
|
8
8
|
import { createRequire } from 'node:module'
|
|
9
9
|
import { readJSON } from '../utils/fs.js'
|
|
10
10
|
|
|
11
|
-
export type Framework = 'react' | 'vue'
|
|
11
|
+
export type Framework = 'react' | 'vue' | 'svelte' | 'solid' | 'astro'
|
|
12
12
|
|
|
13
13
|
export interface FrameworkDetection {
|
|
14
14
|
supported: Framework[]
|
|
@@ -25,11 +25,14 @@ interface PackageJSON {
|
|
|
25
25
|
const META_FRAMEWORK_MAP: Record<string, Framework> = {
|
|
26
26
|
next: 'react',
|
|
27
27
|
nuxt: 'vue',
|
|
28
|
+
'@sveltejs/kit': 'svelte',
|
|
28
29
|
'@remix-run/react': 'react',
|
|
29
30
|
'@remix-run/dev': 'react',
|
|
30
31
|
'@vue/nuxt': 'vue',
|
|
31
32
|
'vite-plugin-vue': 'vue',
|
|
32
33
|
'@vitejs/plugin-vue': 'vue',
|
|
34
|
+
'@sveltejs/vite-plugin-svelte': 'svelte',
|
|
35
|
+
'vite-plugin-solid': 'solid',
|
|
33
36
|
'@vitejs/plugin-react': 'react',
|
|
34
37
|
'@vitejs/plugin-react-swc': 'react',
|
|
35
38
|
}
|
|
@@ -38,13 +41,13 @@ const META_FRAMEWORK_MAP: Record<string, Framework> = {
|
|
|
38
41
|
const SUPPORTED_FRAMEWORKS: { framework: Framework; deps: string[] }[] = [
|
|
39
42
|
{ framework: 'react', deps: ['react', 'react-dom'] },
|
|
40
43
|
{ framework: 'vue', deps: ['vue'] },
|
|
44
|
+
{ framework: 'svelte', deps: ['svelte'] },
|
|
45
|
+
{ framework: 'solid', deps: ['solid-js'] },
|
|
46
|
+
{ framework: 'astro', deps: ['astro'] },
|
|
41
47
|
]
|
|
42
48
|
|
|
43
49
|
/** Recognized but not supported in v1 — detect and warn */
|
|
44
50
|
const UNSUPPORTED_FRAMEWORKS: { name: string; dep: string }[] = [
|
|
45
|
-
{ name: 'Solid', dep: 'solid-js' },
|
|
46
|
-
{ name: 'Svelte', dep: 'svelte' },
|
|
47
|
-
{ name: 'SvelteKit', dep: '@sveltejs/kit' },
|
|
48
51
|
{ name: 'Angular', dep: '@angular/core' },
|
|
49
52
|
{ name: 'Preact', dep: 'preact' },
|
|
50
53
|
{ name: 'Lit', dep: 'lit' },
|
package/src/detect/ide.ts
CHANGED
|
@@ -31,8 +31,14 @@ export async function detectIDE(root: string): Promise<IDEProbeResult> {
|
|
|
31
31
|
detected.set('Cursor', { ide: 'cursor', supported: true })
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// Trae
|
|
34
|
+
// Trae CN
|
|
35
35
|
if (
|
|
36
|
+
process.env.__CFBundleIdentifier === 'com.byteocean.trae.cn' ||
|
|
37
|
+
process.env.COCO_IDE_PLUGIN_TYPE === 'TraeCN' ||
|
|
38
|
+
(process.env.npm_config_user_agent && process.env.npm_config_user_agent.includes('trae-cn'))
|
|
39
|
+
) {
|
|
40
|
+
detected.set('Trae CN', { ide: 'trae-cn', supported: true })
|
|
41
|
+
} else if (
|
|
36
42
|
process.env.TRAE_APP_DIR ||
|
|
37
43
|
process.env.__CFBundleIdentifier === 'com.byteocean.trae' ||
|
|
38
44
|
process.env.COCO_IDE_PLUGIN_TYPE === 'Trae' ||
|
|
@@ -41,6 +47,22 @@ export async function detectIDE(root: string): Promise<IDEProbeResult> {
|
|
|
41
47
|
detected.set('Trae', { ide: 'trae', supported: true })
|
|
42
48
|
}
|
|
43
49
|
|
|
50
|
+
// CodeBuddy CN
|
|
51
|
+
if (
|
|
52
|
+
process.env.__CFBundleIdentifier === 'ai.codebuddy.mac.cn' ||
|
|
53
|
+
process.env.COCO_IDE_PLUGIN_TYPE === 'CodeBuddyCN' ||
|
|
54
|
+
(process.env.npm_config_user_agent &&
|
|
55
|
+
process.env.npm_config_user_agent.includes('codebuddy-cn'))
|
|
56
|
+
) {
|
|
57
|
+
detected.set('CodeBuddy CN', { ide: 'codebuddy-cn', supported: true })
|
|
58
|
+
} else if (
|
|
59
|
+
process.env.__CFBundleIdentifier === 'ai.codebuddy.mac' ||
|
|
60
|
+
process.env.COCO_IDE_PLUGIN_TYPE === 'CodeBuddy' ||
|
|
61
|
+
(process.env.npm_config_user_agent && process.env.npm_config_user_agent.includes('codebuddy'))
|
|
62
|
+
) {
|
|
63
|
+
detected.set('CodeBuddy', { ide: 'codebuddy', supported: true })
|
|
64
|
+
}
|
|
65
|
+
|
|
44
66
|
// Zed
|
|
45
67
|
if (process.env.ZED_TERM) {
|
|
46
68
|
detected.set('Zed', { ide: 'Zed', supported: false })
|
|
@@ -62,18 +84,31 @@ export async function detectIDE(root: string): Promise<IDEProbeResult> {
|
|
|
62
84
|
// if (process.env.TERM_PROGRAM === 'vscode') { ... }
|
|
63
85
|
|
|
64
86
|
// 2. Check Directory Artifacts (Indicates project has been opened in these IDEs)
|
|
65
|
-
const [hasTrae, hasCursor, hasVscode, hasIdea] =
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
87
|
+
const [hasTrae, hasTraeCn, hasCursor, hasVscode, hasIdea, hasCodeBuddy, hasCodeBuddyCn] =
|
|
88
|
+
await Promise.all([
|
|
89
|
+
exists(path.join(root, '.trae')),
|
|
90
|
+
exists(path.join(root, '.trae-cn')),
|
|
91
|
+
exists(path.join(root, '.cursor')),
|
|
92
|
+
exists(path.join(root, '.vscode')),
|
|
93
|
+
exists(path.join(root, '.idea')),
|
|
94
|
+
exists(path.join(root, '.codebuddy')),
|
|
95
|
+
exists(path.join(root, '.codebuddy-cn')),
|
|
96
|
+
])
|
|
71
97
|
|
|
72
98
|
// If a directory artifact exists, add it to the detection list.
|
|
73
99
|
// This allows us to surface multiple options (e.g. if you are in Cursor but also have a .vscode folder).
|
|
74
100
|
if (hasTrae && !detected.has('Trae')) {
|
|
75
101
|
detected.set('Trae', { ide: 'trae', supported: true })
|
|
76
102
|
}
|
|
103
|
+
if (hasTraeCn && !detected.has('Trae CN')) {
|
|
104
|
+
detected.set('Trae CN', { ide: 'trae-cn', supported: true })
|
|
105
|
+
}
|
|
106
|
+
if (hasCodeBuddy && !detected.has('CodeBuddy')) {
|
|
107
|
+
detected.set('CodeBuddy', { ide: 'codebuddy', supported: true })
|
|
108
|
+
}
|
|
109
|
+
if (hasCodeBuddyCn && !detected.has('CodeBuddy CN')) {
|
|
110
|
+
detected.set('CodeBuddy CN', { ide: 'codebuddy-cn', supported: true })
|
|
111
|
+
}
|
|
77
112
|
if (hasCursor && !detected.has('Cursor')) {
|
|
78
113
|
detected.set('Cursor', { ide: 'cursor', supported: true })
|
|
79
114
|
}
|
package/src/detect/provider.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import path from 'node:path'
|
|
7
7
|
import { exists, readJSON } from '../utils/fs.js'
|
|
8
8
|
import { which } from '../utils/exec.js'
|
|
9
|
-
import type { Provider
|
|
9
|
+
import type { Provider } from '@inspecto-dev/types'
|
|
10
10
|
|
|
11
11
|
export interface ProviderDetection {
|
|
12
12
|
id: Provider
|
package/src/inject/extension.ts
CHANGED
|
@@ -256,6 +256,36 @@ export async function installExtension(
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
+
if (ide === 'codebuddy' && process.platform === 'darwin') {
|
|
260
|
+
const codebuddyPath = await findIdeBinary('codebuddy')
|
|
261
|
+
if (codebuddyPath) {
|
|
262
|
+
const result = await installAlternativeIdeExtension(
|
|
263
|
+
codebuddyPath,
|
|
264
|
+
getHostIdeLabel('codebuddy'),
|
|
265
|
+
extensionRef,
|
|
266
|
+
quiet,
|
|
267
|
+
)
|
|
268
|
+
if (result) {
|
|
269
|
+
return result
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (ide === 'codebuddy-cn' && process.platform === 'darwin') {
|
|
275
|
+
const codebuddyCnPath = await findIdeBinary('codebuddy-cn')
|
|
276
|
+
if (codebuddyCnPath) {
|
|
277
|
+
const result = await installAlternativeIdeExtension(
|
|
278
|
+
codebuddyCnPath,
|
|
279
|
+
getHostIdeLabel('codebuddy-cn'),
|
|
280
|
+
extensionRef,
|
|
281
|
+
quiet,
|
|
282
|
+
)
|
|
283
|
+
if (result) {
|
|
284
|
+
return result
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
259
289
|
// Other IDEs: Prompt to install via VSIX
|
|
260
290
|
if (!quiet) {
|
|
261
291
|
log.warn(`Could not auto-install extension for ${ide}`)
|
|
@@ -8,11 +8,11 @@ export class EsbuildStrategy implements InjectStrategy {
|
|
|
8
8
|
return tool === 'esbuild'
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
inject(
|
|
11
|
+
inject(_options: InjectOptions): void {
|
|
12
12
|
throw new Error('Esbuild requires manual plugin configuration')
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
getManualInstructions(detection: BuildToolDetection,
|
|
15
|
+
getManualInstructions(detection: BuildToolDetection, _reason: string): string[] {
|
|
16
16
|
return [
|
|
17
17
|
`1. Update your esbuild config (${detection.configPath}):`,
|
|
18
18
|
`import { esbuildPlugin as inspecto } from '@inspecto-dev/plugin'`,
|
|
@@ -8,11 +8,11 @@ export class RollupStrategy implements InjectStrategy {
|
|
|
8
8
|
return tool === 'rollup'
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
inject(
|
|
11
|
+
inject(_options: InjectOptions): void {
|
|
12
12
|
throw new Error('Rollup requires manual plugin configuration')
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
getManualInstructions(detection: BuildToolDetection,
|
|
15
|
+
getManualInstructions(detection: BuildToolDetection, _reason: string): string[] {
|
|
16
16
|
return [
|
|
17
17
|
`1. Update your rollup config (${detection.configPath}):`,
|
|
18
18
|
`import { rollupPlugin as inspecto } from '@inspecto-dev/plugin'`,
|
|
@@ -8,11 +8,11 @@ export class RsbuildStrategy implements InjectStrategy {
|
|
|
8
8
|
return tool === 'rsbuild'
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
inject(
|
|
11
|
+
inject(_options: InjectOptions): void {
|
|
12
12
|
throw new Error('Rsbuild requires manual plugin configuration due to nested structure')
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
getManualInstructions(
|
|
15
|
+
getManualInstructions(_detection: BuildToolDetection, _reason: string): string[] {
|
|
16
16
|
return [
|
|
17
17
|
`import { rspackPlugin as inspecto } from '@inspecto-dev/plugin'`,
|
|
18
18
|
'',
|
|
@@ -8,11 +8,11 @@ export class RspackStrategy implements InjectStrategy {
|
|
|
8
8
|
return tool === 'rspack'
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
inject(
|
|
11
|
+
inject(_options: InjectOptions): void {
|
|
12
12
|
throw new Error('Rspack requires manual plugin configuration')
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
getManualInstructions(detection: BuildToolDetection,
|
|
15
|
+
getManualInstructions(detection: BuildToolDetection, _reason: string): string[] {
|
|
16
16
|
const importPkg = detection.isLegacyRspack
|
|
17
17
|
? '@inspecto-dev/plugin/legacy/rspack'
|
|
18
18
|
: '@inspecto-dev/plugin'
|
|
@@ -9,7 +9,7 @@ export class ViteStrategy implements InjectStrategy {
|
|
|
9
9
|
return tool === 'vite'
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
inject({ mod, detection }: InjectOptions): void {
|
|
12
|
+
inject({ mod, detection: _detection }: InjectOptions): void {
|
|
13
13
|
addVitePlugin(mod, {
|
|
14
14
|
from: '@inspecto-dev/plugin',
|
|
15
15
|
constructor: 'inspecto',
|
|
@@ -17,7 +17,7 @@ export class ViteStrategy implements InjectStrategy {
|
|
|
17
17
|
})
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
getManualInstructions(
|
|
20
|
+
getManualInstructions(_detection: BuildToolDetection, _reason: string): string[] {
|
|
21
21
|
return [
|
|
22
22
|
`import { vitePlugin as inspecto } from '@inspecto-dev/plugin'`,
|
|
23
23
|
'',
|
|
@@ -8,12 +8,12 @@ export class WebpackStrategy implements InjectStrategy {
|
|
|
8
8
|
return tool === 'webpack'
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
inject(
|
|
11
|
+
inject(_options: InjectOptions): void {
|
|
12
12
|
// AST manipulation for Webpack configs (often CommonJS or complex objects) is brittle in v1
|
|
13
13
|
throw new Error('Webpack requires manual plugin configuration')
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
getManualInstructions(detection: BuildToolDetection,
|
|
16
|
+
getManualInstructions(detection: BuildToolDetection, _reason: string): string[] {
|
|
17
17
|
const importPkg = detection.isLegacyWebpack
|
|
18
18
|
? '@inspecto-dev/plugin/legacy/webpack4'
|
|
19
19
|
: '@inspecto-dev/plugin'
|
|
@@ -94,6 +94,44 @@ export const HOST_IDE_CAPABILITIES: Record<SupportedHostIde, HostIdeCapability>
|
|
|
94
94
|
],
|
|
95
95
|
},
|
|
96
96
|
},
|
|
97
|
+
codebuddy: {
|
|
98
|
+
label: 'CodeBuddy',
|
|
99
|
+
artifactDir: '.codebuddy',
|
|
100
|
+
extensionDir: '.codebuddy/extensions',
|
|
101
|
+
binaryName: 'codebuddy',
|
|
102
|
+
binaryPaths: {
|
|
103
|
+
darwin: [
|
|
104
|
+
'/Applications/CodeBuddy.app/Contents/Resources/app/bin/codebuddy',
|
|
105
|
+
'/Applications/CodeBuddy.app/Contents/Resources/app/bin/code',
|
|
106
|
+
`${process.env.HOME}/Applications/CodeBuddy.app/Contents/Resources/app/bin/codebuddy`,
|
|
107
|
+
`${process.env.HOME}/Applications/CodeBuddy.app/Contents/Resources/app/bin/code`,
|
|
108
|
+
],
|
|
109
|
+
linux: ['/usr/bin/codebuddy', '/opt/CodeBuddy/resources/app/bin/codebuddy'],
|
|
110
|
+
win32: [
|
|
111
|
+
`${process.env.LOCALAPPDATA}\\Programs\\CodeBuddy\\resources\\app\\bin\\codebuddy.cmd`,
|
|
112
|
+
`${process.env.PROGRAMFILES}\\CodeBuddy\\resources\\app\\bin\\codebuddy.cmd`,
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
'codebuddy-cn': {
|
|
117
|
+
label: 'CodeBuddy CN',
|
|
118
|
+
artifactDir: '.codebuddy-cn',
|
|
119
|
+
extensionDir: '.codebuddy-cn/extensions',
|
|
120
|
+
binaryName: 'codebuddy-cn',
|
|
121
|
+
binaryPaths: {
|
|
122
|
+
darwin: [
|
|
123
|
+
'/Applications/CodeBuddy CN.app/Contents/Resources/app/bin/codebuddy-cn',
|
|
124
|
+
'/Applications/CodeBuddy CN.app/Contents/Resources/app/bin/code',
|
|
125
|
+
`${process.env.HOME}/Applications/CodeBuddy CN.app/Contents/Resources/app/bin/codebuddy-cn`,
|
|
126
|
+
`${process.env.HOME}/Applications/CodeBuddy CN.app/Contents/Resources/app/bin/code`,
|
|
127
|
+
],
|
|
128
|
+
linux: ['/usr/bin/codebuddy-cn', '/opt/CodeBuddy CN/resources/app/bin/codebuddy-cn'],
|
|
129
|
+
win32: [
|
|
130
|
+
`${process.env.LOCALAPPDATA}\\Programs\\CodeBuddy CN\\resources\\app\\bin\\codebuddy-cn.cmd`,
|
|
131
|
+
`${process.env.PROGRAMFILES}\\CodeBuddy CN\\resources\\app\\bin\\codebuddy-cn.cmd`,
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
},
|
|
97
135
|
}
|
|
98
136
|
|
|
99
137
|
export { HOST_IDE_IDS, getHostIdeLabel, isSupportedHostIde }
|
package/tests/detect.test.ts
CHANGED
|
@@ -45,7 +45,7 @@ describe('buildOnboardingContext', () => {
|
|
|
45
45
|
})
|
|
46
46
|
vi.mocked(frameworkDetector.detectFrameworks).mockResolvedValue({
|
|
47
47
|
supported: ['react'],
|
|
48
|
-
unsupported: [{ name: '
|
|
48
|
+
unsupported: [{ name: 'Angular', dep: 'angular' }],
|
|
49
49
|
})
|
|
50
50
|
vi.mocked(ideDetector.detectIDE).mockResolvedValue({
|
|
51
51
|
detected: [{ ide: 'vscode', supported: true }],
|
|
@@ -79,7 +79,7 @@ describe('buildOnboardingContext', () => {
|
|
|
79
79
|
},
|
|
80
80
|
frameworks: {
|
|
81
81
|
supported: ['react'],
|
|
82
|
-
unsupported: ['
|
|
82
|
+
unsupported: ['Angular'],
|
|
83
83
|
},
|
|
84
84
|
ides: [{ ide: 'vscode', supported: true }],
|
|
85
85
|
providers: [{ id: 'codex', label: 'Codex CLI', supported: true, preferredMode: 'cli' }],
|
|
@@ -177,6 +177,36 @@ describe('installExtension', () => {
|
|
|
177
177
|
expect(logMock.success).toHaveBeenCalledWith('Trae CN extension already installed')
|
|
178
178
|
expect(logMock.warn).not.toHaveBeenCalledWith('Could not auto-install extension for trae-cn')
|
|
179
179
|
})
|
|
180
|
+
|
|
181
|
+
it('installs the CodeBuddy CN extension via the app bundle code launcher on macOS when available', async () => {
|
|
182
|
+
vi.spyOn(process, 'platform', 'get').mockReturnValue('darwin')
|
|
183
|
+
whichMock.mockResolvedValue(false)
|
|
184
|
+
existsMock.mockImplementation(async filePath => {
|
|
185
|
+
return filePath === '/Applications/CodeBuddy CN.app/Contents/Resources/app/bin/code'
|
|
186
|
+
})
|
|
187
|
+
runMock.mockImplementation(async (_command, args: string[]) => {
|
|
188
|
+
if (args[0] === '--list-extensions') {
|
|
189
|
+
return { stdout: '', stderr: '' }
|
|
190
|
+
}
|
|
191
|
+
if (args[0] === '--install-extension') {
|
|
192
|
+
return { stdout: '', stderr: '' }
|
|
193
|
+
}
|
|
194
|
+
throw new Error(`unexpected args: ${args.join(' ')}`)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
const { installExtension } = await import('../src/inject/extension.js')
|
|
198
|
+
|
|
199
|
+
await expect(installExtension(false, 'codebuddy-cn')).resolves.toMatchObject({
|
|
200
|
+
type: 'extension_installed',
|
|
201
|
+
id: 'inspecto.inspecto',
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
expect(runMock).toHaveBeenCalledWith(
|
|
205
|
+
'/Applications/CodeBuddy CN.app/Contents/Resources/app/bin/code',
|
|
206
|
+
['--install-extension', 'inspecto.inspecto', '--force'],
|
|
207
|
+
)
|
|
208
|
+
expect(logMock.success).toHaveBeenCalledWith('CodeBuddy CN extension installed via CLI')
|
|
209
|
+
})
|
|
180
210
|
})
|
|
181
211
|
|
|
182
212
|
describe('openIdeWorkspace', () => {
|
|
@@ -202,4 +232,22 @@ describe('openIdeWorkspace', () => {
|
|
|
202
232
|
['--new-window', '/repo/app'],
|
|
203
233
|
)
|
|
204
234
|
})
|
|
235
|
+
|
|
236
|
+
it('opens CodeBuddy in a new window via the app bundle code launcher when available', async () => {
|
|
237
|
+
vi.spyOn(process, 'platform', 'get').mockReturnValue('darwin')
|
|
238
|
+
whichMock.mockResolvedValue(false)
|
|
239
|
+
existsMock.mockImplementation(async filePath => {
|
|
240
|
+
return filePath === '/Applications/CodeBuddy.app/Contents/Resources/app/bin/code'
|
|
241
|
+
})
|
|
242
|
+
runMock.mockResolvedValue({ stdout: '', stderr: '' })
|
|
243
|
+
|
|
244
|
+
const { openIdeWorkspace } = await import('../src/inject/extension.js')
|
|
245
|
+
|
|
246
|
+
await expect(openIdeWorkspace('codebuddy', '/repo/app')).resolves.toBe(true)
|
|
247
|
+
|
|
248
|
+
expect(runMock).toHaveBeenCalledWith(
|
|
249
|
+
'/Applications/CodeBuddy.app/Contents/Resources/app/bin/code',
|
|
250
|
+
['--new-window', '/repo/app'],
|
|
251
|
+
)
|
|
252
|
+
})
|
|
205
253
|
})
|
package/tests/framework.test.ts
CHANGED
|
@@ -31,7 +31,7 @@ describe('detectFrameworks', () => {
|
|
|
31
31
|
expect(result.unsupported).toHaveLength(0)
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
-
it('detects Svelte as
|
|
34
|
+
it('detects Svelte as supported framework', async () => {
|
|
35
35
|
vi.mocked(fsUtils.readJSON).mockResolvedValue({
|
|
36
36
|
devDependencies: {
|
|
37
37
|
svelte: '^4.0.0',
|
|
@@ -39,8 +39,32 @@ describe('detectFrameworks', () => {
|
|
|
39
39
|
})
|
|
40
40
|
|
|
41
41
|
const result = await detectFrameworks('/mock/root')
|
|
42
|
-
expect(result.supported).
|
|
43
|
-
expect(result.unsupported).
|
|
42
|
+
expect(result.supported).toContain('svelte')
|
|
43
|
+
expect(result.unsupported).toHaveLength(0)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('detects Solid as supported framework', async () => {
|
|
47
|
+
vi.mocked(fsUtils.readJSON).mockResolvedValue({
|
|
48
|
+
devDependencies: {
|
|
49
|
+
'solid-js': '^1.0.0',
|
|
50
|
+
},
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const result = await detectFrameworks('/mock/root')
|
|
54
|
+
expect(result.supported).toContain('solid')
|
|
55
|
+
expect(result.unsupported).toHaveLength(0)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('detects Astro as supported framework', async () => {
|
|
59
|
+
vi.mocked(fsUtils.readJSON).mockResolvedValue({
|
|
60
|
+
devDependencies: {
|
|
61
|
+
astro: '^4.0.0',
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const result = await detectFrameworks('/mock/root')
|
|
66
|
+
expect(result.supported).toContain('astro')
|
|
67
|
+
expect(result.unsupported).toHaveLength(0)
|
|
44
68
|
})
|
|
45
69
|
|
|
46
70
|
it('returns empty if no framework is matched', async () => {
|
|
@@ -335,7 +335,7 @@ describe('runIntegrationAutomation', () => {
|
|
|
335
335
|
'Step 2/6: Could not confidently resolve the host IDE',
|
|
336
336
|
)
|
|
337
337
|
expect(logMock.hint).toHaveBeenCalledWith(
|
|
338
|
-
'Re-run with --host-ide <vscode|cursor|trae|trae-cn> or run the command from the target IDE terminal to continue automatic setup.',
|
|
338
|
+
'Re-run with --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn> or run the command from the target IDE terminal to continue automatic setup.',
|
|
339
339
|
)
|
|
340
340
|
})
|
|
341
341
|
|
|
@@ -57,6 +57,21 @@ describe('resolveIntegrationHostIde', () => {
|
|
|
57
57
|
})
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
+
it('accepts codebuddy as an explicit ide argument', async () => {
|
|
61
|
+
const { resolveIntegrationHostIde } = await import('../src/commands/integration-host-ide.js')
|
|
62
|
+
|
|
63
|
+
await expect(
|
|
64
|
+
resolveIntegrationHostIde({
|
|
65
|
+
explicitIde: 'codebuddy',
|
|
66
|
+
cwd: '/repo',
|
|
67
|
+
}),
|
|
68
|
+
).resolves.toMatchObject({
|
|
69
|
+
ide: 'codebuddy',
|
|
70
|
+
confidence: 'high',
|
|
71
|
+
source: 'explicit',
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
60
75
|
it('uses .inspecto settings ide when present', async () => {
|
|
61
76
|
vi.mocked(fsUtils.readJSON).mockImplementation(async filePath => {
|
|
62
77
|
if (filePath === '/repo/.inspecto/settings.local.json') {
|
|
@@ -99,6 +114,27 @@ describe('resolveIntegrationHostIde', () => {
|
|
|
99
114
|
})
|
|
100
115
|
})
|
|
101
116
|
|
|
117
|
+
it('uses codebuddy-cn from .inspecto settings when present', async () => {
|
|
118
|
+
vi.mocked(fsUtils.readJSON).mockImplementation(async filePath => {
|
|
119
|
+
if (filePath === '/repo/.inspecto/settings.local.json') {
|
|
120
|
+
return { ide: 'codebuddy-cn' }
|
|
121
|
+
}
|
|
122
|
+
return null
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
const { resolveIntegrationHostIde } = await import('../src/commands/integration-host-ide.js')
|
|
126
|
+
|
|
127
|
+
await expect(
|
|
128
|
+
resolveIntegrationHostIde({
|
|
129
|
+
cwd: '/repo',
|
|
130
|
+
}),
|
|
131
|
+
).resolves.toMatchObject({
|
|
132
|
+
ide: 'codebuddy-cn',
|
|
133
|
+
confidence: 'high',
|
|
134
|
+
source: 'config',
|
|
135
|
+
})
|
|
136
|
+
})
|
|
137
|
+
|
|
102
138
|
it('treats a single env-detected ide as high confidence', async () => {
|
|
103
139
|
process.env.CURSOR_CHANNEL = 'stable'
|
|
104
140
|
|
|
@@ -151,6 +187,24 @@ describe('resolveIntegrationHostIde', () => {
|
|
|
151
187
|
})
|
|
152
188
|
})
|
|
153
189
|
|
|
190
|
+
it('treats a .codebuddy-cn project artifact as medium confidence', async () => {
|
|
191
|
+
vi.mocked(fsUtils.exists).mockImplementation(async filePath => {
|
|
192
|
+
return filePath === '/repo/.codebuddy-cn'
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
const { resolveIntegrationHostIde } = await import('../src/commands/integration-host-ide.js')
|
|
196
|
+
|
|
197
|
+
await expect(
|
|
198
|
+
resolveIntegrationHostIde({
|
|
199
|
+
cwd: '/repo',
|
|
200
|
+
}),
|
|
201
|
+
).resolves.toMatchObject({
|
|
202
|
+
ide: 'codebuddy-cn',
|
|
203
|
+
confidence: 'medium',
|
|
204
|
+
source: 'artifact',
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
|
|
154
208
|
it('refuses to resolve an ide when project artifacts are ambiguous', async () => {
|
|
155
209
|
vi.mocked(fsUtils.exists).mockImplementation(async filePath => {
|
|
156
210
|
return filePath === '/repo/.cursor' || filePath === '/repo/.vscode'
|