create-snipara 1.3.15 → 1.3.17

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 +15 -8
  2. package/dist/index.js +314 -43
  3. package/package.json +5 -1
package/README.md CHANGED
@@ -16,7 +16,7 @@ so an LLM client can use Snipara context and reviewed memory.
16
16
 
17
17
  Use it for:
18
18
 
19
- - Hosted MCP onboarding for Codex, Claude Code, Cursor, ChatGPT Desktop, and similar clients
19
+ - Hosted MCP onboarding for Claude Code, Cursor, Windsurf, Codex, Gemini, VS Code/Copilot, Continue, ChatGPT Desktop, and similar clients
20
20
  - free account signup with reviewed Context + Memory
21
21
  - local project wiring, `doctor`, `repair`, and `upgrade`
22
22
  - GitHub repository sync and PR Answer Packs approval when the current folder is a GitHub repo
@@ -32,8 +32,8 @@ flowchart LR
32
32
  Project["Local project"] --> CLI["npx create-snipara"]
33
33
  CLI --> Auth["Snipara auth and project key"]
34
34
  CLI --> MCP["Hosted MCP config"]
35
- CLI --> Templates["AGENTS.md, CLAUDE.md, Cursor, Codex snippets"]
36
- MCP --> Agents["Codex, Claude Code, Cursor, ChatGPT Desktop"]
35
+ CLI --> Templates["AGENTS.md, CLAUDE.md, Cursor, Codex, MCP references"]
36
+ MCP --> Agents["Claude Code, Cursor, Codex, Gemini, VS Code, ChatGPT"]
37
37
  Templates --> Agents
38
38
  Agents --> Context["Snipara context and memory"]
