@shahmilsaari/memory-core 1.0.26 → 1.0.28
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/README.md +68 -73
- package/dist/cli.js +243 -48
- package/dist/dashboard/assets/index-9hcL4kCI.js +2 -0
- package/dist/dashboard/assets/index-DAEzcad9.css +1 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/{dashboard-server-EEFNE6NX.js → dashboard-server-S6T2XPRI.js} +35 -7
- package/package.json +1 -1
- package/dist/dashboard/assets/index-CE3AMEOD.js +0 -2
- package/dist/dashboard/assets/index-CNc2vvZF.css +0 -1
package/README.md
CHANGED
|
@@ -2,128 +2,123 @@
|
|
|
2
2
|
|
|
3
3
|
> Universal AI memory for developers. Store architecture rules once — every AI coding agent reads them before writing code.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@shahmilsaari/memory-core)
|
|
5
|
+
[](https://www.npmjs.com/package/@shahmilsaari/memory-core)
|
|
6
|
+
[](https://www.npmjs.com/package/@shahmilsaari/memory-core)
|
|
7
|
+
[](https://nodejs.org)
|
|
6
8
|
[](LICENSE)
|
|
7
9
|
|
|
8
10
|
---
|
|
9
11
|
|
|
10
|
-
##
|
|
12
|
+
## The problem
|
|
13
|
+
|
|
14
|
+
AI tools like Copilot, Cursor, and Claude Code start fresh every session. They don't know your architecture decisions, your layer boundaries, or your team conventions. They write code that violates patterns you spent months establishing.
|
|
15
|
+
|
|
16
|
+
**memory-core fixes that.** Store your rules once, enforce them everywhere.
|
|
17
|
+
|
|
18
|
+
---
|
|
11
19
|
|
|
12
|
-
|
|
20
|
+
## What it does
|
|
13
21
|
|
|
14
|
-
1. **Remember** — store architecture decisions and rules in PostgreSQL with reasons
|
|
15
|
-
2. **Distribute** — generate instruction files for 14 AI agents from your stored rules
|
|
16
|
-
3. **Enforce** — two-tier pipeline catches violations: deterministic layer graph (instant, confidence 1.0) then AI semantic review
|
|
22
|
+
1. **Remember** — store architecture decisions and rules in PostgreSQL with plain-English reasons
|
|
23
|
+
2. **Distribute** — generate instruction files for 14 AI agents automatically from your stored rules
|
|
24
|
+
3. **Enforce** — two-tier pipeline catches violations before they merge: deterministic layer graph (instant, confidence 1.0) then AI semantic review
|
|
17
25
|
|
|
18
26
|
```bash
|
|
19
27
|
npx @shahmilsaari/memory-core init
|
|
20
28
|
```
|
|
21
29
|
|
|
22
|
-
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Key features
|
|
33
|
+
|
|
34
|
+
- **281 pre-built rules** — seed best-practice rules for your stack in one command, with plain-English reasons
|
|
35
|
+
- **14 AI agents supported** — generates instruction files for Copilot, Cursor, Claude Code, Windsurf, and more automatically
|
|
36
|
+
- **Evidence-based enforcement** — catches layer violations deterministically before touching AI, then uses semantic review for the rest
|
|
37
|
+
- **Runs fully local** — embeddings stay on your machine via Ollama; use any cloud provider (DeepSeek, OpenAI, Anthropic) only for code analysis
|
|
38
|
+
- **Live dashboard** — real-time violations feed, interactive architecture graph, and model switcher at `localhost:5178`
|
|
39
|
+
- **Team-ready** — export rules to `memories.json`, commit it, and teammates import with one command — no shared database needed
|
|
40
|
+
- **CI/CD built-in** — generates a GitHub Actions workflow; CI reads `memories.json` directly, no Ollama required
|
|
41
|
+
- **Commit message linting** — enforce conventional commits or any regex pattern via the `commit-msg` hook
|
|
42
|
+
- **Violation analytics** — track which rules fire most and auto-tune noisy ones with `memory-core tune`
|
|
43
|
+
- **Pre-commit hook** — advisory or strict mode; bypass anytime with `MEMORY_CORE_SKIP_HOOK=1`
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Get started
|
|
48
|
+
|
|
49
|
+
**Requires:** Node.js ≥ 18, PostgreSQL 14+, [Ollama](https://ollama.com) with `nomic-embed-text`
|
|
23
50
|
|
|
24
51
|
```bash
|
|
25
52
|
# 1. Initialize in your project
|
|
26
53
|
npx @shahmilsaari/memory-core init
|
|
27
54
|
|
|
28
|
-
# 2. Load best-practice rules for your
|
|
55
|
+
# 2. Load best-practice rules for your stack
|
|
29
56
|
memory-core seed --arch clean-architecture
|
|
30
57
|
|
|
31
|
-
# 3. Store
|
|
58
|
+
# 3. Store your own decisions
|
|
32
59
|
memory-core remember "No direct DB calls from controllers"
|
|
33
60
|
|
|
34
|
-
# 4. Enforce on every
|
|
35
|
-
memory-core
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Architecture enforcement
|
|
39
|
-
|
|
40
|
-
The `check --diff` command runs a two-tier enforcement pipeline:
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
git diff → FileClassifier → ASTAnalyzer → GraphBuilder
|
|
44
|
-
→ RuleMatcher → EvidencePacketBuilder
|
|
45
|
-
→ graphEngine (full codebase graph)
|
|
46
|
-
→ DeterministicValidator (confidence 1.0)
|
|
47
|
-
→ AI judge (OllamaJudge / DeepSeek / OpenAI-compatible)
|
|
48
|
-
→ ConfidenceGate → allow | warn | block
|
|
61
|
+
# 4. Enforce on every commit
|
|
62
|
+
memory-core hook install
|
|
49
63
|
```
|
|
50
64
|
|
|
51
|
-
|
|
65
|
+
That's it. Every AI agent in your project now reads your rules before writing code.
|
|
52
66
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
## Installation requirements
|
|
67
|
+
---
|
|
56
68
|
|
|
57
|
-
|
|
58
|
-
|---|---|---|
|
|
59
|
-
| Node.js 18+ | Runtime | — |
|
|
60
|
-
| PostgreSQL 14+ | Rules storage | `brew install postgresql@16` |
|
|
61
|
-
| pgvector | Semantic search | `brew install pgvector` |
|
|
62
|
-
| Ollama | Local embeddings | `ollama pull nomic-embed-text` |
|
|
69
|
+
## Supported agents
|
|
63
70
|
|
|
64
|
-
|
|
71
|
+
Claude Code · GitHub Copilot · Cursor · Windsurf · Cline · Roo Code · Aider · Continue.dev · Devin · Amazon Q · Gemini Code Assist · Zed AI · JetBrains AI · OpenHands
|
|
65
72
|
|
|
66
|
-
|
|
73
|
+
---
|
|
67
74
|
|
|
68
|
-
|
|
75
|
+
## Architecture profiles
|
|
69
76
|
|
|
70
|
-
|
|
77
|
+
281 pre-built rules ready to load:
|
|
71
78
|
|
|
72
|
-
|
|
73
|
-
|---|---|
|
|
74
|
-
| `memory-core init` | Set up memory-core in the current project |
|
|
75
|
-
| `memory-core remember "..."` | Store an architecture decision |
|
|
76
|
-
| `memory-core check --diff <ref>` | Evidence-based arch enforcement against a git ref |
|
|
77
|
-
| `memory-core check --staged` | Check staged diff (pre-commit hook path) |
|
|
78
|
-
| `memory-core watch --auto-fix` | Real-time violation detection with AI auto-fix |
|
|
79
|
-
| `memory-core dashboard` | Live command center at `localhost:5178` |
|
|
80
|
-
| `memory-core graph build` | Snapshot full codebase dependency graph |
|
|
81
|
-
| `memory-core seed` | Load 281 best-practice rules |
|
|
82
|
-
| `memory-core sync` | Regenerate all agent instruction files |
|
|
83
|
-
| `memory-core export` | Export rules to `memories.json` for team sharing |
|
|
79
|
+
`clean-architecture` · `nestjs` · `react` · `svelte` · `vue` · `hexagonal` · `modular-monolith` · `mvc` · `laravel-service-repository` · `nuxt` · `angular` · `go-api` · `react-native`
|
|
84
80
|
|
|
85
|
-
|
|
81
|
+
---
|
|
86
82
|
|
|
87
|
-
##
|
|
83
|
+
## Commands
|
|
88
84
|
|
|
89
85
|
```bash
|
|
90
|
-
memory-core
|
|
86
|
+
memory-core remember "..." # store a rule or decision
|
|
87
|
+
memory-core sync # push rules to all AI agent files
|
|
88
|
+
memory-core check --diff HEAD~1 # enforce architecture on a diff
|
|
89
|
+
memory-core watch # real-time violation detection
|
|
90
|
+
memory-core dashboard # live command center at localhost:5178
|
|
91
|
+
memory-core export # share rules with your team via memories.json
|
|
92
|
+
memory-core stats # see which rules fire most
|
|
91
93
|
```
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
- Model switcher — change provider/model without restart
|
|
97
|
-
- Token usage — Ollama shows "LOCAL (FREE)", paid providers show real counts
|
|
98
|
-
- Actions panel — Sync Agents, Check All without opening a terminal
|
|
95
|
+
→ [Full command reference](COMMANDS.md)
|
|
96
|
+
|
|
97
|
+
---
|
|
99
98
|
|
|
100
99
|
## Environment
|
|
101
100
|
|
|
102
101
|
```env
|
|
103
|
-
|
|
104
|
-
DATABASE_URL=postgres://localhost:5432/memory_core
|
|
105
|
-
|
|
106
|
-
# Ollama (local, for embeddings)
|
|
102
|
+
DATABASE_URL=postgresql://localhost:5432/memory_core
|
|
107
103
|
OLLAMA_URL=http://localhost:11434
|
|
108
104
|
OLLAMA_MODEL=nomic-embed-text
|
|
109
105
|
|
|
110
|
-
# AI provider for code analysis
|
|
111
|
-
CHAT_PROVIDER=ollama
|
|
112
|
-
CHAT_MODEL=qwen2.5-coder:7b
|
|
113
|
-
|
|
114
|
-
# OpenAI-compatible (e.g. DeepSeek)
|
|
106
|
+
# Pick your AI provider for code analysis
|
|
115
107
|
CHAT_PROVIDER=openai-compatible
|
|
116
|
-
CHAT_BASE_URL=https://api.deepseek.com
|
|
108
|
+
CHAT_BASE_URL=https://api.deepseek.com
|
|
117
109
|
CHAT_MODEL=deepseek-chat
|
|
118
110
|
CHAT_API_KEY=sk-...
|
|
119
111
|
```
|
|
120
112
|
|
|
121
|
-
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Links
|
|
122
116
|
|
|
117
|
+
- [Website](https://memory-core.shahmilsaari.my/)
|
|
123
118
|
- [Commands reference](COMMANDS.md)
|
|
124
|
-
- [Dashboard](docs/dashboard.md)
|
|
125
|
-
|
|
126
|
-
|
|
119
|
+
- [Dashboard guide](docs/dashboard.md)
|
|
120
|
+
|
|
121
|
+
---
|
|
127
122
|
|
|
128
123
|
## License
|
|
129
124
|
|
package/dist/cli.js
CHANGED
|
@@ -130,8 +130,15 @@ function printBanner(projectName, agentCount, status) {
|
|
|
130
130
|
}
|
|
131
131
|
var { version } = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
132
132
|
var CONFIG_FILE = ".memory-core.json";
|
|
133
|
-
var LOCAL_GENERATED_FILES = [".memory-core-stats.json"];
|
|
133
|
+
var LOCAL_GENERATED_FILES = [".memory-core-stats.json", ".memory-core-db-version"];
|
|
134
134
|
var LOCAL_STATE_FILES = [CONFIG_FILE, ".memory-core.env", ...LOCAL_GENERATED_FILES];
|
|
135
|
+
var ARCHMIND_RUNTIME_FILES = [
|
|
136
|
+
".archmind/approval-queue.json",
|
|
137
|
+
".archmind/watch-errors.json",
|
|
138
|
+
".archmind/check.log",
|
|
139
|
+
".archmind/cache/",
|
|
140
|
+
".archmind/violation-history.json"
|
|
141
|
+
];
|
|
135
142
|
var CI_WORKFLOW_FILE = ".github/workflows/memory-core.yml";
|
|
136
143
|
var GITIGNORE_HEADING = "# memory-core generated files";
|
|
137
144
|
var DEFAULT_OLLAMA_URL = "http://localhost:11434";
|
|
@@ -720,7 +727,7 @@ program.command("init").description("Initialize memory-core in the current proje
|
|
|
720
727
|
};
|
|
721
728
|
writeRuntimeEnv(envValues, envPath);
|
|
722
729
|
applyRuntimeEnv(envValues);
|
|
723
|
-
appendMissingGitignoreEntries(LOCAL_STATE_FILES, GITIGNORE_HEADING);
|
|
730
|
+
appendMissingGitignoreEntries([...LOCAL_STATE_FILES, ...ARCHMIND_RUNTIME_FILES], GITIGNORE_HEADING);
|
|
724
731
|
console.log(chalk.green(" \u2713 .memory-core.env created with local defaults"));
|
|
725
732
|
} else if (!hasEnv) {
|
|
726
733
|
console.log(chalk.dim(" No .memory-core.env found \u2014 let's set up your connection.\n"));
|
|
@@ -868,7 +875,7 @@ program.command("init").description("Initialize memory-core in the current proje
|
|
|
868
875
|
if (chatApiKey) envValues.CHAT_API_KEY = chatApiKey;
|
|
869
876
|
writeRuntimeEnv(envValues, envPath);
|
|
870
877
|
applyRuntimeEnv(envValues);
|
|
871
|
-
appendMissingGitignoreEntries(LOCAL_STATE_FILES, GITIGNORE_HEADING);
|
|
878
|
+
appendMissingGitignoreEntries([...LOCAL_STATE_FILES, ...ARCHMIND_RUNTIME_FILES], GITIGNORE_HEADING);
|
|
872
879
|
console.log(chalk.green("\n \u2713 .memory-core.env created"));
|
|
873
880
|
console.log(chalk.gray(" Added to .gitignore \u2014 your DB credentials stay local.\n"));
|
|
874
881
|
} else {
|
|
@@ -1067,7 +1074,8 @@ program.command("init").description("Initialize memory-core in the current proje
|
|
|
1067
1074
|
console.log(chalk.green(" \u2713 Created .archmind/layers.json"));
|
|
1068
1075
|
}
|
|
1069
1076
|
if (!existsSync(rulesPath)) {
|
|
1070
|
-
|
|
1077
|
+
const arch2 = backendArchitecture ?? frontendFramework ?? "custom";
|
|
1078
|
+
writeFileSync(rulesPath, JSON.stringify(buildArchRules(arch2), null, 2) + "\n", "utf-8");
|
|
1071
1079
|
console.log(chalk.green(" \u2713 Created .archmind/rules.json"));
|
|
1072
1080
|
}
|
|
1073
1081
|
if (!existsSync(archmindGitignorePath)) {
|
|
@@ -1082,7 +1090,7 @@ program.command("init").description("Initialize memory-core in the current proje
|
|
|
1082
1090
|
} catch {
|
|
1083
1091
|
console.log(chalk.dim(" (graph build skipped \u2014 run `memory-core graph build` once manually)"));
|
|
1084
1092
|
}
|
|
1085
|
-
const gitignoreEntries = [...written.written, ...LOCAL_GENERATED_FILES];
|
|
1093
|
+
const gitignoreEntries = [...written.written, ...LOCAL_GENERATED_FILES, ...ARCHMIND_RUNTIME_FILES];
|
|
1086
1094
|
if (gitignoreEntries.length > 0) {
|
|
1087
1095
|
const added = appendMissingGitignoreEntries(gitignoreEntries, GITIGNORE_HEADING);
|
|
1088
1096
|
if (added > 0) {
|
|
@@ -1745,7 +1753,7 @@ program.command("dashboard").description("Start the live Svelte dashboard with W
|
|
|
1745
1753
|
}
|
|
1746
1754
|
return void 0;
|
|
1747
1755
|
};
|
|
1748
|
-
const { startDashboard } = await import("./dashboard-server-
|
|
1756
|
+
const { startDashboard } = await import("./dashboard-server-S6T2XPRI.js");
|
|
1749
1757
|
await startDashboard({
|
|
1750
1758
|
port: parseInt(opts.port, 10),
|
|
1751
1759
|
path: resolveDashboardPath(),
|
|
@@ -1795,6 +1803,19 @@ program.command("seed").description("Load all predefined memories into the datab
|
|
|
1795
1803
|
const dbVersionPath = join(process.cwd(), ".memory-core-db-version");
|
|
1796
1804
|
writeFileSync(dbVersionPath, (/* @__PURE__ */ new Date()).toISOString() + "\n", "utf-8");
|
|
1797
1805
|
}
|
|
1806
|
+
if (opts.arch) {
|
|
1807
|
+
try {
|
|
1808
|
+
const archmindDir = join(process.cwd(), ".archmind");
|
|
1809
|
+
mkdirSync(archmindDir, { recursive: true });
|
|
1810
|
+
const layersPath = join(archmindDir, "layers.json");
|
|
1811
|
+
const rulesPath = join(archmindDir, "rules.json");
|
|
1812
|
+
writeFileSync(layersPath, JSON.stringify(buildLayersTemplate(opts.arch), null, 2) + "\n", "utf-8");
|
|
1813
|
+
writeFileSync(rulesPath, JSON.stringify(buildArchRules(opts.arch), null, 2) + "\n", "utf-8");
|
|
1814
|
+
console.log(chalk.green(` \u2713 Updated .archmind/layers.json for ${opts.arch}`));
|
|
1815
|
+
console.log(chalk.green(` \u2713 Updated .archmind/rules.json for ${opts.arch}`));
|
|
1816
|
+
} catch {
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1798
1819
|
console.log(chalk.bold.green(`
|
|
1799
1820
|
Done. ${saved} memories seeded, ${skipped} skipped.
|
|
1800
1821
|
`));
|
|
@@ -2554,51 +2575,225 @@ program.command("watch").description("Watch source files and check violations in
|
|
|
2554
2575
|
});
|
|
2555
2576
|
});
|
|
2556
2577
|
var ARCHMIND_DIR = join(process.cwd(), ".archmind");
|
|
2557
|
-
var DEFAULT_ARCH_RULES = {
|
|
2558
|
-
rules: [
|
|
2559
|
-
{ id: "domain-no-infra", name: "Domain must not import infrastructure", fromLayer: "domain", toLayer: "infrastructure", allowed: false, severity: "critical", enforcement: "block" },
|
|
2560
|
-
{ id: "domain-no-api", name: "Domain must not import API layer", fromLayer: "domain", toLayer: "api", allowed: false, severity: "critical", enforcement: "block" },
|
|
2561
|
-
{ id: "api-no-infra-direct", name: "API should not import infrastructure directly", fromLayer: "api", toLayer: "infrastructure", allowed: false, severity: "medium", enforcement: "warn" },
|
|
2562
|
-
{ id: "api-depends-on-domain", name: "API depends on domain", fromLayer: "api", toLayer: "domain", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2563
|
-
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2564
|
-
{ id: "application-no-api", name: "Application must not import API layer", fromLayer: "application", toLayer: "api", allowed: false, severity: "critical", enforcement: "block" },
|
|
2565
|
-
{ id: "application-uses-domain", name: "Application depends on domain", fromLayer: "application", toLayer: "domain", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2566
|
-
{ id: "shared-no-domain", name: "Shared must not import domain", fromLayer: "shared", toLayer: "domain", allowed: false, severity: "medium", enforcement: "warn" }
|
|
2567
|
-
]
|
|
2568
|
-
};
|
|
2569
2578
|
function buildLayersTemplate(arch2) {
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2579
|
+
switch (arch2) {
|
|
2580
|
+
case "nestjs":
|
|
2581
|
+
return {
|
|
2582
|
+
layers: [
|
|
2583
|
+
{ name: "modules", paths: ["src/modules/**"], description: "Feature modules \u2014 each owns its controller, service, DTOs, entities" },
|
|
2584
|
+
{ name: "controllers", paths: ["src/modules/*/controllers/**", "src/modules/*.controller.ts"], description: "HTTP request handlers \u2014 thin, delegate to services" },
|
|
2585
|
+
{ name: "services", paths: ["src/modules/*/services/**", "src/modules/*.service.ts"], description: "Business logic \u2014 never import controllers or HTTP classes" },
|
|
2586
|
+
{ name: "repositories", paths: ["src/modules/*/repositories/**"], description: "Data access \u2014 services depend on these interfaces" },
|
|
2587
|
+
{ name: "common", paths: ["src/common/**", "src/guards/**", "src/filters/**", "src/interceptors/**", "src/pipes/**"], description: "Guards, filters, interceptors, pipes" }
|
|
2588
|
+
]
|
|
2589
|
+
};
|
|
2590
|
+
case "mvc":
|
|
2591
|
+
return {
|
|
2592
|
+
layers: [
|
|
2593
|
+
{ name: "models", paths: ["src/models/**", "app/models/**"], description: "Data models \u2014 represent DB records" },
|
|
2594
|
+
{ name: "controllers", paths: ["src/controllers/**", "app/controllers/**"], description: "Route handlers \u2014 thin, delegate to services" },
|
|
2595
|
+
{ name: "services", paths: ["src/services/**", "app/services/**"], description: "Business logic \u2014 called by controllers" },
|
|
2596
|
+
{ name: "views", paths: ["src/views/**", "app/views/**", "resources/views/**"], description: "Templates and view logic" },
|
|
2597
|
+
{ name: "shared", paths: ["src/utils/**", "src/helpers/**", "app/helpers/**"], description: "Shared utilities and helpers" }
|
|
2598
|
+
]
|
|
2599
|
+
};
|
|
2600
|
+
case "laravel-service-repository":
|
|
2601
|
+
return {
|
|
2602
|
+
layers: [
|
|
2603
|
+
{ name: "models", paths: ["app/Models/**"], description: "Eloquent models" },
|
|
2604
|
+
{ name: "controllers", paths: ["app/Http/Controllers/**"], description: "HTTP controllers \u2014 thin, delegate to services" },
|
|
2605
|
+
{ name: "services", paths: ["app/Services/**"], description: "Business logic services" },
|
|
2606
|
+
{ name: "repositories", paths: ["app/Repositories/**"], description: "Data access \u2014 services depend on these" },
|
|
2607
|
+
{ name: "shared", paths: ["app/Helpers/**", "app/Traits/**"], description: "Helpers and traits" }
|
|
2608
|
+
]
|
|
2609
|
+
};
|
|
2610
|
+
case "go-api":
|
|
2611
|
+
return {
|
|
2612
|
+
layers: [
|
|
2613
|
+
{ name: "handlers", paths: ["internal/handlers/**", "api/**"], description: "HTTP handlers \u2014 parse request, call service, write response" },
|
|
2614
|
+
{ name: "services", paths: ["internal/services/**"], description: "Business logic \u2014 orchestrates domain and repositories" },
|
|
2615
|
+
{ name: "repositories", paths: ["internal/repositories/**", "internal/store/**"], description: "Data access \u2014 DB queries, external calls" },
|
|
2616
|
+
{ name: "models", paths: ["internal/models/**", "internal/domain/**"], description: "Structs and domain types" },
|
|
2617
|
+
{ name: "shared", paths: ["pkg/**", "internal/utils/**"], description: "Shared packages \u2014 no business logic" }
|
|
2618
|
+
]
|
|
2619
|
+
};
|
|
2620
|
+
case "react":
|
|
2621
|
+
return {
|
|
2622
|
+
layers: [
|
|
2623
|
+
{ name: "pages", paths: ["src/pages/**", "src/app/**", "src/routes/**"], description: "Route-level components \u2014 wire hooks and components together" },
|
|
2624
|
+
{ name: "components", paths: ["src/components/**"], description: "Reusable UI components \u2014 presentational and feature" },
|
|
2625
|
+
{ name: "hooks", paths: ["src/hooks/**"], description: "Custom hooks \u2014 stateful and side-effect logic" },
|
|
2626
|
+
{ name: "store", paths: ["src/store/**", "src/state/**", "src/atoms/**"], description: "Global client state \u2014 Zustand, Jotai, Redux" },
|
|
2627
|
+
{ name: "services", paths: ["src/services/**", "src/api/**", "src/clients/**"], description: "API clients and external service calls" }
|
|
2628
|
+
]
|
|
2629
|
+
};
|
|
2630
|
+
case "vue":
|
|
2631
|
+
return {
|
|
2632
|
+
layers: [
|
|
2633
|
+
{ name: "pages", paths: ["src/pages/**", "src/views/**"], description: "Route-level views" },
|
|
2634
|
+
{ name: "components", paths: ["src/components/**"], description: "Reusable Vue components" },
|
|
2635
|
+
{ name: "composables", paths: ["src/composables/**"], description: "Composables \u2014 stateful and reusable logic" },
|
|
2636
|
+
{ name: "store", paths: ["src/stores/**", "src/store/**"], description: "Pinia stores \u2014 global state" },
|
|
2637
|
+
{ name: "services", paths: ["src/services/**", "src/api/**"], description: "API clients and external calls" }
|
|
2638
|
+
]
|
|
2639
|
+
};
|
|
2640
|
+
case "svelte":
|
|
2641
|
+
return {
|
|
2642
|
+
layers: [
|
|
2643
|
+
{ name: "routes", paths: ["src/routes/**"], description: "SvelteKit routes \u2014 pages and layouts" },
|
|
2644
|
+
{ name: "components", paths: ["src/lib/components/**", "src/components/**"], description: "Reusable Svelte components" },
|
|
2645
|
+
{ name: "stores", paths: ["src/lib/stores/**", "src/stores/**"], description: "Svelte stores \u2014 reactive state" },
|
|
2646
|
+
{ name: "lib", paths: ["src/lib/**"], description: "Shared utilities, server actions, API clients" },
|
|
2647
|
+
{ name: "utils", paths: ["src/utils/**", "src/helpers/**"], description: "Pure utility functions" }
|
|
2648
|
+
]
|
|
2649
|
+
};
|
|
2650
|
+
case "nuxt":
|
|
2651
|
+
return {
|
|
2652
|
+
layers: [
|
|
2653
|
+
{ name: "pages", paths: ["pages/**"], description: "Nuxt pages \u2014 file-based routing" },
|
|
2654
|
+
{ name: "components", paths: ["components/**"], description: "Auto-imported Vue components" },
|
|
2655
|
+
{ name: "composables", paths: ["composables/**"], description: "Auto-imported composables" },
|
|
2656
|
+
{ name: "server", paths: ["server/**"], description: "Nitro server routes and API" },
|
|
2657
|
+
{ name: "utils", paths: ["utils/**", "lib/**"], description: "Shared utilities" }
|
|
2658
|
+
]
|
|
2659
|
+
};
|
|
2660
|
+
case "angular":
|
|
2661
|
+
return {
|
|
2662
|
+
layers: [
|
|
2663
|
+
{ name: "modules", paths: ["src/app/**/*.module.ts"], description: "Angular feature modules" },
|
|
2664
|
+
{ name: "components", paths: ["src/app/**/*.component.ts"], description: "Components \u2014 UI logic only" },
|
|
2665
|
+
{ name: "services", paths: ["src/app/**/*.service.ts"], description: "Injectable services \u2014 business logic and HTTP" },
|
|
2666
|
+
{ name: "guards", paths: ["src/app/**/*.guard.ts"], description: "Route guards \u2014 auth and access control" },
|
|
2667
|
+
{ name: "shared", paths: ["src/app/shared/**", "src/shared/**"], description: "Shared module \u2014 directives, pipes, components" }
|
|
2668
|
+
]
|
|
2669
|
+
};
|
|
2670
|
+
case "react-native":
|
|
2671
|
+
return {
|
|
2672
|
+
layers: [
|
|
2673
|
+
{ name: "screens", paths: ["src/screens/**", "app/**"], description: "Screen components \u2014 navigation targets" },
|
|
2674
|
+
{ name: "components", paths: ["src/components/**"], description: "Reusable UI components" },
|
|
2675
|
+
{ name: "hooks", paths: ["src/hooks/**"], description: "Custom hooks \u2014 stateful logic" },
|
|
2676
|
+
{ name: "store", paths: ["src/store/**", "src/state/**"], description: "Global state \u2014 Zustand, Redux, Jotai" },
|
|
2677
|
+
{ name: "services", paths: ["src/services/**", "src/api/**"], description: "API clients and native service wrappers" }
|
|
2678
|
+
]
|
|
2679
|
+
};
|
|
2680
|
+
case "hexagonal":
|
|
2681
|
+
return {
|
|
2682
|
+
layers: [
|
|
2683
|
+
{ name: "domain", paths: ["src/domain/**", "src/core/**"], description: "Pure domain \u2014 entities, value objects, domain services" },
|
|
2684
|
+
{ name: "ports", paths: ["src/ports/**", "src/application/ports/**"], description: "Interfaces \u2014 driving and driven port contracts" },
|
|
2685
|
+
{ name: "adapters", paths: ["src/adapters/**", "src/infrastructure/adapters/**"], description: "Adapter implementations \u2014 REST, DB, queues" },
|
|
2686
|
+
{ name: "infrastructure", paths: ["src/infrastructure/**"], description: "Technical infrastructure \u2014 config, DI, framework" },
|
|
2687
|
+
{ name: "shared", paths: ["src/shared/**", "src/utils/**"], description: "Cross-cutting utilities" }
|
|
2688
|
+
]
|
|
2689
|
+
};
|
|
2690
|
+
case "modular-monolith":
|
|
2691
|
+
return {
|
|
2692
|
+
layers: [
|
|
2693
|
+
{ name: "modules", paths: ["src/modules/**"], description: "Self-contained feature modules \u2014 each owns its DB, API, logic" },
|
|
2694
|
+
{ name: "shared", paths: ["src/shared/**", "src/common/**"], description: "Shared kernel \u2014 only pure utilities, no module business logic" },
|
|
2695
|
+
{ name: "infrastructure", paths: ["src/infrastructure/**"], description: "Technical infrastructure \u2014 DB connections, messaging, config" },
|
|
2696
|
+
{ name: "api", paths: ["src/api/**", "src/interfaces/**"], description: "Public API surface \u2014 HTTP, GraphQL, events" }
|
|
2697
|
+
]
|
|
2698
|
+
};
|
|
2699
|
+
default:
|
|
2700
|
+
return {
|
|
2701
|
+
layers: [
|
|
2702
|
+
{ name: "domain", paths: ["src/domain/**", "src/core/domain/**", "src/modules/*/domain/**"], description: "Business logic, entities, use cases" },
|
|
2703
|
+
{ name: "application", paths: ["src/application/**", "src/core/application/**", "src/modules/*/application/**"], description: "Use cases and orchestration" },
|
|
2704
|
+
{ name: "infrastructure", paths: ["src/infrastructure/**", "src/modules/*/infrastructure/**"], description: "Database, external APIs, low-level I/O" },
|
|
2705
|
+
{ name: "api", paths: ["src/api/**", "src/interfaces/**", "src/controllers/**"], description: "HTTP handlers, request/response" },
|
|
2706
|
+
{ name: "shared", paths: ["src/shared/**", "src/utils/**", "src/helpers/**"], description: "Utilities, helpers, constants" }
|
|
2707
|
+
]
|
|
2708
|
+
};
|
|
2581
2709
|
}
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
{
|
|
2588
|
-
{ name: "
|
|
2589
|
-
{
|
|
2590
|
-
|
|
2591
|
-
|
|
2710
|
+
}
|
|
2711
|
+
function buildArchRules(arch2) {
|
|
2712
|
+
switch (arch2) {
|
|
2713
|
+
case "nestjs":
|
|
2714
|
+
return { rules: [
|
|
2715
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2716
|
+
{ id: "controllers-no-repos", name: "Controllers must not import repositories", fromLayer: "controllers", toLayer: "repositories", allowed: false, severity: "critical", enforcement: "block" },
|
|
2717
|
+
{ id: "services-no-controllers", name: "Services must not import controllers", fromLayer: "services", toLayer: "controllers", allowed: false, severity: "critical", enforcement: "block" },
|
|
2718
|
+
{ id: "controllers-use-services", name: "Controllers delegate to services", fromLayer: "controllers", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2719
|
+
{ id: "services-use-repos", name: "Services use repositories", fromLayer: "services", toLayer: "repositories", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2720
|
+
{ id: "common-no-modules", name: "Common must not import feature modules", fromLayer: "common", toLayer: "modules", allowed: false, severity: "medium", enforcement: "warn" }
|
|
2721
|
+
] };
|
|
2722
|
+
case "mvc":
|
|
2723
|
+
case "laravel-service-repository":
|
|
2724
|
+
return { rules: [
|
|
2725
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2726
|
+
{ id: "controllers-no-models", name: "Controllers must not query models directly", fromLayer: "controllers", toLayer: "models", allowed: false, severity: "medium", enforcement: "warn" },
|
|
2727
|
+
{ id: "controllers-use-services", name: "Controllers delegate to services", fromLayer: "controllers", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2728
|
+
{ id: "services-use-repos", name: "Services use repositories for data access", fromLayer: "services", toLayer: "repositories", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2729
|
+
{ id: "shared-no-controllers", name: "Shared must not import controllers", fromLayer: "shared", toLayer: "controllers", allowed: false, severity: "medium", enforcement: "warn" }
|
|
2730
|
+
] };
|
|
2731
|
+
case "go-api":
|
|
2732
|
+
return { rules: [
|
|
2733
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2734
|
+
{ id: "handlers-no-repos", name: "Handlers must not import repositories", fromLayer: "handlers", toLayer: "repositories", allowed: false, severity: "critical", enforcement: "block" },
|
|
2735
|
+
{ id: "handlers-use-services", name: "Handlers call services only", fromLayer: "handlers", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2736
|
+
{ id: "services-use-repos", name: "Services use repositories", fromLayer: "services", toLayer: "repositories", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2737
|
+
{ id: "shared-no-services", name: "Shared must not import services", fromLayer: "shared", toLayer: "services", allowed: false, severity: "medium", enforcement: "warn" }
|
|
2738
|
+
] };
|
|
2739
|
+
case "react":
|
|
2740
|
+
case "react-native":
|
|
2741
|
+
return { rules: [
|
|
2742
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2743
|
+
{ id: "components-no-pages", name: "Components must not import pages", fromLayer: "components", toLayer: "pages", allowed: false, severity: "critical", enforcement: "block" },
|
|
2744
|
+
{ id: "components-no-store", name: "Presentational components must not read store", fromLayer: "components", toLayer: "store", allowed: false, severity: "medium", enforcement: "warn" },
|
|
2745
|
+
{ id: "services-no-components", name: "Services must not import components", fromLayer: "services", toLayer: "components", allowed: false, severity: "critical", enforcement: "block" },
|
|
2746
|
+
{ id: "hooks-use-services", name: "Hooks use services for API calls", fromLayer: "hooks", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" }
|
|
2747
|
+
] };
|
|
2748
|
+
case "vue":
|
|
2749
|
+
case "nuxt":
|
|
2750
|
+
return { rules: [
|
|
2751
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2752
|
+
{ id: "components-no-pages", name: "Components must not import pages/views", fromLayer: "components", toLayer: "pages", allowed: false, severity: "critical", enforcement: "block" },
|
|
2753
|
+
{ id: "services-no-components", name: "Services must not import components", fromLayer: "services", toLayer: "components", allowed: false, severity: "critical", enforcement: "block" },
|
|
2754
|
+
{ id: "composables-use-services", name: "Composables use services for API calls", fromLayer: "composables", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2755
|
+
{ id: "store-no-components", name: "Store must not import components", fromLayer: "store", toLayer: "components", allowed: false, severity: "medium", enforcement: "warn" }
|
|
2756
|
+
] };
|
|
2757
|
+
case "svelte":
|
|
2758
|
+
return { rules: [
|
|
2759
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2760
|
+
{ id: "components-no-routes", name: "Components must not import route modules", fromLayer: "components", toLayer: "routes", allowed: false, severity: "critical", enforcement: "block" },
|
|
2761
|
+
{ id: "stores-no-components", name: "Stores must not import components", fromLayer: "stores", toLayer: "components", allowed: false, severity: "critical", enforcement: "block" },
|
|
2762
|
+
{ id: "utils-no-stores", name: "Utils must not import stores", fromLayer: "utils", toLayer: "stores", allowed: false, severity: "medium", enforcement: "warn" }
|
|
2763
|
+
] };
|
|
2764
|
+
case "angular":
|
|
2765
|
+
return { rules: [
|
|
2766
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2767
|
+
{ id: "components-no-services-in-template", name: "Components use DI \u2014 do not import services directly", fromLayer: "components", toLayer: "services", allowed: false, severity: "medium", enforcement: "warn" },
|
|
2768
|
+
{ id: "guards-use-services", name: "Guards use auth services", fromLayer: "guards", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2769
|
+
{ id: "shared-no-modules", name: "Shared must not import feature modules", fromLayer: "shared", toLayer: "modules", allowed: false, severity: "medium", enforcement: "warn" }
|
|
2770
|
+
] };
|
|
2771
|
+
case "hexagonal":
|
|
2772
|
+
return { rules: [
|
|
2773
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2774
|
+
{ id: "domain-no-adapters", name: "Domain must not import adapters", fromLayer: "domain", toLayer: "adapters", allowed: false, severity: "critical", enforcement: "block" },
|
|
2775
|
+
{ id: "domain-no-infra", name: "Domain must not import infrastructure", fromLayer: "domain", toLayer: "infrastructure", allowed: false, severity: "critical", enforcement: "block" },
|
|
2776
|
+
{ id: "adapters-implement-ports", name: "Adapters implement port interfaces", fromLayer: "adapters", toLayer: "ports", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2777
|
+
{ id: "ports-no-adapters", name: "Ports must not import adapters", fromLayer: "ports", toLayer: "adapters", allowed: false, severity: "critical", enforcement: "block" }
|
|
2778
|
+
] };
|
|
2779
|
+
case "modular-monolith":
|
|
2780
|
+
return { rules: [
|
|
2781
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2782
|
+
{ id: "modules-no-direct-import", name: "Modules must not import each other directly", fromLayer: "modules", toLayer: "modules", allowed: false, severity: "critical", enforcement: "block" },
|
|
2783
|
+
{ id: "shared-no-modules", name: "Shared kernel must not import feature modules", fromLayer: "shared", toLayer: "modules", allowed: false, severity: "critical", enforcement: "block" },
|
|
2784
|
+
{ id: "modules-use-shared", name: "Modules may use shared kernel", fromLayer: "modules", toLayer: "shared", allowed: true, severity: "low", enforcement: "suggest" }
|
|
2785
|
+
] };
|
|
2786
|
+
default:
|
|
2787
|
+
return { rules: [
|
|
2788
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
2789
|
+
{ id: "domain-no-infra", name: "Domain must not import infrastructure", fromLayer: "domain", toLayer: "infrastructure", allowed: false, severity: "critical", enforcement: "block" },
|
|
2790
|
+
{ id: "domain-no-api", name: "Domain must not import API layer", fromLayer: "domain", toLayer: "api", allowed: false, severity: "critical", enforcement: "block" },
|
|
2791
|
+
{ id: "api-no-infra-direct", name: "API should not import infrastructure directly", fromLayer: "api", toLayer: "infrastructure", allowed: false, severity: "medium", enforcement: "warn" },
|
|
2792
|
+
{ id: "application-no-api", name: "Application must not import API layer", fromLayer: "application", toLayer: "api", allowed: false, severity: "critical", enforcement: "block" },
|
|
2793
|
+
{ id: "application-uses-domain", name: "Application depends on domain", fromLayer: "application", toLayer: "domain", allowed: true, severity: "low", enforcement: "suggest" },
|
|
2794
|
+
{ id: "shared-no-domain", name: "Shared must not import domain", fromLayer: "shared", toLayer: "domain", allowed: false, severity: "medium", enforcement: "warn" }
|
|
2795
|
+
] };
|
|
2592
2796
|
}
|
|
2593
|
-
return {
|
|
2594
|
-
layers: [
|
|
2595
|
-
{ name: "domain", paths: ["src/domain/**", "src/core/domain/**", "src/modules/*/domain/**"], description: "Business logic, entities, use cases" },
|
|
2596
|
-
{ name: "application", paths: ["src/application/**", "src/core/application/**", "src/modules/*/application/**"], description: "Use cases and orchestration" },
|
|
2597
|
-
{ name: "infrastructure", paths: ["src/infrastructure/**", "src/modules/*/infrastructure/**"], description: "Database, external APIs, low-level I/O" },
|
|
2598
|
-
{ name: "api", paths: ["src/api/**", "src/interfaces/**", "src/controllers/**"], description: "HTTP handlers, request/response" },
|
|
2599
|
-
{ name: "shared", paths: ["src/shared/**", "src/utils/**", "src/helpers/**"], description: "Utilities, helpers, constants" }
|
|
2600
|
-
]
|
|
2601
|
-
};
|
|
2602
2797
|
}
|
|
2603
2798
|
function getArchmindDir() {
|
|
2604
2799
|
return ARCHMIND_DIR;
|