create-snipara 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +159 -29
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9,11 +9,11 @@ import fs from "fs";
9
9
  import path from "path";
10
10
  import { execSync } from "child_process";
11
11
  import { homedir } from "os";
12
- var VERSION = "1.0.0";
12
+ var VERSION = "1.1.0";
13
13
  var BASE_URL = "https://www.snipara.com";
14
14
  var API_URL = "https://api.snipara.com";
15
15
  async function main() {
16
- program.name("create-snipara").description("Initialize Snipara MCP + RLM-Runtime with a single command").version(VERSION).option("--api-key <key>", "Snipara API key (project or team)").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID (optional, for advanced use)").option("--skip-mcp", "Skip snipara-mcp installation").option("--skip-runtime", "Skip rlm-runtime installation").option("--skip-hooks", "Skip hooks installation").option("--skip-test", "Skip connection test").option("-y, --yes", "Accept defaults without prompting").parse();
16
+ program.name("create-snipara").description("Initialize Snipara MCP + RLM-Runtime with a single command").version(VERSION).option("--api-key <key>", "Snipara API key (project or team)").option("--team-key <key>", "Team API key (access all team projects)").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID (optional, for advanced use)").option("--skip-mcp", "Skip snipara-mcp installation").option("--skip-runtime", "Skip rlm-runtime installation").option("--skip-hooks", "Skip hooks installation").option("--skip-test", "Skip connection test").option("--runtime-only", "Install only RLM-Runtime (no API key needed for local execution)").option("-y, --yes", "Accept defaults without prompting").parse();
17
17
  const options = program.opts();
18
18
  printBanner();
19
19
  const answers = await gatherConfiguration(options);
@@ -57,11 +57,29 @@ async function gatherConfiguration(options) {
57
57
  detectedSlug = existingConfig.slug || detectedSlug;
58
58
  detectedProjectId = existingConfig.projectId || "";
59
59
  }
60
+ if (options.runtimeOnly) {
61
+ console.log(chalk.cyan("\n \u2139\uFE0F Runtime-only mode: No API key needed for local code execution\n"));
62
+ console.log(chalk.dim(" execute_python works without any API key when used in Claude Code."));
63
+ console.log(chalk.dim(" For rlm run/agent CLI, you'll need OPENAI_API_KEY or ANTHROPIC_API_KEY.\n"));
64
+ return {
65
+ projectSlug: options.slug || detectedSlug || "my-project",
66
+ projectId: "",
67
+ apiKey: "",
68
+ apiKeyType: "none",
69
+ installMcp: false,
70
+ installRuntime: true,
71
+ installHooks: false,
72
+ aiClient: detectedClient
73
+ };
74
+ }
60
75
  if (options.yes) {
76
+ const apiKey2 = options.teamKey || options.apiKey || "YOUR_API_KEY_HERE";
77
+ const apiKeyType2 = options.teamKey ? "team" : "project";
61
78
  return {
62
79
  projectSlug: options.slug || detectedSlug || "my-project",
63
80
  projectId: options.projectId || detectedProjectId,
64
- apiKey: options.apiKey || "YOUR_API_KEY_HERE",
81
+ apiKey: apiKey2,
82
+ apiKeyType: apiKeyType2,
65
83
  installMcp: !options.skipMcp,
66
84
  installRuntime: !options.skipRuntime,
67
85
  installHooks: !options.skipHooks && detectedClient === "claude-code",
@@ -83,19 +101,34 @@ async function gatherConfiguration(options) {
83
101
  initial: options.projectId || detectedProjectId || ""
84
102
  },
85
103
  {
86
- type: options.apiKey ? null : "select",
87
- name: "authMethod",
88
- message: "How would you like to authenticate?",
104
+ type: options.apiKey || options.teamKey ? null : "select",
105
+ name: "apiKeyType",
106
+ message: "What type of API key do you have?",
89
107
  choices: [
90
- { title: "I have a Snipara API key", value: "existing" },
91
- { title: "Sign up for free (100 queries/mo)", value: "signup" },
92
- { title: "I'll add the API key later", value: "skip" }
108
+ {
109
+ title: "Project API key",
110
+ value: "project",
111
+ description: "Access to a single project"
112
+ },
113
+ {
114
+ title: "Team API key",
115
+ value: "team",
116
+ description: "Access to all projects in your team"
117
+ },
118
+ {
119
+ title: "Sign up for free (100 queries/mo)",
120
+ value: "signup"
121
+ },
122
+ {
123
+ title: "I'll add the API key later",
124
+ value: "skip"
125
+ }
93
126
  ]
94
127
  },
95
128
  {
96
- type: (prev, values) => values.authMethod === "existing" ? "text" : null,
129
+ type: (prev, values) => values.apiKeyType === "project" || values.apiKeyType === "team" ? "text" : null,
97
130
  name: "apiKey",
98
- message: "Enter your API key:",
131
+ message: (prev, values) => values.apiKeyType === "team" ? "Enter your Team API key:" : "Enter your Project API key:",
99
132
  validate: (v) => v.startsWith("rlm_") ? true : "API key should start with rlm_"
100
133
  },
101
134
  {
@@ -133,13 +166,13 @@ async function gatherConfiguration(options) {
133
166
  title: "snipara-mcp",
134
167
  value: "mcp",
135
168
  selected: !options.skipMcp,
136
- description: "MCP server for context queries"
169
+ description: "MCP server for context queries (requires API key)"
137
170
  },
138
171
  {
139
172
  title: "rlm-runtime",
140
173
  value: "runtime",
141
174
  selected: !options.skipRuntime,
142
- description: "Safe code execution with Docker"
175
+ description: "Safe code execution (no API key for execute_python)"
143
176
  },
144
177
  {
145
178
  title: "Claude Code hooks",
@@ -151,23 +184,80 @@ async function gatherConfiguration(options) {
151
184
  hint: "Space to toggle, Enter to confirm"
152
185
  }
153
186
  ]);
154
- let apiKey = options.apiKey;
155
- if (response.authMethod === "signup") {
156
- apiKey = await handleSignup();
157
- } else if (response.authMethod === "existing") {
158
- apiKey = response.apiKey;
159
- } else if (response.authMethod === "skip") {
160
- apiKey = "YOUR_API_KEY_HERE";
187
+ let apiKey = options.teamKey || options.apiKey;
188
+ let apiKeyType = options.teamKey ? "team" : "project";
189
+ if (!apiKey) {
190
+ if (response.apiKeyType === "signup") {
191
+ apiKey = await handleSignup();
192
+ apiKeyType = "project";
193
+ } else if (response.apiKeyType === "project" || response.apiKeyType === "team") {
194
+ apiKey = response.apiKey;
195
+ apiKeyType = response.apiKeyType;
196
+ } else if (response.apiKeyType === "skip") {
197
+ apiKey = "YOUR_API_KEY_HERE";
198
+ apiKeyType = "none";
199
+ }
161
200
  }
162
201
  const packages = response.packages || [];
202
+ let llmProvider;
203
+ let llmApiKey;
204
+ if (packages.includes("runtime")) {
205
+ console.log(chalk.cyan("\n \u2139\uFE0F RLM-Runtime API Key Info:\n"));
206
+ console.log(chalk.dim(" \u2022 execute_python MCP tool: No LLM API key needed"));
207
+ console.log(chalk.dim(" (Your AI client - Claude, GPT, etc. - provides the LLM)"));
208
+ console.log(chalk.dim(" \u2022 rlm run / rlm agent CLI: Requires an LLM API key\n"));
209
+ const llmResponse = await prompts([
210
+ {
211
+ type: "select",
212
+ name: "llmProvider",
213
+ message: "Will you use rlm run/agent CLI? (requires LLM API key)",
214
+ choices: [
215
+ {
216
+ title: "No - I'll only use execute_python in my AI client",
217
+ value: "none",
218
+ description: "No additional API key needed"
219
+ },
220
+ {
221
+ title: "Yes - OpenAI (GPT-4, etc.)",
222
+ value: "openai",
223
+ description: "Requires OPENAI_API_KEY"
224
+ },
225
+ {
226
+ title: "Yes - Anthropic (Claude)",
227
+ value: "anthropic",
228
+ description: "Requires ANTHROPIC_API_KEY"
229
+ }
230
+ ]
231
+ },
232
+ {
233
+ type: (prev) => prev !== "none" ? "text" : null,
234
+ name: "llmApiKey",
235
+ message: (prev) => prev === "openai" ? "Enter your OpenAI API key (sk-...):" : "Enter your Anthropic API key (sk-ant-...):",
236
+ validate: (v, values) => {
237
+ if (values.llmProvider === "openai" && !v.startsWith("sk-")) {
238
+ return "OpenAI key should start with sk-";
239
+ }
240
+ if (values.llmProvider === "anthropic" && !v.startsWith("sk-ant-")) {
241
+ return "Anthropic key should start with sk-ant-";
242
+ }
243
+ return true;
244
+ }
245
+ }
246
+ ]);
247
+ llmProvider = llmResponse.llmProvider;
248
+ llmApiKey = llmResponse.llmApiKey;
249
+ }
163
250
  return {
164
251
  projectSlug: response.projectSlug,
165
252
  projectId: response.projectId || "",
166
253
  apiKey: apiKey || "YOUR_API_KEY_HERE",
254
+ apiKeyType,
167
255
  installMcp: packages.includes("mcp"),
168
256
  installRuntime: packages.includes("runtime"),
169
257
  installHooks: packages.includes("hooks"),
170
- aiClient: response.aiClient || detectedClient
258
+ aiClient: response.aiClient || detectedClient,
259
+ llmProvider,
260
+ llmApiKey
171
261
  };
172
262
  }
173
263
  async function handleSignup() {
@@ -474,12 +564,27 @@ async function updateEnvFiles(answers) {
474
564
  const envExamplePath = path.join(process.cwd(), ".env.example");
475
565
  const envLocalPath = path.join(process.cwd(), ".env.local");
476
566
  const envPath = path.join(process.cwd(), ".env");
477
- const envVars = `
567
+ let envVars = "";
568
+ if (answers.apiKeyType !== "none") {
569
+ envVars += `
478
570
  # Snipara Configuration
479
571
  SNIPARA_API_KEY=${answers.apiKey.includes("YOUR_") ? "your_api_key_here" : answers.apiKey}
480
572
  SNIPARA_PROJECT_SLUG=${answers.projectSlug}
481
573
  ${answers.projectId ? `SNIPARA_PROJECT_ID=${answers.projectId}` : ""}
482
574
  `.trim();
575
+ }
576
+ if (answers.llmProvider && answers.llmProvider !== "none" && answers.llmApiKey) {
577
+ const llmVarName = answers.llmProvider === "openai" ? "OPENAI_API_KEY" : "ANTHROPIC_API_KEY";
578
+ envVars += `
579
+
580
+ # RLM-Runtime LLM Provider (for rlm run/agent CLI)
581
+ ${llmVarName}=${answers.llmApiKey}`;
582
+ }
583
+ envVars = envVars.trim();
584
+ if (!envVars) {
585
+ console.log(chalk.dim(" No environment variables to save"));
586
+ return;
587
+ }
483
588
  if (fs.existsSync(envExamplePath)) {
484
589
  const content = fs.readFileSync(envExamplePath, "utf-8");
485
590
  if (!content.includes("SNIPARA_API_KEY")) {
@@ -561,9 +666,23 @@ function printSuccess(answers) {
561
666
  if (answers.installHooks) {
562
667
  console.log(chalk.green(" \u2713 Claude Code hooks") + chalk.dim(" - Session memory automation"));
563
668
  }
564
- console.log(chalk.green(" \u2713 .mcp.json") + chalk.dim(" - MCP server configuration"));
669
+ if (answers.apiKeyType !== "none") {
670
+ console.log(chalk.green(" \u2713 .mcp.json") + chalk.dim(" - MCP server configuration"));
671
+ }
672
+ if (answers.apiKeyType === "team") {
673
+ console.log(chalk.cyan("\n \u{1F511} Using Team API key - access to all team projects"));
674
+ } else if (answers.apiKeyType === "project") {
675
+ console.log(chalk.dim(`
676
+ \u{1F511} Using Project API key for: ${answers.projectSlug}`));
677
+ }
565
678
  console.log(chalk.bold("\nNext steps:\n"));
566
- if (answers.apiKey.includes("YOUR_")) {
679
+ if (answers.apiKeyType === "none" && answers.installRuntime) {
680
+ console.log(" 1. Restart your AI client (Claude Code, Cursor, etc.)");
681
+ console.log(" 2. Use execute_python MCP tool - no API key needed!");
682
+ console.log(chalk.dim("\n For rlm run/agent CLI, set one of these env vars:"));
683
+ console.log(chalk.dim(" export OPENAI_API_KEY=sk-..."));
684
+ console.log(chalk.dim(" export ANTHROPIC_API_KEY=sk-ant-..."));
685
+ } else if (answers.apiKey.includes("YOUR_") || answers.apiKeyType === "none") {
567
686
  console.log(` 1. Get your API key at ${chalk.cyan(`${BASE_URL}/signup`)}`);
568
687
  console.log(" 2. Update SNIPARA_API_KEY in .mcp.json");
569
688
  console.log(" 3. Restart your AI client");
@@ -573,11 +692,22 @@ function printSuccess(answers) {
573
692
  console.log(" 3. Start using MCP tools like rlm_context_query");
574
693
  }
575
694
  if (answers.installRuntime) {
576
- console.log(chalk.bold("\nRLM-Runtime commands:\n"));
577
- console.log(chalk.dim(" rlm init # Initialize configuration"));
578
- console.log(chalk.dim(" rlm run --env docker # Run with Docker isolation"));
579
- console.log(chalk.dim(" rlm serve # Start MCP server"));
580
- console.log(chalk.dim(" rlm visualize # Launch trajectory dashboard"));
695
+ console.log(chalk.bold("\nRLM-Runtime:\n"));
696
+ console.log(chalk.dim(" MCP tools (no LLM API key needed - your AI client provides the LLM):"));
697
+ console.log(chalk.dim(" \u2022 execute_python - Run Python in sandbox"));
698
+ console.log(chalk.dim(" \u2022 get_repl_context - Get session variables"));
699
+ if (answers.llmProvider && answers.llmProvider !== "none") {
700
+ const providerName = answers.llmProvider === "openai" ? "OpenAI" : "Anthropic";
701
+ console.log(chalk.dim(`
702
+ CLI commands (using ${providerName}):`));
703
+ console.log(chalk.dim(" \u2022 rlm run - Run with LLM orchestration"));
704
+ console.log(chalk.dim(" \u2022 rlm agent - Autonomous agent mode"));
705
+ console.log(chalk.dim(" \u2022 rlm visualize - Trajectory dashboard"));
706
+ } else {
707
+ console.log(chalk.dim("\n CLI commands (not configured - set LLM API key later if needed):"));
708
+ console.log(chalk.dim(" \u2022 rlm run - Requires OPENAI_API_KEY or ANTHROPIC_API_KEY"));
709
+ console.log(chalk.dim(" \u2022 rlm agent - Requires OPENAI_API_KEY or ANTHROPIC_API_KEY"));
710
+ }
581
711
  }
582
712
  console.log(chalk.dim(`
583
713
  Docs: ${BASE_URL}/docs`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-snipara",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Initialize Snipara MCP + RLM-Runtime with a single command - context optimization, semantic memory, and safe code execution",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",