39
39
  ```
@@ -74,7 +74,7 @@ Free onboarding is now **Context + Memory**, not Context-only:
74
74
 
75
75
  - Context Free: three projects and 1,000 context queries/month
76
76
  - Memory Free: reviewed hosted memories for continuity across sessions
77
- - Hosted MCP: direct connection for Claude Code, Codex, Cursor, ChatGPT Desktop, and other MCP clients
77
+ - Hosted MCP: direct connection for Claude Code, Cursor, Windsurf, Codex, Gemini, VS Code/Copilot, Continue, ChatGPT Desktop, and other MCP clients
78
78
 
79
79
  The CLI opens a browser device-flow login when the user does not already have a key, auto-provisions the free Context + Memory account when needed, then writes the returned API key into the local MCP config.
80
80
 
@@ -105,6 +105,7 @@ That distinction matters:
105
105
  - configures `.mcp.json`
106
106
  - generates merge-ready AI agent templates in `.snipara/templates/`, including Pro+ symbol-card, code-impact, and managed workflow guidance for paid Context plans
107
107
  - creates `AGENTS.md`, `CLAUDE.md`, `.cursor/rules/snipara.mdc`, and `.codex/config.toml` when those files do not already exist
108
+ - writes client-specific companion packs such as `.snipara/companion/CODEX.md` or `.snipara/companion/GEMINI.md`
108
109
  - updates `.env`, `.env.local`, and `.env.example`
109
110
  - generates `.snipara/companion/README.md`
110
111
  - generates `.snipara/companion/commands.json`
@@ -155,6 +156,7 @@ The generated agent templates cover:
155
156
  - Cursor `.cursor/rules/snipara.mdc`
156
157
  - Codex `.codex/config.toml` snippet
157
158
  - ChatGPT/OpenAI HTTP MCP snippet
159
+ - Gemini, VS Code, Continue, and custom HTTP MCP reference snippets
158
160
 
159
161
  When `snipara-companion` is installed, the companion pack also includes the compaction-safe managed workflow:
160
162
 
@@ -297,18 +299,22 @@ The intended split is:
297
299
  - `snipara-mcp`: local stdio bridge, client-package development, compatibility, and testing
298
300
  - `snipara-sandbox`: optional local execution engine
299
301
 
300
- ## Codex Setup
302
+ ## Client Packs
301
303
 
302
- For Codex, keep Hosted MCP as the core path and let companion add workflow
303
- ergonomics:
304
+ For every selected AI client, keep Hosted MCP as the core path and let
305
+ companion add workflow ergonomics:
304
306
 
305
307
  - use Hosted MCP as the core Snipara surface
306
308
  - use `AGENTS.md` for project instructions
309
+ - use the selected pack under `.snipara/companion/`, for example `CODEX.md`, `CURSOR.md`, or `GEMINI.md`
307
310
  - use the default `hosted-companion` path when you want compaction-safe local phase commits
308
311
  - choose `hosted-only` or `--skip-companion` only in locked-down environments
309
312
  - use local `snipara-mcp` only for stdio compatibility, development, or tests
310
313
 
311
- Codex does not require hook presets to use Snipara successfully.
314
+ Claude Code, Cursor, and Windsurf can receive generated automation files when
315
+ that client has a useful local hook surface. Codex, Gemini, VS Code, Continue,
316
+ ChatGPT, and custom clients are treated as MCP-first: they get the hosted MCP
317
+ configuration/reference and agent instructions, not invented local hooks.
312
318
 
313
319
  This keeps setup and runtime separated while still giving the user one obvious command to start from.
314
320
 
@@ -317,6 +323,7 @@ This keeps setup and runtime separated while still giving the user one obvious c
317
323
  After setup, the project gets a local pack at `.snipara/companion/`:
318
324
 
319
325
  - `README.md`: local usage guidance
326
+ - `<CLIENT>.md`: selected client setup overlay, such as `CODEX.md` or `GEMINI.md`
320
327
  - `commands.json`: starter commands for the current project
321
328
  - `doctor.json`: most recent validation report
322
329
 
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ 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
- var VERSION = "1.3.15";
12
+ var VERSION = "1.3.17";
13
13
  var BASE_URL = "https://www.snipara.com";
14
14
  var API_URL = "https://api.snipara.com";
15
15
  var COMPANION_PACKAGE_NAME = "snipara-companion";
@@ -25,11 +25,68 @@ var LEGACY_SANDBOX_COMMAND_NAME = "rlm";
25
25
  var DEVICE_CLIENT_ID = "create-snipara";
26
26
  var DeviceAuthorizationAborted = class extends Error {
27
27
  };
28
+ var AI_CLIENT_CHOICES = [
29
+ {
30
+ title: "Claude Code (CLI/VS Code extension)",
31
+ value: "claude-code",
32
+ description: "Best hooks support"
33
+ },
34
+ {
35
+ title: "Cursor",
36
+ value: "cursor",
37
+ description: "Hosted MCP plus Cursor rules and automation bundles"
38
+ },
39
+ {
40
+ title: "Windsurf",
41
+ value: "windsurf",
42
+ description: "Hosted MCP plus Windsurf automation bundles"
43
+ },
44
+ {
45
+ title: "OpenAI Codex",
46
+ value: "codex",
47
+ description: "Hosted MCP plus AGENTS.md and Codex config"
48
+ },
49
+ {
50
+ title: "Gemini CLI",
51
+ value: "gemini",
52
+ description: "Hosted MCP reference plus agent instructions"
53
+ },
54
+ {
55
+ title: "VS Code / Copilot",
56
+ value: "vscode",
57
+ description: "Hosted MCP reference for VS Code-compatible clients"
58
+ },
59
+ {
60
+ title: "Continue",
61
+ value: "continue",
62
+ description: "Hosted MCP reference for Continue"
63
+ },
64
+ {
65
+ title: "ChatGPT / OpenAI MCP",
66
+ value: "chatgpt",
67
+ description: "Hosted MCP for ChatGPT Desktop or OpenAI-compatible clients"
68
+ },
69
+ {
70
+ title: "Claude Desktop",
71
+ value: "claude-desktop",
72
+ description: "Desktop MCP config flow"
73
+ },
74
+ { title: "Other MCP client", value: "other" }
75
+ ];
28
76
  function getCompanionInitClientFlag(aiClient) {
29
- if (aiClient === "cursor") {
30
- return " --client cursor";
31
- }
32
- return aiClient === "claude-code" ? " --client claude-code" : "";
77
+ const supportedClientMap = {
78
+ "claude-code": "claude-code",
79
+ cursor: "cursor",
80
+ windsurf: "windsurf",
81
+ codex: "codex",
82
+ gemini: "gemini",
83
+ chatgpt: "chatgpt",
84
+ vscode: "vscode",
85
+ continue: "continue",
86
+ other: "custom"
87
+ };
88
+ const companionClient = supportedClientMap[aiClient];
89
+ return companionClient ? ` --client ${companionClient}` : "";
33
90
  }
34
91
  function buildProgram() {
35
92
  const program = new Command();
@@ -363,37 +420,11 @@ async function gatherConfiguration(options) {
363
420
  type: "select",
364
421
  name: "aiClient",
365
422
  message: "Which AI client are you using?",
366
- initial: ["claude-code", "cursor", "codex", "chatgpt", "claude-desktop", "other"].indexOf(
367
- detectedClient
423
+ initial: Math.max(
424
+ 0,
425
+ AI_CLIENT_CHOICES.findIndex((choice) => choice.value === detectedClient)
368
426
  ),
369
- choices: [
370
- {
371
- title: "Claude Code (CLI/VS Code extension)",
372
- value: "claude-code",
373
- description: "Best hooks support"
374
- },
375
- {
376
- title: "Cursor",
377
- value: "cursor",
378
- description: "MCP via .mcp.json plus companion terminal workflows"
379
- },
380
- {
381
- title: "OpenAI Codex",
382
- value: "codex",
383
- description: "Hosted MCP plus AGENTS.md"
384
- },
385
- {
386
- title: "ChatGPT / OpenAI MCP",
387
- value: "chatgpt",
388
- description: "Hosted MCP for ChatGPT Desktop or OpenAI-compatible clients"
389
- },
390
- {
391
- title: "Claude Desktop",
392
- value: "claude-desktop",
393
- description: "Desktop MCP config flow"
394
- },
395
- { title: "Other", value: "other" }
396
- ]
427
+ choices: AI_CLIENT_CHOICES
397
428
  },
398
429
  {
399
430
  type: showAdvancedPrompts ? "confirm" : null,
@@ -906,6 +937,22 @@ async function createAgentTemplates(answers) {
906
937
  {
907
938
  path: path.join(templatesDir, "chatgpt-openai-mcp.json"),
908
939
  content: buildChatGptMcpTemplate(answers)
940
+ },
941
+ {
942
+ path: path.join(templatesDir, "gemini-mcp-reference.json"),
943
+ content: buildGenericMcpReferenceTemplate(answers, "gemini")
944
+ },
945
+ {
946
+ path: path.join(templatesDir, "vscode-mcp-reference.json"),
947
+ content: buildGenericMcpReferenceTemplate(answers, "vscode")
948
+ },
949
+ {
950
+ path: path.join(templatesDir, "continue-mcp-reference.json"),
951
+ content: buildGenericMcpReferenceTemplate(answers, "continue")
952
+ },
953
+ {
954
+ path: path.join(templatesDir, "custom-mcp-reference.json"),
955
+ content: buildGenericMcpReferenceTemplate(answers, "custom")
909
956
  }
910
957
  ];
911
958
  for (const template of templates) {
@@ -974,9 +1021,10 @@ Agent task lifecycle:
974
1021
  11. If \`git status --short\` is dirty, warn that Snipara's indexed code graph may not include local edits; use local reads/tests for exact edits and Snipara for architecture/code graph context.
975
1022
  12. Use Snipara Sandbox only when sandboxed execution, repeatable validation, or isolated transformations materially help.
976
1023
  13. If a broad query is slow, retry once with a narrow keyword query before falling back to local search.
977
- 14. End each substantial phase with \`snipara_end_of_task_commit\` or \`snipara-companion workflow phase-commit\` when companion manages the plan. End the whole managed workflow with \`snipara-companion final-commit\`.
978
- 15. Use \`snipara_remember_if_novel\` for one reusable memory while avoiding duplicates, and use \`snipara_remember\` for explicit direct memory writes.
979
- 16. Do not store secrets, tokens, passwords, private keys, raw logs, transient command output, or unreviewed guesses in memory.
1024
+ 14. When generated hooks are enabled, \`snipara-companion pre-tool\`, \`post-tool\`, and \`stuck-guard status\` provide runtime Rescue Pack checks for repeated failures, empty searches, and risky workflows.
1025
+ 15. End each substantial phase with \`snipara_end_of_task_commit\` or \`snipara-companion workflow phase-commit\` when companion manages the plan. End the whole managed workflow with \`snipara-companion final-commit\`.
1026
+ 16. Use \`snipara_remember_if_novel\` for one reusable memory while avoiding duplicates, and use \`snipara_remember\` for explicit direct memory writes.
1027
+ 17. Do not store secrets, tokens, passwords, private keys, raw logs, transient command output, or unreviewed guesses in memory.
980
1028
  `;
