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.
- package/README.md +15 -8
- package/dist/index.js +314 -43
- 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,
|
|
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
|
|
36
|
-
MCP --> Agents["
|
|
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,
|
|
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
|
-
##
|
|
302
|
+
## Client Packs
|
|
301
303
|
|
|
302
|
-
For
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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:
|
|
367
|
-
|
|
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.
|
|
978
|
-
15.
|
|
979
|
-
16.
|
|
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
|
-
|
|
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
|
|
1337
|
-
"Use the companion
|
|
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 =
|
|
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.
|
|
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",
|