@noorm/marie-cli 0.1.17 → 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 (299) hide show
  1. package/README.md +7 -15
  2. package/SENTINEL.md +4 -7
  3. package/dist/cli-new/components/AgenticSpinner.js +28 -0
  4. package/dist/cli-new/components/AgenticSpinner.js.map +1 -0
  5. package/dist/cli-new/components/App.js +16 -63
  6. package/dist/cli-new/components/App.js.map +1 -1
  7. package/dist/cli-new/components/ApprovalDialog.js +3 -2
  8. package/dist/cli-new/components/ApprovalDialog.js.map +1 -1
  9. package/dist/cli-new/components/Banner.js +16 -5
  10. package/dist/cli-new/components/Banner.js.map +1 -1
  11. package/dist/cli-new/components/ChatArea.js +6 -7
  12. package/dist/cli-new/components/ChatArea.js.map +1 -1
  13. package/dist/cli-new/components/Header.js +14 -8
  14. package/dist/cli-new/components/Header.js.map +1 -1
  15. package/dist/cli-new/components/InputArea.js +98 -31
  16. package/dist/cli-new/components/InputArea.js.map +1 -1
  17. package/dist/cli-new/components/MessageBubble.js +28 -19
  18. package/dist/cli-new/components/MessageBubble.js.map +1 -1
  19. package/dist/cli-new/components/SessionSwitcher.js +6 -9
  20. package/dist/cli-new/components/SessionSwitcher.js.map +1 -1
  21. package/dist/cli-new/components/SetupWizard.js +80 -257
  22. package/dist/cli-new/components/SetupWizard.js.map +1 -1
  23. package/dist/cli-new/components/ToolCallDisplay.js +20 -5
  24. package/dist/cli-new/components/ToolCallDisplay.js.map +1 -1
  25. package/dist/cli-new/components/WizardSteps.js +22 -0
  26. package/dist/cli-new/components/WizardSteps.js.map +1 -0
  27. package/dist/cli-new/constants/SetupConstants.js +42 -0
  28. package/dist/cli-new/constants/SetupConstants.js.map +1 -0
  29. package/dist/cli-new/hooks/useGit.js +19 -62
  30. package/dist/cli-new/hooks/useGit.js.map +1 -1
  31. package/dist/cli-new/hooks/useMarie.js +26 -18
  32. package/dist/cli-new/hooks/useMarie.js.map +1 -1
  33. package/dist/cli-new/hooks/useSessions.js +1 -1
  34. package/dist/cli-new/hooks/useSessions.js.map +1 -1
  35. package/dist/cli-new/hooks/useSetupWizard.js +88 -0
  36. package/dist/cli-new/hooks/useSetupWizard.js.map +1 -0
  37. package/dist/cli-new/hooks/useUpdateCheck.js +4 -3
  38. package/dist/cli-new/hooks/useUpdateCheck.js.map +1 -1
  39. package/dist/cli-new/index.js +2 -4
  40. package/dist/cli-new/index.js.map +1 -1
  41. package/dist/cli-new/services/CommandService.js +104 -0
  42. package/dist/cli-new/services/CommandService.js.map +1 -0
  43. package/dist/cli-new/services/GitService.js +91 -0
  44. package/dist/cli-new/services/GitService.js.map +1 -0
  45. package/dist/cli-new/services/MarieService.js +77 -0
  46. package/dist/cli-new/services/MarieService.js.map +1 -0
  47. package/dist/cli-new/services/auth-server.js +128 -0
  48. package/dist/cli-new/services/auth-server.js.map +1 -0
  49. package/dist/cli-new/styles/theme.js +17 -17
  50. package/dist/cli-new/styles/theme.js.map +1 -1
  51. package/dist/cli-new/utils/version.js +24 -0
  52. package/dist/cli-new/utils/version.js.map +1 -0
  53. package/dist/monolith/adapters/CliMarieAdapter.js +19 -18
  54. package/dist/monolith/adapters/CliMarieAdapter.js.map +1 -1
  55. package/dist/monolith/cli/CliFileSystemPort.js +17 -3
  56. package/dist/monolith/cli/CliFileSystemPort.js.map +1 -1
  57. package/dist/monolith/cli/MarieToolDefinitionsCLI.js +44 -33
  58. package/dist/monolith/cli/MarieToolDefinitionsCLI.js.map +1 -1
  59. package/dist/monolith/cli/index.js +11 -20
  60. package/dist/monolith/cli/index.js.map +1 -1
  61. package/dist/monolith/cli/services/JoyAutomationServiceCLI.js +15 -62
  62. package/dist/monolith/cli/services/JoyAutomationServiceCLI.js.map +1 -1
  63. package/dist/monolith/cli/storage.js +154 -65
  64. package/dist/monolith/cli/storage.js.map +1 -1
  65. package/dist/monolith/domain/joy/RitualService.js +44 -46
  66. package/dist/monolith/domain/joy/RitualService.js.map +1 -1
  67. package/dist/monolith/domain/marie/MarieCortex.js +148 -0
  68. package/dist/monolith/domain/marie/MarieCortex.js.map +1 -0
  69. package/dist/monolith/domain/marie/PersonalityRenderer.js +97 -0
  70. package/dist/monolith/domain/marie/PersonalityRenderer.js.map +1 -0
  71. package/dist/monolith/infrastructure/Configuration.js +68 -0
  72. package/dist/monolith/infrastructure/Configuration.js.map +1 -0
  73. package/dist/monolith/infrastructure/CoreInfrastructure.js +204 -0
  74. package/dist/monolith/infrastructure/CoreInfrastructure.js.map +1 -0
  75. package/dist/monolith/infrastructure/ai/agents/MarieAscendant.js +3 -3
  76. package/dist/monolith/infrastructure/ai/agents/MarieAscendant.js.map +1 -1
  77. package/dist/monolith/infrastructure/ai/context/ContextArchiveService.js +51 -57
  78. package/dist/monolith/infrastructure/ai/context/ContextArchiveService.js.map +1 -1
  79. package/dist/monolith/infrastructure/ai/context/ContextManager.js +142 -98
  80. package/dist/monolith/infrastructure/ai/context/ContextManager.js.map +1 -1
  81. package/dist/monolith/infrastructure/ai/core/MarieEngine.js +104 -556
  82. package/dist/monolith/infrastructure/ai/core/MarieEngine.js.map +1 -1
  83. package/dist/monolith/infrastructure/ai/core/MarieEventDispatcher.js +1 -37
  84. package/dist/monolith/infrastructure/ai/core/MarieEventDispatcher.js.map +1 -1
  85. package/dist/monolith/infrastructure/ai/core/MarieLockManager.js +30 -5
  86. package/dist/monolith/infrastructure/ai/core/MarieLockManager.js.map +1 -1
  87. package/dist/monolith/infrastructure/ai/core/MarieProgressTracker.js +176 -196
  88. package/dist/monolith/infrastructure/ai/core/MarieProgressTracker.js.map +1 -1
  89. package/dist/monolith/infrastructure/ai/core/MariePulseService.js +41 -7
  90. package/dist/monolith/infrastructure/ai/core/MariePulseService.js.map +1 -1
  91. package/dist/monolith/infrastructure/ai/core/MarieSanitizer.js +303 -63
  92. package/dist/monolith/infrastructure/ai/core/MarieSanitizer.js.map +1 -1
  93. package/dist/monolith/infrastructure/ai/core/MarieSemaphore.js +47 -4
  94. package/dist/monolith/infrastructure/ai/core/MarieSemaphore.js.map +1 -1
  95. package/dist/monolith/infrastructure/ai/core/MarieSession.js +95 -15
  96. package/dist/monolith/infrastructure/ai/core/MarieSession.js.map +1 -1
  97. package/dist/monolith/infrastructure/ai/core/MarieStabilityMonitor.js +21 -0
  98. package/dist/monolith/infrastructure/ai/core/MarieStabilityMonitor.js.map +1 -1
  99. package/dist/monolith/infrastructure/ai/core/MarieToolMender.js +12 -0
  100. package/dist/monolith/infrastructure/ai/core/MarieToolMender.js.map +1 -1
  101. package/dist/monolith/infrastructure/ai/core/MarieToolProcessor.js +339 -481
  102. package/dist/monolith/infrastructure/ai/core/MarieToolProcessor.js.map +1 -1
  103. package/dist/monolith/infrastructure/ai/core/MarieVitality.js +238 -0
  104. package/dist/monolith/infrastructure/ai/core/MarieVitality.js.map +1 -0
  105. package/dist/monolith/infrastructure/ai/core/ReasoningBudget.js +23 -12
  106. package/dist/monolith/infrastructure/ai/core/ReasoningBudget.js.map +1 -1
  107. package/dist/monolith/infrastructure/ai/core/SessionLogService.js +9 -2
  108. package/dist/monolith/infrastructure/ai/core/SessionLogService.js.map +1 -1
  109. package/dist/monolith/infrastructure/ai/providers/AIProvider.js +402 -1
  110. package/dist/monolith/infrastructure/ai/providers/AIProvider.js.map +1 -1
  111. package/dist/monolith/infrastructure/ai/providers/DreamBeesProvider.js +114 -0
  112. package/dist/monolith/infrastructure/ai/providers/DreamBeesProvider.js.map +1 -0
  113. package/dist/monolith/infrastructure/ai/providers/OpenRouterProvider.js +426 -370
  114. package/dist/monolith/infrastructure/ai/providers/OpenRouterProvider.js.map +1 -1
  115. package/dist/monolith/infrastructure/ai/providers/OpenRouterStreamParser.js +235 -241
  116. package/dist/monolith/infrastructure/ai/providers/OpenRouterStreamParser.js.map +1 -1
  117. package/dist/monolith/infrastructure/ai/workerAi.js +185 -0
  118. package/dist/monolith/infrastructure/ai/workerAi.js.map +1 -0
  119. package/dist/monolith/infrastructure/config/ConfigService.js +216 -359
  120. package/dist/monolith/infrastructure/config/ConfigService.js.map +1 -1
  121. package/dist/monolith/infrastructure/joy/CognitiveRituals.js +8 -0
  122. package/dist/monolith/infrastructure/joy/CognitiveRituals.js.map +1 -0
  123. package/dist/monolith/infrastructure/joy/JoyTools.js +23 -43
  124. package/dist/monolith/infrastructure/joy/JoyTools.js.map +1 -1
  125. package/dist/monolith/infrastructure/persistence/MarieMindAutonomics.js +4 -0
  126. package/dist/monolith/infrastructure/persistence/MarieMindAutonomics.js.map +1 -0
  127. package/dist/monolith/infrastructure/persistence/MarieMindEngine.js +11 -0
  128. package/dist/monolith/infrastructure/persistence/MarieMindEngine.js.map +1 -0
  129. package/dist/monolith/infrastructure/persistence/NoormmeAutonomics.js +135 -0
  130. package/dist/monolith/infrastructure/persistence/NoormmeAutonomics.js.map +1 -0
  131. package/dist/monolith/infrastructure/persistence/NoormmeEngine.js +523 -0
  132. package/dist/monolith/infrastructure/persistence/NoormmeEngine.js.map +1 -0
  133. package/dist/monolith/infrastructure/persistence/NoormmeSchema.js +179 -0
  134. package/dist/monolith/infrastructure/persistence/NoormmeSchema.js.map +1 -0
  135. package/dist/monolith/infrastructure/persistence/NoormmeSeeder.js +94 -0
  136. package/dist/monolith/infrastructure/persistence/NoormmeSeeder.js.map +1 -0
  137. package/dist/monolith/infrastructure/persistence/NoormmeTools.js +371 -0
  138. package/dist/monolith/infrastructure/persistence/NoormmeTools.js.map +1 -0
  139. package/dist/monolith/infrastructure/services/MarieMemoryStore.js +133 -134
  140. package/dist/monolith/infrastructure/services/MarieMemoryStore.js.map +1 -1
  141. package/dist/monolith/infrastructure/tools/MarieToolDefinitions.js +6 -1578
  142. package/dist/monolith/infrastructure/tools/MarieToolDefinitions.js.map +1 -1
  143. package/dist/monolith/infrastructure/tools/PureStreamParser.js +68 -80
  144. package/dist/monolith/infrastructure/tools/PureStreamParser.js.map +1 -1
  145. package/dist/monolith/infrastructure/tools/SharedToolDefinitions.js +12 -11
  146. package/dist/monolith/infrastructure/tools/SharedToolDefinitions.js.map +1 -1
  147. package/dist/monolith/infrastructure/tools/SovereignTools.js +326 -0
  148. package/dist/monolith/infrastructure/tools/SovereignTools.js.map +1 -0
  149. package/dist/monolith/infrastructure/tools/ToolRegistry.js +45 -26
  150. package/dist/monolith/infrastructure/tools/ToolRegistry.js.map +1 -1
  151. package/dist/monolith/infrastructure/tools/definitions/AnalysisTools.js +232 -0
  152. package/dist/monolith/infrastructure/tools/definitions/AnalysisTools.js.map +1 -0
  153. package/dist/monolith/infrastructure/tools/definitions/AutomationTools.js +274 -0
  154. package/dist/monolith/infrastructure/tools/definitions/AutomationTools.js.map +1 -0
  155. package/dist/monolith/infrastructure/tools/definitions/ContextTools.js +71 -0
  156. package/dist/monolith/infrastructure/tools/definitions/ContextTools.js.map +1 -0
  157. package/dist/monolith/infrastructure/tools/definitions/CoreTools.js +37 -0
  158. package/dist/monolith/infrastructure/tools/definitions/CoreTools.js.map +1 -0
  159. package/dist/monolith/infrastructure/tools/definitions/DiagnosticTools.js +154 -0
  160. package/dist/monolith/infrastructure/tools/definitions/DiagnosticTools.js.map +1 -0
  161. package/dist/monolith/infrastructure/tools/definitions/NavigationTools.js +197 -0
  162. package/dist/monolith/infrastructure/tools/definitions/NavigationTools.js.map +1 -0
  163. package/dist/monolith/infrastructure/tools/definitions/PlanningTools.js +300 -0
  164. package/dist/monolith/infrastructure/tools/definitions/PlanningTools.js.map +1 -0
  165. package/dist/monolith/plumbing/Plumbing.js +238 -0
  166. package/dist/monolith/plumbing/Plumbing.js.map +1 -0
  167. package/dist/monolith/plumbing/PlumbingAnalysis.js +109 -0
  168. package/dist/monolith/plumbing/PlumbingAnalysis.js.map +1 -0
  169. package/dist/monolith/plumbing/PlumbingSystem.js +169 -0
  170. package/dist/monolith/plumbing/PlumbingSystem.js.map +1 -0
  171. package/dist/monolith/plumbing/analysis/ComplexityService.js +30 -34
  172. package/dist/monolith/plumbing/analysis/ComplexityService.js.map +1 -1
  173. package/dist/monolith/plumbing/analysis/DependencyService.js +55 -44
  174. package/dist/monolith/plumbing/analysis/DependencyService.js.map +1 -1
  175. package/dist/monolith/plumbing/analysis/DiscoveryService.js +40 -42
  176. package/dist/monolith/plumbing/analysis/DiscoveryService.js.map +1 -1
  177. package/dist/monolith/plumbing/analysis/JoyMapService.js +52 -56
  178. package/dist/monolith/plumbing/analysis/JoyMapService.js.map +1 -1
  179. package/dist/monolith/plumbing/analysis/LintService.js +118 -118
  180. package/dist/monolith/plumbing/analysis/LintService.js.map +1 -1
  181. package/dist/monolith/plumbing/analysis/MarieSentinelService.js +278 -269
  182. package/dist/monolith/plumbing/analysis/MarieSentinelService.js.map +1 -1
  183. package/dist/monolith/plumbing/analysis/QualityGuardrailService.js +116 -114
  184. package/dist/monolith/plumbing/analysis/QualityGuardrailService.js.map +1 -1
  185. package/dist/monolith/plumbing/analysis/SurgicalMender.js +57 -59
  186. package/dist/monolith/plumbing/analysis/SurgicalMender.js.map +1 -1
  187. package/dist/monolith/plumbing/analysis/TestService.js +89 -89
  188. package/dist/monolith/plumbing/analysis/TestService.js.map +1 -1
  189. package/dist/monolith/plumbing/filesystem/FileService.js +123 -195
  190. package/dist/monolith/plumbing/filesystem/FileService.js.map +1 -1
  191. package/dist/monolith/plumbing/filesystem/PathResolver.js +7 -8
  192. package/dist/monolith/plumbing/filesystem/PathResolver.js.map +1 -1
  193. package/dist/monolith/plumbing/git/GitService.js +4 -4
  194. package/dist/monolith/plumbing/git/GitService.js.map +1 -1
  195. package/dist/monolith/plumbing/lsp/SymbolService.js +5 -34
  196. package/dist/monolith/plumbing/lsp/SymbolService.js.map +1 -1
  197. package/dist/monolith/plumbing/terminal/ProcessRegistry.js +20 -22
  198. package/dist/monolith/plumbing/terminal/ProcessRegistry.js.map +1 -1
  199. package/dist/monolith/plumbing/terminal/TerminalService.js +127 -136
  200. package/dist/monolith/plumbing/terminal/TerminalService.js.map +1 -1
  201. package/dist/monolith/plumbing/utils/EnvironmentUtils.js +3 -23
  202. package/dist/monolith/plumbing/utils/EnvironmentUtils.js.map +1 -1
  203. package/dist/monolith/plumbing/utils/JsonUtils.js +252 -311
  204. package/dist/monolith/plumbing/utils/JsonUtils.js.map +1 -1
  205. package/dist/monolith/plumbing/utils/MutexUtils.js.map +1 -1
  206. package/dist/monolith/plumbing/utils/PlumbingCore.js +549 -0
  207. package/dist/monolith/plumbing/utils/PlumbingCore.js.map +1 -0
  208. package/dist/monolith/plumbing/utils/PrefixTree.js +61 -114
  209. package/dist/monolith/plumbing/utils/PrefixTree.js.map +1 -1
  210. package/dist/monolith/plumbing/utils/StreamTagDetector.js +89 -127
  211. package/dist/monolith/plumbing/utils/StreamTagDetector.js.map +1 -1
  212. package/dist/monolith/plumbing/utils/StringUtils.js +87 -89
  213. package/dist/monolith/plumbing/utils/StringUtils.js.map +1 -1
  214. package/dist/monolith/runtime/MarieRuntime.js +76 -417
  215. package/dist/monolith/runtime/MarieRuntime.js.map +1 -1
  216. package/dist/monolith/runtime/RuntimeAdapterBase.js +1 -1
  217. package/dist/monolith/runtime/RuntimeAdapterBase.js.map +1 -1
  218. package/dist/monolith/runtime/providerFactory.js +1 -7
  219. package/dist/monolith/runtime/providerFactory.js.map +1 -1
  220. package/dist/monolith/services/HealthService.js +29 -32
  221. package/dist/monolith/services/HealthService.js.map +1 -1
  222. package/dist/monolith/services/JoyAutomationService.js +58 -95
  223. package/dist/monolith/services/JoyAutomationService.js.map +1 -1
  224. package/dist/monolith/services/MarieAutomationService.js +59 -0
  225. package/dist/monolith/services/MarieAutomationService.js.map +1 -0
  226. package/dist/monolith/services/MarieGhostService.js +46 -161
  227. package/dist/monolith/services/MarieGhostService.js.map +1 -1
  228. package/dist/monolith/services/MarieServices.js +102 -0
  229. package/dist/monolith/services/MarieServices.js.map +1 -0
  230. package/dist/monolith/services/MarieTypes.js +2 -0
  231. package/dist/monolith/services/MarieTypes.js.map +1 -0
  232. package/dist/monolith/services/UpdateService.js +47 -49
  233. package/dist/monolith/services/UpdateService.js.map +1 -1
  234. package/dist/prompts.js +11 -5
  235. package/dist/prompts.js.map +1 -1
  236. package/dist/test_prefix_tree.js +9 -9
  237. package/dist/test_prefix_tree.js.map +1 -1
  238. package/package.json +18 -88
  239. package/run_test.js +5 -0
  240. package/.marie_visual_verify_1771225696548/progress_bar_check.txt +0 -1
  241. package/dist/extension.cjs +0 -635
  242. package/dist/extension.js +0 -473
  243. package/dist/extension.js.map +0 -1
  244. package/dist/monolith/adapters/VscodeMarieAdapter.js +0 -81
  245. package/dist/monolith/adapters/VscodeMarieAdapter.js.map +0 -1
  246. package/dist/monolith/domain/joy/JoyTools.js +0 -535
  247. package/dist/monolith/domain/joy/JoyTools.js.map +0 -1
  248. package/dist/monolith/infrastructure/ai/agents/MarieYOLO.js +0 -207
  249. package/dist/monolith/infrastructure/ai/agents/MarieYOLO.js.map +0 -1
  250. package/dist/monolith/infrastructure/ai/core/GhostPort.js +0 -2
  251. package/dist/monolith/infrastructure/ai/core/GhostPort.js.map +0 -1
  252. package/dist/monolith/infrastructure/ai/core/MarieYOLOTypes.js +0 -2
  253. package/dist/monolith/infrastructure/ai/core/MarieYOLOTypes.js.map +0 -1
  254. package/dist/monolith/infrastructure/ai/core/VscodeFileSystemPort.js +0 -33
  255. package/dist/monolith/infrastructure/ai/core/VscodeFileSystemPort.js.map +0 -1
  256. package/dist/monolith/infrastructure/ai/providers/AnthropicProvider.js +0 -148
  257. package/dist/monolith/infrastructure/ai/providers/AnthropicProvider.js.map +0 -1
  258. package/dist/monolith/infrastructure/ai/providers/CerebrasProvider.js +0 -208
  259. package/dist/monolith/infrastructure/ai/providers/CerebrasProvider.js.map +0 -1
  260. package/dist/monolith/plumbing/ui/DecorationService.js +0 -54
  261. package/dist/monolith/plumbing/ui/DecorationService.js.map +0 -1
  262. package/dist/monolith/services/JoyLogService.js +0 -48
  263. package/dist/monolith/services/JoyLogService.js.map +0 -1
  264. package/dist/monolith/services/JoyService.js +0 -209
  265. package/dist/monolith/services/JoyService.js.map +0 -1
  266. package/dist/monolith/services/MarieSCMProvider.js +0 -41
  267. package/dist/monolith/services/MarieSCMProvider.js.map +0 -1
  268. package/dist/test_agent_stream_control_plane.js +0 -170
  269. package/dist/test_agent_stream_control_plane.js.map +0 -1
  270. package/dist/test_strategy_integration.js +0 -114
  271. package/dist/test_strategy_integration.js.map +0 -1
  272. package/dist/test_streaming_fragility.js +0 -191
  273. package/dist/test_streaming_fragility.js.map +0 -1
  274. package/dist/webview-ui/App.js +0 -16
  275. package/dist/webview-ui/App.js.map +0 -1
  276. package/dist/webview-ui/Providers.js +0 -6
  277. package/dist/webview-ui/Providers.js.map +0 -1
  278. package/dist/webview-ui/components/ApprovalPanel.js +0 -8
  279. package/dist/webview-ui/components/ApprovalPanel.js.map +0 -1
  280. package/dist/webview-ui/components/ChatPanel.js +0 -19
  281. package/dist/webview-ui/components/ChatPanel.js.map +0 -1
  282. package/dist/webview-ui/components/Composer.js +0 -19
  283. package/dist/webview-ui/components/Composer.js.map +0 -1
  284. package/dist/webview-ui/components/HeaderBar.js +0 -5
  285. package/dist/webview-ui/components/HeaderBar.js.map +0 -1
  286. package/dist/webview-ui/components/SessionList.js +0 -14
  287. package/dist/webview-ui/components/SessionList.js.map +0 -1
  288. package/dist/webview-ui/context/WebviewStateContext.js +0 -146
  289. package/dist/webview-ui/context/WebviewStateContext.js.map +0 -1
  290. package/dist/webview-ui/main.css +0 -1
  291. package/dist/webview-ui/main.js +0 -108
  292. package/dist/webview-ui/main.js.map +0 -1
  293. package/dist/webview-ui/types.js +0 -2
  294. package/dist/webview-ui/types.js.map +0 -1
  295. package/dist/webview-ui/vscode.js +0 -4
  296. package/dist/webview-ui/vscode.js.map +0 -1
  297. package/lint_output.txt +0 -705
  298. package/lint_output_v2.txt +0 -711
  299. package/marie-coder-0.1.16.vsix +0 -0