981
1029
  }
982
1030
  function buildClaudeMdTemplate(answers) {
@@ -997,6 +1045,7 @@ Use Snipara Hosted MCP before answering project-specific questions.
997
1045
  - Check every \`snipara_code_*\` response for indexed commit SHA, indexing time, included files, coverage, and freshness warnings. Legacy \`rlm_code_*\` IDs return the same payloads.
998
1046
  - Use local file reads, \`rg\`, \`git status --short\`, and tests for exact edits/current working tree; use Snipara for architecture and indexed code graph context.
999
1047
  - When the plan is visible and \`snipara-companion\` is installed, use \`snipara-companion workflow start\`, \`phase-start\`, \`phase-commit\`, \`workflow resume\`, and \`final-commit\` to keep phase state durable across compaction. Legacy \`rlm-hook\` commands remain compatible.
1048
+ - If generated hooks are enabled, \`snipara-companion pre-tool\`, \`post-tool\`, and \`stuck-guard status\` provide runtime Rescue Pack checks when the agent loops on failures or empty searches.
1000
1049
  - Use Snipara Sandbox only when sandboxed execution or repeatable validation materially helps.
1001
1050
  - End substantial work with \`snipara_end_of_task_commit\` when available; for managed workflows, end every phase with \`snipara-companion workflow phase-commit\` and the task with \`snipara-companion final-commit\`.
1002
1051
  - Use \`snipara_remember_if_novel\` or \`snipara_remember\` only for narrow durable memories.
@@ -1026,6 +1075,7 @@ This workspace uses Snipara Hosted MCP for current project context, business/cli
1026
1075
  - Use \`snipara_plan\` or \`snipara_decompose\` only for complex work and only when available.
1027
1076
  - Use local file reads, \`rg\`, \`git status --short\`, and tests for exact code edits and current working-tree state.
1028
1077
  - When \`snipara-companion\` is installed and the LLM has a visible multi-phase plan, use \`snipara-companion workflow start\`, \`phase-start\`, \`phase-commit\`, \`workflow resume\`, and \`final-commit\` so the next phase survives compaction. Legacy \`rlm-hook\` commands remain compatible.
1078
+ - Generated hooks can call \`snipara-companion pre-tool\`, \`post-tool\`, and \`stuck-guard status\` so Rescue Packs are runtime-triggered rather than relying only on instructions.
1029
1079
  - Use Snipara Sandbox only when sandboxed execution or repeatable validation materially helps.
1030
1080
  - End substantial work with \`snipara_end_of_task_commit\` when available; for managed workflows, end every phase with \`snipara-companion workflow phase-commit\` and the task with \`snipara-companion final-commit\`. Use \`snipara_remember_if_novel\` or \`snipara_remember\` only for narrow durable memories. Never store secrets.
1031
1081
  `;
@@ -1051,6 +1101,26 @@ function buildChatGptMcpTemplate(answers) {
1051
1101
  )}
