pikakit 2.0.0 → 3.0.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 (92) hide show
  1. package/README.md +8 -8
  2. package/lib/agent-cli/bin/agent.js +187 -0
  3. package/lib/agent-cli/lib/audit.js +154 -0
  4. package/lib/agent-cli/lib/audit.test.js +100 -0
  5. package/lib/agent-cli/lib/auto-learn.js +319 -0
  6. package/lib/agent-cli/lib/backup.js +138 -0
  7. package/lib/agent-cli/lib/backup.test.js +78 -0
  8. package/lib/agent-cli/lib/cognitive-lesson.js +476 -0
  9. package/lib/agent-cli/lib/completion.js +149 -0
  10. package/lib/agent-cli/lib/config.js +35 -0
  11. package/lib/agent-cli/lib/eslint-fix.js +238 -0
  12. package/lib/agent-cli/lib/evolution-signal.js +215 -0
  13. package/lib/agent-cli/lib/export.js +86 -0
  14. package/lib/agent-cli/lib/export.test.js +65 -0
  15. package/lib/agent-cli/lib/fix.js +337 -0
  16. package/lib/agent-cli/lib/fix.test.js +80 -0
  17. package/lib/agent-cli/lib/gemini-export.js +83 -0
  18. package/lib/agent-cli/lib/generate-registry.js +42 -0
  19. package/lib/agent-cli/lib/hooks/install-hooks.js +152 -0
  20. package/lib/agent-cli/lib/hooks/lint-learn.js +172 -0
  21. package/lib/agent-cli/lib/icons.js +93 -0
  22. package/lib/agent-cli/lib/ignore.js +116 -0
  23. package/lib/agent-cli/lib/ignore.test.js +58 -0
  24. package/lib/agent-cli/lib/init.js +124 -0
  25. package/lib/agent-cli/lib/knowledge-index.js +326 -0
  26. package/lib/agent-cli/lib/knowledge-metrics.js +335 -0
  27. package/lib/agent-cli/lib/knowledge-retention.js +398 -0
  28. package/lib/agent-cli/lib/knowledge-validator.js +312 -0
  29. package/lib/agent-cli/lib/learn.js +255 -0
  30. package/lib/agent-cli/lib/learn.test.js +70 -0
  31. package/lib/agent-cli/lib/proposals.js +199 -0
  32. package/lib/agent-cli/lib/proposals.test.js +56 -0
  33. package/lib/agent-cli/lib/recall.js +835 -0
  34. package/lib/agent-cli/lib/recall.test.js +107 -0
  35. package/lib/agent-cli/lib/selfevolution-bridge.js +167 -0
  36. package/lib/agent-cli/lib/settings.js +203 -0
  37. package/lib/agent-cli/lib/skill-learn.js +296 -0
  38. package/lib/agent-cli/lib/stats.js +132 -0
  39. package/lib/agent-cli/lib/stats.test.js +94 -0
  40. package/lib/agent-cli/lib/types.js +33 -0
  41. package/lib/agent-cli/lib/ui/audit-ui.js +146 -0
  42. package/lib/agent-cli/lib/ui/backup-ui.js +107 -0
  43. package/lib/agent-cli/lib/ui/clack-helpers.js +317 -0
  44. package/lib/agent-cli/lib/ui/common.js +83 -0
  45. package/lib/agent-cli/lib/ui/completion-ui.js +126 -0
  46. package/lib/agent-cli/lib/ui/custom-select.js +69 -0
  47. package/lib/agent-cli/lib/ui/dashboard-ui.js +222 -0
  48. package/lib/agent-cli/lib/ui/evolution-signals-ui.js +107 -0
  49. package/lib/agent-cli/lib/ui/export-ui.js +94 -0
  50. package/lib/agent-cli/lib/ui/fix-all-ui.js +191 -0
  51. package/lib/agent-cli/lib/ui/help-ui.js +49 -0
  52. package/lib/agent-cli/lib/ui/index.js +199 -0
  53. package/lib/agent-cli/lib/ui/init-ui.js +56 -0
  54. package/lib/agent-cli/lib/ui/knowledge-ui.js +55 -0
  55. package/lib/agent-cli/lib/ui/learn-ui.js +706 -0
  56. package/lib/agent-cli/lib/ui/lessons-ui.js +148 -0
  57. package/lib/agent-cli/lib/ui/pretty.js +145 -0
  58. package/lib/agent-cli/lib/ui/proposals-ui.js +99 -0
  59. package/lib/agent-cli/lib/ui/recall-ui.js +342 -0
  60. package/lib/agent-cli/lib/ui/routing-demo.js +79 -0
  61. package/lib/agent-cli/lib/ui/routing-ui.js +325 -0
  62. package/lib/agent-cli/lib/ui/settings-ui.js +381 -0
  63. package/lib/agent-cli/lib/ui/stats-ui.js +123 -0
  64. package/lib/agent-cli/lib/ui/watch-ui.js +236 -0
  65. package/lib/agent-cli/lib/watcher.js +181 -0
  66. package/lib/agent-cli/lib/watcher.test.js +85 -0
  67. package/lib/agent-cli/src/MIGRATION.md +418 -0
  68. package/lib/agent-cli/src/README.md +367 -0
  69. package/lib/agent-cli/src/core/evolution/evolution-signal.js +42 -0
  70. package/lib/agent-cli/src/core/evolution/index.js +17 -0
  71. package/lib/agent-cli/src/core/evolution/review-gate.js +40 -0
  72. package/lib/agent-cli/src/core/evolution/signal-detector.js +137 -0
  73. package/lib/agent-cli/src/core/evolution/signal-queue.js +79 -0
  74. package/lib/agent-cli/src/core/evolution/threshold-checker.js +79 -0
  75. package/lib/agent-cli/src/core/index.js +15 -0
  76. package/lib/agent-cli/src/core/learning/cognitive-enhancer.js +282 -0
  77. package/lib/agent-cli/src/core/learning/index.js +12 -0
  78. package/lib/agent-cli/src/core/learning/lesson-synthesizer.js +83 -0
  79. package/lib/agent-cli/src/core/scanning/index.js +14 -0
  80. package/lib/agent-cli/src/data/index.js +13 -0
  81. package/lib/agent-cli/src/data/repositories/index.js +8 -0
  82. package/lib/agent-cli/src/data/repositories/lesson-repository.js +130 -0
  83. package/lib/agent-cli/src/data/repositories/signal-repository.js +119 -0
  84. package/lib/agent-cli/src/data/storage/index.js +8 -0
  85. package/lib/agent-cli/src/data/storage/json-storage.js +64 -0
  86. package/lib/agent-cli/src/data/storage/yaml-storage.js +66 -0
  87. package/lib/agent-cli/src/infrastructure/index.js +13 -0
  88. package/lib/agent-cli/src/presentation/formatters/skill-formatter.js +232 -0
  89. package/lib/agent-cli/src/services/export-service.js +162 -0
  90. package/lib/agent-cli/src/services/index.js +13 -0
  91. package/lib/agent-cli/src/services/learning-service.js +99 -0
  92. package/package.json +5 -3
