create-snipara 1.3.11 → 1.3.13

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 +43 -39
  2. package/dist/index.js +252 -159
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -50,8 +50,8 @@ The product surfaces remain:
50
50
 
51
51
  The default CLI path wires the local companion around those surfaces:
52
52
 
53
- - `snipara-companion` for local `rlm-hook` workflows and managed phase commits
54
- - `rlm-runtime` for optional local code execution
53
+ - `snipara-companion` for local workflow commands and managed phase commits; legacy `rlm-hook` commands remain compatible
54
+ - `snipara-sandbox` for optional local code execution
55
55
  - local config, env files, hook scripts, and a project companion pack
56
56
  - `snipara-mcp` only for local stdio compatibility, development, or testing
57
57
 
@@ -59,12 +59,12 @@ The default CLI path wires the local companion around those surfaces:
59
59
 
60
60
  The CLI now works around explicit install profiles:
61
61
 
62
- | Profile | What it installs | Best for |
63
- | ------------------ | ----------------------------------------- | --------------------------------------------------- |
64
- | `hosted-companion` | MCP + `snipara-companion` | Default: hosted context plus managed local workflow |
65
- | `hosted-only` | Hosted MCP config only | Locked-down or minimal environments |
66
- | `full-stack` | MCP + `snipara-companion` + `rlm-runtime` | Hosted context plus sandboxed local execution |
67
- | `runtime-only` | `rlm-runtime` only | Local execution without hosted API |
62
+ | Profile | What it installs | Best for |
63
+ | ------------------ | --------------------------------------------- | --------------------------------------------------- |
64
+ | `hosted-companion` | MCP + `snipara-companion` | Default: hosted context plus managed local workflow |
65
+ | `hosted-only` | Hosted MCP config only | Locked-down or minimal environments |
66
+ | `full-stack` | MCP + `snipara-companion` + `snipara-sandbox` | Hosted context plus sandboxed local execution |
67
+ | `runtime-only` | `snipara-sandbox` only | Local execution without hosted API |
68
68
 
69
69
  Default profile: `hosted-companion`
70
70
 
@@ -76,7 +76,7 @@ Free onboarding is now **Context + Memory**, not Context-only:
76
76
  - Memory Free: reviewed hosted memories for continuity across sessions
77
77
  - Hosted MCP: direct connection for Claude Code, Codex, Cursor, ChatGPT Desktop, and other MCP clients
78
78
 
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 project key into the local MCP config.
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
 
81
81
  ## The Two Approval Paths
82
82
 
@@ -100,7 +100,7 @@ That distinction matters:
100
100
  - writes Hosted MCP configuration
101
101
  - detects a GitHub remote and can open the Snipara GitHub App automation path
102
102
  - installs `snipara-companion` by default for local managed workflows
103
- - installs optional `rlm-runtime`
103
+ - installs optional `snipara-sandbox`
104
104
  - configures `.mcp.json`
105
105
  - generates merge-ready AI agent templates in `.snipara/templates/`, including Pro+ symbol-card, code-impact, and managed workflow guidance for paid Context plans
106
106
  - creates `AGENTS.md`, `CLAUDE.md`, `.cursor/rules/snipara.mdc`, and `.codex/config.toml` when those files do not already exist
@@ -131,13 +131,13 @@ npx create-snipara
131
131
  The interactive flow now asks for:
132
132
 
133
133
  - project slug
134
- - API key path: project key, team key, free signup, or add key later
134
+ - API key path: existing API key, free signup, or add key later
135
135
  - AI client
136
136
 
137
137
  By default, this uses the recommended `hosted-companion` setup: hosted MCP plus
138
- the local `rlm-hook` workflow helper. Add `--advanced` when you want profile
139
- selection, project id entry, hook prompts, GitHub automation prompts, or runtime
140
- provider prompts.
138
+ the local `snipara-companion` workflow helper. Legacy `rlm-hook` commands remain
139
+ compatible. Add `--advanced` when you want profile selection, project id entry,
140
+ hook prompts, GitHub automation prompts, or sandbox provider prompts.
141
141
 
142
142
  The advanced flow asks for:
143
143
 
@@ -145,7 +145,7 @@ The advanced flow asks for:
145
145
  - optional project id
146
146
  - whether hooks should be generated
147
147
  - whether to open GitHub repository automation when a GitHub remote is detected
148
- - optional runtime provider config when `rlm-runtime` is installed
148
+ - optional sandbox provider config when `snipara-sandbox` is installed
149
149
 
150
150
  The generated agent templates cover:
151
151
 
@@ -158,12 +158,12 @@ The generated agent templates cover:
158
158
  When `snipara-companion` is installed, the companion pack also includes the compaction-safe managed workflow:
159
159
 
160
160
  ```bash
161
- rlm-hook workflow start --goal "ship auth hardening" --plan-file ./plan.md
162
- rlm-hook workflow phase-start context
163
- rlm-hook workflow run --mode full --include-session-context --query "load auth context"
164
- rlm-hook code impact --changed-files src/auth.ts tests/auth.test.ts --diff-summary "auth hardening"
165
- rlm-hook workflow phase-commit context --summary "Loaded context and mapped impacted files" --files src/auth.ts
166
- rlm-hook final-commit --summary "Shipped auth hardening and tests" --files src/auth.ts tests/auth.test.ts
161
+ snipara-companion workflow start --goal "ship auth hardening" --plan-file ./plan.md
162
+ snipara-companion workflow phase-start context
163
+ snipara-companion workflow run --mode full --include-session-context --query "load auth context"
164
+ snipara-companion code impact --changed-files src/auth.ts tests/auth.test.ts --diff-summary "auth hardening"
165
+ snipara-companion workflow phase-commit context --summary "Loaded context and mapped impacted files" --files src/auth.ts
166
+ snipara-companion final-commit --summary "Shipped auth hardening and tests" --files src/auth.ts tests/auth.test.ts
167
167
  ```
168
168
 
169
169
  ## Main Commands
@@ -187,7 +187,7 @@ Writes `.snipara/companion/doctor.json` and validates:
187
187
 
188
188
  - local config files
189
189
  - companion CLI presence
190
- - runtime CLI presence
190
+ - Snipara Sandbox CLI presence
191
191
  - environment files
192
192
  - hosted MCP reachability when a live API key is available
193
193
 
@@ -264,11 +264,11 @@ npx create-snipara --profile hosted-only
264
264
  npx create-snipara --profile full-stack
265
265
  npx create-snipara --advanced
266
266
 
267
- # Runtime-only local execution
267
+ # Sandbox-only local execution
268
268
  npx create-snipara --runtime-only
269
269
 
270
- # Non-interactive setup
271
- npx create-snipara -y --api-key rlm_xxx --slug my-project
270
+ # Non-interactive setup with an existing API key
271
+ npx create-snipara -y --api-key snp-xxx --slug my-project
272
272
 
273
273
  # Open GitHub automation after setup when a GitHub remote is detected
274
274
  npx create-snipara --github
@@ -292,9 +292,9 @@ npx create-snipara upgrade --with-runtime
292
292
  The intended split is:
293
293
 
294
294
  - `create-snipara`: Context + Memory onboarding, auth, config, inspect, repair, and upgrade
295
- - `snipara-companion`: default local workflow helper through `rlm-hook`; optional only for `hosted-only`
295
+ - `snipara-companion`: default local workflow helper; legacy `rlm-hook` commands remain compatible
296
296
  - `snipara-mcp`: local stdio bridge, client-package development, compatibility, and testing
297
- - `rlm-runtime`: optional local execution engine
297
+ - `snipara-sandbox`: optional local execution engine
298
298
 
299
299
  ## Codex Setup
300
300
 
@@ -324,8 +324,8 @@ This pack is meant to be the local source of truth for machine-level setup. When
324
324
  such as:
325
325
 
326
326
  ```bash
327
- rlm-hook onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json
328
- rlm-hook onboard-folder ./client-export --source-provider local_folder --apply
327
+ snipara-companion onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json
328
+ snipara-companion onboard-folder ./client-export --source-provider local_folder --apply
329
329
  ```
330
330
 
331
331
  Use this for dashboardless business-context imports after an LLM client has
@@ -356,13 +356,17 @@ Recommended explanation to users:
356
356
 
357
357
  ## API Key Requirements
358
358
 
