create-snipara 1.3.36 → 1.3.37
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 +6 -1
- package/dist/index.js +69 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -106,7 +106,8 @@ That distinction matters:
|
|
|
106
106
|
- installs optional `snipara-orchestrator` for proof gates, drift checks, and htask workflows when requested
|
|
107
107
|
- configures `.mcp.json`
|
|
108
108
|
- generates merge-ready AI agent templates in `.snipara/templates/`, including Pro+ symbol-card, code-impact, and managed workflow guidance for paid Context plans
|
|
109
|
-
- creates `AGENTS.md
|
|
109
|
+
- creates `AGENTS.md` and `CLAUDE.md` when missing, or appends a marked Snipara section when those files already exist
|
|
110
|
+
- creates `.cursor/rules/snipara.mdc` and `.codex/config.toml` when those files do not already exist
|
|
110
111
|
- writes client-specific companion packs such as `.snipara/companion/CODEX.md` or `.snipara/companion/GEMINI.md`
|
|
111
112
|
- updates `.env`, `.env.local`, and `.env.example`
|
|
112
113
|
- generates `.snipara/companion/README.md`
|
|
@@ -162,6 +163,10 @@ The generated agent templates cover:
|
|
|
162
163
|
- ChatGPT/OpenAI HTTP MCP snippet
|
|
163
164
|
- Gemini, VS Code, Continue, and custom HTTP MCP reference snippets
|
|
164
165
|
|
|
166
|
+
Existing root `AGENTS.md` and `CLAUDE.md` files are not replaced. The installer
|
|
167
|
+
adds or refreshes a marked Snipara section so project-specific instructions stay
|
|
168
|
+
intact.
|
|
169
|
+
|
|
165
170
|
When `snipara-companion` is installed, the companion pack also includes the compaction-safe managed workflow:
|
|
166
171
|
|
|
167
172
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { homedir } from "os";
|
|
|
13
13
|
// package.json
|
|
14
14
|
var package_default = {
|
|
15
15
|
name: "create-snipara",
|
|
16
|
-
version: "1.3.
|
|
16
|
+
version: "1.3.37",
|
|
17
17
|
description: "Onboard Snipara Hosted MCP Context + Memory with auth, companion workflows, and optional Snipara Sandbox",
|
|
18
18
|
main: "dist/index.js",
|
|
19
19
|
type: "module",
|
|
@@ -163,10 +163,19 @@ function getCompanionInitClientFlag(aiClient) {
|
|
|
163
163
|
const companionClient = supportedClientMap[aiClient];
|
|
164
164
|
return companionClient ? ` --client ${companionClient}` : "";
|
|
165
165
|
}
|
|
166
|
+
function getAutomationClientId(aiClient) {
|
|
167
|
+
if (aiClient === "other" || aiClient === "claude-desktop") {
|
|
168
|
+
return "custom";
|
|
169
|
+
}
|
|
170
|
+
return aiClient;
|
|
171
|
+
}
|
|
166
172
|
function buildProgram() {
|
|
167
173
|
const program = new Command();
|
|
168
174
|
program.name("create-snipara").description("Scaffold hosted Snipara MCP config plus companion workflow helpers").version(VERSION);
|
|
169
|
-
program.command("init").description("Install and configure Snipara for this project").option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option(
|
|
175
|
+
program.command("init").description("Install and configure Snipara for this project").option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option(
|
|
176
|
+
"--client <client>",
|
|
177
|
+
"AI client: claude-code, cursor, windsurf, codex, gemini, chatgpt, vscode, continue, claude-desktop, other"
|
|
178
|
+
).option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
|
|
170
179
|
"--profile <profile>",
|
|
171
180
|
"Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
|
|
172
181
|
).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").addOption(new Option("--full", "Legacy alias for --profile full-stack").hideHelp()).option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
|
|
@@ -200,7 +209,10 @@ function buildProgram() {
|
|
|
200
209
|
return program;
|
|
201
210
|
}
|
|
202
211
|
function addSharedRootOptions(program) {
|
|
203
|
-
program.option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option(
|
|
212
|
+
program.option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option(
|
|
213
|
+
"--client <client>",
|
|
214
|
+
"AI client: claude-code, cursor, windsurf, codex, gemini, chatgpt, vscode, continue, claude-desktop, other"
|
|
215
|
+
).option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
|
|
204
216
|
"--profile <profile>",
|
|
205
217
|
"Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
|
|
206
218
|
).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").addOption(new Option("--full", "Legacy alias for --profile full-stack").hideHelp()).option("-y, --yes", "Accept defaults without prompting");
|
|
@@ -233,6 +245,7 @@ function parseInitOptionsFromArgv(args) {
|
|
|
233
245
|
"--api-key": "apiKey",
|
|
234
246
|
"--slug": "slug",
|
|
235
247
|
"--project-id": "projectId",
|
|
248
|
+
"--client": "client",
|
|
236
249
|
"--profile": "profile",
|
|
237
250
|
"--github-path": "githubPath"
|
|
238
251
|
};
|
|
@@ -295,6 +308,7 @@ async function runInit(options) {
|
|
|
295
308
|
}
|
|
296
309
|
await updateEnvFiles(answers);
|
|
297
310
|
await createCompanionConfig(answers);
|
|
311
|
+
await syncRemoteAutomationClient(answers, { enabled: !options.skipTest });
|
|
298
312
|
await createCompanionPack(answers);
|
|
299
313
|
const validationReport = await runValidation(answers, !options.skipTest);
|
|
300
314
|
writeDoctorReport(validationReport);
|
|
@@ -454,6 +468,7 @@ function printBanner() {
|
|
|
454
468
|
async function gatherConfiguration(options) {
|
|
455
469
|
console.log(chalk.bold("\n\u{1F4CB} Project Configuration\n"));
|
|
456
470
|
const detectedClient = detectAiClient();
|
|
471
|
+
const requestedClient = normalizeClientOption(options.client);
|
|
457
472
|
const existingConfig = getExistingConfig();
|
|
458
473
|
const projectSlugResolution = resolveProjectSlug(existingConfig);
|
|
459
474
|
let detectedSlug = projectSlugResolution.slug;
|
|
@@ -486,7 +501,7 @@ async function gatherConfiguration(options) {
|
|
|
486
501
|
apiKey: providedApiKey || "YOUR_API_KEY_HERE",
|
|
487
502
|
apiKeyType: providedApiKey ? "api" : "none",
|
|
488
503
|
profile: initialProfile,
|
|
489
|
-
aiClient: detectedClient,
|
|
504
|
+
aiClient: requestedClient || detectedClient,
|
|
490
505
|
skipCompanion: !!options.skipCompanion,
|
|
491
506
|
skipMcp: !!options.skipMcp,
|
|
492
507
|
skipRuntime: !!options.skipRuntime,
|
|
@@ -553,7 +568,9 @@ async function gatherConfiguration(options) {
|
|
|
553
568
|
message: "Which AI client are you using?",
|
|
554
569
|
initial: Math.max(
|
|
555
570
|
0,
|
|
556
|
-
AI_CLIENT_CHOICES.findIndex(
|
|
571
|
+
AI_CLIENT_CHOICES.findIndex(
|
|
572
|
+
(choice) => choice.value === (requestedClient || detectedClient)
|
|
573
|
+
)
|
|
557
574
|
),
|
|
558
575
|
choices: AI_CLIENT_CHOICES
|
|
559
576
|
},
|
|
@@ -604,7 +621,7 @@ async function gatherConfiguration(options) {
|
|
|
604
621
|
apiKey: apiKey || "",
|
|
605
622
|
apiKeyType,
|
|
606
623
|
profile: response.profile || initialProfile,
|
|
607
|
-
aiClient: response.aiClient || detectedClient,
|
|
624
|
+
aiClient: requestedClient || response.aiClient || detectedClient,
|
|
608
625
|
skipCompanion: !!options.skipCompanion,
|
|
609
626
|
skipMcp: !!options.skipMcp,
|
|
610
627
|
skipRuntime: !!options.skipRuntime,
|
|
@@ -702,7 +719,8 @@ function normalizeClientOption(value) {
|
|
|
702
719
|
chatgpt: "chatgpt",
|
|
703
720
|
vscode: "vscode",
|
|
704
721
|
continue: "continue",
|
|
705
|
-
other: "other"
|
|
722
|
+
other: "other",
|
|
723
|
+
custom: "other"
|
|
706
724
|
};
|
|
707
725
|
const client = aliases[normalized];
|
|
708
726
|
if (!client) {
|
|
@@ -870,10 +888,14 @@ async function runDeviceAuthorization() {
|
|
|
870
888
|
spinner.fail("Authorization expired");
|
|
871
889
|
throw new Error("device code expired");
|
|
872
890
|
}
|
|
873
|
-
async function postJson(url, body, allowErrorResponse = false) {
|
|
891
|
+
async function postJson(url, body, allowErrorResponse = false, init = {}) {
|
|
892
|
+
const headers = {
|
|
893
|
+
...init.headers ?? {},
|
|
894
|
+
"Content-Type": "application/json"
|
|
895
|
+
};
|
|
874
896
|
const response = await fetch(url, {
|
|
875
|
-
method: "POST",
|
|
876
|
-
headers
|
|
897
|
+
method: init.method ?? "POST",
|
|
898
|
+
headers,
|
|
877
899
|
body: JSON.stringify(body)
|
|
878
900
|
});
|
|
879
901
|
const data = await response.json().catch(() => ({}));
|
|
@@ -1679,31 +1701,49 @@ async function createCompanionConfig(answers) {
|
|
|
1679
1701
|
}
|
|
1680
1702
|
const configDir = path.join(process.cwd(), ".snipara", "companion");
|
|
1681
1703
|
const configPath = path.join(configDir, "config.json");
|
|
1682
|
-
const globalConfigPath = getGlobalCompanionConfigPath();
|
|
1683
1704
|
fs.mkdirSync(configDir, { recursive: true });
|
|
1684
|
-
fs.mkdirSync(path.dirname(globalConfigPath), { recursive: true });
|
|
1685
|
-
const existingGlobalConfig = readCompanionConfigFile(globalConfigPath);
|
|
1686
1705
|
const existingWorkspaceConfig = readCompanionConfigFile(configPath);
|
|
1687
|
-
const globalConfig = {
|
|
1688
|
-
...existingGlobalConfig,
|
|
1689
|
-
apiKey: answers.apiKey,
|
|
1690
|
-
apiUrl: API_URL
|
|
1691
|
-
};
|
|
1692
1706
|
const workspaceConfig = {
|
|
1693
|
-
|
|
1694
|
-
|
|
1707
|
+
...existingWorkspaceConfig,
|
|
1708
|
+
apiKey: answers.apiKey,
|
|
1709
|
+
apiUrl: API_URL,
|
|
1710
|
+
projectId: answers.projectId || answers.projectSlug,
|
|
1711
|
+
sessionId: typeof existingWorkspaceConfig.sessionId === "string" && existingWorkspaceConfig.sessionId ? existingWorkspaceConfig.sessionId : `sess_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
1712
|
+
client: getAutomationClientId(answers.aiClient)
|
|
1695
1713
|
};
|
|
1696
|
-
fs.writeFileSync(globalConfigPath, JSON.stringify(globalConfig, null, 2) + "\n");
|
|
1697
1714
|
fs.writeFileSync(configPath, JSON.stringify(workspaceConfig, null, 2) + "\n");
|
|
1698
|
-
ensureGitignoreEntry(
|
|
1699
|
-
|
|
1700
|
-
"# Snipara local companion workspace config"
|
|
1701
|
-
);
|
|
1702
|
-
console.log(chalk.green(" \u2713 Configured global companion auth"));
|
|
1703
|
-
console.log(chalk.green(" \u2713 Configured local companion workspace"));
|
|
1715
|
+
ensureGitignoreEntry(".snipara/companion/config.json", "# Snipara local companion config");
|
|
1716
|
+
console.log(chalk.green(" \u2713 Configured local companion config"));
|
|
1704
1717
|
}
|
|
1705
|
-
function
|
|
1706
|
-
|
|
1718
|
+
async function syncRemoteAutomationClient(answers, options) {
|
|
1719
|
+
if (!options.enabled || answers.apiKeyType === "none" || !answers.apiKey || answers.apiKey.includes("YOUR_") || !answers.projectSlug) {
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
const automationClient = getAutomationClientId(answers.aiClient);
|
|
1723
|
+
const url = `${BASE_URL}/api/cli/projects/${encodeURIComponent(
|
|
1724
|
+
answers.projectSlug
|
|
1725
|
+
)}/automation-client`;
|
|
1726
|
+
try {
|
|
1727
|
+
const response = await postJson(
|
|
1728
|
+
url,
|
|
1729
|
+
{ automationClient },
|
|
1730
|
+
false,
|
|
1731
|
+
{
|
|
1732
|
+
method: "PATCH",
|
|
1733
|
+
headers: { "X-API-Key": answers.apiKey }
|
|
1734
|
+
}
|
|
1735
|
+
);
|
|
1736
|
+
if (response.success === false) {
|
|
1737
|
+
throw new Error(response.message || "dashboard rejected automation client update");
|
|
1738
|
+
}
|
|
1739
|
+
console.log(chalk.green(` \u2713 Synced dashboard automation client: ${automationClient}`));
|
|
1740
|
+
} catch (error) {
|
|
1741
|
+
console.log(
|
|
1742
|
+
chalk.yellow(
|
|
1743
|
+
` \u26A0\uFE0F Could not sync dashboard automation client: ${error instanceof Error ? error.message : "unknown error"}`
|
|
1744
|
+
)
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1707
1747
|
}
|
|
1708
1748
|
function readCompanionConfigFile(filePath) {
|
|
1709
1749
|
if (!fs.existsSync(filePath)) {
|
package/package.json
CHANGED