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.
- package/README.md +2 -1
- package/dist/index.js +734 -11
- 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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
1769
|
-
|
|
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
|
-
-
|
|
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
|
-
-
|
|
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
|
|
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
|
|
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