@@ -1,288 +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") &&
192
- !content.includes("Breadcrumbs")) {
193
- navigationDrifts.push(`[Liturgical Violation] ${relativePath} is a content view missing mandatory Breadcrumbs.`);
194
- }
179
+ if (zone === ZONES.INFRASTRUCTURE && impZone === ZONES.PLUMBING) {
180
+ zoneViolations.push(`[Architecture Leak] ${relativePath} -> ${impPath} (Infrastructure cannot use Plumbing)`);
195
181
  }
196
182
  }
197
- static getZone(filePath) {
198
- if (filePath.includes("src/domain") || filePath.includes("/domain/"))
199
- return this.ZONES.DOMAIN;
200
- if (filePath.includes("src/infrastructure") ||
201
- filePath.includes("/infrastructure/"))
202
- return this.ZONES.INFRASTRUCTURE;
203
- if (filePath.includes("src/plumbing") || filePath.includes("/plumbing/"))
204
- return this.ZONES.PLUMBING;
205
- return null;
206
- }
207
- static extractImports(content) {
208
- const imports = [];
209
- const importRegex = /from\s+['"](.*?)['"]/g;
210
- const requireRegex = /require\(['"](.*?)['"]\)/g;
211
- let match;
212
- while ((match = importRegex.exec(content)) !== null)
213
- imports.push(match[1]);
214
- while ((match = requireRegex.exec(content)) !== null)
215
- imports.push(match[1]);
216
- return Array.from(new Set(imports));
217
- }
218
- static detectCycles(graph) {
219
- const cycles = [];
220
- const visited = new Set();
221
- const stack = new Set();
222
- const dfs = (node, path) => {
223
- visited.add(node);
224
- stack.add(node);
225
- for (const neighbor of graph.get(node) || []) {
226
- if (stack.has(neighbor)) {
227
- cycles.push(`🔄 ${path.join(" -> ")} -> ${neighbor}`);
228
- }
229
- else if (!visited.has(neighbor)) {
230
- dfs(neighbor, [...path, neighbor]);
231
- }
232
- }
233
- stack.delete(node);
234
- };
235
- for (const node of graph.keys()) {
236
- if (!visited.has(node))
237
- 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.`);
238
188
  }
239
- return cycles;
240
189
  }
241
- static generateMermaidGraph(graph, violations) {
242
- let mermaid = "graph TD;\n";
243
- const nodes = Array.from(graph.keys()).slice(0, 40);
244
- nodes.forEach((node) => {
245
- const id = node.replace(/[^a-zA-Z0-9]/g, "_");
246
- const name = path.basename(node);
247
- graph.get(node)?.forEach((dep) => {
248
- const depId = dep.replace(/[^a-zA-Z0-9]/g, "_");
249
- const isViolated = violations.some((v) => v.includes(node) && v.includes(dep));
250
- mermaid += ` ${id}[${name}] --> ${depId}[${path.basename(dep)}];\n`;
251
- if (isViolated)
252
- mermaid += ` style ${id} fill:#f96,stroke:#333,stroke-width:2px\n`;
253
- });
254
- });
255
- return mermaid;
190
+ // C. Complexity Guard
191
+ const metrics = await analyzeComplexity(file);
192
+ if (metrics.cyclomaticComplexity > 20 || metrics.clutterLevel === "Toxic") {
193
+ toxicFiles.push(relativePath);
256
194
  }
257
- static async loadState(workingDir) {
258
- try {
259
- const content = await fs.readFile(path.join(workingDir, this.STATE_FILE), "utf8");
260
- 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).`);
261
200
  }
262
- catch {
263
- 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.`);
264
204
  }