1052
1102
  `;
1053
1103
  }
1104
+ function buildGenericMcpReferenceTemplate(answers, client) {
1105
+ return `${JSON.stringify(
1106
+ {
1107
+ client,
1108
+ note: "Reference format only; paste the server fields into this client's MCP settings.",
1109
+ mcpServers: {
1110
+ snipara: {
1111
+ type: "http",
1112
+ url: buildHostedMcpEndpoint(answers),
1113
+ headers: {
1114
+ "X-API-Key": "${SNIPARA_API_KEY}"
1115
+ }
1116
+ }
1117
+ }
1118
+ },
1119
+ null,
1120
+ 2
1121
+ )}
1122
+ `;
1123
+ }
1054
1124
  function ensureGitignoreEntry(entry, comment) {
1055
1125
  const gitignorePath = path.join(process.cwd(), ".gitignore");
1056
1126
  if (fs.existsSync(gitignorePath)) {
@@ -1121,6 +1191,10 @@ async function installClaudeCodeHooks(answers) {
1121
1191
  fs.mkdirSync(hooksDir, { recursive: true });
1122
1192
  }
1123
1193
  const hooks = [
1194
+ {
1195
+ name: "snipara-stuck-guard.sh",
1196
+ content: createStuckGuardHook(answers)
1197
+ },
1124
1198
  {
1125
1199
  name: "snipara-startup.sh",
1126
1200
  content: createStartupHook(answers)
@@ -1152,6 +1226,11 @@ async function installClaudeCodeHooks(answers) {
1152
1226
  settings.hooks = settings.hooks || {};
1153
1227
  const hooksConfig = settings.hooks;
1154
1228
  const hookEntries = [
1229
+ {
1230
+ event: "PreToolUse",
1231
+ script: path.join(hooksDir, "snipara-stuck-guard.sh"),
1232
+ matcher: { tool_name: "Bash|Read|Grep|Glob|Edit|MultiEdit|Write" }
1233
+ },
1155
1234
  {
1156
1235
  event: "PreToolUse",
1157
1236
  script: path.join(hooksDir, "snipara-startup.sh"),
@@ -1160,7 +1239,7 @@ async function installClaudeCodeHooks(answers) {
1160
1239
  {
1161
1240
  event: "PostToolUse",
1162
1241
  script: path.join(hooksDir, "snipara-session.sh"),
1163
- matcher: { tool_name: "Bash" }
1242
+ matcher: { tool_name: "Bash|Read|Grep|Glob|Edit|MultiEdit|Write" }
1164
1243
  },
1165
1244
  {
1166
1245
  event: "PreCompact",
@@ -1180,6 +1259,26 @@ async function installClaudeCodeHooks(answers) {
1180
1259
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
1181
1260
  console.log(chalk.green(" \u2713 Updated ~/.claude/settings.json"));
1182
1261
  }
1262
+ function createStuckGuardHook(answers) {
1263
+ return `#!/usr/bin/env bash
1264
+ set -euo pipefail
1265
+
1266
+ export SNIPARA_PROJECT_SLUG="${answers.projectSlug}"
1267
+ ${answers.projectId ? `export SNIPARA_PROJECT_ID="${answers.projectId}"` : ""}
1268
+
1269
+ SNIPARA_COMPANION_BIN=""
1270
+ if command -v ${COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1271
+ SNIPARA_COMPANION_BIN="${COMPANION_COMMAND_NAME}"
1272
+ elif command -v ${LEGACY_COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1273
+ SNIPARA_COMPANION_BIN="${LEGACY_COMPANION_COMMAND_NAME}"
1274
+ fi
1275
+
1276
+ if [ -n "$SNIPARA_COMPANION_BIN" ]; then
1277
+ INPUT=$(cat || true)
1278
+ "$SNIPARA_COMPANION_BIN" pre-tool "$INPUT" || true
1279
+ fi
1280
+ `;
1281
+ }
1183
1282
  function createStartupHook(answers) {
1184
1283
  return `#!/usr/bin/env bash
1185
1284
  set -euo pipefail
@@ -1218,7 +1317,8 @@ elif command -v ${LEGACY_COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1218
1317
  fi
1219
1318
 
1220
1319
  if [ -n "$SNIPARA_COMPANION_BIN" ]; then
1221
- "$SNIPARA_COMPANION_BIN" emit-event --event-type tool_result --json '{"source":"claude-code-hook"}' || true
1320
+ INPUT=$(cat || true)
1321
+ "$SNIPARA_COMPANION_BIN" post-tool "$INPUT" || true
1222
1322
  fi
1223
1323
  `;
1224
1324
  }
@@ -1314,12 +1414,36 @@ function getClientGuidance(client) {
1314
1414
  "Use the companion CLI only for explicit upload, planning, chunk lookup, doctor, and task commit workflows outside the editor UI."
1315
1415
  ];
1316
1416
  }
1417
+ if (client === "windsurf") {
1418
+ return [
1419
+ "Windsurf should use the hosted MCP surface plus generated Windsurf automation bundles when available.",
1420
+ "Use snipara-companion automations install --client windsurf when you want dashboard-managed hook files in the local project."
1421
+ ];
1422
+ }
1317
1423
  if (client === "codex") {
1318
1424
  return [
1319
1425
  "Codex should use the hosted MCP surface plus AGENTS.md as the canonical project instruction file.",
1320
1426
  "The generated .snipara/templates/codex-config.toml is a merge-ready snippet for ~/.codex/config.toml if your Codex app does not read project .codex/config.toml."
1321
1427
  ];
1322
1428
  }
1429
+ if (client === "gemini") {
1430
+ return [
1431
+ "Gemini should use Hosted MCP plus the generated AGENTS.md rules; no local shell hooks are assumed.",
1432
+ "Use .snipara/templates/gemini-mcp-reference.json as a field reference for the client's MCP settings."
1433
+ ];
1434
+ }
1435
+ if (client === "vscode") {
1436
+ return [
1437
+ "VS Code and Copilot-style clients should use Hosted MCP plus AGENTS.md for project workflow rules.",
1438
+ "Use .snipara/templates/vscode-mcp-reference.json as the Snipara server reference when adding an MCP server."
1439
+ ];
1440
+ }
1441
+ if (client === "continue") {
1442
+ return [
1443
+ "Continue should use Hosted MCP for Snipara tools and keep AGENTS.md as the shared project instruction source.",
1444
+ "Use .snipara/templates/continue-mcp-reference.json as the Snipara server reference when wiring MCP."
1445
+ ];
1446
+ }
1323
1447
  if (client === "chatgpt") {
1324
1448
  return [
1325
1449
  "ChatGPT and OpenAI-compatible MCP clients should use the direct hosted MCP endpoint.",
@@ -1333,13 +1457,13 @@ function getClientGuidance(client) {
1333
1457
  ];
1334
1458
  }
1335
1459
  return [
1336
- "The generated pack assumes Hosted MCP for agents and API / SDK for product integrations.",
1337
- "Use the companion CLI only when local planning, upload, doctor, or task commit flows help."
1460
+ "The generated pack assumes a generic streamable HTTP MCP client plus AGENTS.md for shared workflow rules.",
1461
+ "Use .snipara/templates/custom-mcp-reference.json as the server reference and use companion only when local planning, upload, doctor, or task commit flows help."
1338
1462
  ];
1339
1463
  }
1340
1464
  function getCompanionCommands(answers) {
1341
1465
  const projectIdFlag = answers.projectId ? ` --project-id ${answers.projectId}` : "";
1342
- const apiKeyFlag = answers.apiKeyType === "none" || answers.apiKey.includes("YOUR_") ? " --api-key <rlm-key>" : ` --api-key ${answers.apiKey}`;
1466
+ const apiKeyFlag = " --api-key <snipara-key>";
1343
1467
  const clientFlag = getCompanionInitClientFlag(answers.aiClient);
1344
1468
  const businessOnboardingCommands = answers.installCompanion ? [
1345
1469
  {
@@ -1431,6 +1555,16 @@ function getCompanionCommands(answers) {
1431
1555
  command: `${COMPANION_COMMAND_NAME} session-bootstrap`,
1432
1556
  purpose: "Load durable decisions, learnings, and optional short-lived carryover at session start."
1433
1557
  },
1558
+ {
1559
+ title: "Check Stuck Guard status",
1560
+ command: `${COMPANION_COMMAND_NAME} stuck-guard status`,
1561
+ purpose: "Inspect whether recent tool failures, empty searches, or risky workflow signals should trigger a Rescue Pack."
1562
+ },
1563
+ {
1564
+ title: "Simulate a Stuck Guard fixture",
1565
+ command: `${COMPANION_COMMAND_NAME} stuck-guard simulate --fixture ./stuck-guard-fixture.json`,
1566
+ purpose: "Replay canonical events against the hosted Stuck Guard decision API before enabling stricter modes."
1567
+ },
1434
1568
  {
1435
1569
  title: "Ask memory about past decisions",
1436
1570
  command: `${COMPANION_COMMAND_NAME} recall --query "What did we decide about auth retries?" --type decision`,
@@ -1453,12 +1587,118 @@ function getCompanionCommands(answers) {
1453
1587
  }
1454
1588
  ];
1455
1589
  }
1590
+ function getClientDisplayName(client) {
1591
+ const names = {
1592
+ "claude-code": "Claude Code",
1593
+ cursor: "Cursor",
1594
+ windsurf: "Windsurf",
1595
+ codex: "OpenAI Codex",
1596
+ gemini: "Gemini",
1597
+ chatgpt: "ChatGPT / OpenAI MCP",
1598
+ vscode: "VS Code",
1599
+ continue: "Continue",
1600
+ "claude-desktop": "Claude Desktop",
1601
+ other: "Custom MCP client"
1602
+ };
1603
+ return names[client];
1604
+ }
1605
+ function getClientPackFilename(client) {
1606
+ const names = {
1607
+ "claude-code": "CLAUDE_CODE.md",
1608
+ cursor: "CURSOR.md",
1609
+ windsurf: "WINDSURF.md",
1610
+ codex: "CODEX.md",
1611
+ gemini: "GEMINI.md",
1612
+ chatgpt: "CHATGPT.md",
1613
+ vscode: "VSCODE.md",
1614
+ continue: "CONTINUE.md",
1615
+ "claude-desktop": "CLAUDE_DESKTOP.md",
1616
+ other: "CUSTOM_MCP.md"
1617
+ };
1618
+ return names[client];
1619
+ }
1620
+ function getClientConfigArtifacts(client) {
1621
+ if (client === "claude-code") {
1622
+ return ["AGENTS.md", "CLAUDE.md", ".claude/settings.json when hooks are installed"];
1623
+ }
1624
+ if (client === "cursor") {
1625
+ return [".mcp.json", ".cursor/rules/snipara.mdc", "dashboard automation bundle when installed"];
1626
+ }
1627
+ if (client === "windsurf") {
1628
+ return [".mcp.json", "dashboard automation bundle when installed"];
1629
+ }
1630
+ if (client === "codex") {
1631
+ return ["AGENTS.md", ".codex/config.toml", ".snipara/templates/codex-config.toml"];
1632
+ }
1633
+ if (client === "gemini") {
1634
+ return ["AGENTS.md", ".snipara/templates/gemini-mcp-reference.json"];
1635
+ }
1636
+ if (client === "vscode") {
1637
+ return ["AGENTS.md", ".snipara/templates/vscode-mcp-reference.json"];
1638
+ }
1639
+ if (client === "continue") {
1640
+ return ["AGENTS.md", ".snipara/templates/continue-mcp-reference.json"];
1641
+ }
1642
+ if (client === "chatgpt") {
1643
+ return ["AGENTS.md", ".snipara/templates/chatgpt-openai-mcp.json"];
1644
+ }
1645
+ if (client === "claude-desktop") {
1646
+ return ["AGENTS.md", "Claude Desktop MCP config"];
1647
+ }
1648
+ return ["AGENTS.md", ".snipara/templates/custom-mcp-reference.json"];
1649
+ }
1650
+ function getClientAutomationCommand(client) {
1651
+ const companionClient = getCompanionInitClientFlag(client).match(/--client\s+(\S+)/)?.[1];
1652
+ return companionClient ? `${COMPANION_COMMAND_NAME} automations install --client ${companionClient}` : null;
1653
+ }
1654
+ function buildClientPackMarkdown(answers, commands, guidance) {
1655
+ const clientName = getClientDisplayName(answers.aiClient);
1656
+ const automationCommand = getClientAutomationCommand(answers.aiClient);
1657
+ const bootstrapCommand = commands.find(
1658
+ (command) => command.title === "Bootstrap local companion"
1659
+ );
1660
+ return `# Snipara Pack: ${clientName}
1661
+
1662
+ This pack is the client-specific overlay for the generated Snipara project setup.
1663
+ Use \`AGENTS.md\` as the shared source of agent behavior, then apply the client-specific files below.
1664
+
1665
+ ## Hosted MCP
1666
+
1667
+ - Endpoint: \`${buildHostedMcpEndpoint(answers)}\`
1668
+ - Auth: \`SNIPARA_API_KEY\` from the environment or local client secret store
1669
+ - Do not commit API keys or bearer tokens.
1670
+
1671
+ ## Client Files
1672
+
1673
+ ${getClientConfigArtifacts(answers.aiClient).map((item) => `- \`${item}\``).join("\n")}
1674
+
1675
+ ## Recommended Setup
1676
+
1677
+ ${bootstrapCommand ? `1. Bootstrap companion: \`${bootstrapCommand.command}\`` : "1. Bootstrap companion with `snipara-companion init`."}
1678
+ 2. Confirm the client can list or call the \`snipara_*\` MCP tools.
1679
+ 3. Keep exact edits, tests, and dirty working-tree checks local; use Snipara for memory, source truth, and indexed code graph context.
1680
+ ${automationCommand ? `4. For generated local automations, run \`${automationCommand}\` when that client exposes usable automation files.` : "4. This client is treated as MCP-first; no local hook surface is assumed."}
1681
+
1682
+ ## Client Guidance
1683
+
1684
+ ${guidance.map((line) => `- ${line}`).join("\n")}
1685
+
1686
+ ## Agent Workflow
1687
+
1688
+ - Start substantial work with \`snipara_recall\` and \`snipara_context_query\`.
1689
+ - Use \`answer_pack\` facts, caveats, source maps, and verification checks before making claims.
1690
+ - Use \`snipara_code_symbol_card\` and \`snipara_code_impact\` for important symbols or risky multi-file changes when available.
1691
+ - Use \`snipara-companion workflow start\`, \`phase-start\`, \`phase-commit\`, \`workflow resume\`, and \`final-commit\` for multi-phase work.
1692
+ - Persist only durable decisions, learnings, preferences, workflows, and troubleshooting outcomes. Never persist secrets.
1693
+ `;
1694
+ }
1456
1695
  async function createCompanionPack(answers) {
1457
1696
  console.log(chalk.bold("\n\u{1F5C2}\uFE0F Generating Companion Pack\n"));
1458
1697
  const packDir = path.join(process.cwd(), ".snipara", "companion");
1459
1698
  const commands = getCompanionCommands(answers);
1460
1699
  const guidance = getClientGuidance(answers.aiClient);
1461
1700
  const detection = detectEnvironment();
1701
+ const clientPackFilename = getClientPackFilename(answers.aiClient);
1462
1702
  fs.mkdirSync(packDir, { recursive: true });
1463
1703
  const readme = `# Snipara Companion Pack
1464
1704
 
@@ -1470,6 +1710,7 @@ This project uses Snipara as a hosted-first context and memory layer with local
1470
1710
  - Project slug: \`${answers.projectSlug}\`
1471
1711
  - Project id: \`${answers.projectId || "not-set"}\`
1472
1712
  - AI client: \`${answers.aiClient}\`
1713
+ - Client pack: \`${clientPackFilename}\`
1473
1714
  - Installed local companion: \`${answers.installCompanion ? "yes" : "no"}\`
1474
1715
  - Generated hosted MCP config: \`${answers.profile !== "runtime-only" ? "yes" : "no"}\`
1475
1716
  - Installed local snipara-mcp package: \`${answers.installMcp ? "yes" : "no"}\`
@@ -1551,13 +1792,19 @@ ${item.purpose}`
1551
1792
  llm_provider: answers.llmProvider || null,
1552
1793
  github_repository: answers.githubRepo || null,
1553
1794
  github_automation_url: answers.githubRepo ? buildGitHubAutomationUrl(answers) : null,
1795
+ client_pack: clientPackFilename,
1554
1796
  commands,
1555
1797
  guidance,
1556
1798
  detection
1557
1799
  };
