@inspecto-dev/cli 0.3.7 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,386 @@
1
+ import fs from 'node:fs'
2
+ import os from 'node:os'
3
+ import path from 'node:path'
4
+ import crypto from 'node:crypto'
5
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
6
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
7
+ import { INSPECTO_API_PATHS } from '@inspecto-dev/types'
8
+ import { z } from 'zod'
9
+
10
+ const DEFAULT_MCP_SERVER_VERSION = '0.0.0'
11
+
12
+ export interface McpCommandOptions {
13
+ serverUrl?: string
14
+ version?: string
15
+ }
16
+
17
+ interface McpToolResult<T extends Record<string, unknown>> {
18
+ [key: string]: unknown
19
+ content: Array<{ type: 'text'; text: string }>
20
+ structuredContent: T
21
+ isError?: boolean
22
+ }
23
+
24
+ export interface InspectoMcpRuntime {
25
+ getSession(args: { sessionId: string }): Promise<Record<string, unknown>>
26
+ claimNext(args?: { timeoutMs?: number }): Promise<{
27
+ success: boolean
28
+ timedOut: boolean
29
+ matchedExisting: boolean
30
+ session?: Record<string, unknown>
31
+ event?: string
32
+ }>
33
+ reply(args: { sessionId: string; text: string }): Promise<Record<string, unknown>>
34
+ resolve(args: { sessionId: string; message?: string }): Promise<Record<string, unknown>>
35
+ dismiss(args: { sessionId: string; message?: string }): Promise<Record<string, unknown>>
36
+ }
37
+
38
+ export interface InspectoMcpToolDefinition {
39
+ name:
40
+ | 'inspecto_get_session'
41
+ | 'inspecto_claim_next'
42
+ | 'inspecto_reply'
43
+ | 'inspecto_resolve'
44
+ | 'inspecto_dismiss'
45
+ description: string
46
+ }
47
+
48
+ export const INSPECTO_MCP_TOOLS: InspectoMcpToolDefinition[] = [
49
+ {
50
+ name: 'inspecto_get_session',
51
+ description: 'Return one Inspecto annotation session by sessionId.',
52
+ },
53
+ {
54
+ name: 'inspecto_claim_next',
55
+ description:
56
+ 'Wait for the next unclaimed Inspecto annotation session, mark it acknowledged, and return full context.',
57
+ },
58
+ {
59
+ name: 'inspecto_reply',
60
+ description: 'Append an agent reply to an Inspecto annotation session.',
61
+ },
62
+ {
63
+ name: 'inspecto_resolve',
64
+ description: 'Resolve an Inspecto annotation session with an optional final message.',
65
+ },
66
+ {
67
+ name: 'inspecto_dismiss',
68
+ description: 'Dismiss an Inspecto annotation session with an optional final message.',
69
+ },
70
+ ]
71
+
72
+ export async function startMcpServer(options: McpCommandOptions = {}): Promise<void> {
73
+ const baseUrl = options.serverUrl ?? resolveInspectoServerBaseUrl(process.cwd())
74
+ if (!baseUrl) {
75
+ throw new Error(
76
+ 'Could not find a running Inspecto dev server. Start your local dev server or pass --server-url <url>.',
77
+ )
78
+ }
79
+
80
+ const server = createInspectoMcpServer({
81
+ baseUrl,
82
+ ...(options.version ? { version: options.version } : {}),
83
+ })
84
+ const transport = new StdioServerTransport()
85
+ await server.connect(transport)
86
+ }
87
+
88
+ export function createInspectoMcpServer(options: { baseUrl: string; version?: string }): McpServer {
89
+ const runtime = createInspectoMcpRuntime(options.baseUrl)
90
+ const server = new McpServer({
91
+ name: 'inspecto-mcp',
92
+ version: options.version ?? DEFAULT_MCP_SERVER_VERSION,
93
+ })
94
+
95
+ server.registerTool(
96
+ 'inspecto_get_session',
97
+ {
98
+ description: getToolDescription('inspecto_get_session'),
99
+ inputSchema: {
100
+ sessionId: z.string().min(1),
101
+ },
102
+ },
103
+ async ({ sessionId }) => {
104
+ try {
105
+ const result = await runtime.getSession({ sessionId })
106
+ return toolSuccess(result)
107
+ } catch (error) {
108
+ return toolError(error)
109
+ }
110
+ },
111
+ )
112
+
113
+ server.registerTool(
114
+ 'inspecto_claim_next',
115
+ {
116
+ description: getToolDescription('inspecto_claim_next'),
117
+ inputSchema: {
118
+ timeoutMs: z.number().int().nonnegative().optional(),
119
+ },
120
+ },
121
+ async ({ timeoutMs }) => {
122
+ try {
123
+ const result = await runtime.claimNext({
124
+ ...(timeoutMs !== undefined ? { timeoutMs } : {}),
125
+ })
126
+ return toolSuccess(result)
127
+ } catch (error) {
128
+ return toolError(error)
129
+ }
130
+ },
131
+ )
132
+
133
+ server.registerTool(
134
+ 'inspecto_reply',
135
+ {
136
+ description: getToolDescription('inspecto_reply'),
137
+ inputSchema: {
138
+ sessionId: z.string().min(1),
139
+ text: z.string().min(1),
140
+ },
141
+ },
142
+ async ({ sessionId, text }) => {
143
+ try {
144
+ const result = await runtime.reply({ sessionId, text })
145
+ return toolSuccess(result)
146
+ } catch (error) {
147
+ return toolError(error)
148
+ }
149
+ },
150
+ )
151
+
152
+ server.registerTool(
153
+ 'inspecto_resolve',
154
+ {
155
+ description: getToolDescription('inspecto_resolve'),
156
+ inputSchema: {
157
+ sessionId: z.string().min(1),
158
+ message: z.string().optional(),
159
+ },
160
+ },
161
+ async ({ sessionId, message }) => {
162
+ try {
163
+ const result = await runtime.resolve({ sessionId, ...(message ? { message } : {}) })
164
+ return toolSuccess(result)
165
+ } catch (error) {
166
+ return toolError(error)
167
+ }
168
+ },
169
+ )
170
+
171
+ server.registerTool(
172
+ 'inspecto_dismiss',
173
+ {
174
+ description: getToolDescription('inspecto_dismiss'),
175
+ inputSchema: {
176
+ sessionId: z.string().min(1),
177
+ message: z.string().optional(),
178
+ },
179
+ },
180
+ async ({ sessionId, message }) => {
181
+ try {
182
+ const result = await runtime.dismiss({ sessionId, ...(message ? { message } : {}) })
183
+ return toolSuccess(result)
184
+ } catch (error) {
185
+ return toolError(error)
186
+ }
187
+ },
188
+ )
189
+
190
+ return server
191
+ }
192
+
193
+ export function getToolDescription(name: InspectoMcpToolDefinition['name']): string {
194
+ return INSPECTO_MCP_TOOLS.find(tool => tool.name === name)?.description ?? name
195
+ }
196
+
197
+ export function createInspectoMcpRuntime(baseUrl: string): InspectoMcpRuntime {
198
+ return {
199
+ async getSession(args) {
200
+ return getSession(baseUrl, args.sessionId)
201
+ },
202
+
203
+ async claimNext(args = {}) {
204
+ return (await postJson(`${baseUrl}${INSPECTO_API_PATHS.SESSION_CLAIM_NEXT}`, {
205
+ ...(args.timeoutMs !== undefined ? { timeoutMs: args.timeoutMs } : {}),
206
+ })) as {
207
+ success: boolean
208
+ timedOut: boolean
209
+ matchedExisting: boolean
210
+ session?: Record<string, unknown>
211
+ event?: string
212
+ }
213
+ },
214
+
215
+ async reply(args) {
216
+ return postJson(
217
+ `${baseUrl}${INSPECTO_API_PATHS.SESSIONS}/${args.sessionId}${INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX}`,
218
+ {
219
+ role: 'agent',
220
+ text: args.text.trim(),
221
+ },
222
+ ) as Promise<Record<string, unknown>>
223
+ },
224
+
225
+ async resolve(args) {
226
+ return postJson(
227
+ `${baseUrl}${INSPECTO_API_PATHS.SESSIONS}/${args.sessionId}${INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX}`,
228
+ args.message?.trim() ? { message: args.message.trim() } : {},
229
+ ) as Promise<Record<string, unknown>>
230
+ },
231
+
232
+ async dismiss(args) {
233
+ return postJson(
234
+ `${baseUrl}${INSPECTO_API_PATHS.SESSIONS}/${args.sessionId}${INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX}`,
235
+ args.message?.trim() ? { message: args.message.trim() } : {},
236
+ ) as Promise<Record<string, unknown>>
237
+ },
238
+ }
239
+ }
240
+
241
+ export function resolveInspectoServerBaseUrl(cwd: string): string | null {
242
+ const ports = resolveServerPorts(cwd)
243
+ const port = ports[0]
244
+ return port ? `http://0.0.0.0:${port}` : null
245
+ }
246
+
247
+ export function resolveServerPorts(cwd: string): number[] {
248
+ const prioritized = readProjectScopedPorts(cwd)
249
+ if (prioritized.length > 0) return prioritized
250
+
251
+ const legacyPortFile = path.join(os.tmpdir(), 'inspecto.port')
252
+ try {
253
+ const raw = fs.readFileSync(legacyPortFile, 'utf-8').trim()
254
+ const port = parseInt(raw, 10)
255
+ if (Number.isInteger(port) && port > 0 && port < 65536) {
256
+ return [port]
257
+ }
258
+ } catch {
259
+ // ignore
260
+ }
261
+
262
+ return Array.from({ length: 23 }, (_, index) => 5678 + index)
263
+ }
264
+
265
+ function toolSuccess<T extends Record<string, unknown>>(value: T): McpToolResult<T> {
266
+ return {
267
+ content: [
268
+ {
269
+ type: 'text',
270
+ text: JSON.stringify(value, null, 2),
271
+ },
272
+ ],
273
+ structuredContent: value,
274
+ }
275
+ }
276
+
277
+ function toolError(error: unknown): McpToolResult<{ success: false; error: string }> {
278
+ const message = error instanceof Error ? error.message : String(error)
279
+ return {
280
+ content: [
281
+ {
282
+ type: 'text',
283
+ text: message,
284
+ },
285
+ ],
286
+ structuredContent: {
287
+ success: false,
288
+ error: message,
289
+ },
290
+ isError: true,
291
+ }
292
+ }
293
+
294
+ async function getJson(url: string): Promise<unknown> {
295
+ const response = await fetch(url)
296
+ const payload = (await response.json().catch(() => ({}))) as Record<string, unknown>
297
+ if (!response.ok) {
298
+ throw new Error(String(payload['error'] ?? `Request failed with status ${response.status}.`))
299
+ }
300
+ return payload
301
+ }
302
+
303
+ async function getSession(baseUrl: string, sessionId: string): Promise<Record<string, unknown>> {
304
+ const trimmed = sessionId.trim()
305
+ if (!trimmed) {
306
+ throw new Error('Session id is required.')
307
+ }
308
+
309
+ const payload = (await getJson(
310
+ `${baseUrl}${INSPECTO_API_PATHS.SESSIONS}/${encodeURIComponent(trimmed)}`,
311
+ )) as {
312
+ success?: boolean
313
+ session?: Record<string, unknown>
314
+ error?: string
315
+ }
316
+
317
+ if (!payload.success || !payload.session) {
318
+ throw new Error(payload.error ?? 'Session not found.')
319
+ }
320
+
321
+ return {
322
+ success: true,
323
+ session: payload.session,
324
+ }
325
+ }
326
+
327
+ async function postJson(url: string, body: Record<string, unknown>): Promise<unknown> {
328
+ const response = await fetch(url, {
329
+ method: 'POST',
330
+ headers: { 'Content-Type': 'application/json' },
331
+ body: JSON.stringify(body),
332
+ })
333
+ const payload = (await response.json().catch(() => ({}))) as Record<string, unknown>
334
+ if (!response.ok || payload['success'] === false) {
335
+ throw new Error(String(payload['error'] ?? `Request failed with status ${response.status}.`))
336
+ }
337
+ return payload
338
+ }
339
+
340
+ function readProjectScopedPorts(cwd: string): number[] {
341
+ const portFile = path.join(os.tmpdir(), 'inspecto.port.json')
342
+ try {
343
+ const raw = fs.readFileSync(portFile, 'utf-8').trim()
344
+ const portData = JSON.parse(raw) as Record<string, number>
345
+ const currentRootHashes = resolveCandidateRootHashes(cwd)
346
+
347
+ const prioritized: number[] = []
348
+ const seen = new Set<number>()
349
+
350
+ for (const rootHash of currentRootHashes) {
351
+ const currentPort = portData[rootHash]
352
+ if (currentPort && !seen.has(currentPort)) {
353
+ prioritized.push(currentPort)
354
+ seen.add(currentPort)
355
+ }
356
+ }
357
+
358
+ for (const port of Object.values(portData)) {
359
+ if (!seen.has(port)) {
360
+ prioritized.push(port)
361
+ seen.add(port)
362
+ }
363
+ }
364
+
365
+ return prioritized
366
+ } catch {
367
+ return []
368
+ }
369
+ }
370
+
371
+ function resolveCandidateRootHashes(cwd: string): string[] {
372
+ const normalized = path.resolve(cwd)
373
+ const candidates = new Set<string>()
374
+ let currentDir = normalized
375
+
376
+ while (true) {
377
+ candidates.add(crypto.createHash('md5').update(currentDir).digest('hex'))
378
+ const parentDir = path.dirname(currentDir)
379
+ if (parentDir === currentDir) {
380
+ break
381
+ }
382
+ currentDir = parentDir
383
+ }
384
+
385
+ return [...candidates]
386
+ }
@@ -57,6 +57,7 @@ function buildAssistantHandoff(
57
57
  ...(result.pendingSteps ? { pendingSteps: result.pendingSteps } : {}),
58
58
  ...(result.assistantPrompt ? { assistantPrompt: result.assistantPrompt } : {}),
59
59
  ...(result.patches ? { patches: result.patches } : {}),
60
+ ...(result.dailyUsage ? { dailyUsage: result.dailyUsage } : {}),
60
61
  }
