@noorm/marie-cli 0.1.18 → 0.1.25

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 (251) hide show
  1. package/README.md +7 -15
  2. package/SENTINEL.md +4 -7
  3. package/dist/cli-new/components/App.js +16 -63
  4. package/dist/cli-new/components/App.js.map +1 -1
  5. package/dist/cli-new/components/ApprovalDialog.js +2 -1
  6. package/dist/cli-new/components/ApprovalDialog.js.map +1 -1
  7. package/dist/cli-new/components/Banner.js +4 -3
  8. package/dist/cli-new/components/Banner.js.map +1 -1
  9. package/dist/cli-new/components/ChatArea.js +6 -7
  10. package/dist/cli-new/components/ChatArea.js.map +1 -1
  11. package/dist/cli-new/components/Header.js +13 -7
  12. package/dist/cli-new/components/Header.js.map +1 -1
  13. package/dist/cli-new/components/InputArea.js +73 -12
  14. package/dist/cli-new/components/InputArea.js.map +1 -1
  15. package/dist/cli-new/components/MessageBubble.js +26 -18
  16. package/dist/cli-new/components/MessageBubble.js.map +1 -1
  17. package/dist/cli-new/components/SessionSwitcher.js +4 -7
  18. package/dist/cli-new/components/SessionSwitcher.js.map +1 -1
  19. package/dist/cli-new/components/SetupWizard.js +80 -257
  20. package/dist/cli-new/components/SetupWizard.js.map +1 -1
  21. package/dist/cli-new/components/ToolCallDisplay.js +20 -5
  22. package/dist/cli-new/components/ToolCallDisplay.js.map +1 -1
  23. package/dist/cli-new/components/WizardSteps.js +22 -0
  24. package/dist/cli-new/components/WizardSteps.js.map +1 -0
  25. package/dist/cli-new/constants/SetupConstants.js +42 -0
  26. package/dist/cli-new/constants/SetupConstants.js.map +1 -0
  27. package/dist/cli-new/hooks/useGit.js +19 -62
  28. package/dist/cli-new/hooks/useGit.js.map +1 -1
  29. package/dist/cli-new/hooks/useMarie.js +26 -18
  30. package/dist/cli-new/hooks/useMarie.js.map +1 -1
  31. package/dist/cli-new/hooks/useSessions.js +1 -1
  32. package/dist/cli-new/hooks/useSessions.js.map +1 -1
  33. package/dist/cli-new/hooks/useSetupWizard.js +88 -0
  34. package/dist/cli-new/hooks/useSetupWizard.js.map +1 -0
  35. package/dist/cli-new/hooks/useUpdateCheck.js +4 -3
  36. package/dist/cli-new/hooks/useUpdateCheck.js.map +1 -1
  37. package/dist/cli-new/index.js +2 -4
  38. package/dist/cli-new/index.js.map +1 -1
  39. package/dist/cli-new/services/CommandService.js +104 -0
  40. package/dist/cli-new/services/CommandService.js.map +1 -0
  41. package/dist/cli-new/services/GitService.js +91 -0
  42. package/dist/cli-new/services/GitService.js.map +1 -0
  43. package/dist/cli-new/services/MarieService.js +77 -0
  44. package/dist/cli-new/services/MarieService.js.map +1 -0
  45. package/dist/cli-new/services/auth-server.js +128 -0
  46. package/dist/cli-new/services/auth-server.js.map +1 -0
  47. package/dist/cli-new/utils/version.js +24 -0
  48. package/dist/cli-new/utils/version.js.map +1 -0
  49. package/dist/monolith/adapters/CliMarieAdapter.js +12 -11
  50. package/dist/monolith/adapters/CliMarieAdapter.js.map +1 -1
  51. package/dist/monolith/cli/CliFileSystemPort.js +17 -3
  52. package/dist/monolith/cli/CliFileSystemPort.js.map +1 -1
  53. package/dist/monolith/cli/MarieToolDefinitionsCLI.js +39 -31
  54. package/dist/monolith/cli/MarieToolDefinitionsCLI.js.map +1 -1
  55. package/dist/monolith/cli/index.js +5 -20
  56. package/dist/monolith/cli/index.js.map +1 -1
  57. package/dist/monolith/cli/services/JoyAutomationServiceCLI.js +15 -62
  58. package/dist/monolith/cli/services/JoyAutomationServiceCLI.js.map +1 -1
  59. package/dist/monolith/cli/storage.js +142 -72
  60. package/dist/monolith/cli/storage.js.map +1 -1
  61. package/dist/monolith/domain/joy/RitualService.js +44 -46
  62. package/dist/monolith/domain/joy/RitualService.js.map +1 -1
  63. package/dist/monolith/domain/marie/MarieCortex.js +148 -0
  64. package/dist/monolith/domain/marie/MarieCortex.js.map +1 -0
  65. package/dist/monolith/domain/marie/PersonalityRenderer.js +97 -0
  66. package/dist/monolith/domain/marie/PersonalityRenderer.js.map +1 -0
  67. package/dist/monolith/infrastructure/Configuration.js +68 -0
  68. package/dist/monolith/infrastructure/Configuration.js.map +1 -0
  69. package/dist/monolith/infrastructure/CoreInfrastructure.js +204 -0
  70. package/dist/monolith/infrastructure/CoreInfrastructure.js.map +1 -0
  71. package/dist/monolith/infrastructure/ai/agents/MarieAscendant.js +3 -3
  72. package/dist/monolith/infrastructure/ai/agents/MarieAscendant.js.map +1 -1
  73. package/dist/monolith/infrastructure/ai/context/ContextArchiveService.js +6 -27
  74. package/dist/monolith/infrastructure/ai/context/ContextArchiveService.js.map +1 -1
  75. package/dist/monolith/infrastructure/ai/context/ContextManager.js +142 -131
  76. package/dist/monolith/infrastructure/ai/context/ContextManager.js.map +1 -1
  77. package/dist/monolith/infrastructure/ai/core/MarieEngine.js +115 -1077
  78. package/dist/monolith/infrastructure/ai/core/MarieEngine.js.map +1 -1
  79. package/dist/monolith/infrastructure/ai/core/MarieEventDispatcher.js +1 -37
  80. package/dist/monolith/infrastructure/ai/core/MarieEventDispatcher.js.map +1 -1
  81. package/dist/monolith/infrastructure/ai/core/MarieLockManager.js +6 -1
  82. package/dist/monolith/infrastructure/ai/core/MarieLockManager.js.map +1 -1
  83. package/dist/monolith/infrastructure/ai/core/MarieProgressTracker.js +172 -221
  84. package/dist/monolith/infrastructure/ai/core/MarieProgressTracker.js.map +1 -1
  85. package/dist/monolith/infrastructure/ai/core/MarieSanitizer.js +292 -141
  86. package/dist/monolith/infrastructure/ai/core/MarieSanitizer.js.map +1 -1
  87. package/dist/monolith/infrastructure/ai/core/MarieToolProcessor.js +331 -614
  88. package/dist/monolith/infrastructure/ai/core/MarieToolProcessor.js.map +1 -1
  89. package/dist/monolith/infrastructure/ai/core/MarieVitality.js +238 -0
  90. package/dist/monolith/infrastructure/ai/core/MarieVitality.js.map +1 -0
  91. package/dist/monolith/infrastructure/ai/core/SessionLogService.js +9 -2
  92. package/dist/monolith/infrastructure/ai/core/SessionLogService.js.map +1 -1
  93. package/dist/monolith/infrastructure/ai/providers/AIProvider.js +402 -1
  94. package/dist/monolith/infrastructure/ai/providers/AIProvider.js.map +1 -1
  95. package/dist/monolith/infrastructure/ai/providers/DreamBeesProvider.js +114 -0
  96. package/dist/monolith/infrastructure/ai/providers/DreamBeesProvider.js.map +1 -0
  97. package/dist/monolith/infrastructure/ai/providers/OpenRouterProvider.js +426 -392
  98. package/dist/monolith/infrastructure/ai/providers/OpenRouterProvider.js.map +1 -1
  99. package/dist/monolith/infrastructure/ai/providers/OpenRouterStreamParser.js +235 -241
  100. package/dist/monolith/infrastructure/ai/providers/OpenRouterStreamParser.js.map +1 -1
  101. package/dist/monolith/infrastructure/ai/workerAi.js +185 -0
  102. package/dist/monolith/infrastructure/ai/workerAi.js.map +1 -0
  103. package/dist/monolith/infrastructure/config/ConfigService.js +216 -503
  104. package/dist/monolith/infrastructure/config/ConfigService.js.map +1 -1
  105. package/dist/monolith/infrastructure/joy/CognitiveRituals.js +4 -165
  106. package/dist/monolith/infrastructure/joy/CognitiveRituals.js.map +1 -1
  107. package/dist/monolith/infrastructure/joy/JoyTools.js +14 -47
  108. package/dist/monolith/infrastructure/joy/JoyTools.js.map +1 -1
  109. package/dist/monolith/infrastructure/persistence/MarieMindAutonomics.js +4 -0
  110. package/dist/monolith/infrastructure/persistence/MarieMindAutonomics.js.map +1 -0
  111. package/dist/monolith/infrastructure/persistence/MarieMindEngine.js +11 -0
  112. package/dist/monolith/infrastructure/persistence/MarieMindEngine.js.map +1 -0
  113. package/dist/monolith/infrastructure/persistence/NoormmeAutonomics.js +123 -106
  114. package/dist/monolith/infrastructure/persistence/NoormmeAutonomics.js.map +1 -1
  115. package/dist/monolith/infrastructure/persistence/NoormmeEngine.js +508 -63
  116. package/dist/monolith/infrastructure/persistence/NoormmeEngine.js.map +1 -1
  117. package/dist/monolith/infrastructure/persistence/NoormmeSchema.js +68 -39
  118. package/dist/monolith/infrastructure/persistence/NoormmeSchema.js.map +1 -1
  119. package/dist/monolith/infrastructure/persistence/NoormmeSeeder.js +80 -67
  120. package/dist/monolith/infrastructure/persistence/NoormmeSeeder.js.map +1 -1
  121. package/dist/monolith/infrastructure/persistence/NoormmeTools.js +122 -75
  122. package/dist/monolith/infrastructure/persistence/NoormmeTools.js.map +1 -1
  123. package/dist/monolith/infrastructure/services/MarieMemoryStore.js +133 -134
  124. package/dist/monolith/infrastructure/services/MarieMemoryStore.js.map +1 -1
  125. package/dist/monolith/infrastructure/tools/MarieToolDefinitions.js +6 -30
  126. package/dist/monolith/infrastructure/tools/MarieToolDefinitions.js.map +1 -1
  127. package/dist/monolith/infrastructure/tools/PureStreamParser.js +68 -80
  128. package/dist/monolith/infrastructure/tools/PureStreamParser.js.map +1 -1
  129. package/dist/monolith/infrastructure/tools/SharedToolDefinitions.js +12 -11
  130. package/dist/monolith/infrastructure/tools/SharedToolDefinitions.js.map +1 -1
  131. package/dist/monolith/infrastructure/tools/SovereignTools.js +326 -0
  132. package/dist/monolith/infrastructure/tools/SovereignTools.js.map +1 -0
  133. package/dist/monolith/infrastructure/tools/ToolRegistry.js +45 -26
  134. package/dist/monolith/infrastructure/tools/ToolRegistry.js.map +1 -1
  135. package/dist/monolith/infrastructure/tools/definitions/AnalysisTools.js +39 -153
  136. package/dist/monolith/infrastructure/tools/definitions/AnalysisTools.js.map +1 -1
  137. package/dist/monolith/infrastructure/tools/definitions/AutomationTools.js +31 -46
  138. package/dist/monolith/infrastructure/tools/definitions/AutomationTools.js.map +1 -1
  139. package/dist/monolith/infrastructure/tools/definitions/ContextTools.js +41 -13
  140. package/dist/monolith/infrastructure/tools/definitions/ContextTools.js.map +1 -1
  141. package/dist/monolith/infrastructure/tools/definitions/CoreTools.js +10 -14
  142. package/dist/monolith/infrastructure/tools/definitions/CoreTools.js.map +1 -1
  143. package/dist/monolith/infrastructure/tools/definitions/DiagnosticTools.js +39 -70
  144. package/dist/monolith/infrastructure/tools/definitions/DiagnosticTools.js.map +1 -1
  145. package/dist/monolith/infrastructure/tools/definitions/NavigationTools.js +30 -181
  146. package/dist/monolith/infrastructure/tools/definitions/NavigationTools.js.map +1 -1
  147. package/dist/monolith/infrastructure/tools/definitions/PlanningTools.js +12 -9
  148. package/dist/monolith/infrastructure/tools/definitions/PlanningTools.js.map +1 -1
  149. package/dist/monolith/plumbing/Plumbing.js +238 -0
  150. package/dist/monolith/plumbing/Plumbing.js.map +1 -0
  151. package/dist/monolith/plumbing/PlumbingAnalysis.js +109 -0
  152. package/dist/monolith/plumbing/PlumbingAnalysis.js.map +1 -0
  153. package/dist/monolith/plumbing/PlumbingSystem.js +169 -0
  154. package/dist/monolith/plumbing/PlumbingSystem.js.map +1 -0
  155. package/dist/monolith/plumbing/analysis/ComplexityService.js +30 -34
  156. package/dist/monolith/plumbing/analysis/ComplexityService.js.map +1 -1
  157. package/dist/monolith/plumbing/analysis/DependencyService.js +55 -44
  158. package/dist/monolith/plumbing/analysis/DependencyService.js.map +1 -1
  159. package/dist/monolith/plumbing/analysis/DiscoveryService.js +40 -42
  160. package/dist/monolith/plumbing/analysis/DiscoveryService.js.map +1 -1
  161. package/dist/monolith/plumbing/analysis/JoyMapService.js +52 -56
  162. package/dist/monolith/plumbing/analysis/JoyMapService.js.map +1 -1
  163. package/dist/monolith/plumbing/analysis/LintService.js +118 -118
  164. package/dist/monolith/plumbing/analysis/LintService.js.map +1 -1
  165. package/dist/monolith/plumbing/analysis/MarieSentinelService.js +278 -268
  166. package/dist/monolith/plumbing/analysis/MarieSentinelService.js.map +1 -1
  167. package/dist/monolith/plumbing/analysis/QualityGuardrailService.js +116 -114
  168. package/dist/monolith/plumbing/analysis/QualityGuardrailService.js.map +1 -1
  169. package/dist/monolith/plumbing/analysis/SurgicalMender.js +57 -59
  170. package/dist/monolith/plumbing/analysis/SurgicalMender.js.map +1 -1
  171. package/dist/monolith/plumbing/analysis/TestService.js +89 -89
  172. package/dist/monolith/plumbing/analysis/TestService.js.map +1 -1
  173. package/dist/monolith/plumbing/filesystem/FileService.js +123 -195
  174. package/dist/monolith/plumbing/filesystem/FileService.js.map +1 -1
  175. package/dist/monolith/plumbing/filesystem/PathResolver.js +7 -8
  176. package/dist/monolith/plumbing/filesystem/PathResolver.js.map +1 -1
  177. package/dist/monolith/plumbing/git/GitService.js +4 -4
  178. package/dist/monolith/plumbing/git/GitService.js.map +1 -1
  179. package/dist/monolith/plumbing/lsp/SymbolService.js +5 -34
  180. package/dist/monolith/plumbing/lsp/SymbolService.js.map +1 -1
  181. package/dist/monolith/plumbing/terminal/ProcessRegistry.js +20 -22
  182. package/dist/monolith/plumbing/terminal/ProcessRegistry.js.map +1 -1
  183. package/dist/monolith/plumbing/terminal/TerminalService.js +127 -141
  184. package/dist/monolith/plumbing/terminal/TerminalService.js.map +1 -1
  185. package/dist/monolith/plumbing/utils/EnvironmentUtils.js +3 -23
  186. package/dist/monolith/plumbing/utils/EnvironmentUtils.js.map +1 -1
  187. package/dist/monolith/plumbing/utils/JsonUtils.js +252 -311
  188. package/dist/monolith/plumbing/utils/JsonUtils.js.map +1 -1
  189. package/dist/monolith/plumbing/utils/PlumbingCore.js +549 -0
  190. package/dist/monolith/plumbing/utils/PlumbingCore.js.map +1 -0
  191. package/dist/monolith/plumbing/utils/PrefixTree.js +61 -114
  192. package/dist/monolith/plumbing/utils/PrefixTree.js.map +1 -1
  193. package/dist/monolith/plumbing/utils/StreamTagDetector.js +89 -127
  194. package/dist/monolith/plumbing/utils/StreamTagDetector.js.map +1 -1
  195. package/dist/monolith/plumbing/utils/StringUtils.js +87 -89
  196. package/dist/monolith/plumbing/utils/StringUtils.js.map +1 -1
  197. package/dist/monolith/runtime/MarieRuntime.js +76 -499
  198. package/dist/monolith/runtime/MarieRuntime.js.map +1 -1
  199. package/dist/monolith/runtime/RuntimeAdapterBase.js +1 -1
  200. package/dist/monolith/runtime/RuntimeAdapterBase.js.map +1 -1
  201. package/dist/monolith/runtime/providerFactory.js +1 -7
  202. package/dist/monolith/runtime/providerFactory.js.map +1 -1
  203. package/dist/monolith/services/HealthService.js +29 -32
  204. package/dist/monolith/services/HealthService.js.map +1 -1
  205. package/dist/monolith/services/JoyAutomationService.js +58 -95
  206. package/dist/monolith/services/JoyAutomationService.js.map +1 -1
  207. package/dist/monolith/services/MarieAutomationService.js +59 -0
  208. package/dist/monolith/services/MarieAutomationService.js.map +1 -0
  209. package/dist/monolith/services/MarieGhostService.js +46 -173
  210. package/dist/monolith/services/MarieGhostService.js.map +1 -1
  211. package/dist/monolith/services/MarieServices.js +102 -0
  212. package/dist/monolith/services/MarieServices.js.map +1 -0
  213. package/dist/monolith/services/MarieTypes.js +2 -0
  214. package/dist/monolith/services/MarieTypes.js.map +1 -0
  215. package/dist/monolith/services/UpdateService.js +47 -49
  216. package/dist/monolith/services/UpdateService.js.map +1 -1
  217. package/dist/prompts.js +11 -5
  218. package/dist/prompts.js.map +1 -1
  219. package/dist/test_prefix_tree.js +9 -9
  220. package/dist/test_prefix_tree.js.map +1 -1
  221. package/package.json +18 -89
  222. package/run_test.js +5 -0
  223. package/.marie_visual_verify_1771225696548/progress_bar_check.txt +0 -1
  224. package/dist/extension.cjs +0 -1155
  225. package/dist/extension.js +0 -474
  226. package/dist/extension.js.map +0 -1
  227. package/dist/monolith/adapters/VscodeMarieAdapter.js +0 -81
  228. package/dist/monolith/adapters/VscodeMarieAdapter.js.map +0 -1
  229. package/dist/monolith/infrastructure/ai/core/GhostPort.js +0 -2
  230. package/dist/monolith/infrastructure/ai/core/GhostPort.js.map +0 -1
  231. package/dist/monolith/infrastructure/ai/core/VscodeFileSystemPort.js +0 -33
  232. package/dist/monolith/infrastructure/ai/core/VscodeFileSystemPort.js.map +0 -1
  233. package/dist/monolith/infrastructure/ai/providers/AnthropicProvider.js +0 -154
  234. package/dist/monolith/infrastructure/ai/providers/AnthropicProvider.js.map +0 -1
  235. package/dist/monolith/infrastructure/ai/providers/CerebrasProvider.js +0 -214
  236. package/dist/monolith/infrastructure/ai/providers/CerebrasProvider.js.map +0 -1
  237. package/dist/monolith/plumbing/ui/DecorationService.js +0 -54
  238. package/dist/monolith/plumbing/ui/DecorationService.js.map +0 -1
  239. package/dist/monolith/services/JoyLogService.js +0 -48
  240. package/dist/monolith/services/JoyLogService.js.map +0 -1
  241. package/dist/monolith/services/JoyService.js +0 -209
  242. package/dist/monolith/services/JoyService.js.map +0 -1
  243. package/dist/monolith/services/MarieSCMProvider.js +0 -41
  244. package/dist/monolith/services/MarieSCMProvider.js.map +0 -1
  245. package/dist/webview-ui/main.css +0 -1
  246. package/dist/webview-ui/main.js +0 -108
  247. package/lint_output.txt +0 -705
  248. package/lint_output_v2.txt +0 -711
  249. package/test-mind-p6.sqlite +0 -0
  250. package/test-mind-p6.sqlite-shm +0 -0
  251. package/test-mind-p6.sqlite-wal +0 -0
