@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.
@@ -2497,7 +2497,7 @@ function buildUmiMountSnippet() {
2497
2497
  " if (process.env.NODE_ENV !== 'production') {",
2498
2498
  " import('@inspecto-dev/core').then(({ mountInspector }) => {",
2499
2499
  " mountInspector({",
2500
- " serverUrl: 'http://127.0.0.1:' + ((window as any).__AI_INSPECTOR_PORT__ || 5678),",
2500
+ " serverUrl: 'http://127.0.0.1:' + ((window as { __AI_INSPECTOR_PORT__?: number }).__AI_INSPECTOR_PORT__ || 5678),",
2501
2501
  " })",
2502
2502
  " })",
2503
2503
  " }",
@@ -3379,21 +3379,29 @@ function resolveOnboardingTarget(input) {
3379
3379
  import prompts from "prompts";
3380
3380
  async function promptIDEChoice(detections) {
3381
3381
  if (!process.stdin.isTTY) {
3382
- log.warn("Multiple IDEs detected but stdin is not interactive");
3383
- log.hint(`Using: ${detections[0].ide} (first match)`);
3384
- return detections[0];
3382
+ if (detections.length > 0) {
3383
+ log.warn("Multiple IDEs detected but stdin is not interactive");
3384
+ log.hint(`Using: ${detections[0].ide} (first match)`);
3385
+ return detections[0];
3386
+ }
3387
+ return { ide: "none", supported: true };
3385
3388
  }
3389
+ const choices = detections.map((d) => ({
3390
+ title: `${d.ide} ${d.supported ? "(supported)" : "(unsupported/limited)"}`,
3391
+ value: d
3392
+ }));
3393
+ choices.push({
3394
+ title: "none (Standalone / MCP / Browser-only)",
3395
+ value: { ide: "none", supported: true }
3396
+ });
3386
3397
  const { choice } = await prompts({
3387
3398
  type: "select",
3388
3399
  name: "choice",
3389
- message: "Detected multiple IDEs, please choose one:",
3390
- choices: detections.map((d, i) => ({
3391
- title: `${d.ide} ${d.supported ? "(supported)" : "(unsupported/limited)"}`,
3392
- value: i
3393
- }))
3400
+ message: "Detected multiple IDEs, please choose one (or select none for standalone use):",
3401
+ choices
3394
3402
  });
3395
3403
  if (choice === void 0) return null;
3396
- return detections[choice];
3404
+ return choice;
3397
3405
  }
3398
3406
  async function promptProviderChoice(detections) {
3399
3407
  if (!process.stdin.isTTY) {
@@ -3724,10 +3732,14 @@ async function init(options) {
3724
3732
  "Please refer to the manual setup guide: https://inspecto-dev.github.io/inspecto/guide/manual-installation"
3725
3733
  );
3726
3734
  }
3727
- let selectedIDE = null;
3735
+ let selectedIDE;
3728
3736
  if (ideProbe.detected.length === 0) {
3729
- log.error("No IDE detected in current project");
3730
- log.hint("Please open this project in a supported IDE (like VS Code)");
3737
+ if (process.stdin.isTTY) {
3738
+ log.warn("No IDE detected in current project");
3739
+ selectedIDE = await promptIDEChoice([]);
3740
+ } else {
3741
+ selectedIDE = { ide: "none", supported: true };
3742
+ }
3731
3743
  } else if (ideProbe.detected.length === 1) {
3732
3744
  selectedIDE = ideProbe.detected[0];
3733
3745
  } else {
@@ -4303,8 +4315,311 @@ async function doctor(options = {}) {
4303
4315
  return writeCommandOutput(result, json, printDoctorResult);
4304
4316
  }
4305
4317
 
4306
- // src/onboarding/session.ts
4318
+ // src/commands/mcp.ts
4319
+ import fs6 from "fs";
4320
+ import os from "os";
4307
4321
  import path17 from "path";
4322
+ import crypto from "crypto";
4323
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4324
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4325
+ import { INSPECTO_API_PATHS } from "@inspecto-dev/types";
4326
+ import { z } from "zod";
4327
+ var DEFAULT_MCP_SERVER_VERSION = "0.0.0";
4328
+ var INSPECTO_MCP_TOOLS = [
4329
+ {
4330
+ name: "inspecto_get_session",
4331
+ description: "Return one Inspecto annotation session by sessionId."
4332
+ },
4333
+ {
4334
+ name: "inspecto_claim_next",
4335
+ description: "Wait for the next unclaimed Inspecto annotation session, mark it acknowledged, and return full context."
4336
+ },
4337
+ {
4338
+ name: "inspecto_reply",
4339
+ description: "Append an agent reply to an Inspecto annotation session."
4340
+ },
4341
+ {
4342
+ name: "inspecto_resolve",
4343
+ description: "Resolve an Inspecto annotation session with an optional final message."
4344
+ },
4345
+ {
4346
+ name: "inspecto_dismiss",
4347
+ description: "Dismiss an Inspecto annotation session with an optional final message."
4348
+ }
4349
+ ];
4350
+ async function startMcpServer(options = {}) {
4351
+ const baseUrl = options.serverUrl ?? resolveInspectoServerBaseUrl(process.cwd());
4352
+ if (!baseUrl) {
4353
+ throw new Error(
4354
+ "Could not find a running Inspecto dev server. Start your local dev server or pass --server-url <url>."
4355
+ );
4356
+ }
4357
+ const server = createInspectoMcpServer({
4358
+ baseUrl,
4359
+ ...options.version ? { version: options.version } : {}
4360
+ });
4361
+ const transport = new StdioServerTransport();
4362
+ await server.connect(transport);
4363
+ }
4364
+ function createInspectoMcpServer(options) {
4365
+ const runtime = createInspectoMcpRuntime(options.baseUrl);
4366
+ const server = new McpServer({
4367
+ name: "inspecto-mcp",
4368
+ version: options.version ?? DEFAULT_MCP_SERVER_VERSION
4369
+ });
4370
+ server.registerTool(
4371
+ "inspecto_get_session",
4372
+ {
4373
+ description: getToolDescription("inspecto_get_session"),
4374
+ inputSchema: {
4375
+ sessionId: z.string().min(1)
4376
+ }
4377
+ },
4378
+ async ({ sessionId }) => {
4379
+ try {
4380
+ const result = await runtime.getSession({ sessionId });
4381
+ return toolSuccess(result);
4382
+ } catch (error) {
4383
+ return toolError(error);
4384
+ }
4385
+ }
4386
+ );
4387
+ server.registerTool(
4388
+ "inspecto_claim_next",
4389
+ {
4390
+ description: getToolDescription("inspecto_claim_next"),
4391
+ inputSchema: {
4392
+ timeoutMs: z.number().int().nonnegative().optional()
4393
+ }
4394
+ },
4395
+ async ({ timeoutMs }) => {
4396
+ try {
4397
+ const result = await runtime.claimNext({
4398
+ ...timeoutMs !== void 0 ? { timeoutMs } : {}
4399
+ });
4400
+ return toolSuccess(result);
4401
+ } catch (error) {
4402
+ return toolError(error);
4403
+ }
4404
+ }
4405
+ );
4406
+ server.registerTool(
4407
+ "inspecto_reply",
4408
+ {
4409
+ description: getToolDescription("inspecto_reply"),
4410
+ inputSchema: {
4411
+ sessionId: z.string().min(1),
4412
+ text: z.string().min(1)
4413
+ }
4414
+ },
4415
+ async ({ sessionId, text }) => {
4416
+ try {
4417
+ const result = await runtime.reply({ sessionId, text });
4418
+ return toolSuccess(result);
4419
+ } catch (error) {
4420
+ return toolError(error);
4421
+ }
4422
+ }
4423
+ );
4424
+ server.registerTool(
4425
+ "inspecto_resolve",
4426
+ {
4427
+ description: getToolDescription("inspecto_resolve"),
4428
+ inputSchema: {
4429
+ sessionId: z.string().min(1),
4430
+ message: z.string().optional()
4431
+ }
4432
+ },
4433
+ async ({ sessionId, message: message2 }) => {
4434
+ try {
4435
+ const result = await runtime.resolve({ sessionId, ...message2 ? { message: message2 } : {} });
4436
+ return toolSuccess(result);
4437
+ } catch (error) {
4438
+ return toolError(error);
4439
+ }
4440
+ }
4441
+ );
4442
+ server.registerTool(
4443
+ "inspecto_dismiss",
4444
+ {
4445
+ description: getToolDescription("inspecto_dismiss"),
4446
+ inputSchema: {
4447
+ sessionId: z.string().min(1),
4448
+ message: z.string().optional()
4449
+ }
4450
+ },
4451
+ async ({ sessionId, message: message2 }) => {
4452
+ try {
4453
+ const result = await runtime.dismiss({ sessionId, ...message2 ? { message: message2 } : {} });
4454
+ return toolSuccess(result);
4455
+ } catch (error) {
4456
+ return toolError(error);
4457
+ }
4458
+ }
4459
+ );
4460
+ return server;
4461
+ }
4462
+ function getToolDescription(name) {
4463
+ return INSPECTO_MCP_TOOLS.find((tool) => tool.name === name)?.description ?? name;
4464
+ }
4465
+ function createInspectoMcpRuntime(baseUrl) {
4466
+ return {
4467
+ async getSession(args) {
4468
+ return getSession(baseUrl, args.sessionId);
4469
+ },
4470
+ async claimNext(args = {}) {
4471
+ return await postJson(`${baseUrl}${INSPECTO_API_PATHS.SESSION_CLAIM_NEXT}`, {
4472
+ ...args.timeoutMs !== void 0 ? { timeoutMs: args.timeoutMs } : {}
4473
+ });
4474
+ },
4475
+ async reply(args) {
4476
+ return postJson(
4477
+ `${baseUrl}${INSPECTO_API_PATHS.SESSIONS}/${args.sessionId}${INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX}`,
4478
+ {
4479
+ role: "agent",
4480
+ text: args.text.trim()
4481
+ }
4482
+ );
4483
+ },
4484
+ async resolve(args) {
4485
+ return postJson(
4486
+ `${baseUrl}${INSPECTO_API_PATHS.SESSIONS}/${args.sessionId}${INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX}`,
4487
+ args.message?.trim() ? { message: args.message.trim() } : {}
4488
+ );
4489
+ },
4490
+ async dismiss(args) {
4491
+ return postJson(
4492
+ `${baseUrl}${INSPECTO_API_PATHS.SESSIONS}/${args.sessionId}${INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX}`,
4493
+ args.message?.trim() ? { message: args.message.trim() } : {}
4494
+ );
4495
+ }
4496
+ };
4497
+ }
4498
+ function resolveInspectoServerBaseUrl(cwd) {
4499
+ const ports = resolveServerPorts(cwd);
4500
+ const port = ports[0];
4501
+ return port ? `http://127.0.0.1:${port}` : null;
4502
+ }
4503
+ function resolveServerPorts(cwd) {
4504
+ const prioritized = readProjectScopedPorts(cwd);
4505
+ if (prioritized.length > 0) return prioritized;
4506
+ const legacyPortFile = path17.join(os.tmpdir(), "inspecto.port");
4507
+ try {
4508
+ const raw = fs6.readFileSync(legacyPortFile, "utf-8").trim();
4509
+ const port = parseInt(raw, 10);
4510
+ if (Number.isInteger(port) && port > 0 && port < 65536) {
4511
+ return [port];
4512
+ }
4513
+ } catch {
4514
+ }
4515
+ return Array.from({ length: 23 }, (_, index) => 5678 + index);
4516
+ }
4517
+ function toolSuccess(value) {
4518
+ return {
4519
+ content: [
4520
+ {
4521
+ type: "text",
4522
+ text: JSON.stringify(value, null, 2)
4523
+ }
4524
+ ],
4525
+ structuredContent: value
4526
+ };
4527
+ }
4528
+ function toolError(error) {
4529
+ const message2 = error instanceof Error ? error.message : String(error);
4530
+ return {
4531
+ content: [
4532
+ {
4533
+ type: "text",
4534
+ text: message2
4535
+ }
4536
+ ],
4537
+ structuredContent: {
4538
+ success: false,
4539
+ error: message2
4540
+ },
4541
+ isError: true
4542
+ };
4543
+ }
4544
+ async function getJson(url) {
4545
+ const response = await fetch(url);
4546
+ const payload = await response.json().catch(() => ({}));
4547
+ if (!response.ok) {
4548
+ throw new Error(String(payload["error"] ?? `Request failed with status ${response.status}.`));
4549
+ }
4550
+ return payload;
4551
+ }
4552
+ async function getSession(baseUrl, sessionId) {
4553
+ const trimmed = sessionId.trim();
4554
+ if (!trimmed) {
4555
+ throw new Error("Session id is required.");
4556
+ }
4557
+ const payload = await getJson(
4558
+ `${baseUrl}${INSPECTO_API_PATHS.SESSIONS}/${encodeURIComponent(trimmed)}`
4559
+ );
4560
+ if (!payload.success || !payload.session) {
4561
+ throw new Error(payload.error ?? "Session not found.");
4562
+ }
4563
+ return {
4564
+ success: true,
4565
+ session: payload.session
4566
+ };
4567
+ }
4568
+ async function postJson(url, body) {
4569
+ const response = await fetch(url, {
4570
+ method: "POST",
4571
+ headers: { "Content-Type": "application/json" },
4572
+ body: JSON.stringify(body)
4573
+ });
4574
+ const payload = await response.json().catch(() => ({}));
4575
+ if (!response.ok || payload["success"] === false) {
4576
+ throw new Error(String(payload["error"] ?? `Request failed with status ${response.status}.`));
4577
+ }
4578
+ return payload;
4579
+ }
4580
+ function readProjectScopedPorts(cwd) {
4581
+ const portFile = path17.join(os.tmpdir(), "inspecto.port.json");
4582
+ try {
4583
+ const raw = fs6.readFileSync(portFile, "utf-8").trim();
4584
+ const portData = JSON.parse(raw);
4585
+ const currentRootHashes = resolveCandidateRootHashes(cwd);
4586
+ const prioritized = [];
4587
+ const seen = /* @__PURE__ */ new Set();
4588
+ for (const rootHash of currentRootHashes) {
4589
+ const currentPort = portData[rootHash];
4590
+ if (currentPort && !seen.has(currentPort)) {
4591
+ prioritized.push(currentPort);
4592
+ seen.add(currentPort);
4593
+ }
4594
+ }
4595
+ for (const port of Object.values(portData)) {
4596
+ if (!seen.has(port)) {
4597
+ prioritized.push(port);
4598
+ seen.add(port);
4599
+ }
4600
+ }
4601
+ return prioritized;
4602
+ } catch {
4603
+ return [];
4604
+ }
4605
+ }
4606
+ function resolveCandidateRootHashes(cwd) {
4607
+ const normalized = path17.resolve(cwd);
4608
+ const candidates = /* @__PURE__ */ new Set();
4609
+ let currentDir = normalized;
4610
+ while (true) {
4611
+ candidates.add(crypto.createHash("md5").update(currentDir).digest("hex"));
4612
+ const parentDir = path17.dirname(currentDir);
4613
+ if (parentDir === currentDir) {
4614
+ break;
4615
+ }
4616
+ currentDir = parentDir;
4617
+ }
4618
+ return [...candidates];
4619
+ }
4620
+
4621
+ // src/onboarding/session.ts
4622
+ import path18 from "path";
4308
4623
  function normalizePackagePath2(packagePath) {
4309
4624
  if (!packagePath || packagePath === ".") return "";
4310
4625
  return packagePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
@@ -4328,7 +4643,7 @@ function getVerificationCommand(packageManager) {
4328
4643
  }
4329
4644
  }
4330
4645
  async function buildVerification(projectRoot, packageManager) {
4331
- const packageJson = await readJSON(path17.join(projectRoot, "package.json"));
4646
+ const packageJson = await readJSON(path18.join(projectRoot, "package.json"));
4332
4647
  if (packageJson?.scripts?.dev) {
4333
4648
  const devCommand = getVerificationCommand(packageManager);
4334
4649
  return {
@@ -4386,7 +4701,7 @@ async function detectFrameworkSupportByPackage2(repoRoot, context) {
4386
4701
  await Promise.all(
4387
4702
  Array.from(packagePaths).map(async (packagePath) => {
4388
4703
  const frameworkResult = await detectFrameworks(
4389
- packagePath ? path17.join(repoRoot, packagePath) : repoRoot
4704
+ packagePath ? path18.join(repoRoot, packagePath) : repoRoot
4390
4705
  );
4391
4706
  supportByPackage[packagePath] = frameworkResult.supported;
4392
4707
  })
@@ -4395,7 +4710,7 @@ async function detectFrameworkSupportByPackage2(repoRoot, context) {
4395
4710
  }
4396
4711
  async function buildTargetedContext(rootContext, target) {
4397
4712
  const packagePath = normalizePackagePath2(target.packagePath);
4398
- const projectRoot = packagePath ? path17.join(rootContext.root, packagePath) : rootContext.root;
4713
+ const projectRoot = packagePath ? path18.join(rootContext.root, packagePath) : rootContext.root;
4399
4714
  const [frameworks, ides, providers] = await Promise.all([
4400
4715
  detectFrameworks(projectRoot),
4401
4716
  detectIDE(projectRoot),
@@ -4470,7 +4785,25 @@ function buildConfirmation(plan2, summary, session, options) {
4470
4785
  question: "Proceed with Inspecto onboarding using the proposed default target and settings?"
4471
4786
  };
4472
4787
  }
4473
- function buildPreApplyResult(status, session) {
4788
+ async function buildDailyUsageHandoff(projectRoot) {
4789
+ const localSettings = await readJSON(
4790
+ path18.join(projectRoot, ".inspecto", "settings.local.json")
4791
+ ) ?? {};
4792
+ const sharedSettings = await readJSON(
4793
+ path18.join(projectRoot, ".inspecto", "settings.json")
4794
+ ) ?? {};
4795
+ const annotateDeliveryMode = localSettings["annotate.deliveryMode"] ?? sharedSettings["annotate.deliveryMode"];
4796
+ if (annotateDeliveryMode !== "agent") {
4797
+ return void 0;
4798
+ }
4799
+ return {
4800
+ mode: "agent",
4801
+ skill: "inspecto-agent",
4802
+ prompt: "Use $inspecto-agent to claim Inspecto tasks continuously",
4803
+ requiresMcp: true
4804
+ };
4805
+ }
4806
+ function buildPreApplyResult(status, session, dailyUsage) {
4474
4807
  const diagnostics = session.summary.risks.length > 0 || session.summary.manualFollowUp.length > 0 || session.plan.blockers.length > 0 ? {
4475
4808
  warnings: session.summary.risks,
4476
4809
  errors: session.plan.blockers.map((item) => item.message),
@@ -4496,6 +4829,7 @@ function buildPreApplyResult(status, session) {
4496
4829
  ...session.pendingSteps ? { pendingSteps: session.pendingSteps } : {},
4497
4830
  ...session.assistantPrompt ? { assistantPrompt: session.assistantPrompt } : {},
4498
4831
  ...session.patches ? { patches: session.patches } : {},
4832
+ ...dailyUsage ? { dailyUsage } : {},
4499
4833
  ...diagnostics ? { diagnostics } : {}
4500
4834
  };
4501
4835
  }
@@ -4536,6 +4870,7 @@ function buildExecutionDiagnostics(session, applyResult) {
4536
4870
  async function resolveOnboardingSession(root, options = {}) {
4537
4871
  const rootContext = await buildOnboardingContext(root);
4538
4872
  const rootVerification = await buildVerification(root, rootContext.packageManager);
4873
+ const rootDailyUsage = await buildDailyUsageHandoff(root);
4539
4874
  const frameworkSupportByPackage = await detectFrameworkSupportByPackage2(root, rootContext);
4540
4875
  const target = resolveOnboardingTarget({
4541
4876
  repoRoot: root,
@@ -4569,7 +4904,8 @@ async function resolveOnboardingSession(root, options = {}) {
4569
4904
  ...plan3.autoApplied ? { autoApplied: plan3.autoApplied } : {},
4570
4905
  ...plan3.pendingSteps ? { pendingSteps: plan3.pendingSteps } : {},
4571
4906
  ...plan3.assistantPrompt ? { assistantPrompt: plan3.assistantPrompt } : {},
4572
- ...plan3.patches ? { patches: plan3.patches } : {}
4907
+ ...plan3.patches ? { patches: plan3.patches } : {},
4908
+ ...rootDailyUsage ? { dailyUsage: rootDailyUsage } : {}
4573
4909
  };
4574
4910
  }
4575
4911
  if (target.status === "needs_selection") {
@@ -4593,6 +4929,7 @@ async function resolveOnboardingSession(root, options = {}) {
4593
4929
  }
4594
4930
  const context = await buildTargetedContext(rootContext, target.selected);
4595
4931
  const verification = await buildVerification(context.root, context.packageManager);
4932
+ const dailyUsage = await buildDailyUsageHandoff(context.root);
4596
4933
  const plan2 = createPlanResult(context);
4597
4934
  const summary = buildOnboardingSummary(plan2, context.root);
4598
4935
  const confirmation = buildConfirmation(
@@ -4636,11 +4973,13 @@ async function resolveOnboardingSession(root, options = {}) {
4636
4973
  ...plan2.autoApplied ? { autoApplied: plan2.autoApplied } : {},
4637
4974
  ...plan2.pendingSteps ? { pendingSteps: plan2.pendingSteps } : {},
4638
4975
  ...plan2.assistantPrompt ? { assistantPrompt: plan2.assistantPrompt } : {},
4639
- ...plan2.patches ? { patches: plan2.patches } : {}
4976
+ ...plan2.patches ? { patches: plan2.patches } : {},
4977
+ ...dailyUsage ? { dailyUsage } : {}
4640
4978
  };
4641
4979
  }
4642
4980
  async function applyResolvedOnboardingSession(session, options = {}) {
4643
4981
  const verification = await buildVerification(session.projectRoot, session.context.packageManager);
4982
+ const dailyUsage = await buildDailyUsageHandoff(session.projectRoot);
4644
4983
  const applyResult = await applyOnboardingPlan({
4645
4984
  repoRoot: process.cwd(),
4646
4985
  projectRoot: session.projectRoot,
@@ -4681,11 +5020,16 @@ async function applyResolvedOnboardingSession(session, options = {}) {
4681
5020
  ...session.pendingSteps ? { pendingSteps: session.pendingSteps } : {},
4682
5021
  ...session.assistantPrompt ? { assistantPrompt: session.assistantPrompt } : {},
4683
5022
  ...session.patches ? { patches: session.patches } : {},
5023
+ ...dailyUsage ? { dailyUsage } : {},
4684
5024
  ...diagnostics ? { diagnostics } : {}
4685
5025
  };
4686
5026
  }
4687
- function buildDeferredOnboardResult(session) {
4688
- return buildPreApplyResult(session.status, session);
5027
+ async function buildDeferredOnboardResult(session) {
5028
+ return buildPreApplyResult(
5029
+ session.status,
5030
+ session,
5031
+ await buildDailyUsageHandoff(session.projectRoot)
5032
+ );
4689
5033
  }
4690
5034
 
4691
5035
  // src/commands/onboard.ts
@@ -4715,7 +5059,8 @@ function buildAssistantHandoff(result) {
4715
5059
  ...result.autoApplied ? { autoApplied: result.autoApplied } : {},
4716
5060
  ...result.pendingSteps ? { pendingSteps: result.pendingSteps } : {},
4717
5061
  ...result.assistantPrompt ? { assistantPrompt: result.assistantPrompt } : {},
4718
- ...result.patches ? { patches: result.patches } : {}
5062
+ ...result.patches ? { patches: result.patches } : {},
5063
+ ...result.dailyUsage ? { dailyUsage: result.dailyUsage } : {}
4719
5064
  };
4720
5065
  }
4721
5066
  function normalizeOnboardResult(result) {
@@ -4763,6 +5108,9 @@ function printOnboardResult(result) {
4763
5108
  if (normalized.handoff?.assistantPrompt) {
4764
5109
  log.hint(normalized.handoff.assistantPrompt);
4765
5110
  }
5111
+ if (normalized.handoff?.dailyUsage?.prompt) {
5112
+ log.hint(normalized.handoff.dailyUsage.prompt);
5113
+ }
4766
5114
  if (normalized.confirmation.required && normalized.confirmation.question) {
4767
5115
  log.warn(normalized.confirmation.question);
4768
5116
  }
@@ -4777,7 +5125,7 @@ async function onboard(options = {}) {
4777
5125
  const session = await resolveOnboardingSession(root, options);
4778
5126
  if (session.status === "error" || session.status === "needs_target_selection" || session.status === "needs_confirmation") {
4779
5127
  return writeCommandOutput(
4780
- normalizeOnboardResult(buildDeferredOnboardResult(session)),
5128
+ normalizeOnboardResult(await buildDeferredOnboardResult(session)),
4781
5129
  options.json ?? false,
4782
5130
  printOnboardResult
4783
5131
  );
@@ -4820,11 +5168,11 @@ async function plan(json = false) {
4820
5168
  }
4821
5169
 
4822
5170
  // src/commands/teardown.ts
4823
- import path18 from "path";
5171
+ import path19 from "path";
4824
5172
  async function teardown() {
4825
5173
  const root = process.cwd();
4826
5174
  log.header("Inspecto Teardown");
4827
- const lockPath = path18.join(root, ".inspecto", "install.lock");
5175
+ const lockPath = path19.join(root, ".inspecto", "install.lock");
4828
5176
  const lock = await readJSON(lockPath);
4829
5177
  if (!lock) {
4830
5178
  log.warn("No .inspecto/install.lock found. Running in best-effort mode.");
@@ -4837,8 +5185,8 @@ async function teardown() {
4837
5185
  } catch {
4838
5186
  log.warn("Could not remove @inspecto-dev/plugin (may not be installed)");
4839
5187
  }
4840
- if (await exists(path18.join(root, ".inspecto"))) {
4841
- await removeDir(path18.join(root, ".inspecto"));
5188
+ if (await exists(path19.join(root, ".inspecto"))) {
5189
+ await removeDir(path19.join(root, ".inspecto"));
4842
5190
  log.success("Deleted .inspecto/ directory");
4843
5191
  }
4844
5192
  await cleanGitignore(root);
@@ -4887,7 +5235,7 @@ async function teardown() {
4887
5235
  }
4888
5236
  }
4889
5237
  }
4890
- await removeDir(path18.join(root, ".inspecto"));
5238
+ await removeDir(path19.join(root, ".inspecto"));
4891
5239
  log.success("Deleted .inspecto/ directory");
4892
5240
  await cleanGitignore(root);
4893
5241
  log.blank();
@@ -4896,13 +5244,13 @@ async function teardown() {
4896
5244
  }
4897
5245
 
4898
5246
  // src/commands/integration-install.ts
4899
- import fs6 from "fs/promises";
5247
+ import fs7 from "fs/promises";
4900
5248
  import { homedir as homedir2 } from "os";
4901
- import path21 from "path";
5249
+ import path22 from "path";
4902
5250
  import { fileURLToPath } from "url";
4903
5251
 
4904
5252
  // src/commands/integration-host-ide.ts
4905
- import path19 from "path";
5253
+ import path20 from "path";
4906
5254
  async function resolveIntegrationHostIde(options = {}) {
4907
5255
  if (isSupportedHostIde(options.explicitIde)) {
4908
5256
  return {
@@ -4967,8 +5315,8 @@ async function resolveIntegrationHostIde(options = {}) {
4967
5315
  }
4968
5316
  async function resolveConfiguredIde(cwd) {
4969
5317
  const settingsPaths = [
4970
- path19.join(cwd, ".inspecto", "settings.local.json"),
4971
- path19.join(cwd, ".inspecto", "settings.json")
5318
+ path20.join(cwd, ".inspecto", "settings.local.json"),
5319
+ path20.join(cwd, ".inspecto", "settings.json")
4972
5320
  ];
4973
5321
  for (const settingsPath of settingsPaths) {
4974
5322
  const settings = await readJSON(settingsPath);
@@ -5019,7 +5367,7 @@ async function detectArtifactHostIdes(cwd) {
5019
5367
 
5020
5368
  // src/commands/integration-dispatch-mode.ts
5021
5369
  import { homedir } from "os";
5022
- import path20 from "path";
5370
+ import path21 from "path";
5023
5371
  async function resolveIntegrationDispatchMode(options) {
5024
5372
  const assistantRule = getDualModeAssistantCapability(options.assistant);
5025
5373
  const home = options.homeDir ?? homedir();
@@ -5062,7 +5410,7 @@ async function isIdeExtensionInstalled(extensionId, extensionsDir) {
5062
5410
  } catch {
5063
5411
  return false;
5064
5412
  }
5065
- const obsoletePath = path20.join(extensionsDir, ".obsolete");
5413
+ const obsoletePath = path21.join(extensionsDir, ".obsolete");
5066
5414
  let obsoleteFolders = /* @__PURE__ */ new Set();
5067
5415
  if (await exists(obsoletePath)) {
5068
5416
  const obsolete = await readJSON(obsoletePath);
@@ -5526,7 +5874,7 @@ async function installIntegration(assistant, options = {}) {
5526
5874
  if (await exists(asset.target)) {
5527
5875
  if (options.force) {
5528
5876
  } else if (manifest.type === "context-template") {
5529
- const originalContent = await fs6.readFile(asset.target, "utf-8");
5877
+ const originalContent = await fs7.readFile(asset.target, "utf-8");
5530
5878
  existingFiles.set(asset.target, originalContent);
5531
5879
  if (!silent) {
5532
5880
  log.info(`File ${asset.target} already exists. Content will be appended safely.`);
@@ -5563,7 +5911,7 @@ ${content}`;
5563
5911
  for (const { asset, content } of downloadedAssets) {
5564
5912
  await writeFile(asset.target, content);
5565
5913
  if (asset.executable) {
5566
- await fs6.chmod(asset.target, 493);
5914
+ await fs7.chmod(asset.target, 493);
5567
5915
  }
5568
5916
  }
5569
5917
  }
@@ -5678,23 +6026,30 @@ async function resolveProviderDefaultForAssistant(assistant, ide) {
5678
6026
  return `${assistant}.${mode}`;
5679
6027
  }
5680
6028
  async function persistProjectOnboardingDefaults(assistant, options) {
5681
- const settingsPath = path21.join(process.cwd(), ".inspecto", "settings.local.json");
6029
+ const settingsPath = path22.join(process.cwd(), ".inspecto", "settings.local.json");
5682
6030
  const existingSettings = await readJSON(settingsPath);
5683
6031
  const resolvedHostIde = await resolveIntegrationHostIde({
5684
6032
  explicitIde: options.ide,
5685
6033
  cwd: process.cwd()
5686
6034
  });
5687
6035
  const providerDefault = resolvedHostIde.ide && resolvedHostIde.confidence !== "low" ? await resolveProviderDefaultForAssistant(assistant, resolvedHostIde.ide) : void 0;
6036
+ const annotateDeliveryMode = resolveAnnotateDefaultDeliveryForAssistant(assistant);
5688
6037
  const mergedSettings = existingSettings && typeof existingSettings === "object" ? {
5689
6038
  ...existingSettings,
5690
6039
  ide: options.ide,
5691
- ...providerDefault ? { "provider.default": providerDefault } : {}
6040
+ ...providerDefault ? { "provider.default": providerDefault } : {},
6041
+ "annotate.deliveryMode": annotateDeliveryMode
5692
6042
  } : {
5693
6043
  ide: options.ide,
5694
- ...providerDefault ? { "provider.default": providerDefault } : {}
6044
+ ...providerDefault ? { "provider.default": providerDefault } : {},
6045
+ "annotate.deliveryMode": annotateDeliveryMode
5695
6046
  };
5696
6047
  await writeJSON(settingsPath, mergedSettings);
5697
6048
  }
6049
+ function resolveAnnotateDefaultDeliveryForAssistant(assistant) {
6050
+ void assistant;
6051
+ return "both";
6052
+ }
5698
6053
  function shouldSkipAutomationForInstall(options) {
5699
6054
  return options.scope === "user" && !options.preview;
5700
6055
  }
@@ -5845,28 +6200,39 @@ function resolveCodexPlan(options) {
5845
6200
  if (options.mode !== void 0) {
5846
6201
  throw new Error("`--mode` is not supported for codex.");
5847
6202
  }
5848
- const baseDir = scope === "user" ? path21.join(homedir2(), ".agents/skills/inspecto-onboarding-codex") : ".agents/skills/inspecto-onboarding-codex";
6203
+ const baseDir = scope === "user" ? path22.join(homedir2(), ".agents/skills/inspecto-onboarding-codex") : ".agents/skills/inspecto-onboarding-codex";
6204
+ const agentDir = scope === "user" ? path22.join(homedir2(), ".agents/skills/inspecto-agent-codex") : ".agents/skills/inspecto-agent-codex";
5849
6205
  return {
5850
6206
  assets: [
5851
6207
  {
5852
6208
  source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-codex/SKILL.md`,
5853
- target: path21.join(baseDir, "SKILL.md"),
6209
+ target: path22.join(baseDir, "SKILL.md"),
5854
6210
  localSource: "skills/inspecto-onboarding-codex/SKILL.md"
5855
6211
  },
5856
6212
  {
5857
6213
  source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-codex/agents/openai.yaml`,
5858
- target: path21.join(baseDir, "agents/openai.yaml"),
6214
+ target: path22.join(baseDir, "agents/openai.yaml"),
5859
6215
  localSource: "skills/inspecto-onboarding-codex/agents/openai.yaml"
5860
6216
  },
5861
6217
  {
5862
6218
  source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-codex/scripts/run-inspecto.sh`,
5863
- target: path21.join(baseDir, "scripts/run-inspecto.sh"),
6219
+ target: path22.join(baseDir, "scripts/run-inspecto.sh"),
5864
6220
  executable: true,
5865
6221
  localSource: "skills/inspecto-onboarding-codex/scripts/run-inspecto.sh"
6222
+ },
6223
+ {
6224
+ source: `${REPO_RAW_BASE}/skills/inspecto-agent-codex/SKILL.md`,
6225
+ target: path22.join(agentDir, "SKILL.md"),
6226
+ localSource: "skills/inspecto-agent-codex/SKILL.md"
6227
+ },
6228
+ {
6229
+ source: `${REPO_RAW_BASE}/skills/inspecto-agent-codex/agents/openai.yaml`,
6230
+ target: path22.join(agentDir, "agents/openai.yaml"),
6231
+ localSource: "skills/inspecto-agent-codex/agents/openai.yaml"
5866
6232
  }
5867
6233
  ],
5868
- successMessage: `Installed Codex skill to ${baseDir}`,
5869
- nextStep: "Restart Codex or start a new Codex session to load the skill."
6234
+ successMessage: `Installed Codex skills to ${baseDir} and ${agentDir}`,
6235
+ nextStep: "Restart Codex or start a new Codex session to load the new skills."
5870
6236
  };
5871
6237
  }
5872
6238
  function resolveClaudeCodePlan(options) {
@@ -5880,22 +6246,22 @@ function resolveClaudeCodePlan(options) {
5880
6246
  if (scope !== "project" && scope !== "user") {
5881
6247
  throw new Error(`Unknown Claude Code scope: ${scope}`);
5882
6248
  }
5883
- const baseDir = scope === "user" ? path21.join(homedir2(), ".claude/skills/inspecto-onboarding-claude-code") : ".claude/skills/inspecto-onboarding-claude-code";
6249
+ const baseDir = scope === "user" ? path22.join(homedir2(), ".claude/skills/inspecto-onboarding-claude-code") : ".claude/skills/inspecto-onboarding-claude-code";
5884
6250
  return {
5885
6251
  assets: [
5886
6252
  {
5887
6253
  source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-claude-code/SKILL.md`,
5888
- target: path21.join(baseDir, "SKILL.md"),
6254
+ target: path22.join(baseDir, "SKILL.md"),
5889
6255
  localSource: "skills/inspecto-onboarding-claude-code/SKILL.md"
5890
6256
  },
5891
6257
  {
5892
6258
  source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-claude-code/agents/openai.yaml`,
5893
- target: path21.join(baseDir, "agents/openai.yaml"),
6259
+ target: path22.join(baseDir, "agents/openai.yaml"),
5894
6260
  localSource: "skills/inspecto-onboarding-claude-code/agents/openai.yaml"
5895
6261
  },
5896
6262
  {
5897
6263
  source: `${REPO_RAW_BASE}/skills/inspecto-onboarding-claude-code/scripts/run-inspecto.sh`,
5898
- target: path21.join(baseDir, "scripts/run-inspecto.sh"),
6264
+ target: path22.join(baseDir, "scripts/run-inspecto.sh"),
5899
6265
  executable: true,
5900
6266
  localSource: "skills/inspecto-onboarding-claude-code/scripts/run-inspecto.sh"
5901
6267
  }
@@ -5960,20 +6326,20 @@ async function loadAsset(asset) {
5960
6326
  if (asset.localSource) {
5961
6327
  const localPath = await resolveBundledAssetPath(asset.localSource);
5962
6328
  if (localPath) {
5963
- return await fs6.readFile(localPath, "utf-8");
6329
+ return await fs7.readFile(localPath, "utf-8");
5964
6330
  }
5965
6331
  }
5966
6332
  return await downloadAsset(asset.source);
5967
6333
  }
5968
6334
  async function resolveBundledAssetPath(relativePath) {
5969
- const startDir = path21.dirname(fileURLToPath(import.meta.url));
6335
+ const startDir = path22.dirname(fileURLToPath(import.meta.url));
5970
6336
  let currentDir = startDir;
5971
6337
  for (let depth = 0; depth < 8; depth += 1) {
5972
- const candidate = path21.join(currentDir, relativePath);
6338
+ const candidate = path22.join(currentDir, relativePath);
5973
6339
  if (await exists(candidate)) {
5974
6340
  return candidate;
5975
6341
  }
5976
- const parent = path21.dirname(currentDir);
6342
+ const parent = path22.dirname(currentDir);
5977
6343
  if (parent === currentDir) break;
5978
6344
  currentDir = parent;
5979
6345
  }
@@ -6087,6 +6453,10 @@ export {
6087
6453
  init,
6088
6454
  collectDoctorResult,
6089
6455
  doctor,
6456
+ startMcpServer,
6457
+ createInspectoMcpServer,
6458
+ createInspectoMcpRuntime,
6459
+ resolveInspectoServerBaseUrl,
6090
6460
  onboard,
6091
6461
  plan,
6092
6462
  teardown,