create-snipara 1.3.21 → 1.3.23
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/README.md +13 -0
- package/dist/index.js +334 -10
- 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
|
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,81 @@ import fs from "fs";
|
|
|
9
9
|
import path from "path";
|
|
10
10
|
import { execSync, spawn } from "child_process";
|
|
11
11
|
import { homedir } from "os";
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
// package.json
|
|
14
|
+
var package_default = {
|
|
15
|
+
name: "create-snipara",
|
|
16
|
+
version: "1.3.23",
|
|
17
|
+
description: "Onboard Snipara Hosted MCP Context + Memory with auth, companion workflows, and optional Snipara Sandbox",
|
|
18
|
+
main: "dist/index.js",
|
|
19
|
+
type: "module",
|
|
20
|
+
bin: {
|
|
21
|
+
"create-snipara": "dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
scripts: {
|
|
24
|
+
build: "tsup src/index.ts --format esm --dts --clean",
|
|
25
|
+
dev: "tsup src/index.ts --format esm --watch",
|
|
26
|
+
prepublishOnly: "npm run build",
|
|
27
|
+
pretest: "pnpm build",
|
|
28
|
+
test: "node --test test/*.test.cjs",
|
|
29
|
+
"pack:smoke": "bash ../../scripts/smoke-node-package.sh packages/create-snipara create-snipara create-snipara --help",
|
|
30
|
+
"type-check": "tsc --noEmit",
|
|
31
|
+
lint: "eslint src --ext .ts"
|
|
32
|
+
},
|
|
33
|
+
keywords: [
|
|
34
|
+
"snipara",
|
|
35
|
+
"create-snipara",
|
|
36
|
+
"mcp",
|
|
37
|
+
"snipara-sandbox",
|
|
38
|
+
"context-optimization",
|
|
39
|
+
"llm",
|
|
40
|
+
"ai-agents",
|
|
41
|
+
"multi-agent",
|
|
42
|
+
"memory",
|
|
43
|
+
"claude-code",
|
|
44
|
+
"codex",
|
|
45
|
+
"chatgpt",
|
|
46
|
+
"openai",
|
|
47
|
+
"cursor",
|
|
48
|
+
"windsurf",
|
|
49
|
+
"gemini",
|
|
50
|
+
"vscode",
|
|
51
|
+
"continue",
|
|
52
|
+
"claude-desktop"
|
|
53
|
+
],
|
|
54
|
+
author: "Snipara",
|
|
55
|
+
license: "MIT",
|
|
56
|
+
repository: {
|
|
57
|
+
type: "git",
|
|
58
|
+
url: "git+https://github.com/Snipara/create-snipara.git"
|
|
59
|
+
},
|
|
60
|
+
homepage: "https://snipara.com/docs/integration/create-snipara",
|
|
61
|
+
dependencies: {
|
|
62
|
+
chalk: "^5.3.0",
|
|
63
|
+
commander: "^12.1.0",
|
|
64
|
+
ora: "^8.0.1",
|
|
65
|
+
prompts: "^2.4.2"
|
|
66
|
+
},
|
|
67
|
+
devDependencies: {
|
|
68
|
+
"@eslint/js": "^9.39.3",
|
|
69
|
+
"@types/node": "^20.17.12",
|
|
70
|
+
"@types/prompts": "^2.4.9",
|
|
71
|
+
"@typescript-eslint/eslint-plugin": "^8.56.0",
|
|
72
|
+
"@typescript-eslint/parser": "^8.56.0",
|
|
73
|
+
eslint: "^9.39.3",
|
|
74
|
+
tsup: "^8.3.5",
|
|
75
|
+
typescript: "^5.7.2"
|
|
76
|
+
},
|
|
77
|
+
engines: {
|
|
78
|
+
node: ">=18"
|
|
79
|
+
},
|
|
80
|
+
files: [
|
|
81
|
+
"dist"
|
|
82
|
+
]
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// src/index.ts
|
|
86
|
+
var VERSION = package_default.version;
|
|
13
87
|
var BASE_URL = "https://www.snipara.com";
|
|
14
88
|
var API_URL = "https://api.snipara.com";
|
|
15
89
|
var COMPANION_PACKAGE_NAME = "snipara-companion";
|
|
@@ -100,7 +174,10 @@ function buildProgram() {
|
|
|
100
174
|
printBanner();
|
|
101
175
|
await runInit(options);
|
|
102
176
|
});
|
|
103
|
-
program.command("doctor").description("Inspect the current project and write a validation report").option(
|
|
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) => {
|
|
104
181
|
printBanner();
|
|
105
182
|
await runDoctor(options);
|
|
106
183
|
});
|
|
@@ -217,8 +294,16 @@ async function runInit(options) {
|
|
|
217
294
|
}
|
|
218
295
|
}
|
|
219
296
|
async function runDoctor(options) {
|
|
220
|
-
const
|
|
221
|
-
const
|
|
297
|
+
const requestedClient = normalizeClientOption(options.client);
|
|
298
|
+
const existingAnswers = loadExistingAnswers(options);
|
|
299
|
+
const answers = {
|
|
300
|
+
...existingAnswers,
|
|
301
|
+
aiClient: requestedClient || existingAnswers.aiClient
|
|
302
|
+
};
|
|
303
|
+
const report = await runValidation(answers, true, {
|
|
304
|
+
client: requestedClient || answers.aiClient,
|
|
305
|
+
includeNpmFreshness: !options.skipNpmCheck
|
|
306
|
+
});
|
|
222
307
|
writeDoctorReport(report);
|
|
223
308
|
if (options.json) {
|
|
224
309
|
console.log(JSON.stringify({ detection: detectEnvironment(), validation: report }, null, 2));
|
|
@@ -557,6 +642,34 @@ function resolveRequestedProfile(options) {
|
|
|
557
642
|
function isInstallProfile(value) {
|
|
558
643
|
return ["hosted-only", "hosted-companion", "full-stack", "runtime-only"].includes(value);
|
|
559
644
|
}
|
|
645
|
+
function normalizeClientOption(value) {
|
|
646
|
+
if (!value) {
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
const normalized = value.trim().toLowerCase();
|
|
650
|
+
const aliases = {
|
|
651
|
+
claude: "claude-code",
|
|
652
|
+
"claude-code": "claude-code",
|
|
653
|
+
claude_code: "claude-code",
|
|
654
|
+
claudecli: "claude-code",
|
|
655
|
+
"claude-cli": "claude-code",
|
|
656
|
+
"claude-desktop": "claude-desktop",
|
|
657
|
+
claude_desktop: "claude-desktop",
|
|
658
|
+
cursor: "cursor",
|
|
659
|
+
windsurf: "windsurf",
|
|
660
|
+
codex: "codex",
|
|
661
|
+
gemini: "gemini",
|
|
662
|
+
chatgpt: "chatgpt",
|
|
663
|
+
vscode: "vscode",
|
|
664
|
+
continue: "continue",
|
|
665
|
+
other: "other"
|
|
666
|
+
};
|
|
667
|
+
const client = aliases[normalized];
|
|
668
|
+
if (!client) {
|
|
669
|
+
throw new Error(`Unknown client '${value}'. Use claude, claude-code, cursor, codex, or other.`);
|
|
670
|
+
}
|
|
671
|
+
return client;
|
|
672
|
+
}
|
|
560
673
|
function installProfileChoices() {
|
|
561
674
|
return [
|
|
562
675
|
{
|
|
@@ -1970,15 +2083,143 @@ function buildGitHubAutomationUrl(answers) {
|
|
|
1970
2083
|
}
|
|
1971
2084
|
return url.toString();
|
|
1972
2085
|
}
|
|
1973
|
-
|
|
2086
|
+
function getClaudeClientChecks(answers, detection) {
|
|
2087
|
+
const checks = [];
|
|
2088
|
+
const claudePaths = getClaudeConfigPaths();
|
|
2089
|
+
const projectConfig = readJsonFile(path.join(process.cwd(), ".mcp.json"));
|
|
2090
|
+
const codeSettings = readJsonFile(claudePaths.codeSettingsPath);
|
|
2091
|
+
const desktopConfig = readJsonFile(claudePaths.desktopConfigPath);
|
|
2092
|
+
const projectHasSnipara = containsSniparaMcpReference(projectConfig);
|
|
2093
|
+
const codeSettingsHasSnipara = containsSniparaMcpReference(codeSettings);
|
|
2094
|
+
const desktopHasSnipara = containsSniparaMcpReference(desktopConfig);
|
|
2095
|
+
checks.push({
|
|
2096
|
+
name: "claude_project_config",
|
|
2097
|
+
status: projectHasSnipara ? "pass" : "warn",
|
|
2098
|
+
detail: projectHasSnipara ? "Project .mcp.json contains a Snipara Hosted MCP server" : "Project .mcp.json does not contain a Snipara Hosted MCP server"
|
|
2099
|
+
});
|
|
2100
|
+
if (answers.aiClient === "claude-code") {
|
|
2101
|
+
checks.push({
|
|
2102
|
+
name: "claude_code_settings",
|
|
2103
|
+
status: detection.files.claudeSettings ? codeSettingsHasSnipara ? "pass" : "warn" : "warn",
|
|
2104
|
+
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"
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
if (answers.aiClient === "claude-desktop") {
|
|
2108
|
+
checks.push({
|
|
2109
|
+
name: "claude_desktop_config",
|
|
2110
|
+
status: detection.files.claudeDesktopConfig ? desktopHasSnipara ? "pass" : "warn" : "warn",
|
|
2111
|
+
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"
|
|
2112
|
+
});
|
|
2113
|
+
}
|
|
2114
|
+
checks.push({
|
|
2115
|
+
name: "claude_tools_visible",
|
|
2116
|
+
status: "warn",
|
|
2117
|
+
detail: "This terminal cannot prove Claude loaded the MCP server; confirm Snipara tools in Claude Settings -> MCP or ToolSearch after restart"
|
|
2118
|
+
});
|
|
2119
|
+
return checks;
|
|
2120
|
+
}
|
|
2121
|
+
function readJsonFile(filePath) {
|
|
2122
|
+
if (!fs.existsSync(filePath)) {
|
|
2123
|
+
return null;
|
|
2124
|
+
}
|
|
2125
|
+
try {
|
|
2126
|
+
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
2127
|
+
} catch {
|
|
2128
|
+
return null;
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
function containsSniparaMcpReference(value) {
|
|
2132
|
+
if (value === null || value === void 0) {
|
|
2133
|
+
return false;
|
|
2134
|
+
}
|
|
2135
|
+
if (typeof value === "string") {
|
|
2136
|
+
return value.includes("api.snipara.com/mcp") || value.includes("snipara-mcp");
|
|
2137
|
+
}
|
|
2138
|
+
if (Array.isArray(value)) {
|
|
2139
|
+
return value.some((item) => containsSniparaMcpReference(item));
|
|
2140
|
+
}
|
|
2141
|
+
if (typeof value === "object") {
|
|
2142
|
+
const record = value;
|
|
2143
|
+
const mcpServers = record.mcpServers;
|
|
2144
|
+
if (mcpServers && typeof mcpServers === "object" && "snipara" in mcpServers) {
|
|
2145
|
+
return true;
|
|
2146
|
+
}
|
|
2147
|
+
return Object.values(record).some((nested) => containsSniparaMcpReference(nested));
|
|
2148
|
+
}
|
|
2149
|
+
return false;
|
|
2150
|
+
}
|
|
2151
|
+
function getCreateSniparaPackageFreshnessCheck() {
|
|
2152
|
+
if (!commandExists("npm")) {
|
|
2153
|
+
return {
|
|
2154
|
+
name: "create_snipara_npm_version",
|
|
2155
|
+
status: "warn",
|
|
2156
|
+
detail: "npm not found; could not compare local create-snipara with npm latest"
|
|
2157
|
+
};
|
|
2158
|
+
}
|
|
2159
|
+
try {
|
|
2160
|
+
const raw = execSync("npm view create-snipara version --json", {
|
|
2161
|
+
encoding: "utf-8",
|
|
2162
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
2163
|
+
shell: "/bin/sh",
|
|
2164
|
+
timeout: 4e3
|
|
2165
|
+
}).trim();
|
|
2166
|
+
const latest = raw.replace(/^"|"$/g, "");
|
|
2167
|
+
const comparison = compareSemver(VERSION, latest);
|
|
2168
|
+
if (comparison === 0) {
|
|
2169
|
+
return {
|
|
2170
|
+
name: "create_snipara_npm_version",
|
|
2171
|
+
status: "pass",
|
|
2172
|
+
detail: `Local package version ${VERSION} matches npm latest`
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
if (comparison > 0) {
|
|
2176
|
+
return {
|
|
2177
|
+
name: "create_snipara_npm_version",
|
|
2178
|
+
status: "warn",
|
|
2179
|
+
detail: `Local package version ${VERSION} is newer than npm latest ${latest}; publish may be pending`
|
|
2180
|
+
};
|
|
2181
|
+
}
|
|
2182
|
+
return {
|
|
2183
|
+
name: "create_snipara_npm_version",
|
|
2184
|
+
status: "warn",
|
|
2185
|
+
detail: `npm latest is ${latest}; rerun with npx create-snipara@latest if this local copy is older`
|
|
2186
|
+
};
|
|
2187
|
+
} catch {
|
|
2188
|
+
return {
|
|
2189
|
+
name: "create_snipara_npm_version",
|
|
2190
|
+
status: "warn",
|
|
2191
|
+
detail: "Could not reach npm to compare create-snipara latest version"
|
|
2192
|
+
};
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
function compareSemver(left, right) {
|
|
2196
|
+
const leftParts = left.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
2197
|
+
const rightParts = right.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
2198
|
+
const length = Math.max(leftParts.length, rightParts.length);
|
|
2199
|
+
for (let index = 0; index < length; index += 1) {
|
|
2200
|
+
const diff = (leftParts[index] || 0) - (rightParts[index] || 0);
|
|
2201
|
+
if (diff !== 0) {
|
|
2202
|
+
return diff > 0 ? 1 : -1;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
return 0;
|
|
2206
|
+
}
|
|
2207
|
+
async function runValidation(answers, includeHostedCheck, options = {}) {
|
|
1974
2208
|
console.log(chalk.bold("\n\u{1FA7A} Running Validation\n"));
|
|
1975
2209
|
const checks = [];
|
|
1976
2210
|
const detection = detectEnvironment();
|
|
2211
|
+
const targetClient = options.client || answers.aiClient;
|
|
2212
|
+
const effectiveAnswers = { ...answers, aiClient: targetClient };
|
|
1977
2213
|
checks.push({
|
|
1978
2214
|
name: "project_slug",
|
|
1979
2215
|
status: answers.projectSlug ? "pass" : "fail",
|
|
1980
2216
|
detail: answers.projectSlug || "Project slug missing"
|
|
1981
2217
|
});
|
|
2218
|
+
checks.push({
|
|
2219
|
+
name: "target_client",
|
|
2220
|
+
status: "pass",
|
|
2221
|
+
detail: getClientDisplayName(targetClient)
|
|
2222
|
+
});
|
|
1982
2223
|
checks.push({
|
|
1983
2224
|
name: "mcp_config",
|
|
1984
2225
|
status: detection.files.mcpConfig ? "pass" : "warn",
|
|
@@ -2016,9 +2257,15 @@ async function runValidation(answers, includeHostedCheck) {
|
|
|
2016
2257
|
});
|
|
2017
2258
|
checks.push({
|
|
2018
2259
|
name: "hooks",
|
|
2019
|
-
status: answers.installHooks &&
|
|
2020
|
-
detail: answers.installHooks &&
|
|
2260
|
+
status: answers.installHooks && targetClient === "claude-code" ? detection.files.claudeDir ? "pass" : "warn" : "pass",
|
|
2261
|
+
detail: answers.installHooks && targetClient === "claude-code" ? detection.files.claudeDir ? "~/.claude detected" : "~/.claude missing" : "Hooks not requested"
|
|
2021
2262
|
});
|
|
2263
|
+
if (targetClient === "claude-code" || targetClient === "claude-desktop") {
|
|
2264
|
+
checks.push(...getClaudeClientChecks(effectiveAnswers, detection));
|
|
2265
|
+
}
|
|
2266
|
+
if (options.includeNpmFreshness) {
|
|
2267
|
+
checks.push(getCreateSniparaPackageFreshnessCheck());
|
|
2268
|
+
}
|
|
2022
2269
|
const githubRepo = answers.githubRepo || detectGitRepository();
|
|
2023
2270
|
checks.push({
|
|
2024
2271
|
name: "github_answer_packs",
|
|
@@ -2051,11 +2298,12 @@ function writeDoctorReport(report) {
|
|
|
2051
2298
|
console.log(chalk.green(" \u2713 Wrote .snipara/companion/doctor.json"));
|
|
2052
2299
|
}
|
|
2053
2300
|
function printDoctorReport(detection, report) {
|
|
2301
|
+
const targetClient = report.checks.find((check) => check.name === "target_client")?.detail || detection.aiClient;
|
|
2054
2302
|
console.log(chalk.bold("\n\u{1FA7A} Snipara Doctor\n"));
|
|
2055
2303
|
console.log(
|
|
2056
2304
|
` Project slug: ${detection.existingConfig.slug || detection.projectSlug || "unknown"}`
|
|
2057
2305
|
);
|
|
2058
|
-
console.log(` AI client: ${
|
|
2306
|
+
console.log(` AI client: ${targetClient}`);
|
|
2059
2307
|
console.log(` In git repo: ${detection.inGitRepo ? "yes" : "no"}`);
|
|
2060
2308
|
console.log(` Profile: ${report.profile}`);
|
|
2061
2309
|
console.log("");
|
|
@@ -2090,22 +2338,31 @@ async function testHostedConnection(answers) {
|
|
|
2090
2338
|
];
|
|
2091
2339
|
}
|
|
2092
2340
|
spinner.succeed("Connected to Snipara Hosted MCP.");
|
|
2341
|
+
const toolNames = extractMcpToolNames(toolsResponse.data);
|
|
2342
|
+
const hasSniparaTools = toolNames.some((name) => name.startsWith("snipara_"));
|
|
2343
|
+
const hasLegacyTools = toolNames.some((name) => name.startsWith("rlm_"));
|
|
2093
2344
|
const checks = [
|
|
2094
2345
|
{
|
|
2095
2346
|
name: "hosted_connection",
|
|
2096
2347
|
status: "pass",
|
|
2097
2348
|
detail: "tools/list succeeded"
|
|
2349
|
+
},
|
|
2350
|
+
{
|
|
2351
|
+
name: "hosted_tool_aliases",
|
|
2352
|
+
status: hasSniparaTools ? "pass" : hasLegacyTools ? "warn" : "warn",
|
|
2353
|
+
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"
|
|
2098
2354
|
}
|
|
2099
2355
|
];
|
|
2356
|
+
const settingsTool = hasSniparaTools ? "snipara_settings" : hasLegacyTools ? "rlm_settings" : "snipara_settings";
|
|
2100
2357
|
const settingsResponse = await callHostedMcp(answers, "tools/call", {
|
|
2101
|
-
name:
|
|
2358
|
+
name: settingsTool,
|
|
2102
2359
|
arguments: {}
|
|
2103
2360
|
});
|
|
2104
2361
|
if (settingsResponse.ok && !settingsResponse.data.error) {
|
|
2105
2362
|
checks.push({
|
|
2106
2363
|
name: "hosted_settings",
|
|
2107
2364
|
status: "pass",
|
|
2108
|
-
detail:
|
|
2365
|
+
detail: `${settingsTool} tool call succeeded`
|
|
2109
2366
|
});
|
|
2110
2367
|
} else {
|
|
2111
2368
|
checks.push({
|
|
@@ -2126,6 +2383,15 @@ async function testHostedConnection(answers) {
|
|
|
2126
2383
|
];
|
|
2127
2384
|
}
|
|
2128
2385
|
}
|
|
2386
|
+
function extractMcpToolNames(data) {
|
|
2387
|
+
const tools = data.result?.tools;
|
|
2388
|
+
if (!Array.isArray(tools)) {
|
|
2389
|
+
return [];
|
|
2390
|
+
}
|
|
2391
|
+
return tools.map(
|
|
2392
|
+
(tool) => tool && typeof tool === "object" && "name" in tool ? String(tool.name || "") : ""
|
|
2393
|
+
).filter(Boolean);
|
|
2394
|
+
}
|
|
2129
2395
|
async function callHostedMcp(answers, method, params) {
|
|
2130
2396
|
const response = await fetch(`${API_URL}/mcp/${answers.projectSlug}`, {
|
|
2131
2397
|
method: "POST",
|
|
@@ -2177,6 +2443,39 @@ function describeJsonRpcError(data) {
|
|
|
2177
2443
|
const code = data.error.code !== void 0 ? ` ${data.error.code}` : "";
|
|
2178
2444
|
return `JSON-RPC error${code}: ${data.error.message || "unknown error"}`;
|
|
2179
2445
|
}
|
|
2446
|
+
function getCheck(report, name) {
|
|
2447
|
+
return report.checks.find((check) => check.name === name);
|
|
2448
|
+
}
|
|
2449
|
+
function formatCheckStatus(check) {
|
|
2450
|
+
if (!check) {
|
|
2451
|
+
return "not checked";
|
|
2452
|
+
}
|
|
2453
|
+
if (check.status === "pass") {
|
|
2454
|
+
return `OK - ${check.detail}`;
|
|
2455
|
+
}
|
|
2456
|
+
if (check.status === "fail") {
|
|
2457
|
+
return `FAILED - ${check.detail}`;
|
|
2458
|
+
}
|
|
2459
|
+
return `NEEDS ATTENTION - ${check.detail}`;
|
|
2460
|
+
}
|
|
2461
|
+
function printSetupVerdict(answers, report) {
|
|
2462
|
+
const hostedConnection = getCheck(report, "hosted_connection");
|
|
2463
|
+
const toolAliases = getCheck(report, "hosted_tool_aliases");
|
|
2464
|
+
const claudeTools = getCheck(report, "claude_tools_visible");
|
|
2465
|
+
console.log(chalk.bold("\nSetup verdict:\n"));
|
|
2466
|
+
console.log(` Config written: ${answers.profile !== "runtime-only" ? "OK" : "not requested"}`);
|
|
2467
|
+
console.log(` Hosted MCP: ${formatCheckStatus(hostedConnection)}`);
|
|
2468
|
+
if (toolAliases) {
|
|
2469
|
+
console.log(` Tool aliases: ${formatCheckStatus(toolAliases)}`);
|
|
2470
|
+
}
|
|
2471
|
+
if (answers.aiClient === "claude-code" || answers.aiClient === "claude-desktop") {
|
|
2472
|
+
console.log(
|
|
2473
|
+
` Claude loaded MCP: ${claudeTools ? formatCheckStatus(claudeTools) : "not verified"}`
|
|
2474
|
+
);
|
|
2475
|
+
} else {
|
|
2476
|
+
console.log(" AI client loaded MCP: not verifiable from this terminal");
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2180
2479
|
function printSuccess(answers, report) {
|
|
2181
2480
|
console.log(
|
|
2182
2481
|
chalk.green(`
|
|
@@ -2189,6 +2488,7 @@ function printSuccess(answers, report) {
|
|
|
2189
2488
|
);
|
|
2190
2489
|
console.log(chalk.bold("Installed profile:\n"));
|
|
2191
2490
|
console.log(` ${chalk.green("\u2713")} ${answers.profile}`);
|
|
2491
|
+
printSetupVerdict(answers, report);
|
|
2192
2492
|
console.log(chalk.bold("\nWhat was installed:\n"));
|
|
2193
2493
|
if (answers.installMcp) {
|
|
2194
2494
|
console.log(
|
|
@@ -2226,6 +2526,20 @@ function printSuccess(answers, report) {
|
|
|
2226
2526
|
nextStep += 1;
|
|
2227
2527
|
};
|
|
2228
2528
|
printNextStep("Restart your AI client if you created or changed hosted MCP config.");
|
|
2529
|
+
if (answers.aiClient === "claude-code") {
|
|
2530
|
+
printNextStep(
|
|
2531
|
+
"For Claude Code, confirm Snipara appears in Settings -> MCP or ToolSearch; local files alone do not prove Claude loaded the server."
|
|
2532
|
+
);
|
|
2533
|
+
printNextStep("If Snipara tools are missing, run: npx create-snipara doctor --client claude");
|
|
2534
|
+
}
|
|
2535
|
+
if (answers.aiClient === "claude-desktop") {
|
|
2536
|
+
printNextStep(
|
|
2537
|
+
"For Claude Desktop, confirm the Snipara server appears in the desktop MCP settings after restart."
|
|
2538
|
+
);
|
|
2539
|
+
printNextStep(
|
|
2540
|
+
"If Snipara tools are missing, run: npx create-snipara doctor --client claude-desktop"
|
|
2541
|
+
);
|
|
2542
|
+
}
|
|
2229
2543
|
if (answers.aiClient === "codex") {
|
|
2230
2544
|
printNextStep(
|
|
2231
2545
|
"For Codex, merge .snipara/templates/codex-config.toml into ~/.codex/config.toml if the app does not read project .codex/config.toml."
|
|
@@ -2291,8 +2605,16 @@ function commandExists(command) {
|
|
|
2291
2605
|
return false;
|
|
2292
2606
|
}
|
|
2293
2607
|
}
|
|
2608
|
+
function getClaudeConfigPaths() {
|
|
2609
|
+
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");
|
|
2610
|
+
return {
|
|
2611
|
+
codeSettingsPath: path.join(homedir(), ".claude", "settings.json"),
|
|
2612
|
+
desktopConfigPath: path.join(desktopDir, "claude_desktop_config.json")
|
|
2613
|
+
};
|
|
2614
|
+
}
|
|
2294
2615
|
function detectEnvironment() {
|
|
2295
2616
|
const existingConfig = getExistingConfig();
|
|
2617
|
+
const claudePaths = getClaudeConfigPaths();
|
|
2296
2618
|
return {
|
|
2297
2619
|
cwd: process.cwd(),
|
|
2298
2620
|
projectSlug: detectProjectSlug(),
|
|
@@ -2308,6 +2630,8 @@ function detectEnvironment() {
|
|
|
2308
2630
|
codexConfig: fs.existsSync(path.join(process.cwd(), ".codex", "config.toml")),
|
|
2309
2631
|
cursorRule: fs.existsSync(path.join(process.cwd(), ".cursor", "rules", "snipara.mdc")),
|
|
2310
2632
|
claudeDir: fs.existsSync(path.join(homedir(), ".claude")),
|
|
2633
|
+
claudeSettings: fs.existsSync(claudePaths.codeSettingsPath),
|
|
2634
|
+
claudeDesktopConfig: fs.existsSync(claudePaths.desktopConfigPath),
|
|
2311
2635
|
cursorDir: fs.existsSync(path.join(homedir(), ".cursor")),
|
|
2312
2636
|
sniparaCompanionPack: fs.existsSync(path.join(process.cwd(), ".snipara", "companion")),
|
|
2313
2637
|
sniparaTemplates: fs.existsSync(path.join(process.cwd(), ".snipara", "templates"))
|
package/package.json
CHANGED