create-snipara 1.3.22 → 1.3.24

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.
Files changed (3) hide show
  1. package/README.md +14 -0
  2. package/dist/index.js +279 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -197,6 +197,19 @@ Writes `.snipara/companion/doctor.json` and validates:
197
197
  - Snipara Sandbox CLI presence
198
198
  - environment files
199
199
  - hosted MCP reachability when a live API key is available
200
+ - exposed Hosted MCP tool aliases (`snipara_*`, with `rlm_*` reported as legacy)
201
+ - client-specific loading gaps that the terminal cannot prove
202
+
203
+ For Claude-specific support, run:
204
+
205
+ ```bash
206
+ npx create-snipara doctor --client claude
207
+ ```
208
+
209
+ This separates "Snipara config was written" from "Claude actually loaded the MCP
210
+ server." If Claude uses its cloud/UI MCP configuration instead of local files,
211
+ the doctor output points the user to Claude **Settings -> MCP** instead of
212
+ repeating local file edits.
200
213
 
201
214
  ### Repair local setup
202
215
 
@@ -269,6 +282,7 @@ That keeps business truth review separate from agent onboarding.
269
282
  npx create-snipara --profile hosted-companion
270
283
  npx create-snipara --profile hosted-only
271
284
  npx create-snipara --profile full-stack
285
+ npx create-snipara --full
272
286
  npx create-snipara --advanced
273
287
 
274
288
  # Sandbox-only local execution
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import { homedir } from "os";
13
13
  // package.json
14
14
  var package_default = {
15
15
  name: "create-snipara",
16
- version: "1.3.22",
16
+ version: "1.3.24",
17
17
  description: "Onboard Snipara Hosted MCP Context + Memory with auth, companion workflows, and optional Snipara Sandbox",
18
18
  main: "dist/index.js",
19
19
  type: "module",
@@ -170,11 +170,14 @@ function buildProgram() {
170
170
  program.command("init").description("Install and configure Snipara for this project").option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
171
171
  "--profile <profile>",
172
172
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
173
- ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
173
+ ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").option("--full", "Alias for --profile full-stack").option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
174
174
  printBanner();
175
175
  await runInit(options);
176
176
  });
