create-snipara 2.0.10 → 2.0.12

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 +3 -0
  2. package/dist/index.js +243 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -14,6 +14,9 @@ npx create-snipara
14
14
  creates or reuses auth, writes Hosted MCP config, and prepares the local project
15
15
  so an LLM client can use Snipara context and reviewed memory. The default path is
16
16
  hosted-only so the first success is a grounded answer, not a local tooling tour.
17
+ It is also the canonical activation engine behind editor setup docs: VS Code can
18
+ surface activation as a native command, Cursor can pair OpenVSX UI with Hosted
19
+ MCP, but both paths should land on the same project context.
17
20
 
18
21
  Use it when the goal is outcome-first agent work: the user asks for judgment,
19
22
  implementation, release, or verification, and the agent handles Snipara context,
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.10",
16
+ version: "2.0.12",
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",
@@ -107,6 +107,8 @@ var DEVICE_CLIENT_ID = "create-snipara";
107
107
  var DAY_ZERO_CORPUS_MAX_FILES = 8;
108
108
  var DAY_ZERO_CORPUS_MAX_FILE_CHARS = 12e3;
109
109
  var DAY_ZERO_CORPUS_MAX_TOTAL_CHARS = 5e4;
110
+ var ACTIVATION_MANIFEST_SCHEMA_VERSION = "snipara.activation.manifest.v1";
111
+ var ACTIVATION_CONSUMER_CONTRACT_VERSION = "snipara.editor.activation.v1";
110
112
  var EXPERIENCE_GOAL_SECTION = `## Experience Goal
111
113
 
112
114
  The target experience is outcome-first agent work across supported clients:
@@ -140,15 +142,23 @@ function getActivationDir() {
140
142
  function getActivationManifestPath() {
141
143
  return path.join(getActivationDir(), "manifest.json");
142
144
  }
145
+ function getStableActivationManifestPath() {
146
+ return path.join(getActivationDir(), "activation-manifest.json");
147
+ }
143
148
  function getActivationHandoffPath() {
144
149
  return path.join(getActivationDir(), "handoff.md");
145
150
  }
151
+ function getFirstWorkBriefPath() {
152
+ return path.join(getActivationDir(), "first-brief.md");
153
+ }
146
154
  function getMemoryCandidatesPath() {
147
155
  return path.join(getActivationDir(), "memory-candidates.json");
148
156
  }
149
157
  function writeActivationManifest(manifest) {
150
158
  fs.mkdirSync(getActivationDir(), { recursive: true });
151
- fs.writeFileSync(getActivationManifestPath(), JSON.stringify(manifest, null, 2) + "\n", "utf8");
159
+ const payload = JSON.stringify(manifest, null, 2) + "\n";
160
+ fs.writeFileSync(getActivationManifestPath(), payload, "utf8");
161
+ fs.writeFileSync(getStableActivationManifestPath(), payload, "utf8");
152
162
  }
153
163
  function updateActivationManifest(manifest) {
154
164
  manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -427,6 +437,9 @@ function writeInitialHandoff(answers, manifest) {
427
437
  `Repo path: ${manifest.repoPath}`,
428
438
  `Git branch: ${manifest.git.branch ?? "not detected"}`,
429
439
  `Git remote: ${manifest.git.remote ?? "not detected"}`,
440
+ `Activation doctrine: ${manifest.surfaceContract.doctrine}`,
441
+ `Activation engine: ${manifest.surfaceContract.engine}`,
442
+ `Entry point: ${manifest.surfaceContract.entryPoint}`,
430
443
  "",
431
444
  "## Activation lanes",
432
445
  ...Object.entries(manifest.lanes).map(
@@ -440,6 +453,7 @@ function writeInitialHandoff(answers, manifest) {
440
453
  ...recentCommits.length > 0 ? recentCommits.map((line) => `- ${line}`) : ["- not available"],
441
454
  "",
442
455
  "## Next",
456
+ `- ${manifest.surfaceContract.nextSurfaceAction}`,
443
457
  "- Ask the coding agent what it should know before editing the first target area.",
444
458
  "- Review memory candidates before accepting durable memory.",
445
459
  "- Connect GitHub later for PRs, reviews, team sync, and continuous sync.",
@@ -447,6 +461,24 @@ function writeInitialHandoff(answers, manifest) {
447
461
  ];
448
462
  fs.writeFileSync(getActivationHandoffPath(), lines.join("\n"), "utf8");
449
463
  }
464
+ function writeFirstWorkBrief(manifest) {
465
+ fs.mkdirSync(getActivationDir(), { recursive: true });
466
+ const lines = [
467
+ `# ${manifest.firstBrief.title}`,
468
+ "",
469
+ `Status: ${manifest.firstBrief.status}`,
470
+ `Activation: ${manifest.activationId}`,
471
+ `Client: ${getClientDisplayName(manifest.aiClient)}`,
472
+ "",
473
+ ...manifest.firstBrief.sections.flatMap((section) => [
474
+ `## ${section.title}`,
475
+ "",
476
+ ...section.lines.map((line) => `- ${line}`),
477
+ ""
478
+ ])
479
+ ];
480
+ fs.writeFileSync(getFirstWorkBriefPath(), lines.join("\n"), "utf8");
481
+ }
450
482
  function detectLocalActivationScan(detection) {
451
483
  const cwd = process.cwd();
452
484
  const exists = (relativePath) => fs.existsSync(path.join(cwd, relativePath));
@@ -549,6 +581,7 @@ function findDecisionArchaeologySources(cwd) {
549
581
  return [.../* @__PURE__ */ new Set([...directSources, ...archaeologySources])].slice(0, 80);
550
582
  }
551
583
  function createInitialFirstWorkBrief(answers, detection, scan) {
584
+ const surfaceContract = buildActivationSurfaceContract(answers.aiClient);
552
585
  const githubLine = answers.githubRepo ? `GitHub detected: ${answers.githubRepo.fullName}` : "No GitHub integration required for first value.";
553
586
  const commands = scan.scripts.length > 0 ? scan.scripts.join(", ") : "no package scripts detected";
554
587
  const docs = scan.files.candidateDocs.length > 0 ? scan.files.candidateDocs.join(", ") : "no standard docs detected";
@@ -566,6 +599,7 @@ function createInitialFirstWorkBrief(answers, detection, scan) {
566
599
  detection.inGitRepo ? "Local Git repository detected." : "Local folder detected.",
567
600
  githubLine,
568
601
  `AI client: ${getClientDisplayName(answers.aiClient)}.`,
602
+ `Activation entry point: ${surfaceContract.entryPoint}.`,
569
603
  `Languages: ${languages}.`
570
604
  ]
571
605
  },
@@ -594,7 +628,10 @@ function createInitialFirstWorkBrief(answers, detection, scan) {
594
628
  },
595
629
  {
596
630
  title: "Suggested next task",
597
- lines: ["Ask your agent what it should know before editing the first target area."]
631
+ lines: [
632
+ surfaceContract.nextSurfaceAction,
633
+ "Ask your agent what it should know before editing the first target area."
634
+ ]
598
635
  },
599
636
  {
600
637
  title: "Top impacted modules",
@@ -612,10 +649,14 @@ function createActivationManifest(answers, detection, mode = "default", scan) {
612
649
  const hasCompanion = answers.installCompanion;
613
650
  const localScan = scan ?? detectLocalActivationScan(detection);
614
651
  const dayZeroQuery = "What is this project, what is currently in flight, and what should an agent know before making the first edit?";
652
+ const surfaceContract = buildActivationSurfaceContract(answers.aiClient);
615
653
  return {
616
654
  version: "create-snipara-activation-v1",
655
+ schemaVersion: ACTIVATION_MANIFEST_SCHEMA_VERSION,
617
656
  activationId: buildActivationId(),
618
657
  mode,
658
+ surfaceContract,
659
+ consumerContract: buildEditorActivationConsumerContract(answers.aiClient),
619
660
  activationMetric: {
620
661
  name: "time_to_how_did_it_know_that",
621
662
  targetMinutes: 5,
@@ -683,9 +724,13 @@ function createActivationManifest(answers, detection, mode = "default", scan) {
683
724
  )
684
725
  },
685
726
  artifacts: {
727
+ activationManifestPath: path.relative(process.cwd(), getStableActivationManifestPath()),
728
+ legacyManifestPath: path.relative(process.cwd(), getActivationManifestPath()),
729
+ firstBriefPath: null,
686
730
  handoffPath: null,
687
731
  memoryCandidatesPath: null
688
732
  },
733
+ nextActions: buildActivationNextActions(surfaceContract, answers),
689
734
  firstBrief: createInitialFirstWorkBrief(answers, detection, localScan),
690
735
  createdAt: now,
691
736
  updatedAt: now
@@ -888,10 +933,12 @@ function createActivationArtifacts(answers, manifest) {
888
933
  "Initial local handoff created.",
889
934
  manifest.artifacts.handoffPath
890
935
  );
936
+ writeFirstWorkBrief(manifest);
937
+ manifest.artifacts.firstBriefPath = path.relative(process.cwd(), getFirstWorkBriefPath());
891
938
  manifest.lanes.firstBrief = createActivationLane(
892
939
  "ready",
893
940
  "First Work Brief generated from local setup and scan signals.",
894
- path.relative(process.cwd(), getActivationManifestPath())
941
+ manifest.artifacts.firstBriefPath
895
942
  );
896
943
  updateActivationManifest(manifest);
897
944
  }
@@ -984,7 +1031,7 @@ function buildProgram() {
984
1031
  ).option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
985
1032
  "--profile <profile>",
986
1033
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
987
- ).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) => {
1034
+ ).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("--json", "Print a machine-readable activation summary after setup").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) => {
988
1035
  printBanner();
989
1036
  await runInit(options);
990
1037
  });
