create-snipara 2.0.7 → 2.0.9

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 +2 -1
  2. package/dist/index.js +734 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -26,6 +26,7 @@ Use it for:
26
26
  - free account signup with reviewed Context + Memory
27
27
  - local project wiring, `doctor`, `repair`, and `upgrade`
28
28
  - local source activation without GitHub, plus optional GitHub repository sync and PR Answer Packs approval when the current folder is a GitHub repo
29
+ - day-zero Project Intelligence proof: a First Work Brief, a ready-to-run `snipara_context_query`, review-only decision archaeology candidates, possible doc-staleness findings, and an estimated context economy report from the user's own repository
29
30
 
30
31
  ## Why It Exists
31
32
 
@@ -114,7 +115,7 @@ That distinction matters:
114
115
  - installs optional `snipara-sandbox`
115
116
  - installs optional `snipara-orchestrator` for proof gates, drift checks, and htask workflows when requested
116
117
  - configures `.mcp.json`
117
- - generates merge-ready AI agent templates in `.snipara/templates/`, including Pro+ symbol-card, code-impact, and managed workflow guidance for paid Context plans
118
+ - generates merge-ready AI agent templates in `.snipara/templates/`, including symbol-card, code-impact, and managed workflow guidance within plan capacity
118
119
  - creates `AGENTS.md` and `CLAUDE.md` when missing, or appends a marked Snipara section when those files already exist
119
120
  - creates `.cursor/rules/snipara.mdc` and `.codex/config.toml` when those files do not already exist
120
121
  - validates Codex config against Hosted MCP plus `bearer_token_env_var = "SNIPARA_API_KEY"` and tells users to restart Codex after MCP config changes
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import { homedir } from "os";
13
13
  // package.json
