@plumpslabs/kuma 2.3.20 → 2.3.23

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 (39) hide show
  1. package/README.md +18 -0
  2. package/dist/index.js +10316 -380
  3. package/package.json +2 -2
  4. package/packages/ide/studio/dist/index.js +90 -9
  5. package/packages/ide/studio/public/index.html +528 -233
  6. package/dist/agentDetector-YOWQVJFR.js +0 -186
  7. package/dist/chunk-3BRBJZ7P.js +0 -1055
  8. package/dist/chunk-3OHYYXYN.js +0 -71
  9. package/dist/chunk-ABKE45T4.js +0 -1264
  10. package/dist/chunk-E2KFPEBT.js +0 -183
  11. package/dist/chunk-FKRSI5U5.js +0 -282
  12. package/dist/chunk-GFLSAXAH.js +0 -155
  13. package/dist/chunk-L7F67KUP.js +0 -172
  14. package/dist/chunk-LVKOGXLC.js +0 -658
  15. package/dist/chunk-PRUTTZBS.js +0 -1113
  16. package/dist/contextDigest-QB5XHPXE.js +0 -177
  17. package/dist/domainRules-QLPAQASB.js +0 -20
  18. package/dist/init-PL4XL662.js +0 -15
  19. package/dist/kumaAstValidator-CNM7FHYA.js +0 -150
  20. package/dist/kumaCheckpoint-J2LDQMEO.js +0 -207
  21. package/dist/kumaCodeScanner-J6B2EHGI.js +0 -563
  22. package/dist/kumaContractEngine-KX27T4N7.js +0 -305
  23. package/dist/kumaDb-4XZ5S2LH.js +0 -65
  24. package/dist/kumaDriftDetector-TOORILSZ.js +0 -237
  25. package/dist/kumaGotchas-XRGFFBTA.js +0 -151
  26. package/dist/kumaGraph-UMXZNGYF.js +0 -44
  27. package/dist/kumaMemory-FBJMV77G.js +0 -16
  28. package/dist/kumaMiner-XJETL7TL.js +0 -176
  29. package/dist/kumaPolicyEngine-2QDJDLM7.js +0 -311
  30. package/dist/kumaProgressiveContext-MWEDRXOH.js +0 -231
  31. package/dist/kumaSearch-PV4QTKE7.js +0 -321
  32. package/dist/kumaTrajectory-7NOAVNG2.js +0 -460
  33. package/dist/kumaVerifier-6YEGC77M.js +0 -265
  34. package/dist/kumaVisualize-264OEBGJ.js +0 -264
  35. package/dist/pathValidator-V4DC6U6Z.js +0 -22
  36. package/dist/safetyAudit-O45SPNTS.js +0 -12
  37. package/dist/safetyScore-TMMRD2MV.js +0 -333
  38. package/dist/sessionMemory-YPKVIOMV.js +0 -6
  39. package/dist/skillGenerator-PWEJKZNX.js +0 -304