61
62
  }
62
63
 
@@ -110,6 +111,9 @@ function printOnboardResult(result: OnboardCommandResult): void {
110
111
  if (normalized.handoff?.assistantPrompt) {
111
112
  log.hint(normalized.handoff.assistantPrompt)
112
113
  }
114
+ if (normalized.handoff?.dailyUsage?.prompt) {
115
+ log.hint(normalized.handoff.dailyUsage.prompt)
116
+ }
113
117
  if (normalized.confirmation.required && normalized.confirmation.question) {
114
118
  log.warn(normalized.confirmation.question)
115
119
  }
@@ -139,7 +143,7 @@ export async function onboard(options: OnboardCommandOptions = {}): Promise<Onbo
139
143
  session.status === 'needs_confirmation'
140
144
  ) {
141
145
  return writeCommandOutput(
142
- normalizeOnboardResult(buildDeferredOnboardResult(session)),
146
+ normalizeOnboardResult(await buildDeferredOnboardResult(session)),
143
147
  options.json ?? false,
144
148
  printOnboardResult,
145
149
  )
@@ -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: Solid, Svelte, Angular, Preact, Lit
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
@@ -51,7 +51,8 @@ export async function detectIDE(root: string): Promise<IDEProbeResult> {
51
51
  if (
52
52
  process.env.__CFBundleIdentifier === 'ai.codebuddy.mac.cn' ||
53
53
  process.env.COCO_IDE_PLUGIN_TYPE === 'CodeBuddyCN' ||
54
- (process.env.npm_config_user_agent && process.env.npm_config_user_agent.includes('codebuddy-cn'))
54
+ (process.env.npm_config_user_agent &&
55
+ process.env.npm_config_user_agent.includes('codebuddy-cn'))
55
56
  ) {
56
57
  detected.set('CodeBuddy CN', { ide: 'codebuddy-cn', supported: true })
57
58
  } else if (
@@ -83,15 +84,16 @@ export async function detectIDE(root: string): Promise<IDEProbeResult> {
83
84
  // if (process.env.TERM_PROGRAM === 'vscode') { ... }
84
85
 
85
86
  // 2. Check Directory Artifacts (Indicates project has been opened in these IDEs)
86
- const [hasTrae, hasTraeCn, hasCursor, hasVscode, hasIdea, hasCodeBuddy, hasCodeBuddyCn] = await Promise.all([
87
- exists(path.join(root, '.trae')),
88
- exists(path.join(root, '.trae-cn')),
89
- exists(path.join(root, '.cursor')),
90
- exists(path.join(root, '.vscode')),
91
- exists(path.join(root, '.idea')),
92
- exists(path.join(root, '.codebuddy')),
93
- exists(path.join(root, '.codebuddy-cn')),
94
- ])
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
+ ])
95
97
 
96
98
  // If a directory artifact exists, add it to the detection list.
97
99
  // This allows us to surface multiple options (e.g. if you are in Cursor but also have a .vscode folder).
@@ -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, ProviderMode } from '@inspecto-dev/types'
9
+ import type { Provider } from '@inspecto-dev/types'
10
10
 
11
11
  export interface ProviderDetection {
12
12
  id: Provider
package/src/index.ts CHANGED
@@ -4,6 +4,12 @@ export { devLink, devStatus, devUnlink } from './commands/dev-config.js'
4
4
  export { init } from './commands/init.js'
5
5
  export { collectDoctorResult, doctor } from './commands/doctor.js'
6
6
  export { integrationDoctor } from './commands/integration-doctor.js'
7
+ export {
8
+ startMcpServer,
9
+ createInspectoMcpRuntime,
10
+ createInspectoMcpServer,
11
+ resolveInspectoServerBaseUrl,
12
+ } from './commands/mcp.js'
7
13
  export { onboard } from './commands/onboard.js'
8
14
  export { plan } from './commands/plan.js'
9
15
  export { teardown } from './commands/teardown.js'
@@ -8,11 +8,11 @@ export class EsbuildStrategy implements InjectStrategy {
8
8
  return tool === 'esbuild'
9
9
  }
10
10
 
11
- inject(options: InjectOptions): void {
11
+ inject(_options: InjectOptions): void {
12
12
  throw new Error('Esbuild requires manual plugin configuration')
13
13
  }
14
14
 
15
- getManualInstructions(detection: BuildToolDetection, reason: string): string[] {
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(options: InjectOptions): void {
11
+ inject(_options: InjectOptions): void {
12
12
  throw new Error('Rollup requires manual plugin configuration')
13
13
  }
14
14
 
15
- getManualInstructions(detection: BuildToolDetection, reason: string): string[] {
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(options: InjectOptions): void {
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(detection: BuildToolDetection, reason: string): string[] {
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(options: InjectOptions): void {
11
+ inject(_options: InjectOptions): void {
12
12
  throw new Error('Rspack requires manual plugin configuration')
13
13
  }
14
14
 
15
- getManualInstructions(detection: BuildToolDetection, reason: string): string[] {
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(detection: BuildToolDetection, reason: string): string[] {
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(options: InjectOptions): void {
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, reason: string): string[] {
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'
@@ -83,7 +83,7 @@ export function printNextJsManualInstructions() {
83
83
  ' useEffect(() => {',
84
84
  " if (process.env.NODE_ENV !== 'production') {",
85
85
  " import('@inspecto-dev/core').then(({ mountInspector }) => {",
86
- " mountInspector({ serverUrl: 'http://127.0.0.1:5678' })",
86
+ " mountInspector({ serverUrl: 'http://0.0.0.0:5678' })",
87
87
  ' })',
88
88
  ' }',
89
89
  ' }, [])',