14
14
  var package_default = {
15
15
  name: "create-snipara",
16
- version: "2.0.7",
16
+ version: "2.0.9",
17
17
  description: "Onboard Snipara Hosted MCP Context + Memory with auth, companion workflows, and optional Snipara Sandbox",
18
18
  main: "dist/index.js",
19
19
  type: "module",
@@ -115,6 +115,612 @@ deployment, and production smoke checks behind the scenes. Surface important
115
115
  decisions, blockers, and evidence, but do not make the user manually orchestrate
116
116
  routine Snipara or release mechanics.`;
117
117
  var UNIVERSAL_CLIENT_GUIDANCE = "The target experience is outcome-first: the user can ask for engineering judgment or a release, and the agent should use Snipara context, workflow state, verification, package checks, Git, deploy, and smoke checks without making the user orchestrate routine mechanics.";
118
+ var DECISION_COMMIT_TERMS = [
119
+ "adopt",
120
+ "because",
121
+ "decide",
122
+ "decision",
123
+ "drop",
124
+ "migrate",
125
+ "prefer",
126
+ "replace",
127
+ "revert",
128
+ "standardize",
129
+ "switch"
130
+ ];
131
+ function buildActivationId() {
132
+ return `act_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
133
+ }
134
+ function getActivationDir() {
135
+ return path.join(process.cwd(), ".snipara", "activation");
136
+ }
137
+ function getActivationManifestPath() {
138
+ return path.join(getActivationDir(), "manifest.json");
139
+ }
140
+ function getActivationHandoffPath() {
141
+ return path.join(getActivationDir(), "handoff.md");
142
+ }
143
+ function getMemoryCandidatesPath() {
144
+ return path.join(getActivationDir(), "memory-candidates.json");
145
+ }
146
+ function writeActivationManifest(manifest) {
147
+ fs.mkdirSync(getActivationDir(), { recursive: true });
148
+ fs.writeFileSync(getActivationManifestPath(), JSON.stringify(manifest, null, 2) + "\n", "utf8");
149
+ }
150
+ function updateActivationManifest(manifest) {
151
+ manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
152
+ writeActivationManifest(manifest);
153
+ }
154
+ function createActivationLane(status, detail, command) {
155
+ return command ? { status, detail, command } : { status, detail };
156
+ }
157
+ function failActivationLane(detail, command, error) {
158
+ const message = error instanceof Error && error.message ? error.message : "unknown error";
159
+ return {
160
+ status: "failed",
161
+ detail,
162
+ command,
163
+ error: message.slice(0, 500)
164
+ };
165
+ }
166
+ function readPackageJsonScripts() {
167
+ const packageJsonPath = path.join(process.cwd(), "package.json");
168
+ if (!fs.existsSync(packageJsonPath)) {
169
+ return [];
170
+ }
171
+ try {
172
+ const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
173
+ return Object.keys(parsed.scripts ?? {}).sort();
174
+ } catch {
175
+ return [];
176
+ }
177
+ }
178
+ function readGitRemote() {
179
+ try {
180
+ const remote = execSync("git remote get-url origin", {
181
+ encoding: "utf-8",
182
+ stdio: ["ignore", "pipe", "ignore"],
183
+ timeout: 500
184
+ }).trim();
185
+ return remote || null;
186
+ } catch {
187
+ return null;
188
+ }
189
+ }
190
+ function readGitStatusPorcelain() {
191
+ try {
192
+ const output = execSync("git status --short", {
193
+ cwd: process.cwd(),
194
+ encoding: "utf-8",
195
+ stdio: ["ignore", "pipe", "ignore"],
196
+ timeout: 1e3
197
+ }).trim();
198
+ return output ? output.split(/\r?\n/).slice(0, 25) : [];
199
+ } catch {
200
+ return [];
201
+ }
202
+ }
203
+ function readRecentCommitSubjects() {
204
+ try {
205
+ const output = execSync("git log --oneline --max-count=5", {
206
+ cwd: process.cwd(),
207
+ encoding: "utf-8",
208
+ stdio: ["ignore", "pipe", "ignore"],
209
+ timeout: 1e3
210
+ }).trim();
211
+ return output ? output.split(/\r?\n/) : [];
212
+ } catch {
213
+ return [];
214
+ }
215
+ }
216
+ function readDecisionCommitSubjectLines() {
217
+ try {
218
+ const output = execSync("git log --pretty=format:%h%x20%s --max-count=50", {
219
+ cwd: process.cwd(),
220
+ encoding: "utf-8",
221
+ stdio: ["ignore", "pipe", "ignore"],
222
+ timeout: 1500
223
+ }).trim();
224
+ if (!output) {
225
+ return [];
226
+ }
227
+ return output.split(/\r?\n/).map((line) => line.trim()).filter((line) => DECISION_COMMIT_TERMS.some((term) => line.toLowerCase().includes(term))).slice(0, 8);
228
+ } catch {
229
+ return [];
230
+ }
231
+ }
232
+ function readMemoryCandidateLines(relativePath) {
233
+ const absolutePath = path.join(process.cwd(), relativePath);
234
+ if (!fs.existsSync(absolutePath) || fs.statSync(absolutePath).isDirectory()) {
235
+ return [];
236
+ }
237
+ const content = fs.readFileSync(absolutePath, "utf8").slice(0, 24e3);
238
+ return content.split(/\r?\n/).map((line) => line.trim()).filter((line) => /decision|decided|must|should|always|never|convention|rule/i.test(line)).slice(0, 4).map((line) => ({
239
+ source: relativePath,
240
+ text: line.slice(0, 280),
241
+ status: "needs_review",
242
+ reason: "Detected project guidance language. Review before storing as durable memory.",
243
+ evidence: classifyDecisionSource(relativePath)
244
+ }));
245
+ }
246
+ function estimateFileTokens(relativePath) {
247
+ const absolutePath = path.join(process.cwd(), relativePath);
248
+ if (!fs.existsSync(absolutePath) || fs.statSync(absolutePath).isDirectory()) {
249
+ return 0;
250
+ }
251
+ try {
252
+ const content = fs.readFileSync(absolutePath, "utf8");
253
+ return Math.ceil(content.length / 4);
254
+ } catch {
255
+ return 0;
256
+ }
257
+ }
258
+ function buildMemoryCandidatePreviews(scan) {
259
+ const seen = /* @__PURE__ */ new Set();
260
+ const gitCandidates = scan.git.recentDecisionCommits.map((line) => ({
261
+ source: "git log",
262
+ text: line.slice(0, 280),
263
+ status: "needs_review",
264
+ reason: "Detected decision-language in recent commit history. Confirm intent before storing.",
265
+ evidence: "git_commit_subject"
266
+ }));
267
+ const candidates = [
268
+ ...scan.files.candidateDocs.flatMap(readMemoryCandidateLines),
269
+ ...gitCandidates
270
+ ];
271
+ return candidates.filter((candidate) => {
272
+ const key = `${candidate.source}:${candidate.text}`;
273
+ if (seen.has(key)) {
274
+ return false;
275
+ }
276
+ seen.add(key);
277
+ return true;
278
+ }).slice(0, 20);
279
+ }
280
+ function readTextFileSnippet(relativePath, maxChars = 24e3) {
281
+ const absolutePath = path.join(process.cwd(), relativePath);
282
+ if (!fs.existsSync(absolutePath) || fs.statSync(absolutePath).isDirectory()) {
283
+ return "";
284
+ }
285
+ try {
286
+ return fs.readFileSync(absolutePath, "utf8").slice(0, maxChars);
287
+ } catch {
288
+ return "";
289
+ }
290
+ }
291
+ function buildStalenessFindings(scan) {
292
+ const findings = [];
293
+ const scriptSet = new Set(scan.scripts);
294
+ for (const source of scan.files.candidateDocs.slice(0, 30)) {
295
+ const content = readTextFileSnippet(source);
296
+ if (!content) {
297
+ continue;
298
+ }
299
+ const scriptMatches = [...content.matchAll(/\b(?:npm|pnpm|yarn|bun)\s+run\s+([a-z0-9:_-]+)/gi)];
300
+ for (const match of scriptMatches) {
301
+ const scriptName = match[1];
302
+ if (scriptName && !scriptSet.has(scriptName)) {
303
+ findings.push({
304
+ source,
305
+ severity: "possible",
306
+ summary: `Documentation references \`${match[0]}\`, but package.json has no \`${scriptName}\` script.`,
307
+ recommendation: "Verify the setup docs or add the missing script before relying on this instruction."
308
+ });
309
+ }
310
+ }
311
+ if (scan.packageManagers.length === 1 && scan.packageManagers[0] === "pnpm" && /\bnpm install\b/i.test(content)) {
312
+ findings.push({
313
+ source,
314
+ severity: "possible",
315
+ summary: "Documentation mentions `npm install`, but the repo has a pnpm lockfile.",
316
+ recommendation: "Confirm whether npm remains supported or update setup docs to pnpm."
317
+ });
318
+ }
319
+ }
320
+ return findings.slice(0, 8);
321
+ }
322
+ function buildContextEconomyReport(scan, dayZeroQuery) {
323
+ const indexedSourceTokens = scan.files.candidateDocs.reduce(
324
+ (total, source) => total + estimateFileTokens(source),
325
+ 0
326
+ );
327
+ const rawWindowBaselineTokens = Math.max(indexedSourceTokens, 8e3);
328
+ const estimatedPromptTokens = Math.ceil(dayZeroQuery.length / 4);
329
+ const estimatedRetrievedTokens = Math.min(
330
+ rawWindowBaselineTokens,
331
+ Math.max(estimatedPromptTokens + scan.files.candidateDocs.length * 160, 1200)
332
+ );
333
+ const estimatedSavedTokens = Math.max(0, rawWindowBaselineTokens - estimatedRetrievedTokens);
334
+ return {
335
+ basis: "activation_estimate",
336
+ rawWindowBaselineTokens,
337
+ estimatedRetrievedTokens,
338
+ estimatedSavedTokens,
339
+ savingsPercent: rawWindowBaselineTokens > 0 ? Math.round(estimatedSavedTokens / rawWindowBaselineTokens * 100) : 0,
340
+ note: "Estimated from activation sources until hosted query receipts provide measured savings."
341
+ };
342
+ }
343
+ function buildAgentReadinessReport(scan) {
344
+ const findings = buildStalenessFindings(scan);
345
+ return {
346
+ stalenessFindings: findings,
347
+ summary: findings.length > 0 ? `${findings.length} possible doc staleness finding(s) need review.` : "No obvious setup-doc staleness found in activation sources."
348
+ };
349
+ }
350
+ function writeMemoryCandidates(candidates) {
351
+ fs.mkdirSync(getActivationDir(), { recursive: true });
352
+ fs.writeFileSync(
353
+ getMemoryCandidatesPath(),
354
+ JSON.stringify({ candidates, note: "Review required before durable memory import." }, null, 2) + "\n",
355
+ "utf8"
356
+ );
357
+ }
358
+ function writeInitialHandoff(answers, manifest) {
359
+ fs.mkdirSync(getActivationDir(), { recursive: true });
360
+ const statusLines = readGitStatusPorcelain();
361
+ const recentCommits = readRecentCommitSubjects();
362
+ const lines = [
363
+ `# Initial Snipara Handoff`,
364
+ "",
365
+ `Project: ${answers.projectSlug}`,
366
+ `AI client: ${getClientDisplayName(answers.aiClient)}`,
367
+ `Repo path: ${manifest.repoPath}`,
368
+ `Git branch: ${manifest.git.branch ?? "not detected"}`,
369
+ `Git remote: ${manifest.git.remote ?? "not detected"}`,
370
+ "",
371
+ "## Activation lanes",
372
+ ...Object.entries(manifest.lanes).map(
373
+ ([name, lane]) => `- ${name}: ${lane.status} - ${lane.detail}`
374
+ ),
375
+ "",
376
+ "## Local status",
377
+ ...statusLines.length > 0 ? statusLines.map((line) => `- ${line}`) : ["- clean or unavailable"],
378
+ "",
379
+ "## Recent commits",
380
+ ...recentCommits.length > 0 ? recentCommits.map((line) => `- ${line}`) : ["- not available"],
381
+ "",
382
+ "## Next",
383
+ "- Ask the coding agent what it should know before editing the first target area.",
384
+ "- Review memory candidates before accepting durable memory.",
385
+ "- Connect GitHub later for PRs, reviews, team sync, and continuous sync.",
386
+ ""
387
+ ];
388
+ fs.writeFileSync(getActivationHandoffPath(), lines.join("\n"), "utf8");
389
+ }
390
+ function detectLocalActivationScan(detection) {
391
+ const cwd = process.cwd();
392
+ const exists = (relativePath) => fs.existsSync(path.join(cwd, relativePath));
393
+ const candidateDocs = findDecisionArchaeologySources(cwd);
394
+ const lockfiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lockb"].filter(
395
+ exists
396
+ );
397
+ const packageManagers = [
398
+ exists("pnpm-lock.yaml") ? "pnpm" : null,
399
+ exists("package-lock.json") ? "npm" : null,
400
+ exists("yarn.lock") ? "yarn" : null,
401
+ exists("bun.lockb") ? "bun" : null
402
+ ].filter((value) => Boolean(value));
403
+ const rootEntries = fs.existsSync(cwd) ? fs.readdirSync(cwd).slice(0, 250) : [];
404
+ const rootExtensions = new Set(
405
+ rootEntries.map((entry) => path.extname(entry).replace(/^\./, "")).filter(Boolean)
406
+ );
407
+ const languages = [
408
+ exists("package.json") || rootExtensions.has("ts") || rootExtensions.has("tsx") ? "typescript" : null,
409
+ exists("package.json") || rootExtensions.has("js") || rootExtensions.has("jsx") ? "javascript" : null,
410
+ exists("pyproject.toml") || exists("requirements.txt") || rootExtensions.has("py") ? "python" : null,
411
+ exists("go.mod") || rootExtensions.has("go") ? "go" : null,
412
+ exists("Cargo.toml") || rootExtensions.has("rs") ? "rust" : null
413
+ ].filter((value) => Boolean(value));
414
+ return {
415
+ files: {
416
+ candidateDocs,
417
+ lockfiles,
418
+ hasPackageJson: exists("package.json"),
419
+ hasPyproject: exists("pyproject.toml"),
420
+ hasRequirements: exists("requirements.txt"),
421
+ hasDockerfile: exists("Dockerfile")
422
+ },
423
+ packageManagers,
424
+ languages: [...new Set(languages)],
425
+ scripts: readPackageJsonScripts(),
426
+ git: {
427
+ detected: detection.inGitRepo,
428
+ branch: detection.inGitRepo ? detectGitBranch() : null,
429
+ remote: detection.inGitRepo ? readGitRemote() : null,
430
+ recentDecisionCommits: detection.inGitRepo ? readDecisionCommitSubjectLines() : []
431
+ }
432
+ };
433
+ }
434
+ function classifyDecisionSource(relativePath) {
435
+ if (/(^|\/)(adr|decisions?)(\/|$)/i.test(relativePath)) {
436
+ return "adr_or_decision_doc";
437
+ }
438
+ if (/AGENTS\.md|CLAUDE\.md|MEMORY\.md|\.cursor\/rules|copilot-instructions/i.test(relativePath)) {
439
+ return "agent_instruction";
440
+ }
441
+ if (/CHANGELOG/i.test(relativePath)) {
442
+ return "changelog";
443
+ }
444
+ return "project_document";
445
+ }
446
+ function listFilesUnder(relativeDir, maxFiles) {
447
+ const root = path.join(process.cwd(), relativeDir);
448
+ if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) {
449
+ return [];
450
+ }
451
+ const results = [];
452
+ const visit = (dir) => {
453
+ if (results.length >= maxFiles) {
454
+ return;
455
+ }
456
+ for (const entry of fs.readdirSync(dir).sort()) {
457
+ const absolutePath = path.join(dir, entry);
458
+ const stat = fs.statSync(absolutePath);
459
+ if (stat.isDirectory()) {
460
+ visit(absolutePath);
461
+ } else if (/\.(md|mdx|txt|mdc)$/i.test(entry)) {
462
+ results.push(path.relative(process.cwd(), absolutePath));
463
+ }
464
+ if (results.length >= maxFiles) {
465
+ return;
466
+ }
467
+ }
468
+ };
469
+ visit(root);
470
+ return results;
471
+ }
472
+ function findDecisionArchaeologySources(cwd) {
473
+ const exists = (relativePath) => fs.existsSync(path.join(cwd, relativePath));
474
+ const directSources = [
475
+ "README.md",
476
+ "CHANGELOG.md",
477
+ "MEMORY.md",
478
+ ...["AGENTS.md", "CLAUDE.md", ".github/copilot-instructions.md"].filter(
479
+ (source) => exists(source)
480
+ )
481
+ ].filter(exists);
482
+ const archaeologySources = [
483
+ ...listFilesUnder("docs/adr", 20),
484
+ ...listFilesUnder("docs/adrs", 20),
485
+ ...listFilesUnder("docs/decision", 20),
486
+ ...listFilesUnder("docs/decisions", 20),
487
+ ...listFilesUnder(".cursor/rules", 20)
488
+ ];
489
+ return [.../* @__PURE__ */ new Set([...directSources, ...archaeologySources])].slice(0, 80);
490
+ }
491
+ function createInitialFirstWorkBrief(answers, detection, scan) {
492
+ const githubLine = answers.githubRepo ? `GitHub detected: ${answers.githubRepo.fullName}` : "No GitHub integration required for first value.";
493
+ const commands = scan.scripts.length > 0 ? scan.scripts.join(", ") : "no package scripts detected";
494
+ const docs = scan.files.candidateDocs.length > 0 ? scan.files.candidateDocs.join(", ") : "no standard docs detected";
495
+ const languages = scan.languages.length > 0 ? scan.languages.join(", ") : "not detected yet";
496
+ const hotFiles = scan.files.candidateDocs.slice(0, 5);
497
+ const hotFileLine = hotFiles.length > 0 ? `First files to ground on: ${hotFiles.join(", ")}.` : "First grounding files will appear after local source sync or hosted provider sync.";
498
+ const dayZeroQuery = "What is this project, what is currently in flight, and what should an agent know before making the first edit?";
499
+ return {
500
+ title: `First Work Brief for ${answers.projectSlug}`,
501
+ status: "partial",
502
+ sections: [
503
+ {
504
+ title: "Repository summary",
505
+ lines: [
506
+ detection.inGitRepo ? "Local Git repository detected." : "Local folder detected.",
507
+ githubLine,
508
+ `AI client: ${getClientDisplayName(answers.aiClient)}.`,
509
+ `Languages: ${languages}.`
510
+ ]
511
+ },
512
+ {
513
+ title: "Current architecture",
514
+ lines: [
515
+ `Initial docs: ${docs}.`,
516
+ `Package scripts: ${commands}.`,
517
+ hotFileLine,
518
+ "Source indexing runs before claiming architecture certainty."
519
+ ]
520
+ },
521
+ {
522
+ title: "Day-zero answer pack",
523
+ lines: [
524
+ `Ask Snipara: "${dayZeroQuery}"`,
525
+ "Goal: reach one correct, non-obvious statement about this repository in under 5 minutes."
526
+ ]
527
+ },
528
+ {
529
+ title: "Current risks",
530
+ lines: [
531
+ "Treat generated memory as candidates until reviewed.",
532
+ "GitHub PR/review intelligence requires explicit GitHub connection later."
533
+ ]
534
+ },
535
+ {
536
+ title: "Suggested next task",
537
+ lines: ["Ask your agent what it should know before editing the first target area."]
538
+ },
539
+ {
540
+ title: "Top impacted modules",
541
+ lines: [
542
+ "Code Graph is available on Free within capacity caps; first answers improve as symbols index.",
543
+ "For the first PR, run snipara_code_impact or companion code impact before editing."
544
+ ]
545
+ }
546
+ ]
547
+ };
548
+ }
549
+ function createActivationManifest(answers, detection, mode = "default", scan) {
550
+ const now = (/* @__PURE__ */ new Date()).toISOString();
551
+ const hasHostedConfig = answers.profile !== "runtime-only";
552
+ const hasCompanion = answers.installCompanion;
553
+ const localScan = scan ?? detectLocalActivationScan(detection);
554
+ const dayZeroQuery = "What is this project, what is currently in flight, and what should an agent know before making the first edit?";
555
+ return {
556
+ version: "create-snipara-activation-v1",
557
+ activationId: buildActivationId(),
558
+ mode,
559
+ activationMetric: {
560
+ name: "time_to_how_did_it_know_that",
561
+ targetMinutes: 5,
562
+ proof: "A correct, non-obvious statement about this repository from the first answer pack."
563
+ },
564
+ dayZeroQuery: {
565
+ tool: "snipara_context_query",
566
+ query: dayZeroQuery,
567
+ expectedOutcome: "First own-repo answer pack before the user reads product docs."
568
+ },
569
+ agentReadiness: buildAgentReadinessReport(localScan),
570
+ contextEconomy: buildContextEconomyReport(localScan, dayZeroQuery),
571
+ projectSlug: answers.projectSlug,
572
+ projectId: answers.projectId || null,
573
+ repoPath: process.cwd(),
574
+ aiClient: answers.aiClient,
575
+ git: {
576
+ detected: detection.inGitRepo,
577
+ branch: answers.githubRepo?.branch ?? localScan.git.branch,
578
+ remote: answers.githubRepo?.remoteUrl ?? localScan.git.remote,
579
+ githubRepo: answers.githubRepo?.fullName ?? null
580
+ },
581
+ localScan,
582
+ lanes: {
583
+ connection: createActivationLane(
584
+ hasHostedConfig ? "ready" : "skipped",
585
+ hasHostedConfig ? "Hosted MCP config written." : "Runtime-only profile skipped Hosted MCP config."
586
+ ),
587
+ clientConfig: createActivationLane(
588
+ hasHostedConfig ? "ready" : "skipped",
589
+ hasHostedConfig ? `${getClientDisplayName(answers.aiClient)} project files generated.` : "No AI client config generated for runtime-only profile."
590
+ ),
591
+ localSnapshot: createActivationLane(
592
+ hasCompanion ? "queued" : "skipped",
593
+ hasCompanion ? "Local source activation will create a repository snapshot." : "Install companion later to activate local source context."
594
+ ),
595
+ contextIndex: createActivationLane(
596
+ hasCompanion ? "queued" : "skipped",
597
+ hasCompanion ? "Context indexing starts from local docs and instruction files." : "Context indexing requires companion or hosted provider sync."
598
+ ),
599
+ codeGraph: createActivationLane(
600
+ hasCompanion ? "queued" : "skipped",
601
+ hasCompanion ? "Free Code Graph indexing starts from local source overlay within capacity caps." : "Free Code Graph is available after companion or hosted provider sync."
602
+ ),
603
+ memoryCandidates: createActivationLane(
604
+ hasCompanion ? "needs_review" : "skipped",
605
+ hasCompanion ? "Candidate decisions stay pending review; no durable memory is auto-approved." : "Install companion later to extract reviewable memory candidates."
606
+ ),
607
+ handoff: createActivationLane(
608
+ hasCompanion ? "queued" : "skipped",
609
+ hasCompanion ? "Initial local handoff will summarize branch, files, and setup state." : "Install companion later to create local handoffs."
610
+ ),
611
+ firstBrief: createActivationLane(
612
+ "ready",
613
+ "First Work Brief and day-zero answer-pack prompt generated from local setup signals."
614
+ ),
615
+ githubSync: createActivationLane(
616
+ answers.configureGitHub && answers.githubRepo ? "queued" : "skipped",
617
+ answers.configureGitHub && answers.githubRepo ? "GitHub automation can be connected after explicit approval." : "No GitHub integration required; connect later for PRs, reviews, and team sync."
618
+ )
619
+ },
620
+ artifacts: {
621
+ handoffPath: null,
622
+ memoryCandidatesPath: null
623
+ },
624
+ firstBrief: createInitialFirstWorkBrief(answers, detection, localScan),
625
+ createdAt: now,
626
+ updatedAt: now
627
+ };
628
+ }
629
+ function runLocalSourceActivation(answers, manifest) {
630
+ if (!answers.installCompanion || answers.profile === "runtime-only") {
631
+ updateActivationManifest(manifest);
632
+ return;
633
+ }
634
+ const companionCommand = detectCompanionCommand();
635
+ if (!companionCommand) {
636
+ const detail = `${COMPANION_COMMAND_NAME} ${MIN_COMPANION_VERSION}+ is not on PATH after setup.`;
637
+ manifest.lanes.localSnapshot = createActivationLane("skipped", detail);
638
+ manifest.lanes.contextIndex = createActivationLane("skipped", detail);
639
+ manifest.lanes.codeGraph = createActivationLane("skipped", detail);
640
+ updateActivationManifest(manifest);
641
+ return;
642
+ }
643
+ const initCommand = `${companionCommand} source init .`;
644
+ const syncCommand = `${companionCommand} source sync --json`;
645
+ const spinner = ora("Activating local Project Intelligence").start();
646
+ try {
647
+ execSync(initCommand, {
648
+ cwd: process.cwd(),
649
+ encoding: "utf-8",
650
+ stdio: ["ignore", "pipe", "pipe"],
651
+ timeout: 3e4
652
+ });
653
+ manifest.lanes.localSnapshot = createActivationLane(
654
+ "ready",
655
+ "Local source snapshot created.",
656
+ initCommand
657
+ );
658
+ } catch (error) {
659
+ spinner.warn("Local source snapshot was not created");
660
+ manifest.lanes.localSnapshot = failActivationLane(
661
+ "Local source activation failed; setup can still continue.",
662
+ initCommand,
663
+ error
664
+ );
665
+ updateActivationManifest(manifest);
666
+ return;
667
+ }
668
+ try {
669
+ execSync(syncCommand, {
670
+ cwd: process.cwd(),
671
+ encoding: "utf-8",
672
+ stdio: ["ignore", "pipe", "pipe"],
673
+ timeout: 45e3
674
+ });
675
+ manifest.lanes.contextIndex = createActivationLane(
676
+ "indexing",
677
+ "Local documents submitted for context indexing.",
678
+ syncCommand
679
+ );
680
+ manifest.lanes.codeGraph = createActivationLane(
681
+ "indexing",
682
+ "Local code overlay submitted for Code Graph indexing.",
683
+ syncCommand
684
+ );
685
+ spinner.succeed("Local Project Intelligence activation started");
686
+ } catch (error) {
687
+ spinner.warn("Local source sync did not complete");
688
+ manifest.lanes.contextIndex = failActivationLane(
689
+ "Context indexing could not be started from the local snapshot.",
690
+ syncCommand,
691
+ error
692
+ );
693
+ manifest.lanes.codeGraph = failActivationLane(
694
+ "Code Graph indexing could not be started from the local snapshot.",
695
+ syncCommand,
696
+ error
697
+ );
698
+ }
699
+ updateActivationManifest(manifest);
700
+ }
701
+ function createActivationArtifacts(answers, manifest) {
702
+ const candidates = buildMemoryCandidatePreviews(manifest.localScan);
703
+ writeMemoryCandidates(candidates);
704
+ manifest.artifacts.memoryCandidatesPath = path.relative(process.cwd(), getMemoryCandidatesPath());
705
+ manifest.lanes.memoryCandidates = createActivationLane(
706
+ candidates.length > 0 ? "needs_review" : "skipped",
707
+ candidates.length > 0 ? `${candidates.length} memory candidates prepared for review; none were imported.` : "No memory candidates found in local docs.",
708
+ manifest.artifacts.memoryCandidatesPath
709
+ );
710
+ writeInitialHandoff(answers, manifest);
711
+ manifest.artifacts.handoffPath = path.relative(process.cwd(), getActivationHandoffPath());
712
+ manifest.lanes.handoff = createActivationLane(
713
+ "ready",
714
+ "Initial local handoff created.",
715
+ manifest.artifacts.handoffPath
716
+ );
717
+ manifest.lanes.firstBrief = createActivationLane(
718
+ "ready",
719
+ "First Work Brief generated from local setup and scan signals.",
720
+ path.relative(process.cwd(), getActivationManifestPath())
721
+ );
722
+ updateActivationManifest(manifest);
723
+ }
118
724
  var DeviceAuthorizationAborted = class extends Error {
119
725
  };
