@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.
- package/CHANGELOG.md +126 -0
- package/gates/agent-no-recursive-dispatch.md +48 -0
- package/gates/budget-description.md +68 -0
- package/gates/no-personal-uuid.md +72 -0
- package/gates/skill-must-include.md +69 -0
- package/gates/sync-idempotent.md +62 -0
- package/kit/agents/advisor-researcher.md +1 -14
- package/kit/agents/assumptions-analyzer.md +1 -14
- package/kit/agents/codebase-mapper.md +2 -15
- package/kit/agents/debugger.md +1 -19
- package/kit/agents/executor.md +18 -18
- package/kit/agents/integration-checker.md +1 -16
- package/kit/agents/nyquist-auditor.md +1 -16
- package/kit/agents/phase-researcher.md +1 -14
- package/kit/agents/plan-checker.md +1 -16
- package/kit/agents/planner.md +36 -16
- package/kit/agents/project-researcher.md +2 -15
- package/kit/agents/research-synthesizer.md +1 -9
- package/kit/agents/roadmapper.md +1 -14
- package/kit/agents/schema-checker.md +4 -4
- package/kit/agents/supabase-architect.md +153 -0
- package/kit/agents/supabase-auth-bootstrapper.md +298 -0
- package/kit/agents/supabase-edge-fn-writer.md +185 -0
- package/kit/agents/supabase-migration-writer.md +156 -0
- package/kit/agents/supabase-realtime-implementer.md +252 -0
- package/kit/agents/supabase-rls-writer.md +218 -0
- package/kit/agents/supabase-storage-implementer.md +240 -0
- package/kit/agents/ui-auditor.md +1 -16
- package/kit/agents/ui-checker.md +1 -16
- package/kit/agents/ui-researcher.md +1 -14
- package/kit/agents/user-profiler.md +2 -10
- package/kit/agents/verifier.md +2 -17
- package/kit/commands/depurar.md +17 -0
- package/kit/commands/expresso.md +9 -0
- package/kit/commands/fazer.md +32 -4
- package/kit/commands/proximo.md +7 -0
- package/kit/commands/rapido.md +6 -0
- package/kit/commands/supabase.md +148 -0
- package/kit/framework/references/output-style.md +22 -0
- package/kit/framework/workflows/discuss-phase.md +62 -327
- package/kit/framework/workflows/help.md +14 -1
- package/kit/framework/workflows/new-project.md +16 -107
- package/kit/framework/workflows/plan-phase.md +53 -147
- package/kit/skills/_shared-supabase/glossary.md +180 -0
- package/kit/skills/supabase-auth-ssr/SKILL.md +260 -0
- package/kit/skills/supabase-cron-queues/SKILL.md +266 -0
- package/kit/skills/supabase-database-functions/SKILL.md +247 -0
- package/kit/skills/supabase-declarative-schema/SKILL.md +183 -0
- package/kit/skills/supabase-edge-functions/SKILL.md +242 -0
- package/kit/skills/supabase-migrations/SKILL.md +175 -0
- package/kit/skills/supabase-pgvector-rag/SKILL.md +253 -0
- package/kit/skills/supabase-postgres-style/SKILL.md +138 -0
- package/kit/skills/supabase-realtime/SKILL.md +236 -0
- package/kit/skills/supabase-rls-policies/SKILL.md +185 -0
- package/kit/skills/supabase-storage/SKILL.md +234 -0
- package/package.json +1 -1
- package/src/core/kit.js +55 -22
- 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
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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 {
|
|
97
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|