359
- | Tooling | Snipara API key | LLM API key |
360
- | ------------------------------------ | -------------------------- | ----------- |
361
- | Hosted MCP queries | Required | Not needed |
362
- | Memory / planning tools | Required with memory scope | Not needed |
363
- | `snipara-companion` hosted workflows | Optional | Not needed |
364
- | `rlm-runtime` `execute_python` MCP | Not needed | Not needed |
365
- | `rlm run` / `rlm agent` CLI | Optional for context | Required |
359
+ Existing manual API keys passed to `create-snipara --api-key` should start with `snp-`;
360
+ legacy `rlm_` keys remain accepted for migration. When `create-snipara` provisions a
361
+ new account through the browser flow, Snipara returns a new `snp-` key from the current hosted API.
362
+
363
+ | Tooling | Snipara API key | LLM API key |
364
+ | --------------------------------------------------- | -------------------------- | ----------- |
365
+ | Hosted MCP queries | Required | Not needed |
366
+ | Memory / planning tools | Required with memory scope | Not needed |
367
+ | `snipara-companion` hosted workflows | Optional | Not needed |
368
+ | `snipara-sandbox` `execute_python` MCP | Not needed | Not needed |
369
+ | `snipara-sandbox run` / `snipara-sandbox agent` CLI | Optional for context | Required |
366
370
 
367
371
  ## Example Flows
368
372
 
@@ -372,7 +376,7 @@ Recommended explanation to users:
372
376
  npx create-snipara
373
377
  ```
374
378
 
375
- Best when the user wants Hosted MCP Context + Memory plus `rlm-hook` managed workflows.
379
+ Best when the user wants Hosted MCP Context + Memory plus `snipara-companion` managed workflows.
376
380
 
377
381
  ### Minimal hosted setup
378
382
 
@@ -388,7 +392,7 @@ Best when the user only wants Hosted MCP Context + Memory and cannot install loc
388
392
  npx create-snipara --profile full-stack --advanced
389
393
  ```
390
394
 
391
- Best when the user also wants sandboxed `rlm-runtime` execution.
395
+ Best when the user also wants sandboxed `snipara-sandbox` execution.
392
396
 
393
397
  ### Connect the current repository
394
398
 
@@ -433,7 +437,7 @@ npx create-snipara print-config --json
433
437
  When testing a locally packed tarball, use `npm exec --package` instead of `npx`, for example:
434
438
 
435
439
  ```bash
436
- npm exec --package ./create-snipara-1.3.11.tgz create-snipara -- --help
440
+ npm exec --package ./create-snipara-1.3.13.tgz create-snipara -- --help
437
441
  ```
438
442
 
439
443
  This avoids `npx` resolution issues with unpublished tarballs.
package/dist/index.js CHANGED
@@ -9,12 +9,18 @@ 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.11";
12
+ var VERSION = "1.3.13";
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";
16
+ var COMPANION_COMMAND_NAME = "snipara-companion";
17
+ var LEGACY_COMPANION_COMMAND_NAME = "rlm-hook";
16
18
  var MCP_PACKAGE_NAME = "snipara-mcp";
17
- var RUNTIME_PACKAGE_NAME = "rlm-runtime[all]";
19
+ var SANDBOX_PACKAGE_NAME = "snipara-sandbox[all]";
20
+ var SANDBOX_SERVER_NAME = "snipara-sandbox";
21
+ var LEGACY_RUNTIME_SERVER_NAME = "rlm-runtime";
22
+ var SANDBOX_COMMAND_NAME = "snipara-sandbox";
23
+ var LEGACY_SANDBOX_COMMAND_NAME = "rlm";
18
24
  var DEVICE_CLIENT_ID = "create-snipara";
19
25
  var DeviceAuthorizationAborted = class extends Error {
20
26
  };
@@ -27,10 +33,10 @@ function getCompanionInitClientFlag(aiClient) {
27
33
  function buildProgram() {
28
34
  const program = new Command();
29
35
  program.name("create-snipara").description("Scaffold hosted Snipara MCP config plus companion workflow helpers").version(VERSION);
30
- program.command("init").description("Install and configure Snipara for this project").option("--api-key <key>", "Snipara project API key").option("--team-key <key>", "Snipara team API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option("--advanced", "Show advanced profile, project id, hooks, GitHub, and runtime prompts").option(
36
+ 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(
31
37
  "--profile <profile>",
32
38
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
33
- ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip rlm-runtime installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").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 RLM-Runtime").option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
39
+ ).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("--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").option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
34
40
  printBanner();
35
41
  await runInit(options);
36
42
  });
@@ -38,11 +44,11 @@ function buildProgram() {
38
44
  printBanner();
39
45
  await runDoctor(options);
40
46
  });