@@ -1025,7 +1072,7 @@ function addSharedRootOptions(program) {
1025
1072
  ).option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
1026
1073
  "--profile <profile>",
1027
1074
  "Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
1028
- ).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");
1075
+ ).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("--json", "Print a machine-readable activation summary after setup").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");
1029
1076
  }
1030
1077
  async function main() {
1031
1078
  const program = buildProgram();
@@ -1125,6 +1172,7 @@ function parseInitOptionsFromArgv(args) {
1125
1172
  "--github": "github",
1126
1173
  "--skip-github": "skipGithub",
1127
1174
  "--starter": "starter",
1175
+ "--json": "json",
1128
1176
  "--yes": "yes",
1129
1177
  "-y": "yes"
1130
1178
  };
@@ -1189,6 +1237,11 @@ async function runInit(options) {
1189
1237
  runLocalSourceActivation(answers, activationManifest);
1190
1238
  createActivationArtifacts(answers, activationManifest);
1191
1239
  printSuccess(answers, validationReport, activationManifest);
1240
+ if (normalizedOptions.json) {
1241
+ console.log(
1242
+ JSON.stringify(buildActivationJsonSummary(activationManifest, validationReport), null, 2)
1243
+ );
1244
+ }
1192
1245
  if (answers.configureGitHub && answers.githubRepo) {
1193
1246
  await openGitHubAutomation(answers);
1194
1247
  }
@@ -1196,6 +1249,35 @@ async function runInit(options) {
1196
1249
  await runSandboxInit();
1197
1250
  }
1198
1251
  }
1252
+ function buildActivationJsonSummary(manifest, validation) {
1253
+ const laneEntries = Object.entries(manifest.lanes);
1254
+ const failedLanes = laneEntries.filter(([, lane]) => lane.status === "failed").map(([name]) => name);
1255
+ const pendingLanes = laneEntries.filter(([, lane]) => lane.status === "queued" || lane.status === "indexing").map(([name]) => name);
1256
+ const activationStatus = failedLanes.length > 0 ? "partial" : pendingLanes.length > 0 ? "partial" : "complete";
1257
+ return {
1258
+ ok: true,
1259
+ activationStatus,
1260
+ activationId: manifest.activationId,
1261
+ schemaVersion: manifest.schemaVersion,
1262
+ consumerContractVersion: manifest.consumerContract.version,
1263
+ projectSlug: manifest.projectSlug,
1264
+ aiClient: manifest.aiClient,
1265
+ profile: validation.profile,
1266
+ artifacts: manifest.artifacts,
1267
+ lanes: Object.fromEntries(
1268
+ laneEntries.map(([name, lane]) => [
1269
+ name,
1270
+ {
1271
+ status: lane.status,
1272
+ detail: lane.detail,
1273
+ command: lane.command
1274
+ }
1275
+ ])
1276
+ ),
1277
+ nextActions: manifest.nextActions,
1278
+ exitCode: activationStatus === "complete" ? 0 : manifest.consumerContract.exitCodes.activation_partial
1279
+ };
1280
+ }
1199
1281
  async function runDoctor(options) {
1200
1282
  const normalizedOptions = normalizeMaintenanceOptions(options);
1201
1283
  const requestedClient = normalizeClientOption(normalizedOptions.client);
@@ -1279,11 +1361,12 @@ async function runUpgrade(options) {
1279
1361
  printDoctorReport(detectEnvironment(), report);
1280
1362
  }
1281
1363
  async function runPrintConfig(options) {
1364
+ const normalizedOptions = normalizeMaintenanceOptions(options);
1282
1365
  const detection = detectEnvironment();
1283
- const answers = loadExistingAnswers(options);
1366
+ const answers = loadExistingAnswers(normalizedOptions);
1284
1367
  const githubRepo = detectGitRepository();
1285
1368
  const githubAnswerPacks = githubRepo ? `${githubRepo.fullName} can be connected with npx create-snipara --github` : "requires a GitHub-backed git remote";
1286
- if (options.json) {
1369
+ if (normalizedOptions.json) {
1287
1370
  console.log(
1288
1371
  JSON.stringify(
1289
1372
  {
@@ -3330,6 +3413,124 @@ function readCompanionConfigFile(filePath) {
3330
3413
  return {};
3331
3414
  }
3332
3415
  }
3416
+ function buildActivationSurfaceContract(client) {
3417
+ const shared = {
3418
+ doctrine: "one_activation_engine_multiple_entry_points",
3419
+ engine: "create-snipara",
3420
+ firstSuccessState: "Hosted MCP connected, local workspace context seeded, and a First Work Brief ready for the next agent session.",
3421
+ mustNotDuplicate: [
3422
+ "Local source scan heuristics",
3423
+ "First Work Brief generation",
3424
+ "memory-candidate extraction",
3425
+ "Hosted MCP config contract"
3426
+ ]
3427
+ };
3428
+ if (client === "cursor") {
3429
+ return {
3430
+ ...shared,
3431
+ entryPoint: "Cursor extension or Cursor agent instructions call create-snipara",
3432
+ clientRole: "Lightweight editor surface: expose rules, skills, and the canonical bootstrap path; do not fork activation logic.",
3433
+ nextSurfaceAction: "In Cursor, ask the agent to run or verify `npx create-snipara@latest init --client cursor --starter`, then use the generated rules and Hosted MCP tools."
3434
+ };
3435
+ }
3436
+ if (client === "vscode") {
3437
+ return {
3438
+ ...shared,
3439
+ entryPoint: "VS Code extension command or create-snipara bootstrap",
3440
+ clientRole: "Native editor UX surface: provide SecretStorage, progress, panels, status, and Copilot handoff while keeping activation semantics aligned with create-snipara.",
3441
+ nextSurfaceAction: "In VS Code, run `Snipara: Activate Workspace` when the extension is installed, or keep using this generated pack when bootstrapping from the terminal."
3442
+ };
3443
+ }
3444
+ if (client === "claude-code") {
3445
+ return {
3446
+ ...shared,
3447
+ entryPoint: "Claude Code plugin or create-snipara bootstrap",
3448
+ clientRole: "Agent-first surface: load Hosted MCP and project instructions, then use Companion only for explicit local continuity workflows.",
3449
+ nextSurfaceAction: "Start a new Claude Code session and validate Snipara tools before enabling hooks or managed workflows."
3450
+ };
3451
+ }
3452
+ return {
3453
+ ...shared,
3454
+ entryPoint: `${getClientDisplayName(client)} setup generated by create-snipara`,
3455
+ clientRole: "MCP-compatible surface: consume the generated Hosted MCP reference and AGENTS.md rather than owning a separate activation model.",
3456
+ nextSurfaceAction: "Restart or reload the client, verify Snipara tools, then ask the first grounded project question from the generated First Work Brief."
3457
+ };
3458
+ }
3459
+ function buildEditorActivationConsumerContract(client) {
3460
+ const secretRule = client === "vscode" ? "Use VS Code SecretStorage for SNIPARA_API_KEY and pass it to create-snipara through the child-process environment; never write raw secrets into extension settings or logs." : "Pass SNIPARA_API_KEY through the process environment or client secret store; never parse, log, or persist raw secrets from terminal output.";
3461
+ return {
3462
+ version: ACTIVATION_CONSUMER_CONTRACT_VERSION,
3463
+ audience: "editor_extension",
3464
+ stableFiles: {
3465
+ activationManifest: ".snipara/activation/activation-manifest.json",
3466
+ firstBrief: ".snipara/activation/first-brief.md",
3467
+ handoff: ".snipara/activation/handoff.md",
3468
+ memoryCandidates: ".snipara/activation/memory-candidates.json"
3469
+ },
3470
+ requiredManifestFields: [
3471
+ "schemaVersion",
3472
+ "consumerContract.version",
3473
+ "surfaceContract",
3474
+ "artifacts.activationManifestPath",
3475
+ "artifacts.firstBriefPath",
3476
+ "artifacts.handoffPath",
3477
+ "lanes.connection.status",
3478
+ "lanes.firstBrief.status",
3479
+ "nextActions"
3480
+ ],
3481
+ laneStatuses: ["ready", "indexing", "queued", "needs_review", "skipped", "failed"],
3482
+ exitCodes: {
3483
+ success: 0,
3484
+ activation_partial: 10,
3485
+ auth_required: 20,
3486
+ missing_api_key: 21,
3487
+ missing_node_or_npm: 30,
3488
+ activation_failed: 40
3489
+ },
3490
+ parseRule: "Read .snipara/activation/activation-manifest.json as the source of truth. If --json is used, parse the last JSON object from stdout as a summary pointer, not as the full durable state.",
3491
+ secretRule
3492
+ };
3493
+ }
3494
+ function buildActivationNextActions(surfaceContract, answers) {
3495
+ const actions = [
3496
+ {
3497
+ id: "open_first_work_brief",
3498
+ label: "Open First Work Brief",
3499
+ target: "editor",
3500
+ when: "artifacts.firstBriefPath is present and lanes.firstBrief.status is ready"
3501
+ },
3502
+ {
3503
+ id: "handoff_to_agent",
3504
+ label: "Hand off to the coding agent",
3505
+ target: "agent",
3506
+ when: "lanes.connection.status is ready and First Work Brief has been shown"
3507
+ },
3508
+ {
3509
+ id: "review_memory_candidates",
3510
+ label: "Review memory candidates",
3511
+ target: "editor",
3512
+ when: "lanes.memoryCandidates.status is needs_review"
3513
+ }
3514
+ ];
3515
+ if (answers.aiClient === "vscode") {
3516
+ actions.unshift({
3517
+ id: "vscode_activate_workspace",
3518
+ label: "Snipara: Activate Workspace",
3519
+ command: "Snipara: Activate Workspace",
3520
+ target: "editor",
3521
+ when: "VS Code extension command is available"
3522
+ });
3523
+ } else {
3524
+ actions.unshift({
3525
+ id: "verify_surface_activation",
3526
+ label: "Verify activation surface",
3527
+ command: surfaceContract.nextSurfaceAction,
3528
+ target: "agent",
3529
+ when: "editor-specific command is unavailable"
3530
+ });
3531
+ }
3532
+ return actions;
3533
+ }
3333
3534
  function getClientGuidance(client) {
3334
3535
  if (client === "claude-code") {
3335
3536
  return [
@@ -3339,6 +3540,7 @@ function getClientGuidance(client) {
3339
3540
  }
3340
3541
  if (client === "cursor") {
3341
3542
  return [
3543
+ "Cursor is a lightweight editor entry point: use create-snipara as the canonical activation engine, then let Cursor consume the generated rules and Hosted MCP context.",
3342
3544
  "Cursor reads the generated .mcp.json directly, so the hosted Snipara MCP surface is available after restart.",
3343
3545
  "Use the companion CLI only for explicit upload, planning, chunk lookup, doctor, and task commit workflows outside the editor UI."
3344
3546
  ];
@@ -3374,6 +3576,7 @@ function getClientGuidance(client) {
3374
3576
  }
3375
3577
  if (client === "vscode") {
3376
3578
  return [
3579
+ "VS Code can provide native activation UX, but create-snipara remains the canonical activation contract for generated files and local briefing semantics.",
3377
3580
  "VS Code and Copilot-style clients should use Hosted MCP plus AGENTS.md for project workflow rules.",
3378
3581
  "Use .snipara/templates/vscode-mcp-reference.json as the Snipara server reference when adding an MCP server."
3379
3582
  ];
@@ -3639,11 +3842,24 @@ function buildClientPackMarkdown(answers, commands, guidance) {
3639
3842
  const bootstrapCommand = commands.find(
3640
3843
  (command) => command.title === "Bootstrap local companion"
3641
3844
  );
3845
+ const surfaceContract = buildActivationSurfaceContract(answers.aiClient);
3642
3846
  return `# Snipara Pack: ${clientName}
3643
3847
 
3644
3848
  This pack is the client-specific overlay for the generated Snipara project setup.
3645
3849
  Use \`AGENTS.md\` as the shared source of agent behavior, then apply the client-specific files below.
3646
3850
 
3851
+ ## Activation Contract
3852
+
3853
+ - Doctrine: one activation engine, multiple entry points
3854
+ - Canonical engine: \`${surfaceContract.engine}\`
3855
+ - Entry point: ${surfaceContract.entryPoint}
3856
+ - Client role: ${surfaceContract.clientRole}
3857
+ - First success state: ${surfaceContract.firstSuccessState}
3858
+ - Next surface action: ${surfaceContract.nextSurfaceAction}
3859
+
3860
+ The client-specific files in this pack should not reimplement local source scanning,
3861
+ First Work Brief generation, memory-candidate extraction, or Hosted MCP config semantics.
3862
+
3647
3863
  ## Hosted MCP
3648
3864
 
3649
3865
  - Endpoint: \`${buildHostedMcpEndpoint(answers)}\`
@@ -3692,6 +3908,8 @@ async function createCompanionPack(answers) {
3692
3908
  const readme = `# Snipara Companion Pack
3693
3909
 
3694
3910
  This project uses Snipara as a hosted-first project intelligence layer with source-backed context, reviewed memory, and local companion workflow helpers.
3911
+ The activation doctrine is: one shared activation engine, multiple entry points.
3912
+ \`create-snipara\` is the canonical bootstrap; editor extensions and plugins should provide UI, rules, or handoff affordances without forking the activation engine.
3695
3913
 
3696
3914
  ## Install Profile
3697
3915
 
@@ -3721,6 +3939,18 @@ This project uses Snipara as a hosted-first project intelligence layer with sour
3721
3939
 
3722
3940
  ${guidance.map((line) => `- ${line}`).join("\n")}
3723
3941
 
3942
+ ## Activation Continuity Loop
3943
+
3944
+ After the First Work Brief, use Companion when local continuity matters:
3945
+
3946
+ 1. Start or resume with \`${COMPANION_NPX_COMMAND} session-bootstrap --include-session-context --max-context-tokens 1000\`.
3947
+ 2. Refresh local source context with \`${COMPANION_NPX_COMMAND} source sync --json\` after meaningful doc or code movement.
3948
+ 3. Before risky edits, use \`${COMPANION_NPX_COMMAND} code impact --changed-files <files> --diff-summary "<change>"\`.
3949
+ 4. End durable work with \`${COMPANION_NPX_COMMAND} task-commit --summary "<what changed>" --files <files>\`.
3950
+
3951
+ Keep quick editor usage in the editor. Use Companion for explicit continuity, source refresh,
3952
+ workflow phase state, guards, impact checks, business-folder onboarding, and durable task memory.
3953
+
3724
3954
  ## Business Folder Onboarding
3725
3955
 
3726
3956
  Use this when Claude, ChatGPT, Codex, or another LLM client has already materialized Drive, Notion, Gmail, or local business files into a folder.
@@ -4511,6 +4741,11 @@ function printActivationSummary(manifest) {
4511
4741
  ` Day-zero corpus: ${manifest.dayZeroCorpus.status} - ${manifest.dayZeroCorpus.detail}`
4512
4742
  )
4513
4743
  );
4744
+ console.log(chalk.bold("\nActivation surface:\n"));
4745
+ console.log(` Engine: ${manifest.surfaceContract.engine}`);
4746
+ console.log(` Entry point: ${manifest.surfaceContract.entryPoint}`);
4747
+ console.log(chalk.dim(` Role: ${manifest.surfaceContract.clientRole}`));
4748
+ console.log(chalk.dim(` Next: ${manifest.surfaceContract.nextSurfaceAction}`));
4514
4749
  console.log(chalk.bold("\nAgent readiness:\n"));
4515
4750
  console.log(` ${manifest.agentReadiness.summary}`);
4516
4751
  for (const finding of manifest.agentReadiness.stalenessFindings.slice(0, 3)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-snipara",
3
- "version": "2.0.10",
3
+ "version": "2.0.12",
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",