create-snipara 2.0.11 → 2.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -4
- package/dist/index.js +227 -27
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ behind the scenes.
|
|
|
25
25
|
|
|
26
26
|
Use it for:
|
|
27
27
|
|
|
28
|
-
- Hosted MCP onboarding for Claude Code, Cursor,
|
|
28
|
+
- Hosted MCP onboarding for Claude Code, Cursor, Kimi Code CLI, Codex, Gemini, Mistral, VS Code/Copilot, Continue, ChatGPT Desktop, Orca-style MCP clients, LM Studio-backed local stacks, and similar clients
|
|
29
29
|
- free account signup with reviewed Context + Memory
|
|
30
30
|
- local project wiring, `doctor`, `repair`, and `upgrade`
|
|
31
31
|
- local source activation without GitHub, plus optional GitHub repository sync and PR Answer Packs approval when the current folder is a GitHub repo
|
|
@@ -86,7 +86,7 @@ Free onboarding is now **Context + Memory**, not Context-only:
|
|
|
86
86
|
|
|
87
87
|
- Context Free: three projects and 1,000 context queries/month
|
|
88
88
|
- Memory Free: reviewed hosted memories for continuity across sessions
|
|
89
|
-
- Hosted MCP: direct connection for Claude Code, Cursor,
|
|
89
|
+
- Hosted MCP: direct connection for Claude Code, Cursor, Kimi Code CLI, Codex, Gemini, Mistral, VS Code/Copilot, Continue, ChatGPT Desktop, Orca-style MCP clients, LM Studio-backed local stacks, and other MCP clients
|
|
90
90
|
|
|
91
91
|
The CLI opens a browser device-flow login when the user does not already have a key, auto-provisions the free Context + Memory account when needed, then writes the returned API key into the local MCP config.
|
|
92
92
|
|
|
@@ -413,10 +413,26 @@ companion add workflow ergonomics:
|
|
|
413
413
|
- choose `hosted-only` or `--skip-companion` only in locked-down environments
|
|
414
414
|
- use local `snipara-mcp` only for stdio compatibility, development, or tests
|
|
415
415
|
|
|
416
|
-
Claude Code, Cursor, and
|
|
417
|
-
that client has a useful local hook surface.
|
|
416
|
+
Claude Code, Cursor, and Kimi Code CLI can receive generated automation files when
|
|
417
|
+
that client has a useful local hook surface. Kimi receives a project-local MCP
|
|
418
|
+
config and a reviewable plugin that must be installed explicitly; its hooks are
|
|
419
|
+
fail-open. Codex, Gemini, VS Code, Continue,
|
|
418
420
|
Mistral, ChatGPT, and custom clients are treated as MCP-first: they get the hosted MCP
|
|
419
421
|
configuration/reference and agent instructions, not invented local hooks.
|
|
422
|
+
|
|
423
|
+
For Kimi Code CLI:
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
npx -y create-snipara@latest init --client kimi --profile hosted-companion --with-hooks
|
|
427
|
+
npx -y snipara-companion@latest automations install --client kimi
|
|
428
|
+
# Then, in Kimi Code after reviewing the plugin:
|
|
429
|
+
/plugins install .kimi-code/snipara-plugin
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Export `SNIPARA_API_KEY` before starting Kimi. The generated
|
|
433
|
+
`.kimi-code/mcp.json` stores only `bearerTokenEnvVar`, never the raw key. Kimi
|
|
434
|
+
installs plugins per user, so the generated handler is project-neutral and
|
|
435
|
+
no-ops outside workspaces carrying a Snipara project or Companion marker.
|
|
420
436
|
For Mistral, request hooks from LangChain are documented as `ChatMistralAI`
|
|
421
437
|
request lifecycle hooks (`beforeRequestHooks`, `requestErrorHooks`, and
|
|
422
438
|
`responseHooks`), not as local agent lifecycle hooks.
|
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.
|
|
16
|
+
version: "2.0.13",
|
|
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",
|
|
@@ -45,7 +45,7 @@ var package_default = {
|
|
|
45
45
|
"chatgpt",
|
|
46
46
|
"openai",
|
|
47
47
|
"cursor",
|
|
48
|
-
"
|
|
48
|
+
"kimi",
|
|
49
49
|
"gemini",
|
|
50
50
|
"mistral",
|
|
51
51
|
"orca",
|
|
@@ -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
|
-
|
|
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();
|
|
@@ -451,6 +461,24 @@ function writeInitialHandoff(answers, manifest) {
|
|
|
451
461
|
];
|
|
452
462
|
fs.writeFileSync(getActivationHandoffPath(), lines.join("\n"), "utf8");
|
|
453
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
|
+
}
|
|
454
482
|
function detectLocalActivationScan(detection) {
|
|
455
483
|
const cwd = process.cwd();
|
|
456
484
|
const exists = (relativePath) => fs.existsSync(path.join(cwd, relativePath));
|
|
@@ -624,9 +652,11 @@ function createActivationManifest(answers, detection, mode = "default", scan) {
|
|
|
624
652
|
const surfaceContract = buildActivationSurfaceContract(answers.aiClient);
|
|
625
653
|
return {
|
|
626
654
|
version: "create-snipara-activation-v1",
|
|
655
|
+
schemaVersion: ACTIVATION_MANIFEST_SCHEMA_VERSION,
|
|
627
656
|
activationId: buildActivationId(),
|
|
628
657
|
mode,
|
|
629
658
|
surfaceContract,
|
|
659
|
+
consumerContract: buildEditorActivationConsumerContract(answers.aiClient),
|
|
630
660
|
activationMetric: {
|
|
631
661
|
name: "time_to_how_did_it_know_that",
|
|
632
662
|
targetMinutes: 5,
|
|
@@ -694,9 +724,13 @@ function createActivationManifest(answers, detection, mode = "default", scan) {
|
|
|
694
724
|
)
|
|
695
725
|
},
|
|
696
726
|
artifacts: {
|
|
727
|
+
activationManifestPath: path.relative(process.cwd(), getStableActivationManifestPath()),
|
|
728
|
+
legacyManifestPath: path.relative(process.cwd(), getActivationManifestPath()),
|
|
729
|
+
firstBriefPath: null,
|
|
697
730
|
handoffPath: null,
|
|
698
731
|
memoryCandidatesPath: null
|
|
699
732
|
},
|
|
733
|
+
nextActions: buildActivationNextActions(surfaceContract, answers),
|
|
700
734
|
firstBrief: createInitialFirstWorkBrief(answers, detection, localScan),
|
|
701
735
|
createdAt: now,
|
|
702
736
|
updatedAt: now
|
|
@@ -899,10 +933,12 @@ function createActivationArtifacts(answers, manifest) {
|
|
|
899
933
|
"Initial local handoff created.",
|
|
900
934
|
manifest.artifacts.handoffPath
|
|
901
935
|
);
|
|
936
|
+
writeFirstWorkBrief(manifest);
|
|
937
|
+
manifest.artifacts.firstBriefPath = path.relative(process.cwd(), getFirstWorkBriefPath());
|
|
902
938
|
manifest.lanes.firstBrief = createActivationLane(
|
|
903
939
|
"ready",
|
|
904
940
|
"First Work Brief generated from local setup and scan signals.",
|
|
905
|
-
|
|
941
|
+
manifest.artifacts.firstBriefPath
|
|
906
942
|
);
|
|
907
943
|
updateActivationManifest(manifest);
|
|
908
944
|
}
|
|
@@ -920,9 +956,9 @@ var AI_CLIENT_CHOICES = [
|
|
|
920
956
|
description: "Hosted MCP plus Cursor rules and automation bundles"
|
|
921
957
|
},
|
|
922
958
|
{
|
|
923
|
-
title: "
|
|
924
|
-
value: "
|
|
925
|
-
description: "
|
|
959
|
+
title: "Kimi Code CLI",
|
|
960
|
+
value: "kimi",
|
|
961
|
+
description: "Project MCP plus a reviewable Snipara Companion plugin"
|
|
926
962
|
},
|
|
927
963
|
{
|
|
928
964
|
title: "OpenAI Codex",
|
|
@@ -965,7 +1001,7 @@ function getCompanionInitClientFlag(aiClient) {
|
|
|
965
1001
|
const supportedClientMap = {
|
|
966
1002
|
"claude-code": "claude-code",
|
|
967
1003
|
cursor: "cursor",
|
|
968
|
-
|
|
1004
|
+
kimi: "kimi",
|
|
969
1005
|
codex: "codex",
|
|
970
1006
|
gemini: "gemini",
|
|
971
1007
|
mistral: "mistral",
|
|
@@ -991,11 +1027,11 @@ function buildProgram() {
|
|
|
991
1027
|
program.name("create-snipara").description("Scaffold hosted Snipara MCP config; advanced flags add local helpers").version(VERSION);
|
|
992
1028
|
program.command("init").description("Install and configure Snipara for this project").option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option(
|
|
993
1029
|
"--client <client>",
|
|
994
|
-
"AI client: claude-code, cursor,
|
|
1030
|
+
"AI client: claude-code, cursor, kimi, codex, gemini, mistral, chatgpt, vscode, continue, claude-desktop, other"
|
|
995
1031
|
).option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
|
|
996
1032
|
"--profile <profile>",
|
|
997
1033
|
"Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
|
|
998
|
-
).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) => {
|
|
999
1035
|
printBanner();
|
|
1000
1036
|
await runInit(options);
|
|
1001
1037
|
});
|
|
@@ -1032,11 +1068,11 @@ function buildProgram() {
|
|
|
1032
1068
|
function addSharedRootOptions(program) {
|
|
1033
1069
|
program.option("--api-key <key>", "Snipara API key").option("--slug <slug>", "Project slug").option("--project-id <id>", "Project ID").option(
|
|
1034
1070
|
"--client <client>",
|
|
1035
|
-
"AI client: claude-code, cursor,
|
|
1071
|
+
"AI client: claude-code, cursor, kimi, codex, gemini, mistral, chatgpt, vscode, continue, claude-desktop, other"
|
|
1036
1072
|
).option("--advanced", "Show advanced profile, project id, hooks, GitHub, and sandbox prompts").option(
|
|
1037
1073
|
"--profile <profile>",
|
|
1038
1074
|
"Install profile: hosted-only, hosted-companion, full-stack, runtime-only"
|
|
1039
|
-
).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");
|
|
1040
1076
|
}
|
|
1041
1077
|
async function main() {
|
|
1042
1078
|
const program = buildProgram();
|
|
@@ -1136,6 +1172,7 @@ function parseInitOptionsFromArgv(args) {
|
|
|
1136
1172
|
"--github": "github",
|
|
1137
1173
|
"--skip-github": "skipGithub",
|
|
1138
1174
|
"--starter": "starter",
|
|
1175
|
+
"--json": "json",
|
|
1139
1176
|
"--yes": "yes",
|
|
1140
1177
|
"-y": "yes"
|
|
1141
1178
|
};
|
|
@@ -1200,6 +1237,11 @@ async function runInit(options) {
|
|
|
1200
1237
|
runLocalSourceActivation(answers, activationManifest);
|
|
1201
1238
|
createActivationArtifacts(answers, activationManifest);
|
|
1202
1239
|
printSuccess(answers, validationReport, activationManifest);
|
|
1240
|
+
if (normalizedOptions.json) {
|
|
1241
|
+
console.log(
|
|
1242
|
+
JSON.stringify(buildActivationJsonSummary(activationManifest, validationReport), null, 2)
|
|
1243
|
+
);
|
|
1244
|
+
}
|
|
1203
1245
|
if (answers.configureGitHub && answers.githubRepo) {
|
|
1204
1246
|
await openGitHubAutomation(answers);
|
|
1205
1247
|
}
|
|
@@ -1207,6 +1249,35 @@ async function runInit(options) {
|
|
|
1207
1249
|
await runSandboxInit();
|
|
1208
1250
|
}
|
|
1209
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
|
+
}
|
|
1210
1281
|
async function runDoctor(options) {
|
|
1211
1282
|
const normalizedOptions = normalizeMaintenanceOptions(options);
|
|
1212
1283
|
const requestedClient = normalizeClientOption(normalizedOptions.client);
|
|
@@ -1290,11 +1361,12 @@ async function runUpgrade(options) {
|
|
|
1290
1361
|
printDoctorReport(detectEnvironment(), report);
|
|
1291
1362
|
}
|
|
1292
1363
|
async function runPrintConfig(options) {
|
|
1364
|
+
const normalizedOptions = normalizeMaintenanceOptions(options);
|
|
1293
1365
|
const detection = detectEnvironment();
|
|
1294
|
-
const answers = loadExistingAnswers(
|
|
1366
|
+
const answers = loadExistingAnswers(normalizedOptions);
|
|
1295
1367
|
const githubRepo = detectGitRepository();
|
|
1296
1368
|
const githubAnswerPacks = githubRepo ? `${githubRepo.fullName} can be connected with npx create-snipara --github` : "requires a GitHub-backed git remote";
|
|
1297
|
-
if (
|
|
1369
|
+
if (normalizedOptions.json) {
|
|
1298
1370
|
console.log(
|
|
1299
1371
|
JSON.stringify(
|
|
1300
1372
|
{
|
|
@@ -1610,7 +1682,7 @@ function normalizeClientOption(value) {
|
|
|
1610
1682
|
"claude-desktop": "claude-desktop",
|
|
1611
1683
|
claude_desktop: "claude-desktop",
|
|
1612
1684
|
cursor: "cursor",
|
|
1613
|
-
|
|
1685
|
+
kimi: "kimi",
|
|
1614
1686
|
codex: "codex",
|
|
1615
1687
|
gemini: "gemini",
|
|
1616
1688
|
mistral: "mistral",
|
|
@@ -1628,7 +1700,7 @@ function normalizeClientOption(value) {
|
|
|
1628
1700
|
const client = aliases[normalized];
|
|
1629
1701
|
if (!client) {
|
|
1630
1702
|
throw new Error(
|
|
1631
|
-
`Unknown client '${value}'. Use claude, claude-code, cursor, codex, mistral, or other.`
|
|
1703
|
+
`Unknown client '${value}'. Use claude, claude-code, cursor, kimi, codex, mistral, or other.`
|
|
1632
1704
|
);
|
|
1633
1705
|
}
|
|
1634
1706
|
return client;
|
|
@@ -2090,10 +2162,34 @@ async function createMcpConfig(answers) {
|
|
|
2090
2162
|
}
|
|
2091
2163
|
console.log(chalk.green(" \u2713 Created .mcp.json"));
|
|
2092
2164
|
ensureGitignoreEntry(".mcp.json", "# Snipara MCP config (contains API key)");
|
|
2165
|
+
if (answers.aiClient === "kimi" && answers.profile !== "runtime-only") {
|
|
2166
|
+
createKimiMcpConfig(answers);
|
|
2167
|
+
}
|
|
2093
2168
|
if (answers.aiClient === "claude-desktop") {
|
|
2094
2169
|
await createClaudeDesktopConfig(answers);
|
|
2095
2170
|
}
|
|
2096
2171
|
}
|
|
2172
|
+
function createKimiMcpConfig(answers) {
|
|
2173
|
+
const kimiDir = path.join(process.cwd(), ".kimi-code");
|
|
2174
|
+
const configPath = path.join(kimiDir, "mcp.json");
|
|
2175
|
+
const existing = asObjectRecord(readJsonFile(configPath));
|
|
2176
|
+
const existingServers = asObjectRecord(existing.mcpServers);
|
|
2177
|
+
const config = {
|
|
2178
|
+
...existing,
|
|
2179
|
+
mcpServers: {
|
|
2180
|
+
...existingServers,
|
|
2181
|
+
snipara: {
|
|
2182
|
+
url: buildHostedMcpEndpoint(answers),
|
|
2183
|
+
bearerTokenEnvVar: "SNIPARA_API_KEY"
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
};
|
|
2187
|
+
fs.mkdirSync(kimiDir, { recursive: true });
|
|
2188
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
2189
|
+
console.log(
|
|
2190
|
+
chalk.green(" \u2713 Created .kimi-code/mcp.json") + chalk.dim(" - SNIPARA_API_KEY stays in the launch environment")
|
|
2191
|
+
);
|
|
2192
|
+
}
|
|
2097
2193
|
function buildHostedMcpServer(answers) {
|
|
2098
2194
|
return {
|
|
2099
2195
|
type: "http",
|
|
@@ -3377,6 +3473,14 @@ function buildActivationSurfaceContract(client) {
|
|
|
3377
3473
|
nextSurfaceAction: "Start a new Claude Code session and validate Snipara tools before enabling hooks or managed workflows."
|
|
3378
3474
|
};
|
|
3379
3475
|
}
|
|
3476
|
+
if (client === "kimi") {
|
|
3477
|
+
return {
|
|
3478
|
+
...shared,
|
|
3479
|
+
entryPoint: "Kimi Code project MCP plus an explicitly installed Snipara plugin",
|
|
3480
|
+
clientRole: "Agent-first CLI surface: load .kimi-code/mcp.json for Hosted MCP and install the generated Companion plugin only after review.",
|
|
3481
|
+
nextSurfaceAction: "Start Kimi Code with SNIPARA_API_KEY exported, verify /mcp, then install .kimi-code/snipara-plugin when lifecycle automation is desired."
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3380
3484
|
return {
|
|
3381
3485
|
...shared,
|
|
3382
3486
|
entryPoint: `${getClientDisplayName(client)} setup generated by create-snipara`,
|
|
@@ -3384,6 +3488,81 @@ function buildActivationSurfaceContract(client) {
|
|
|
3384
3488
|
nextSurfaceAction: "Restart or reload the client, verify Snipara tools, then ask the first grounded project question from the generated First Work Brief."
|
|
3385
3489
|
};
|
|
3386
3490
|
}
|
|
3491
|
+
function buildEditorActivationConsumerContract(client) {
|
|
3492
|
+
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.";
|
|
3493
|
+
return {
|
|
3494
|
+
version: ACTIVATION_CONSUMER_CONTRACT_VERSION,
|
|
3495
|
+
audience: "editor_extension",
|
|
3496
|
+
stableFiles: {
|
|
3497
|
+
activationManifest: ".snipara/activation/activation-manifest.json",
|
|
3498
|
+
firstBrief: ".snipara/activation/first-brief.md",
|
|
3499
|
+
handoff: ".snipara/activation/handoff.md",
|
|
3500
|
+
memoryCandidates: ".snipara/activation/memory-candidates.json"
|
|
3501
|
+
},
|
|
3502
|
+
requiredManifestFields: [
|
|
3503
|
+
"schemaVersion",
|
|
3504
|
+
"consumerContract.version",
|
|
3505
|
+
"surfaceContract",
|
|
3506
|
+
"artifacts.activationManifestPath",
|
|
3507
|
+
"artifacts.firstBriefPath",
|
|
3508
|
+
"artifacts.handoffPath",
|
|
3509
|
+
"lanes.connection.status",
|
|
3510
|
+
"lanes.firstBrief.status",
|
|
3511
|
+
"nextActions"
|
|
3512
|
+
],
|
|
3513
|
+
laneStatuses: ["ready", "indexing", "queued", "needs_review", "skipped", "failed"],
|
|
3514
|
+
exitCodes: {
|
|
3515
|
+
success: 0,
|
|
3516
|
+
activation_partial: 10,
|
|
3517
|
+
auth_required: 20,
|
|
3518
|
+
missing_api_key: 21,
|
|
3519
|
+
missing_node_or_npm: 30,
|
|
3520
|
+
activation_failed: 40
|
|
3521
|
+
},
|
|
3522
|
+
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.",
|
|
3523
|
+
secretRule
|
|
3524
|
+
};
|
|
3525
|
+
}
|
|
3526
|
+
function buildActivationNextActions(surfaceContract, answers) {
|
|
3527
|
+
const actions = [
|
|
3528
|
+
{
|
|
3529
|
+
id: "open_first_work_brief",
|
|
3530
|
+
label: "Open First Work Brief",
|
|
3531
|
+
target: "editor",
|
|
3532
|
+
when: "artifacts.firstBriefPath is present and lanes.firstBrief.status is ready"
|
|
3533
|
+
},
|
|
3534
|
+
{
|
|
3535
|
+
id: "handoff_to_agent",
|
|
3536
|
+
label: "Hand off to the coding agent",
|
|
3537
|
+
target: "agent",
|
|
3538
|
+
when: "lanes.connection.status is ready and First Work Brief has been shown"
|
|
3539
|
+
},
|
|
3540
|
+
{
|
|
3541
|
+
id: "review_memory_candidates",
|
|
3542
|
+
label: "Review memory candidates",
|
|
3543
|
+
target: "editor",
|
|
3544
|
+
when: "lanes.memoryCandidates.status is needs_review"
|
|
3545
|
+
}
|
|
3546
|
+
];
|
|
3547
|
+
if (answers.aiClient === "vscode") {
|
|
3548
|
+
actions.unshift({
|
|
3549
|
+
id: "vscode_activate_workspace",
|
|
3550
|
+
label: "Snipara: Activate Workspace",
|
|
3551
|
+
command: "Snipara: Activate Workspace",
|
|
3552
|
+
target: "editor",
|
|
3553
|
+
when: "VS Code extension command is available"
|
|
3554
|
+
});
|
|
3555
|
+
} else {
|
|
3556
|
+
actions.unshift({
|
|
3557
|
+
id: "verify_surface_activation",
|
|
3558
|
+
label: "Verify activation surface",
|
|
3559
|
+
command: surfaceContract.nextSurfaceAction,
|
|
3560
|
+
target: "agent",
|
|
3561
|
+
when: "editor-specific command is unavailable"
|
|
3562
|
+
});
|
|
3563
|
+
}
|
|
3564
|
+
return actions;
|
|
3565
|
+
}
|
|
3387
3566
|
function getClientGuidance(client) {
|
|
3388
3567
|
if (client === "claude-code") {
|
|
3389
3568
|
return [
|
|
@@ -3398,10 +3577,11 @@ function getClientGuidance(client) {
|
|
|
3398
3577
|
"Use the companion CLI only for explicit upload, planning, chunk lookup, doctor, and task commit workflows outside the editor UI."
|
|
3399
3578
|
];
|
|
3400
3579
|
}
|
|
3401
|
-
if (client === "
|
|
3580
|
+
if (client === "kimi") {
|
|
3402
3581
|
return [
|
|
3403
|
-
"
|
|
3404
|
-
"Use npx -y snipara-companion@latest automations install --client
|
|
3582
|
+
"Kimi Code CLI reads the project-local .kimi-code/mcp.json and resolves SNIPARA_API_KEY from the launch environment.",
|
|
3583
|
+
"Use npx -y snipara-companion@latest automations install --client kimi to download the reviewable plugin bundle, then install it explicitly inside Kimi with /plugins install .kimi-code/snipara-plugin.",
|
|
3584
|
+
"Kimi hooks are fail-open. Keep risky tool approvals enabled and use Hosted MCP tenant checks plus Companion guards as the authoritative boundary."
|
|
3405
3585
|
];
|
|
3406
3586
|
}
|
|
3407
3587
|
if (client === "codex") {
|
|
@@ -3618,7 +3798,7 @@ function getClientDisplayName(client) {
|
|
|
3618
3798
|
const names = {
|
|
3619
3799
|
"claude-code": "Claude Code",
|
|
3620
3800
|
cursor: "Cursor",
|
|
3621
|
-
|
|
3801
|
+
kimi: "Kimi Code CLI",
|
|
3622
3802
|
codex: "OpenAI Codex",
|
|
3623
3803
|
gemini: "Gemini",
|
|
3624
3804
|
mistral: "Mistral Le Chat / Vibe",
|
|
@@ -3634,7 +3814,7 @@ function getClientPackFilename(client) {
|
|
|
3634
3814
|
const names = {
|
|
3635
3815
|
"claude-code": "CLAUDE_CODE.md",
|
|
3636
3816
|
cursor: "CURSOR.md",
|
|
3637
|
-
|
|
3817
|
+
kimi: "KIMI.md",
|
|
3638
3818
|
codex: "CODEX.md",
|
|
3639
3819
|
gemini: "GEMINI.md",
|
|
3640
3820
|
mistral: "MISTRAL.md",
|
|
@@ -3653,8 +3833,12 @@ function getClientConfigArtifacts(client) {
|
|
|
3653
3833
|
if (client === "cursor") {
|
|
3654
3834
|
return [".mcp.json", ".cursor/rules/snipara.mdc", "dashboard automation bundle when installed"];
|
|
3655
3835
|
}
|
|
3656
|
-
if (client === "
|
|
3657
|
-
return [
|
|
3836
|
+
if (client === "kimi") {
|
|
3837
|
+
return [
|
|
3838
|
+
"AGENTS.md",
|
|
3839
|
+
".kimi-code/mcp.json",
|
|
3840
|
+
".kimi-code/snipara-plugin when installed through Companion"
|
|
3841
|
+
];
|
|
3658
3842
|
}
|
|
3659
3843
|
if (client === "codex") {
|
|
3660
3844
|
return ["AGENTS.md", ".codex/config.toml", ".snipara/templates/codex-config.toml"];
|
|
@@ -4676,6 +4860,11 @@ function printSuccess(answers, report, activationManifest) {
|
|
|
4676
4860
|
chalk.green(" \u2713 Claude Code") + chalk.dim(" - .mcp.json MCP config, .claude/settings.json hooks when enabled")
|
|
4677
4861
|
);
|
|
4678
4862
|
}
|
|
4863
|
+
if (answers.aiClient === "kimi" && answers.profile !== "runtime-only") {
|
|
4864
|
+
console.log(
|
|
4865
|
+
chalk.green(" \u2713 Kimi Code CLI") + chalk.dim(" - .kimi-code/mcp.json with environment-backed authentication")
|
|
4866
|
+
);
|
|
4867
|
+
}
|
|
4679
4868
|
console.log(
|
|
4680
4869
|
chalk.green(" \u2713 .snipara/companion") + chalk.dim(" - Doctor report and optional command references")
|
|
4681
4870
|
);
|
|
@@ -4712,6 +4901,17 @@ function printSuccess(answers, report, activationManifest) {
|
|
|
4712
4901
|
`If Snipara tools are missing, run: ${CREATE_SNIPARA_NPX_COMMAND} doctor --client claude-desktop`
|
|
4713
4902
|
);
|
|
4714
4903
|
}
|
|
4904
|
+
if (answers.aiClient === "kimi") {
|
|
4905
|
+
printNextStep(
|
|
4906
|
+
"For Kimi Code CLI, export SNIPARA_API_KEY before launch and run /mcp to verify the project-local server."
|
|
4907
|
+
);
|
|
4908
|
+
printNextStep(
|
|
4909
|
+
`To enable Companion lifecycle hooks, run ${COMPANION_NPX_COMMAND} automations install --client kimi, review .kimi-code/snipara-plugin, then install it in Kimi with /plugins install .kimi-code/snipara-plugin.`
|
|
4910
|
+
);
|
|
4911
|
+
printNextStep(
|
|
4912
|
+
"Keep manual approval for risky tools because Kimi hooks are fail-open and are not a standalone security boundary."
|
|
4913
|
+
);
|
|
4914
|
+
}
|
|
4715
4915
|
if (answers.aiClient === "codex") {
|
|
4716
4916
|
printNextStep(
|
|
4717
4917
|
"For Codex, merge .snipara/templates/codex-config.toml into ~/.codex/config.toml if the app does not read project .codex/config.toml."
|
|
@@ -5153,8 +5353,8 @@ function detectAiClient() {
|
|
|
5153
5353
|
if (fs.existsSync(path.join(process.cwd(), ".cursor"))) {
|
|
5154
5354
|
return "cursor";
|
|
5155
5355
|
}
|
|
5156
|
-
if (fs.existsSync(path.join(process.cwd(), ".
|
|
5157
|
-
return "
|
|
5356
|
+
if (fs.existsSync(path.join(process.cwd(), ".kimi-code"))) {
|
|
5357
|
+
return "kimi";
|
|
5158
5358
|
}
|
|
5159
5359
|
if (fs.existsSync(path.join(process.cwd(), ".gemini"))) {
|
|
5160
5360
|
return "gemini";
|
|
@@ -5174,8 +5374,8 @@ function detectAiClient() {
|
|
|
5174
5374
|
if (fs.existsSync(path.join(homedir(), ".cursor")) || process.env.CURSOR_EDITOR) {
|
|
5175
5375
|
return "cursor";
|
|
5176
5376
|
}
|
|
5177
|
-
if (fs.existsSync(path.join(homedir(), ".
|
|
5178
|
-
return "
|
|
5377
|
+
if (fs.existsSync(path.join(homedir(), ".kimi-code")) || process.env.KIMI_CODE_HOME) {
|
|
5378
|
+
return "kimi";
|
|
5179
5379
|
}
|
|
5180
5380
|
if (fs.existsSync(path.join(homedir(), ".gemini")) || process.env.GEMINI_CLI) {
|
|
5181
5381
|
return "gemini";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-snipara",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.13",
|
|
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",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"chatgpt",
|
|
33
33
|
"openai",
|
|
34
34
|
"cursor",
|
|
35
|
-
"
|
|
35
|
+
"kimi",
|
|
36
36
|
"gemini",
|
|
37
37
|
"mistral",
|
|
38
38
|
"orca",
|