create-snipara 2.0.8 → 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 +262 -34
  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.8",
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,19 @@ 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
+ ];
118
131
  function buildActivationId() {
119
132
  return `act_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
120
133
  }
@@ -200,23 +213,139 @@ function readRecentCommitSubjects() {
200
213
  return [];
201
214
  }
202
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
+ }
203
232
  function readMemoryCandidateLines(relativePath) {
204
233
  const absolutePath = path.join(process.cwd(), relativePath);
205
234
  if (!fs.existsSync(absolutePath) || fs.statSync(absolutePath).isDirectory()) {
206
235
  return [];
207
236
  }
208
237
  const content = fs.readFileSync(absolutePath, "utf8").slice(0, 24e3);
209
- return content.split(/\r?\n/).map((line) => line.trim()).filter((line) => /decision|decided|must|should|always|never|convention|rule/i.test(line)).slice(0, 3);
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
+ }
210
257
  }
211
258
  function buildMemoryCandidatePreviews(scan) {
212
- return scan.files.candidateDocs.flatMap(
213
- (source) => readMemoryCandidateLines(source).map((line) => ({
214
- source,
215
- text: line.slice(0, 280),
216
- status: "needs_review",
217
- reason: "Detected project guidance language. Review before storing as durable memory."
218
- }))
219
- ).slice(0, 12);
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
+ };
220
349
  }
221
350
  function writeMemoryCandidates(candidates) {
222
351
  fs.mkdirSync(getActivationDir(), { recursive: true });
@@ -261,15 +390,7 @@ function writeInitialHandoff(answers, manifest) {
261
390
  function detectLocalActivationScan(detection) {
262
391
  const cwd = process.cwd();
263
392
  const exists = (relativePath) => fs.existsSync(path.join(cwd, relativePath));
264
- const candidateDocs = [
265
- "README.md",
266
- "AGENTS.md",
267
- "CLAUDE.md",
268
- "CHANGELOG.md",
269
- "docs",
270
- ".cursor/rules",
271
- ".github"
272
- ].filter(exists);
393
+ const candidateDocs = findDecisionArchaeologySources(cwd);
273
394
  const lockfiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lockb"].filter(
274
395
  exists
275
396
  );
@@ -305,15 +426,76 @@ function detectLocalActivationScan(detection) {
305
426
  git: {
306
427
  detected: detection.inGitRepo,
307
428
  branch: detection.inGitRepo ? detectGitBranch() : null,
308
- remote: detection.inGitRepo ? readGitRemote() : 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
+ }
309
467
  }
310
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);
311
490
  }
312
491
  function createInitialFirstWorkBrief(answers, detection, scan) {
313
492
  const githubLine = answers.githubRepo ? `GitHub detected: ${answers.githubRepo.fullName}` : "No GitHub integration required for first value.";
314
493
  const commands = scan.scripts.length > 0 ? scan.scripts.join(", ") : "no package scripts detected";
315
494
  const docs = scan.files.candidateDocs.length > 0 ? scan.files.candidateDocs.join(", ") : "no standard docs detected";
316
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?";
317
499
  return {
318
500
  title: `First Work Brief for ${answers.projectSlug}`,
319
501
  status: "partial",
@@ -332,9 +514,17 @@ function createInitialFirstWorkBrief(answers, detection, scan) {
332
514
  lines: [
333
515
  `Initial docs: ${docs}.`,
334
516
  `Package scripts: ${commands}.`,
517
+ hotFileLine,
335
518
  "Source indexing runs before claiming architecture certainty."
336
519
  ]
337
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
+ },
338
528
  {
339
529
  title: "Current risks",
340
530
  lines: [
@@ -349,22 +539,35 @@ function createInitialFirstWorkBrief(answers, detection, scan) {
349
539
  {
350
540
  title: "Top impacted modules",
351
541
  lines: [
352
- "Code Graph is indexing; impacted modules will improve as symbols are available.",
353
- "Use the activation dashboard or companion code impact once indexing reports ready."
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."
354
544
  ]
355
545
  }
356
546
  ]
357
547
  };
358
548
  }
359
- function createActivationManifest(answers, detection, mode = "default") {
549
+ function createActivationManifest(answers, detection, mode = "default", scan) {
360
550
  const now = (/* @__PURE__ */ new Date()).toISOString();
361
551
  const hasHostedConfig = answers.profile !== "runtime-only";
362
552
  const hasCompanion = answers.installCompanion;
363
- const localScan = detectLocalActivationScan(detection);
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?";
364
555
  return {
365
556
  version: "create-snipara-activation-v1",
366
557
  activationId: buildActivationId(),
367
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),
368
571
  projectSlug: answers.projectSlug,
369
572
  projectId: answers.projectId || null,
370
573
  repoPath: process.cwd(),
@@ -395,7 +598,7 @@ function createActivationManifest(answers, detection, mode = "default") {
395
598
  ),
396
599
  codeGraph: createActivationLane(
397
600
  hasCompanion ? "queued" : "skipped",
398
- hasCompanion ? "Code Graph indexing starts from local source overlay." : "Code Graph indexing requires companion or hosted provider sync."
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."
399
602
  ),
400
603
  memoryCandidates: createActivationLane(
401
604
  hasCompanion ? "needs_review" : "skipped",
@@ -407,7 +610,7 @@ function createActivationManifest(answers, detection, mode = "default") {
407
610
  ),
408
611
  firstBrief: createActivationLane(
409
612
  "ready",
410
- "First Work Brief preview generated from local setup signals."
613
+ "First Work Brief and day-zero answer-pack prompt generated from local setup signals."
411
614
  ),
412
615
  githubSync: createActivationLane(
413
616
  answers.configureGitHub && answers.githubRepo ? "queued" : "skipped",
@@ -776,6 +979,8 @@ function parseInitOptionsFromArgv(args) {
776
979
  async function runInit(options) {
777
980
  const normalizedOptions = normalizeInitOptions(options);
778
981
  const answers = await gatherConfiguration(normalizedOptions);
982
+ const activationDetection = detectEnvironment();
983
+ const activationScan = detectLocalActivationScan(activationDetection);
779
984
  if (answers.installMcp || answers.installRuntime || answers.installOrchestrator) {
780
985
  await installPythonPackages(answers, false);
781
986
  }
@@ -802,8 +1007,9 @@ async function runInit(options) {
802
1007
  writeDoctorReport(validationReport);
803
1008
  const activationManifest = createActivationManifest(
804
1009
  answers,
805
- detectEnvironment(),
806
- normalizedOptions.starter ? "starter" : "default"
1010
+ activationDetection,
1011
+ normalizedOptions.starter ? "starter" : "default",
1012
+ activationScan
807
1013
  );
808
1014
  runLocalSourceActivation(answers, activationManifest);
809
1015
  createActivationArtifacts(answers, activationManifest);
@@ -2201,8 +2407,8 @@ Agent task lifecycle:
2201
2407
  work.
2202
2408
  6. Use whichever structural code graph tools are exposed in the current session
2203
2409
  for callers, imports, neighbors, and path questions. Tool exposure can vary.
2204
- 7. On paid Context plans, use \`snipara_code_symbol_card\` for agent-ready symbol
2205
- 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
2206
2412
  reviews, routes, services, jobs, auth, billing, deployment, schema, migrations,
2207
2413
  or explicit "what is missing" assessments.
2208
2414
  8. Use \`snipara_plan\` for complex or multi-surface work in any plan when
@@ -2269,7 +2475,7 @@ ${EXPERIENCE_GOAL_SECTION}
2269
2475
  - Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for canonical structural code questions.
2270
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.
2271
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.
2272
- - 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.
2273
2479
  - Check every \`snipara_code_*\` response for indexed commit SHA, indexing time, included files, coverage, and freshness warnings.
2274
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.
2275
2481
  - If a broad query is slow, retry once with a narrow keyword query before falling back to local search.
@@ -2309,7 +2515,7 @@ ${EXPERIENCE_GOAL_SECTION}
2309
2515
  - Use \`snipara_code_callers\`, \`snipara_code_imports\`, \`snipara_code_neighbors\`, or \`snipara_code_shortest_path\` for canonical structural code questions.
2310
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.
2311
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.
2312
- - 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.
2313
2519
  - Check every \`snipara_code_*\` response for indexed commit SHA, indexing time, included files, coverage, and freshness warnings.
2314
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.
2315
2521
  - Use local file reads, \`rg\`, \`git status --short\`, and tests for exact code edits and current working-tree state.
@@ -3121,7 +3327,7 @@ function getCompanionCommands(answers) {
3121
3327
  {
3122
3328
  title: "Analyze code impact before a risky change",
3123
3329
  command: `${COMPANION_NPX_COMMAND} code impact --changed-files src/api/webhooks.ts tests/webhooks.test.ts --diff-summary "webhook retry hardening"`,
3124
- 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."
3125
3331
  },
3126
3332
  {
3127
3333
  title: answers.installOrchestrator ? "Run an explicit production orchestration gate" : "Enable explicit production orchestration",
@@ -3292,7 +3498,7 @@ ${guidance.map((line) => `- ${line}`).join("\n")}
3292
3498
  - Use \`answer_pack\` facts, caveats, source maps, and verification checks before making claims.
3293
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.
3294
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.
3295
- - 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.
3296
3502
  - Use the installed \`snipara-companion\` binary for low-latency hooks; use \`${COMPANION_NPX_COMMAND}\` for one-off terminal commands when freshness matters.
3297
3503
  - If a broad query is slow, retry once with a narrow keyword query before falling back to local search.
3298
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.
@@ -4117,6 +4323,28 @@ function printActivationSummary(manifest) {
4117
4323
  console.log(chalk.dim(` - ${line}`));
4118
4324
  }
4119
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
+ );
4120
4348
  console.log(
4121
4349
  chalk.dim(
4122
4350
  `
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-snipara",
3
- "version": "2.0.8",
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",