120
726
  var AI_CLIENT_CHOICES = [
@@ -204,7 +810,7 @@ function buildProgram() {
204
810
  ).option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
205
811
  "--profile <profile>",
206
812
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
207
- ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").addOption(new Option("--full", "Legacy alias for --profile full-stack").hideHelp()).option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
813
+ ).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("--starter", "Mark this run as a starter activation and print dashboard-first guidance").option("--runtime-only", "Install only Snipara Sandbox").addOption(new Option("--full", "Legacy alias for --profile full-stack").hideHelp()).option("-y, --yes", "Accept defaults without prompting").action(async (options) => {
208
814
  printBanner();
209
815
  await runInit(options);
210
816
  });
@@ -219,6 +825,10 @@ function buildProgram() {
219
825
  printBanner();
220
826
  await runRepair(options);
221
827
  });
828
+ program.command("demo").description("Open the guided Snipara activation demo without changing this repository").option("--no-open", "Print demo links without opening a browser").action((options) => {
829
+ printBanner();
830
+ runDemo(options);
831
+ });
222
832
  program.command("upgrade").description("Upgrade installed Snipara local components").option("--slug <slug>", "Project slug override").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) => {
223
833
  printBanner();
224
834
  await runUpgrade(options);
@@ -241,7 +851,7 @@ function addSharedRootOptions(program) {
241
851
  ).option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
242
852
  "--profile <profile>",
243
853
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
244
- ).option("--skip-companion", "Skip local companion CLI installation").option("--skip-mcp", "Skip local snipara-mcp package installation").option("--skip-runtime", "Skip snipara-sandbox installation").option("--skip-hooks", "Skip hook generation").option("--skip-test", "Skip hosted connection test").option("--with-orchestrator", "Install optional snipara-orchestrator package").option("--github", "Open GitHub repository automation setup when a git remote is detected").option("--skip-github", "Skip the GitHub automation prompt").option("--github-path <path>", "Optional GitHub path filter for the initial repository sync").option("--runtime-only", "Install only Snipara Sandbox").addOption(new Option("--full", "Legacy alias for --profile full-stack").hideHelp()).option("-y, --yes", "Accept defaults without prompting");
854
+ ).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("--starter", "Mark this run as a starter activation and print dashboard-first guidance").option("--runtime-only", "Install only Snipara Sandbox").addOption(new Option("--full", "Legacy alias for --profile full-stack").hideHelp()).option("-y, --yes", "Accept defaults without prompting");
245
855
  }
