@inspecto-dev/cli 0.3.8 → 0.3.10
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 +206 -6777
- package/CHANGELOG.md +16 -0
- package/dist/bin.js +12 -1
- package/dist/{chunk-B5JDHSP7.js → chunk-WOZPOTWE.js} +425 -55
- package/dist/index.d.ts +50 -1
- package/dist/index.js +9 -1
- package/package.json +5 -3
- package/src/bin.ts +20 -0
- package/src/commands/init.ts +7 -3
- package/src/commands/integration-install.ts +27 -2
- package/src/commands/mcp.ts +386 -0
- package/src/commands/onboard.ts +5 -1
- package/src/index.ts +6 -0
- package/src/onboarding/session.ts +43 -3
- package/src/onboarding/umi-guidance.ts +1 -1
- package/src/prompts.ts +19 -9
- package/src/types.ts +10 -0
- package/tests/integration-install.test.ts +16 -0
- package/tests/mcp.test.ts +197 -0
- package/tests/onboard.test.ts +15 -0
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'
|
|
@@ -14,6 +14,7 @@ import { resolveOnboardingTarget } from './target-resolution.js'
|
|
|
14
14
|
import { readJSON } from '../utils/fs.js'
|
|
15
15
|
import type {
|
|
16
16
|
OnboardCommandResult,
|
|
17
|
+
OnboardingDailyUsageHandoff,
|
|
17
18
|
OnboardingContext,
|
|
18
19
|
OnboardingDiagnostics,
|
|
19
20
|
OnboardingExecutionResult,
|
|
@@ -256,9 +257,37 @@ function buildConfirmation(
|
|
|
256
257
|
}
|
|
257
258
|
}
|
|
258
259
|
|
|
260
|
+
async function buildDailyUsageHandoff(
|
|
261
|
+
projectRoot: string,
|
|
262
|
+
): Promise<OnboardingDailyUsageHandoff | undefined> {
|
|
263
|
+
const localSettings =
|
|
264
|
+
(await readJSON<Record<string, unknown>>(
|
|
265
|
+
path.join(projectRoot, '.inspecto', 'settings.local.json'),
|
|
266
|
+
)) ?? {}
|
|
267
|
+
const sharedSettings =
|
|
268
|
+
(await readJSON<Record<string, unknown>>(
|
|
269
|
+
path.join(projectRoot, '.inspecto', 'settings.json'),
|
|
270
|
+
)) ?? {}
|
|
271
|
+
const annotateDeliveryMode =
|
|
272
|
+
(localSettings['annotate.deliveryMode'] as string | undefined) ??
|
|
273
|
+
(sharedSettings['annotate.deliveryMode'] as string | undefined)
|
|
274
|
+
|
|
275
|
+
if (annotateDeliveryMode !== 'agent') {
|
|
276
|
+
return undefined
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return {
|
|
280
|
+
mode: 'agent',
|
|
281
|
+
skill: 'inspecto-agent',
|
|
282
|
+
prompt: 'Use $inspecto-agent to claim Inspecto tasks continuously',
|
|
283
|
+
requiresMcp: true,
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
259
287
|
function buildPreApplyResult(
|
|
260
288
|
status: ResolvedOnboardingSession['status'],
|
|
261
289
|
session: ResolvedOnboardingSession,
|
|
290
|
+
dailyUsage?: OnboardingDailyUsageHandoff,
|
|
262
291
|
): OnboardCommandResult {
|
|
263
292
|
const diagnostics: OnboardingDiagnostics | undefined =
|
|
264
293
|
session.summary.risks.length > 0 ||
|
|
@@ -292,6 +321,7 @@ function buildPreApplyResult(
|
|
|
292
321
|
...(session.pendingSteps ? { pendingSteps: session.pendingSteps } : {}),
|
|
293
322
|
...(session.assistantPrompt ? { assistantPrompt: session.assistantPrompt } : {}),
|
|
294
323
|
...(session.patches ? { patches: session.patches } : {}),
|
|
324
|
+
...(dailyUsage ? { dailyUsage } : {}),
|
|
295
325
|
...(diagnostics ? { diagnostics } : {}),
|
|
296
326
|
}
|
|
297
327
|
}
|
|
@@ -353,6 +383,7 @@ export async function resolveOnboardingSession(
|
|
|
353
383
|
): Promise<ResolvedOnboardingSession> {
|
|
354
384
|
const rootContext = await buildOnboardingContext(root)
|
|
355
385
|
const rootVerification = await buildVerification(root, rootContext.packageManager)
|
|
386
|
+
const rootDailyUsage = await buildDailyUsageHandoff(root)
|
|
356
387
|
const frameworkSupportByPackage = await detectFrameworkSupportByPackage(root, rootContext)
|
|
357
388
|
const target = resolveOnboardingTarget({
|
|
358
389
|
repoRoot: root,
|
|
@@ -392,6 +423,7 @@ export async function resolveOnboardingSession(
|
|
|
392
423
|
...(plan.pendingSteps ? { pendingSteps: plan.pendingSteps } : {}),
|
|
393
424
|
...(plan.assistantPrompt ? { assistantPrompt: plan.assistantPrompt } : {}),
|
|
394
425
|
...(plan.patches ? { patches: plan.patches } : {}),
|
|
426
|
+
...(rootDailyUsage ? { dailyUsage: rootDailyUsage } : {}),
|
|
395
427
|
}
|
|
396
428
|
}
|
|
397
429
|
|
|
@@ -418,6 +450,7 @@ export async function resolveOnboardingSession(
|
|
|
418
450
|
|
|
419
451
|
const context = await buildTargetedContext(rootContext, target.selected!)
|
|
420
452
|
const verification = await buildVerification(context.root, context.packageManager)
|
|
453
|
+
const dailyUsage = await buildDailyUsageHandoff(context.root)
|
|
421
454
|
const plan = createPlanResult(context)
|
|
422
455
|
const summary = buildOnboardingSummary(plan, context.root)
|
|
423
456
|
const confirmation = buildConfirmation(
|
|
@@ -469,6 +502,7 @@ export async function resolveOnboardingSession(
|
|
|
469
502
|
...(plan.pendingSteps ? { pendingSteps: plan.pendingSteps } : {}),
|
|
470
503
|
...(plan.assistantPrompt ? { assistantPrompt: plan.assistantPrompt } : {}),
|
|
471
504
|
...(plan.patches ? { patches: plan.patches } : {}),
|
|
505
|
+
...(dailyUsage ? { dailyUsage } : {}),
|
|
472
506
|
}
|
|
473
507
|
}
|
|
474
508
|
|
|
@@ -477,6 +511,7 @@ export async function applyResolvedOnboardingSession(
|
|
|
477
511
|
options: ResolveOnboardingSessionOptions = {},
|
|
478
512
|
): Promise<OnboardCommandResult> {
|
|
479
513
|
const verification = await buildVerification(session.projectRoot, session.context.packageManager)
|
|
514
|
+
const dailyUsage = await buildDailyUsageHandoff(session.projectRoot)
|
|
480
515
|
const applyResult = await applyOnboardingPlan({
|
|
481
516
|
repoRoot: process.cwd(),
|
|
482
517
|
projectRoot: session.projectRoot,
|
|
@@ -528,12 +563,17 @@ export async function applyResolvedOnboardingSession(
|
|
|
528
563
|
...(session.pendingSteps ? { pendingSteps: session.pendingSteps } : {}),
|
|
529
564
|
...(session.assistantPrompt ? { assistantPrompt: session.assistantPrompt } : {}),
|
|
530
565
|
...(session.patches ? { patches: session.patches } : {}),
|
|
566
|
+
...(dailyUsage ? { dailyUsage } : {}),
|
|
531
567
|
...(diagnostics ? { diagnostics } : {}),
|
|
532
568
|
}
|
|
533
569
|
}
|
|
534
570
|
|
|
535
|
-
export function buildDeferredOnboardResult(
|
|
571
|
+
export async function buildDeferredOnboardResult(
|
|
536
572
|
session: ResolvedOnboardingSession,
|
|
537
|
-
): OnboardCommandResult {
|
|
538
|
-
return buildPreApplyResult(
|
|
573
|
+
): Promise<OnboardCommandResult> {
|
|
574
|
+
return buildPreApplyResult(
|
|
575
|
+
session.status,
|
|
576
|
+
session,
|
|
577
|
+
await buildDailyUsageHandoff(session.projectRoot),
|
|
578
|
+
)
|
|
539
579
|
}
|
|
@@ -93,7 +93,7 @@ function buildUmiMountSnippet(): string {
|
|
|
93
93
|
" if (process.env.NODE_ENV !== 'production') {",
|
|
94
94
|
" import('@inspecto-dev/core').then(({ mountInspector }) => {",
|
|
95
95
|
' mountInspector({',
|
|
96
|
-
" serverUrl: 'http://127.0.0.1:' + ((window as
|
|
96
|
+
" serverUrl: 'http://127.0.0.1:' + ((window as { __AI_INSPECTOR_PORT__?: number }).__AI_INSPECTOR_PORT__ || 5678),",
|
|
97
97
|
' })',
|
|
98
98
|
' })',
|
|
99
99
|
' }',
|
package/src/prompts.ts
CHANGED
|
@@ -10,23 +10,33 @@ export async function promptIDEChoice(
|
|
|
10
10
|
detections: { ide: string; supported: boolean }[],
|
|
11
11
|
): Promise<{ ide: string; supported: boolean } | null> {
|
|
12
12
|
if (!process.stdin.isTTY) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (detections.length > 0) {
|
|
14
|
+
log.warn('Multiple IDEs detected but stdin is not interactive')
|
|
15
|
+
log.hint(`Using: ${detections[0]!.ide} (first match)`)
|
|
16
|
+
return detections[0]!
|
|
17
|
+
}
|
|
18
|
+
return { ide: 'none', supported: true }
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
const choices = detections.map(d => ({
|
|
22
|
+
title: `${d.ide} ${d.supported ? '(supported)' : '(unsupported/limited)'}`,
|
|
23
|
+
value: d,
|
|
24
|
+
}))
|
|
25
|
+
|
|
26
|
+
choices.push({
|
|
27
|
+
title: 'none (Standalone / MCP / Browser-only)',
|
|
28
|
+
value: { ide: 'none', supported: true },
|
|
29
|
+
})
|
|
30
|
+
|
|
18
31
|
const { choice } = await prompts({
|
|
19
32
|
type: 'select',
|
|
20
33
|
name: 'choice',
|
|
21
|
-
message: 'Detected multiple IDEs, please choose one:',
|
|
22
|
-
choices
|
|
23
|
-
title: `${d.ide} ${d.supported ? '(supported)' : '(unsupported/limited)'}`,
|
|
24
|
-
value: i,
|
|
25
|
-
})),
|
|
34
|
+
message: 'Detected multiple IDEs, please choose one (or select none for standalone use):',
|
|
35
|
+
choices,
|
|
26
36
|
})
|
|
27
37
|
|
|
28
38
|
if (choice === undefined) return null
|
|
29
|
-
return
|
|
39
|
+
return choice
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
/**
|
package/src/types.ts
CHANGED
|
@@ -134,6 +134,13 @@ export interface OnboardingVerification {
|
|
|
134
134
|
message: string
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
export interface OnboardingDailyUsageHandoff {
|
|
138
|
+
mode: 'agent'
|
|
139
|
+
skill: string
|
|
140
|
+
prompt: string
|
|
141
|
+
requiresMcp: boolean
|
|
142
|
+
}
|
|
143
|
+
|
|
137
144
|
export interface OnboardingAssistantHandoff {
|
|
138
145
|
framework?: string
|
|
139
146
|
metaFramework?: string
|
|
@@ -142,6 +149,7 @@ export interface OnboardingAssistantHandoff {
|
|
|
142
149
|
pendingSteps?: string[]
|
|
143
150
|
assistantPrompt?: string
|
|
144
151
|
patches?: OnboardingPatchPlan[]
|
|
152
|
+
dailyUsage?: OnboardingDailyUsageHandoff
|
|
145
153
|
}
|
|
146
154
|
|
|
147
155
|
export interface ResolvedOnboardingSession {
|
|
@@ -162,6 +170,7 @@ export interface ResolvedOnboardingSession {
|
|
|
162
170
|
pendingSteps?: string[]
|
|
163
171
|
assistantPrompt?: string
|
|
164
172
|
patches?: OnboardingPatchPlan[]
|
|
173
|
+
dailyUsage?: OnboardingDailyUsageHandoff
|
|
165
174
|
handoff?: OnboardingAssistantHandoff
|
|
166
175
|
}
|
|
167
176
|
|
|
@@ -181,6 +190,7 @@ export interface OnboardCommandResult {
|
|
|
181
190
|
pendingSteps?: string[]
|
|
182
191
|
assistantPrompt?: string
|
|
183
192
|
patches?: OnboardingPatchPlan[]
|
|
193
|
+
dailyUsage?: OnboardingDailyUsageHandoff
|
|
184
194
|
handoff?: OnboardingAssistantHandoff
|
|
185
195
|
}
|
|
186
196
|
|
|
@@ -126,6 +126,14 @@ describe('integration install', () => {
|
|
|
126
126
|
'/Users/tester/.agents/skills/inspecto-onboarding-codex/scripts/run-inspecto.sh',
|
|
127
127
|
'# mock asset',
|
|
128
128
|
)
|
|
129
|
+
expect(writeFileMock).toHaveBeenCalledWith(
|
|
130
|
+
'/Users/tester/.agents/skills/inspecto-agent-codex/SKILL.md',
|
|
131
|
+
'# mock asset',
|
|
132
|
+
)
|
|
133
|
+
expect(writeFileMock).toHaveBeenCalledWith(
|
|
134
|
+
'/Users/tester/.agents/skills/inspecto-agent-codex/agents/openai.yaml',
|
|
135
|
+
'# mock asset',
|
|
136
|
+
)
|
|
129
137
|
expect(chmodMock).toHaveBeenCalledWith(
|
|
130
138
|
'/Users/tester/.agents/skills/inspecto-onboarding-codex/scripts/run-inspecto.sh',
|
|
131
139
|
0o755,
|
|
@@ -134,6 +142,9 @@ describe('integration install', () => {
|
|
|
134
142
|
expect(logMock.hint).toHaveBeenCalledWith(
|
|
135
143
|
'/Users/tester/.agents/skills/inspecto-onboarding-codex/SKILL.md',
|
|
136
144
|
)
|
|
145
|
+
expect(logMock.hint).toHaveBeenCalledWith(
|
|
146
|
+
'/Users/tester/.agents/skills/inspecto-agent-codex/SKILL.md',
|
|
147
|
+
)
|
|
137
148
|
expect(runIntegrationAutomationMock).not.toHaveBeenCalled()
|
|
138
149
|
expect(logMock.ready).toHaveBeenCalledWith(
|
|
139
150
|
'Installed Codex integration assets. User-level installs only write integration assets and do not launch onboarding automatically.',
|
|
@@ -199,6 +210,7 @@ describe('integration install', () => {
|
|
|
199
210
|
expect(writeJSONMock).toHaveBeenCalledWith('/repo/.inspecto/settings.local.json', {
|
|
200
211
|
ide: 'trae-cn',
|
|
201
212
|
'provider.default': 'gemini.extension',
|
|
213
|
+
'annotate.deliveryMode': 'both',
|
|
202
214
|
})
|
|
203
215
|
})
|
|
204
216
|
|
|
@@ -216,6 +228,7 @@ describe('integration install', () => {
|
|
|
216
228
|
expect(writeJSONMock).toHaveBeenCalledWith('/repo/.inspecto/settings.local.json', {
|
|
217
229
|
ide: 'trae-cn',
|
|
218
230
|
'provider.default': 'gemini.extension',
|
|
231
|
+
'annotate.deliveryMode': 'both',
|
|
219
232
|
'prompt.autoSend': true,
|
|
220
233
|
})
|
|
221
234
|
})
|
|
@@ -228,6 +241,7 @@ describe('integration install', () => {
|
|
|
228
241
|
expect(writeJSONMock).toHaveBeenCalledWith('/repo/.inspecto/settings.local.json', {
|
|
229
242
|
ide: 'cursor',
|
|
230
243
|
'provider.default': 'codex.extension',
|
|
244
|
+
'annotate.deliveryMode': 'both',
|
|
231
245
|
})
|
|
232
246
|
})
|
|
233
247
|
|
|
@@ -540,6 +554,8 @@ describe('integration install', () => {
|
|
|
540
554
|
'/Users/tester/.agents/skills/inspecto-onboarding-codex/SKILL.md',
|
|
541
555
|
'/Users/tester/.agents/skills/inspecto-onboarding-codex/agents/openai.yaml',
|
|
542
556
|
'/Users/tester/.agents/skills/inspecto-onboarding-codex/scripts/run-inspecto.sh',
|
|
557
|
+
'/Users/tester/.agents/skills/inspecto-agent-codex/SKILL.md',
|
|
558
|
+
'/Users/tester/.agents/skills/inspecto-agent-codex/agents/openai.yaml',
|
|
543
559
|
],
|
|
544
560
|
preferredInstall:
|
|
545
561
|
'npx @inspecto-dev/cli integrations install codex --host-ide <vscode|cursor|trae|trae-cn|codebuddy|codebuddy-cn>',
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import crypto from 'node:crypto'
|
|
6
|
+
import {
|
|
7
|
+
INSPECTO_MCP_TOOLS,
|
|
8
|
+
createInspectoMcpRuntime,
|
|
9
|
+
resolveInspectoServerBaseUrl,
|
|
10
|
+
} from '../src/commands/mcp.js'
|
|
11
|
+
|
|
12
|
+
describe('inspecto mcp command', () => {
|
|
13
|
+
const portFile = path.join(os.tmpdir(), 'inspecto.port.json')
|
|
14
|
+
let originalPortFile: string | null = null
|
|
15
|
+
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
vi.restoreAllMocks()
|
|
18
|
+
try {
|
|
19
|
+
fs.unlinkSync(portFile)
|
|
20
|
+
} catch {
|
|
21
|
+
// ignore
|
|
22
|
+
}
|
|
23
|
+
if (originalPortFile !== null) {
|
|
24
|
+
fs.writeFileSync(portFile, originalPortFile, 'utf-8')
|
|
25
|
+
originalPortFile = null
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('resolves the current project server URL from inspecto.port.json', () => {
|
|
30
|
+
originalPortFile = fs.existsSync(portFile) ? fs.readFileSync(portFile, 'utf-8') : null
|
|
31
|
+
const cwd = '/repo/current'
|
|
32
|
+
const currentHash = crypto.createHash('md5').update(cwd).digest('hex')
|
|
33
|
+
const otherHash = crypto.createHash('md5').update('/repo/other').digest('hex')
|
|
34
|
+
|
|
35
|
+
fs.writeFileSync(
|
|
36
|
+
portFile,
|
|
37
|
+
JSON.stringify(
|
|
38
|
+
{
|
|
39
|
+
[otherHash]: 5679,
|
|
40
|
+
[currentHash]: 5680,
|
|
41
|
+
},
|
|
42
|
+
null,
|
|
43
|
+
2,
|
|
44
|
+
),
|
|
45
|
+
'utf-8',
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
expect(resolveInspectoServerBaseUrl(cwd)).toBe('http://127.0.0.1:5680')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('resolves the project server URL when Codex runs from a nested working directory', () => {
|
|
52
|
+
originalPortFile = fs.existsSync(portFile) ? fs.readFileSync(portFile, 'utf-8') : null
|
|
53
|
+
const projectRoot = '/repo/current'
|
|
54
|
+
const nestedCwd = '/repo/current/packages/app'
|
|
55
|
+
const projectRootHash = crypto.createHash('md5').update(projectRoot).digest('hex')
|
|
56
|
+
|
|
57
|
+
fs.writeFileSync(
|
|
58
|
+
portFile,
|
|
59
|
+
JSON.stringify(
|
|
60
|
+
{
|
|
61
|
+
[projectRootHash]: 5681,
|
|
62
|
+
},
|
|
63
|
+
null,
|
|
64
|
+
2,
|
|
65
|
+
),
|
|
66
|
+
'utf-8',
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
expect(resolveInspectoServerBaseUrl(nestedCwd)).toBe('http://127.0.0.1:5681')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('exposes the expected MCP tool definitions', () => {
|
|
73
|
+
expect(INSPECTO_MCP_TOOLS.map(tool => tool.name)).toEqual([
|
|
74
|
+
'inspecto_get_session',
|
|
75
|
+
'inspecto_claim_next',
|
|
76
|
+
'inspecto_reply',
|
|
77
|
+
'inspecto_resolve',
|
|
78
|
+
'inspecto_dismiss',
|
|
79
|
+
])
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('maps getSession and claimNext to the HTTP session endpoints', async () => {
|
|
83
|
+
const fetchMock = vi
|
|
84
|
+
.spyOn(globalThis, 'fetch')
|
|
85
|
+
.mockResolvedValueOnce({
|
|
86
|
+
ok: true,
|
|
87
|
+
json: async () => ({ success: true, session: { id: 'session-1' } }),
|
|
88
|
+
} as Response)
|
|
89
|
+
.mockResolvedValueOnce({
|
|
90
|
+
ok: true,
|
|
91
|
+
json: async () => ({
|
|
92
|
+
success: true,
|
|
93
|
+
timedOut: false,
|
|
94
|
+
matchedExisting: true,
|
|
95
|
+
session: { id: 'session-claim', status: 'acknowledged' },
|
|
96
|
+
}),
|
|
97
|
+
} as Response)
|
|
98
|
+
const runtime = createInspectoMcpRuntime('http://0.0.0.0:5678')
|
|
99
|
+
|
|
100
|
+
const session = await runtime.getSession({ sessionId: 'session-1' })
|
|
101
|
+
|
|
102
|
+
expect(fetchMock).toHaveBeenCalledWith('http://0.0.0.0:5678/inspecto/api/v1/sessions/session-1')
|
|
103
|
+
expect(session).toEqual({ success: true, session: { id: 'session-1' } })
|
|
104
|
+
|
|
105
|
+
const claim = await runtime.claimNext()
|
|
106
|
+
|
|
107
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
108
|
+
'http://0.0.0.0:5678/inspecto/api/v1/sessions/claim',
|
|
109
|
+
expect.objectContaining({
|
|
110
|
+
method: 'POST',
|
|
111
|
+
body: JSON.stringify({}),
|
|
112
|
+
}),
|
|
113
|
+
)
|
|
114
|
+
expect(claim).toEqual({
|
|
115
|
+
success: true,
|
|
116
|
+
timedOut: false,
|
|
117
|
+
matchedExisting: true,
|
|
118
|
+
session: { id: 'session-claim', status: 'acknowledged' },
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('maps reply, resolve, and dismiss to session mutation endpoints', async () => {
|
|
123
|
+
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue({
|
|
124
|
+
ok: true,
|
|
125
|
+
json: async () => ({ success: true, session: { id: 'session-1' } }),
|
|
126
|
+
} as Response)
|
|
127
|
+
const runtime = createInspectoMcpRuntime('http://0.0.0.0:5678')
|
|
128
|
+
|
|
129
|
+
const reply = await runtime.reply({
|
|
130
|
+
sessionId: 'session-1',
|
|
131
|
+
text: 'Working on it.',
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
135
|
+
'http://0.0.0.0:5678/inspecto/api/v1/sessions/session-1/reply',
|
|
136
|
+
expect.objectContaining({
|
|
137
|
+
method: 'POST',
|
|
138
|
+
}),
|
|
139
|
+
)
|
|
140
|
+
expect(reply).toEqual({ success: true, session: { id: 'session-1' } })
|
|
141
|
+
|
|
142
|
+
const resolve = await runtime.resolve({
|
|
143
|
+
sessionId: 'session-1',
|
|
144
|
+
message: 'Done.',
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
148
|
+
'http://0.0.0.0:5678/inspecto/api/v1/sessions/session-1/resolve',
|
|
149
|
+
expect.objectContaining({
|
|
150
|
+
method: 'POST',
|
|
151
|
+
}),
|
|
152
|
+
)
|
|
153
|
+
expect(resolve).toEqual({ success: true, session: { id: 'session-1' } })
|
|
154
|
+
|
|
155
|
+
const dismiss = await runtime.dismiss({
|
|
156
|
+
sessionId: 'session-1',
|
|
157
|
+
message: 'No action needed.',
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
161
|
+
'http://0.0.0.0:5678/inspecto/api/v1/sessions/session-1/dismiss',
|
|
162
|
+
expect.objectContaining({
|
|
163
|
+
method: 'POST',
|
|
164
|
+
}),
|
|
165
|
+
)
|
|
166
|
+
expect(dismiss).toEqual({ success: true, session: { id: 'session-1' } })
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('surfaces failed session mutations as rejected runtime calls', async () => {
|
|
170
|
+
vi.spyOn(globalThis, 'fetch').mockResolvedValue({
|
|
171
|
+
ok: false,
|
|
172
|
+
status: 404,
|
|
173
|
+
json: async () => ({ success: false, error: 'Session not found' }),
|
|
174
|
+
} as Response)
|
|
175
|
+
const runtime = createInspectoMcpRuntime('http://0.0.0.0:5678')
|
|
176
|
+
|
|
177
|
+
await expect(
|
|
178
|
+
runtime.reply({
|
|
179
|
+
sessionId: 'missing-session',
|
|
180
|
+
text: 'Working on it.',
|
|
181
|
+
}),
|
|
182
|
+
).rejects.toThrow('Session not found')
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('surfaces direct session lookup failures as rejected runtime calls', async () => {
|
|
186
|
+
vi.spyOn(globalThis, 'fetch').mockResolvedValue({
|
|
187
|
+
ok: false,
|
|
188
|
+
status: 404,
|
|
189
|
+
json: async () => ({ success: false, error: 'Session not found' }),
|
|
190
|
+
} as Response)
|
|
191
|
+
const runtime = createInspectoMcpRuntime('http://0.0.0.0:5678')
|
|
192
|
+
|
|
193
|
+
await expect(runtime.getSession({ sessionId: 'missing-session' })).rejects.toThrow(
|
|
194
|
+
'Session not found',
|
|
195
|
+
)
|
|
196
|
+
})
|
|
197
|
+
})
|
package/tests/onboard.test.ts
CHANGED
|
@@ -352,6 +352,12 @@ describe('onboard command', () => {
|
|
|
352
352
|
'Complete the remaining client-side mount step for your App Router entry.',
|
|
353
353
|
],
|
|
354
354
|
assistantPrompt: 'Complete the remaining Inspecto onboarding for this Next.js project.',
|
|
355
|
+
dailyUsage: {
|
|
356
|
+
mode: 'agent',
|
|
357
|
+
skill: 'inspecto-agent',
|
|
358
|
+
prompt: 'Use $inspecto-agent to claim Inspecto tasks continuously',
|
|
359
|
+
requiresMcp: true,
|
|
360
|
+
},
|
|
355
361
|
patches: [
|
|
356
362
|
{
|
|
357
363
|
path: 'next.config.mjs',
|
|
@@ -393,6 +399,12 @@ describe('onboard command', () => {
|
|
|
393
399
|
'Complete the remaining client-side mount step for your App Router entry.',
|
|
394
400
|
],
|
|
395
401
|
assistantPrompt: 'Complete the remaining Inspecto onboarding for this Next.js project.',
|
|
402
|
+
dailyUsage: {
|
|
403
|
+
mode: 'agent',
|
|
404
|
+
skill: 'inspecto-agent',
|
|
405
|
+
prompt: 'Use $inspecto-agent to claim Inspecto tasks continuously',
|
|
406
|
+
requiresMcp: true,
|
|
407
|
+
},
|
|
396
408
|
patches: [
|
|
397
409
|
{
|
|
398
410
|
path: 'next.config.mjs',
|
|
@@ -425,6 +437,9 @@ describe('onboard command', () => {
|
|
|
425
437
|
'Complete the remaining client-side mount step for your App Router entry.',
|
|
426
438
|
]),
|
|
427
439
|
)
|
|
440
|
+
expect(result.handoff?.dailyUsage?.prompt).toBe(
|
|
441
|
+
'Use $inspecto-agent to claim Inspecto tasks continuously',
|
|
442
|
+
)
|
|
428
443
|
expect(result.assistantPrompt).toContain('Complete the remaining Inspecto onboarding')
|
|
429
444
|
expect(result.patches).toEqual(
|
|
430
445
|
expect.arrayContaining([
|