1558
1800
  fs.writeFileSync(path.join(packDir, "README.md"), readme + "\n");
1801
+ fs.writeFileSync(
1802
+ path.join(packDir, clientPackFilename),
1803
+ buildClientPackMarkdown(answers, commands, guidance) + "\n"
1804
+ );
1559
1805
  fs.writeFileSync(path.join(packDir, "commands.json"), JSON.stringify(pack, null, 2) + "\n");
1560
1806
  console.log(chalk.green(" \u2713 Created .snipara/companion/README.md"));
1807
+ console.log(chalk.green(` \u2713 Created .snipara/companion/${clientPackFilename}`));
1561
1808
  console.log(chalk.green(" \u2713 Created .snipara/companion/commands.json"));
1562
1809
  }
1563
1810
  async function runSandboxInit() {
@@ -2100,12 +2347,36 @@ function detectAiClient() {
2100
2347
  if (fs.existsSync(path.join(process.cwd(), ".codex"))) {
2101
2348
  return "codex";
2102
2349
  }
2350
+ if (fs.existsSync(path.join(process.cwd(), ".cursor"))) {
2351
+ return "cursor";
2352
+ }
2353
+ if (fs.existsSync(path.join(process.cwd(), ".windsurf"))) {
2354
+ return "windsurf";
2355
+ }
2356
+ if (fs.existsSync(path.join(process.cwd(), ".gemini"))) {
2357
+ return "gemini";
2358
+ }
2359
+ if (fs.existsSync(path.join(process.cwd(), ".continue"))) {
2360
+ return "continue";
2361
+ }
2362
+ if (fs.existsSync(path.join(process.cwd(), ".vscode"))) {
2363
+ return "vscode";
2364
+ }
2103
2365
  if (fs.existsSync(path.join(homedir(), ".claude")) || process.env.CLAUDE_CODE) {
2104
2366
  return "claude-code";
2105
2367
  }
2106
2368
  if (fs.existsSync(path.join(homedir(), ".cursor")) || process.env.CURSOR_EDITOR) {
2107
2369
  return "cursor";
2108
2370
  }
2371
+ if (fs.existsSync(path.join(homedir(), ".windsurf")) || process.env.WINDSURF_EDITOR) {
2372
+ return "windsurf";
2373
+ }
2374
+ if (fs.existsSync(path.join(homedir(), ".gemini")) || process.env.GEMINI_CLI) {
2375
+ return "gemini";
2376
+ }
2377
+ if (fs.existsSync(path.join(homedir(), ".continue")) || process.env.CONTINUE_GLOBAL_DIR) {
2378
+ return "continue";
2379
+ }
2109
2380
  const claudeDesktopPath = process.platform === "darwin" ? path.join(homedir(), "Library", "Application Support", "Claude") : process.platform === "win32" ? path.join(homedir(), "AppData", "Roaming", "Claude") : path.join(homedir(), ".config", "claude");
2110
2381
  if (fs.existsSync(claudeDesktopPath)) {
2111
2382
  return "claude-desktop";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-snipara",
3
- "version": "1.3.15",
3
+ "version": "1.3.17",
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",
@@ -32,6 +32,10 @@
32
32
  "chatgpt",
33
33
  "openai",
34
34
  "cursor",
35
+ "windsurf",
36
+ "gemini",
37
+ "vscode",
38
+ "continue",
35
39
  "claude-desktop"
36
40
  ],
37
41
  "author": "Snipara",