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.
Files changed (3) hide show
  1. package/README.md +6 -1
  2. package/dist/index.js +69 -29
  3. 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`, `CLAUDE.md`, `.cursor/rules/snipara.mdc`, and `.codex/config.toml` when those files do not already exist
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.36",
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("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").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("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").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((choice) => choice.value === detectedClient)
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: { "Content-Type": "application/json" },
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
- projectId: answers.projectSlug,
1694
- sessionId: typeof existingWorkspaceConfig.sessionId === "string" && existingWorkspaceConfig.sessionId ? existingWorkspaceConfig.sessionId : `sess_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
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
- ".snipara/companion/config.json",
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 getGlobalCompanionConfigPath() {
1706
- return path.join(homedir(), ".rlmsaas", "config.json");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-snipara",
3
- "version": "1.3.36",
3
+ "version": "1.3.37",
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",