create-snipara 1.3.22 → 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 +260 -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
|
@@ -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.
|
|
16
|
+
version: "1.3.23",
|
|
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",
|
|
@@ -174,7 +174,10 @@ function buildProgram() {
|
|
|
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(
|
|
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
|
});
|
|
@@ -291,8 +294,16 @@ async function runInit(options) {
|
|
|
291
294
|
}
|
|
292
295
|
}
|
|
293
296
|
async function runDoctor(options) {
|
|
294
|
-
const
|
|
295
|
-
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
|
+
});
|
|
296
307
|
writeDoctorReport(report);
|
|
297
308
|
if (options.json) {
|
|
298
309
|
console.log(JSON.stringify({ detection: detectEnvironment(), validation: report }, null, 2));
|
|
@@ -631,6 +642,34 @@ function resolveRequestedProfile(options) {
|
|
|
631
642
|
function isInstallProfile(value) {
|
|
632
643
|
return ["hosted-only", "hosted-companion", "full-stack", "runtime-only"].includes(value);
|
|
633
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
|
+
}
|
|
634
673
|
function installProfileChoices() {
|
|
635
674
|
return [
|
|
636
675
|
{
|
|
@@ -2044,15 +2083,143 @@ function buildGitHubAutomationUrl(answers) {
|
|
|
2044
2083
|
}
|
|
2045
2084
|
return url.toString();
|
|
2046
2085
|
}
|
|
2047
|
-
|
|
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 = {}) {
|
|
2048
2208
|
console.log(chalk.bold("\n\u{1FA7A} Running Validation\n"));
|
|
2049
2209
|
const checks = [];
|
|
2050
2210
|
const detection = detectEnvironment();
|
|
2211
|
+
const targetClient = options.client || answers.aiClient;
|
|
2212
|
+
const effectiveAnswers = { ...answers, aiClient: targetClient };
|
|
2051
2213
|
checks.push({
|
|
2052
2214
|
name: "project_slug",
|
|
2053
2215
|
status: answers.projectSlug ? "pass" : "fail",
|
|
2054
2216
|
detail: answers.projectSlug || "Project slug missing"
|
|
2055
2217
|
});
|
|
2218
|
+
checks.push({
|
|
2219
|
+
name: "target_client",
|
|
2220
|
+
status: "pass",
|
|
2221
|
+
detail: getClientDisplayName(targetClient)
|
|
2222
|
+
});
|
|
2056
2223
|
checks.push({
|
|
2057
2224
|
name: "mcp_config",
|
|
2058
2225
|
status: detection.files.mcpConfig ? "pass" : "warn",
|
|
@@ -2090,9 +2257,15 @@ async function runValidation(answers, includeHostedCheck) {
|
|
|
2090
2257
|
});
|
|
2091
2258
|
checks.push({
|
|
2092
2259
|
name: "hooks",
|
|
2093
|
-
status: answers.installHooks &&
|
|
2094
|
-
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"
|
|
2095
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
|
+
}
|
|
2096
2269
|
const githubRepo = answers.githubRepo || detectGitRepository();
|
|
2097
2270
|
checks.push({
|
|
2098
2271
|
name: "github_answer_packs",
|
|
@@ -2125,11 +2298,12 @@ function writeDoctorReport(report) {
|
|
|
2125
2298
|
console.log(chalk.green(" \u2713 Wrote .snipara/companion/doctor.json"));
|
|
2126
2299
|
}
|
|
2127
2300
|
function printDoctorReport(detection, report) {
|
|
2301
|
+
const targetClient = report.checks.find((check) => check.name === "target_client")?.detail || detection.aiClient;
|
|
2128
2302
|
console.log(chalk.bold("\n\u{1FA7A} Snipara Doctor\n"));
|
|
2129
2303
|
console.log(
|
|
2130
2304
|
` Project slug: ${detection.existingConfig.slug || detection.projectSlug || "unknown"}`
|
|
2131
2305
|
);
|
|
2132
|
-
console.log(` AI client: ${
|
|
2306
|
+
console.log(` AI client: ${targetClient}`);
|
|
2133
2307
|
console.log(` In git repo: ${detection.inGitRepo ? "yes" : "no"}`);
|
|
2134
2308
|
console.log(` Profile: ${report.profile}`);
|
|
2135
2309
|
console.log("");
|
|
@@ -2164,22 +2338,31 @@ async function testHostedConnection(answers) {
|
|
|
2164
2338
|
];
|
|
2165
2339
|
}
|
|
2166
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_"));
|
|
2167
2344
|
const checks = [
|
|
2168
2345
|
{
|
|
2169
2346
|
name: "hosted_connection",
|
|
2170
2347
|
status: "pass",
|
|
2171
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"
|
|
2172
2354
|
}
|
|
2173
2355
|
];
|
|
2356
|
+
const settingsTool = hasSniparaTools ? "snipara_settings" : hasLegacyTools ? "rlm_settings" : "snipara_settings";
|
|
2174
2357
|
const settingsResponse = await callHostedMcp(answers, "tools/call", {
|
|
2175
|
-
name:
|
|
2358
|
+
name: settingsTool,
|
|
2176
2359
|
arguments: {}
|
|
2177
2360
|
});
|
|
2178
2361
|
if (settingsResponse.ok && !settingsResponse.data.error) {
|
|
2179
2362
|
checks.push({
|
|
2180
2363
|
name: "hosted_settings",
|
|
2181
2364
|
status: "pass",
|
|
2182
|
-
detail:
|
|
2365
|
+
detail: `${settingsTool} tool call succeeded`
|
|
2183
2366
|
});
|
|
2184
2367
|
} else {
|
|
2185
2368
|
checks.push({
|
|
@@ -2200,6 +2383,15 @@ async function testHostedConnection(answers) {
|
|
|
2200
2383
|
];
|
|
2201
2384
|
}
|
|
2202
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
|
+
}
|
|
2203
2395
|
async function callHostedMcp(answers, method, params) {
|
|
2204
2396
|
const response = await fetch(`${API_URL}/mcp/${answers.projectSlug}`, {
|
|
2205
2397
|
method: "POST",
|
|
@@ -2251,6 +2443,39 @@ function describeJsonRpcError(data) {
|
|
|
2251
2443
|
const code = data.error.code !== void 0 ? ` ${data.error.code}` : "";
|
|
2252
2444
|
return `JSON-RPC error${code}: ${data.error.message || "unknown error"}`;
|
|
2253
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
|
+
}
|
|
2254
2479
|
function printSuccess(answers, report) {
|
|
2255
2480
|
console.log(
|
|
2256
2481
|
chalk.green(`
|
|
@@ -2263,6 +2488,7 @@ function printSuccess(answers, report) {
|
|
|
2263
2488
|
);
|
|
2264
2489
|
console.log(chalk.bold("Installed profile:\n"));
|
|
2265
2490
|
console.log(` ${chalk.green("\u2713")} ${answers.profile}`);
|
|
2491
|
+
printSetupVerdict(answers, report);
|
|
2266
2492
|
console.log(chalk.bold("\nWhat was installed:\n"));
|
|
2267
2493
|
if (answers.installMcp) {
|
|
2268
2494
|
console.log(
|
|
@@ -2300,6 +2526,20 @@ function printSuccess(answers, report) {
|
|
|
2300
2526
|
nextStep += 1;
|
|
2301
2527
|
};
|
|
2302
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
|
+
}
|
|
2303
2543
|
if (answers.aiClient === "codex") {
|
|
2304
2544
|
printNextStep(
|
|
2305
2545
|
"For Codex, merge .snipara/templates/codex-config.toml into ~/.codex/config.toml if the app does not read project .codex/config.toml."
|
|
@@ -2365,8 +2605,16 @@ function commandExists(command) {
|
|
|
2365
2605
|
return false;
|
|
2366
2606
|
}
|
|
2367
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
|
+
}
|
|
2368
2615
|
function detectEnvironment() {
|
|
2369
2616
|
const existingConfig = getExistingConfig();
|
|
2617
|
+
const claudePaths = getClaudeConfigPaths();
|
|
2370
2618
|
return {
|
|
2371
2619
|
cwd: process.cwd(),
|
|
2372
2620
|
projectSlug: detectProjectSlug(),
|
|
@@ -2382,6 +2630,8 @@ function detectEnvironment() {
|
|
|
2382
2630
|
codexConfig: fs.existsSync(path.join(process.cwd(), ".codex", "config.toml")),
|
|
2383
2631
|
cursorRule: fs.existsSync(path.join(process.cwd(), ".cursor", "rules", "snipara.mdc")),
|
|
2384
2632
|
claudeDir: fs.existsSync(path.join(homedir(), ".claude")),
|
|
2633
|
+
claudeSettings: fs.existsSync(claudePaths.codeSettingsPath),
|
|
2634
|
+
claudeDesktopConfig: fs.existsSync(claudePaths.desktopConfigPath),
|
|
2385
2635
|
cursorDir: fs.existsSync(path.join(homedir(), ".cursor")),
|
|
2386
2636
|
sniparaCompanionPack: fs.existsSync(path.join(process.cwd(), ".snipara", "companion")),
|
|
2387
2637
|
sniparaTemplates: fs.existsSync(path.join(process.cwd(), ".snipara", "templates"))
|
package/package.json
CHANGED