conare 0.3.8 → 0.4.0
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/dist/index.js +308 -167
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1575,27 +1575,23 @@ async function countCursorSessions(dbPath) {
|
|
|
1575
1575
|
}
|
|
1576
1576
|
async function detect() {
|
|
1577
1577
|
const home = homedir();
|
|
1578
|
+
const os = platform();
|
|
1578
1579
|
const tools = [];
|
|
1579
1580
|
const claudeDir = join(home, ".claude", "projects");
|
|
1580
1581
|
if (existsSync(claudeDir)) {
|
|
1581
1582
|
const sessionCount = countJsonlFiles(claudeDir);
|
|
1582
|
-
tools.push({
|
|
1583
|
-
name: "Claude Code",
|
|
1584
|
-
available: sessionCount > 0,
|
|
1585
|
-
path: claudeDir,
|
|
1586
|
-
sessionCount
|
|
1587
|
-
});
|
|
1583
|
+
tools.push({ name: "Claude Code", id: "claude", available: sessionCount > 0, path: claudeDir, sessionCount });
|
|
1588
1584
|
} else {
|
|
1589
|
-
tools.push({ name: "Claude Code", available: false, path: claudeDir, sessionCount: 0 });
|
|
1585
|
+
tools.push({ name: "Claude Code", id: "claude", available: false, path: claudeDir, sessionCount: 0 });
|
|
1590
1586
|
}
|
|
1587
|
+
const codexConfig = join(home, ".codex", "config.toml");
|
|
1591
1588
|
const codexHistory = join(home, ".codex", "history.jsonl");
|
|
1592
1589
|
const codexSessions = join(home, ".codex", "sessions");
|
|
1593
|
-
if (existsSync(codexHistory) || existsSync(codexSessions)) {
|
|
1590
|
+
if (existsSync(codexConfig) || existsSync(codexHistory) || existsSync(codexSessions)) {
|
|
1594
1591
|
let sessionCount = 0;
|
|
1595
1592
|
if (existsSync(codexHistory)) {
|
|
1596
1593
|
try {
|
|
1597
|
-
const
|
|
1598
|
-
const lines = readFileSync2(codexHistory, "utf-8").split(`
|
|
1594
|
+
const lines = readFileSync(codexHistory, "utf-8").split(`
|
|
1599
1595
|
`).filter(Boolean);
|
|
1600
1596
|
const sessions = new Set(lines.map((l) => {
|
|
1601
1597
|
try {
|
|
@@ -1608,16 +1604,10 @@ async function detect() {
|
|
|
1608
1604
|
sessionCount = sessions.size;
|
|
1609
1605
|
} catch {}
|
|
1610
1606
|
}
|
|
1611
|
-
tools.push({
|
|
1612
|
-
name: "Codex",
|
|
1613
|
-
available: true,
|
|
1614
|
-
path: existsSync(codexHistory) ? codexHistory : codexSessions,
|
|
1615
|
-
sessionCount
|
|
1616
|
-
});
|
|
1607
|
+
tools.push({ name: "Codex", id: "codex", available: true, path: codexConfig, sessionCount });
|
|
1617
1608
|
} else {
|
|
1618
|
-
tools.push({ name: "Codex", available: false, path:
|
|
1609
|
+
tools.push({ name: "Codex", id: "codex", available: false, path: codexConfig, sessionCount: 0 });
|
|
1619
1610
|
}
|
|
1620
|
-
const os = platform();
|
|
1621
1611
|
let cursorDbPath;
|
|
1622
1612
|
if (os === "darwin") {
|
|
1623
1613
|
cursorDbPath = join(home, "Library", "Application Support", "Cursor", "User", "globalStorage", "state.vscdb");
|
|
@@ -1628,10 +1618,65 @@ async function detect() {
|
|
|
1628
1618
|
}
|
|
1629
1619
|
tools.push({
|
|
1630
1620
|
name: "Cursor",
|
|
1621
|
+
id: "cursor",
|
|
1631
1622
|
available: existsSync(cursorDbPath),
|
|
1632
1623
|
path: cursorDbPath,
|
|
1633
1624
|
sessionCount: existsSync(cursorDbPath) ? await countCursorSessions(cursorDbPath) : 0
|
|
1634
1625
|
});
|
|
1626
|
+
const windsurfDir = join(home, ".codeium", "windsurf");
|
|
1627
|
+
tools.push({
|
|
1628
|
+
name: "Windsurf",
|
|
1629
|
+
id: "windsurf",
|
|
1630
|
+
available: existsSync(windsurfDir),
|
|
1631
|
+
path: join(windsurfDir, "mcp_config.json"),
|
|
1632
|
+
sessionCount: 0
|
|
1633
|
+
});
|
|
1634
|
+
let vscodePath;
|
|
1635
|
+
if (os === "darwin") {
|
|
1636
|
+
vscodePath = join(home, "Library", "Application Support", "Code");
|
|
1637
|
+
} else if (os === "win32") {
|
|
1638
|
+
vscodePath = join(process.env.APPDATA || join(home, "AppData", "Roaming"), "Code");
|
|
1639
|
+
} else {
|
|
1640
|
+
vscodePath = join(home, ".config", "Code");
|
|
1641
|
+
}
|
|
1642
|
+
tools.push({
|
|
1643
|
+
name: "VS Code Copilot",
|
|
1644
|
+
id: "vscode",
|
|
1645
|
+
available: existsSync(vscodePath),
|
|
1646
|
+
path: join(vscodePath, "User", "mcp.json"),
|
|
1647
|
+
sessionCount: 0
|
|
1648
|
+
});
|
|
1649
|
+
let clinePath;
|
|
1650
|
+
if (os === "darwin") {
|
|
1651
|
+
clinePath = join(home, "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev");
|
|
1652
|
+
} else if (os === "win32") {
|
|
1653
|
+
clinePath = join(process.env.APPDATA || join(home, "AppData", "Roaming"), "Code", "User", "globalStorage", "saoudrizwan.claude-dev");
|
|
1654
|
+
} else {
|
|
1655
|
+
clinePath = join(home, ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev");
|
|
1656
|
+
}
|
|
1657
|
+
tools.push({
|
|
1658
|
+
name: "Cline",
|
|
1659
|
+
id: "cline",
|
|
1660
|
+
available: existsSync(clinePath),
|
|
1661
|
+
path: join(clinePath, "settings", "cline_mcp_settings.json"),
|
|
1662
|
+
sessionCount: 0
|
|
1663
|
+
});
|
|
1664
|
+
const zedPath = os === "darwin" ? join(home, ".zed") : join(home, ".config", "zed");
|
|
1665
|
+
tools.push({
|
|
1666
|
+
name: "Zed",
|
|
1667
|
+
id: "zed",
|
|
1668
|
+
available: existsSync(zedPath),
|
|
1669
|
+
path: join(zedPath, "settings.json"),
|
|
1670
|
+
sessionCount: 0
|
|
1671
|
+
});
|
|
1672
|
+
const openclawDir = join(home, ".openclaw");
|
|
1673
|
+
tools.push({
|
|
1674
|
+
name: "OpenClaw",
|
|
1675
|
+
id: "openclaw",
|
|
1676
|
+
available: existsSync(openclawDir),
|
|
1677
|
+
path: join(openclawDir, "openclaw.json"),
|
|
1678
|
+
sessionCount: 0
|
|
1679
|
+
});
|
|
1635
1680
|
return tools;
|
|
1636
1681
|
}
|
|
1637
1682
|
|
|
@@ -2240,9 +2285,14 @@ import { spawnSync } from "node:child_process";
|
|
|
2240
2285
|
var CONARE_URL = "https://mcp.conare.ai";
|
|
2241
2286
|
var SERVER_NAME = "conare";
|
|
2242
2287
|
var MCP_TARGETS = [
|
|
2243
|
-
{ id: "claude", label: "Claude Code" },
|
|
2244
|
-
{ id: "
|
|
2245
|
-
{ id: "
|
|
2288
|
+
{ id: "claude", label: "Claude Code", defaultSelected: true },
|
|
2289
|
+
{ id: "codex", label: "Codex", defaultSelected: true },
|
|
2290
|
+
{ id: "cursor", label: "Cursor", defaultSelected: false },
|
|
2291
|
+
{ id: "windsurf", label: "Windsurf", defaultSelected: false },
|
|
2292
|
+
{ id: "vscode", label: "VS Code Copilot", defaultSelected: false },
|
|
2293
|
+
{ id: "cline", label: "Cline", defaultSelected: false },
|
|
2294
|
+
{ id: "zed", label: "Zed", defaultSelected: false },
|
|
2295
|
+
{ id: "openclaw", label: "OpenClaw", defaultSelected: false }
|
|
2246
2296
|
];
|
|
2247
2297
|
function readJsonFile(path) {
|
|
2248
2298
|
try {
|
|
@@ -2265,14 +2315,6 @@ function getServerConfig(apiKey) {
|
|
|
2265
2315
|
}
|
|
2266
2316
|
};
|
|
2267
2317
|
}
|
|
2268
|
-
function upsertMcpServer(path, apiKey) {
|
|
2269
|
-
const config = readJsonFile(path);
|
|
2270
|
-
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2271
|
-
config.mcpServers = {};
|
|
2272
|
-
}
|
|
2273
|
-
config.mcpServers[SERVER_NAME] = getServerConfig(apiKey);
|
|
2274
|
-
writeJsonFile(path, config);
|
|
2275
|
-
}
|
|
2276
2318
|
function configureClaude(apiKey) {
|
|
2277
2319
|
const claudeConfigPath = join7(homedir5(), ".claude.json");
|
|
2278
2320
|
const claudeMcpPath = join7(homedir5(), ".claude", "mcp.json");
|
|
@@ -2282,16 +2324,193 @@ function configureClaude(apiKey) {
|
|
|
2282
2324
|
}).status === 0) {
|
|
2283
2325
|
return "Claude Code configured via `claude mcp add-json`";
|
|
2284
2326
|
}
|
|
2285
|
-
|
|
2327
|
+
const config = readJsonFile(claudeConfigPath);
|
|
2328
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2329
|
+
config.mcpServers = {};
|
|
2330
|
+
}
|
|
2331
|
+
config.mcpServers[SERVER_NAME] = getServerConfig(apiKey);
|
|
2332
|
+
writeJsonFile(claudeConfigPath, config);
|
|
2286
2333
|
if (existsSync6(join7(homedir5(), ".claude"))) {
|
|
2287
|
-
|
|
2334
|
+
const mcpConfig = readJsonFile(claudeMcpPath);
|
|
2335
|
+
if (!mcpConfig.mcpServers || typeof mcpConfig.mcpServers !== "object") {
|
|
2336
|
+
mcpConfig.mcpServers = {};
|
|
2337
|
+
}
|
|
2338
|
+
mcpConfig.mcpServers[SERVER_NAME] = getServerConfig(apiKey);
|
|
2339
|
+
writeJsonFile(claudeMcpPath, mcpConfig);
|
|
2288
2340
|
}
|
|
2289
2341
|
return `Claude Code configured at ${claudeConfigPath}`;
|
|
2290
2342
|
}
|
|
2291
|
-
function
|
|
2292
|
-
|
|
2293
|
-
|
|
2343
|
+
function configureCodex(apiKey) {
|
|
2344
|
+
const configPath = join7(homedir5(), ".codex", "config.toml");
|
|
2345
|
+
if (spawnSync("codex", ["mcp", "add", SERVER_NAME, "--url", `${CONARE_URL}/mcp`, "--header", `Authorization: Bearer ${apiKey}`], {
|
|
2346
|
+
stdio: "ignore",
|
|
2347
|
+
shell: platform5() === "win32"
|
|
2348
|
+
}).status === 0) {
|
|
2349
|
+
return "Codex configured via `codex mcp add`";
|
|
2350
|
+
}
|
|
2351
|
+
let toml = "";
|
|
2352
|
+
try {
|
|
2353
|
+
toml = readFileSync7(configPath, "utf-8");
|
|
2354
|
+
} catch {}
|
|
2355
|
+
const sectionHeader = `[mcp_servers.${SERVER_NAME}]`;
|
|
2356
|
+
const newSection = [
|
|
2357
|
+
sectionHeader,
|
|
2358
|
+
`url = "${CONARE_URL}/mcp"`,
|
|
2359
|
+
`enabled = true`,
|
|
2360
|
+
"",
|
|
2361
|
+
`[mcp_servers.${SERVER_NAME}.http_headers]`,
|
|
2362
|
+
`"Authorization" = "Bearer ${apiKey}"`
|
|
2363
|
+
].join(`
|
|
2364
|
+
`);
|
|
2365
|
+
const sectionRegex = new RegExp(`\\[mcp_servers\\.${SERVER_NAME}(?:\\.[^\\]]*)?\\][^\\[]*`, "g");
|
|
2366
|
+
const cleaned = toml.replace(sectionRegex, "").replace(/\n{3,}/g, `
|
|
2367
|
+
|
|
2368
|
+
`).trim();
|
|
2369
|
+
const result = cleaned ? `${cleaned}
|
|
2370
|
+
|
|
2371
|
+
${newSection}
|
|
2372
|
+
` : `${newSection}
|
|
2373
|
+
`;
|
|
2374
|
+
mkdirSync2(dirname(configPath), { recursive: true });
|
|
2375
|
+
writeFileSync2(configPath, result);
|
|
2376
|
+
const oldMcpJson = join7(homedir5(), ".codex", "mcp.json");
|
|
2377
|
+
try {
|
|
2378
|
+
if (existsSync6(oldMcpJson)) {
|
|
2379
|
+
const old = readJsonFile(oldMcpJson);
|
|
2380
|
+
const servers = old.mcpServers;
|
|
2381
|
+
if (servers && (("conare" in servers) || ("conare-memory" in servers))) {
|
|
2382
|
+
delete servers["conare"];
|
|
2383
|
+
delete servers["conare-memory"];
|
|
2384
|
+
if (Object.keys(servers).length === 0) {
|
|
2385
|
+
rmSync(oldMcpJson);
|
|
2386
|
+
} else {
|
|
2387
|
+
writeJsonFile(oldMcpJson, old);
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
} catch {}
|
|
2392
|
+
return `Codex configured at ${configPath}`;
|
|
2393
|
+
}
|
|
2394
|
+
function configureCursor(apiKey) {
|
|
2395
|
+
const configPath = join7(homedir5(), ".cursor", "mcp.json");
|
|
2396
|
+
const config = readJsonFile(configPath);
|
|
2397
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2398
|
+
config.mcpServers = {};
|
|
2399
|
+
}
|
|
2400
|
+
config.mcpServers[SERVER_NAME] = {
|
|
2401
|
+
url: `${CONARE_URL}/mcp`,
|
|
2402
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
2403
|
+
};
|
|
2404
|
+
writeJsonFile(configPath, config);
|
|
2405
|
+
return `Cursor configured at ${configPath}`;
|
|
2294
2406
|
}
|
|
2407
|
+
function configureWindsurf(apiKey) {
|
|
2408
|
+
const configPath = join7(homedir5(), ".codeium", "windsurf", "mcp_config.json");
|
|
2409
|
+
const config = readJsonFile(configPath);
|
|
2410
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2411
|
+
config.mcpServers = {};
|
|
2412
|
+
}
|
|
2413
|
+
config.mcpServers[SERVER_NAME] = {
|
|
2414
|
+
serverUrl: `${CONARE_URL}/mcp`,
|
|
2415
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
2416
|
+
};
|
|
2417
|
+
writeJsonFile(configPath, config);
|
|
2418
|
+
return `Windsurf configured at ${configPath}`;
|
|
2419
|
+
}
|
|
2420
|
+
function configureVscode(apiKey) {
|
|
2421
|
+
const os = platform5();
|
|
2422
|
+
let configPath;
|
|
2423
|
+
if (os === "darwin") {
|
|
2424
|
+
configPath = join7(homedir5(), "Library", "Application Support", "Code", "User", "mcp.json");
|
|
2425
|
+
} else if (os === "win32") {
|
|
2426
|
+
configPath = join7(process.env.APPDATA || join7(homedir5(), "AppData", "Roaming"), "Code", "User", "mcp.json");
|
|
2427
|
+
} else {
|
|
2428
|
+
configPath = join7(homedir5(), ".config", "Code", "User", "mcp.json");
|
|
2429
|
+
}
|
|
2430
|
+
const config = readJsonFile(configPath);
|
|
2431
|
+
if (!config.servers || typeof config.servers !== "object") {
|
|
2432
|
+
config.servers = {};
|
|
2433
|
+
}
|
|
2434
|
+
config.servers[SERVER_NAME] = {
|
|
2435
|
+
type: "http",
|
|
2436
|
+
url: `${CONARE_URL}/mcp`,
|
|
2437
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
2438
|
+
};
|
|
2439
|
+
writeJsonFile(configPath, config);
|
|
2440
|
+
return `VS Code Copilot configured at ${configPath}`;
|
|
2441
|
+
}
|
|
2442
|
+
function configureCline(apiKey) {
|
|
2443
|
+
const os = platform5();
|
|
2444
|
+
let configPath;
|
|
2445
|
+
if (os === "darwin") {
|
|
2446
|
+
configPath = join7(homedir5(), "Library", "Application Support", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json");
|
|
2447
|
+
} else if (os === "win32") {
|
|
2448
|
+
configPath = join7(process.env.APPDATA || join7(homedir5(), "AppData", "Roaming"), "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json");
|
|
2449
|
+
} else {
|
|
2450
|
+
configPath = join7(homedir5(), ".config", "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json");
|
|
2451
|
+
}
|
|
2452
|
+
const config = readJsonFile(configPath);
|
|
2453
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2454
|
+
config.mcpServers = {};
|
|
2455
|
+
}
|
|
2456
|
+
config.mcpServers[SERVER_NAME] = {
|
|
2457
|
+
url: `${CONARE_URL}/mcp`,
|
|
2458
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
2459
|
+
disabled: false
|
|
2460
|
+
};
|
|
2461
|
+
writeJsonFile(configPath, config);
|
|
2462
|
+
return `Cline configured at ${configPath}`;
|
|
2463
|
+
}
|
|
2464
|
+
function configureZed(apiKey) {
|
|
2465
|
+
const os = platform5();
|
|
2466
|
+
let configPath;
|
|
2467
|
+
if (os === "darwin") {
|
|
2468
|
+
configPath = join7(homedir5(), ".zed", "settings.json");
|
|
2469
|
+
} else {
|
|
2470
|
+
configPath = join7(homedir5(), ".config", "zed", "settings.json");
|
|
2471
|
+
}
|
|
2472
|
+
const config = readJsonFile(configPath);
|
|
2473
|
+
if (!config.context_servers || typeof config.context_servers !== "object") {
|
|
2474
|
+
config.context_servers = {};
|
|
2475
|
+
}
|
|
2476
|
+
config.context_servers[SERVER_NAME] = {
|
|
2477
|
+
command: "npx",
|
|
2478
|
+
args: [
|
|
2479
|
+
"-y",
|
|
2480
|
+
"mcp-remote",
|
|
2481
|
+
`${CONARE_URL}/mcp`,
|
|
2482
|
+
"--header",
|
|
2483
|
+
`Authorization:Bearer ${apiKey}`
|
|
2484
|
+
],
|
|
2485
|
+
env: {}
|
|
2486
|
+
};
|
|
2487
|
+
writeJsonFile(configPath, config);
|
|
2488
|
+
return `Zed configured at ${configPath}`;
|
|
2489
|
+
}
|
|
2490
|
+
function configureOpenclaw(apiKey) {
|
|
2491
|
+
const configPath = join7(homedir5(), ".openclaw", "openclaw.json");
|
|
2492
|
+
const config = readJsonFile(configPath);
|
|
2493
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
2494
|
+
config.mcpServers = {};
|
|
2495
|
+
}
|
|
2496
|
+
config.mcpServers[SERVER_NAME] = {
|
|
2497
|
+
type: "streamable-http",
|
|
2498
|
+
url: `${CONARE_URL}/mcp`,
|
|
2499
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
2500
|
+
};
|
|
2501
|
+
writeJsonFile(configPath, config);
|
|
2502
|
+
return `OpenClaw configured at ${configPath}`;
|
|
2503
|
+
}
|
|
2504
|
+
var CLIENT_CONFIGURATORS = {
|
|
2505
|
+
claude: configureClaude,
|
|
2506
|
+
codex: configureCodex,
|
|
2507
|
+
cursor: configureCursor,
|
|
2508
|
+
windsurf: configureWindsurf,
|
|
2509
|
+
vscode: configureVscode,
|
|
2510
|
+
cline: configureCline,
|
|
2511
|
+
zed: configureZed,
|
|
2512
|
+
openclaw: configureOpenclaw
|
|
2513
|
+
};
|
|
2295
2514
|
var SKILL_MD = `---
|
|
2296
2515
|
name: conare
|
|
2297
2516
|
description: Complements the Conare MCP server by teaching the agent when and how to load prior project context, search past sessions, save durable preferences, list stored memories, and forget saved items. Use when the user asks what they worked on before, wants prior context loaded at the start of a task, asks to remember or forget something, or needs past conversations, decisions, or code recalled from memory.
|
|
@@ -2365,95 +2584,6 @@ Expected outcome: future \`recall\` calls surface the information automatically
|
|
|
2365
2584
|
- Keep \`limit\` low (3-5) for focused results, higher (10-15) for broad exploration
|
|
2366
2585
|
- When user asks to "remember" something, save it with \`save\` — it goes to the \`preferences\` container and gets surfaced by \`recall\` in future sessions
|
|
2367
2586
|
|
|
2368
|
-
## Examples
|
|
2369
|
-
|
|
2370
|
-
### Example 1: Start with context
|
|
2371
|
-
|
|
2372
|
-
User says: "Help me continue the OAuth migration in this repo."
|
|
2373
|
-
|
|
2374
|
-
Actions:
|
|
2375
|
-
1. Call \`recall\` with context like "continue OAuth migration in the current repository".
|
|
2376
|
-
2. Review returned memories for prior migration decisions, unresolved blockers, and saved preferences.
|
|
2377
|
-
3. Proceed with implementation using that context.
|
|
2378
|
-
|
|
2379
|
-
Result: the agent starts with the relevant project history instead of asking the user to restate it.
|
|
2380
|
-
|
|
2381
|
-
### Example 2: Find prior work
|
|
2382
|
-
|
|
2383
|
-
User says: "What did we decide last week about billing webhooks?"
|
|
2384
|
-
|
|
2385
|
-
Actions:
|
|
2386
|
-
1. Call \`search\` with a descriptive query such as "billing webhook decision refunds retries last week".
|
|
2387
|
-
2. If results are weak, retry with alternatives like "refund webhook handling" or "billing retry policy".
|
|
2388
|
-
3. Summarize the decision and note uncertainty if memories conflict.
|
|
2389
|
-
|
|
2390
|
-
Result: the agent retrieves prior decisions from memory rather than guessing.
|
|
2391
|
-
|
|
2392
|
-
### Example 3: Save a durable preference
|
|
2393
|
-
|
|
2394
|
-
User says: "Remember that I prefer ripgrep over grep."
|
|
2395
|
-
|
|
2396
|
-
Actions:
|
|
2397
|
-
1. Call \`save\` with the preference in durable wording.
|
|
2398
|
-
2. Confirm the preference was saved.
|
|
2399
|
-
|
|
2400
|
-
Result: future \`recall\` results can surface that preference automatically.
|
|
2401
|
-
|
|
2402
|
-
## Troubleshooting
|
|
2403
|
-
|
|
2404
|
-
### Weak or irrelevant search results
|
|
2405
|
-
|
|
2406
|
-
Cause:
|
|
2407
|
-
- Query is too short or too generic.
|
|
2408
|
-
- Search needs a different phrasing or time scope.
|
|
2409
|
-
|
|
2410
|
-
Response:
|
|
2411
|
-
1. Rewrite the query with concrete nouns, entities, and actions.
|
|
2412
|
-
2. Add \`after\`/\`before\` when the user implies a time window.
|
|
2413
|
-
3. Add \`project\` or \`containerTag\` when the scope is known.
|
|
2414
|
-
|
|
2415
|
-
### \`recall\` returns little useful context
|
|
2416
|
-
|
|
2417
|
-
Cause:
|
|
2418
|
-
- Conversation context passed to \`recall\` was too vague.
|
|
2419
|
-
- The project parameter was omitted when it should have been included.
|
|
2420
|
-
|
|
2421
|
-
Response:
|
|
2422
|
-
1. Retry \`recall\` with a more specific task description.
|
|
2423
|
-
2. Include \`project\` if the workspace or repository is known.
|
|
2424
|
-
3. Fall back to \`search\` for the exact topic the user cares about.
|
|
2425
|
-
|
|
2426
|
-
### Unsure whether to save something
|
|
2427
|
-
|
|
2428
|
-
Cause:
|
|
2429
|
-
- The information may be temporary rather than durable.
|
|
2430
|
-
|
|
2431
|
-
Response:
|
|
2432
|
-
1. Save it when it is likely to help in future sessions, especially if it reflects a preference, rule, decision, or durable project fact.
|
|
2433
|
-
2. Skip only clearly transient implementation notes unless the user explicitly asks to retain them.
|
|
2434
|
-
|
|
2435
|
-
## Triggering Tests
|
|
2436
|
-
|
|
2437
|
-
Use these tests to validate whether the skill description is tuned correctly.
|
|
2438
|
-
|
|
2439
|
-
Should trigger:
|
|
2440
|
-
- "What did we work on in this repo last week?"
|
|
2441
|
-
- "Load context for the auth refactor before we continue."
|
|
2442
|
-
- "Remember that I prefer pnpm in JavaScript projects."
|
|
2443
|
-
- "Forget the note about using staging Stripe keys."
|
|
2444
|
-
- "Search my past sessions for the DO migration fix."
|
|
2445
|
-
|
|
2446
|
-
Should not trigger:
|
|
2447
|
-
- "Write a sorting function in TypeScript."
|
|
2448
|
-
- "What is the weather in San Francisco?"
|
|
2449
|
-
- "Explain how PostgreSQL indexes work."
|
|
2450
|
-
- "Create a landing page from this mockup."
|
|
2451
|
-
|
|
2452
|
-
Success criteria:
|
|
2453
|
-
- Triggers on memory-oriented requests and start-of-task context loading.
|
|
2454
|
-
- Does not trigger on generic coding or research tasks with no memory component.
|
|
2455
|
-
- Uses \`recall\` first for new task continuation, and uses \`search\` only when the user asks about specific past work.
|
|
2456
|
-
|
|
2457
2587
|
## Setup
|
|
2458
2588
|
|
|
2459
2589
|
Install with a single command:
|
|
@@ -2486,16 +2616,17 @@ function installSkill() {
|
|
|
2486
2616
|
} catch {}
|
|
2487
2617
|
return "Agent Skill installed";
|
|
2488
2618
|
}
|
|
2489
|
-
function configureMcp(apiKey, targets = ["claude", "
|
|
2619
|
+
function configureMcp(apiKey, targets = ["claude", "codex"]) {
|
|
2490
2620
|
const results = [];
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2621
|
+
for (const target of targets) {
|
|
2622
|
+
const configurator = CLIENT_CONFIGURATORS[target];
|
|
2623
|
+
if (configurator) {
|
|
2624
|
+
try {
|
|
2625
|
+
results.push(configurator(apiKey));
|
|
2626
|
+
} catch (e) {
|
|
2627
|
+
results.push(`${target}: failed — ${e.message}`);
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2499
2630
|
}
|
|
2500
2631
|
try {
|
|
2501
2632
|
results.push(installSkill());
|
|
@@ -3132,10 +3263,13 @@ conare — AI memory for your coding tools
|
|
|
3132
3263
|
|
|
3133
3264
|
Usage:
|
|
3134
3265
|
conare Interactive setup with browser auth
|
|
3135
|
-
conare install Just install the MCP
|
|
3266
|
+
conare install Just install the MCP (all detected clients)
|
|
3136
3267
|
conare --key <api_key> Ingest chat history (key optional with browser auth)
|
|
3137
3268
|
conare --key <api_key> --index [path] Index codebase
|
|
3138
3269
|
|
|
3270
|
+
Supported clients:
|
|
3271
|
+
Claude Code, Codex, Cursor, Windsurf, VS Code Copilot, Cline, Zed, OpenClaw
|
|
3272
|
+
|
|
3139
3273
|
Options:
|
|
3140
3274
|
--key <key> Your Conare API key (optional if using browser auth, starts with cmem_)
|
|
3141
3275
|
--config-file <path> Read API key from JSON config file (e.g. ~/.conare/config.json)
|
|
@@ -3179,23 +3313,25 @@ async function runInstall() {
|
|
|
3179
3313
|
}
|
|
3180
3314
|
const savedApiKey = getSavedApiKey();
|
|
3181
3315
|
const hasTty = !!process.stdin.isTTY && !!process.stdout.isTTY;
|
|
3182
|
-
let apiKey = key || process.env.CONARE_API_KEY ||
|
|
3316
|
+
let apiKey = key || process.env.CONARE_API_KEY || savedApiKey;
|
|
3183
3317
|
if (!apiKey && hasTty) {
|
|
3184
3318
|
const { promptAuth: promptAuthFn } = await Promise.resolve().then(() => (init_interactive(), exports_interactive));
|
|
3185
3319
|
const { spinner: clackSpinner } = await Promise.resolve().then(() => (init_interactive(), exports_interactive));
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3320
|
+
if (!apiKey) {
|
|
3321
|
+
const authResult = await promptAuthFn({});
|
|
3322
|
+
if (authResult === "__BROWSER_AUTH__") {
|
|
3323
|
+
const authSpinner = clackSpinner();
|
|
3324
|
+
authSpinner.start("Waiting for browser sign-in...");
|
|
3325
|
+
try {
|
|
3326
|
+
apiKey = await browserAuth();
|
|
3327
|
+
authSpinner.stop("Signed in successfully.");
|
|
3328
|
+
} catch (e2) {
|
|
3329
|
+
authSpinner.stop(`Authentication failed: ${e2.message}`);
|
|
3330
|
+
process.exit(1);
|
|
3331
|
+
}
|
|
3332
|
+
} else {
|
|
3333
|
+
apiKey = authResult || "";
|
|
3196
3334
|
}
|
|
3197
|
-
} else {
|
|
3198
|
-
apiKey = authResult || "";
|
|
3199
3335
|
}
|
|
3200
3336
|
}
|
|
3201
3337
|
if (!apiKey) {
|
|
@@ -3208,8 +3344,12 @@ async function runInstall() {
|
|
|
3208
3344
|
process.exit(1);
|
|
3209
3345
|
}
|
|
3210
3346
|
saveApiKey(apiKey);
|
|
3211
|
-
const
|
|
3212
|
-
const
|
|
3347
|
+
const detectedTools = await detect();
|
|
3348
|
+
const targets = MCP_TARGETS.filter((t) => {
|
|
3349
|
+
const detected = detectedTools.find((d3) => d3.id === t.id);
|
|
3350
|
+
return detected?.available || t.defaultSelected;
|
|
3351
|
+
}).map((t) => t.id);
|
|
3352
|
+
const lines = configureMcp(apiKey, targets);
|
|
3213
3353
|
for (const line of lines)
|
|
3214
3354
|
console.log(` ${line}`);
|
|
3215
3355
|
console.log("");
|
|
@@ -3241,7 +3381,7 @@ async function main() {
|
|
|
3241
3381
|
const savedApiKey = getSavedApiKey();
|
|
3242
3382
|
const hasTty = !!process.stdin.isTTY && !!process.stdout.isTTY;
|
|
3243
3383
|
const shouldRunInteractive = hasTty && !opts.dryRun && !opts.quiet && (opts.interactive || !opts.force && !opts.source && !opts.indexPath && !opts.configOnly && !opts.ingestOnly && !opts.wasmDir);
|
|
3244
|
-
let selectedTargets = MCP_TARGETS.map((
|
|
3384
|
+
let selectedTargets = MCP_TARGETS.filter((t) => t.defaultSelected).map((t) => t.id);
|
|
3245
3385
|
let effectiveConfigOnly = opts.configOnly;
|
|
3246
3386
|
let effectiveIngestOnly = opts.ingestOnly;
|
|
3247
3387
|
let effectiveIndexPath = opts.indexPath;
|
|
@@ -3252,39 +3392,40 @@ async function main() {
|
|
|
3252
3392
|
id: target.id,
|
|
3253
3393
|
label: target.label,
|
|
3254
3394
|
available: true,
|
|
3255
|
-
recommended:
|
|
3395
|
+
recommended: target.defaultSelected,
|
|
3256
3396
|
detectedCount: undefined
|
|
3257
3397
|
}));
|
|
3258
3398
|
let interactiveMode = false;
|
|
3259
3399
|
if (shouldRunInteractive) {
|
|
3260
3400
|
const detectedTools = await detect();
|
|
3261
3401
|
interactiveTargets = MCP_TARGETS.map((target) => {
|
|
3262
|
-
const detected = detectedTools.find((tool) =>
|
|
3402
|
+
const detected = detectedTools.find((tool) => tool.id === target.id);
|
|
3263
3403
|
return {
|
|
3264
3404
|
id: target.id,
|
|
3265
3405
|
label: target.label,
|
|
3266
3406
|
available: detected?.available,
|
|
3267
|
-
recommended: detected?.available !== false,
|
|
3407
|
+
recommended: target.defaultSelected && detected?.available !== false,
|
|
3268
3408
|
detectedCount: detected?.sessionCount
|
|
3269
3409
|
};
|
|
3270
3410
|
});
|
|
3271
|
-
apiKey = opts.key || configFileKey || process.env.CONARE_API_KEY;
|
|
3272
3411
|
startSetup();
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3412
|
+
if (!apiKey) {
|
|
3413
|
+
const authResult = await promptAuth({
|
|
3414
|
+
providedApiKey: opts.key
|
|
3415
|
+
});
|
|
3416
|
+
if (authResult === "__BROWSER_AUTH__") {
|
|
3417
|
+
const authSpinner = Y2();
|
|
3418
|
+
authSpinner.start("Waiting for browser sign-in...");
|
|
3419
|
+
try {
|
|
3420
|
+
apiKey = await browserAuth();
|
|
3421
|
+
authSpinner.stop("Signed in successfully.");
|
|
3422
|
+
} catch (e2) {
|
|
3423
|
+
authSpinner.stop(`Authentication failed: ${e2.message}`);
|
|
3424
|
+
process.exit(1);
|
|
3425
|
+
}
|
|
3426
|
+
} else {
|
|
3427
|
+
apiKey = authResult || apiKey;
|
|
3285
3428
|
}
|
|
3286
|
-
} else {
|
|
3287
|
-
apiKey = authResult || apiKey;
|
|
3288
3429
|
}
|
|
3289
3430
|
showDetectedApps(interactiveTargets);
|
|
3290
3431
|
selectedSources = await selectChatSources(interactiveTargets);
|