@shahmilsaari/memory-core 1.0.32 → 1.0.35
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 +8 -6
- package/dist/{approval-queue-YBYRGBHP.js → approval-queue-4RK46FNE.js} +2 -1
- package/dist/{ast-analyzer-JM4CIOFY.js → ast-analyzer-WGTJKGAP.js} +1 -0
- package/dist/{check-cache-6NWRTZJD.js → check-cache-ZVFHTA2C.js} +1 -0
- package/dist/{check-logger-5HYSWA3S.js → check-logger-F4DW4LBY.js} +1 -0
- package/dist/chunk-2LNDQGDD.js +37 -0
- package/dist/{chunk-23GUWJ6F.js → chunk-4QWIYO2G.js} +3071 -3271
- package/dist/{chunk-GIPKVQSA.js → chunk-5T2QBBYT.js} +3 -29
- package/dist/chunk-FPRSYCOZ.js +77 -0
- package/dist/chunk-HJCPBM7B.js +238 -0
- package/dist/chunk-K3NQKI34.js +10 -0
- package/dist/chunk-SKR44CRD.js +35 -0
- package/dist/{chunk-W6WEAV3S.js → chunk-UMYJQWIE.js} +13 -11
- package/dist/{chunk-PQBWHAZN.js → chunk-XAE3RY5D.js} +5 -2
- package/dist/{classifier-MZ65R7FK.js → classifier-D5K3X7FQ.js} +1 -0
- package/dist/cli.js +244 -80
- package/dist/{confidence-gate-ZQDAOS6P.js → confidence-gate-AT2MW4NK.js} +8 -6
- package/dist/dashboard/assets/index-BcDOsQwz.css +1 -0
- package/dist/dashboard/assets/index-DGx4sRHq.js +2 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/{dashboard-server-MD6NVL2F.js → dashboard-server-UBZHOPRC.js} +274 -21
- package/dist/{db-FLFZZXG3.js → db-RE23O4DV.js} +3 -1
- package/dist/{deterministic-validator-PP56B46I.js → deterministic-validator-3LB234OG.js} +1 -0
- package/dist/draft-rule-NUXOSRRS.js +11 -0
- package/dist/embedding-VIMV6O2P.js +9 -0
- package/dist/{evidence-HVMSONTT.js → evidence-WFMGWSOP.js} +1 -0
- package/dist/{graph-TFNTB5OK.js → graph-UJJAKNHD.js} +1 -0
- package/dist/{incident-capture-RVPZULS7.js → incident-capture-5YUVJJM3.js} +11 -0
- package/dist/mcp-server-3N7R46BS.js +14958 -0
- package/dist/memory-selection-A5CQ6ZT5.js +29 -0
- package/dist/{deepseek-critique-MALVIYGF.js → model-critique-E2GNZ42U.js} +18 -32
- package/dist/{ollama-judge-D2LFK5PB.js → ollama-judge-6ZEZN4JV.js} +29 -41
- package/dist/{rate-limiter-SLIPCXRF.js → rate-limiter-KIMXTAAU.js} +1 -0
- package/dist/{rules-V3QMN3AR.js → rules-UUVIKEDM.js} +1 -0
- package/dist/{watch-errors-B3FA26N4.js → watch-errors-DZMW3CFN.js} +28 -33
- package/package.json +2 -1
- package/templates/AGENTS.md.hbs +11 -27
- package/templates/AI_RULES.md.hbs +9 -23
- package/templates/ARCHITECTURE.md.hbs +9 -30
- package/templates/CLAUDE.md.hbs +10 -35
- package/templates/DEVIN.md.hbs +7 -16
- package/templates/PROJECT_MEMORY.md.hbs +5 -21
- package/templates/amazonq-guidelines.md.hbs +7 -16
- package/templates/clinerules.hbs +8 -17
- package/templates/copilot-instructions.md.hbs +7 -16
- package/templates/cursor-rule.mdc.hbs +4 -9
- package/templates/cursorrules.hbs +8 -14
- package/templates/gemini-styleguide.md.hbs +7 -16
- package/templates/jetbrains-ai.md.hbs +6 -15
- package/templates/roo-rule.md.hbs +6 -15
- package/templates/windsurfrules.hbs +9 -18
- package/dist/dashboard/assets/index-BFwqVRYO.js +0 -2
- package/dist/dashboard/assets/index-y7eHWJtq.css +0 -1
|
@@ -1,36 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
Config
|
|
4
|
+
} from "./chunk-2LNDQGDD.js";
|
|
2
5
|
|
|
3
6
|
// src/db.ts
|
|
4
7
|
import pg from "pg";
|
|
5
8
|
import { createHash } from "crypto";
|
|
6
|
-
|
|
7
|
-
// src/config.ts
|
|
8
|
-
import { config } from "dotenv";
|
|
9
|
-
import { join } from "path";
|
|
10
|
-
var localEnv = join(process.cwd(), ".memory-core.env");
|
|
11
|
-
config({ path: localEnv });
|
|
12
|
-
var Config = {
|
|
13
|
-
get databaseUrl() {
|
|
14
|
-
return process.env.DATABASE_URL ?? "";
|
|
15
|
-
},
|
|
16
|
-
get ollamaUrl() {
|
|
17
|
-
return process.env.OLLAMA_URL ?? "http://localhost:11434";
|
|
18
|
-
},
|
|
19
|
-
get ollamaModel() {
|
|
20
|
-
return process.env.OLLAMA_MODEL ?? "nomic-embed-text";
|
|
21
|
-
},
|
|
22
|
-
get chatModel() {
|
|
23
|
-
return process.env.CHAT_MODEL ?? process.env.OLLAMA_CHAT_MODEL ?? "llama3.2";
|
|
24
|
-
},
|
|
25
|
-
get chatProvider() {
|
|
26
|
-
return process.env.CHAT_PROVIDER ?? "ollama";
|
|
27
|
-
},
|
|
28
|
-
get chatApiKey() {
|
|
29
|
-
return process.env.CHAT_API_KEY ?? "";
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// src/db.ts
|
|
34
9
|
var { Pool } = pg;
|
|
35
10
|
var pool = null;
|
|
36
11
|
var migrationsRun = false;
|
|
@@ -386,7 +361,6 @@ async function deleteUser(id) {
|
|
|
386
361
|
}
|
|
387
362
|
|
|
388
363
|
export {
|
|
389
|
-
Config,
|
|
390
364
|
hashMemoryContent,
|
|
391
365
|
getPool,
|
|
392
366
|
runMigrations,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
callChatModel
|
|
4
|
+
} from "./chunk-XAE3RY5D.js";
|
|
5
|
+
|
|
6
|
+
// src/automation/draft-rule.ts
|
|
7
|
+
var SYSTEM = `You are an architecture rule extractor. Given an error, incident, or bug context, extract a single actionable architecture rule.
|
|
8
|
+
|
|
9
|
+
Respond with ONLY valid JSON in this exact shape:
|
|
10
|
+
{
|
|
11
|
+
"name": "short imperative rule title (max 80 chars)",
|
|
12
|
+
"description": "what must/must not happen and why (max 200 chars)",
|
|
13
|
+
"severity": "critical|medium|low",
|
|
14
|
+
"confidence": "high|medium|low"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
Rules for confidence:
|
|
18
|
+
- high: error clearly maps to a structural/architectural pattern that will recur
|
|
19
|
+
- medium: pattern is plausible but may be context-specific
|
|
20
|
+
- low: generic or uncertain
|
|
21
|
+
|
|
22
|
+
Return ONLY the JSON object, no markdown, no explanation.`;
|
|
23
|
+
async function draftRuleWithAI(input) {
|
|
24
|
+
try {
|
|
25
|
+
const prompt = `Source: ${input.source}
|
|
26
|
+
Context: ${input.context}${input.hint ? `
|
|
27
|
+
Hint: ${input.hint}` : ""}`;
|
|
28
|
+
const result = await callChatModel(
|
|
29
|
+
[
|
|
30
|
+
{ role: "system", content: SYSTEM },
|
|
31
|
+
{ role: "user", content: prompt }
|
|
32
|
+
],
|
|
33
|
+
{ timeoutMs: 15e3 }
|
|
34
|
+
);
|
|
35
|
+
const text = result.content.trim().replace(/^```json\n?/, "").replace(/\n?```$/, "");
|
|
36
|
+
const parsed = JSON.parse(text);
|
|
37
|
+
if (!parsed.name || !parsed.description) return null;
|
|
38
|
+
const severity = ["critical", "medium", "low"].find((s) => s === parsed.severity) ?? "medium";
|
|
39
|
+
const confidence = ["high", "medium", "low"].find((c) => c === parsed.confidence) ?? "low";
|
|
40
|
+
const enforcement = severity === "critical" ? "block" : severity === "medium" ? "warn" : "suggest";
|
|
41
|
+
return {
|
|
42
|
+
rule: {
|
|
43
|
+
id: `auto-${input.source}-${Date.now()}`,
|
|
44
|
+
name: parsed.name.slice(0, 80),
|
|
45
|
+
description: parsed.description.slice(0, 200),
|
|
46
|
+
fromLayer: "*",
|
|
47
|
+
toLayer: "*",
|
|
48
|
+
allowed: false,
|
|
49
|
+
severity,
|
|
50
|
+
enforcement
|
|
51
|
+
},
|
|
52
|
+
confidence
|
|
53
|
+
};
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function draftRuleFallback(input, id) {
|
|
59
|
+
return {
|
|
60
|
+
rule: {
|
|
61
|
+
id: id ?? `auto-${input.source}-${Date.now()}`,
|
|
62
|
+
name: `[${input.source.toUpperCase()}] ${input.context.slice(0, 60)}`,
|
|
63
|
+
description: input.context.slice(0, 200),
|
|
64
|
+
fromLayer: "*",
|
|
65
|
+
toLayer: "*",
|
|
66
|
+
allowed: false,
|
|
67
|
+
severity: "low",
|
|
68
|
+
enforcement: "suggest"
|
|
69
|
+
},
|
|
70
|
+
confidence: "low"
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
draftRuleWithAI,
|
|
76
|
+
draftRuleFallback
|
|
77
|
+
};
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/arch-profiles.ts
|
|
4
|
+
function buildLayersTemplate(arch) {
|
|
5
|
+
switch (arch) {
|
|
6
|
+
case "nestjs":
|
|
7
|
+
return {
|
|
8
|
+
layers: [
|
|
9
|
+
{ name: "modules", paths: ["src/modules/**"], description: "Feature modules \u2014 each owns its controller, service, DTOs, entities" },
|
|
10
|
+
{ name: "controllers", paths: ["src/modules/*/controllers/**", "src/modules/*.controller.ts"], description: "HTTP request handlers \u2014 thin, delegate to services" },
|
|
11
|
+
{ name: "services", paths: ["src/modules/*/services/**", "src/modules/*.service.ts"], description: "Business logic \u2014 never import controllers or HTTP classes" },
|
|
12
|
+
{ name: "repositories", paths: ["src/modules/*/repositories/**"], description: "Data access \u2014 services depend on these interfaces" },
|
|
13
|
+
{ name: "common", paths: ["src/common/**", "src/guards/**", "src/filters/**", "src/interceptors/**", "src/pipes/**"], description: "Guards, filters, interceptors, pipes" }
|
|
14
|
+
]
|
|
15
|
+
};
|
|
16
|
+
case "mvc":
|
|
17
|
+
return {
|
|
18
|
+
layers: [
|
|
19
|
+
{ name: "models", paths: ["src/models/**", "app/models/**"], description: "Data models \u2014 represent DB records" },
|
|
20
|
+
{ name: "controllers", paths: ["src/controllers/**", "app/controllers/**"], description: "Route handlers \u2014 thin, delegate to services" },
|
|
21
|
+
{ name: "services", paths: ["src/services/**", "app/services/**"], description: "Business logic \u2014 called by controllers" },
|
|
22
|
+
{ name: "views", paths: ["src/views/**", "app/views/**", "resources/views/**"], description: "Templates and view logic" },
|
|
23
|
+
{ name: "shared", paths: ["src/utils/**", "src/helpers/**", "app/helpers/**"], description: "Shared utilities and helpers" }
|
|
24
|
+
]
|
|
25
|
+
};
|
|
26
|
+
case "laravel-service-repository":
|
|
27
|
+
return {
|
|
28
|
+
layers: [
|
|
29
|
+
{ name: "models", paths: ["app/Models/**"], description: "Eloquent models" },
|
|
30
|
+
{ name: "controllers", paths: ["app/Http/Controllers/**"], description: "HTTP controllers \u2014 thin, delegate to services" },
|
|
31
|
+
{ name: "services", paths: ["app/Services/**"], description: "Business logic services" },
|
|
32
|
+
{ name: "repositories", paths: ["app/Repositories/**"], description: "Data access \u2014 services depend on these" },
|
|
33
|
+
{ name: "shared", paths: ["app/Helpers/**", "app/Traits/**"], description: "Helpers and traits" }
|
|
34
|
+
]
|
|
35
|
+
};
|
|
36
|
+
case "go-api":
|
|
37
|
+
return {
|
|
38
|
+
layers: [
|
|
39
|
+
{ name: "handlers", paths: ["internal/handlers/**", "api/**"], description: "HTTP handlers \u2014 parse request, call service, write response" },
|
|
40
|
+
{ name: "services", paths: ["internal/services/**"], description: "Business logic \u2014 orchestrates domain and repositories" },
|
|
41
|
+
{ name: "repositories", paths: ["internal/repositories/**", "internal/store/**"], description: "Data access \u2014 DB queries, external calls" },
|
|
42
|
+
{ name: "models", paths: ["internal/models/**", "internal/domain/**"], description: "Structs and domain types" },
|
|
43
|
+
{ name: "shared", paths: ["pkg/**", "internal/utils/**"], description: "Shared packages \u2014 no business logic" }
|
|
44
|
+
]
|
|
45
|
+
};
|
|
46
|
+
case "react":
|
|
47
|
+
return {
|
|
48
|
+
layers: [
|
|
49
|
+
{ name: "pages", paths: ["src/pages/**", "src/app/**", "src/routes/**"], description: "Route-level components \u2014 wire hooks and components together" },
|
|
50
|
+
{ name: "components", paths: ["src/components/**"], description: "Reusable UI components \u2014 presentational and feature" },
|
|
51
|
+
{ name: "hooks", paths: ["src/hooks/**"], description: "Custom hooks \u2014 stateful and side-effect logic" },
|
|
52
|
+
{ name: "store", paths: ["src/store/**", "src/state/**", "src/atoms/**"], description: "Global client state \u2014 Zustand, Jotai, Redux" },
|
|
53
|
+
{ name: "services", paths: ["src/services/**", "src/api/**", "src/clients/**"], description: "API clients and external service calls" }
|
|
54
|
+
]
|
|
55
|
+
};
|
|
56
|
+
case "vue":
|
|
57
|
+
return {
|
|
58
|
+
layers: [
|
|
59
|
+
{ name: "pages", paths: ["src/pages/**", "src/views/**"], description: "Route-level views" },
|
|
60
|
+
{ name: "components", paths: ["src/components/**"], description: "Reusable Vue components" },
|
|
61
|
+
{ name: "composables", paths: ["src/composables/**"], description: "Composables \u2014 stateful and reusable logic" },
|
|
62
|
+
{ name: "store", paths: ["src/stores/**", "src/store/**"], description: "Pinia stores \u2014 global state" },
|
|
63
|
+
{ name: "services", paths: ["src/services/**", "src/api/**"], description: "API clients and external calls" }
|
|
64
|
+
]
|
|
65
|
+
};
|
|
66
|
+
case "svelte":
|
|
67
|
+
return {
|
|
68
|
+
layers: [
|
|
69
|
+
{ name: "routes", paths: ["src/routes/**"], description: "SvelteKit routes \u2014 pages and layouts" },
|
|
70
|
+
{ name: "components", paths: ["src/lib/components/**", "src/components/**"], description: "Reusable Svelte components" },
|
|
71
|
+
{ name: "stores", paths: ["src/lib/stores/**", "src/stores/**"], description: "Svelte stores \u2014 reactive state" },
|
|
72
|
+
{ name: "lib", paths: ["src/lib/**"], description: "Shared utilities, server actions, API clients" },
|
|
73
|
+
{ name: "utils", paths: ["src/utils/**", "src/helpers/**"], description: "Pure utility functions" }
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
case "nuxt":
|
|
77
|
+
return {
|
|
78
|
+
layers: [
|
|
79
|
+
{ name: "pages", paths: ["pages/**"], description: "Nuxt pages \u2014 file-based routing" },
|
|
80
|
+
{ name: "components", paths: ["components/**"], description: "Auto-imported Vue components" },
|
|
81
|
+
{ name: "composables", paths: ["composables/**"], description: "Auto-imported composables" },
|
|
82
|
+
{ name: "server", paths: ["server/**"], description: "Nitro server routes and API" },
|
|
83
|
+
{ name: "utils", paths: ["utils/**", "lib/**"], description: "Shared utilities" }
|
|
84
|
+
]
|
|
85
|
+
};
|
|
86
|
+
case "angular":
|
|
87
|
+
return {
|
|
88
|
+
layers: [
|
|
89
|
+
{ name: "modules", paths: ["src/app/**/*.module.ts"], description: "Angular feature modules" },
|
|
90
|
+
{ name: "components", paths: ["src/app/**/*.component.ts"], description: "Components \u2014 UI logic only" },
|
|
91
|
+
{ name: "services", paths: ["src/app/**/*.service.ts"], description: "Injectable services \u2014 business logic and HTTP" },
|
|
92
|
+
{ name: "guards", paths: ["src/app/**/*.guard.ts"], description: "Route guards \u2014 auth and access control" },
|
|
93
|
+
{ name: "shared", paths: ["src/app/shared/**", "src/shared/**"], description: "Shared module \u2014 directives, pipes, components" }
|
|
94
|
+
]
|
|
95
|
+
};
|
|
96
|
+
case "react-native":
|
|
97
|
+
return {
|
|
98
|
+
layers: [
|
|
99
|
+
{ name: "screens", paths: ["src/screens/**", "app/**"], description: "Screen components \u2014 navigation targets" },
|
|
100
|
+
{ name: "components", paths: ["src/components/**"], description: "Reusable UI components" },
|
|
101
|
+
{ name: "hooks", paths: ["src/hooks/**"], description: "Custom hooks \u2014 stateful logic" },
|
|
102
|
+
{ name: "store", paths: ["src/store/**", "src/state/**"], description: "Global state \u2014 Zustand, Redux, Jotai" },
|
|
103
|
+
{ name: "services", paths: ["src/services/**", "src/api/**"], description: "API clients and native service wrappers" }
|
|
104
|
+
]
|
|
105
|
+
};
|
|
106
|
+
case "hexagonal":
|
|
107
|
+
return {
|
|
108
|
+
layers: [
|
|
109
|
+
{ name: "domain", paths: ["src/domain/**", "src/core/**"], description: "Pure domain \u2014 entities, value objects, domain services" },
|
|
110
|
+
{ name: "ports", paths: ["src/ports/**", "src/application/ports/**"], description: "Interfaces \u2014 driving and driven port contracts" },
|
|
111
|
+
{ name: "adapters", paths: ["src/adapters/**", "src/infrastructure/adapters/**"], description: "Adapter implementations \u2014 REST, DB, queues" },
|
|
112
|
+
{ name: "infrastructure", paths: ["src/infrastructure/**"], description: "Technical infrastructure \u2014 config, DI, framework" },
|
|
113
|
+
{ name: "shared", paths: ["src/shared/**", "src/utils/**"], description: "Cross-cutting utilities" }
|
|
114
|
+
]
|
|
115
|
+
};
|
|
116
|
+
case "modular-monolith":
|
|
117
|
+
return {
|
|
118
|
+
layers: [
|
|
119
|
+
{ name: "modules", paths: ["src/modules/**"], description: "Self-contained feature modules \u2014 each owns its DB, API, logic" },
|
|
120
|
+
{ name: "shared", paths: ["src/shared/**", "src/common/**"], description: "Shared kernel \u2014 only pure utilities, no module business logic" },
|
|
121
|
+
{ name: "infrastructure", paths: ["src/infrastructure/**"], description: "Technical infrastructure \u2014 DB connections, messaging, config" },
|
|
122
|
+
{ name: "api", paths: ["src/api/**", "src/interfaces/**"], description: "Public API surface \u2014 HTTP, GraphQL, events" }
|
|
123
|
+
]
|
|
124
|
+
};
|
|
125
|
+
default:
|
|
126
|
+
return {
|
|
127
|
+
layers: [
|
|
128
|
+
{ name: "domain", paths: ["src/domain/**", "src/core/domain/**", "src/modules/*/domain/**"], description: "Business logic, entities, use cases" },
|
|
129
|
+
{ name: "application", paths: ["src/application/**", "src/core/application/**", "src/modules/*/application/**"], description: "Use cases and orchestration" },
|
|
130
|
+
{ name: "infrastructure", paths: ["src/infrastructure/**", "src/modules/*/infrastructure/**"], description: "Database, external APIs, low-level I/O" },
|
|
131
|
+
{ name: "api", paths: ["src/api/**", "src/interfaces/**", "src/controllers/**"], description: "HTTP handlers, request/response" },
|
|
132
|
+
{ name: "shared", paths: ["src/shared/**", "src/utils/**", "src/helpers/**"], description: "Utilities, helpers, constants" }
|
|
133
|
+
]
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function buildArchRules(arch) {
|
|
138
|
+
switch (arch) {
|
|
139
|
+
case "nestjs":
|
|
140
|
+
return { rules: [
|
|
141
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
142
|
+
{ id: "controllers-no-repos", name: "Controllers must not import repositories", fromLayer: "controllers", toLayer: "repositories", allowed: false, severity: "critical", enforcement: "block" },
|
|
143
|
+
{ id: "services-no-controllers", name: "Services must not import controllers", fromLayer: "services", toLayer: "controllers", allowed: false, severity: "critical", enforcement: "block" },
|
|
144
|
+
{ id: "controllers-use-services", name: "Controllers delegate to services", fromLayer: "controllers", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
145
|
+
{ id: "services-use-repos", name: "Services use repositories", fromLayer: "services", toLayer: "repositories", allowed: true, severity: "low", enforcement: "suggest" },
|
|
146
|
+
{ id: "common-no-modules", name: "Common must not import feature modules", fromLayer: "common", toLayer: "modules", allowed: false, severity: "medium", enforcement: "warn" }
|
|
147
|
+
] };
|
|
148
|
+
case "mvc":
|
|
149
|
+
case "laravel-service-repository":
|
|
150
|
+
return { rules: [
|
|
151
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
152
|
+
{ id: "controllers-no-models", name: "Controllers must not query models directly", fromLayer: "controllers", toLayer: "models", allowed: false, severity: "medium", enforcement: "warn" },
|
|
153
|
+
{ id: "controllers-use-services", name: "Controllers delegate to services", fromLayer: "controllers", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
154
|
+
{ id: "services-use-repos", name: "Services use repositories for data access", fromLayer: "services", toLayer: "repositories", allowed: true, severity: "low", enforcement: "suggest" },
|
|
155
|
+
{ id: "shared-no-controllers", name: "Shared must not import controllers", fromLayer: "shared", toLayer: "controllers", allowed: false, severity: "medium", enforcement: "warn" }
|
|
156
|
+
] };
|
|
157
|
+
case "go-api":
|
|
158
|
+
return { rules: [
|
|
159
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
160
|
+
{ id: "handlers-no-repos", name: "Handlers must not import repositories", fromLayer: "handlers", toLayer: "repositories", allowed: false, severity: "critical", enforcement: "block" },
|
|
161
|
+
{ id: "handlers-use-services", name: "Handlers call services only", fromLayer: "handlers", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
162
|
+
{ id: "services-use-repos", name: "Services use repositories", fromLayer: "services", toLayer: "repositories", allowed: true, severity: "low", enforcement: "suggest" },
|
|
163
|
+
{ id: "shared-no-services", name: "Shared must not import services", fromLayer: "shared", toLayer: "services", allowed: false, severity: "medium", enforcement: "warn" }
|
|
164
|
+
] };
|
|
165
|
+
case "react":
|
|
166
|
+
case "react-native":
|
|
167
|
+
return { rules: [
|
|
168
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
169
|
+
{ id: "components-no-pages", name: "Components must not import pages", fromLayer: "components", toLayer: "pages", allowed: false, severity: "critical", enforcement: "block" },
|
|
170
|
+
{ id: "components-no-store", name: "Presentational components must not read store", fromLayer: "components", toLayer: "store", allowed: false, severity: "medium", enforcement: "warn" },
|
|
171
|
+
{ id: "services-no-components", name: "Services must not import components", fromLayer: "services", toLayer: "components", allowed: false, severity: "critical", enforcement: "block" },
|
|
172
|
+
{ id: "hooks-use-services", name: "Hooks use services for API calls", fromLayer: "hooks", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" }
|
|
173
|
+
] };
|
|
174
|
+
case "vue":
|
|
175
|
+
case "nuxt":
|
|
176
|
+
return { rules: [
|
|
177
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
178
|
+
{ id: "components-no-pages", name: "Components must not import pages/views", fromLayer: "components", toLayer: "pages", allowed: false, severity: "critical", enforcement: "block" },
|
|
179
|
+
{ id: "services-no-components", name: "Services must not import components", fromLayer: "services", toLayer: "components", allowed: false, severity: "critical", enforcement: "block" },
|
|
180
|
+
{ id: "composables-use-services", name: "Composables use services for API calls", fromLayer: "composables", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
181
|
+
{ id: "store-no-components", name: "Store must not import components", fromLayer: "store", toLayer: "components", allowed: false, severity: "medium", enforcement: "warn" }
|
|
182
|
+
] };
|
|
183
|
+
case "svelte":
|
|
184
|
+
return { rules: [
|
|
185
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
186
|
+
{ id: "components-no-routes", name: "Components must not import route modules", fromLayer: "components", toLayer: "routes", allowed: false, severity: "critical", enforcement: "block" },
|
|
187
|
+
{ id: "stores-no-components", name: "Stores must not import components", fromLayer: "stores", toLayer: "components", allowed: false, severity: "critical", enforcement: "block" },
|
|
188
|
+
{ id: "lib-no-routes", name: "Lib must not import routes", fromLayer: "lib", toLayer: "routes", allowed: false, severity: "critical", enforcement: "block" },
|
|
189
|
+
{ id: "lib-no-stores", name: "Lib must not import client stores", fromLayer: "lib", toLayer: "stores", allowed: false, severity: "critical", enforcement: "block" },
|
|
190
|
+
{ id: "lib-no-components", name: "Lib must not import components", fromLayer: "lib", toLayer: "components", allowed: false, severity: "critical", enforcement: "block" },
|
|
191
|
+
{ id: "utils-no-stores", name: "Utils must not import stores", fromLayer: "utils", toLayer: "stores", allowed: false, severity: "medium", enforcement: "warn" },
|
|
192
|
+
{ id: "utils-no-lib", name: "Utils must not import lib \u2014 keep utils pure", fromLayer: "utils", toLayer: "lib", allowed: false, severity: "medium", enforcement: "warn" },
|
|
193
|
+
{ id: "routes-use-components", name: "Routes use components", fromLayer: "routes", toLayer: "components", allowed: true, severity: "low", enforcement: "suggest" },
|
|
194
|
+
{ id: "routes-use-stores", name: "Routes use stores", fromLayer: "routes", toLayer: "stores", allowed: true, severity: "low", enforcement: "suggest" },
|
|
195
|
+
{ id: "routes-use-lib", name: "Routes use lib for server actions and API", fromLayer: "routes", toLayer: "lib", allowed: true, severity: "low", enforcement: "suggest" },
|
|
196
|
+
{ id: "components-use-stores", name: "Components use stores for reactive state", fromLayer: "components", toLayer: "stores", allowed: true, severity: "low", enforcement: "suggest" },
|
|
197
|
+
{ id: "components-use-lib", name: "Components use lib for API clients", fromLayer: "components", toLayer: "lib", allowed: true, severity: "low", enforcement: "suggest" },
|
|
198
|
+
{ id: "stores-use-lib", name: "Stores use lib for API and utilities", fromLayer: "stores", toLayer: "lib", allowed: true, severity: "low", enforcement: "suggest" }
|
|
199
|
+
] };
|
|
200
|
+
case "angular":
|
|
201
|
+
return { rules: [
|
|
202
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
203
|
+
{ 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" },
|
|
204
|
+
{ id: "guards-use-services", name: "Guards use auth services", fromLayer: "guards", toLayer: "services", allowed: true, severity: "low", enforcement: "suggest" },
|
|
205
|
+
{ id: "shared-no-modules", name: "Shared must not import feature modules", fromLayer: "shared", toLayer: "modules", allowed: false, severity: "medium", enforcement: "warn" }
|
|
206
|
+
] };
|
|
207
|
+
case "hexagonal":
|
|
208
|
+
return { rules: [
|
|
209
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
210
|
+
{ id: "domain-no-adapters", name: "Domain must not import adapters", fromLayer: "domain", toLayer: "adapters", allowed: false, severity: "critical", enforcement: "block" },
|
|
211
|
+
{ id: "domain-no-infra", name: "Domain must not import infrastructure", fromLayer: "domain", toLayer: "infrastructure", allowed: false, severity: "critical", enforcement: "block" },
|
|
212
|
+
{ id: "adapters-implement-ports", name: "Adapters implement port interfaces", fromLayer: "adapters", toLayer: "ports", allowed: true, severity: "low", enforcement: "suggest" },
|
|
213
|
+
{ id: "ports-no-adapters", name: "Ports must not import adapters", fromLayer: "ports", toLayer: "adapters", allowed: false, severity: "critical", enforcement: "block" }
|
|
214
|
+
] };
|
|
215
|
+
case "modular-monolith":
|
|
216
|
+
return { rules: [
|
|
217
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
218
|
+
{ id: "modules-no-direct-import", name: "Modules must not import each other directly", fromLayer: "modules", toLayer: "modules", allowed: false, severity: "critical", enforcement: "block" },
|
|
219
|
+
{ id: "shared-no-modules", name: "Shared kernel must not import feature modules", fromLayer: "shared", toLayer: "modules", allowed: false, severity: "critical", enforcement: "block" },
|
|
220
|
+
{ id: "modules-use-shared", name: "Modules may use shared kernel", fromLayer: "modules", toLayer: "shared", allowed: true, severity: "low", enforcement: "suggest" }
|
|
221
|
+
] };
|
|
222
|
+
default:
|
|
223
|
+
return { rules: [
|
|
224
|
+
{ id: "no-circular", name: "No circular dependencies", fromLayer: "*", toLayer: "*", allowed: false, severity: "critical", enforcement: "block" },
|
|
225
|
+
{ id: "domain-no-infra", name: "Domain must not import infrastructure", fromLayer: "domain", toLayer: "infrastructure", allowed: false, severity: "critical", enforcement: "block" },
|
|
226
|
+
{ id: "domain-no-api", name: "Domain must not import API layer", fromLayer: "domain", toLayer: "api", allowed: false, severity: "critical", enforcement: "block" },
|
|
227
|
+
{ id: "api-no-infra-direct", name: "API should not import infrastructure directly", fromLayer: "api", toLayer: "infrastructure", allowed: false, severity: "medium", enforcement: "warn" },
|
|
228
|
+
{ id: "application-no-api", name: "Application must not import API layer", fromLayer: "application", toLayer: "api", allowed: false, severity: "critical", enforcement: "block" },
|
|
229
|
+
{ id: "application-uses-domain", name: "Application depends on domain", fromLayer: "application", toLayer: "domain", allowed: true, severity: "low", enforcement: "suggest" },
|
|
230
|
+
{ id: "shared-no-domain", name: "Shared must not import domain", fromLayer: "shared", toLayer: "domain", allowed: false, severity: "medium", enforcement: "warn" }
|
|
231
|
+
] };
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export {
|
|
236
|
+
buildLayersTemplate,
|
|
237
|
+
buildArchRules
|
|
238
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
Config
|
|
4
|
+
} from "./chunk-2LNDQGDD.js";
|
|
5
|
+
|
|
6
|
+
// src/embedding.ts
|
|
7
|
+
function getEmbeddingTimeoutMs() {
|
|
8
|
+
const raw = Number(process.env.EMBEDDING_TIMEOUT_MS ?? process.env.MEMORY_CORE_RETRIEVAL_TIMEOUT_MS ?? 5e3);
|
|
9
|
+
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : 5e3;
|
|
10
|
+
}
|
|
11
|
+
async function embed(text) {
|
|
12
|
+
let response;
|
|
13
|
+
try {
|
|
14
|
+
response = await fetch(`${Config.embeddingUrl}/api/embeddings`, {
|
|
15
|
+
method: "POST",
|
|
16
|
+
headers: { "Content-Type": "application/json" },
|
|
17
|
+
signal: AbortSignal.timeout(getEmbeddingTimeoutMs()),
|
|
18
|
+
body: JSON.stringify({ model: Config.embeddingModel, prompt: text })
|
|
19
|
+
});
|
|
20
|
+
} catch {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Cannot reach embedding service at ${Config.embeddingUrl}. Run: ollama serve`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
const body = await response.text();
|
|
27
|
+
throw new Error(`Ollama embedding failed (${response.status}): ${body}`);
|
|
28
|
+
}
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
return data.embedding;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
embed
|
|
35
|
+
};
|
|
@@ -18,15 +18,21 @@ var ApprovalQueue = class {
|
|
|
18
18
|
save(items) {
|
|
19
19
|
writeFileSync(this.queuePath, JSON.stringify(items, null, 2));
|
|
20
20
|
}
|
|
21
|
-
add(rule, source, confidence) {
|
|
21
|
+
add(rule, source, confidence, meta) {
|
|
22
22
|
const items = this.load();
|
|
23
|
+
const needle = rule.description.toLowerCase().slice(0, 60);
|
|
24
|
+
const duplicate = items.find(
|
|
25
|
+
(i) => i.status === "pending" && i.rule.description.toLowerCase().slice(0, 60) === needle
|
|
26
|
+
);
|
|
27
|
+
if (duplicate) return duplicate;
|
|
23
28
|
const item = {
|
|
24
29
|
id: rule.id,
|
|
25
30
|
rule,
|
|
26
31
|
source,
|
|
27
32
|
confidence,
|
|
28
33
|
status: "pending",
|
|
29
|
-
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
34
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
35
|
+
...meta
|
|
30
36
|
};
|
|
31
37
|
items.push(item);
|
|
32
38
|
this.save(items);
|
|
@@ -51,16 +57,12 @@ var ApprovalQueue = class {
|
|
|
51
57
|
pending() {
|
|
52
58
|
return this.load().filter((i) => i.status === "pending");
|
|
53
59
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
const merged = [...existing, ...approved.map((i) => i.rule)];
|
|
60
|
-
writeFileSync(rulesPath, JSON.stringify({ rules: merged }, null, 2));
|
|
61
|
-
const remaining = items.filter((i) => i.status !== "approved");
|
|
60
|
+
approved() {
|
|
61
|
+
return this.load().filter((i) => i.status === "approved");
|
|
62
|
+
}
|
|
63
|
+
clearApproved() {
|
|
64
|
+
const remaining = this.load().filter((i) => i.status !== "approved");
|
|
62
65
|
this.save(remaining);
|
|
63
|
-
return approved.length;
|
|
64
66
|
}
|
|
65
67
|
};
|
|
66
68
|
|
|
@@ -7,7 +7,7 @@ function getChatConfig() {
|
|
|
7
7
|
return {
|
|
8
8
|
provider,
|
|
9
9
|
model,
|
|
10
|
-
ollamaUrl: process.env.OLLAMA_URL ?? "http://localhost:11434",
|
|
10
|
+
ollamaUrl: process.env.EMBEDDING_URL ?? process.env.OLLAMA_URL ?? "http://localhost:11434",
|
|
11
11
|
apiKey: process.env.CHAT_API_KEY ?? "",
|
|
12
12
|
baseUrl: process.env.CHAT_BASE_URL ?? ""
|
|
13
13
|
};
|
|
@@ -75,8 +75,11 @@ async function callOpenAICompat(cfg, messages, options = {}) {
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
async function callAnthropic(cfg, messages, options = {}) {
|
|
78
|
-
const
|
|
78
|
+
const sysMsg = messages.find((m) => m.role === "system");
|
|
79
|
+
const systemContent = sysMsg?.content ?? "";
|
|
80
|
+
const cacheSystem = sysMsg?.cache ?? false;
|
|
79
81
|
const userMessages = messages.filter((m) => m.role !== "system");
|
|
82
|
+
const system = cacheSystem ? [{ type: "text", text: systemContent, cache_control: { type: "ephemeral" } }] : systemContent;
|
|
80
83
|
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
|
81
84
|
method: "POST",
|
|
82
85
|
headers: {
|