knit-mcp 0.7.1 → 0.8.0

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 CHANGED
@@ -59,6 +59,27 @@ Adds the Knit MCP server to your Claude Code config (`~/.claude.json`). No per-p
59
59
 
60
60
  **Supported shells:** macOS, Linux, WSL, Git Bash, and Windows PowerShell. The generated hooks use POSIX-style single-quoted `node -e '…'` payloads. Windows `cmd.exe` does not treat single quotes as delimiters and is not supported as the hook-runner shell — on Windows, use PowerShell (default in modern Windows Terminal) or Git Bash. If you hit a hook error on Windows, file an issue with the shell you're using.
61
61
 
62
+ ### Quiet mode (no hook enforcement)
63
+
64
+ Knit ships Protocol Guard in `warn` mode by default — hooks print reminders, they never block. If you want it fully silent (no PreToolUse classification gate, no reminder messages), run this once inside Claude Code:
65
+
66
+ > `knit_set_protocol_strictness({ level: "off" })`
67
+
68
+ The other hooks (LEARN compliance, KB metrics, final build verification) stay as observability nudges — they print, they don't gate. To remove them too, see Uninstall below.
69
+
70
+ ### Uninstall
71
+
72
+ ```bash
73
+ rm -rf ~/.knit # all per-project + global memory
74
+ ```
75
+
76
+ Then:
77
+ 1. Remove `"knit-brain"` from `mcpServers` in `~/.claude.json`
78
+ 2. Delete the `<!-- knit:start --> ... <!-- knit:end -->` block from each project's `CLAUDE.md`
79
+ 3. Remove `_knitOwned` entries from each project's `.claude/settings.local.json` (or delete the file if Knit was the only thing in it)
80
+
81
+ Total time: ~30 seconds per project. Knit doesn't write anywhere else on your machine.
82
+
62
83
  ## How data is stored
63
84
 
64
85
  Knit data is centralized — not in every repo's working tree:
@@ -2,13 +2,13 @@ import {
2
2
  detectProjectRoot,
3
3
  getBrain,
4
4
  refreshBrain
5
- } from "./chunk-X6TGTET3.js";
6
- import "./chunk-3XR77YJM.js";
7
- import "./chunk-SLN5ABF5.js";
8
- import "./chunk-7PPC6IG6.js";
5
+ } from "./chunk-WN4AQFMO.js";
6
+ import "./chunk-N7R4P42P.js";
7
+ import "./chunk-MOOVNMIN.js";
8
+ import "./chunk-JJ367RK5.js";
9
9
  import "./chunk-M3YZOJNW.js";
10
10
  import "./chunk-BAUQEFYY.js";
