@luanpdd/kit-mcp 1.6.1 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/gates/agent-no-recursive-dispatch.md +48 -0
  3. package/gates/budget-description.md +68 -0
  4. package/gates/no-personal-uuid.md +72 -0
  5. package/gates/skill-must-include.md +69 -0
  6. package/gates/sync-idempotent.md +62 -0
  7. package/kit/agents/advisor-researcher.md +1 -14
  8. package/kit/agents/assumptions-analyzer.md +1 -14
  9. package/kit/agents/codebase-mapper.md +2 -15
  10. package/kit/agents/debugger.md +1 -19
  11. package/kit/agents/executor.md +18 -18
  12. package/kit/agents/integration-checker.md +1 -16
  13. package/kit/agents/nyquist-auditor.md +1 -16
  14. package/kit/agents/phase-researcher.md +1 -14
  15. package/kit/agents/plan-checker.md +1 -16
  16. package/kit/agents/planner.md +36 -16
  17. package/kit/agents/project-researcher.md +2 -15
  18. package/kit/agents/research-synthesizer.md +1 -9
  19. package/kit/agents/roadmapper.md +1 -14
  20. package/kit/agents/schema-checker.md +4 -4
  21. package/kit/agents/supabase-architect.md +153 -0
  22. package/kit/agents/supabase-auth-bootstrapper.md +298 -0
  23. package/kit/agents/supabase-edge-fn-writer.md +185 -0
  24. package/kit/agents/supabase-migration-writer.md +156 -0
  25. package/kit/agents/supabase-realtime-implementer.md +252 -0
  26. package/kit/agents/supabase-rls-writer.md +218 -0
  27. package/kit/agents/supabase-storage-implementer.md +240 -0
  28. package/kit/agents/ui-auditor.md +1 -16
  29. package/kit/agents/ui-checker.md +1 -16
  30. package/kit/agents/ui-researcher.md +1 -14
  31. package/kit/agents/user-profiler.md +2 -10
  32. package/kit/agents/verifier.md +2 -17
  33. package/kit/commands/depurar.md +17 -0
  34. package/kit/commands/expresso.md +9 -0
  35. package/kit/commands/fazer.md +32 -4
  36. package/kit/commands/proximo.md +7 -0
  37. package/kit/commands/rapido.md +6 -0
  38. package/kit/commands/supabase.md +148 -0
  39. package/kit/framework/references/output-style.md +22 -0
  40. package/kit/framework/workflows/discuss-phase.md +62 -327
  41. package/kit/framework/workflows/help.md +14 -1
  42. package/kit/framework/workflows/new-project.md +16 -107
  43. package/kit/framework/workflows/plan-phase.md +53 -147
  44. package/kit/skills/_shared-supabase/glossary.md +180 -0
  45. package/kit/skills/supabase-auth-ssr/SKILL.md +260 -0
  46. package/kit/skills/supabase-cron-queues/SKILL.md +266 -0
  47. package/kit/skills/supabase-database-functions/SKILL.md +247 -0
  48. package/kit/skills/supabase-declarative-schema/SKILL.md +183 -0
  49. package/kit/skills/supabase-edge-functions/SKILL.md +242 -0
  50. package/kit/skills/supabase-migrations/SKILL.md +175 -0
  51. package/kit/skills/supabase-pgvector-rag/SKILL.md +253 -0
  52. package/kit/skills/supabase-postgres-style/SKILL.md +138 -0
  53. package/kit/skills/supabase-realtime/SKILL.md +236 -0
  54. package/kit/skills/supabase-rls-policies/SKILL.md +185 -0
  55. package/kit/skills/supabase-storage/SKILL.md +234 -0
  56. package/package.json +1 -1
  57. package/src/core/kit.js +55 -22
  58. package/src/core/sync.js +3 -1