package/README.md CHANGED
@@ -19,8 +19,8 @@ npx pikakit
19
19
 
20
20
  | Component | Count | Description |
21
21
  |-----------|-------|-------------|
22
- | **Skills** | 49 | FAANG-grade coding skills |
23
- | **Workflows** | 26 | `/think`, `/build`, `/autopilot`, etc. |
22
+ | **Skills** | 50 | FAANG-grade coding skills |
23
+ | **Workflows** | 25 | `/think`, `/build`, `/autopilot`, etc. |
24
24
  | **Agents** | 25 | Specialist AI agents |
25
25
  | **Rules** | GEMINI.md | AI behavior configuration |
26
26
  | **Scripts** | 25 | JavaScript automation scripts |
@@ -63,8 +63,8 @@ npx pikakit add myteam/company-skills # Custom skills
63
63
  your-project/
64
64
  ├── .agent/
65
65
  │ ├── GEMINI.md # AI Rules
66
- │ ├── skills/ # 49 Skills
67
- │ ├── workflows/ # 26 Workflows
66
+ │ ├── skills/ # 50 Skills
67
+ │ ├── workflows/ # 25 Workflows
68
68
  │ ├── agents/ # 25 Agents
69
69
  │ ├── knowledge/ # Learning memory
70
70
  │ ├── config/ # Configuration