11
- import "./chunk-HBMF62U4.js";
11
+ import "./chunk-SBJMHDBM.js";
12
12
  export {
13
13
  detectProjectRoot,
14
14
  getBrain,
@@ -24,6 +24,7 @@ The protocol enforces a 4-tier classifier:
24
24
  - Complex: cross-domain, types/auth-touching, high-fanout, or any task spanning more than one commit \u2014 full 6 phases with auto plan mode on RESEARCH.
25
25
 
26
26
  Knit provides inputs; you make the calls. When in doubt, under-classify \u2014 easier to escalate mid-task than to downgrade.`;
27
+
27
28
  export {
28
29
  KNIT_INSTRUCTIONS
29
30
  };
@@ -271,6 +271,162 @@ function detectGit(root) {
271
271
  return { isRepo, defaultBranch, hasRemote };
272
272
  }
273
273
 
274
+ // src/generators/claude-md.ts
275
+ var KNIT_MARKER_START = "<!-- knit:start -->";
276
+ var KNIT_MARKER_END = "<!-- knit:end -->";
277
+ var LEGACY_ENGRAM_MARKER_START = "<!-- engram:start -->";
278
+ var LEGACY_ENGRAM_MARKER_END = "<!-- engram:end -->";
279
+ function generateClaudeMd(config, knowledge, falsePositives) {
280
+ const sections = [
281
+ generateHeader(config),
282
+ generateSessionStartup(),
283
+ knowledge ? generateProjectMap(knowledge) : null,
284
+ generateDomainArchitecture(config),
285
+ falsePositives && falsePositives.length > 0 ? generateFalsePositives(falsePositives) : null,
286
+ generateBuildGates(config),
287
+ generateTierVocabulary(),
288
+ generateWorkflowPointer()
289
+ ];
290
+ const body = sections.filter(Boolean).join("\n\n---\n\n");
291
+ return `${KNIT_MARKER_START}
292
+
293
+ ${body}
294
+
295
+ ${KNIT_MARKER_END}
296
+ `;
297
+ }
298
+ function spliceKnitBlock(existing, newBlock) {
299
+ const markerPairs = [
300
+ [KNIT_MARKER_START, KNIT_MARKER_END],
301
+ [LEGACY_ENGRAM_MARKER_START, LEGACY_ENGRAM_MARKER_END]
302
+ ];
303
+ for (const [startMarker, endMarker] of markerPairs) {
304
+ const startIdx = existing.indexOf(startMarker);
305
+ const endIdx = existing.indexOf(endMarker);
306
+ if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
307
+ const before = existing.slice(0, startIdx);
308
+ const after = existing.slice(endIdx + endMarker.length);
309
+ return { content: before + newBlock.trimEnd() + after, mode: "replaced" };
310
+ }
311
+ }
312
+ return { content: existing, mode: "sidecar-needed" };
313
+ }
314
+ function generateHeader(config) {
315
+ const stackParts = [
316
+ config.stack.language !== "unknown" ? config.stack.language : null,
317
+ config.stack.framework
318
+ ].filter(Boolean);
319
+ const stackDesc = stackParts.length > 0 ? `${stackParts.join(" + ")} project. ` : "";
320
+ return `# ${config.name}
321
+
322
+ ${stackDesc}Knit-powered workflow. The protocol depth is fetched on demand via \`knit_get_workflow({phase})\` \u2014 this file holds only project-specific facts.`;
323
+ }
324
+ function generateSessionStartup() {
325
+ return `## Session start
326
+
327
+ First action: call \`knit_load_session\`. One MCP call returns last sessions, handoff, learnings, false positives. If \`handoff.md\` exists at the repo root, resume that work first.
328
+
329
+ Protocol Guard runs in \`warn\` mode by default \u2014 adjust with \`knit_set_protocol_strictness\`.`;
330
+ }
331
+ function generateProjectMap(knowledge) {
332
+ const { summary } = knowledge;
333
+ let content = `## Project Map (auto-generated)
334
+
335
+ `;
336
+ if (summary.entryPoints.length > 0) {
337
+ content += `**Entry points:** \`${summary.entryPoints.join("`, `")}\`
338
+ `;
339
+ }
340
+ if (summary.highFanoutFiles.length > 0) {
341
+ const shown = summary.highFanoutFiles.slice(0, 5);
342
+ content += `**High-fanout (change carefully):** \`${shown.join("`, `")}\``;
343
+ if (summary.highFanoutFiles.length > 5) {
344
+ content += ` (+${summary.highFanoutFiles.length - 5} more \u2014 \`knit_find_fanout\`)`;
345
+ }
346
+ content += "\n";
347
+ }
348
+ if (summary.untestedFiles.length > 0) {
349
+ const shown = summary.untestedFiles.slice(0, 3);
350
+ content += `**Untested:** \`${shown.join("`, `")}\``;
351
+ if (summary.untestedFiles.length > 3) {
352
+ content += ` (+${summary.untestedFiles.length - 3} more \u2014 \`knit_query_tests({filter:"untested"})\`)`;
353
+ }
354
+ content += "\n";
355
+ }
356
+ if (summary.largestFiles.length > 0) {
357
+ const top3 = summary.largestFiles.slice(0, 3);
358
+ const list = top3.map((f) => `\`${f.path}\` (${f.lines})`).join(", ");
359
+ content += `**Largest:** ${list}
360
+ `;
361
+ }
362
+ content += `
363
+ **Stats:** ${summary.totalFiles} files, ${summary.totalLines.toLocaleString()} lines`;
364
+ const langs = Object.entries(summary.languageBreakdown).sort((a, b) => b[1] - a[1]).slice(0, 3).map(([ext, count]) => `${ext}: ${count}`);
365
+ if (langs.length > 0) content += ` (${langs.join(", ")})`;
366
+ return content;
367
+ }
368
+ function generateDomainArchitecture(config) {
369
+ if (!config.domains || config.domains.length === 0) {
370
+ return `## Domain Architecture
371
+
372
+ No domains detected. Use \`knit_setup_project\` to describe your project \u2014 Knit will configure domains and review agents.`;
373
+ }
374
+ const rows = config.domains.map((d) => {
375
+ const patterns = d.filePatterns.slice(0, 3).join(", ");
376
+ const agents = d.agents.join(", ");
377
+ return `### ${d.name}
378
+ **Files:** \`${patterns}\`
379
+ **Concern:** ${d.description}
380
+ **Review agents:** \`${agents}\``;
381
+ }).join("\n\n");
382
+ return `## Domain Architecture
383
+
384
+ ${rows}`;
385
+ }
386
+ function generateFalsePositives(fps) {
387
+ const items = fps.slice(0, 10).map((fp) => `- **${fp.summary}** \u2014 ${fp.lesson}`).join("\n");
388
+ return `## Known False Positives
389
+
390
+ Review agents should NOT re-flag these \u2014 they're confirmed non-issues from prior sessions:
391
+
392
+ ${items}`;
393
+ }
394
+ function generateBuildGates(config) {
395
+ const gates = [];
396
+ if (config.stack.typecheckCommand) gates.push(`- \`${config.stack.typecheckCommand}\``);
397
+ if (config.stack.lintCommand) gates.push(`- \`${config.stack.lintCommand}\``);
398
+ if (config.stack.testFramework) {
399
+ const pm = config.packageManager === "unknown" ? "npm" : config.packageManager;
400
+ gates.push(`- \`${pm} test\``);
401
+ }
402
+ if (config.stack.buildCommand) gates.push(`- \`${config.stack.buildCommand}\``);
403
+ if (gates.length === 0) {
404
+ return `## Build Gates
405
+
406
+ No build gates auto-detected. Add typecheck/lint/test/build commands to your package.json.`;
407
+ }
408
+ return `## Build Gates
409
+
410
+ All must pass before commit:
411
+
412
+ ${gates.join("\n")}`;
413
+ }
414
+ function generateTierVocabulary() {
415
+ return `## Tier vocabulary
416
+
417
+ | Tier | When |
418
+ |------|------|
419
+ | **Inquiry** | Read-only ("what", "where", "audit") \u2014 just answer. |
420
+ | **Trivial** | One-line fix \u2014 execute \u2192 verify. |
421
+ | **Standard** | Single-domain bug fix or feature \u2014 research \u2192 execute \u2192 review. |
422
+ | **Complex** | Cross-domain, touches types/auth, high-fanout, or multi-commit arc \u2014 full 6 phases + auto plan mode. |`;
423
+ }
424
+ function generateWorkflowPointer() {
425
+ return `## Workflow on demand
426
+
427
+ Fetch any phase via \`knit_get_workflow({phase})\`. Call with no phase to list available sections.`;
428
+ }
429
+
274
430
  export {
275
431
  VOLTAGENT_PINNED_SHA,
276
432
  VOLTAGENT_REF,
@@ -278,5 +434,11 @@ export {
278
434
  categoryOf,
279
435
  rawAgentUrl,
280
436
  isBundledCore,
281
- scanProject
437
+ scanProject,
438
+ KNIT_MARKER_START,
439
+ KNIT_MARKER_END,
440
+ LEGACY_ENGRAM_MARKER_START,
441
+ LEGACY_ENGRAM_MARKER_END,
442
+ generateClaudeMd,
443
+ spliceKnitBlock
282
444
  };
@@ -358,166 +358,7 @@ function buildReverseDependencies(importGraph) {
358
358
  return reverse;
359
359
  }
360
360
 
361
- // src/generators/claude-md.ts
362
- var KNIT_MARKER_START = "<!-- knit:start -->";
363
- var KNIT_MARKER_END = "<!-- knit:end -->";
364
- var LEGACY_ENGRAM_MARKER_START = "<!-- engram:start -->";
365
- var LEGACY_ENGRAM_MARKER_END = "<!-- engram:end -->";
366
- function generateClaudeMd(config, knowledge, falsePositives) {
367
- const sections = [
368
- generateHeader(config),
369
- generateSessionStartup(),
370
- knowledge ? generateProjectMap(knowledge) : null,
371
- generateDomainArchitecture(config),
372
- falsePositives && falsePositives.length > 0 ? generateFalsePositives(falsePositives) : null,
373
- generateBuildGates(config),
374
- generateTierVocabulary(),
375
- generateWorkflowPointer()
376
- ];
377
- const body = sections.filter(Boolean).join("\n\n---\n\n");
378
- return `${KNIT_MARKER_START}
379
-
380
- ${body}
381
-
382
- ${KNIT_MARKER_END}
383
- `;
384
- }
385
- function spliceKnitBlock(existing, newBlock) {
386
- const markerPairs = [
387
- [KNIT_MARKER_START, KNIT_MARKER_END],
388
- [LEGACY_ENGRAM_MARKER_START, LEGACY_ENGRAM_MARKER_END]
389
- ];
390
- for (const [startMarker, endMarker] of markerPairs) {
391
- const startIdx = existing.indexOf(startMarker);
392
- const endIdx = existing.indexOf(endMarker);
393
- if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
394
- const before = existing.slice(0, startIdx);
395
- const after = existing.slice(endIdx + endMarker.length);
396
- return { content: before + newBlock.trimEnd() + after, mode: "replaced" };
397
- }
398
- }
399
- return { content: existing, mode: "sidecar-needed" };
400
- }
401
- function generateHeader(config) {
402
- const stackParts = [
403
- config.stack.language !== "unknown" ? config.stack.language : null,
404
- config.stack.framework
405
- ].filter(Boolean);
406
- const stackDesc = stackParts.length > 0 ? `${stackParts.join(" + ")} project. ` : "";
407
- return `# ${config.name}
408
-
409
- ${stackDesc}Knit-powered workflow. The protocol depth is fetched on demand via \`knit_get_workflow({phase})\` \u2014 this file holds only project-specific facts.`;
410
- }
411
- function generateSessionStartup() {
412
- return `## Session start
413
-
414
- First action: call \`knit_load_session\`. One MCP call returns last sessions, handoff, learnings, false positives. If \`handoff.md\` exists at the repo root, resume that work first.
415
-
416
- Protocol Guard runs in \`warn\` mode by default \u2014 adjust with \`knit_set_protocol_strictness\`.`;
417
- }
418
- function generateProjectMap(knowledge) {
419
- const { summary } = knowledge;
420
- let content = `## Project Map (auto-generated)
421
-
422
- `;
423
- if (summary.entryPoints.length > 0) {
424
- content += `**Entry points:** \`${summary.entryPoints.join("`, `")}\`
425
- `;
426
- }
427
- if (summary.highFanoutFiles.length > 0) {
428
- const shown = summary.highFanoutFiles.slice(0, 5);
429
- content += `**High-fanout (change carefully):** \`${shown.join("`, `")}\``;
430
- if (summary.highFanoutFiles.length > 5) {
431
- content += ` (+${summary.highFanoutFiles.length - 5} more \u2014 \`knit_find_fanout\`)`;
432
- }
433
- content += "\n";
434
- }
435
- if (summary.untestedFiles.length > 0) {
436
- const shown = summary.untestedFiles.slice(0, 3);
437
- content += `**Untested:** \`${shown.join("`, `")}\``;
438
- if (summary.untestedFiles.length > 3) {
439
- content += ` (+${summary.untestedFiles.length - 3} more \u2014 \`knit_query_tests({filter:"untested"})\`)`;
440
- }
441
- content += "\n";
442
- }
443
- if (summary.largestFiles.length > 0) {
444
- const top3 = summary.largestFiles.slice(0, 3);
445
- const list = top3.map((f) => `\`${f.path}\` (${f.lines})`).join(", ");
446
- content += `**Largest:** ${list}
447
- `;
448
- }
449
- content += `
450
- **Stats:** ${summary.totalFiles} files, ${summary.totalLines.toLocaleString()} lines`;
451
- const langs = Object.entries(summary.languageBreakdown).sort((a, b) => b[1] - a[1]).slice(0, 3).map(([ext, count]) => `${ext}: ${count}`);
452
- if (langs.length > 0) content += ` (${langs.join(", ")})`;
453
- return content;
454
- }
455
- function generateDomainArchitecture(config) {
456
- if (!config.domains || config.domains.length === 0) {
457
- return `## Domain Architecture
458
-
459
- No domains detected. Use \`knit_setup_project\` to describe your project \u2014 Knit will configure domains and review agents.`;
460
- }
461
- const rows = config.domains.map((d) => {
462
- const patterns = d.filePatterns.slice(0, 3).join(", ");
463
- const agents = d.agents.join(", ");
464
- return `### ${d.name}
465
- **Files:** \`${patterns}\`
466
- **Concern:** ${d.description}
467
- **Review agents:** \`${agents}\``;
468
- }).join("\n\n");
469
- return `## Domain Architecture
470
-
471
- ${rows}`;
472
- }
473
- function generateFalsePositives(fps) {
474
- const items = fps.slice(0, 10).map((fp) => `- **${fp.summary}** \u2014 ${fp.lesson}`).join("\n");
475
- return `## Known False Positives
476
-
477
- Review agents should NOT re-flag these \u2014 they're confirmed non-issues from prior sessions:
478
-
479
- ${items}`;
480
- }
481
- function generateBuildGates(config) {
482
- const gates = [];
483
- if (config.stack.typecheckCommand) gates.push(`- \`${config.stack.typecheckCommand}\``);
484
- if (config.stack.lintCommand) gates.push(`- \`${config.stack.lintCommand}\``);
485
- if (config.stack.testFramework) {
486
- const pm = config.packageManager === "unknown" ? "npm" : config.packageManager;
487
- gates.push(`- \`${pm} test\``);
488
- }
489
- if (config.stack.buildCommand) gates.push(`- \`${config.stack.buildCommand}\``);
490
- if (gates.length === 0) {
491
- return `## Build Gates
492
-
493
- No build gates auto-detected. Add typecheck/lint/test/build commands to your package.json.`;
494
- }
495
- return `## Build Gates
496
-
497
- All must pass before commit:
498
-
499
- ${gates.join("\n")}`;
500
- }
501
- function generateTierVocabulary() {
502
- return `## Tier vocabulary
503
-
504
- | Tier | When |
505
- |------|------|
506
- | **Inquiry** | Read-only ("what", "where", "audit") \u2014 just answer. |
507
- | **Trivial** | One-line fix \u2014 execute \u2192 verify. |
508
- | **Standard** | Single-domain bug fix or feature \u2014 research \u2192 execute \u2192 review. |
509
- | **Complex** | Cross-domain, touches types/auth, high-fanout, or multi-commit arc \u2014 full 6 phases + auto plan mode. |`;
510
- }
511
- function generateWorkflowPointer() {
512
- return `## Workflow on demand
513
-
514
- Fetch any phase via \`knit_get_workflow({phase})\`. Call with no phase to list available sections.`;
515
- }
516
-
517
361
  export {
518
362
  buildKnowledge,
519
- buildReverseDependencies,
520
- KNIT_MARKER_START,
521
- generateClaudeMd,
522
- spliceKnitBlock
363
+ buildReverseDependencies
523
364
  };