package/src/core/kit.js CHANGED
@@ -33,28 +33,50 @@ export function resolveKitRoot(kitRoot) {
33
33
  // disk on every invocation. Trade-off: callers that edit kit/ inside the same
34
34
  // process may see stale data for up to 30s. Acceptable for MCP/CLI ergonomics.
35
35
  const KIT_CACHE_TTL_MS = 30_000;
36
- const kitCache = new Map(); // kitRoot -> { value, ts }
36
+ const kitCache = new Map(); // `${kitRoot}:${mode}` -> { value, ts }
37
+
38
+ // PERF-S1: when sync runs in mode=reference (default), the body/content of each
39
+ // kit file is never used — only frontmatter (name + description). Reading just
40
+ // the first STUB_READ_BYTES is enough for any frontmatter we'd ever produce and
41
+ // avoids loading 50 KB+ files (planner.md etc) from disk.
42
+ const STUB_READ_BYTES = 4096;
37
43
 
38
44
  export function clearKitCache() { kitCache.clear(); }
39
45
 
40
- export async function listKit(kitRoot) {
46
+ export async function listKit(kitRoot, opts = {}) {
41
47
  kitRoot = resolveKitRoot(kitRoot);
42
- const cached = kitCache.get(kitRoot);
48
+ const stubsOnly = opts.stubsOnly === true;
49
+ const cacheKey = `${kitRoot}:${stubsOnly ? 'stubs' : 'full'}`;
50
+ const cached = kitCache.get(cacheKey);
43
51
  if (cached && Date.now() - cached.ts < KIT_CACHE_TTL_MS) {
44
52
  return cached.value;
45
53
  }
46
54
  const [agents, commands, skills, skillsExtras] = await Promise.all([
47
- readMdDir(path.join(kitRoot, 'agents'), 'agent'),
48
- readMdDir(path.join(kitRoot, 'commands'), 'command'),
49
- readSkillsDir(path.join(kitRoot, 'skills')),
50
- readSkillsDir(path.join(kitRoot, 'skills-extras')).catch(() => []),
55
+ readMdDir(path.join(kitRoot, 'agents'), 'agent', { stubsOnly }),
56
+ readMdDir(path.join(kitRoot, 'commands'), 'command', { stubsOnly }),
57
+ readSkillsDir(path.join(kitRoot, 'skills'), { stubsOnly }),
58
+ readSkillsDir(path.join(kitRoot, 'skills-extras'), { stubsOnly }).catch(() => []),
51
59
  ]);
52
- const value = { agents, commands, skills, skillsExtras, kitRoot };
53
- kitCache.set(kitRoot, { value, ts: Date.now() });
60
+ const value = { agents, commands, skills, skillsExtras, kitRoot, stubsOnly };
61
+ kitCache.set(cacheKey, { value, ts: Date.now() });
54
62
  return value;
55
63
  }
56
64
 
57
- async function readMdDir(dir, kind) {
65
+ // Read just enough bytes from the head of the file to capture the frontmatter.
66
+ // Returns the partial string. fs.open + fd.read avoids the OS pre-fetching the
67
+ // rest of the file (which fs.readFile would force).
68
+ async function readHead(absPath, n) {
69
+ const fd = await fs.open(absPath, 'r');
70
+ try {
71
+ const buf = Buffer.alloc(n);
72
+ const { bytesRead } = await fd.read(buf, 0, n, 0);
73
+ return buf.subarray(0, bytesRead).toString('utf8');
74
+ } finally {
75
+ await fd.close();
76
+ }
77
+ }
78
+
79
+ async function readMdDir(dir, kind, { stubsOnly = false } = {}) {
58
80
  let entries;
59
81
  try {
60
82
  entries = await fs.readdir(dir, { withFileTypes: true });
@@ -65,23 +87,28 @@ async function readMdDir(dir, kind) {
65
87
  for (const e of entries) {
66
88
  if (!e.isFile() || !e.name.endsWith('.md')) continue;
67
89
  const absPath = path.join(dir, e.name);
68
- const raw = await fs.readFile(absPath, 'utf8');
90
+ const raw = stubsOnly
91
+ ? await readHead(absPath, STUB_READ_BYTES)
92
+ : await fs.readFile(absPath, 'utf8');
69
93
  const { frontmatter, body } = splitFrontmatter(raw);
70
- out.push({
94
+ const item = {
71
95
  kind,
72
96
  name: e.name.replace(/\.md$/, ''),
73
97
  absPath,
74
98
  frontmatter,
75
99
  frontmatterRaw: matchFrontmatterRaw(raw),
76
- body,
77
- content: raw,
78
100
  description: frontmatter?.description ?? firstNonEmptyLine(body),
79
- });
101
+ };
102
+ if (!stubsOnly) {
103
+ item.body = body;
104
+ item.content = raw;
105
+ }
106
+ out.push(item);
80
107
  }
81
108
  return out.sort((a, b) => a.name.localeCompare(b.name));
82
109
  }
83
110
 
84
- async function readSkillsDir(dir) {
111
+ async function readSkillsDir(dir, { stubsOnly = false } = {}) {
85
112
  let entries;
86
113
  try {
87
114
  entries = await fs.readdir(dir, { withFileTypes: true });
@@ -93,20 +120,26 @@ async function readSkillsDir(dir) {
93
120
  if (!e.isDirectory()) continue;
94
121
  const skillPath = path.join(dir, e.name, 'SKILL.md');
95
122
  let raw;
96
- try { raw = await fs.readFile(skillPath, 'utf8'); }
97
- catch { continue; }
123
+ try {
124
+ raw = stubsOnly
125
+ ? await readHead(skillPath, STUB_READ_BYTES)
126
+ : await fs.readFile(skillPath, 'utf8');
127
+ } catch { continue; }
98
128
  const { frontmatter, body } = splitFrontmatter(raw);
99
- out.push({
129
+ const item = {
100
130
  kind: 'skill',
101
131
  name: e.name,
102
132
  absPath: skillPath,
103
133
  dirPath: path.join(dir, e.name),
104
134
  frontmatter,
105
135
  frontmatterRaw: matchFrontmatterRaw(raw),
106
- body,
107
- skillContent: raw,
108
136
  description: frontmatter?.description ?? firstNonEmptyLine(body),
109
- });
137
+ };
138
+ if (!stubsOnly) {
139
+ item.body = body;
140
+ item.skillContent = raw;
141
+ }
142
+ out.push(item);
110
143
  }
111
144
  return out.sort((a, b) => a.name.localeCompare(b.name));
112
145
  }
package/src/core/sync.js CHANGED
@@ -28,7 +28,9 @@ export async function syncTo(targetId, opts = {}) {
28
28
 
29
29
  // PERF-03: accept a pre-loaded kit to avoid re-walking the disk when callers
30
30
  // already have one in hand (CLI sync that follows reverse-sync detect, etc).
31
- const kit = opts.kit ?? await listKit(kitRoot);
31
+ // PERF-S1: in mode=reference (default), read just frontmatter — body/content
32
+ // is never used by stub renderers. Saves I/O on big kit files (planner.md etc).
33
+ const kit = opts.kit ?? await listKit(kitRoot, { stubsOnly: mode === 'reference' });
32
34
  const ops = [];
33
35
 
34
36
  if (target.rules) {