@@ -158,19 +158,19 @@ npx pikakit add pikakit-agent-skills --force
158
158
  ├── CONTINUOUS_EXECUTION_POLICY.md # Autopilot Rules
159
159
  ├── WORKFLOW_CHAINS.md # Workflow Patterns
160
160
 
161
- ├── skills/ # 49 Skills
161
+ ├── skills/ # 50 Skills
162
162
  │ ├── auto-learner/
163
163
  │ ├── react-architect/
164
164
  │ ├── typescript-expert/
165
165
  │ ├── debug-pro/
166
166
  │ ├── studio/
167
- │ └── ... (44 more)
167
+ │ └── ... (45 more)
168
168
 
169
- ├── workflows/ # 26 Workflows
169
+ ├── workflows/ # 25 Workflows
170
170
  │ ├── think.md
171
171
  │ ├── build.md
172
172
  │ ├── autopilot.md
173
- │ └── ... (23 more)
173
+ │ └── ... (22 more)
174
174
 
175
175
  ├── agents/ # 25 Agents
176
176
  │ ├── frontend-specialist.md
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Smart Agent CLI - ESM Version (Production-Ready)
4
+ *
5
+ * The main interface for humans to interact with the Smart Agent Skills system.
6
+ *
7
+ * Commands:
8
+ * learn Add new lessons to memory
9
+ * recall Check files against memory
10
+ * audit Full compliance audit
11
+ * watch Real-time file monitoring
12
+ * stats Knowledge base statistics
13
+ * install-hooks Install git pre-commit hook
14
+ * lint-learn Auto-learn from ESLint output
15
+ */
16
+
17
+ import { spawn } from "child_process";
18
+ import path from "path";
19
+ import { fileURLToPath } from "url";
20
+ import { VERSION } from "../lib/config.js";
21
+
22
+ // Fix UTF-8 output on Windows PowerShell/Console
23
+ if (process.platform === "win32" && process.stdout.isTTY) {
24
+ process.stdout.setDefaultEncoding("utf8");
25
+ }
26
+
27
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
28
+ const ARGS = process.argv.slice(2);
29
+ const COMMAND = ARGS[0];
30
+ const SCRIPTS_DIR = path.join(__dirname, "..", "lib");
31
+ const HOOKS_DIR = path.join(SCRIPTS_DIR, "hooks");
32
+
33
+ /**
34
+ * Run a script with given arguments
35
+ * @param {string} script - Script filename (relative to lib/)
36
+ * @param {string[]} args - Arguments to pass
37
+ * @param {string} baseDir - Base directory for script
38
+ */
39
+ function run(script, args = [], baseDir = SCRIPTS_DIR) {
40
+ const scriptPath = path.join(baseDir, script);
41
+ const child = spawn("node", [scriptPath, ...args], {
42
+ stdio: "inherit",
43
+ shell: true
44
+ });
45
+
46
+ child.on("close", (code) => {
47
+ process.exit(code || 0);
48
+ });
49
+
50
+ child.on("error", (err) => {
51
+ console.error(`❌ Failed to run ${script}:`, err.message);
52
+ process.exit(1);
53
+ });
54
+ }
55
+
56
+ function printHelp() {
57
+ console.log(`
58
+ 🤖 PikaKit CLI v${VERSION}
59
+
60
+ Usage: ag-smart <command> [options]
61
+
62
+ ${"─".repeat(50)}
63
+
64
+ 📚 CORE COMMANDS:
65
+
66
+ learn Teach a new lesson to the memory
67
+ ag-smart learn --add --pattern "var " --message "Use let/const"
68
+ ag-smart learn --list
69
+ ag-smart learn --remove LEARN-001
70
+
71
+ recall Check file(s) against learned patterns
72
+ ag-smart recall src/app.js
73
+ ag-smart recall ./src
74
+
75
+ audit Run full compliance audit
76
+ ag-smart audit [directory]
77
+
78
+ ${"─".repeat(50)}
79
+
80
+ 🚀 PRODUCTION FEATURES:
81
+
82
+ watch Real-time file monitoring
83
+ ag-smart watch [directory]
84
+
85
+ stats Knowledge base statistics
86
+ ag-smart stats
87
+
88
+ install-hooks Install git pre-commit hook
89
+ ag-smart install-hooks
90
+ ag-smart install-hooks --remove
91
+
92
+ lint-learn Auto-learn from ESLint JSON output
93
+ npx eslint . --format json | ag-smart lint-learn
94
+
95
+ fix 🆕 Auto-fix violations
96
+ ag-smart fix <file|dir> [--mode safe|aggressive]
97
+
98
+ sync-skills 🆕 Sync hot patterns to SKILL.md
99
+ ag-smart sync-skills
100
+
101
+ index 🆕 Knowledge index management
102
+ ag-smart index --rebuild | --status
103
+
104
+ metrics 🆕 Knowledge metrics dashboard
105
+ ag-smart metrics [--json]
106
+
107
+ validate Schema validation for knowledge files
108
+ ag-smart validate [--fix] [--json]
109
+
110
+ retention Retention policy runner
111
+ ag-smart retention [--dry-run] [--apply] [--status]
112
+
113
+ ${"─".repeat(50)}
114
+
115
+ 📖 HELP:
116
+
117
+ help, --help Show this help message
118
+ --version Show version number
119
+
120
+ 💡 Docs: https://github.com/pikakit/agent-skills
121
+ `);
122
+ }
123
+
124
+ // Command routing
125
+ switch (COMMAND) {
126
+ // Core commands (v2 versions)
127
+ case "learn":
128
+ run("learn.js", ARGS.slice(1));
129
+ break;
130
+ case "recall":
131
+ run("recall.js", ARGS.slice(1));
132
+ break;
133
+ case "audit":
134
+ run("audit.js", ARGS.slice(1));
135
+ break;
136
+
137
+ // Production features
138
+ case "watch":
139
+ run("watcher.js", ARGS.slice(1));
140
+ break;
141
+ case "stats":
142
+ run("stats.js", ARGS.slice(1));
143
+ break;
144
+ case "install-hooks":
145
+ run("install-hooks.js", ARGS.slice(1), HOOKS_DIR);
146
+ break;
147
+ case "lint-learn":
148
+ run("lint-learn.js", ARGS.slice(1), HOOKS_DIR);
149
+ break;
150
+ case "fix":
151
+ run("fix.js", ARGS.slice(1));
152
+ break;
153
+ case "sync-skills":
154
+ run("skill-learn.js", ARGS.slice(1));
155
+ break;
156
+ case "index":
157
+ run("knowledge-index.js", ARGS.slice(1));
158
+ break;
159
+ case "metrics":
160
+ run("knowledge-metrics.js", ARGS.slice(1));
161
+ break;
162
+ case "validate":
163
+ run("knowledge-validator.js", ARGS.slice(1));
164
+ break;
165
+ case "retention":
166
+ run("knowledge-retention.js", ARGS.slice(1));
167
+ break;
168
+
169
+ // Meta
170
+ case "--version":
171
+ case "-v":
172
+ console.log(VERSION);
173
+ break;
174
+ case "help":
175
+ case "--help":
176
+ case "-h":
177
+ printHelp();
178
+ break;
179
+ case undefined:
180
+ // No command = show interactive Clack menu
181
+ import("../lib/ui/index.js").then(m => m.showMainMenu()).catch(console.error);
182
+ break;
183
+ default:
184
+ console.log(`❌ Unknown command: ${COMMAND}`);
185
+ console.log(" Run 'ag-smart help' for available commands.\n");
186
+ process.exit(1);
187
+ }
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Smart Audit Script (Production-Ready)
4
+ *
5
+ * The "Judge" - Orchestrates all compliance checks:
6
+ * 1. Memory Recall (Past Mistakes)
7
+ * 2. Constitution Checks (Governance)
8
+ * 3. Real-time Analysis
9
+ *
10
+ * Usage: agent audit [directory]
11
+ */
12
+
13
+ import fs from "fs";
14
+ import path from "path";
15
+ import { fileURLToPath } from "url";
16
+ import { scanDirectory, loadKnowledge, saveKnowledge, printResults } from "./recall.js";
17
+ import { AGENT_DIR, VERSION } from "./config.js";
18
+ import * as p from "@clack/prompts";
19
+ import pc from "picocolors";
20
+
21
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
22
+
23
+ // ============================================================================
24
+ // AUDIT CONFIGURATION
25
+ // ============================================================================
26
+
27
+ const SCAN_EXTENSIONS = [".js", ".ts", ".tsx", ".jsx", ".mjs"];
28
+
29
+ // ============================================================================
30
+ // GOVERNANCE CHECKS
31
+ // ============================================================================
32
+
33
+ /**
34
+ * Check if governance files exist
35
+ * @param {string} projectRoot
36
+ * @returns {{ passed: boolean, details: string[] }}
37
+ */
38
+ function checkGovernance(projectRoot) {
39
+ const details = [];
40
+ let passed = true;
41
+
42
+ const governanceFiles = [
43
+ { path: path.join(projectRoot, ".agent", "GEMINI.md"), name: "GEMINI.md" },
44
+ { path: path.join(projectRoot, ".agent", "ARCHITECTURE.md"), name: "ARCHITECTURE.md" }
45
+ ];
46
+
47
+ governanceFiles.forEach(file => {
48
+ if (fs.existsSync(file.path)) {
49
+ details.push(`${pc.green("✓")} ${file.name} found`);
50
+ } else {
51
+ details.push(`${pc.yellow("⚠")} ${file.name} not found (optional)`);
52
+ }
53
+ });
54
+
55
+ // Check for skills
56
+ const skillsDir = path.join(projectRoot, ".agent", "skills");
57
+ if (fs.existsSync(skillsDir)) {
58
+ const skills = fs.readdirSync(skillsDir).filter(f =>
59
+ fs.statSync(path.join(skillsDir, f)).isDirectory()
60
+ );
61
+ details.push(`${pc.green("✓")} ${skills.length} skill(s) loaded`);
62
+ }
63
+
64
+ return { passed, details };
65
+ }
66
+
67
+ // ============================================================================
68
+ // MAIN AUDIT
69
+ // ============================================================================
70
+
71
+ /**
72
+ * Run full audit on a project
73
+ * @param {string} projectRoot
74
+ */
75
+ async function runAudit(projectRoot) {
76
+ p.intro(pc.cyan(`⚖️ SMART AUDIT v${VERSION}`));
77
+
78
+ let exitCode = 0;
79
+ const startTime = Date.now();
80
+
81
+ // Phase 1: Memory Recall
82
+ const s1 = p.spinner();
83
+ s1.start("Phase 1: Memory Recall");
84
+
85
+ const db = loadKnowledge();
86
+
87
+ if (db.lessons.length === 0) {
88
+ s1.stop("Phase 1: No lessons learned yet");
89
+ } else {
90
+ const { results } = scanDirectory(projectRoot, db, SCAN_EXTENSIONS);
91
+
92
+ if (results.length > 0) {
93
+ const stats = printResults(results);
94
+ saveKnowledge(db);
95
+
96
+ if (stats.errors > 0) {
97
+ exitCode = 1;
98
+ }
99
+ s1.stop(`Phase 1: Found ${stats.total} violation(s)`);
100
+ } else {
101
+ s1.stop("Phase 1: No violations found");
102
+ }
103
+ }
104
+
105
+ // Phase 2: Governance
106
+ const s2 = p.spinner();
107
+ s2.start("Phase 2: Governance Check");
108
+
109
+ const govResult = checkGovernance(projectRoot);
110
+ s2.stop("Phase 2: Governance checked");
111
+
112
+ p.note(govResult.details.join("\n"), pc.dim("Governance"));
113
+
114
+ // Phase 3: Summary
115
+ const duration = ((Date.now() - startTime) / 1000).toFixed(2);
116
+ const totalHits = db.lessons.reduce((sum, l) => sum + (l.hitCount || 0), 0);
117
+
118
+ const summaryLines = [
119
+ `⏱️ Completed in ${duration}s`,
120
+ `📊 Lessons in memory: ${db.lessons.length}`,
121
+ `🎯 Total pattern hits: ${totalHits}`
122
+ ];
123
+ p.note(summaryLines.join("\n"), pc.dim("Summary"));
124
+
125
+ if (exitCode === 0) {
126
+ p.outro(pc.green("✅ AUDIT PASSED: Code is smart and compliant"));
127
+ } else {
128
+ p.outro(pc.red("❌ AUDIT FAILED: Please fix ERROR violations"));
129
+ }
130
+
131
+ process.exit(exitCode);
132
+ }
133
+
134
+ // ============================================================================
135
+ // CLI
136
+ // ============================================================================
137
+
138
+ const args = process.argv.slice(2);
139
+ const projectRoot = args[0] || process.cwd();
140
+
141
+ if (args.includes("--help")) {
142
+ console.log(`
143
+ ⚖️ Smart Audit - Compliance Checker
144
+
145
+ Usage:
146
+ agent audit [directory]
147
+
148
+ Options:
149
+ --help Show this help
150
+ `);
151
+ process.exit(0);
152
+ }
153
+
154
+ runAudit(projectRoot);
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @fileoverview Tests for audit.js functionality
3
+ */
4
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import os from "os";
8
+
9
+ const TEST_DIR = path.join(os.tmpdir(), "agent-skill-kit-audit-test");
10
+ const AGENT_DIR = path.join(TEST_DIR, ".agent");
11
+
12
+ describe("Audit - Governance Check", () => {
13
+ beforeEach(() => {
14
+ fs.mkdirSync(AGENT_DIR, { recursive: true });
15
+ });
16
+
17
+ afterEach(() => {
18
+ fs.rmSync(TEST_DIR, { recursive: true, force: true });
19
+ });
20
+
21
+ it("detects GEMINI.md presence", () => {
22
+ const geminiPath = path.join(AGENT_DIR, "GEMINI.md");
23
+
24
+ // Before creation
25
+ expect(fs.existsSync(geminiPath)).toBe(false);
26
+
27
+ // After creation
28
+ fs.writeFileSync(geminiPath, "# Test", "utf8");
29
+ expect(fs.existsSync(geminiPath)).toBe(true);
30
+ });
31
+
32
+ it("detects ARCHITECTURE.md presence", () => {
33
+ const archPath = path.join(AGENT_DIR, "ARCHITECTURE.md");
34
+ fs.writeFileSync(archPath, "# Architecture", "utf8");
35
+
36
+ expect(fs.existsSync(archPath)).toBe(true);
37
+ });
38
+
39
+ it("counts skills in skills directory", () => {
40
+ const skillsDir = path.join(AGENT_DIR, "skills");
41
+ fs.mkdirSync(skillsDir, { recursive: true });
42
+
43
+ // Create mock skills
44
+ fs.mkdirSync(path.join(skillsDir, "skill-1"));
45
+ fs.mkdirSync(path.join(skillsDir, "skill-2"));
46
+
47
+ const skills = fs.readdirSync(skillsDir).filter(f =>
48
+ fs.statSync(path.join(skillsDir, f)).isDirectory()
49
+ );
50
+
51
+ expect(skills.length).toBe(2);
52
+ });
53
+ });
54
+
55
+ describe("Audit - Compliance Results", () => {
56
+ it("calculates pass/fail status correctly", () => {
57
+ const results = {
58
+ errors: 0,
59
+ warnings: 2,
60
+ total: 2
61
+ };
62
+
63
+ // Errors = 0 means pass
64
+ expect(results.errors === 0).toBe(true);
65
+ });
66
+
67
+ it("fails when errors exist", () => {
68
+ const results = {
69
+ errors: 1,
70
+ warnings: 0,
71
+ total: 1
72
+ };
73
+
74
+ expect(results.errors > 0).toBe(true);
75
+ });
76
+
77
+ it("calculates total correctly", () => {
78
+ const violations = [
79
+ { lesson: { severity: "ERROR" }, matches: [1, 2] },
80
+ { lesson: { severity: "WARNING" }, matches: [1] }
81
+ ];
82
+
83
+ let total = 0;
84
+ let errors = 0;
85
+ let warnings = 0;
86
+
87
+ violations.forEach(v => {
88
+ total += v.matches.length;
89
+ if (v.lesson.severity === "ERROR") {
90
+ errors += v.matches.length;
91
+ } else {
92
+ warnings += v.matches.length;
93
+ }
94
+ });
95
+
96
+ expect(total).toBe(3);
97
+ expect(errors).toBe(2);
98
+ expect(warnings).toBe(1);
99
+ });
100
+ });