265
205
  }
266
- static async saveState(workingDir, state) {
267
- const dir = path.join(workingDir, ".marie");
268
- await fs.mkdir(dir, { recursive: true });
269
- 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]);
270
248
  }
271
- static async getAllFiles(dir) {
272
- const entries = await fs.readdir(dir, { withFileTypes: true });
273
- const files = await Promise.all(entries.map((entry) => {
274
- const res = path.resolve(dir, entry.name);
275
- if (res.includes("node_modules") ||
276
- res.includes(".git") ||
277
- res.includes("dist"))
278
- return [];
279
- return entry.isDirectory() ? this.getAllFiles(res) : res;
280
- }));
281
- 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);
282
271
  }
283
- static async writeToSentinelLog(workingDir, report) {
284
- const logPath = path.join(workingDir, "SENTINEL.md");
285
- 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 = `
286
296
  # 🛡️ Sentinel Report: ${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}
287
297
 
288
298
  **Stability**: ${report.stability}
@@ -303,26 +313,25 @@ ${report.graphDefinition}
303
313
 
304
314
  ## 📜 High-Priority Alerts
305
315
  ${report.zoneViolations
306
- .slice(0, 5)
307
- .map((v) => `- ❌ ${v}`)
308
- .join("\n")}
316
+ .slice(0, 5)
317
+ .map((v) => `- ❌ ${v}`)
318
+ .join("\n")}
309
319
  ${report.circularDependencies
310
- .slice(0, 3)
311
- .map((c) => `- 🔄 ${c}`)
312
- .join("\n")}
320
+ .slice(0, 3)
321
+ .map((c) => `- 🔄 ${c}`)
322
+ .join("\n")}
313
323
  ${report.duplication
314
- .slice(0, 3)
315
- .map((d) => `- 👯 ${d}`)
316
- .join("\n")}
324
+ .slice(0, 3)
325
+ .map((d) => `- 👯 ${d}`)
326
+ .join("\n")}
317
327
  ${report.navigationDrifts
318
- .slice(0, 5)
319
- .map((n) => `- 🧭 ${n}`)
320
- .join("\n")}
328
+ .slice(0, 5)
329
+ .map((n) => `- 🧭 ${n}`)
330
+ .join("\n")}
321
331
 
322
332
  ---
323
333
  *Marie Sentinel v3.1 — Grounded Architectural Guardian*
324
334
  `;
325
- await fs.writeFile(logPath, summary);
326
- }
335
+ await fs.writeFile(logPath, summary);
327
336
  }
328
337
  //# sourceMappingURL=MarieSentinelService.js.map