@plumpslabs/kuma 2.3.16 → 2.3.17

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.
@@ -474,6 +474,78 @@ function generateInitMdContent() {
474
474
  " kuma_memory \u2192 mine \u2014 Historical context",
475
475
  "```",
476
476
  "",
477
+ "## \u{1F9E0} How the Scanner Works",
478
+ "",
479
+ "Kuma's code scanner (`kumaCodeScanner.ts`) uses **regex-based pattern matching**",
480
+ "to detect code structure. It is NOT a full AST parser (no Babel/TypeScript compiler dependency).",
481
+ "",
482
+ "**What it detects (line-by-line regex):**",
483
+ "- `function` declarations (named + async + generator)",
484
+ "- Arrow function assignments (`const foo = (...) => ...`)",
485
+ "- Typed arrow functions (`const foo: Type = (...) => ...`)",
486
+ "- Class declarations (includes extends/implements)",
487
+ "- React/Vue components (functions returning JSX)",
488
+ "- API route handlers (Express + Hono patterns)",
489
+ "- Import statements (local file imports only)",
490
+ "- Function calls cross-file (`calls` edges)",
491
+ "- Test files (`.test.`, `.spec.`, `__tests__/`)",
492
+ "",
493
+ "**Known limitations:**",
494
+ "- Regex-based = can miss multi-line constructs or non-standard patterns",
495
+ "- Complex generics or deeply nested syntax may not match",
496
+ "- TypeScript advanced types may be partially parsed",
497
+ "- Scanner runs automatically during `kuma_context research` step 3",
498
+ "- If scanner returns 0 structural nodes, the regex patterns didn't match your code style",
499
+ "",
500
+ "**For richer code analysis:**",
501
+ "- Record findings INLINE as you read/grep \u2014 this builds the graph manually",
502
+ "- Call `research_save` after exploring files to persist function/class/import nodes",
503
+ "- The more you use Kuma, the richer the graph becomes (persistent across sessions)",
504
+ "",
505
+ "---",
506
+ "",
507
+ "## \u{1F4BE} How to Read Memory & Search the Graph",
508
+ "",
509
+ "Kuma stores knowledge in two places:",
510
+ "",
511
+ "**1. Knowledge Graph (SQLite - `.kuma/kuma.db`)**",
512
+ "- Nodes: files, functions, classes, components, routes, tests, gotchas, decisions",
513
+ "- Edges: imports, calls, extends, contains, composes, routes",
514
+ '- Query: `kuma_memory({ action: "search", query: "<term>" })`',
515
+ "- Falls back to codebase grep if graph is empty",
516
+ "",
517
+ "**2. Research Cache (SQLite - `.kuma/kuma.db`)**",
518
+ '- Saved via `kuma_memory({ action: "research_save", scope: "<area>", confidence: 0.8 })`',
519
+ '- List: `kuma_context({ action: "researches" })`',
520
+ '- Auto-loaded during `kuma_context({ action: "research", scope: "<area>" })`',
521
+ "",
522
+ "**Quick memory reading tips:**",
523
+ '- `kuma_context({ action: "init" })` \u2014 shows graph stats + recent research + health score',
524
+ '- `kuma_context({ action: "research", scope: "<area>" })` \u2014 deep research with graph query',
525
+ '- `kuma_memory({ action: "search", query: "<term>" })` \u2014 search all memories + graph',
526
+ '- `kuma_context({ action: "visualize" })` \u2014 Mermaid diagram of the graph',
527
+ '- `kuma_context({ action: "drift" })` \u2014 check if memories are stale vs actual code',
528
+ '- `kuma_context({ action: "changes" })` \u2014 view session activity log',
529
+ "",
530
+ "---",
531
+ "",
532
+ "## \u{1F52C} How Verification Works",
533
+ "",
534
+ '`kuma_safety({ action: "verify", scope: "<area>" })` \u2014 STEP 9',
535
+ "",
536
+ "**Auto-detection logic:**",
537
+ "1. Checks `package.json` \u2192 `scripts.test` \u2192 uses npm/pnpm/yarn test",
538
+ "2. If no test script, checks for Makefile with `test:` target",
539
+ "3. Falls back to Python (pytest), Rust (cargo test), Go (go test)",
540
+ "4. Last resort: `npx tsc --noEmit` (TypeScript syntax check) or `node -c`",
541
+ "5. If nothing found: returns informative message instead of failing",
542
+ "",
543
+ "**Important:** Verification is NEVER auto-triggered. You must call it explicitly.",
544
+ "The 5-layer safety guard (concurrency lock, rate limiting, staleness cache,",
545
+ "runaway detection, hard timeout) prevents resource exhaustion.",
546
+ "",
547
+ "---",
548
+ "",
477
549
  "## \u{1F6AB} What Kuma Does NOT Do (Use Agent Native Tools)",
478
550
  "",
479
551
  "| Function | Correct Tool |",
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  ALL_CONFIG_TYPES,
9
9
  formatInitResults,
10
10
  runInit
11
- } from "./chunk-S7BQGNHQ.js";
11
+ } from "./chunk-AJ7HHUDW.js";
12
12
  import {
13
13
  formatDecisionTemplate,
14
14
  getProactiveMemories,
@@ -336,7 +336,7 @@ async function handleResearch(params) {
336
336
  lines.push(" \u26A0\uFE0F Graph query failed");
337
337
  }
338
338
  try {
339
- const { scanCodebase } = await import("./kumaCodeScanner-LFJGPJNH.js");
339
+ const { scanCodebase } = await import("./kumaCodeScanner-QYQUL4W6.js");
340
340
  const scanResult = await scanCodebase({ scope, maxFiles: 100 });
341
341
  if (scanResult.nodeCount > 0 || scanResult.edgeCount > 0) {
342
342
  lines.push(` \u{1F52C} Auto-scanned ${scanResult.filesScanned} files \u2192 ${scanResult.nodeCount} nodes, ${scanResult.edgeCount} edges`);
@@ -2149,7 +2149,7 @@ async function handleVerify(params) {
2149
2149
  }
2150
2150
  _lastVerifyCall = now;
2151
2151
  sessionMemory.recordToolCall("kuma_safety_verify", { scope: params.scope || params.filePath });
2152
- const { runAutoVerification } = await import("./kumaVerifier-KAYJHR5K.js");
2152
+ const { runAutoVerification } = await import("./kumaVerifier-6NTJQU7B.js");
2153
2153
  return await runAutoVerification({
2154
2154
  scope: params.scope || params.filePath,
2155
2155
  force: params.force,
@@ -2362,7 +2362,7 @@ async function main() {
2362
2362
  console.error("");
2363
2363
  let killedCount = 0;
2364
2364
  try {
2365
- const { getRunningVerificationPid } = await import("./kumaVerifier-KAYJHR5K.js");
2365
+ const { getRunningVerificationPid } = await import("./kumaVerifier-6NTJQU7B.js");
2366
2366
  const pid = getRunningVerificationPid();
2367
2367
  if (pid) {
2368
2368
  try {
@@ -2571,7 +2571,7 @@ async function main() {
2571
2571
  });
2572
2572
  (async () => {
2573
2573
  try {
2574
- const { generateInitMdContent } = await import("./init-P3DAC23E.js");
2574
+ const { generateInitMdContent } = await import("./init-BC7FG4C2.js");
2575
2575
  const fs7 = await import("fs");
2576
2576
  const path7 = await import("path");
2577
2577
  const initMdPath = path7.resolve(process.cwd(), ".kuma/init.md");
@@ -4,7 +4,7 @@ import {
4
4
  formatInitResults,
5
5
  generateInitMdContent,
6
6
  runInit
7
- } from "./chunk-S7BQGNHQ.js";
7
+ } from "./chunk-AJ7HHUDW.js";
8
8
  import "./chunk-E2KFPEBT.js";
9
9
  export {
10
10
  ALL_CONFIG_TYPES,
@@ -21,8 +21,8 @@ function getRoot() {
21
21
  return _cachedRoot;
22
22
  }
23
23
  var FUNCTION_DECL_RE = /(?:export\s+)?(?:async\s+)?function\s*(?:\*\s*)?(\w+)\s*\(/g;
24
- var ARROW_FN_RE = /(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*(?::\s*\w+(?:<[^>]*>)?)?\s*=>/g;
25
- var TYPED_ARROW_RE = /(?:export\s+)?(?:const|let|var)\s+(\w+)\s*:\s*(?:\w+(?:<[^>]*>)?)?\s*=\s*(?:async\s*)?\(/g;
24
+ var ARROW_FN_RE = /(?:export\s+)?(?:const|let|var)\s+(\w+)\s*[=:]\s*(?:async\s*)?(?:<[^>]+>\s*)?(?:\([\s\S]*?\)|\w+)\s*(?::\s*\w+(?:<[^>]*>)?)?\s*=>/g;
25
+ var TYPED_ARROW_RE = /(?:export\s+)?(?:const|let|var)\s+(\w+)\s*:\s*(?:\w+(?:<[^>]*>)?)?\s*=\s*(?:async\s*)?(?:<[^>]+>\s*)?\(/g;
26
26
  var CLASS_RE = /(?:export\s+)?(?:abstract\s+)?class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([\w,\s]+))?/g;
27
27
  var IMPORT_RE = /import\s+(?:\{([^}]*)\}\s+from\s+)?(?:\w+\s+from\s+)?(?:\*\s+as\s+\w+\s+from\s+)?['"]([^'"]+)['"]/g;
28
28
  var JSX_RETURN_RE = /return\s*\(?\s*</;
@@ -93,7 +93,14 @@ function detectTestRunner(root = process.cwd()) {
93
93
  if (fs.existsSync(path.join(root, "pytest.ini")) || fs.existsSync(path.join(root, "pyproject.toml"))) return { runner: "pytest", baseCommand: "pytest" };
94
94
  if (fs.existsSync(path.join(root, "Cargo.toml"))) return { runner: "cargo", baseCommand: "cargo test" };
95
95
  if (fs.existsSync(path.join(root, "go.mod"))) return { runner: "go", baseCommand: "go test ./..." };
96
- if (fs.existsSync(path.join(root, "Makefile"))) return { runner: "make", baseCommand: "make test" };
96
+ if (fs.existsSync(path.join(root, "Makefile"))) {
97
+ try {
98
+ const makefileContent = fs.readFileSync(path.join(root, "Makefile"), "utf-8");
99
+ const hasTestTarget = /^test:/m.test(makefileContent) || /^\s+test:/.test(makefileContent);
100
+ if (hasTestTarget) return { runner: "make", baseCommand: "make test" };
101
+ } catch {
102
+ }
103
+ }
97
104
  if (fs.existsSync(path.join(root, "package.json"))) {
98
105
  try {
99
106
  const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf-8"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumpslabs/kuma",
3
- "version": "2.3.16",
3
+ "version": "2.3.17",
4
4
  "description": "Safety-first context & orchestration engine for AI coding agents. MCP server with mandatory research pipeline, knowledge graph, impact analysis, decision memory, and safety guard — works with any MCP client.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",