@@ -1,287 +1,298 @@
1
1
  import * as fs from "fs/promises";
2
2
  import * as path from "path";
3
3
  import * as crypto from "crypto";
4
- import { LintService } from "./LintService.js";
5
- import { ComplexityService } from "./ComplexityService.js";
6
- import { ConfigService } from "../../infrastructure/config/ConfigService.js";
4
+ import { runLint } from "./LintService.js";
5
+ import { analyzeComplexity } from "./ComplexityService.js";
6
+ import { getAutonomyMode } from "../../infrastructure/config/ConfigService.js";
7
+ import { safeStringify } from "../../infrastructure/ai/core/MarieSanitizer.js";
7
8
  /**
8
9
  * MARIE SENTINEL v3.1: THE GROUNDED GUARDIAN
9
10
  * Improved accuracy in resolution, duplication, and graph fidelity.
10
11
  */
11
- export class MarieSentinelService {
12
- static ZONES = {
13
- DOMAIN: "domain",
14
- INFRASTRUCTURE: "infrastructure",
15
- PLUMBING: "plumbing",
16
- };
17
- static STATE_FILE = ".marie/sentinel_state.json";
18
- static async audit(workingDir, specificFile) {
19
- const allFiles = await this.getAllFiles(workingDir);
20
- const targetFiles = specificFile ? [specificFile] : allFiles;
21
- const zoneViolations = [];
22
- const circularDependencies = [];
23
- const leakyAbstractions = [];
24
- const duplication = [];
25
- const navigationDrifts = [];
26
- const toxicFiles = [];
27
- // 1. Precise Dependency Graph & Semantic Content Maps
28
- const dependencyGraph = new Map();
29
- const semanticHashMap = new Map(); // Hash -> FilePath
30
- // INCREMENTAL SENTINEL: Load state to check mtimes
31
- const state = await this.loadState(workingDir);
32
- const lastMtimes = state.fileHashes || {};
33
- const newMtimes = {};
34
- // FAST PATH: Check ascension mode
35
- const isAscension = ConfigService.getAutonomyMode() === "ascension";
36
- await Promise.all(allFiles.map(async (file) => {
37
- const stats = await fs.stat(file);
38
- const mtime = stats.mtimeMs;
39
- const relativePath = path.relative(workingDir, file);
40
- newMtimes[relativePath] = mtime;
41
- const hasChanged = lastMtimes[relativePath] !== mtime;
42
- const content = await fs.readFile(file, "utf8");
43
- // A. Semantic Duplication
44
- if (!isAscension) {
45
- const semanticHash = this.computeSemanticHash(content);
46
- if (semanticHashMap.has(semanticHash)) {
47
- const original = semanticHashMap.get(semanticHash);
48
- if (original !== relativePath) {
49
- duplication.push(`[Semantic Duplicate] ${relativePath} matches ${original}`);
12
+ const ZONES = {
13
+ DOMAIN: "domain",
14
+ INFRASTRUCTURE: "infrastructure",
15
+ PLUMBING: "plumbing",
16
+ };
17
+ const STATE_FILE = ".marie/sentinel_state.json";
18
+ export async function audit(workingDir, specificFile) {
19
+ const allFiles = await getAllFiles(workingDir);
20
+ const targetFiles = specificFile ? [specificFile] : allFiles;
21
+ const zoneViolations = [];
22
+ const circularDependencies = [];
23
+ const leakyAbstractions = [];
24
+ const duplication = [];
25
+ const navigationDrifts = [];
26
+ const toxicFiles = [];
27
+ // 1. Precise Dependency Graph & Semantic Content Maps
28
+ const dependencyGraph = new Map();
29
+ const semanticHashMap = new Map(); // Hash -> FilePath
30
+ // INCREMENTAL SENTINEL: Load state to check mtimes
31
+ const state = await loadState(workingDir);
32
+ const lastMtimes = state.fileHashes || {};
33
+ const newMtimes = {};
34
+ // FAST PATH: Check ascension mode
35
+ const isAscension = getAutonomyMode() === "ascension";
36
+ // CHUNKING: Prevent EMFILE or OOM by processing files in batches
37
+ const BATCH_SIZE = 50;
38
+ for (let i = 0; i < allFiles.length; i += BATCH_SIZE) {
39
+ const batch = allFiles.slice(i, i + BATCH_SIZE);
40
+ await Promise.all(batch.map(async (file) => {
41
+ try {
42
+ const stats = await fs.stat(file);
43
+ const mtime = stats.mtimeMs;
44
+ const relativePath = path.relative(workingDir, file);
45
+ newMtimes[relativePath] = mtime;
46
+ const hasChanged = lastMtimes[relativePath] !== mtime;
47
+ const content = await fs.readFile(file, "utf8");
48
+ // A. Semantic Duplication
49
+ if (!isAscension) {
50
+ const semanticHash = computeSemanticHash(content);
51
+ if (semanticHashMap.has(semanticHash)) {
52
+ const original = semanticHashMap.get(semanticHash);
53
+ if (original !== relativePath) {
54
+ duplication.push(`[Semantic Duplicate] ${relativePath} matches ${original}`);
55
+ }
56
+ }
57
+ else {
58
+ semanticHashMap.set(semanticHash, relativePath);
50
59
  }
51
60
  }
52
- else {
53
- semanticHashMap.set(semanticHash, relativePath);
61
+ // B. Robust Import Extraction & Resolution
62
+ const rawImports = extractImports(content);
63
+ const resolvedImports = await Promise.all(rawImports.map((imp) => resolveImportDeep(imp, file, workingDir)));
64
+ const validImports = resolvedImports.filter(Boolean);
65
+ dependencyGraph.set(relativePath, validImports);
66
+ // C. Target Analysis
67
+ if (targetFiles.includes(file) && hasChanged) {
68
+ await analyzeFile(file, workingDir, content, validImports, zoneViolations, leakyAbstractions, navigationDrifts, toxicFiles);
54
69
  }
55
70
  }
56
- // B. Robust Import Extraction & Resolution
57
- const rawImports = this.extractImports(content);
58
- const resolvedImports = await Promise.all(rawImports.map((i) => this.resolveImportDeep(i, file, workingDir)));
59
- const validImports = resolvedImports.filter(Boolean);
60
- dependencyGraph.set(relativePath, validImports);
61
- // C. Target Analysis
62
- if (targetFiles.includes(file) && hasChanged) {
63
- await this.analyzeFile(file, workingDir, content, validImports, zoneViolations, leakyAbstractions, navigationDrifts, toxicFiles);
71
+ catch (e) {
72
+ console.warn(`[Sentinel] Failed to analyze file ${file}:`, e);
64
73
  }
65
74
  }));
66
- // 2. Cycle Detection (Global)
67
- // FAST PATH: Skip expensive cycle detection in Ascension mode
68
- if (!isAscension) {
69
- const cycles = this.detectCycles(dependencyGraph);
70
- circularDependencies.push(...cycles);
71
- }
72
- // 3. Score Normalization & Ratchet
73
- const lintErrors = await LintService.runLint(workingDir);
74
- const entropyScore = zoneViolations.length * 8 + // Weighted higher
75
- lintErrors.length * 1 +
76
- circularDependencies.length * 15 + // Structural rot is expensive
77
- toxicFiles.length * 6 +
78
- leakyAbstractions.length * 5 +
79
- duplication.length * 10 +
80
- navigationDrifts.length * 12; // Ecclesiastical Navigation is mandatory
81
- const entropyDelta = entropyScore - state.lastEntropy;
82
- await this.saveState(workingDir, {
83
- lastEntropy: entropyScore,
84
- history: [
85
- ...state.history,
86
- { date: new Date().toISOString(), entropy: entropyScore },
87
- ].slice(-20),
88
- fileHashes: newMtimes,
89
- });
90
- let stability = "Stable";
91
- if (entropyScore > 30)
92
- stability = "Toxic";
93
- else if (entropyScore > 15)
94
- stability = "Fragile";
95
- else if (entropyScore > 7)
96
- stability = "Fluid";
97
- const report = {
98
- timestamp: new Date().toISOString(),
99
- zoneViolations,
100
- circularDependencies,
101
- leakyAbstractions,
102
- duplication,
103
- entropyScore,
104
- entropyDelta,
105
- stability,
106
- hotspots: Array.from(new Set([...zoneViolations.map((v) => v.split(" ")[1]), ...toxicFiles])).slice(0, 5),
107
- quarantineCandidates: toxicFiles,
108
- navigationDrifts,
109
- graphDefinition: this.generateMermaidGraph(dependencyGraph, zoneViolations),
110
- passed: entropyScore < 20 && entropyDelta <= 0,
111
- };
112
- await this.writeToSentinelLog(workingDir, report);
113
- return report;
114
- }
115
- /**
116
- * Computes a "Semantic Hash" by tokenizing the code and stripping noise.
117
- * This catches duplication even if variables are renamed (shallowly).
118
- */
119
- static computeSemanticHash(content) {
120
- const tokens = content
121
- .replace(/\/\/.*$/gm, "") // Strip line comments
122
- .replace(/\/\*[\s\S]*?\*\//g, "") // Strip block comments
123
- .replace(/\s+/g, " ") // Normalize whitespace
124
- .replace(/\b(const|let|var)\s+\w+\b/g, "VAR") // Normalize variable declarations
125
- .replace(/\bfunction\s+\w+\b/g, "FUNC") // Normalize function names
126
- .trim();
127
- return crypto.createHash("sha256").update(tokens).digest("hex");
128
75
  }
129
- static async resolveImportDeep(imp, sourceFile, workingDir) {
130
- if (!imp.startsWith("."))
131
- return null; // Ignore external for now
132
- const baseDir = path.dirname(sourceFile);
133
- const candidatePaths = [
134
- path.resolve(baseDir, imp),
135
- path.resolve(baseDir, `${imp}.ts`),
136
- path.resolve(baseDir, `${imp}.tsx`),
137
- path.resolve(baseDir, `${imp}.js`),
138
- path.resolve(baseDir, imp, "index.ts"),
139
- path.resolve(baseDir, imp, "index.js"),
140
- ];
141
- for (const p of candidatePaths) {
142
- try {
143
- const stats = await fs.stat(p);
144
- if (stats.isFile()) {
145
- return path.relative(workingDir, p);
146
- }
147
- }
148
- catch {
149
- continue;
150
- }
76
+ // 2. Cycle Detection (Global)
77
+ // FAST PATH: Skip expensive cycle detection in Ascension mode
78
+ if (!isAscension) {
79
+ const cycles = detectCycles(dependencyGraph);
80
+ for (const cycle of cycles) {
81
+ circularDependencies.push(cycle);
151
82
  }
152
- return null;
153
83
  }
154
- static async analyzeFile(file, workingDir, content, resolvedImports, zoneViolations, leakyAbstractions, navigationDrifts, toxicFiles) {
155
- const relativePath = path.relative(workingDir, file);
156
- const zone = this.getZone(relativePath);
157
- if (!zone)
158
- return;
159
- // A. Real Zone Verification (based on RESOLVED paths)
160
- for (const impPath of resolvedImports) {
161
- const impZone = this.getZone(impPath);
162
- if (!impZone)
163
- continue;
164
- if (zone === this.ZONES.DOMAIN && impZone !== this.ZONES.DOMAIN) {
165
- zoneViolations.push(`[Purity Breach] ${relativePath} -> ${impPath} (${impZone})`);
166
- }
167
- if (zone === this.ZONES.INFRASTRUCTURE &&
168
- impZone === this.ZONES.PLUMBING) {
169
- zoneViolations.push(`[Architecture Leak] ${relativePath} -> ${impPath} (Infrastructure cannot use Plumbing)`);
84
+ // 3. Score Normalization & Ratchet
85
+ const lintErrors = await runLint(workingDir);
86
+ const entropyScore = zoneViolations.length * 8 + // Weighted higher
87
+ lintErrors.length * 1 +
88
+ circularDependencies.length * 15 + // Structural rot is expensive
89
+ toxicFiles.length * 6 +
90
+ leakyAbstractions.length * 5 +
91
+ duplication.length * 10 +
92
+ navigationDrifts.length * 12; // Ecclesiastical Navigation is mandatory
93
+ const entropyDelta = entropyScore - state.lastEntropy;
94
+ await saveState(workingDir, {
95
+ lastEntropy: entropyScore,
96
+ history: [
97
+ ...state.history,
98
+ { date: new Date().toISOString(), entropy: entropyScore },
99
+ ].slice(-20),
100
+ fileHashes: newMtimes,
101
+ });
102
+ let stability = "Stable";
103
+ if (entropyScore > 30)
104
+ stability = "Toxic";
105
+ else if (entropyScore > 15)
106
+ stability = "Fragile";
107
+ else if (entropyScore > 7)
108
+ stability = "Fluid";
109
+ const report = {
110
+ timestamp: new Date().toISOString(),
111
+ zoneViolations,
112
+ circularDependencies,
113
+ leakyAbstractions,
114
+ duplication,
115
+ entropyScore,
116
+ entropyDelta,
117
+ stability,
118
+ hotspots: Array.from(new Set([...zoneViolations.map((v) => v.split(" ")[1]), ...toxicFiles])).slice(0, 5),
119
+ quarantineCandidates: toxicFiles,
120
+ navigationDrifts,
121
+ graphDefinition: generateMermaidGraph(dependencyGraph, zoneViolations),
122
+ passed: entropyScore < 20 && entropyDelta <= 0,
123
+ };
124
+ await writeToSentinelLog(workingDir, report);
125
+ return report;
126
+ }
127
+ /**
128
+ * Computes a "Semantic Hash" by tokenizing the code and stripping noise.
129
+ * This catches duplication even if variables are renamed (shallowly).
130
+ */
131
+ export function computeSemanticHash(content) {
132
+ const tokens = content
133
+ .replace(/\/\/.*$/gm, "") // Strip line comments
134
+ .replace(/\/\*[\s\S]*?\*\//g, "") // Strip block comments
135
+ .replace(/\s+/g, " ") // Normalize whitespace
136
+ .replace(/\b(const|let|var)\s+\w+\b/g, "VAR") // Normalize variable declarations
137
+ .replace(/\bfunction\s+\w+\b/g, "FUNC") // Normalize function names
138
+ .trim();
139
+ return crypto.createHash("sha256").update(tokens).digest("hex");
140
+ }
141
+ export async function resolveImportDeep(imp, sourceFile, workingDir) {
142
+ if (!imp.startsWith("."))
143
+ return null; // Ignore external for now
144
+ const baseDir = path.dirname(sourceFile);
145
+ const candidatePaths = [
146
+ path.resolve(baseDir, imp),
147
+ path.resolve(baseDir, `${imp}.ts`),
148
+ path.resolve(baseDir, `${imp}.tsx`),
149
+ path.resolve(baseDir, `${imp}.js`),
150
+ path.resolve(baseDir, imp, "index.ts"),
151
+ path.resolve(baseDir, imp, "index.js"),
152
+ ];
153
+ for (const p of candidatePaths) {
154
+ try {
155
+ const stats = await fs.stat(p);
156
+ if (stats.isFile()) {
157
+ return path.relative(workingDir, p);
170
158
  }
171
159
  }
172
- // B. Purity Scan (System Types in Domain)
173
- if (zone === this.ZONES.DOMAIN) {
174
- const systemKeywords = /\b(fs|path|os|vscode|express|React|HTMLElement|Buffer|process|window|document)\b/;
175
- if (systemKeywords.test(content)) {
176
- leakyAbstractions.push(`[System Leak] ${relativePath} references non-domain types.`);
177
- }
160
+ catch {
161
+ continue;
178
162
  }
179
- // C. Complexity Guard
180
- const metrics = await ComplexityService.analyze(file);
181
- if (metrics.cyclomaticComplexity > 20 || metrics.clutterLevel === "Toxic") {
182
- toxicFiles.push(relativePath);
163
+ }
164
+ return null;
165
+ }
166
+ export async function analyzeFile(file, workingDir, content, resolvedImports, zoneViolations, leakyAbstractions, navigationDrifts, toxicFiles) {
167
+ const relativePath = path.relative(workingDir, file);
168
+ const zone = getZone(relativePath);
169
+ if (!zone)
170
+ return;
171
+ // A. Real Zone Verification (based on RESOLVED paths)
172
+ for (const impPath of resolvedImports) {
173
+ const impZone = getZone(impPath);
174
+ if (!impZone)
175
+ continue;
176
+ if (zone === ZONES.DOMAIN && impZone !== ZONES.DOMAIN) {
177
+ zoneViolations.push(`[Purity Breach] ${relativePath} -> ${impPath} (${impZone})`);
183
178
  }
184
- // D. Ecclesiastical Navigation Check (Webapp/UI Files)
185
- if (relativePath.includes(".tsx") || content.includes("react-router-dom")) {
186
- const flatRouteRegex = /path=['"]\/(blog|docs|legal|support)\/:slug['"]/g;
187
- if (flatRouteRegex.test(content)) {
188
- navigationDrifts.push(`[Ecclesiastical Violation] ${relativePath} uses flat routes. Use hierarchical schema (e.g., /blog/:year/:month/:slug).`);
189
- }
190
- // Secondary check for Breadcrumb presence in content views
191
- if (content.includes("ArticleView") && !content.includes("Breadcrumbs")) {
192
- navigationDrifts.push(`[Liturgical Violation] ${relativePath} is a content view missing mandatory Breadcrumbs.`);
193
- }
179
+ if (zone === ZONES.INFRASTRUCTURE && impZone === ZONES.PLUMBING) {
180
+ zoneViolations.push(`[Architecture Leak] ${relativePath} -> ${impPath} (Infrastructure cannot use Plumbing)`);
194
181
  }
195
182
  }
196
- static getZone(filePath) {
197
- if (filePath.includes("src/domain") || filePath.includes("/domain/"))
198
- return this.ZONES.DOMAIN;
199
- if (filePath.includes("src/infrastructure") ||
200
- filePath.includes("/infrastructure/"))
201
- return this.ZONES.INFRASTRUCTURE;
202
- if (filePath.includes("src/plumbing") || filePath.includes("/plumbing/"))
203
- return this.ZONES.PLUMBING;
204
- return null;
205
- }
206
- static extractImports(content) {
207
- const imports = [];
208
- const importRegex = /from\s+['"](.*?)['"]/g;
209
- const requireRegex = /require\(['"](.*?)['"]\)/g;
210
- let match;
211
- while ((match = importRegex.exec(content)) !== null)
212
- imports.push(match[1]);
213
- while ((match = requireRegex.exec(content)) !== null)
214
- imports.push(match[1]);
215
- return Array.from(new Set(imports));
216
- }
217
- static detectCycles(graph) {
218
- const cycles = [];
219
- const visited = new Set();
220
- const stack = new Set();
221
- const dfs = (node, path) => {
222
- visited.add(node);
223
- stack.add(node);
224
- for (const neighbor of graph.get(node) || []) {
225
- if (stack.has(neighbor)) {
226
- cycles.push(`🔄 ${path.join(" -> ")} -> ${neighbor}`);
227
- }
228
- else if (!visited.has(neighbor)) {
229
- dfs(neighbor, [...path, neighbor]);
230
- }
231
- }
232
- stack.delete(node);
233
- };
234
- for (const node of graph.keys()) {
235
- if (!visited.has(node))
236
- dfs(node, [node]);
183
+ // B. Purity Scan (System Types in Domain)
184
+ if (zone === ZONES.DOMAIN) {
185
+ const systemKeywords = /\b(fs|path|os|express|React|HTMLElement|Buffer|process|window|document)\b/;
186
+ if (systemKeywords.test(content)) {
187
+ leakyAbstractions.push(`[System Leak] ${relativePath} references non-domain types.`);
237
188
  }
238
- return cycles;
239
189
  }
240
- static generateMermaidGraph(graph, violations) {
241
- let mermaid = "graph TD;\n";
242
- const nodes = Array.from(graph.keys()).slice(0, 40);
243
- nodes.forEach((node) => {
244
- const id = node.replace(/[^a-zA-Z0-9]/g, "_");
245
- const name = path.basename(node);
246
- graph.get(node)?.forEach((dep) => {
247
- const depId = dep.replace(/[^a-zA-Z0-9]/g, "_");
248
- const isViolated = violations.some((v) => v.includes(node) && v.includes(dep));
249
- mermaid += ` ${id}[${name}] --> ${depId}[${path.basename(dep)}];\n`;
250
- if (isViolated)
251
- mermaid += ` style ${id} fill:#f96,stroke:#333,stroke-width:2px\n`;
252
- });
253
- });
254
- return mermaid;
190
+ // C. Complexity Guard
191
+ const metrics = await analyzeComplexity(file);
192
+ if (metrics.cyclomaticComplexity > 20 || metrics.clutterLevel === "Toxic") {
193
+ toxicFiles.push(relativePath);
255
194
  }
256
- static async loadState(workingDir) {
257
- try {
258
- const content = await fs.readFile(path.join(workingDir, this.STATE_FILE), "utf8");
259
- return JSON.parse(content);
195
+ // D. Ecclesiastical Navigation Check (Webapp/UI Files)
196
+ if (relativePath.includes(".tsx") || content.includes("react-router-dom")) {
197
+ const flatRouteRegex = /path=['"]\/(blog|docs|legal|support)\/:slug['"]/g;
198
+ if (flatRouteRegex.test(content)) {
199
+ navigationDrifts.push(`[Ecclesiastical Violation] ${relativePath} uses flat routes. Use hierarchical schema (e.g., /blog/:year/:month/:slug).`);
260
200
  }
261
- catch {
262
- return { lastEntropy: 0, history: [], fileHashes: {} };
201
+ // Secondary check for Breadcrumb presence in content views
202
+ if (content.includes("ArticleView") && !content.includes("Breadcrumbs")) {
203
+ navigationDrifts.push(`[Liturgical Violation] ${relativePath} is a content view missing mandatory Breadcrumbs.`);
263
204
  }
264
205
  }
265
- static async saveState(workingDir, state) {
266
- const dir = path.join(workingDir, ".marie");
267
- await fs.mkdir(dir, { recursive: true });
268
- await fs.writeFile(path.join(workingDir, this.STATE_FILE), JSON.stringify(state, null, 2));
206
+ }
207
+ export function getZone(filePath) {
208
+ if (filePath.includes("src/domain") || filePath.includes("/domain/"))
209
+ return ZONES.DOMAIN;
210
+ if (filePath.includes("src/infrastructure") ||
211
+ filePath.includes("/infrastructure/"))
212
+ return ZONES.INFRASTRUCTURE;
213
+ if (filePath.includes("src/plumbing") || filePath.includes("/plumbing/"))
214
+ return ZONES.PLUMBING;
215
+ return null;
216
+ }
217
+ export function extractImports(content) {
218
+ const imports = [];
219
+ const importRegex = /from\s+['"](.*?)['"]/g;
220
+ const requireRegex = /require\(['"](.*?)['"]\)/g;
221
+ let match;
222
+ while ((match = importRegex.exec(content)) !== null)
223
+ imports.push(match[1]);
224
+ while ((match = requireRegex.exec(content)) !== null)
225
+ imports.push(match[1]);
226
+ return Array.from(new Set(imports));
227
+ }
228
+ export function detectCycles(graph) {
229
+ const cycles = [];
230
+ const visited = new Set();
231
+ const stack = new Set();
232
+ const dfs = (node, path) => {
233
+ visited.add(node);
234
+ stack.add(node);
235
+ for (const neighbor of graph.get(node) || []) {
236
+ if (stack.has(neighbor)) {
237
+ cycles.push(`🔄 ${path.join(" -> ")} -> ${neighbor}`);
238
+ }
239
+ else if (!visited.has(neighbor)) {
240
+ dfs(neighbor, [...path, neighbor]);
241
+ }
242
+ }
243
+ stack.delete(node);
244
+ };
245
+ for (const node of graph.keys()) {
246
+ if (!visited.has(node))
247
+ dfs(node, [node]);
269
248
  }
270
- static async getAllFiles(dir) {
271
- const entries = await fs.readdir(dir, { withFileTypes: true });
272
- const files = await Promise.all(entries.map((entry) => {
273
- const res = path.resolve(dir, entry.name);
274
- if (res.includes("node_modules") ||
275
- res.includes(".git") ||
276
- res.includes("dist"))
277
- return [];
278
- return entry.isDirectory() ? this.getAllFiles(res) : res;
279
- }));
280
- return files.flat().filter((f) => /\.(ts|tsx)$/.test(f));
249
+ return cycles;
250
+ }
251
+ export function generateMermaidGraph(graph, violations) {
252
+ let mermaid = "graph TD;\n";
253
+ const nodes = Array.from(graph.keys()).slice(0, 40);
254
+ nodes.forEach((node) => {
255
+ const id = node.replace(/[^a-zA-Z0-9]/g, "_");
256
+ const name = path.basename(node);
257
+ graph.get(node)?.forEach((dep) => {
258
+ const depId = dep.replace(/[^a-zA-Z0-9]/g, "_");
259
+ const isViolated = violations.some((v) => v.includes(node) && v.includes(dep));
260
+ mermaid += ` ${id}[${name}] --> ${depId}[${path.basename(dep)}];\n`;
261
+ if (isViolated)
262
+ mermaid += ` style ${id} fill:#f96,stroke:#333,stroke-width:2px\n`;
263
+ });
264
+ });
265
+ return mermaid;
266
+ }
267
+ export async function loadState(workingDir) {
268
+ try {
269
+ const content = await fs.readFile(path.join(workingDir, STATE_FILE), "utf8");
270
+ return JSON.parse(content);
281
271
  }
282
- static async writeToSentinelLog(workingDir, report) {
283
- const logPath = path.join(workingDir, "SENTINEL.md");
284
- const summary = `
272
+ catch {
273
+ return { lastEntropy: 0, history: [], fileHashes: {} };
274
+ }
275
+ }
276
+ export async function saveState(workingDir, state) {
277
+ const dir = path.join(workingDir, ".marie");
278
+ await fs.mkdir(dir, { recursive: true });
279
+ await fs.writeFile(path.join(workingDir, STATE_FILE), safeStringify(state, 2));
280
+ }
281
+ export async function getAllFiles(dir) {
282
+ const entries = await fs.readdir(dir, { withFileTypes: true });
283
+ const files = await Promise.all(entries.map((entry) => {
284
+ const res = path.resolve(dir, entry.name);
285
+ if (res.includes("node_modules") ||
286
+ res.includes(".git") ||
287
+ res.includes("dist"))
288
+ return [];
289
+ return entry.isDirectory() ? getAllFiles(res) : res;
290
+ }));
291
+ return files.flat().filter((f) => /\.(ts|tsx)$/.test(f));
292
+ }
293
+ export async function writeToSentinelLog(workingDir, report) {
294
+ const logPath = path.join(workingDir, "SENTINEL.md");
295
+ const summary = `
285
296
  # 🛡️ Sentinel Report: ${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}
286
297
 
287
298
  **Stability**: ${report.stability}
@@ -302,26 +313,25 @@ ${report.graphDefinition}
302
313
 
303
314
  ## 📜 High-Priority Alerts
304
315
  ${report.zoneViolations
305
- .slice(0, 5)
306
- .map((v) => `- ❌ ${v}`)
307
- .join("\n")}
316
+ .slice(0, 5)
317
+ .map((v) => `- ❌ ${v}`)
318
+ .join("\n")}
308
319
  ${report.circularDependencies
309
- .slice(0, 3)
310
- .map((c) => `- 🔄 ${c}`)
311
- .join("\n")}
320
+ .slice(0, 3)
321
+ .map((c) => `- 🔄 ${c}`)
322
+ .join("\n")}
312
323
  ${report.duplication
313
- .slice(0, 3)
314
- .map((d) => `- 👯 ${d}`)
315
- .join("\n")}
324
+ .slice(0, 3)
325
+ .map((d) => `- 👯 ${d}`)
326
+ .join("\n")}
316
327
  ${report.navigationDrifts
317
- .slice(0, 5)
318
- .map((n) => `- 🧭 ${n}`)
319
- .join("\n")}
328
+ .slice(0, 5)
329
+ .map((n) => `- 🧭 ${n}`)
330
+ .join("\n")}
320
331
 
321
332
  ---
322
333
  *Marie Sentinel v3.1 — Grounded Architectural Guardian*
323
334
  `;
324
- await fs.writeFile(logPath, summary);
325
- }
335
+ await fs.writeFile(logPath, summary);
326
336
  }
327
337
  //# sourceMappingURL=MarieSentinelService.js.map