create-snipara 1.3.17 → 1.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -6
- package/dist/index.js +108 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@ The default CLI path wires the local companion around those surfaces:
|
|
|
52
52
|
|
|
53
53
|
- `snipara-companion` for local workflow commands and managed phase commits; legacy `rlm-hook` commands remain compatible
|
|
54
54
|
- `snipara-sandbox` for optional local code execution
|
|
55
|
+
- `snipara-orchestrator` only when explicitly requested with `--with-orchestrator`
|
|
55
56
|
- local config, env files, hook scripts, and a project companion pack
|
|
56
57
|
- `snipara-mcp` only for local stdio compatibility, development, or testing
|
|
57
58
|
|
|
@@ -59,12 +60,12 @@ The default CLI path wires the local companion around those surfaces:
|
|
|
59
60
|
|
|
60
61
|
The CLI now works around explicit install profiles:
|
|
61
62
|
|
|
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
|
|
63
|
+
| Profile | What it installs | Best for |
|
|
64
|
+
| ------------------ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
65
|
+
| `hosted-companion` | MCP + `snipara-companion` | Default: hosted context plus managed local workflow |
|
|
66
|
+
| `hosted-only` | Hosted MCP config only | Locked-down or minimal environments |
|
|
67
|
+
| `full-stack` | MCP + `snipara-companion` + `snipara-sandbox` | Hosted context plus sandboxed local execution. Does not include orchestrator unless `--with-orchestrator` is passed |
|
|
68
|
+
| `runtime-only` | `snipara-sandbox` only | Local execution without hosted API |
|
|
68
69
|
|
|
69
70
|
Default profile: `hosted-companion`
|
|
70
71
|
|
|
@@ -102,6 +103,7 @@ That distinction matters:
|
|
|
102
103
|
- explains the GitHub PR Answer Packs path for AI-assisted pull request workflows
|
|
103
104
|
- installs `snipara-companion` by default for local managed workflows
|
|
104
105
|
- installs optional `snipara-sandbox`
|
|
106
|
+
- installs optional `snipara-orchestrator` for proof gates, drift checks, and htask workflows when requested
|
|
105
107
|
- configures `.mcp.json`
|
|
106
108
|
- generates merge-ready AI agent templates in `.snipara/templates/`, including Pro+ symbol-card, code-impact, and managed workflow guidance for paid Context plans
|
|
107
109
|
- creates `AGENTS.md`, `CLAUDE.md`, `.cursor/rules/snipara.mdc`, and `.codex/config.toml` when those files do not already exist
|
|
@@ -140,6 +142,8 @@ By default, this uses the recommended `hosted-companion` setup: hosted MCP plus
|
|
|
140
142
|
the local `snipara-companion` workflow helper. Legacy `rlm-hook` commands remain
|
|
141
143
|
compatible. Add `--advanced` when you want profile selection, project id entry,
|
|
142
144
|
hook prompts, GitHub automation prompts, or sandbox provider prompts.
|
|
145
|
+
Use `--with-orchestrator` only when you explicitly need the advanced production
|
|
146
|
+
validation and htask package; it is not part of `full-stack` by default.
|
|
143
147
|
|
|
144
148
|
The advanced flow asks for:
|
|
145
149
|
|
|
@@ -421,6 +425,16 @@ npx create-snipara --profile full-stack --advanced
|
|
|
421
425
|
|
|
422
426
|
Best when the user also wants sandboxed `snipara-sandbox` execution.
|
|
423
427
|
|
|
428
|
+
### Full local stack plus production orchestration
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
npx create-snipara --profile full-stack --with-orchestrator
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Best when the user wants Hosted MCP, companion workflows, Sandbox execution, and
|
|
435
|
+
the explicit `snipara-orchestrator` package for production gates, drift checks,
|
|
436
|
+
or htask coordination.
|
|
437
|
+
|
|
424
438
|
### Connect the current repository
|
|
425
439
|
|
|
426
440
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ 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.
|
|
12
|
+
var VERSION = "1.3.19";
|
|
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";
|
|
@@ -18,10 +18,12 @@ var LEGACY_COMPANION_COMMAND_NAME = "rlm-hook";
|
|
|
18
18
|
var GITHUB_ANSWER_PACKS_LABEL = "GitHub PR Answer Packs";
|
|
19
19
|
var MCP_PACKAGE_NAME = "snipara-mcp";
|
|
20
20
|
var SANDBOX_PACKAGE_NAME = "snipara-sandbox[all]";
|
|
21
|
+
var ORCHESTRATOR_PACKAGE_NAME = "snipara-orchestrator";
|
|
21
22
|
var SANDBOX_SERVER_NAME = "snipara-sandbox";
|
|
22
23
|
var LEGACY_RUNTIME_SERVER_NAME = "rlm-runtime";
|
|
23
24
|
var SANDBOX_COMMAND_NAME = "snipara-sandbox";
|
|
24
25
|
var LEGACY_SANDBOX_COMMAND_NAME = "rlm";
|
|
26
|
+
var ORCHESTRATOR_COMMAND_NAME = "snipara-orchestrator";
|
|
25
27
|
var DEVICE_CLIENT_ID = "create-snipara";
|
|
26
28
|
var DeviceAuthorizationAborted = class extends Error {
|
|
27
29
|
};
|
|
@@ -94,7 +96,7 @@ function buildProgram() {
|
|
|
94
96
|
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(
|
|
95
97
|
"--profile <profile>",
|
|
96
98
|
"Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
|
|
97
|
-
).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) => {
|
|
99
|
+
).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
|
|
98
100
|
printBanner();
|
|
99
101
|
await runInit(options);
|
|
100
102
|
});
|
|
@@ -102,11 +104,11 @@ function buildProgram() {
|
|
|
102
104
|
printBanner();
|
|
103
105
|
await runDoctor(options);
|
|
104
106
|
});
|
|
105
|
-
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) => {
|
|
107
|
+
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").option("--with-orchestrator", "Install optional snipara-orchestrator package").action(async (options) => {
|
|
106
108
|
printBanner();
|
|
107
109
|
await runRepair(options);
|
|
108
110
|
});
|
|
109
|
-
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) => {
|
|
111
|
+
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").option("--with-orchestrator", "Upgrade snipara-orchestrator even if not detected").action(async (options) => {
|
|
110
112
|
printBanner();
|
|
111
113
|
await runUpgrade(options);
|
|
112
114
|
});
|
|
@@ -125,7 +127,7 @@ function addSharedRootOptions(program) {
|
|
|
125
127
|
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(
|
|
126
128
|
"--profile <profile>",
|
|
127
129
|
"Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
|
|
128
|
-
).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");
|
|
130
|
+
).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").option("-y, --yes", "Accept defaults without prompting");
|
|
129
131
|
}
|
|
130
132
|
async function main() {
|
|
131
133
|
const program = buildProgram();
|
|
@@ -157,6 +159,7 @@ function parseInitOptionsFromArgv(args) {
|
|
|
157
159
|
"--skip-runtime": "skipRuntime",
|
|
158
160
|
"--skip-hooks": "skipHooks",
|
|
159
161
|
"--skip-test": "skipTest",
|
|
162
|
+
"--with-orchestrator": "withOrchestrator",
|
|
160
163
|
"--runtime-only": "runtimeOnly",
|
|
161
164
|
"--github": "github",
|
|
162
165
|
"--skip-github": "skipGithub",
|
|
@@ -187,7 +190,7 @@ function parseInitOptionsFromArgv(args) {
|
|
|
187
190
|
}
|
|
188
191
|
async function runInit(options) {
|
|
189
192
|
const answers = await gatherConfiguration(normalizeInitOptions(options));
|
|
190
|
-
if (answers.installMcp || answers.installRuntime) {
|
|
193
|
+
if (answers.installMcp || answers.installRuntime || answers.installOrchestrator) {
|
|
191
194
|
await installPythonPackages(answers, false);
|
|
192
195
|
}
|
|
193
196
|
if (answers.installCompanion) {
|
|
@@ -201,6 +204,7 @@ async function runInit(options) {
|
|
|
201
204
|
await installClaudeCodeHooks(answers);
|
|
202
205
|
}
|
|
203
206
|
await updateEnvFiles(answers);
|
|
207
|
+
await createCompanionConfig(answers);
|
|
204
208
|
await createCompanionPack(answers);
|
|
205
209
|
const validationReport = await runValidation(answers, !options.skipTest);
|
|
206
210
|
writeDoctorReport(validationReport);
|
|
@@ -225,7 +229,7 @@ async function runDoctor(options) {
|
|
|
225
229
|
async function runRepair(options) {
|
|
226
230
|
const answers = loadExistingAnswers(options);
|
|
227
231
|
console.log(chalk.bold("\n\u{1F6E0}\uFE0F Repairing Local Setup\n"));
|
|
228
|
-
if (answers.installMcp || answers.installRuntime) {
|
|
232
|
+
if (answers.installMcp || answers.installRuntime || answers.installOrchestrator) {
|
|
229
233
|
await installPythonPackages(answers, true);
|
|
230
234
|
}
|
|
231
235
|
if (answers.installCompanion) {
|
|
@@ -234,6 +238,7 @@ async function runRepair(options) {
|
|
|
234
238
|
await createMcpConfig(answers);
|
|
235
239
|
await createAgentTemplates(answers);
|
|
236
240
|
await updateEnvFiles(answers);
|
|
241
|
+
await createCompanionConfig(answers);
|
|
237
242
|
await createCompanionPack(answers);
|
|
238
243
|
if (answers.installHooks && answers.aiClient === "claude-code") {
|
|
239
244
|
await installClaudeCodeHooks(answers);
|
|
@@ -248,10 +253,11 @@ async function runUpgrade(options) {
|
|
|
248
253
|
const upgradedAnswers = {
|
|
249
254
|
...answers,
|
|
250
255
|
installMcp: options.withMcp || answers.installMcp,
|
|
251
|
-
installRuntime: options.withRuntime || answers.installRuntime
|
|
256
|
+
installRuntime: options.withRuntime || answers.installRuntime,
|
|
257
|
+
installOrchestrator: options.withOrchestrator || answers.installOrchestrator
|
|
252
258
|
};
|
|
253
259
|
console.log(chalk.bold("\n\u2B06\uFE0F Upgrading Local Components\n"));
|
|
254
|
-
if (options.withMcp || options.withRuntime || detection.existingConfig.hasRuntimeServer) {
|
|
260
|
+
if (options.withMcp || options.withRuntime || options.withOrchestrator || detection.existingConfig.hasRuntimeServer || detection.tooling.orchestratorCli) {
|
|
255
261
|
await installPythonPackages(upgradedAnswers, true);
|
|
256
262
|
}
|
|
257
263
|
if (options.withCompanion || detection.tooling.companionCli || answers.installCompanion) {
|
|
@@ -261,11 +267,12 @@ async function runUpgrade(options) {
|
|
|
261
267
|
await createMcpConfig(upgradedAnswers);
|
|
262
268
|
}
|
|
263
269
|
await createAgentTemplates(upgradedAnswers);
|
|
270
|
+
await createCompanionConfig(upgradedAnswers);
|
|
264
271
|
if (options.withHooks || answers.installHooks) {
|
|
265
272
|
await installClaudeCodeHooks({ ...answers, installHooks: true });
|
|
266
273
|
}
|
|
267
|
-
await createCompanionPack(
|
|
268
|
-
const report = await runValidation(
|
|
274
|
+
await createCompanionPack(upgradedAnswers);
|
|
275
|
+
const report = await runValidation(upgradedAnswers, true);
|
|
269
276
|
writeDoctorReport(report);
|
|
270
277
|
printDoctorReport(detectEnvironment(), report);
|
|
271
278
|
}
|
|
@@ -302,6 +309,7 @@ async function runPrintConfig(options) {
|
|
|
302
309
|
);
|
|
303
310
|
console.log(` Local snipara-mcp package: ${answers.installMcp ? "enabled" : "disabled"}`);
|
|
304
311
|
console.log(` Snipara Sandbox: ${answers.installRuntime ? "enabled" : "disabled"}`);
|
|
312
|
+
console.log(` Snipara Orchestrator: ${answers.installOrchestrator ? "enabled" : "disabled"}`);
|
|
305
313
|
console.log(` Hooks: ${answers.installHooks ? "enabled" : "disabled"}`);
|
|
306
314
|
console.log(` GitHub repo: ${githubRepo ? githubRepo.fullName : "not detected"}`);
|
|
307
315
|
console.log(` ${GITHUB_ANSWER_PACKS_LABEL}: ${githubAnswerPacks}`);
|
|
@@ -362,6 +370,7 @@ async function gatherConfiguration(options) {
|
|
|
362
370
|
skipCompanion: !!options.skipCompanion,
|
|
363
371
|
skipMcp: !!options.skipMcp,
|
|
364
372
|
skipRuntime: !!options.skipRuntime,
|
|
373
|
+
withOrchestrator: !!options.withOrchestrator,
|
|
365
374
|
skipHooks: !!options.skipHooks,
|
|
366
375
|
configureGitHub: Boolean(options.github && detectedGitRepo && !options.skipGithub),
|
|
367
376
|
githubRepo: detectedGitRepo || void 0,
|
|
@@ -426,6 +435,12 @@ async function gatherConfiguration(options) {
|
|
|
426
435
|
),
|
|
427
436
|
choices: AI_CLIENT_CHOICES
|
|
428
437
|
},
|
|
438
|
+
{
|
|
439
|
+
type: showAdvancedPrompts ? "confirm" : null,
|
|
440
|
+
name: "installOrchestrator",
|
|
441
|
+
message: "Install snipara-orchestrator for production gates, drift checks, or htask workflows?",
|
|
442
|
+
initial: Boolean(options.withOrchestrator)
|
|
443
|
+
},
|
|
429
444
|
{
|
|
430
445
|
type: showAdvancedPrompts ? "confirm" : null,
|
|
431
446
|
name: "installHooks",
|
|
@@ -471,6 +486,7 @@ async function gatherConfiguration(options) {
|
|
|
471
486
|
skipCompanion: !!options.skipCompanion,
|
|
472
487
|
skipMcp: !!options.skipMcp,
|
|
473
488
|
skipRuntime: !!options.skipRuntime,
|
|
489
|
+
withOrchestrator: Boolean(options.withOrchestrator || response.installOrchestrator),
|
|
474
490
|
skipHooks: !!options.skipHooks || !response.installHooks,
|
|
475
491
|
configureGitHub: Boolean(
|
|
476
492
|
(response.configureGitHub || options.github) && detectedGitRepo && !options.skipGithub
|
|
@@ -602,6 +618,7 @@ function buildAnswersFromProfile(input) {
|
|
|
602
618
|
installCompanion: selected.installCompanion && !input.skipCompanion,
|
|
603
619
|
installMcp: selected.installMcp && !input.skipMcp,
|
|
604
620
|
installRuntime: selected.installRuntime && !input.skipRuntime,
|
|
621
|
+
installOrchestrator: input.withOrchestrator,
|
|
605
622
|
installHooks: selected.installHooks && !input.skipHooks,
|
|
606
623
|
aiClient: input.aiClient,
|
|
607
624
|
configureGitHub: Boolean(input.configureGitHub && input.githubRepo),
|
|
@@ -756,6 +773,9 @@ function detectSandboxCommand() {
|
|
|
756
773
|
}
|
|
757
774
|
return null;
|
|
758
775
|
}
|
|
776
|
+
function detectOrchestratorCommand() {
|
|
777
|
+
return commandExists(ORCHESTRATOR_COMMAND_NAME) ? ORCHESTRATOR_COMMAND_NAME : null;
|
|
778
|
+
}
|
|
759
779
|
async function installPythonPackages(answers, upgrade) {
|
|
760
780
|
console.log(chalk.bold(`
|
|
761
781
|
\u{1F4E6} ${upgrade ? "Upgrading" : "Installing"} Python Packages
|
|
@@ -769,6 +789,11 @@ async function installPythonPackages(answers, upgrade) {
|
|
|
769
789
|
if (answers.installRuntime) {
|
|
770
790
|
console.log(chalk.gray(` pip install ${upgrade ? "-U " : ""}${SANDBOX_PACKAGE_NAME}`));
|
|
771
791
|
}
|
|
792
|
+
if (answers.installOrchestrator) {
|
|
793
|
+
console.log(
|
|
794
|
+
chalk.gray(` pip install ${upgrade ? "-U " : ""}${ORCHESTRATOR_PACKAGE_NAME}`)
|
|
795
|
+
);
|
|
796
|
+
}
|
|
772
797
|
console.log("");
|
|
773
798
|
return;
|
|
774
799
|
}
|
|
@@ -779,6 +804,9 @@ async function installPythonPackages(answers, upgrade) {
|
|
|
779
804
|
if (answers.installRuntime) {
|
|
780
805
|
packages.push(SANDBOX_PACKAGE_NAME);
|
|
781
806
|
}
|
|
807
|
+
if (answers.installOrchestrator) {
|
|
808
|
+
packages.push(ORCHESTRATOR_PACKAGE_NAME);
|
|
809
|
+
}
|
|
782
810
|
if (packages.length === 0) return;
|
|
783
811
|
const spinner = ora(
|
|
784
812
|
`${upgrade ? "Upgrading" : "Installing"} ${packages.map(stripExtras).join(", ")}...`
|
|
@@ -1154,11 +1182,10 @@ async function createClaudeDesktopConfig(answers) {
|
|
|
1154
1182
|
}
|
|
1155
1183
|
config.mcpServers = config.mcpServers || {};
|
|
1156
1184
|
config.mcpServers.snipara = {
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
SNIPARA_PROJECT_SLUG: answers.projectSlug
|
|
1185
|
+
type: "http",
|
|
1186
|
+
url: buildHostedMcpEndpoint(answers),
|
|
1187
|
+
headers: {
|
|
1188
|
+
"X-API-Key": answers.apiKey
|
|
1162
1189
|
}
|
|
1163
1190
|
};
|
|
1164
1191
|
if (answers.installRuntime) {
|
|
@@ -1351,12 +1378,19 @@ async function updateEnvFiles(answers) {
|
|
|
1351
1378
|
const envLocalPath = path.join(process.cwd(), ".env.local");
|
|
1352
1379
|
const envPath = path.join(process.cwd(), ".env");
|
|
1353
1380
|
let envVars = "";
|
|
1381
|
+
let envExampleVars = "";
|
|
1354
1382
|
if (answers.apiKeyType !== "none") {
|
|
1355
1383
|
envVars += `
|
|
1356
1384
|
# Snipara Configuration
|
|
1357
1385
|
SNIPARA_API_KEY=${answers.apiKey.includes("YOUR_") ? "your_api_key_here" : answers.apiKey}
|
|
1358
1386
|
SNIPARA_PROJECT_SLUG=${answers.projectSlug}
|
|
1359
1387
|
${answers.projectId ? `SNIPARA_PROJECT_ID=${answers.projectId}` : ""}
|
|
1388
|
+
`.trim();
|
|
1389
|
+
envExampleVars += `
|
|
1390
|
+
# Snipara Configuration
|
|
1391
|
+
SNIPARA_API_KEY=your_api_key_here
|
|
1392
|
+
SNIPARA_PROJECT_SLUG=${answers.projectSlug || "your_project_slug"}
|
|
1393
|
+
${answers.projectId ? `SNIPARA_PROJECT_ID=${answers.projectId}` : "SNIPARA_PROJECT_ID=your_project_id"}
|
|
1360
1394
|
`.trim();
|
|
1361
1395
|
}
|
|
1362
1396
|
if (answers.llmProvider && answers.llmProvider !== "none" && answers.llmApiKey) {
|
|
@@ -1365,23 +1399,28 @@ ${answers.projectId ? `SNIPARA_PROJECT_ID=${answers.projectId}` : ""}
|
|
|
1365
1399
|
|
|
1366
1400
|
# Snipara Sandbox LLM Provider (for snipara-sandbox run/agent CLI)
|
|
1367
1401
|
${llmVarName}=${answers.llmApiKey}`;
|
|
1402
|
+
envExampleVars += `
|
|
1403
|
+
|
|
1404
|
+
# Snipara Sandbox LLM Provider (for snipara-sandbox run/agent CLI)
|
|
1405
|
+
${llmVarName}=your_${answers.llmProvider}_api_key_here`;
|
|
1368
1406
|
}
|
|
1369
1407
|
envVars = envVars.trim();
|
|
1370
|
-
|
|
1408
|
+
envExampleVars = envExampleVars.trim();
|
|
1409
|
+
if (!envVars && !envExampleVars) {
|
|
1371
1410
|
console.log(chalk.dim(" No environment variables to save"));
|
|
1372
1411
|
return;
|
|
1373
1412
|
}
|
|
1374
|
-
if (fs.existsSync(envExamplePath)) {
|
|
1413
|
+
if (envExampleVars && fs.existsSync(envExamplePath)) {
|
|
1375
1414
|
const content = fs.readFileSync(envExamplePath, "utf-8");
|
|
1376
1415
|
if (!content.includes("SNIPARA_API_KEY") && !content.includes("SNIPARA_PROJECT_SLUG")) {
|
|
1377
1416
|
fs.appendFileSync(envExamplePath, `
|
|
1378
1417
|
|
|
1379
|
-
${
|
|
1418
|
+
${envExampleVars}
|
|
1380
1419
|
`);
|
|
1381
1420
|
console.log(chalk.green(" \u2713 Updated .env.example"));
|
|
1382
1421
|
}
|
|
1383
|
-
} else {
|
|
1384
|
-
fs.writeFileSync(envExamplePath,
|
|
1422
|
+
} else if (envExampleVars) {
|
|
1423
|
+
fs.writeFileSync(envExamplePath, envExampleVars + "\n");
|
|
1385
1424
|
console.log(chalk.green(" \u2713 Created .env.example"));
|
|
1386
1425
|
}
|
|
1387
1426
|
const targetEnvPath = fs.existsSync(envLocalPath) ? envLocalPath : envPath;
|
|
@@ -1401,6 +1440,26 @@ ${envVars}
|
|
|
1401
1440
|
console.log(chalk.green(` \u2713 Created ${path.basename(targetEnvPath)}`));
|
|
1402
1441
|
}
|
|
1403
1442
|
}
|
|
1443
|
+
async function createCompanionConfig(answers) {
|
|
1444
|
+
if (!answers.installCompanion || answers.apiKeyType === "none" || !answers.apiKey || answers.apiKey.includes("YOUR_")) {
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
const configDir = path.join(process.cwd(), ".snipara", "companion");
|
|
1448
|
+
const configPath = path.join(configDir, "config.json");
|
|
1449
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
1450
|
+
const config = {
|
|
1451
|
+
apiKey: answers.apiKey,
|
|
1452
|
+
projectId: answers.projectId || answers.projectSlug,
|
|
1453
|
+
apiUrl: API_URL,
|
|
1454
|
+
sessionId: `sess_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
|
|
1455
|
+
};
|
|
1456
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1457
|
+
ensureGitignoreEntry(
|
|
1458
|
+
".snipara/companion/config.json",
|
|
1459
|
+
"# Snipara local companion config (contains API key)"
|
|
1460
|
+
);
|
|
1461
|
+
console.log(chalk.green(" \u2713 Configured local companion workspace"));
|
|
1462
|
+
}
|
|
1404
1463
|
function getClientGuidance(client) {
|
|
1405
1464
|
if (client === "claude-code") {
|
|
1406
1465
|
return [
|
|
@@ -1463,7 +1522,6 @@ function getClientGuidance(client) {
|
|
|
1463
1522
|
}
|
|
1464
1523
|
function getCompanionCommands(answers) {
|
|
1465
1524
|
const projectIdFlag = answers.projectId ? ` --project-id ${answers.projectId}` : "";
|
|
1466
|
-
const apiKeyFlag = " --api-key <snipara-key>";
|
|
1467
1525
|
const clientFlag = getCompanionInitClientFlag(answers.aiClient);
|
|
1468
1526
|
const businessOnboardingCommands = answers.installCompanion ? [
|
|
1469
1527
|
{
|
|
@@ -1495,8 +1553,8 @@ function getCompanionCommands(answers) {
|
|
|
1495
1553
|
return [
|
|
1496
1554
|
{
|
|
1497
1555
|
title: "Bootstrap local companion",
|
|
1498
|
-
command: `${COMPANION_COMMAND_NAME} init${clientFlag}${projectIdFlag}
|
|
1499
|
-
purpose: "
|
|
1556
|
+
command: `${COMPANION_COMMAND_NAME} init${clientFlag}${projectIdFlag}`,
|
|
1557
|
+
purpose: "Re-run local companion setup if this workstation needs to refresh browser login or project selection."
|
|
1500
1558
|
},
|
|
1501
1559
|
{
|
|
1502
1560
|
title: "Run doctor for this project",
|
|
@@ -1538,6 +1596,11 @@ function getCompanionCommands(answers) {
|
|
|
1538
1596
|
command: `${COMPANION_COMMAND_NAME} code impact --changed-files src/api/webhooks.ts tests/webhooks.test.ts --diff-summary "webhook retry hardening"`,
|
|
1539
1597
|
purpose: "Use paid Context code impact analysis to surface likely tests, docs, routes, config, and risks."
|
|
1540
1598
|
},
|
|
1599
|
+
{
|
|
1600
|
+
title: answers.installOrchestrator ? "Run an explicit production orchestration gate" : "Enable explicit production orchestration",
|
|
1601
|
+
command: answers.installOrchestrator ? `${ORCHESTRATOR_COMMAND_NAME} check-drift --route /api/health` : "npx create-snipara repair --with-orchestrator",
|
|
1602
|
+
purpose: answers.installOrchestrator ? "Use snipara-orchestrator only for proof-based validation, drift checks, htasks, or multi-agent coordination." : "Install snipara-orchestrator only when production gates, drift checks, htasks, or multi-agent coordination are required."
|
|
1603
|
+
},
|
|
1541
1604
|
githubAnswerPacksCommand,
|
|
1542
1605
|
{
|
|
1543
1606
|
title: "Upload or refresh a doc",
|
|
@@ -1715,6 +1778,7 @@ This project uses Snipara as a hosted-first context and memory layer with local
|
|
|
1715
1778
|
- Generated hosted MCP config: \`${answers.profile !== "runtime-only" ? "yes" : "no"}\`
|
|
1716
1779
|
- Installed local snipara-mcp package: \`${answers.installMcp ? "yes" : "no"}\`
|
|
1717
1780
|
- Installed Snipara Sandbox: \`${answers.installRuntime ? "yes" : "no"}\`
|
|
1781
|
+
- Installed Snipara Orchestrator: \`${answers.installOrchestrator ? "yes" : "no"}\`
|
|
1718
1782
|
- Generated hooks: \`${answers.installHooks ? "yes" : "no"}\`
|
|
1719
1783
|
- GitHub repository: \`${answers.githubRepo ? answers.githubRepo.fullName : "not-detected"}\`
|
|
1720
1784
|
|
|
@@ -1725,6 +1789,7 @@ This project uses Snipara as a hosted-first context and memory layer with local
|
|
|
1725
1789
|
- .env.local present: \`${detection.files.envLocal ? "yes" : "no"}\`
|
|
1726
1790
|
- Companion CLI on PATH: \`${detection.tooling.companionCli ? "yes" : "no"}\`
|
|
1727
1791
|
- Snipara Sandbox CLI on PATH: \`${detection.tooling.runtimeCli ? "yes" : "no"}\`
|
|
1792
|
+
- Snipara Orchestrator CLI on PATH: \`${detection.tooling.orchestratorCli ? "yes" : "no"}\`
|
|
1728
1793
|
|
|
1729
1794
|
## Client Guidance
|
|
1730
1795
|
|
|
@@ -1790,6 +1855,7 @@ ${item.purpose}`
|
|
|
1790
1855
|
ai_client: answers.aiClient,
|
|
1791
1856
|
profile: answers.profile,
|
|
1792
1857
|
llm_provider: answers.llmProvider || null,
|
|
1858
|
+
install_orchestrator: answers.installOrchestrator,
|
|
1793
1859
|
github_repository: answers.githubRepo || null,
|
|
1794
1860
|
github_automation_url: answers.githubRepo ? buildGitHubAutomationUrl(answers) : null,
|
|
1795
1861
|
client_pack: clientPackFilename,
|
|
@@ -1895,6 +1961,11 @@ async function runValidation(answers, includeHostedCheck) {
|
|
|
1895
1961
|
status: answers.installRuntime ? detection.tooling.runtimeCli ? "pass" : "warn" : "pass",
|
|
1896
1962
|
detail: answers.installRuntime && !detection.tooling.runtimeCli ? `${SANDBOX_COMMAND_NAME} CLI not found on PATH` : "Snipara Sandbox CLI ready or not requested"
|
|
1897
1963
|
});
|
|
1964
|
+
checks.push({
|
|
1965
|
+
name: "orchestrator_cli",
|
|
1966
|
+
status: answers.installOrchestrator ? detection.tooling.orchestratorCli ? "pass" : "warn" : "pass",
|
|
1967
|
+
detail: answers.installOrchestrator && !detection.tooling.orchestratorCli ? `${ORCHESTRATOR_COMMAND_NAME} CLI not found on PATH` : "Snipara Orchestrator ready or not requested"
|
|
1968
|
+
});
|
|
1898
1969
|
checks.push({
|
|
1899
1970
|
name: "companion_pack",
|
|
1900
1971
|
status: detection.files.sniparaCompanionPack ? "pass" : "warn",
|
|
@@ -2096,6 +2167,11 @@ function printSuccess(answers, report) {
|
|
|
2096
2167
|
chalk.green(` \u2713 ${stripExtras(SANDBOX_PACKAGE_NAME)}`) + chalk.dim(" - Safe code execution")
|
|
2097
2168
|
);
|
|
2098
2169
|
}
|
|
2170
|
+
if (answers.installOrchestrator) {
|
|
2171
|
+
console.log(
|
|
2172
|
+
chalk.green(` \u2713 ${ORCHESTRATOR_PACKAGE_NAME}`) + chalk.dim(" - Production gates, drift checks, and htask workflows")
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2099
2175
|
if (answers.installCompanion) {
|
|
2100
2176
|
console.log(
|
|
2101
2177
|
chalk.green(` \u2713 ${COMPANION_PACKAGE_NAME}`) + chalk.dim(" - Local companion workflows and hook bootstrap")
|
|
@@ -2147,6 +2223,11 @@ function printSuccess(answers, report) {
|
|
|
2147
2223
|
`Run ${SANDBOX_COMMAND_NAME} init when you want to choose sandbox/docker/local execution.`
|
|
2148
2224
|
);
|
|
2149
2225
|
}
|
|
2226
|
+
if (answers.installOrchestrator) {
|
|
2227
|
+
printNextStep(
|
|
2228
|
+
`Use ${ORCHESTRATOR_COMMAND_NAME} explicitly for production proof gates, drift checks, or htask coordination.`
|
|
2229
|
+
);
|
|
2230
|
+
}
|
|
2150
2231
|
if (answers.githubRepo) {
|
|
2151
2232
|
printNextStep(
|
|
2152
2233
|
`Connect GitHub automation for ${answers.githubRepo.fullName} from the generated Snipara link.`
|
|
@@ -2213,7 +2294,8 @@ function detectEnvironment() {
|
|
|
2213
2294
|
docker: commandExists("docker"),
|
|
2214
2295
|
git: commandExists("git"),
|
|
2215
2296
|
companionCli: Boolean(detectCompanionCommand()),
|
|
2216
|
-
runtimeCli: Boolean(detectSandboxCommand())
|
|
2297
|
+
runtimeCli: Boolean(detectSandboxCommand()),
|
|
2298
|
+
orchestratorCli: Boolean(detectOrchestratorCommand())
|
|
2217
2299
|
},
|
|
2218
2300
|
existingConfig: {
|
|
2219
2301
|
slug: existingConfig?.slug,
|
|
@@ -2243,6 +2325,7 @@ function loadExistingAnswers(options) {
|
|
|
2243
2325
|
skipCompanion: options.withCompanion === true ? false : !detection.tooling.companionCli && effectiveProfile !== "hosted-companion" && effectiveProfile !== "full-stack",
|
|
2244
2326
|
skipMcp: options.withMcp === true ? false : !detection.existingConfig.hasSniparaServer && effectiveProfile === "runtime-only",
|
|
2245
2327
|
skipRuntime: options.withRuntime === true ? false : !detection.existingConfig.hasRuntimeServer && effectiveProfile !== "full-stack" && effectiveProfile !== "runtime-only",
|
|
2328
|
+
withOrchestrator: Boolean(options.withOrchestrator || detection.tooling.orchestratorCli),
|
|
2246
2329
|
skipHooks: options.withHooks ? false : detection.aiClient !== "claude-code"
|
|
2247
2330
|
});
|
|
2248
2331
|
}
|
package/package.json
CHANGED