@@ -1,1264 +0,0 @@
1
- import {
2
- getProjectRoot
3
- } from "./chunk-E2KFPEBT.js";
4
-
5
- // src/cli/init.ts
6
- import fs from "fs";
7
- import path from "path";
8
- var ALL_CONFIG_TYPES = [
9
- "claude",
10
- "cursor",
11
- "windsurf",
12
- "copilot",
13
- "cline",
14
- "aider",
15
- "antigravity",
16
- "opencode",
17
- "codex",
18
- "qwen",
19
- "kiro",
20
- "openclaw",
21
- "codewhale"
22
- ];
23
- var CONFIG_LABELS = {
24
- claude: "Claude Code (CLAUDE.md / plugin)",
25
- cursor: "Cursor (.cursor/rules/*.mdc)",
26
- windsurf: "Windsurf (.windsurf/rules/)",
27
- copilot: "GitHub Copilot Editor (AGENTS.md + Skill)",
28
- cline: "Cline (.clinerules/*.md)",
29
- aider: "Aider (CONVENTIONS.md via .aider.conf.yml)",
30
- antigravity: "Antigravity CLI (.agents/skills/)",
31
- opencode: "OpenCode (AGENTS.md + skills)",
32
- codex: "Codex CLI (AGENTS.md + .codex/config.toml)",
33
- qwen: "Qwen Code (AGENTS.md + settings.json)",
34
- kiro: "Kiro (.kiro/steering/*.md)",
35
- openclaw: "OpenClaw (skills/)",
36
- codewhale: "CodeWhale (skills/ + .codewhale/mcp.json)"
37
- };
38
- function configFilePath(type) {
39
- switch (type) {
40
- case "claude":
41
- return "CLAUDE.md";
42
- case "cursor":
43
- return ".cursor/rules/kuma.mdc";
44
- case "windsurf":
45
- return ".windsurf/rules/kuma.md";
46
- case "copilot":
47
- return "AGENTS.md";
48
- case "cline":
49
- return ".clinerules/kuma.md";
50
- case "aider":
51
- return "CONVENTIONS.md";
52
- case "antigravity":
53
- return ".agents/skills/kuma/SKILL.md";
54
- case "opencode":
55
- return "AGENTS.md";
56
- case "codex":
57
- return "AGENTS.md";
58
- case "qwen":
59
- return "AGENTS.md";
60
- case "kiro":
61
- return ".kiro/steering/kuma.md";
62
- case "openclaw":
63
- return "skills/kuma/SKILL.md";
64
- case "codewhale":
65
- return "skills/kuma/SKILL.md";
66
- }
67
- }
68
- var BOOTSTRAP_LINES = [
69
- "Kuma MCP tools are installed (kuma_context, kuma_memory, kuma_safety).",
70
- '**Before coding, call `kuma_context({ action: "init" })`** to load project context and session memory.',
71
- "Project knowledge persists in `.kuma/memories/*.md` across sessions.",
72
- "",
73
- "\u26A0\uFE0F **MANDATORY WORKFLOW** \u2014 Follow in order every session (including research-only):",
74
- "",
75
- ' 1. `kuma_context({ action: "init" })` \u2014 Load context (START HERE)',
76
- ' 2. `kuma_safety({ action: "guard" })` \u2014 Safety check before work',
77
- ' 3. `kuma_context({ action: "research", scope: "<area>" })` \u2014 Research before editing',
78
- " 4. *(edit/read using native tools)*",
79
- ' 5. `kuma_memory({ action: "research_save", ... })` \u2014 After exploring area (creates search cache)',
80
- ' 6. `kuma_memory({ action: "gotcha" })` \u2014 \u{1F525} IMMEDIATELY when bug found (exponential value)',
81
- ' 7. `kuma_memory({ action: "arch_flow" })` \u2014 \u{1F525} IMMEDIATELY after each flow hop (exponential value)',
82
- ' 8. `kuma_memory({ action: "decision" })` \u2014 When choosing between options (preserves rationale)',
83
- ' 9. `kuma_safety({ action: "verify", ... })` \u2014 Run tests / confirm nothing broken',
84
- ' 10. `kuma_context({ action: "changes" })` \u2014 Review session activity',
85
- "",
86
- "\u{1F525} **Power Curve:** `arch_flow` + `gotcha` are EXPONENTIAL \u2014 each record saves 5-10 files next session.",
87
- " The more you record, the more overpowered the agent becomes. These are the highest-value actions.",
88
- "\u{1F7E2} **SKIP** recording function/class/component nodes \u2014 grep/glob is faster.",
89
- "\u{1F9E0} Knowledge graph is persistent \u2014 nodes/edges accumulate across sessions, getting richer over time.",
90
- "",
91
- "\u26D4 Do NOT skip steps 5-10 after research \u2014 even if no code was changed.",
92
- "\u{1F4D6} Full rules: `.kuma/init.md`",
93
- "\u{1F9E0} Tools: `kuma_context` | `kuma_memory` | `kuma_safety`"
94
- ].join("\n");
95
- var KUMA_CORE_INSTRUCTIONS = BOOTSTRAP_LINES;
96
- function claudeTemplate() {
97
- return [
98
- "# Kuma MCP",
99
- "",
100
- KUMA_CORE_INSTRUCTIONS,
101
- "",
102
- "\u{1F4D6} Rules: `.kuma/init.md`",
103
- "\u{1F9E0} Memories: `.kuma/memories/*.md`"
104
- ].join("\n");
105
- }
106
- function cursorRulesTemplate() {
107
- return [
108
- "---",
109
- "description: Kuma MCP \u2014 .kuma/ is the single source of truth",
110
- "alwaysApply: true",
111
- "---",
112
- "",
113
- KUMA_CORE_INSTRUCTIONS,
114
- "",
115
- "\u{1F4D6} Read `.kuma/init.md` for detailed rules."
116
- ].join("\n");
117
- }
118
- function windsurfRulesTemplate() {
119
- return [
120
- "# Kuma MCP \u2014 Windsurf",
121
- "",
122
- "Windsurf Cascade agent: Kuma MCP tools are installed.",
123
- "All behavioral rules are in `.kuma/init.md`.",
124
- '**Before coding, call `kuma_context({ action: "init" })`** to load project context and session memory.',
125
- "Project knowledge persists in `.kuma/memories/*.md` across sessions.",
126
- "",
127
- "Also auto-detected as SKILL.md in `.windsurf/skills/` and `.agents/skills/`."
128
- ].join("\n");
129
- }
130
- function copilotTemplate() {
131
- return [
132
- "## Kuma MCP",
133
- "",
134
- KUMA_CORE_INSTRUCTIONS
135
- ].join("\n");
136
- }
137
- function clineRulesTemplate() {
138
- return [
139
- "---",
140
- "description: Kuma MCP \u2014 .kuma/ is the single source of truth",
141
- "paths:",
142
- ' - "*"',
143
- "---",
144
- "",
145
- KUMA_CORE_INSTRUCTIONS,
146
- "",
147
- "\u{1F4D6} Read `.kuma/init.md` for detailed rules."
148
- ].join("\n");
149
- }
150
- function aiderTemplate() {
151
- return [
152
- "# Kuma MCP",
153
- "",
154
- KUMA_CORE_INSTRUCTIONS
155
- ].join("\n");
156
- }
157
- function opencodeAgentsMdTemplate() {
158
- const opencodeLines = [
159
- "Kuma MCP tools are installed (kuma_kuma_context, kuma_kuma_memory, kuma_kuma_safety).",
160
- '**Before coding, call `kuma_kuma_context({ action: "init" })`** to load project context.',
161
- "Project knowledge persists in `.kuma/memories/*.md` across sessions.",
162
- "",
163
- "\u26A0\uFE0F **MANDATORY WORKFLOW** \u2014 Follow in order every session (including research-only):",
164
- "",
165
- ' 1. `kuma_kuma_context({ action: "init" })` \u2014 Load context (START HERE)',
166
- ' 2. `kuma_kuma_safety({ action: "guard" })` \u2014 Safety check before work',
167
- ' 3. `kuma_kuma_context({ action: "research", scope: "<area>" })` \u2014 Research before editing',
168
- " 4. *(edit/read using native tools)*",
169
- ' 5. `kuma_kuma_memory({ action: "research_save", ... })` \u2014 After exploring area (creates search cache)',
170
- ' 6. `kuma_kuma_memory({ action: "gotcha" })` \u2014 \u{1F525} IMMEDIATELY when bug found (exponential value)',
171
- ' 7. `kuma_kuma_memory({ action: "arch_flow" })` \u2014 \u{1F525} IMMEDIATELY after each flow hop (exponential value)',
172
- ' 8. `kuma_kuma_memory({ action: "decision" })` \u2014 When choosing between options (preserves rationale)',
173
- ' 9. `kuma_kuma_safety({ action: "verify", ... })` \u2014 Run tests / confirm nothing broken',
174
- ' 10. `kuma_kuma_context({ action: "changes" })` \u2014 Review session activity',
175
- "",
176
- "\u{1F525} **Power Curve:** `arch_flow` + `gotcha` are EXPONENTIAL \u2014 each record saves 5-10 files next session.",
177
- " The more you record, the more overpowered the agent becomes. These are the highest-value actions.",
178
- "\u{1F7E2} **SKIP** recording function/class/component nodes \u2014 grep/glob is faster.",
179
- "\u{1F9E0} Knowledge graph is persistent \u2014 nodes/edges accumulate across sessions, getting richer over time.",
180
- "",
181
- "\u26A0\uFE0F **OpenCode platform note:** Tool names use `kuma_kuma_*` prefix",
182
- " (server name `kuma` + already-prefixed tool name `kuma_context`).",
183
- ""
184
- ].join("\n");
185
- return [
186
- "## Kuma MCP \u2014 OpenCode",
187
- "",
188
- opencodeLines,
189
- "\u{1F4D6} Rules: `.kuma/init.md`",
190
- "\u{1F9E0} Skill: `.agents/skills/kuma/SKILL.md`"
191
- ].join("\n");
192
- }
193
- function codexTemplate() {
194
- return [
195
- "## Kuma MCP",
196
- "",
197
- KUMA_CORE_INSTRUCTIONS,
198
- "",
199
- "\u{1F4D6} Rules: `.kuma/init.md`"
200
- ].join("\n");
201
- }
202
- function codexConfigTomlTemplate() {
203
- return [
204
- "# Generated by Kuma MCP - https://github.com/plumpslabs/kuma",
205
- "# Kuma MCP server config for Codex CLI",
206
- "",
207
- "[mcp_servers.kuma]",
208
- 'command = "npx"',
209
- 'args = ["-y", "@plumpslabs/kuma"]',
210
- ""
211
- ].join("\n");
212
- }
213
- function qwenTemplate() {
214
- return [
215
- "## Kuma MCP",
216
- "",
217
- KUMA_CORE_INSTRUCTIONS,
218
- "",
219
- "\u{1F4D6} Rules: `.kuma/init.md`"
220
- ].join("\n");
221
- }
222
- function qwenSettingsTemplate() {
223
- const config = {
224
- mcpServers: {
225
- kuma: {
226
- command: "npx",
227
- args: ["-y", "@plumpslabs/kuma"],
228
- env: {}
229
- }
230
- }
231
- };
232
- return JSON.stringify(config, null, 2) + "\n";
233
- }
234
- function kiroRulesTemplate() {
235
- return [
236
- "---",
237
- "name: kuma-mcp",
238
- "description: Kuma MCP \u2014 .kuma/ is the single source of truth",
239
- "inclusion: always",
240
- "---",
241
- "",
242
- KUMA_CORE_INSTRUCTIONS,
243
- "",
244
- "\u{1F4D6} Read `.kuma/init.md` for detailed rules."
245
- ].join("\n");
246
- }
247
- function openclawSkillTemplate() {
248
- return [
249
- "---",
250
- "name: kuma-mcp",
251
- "description: Kuma MCP \u2014 .kuma/ is the single source of truth",
252
- "---",
253
- "",
254
- KUMA_CORE_INSTRUCTIONS,
255
- "",
256
- "\u{1F4D6} Read `.kuma/init.md` for detailed rules.",
257
- "\u{1F9E0} Memories: `.kuma/memories/*.md`"
258
- ].join("\n");
259
- }
260
- function codewhaleTemplate() {
261
- return [
262
- "---",
263
- "name: kuma-mcp",
264
- "description: Kuma MCP \u2014 .kuma/ is the single source of truth",
265
- "---",
266
- "",
267
- KUMA_CORE_INSTRUCTIONS,
268
- "",
269
- "\u{1F4D6} Read `.kuma/init.md` for detailed rules.",
270
- "\u{1F9E0} Memories: `.kuma/memories/*.md`"
271
- ].join("\n");
272
- }
273
- function antigravitySkillTemplate() {
274
- return [
275
- "---",
276
- "name: kuma-mcp",
277
- "description: Kuma MCP \u2014 .kuma/ is the single source of truth",
278
- "---",
279
- "",
280
- KUMA_CORE_INSTRUCTIONS,
281
- "",
282
- "\u{1F4D6} Read `.kuma/init.md` for detailed rules.",
283
- "\u{1F9E0} Memories: `.kuma/memories/*.md`"
284
- ].join("\n");
285
- }
286
- function antigravityMcpConfigTemplate() {
287
- const config = {
288
- mcpServers: {
289
- kuma: {
290
- command: "npx",
291
- args: ["-y", "@plumpslabs/kuma"],
292
- env: {}
293
- }
294
- }
295
- };
296
- return JSON.stringify(config, null, 2) + "\n";
297
- }
298
- function generateInitMdContent() {
299
- return [
300
- "# Kuma Init \u2014 Mandatory Workflow",
301
- "",
302
- "_(Auto-generated by `kuma init` \u2014 edit this file directly to customize rules)_",
303
- "",
304
- "---",
305
- "",
306
- "> \u26A0\uFE0F **Platform Tool Names:**",
307
- '> \u2022 **OpenCode / Antigravity:** Use `kuma_kuma_*` prefix (e.g. `kuma_kuma_context({ action: "init" })`)',
308
- '> \u2022 **Other platforms (Claude, Cursor, Cline, etc.):** Use `kuma_*` directly (e.g. `kuma_context({ action: "init" })`)',
309
- "> \u2022 **Replace `kuma_` with `kuma_kuma_` in all examples below if you're on OpenCode.**",
310
- "",
311
- "---",
312
- "",
313
- "## \u26A0\uFE0F SESSION WORKFLOW \u2014 Follow Steps in Order",
314
- "",
315
- "### STEP 1: Init Session (ALWAYS \u2014 Start of Session)",
316
- "```",
317
- 'kuma_context({ action: "init" })',
318
- "```",
319
- "**When:** Every session start or project switch",
320
- "**Why:** Load project brief, restore session memory, populate knowledge graph",
321
- "",
322
- "### STEP 2: Safety Guard (ALWAYS \u2014 Before Work)",
323
- "```",
324
- 'kuma_safety({ action: "guard", guardGoal: "describe your intent" })',
325
- "```",
326
- "**When:** After STEP 1, before research or editing",
327
- "**Why:** Detect anti-patterns, code drift, runaway loops upfront",
328
- "",
329
- "### STEP 3: Research (MANDATORY \u2014 Before Editing Unfamiliar Code)",
330
- "```",
331
- 'kuma_context({ action: "research", scope: "<target area>" })',
332
- "```",
333
- "**When:** Every time you plan to edit code in an unfamiliar area",
334
- "**Why:** 5-step pipeline: cache load \u2192 staleness check \u2192 graph query \u2192 impact analysis \u2192 decision lookup",
335
- "",
336
- "> \u26D4 DO NOT EDIT FILES BEFORE STEP 3 \u2014 Unless trivial/minor change",
337
- "",
338
- "### STEP 4: EDIT/READ \u2014 Implement (Use Agent Native Tools)",
339
- "```",
340
- "# Use agent BUILT-IN tools to read, grep, edit, create files",
341
- "# Kuma does NOT manage files \u2014 that's your agent's job",
342
- "```",
343
- "",
344
- "> \u26A0\uFE0F **Research-only sessions included.** Workflow ini wajib meskipun session hanya membaca/riset tanpa code changes.",
345
- "",
346
- "> \u{1F9E0} **Graph Philosophy:** Record findings INLINE as you work, not just at the end. Every time you read a",
347
- "> file, grep a pattern, or trace a flow \u2014 call `research_save` immediately to persist what you learned.",
348
- "> The knowledge graph accumulates across sessions. The more you use it, the richer it becomes.",
349
- "",
350
- "> \u{1F52C} **Scanner vs Inline Recording:**",
351
- "> \u2022 Scanner = cold start only. Auto-detects structure in TS/JS/TSX/JSX files during research step 3.",
352
- "> \u2022 Inline Recording = primary method. You (the agent) record findings as you read/grep/edit.",
353
- "> \u2022 Non-TS/JS projects (Go, Ruby, Python, Rust, PHP) rely ENTIRELY on inline recording.",
354
- "",
355
- "**AUTO-RECORDED (cold start scanner \u2014 TS/JS only):**",
356
- "- Files, Functions, Classes \u2192 scanned during research step 3",
357
- "- Imports, Calls, Extends \u2192 scanned edges",
358
- "- Components, Routes \u2192 scanned when patterns match",
359
- "",
360
- "\u{1F534} **MUST RECORD \u2014 High Impact (use MCP):**",
361
- "- `arch_flow` \u2014 IMMEDIATELY after each flow hop. Saves reading 5-10 files next session.",
362
- "- `gotcha` \u2014 IMMEDIATELY when bug/quirk found. No re-research needed.",
363
- "- `decision` \u2014 IMMEDIATELY when choosing. Preserves rationale context.",
364
- "- `research_save` \u2014 After exploring area. Creates searchable cache + graph file node.",
365
- "",
366
- "\u{1F7E2} **SKIP \u2014 Low Impact (agent can grep faster):**",
367
- "- Function/class nodes \u2192 grep `funcName(` / `class ClassName`",
368
- "- Component nodes \u2192 glob `**/*ComponentName*`",
369
- "- Import edges \u2192 check imports directly",
370
- "- Route nodes \u2192 check router file directly",
371
- "- Visual graph \u2192 for humans, not AI agents",
372
- "",
373
- "**RECORD INLINE \u2014 Focus on high-impact actions:**",
374
- "- Finished tracing a flow? \u2192 `arch_flow` IMMEDIATELY (saves reading 5-10 files next session)",
375
- "- Found a bug/quirk? \u2192 `gotcha` IMMEDIATELY (no re-research needed)",
376
- "- Chose between options? \u2192 `decision` IMMEDIATELY (preserves rationale)",
377
- "- Explored a new area? \u2192 `research_save` (creates searchable cache)",
378
- "",
379
- "**SKIP recording these \u2014 grep/glob is faster:**",
380
- "- Function/class nodes \u2192 just `grep funcName(` or `grep class ClassName`",
381
- "- Component/route nodes \u2192 glob directly",
382
- "- Import edges \u2192 read import statements",
383
- "- Visual graph \u2192 for humans, not AI",
384
- "",
385
- "### STEP 5: Save Research (RECORD INLINE \u2014 After Every Read/Grep)",
386
- "```",
387
- 'kuma_memory({ action: "research_save", scope: "<file or area>", confidence: 0.8 })',
388
- "```",
389
- "**When:** After EVERY read/grep that discovers new files, functions, imports, or patterns. Don't wait \u2014 record inline!",
390
- "**Why:** Persist findings into knowledge graph + research cache. Graph grows richer across sessions.",
391
- "",
392
- "### STEP 6: Record Gotchas (RECORD INLINE \u2014 When Bug Found)",
393
- "```",
394
- 'kuma_memory({ action: "gotcha", filePath: "<file>", description: "...", severity: "medium" })',
395
- "```",
396
- "**When:** IMMEDIATELY when you discover bugs, quirks, unexpected behavior, or workarounds. Record INLINE, don't save for later.",
397
- "**Why:** Prevents future agents from hitting the same issues. Every bug = a gotcha. Skip now = lost forever.",
398
- "",
399
- "### STEP 7: Record Arch Flow (RECORD INLINE \u2014 When Tracing Flow)",
400
- "```",
401
- 'kuma_memory({ action: "arch_flow", content: "..." })',
402
- "```",
403
- "**When:** IMMEDIATELY after tracing EACH hop in a data/control flow. Record INLINE, then continue tracing the next hop.",
404
- "**Why:** Architecture knowledge dissipates fast. Record each hop before moving to the next file/task.",
405
- "",
406
- "### STEP 8: Record Decision (RECORD INLINE \u2014 When Choosing)",
407
- "```",
408
- 'kuma_memory({ action: "decision", decisionAction: "record", title: "...", outcome: "..." })',
409
- "```",
410
- "**When:** IMMEDIATELY when you choose between 2+ options, uncover an architecture pattern, or identify a root cause.",
411
- "**Why:** Saves ADR (Architecture Decision Record). Bukan cuma code changes \u2014 temuan, tradeoffs, root causes juga.",
412
- "",
413
- "### STEP 9: Verify (MANDATORY \u2014 After Research/Editing)",
414
- "```",
415
- 'kuma_safety({ action: "verify", scope: "<area or file>" })',
416
- "```",
417
- "**When:** After research/edits are done, before switching tasks. Even for research-only \u2014 confirms nothing is broken.",
418
- '**Why:** Auto-run scoped tests + AST code validation. If no test framework, at minimum report "No tests to run".',
419
- "",
420
- "### STEP 10: Check Changes (MANDATORY \u2014 End of Session)",
421
- "```",
422
- 'kuma_context({ action: "changes" })',
423
- "```",
424
- "**When:** End of session or before git commit. Even 0 changes = valid result to confirm.",
425
- "**Why:** View session log of all modifications + tool calls made in this session.",
426
- "",
427
- "---",
428
- "",
429
- "## \u{1F4CB} Tool Reference",
430
- "",
431
- "### \u{1F9E0} kuma_context \u2014 Context & Research",
432
- "",
433
- "| Action | Description | When to Call |",
434
- "|--------|-------------|--------------|",
435
- "| `init` | Load project brief, restore session | STEP 1 \u2014 Every session |",
436
- "| `research` | 5-step research pipeline | STEP 3 \u2014 Before edits |",
437
- "| `impact` | Analyze change effects on symbol | After research, before design |",
438
- "| `navigate` | Trace code flow | When need to understand call flow |",
439
- "| `changes` | View session change log | STEP 10 \u2014 End of session |",
440
- "| `health` | Project health score 0-100 | Periodic check |",
441
- "| `digest` | Ultra-compact project briefing | Session start (alt to init) |",
442
- "| `drift` | Detect memory staleness | When suspecting stale context |",
443
- "",
444
- "### \u{1F4DD} kuma_memory \u2014 Decision & Knowledge",
445
- "",
446
- "| Action | Description | When to Call |",
447
- "|--------|-------------|--------------|",
448
- "| `research_save` | Save research results | STEP 5 \u2014 IMMEDIATELY after every read/grep (inline) |",
449
- "| `gotcha` | Record bugs/quirks/workarounds | STEP 6 \u2014 IMMEDIATELY when bug found (inline) |",
450
- "| `arch_flow` | Document architecture flow | STEP 7 \u2014 IMMEDIATELY after each flow hop (inline) |",
451
- "| `decision` | ADR-style decision record | STEP 8 \u2014 IMMEDIATELY when choosing (inline) |",
452
- "| `mine` | Mine decisions from git log | When need historical context |",
453
- "| `session` | Session summary | End of session |",
454
- "| `heal` | Self-heal knowledge graph | When graph has errors |",
455
- "| `search` | Search memories + graph | Find stored information |",
456
- "| `todo` | Persistent todo CRUD | When managing tasks |",
457
- "| `context` | Inject context notes | Additional notes when needed |",
458
- "| `domain_rules` | Layer 1: business rules | Record business rules when discovered |",
459
- "| `add_node` | Create structural nodes (low impact \u2014 grep is faster) | Rarely needed; only for visualize debugging |",
460
- "| `layers` | Show all 3 layers summary | Overview memory layers |",
461
- "",
462
- "### \u{1F6E1}\uFE0F kuma_safety \u2014 Safety & Policy",
463
- "",
464
- "| Action | Description | When to Call |",
465
- "|--------|-------------|--------------|",
466
- "| `guard` | Anti-pattern, drift, loop | STEP 2 \u2014 Before work |",
467
- "| `verify` | Auto-run scoped tests + validation | STEP 9 \u2014 After research/edits |",
468
- "| `check` | Pre-execution safety check | Before risky operations |",
469
- "| `audit` | Query safety audit trail | Security investigation |",
470
- "| `lock` | Multi-agent file lock | Multi-agent collaboration |",
471
- "| `health` | Safety score 0-100 | Periodic check |",
472
- "| `policy` | Policy-as-Code engine | Evaluate command/file paths |",
473
- "| `ast` | AST-based code validation | Code correctness checks |",
474
- "| `checkpoint` | Create atomic snapshot | Before major refactors |",
475
- "| `contract` | Pre/post-condition check | Contract verification |",
476
- "",
477
- "---",
478
- "",
479
- "## \u{1F4CA} Knowledge Graph \u2014 Node Types & Shapes",
480
- "",
481
- "Kuma's knowledge graph visualizes your project structure. Each node type has a unique shape:",
482
- "",
483
- "| Shape | Node Type | Description | Auto/Manual |",
484
- "|-------|-----------|-------------|-------------|",
485
- "| \u25A2 `box` | function | Functions (named/arrow) | AUTO by scanner |",
486
- "| \u2B21 `hexagon` | class | Classes (TS/JS) | AUTO by scanner |",
487
- "| \u25CB `ellipse` | module | Directory modules | AUTO by scanner |",
488
- "| \u25C7 `diamond` | component | React/Vue components | AUTO by scanner |",
489
- "| \u25A3 `square` | file | Source files | AUTO by scanner |",
490
- "| \u25B2 `triangle` | route | API routes | AUTO by scanner |",
491
- "| \u2B52 `star` | test | Test files/describes | AUTO by scanner |",
492
- "| \u{1F4C4} `note` | context | Manual context notes | MANUAL \u2014 kuma_memory context |",
493
- "| \u{1F3DB}\uFE0F `feature_domain` | FeatureDomain | High-level feature domain anchor | MANUAL \u2014 kuma_memory arch_flow (domain:) |",
494
- "| \u{1F517} `cross_service_link` | Workflow hop | Cross-service/inter-file flow step | MANUAL \u2014 kuma_memory arch_flow (hops:) |",
495
- "| \u{1F3F7}\uFE0F `tag` | domain_rule | Business rules (Layer 1) | MANUAL \u2014 kuma_memory domain_rules |",
496
- "| \u{1F500} `flow` | arch_flow | Architecture flows (Layer 2) | MANUAL \u2014 kuma_memory arch_flow |",
497
- "| \u26A0\uFE0F `warning` | gotcha | Known gotchas (Layer 3) | MANUAL \u2014 kuma_memory gotcha |",
498
- "| \u{1F4CC} `milestone` | decision | Architecture decisions | MANUAL \u2014 kuma_memory decision |",
499
- "| \u2705 `checklist` | todo | Persistent todos | MANUAL \u2014 kuma_memory todo |",
500
- "",
501
- "**Edges (connections between nodes):**",
502
- "- `imports` \u2014 file imports another (AUTO)",
503
- "- `calls` \u2014 function calls another (AUTO)",
504
- "- `defines` \u2014 file defines function/class (AUTO)",
505
- "- `depends_on` \u2014 logical dependency (AUTO + MANUAL)",
506
- "- `extends` \u2014 class extends class (AUTO)",
507
- "- `contains` \u2014 file contains function (AUTO)",
508
- "- `composes` \u2014 component contains sub-component (AUTO)",
509
- "- `references` \u2014 node references context note (MANUAL)",
510
- "",
511
- "---",
512
- "",
513
- "## \u{1F4CC} Workflow Summary",
514
- "",
515
- "```",
516
- "EVERY SESSION (Mandatory \u2014 including research-only):",
517
- " 1. kuma_context \u2192 init \u2014 Load project context",
518
- " 2. kuma_safety \u2192 guard \u2014 Safety check",
519
- " 3. kuma_context \u2192 research \u2014 Research target area",
520
- " --- EDIT/READ (use native tools) ---",
521
- " 5. kuma_memory \u2192 research_save \u2014 After exploring area (creates search cache)",
522
- " 6. kuma_memory \u2192 gotcha \u2014 \u{1F525} IMMEDIATELY when bug found (exponential)",
523
- " 7. kuma_memory \u2192 arch_flow \u2014 \u{1F525} IMMEDIATELY after each flow hop (exponential)",
524
- " 8. kuma_memory \u2192 decision \u2014 When choosing (preserves rationale)",
525
- " 9. kuma_safety \u2192 verify \u2014 Run tests / confirm nothing broken",
526
- " 10. kuma_context \u2192 changes \u2014 Review session activity",
527
- "",
528
- "\u{1F525} `arch_flow` + `gotcha` are EXPONENTIAL \u2014 each record saves 5-10 files next session.",
529
- "\u{1F7E2} SKIP recording function/class/component nodes \u2014 grep/glob is faster.",
530
- "\u{1F9E0} Graph is persistent \u2014 nodes/edges accumulate across sessions.",
531
- "",
532
- "ON DISCOVERY (When needed):",
533
- " kuma_memory \u2192 domain_rules \u2014 Business rules (Layer 1)",
534
- " kuma_memory \u2192 context \u2014 Additional notes",
535
- " kuma_memory \u2192 todo \u2014 Task management",
536
- " kuma_memory \u2192 mine \u2014 Historical context",
537
- " kuma_memory \u2192 add_node \u2014 Manual function/class/component node (for visualize)",
538
- "```",
539
- "",
540
- "## \u{1F9E0} How the Scanner Works",
541
- "",
542
- "Kuma's code scanner (`kumaCodeScanner.ts`) uses **lightweight regex-based pattern matching**",
543
- "for **cold start** \u2014 giving new agents basic project structure on first session.",
544
- "It is NOT a full AST parser (no Babel/TypeScript compiler dependency).",
545
- "",
546
- "**Scope:** TS/JS/TSX/JSX only. Non-TypeScript projects (Go, Ruby, Python, Rust, PHP, etc.)",
547
- "rely entirely on **AI inline recording** \u2014 the agent records what it discovers as it works.",
548
- "",
549
- "**What auto-scanner detects (line-by-line regex, TS/JS only):**",
550
- "- `function` declarations (named + async + generator)",
551
- "- Arrow function assignments (`const foo = (...) => ...`)",
552
- "- Typed arrow functions (`const foo: Type = (...) => ...`)",
553
- "- Class declarations (includes extends/implements)",
554
- "- React/Vue components (functions returning JSX)",
555
- "- API route handlers (Express + Hono patterns)",
556
- "- Import statements (local file imports only)",
557
- "- Function calls cross-file (`calls` edges)",
558
- "- Test files (`.test.`, `.spec.`, `__tests__/`)",
559
- "",
560
- "**Known limitations:**",
561
- "- Regex-based: can miss multi-line constructs or non-standard patterns",
562
- "- Complex generics or deeply nested syntax may not match",
563
- "- TypeScript advanced types may be partially parsed",
564
- "- Scanner runs during `kuma_context research` step 3 (max 200 files)",
565
- "- If scanner returns 0 structural nodes, the regex patterns didn't match your code style",
566
- "",
567
- "**Key principle: Scanner = cold start, Inline Recording = primary.**",
568
- "The scanner populates initial graph structure. Every subsequent session, the agent's",
569
- "inline recording (research_save, gotcha, arch_flow, decision) enriches the graph further.",
570
- "The more you use Kuma, the richer the graph becomes \u2014 persistent across sessions.",
571
- "",
572
- "---",
573
- "",
574
- "## \u{1F4BE} How to Retrieve Past Research \u2014 research_save \u2192 search",
575
- "",
576
- "Kuma stores knowledge in two places. The primary retrieval method for AI agents",
577
- "is **`search`**, not `visualize`. Visualize is for human debugging, not agent consumption.",
578
- "",
579
- "**Flow: research_save \u2192 search (for agents)**",
580
- '- Save: `kuma_memory({ action: "research_save", scope: "<file or area>", confidence: 0.8 })`',
581
- '- Retrieve: `kuma_memory({ action: "search", query: "<term>" })`',
582
- '- Auto-load: `kuma_context({ action: "research", scope: "<area>" })`',
583
- '- List cache: `kuma_context({ action: "researches" })`',
584
- "",
585
- "**Key design:** `research_save` now creates BOTH research cache entries AND",
586
- "knowledge graph nodes (file + research scope). This means `search` finds",
587
- "past research even if the graph scanner didn't detect your code style.",
588
- "",
589
- "**Quick retrieval tips:**",
590
- '- `kuma_memory({ action: "search", query: "<term>" })` \u2014 **primary method**. Finds past research + graph nodes + codebase',
591
- '- `kuma_context({ action: "research", scope: "<area>" })` \u2014 deep 5-step research, auto-loads past cache',
592
- '- `kuma_context({ action: "init" })` \u2014 shows graph stats + recent research + health score',
593
- '- `kuma_context({ action: "drift" })` \u2014 check if memories are stale vs actual code',
594
- '- `kuma_context({ action: "changes" })` \u2014 view session activity log',
595
- '- `kuma_context({ action: "visualize" })` \u2014 (human debugging) Mermaid diagram of the graph',
596
- "",
597
- "---",
598
- "",
599
- "## \u{1F52C} How Verification Works",
600
- "",
601
- '`kuma_safety({ action: "verify", scope: "<area>" })` \u2014 STEP 9',
602
- "",
603
- "**Auto-detection logic:**",
604
- "1. Checks `package.json` \u2192 `scripts.test` \u2192 uses npm/pnpm/yarn test",
605
- "2. If no test script, checks for Makefile with `test:` target",
606
- "3. Falls back to Python (pytest), Rust (cargo test), Go (go test)",
607
- "4. Last resort: `npx tsc --noEmit` (TypeScript syntax check) or `node -c`",
608
- "5. If nothing found: returns informative message instead of failing",
609
- "",
610
- "**Important:** Verification is NEVER auto-triggered. You must call it explicitly.",
611
- "The 5-layer safety guard (concurrency lock, rate limiting, staleness cache,",
612
- "runaway detection, hard timeout) prevents resource exhaustion.",
613
- "",
614
- "---",
615
- "",
616
- "## \u{1F6AB} What Kuma Does NOT Do (Use Agent Native Tools)",
617
- "",
618
- "| Function | Correct Tool |",
619
- "|----------|-------------|",
620
- "| Edit files | Agent native edit tools |",
621
- "| Search code | Agent native grep/search |",
622
- "| Run commands | Agent native terminal |",
623
- "| Create files | Agent native file creation |",
624
- "| Git operations | Agent native git tools |",
625
- "| Lint/test | Agent native run commands |",
626
- "",
627
- "---",
628
- "_Generated by Kuma MCP - https://github.com/plumpslabs/kuma_"
629
- ].join("\n");
630
- }
631
- var TEMPLATES = {
632
- claude: claudeTemplate,
633
- cursor: cursorRulesTemplate,
634
- windsurf: windsurfRulesTemplate,
635
- copilot: copilotTemplate,
636
- cline: clineRulesTemplate,
637
- aider: aiderTemplate,
638
- antigravity: antigravitySkillTemplate,
639
- opencode: opencodeAgentsMdTemplate,
640
- codex: codexTemplate,
641
- qwen: qwenTemplate,
642
- kiro: kiroRulesTemplate,
643
- openclaw: openclawSkillTemplate,
644
- codewhale: codewhaleTemplate
645
- };
646
- var APPEND_SEPARATOR = "\n\n---\n_Generated by Kuma MCP - https://github.com/plumpslabs/kuma_\n\n";
647
- function handleOpencodeSecondary(root, results) {
648
- const skillPath = path.resolve(root, ".agents", "skills", "kuma", "SKILL.md");
649
- if (results.some((r) => r.filePath === ".agents/skills/kuma/SKILL.md")) return;
650
- try {
651
- const dir = path.dirname(skillPath);
652
- const content = [
653
- "---",
654
- "name: kuma-mcp",
655
- "description: Kuma MCP \u2014 safety toolkit for AI coding agents. Research, memory, and safety guard.",
656
- "---",
657
- "",
658
- "Kuma MCP tools are installed (kuma_kuma_context, kuma_kuma_memory, kuma_kuma_safety).",
659
- '**Before coding, call `kuma_kuma_context({ action: "init" })`** to load project context and session memory.',
660
- "Project knowledge persists in `.kuma/memories/*.md` across sessions.",
661
- "",
662
- "\u26A0\uFE0F **MANDATORY WORKFLOW** \u2014 Follow in order every session (including research-only):",
663
- "",
664
- ' 1. `kuma_kuma_context({ action: "init" })` \u2014 Load context (START HERE)',
665
- ' 2. `kuma_kuma_safety({ action: "guard" })` \u2014 Safety check before work',
666
- ' 3. `kuma_kuma_context({ action: "research", scope: "<area>" })` \u2014 Research before editing',
667
- " 4. *(edit/read using native tools)*",
668
- ' 5. `kuma_kuma_memory({ action: "research_save", ... })` \u2014 After exploring area (creates search cache)',
669
- ' 6. `kuma_kuma_memory({ action: "gotcha" })` \u2014 \u{1F525} IMMEDIATELY when bug found (exponential)',
670
- ' 7. `kuma_kuma_memory({ action: "arch_flow" })` \u2014 \u{1F525} IMMEDIATELY after each flow hop (exponential)',
671
- ' 8. `kuma_kuma_memory({ action: "decision" })` \u2014 When choosing (preserves rationale)',
672
- ' 9. `kuma_kuma_safety({ action: "verify", ... })` \u2014 Run tests / confirm nothing broken',
673
- ' 10. `kuma_kuma_context({ action: "changes" })` \u2014 Review session activity',
674
- "",
675
- "\u{1F525} `arch_flow` + `gotcha` = EXPONENTIAL value. Each record saves 5-10 files next session.",
676
- "\u{1F7E2} SKIP recording function/class/component nodes \u2014 grep/glob is faster.",
677
- "\u{1F9E0} Graph is persistent \u2014 nodes/edges accumulate across sessions.",
678
- "",
679
- "\u26A0\uFE0F **OpenCode platform note:** Tool names are prefixed with `kuma_kuma_*`",
680
- " (server name `kuma` + already-prefixed tool name `kuma_context`).",
681
- "",
682
- "\u{1F4D6} Full rules: `.kuma/init.md`"
683
- ].join("\n");
684
- if (fs.existsSync(skillPath)) {
685
- const existing = fs.readFileSync(skillPath, "utf-8");
686
- if (existing.includes("kuma-mcp")) {
687
- results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "skipped" });
688
- return;
689
- }
690
- const newContent = existing.trimEnd() + "\n\n---\n\n" + content;
691
- fs.writeFileSync(skillPath, newContent, "utf-8");
692
- results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "appended" });
693
- } else {
694
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
695
- fs.writeFileSync(skillPath, content, "utf-8");
696
- results.push({ type: "opencode", filePath: ".agents/skills/kuma/SKILL.md", action: "created" });
697
- }
698
- } catch (err) {
699
- results.push({
700
- type: "opencode",
701
- filePath: ".agents/skills/kuma/SKILL.md",
702
- action: "error",
703
- error: err instanceof Error ? err.message : String(err)
704
- });
705
- }
706
- }
707
- function handleCodexSecondary(root, results) {
708
- const tomlPath = path.resolve(root, ".codex/config.toml");
709
- if (results.some((r) => r.filePath === ".codex/config.toml")) return;
710
- try {
711
- const dir = path.dirname(tomlPath);
712
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
713
- if (fs.existsSync(tomlPath)) {
714
- const existingContent = fs.readFileSync(tomlPath, "utf-8");
715
- if (existingContent.includes("kuma")) {
716
- results.push({ type: "codex", filePath: ".codex/config.toml", action: "skipped" });
717
- return;
718
- }
719
- fs.writeFileSync(tomlPath, existingContent.trimEnd() + "\n\n" + codexConfigTomlTemplate(), "utf-8");
720
- results.push({ type: "codex", filePath: ".codex/config.toml", action: "appended" });
721
- } else {
722
- fs.writeFileSync(tomlPath, codexConfigTomlTemplate(), "utf-8");
723
- results.push({ type: "codex", filePath: ".codex/config.toml", action: "created" });
724
- }
725
- } catch (err) {
726
- results.push({
727
- type: "codex",
728
- filePath: ".codex/config.toml",
729
- action: "error",
730
- error: err instanceof Error ? err.message : String(err)
731
- });
732
- }
733
- }
734
- function handleQwenSecondary(root, results) {
735
- const settingsPath = path.resolve(root, "settings.json");
736
- if (results.some((r) => r.filePath === "settings.json")) return;
737
- try {
738
- if (fs.existsSync(settingsPath)) {
739
- const existingContent = fs.readFileSync(settingsPath, "utf-8");
740
- if (existingContent.includes("kuma")) {
741
- if (!existingContent.includes("_Generated by Kuma MCP_")) {
742
- try {
743
- const parsed = JSON.parse(existingContent);
744
- parsed.mcpServers = parsed.mcpServers || {};
745
- if (!parsed.mcpServers.kuma) {
746
- parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
747
- fs.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
748
- results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
749
- return;
750
- }
751
- } catch {
752
- }
753
- }
754
- results.push({ type: "qwen", filePath: "settings.json", action: "skipped" });
755
- return;
756
- }
757
- try {
758
- const parsed = JSON.parse(existingContent);
759
- parsed.mcpServers = parsed.mcpServers || {};
760
- if (!parsed.mcpServers.kuma) {
761
- parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
762
- fs.writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
763
- results.push({ type: "qwen", filePath: "settings.json", action: "appended" });
764
- }
765
- } catch {
766
- }
767
- } else {
768
- fs.writeFileSync(settingsPath, qwenSettingsTemplate(), "utf-8");
769
- results.push({ type: "qwen", filePath: "settings.json", action: "created" });
770
- }
771
- } catch (err) {
772
- results.push({
773
- type: "qwen",
774
- filePath: "settings.json",
775
- action: "error",
776
- error: err instanceof Error ? err.message : String(err)
777
- });
778
- }
779
- }
780
- var AGENTS_MD_TYPES = ["opencode", "codex", "qwen", "copilot"];
781
- function getCombinedAgentsMd(selectedTypes) {
782
- const lines = [
783
- "# Kuma MCP \u2014 Combined Agent Instructions",
784
- "",
785
- "This file contains behavioral rules for AI coding agents. Unused sections can be safely removed.",
786
- "",
787
- "---",
788
- "",
789
- '> \u26A0\uFE0F **WARNING:** Agent often skip steps due to "research-only" bias. Do NOT skip.',
790
- "> Follow the full 10-step workflow even for read-only investigations.",
791
- "",
792
- "## \u26A0\uFE0F MANDATORY WORKFLOW",
793
- "",
794
- "Follow these steps in order every session (including research-only):",
795
- "",
796
- ' 1. `[kuma_]context({ action: "init" })` \u2014 Load project context (START HERE)',
797
- ' 2. `[kuma_]safety({ action: "guard" })` \u2014 Safety check before editing',
798
- ' 3. `[kuma_]context({ action: "research", scope: "<area>" })` \u2014 Research before editing',
799
- " 4. *(edit/read using native tools)*",
800
- ' 5. `[kuma_]memory({ action: "research_save", ... })` \u2014 After exploring area (creates search cache)',
801
- ' 6. `[kuma_]memory({ action: "gotcha" })` \u2014 \u{1F525} IMMEDIATELY when bug found (exponential)',
802
- ' 7. `[kuma_]memory({ action: "arch_flow" })` \u2014 \u{1F525} IMMEDIATELY after each flow hop (exponential)',
803
- ' 8. `[kuma_]memory({ action: "decision" })` \u2014 When choosing (preserves rationale)',
804
- ' 9. `[kuma_]safety({ action: "verify", ... })` \u2014 Run tests / confirm nothing broken',
805
- ' 10. `[kuma_]context({ action: "changes" })` \u2014 Review session activity',
806
- "",
807
- "\u{1F525} `arch_flow` + `gotcha` = EXPONENTIAL value. Each record saves 5-10 files next session.",
808
- "\u{1F7E2} SKIP recording function/class/component nodes \u2014 grep/glob is faster.",
809
- "\u{1F9E0} Graph is persistent \u2014 nodes/edges accumulate across sessions.",
810
- "",
811
- "\u26D4 Do NOT skip steps 5-10 after research \u2014 even if no code was changed.",
812
- "",
813
- "Replace `[kuma_]` with the correct prefix for your platform (see below).",
814
- "",
815
- "---",
816
- ""
817
- ];
818
- if (selectedTypes.has("opencode")) {
819
- lines.push(
820
- "### OpenCode",
821
- "",
822
- "OpenCode adds the MCP server name (`kuma`) as a prefix to tool names.",
823
- "The server-registered names (kuma_context, kuma_memory, kuma_safety) become:",
824
- "",
825
- "| Action | Call this |",
826
- "|--------|-----------|",
827
- '| Init | `kuma_kuma_context({ action: "init" })` |',
828
- '| Guard | `kuma_kuma_safety({ action: "guard" })` |',
829
- '| Research | `kuma_kuma_context({ action: "research", scope: "..." })` |',
830
- '| Save | `kuma_kuma_memory({ action: "research_save", ... })` |',
831
- '| Verify | `kuma_kuma_safety({ action: "verify", ... })` |',
832
- '| Changes | `kuma_kuma_context({ action: "changes" })` |',
833
- "",
834
- "\u{1F4D6} Skill: `.agents/skills/kuma/SKILL.md`",
835
- "",
836
- "---",
837
- ""
838
- );
839
- }
840
- const nonOpenCode = Array.from(selectedTypes).filter((t) => t !== "opencode");
841
- if (nonOpenCode.length > 0) {
842
- lines.push(
843
- "### Other Platforms",
844
- "",
845
- ...nonOpenCode.map((t) => `- ${CONFIG_LABELS[t]}`),
846
- "",
847
- "Tool names are registered directly \u2014 no server prefix added:",
848
- "",
849
- "| Action | Call this |",
850
- "|--------|-----------|",
851
- '| Init | `kuma_context({ action: "init" })` |',
852
- '| Guard | `kuma_safety({ action: "guard" })` |',
853
- '| Research | `kuma_context({ action: "research", scope: "..." })` |',
854
- '| Save | `kuma_memory({ action: "research_save", ... })` |',
855
- '| Verify | `kuma_safety({ action: "verify", ... })` |',
856
- '| Changes | `kuma_context({ action: "changes" })` |',
857
- "",
858
- "---",
859
- ""
860
- );
861
- }
862
- lines.push(
863
- "\u{1F4D6} Rules: `.kuma/init.md`",
864
- "\u{1F9E0} Memories: `.kuma/memories/*.md`",
865
- "",
866
- "_Generated by Kuma MCP - https://github.com/plumpslabs/kuma_"
867
- );
868
- return lines.join("\n");
869
- }
870
- function handleAntigravityMcpConfig(root, results) {
871
- const mcpPath = path.resolve(root, ".agents/mcp_config.json");
872
- if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
873
- try {
874
- const mcpDir = path.dirname(mcpPath);
875
- if (fs.existsSync(mcpPath)) {
876
- const existingContent = fs.readFileSync(mcpPath, "utf-8");
877
- if (existingContent.includes("kuma")) {
878
- if (!existingContent.includes("_Generated by Kuma MCP_")) {
879
- const trimmed = existingContent.trimEnd();
880
- if (trimmed.endsWith("}")) {
881
- const updated = trimmed.slice(0, -1).trimEnd() + ',\n "_kuma_note": "Kuma MCP - Generated by kuma init"\n}\n';
882
- fs.writeFileSync(mcpPath, updated, "utf-8");
883
- results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "appended" });
884
- }
885
- }
886
- return;
887
- }
888
- const parsed = JSON.parse(existingContent);
889
- parsed.mcpServers = parsed.mcpServers || {};
890
- parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
891
- fs.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
892
- results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "appended" });
893
- } else {
894
- if (!fs.existsSync(mcpDir)) fs.mkdirSync(mcpDir, { recursive: true });
895
- fs.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
896
- results.push({ type: "antigravity", filePath: ".agents/mcp_config.json", action: "created" });
897
- }
898
- } catch (err) {
899
- results.push({
900
- type: "antigravity",
901
- filePath: ".agents/mcp_config.json",
902
- action: "error",
903
- error: err instanceof Error ? err.message : String(err)
904
- });
905
- }
906
- }
907
- function handleAiderSecondary(root, results) {
908
- const ymlPath = path.resolve(root, ".aider.conf.yml");
909
- if (results.some((r) => r.filePath === ".aider.conf.yml")) return;
910
- try {
911
- const conventionsRef = "read: CONVENTIONS.md";
912
- if (fs.existsSync(ymlPath)) {
913
- const existingContent = fs.readFileSync(ymlPath, "utf-8");
914
- if (existingContent.includes("CONVENTIONS.md") || existingContent.includes("kuma")) {
915
- results.push({ type: "aider", filePath: ".aider.conf.yml", action: "skipped" });
916
- return;
917
- }
918
- const newContent = existingContent.trimEnd() + "\n\n# Kuma MCP conventions\n" + conventionsRef + "\n";
919
- fs.writeFileSync(ymlPath, newContent, "utf-8");
920
- results.push({ type: "aider", filePath: ".aider.conf.yml", action: "appended" });
921
- } else {
922
- const content = [
923
- "# Generated by Kuma MCP - https://github.com/plumpslabs/kuma",
924
- "# Aider will read CONVENTIONS.md for coding conventions",
925
- "",
926
- conventionsRef,
927
- ""
928
- ].join("\n");
929
- fs.writeFileSync(ymlPath, content, "utf-8");
930
- results.push({ type: "aider", filePath: ".aider.conf.yml", action: "created" });
931
- }
932
- } catch (err) {
933
- results.push({
934
- type: "aider",
935
- filePath: ".aider.conf.yml",
936
- action: "error",
937
- error: err instanceof Error ? err.message : String(err)
938
- });
939
- }
940
- }
941
- function handleCopilotSecondary(root, results) {
942
- const skillPath = path.resolve(root, ".github/skills/kuma/SKILL.md");
943
- if (results.some((r) => r.filePath === ".github/skills/kuma/SKILL.md")) return;
944
- try {
945
- const dir = path.dirname(skillPath);
946
- const content = [
947
- "---",
948
- "name: kuma-mcp",
949
- "description: Kuma MCP \u2014 .kuma/ is the single source of truth",
950
- "---",
951
- "",
952
- KUMA_CORE_INSTRUCTIONS,
953
- "",
954
- "\u{1F4D6} Read `.kuma/init.md` for detailed rules."
955
- ].join("\n");
956
- if (fs.existsSync(skillPath)) {
957
- const existingContent = fs.readFileSync(skillPath, "utf-8");
958
- if (existingContent.includes("kuma")) {
959
- results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "skipped" });
960
- return;
961
- }
962
- fs.writeFileSync(skillPath, existingContent.trimEnd() + "\n\n" + content, "utf-8");
963
- results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "appended" });
964
- } else {
965
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
966
- fs.writeFileSync(skillPath, content, "utf-8");
967
- results.push({ type: "copilot", filePath: ".github/skills/kuma/SKILL.md", action: "created" });
968
- }
969
- } catch (err) {
970
- results.push({
971
- type: "copilot",
972
- filePath: ".github/skills/kuma/SKILL.md",
973
- action: "error",
974
- error: err instanceof Error ? err.message : String(err)
975
- });
976
- }
977
- }
978
- function handleOpenclawSecondary(root, results) {
979
- const mcpPath = path.resolve(root, ".agents/mcp_config.json");
980
- if (results.some((r) => r.filePath === ".agents/mcp_config.json")) return;
981
- try {
982
- const dir = path.dirname(mcpPath);
983
- if (fs.existsSync(mcpPath)) {
984
- const existingContent = fs.readFileSync(mcpPath, "utf-8");
985
- if (existingContent.includes("kuma")) return;
986
- const parsed = JSON.parse(existingContent);
987
- parsed.mcpServers = parsed.mcpServers || {};
988
- parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
989
- fs.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
990
- results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "appended" });
991
- } else {
992
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
993
- fs.writeFileSync(mcpPath, antigravityMcpConfigTemplate(), "utf-8");
994
- results.push({ type: "openclaw", filePath: ".agents/mcp_config.json", action: "created" });
995
- }
996
- } catch (err) {
997
- results.push({
998
- type: "openclaw",
999
- filePath: ".agents/mcp_config.json",
1000
- action: "error",
1001
- error: err instanceof Error ? err.message : String(err)
1002
- });
1003
- }
1004
- }
1005
- function handleQuickrefGeneration(root, results) {
1006
- const quickrefPath = path.resolve(root, ".kuma/quickref.md");
1007
- const content = [
1008
- "# Kuma Quick Reference",
1009
- "",
1010
- "_(Auto-generated by `kuma init` \u2014 simplified workflow cheat sheet)_",
1011
- "",
1012
- "## Every Session (Mandatory \u2014 including research-only)",
1013
- "",
1014
- ' 1. `kuma_context({ action: "init" })` \u2014 Load context',
1015
- ' 2. `kuma_safety({ action: "guard" })` \u2014 Safety check',
1016
- ' 3. `kuma_context({ action: "research", scope: "<area>" })` \u2014 Research',
1017
- " 4. *(edit/read using native tools)*",
1018
- ' 5. `kuma_memory({ action: "research_save", ... })` \u2014 After exploring area (creates search cache)',
1019
- ' 6. `kuma_memory({ action: "gotcha" })` \u2014 \u{1F525} IMMEDIATELY when bug found (exponential)',
1020
- ' 7. `kuma_memory({ action: "arch_flow" })` \u2014 \u{1F525} IMMEDIATELY after each flow hop (exponential)',
1021
- ' 8. `kuma_memory({ action: "decision" })` \u2014 When choosing (preserves rationale)',
1022
- ' 9. `kuma_safety({ action: "verify", ... })` \u2014 Run tests / confirm nothing broken',
1023
- ' 10. `kuma_context({ action: "changes" })` \u2014 Review session activity',
1024
- "",
1025
- "\u{1F525} `arch_flow` + `gotcha` = EXPONENTIAL value. Each record saves 5-10 files next session.",
1026
- "\u{1F7E2} SKIP recording function/class/component nodes \u2014 grep/glob is faster.",
1027
- "\u{1F9E0} Graph is persistent \u2014 nodes/edges accumulate across sessions.",
1028
- "",
1029
- "\u26D4 Steps 5-10 are mandatory even for research-only sessions!",
1030
- "",
1031
- "## Platform Tool Names",
1032
- "",
1033
- "- **OpenCode:** Use `kuma_kuma_*` prefix (e.g. `kuma_kuma_context`)",
1034
- "- **Other platforms:** Use `kuma_*` directly (e.g. `kuma_context`)",
1035
- "",
1036
- "\u{1F4D6} Full rules: `.kuma/init.md`",
1037
- "_Generated by Kuma MCP - https://github.com/plumpslabs/kuma_"
1038
- ].join("\n");
1039
- try {
1040
- const kumaDir = path.dirname(quickrefPath);
1041
- if (!fs.existsSync(kumaDir)) fs.mkdirSync(kumaDir, { recursive: true });
1042
- if (fs.existsSync(quickrefPath)) {
1043
- const existing = fs.readFileSync(quickrefPath, "utf-8");
1044
- if (existing.includes("_Generated by Kuma MCP_")) {
1045
- results.push({ type: "claude", filePath: ".kuma/quickref.md", action: "skipped" });
1046
- return;
1047
- }
1048
- results.push({ type: "claude", filePath: ".kuma/quickref.md", action: "skipped" });
1049
- } else {
1050
- fs.writeFileSync(quickrefPath, content, "utf-8");
1051
- results.push({ type: "claude", filePath: ".kuma/quickref.md", action: "created" });
1052
- }
1053
- } catch (err) {
1054
- results.push({
1055
- type: "claude",
1056
- filePath: ".kuma/quickref.md",
1057
- action: "error",
1058
- error: err instanceof Error ? err.message : String(err)
1059
- });
1060
- }
1061
- }
1062
- function handleInitMdGeneration(root, results) {
1063
- const initMdPath = path.resolve(root, ".kuma/init.md");
1064
- try {
1065
- const kumaDir = path.dirname(initMdPath);
1066
- if (!fs.existsSync(kumaDir)) fs.mkdirSync(kumaDir, { recursive: true });
1067
- if (fs.existsSync(initMdPath)) {
1068
- const existing = fs.readFileSync(initMdPath, "utf-8");
1069
- if (existing.includes("_Generated by Kuma MCP_")) {
1070
- results.push({ type: "claude", filePath: ".kuma/init.md", action: "skipped" });
1071
- return;
1072
- }
1073
- fs.writeFileSync(initMdPath, existing.trimEnd() + "\n\n" + generateInitMdContent(), "utf-8");
1074
- results.push({ type: "claude", filePath: ".kuma/init.md", action: "appended" });
1075
- } else {
1076
- fs.writeFileSync(initMdPath, generateInitMdContent(), "utf-8");
1077
- results.push({ type: "claude", filePath: ".kuma/init.md", action: "created" });
1078
- }
1079
- } catch (err) {
1080
- results.push({
1081
- type: "claude",
1082
- filePath: ".kuma/init.md",
1083
- action: "error",
1084
- error: err instanceof Error ? err.message : String(err)
1085
- });
1086
- }
1087
- handleQuickrefGeneration(root, results);
1088
- }
1089
- function handleCodewhaleSecondary(root, results) {
1090
- const mcpPath = path.resolve(root, ".codewhale/mcp.json");
1091
- if (results.some((r) => r.filePath === ".codewhale/mcp.json")) return;
1092
- try {
1093
- const dir = path.dirname(mcpPath);
1094
- if (fs.existsSync(mcpPath)) {
1095
- const existingContent = fs.readFileSync(mcpPath, "utf-8");
1096
- if (existingContent.includes("kuma")) return;
1097
- const parsed = JSON.parse(existingContent);
1098
- parsed.mcpServers = parsed.mcpServers || {};
1099
- parsed.mcpServers.kuma = { command: "npx", args: ["-y", "@plumpslabs/kuma"], env: {} };
1100
- fs.writeFileSync(mcpPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
1101
- results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "appended" });
1102
- } else {
1103
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
1104
- const config = {
1105
- mcpServers: {
1106
- kuma: {
1107
- command: "npx",
1108
- args: ["-y", "@plumpslabs/kuma"],
1109
- env: {}
1110
- }
1111
- }
1112
- };
1113
- fs.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
1114
- results.push({ type: "codewhale", filePath: ".codewhale/mcp.json", action: "created" });
1115
- }
1116
- } catch (err) {
1117
- results.push({
1118
- type: "codewhale",
1119
- filePath: ".codewhale/mcp.json",
1120
- action: "error",
1121
- error: err instanceof Error ? err.message : String(err)
1122
- });
1123
- }
1124
- }
1125
- function runInit(options) {
1126
- const root = options.projectRoot ?? getProjectRoot();
1127
- const selected = options.types.length > 0 ? options.types : ALL_CONFIG_TYPES;
1128
- const results = [];
1129
- handleInitMdGeneration(root, results);
1130
- const selectedSet = new Set(selected);
1131
- const agentsMdSelected = AGENTS_MD_TYPES.filter((t) => selectedSet.has(t));
1132
- let agentsMdHandled = false;
1133
- for (const type of selected) {
1134
- const relativePath = configFilePath(type);
1135
- const fullPath = path.resolve(root, relativePath);
1136
- const getTemplate = TEMPLATES[type];
1137
- try {
1138
- if (AGENTS_MD_TYPES.includes(type) && !agentsMdHandled) {
1139
- agentsMdHandled = true;
1140
- const combinedContent = getCombinedAgentsMd(new Set(agentsMdSelected));
1141
- if (fs.existsSync(fullPath)) {
1142
- if (options.skipExisting) {
1143
- results.push({ type, filePath: relativePath, action: "skipped" });
1144
- } else {
1145
- const existingContent = fs.readFileSync(fullPath, "utf-8");
1146
- if (existingContent.includes("_Generated by Kuma MCP_")) {
1147
- results.push({ type, filePath: relativePath, action: "skipped" });
1148
- } else {
1149
- fs.writeFileSync(fullPath, existingContent.trimEnd() + "\n\n" + combinedContent, "utf-8");
1150
- results.push({ type, filePath: relativePath, action: "appended" });
1151
- }
1152
- }
1153
- } else {
1154
- const dir = path.dirname(fullPath);
1155
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
1156
- fs.writeFileSync(fullPath, combinedContent, "utf-8");
1157
- results.push({ type, filePath: relativePath, action: "created" });
1158
- }
1159
- if (selectedSet.has("opencode")) handleOpencodeSecondary(root, results);
1160
- if (selectedSet.has("codex")) handleCodexSecondary(root, results);
1161
- if (selectedSet.has("qwen")) handleQwenSecondary(root, results);
1162
- if (selectedSet.has("copilot")) handleCopilotSecondary(root, results);
1163
- } else if (AGENTS_MD_TYPES.includes(type) && agentsMdHandled) {
1164
- results.push({ type, filePath: relativePath, action: "skipped" });
1165
- continue;
1166
- } else {
1167
- const template = getTemplate();
1168
- if (fs.existsSync(fullPath)) {
1169
- if (options.skipExisting) {
1170
- results.push({ type, filePath: relativePath, action: "skipped" });
1171
- continue;
1172
- }
1173
- const existingContent = fs.readFileSync(fullPath, "utf-8");
1174
- if (existingContent.includes("_Generated by Kuma MCP_")) {
1175
- if (type === "antigravity") {
1176
- handleAntigravityMcpConfig(root, results);
1177
- } else if (type === "openclaw") {
1178
- handleOpenclawSecondary(root, results);
1179
- } else if (type === "codewhale") {
1180
- handleCodewhaleSecondary(root, results);
1181
- }
1182
- results.push({ type, filePath: relativePath, action: "skipped" });
1183
- continue;
1184
- }
1185
- const newContent = existingContent.trimEnd() + APPEND_SEPARATOR + template;
1186
- fs.writeFileSync(fullPath, newContent, "utf-8");
1187
- results.push({ type, filePath: relativePath, action: "appended" });
1188
- } else {
1189
- const dir = path.dirname(fullPath);
1190
- if (!fs.existsSync(dir)) {
1191
- fs.mkdirSync(dir, { recursive: true });
1192
- }
1193
- fs.writeFileSync(fullPath, template, "utf-8");
1194
- results.push({ type, filePath: relativePath, action: "created" });
1195
- }
1196
- if (type === "antigravity") {
1197
- handleAntigravityMcpConfig(root, results);
1198
- } else if (type === "openclaw") {
1199
- handleOpenclawSecondary(root, results);
1200
- } else if (type === "codewhale") {
1201
- handleCodewhaleSecondary(root, results);
1202
- } else if (type === "aider") {
1203
- handleAiderSecondary(root, results);
1204
- }
1205
- }
1206
- } catch (err) {
1207
- results.push({
1208
- type,
1209
- filePath: relativePath,
1210
- action: "error",
1211
- error: err instanceof Error ? err.message : String(err)
1212
- });
1213
- }
1214
- }
1215
- return results;
1216
- }
1217
- function formatInitResults(results) {
1218
- const lines = [
1219
- "\u{1F43B} **Kuma Init - AI Agent Config Generator**",
1220
- ""
1221
- ];
1222
- for (const r of results) {
1223
- const label = CONFIG_LABELS[r.type];
1224
- switch (r.action) {
1225
- case "created":
1226
- lines.push(" \u2705 " + label);
1227
- lines.push(" \u2192 Created: " + r.filePath);
1228
- break;
1229
- case "appended":
1230
- lines.push(" \u2795 " + label);
1231
- lines.push(" \u2192 Appended to: " + r.filePath);
1232
- break;
1233
- case "skipped":
1234
- lines.push(" \u23ED " + label);
1235
- lines.push(" \u2192 Skipped (already has Kuma): " + r.filePath);
1236
- break;
1237
- case "error":
1238
- lines.push(" \u274C " + label);
1239
- lines.push(" \u2192 Error: " + (r.error ?? "unknown"));
1240
- break;
1241
- }
1242
- }
1243
- const created = results.filter((r) => r.action === "created").length;
1244
- const appended = results.filter((r) => r.action === "appended").length;
1245
- const skipped = results.filter((r) => r.action === "skipped").length;
1246
- const errors = results.filter((r) => r.action === "error").length;
1247
- lines.push(
1248
- "",
1249
- "\u{1F4CA} Summary: " + created + " created, " + appended + " appended, " + skipped + " skipped, " + errors + " errors",
1250
- "",
1251
- "\u{1F4A1} Rules are in `.kuma/init.md` \u2014 single source of truth for all tools.",
1252
- "\u{1F4A1} Call `kuma_init()` at session start to load project context.",
1253
- "\u{1F4A1} Run again to generate additional config files anytime."
1254
- );
1255
- return lines.join("\n");
1256
- }
1257
-
1258
- export {
1259
- ALL_CONFIG_TYPES,
1260
- CONFIG_LABELS,
1261
- generateInitMdContent,
1262
- runInit,
1263
- formatInitResults
1264
- };