177
- program.command("doctor").description("Inspect the current project and write a validation report").option("--json", "Print the report as JSON").action(async (options) => {
177
+ program.command("doctor").description("Inspect the current project and write a validation report").option(
178
+ "--client <client>",
179
+ "Run client-specific diagnostics: claude, claude-code, claude-desktop, cursor, codex, etc."
180
+ ).option("--skip-npm-check", "Skip npm latest-version freshness check").option("--json", "Print the report as JSON").action(async (options) => {
178
181
  printBanner();
179
182
  await runDoctor(options);
180
183
  });
@@ -201,12 +204,20 @@ function addSharedRootOptions(program) {
201
204
  program.option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
202
205
  "--profile <profile>",
203
206
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
204
- ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").option("-y, --yes", "Accept defaults without prompting");
207
+ ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").option("--full", "Alias for --profile full-stack").option("-y, --yes", "Accept defaults without prompting");
205
208
  }
206
209
  async function main() {
207
210
  const program = buildProgram();
211
+ normalizeLegacyArgAliases(process.argv);
208
212
  await program.parseAsync(process.argv);
209
213
  }
214
+ function normalizeLegacyArgAliases(argv) {
215
+ for (let index = 2; index < argv.length; index += 1) {
216
+ if (argv[index] === "--Full") {
217
+ argv[index] = "--full";
218
+ }
219
+ }
220
+ }
210
221
  function normalizeInitOptions(options) {
211
222
  const parsed = parseInitOptionsFromArgv(process.argv.slice(2));
212
223
  const normalized = { ...parsed };
@@ -235,6 +246,8 @@ function parseInitOptionsFromArgv(args) {
235
246
  "--skip-test": "skipTest",
236
247
  "--with-orchestrator": "withOrchestrator",
237
248
  "--runtime-only": "runtimeOnly",
249
+ "--full": "full",
250
+ "--Full": "full",
238
251
  "--github": "github",
239
252
  "--skip-github": "skipGithub",
240
253
  "--yes": "yes",
@@ -291,8 +304,16 @@ async function runInit(options) {
291
304
  }
292
305
  }
293
306
  async function runDoctor(options) {
294
- const answers = loadExistingAnswers(options);
295
- const report = await runValidation(answers, true);
307
+ const requestedClient = normalizeClientOption(options.client);
308
+ const existingAnswers = loadExistingAnswers(options);
309
+ const answers = {
310
+ ...existingAnswers,
311
+ aiClient: requestedClient || existingAnswers.aiClient
312
+ };
313
+ const report = await runValidation(answers, true, {
314
+ client: requestedClient || answers.aiClient,
315
+ includeNpmFreshness: !options.skipNpmCheck
316
+ });
296
317
  writeDoctorReport(report);
297
318
  if (options.json) {
298
319
  console.log(JSON.stringify({ detection: detectEnvironment(), validation: report }, null, 2));
@@ -446,7 +467,9 @@ async function gatherConfiguration(options) {
446
467
  skipRuntime: !!options.skipRuntime,
447
468
  withOrchestrator: !!options.withOrchestrator,
448
469
  skipHooks: !!options.skipHooks,
449
- configureGitHub: Boolean(options.github && detectedGitRepo && !options.skipGithub),
470
+ configureGitHub: Boolean(
471
+ (options.github || options.githubPath) && detectedGitRepo && !options.skipGithub
472
+ ),
450
473
  githubRepo: detectedGitRepo || void 0,
451
474
  githubPath: options.githubPath
452
475
  });
@@ -563,7 +586,7 @@ async function gatherConfiguration(options) {
563
586
  withOrchestrator: Boolean(options.withOrchestrator || response.installOrchestrator),
564
587
  skipHooks: !!options.skipHooks || !response.installHooks,
565
588
  configureGitHub: Boolean(
566
- (response.configureGitHub || options.github) && detectedGitRepo && !options.skipGithub
589
+ (response.configureGitHub || options.github || options.githubPath) && detectedGitRepo && !options.skipGithub
567
590
  ),
568
591
  githubRepo: detectedGitRepo || void 0,
569
592
  githubPath: response.githubPath || options.githubPath
@@ -623,6 +646,9 @@ function resolveRequestedProfile(options) {
623
646
  if ("runtimeOnly" in options && options.runtimeOnly) {
624
647
  return "runtime-only";
625
648
  }
649
+ if ("full" in options && options.full) {
650
+ return "full-stack";
651
+ }
626
652
  if (options.profile && isInstallProfile(options.profile)) {
627
653
  return options.profile;
628
654
  }
@@ -631,6 +657,34 @@ function resolveRequestedProfile(options) {
631
657
  function isInstallProfile(value) {
632
658
  return ["hosted-only", "hosted-companion", "full-stack", "runtime-only"].includes(value);
633
659
  }
660
+ function normalizeClientOption(value) {
661
+ if (!value) {
662
+ return null;
663
+ }
664
+ const normalized = value.trim().toLowerCase();
665
+ const aliases = {
666
+ claude: "claude-code",
667
+ "claude-code": "claude-code",
668
+ claude_code: "claude-code",
669
+ claudecli: "claude-code",
670
+ "claude-cli": "claude-code",
671
+ "claude-desktop": "claude-desktop",
672
+ claude_desktop: "claude-desktop",
673
+ cursor: "cursor",
674
+ windsurf: "windsurf",
675
+ codex: "codex",
676
+ gemini: "gemini",
677
+ chatgpt: "chatgpt",
678
+ vscode: "vscode",
679
+ continue: "continue",
680
+ other: "other"
681
+ };
682
+ const client = aliases[normalized];
683
+ if (!client) {
684
+ throw new Error(`Unknown client '${value}'. Use claude, claude-code, cursor, codex, or other.`);
685
+ }
686
+ return client;
687
+ }
634
688
  function installProfileChoices() {
635
689
  return [
636
690
  {
@@ -2044,15 +2098,143 @@ function buildGitHubAutomationUrl(answers) {
2044
2098
  }
2045
2099
  return url.toString();
2046
2100
  }
2047
- async function runValidation(answers, includeHostedCheck) {
2101
+ function getClaudeClientChecks(answers, detection) {
2102
+ const checks = [];
2103
+ const claudePaths = getClaudeConfigPaths();
2104
+ const projectConfig = readJsonFile(path.join(process.cwd(), ".mcp.json"));
2105
+ const codeSettings = readJsonFile(claudePaths.codeSettingsPath);
2106
+ const desktopConfig = readJsonFile(claudePaths.desktopConfigPath);
2107
+ const projectHasSnipara = containsSniparaMcpReference(projectConfig);
2108
+ const codeSettingsHasSnipara = containsSniparaMcpReference(codeSettings);
2109
+ const desktopHasSnipara = containsSniparaMcpReference(desktopConfig);
2110
+ checks.push({
2111
+ name: "claude_project_config",
2112
+ status: projectHasSnipara ? "pass" : "warn",
2113
+ detail: projectHasSnipara ? "Project .mcp.json contains a Snipara Hosted MCP server" : "Project .mcp.json does not contain a Snipara Hosted MCP server"
2114
+ });
2115
+ if (answers.aiClient === "claude-code") {
2116
+ checks.push({
2117
+ name: "claude_code_settings",
2118
+ status: detection.files.claudeSettings ? codeSettingsHasSnipara ? "pass" : "warn" : "warn",
2119
+ detail: detection.files.claudeSettings ? codeSettingsHasSnipara ? "~/.claude/settings.json references Snipara" : "~/.claude/settings.json exists but no Snipara MCP server was found" : "~/.claude/settings.json not found; Claude may require Settings -> MCP UI setup"
2120
+ });
2121
+ }
2122
+ if (answers.aiClient === "claude-desktop") {
2123
+ checks.push({
2124
+ name: "claude_desktop_config",
2125
+ status: detection.files.claudeDesktopConfig ? desktopHasSnipara ? "pass" : "warn" : "warn",
2126
+ detail: detection.files.claudeDesktopConfig ? desktopHasSnipara ? "Claude Desktop config references Snipara" : "Claude Desktop config exists but no Snipara MCP server was found" : "Claude Desktop config not found"
2127
+ });
2128
+ }
2129
+ checks.push({
2130
+ name: "claude_tools_visible",
2131
+ status: "warn",
2132
+ detail: "This terminal cannot prove Claude loaded the MCP server; confirm Snipara tools in Claude Settings -> MCP or ToolSearch after restart"
2133
+ });
2134
+ return checks;
2135
+ }
2136
+ function readJsonFile(filePath) {
2137
+ if (!fs.existsSync(filePath)) {
2138
+ return null;
2139
+ }
2140
+ try {
2141
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
2142
+ } catch {
2143
+ return null;
2144
+ }
2145
+ }
2146
+ function containsSniparaMcpReference(value) {
2147
+ if (value === null || value === void 0) {
2148
+ return false;
2149
+ }
2150
+ if (typeof value === "string") {
2151
+ return value.includes("api.snipara.com/mcp") || value.includes("snipara-mcp");
2152
+ }
2153
+ if (Array.isArray(value)) {
2154
+ return value.some((item) => containsSniparaMcpReference(item));
2155
+ }
2156
+ if (typeof value === "object") {
2157
+ const record = value;
2158
+ const mcpServers = record.mcpServers;
2159
+ if (mcpServers && typeof mcpServers === "object" && "snipara" in mcpServers) {
2160
+ return true;
2161
+ }
2162
+ return Object.values(record).some((nested) => containsSniparaMcpReference(nested));
2163
+ }
2164
+ return false;
2165
+ }
2166
+ function getCreateSniparaPackageFreshnessCheck() {
2167
+ if (!commandExists("npm")) {
2168
+ return {
2169
+ name: "create_snipara_npm_version",
2170
+ status: "warn",
2171
+ detail: "npm not found; could not compare local create-snipara with npm latest"
2172
+ };
2173
+ }
2174
+ try {
2175
+ const raw = execSync("npm view create-snipara version --json", {
2176
+ encoding: "utf-8",
2177
+ stdio: ["ignore", "pipe", "ignore"],
2178
+ shell: "/bin/sh",
2179
+ timeout: 4e3
2180
+ }).trim();
2181
+ const latest = raw.replace(/^"|"$/g, "");
2182
+ const comparison = compareSemver(VERSION, latest);
2183
+ if (comparison === 0) {
2184
+ return {
2185
+ name: "create_snipara_npm_version",
2186
+ status: "pass",
2187
+ detail: `Local package version ${VERSION} matches npm latest`
2188
+ };
2189
+ }
2190
+ if (comparison > 0) {
2191
+ return {
2192
+ name: "create_snipara_npm_version",
2193
+ status: "warn",
2194
+ detail: `Local package version ${VERSION} is newer than npm latest ${latest}; publish may be pending`
2195
+ };
2196
+ }
2197
+ return {
2198
+ name: "create_snipara_npm_version",
2199
+ status: "warn",
2200
+ detail: `npm latest is ${latest}; rerun with npx create-snipara@latest if this local copy is older`
2201
+ };
2202
+ } catch {
2203
+ return {
2204
+ name: "create_snipara_npm_version",
2205
+ status: "warn",
2206
+ detail: "Could not reach npm to compare create-snipara latest version"
2207
+ };
2208
+ }
2209
+ }
2210
+ function compareSemver(left, right) {
2211
+ const leftParts = left.split(".").map((part) => Number.parseInt(part, 10) || 0);
2212
+ const rightParts = right.split(".").map((part) => Number.parseInt(part, 10) || 0);
2213
+ const length = Math.max(leftParts.length, rightParts.length);
2214
+ for (let index = 0; index < length; index += 1) {
2215
+ const diff = (leftParts[index] || 0) - (rightParts[index] || 0);
2216
+ if (diff !== 0) {
2217
+ return diff > 0 ? 1 : -1;
2218
+ }
2219
+ }
2220
+ return 0;
2221
+ }
2222
+ async function runValidation(answers, includeHostedCheck, options = {}) {
2048
2223
  console.log(chalk.bold("\n\u{1FA7A} Running Validation\n"));
2049
2224
  const checks = [];
2050
2225
  const detection = detectEnvironment();
2226
+ const targetClient = options.client || answers.aiClient;
2227
+ const effectiveAnswers = { ...answers, aiClient: targetClient };
2051
2228
  checks.push({
2052
2229
  name: "project_slug",
2053
2230
  status: answers.projectSlug ? "pass" : "fail",
2054
2231
  detail: answers.projectSlug || "Project slug missing"
2055
2232
  });
2233
+ checks.push({
2234
+ name: "target_client",
2235
+ status: "pass",
2236
+ detail: getClientDisplayName(targetClient)
2237
+ });
2056
2238
  checks.push({
2057
2239
  name: "mcp_config",
2058
2240
  status: detection.files.mcpConfig ? "pass" : "warn",
@@ -2090,9 +2272,15 @@ async function runValidation(answers, includeHostedCheck) {
2090
2272
  });
2091
2273
  checks.push({
2092
2274
  name: "hooks",
2093
- status: answers.installHooks && answers.aiClient === "claude-code" ? detection.files.claudeDir ? "pass" : "warn" : "pass",
2094
- detail: answers.installHooks && answers.aiClient === "claude-code" ? detection.files.claudeDir ? "~/.claude detected" : "~/.claude missing" : "Hooks not requested"
2275
+ status: answers.installHooks && targetClient === "claude-code" ? detection.files.claudeDir ? "pass" : "warn" : "pass",
2276
+ detail: answers.installHooks && targetClient === "claude-code" ? detection.files.claudeDir ? "~/.claude detected" : "~/.claude missing" : "Hooks not requested"
2095
2277
  });
2278
+ if (targetClient === "claude-code" || targetClient === "claude-desktop") {
2279
+ checks.push(...getClaudeClientChecks(effectiveAnswers, detection));
2280
+ }
2281
+ if (options.includeNpmFreshness) {
2282
+ checks.push(getCreateSniparaPackageFreshnessCheck());
2283
+ }
2096
2284
  const githubRepo = answers.githubRepo || detectGitRepository();
2097
2285
  checks.push({
2098
2286
  name: "github_answer_packs",
@@ -2125,11 +2313,12 @@ function writeDoctorReport(report) {
2125
2313
  console.log(chalk.green(" \u2713 Wrote .snipara/companion/doctor.json"));
2126
2314
  }
2127
2315
  function printDoctorReport(detection, report) {
2316
+ const targetClient = report.checks.find((check) => check.name === "target_client")?.detail || detection.aiClient;
2128
2317
  console.log(chalk.bold("\n\u{1FA7A} Snipara Doctor\n"));
2129
2318
  console.log(
2130
2319
  ` Project slug: ${detection.existingConfig.slug || detection.projectSlug || "unknown"}`
2131
2320
  );
2132
- console.log(` AI client: ${detection.aiClient}`);
2321
+ console.log(` AI client: ${targetClient}`);
2133
2322
  console.log(` In git repo: ${detection.inGitRepo ? "yes" : "no"}`);
2134
2323
  console.log(` Profile: ${report.profile}`);
2135
2324
  console.log("");
@@ -2164,22 +2353,31 @@ async function testHostedConnection(answers) {
2164
2353
  ];
2165
2354
  }
2166
2355
  spinner.succeed("Connected to Snipara Hosted MCP.");
2356
+ const toolNames = extractMcpToolNames(toolsResponse.data);
2357
+ const hasSniparaTools = toolNames.some((name) => name.startsWith("snipara_"));
2358
+ const hasLegacyTools = toolNames.some((name) => name.startsWith("rlm_"));
2167
2359
  const checks = [
2168
2360
  {
2169
2361
  name: "hosted_connection",
2170
2362
  status: "pass",
2171
2363
  detail: "tools/list succeeded"
2364
+ },
2365
+ {
2366
+ name: "hosted_tool_aliases",
2367
+ status: hasSniparaTools ? "pass" : hasLegacyTools ? "warn" : "warn",
2368
+ detail: hasSniparaTools ? "snipara_* tools are exposed by Hosted MCP" : hasLegacyTools ? "Only legacy rlm_* tool aliases were detected; Hosted MCP is usable but naming is stale" : "tools/list succeeded, but expected snipara_* tools were not detected"
2172
2369
  }
2173
2370
  ];
2371
+ const settingsTool = hasSniparaTools ? "snipara_settings" : hasLegacyTools ? "rlm_settings" : "snipara_settings";
2174
2372
  const settingsResponse = await callHostedMcp(answers, "tools/call", {
2175
- name: "snipara_settings",
2373
+ name: settingsTool,
2176
2374
  arguments: {}
2177
2375
  });
2178
2376
  if (settingsResponse.ok && !settingsResponse.data.error) {
2179
2377
  checks.push({
2180
2378
  name: "hosted_settings",
2181
2379
  status: "pass",
2182
- detail: "snipara_settings tool call succeeded"
2380
+ detail: `${settingsTool} tool call succeeded`
2183
2381
  });
2184
2382
  } else {
2185
2383
  checks.push({
@@ -2200,6 +2398,15 @@ async function testHostedConnection(answers) {
2200
2398
  ];
2201
2399
  }
2202
2400
  }
2401
+ function extractMcpToolNames(data) {
2402
+ const tools = data.result?.tools;
2403
+ if (!Array.isArray(tools)) {
2404
+ return [];
2405
+ }
2406
+ return tools.map(
2407
+ (tool) => tool && typeof tool === "object" && "name" in tool ? String(tool.name || "") : ""
2408
+ ).filter(Boolean);
2409
+ }
2203
2410
  async function callHostedMcp(answers, method, params) {
2204
2411
  const response = await fetch(`${API_URL}/mcp/${answers.projectSlug}`, {
2205
2412
  method: "POST",
@@ -2251,6 +2458,39 @@ function describeJsonRpcError(data) {
2251
2458
  const code = data.error.code !== void 0 ? ` ${data.error.code}` : "";
2252
2459
  return `JSON-RPC error${code}: ${data.error.message || "unknown error"}`;
2253
2460
  }
2461
+ function getCheck(report, name) {
2462
+ return report.checks.find((check) => check.name === name);
2463
+ }
2464
+ function formatCheckStatus(check) {
2465
+ if (!check) {
2466
+ return "not checked";
2467
+ }
2468
+ if (check.status === "pass") {
2469
+ return `OK - ${check.detail}`;
2470
+ }
2471
+ if (check.status === "fail") {
2472
+ return `FAILED - ${check.detail}`;
2473
+ }
2474
+ return `NEEDS ATTENTION - ${check.detail}`;
2475
+ }
2476
+ function printSetupVerdict(answers, report) {
2477
+ const hostedConnection = getCheck(report, "hosted_connection");
2478
+ const toolAliases = getCheck(report, "hosted_tool_aliases");
2479
+ const claudeTools = getCheck(report, "claude_tools_visible");
2480
+ console.log(chalk.bold("\nSetup verdict:\n"));
2481
+ console.log(` Config written: ${answers.profile !== "runtime-only" ? "OK" : "not requested"}`);
2482
+ console.log(` Hosted MCP: ${formatCheckStatus(hostedConnection)}`);
2483
+ if (toolAliases) {
2484
+ console.log(` Tool aliases: ${formatCheckStatus(toolAliases)}`);
2485
+ }
2486
+ if (answers.aiClient === "claude-code" || answers.aiClient === "claude-desktop") {
2487
+ console.log(
2488
+ ` Claude loaded MCP: ${claudeTools ? formatCheckStatus(claudeTools) : "not verified"}`
2489
+ );
2490
+ } else {
2491
+ console.log(" AI client loaded MCP: not verifiable from this terminal");
2492
+ }
2493
+ }
2254
2494
  function printSuccess(answers, report) {
2255
2495
  console.log(
2256
2496
  chalk.green(`
@@ -2263,6 +2503,7 @@ function printSuccess(answers, report) {
2263
2503
  );
2264
2504
  console.log(chalk.bold("Installed profile:\n"));
2265
2505
  console.log(` ${chalk.green("\u2713")} ${answers.profile}`);
2506
+ printSetupVerdict(answers, report);
2266
2507
  console.log(chalk.bold("\nWhat was installed:\n"));
2267
2508
  if (answers.installMcp) {
2268
2509
  console.log(
@@ -2300,6 +2541,20 @@ function printSuccess(answers, report) {
2300
2541
  nextStep += 1;
2301
2542
  };
2302
2543
  printNextStep("Restart your AI client if you created or changed hosted MCP config.");
2544
+ if (answers.aiClient === "claude-code") {
2545
+ printNextStep(
2546
+ "For Claude Code, confirm Snipara appears in Settings -> MCP or ToolSearch; local files alone do not prove Claude loaded the server."
2547
+ );
2548
+ printNextStep("If Snipara tools are missing, run: npx create-snipara doctor --client claude");
2549
+ }
2550
+ if (answers.aiClient === "claude-desktop") {
2551
+ printNextStep(
2552
+ "For Claude Desktop, confirm the Snipara server appears in the desktop MCP settings after restart."
2553
+ );
2554
+ printNextStep(
2555
+ "If Snipara tools are missing, run: npx create-snipara doctor --client claude-desktop"
2556
+ );
2557
+ }
2303
2558
  if (answers.aiClient === "codex") {
2304
2559
  printNextStep(
2305
2560
  "For Codex, merge .snipara/templates/codex-config.toml into ~/.codex/config.toml if the app does not read project .codex/config.toml."
@@ -2365,8 +2620,16 @@ function commandExists(command) {
2365
2620
  return false;
2366
2621
  }
2367
2622
  }
2623
+ function getClaudeConfigPaths() {
2624
+ const desktopDir = process.platform === "darwin" ? path.join(homedir(), "Library", "Application Support", "Claude") : process.platform === "win32" ? path.join(homedir(), "AppData", "Roaming", "Claude") : path.join(homedir(), ".config", "claude");
2625
+ return {
2626
+ codeSettingsPath: path.join(homedir(), ".claude", "settings.json"),
2627
+ desktopConfigPath: path.join(desktopDir, "claude_desktop_config.json")
2628
+ };
2629
+ }
2368
2630
  function detectEnvironment() {
2369
2631
  const existingConfig = getExistingConfig();
2632
+ const claudePaths = getClaudeConfigPaths();
2370
2633
  return {
2371
2634
  cwd: process.cwd(),
2372
2635
  projectSlug: detectProjectSlug(),
@@ -2382,6 +2645,8 @@ function detectEnvironment() {
2382
2645
  codexConfig: fs.existsSync(path.join(process.cwd(), ".codex", "config.toml")),
2383
2646
  cursorRule: fs.existsSync(path.join(process.cwd(), ".cursor", "rules", "snipara.mdc")),
2384
2647
  claudeDir: fs.existsSync(path.join(homedir(), ".claude")),
2648
+ claudeSettings: fs.existsSync(claudePaths.codeSettingsPath),
2649
+ claudeDesktopConfig: fs.existsSync(claudePaths.desktopConfigPath),
2385
2650
  cursorDir: fs.existsSync(path.join(homedir(), ".cursor")),
2386
2651
  sniparaCompanionPack: fs.existsSync(path.join(process.cwd(), ".snipara", "companion")),
2387
2652
  sniparaTemplates: fs.existsSync(path.join(process.cwd(), ".snipara", "templates"))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-snipara",
3
- "version": "1.3.22",
3
+ "version": "1.3.24",
4
4
  "description": "Onboard Snipara Hosted MCP Context + Memory with auth, companion workflows, and optional Snipara Sandbox",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",