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.
- package/dist/index.js +159 -29
- 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.
|
|
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:
|
|
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: "
|
|
88
|
-
message: "
|
|
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
|
-
{
|
|
91
|
-
|
|
92
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
577
|
-
console.log(chalk.dim("
|
|
578
|
-
console.log(chalk.dim("
|
|
579
|
-
console.log(chalk.dim("
|
|
580
|
-
|
|
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