41
- program.command("repair").description("Rebuild local Snipara config and re-run validation").option("--api-key <key>", "Snipara project API key override").option("--team-key <key>", "Snipara team API key override").option("--slug <slug>", "Project slug override").option("--project-id <id>", "Project ID override").option("--profile <profile>", "Target install profile").option("--with-hooks", "Force hook generation").option("--with-runtime", "Force runtime server/config").option("--with-mcp", "Force MCP config").option("--with-companion", "Force companion pack generation").action(async (options) => {
47
+ program.command("repair").description("Rebuild local Snipara config and re-run validation").option("--api-key <key>", "Snipara API key override").option("--slug <slug>", "Project slug override").option("--project-id <id>", "Project ID override").option("--profile <profile>", "Target install profile").option("--with-hooks", "Force hook generation").option("--with-runtime", "Force Snipara Sandbox server/config").option("--with-mcp", "Force MCP config").option("--with-companion", "Force companion pack generation").action(async (options) => {
42
48
  printBanner();
43
49
  await runRepair(options);
44
50
  });
45
- program.command("upgrade").description("Upgrade installed Snipara local components").option("--with-hooks", "Refresh hooks after upgrade").option("--with-runtime", "Upgrade runtime even if not detected").option("--with-mcp", "Upgrade snipara-mcp even if not detected").option("--with-companion", "Upgrade companion even if not detected").action(async (options) => {
51
+ program.command("upgrade").description("Upgrade installed Snipara local components").option("--with-hooks", "Refresh hooks after upgrade").option("--with-runtime", "Upgrade Snipara Sandbox even if not detected").option("--with-mcp", "Upgrade snipara-mcp even if not detected").option("--with-companion", "Upgrade companion even if not detected").action(async (options) => {
46
52
  printBanner();
47
53
  await runUpgrade(options);
48
54
  });
@@ -58,10 +64,10 @@ function buildProgram() {
58
64
  return program;
59
65
  }
60
66
  function addSharedRootOptions(program) {
61
- program.option("--api-key <key>", "Snipara project API key").option("--team-key <key>", "Snipara team API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option("--advanced", "Show advanced profile, project id, hooks, GitHub, and runtime prompts").option(
67
+ 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(
62
68
  "--profile <profile>",
63
69
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
64
- ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip rlm-runtime installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").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 RLM-Runtime").option("-y, --yes", "Accept defaults without prompting");
70
+ ).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("--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").option("-y, --yes", "Accept defaults without prompting");
65
71
  }
66
72
  async function main() {
67
73
  const program = buildProgram();
@@ -81,7 +87,6 @@ function parseInitOptionsFromArgv(args) {
81
87
  const parsed = {};
82
88
  const valueFlags = {
83
89
  "--api-key": "apiKey",
84
- "--team-key": "teamKey",
85
90
  "--slug": "slug",
86
91
  "--project-id": "projectId",
87
92
  "--profile": "profile",
@@ -145,8 +150,8 @@ async function runInit(options) {
145
150
  if (answers.configureGitHub && answers.githubRepo) {
146
151
  await openGitHubAutomation(answers);
147
152
  }
148
- if (answers.runRlmInit && answers.installRuntime) {
149
- await runRlmInit();
153
+ if (answers.runSandboxInit && answers.installRuntime) {
154
+ await runSandboxInit();
150
155
  }
151
156
  }
152
157
  async function runDoctor(options) {
@@ -223,7 +228,7 @@ async function runPrintConfig(options) {
223
228
  ` Hosted MCP config: ${answers.profile !== "runtime-only" ? "enabled" : "disabled"}`
224
229
  );
225
230
  console.log(` Local snipara-mcp package: ${answers.installMcp ? "enabled" : "disabled"}`);
226
- console.log(` Runtime: ${answers.installRuntime ? "enabled" : "disabled"}`);
231
+ console.log(` Snipara Sandbox: ${answers.installRuntime ? "enabled" : "disabled"}`);
227
232
  console.log(` Hooks: ${answers.installHooks ? "enabled" : "disabled"}`);
228
233
  console.log(` Existing .mcp.json: ${detection.files.mcpConfig ? "yes" : "no"}`);
229
234
  console.log(` Companion pack: ${detection.files.sniparaCompanionPack ? "yes" : "no"}`);
@@ -239,7 +244,7 @@ function printBanner() {
239
244
  \u2551 \u2022 Hosted MCP for LLM agents \u2551
240
245
  \u2551 \u2022 Free account path with hosted context and reviewed memory \u2551
241
246
  \u2551 \u2022 API / SDK for product integrations \u2551
242
- \u2551 \u2022 Optional local companion and runtime helpers \u2551
247
+ \u2551 \u2022 Optional local companion and Snipara Sandbox helpers \u2551
243
248
  \u2551 \u2022 One CLI for auth, config, doctor, repair, and upgrade \u2551
244
249
  \u2551 \u2551
245
250
  \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
@@ -267,12 +272,16 @@ async function gatherConfiguration(options) {
267
272
  detectedProjectId = existingConfig.projectId || "";
268
273
  }
269
274
  const initialProfile = resolveRequestedProfile(options);
275
+ const providedApiKey = options.apiKey?.trim();
276
+ if (providedApiKey && !isManualApiKey(providedApiKey)) {
277
+ throw new Error(manualApiKeyValidationMessage());
278
+ }
270
279
  if (options.yes) {
271
280
  return buildAnswersFromProfile({
272
281
  projectSlug: options.slug || detectedSlug || "my-project",
273
282
  projectId: options.projectId || detectedProjectId,
274
- apiKey: options.teamKey || options.apiKey || "YOUR_API_KEY_HERE",
275
- apiKeyType: options.teamKey ? "team" : options.apiKey ? "project" : "none",
283
+ apiKey: providedApiKey || "YOUR_API_KEY_HERE",
284
+ apiKeyType: providedApiKey ? "api" : "none",
276
285
  profile: initialProfile,
277
286
  aiClient: detectedClient,
278
287
  skipCompanion: !!options.skipCompanion,
@@ -306,19 +315,14 @@ async function gatherConfiguration(options) {
306
315
  initial: options.projectId || detectedProjectId || ""
307
316
  },
308
317
  {
309
- type: (_, values) => values.profile === "runtime-only" || options.apiKey || options.teamKey ? null : "select",
318
+ type: (_, values) => values.profile === "runtime-only" || providedApiKey ? null : "select",
310
319
  name: "apiKeyType",
311
- message: "What type of API key do you have?",
320
+ message: "How do you want to add your Snipara API key?",
312
321
  choices: [
313
322
  {
314
- title: "Project API key",
315
- value: "project",
316
- description: "Access to a single project"
317
- },
318
- {
319
- title: "Team API key",
320
- value: "team",
321
- description: "Access to all projects in your team"
323
+ title: "I have an API key",
324
+ value: "api",
325
+ description: "Paste an API key that starts with snp- or legacy rlm_"
322
326
  },
323
327
  {
324
328
  title: "Create free Context + Memory account",
@@ -332,10 +336,10 @@ async function gatherConfiguration(options) {
332
336
  ]
333
337
  },
334
338
  {
335
- type: (_, values) => values.profile === "runtime-only" ? null : values.apiKeyType === "project" || values.apiKeyType === "team" ? "text" : null,
339
+ type: (_, values) => values.profile === "runtime-only" ? null : values.apiKeyType === "api" ? "text" : null,
336
340
  name: "apiKey",
337
- message: (_, values) => values.apiKeyType === "team" ? "Enter your Team API key:" : "Enter your Project API key:",
338
- validate: (value) => value.startsWith("rlm_") ? true : "API key should start with rlm_"
341
+ message: (_, values) => values.apiKeyType === "api" ? "Enter your Snipara API key:" : "Enter your API key:",
342
+ validate: (value) => isManualApiKey(value) ? true : manualApiKeyValidationMessage()
339
343
  },
340
344
  {
341
345
  type: "select",
@@ -392,17 +396,17 @@ async function gatherConfiguration(options) {
392
396
  initial: options.githubPath || ""
393
397
  }
394
398
  ]);
395
- let apiKey = options.teamKey || options.apiKey;
396
- let apiKeyType = response.profile === "runtime-only" ? "none" : options.teamKey ? "team" : options.apiKey ? "project" : "none";
399
+ let apiKey = providedApiKey;
400
+ let apiKeyType = response.profile === "runtime-only" ? "none" : providedApiKey ? "api" : "none";
397
401
  let signupResult = null;
398
402
  if (!apiKey && response.profile !== "runtime-only") {
399
403
  if (response.apiKeyType === "signup") {
400
404
  signupResult = await handleSignup();
401
405
  apiKey = signupResult.apiKey;
402
- apiKeyType = "project";
403
- } else if (response.apiKeyType === "project" || response.apiKeyType === "team") {
406
+ apiKeyType = "api";
407
+ } else if (response.apiKeyType === "api") {
404
408
  apiKey = response.apiKey;
405
- apiKeyType = response.apiKeyType;
409
+ apiKeyType = "api";
406
410
  } else {
407
411
  apiKey = "YOUR_API_KEY_HERE";
408
412
  apiKeyType = "none";
@@ -430,7 +434,7 @@ async function gatherConfiguration(options) {
430
434
  {
431
435
  type: "select",
432
436
  name: "llmProvider",
433
- message: "Will you use rlm run/agent CLI too?",
437
+ message: "Will you use the Snipara Sandbox run/agent CLI too?",
434
438
  choices: [
435
439
  {
436
440
  title: "No - execute_python only",
@@ -465,14 +469,14 @@ async function gatherConfiguration(options) {
465
469
  },
466
470
  {
467
471
  type: "confirm",
468
- name: "runRlmInit",
469
- message: "Run 'rlm init' now to choose sandbox/docker/local?",
472
+ name: "runSandboxInit",
473
+ message: "Run Snipara Sandbox init now to choose sandbox/docker/local?",
470
474
  initial: false
471
475
  }
472
476
  ]);
473
477
  answers.llmProvider = runtimeResponse.llmProvider;
474
478
  answers.llmApiKey = runtimeResponse.llmApiKey;
475
- answers.runRlmInit = runtimeResponse.runRlmInit || false;
479
+ answers.runSandboxInit = runtimeResponse.runSandboxInit || false;
476
480
  }
477
481
  return answers;
478
482
  }
@@ -498,17 +502,17 @@ function installProfileChoices() {
498
502
  {
499
503
  title: "Hosted only",
500
504
  value: "hosted-only",
501
- description: "Minimal setup: hosted MCP config, no local companion or runtime"
505
+ description: "Minimal setup: hosted MCP config, no local companion or sandbox"
502
506
  },
503
507
  {
504
- title: "Hosted + Companion + Runtime",
508
+ title: "Hosted + Companion + Sandbox",
505
509
  value: "full-stack",
506
- description: "Add sandboxed local runtime execution as well"
510
+ description: "Add Snipara Sandbox local execution as well"
507
511
  },
508
512
  {
509
- title: "Runtime only",
513
+ title: "Sandbox only",
510
514
  value: "runtime-only",
511
- description: "Local execution only, no hosted API key required"
515
+ description: "Snipara Sandbox execution only, no hosted API key required"
512
516
  }
513
517
  ];
514
518
  }
@@ -582,8 +586,8 @@ async function handleManualSignup() {
582
586
  const response = await prompts({
583
587
  type: "text",
584
588
  name: "apiKey",
585
- message: "Paste your Project API key when ready:",
586
- validate: (value) => value.startsWith("rlm_") ? true : "API key should start with rlm_"
589
+ message: "Paste your API key when ready:",
590
+ validate: (value) => isProvisionedApiKey(value) ? true : provisionedApiKeyValidationMessage()
587
591
  });
588
592
  return { apiKey: response.apiKey };
589
593
  }
@@ -618,7 +622,10 @@ async function runDeviceAuthorization() {
618
622
  );
619
623
  if (!tokenResponse.error) {
620
624
  if (!tokenResponse.api_key) {
621
- throw new Error("Device flow completed but no project API key was returned");
625
+ throw new Error("Device flow completed but no API key was returned");
626
+ }
627
+ if (!isProvisionedApiKey(tokenResponse.api_key)) {
628
+ throw new Error("Device flow returned an API key that does not start with snp-");
622
629
  }
623
630
  spinner.succeed(
624
631
  tokenResponse.project_name ? `Authorized ${tokenResponse.project_name}` : "Authorized Snipara account"
@@ -669,6 +676,37 @@ function openBrowser(url) {
669
676
  function sleep(ms) {
670
677
  return new Promise((resolve) => setTimeout(resolve, ms));
671
678
  }
679
+ function isManualApiKey(value) {
680
+ const trimmed = value.trim();
681
+ return trimmed.startsWith("snp-") || trimmed.startsWith("rlm_");
682
+ }
683
+ function manualApiKeyValidationMessage() {
684
+ return "API key should start with snp- or legacy rlm_";
685
+ }
686
+ function isProvisionedApiKey(value) {
687
+ return value.trim().startsWith("snp-");
688
+ }
689
+ function provisionedApiKeyValidationMessage() {
690
+ return "New Snipara API keys should start with snp-";
691
+ }
692
+ function detectCompanionCommand() {
693
+ if (commandExists(COMPANION_COMMAND_NAME)) {
694
+ return COMPANION_COMMAND_NAME;
695
+ }
696
+ if (commandExists(LEGACY_COMPANION_COMMAND_NAME)) {
697
+ return LEGACY_COMPANION_COMMAND_NAME;
698
+ }
699
+ return null;
700
+ }
701
+ function detectSandboxCommand() {
702
+ if (commandExists(SANDBOX_COMMAND_NAME)) {
703
+ return SANDBOX_COMMAND_NAME;
704
+ }
705
+ if (commandExists(LEGACY_SANDBOX_COMMAND_NAME)) {
706
+ return LEGACY_SANDBOX_COMMAND_NAME;
707
+ }
708
+ return null;
709
+ }
672
710
  async function installPythonPackages(answers, upgrade) {
673
711
  console.log(chalk.bold(`
674
712
  \u{1F4E6} ${upgrade ? "Upgrading" : "Installing"} Python Packages
@@ -680,7 +718,7 @@ async function installPythonPackages(answers, upgrade) {
680
718
  console.log(chalk.gray(` pip install ${upgrade ? "-U " : ""}${MCP_PACKAGE_NAME}`));
681
719
  }
682
720
  if (answers.installRuntime) {
683
- console.log(chalk.gray(` pip install ${upgrade ? "-U " : ""}${RUNTIME_PACKAGE_NAME}`));
721
+ console.log(chalk.gray(` pip install ${upgrade ? "-U " : ""}${SANDBOX_PACKAGE_NAME}`));
684
722
  }
685
723
  console.log("");
686
724
  return;
@@ -690,27 +728,40 @@ async function installPythonPackages(answers, upgrade) {
690
728
  packages.push(MCP_PACKAGE_NAME);
691
729
  }
692
730
  if (answers.installRuntime) {
693
- packages.push(RUNTIME_PACKAGE_NAME);
731
+ packages.push(SANDBOX_PACKAGE_NAME);
694
732
  }
695
733
  if (packages.length === 0) return;
696
734
  const spinner = ora(
697
735
  `${upgrade ? "Upgrading" : "Installing"} ${packages.map(stripExtras).join(", ")}...`
698
736
  ).start();
699
- try {
700
- const installCmd = pipCmd === "uv" ? `uv pip install ${upgrade ? "--upgrade " : ""}${packages.join(" ")}` : `${pipCmd} install ${upgrade ? "--upgrade " : ""}${packages.join(" ")}`;
701
- execSync(installCmd, {
702
- stdio: "pipe",
703
- encoding: "utf-8"
704
- });
705
- spinner.succeed(
706
- `${upgrade ? "Upgraded" : "Installed"} ${packages.map(stripExtras).join(", ")}`
707
- );
708
- } catch {
709
- spinner.fail(`Failed to ${upgrade ? "upgrade" : "install"} Python packages`);
710
- console.log(chalk.yellow("\n Install manually with:"));
711
- console.log(chalk.gray(` pip install ${upgrade ? "--upgrade " : ""}${packages.join(" ")}
712
- `));
737
+ const attempts = [packages];
738
+ const failures = [];
739
+ for (const attemptPackages of attempts) {
740
+ try {
741
+ const installCmd = pipCmd === "uv" ? `uv pip install ${upgrade ? "--upgrade " : ""}${attemptPackages.join(" ")}` : `${pipCmd} install ${upgrade ? "--upgrade " : ""}${attemptPackages.join(" ")}`;
742
+ execSync(installCmd, {
743
+ stdio: "pipe",
744
+ encoding: "utf-8"
745
+ });
746
+ spinner.succeed(
747
+ `${upgrade ? "Upgraded" : "Installed"} ${attemptPackages.map(stripExtras).join(", ")}`
748
+ );
749
+ return;
750
+ } catch (error) {
751
+ const detail = error instanceof Error && "message" in error ? error.message.split("\n")[0] : "unknown error";
752
+ failures.push(`${attemptPackages.join(" ")}: ${detail}`);
753
+ }
754
+ }
755
+ spinner.fail(`Failed to ${upgrade ? "upgrade" : "install"} Python packages`);
756
+ if (failures.length > 0) {
757
+ console.log(chalk.yellow("\n Attempt summary:"));
758
+ for (const failure of failures) {
759
+ console.log(chalk.gray(` - ${failure}`));
760
+ }
713
761
  }
762
+ console.log(chalk.yellow("\n Install manually with:"));
763
+ console.log(chalk.gray(` pip install ${upgrade ? "--upgrade " : ""}${packages.join(" ")}
764
+ `));
714
765
  }
715
766
  function stripExtras(name) {
716
767
  return name.replace(/\[.*\]$/, "");
@@ -753,14 +804,15 @@ async function installNodeCompanion(upgrade) {
753
804
  stdio: "pipe",
754
805
  encoding: "utf-8"
755
806
  });
756
- if (commandExists("rlm-hook")) {
807
+ const installedCommand = detectCompanionCommand();
808
+ if (installedCommand) {
757
809
  spinner.succeed(
758
810
  `${upgrade ? "Upgraded" : "Installed"} ${COMPANION_PACKAGE_NAME} via ${packageManager}`
759
811
  );
760
812
  return;
761
813
  }
762
814
  failures.push(
763
- `${packageManager}: command completed but rlm-hook is still not available on PATH`
815
+ `${packageManager}: command completed but ${COMPANION_COMMAND_NAME} is still not available on PATH (legacy ${LEGACY_COMPANION_COMMAND_NAME} is also accepted)`
764
816
  );
765
817
  } catch (error) {
766
818
  const detail = error instanceof Error && "message" in error ? error.message.split("\n")[0] : "unknown error";
@@ -802,7 +854,7 @@ async function createMcpConfig(answers) {
802
854
  };
803
855
  }
804
856
  if (answers.installRuntime) {
805
- mcpConfig.mcpServers["rlm-runtime"] = {
857
+ mcpConfig.mcpServers[SANDBOX_SERVER_NAME] = {
806
858
  type: "http",
807
859
  url: "http://localhost:8765/mcp",
808
860
  headers: {}
@@ -887,25 +939,25 @@ function buildAgentsMdTemplate(answers) {
887
939
  This project uses Snipara Hosted MCP for project context and reviewed memory.
888
940
 
889
941
  - Endpoint: \`${buildHostedMcpEndpoint(answers)}\`
890
- - Auth: use \`SNIPARA_API_KEY\` or \`RLM_API_KEY\` from the environment. Never commit keys.
942
+ - Auth: use \`SNIPARA_API_KEY\` from the environment. Never commit keys.
891
943
 
892
944
  Agent task lifecycle:
893
945
 
894
- 1. Start substantial work with \`rlm_recall\` and a targeted \`rlm_context_query\`.
895
- 2. Use \`rlm_context_query\` for docs, business context, client/project truth, architecture notes, runbooks, and narrative source material.
896
- 3. When \`rlm_context_query\` returns \`answer_pack\`, treat it as the first-pass response plan: use its source facts, caveats, source map, and verification checklist before drafting claims.
897
- 4. Use \`rlm_get_chunk\` to load cited source sections returned by reference-based queries before relying on precise wording.
898
- 5. Use \`rlm_code_callers\`, \`rlm_code_imports\`, \`rlm_code_neighbors\`, or \`rlm_code_shortest_path\` for structural code questions.
899
- 6. On paid Context plans, use \`rlm_code_symbol_card\` for agent-ready symbol context and \`rlm_code_impact\` before risky multi-file changes or PR reviews.
900
- 7. Use \`rlm_plan\` or \`rlm_decompose\` only for complex work and only when the hosted server exposes them.
901
- 8. When the LLM has produced a visible multi-phase plan and \`snipara-companion\` is installed, run \`rlm-hook workflow start --goal "<goal>" --plan-file <plan_file>\`, then use \`workflow phase-start\`, \`workflow phase-commit\`, \`workflow resume\`, and \`final-commit\` so compaction cannot lose the next phase.
946
+ 1. Start substantial work with \`snipara_recall\` and a targeted \`snipara_context_query\`.
947
+ 2. Use \`snipara_context_query\` for docs, business context, client/project truth, architecture notes, runbooks, and narrative source material.
948
+ 3. When \`snipara_context_query\` returns \`answer_pack\`, treat it as the first-pass response plan: use its source facts, caveats, source map, and verification checklist before drafting claims.
949
+ 4. Use \`snipara_get_chunk\` to load cited source sections returned by reference-based queries before relying on precise wording.
950
+ 5. Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for structural code questions.
951
+ 6. On paid Context plans, use \`snipara_code_symbol_card\` for agent-ready symbol context and \`snipara_code_impact\` before risky multi-file changes or PR reviews.
952
+ 7. Use \`snipara_plan\` or \`snipara_decompose\` only for complex work and only when the hosted server exposes them.
953
+ 8. When the LLM has produced a visible multi-phase plan and \`snipara-companion\` is installed, run \`snipara-companion workflow start --goal "<goal>" --plan-file <plan_file>\`, then use \`workflow phase-start\`, \`workflow phase-commit\`, \`workflow resume\`, and \`final-commit\` so compaction cannot lose the next phase. Legacy \`rlm-hook\` commands remain compatible.
902
954
  9. Use local file reads, \`rg\`, git commands, and test commands for exact edits, current working-tree state, and verification.
903
- 10. Treat every \`rlm_code_*\` response as indexed context: check its indexed commit SHA, indexing time, included file sample, coverage, freshness warnings, and sync guidance before relying on it.
955
+ 10. Treat every \`snipara_code_*\` response as indexed context: check its indexed commit SHA, indexing time, included file sample, coverage, freshness warnings, and sync guidance before relying on it. Legacy \`rlm_code_*\` tool IDs return the same payloads.
904
956
  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.
905
- 12. Use RLM Runtime only when sandboxed execution, repeatable validation, or isolated transformations materially help.
957
+ 12. Use Snipara Sandbox only when sandboxed execution, repeatable validation, or isolated transformations materially help.
906
958
  13. If a broad query is slow, retry once with a narrow keyword query before falling back to local search.
907
- 14. End each substantial phase with \`rlm_end_of_task_commit\` or \`rlm-hook workflow phase-commit\` when companion manages the plan. End the whole managed workflow with \`rlm-hook final-commit\`.
908
- 15. Use \`rlm_remember_if_novel\` for one reusable memory while avoiding duplicates, and use \`rlm_remember\` for explicit direct memory writes.
959
+ 14. 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\`.
960
+ 15. Use \`snipara_remember_if_novel\` for one reusable memory while avoiding duplicates, and use \`snipara_remember\` for explicit direct memory writes.
909
961
  16. Do not store secrets, tokens, passwords, private keys, raw logs, transient command output, or unreviewed guesses in memory.
910
962
  `;
911
963
  }
@@ -919,17 +971,17 @@ Canonical project context is in \`AGENTS.md\`. This file exists for Claude Code
919
971
  Use Snipara Hosted MCP before answering project-specific questions.
920
972
 
921
973
  - Endpoint: \`${buildHostedMcpEndpoint(answers)}\`
922
- - Start substantial work with \`rlm_recall\` and a targeted \`rlm_context_query\`.
923
- - Use \`rlm_context_query\` for source truth and \`rlm_get_chunk\` for exact cited sections.
924
- - When \`rlm_context_query\` returns \`answer_pack\`, use its facts, caveats, source map, and verification checklist before drafting claims.
925
- - Use \`rlm_code_callers\`, \`rlm_code_imports\`, \`rlm_code_neighbors\`, or \`rlm_code_shortest_path\` for structural code questions.
926
- - On paid Context plans, use \`rlm_code_symbol_card\` before editing important symbols and \`rlm_code_impact\` before risky multi-file changes or PR reviews.
927
- - Check every \`rlm_code_*\` response for indexed commit SHA, indexing time, included files, coverage, and freshness warnings.
974
+ - Start substantial work with \`snipara_recall\` and a targeted \`snipara_context_query\`.
975
+ - Use \`snipara_context_query\` for source truth and \`snipara_get_chunk\` for exact cited sections.
976
+ - When \`snipara_context_query\` returns \`answer_pack\`, use its facts, caveats, source map, and verification checklist before drafting claims.
977
+ - Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for structural code questions.
978
+ - On paid Context plans, use \`snipara_code_symbol_card\` before editing important symbols and \`snipara_code_impact\` before risky multi-file changes or PR reviews.
979
+ - 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.
928
980
  - 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.
929
- - When the plan is visible and \`snipara-companion\` is installed, use \`rlm-hook workflow start\`, \`phase-start\`, \`phase-commit\`, \`workflow resume\`, and \`final-commit\` to keep phase state durable across compaction.
930
- - Use RLM Runtime only when sandboxed execution or repeatable validation materially helps.
931
- - End substantial work with \`rlm_end_of_task_commit\` when available; for managed workflows, end every phase with \`rlm-hook workflow phase-commit\` and the task with \`rlm-hook final-commit\`.
932
- - Use \`rlm_remember_if_novel\` or \`rlm_remember\` only for narrow durable memories.
981
+ - 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.
982
+ - Use Snipara Sandbox only when sandboxed execution or repeatable validation materially helps.
983
+ - 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\`.
984
+ - Use \`snipara_remember_if_novel\` or \`snipara_remember\` only for narrow durable memories.
933
985
  - Do not store secrets, one-off command output, raw logs, or unreviewed guesses in memory.
934
986
  - Use the Snipara Claude Code plugin only when slash commands, skills, or hooks are helpful; Hosted MCP remains the normal agent path.
935
987
  `;
@@ -946,18 +998,18 @@ This workspace uses Snipara Hosted MCP for current project context, business/cli
946
998
 
947
999
  - Check the configured Snipara MCP server before answering project-specific questions.
948
1000
  - Endpoint: \`${buildHostedMcpEndpoint(answers)}\`
949
- - Use \`rlm_recall\` for durable decisions, preferences, and validated learnings.
950
- - Use \`rlm_context_query\` for docs, business context, current client/project truth, and narrative source material.
951
- - When \`rlm_context_query\` returns \`answer_pack\`, use its facts, caveats, source map, and verification checklist before drafting claims.
952
- - Use \`rlm_get_chunk\` before relying on exact cited wording from reference-based results.
953
- - Use \`rlm_code_callers\`, \`rlm_code_imports\`, \`rlm_code_neighbors\`, or \`rlm_code_shortest_path\` for structural code questions.
954
- - On paid Context plans, use \`rlm_code_symbol_card\` before editing important symbols and \`rlm_code_impact\` before risky multi-file changes or PR reviews.
955
- - Check every \`rlm_code_*\` response for indexed commit SHA, indexing time, included files, coverage, and freshness warnings.
956
- - Use \`rlm_plan\` or \`rlm_decompose\` only for complex work and only when available.
1001
+ - Use \`snipara_recall\` for durable decisions, preferences, and validated learnings.
1002
+ - Use \`snipara_context_query\` for docs, business context, current client/project truth, and narrative source material.
1003
+ - When \`snipara_context_query\` returns \`answer_pack\`, use its facts, caveats, source map, and verification checklist before drafting claims.
1004
+ - Use \`snipara_get_chunk\` before relying on exact cited wording from reference-based results.
1005
+ - Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for structural code questions.
1006
+ - On paid Context plans, use \`snipara_code_symbol_card\` before editing important symbols and \`snipara_code_impact\` before risky multi-file changes or PR reviews.
1007
+ - 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.
1008
+ - Use \`snipara_plan\` or \`snipara_decompose\` only for complex work and only when available.
957
1009
  - Use local file reads, \`rg\`, \`git status --short\`, and tests for exact code edits and current working-tree state.
958
- - When \`snipara-companion\` is installed and the LLM has a visible multi-phase plan, use \`rlm-hook workflow start\`, \`phase-start\`, \`phase-commit\`, \`workflow resume\`, and \`final-commit\` so the next phase survives compaction.
959
- - Use RLM Runtime only when sandboxed execution or repeatable validation materially helps.
960
- - End substantial work with \`rlm_end_of_task_commit\` when available; for managed workflows, end every phase with \`rlm-hook workflow phase-commit\` and the task with \`rlm-hook final-commit\`. Use \`rlm_remember_if_novel\` or \`rlm_remember\` only for narrow durable memories. Never store secrets.
1010
+ - 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.
1011
+ - Use Snipara Sandbox only when sandboxed execution or repeatable validation materially helps.
1012
+ - 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.
961
1013
  `;
962
1014
  }
963
1015
  function buildCodexConfigTemplate(answers) {
@@ -1022,8 +1074,8 @@ async function createClaudeDesktopConfig(answers) {
1022
1074
  }
1023
1075
  };
1024
1076
  if (answers.installRuntime) {
1025
- config.mcpServers["rlm-runtime"] = {
1026
- command: "rlm",
1077
+ config.mcpServers[SANDBOX_SERVER_NAME] = {
1078
+ command: detectSandboxCommand() || SANDBOX_COMMAND_NAME,
1027
1079
  args: ["mcp-serve"],
1028
1080
  env: {
1029
1081
  SNIPARA_API_KEY: answers.apiKey,
@@ -1117,11 +1169,18 @@ set -euo pipefail
1117
1169
  export SNIPARA_PROJECT_SLUG="${answers.projectSlug}"
1118
1170
  ${answers.projectId ? `export SNIPARA_PROJECT_ID="${answers.projectId}"` : ""}
1119
1171
 
1120
- if command -v rlm-hook >/dev/null 2>&1; then
1172
+ SNIPARA_COMPANION_BIN=""
1173
+ if command -v ${COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1174
+ SNIPARA_COMPANION_BIN="${COMPANION_COMMAND_NAME}"
1175
+ elif command -v ${LEGACY_COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1176
+ SNIPARA_COMPANION_BIN="${LEGACY_COMPANION_COMMAND_NAME}"
1177
+ fi
1178
+
1179
+ if [ -n "$SNIPARA_COMPANION_BIN" ]; then
1121
1180
  if [ -f ".snipara/workflow/current.json" ]; then
1122
- rlm-hook workflow resume --include-session-context || true
1181
+ "$SNIPARA_COMPANION_BIN" workflow resume --include-session-context || true
1123
1182
  else
1124
- rlm-hook session-bootstrap || true
1183
+ "$SNIPARA_COMPANION_BIN" session-bootstrap || true
1125
1184
  fi
1126
1185
  fi
1127
1186
  `;
@@ -1133,8 +1192,15 @@ set -euo pipefail
1133
1192
  export SNIPARA_PROJECT_SLUG="${answers.projectSlug}"
1134
1193
  ${answers.projectId ? `export SNIPARA_PROJECT_ID="${answers.projectId}"` : ""}
1135
1194
 
1136
- if command -v rlm-hook >/dev/null 2>&1; then
1137
- rlm-hook emit-event --event-type tool_result --json '{"source":"claude-code-hook"}' || true
1195
+ SNIPARA_COMPANION_BIN=""
1196
+ if command -v ${COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1197
+ SNIPARA_COMPANION_BIN="${COMPANION_COMMAND_NAME}"
1198
+ elif command -v ${LEGACY_COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1199
+ SNIPARA_COMPANION_BIN="${LEGACY_COMPANION_COMMAND_NAME}"
1200
+ fi
1201
+
1202
+ if [ -n "$SNIPARA_COMPANION_BIN" ]; then
1203
+ "$SNIPARA_COMPANION_BIN" emit-event --event-type tool_result --json '{"source":"claude-code-hook"}' || true
1138
1204
  fi
1139
1205
  `;
1140
1206
  }
@@ -1145,11 +1211,18 @@ set -euo pipefail
1145
1211
  export SNIPARA_PROJECT_SLUG="${answers.projectSlug}"
1146
1212
  ${answers.projectId ? `export SNIPARA_PROJECT_ID="${answers.projectId}"` : ""}
1147
1213
 
1148
- if command -v rlm-hook >/dev/null 2>&1; then
1214
+ SNIPARA_COMPANION_BIN=""
1215
+ if command -v ${COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1216
+ SNIPARA_COMPANION_BIN="${COMPANION_COMMAND_NAME}"
1217
+ elif command -v ${LEGACY_COMPANION_COMMAND_NAME} >/dev/null 2>&1; then
1218
+ SNIPARA_COMPANION_BIN="${LEGACY_COMPANION_COMMAND_NAME}"
1219
+ fi
1220
+
1221
+ if [ -n "$SNIPARA_COMPANION_BIN" ]; then
1149
1222
  if [ -f ".snipara/workflow/current.json" ]; then
1150
- rlm-hook task-commit --summary "Claude Code compacted while a managed workflow state existed. Resume with rlm-hook workflow resume --include-session-context and continue from .snipara/workflow/current.json." --category workflow-compaction --outcome partial || true
1223
+ "$SNIPARA_COMPANION_BIN" task-commit --summary "Claude Code compacted while a managed workflow state existed. Resume with snipara-companion workflow resume --include-session-context and continue from .snipara/workflow/current.json." --category workflow-compaction --outcome partial || true
1151
1224
  else
1152
- rlm-hook task-commit --summary "Claude Code compacted local session context" --outcome partial || true
1225
+ "$SNIPARA_COMPANION_BIN" task-commit --summary "Claude Code compacted local session context" --outcome partial || true
1153
1226
  fi
1154
1227
  fi
1155
1228
  `;
@@ -1172,7 +1245,7 @@ ${answers.projectId ? `SNIPARA_PROJECT_ID=${answers.projectId}` : ""}
1172
1245
  const llmVarName = answers.llmProvider === "openai" ? "OPENAI_API_KEY" : "ANTHROPIC_API_KEY";
1173
1246
  envVars += `
1174
1247
 
1175
- # RLM-Runtime LLM Provider (for rlm run/agent CLI)
1248
+ # Snipara Sandbox LLM Provider (for snipara-sandbox run/agent CLI)
1176
1249
  ${llmVarName}=${answers.llmApiKey}`;
1177
1250
  }
1178
1251
  envVars = envVars.trim();
@@ -1213,7 +1286,7 @@ ${envVars}
1213
1286
  function getClientGuidance(client) {
1214
1287
  if (client === "claude-code") {
1215
1288
  return [
1216
- "Claude Code can use both the hosted MCP surface and the local rlm-hook companion flows.",
1289
+ "Claude Code can use both the hosted MCP surface and the local snipara-companion flows.",
1217
1290
  "If hooks are enabled, the edge layer forwards lifecycle signals without owning durable memory locally."
1218
1291
  ];
1219
1292
  }
@@ -1248,30 +1321,30 @@ function getClientGuidance(client) {
1248
1321
  }
1249
1322
  function getCompanionCommands(answers) {
1250
1323
  const projectIdFlag = answers.projectId ? ` --project-id ${answers.projectId}` : "";
1251
- const apiKeyFlag = answers.apiKeyType === "none" || answers.apiKey.includes("YOUR_") ? " --api-key <rlm_key>" : ` --api-key ${answers.apiKey}`;
1324
+ const apiKeyFlag = answers.apiKeyType === "none" || answers.apiKey.includes("YOUR_") ? " --api-key <rlm-key>" : ` --api-key ${answers.apiKey}`;
1252
1325
  const clientFlag = getCompanionInitClientFlag(answers.aiClient);
1253
1326
  const businessOnboardingCommands = answers.installCompanion ? [
1254
1327
  {
1255
1328
  title: "Preview a business folder import",
1256
- command: "rlm-hook onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json",
1329
+ command: `${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json`,
1257
1330
  purpose: "Classify a local or LLM-materialized business folder and review the Snipara sync manifest before upload."
1258
1331
  },
1259
1332
  {
1260
1333
  title: "Apply a business folder import",
1261
- command: "rlm-hook onboard-folder ./client-export --source-provider local_folder --apply",
1334
+ command: `${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --apply`,
1262
1335
  purpose: "Upload approved business-context documents to hosted Snipara and trigger document reindexing."
1263
1336
  }
1264
1337
  ] : [
1265
1338
  {
1266
1339
  title: "Enable business folder onboarding",
1267
1340
  command: "npx create-snipara repair --with-companion",
1268
- purpose: "Install snipara-companion so this project can run rlm-hook onboard-folder without using the dashboard."
1341
+ purpose: `Install ${COMPANION_PACKAGE_NAME} so this project can run ${COMPANION_COMMAND_NAME} onboard-folder without using the dashboard.`
1269
1342
  }
1270
1343
  ];
1271
1344
  return [
1272
1345
  {
1273
1346
  title: "Bootstrap local companion",
1274
- command: `rlm-hook init${clientFlag}${projectIdFlag}${apiKeyFlag}`,
1347
+ command: `${COMPANION_COMMAND_NAME} init${clientFlag}${projectIdFlag}${apiKeyFlag}`,
1275
1348
  purpose: "Write local companion config for this workstation."
1276
1349
  },
1277
1350
  {
@@ -1286,68 +1359,68 @@ function getCompanionCommands(answers) {
1286
1359
  },
1287
1360
  {
1288
1361
  title: "Run a focused hosted query",
1289
- command: 'rlm-hook query --query "how does auth middleware work?" --max-tokens 4000',
1362
+ command: `${COMPANION_COMMAND_NAME} query --query "how does auth middleware work?" --max-tokens 4000`,
1290
1363
  purpose: "Pull ranked source context before editing, reviewing, or drafting."
1291
1364
  },
1292
1365
  {
1293
1366
  title: "Load linked standards only when needed",
1294
- command: "rlm-hook shared-context --categories MANDATORY BEST_PRACTICES",
1367
+ command: `${COMPANION_COMMAND_NAME} shared-context --categories MANDATORY BEST_PRACTICES`,
1295
1368
  purpose: "Fetch project-linked team or workspace guidance without treating it as memory."
1296
1369
  },
1297
1370
  {
1298
1371
  title: "Generate a hosted plan",
1299
- command: 'rlm-hook plan --query "Implement webhook retry hardening" --max-tokens 3000',
1372
+ command: `${COMPANION_COMMAND_NAME} plan --query "Implement webhook retry hardening" --max-tokens 3000`,
1300
1373
  purpose: "Produce a structured execution plan against indexed project knowledge."
1301
1374
  },
1302
1375
  {
1303
1376
  title: "Start a managed workflow from the visible plan",
1304
- command: 'rlm-hook workflow start --goal "Implement webhook retry hardening" --plan-file ./plan.md',
1377
+ command: `${COMPANION_COMMAND_NAME} workflow start --goal "Implement webhook retry hardening" --plan-file ./plan.md`,
1305
1378
  purpose: "Record the LLM-visible plan in .snipara/workflow/current.json so phase state survives compaction."
1306
1379
  },
1307
1380
  {
1308
1381
  title: "Start the current workflow phase",
1309
- command: "rlm-hook workflow phase-start context",
1382
+ command: `${COMPANION_COMMAND_NAME} workflow phase-start context`,
1310
1383
  purpose: "Mark a phase active and print the required Snipara context gate for the agent."
1311
1384
  },
1312
1385
  {
1313
1386
  title: "Analyze code impact before a risky change",
1314
- command: 'rlm-hook code impact --changed-files src/api/webhooks.ts tests/webhooks.test.ts --diff-summary "webhook retry hardening"',
1387
+ command: `${COMPANION_COMMAND_NAME} code impact --changed-files src/api/webhooks.ts tests/webhooks.test.ts --diff-summary "webhook retry hardening"`,
1315
1388
  purpose: "Use paid Context code impact analysis to surface likely tests, docs, routes, config, and risks."
1316
1389
  },
1317
1390
  {
1318
1391
  title: "Upload or refresh a doc",
1319
- command: "rlm-hook upload --path docs/local-playbook.md --file ./docs/local-playbook.md",
1392
+ command: `${COMPANION_COMMAND_NAME} upload --path docs/local-playbook.md --file ./docs/local-playbook.md`,
1320
1393
  purpose: "Push local notes or docs into hosted Snipara context."
1321
1394
  },
1322
1395
  ...businessOnboardingCommands,
1323
1396
  {
1324
1397
  title: "Inspect a specific chunk",
1325
- command: "rlm-hook chunk get --chunk-id <chunk_id>",
1398
+ command: `${COMPANION_COMMAND_NAME} chunk get --chunk-id <chunk_id>`,
1326
1399
  purpose: "Open an exact chunk returned by references-based search."
1327
1400
  },
1328
1401
  {
1329
1402
  title: "Bootstrap the session memory view",
1330
- command: "rlm-hook session-bootstrap",
1403
+ command: `${COMPANION_COMMAND_NAME} session-bootstrap`,
1331
1404
  purpose: "Load durable decisions, learnings, and optional short-lived carryover at session start."
1332
1405
  },
1333
1406
  {
1334
1407
  title: "Ask memory about past decisions",
1335
- command: 'rlm-hook recall --query "What did we decide about auth retries?" --type decision',
1408
+ command: `${COMPANION_COMMAND_NAME} recall --query "What did we decide about auth retries?" --type decision`,
1336
1409
  purpose: "Query durable memory for past decisions, preferences, or validated learnings."
1337
1410
  },
1338
1411
  {
1339
1412
  title: "Commit durable task memory",
1340
- command: 'rlm-hook task-commit --summary "Hardened webhook retries and updated tests" --category engineering --outcome completed --files src/api/webhooks.ts tests/webhooks.test.ts',
1413
+ command: `${COMPANION_COMMAND_NAME} task-commit --summary "Hardened webhook retries and updated tests" --category engineering --outcome completed --files src/api/webhooks.ts tests/webhooks.test.ts`,
1341
1414
  purpose: "Persist reusable outcomes back into hosted memory after the work is done."
1342
1415
  },
1343
1416
  {
1344
1417
  title: "Commit a managed workflow phase",
1345
- command: 'rlm-hook workflow phase-commit context --summary "Loaded context and mapped impacted files" --files src/api/webhooks.ts tests/webhooks.test.ts',
1418
+ command: `${COMPANION_COMMAND_NAME} workflow phase-commit context --summary "Loaded context and mapped impacted files" --files src/api/webhooks.ts tests/webhooks.test.ts`,
1346
1419
  purpose: "Persist this phase through hosted memory and advance the local managed workflow state."
1347
1420
  },
1348
1421
  {
1349
1422
  title: "Commit the final managed workflow result",
1350
- command: 'rlm-hook final-commit --summary "Shipped webhook retry hardening and tests" --files src/api/webhooks.ts tests/webhooks.test.ts',
1423
+ command: `${COMPANION_COMMAND_NAME} final-commit --summary "Shipped webhook retry hardening and tests" --files src/api/webhooks.ts tests/webhooks.test.ts`,
1351
1424
  purpose: "Persist the final workflow outcome and close the managed workflow after verification."
1352
1425
  }
1353
1426
  ];
@@ -1372,7 +1445,7 @@ This project uses Snipara as a hosted-first context and memory layer with local
1372
1445
  - Installed local companion: \`${answers.installCompanion ? "yes" : "no"}\`
1373
1446
  - Generated hosted MCP config: \`${answers.profile !== "runtime-only" ? "yes" : "no"}\`
1374
1447
  - Installed local snipara-mcp package: \`${answers.installMcp ? "yes" : "no"}\`
1375
- - Installed runtime: \`${answers.installRuntime ? "yes" : "no"}\`
1448
+ - Installed Snipara Sandbox: \`${answers.installRuntime ? "yes" : "no"}\`
1376
1449
  - Generated hooks: \`${answers.installHooks ? "yes" : "no"}\`
1377
1450
 
1378
1451
  ## Local Detection Snapshot
@@ -1381,7 +1454,7 @@ This project uses Snipara as a hosted-first context and memory layer with local
1381
1454
  - .mcp.json present: \`${detection.files.mcpConfig ? "yes" : "no"}\`
1382
1455
  - .env.local present: \`${detection.files.envLocal ? "yes" : "no"}\`
1383
1456
  - Companion CLI on PATH: \`${detection.tooling.companionCli ? "yes" : "no"}\`
1384
- - Runtime CLI on PATH: \`${detection.tooling.runtimeCli ? "yes" : "no"}\`
1457
+ - Snipara Sandbox CLI on PATH: \`${detection.tooling.runtimeCli ? "yes" : "no"}\`
1385
1458
 
1386
1459
  ## Client Guidance
1387
1460
 
@@ -1393,11 +1466,11 @@ Use this when Claude, ChatGPT, Codex, or another LLM client has already material
1393
1466
 
1394
1467
  ${answers.installCompanion ? `Preview first:
1395
1468
 
1396
- \`rlm-hook onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json\`
1469
+ \`${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json\`
1397
1470
 
1398
1471
  Apply only after reviewing the manifest:
1399
1472
 
1400
- \`rlm-hook onboard-folder ./client-export --source-provider local_folder --apply\`` : `This setup did not install snipara-companion. Enable it before business folder imports:
1473
+ \`${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --apply\`` : `This setup did not install snipara-companion. Enable it before business folder imports:
1401
1474
 
1402
1475
  \`npx create-snipara repair --with-companion\``}
1403
1476
 
@@ -1449,30 +1522,36 @@ ${item.purpose}`
1449
1522
  console.log(chalk.green(" \u2713 Created .snipara/companion/README.md"));
1450
1523
  console.log(chalk.green(" \u2713 Created .snipara/companion/commands.json"));
1451
1524
  }
1452
- async function runRlmInit() {
1453
- console.log(chalk.bold("\n\u{1F527} Running RLM-Runtime Configuration\n"));
1525
+ async function runSandboxInit() {
1526
+ const sandboxCommand = detectSandboxCommand() || SANDBOX_COMMAND_NAME;
1527
+ console.log(chalk.bold("\n\u{1F527} Running Snipara Sandbox Configuration\n"));
1454
1528
  console.log(
1455
- chalk.dim(" Starting 'rlm init' - follow the prompts to configure execution environment...\n")
1529
+ chalk.dim(
1530
+ ` Starting '${sandboxCommand} init' - follow the prompts to configure execution environment...
1531
+ `
1532
+ )
1456
1533
  );
1457
1534
  return new Promise((resolve) => {
1458
- const child = spawn("rlm", ["init"], {
1535
+ const child = spawn(sandboxCommand, ["init"], {
1459
1536
  stdio: "inherit",
1460
1537
  shell: true
1461
1538
  });
1462
1539
  child.on("close", (code) => {
1463
1540
  if (code === 0) {
1464
- console.log(chalk.green("\n \u2713 RLM-Runtime configured successfully"));
1541
+ console.log(chalk.green("\n \u2713 Snipara Sandbox configured successfully"));
1465
1542
  } else if (code !== null) {
1466
1543
  console.log(chalk.yellow(`
1467
- \u26A0\uFE0F rlm init exited with code ${code}`));
1468
- console.log(chalk.dim(" You can run 'rlm init' manually later."));
1544
+ \u26A0\uFE0F ${sandboxCommand} init exited with code ${code}`));
1545
+ console.log(chalk.dim(` You can run '${sandboxCommand} init' manually later.`));
1469
1546
  }
1470
1547
  resolve();
1471
1548
  });
1472
1549
  child.on("error", (error) => {
1473
1550
  console.log(chalk.yellow(`
1474
- \u26A0\uFE0F Could not run rlm init: ${error.message}`));
1475
- console.log(chalk.dim(" Run 'rlm init' manually after installation completes."));
1551
+ \u26A0\uFE0F Could not run ${sandboxCommand} init: ${error.message}`));
1552
+ console.log(
1553
+ chalk.dim(` Run '${SANDBOX_COMMAND_NAME} init' manually after installation completes.`)
1554
+ );
1476
1555
  resolve();
1477
1556
  });
1478
1557
  });
@@ -1527,9 +1606,9 @@ async function runValidation(answers, includeHostedCheck) {
1527
1606
  detail: answers.installCompanion && !detection.tooling.companionCli ? `${COMPANION_PACKAGE_NAME} not found on PATH` : "Companion CLI ready or not requested"
1528
1607
  });
1529
1608
  checks.push({
1530
- name: "runtime_cli",
1609
+ name: "sandbox_cli",
1531
1610
  status: answers.installRuntime ? detection.tooling.runtimeCli ? "pass" : "warn" : "pass",
1532
- detail: answers.installRuntime && !detection.tooling.runtimeCli ? "rlm CLI not found on PATH" : "Runtime CLI ready or not requested"
1611
+ detail: answers.installRuntime && !detection.tooling.runtimeCli ? `${SANDBOX_COMMAND_NAME} CLI not found on PATH` : "Snipara Sandbox CLI ready or not requested"
1533
1612
  });
1534
1613
  checks.push({
1535
1614
  name: "companion_pack",
@@ -1625,14 +1704,14 @@ async function testHostedConnection(answers) {
1625
1704
  }
1626
1705
  ];
1627
1706
  const settingsResponse = await callHostedMcp(answers, "tools/call", {
1628
- name: "rlm_settings",
1707
+ name: "snipara_settings",
1629
1708
  arguments: {}
1630
1709
  });
1631
1710
  if (settingsResponse.ok && !settingsResponse.data.error) {
1632
1711
  checks.push({
1633
1712
  name: "hosted_settings",
1634
1713
  status: "pass",
1635
- detail: "rlm_settings tool call succeeded"
1714
+ detail: "snipara_settings tool call succeeded"
1636
1715
  });
1637
1716
  } else {
1638
1717
  checks.push({
@@ -1684,7 +1763,7 @@ async function callHostedMcp(answers, method, params) {
1684
1763
  function describeHostedHttpFailure(status, bodyText) {
1685
1764
  const detail = bodyText.trim().slice(0, 120);
1686
1765
  if (status === 401 || status === 403) {
1687
- return `Auth failed (${status}). Check the project/team API key and project slug.`;
1766
+ return `Auth failed (${status}). Check the API key and project slug.`;
1688
1767
  }
1689
1768
  if (status === 404) {
1690
1769
  return "Endpoint or project slug was not found. Check the hosted MCP URL.";
@@ -1723,7 +1802,9 @@ function printSuccess(answers, report) {
1723
1802
  );
1724
1803
  }
1725
1804
  if (answers.installRuntime) {
1726
- console.log(chalk.green(" \u2713 rlm-runtime") + chalk.dim(" - Safe code execution"));
1805
+ console.log(
1806
+ chalk.green(` \u2713 ${stripExtras(SANDBOX_PACKAGE_NAME)}`) + chalk.dim(" - Safe code execution")
1807
+ );
1727
1808
  }
1728
1809
  if (answers.installCompanion) {
1729
1810
  console.log(
@@ -1754,20 +1835,27 @@ function printSuccess(answers, report) {
1754
1835
  printNextStep("Open .snipara/companion/README.md for local commands and repair flow.");
1755
1836
  printNextStep("Run create-snipara doctor anytime you want a fresh local validation report.");
1756
1837
  if (answers.installCompanion) {
1757
- printNextStep("Use rlm-hook query / plan / upload / task-commit for explicit local workflows.");
1758
1838
  printNextStep(
1759
- "For business folders, preview with: rlm-hook onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json"
1839
+ `${COMPANION_COMMAND_NAME} is the primary companion command; legacy ${LEGACY_COMPANION_COMMAND_NAME} remains compatible.`
1760
1840
  );
1761
1841
  printNextStep(
1762
- "Apply after review with: rlm-hook onboard-folder ./client-export --source-provider local_folder --apply"
1842
+ `Use ${COMPANION_COMMAND_NAME} query / plan / upload / task-commit for explicit local workflows.`
1843
+ );
1844
+ printNextStep(
1845
+ `For business folders, preview with: ${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --write-manifest ./snipara-onboard.json`
1846
+ );
1847
+ printNextStep(
1848
+ `Apply after review with: ${COMPANION_COMMAND_NAME} onboard-folder ./client-export --source-provider local_folder --apply`
1763
1849
  );
1764
1850
  } else if (answers.profile !== "runtime-only") {
1765
1851
  printNextStep(
1766
1852
  "For dashboardless business folder imports, enable companion with: npx create-snipara repair --with-companion"
1767
1853
  );
1768
1854
  }
1769
- if (answers.installRuntime && !answers.runRlmInit) {
1770
- printNextStep("Run rlm init when you want to choose sandbox/docker/local execution.");
1855
+ if (answers.installRuntime && !answers.runSandboxInit) {
1856
+ printNextStep(
1857
+ `Run ${SANDBOX_COMMAND_NAME} init when you want to choose sandbox/docker/local execution.`
1858
+ );
1771
1859
  }
1772
1860
  if (answers.githubRepo) {
1773
1861
  printNextStep(
@@ -1793,11 +1881,11 @@ function printSuccess(answers, report) {
1793
1881
  }
1794
1882
  function commandExists(command) {
1795
1883
  try {
1796
- execSync(`${command} --version`, { stdio: "ignore", shell: "/bin/sh" });
1884
+ execSync(`${command} --version`, { stdio: "ignore", shell: "/bin/sh", timeout: 2500 });
1797
1885
  return true;
1798
1886
  } catch {
1799
1887
  try {
1800
- execSync(`command -v ${command}`, { stdio: "ignore", shell: "/bin/sh" });
1888
+ execSync(`command -v ${command}`, { stdio: "ignore", shell: "/bin/sh", timeout: 1e3 });
1801
1889
  return true;
1802
1890
  } catch {
1803
1891
  return false;
@@ -1834,8 +1922,8 @@ function detectEnvironment() {
1834
1922
  uv: commandExists("uv"),
1835
1923
  docker: commandExists("docker"),
1836
1924
  git: commandExists("git"),
1837
- companionCli: commandExists("rlm-hook"),
1838
- runtimeCli: commandExists("rlm")
1925
+ companionCli: Boolean(detectCompanionCommand()),
1926
+ runtimeCli: Boolean(detectSandboxCommand())
1839
1927
  },
1840
1928
  existingConfig: {
1841
1929
  slug: existingConfig?.slug,
@@ -1848,8 +1936,13 @@ function detectEnvironment() {
1848
1936
  function loadExistingAnswers(options) {
1849
1937
  const detection = detectEnvironment();
1850
1938
  const effectiveProfile = resolveMaintenanceProfile(detection, options.profile);
1851
- const apiKey = options.teamKey || options.apiKey || readApiKeyFromEnvFiles() || "YOUR_API_KEY_HERE";
1852
- const apiKeyType = options.teamKey ? "team" : options.apiKey || readApiKeyFromEnvFiles() ? "project" : effectiveProfile === "runtime-only" ? "none" : "none";
1939
+ const providedApiKey = options.apiKey?.trim();
1940
+ if (providedApiKey && !isManualApiKey(providedApiKey)) {
1941
+ throw new Error(manualApiKeyValidationMessage());
1942
+ }
1943
+ const envApiKey = readApiKeyFromEnvFiles();
1944
+ const apiKey = providedApiKey || envApiKey || "YOUR_API_KEY_HERE";
1945
+ const apiKeyType = effectiveProfile === "runtime-only" ? "none" : providedApiKey || envApiKey ? "api" : "none";
1853
1946
  return buildAnswersFromProfile({
1854
1947
  projectSlug: options.slug || detection.existingConfig.slug || detection.projectSlug || "my-project",
1855
1948
  projectId: options.projectId || detection.existingConfig.projectId || "",
@@ -1996,7 +2089,7 @@ function getExistingConfig() {
1996
2089
  try {
1997
2090
  const config = JSON.parse(fs.readFileSync(mcpConfigPath, "utf-8"));
1998
2091
  const sniparaServer = config.mcpServers?.snipara;
1999
- const runtimeServer = config.mcpServers?.["rlm-runtime"];
2092
+ const runtimeServer = config.mcpServers?.[SANDBOX_SERVER_NAME] || config.mcpServers?.[LEGACY_RUNTIME_SERVER_NAME];
2000
2093
  const match = sniparaServer?.url?.match(/\/mcp\/([^/]+)$/);
2001
2094
  return {
2002
2095
  slug: match?.[1],
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-snipara",
3
- "version": "1.3.11",
4
- "description": "Onboard Snipara Hosted MCP Context + Memory with auth, companion workflows, and optional runtime",
3
+ "version": "1.3.13",
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",
7
7
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "snipara",
22
22
  "create-snipara",
23
23
  "mcp",
24
- "rlm-runtime",
24
+ "snipara-sandbox",
25
25
  "context-optimization",
26
26
  "llm",
27
27
  "ai-agents",