246
856
  async function main() {
247
857
  const program = buildProgram();
@@ -340,6 +950,7 @@ function parseInitOptionsFromArgv(args) {
340
950
  "--Full": "full",
341
951
  "--github": "github",
342
952
  "--skip-github": "skipGithub",
953
+ "--starter": "starter",
343
954
  "--yes": "yes",
344
955
  "-y": "yes"
345
956
  };
@@ -368,6 +979,8 @@ function parseInitOptionsFromArgv(args) {
368
979
  async function runInit(options) {
369
980
  const normalizedOptions = normalizeInitOptions(options);
370
981
  const answers = await gatherConfiguration(normalizedOptions);
982
+ const activationDetection = detectEnvironment();
983
+ const activationScan = detectLocalActivationScan(activationDetection);
371
984
  if (answers.installMcp || answers.installRuntime || answers.installOrchestrator) {
372
985
  await installPythonPackages(answers, false);
373
986
  }
@@ -392,7 +1005,15 @@ async function runInit(options) {
392
1005
  await createCompanionPack(answers);
393
1006
  const validationReport = await runValidation(answers, !normalizedOptions.skipTest);
394
1007
  writeDoctorReport(validationReport);
395
- printSuccess(answers, validationReport);
1008
+ const activationManifest = createActivationManifest(
1009
+ answers,
1010
+ activationDetection,
1011
+ normalizedOptions.starter ? "starter" : "default",
1012
+ activationScan
1013
+ );
1014
+ runLocalSourceActivation(answers, activationManifest);
1015
+ createActivationArtifacts(answers, activationManifest);
1016
+ printSuccess(answers, validationReport, activationManifest);
396
1017
  if (answers.configureGitHub && answers.githubRepo) {
397
1018
  await openGitHubAutomation(answers);
398
1019
  }
@@ -1031,6 +1652,27 @@ function openBrowser(url) {
1031
1652
  `));
1032
1653
  }
1033
1654
  }
1655
+ function runDemo(options) {
1656
+ const demoUrl = `${BASE_URL}/demo#sixty-second-demo`;
1657
+ const docsUrl = `${BASE_URL}/docs/integration/create-snipara`;
1658
+ const proofUrl = `${BASE_URL}/proof`;
1659
+ console.log(chalk.bold("\nSnipara activation demo\n"));
1660
+ console.log("Use this when you want to see the value before connecting a real repository.");
1661
+ console.log("\nWhat to inspect:");
1662
+ console.log(" 1. What Changed");
1663
+ console.log(" 2. Start Work / First Work Brief");
1664
+ console.log(" 3. Project Intelligence");
1665
+ console.log(" 4. Impact Graph");
1666
+ console.log(" 5. Adaptive Routing");
1667
+ console.log("\nLinks:");
1668
+ console.log(` Demo: ${demoUrl}`);
1669
+ console.log(` Setup docs: ${docsUrl}`);
1670
+ console.log(` Proof: ${proofUrl}`);
1671
+ if (options.open !== false) {
1672
+ console.log(chalk.dim("\nOpening the 60-second demo...\n"));
1673
+ openBrowser(demoUrl);
1674
+ }
1675
+ }
1034
1676
  function sleep(ms) {
1035
1677
  return new Promise((resolve) => setTimeout(resolve, ms));
1036
1678
  }
@@ -1765,8 +2407,8 @@ Agent task lifecycle:
1765
2407
  work.
1766
2408
  6. Use whichever structural code graph tools are exposed in the current session
1767
2409
  for callers, imports, neighbors, and path questions. Tool exposure can vary.
1768
- 7. On paid Context plans, use \`snipara_code_symbol_card\` for agent-ready symbol
1769
- context and \`snipara-companion code impact\` before risky multi-file changes, PR
2410
+ 7. Use \`snipara_code_symbol_card\` for agent-ready symbol context within plan
2411
+ capacity and \`snipara-companion code impact\` before risky multi-file changes, PR
1770
2412
  reviews, routes, services, jobs, auth, billing, deployment, schema, migrations,
1771
2413
  or explicit "what is missing" assessments.
1772
2414
  8. Use \`snipara_plan\` for complex or multi-surface work in any plan when
@@ -1833,7 +2475,7 @@ ${EXPERIENCE_GOAL_SECTION}
1833
2475
  - Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for canonical structural code questions.
1834
2476
  - For code impact and structural code questions, use \`snipara-companion code callers/imports/neighbors/shortest-path/impact\` first when \`snipara-companion\` is installed; it auto-selects hosted MCP for clean indexed code or the local overlay for dirty/ahead worktrees and reports \`sourceSelection\`. Use hosted \`snipara_code_impact\` only when companion is unavailable or after push/reindex for canonical graph impact.
1835
2477
  - Run \`snipara-companion code impact\` before risky multi-file changes, PR reviews, routes, services, jobs, auth, billing, deployment, schema, migrations, or explicit "what is missing" assessments.
1836
- - On paid Context plans, use \`snipara_code_symbol_card\` before editing important symbols.
2478
+ - Use \`snipara_code_symbol_card\` before editing important symbols within plan capacity.
1837
2479
  - Check every \`snipara_code_*\` response for indexed commit SHA, indexing time, included files, coverage, and freshness warnings.
1838
2480
  - 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.
1839
2481
  - If a broad query is slow, retry once with a narrow keyword query before falling back to local search.
@@ -1873,7 +2515,7 @@ ${EXPERIENCE_GOAL_SECTION}
1873
2515
  - Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for canonical structural code questions.
1874
2516
  - For code impact and structural code questions, use \`snipara-companion code callers/imports/neighbors/shortest-path/impact\` first when \`snipara-companion\` is installed; it auto-selects hosted MCP for clean indexed code or the local overlay for dirty/ahead worktrees and reports \`sourceSelection\`. Use hosted \`snipara_code_impact\` only when companion is unavailable or after push/reindex for canonical graph impact.
1875
2517
  - Run \`snipara-companion code impact\` before risky multi-file changes, PR reviews, routes, services, jobs, auth, billing, deployment, schema, migrations, or explicit "what is missing" assessments.
1876
- - On paid Context plans, use \`snipara_code_symbol_card\` before editing important symbols.
2518
+ - Use \`snipara_code_symbol_card\` before editing important symbols within plan capacity.
1877
2519
  - Check every \`snipara_code_*\` response for indexed commit SHA, indexing time, included files, coverage, and freshness warnings.
1878
2520
  - Use \`snipara_plan\` for complex or multi-surface work when available. Keep simple Q&A on targeted \`snipara_context_query\`; for FULL-mode audits, comparisons, roadmap/implementation planning, release readiness, or package-surface reviews, use \`snipara_decompose\` to preserve axes and \`snipara_multi_query\` for independent follow-up questions when Pro+ tools are exposed.
1879
2521
  - Use local file reads, \`rg\`, \`git status --short\`, and tests for exact code edits and current working-tree state.
@@ -2685,7 +3327,7 @@ function getCompanionCommands(answers) {
2685
3327
  {
2686
3328
  title: "Analyze code impact before a risky change",
2687
3329
  command: `${COMPANION_NPX_COMMAND} code impact --changed-files src/api/webhooks.ts tests/webhooks.test.ts --diff-summary "webhook retry hardening"`,
2688
- purpose: "Use paid Context code impact analysis to surface likely tests, docs, routes, config, and risks."
3330
+ purpose: "Use code impact analysis within plan capacity to surface likely tests, docs, routes, config, and risks."
2689
3331
  },
2690
3332
  {
2691
3333
  title: answers.installOrchestrator ? "Run an explicit production orchestration gate" : "Enable explicit production orchestration",
@@ -2856,7 +3498,7 @@ ${guidance.map((line) => `- ${line}`).join("\n")}
2856
3498
  - Use \`answer_pack\` facts, caveats, source maps, and verification checks before making claims.
2857
3499
  - For coding tasks, choose a workflow mode before editing: LITE for small single-phase changes, FULL managed workflow for multi-file, risky, release/deploy, architectural, compaction-prone, or future-maintainer-sensitive work.
2858
3500
  - Use \`snipara_plan\` for complex or multi-surface work when exposed. Keep simple Q&A on targeted \`snipara_context_query\`; for FULL-mode audits, comparisons, roadmap/implementation planning, release readiness, or package-surface reviews, use \`snipara_decompose\` to preserve axes and \`snipara_multi_query\` for independent follow-up questions when Pro+ tools are exposed.
2859
- - Use \`snipara_code_symbol_card\` for important symbols. For risky multi-file changes, PR reviews, routes, services, jobs, auth, billing, deployment, schema, migrations, or explicit "what is missing" assessments, use \`snipara-companion code impact\` first when companion is available; use hosted \`snipara_code_impact\` only when companion is unavailable or after push/reindex for canonical graph impact.
3501
+ - Use \`snipara_code_symbol_card\` for important symbols within plan capacity. For risky multi-file changes, PR reviews, routes, services, jobs, auth, billing, deployment, schema, migrations, or explicit "what is missing" assessments, use \`snipara-companion code impact\` first when companion is available; use hosted \`snipara_code_impact\` only when companion is unavailable or after push/reindex for canonical graph impact.
2860
3502
  - Use the installed \`snipara-companion\` binary for low-latency hooks; use \`${COMPANION_NPX_COMMAND}\` for one-off terminal commands when freshness matters.
2861
3503
  - If a broad query is slow, retry once with a narrow keyword query before falling back to local search.
2862
3504
  - Use a JSON machine plan plus \`snipara-companion workflow start\`, \`phase-start\`, \`phase-commit\`, \`workflow resume\`, and \`final-commit\` for multi-phase work. After \`workflow resume\`, rerun \`workflow phase-start <phase_id>\` before editing again.
@@ -3643,7 +4285,85 @@ function printSetupVerdict(answers, report) {
3643
4285
  console.log(" AI client loaded MCP: not verifiable from this terminal");
3644
4286
  }
3645
4287
  }
3646
- function printSuccess(answers, report) {
4288
+ function formatActivationStatus(status) {
4289
+ if (status === "ready") {
4290
+ return chalk.green("\u2713 ready");
4291
+ }
4292
+ if (status === "indexing" || status === "queued") {
4293
+ return chalk.yellow(`\u23F3 ${status}`);
4294
+ }
4295
+ if (status === "needs_review") {
4296
+ return chalk.yellow("review");
4297
+ }
4298
+ if (status === "failed") {
4299
+ return chalk.red("failed");
4300
+ }
4301
+ return chalk.dim("skipped");
4302
+ }
4303
+ function printActivationSummary(manifest) {
4304
+ console.log(chalk.bold("\nProject Intelligence activation:\n"));
4305
+ const orderedLanes = [
4306
+ ["Connected", manifest.lanes.connection],
4307
+ ["AI client configured", manifest.lanes.clientConfig],
4308
+ ["Repository analyzed", manifest.lanes.localSnapshot],
4309
+ ["Context index", manifest.lanes.contextIndex],
4310
+ ["Code Graph", manifest.lanes.codeGraph],
4311
+ ["Memory candidates", manifest.lanes.memoryCandidates],
4312
+ ["Initial handoff", manifest.lanes.handoff],
4313
+ ["First Work Brief", manifest.lanes.firstBrief],
4314
+ ["GitHub sync", manifest.lanes.githubSync]
4315
+ ];
4316
+ for (const [label, lane] of orderedLanes) {
4317
+ console.log(` ${formatActivationStatus(lane.status)} ${label} - ${lane.detail}`);
4318
+ }
4319
+ console.log(chalk.bold("\nFirst Work Brief:\n"));
4320
+ for (const section of manifest.firstBrief.sections) {
4321
+ console.log(` ${section.title}`);
4322
+ for (const line of section.lines.slice(0, 2)) {
4323
+ console.log(chalk.dim(` - ${line}`));
4324
+ }
4325
+ }
4326
+ console.log(chalk.bold("\nDay-zero proof:\n"));
4327
+ console.log(` Tool: ${manifest.dayZeroQuery.tool}`);
4328
+ console.log(` Query: ${manifest.dayZeroQuery.query}`);
4329
+ console.log(
4330
+ chalk.dim(
4331
+ ` Target: ${manifest.activationMetric.targetMinutes} minutes to a true, non-obvious own-repo answer.`
4332
+ )
4333
+ );
4334
+ console.log(chalk.bold("\nAgent readiness:\n"));
4335
+ console.log(` ${manifest.agentReadiness.summary}`);
4336
+ for (const finding of manifest.agentReadiness.stalenessFindings.slice(0, 3)) {
4337
+ console.log(chalk.dim(` - ${finding.source}: ${finding.summary}`));
4338
+ }
4339
+ console.log(chalk.bold("\nContext economy:\n"));
4340
+ console.log(
4341
+ ` Estimated ${manifest.contextEconomy.estimatedRetrievedTokens.toLocaleString("en-US")} tokens retrieved instead of ${manifest.contextEconomy.rawWindowBaselineTokens.toLocaleString("en-US")} raw-window tokens.`
4342
+ );
4343
+ console.log(
4344
+ chalk.dim(
4345
+ ` Saved about ${manifest.contextEconomy.estimatedSavedTokens.toLocaleString("en-US")} tokens (${manifest.contextEconomy.savingsPercent}%). ${manifest.contextEconomy.note}`
4346
+ )
4347
+ );
4348
+ console.log(
4349
+ chalk.dim(
4350
+ `
4351
+ Activation manifest: ${path.relative(process.cwd(), getActivationManifestPath())}`
4352
+ )
4353
+ );
4354
+ if (manifest.artifacts.handoffPath) {
4355
+ console.log(chalk.dim(` Initial handoff: ${manifest.artifacts.handoffPath}`));
4356
+ }
4357
+ if (manifest.artifacts.memoryCandidatesPath) {
4358
+ console.log(chalk.dim(` Memory candidates: ${manifest.artifacts.memoryCandidatesPath}`));
4359
+ }
4360
+ if (manifest.mode === "starter") {
4361
+ console.log(
4362
+ chalk.dim(` Starter tour: ${BASE_URL}/demo#sixty-second-demo and ${BASE_URL}/dashboard`)
4363
+ );
4364
+ }
4365
+ }
4366
+ function printSuccess(answers, report, activationManifest) {
3647
4367
  console.log(
3648
4368
  chalk.green(`
3649
4369
  \u2554\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\u2557
@@ -3691,6 +4411,9 @@ function printSuccess(answers, report) {
3691
4411
  console.log(
3692
4412
  chalk.green(" \u2713 .snipara/companion") + chalk.dim(" - Doctor report and optional command references")
3693
4413
  );
4414
+ if (activationManifest) {
4415
+ printActivationSummary(activationManifest);
4416
+ }
3694
4417
  const failedChecks = report.checks.filter((check) => check.status === "fail");
3695
4418
  const warnedChecks = report.checks.filter((check) => check.status === "warn");
3696
4419
  console.log(chalk.bold("\nNext steps:\n"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-snipara",
3
- "version": "2.0.7",
3
+ "version": "2.0.9",
4
4
  "description": "Onboard Snipara Hosted MCP Context + Memory with auth, companion workflows, and optional Snipara Sandbox",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",