@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,462 +1,320 @@
1
+ import { getTool, getRegisteredTools } from "../../tools/ToolRegistry.js";
1
2
  import * as path from "path";
2
- import { nodeRequire } from "../../../plumbing/utils/EnvironmentUtils.js";
3
- import { NoormmeEngine } from "../../persistence/NoormmeEngine.js";
4
- import { ConfigService } from "../../config/ConfigService.js";
3
+ import { getWorkspaceRoot, nodeRequire, } from "../../../plumbing/utils/EnvironmentUtils.js";
4
+ import { getInstance, } from "../../persistence/NoormmeEngine.js";
5
+ import { getCapabilities, isMfaRequired } from "../../config/ConfigService.js";
5
6
  const require = nodeRequire;
6
- // Lazy-load vscode to avoid CLI errors
7
- let vscodeModule = null;
8
- let hasAttemptedVscodeLoad = false;
9
- function getVscode() {
10
- if (!hasAttemptedVscodeLoad) {
11
- hasAttemptedVscodeLoad = true;
12
- try {
13
- vscodeModule = require("vscode");
14
- }
15
- catch {
16
- vscodeModule = null;
17
- }
18
- }
19
- return vscodeModule;
20
- }
21
- import { getStringArg } from "../../tools/ToolUtils.js";
22
7
  import { getErrorMessage } from "../../../plumbing/utils/ErrorUtils.js";
23
8
  import { withRetry, RetryConfig } from "../../../plumbing/utils/RetryUtils.js";
24
- import { rollbackAll, } from "../../../plumbing/filesystem/FileService.js";
25
- import { MarieSanitizer } from "./MarieSanitizer.js";
9
+ import { rollbackAll } from "../../../plumbing/filesystem/FileService.js";
10
+ import { similarity } from "../../../plumbing/utils/StringUtils.js";
11
+ import { repairJsonDetailed, } from "../../../plumbing/utils/JsonUtils.js";
12
+ import { safeStringify, safeSpread } from "./MarieSanitizer.js";
13
+ const PROACTIVE_REPAIRS = {
14
+ write_file: "write_to_file",
15
+ edit_file: "replace_file_content",
16
+ replace_in_file: "replace_file_content",
17
+ read_files: "read_file",
18
+ list_files: "list_dir",
19
+ search_files: "grep_search",
20
+ execute_command: "run_command",
21
+ get_folder_tree: "get_folder_structure",
22
+ multi_replace: "multi_replace_file_content",
23
+ delete_file: "discard_file",
24
+ discard_file: "delete_file",
25
+ };
26
26
  /**
27
27
  * Handles the validation and execution of AI tool calls.
28
+ * Principle 2: Compressed Common Path.
28
29
  */
29
30
  export class MarieToolProcessor {
30
- toolRegistry;
31
31
  tracker;
32
32
  approvalRequester;
33
33
  state;
34
34
  fs;
35
+ vitality;
35
36
  static RETRY_CONFIG = new RetryConfig();
36
37
  failureCircuitBreaker = new Map();
37
- static TOOL_CAPABILITIES = {
38
- // READ
39
- "read_file": ["READ"],
40
- "view_file": ["READ"],
41
- "list_dir": ["READ"],
42
- "grep_search": ["READ"],
43
- "find_by_name": ["READ"],
44
- "get_file_diagnostics": ["READ"],
45
- // WRITE
46
- "write_to_file": ["WRITE"],
47
- "replace_file_content": ["WRITE"],
48
- "multi_replace_file_content": ["WRITE"],
49
- "delete_file": ["WRITE"],
50
- "rename_file": ["WRITE"],
51
- "move_file": ["WRITE"],
52
- // SHELL
53
- "run_command": ["SHELL"],
54
- // NETWORK
55
- "search_web": ["NETWORK"],
56
- "read_url_content": ["NETWORK"],
57
- "read_browser_page": ["NETWORK"],
58
- "open_browser_url": ["NETWORK"],
59
- // SOVEREIGN OPS
60
- "evolve_mind_structure": ["WRITE", "SHELL"],
61
- "prune_sovereign_memory": ["WRITE"],
62
- "complete_task_ritual": ["READ", "WRITE"],
63
- // COMPLEX / MULTI
64
- "execute_semantic_move": ["READ", "WRITE"],
65
- "self_heal": ["READ", "WRITE", "SHELL"],
66
- };
67
- constructor(toolRegistry, tracker, approvalRequester, state, fs) {
68
- this.toolRegistry = toolRegistry;
38
+ constructor(tracker, approvalRequester, state, fs, vitality) {
69
39
  this.tracker = tracker;
70
40
  this.approvalRequester = approvalRequester;
71
41
  this.state = state;
72
42
  this.fs = fs;
43
+ this.vitality = vitality;
73
44
  }
74
45
  async process(toolCall, signal) {
75
- const { name, start_line, end_line, repaired } = toolCall;
76
- const input = toolCall.input;
77
- const inputStr = JSON.stringify(input);
78
- if (repaired) {
79
- this.tracker.recordHeuristicFix(toolCall.name);
80
- }
81
- // SUB-ATOMIC INTEGRITY: Persistent Tool Circuit Breaker
82
- // Check if this tool + input has failed repeatedly in the recent past (persisted in NOORMME)
46
+ const { name, input, repaired, id } = toolCall;
47
+ const inputStr = safeStringify(input);
48
+ if (repaired)
49
+ this.tracker.recordHeuristicFix(name);
83
50
  try {
84
- const db = await NoormmeEngine.getInstance();
85
- const recentFailures = await db.execute(`SELECT COUNT(*) as count FROM agent_actions
86
- WHERE tool_name = ? AND input_summary = ? AND status = 'failure'
87
- AND created_at > datetime('now', '-1 hour')`, [name, inputStr.slice(0, 500)] // Use input_summary or similar if available, otherwise truncate input
88
- );
89
- if (recentFailures[0]?.count >= 3) {
90
- this.recordError(name, `PERSISTENT CIRCUIT BREAKER: ${name} has failed ${recentFailures[0].count} times recently with similar input.`, true);
91
- return `HALT: Protocol Violation. Persistent circuit breaker tripped for ${name}. Your current trajectory for this tool is failing repeatedly. Pivot your strategy.`;
92
- }
51
+ // 1. Pre-Execute: Circuit Breaker & Validation
52
+ const preError = await this.preExecute(name, input, inputStr);
53
+ if (preError)
54
+ return preError;
55
+ const tool = getTool(name);
56
+ if (!tool)
57
+ return `Error: Tool "${name}" not found.`;
58
+ // 2. Prepare: Logging & Backups
59
+ const toolStartTime = Date.now();
60
+ await this.prepareExecution(name, input, id, tool.isDestructive, signal);
61
+ // 3. Execute
62
+ const result = await withRetry(() => tool.execute(input, (update) => this.handleToolUpdate(update, name), signal), MarieToolProcessor.RETRY_CONFIG, `Tool: ${name}`, signal);
63
+ // 4. Post-Execute: Truncation, Metrics, Sentinels
64
+ return await this.postExecute(name, input, result, toolStartTime, id, tool.isDestructive, signal);
93
65
  }
94
- catch (e) {
95
- console.warn("[MarieToolProcessor] Persistent circuit breaker check failed", e);
96
- // Fallback to in-memory breaker if DB is unavailable
97
- const failureState = this.failureCircuitBreaker.get(name);
98
- if (failureState &&
99
- failureState.lastInput === inputStr &&
100
- failureState.count >= 3) {
101
- return `HALT: Protocol Violation. In-memory circuit breaker tripped for ${name}.`;
102
- }
66
+ catch (error) {
67
+ const repairedResult = await this.performFuzzyRepair(toolCall, error, signal);
68
+ if (repairedResult)
69
+ return repairedResult;
70
+ return await this.handleError(name, inputStr, error, id, signal);
103
71
  }
104
- const tool = this.toolRegistry.getTool(toolCall.name);
105
- try {
106
- const validationError = this.validate(toolCall.name, input);
107
- if (validationError) {
108
- this.recordError(toolCall.name, validationError);
109
- return `Error: ${validationError}`;
110
- }
111
- // PHASE 23: COGNITIVE MULTI-FACTOR AUTHENTICATION (C-MFA)
112
- if (this.requiresSovereignAffirmation(toolCall.name, input)) {
113
- const approved = await this.requestApproval(toolCall.name, input);
114
- if (!approved) {
115
- return `Sovereign Denial: High-Entropy operation "${toolCall.name}" rejected by governor. 🛡️`;
116
- }
72
+ }
73
+ async performFuzzyRepair(toolCall, error, signal) {
74
+ const errorMsg = getErrorMessage(error);
75
+ if (!errorMsg.includes("not found") &&
76
+ !errorMsg.includes("ENOENT") &&
77
+ !errorMsg.includes("registry"))
78
+ return null;
79
+ // 1. Proactive Mapping
80
+ if (PROACTIVE_REPAIRS[toolCall.name]) {
81
+ const mapped = PROACTIVE_REPAIRS[toolCall.name];
82
+ if (getTool(mapped)) {
117
83
  this.tracker.emitEvent({
118
84
  type: "reasoning",
119
85
  runId: this.tracker.getRun().runId,
120
- text: `🔐 **C-MFA AFFIRMED**: Sovereign clearance granted for high-risk operation.`,
86
+ text: `🩹 REPAIR: ${toolCall.name} -> ${mapped}`,
121
87
  elapsedMs: this.tracker.elapsedMs(),
122
88
  });
89
+ toolCall.name = mapped;
90
+ toolCall.repaired = true;
91
+ return this.process(toolCall, signal);
123
92
  }
124
- // Autonomy: destructive tools execute immediately without approval gates (UNLESS C-MFA triggered above).
125
- const toolStartTime = Date.now();
126
- const startMsg = `[Marie] Tool ${toolCall.name} starting. ID: ${toolCall.id}`;
127
- console.log(startMsg);
128
- this.tracker.recordLog(startMsg);
129
- const sanitizedInput = { ...input };
130
- // Hygiene: Truncate massive fields to prevent log bloat
131
- if (typeof sanitizedInput.content === "string" &&
132
- sanitizedInput.content.length > 500) {
133
- sanitizedInput.content =
134
- sanitizedInput.content.substring(0, 500) + "...[TRUNCATED]";
135
- }
136
- if (typeof sanitizedInput.replacementContent === "string" &&
137
- sanitizedInput.replacementContent.length > 500) {
138
- sanitizedInput.replacementContent =
139
- sanitizedInput.replacementContent.substring(0, 500) +
140
- "...[TRUNCATED]";
141
- }
93
+ }
94
+ // 2. Fuzzy Tool Name
95
+ const tools = getRegisteredTools();
96
+ let bestMatch = { name: "", sim: 0 };
97
+ for (const t of tools) {
98
+ const sim = similarity(toolCall.name, t.name);
99
+ if (sim > bestMatch.sim)
100
+ bestMatch = { name: t.name, sim };
101
+ }
102
+ if (bestMatch.sim > 0.8 && bestMatch.name !== toolCall.name) {
142
103
  this.tracker.emitEvent({
143
- type: "tool",
104
+ type: "reasoning",
144
105
  runId: this.tracker.getRun().runId,
145
- id: toolCall.id,
146
- phase: "start",
147
- name: toolCall.name,
148
- input: sanitizedInput,
106
+ text: `🩹 FUZZY REPAIR: ${toolCall.name} -> ${bestMatch.name}`,
149
107
  elapsedMs: this.tracker.elapsedMs(),
150
108
  });
151
- const run = this.tracker.getRun();
152
- run.activeToolName = toolCall.name;
153
- run.lastToolName = toolCall.name;
154
- this.tracker.emitProgressUpdate();
155
- this.tracker.recordToolUsage(toolCall.name);
156
- // TRANSACTIONAL INTEGRITY: Backup files before destructive operations
157
- const impactedFiles = [];
158
- const execFile = toolCall.input?.path ||
159
- toolCall.input?.targetFile ||
160
- toolCall.input?.file ||
161
- toolCall.input?.filePath;
162
- // UI FEEDBACK: Set active file path for editor visualization
163
- if (execFile && typeof execFile === "string") {
164
- run.activeFilePath = execFile;
165
- this.tracker.emitEvent({
166
- type: "stage",
167
- runId: run.runId,
168
- stage: "editing",
169
- label: `Editing ${path.basename(execFile)}...`,
170
- elapsedMs: this.tracker.elapsedMs(),
171
- });
172
- this.tracker.emitProgressUpdate();
173
- }
174
- if (tool.isDestructive) {
175
- if (execFile && typeof execFile === "string") {
176
- impactedFiles.push(execFile);
177
- if (this.fs) {
178
- await this.fs.backupFile(execFile, signal);
179
- }
180
- }
181
- // Custom handling for multi-file tools
182
- if (name === "execute_semantic_move" && input.dest) {
183
- impactedFiles.push(input.dest);
184
- if (this.fs) {
185
- await this.fs.backupFile(input.dest, signal);
186
- }
187
- }
188
- }
189
- let result = await withRetry(() => tool.execute(input, (update) => {
190
- if (update.bytesWritten !== undefined && update.path) {
191
- this.tracker.emitEvent({
192
- type: "file_stream_delta",
193
- runId: this.tracker.getRun().runId,
194
- path: update.path,
195
- bytesWritten: update.bytesWritten,
196
- totalBytes: update.totalBytes,
197
- elapsedMs: this.tracker.elapsedMs(),
198
- });
199
- }
200
- else {
201
- this.applyUpdate(update, toolCall.name);
202
- }
203
- }, signal), MarieToolProcessor.RETRY_CONFIG, `Tool: ${toolCall.name}`, signal);
204
- // PROACTIVE TRUNCATION: Source-level safety cap (512KB)
205
- if (typeof result === "string" && result.length > 512 * 1024) {
206
- console.warn(`[MarieStability] Tool ${toolCall.name} output exceeded 512KB. Truncating at source.`);
207
- result =
208
- result.substring(0, 512 * 1024) +
209
- "\n\n🚨 STABILITY ALERT: Output truncated at 512KB to prevent Extension Host lag.";
210
- }
211
- else if (result && typeof result === "object") {
212
- const json = JSON.stringify(result);
213
- if (json.length > 512 * 1024) {
214
- console.warn(`[MarieStability] Tool ${toolCall.name} JSON output exceeded 512KB. Truncating at source.`);
215
- result =
216
- json.substring(0, 512 * 1024) +
217
- "\n\n🚨 STABILITY ALERT: JSON output truncated at 512KB.";
218
- }
219
- }
220
- // TRANSACTIONAL SUCCESS: Clear backups for this tool/turn
221
- if (this.fs) {
222
- this.fs.clearBackups();
223
- }
224
- // CIRCUIT BREAKER FLUSH: Tool succeeded
225
- this.failureCircuitBreaker.delete(name);
226
- // PHASE 7: Milestone Verification
227
- try {
228
- const { NoormmeEngine } = await import("../../persistence/NoormmeEngine.js");
229
- const db = await NoormmeEngine.getInstance();
230
- const originatingSessionId = this.tracker.getRun().originatingSessionId || "default";
231
- const pendingGoals = await db.agent.cortex.sessions.getGoals(originatingSessionId);
232
- for (const goal of pendingGoals) {
233
- if (goal.status !== "completed" && goal.description.toLowerCase().includes(name.toLowerCase())) {
234
- await db.agent.cortex.goalArchitect.markGoalAs(goal.id, "completed");
235
- this.tracker.emitEvent({
236
- type: "reasoning",
237
- runId: this.tracker.getRun().runId,
238
- text: `✅ **Milestone Achieved**: ${goal.description}`,
239
- elapsedMs: this.tracker.elapsedMs(),
240
- });
241
- }
242
- }
243
- }
244
- catch (e) {
245
- console.warn("[MarieToolProcessor] Milestone verification failed", e);
246
- }
247
- const toolDurationMs = Date.now() - toolStartTime;
248
- console.log(`[Marie] Tool ${toolCall.name} completed in ${toolDurationMs}ms.`);
109
+ toolCall.name = bestMatch.name;
110
+ toolCall.repaired = true;
111
+ return this.process(toolCall, signal);
112
+ }
113
+ return null;
114
+ }
115
+ repairJsonString(json) {
116
+ const { repaired } = repairJsonDetailed(json);
117
+ try {
118
+ JSON.parse(repaired);
119
+ return repaired;
120
+ }
121
+ catch {
122
+ return json;
123
+ }
124
+ }
125
+ async preExecute(name, input, inputStr) {
126
+ // Persistent Circuit Breaker
127
+ try {
128
+ const db = await getInstance();
129
+ const failures = await db.execute("SELECT COUNT(*) as count FROM agent_actions WHERE tool_name = ? AND input_summary = ? AND status = 'failure' AND created_at > datetime('now', '-1 hour')", [name, inputStr.slice(0, 500)]);
130
+ if (failures[0]?.count >= 3)
131
+ return `HALT: Persistent circuit breaker tripped for ${name}. Pivot your strategy.`;
132
+ }
133
+ catch (e) {
134
+ const state = this.failureCircuitBreaker.get(name);
135
+ if (state && state.lastInput === inputStr && state.count >= 3)
136
+ return `HALT: In-memory circuit breaker tripped for ${name}.`;
137
+ }
138
+ // Validation
139
+ const validationError = this.validate(name, input);
140
+ if (validationError) {
141
+ this.recordError(name, validationError);
142
+ return `Error: ${validationError}`;
143
+ }
144
+ // Sovereign Affirmation (MFA)
145
+ if (this.requiresSovereignAffirmation(name, input)) {
146
+ if (!(await this.requestApproval(name, input)))
147
+ return `Sovereign Denial: Operation "${name}" rejected by governor. 🛡️`;
249
148
  this.tracker.emitEvent({
250
- type: "tool",
149
+ type: "reasoning",
251
150
  runId: this.tracker.getRun().runId,
252
- id: toolCall.id,
253
- phase: "complete",
254
- name: toolCall.name,
255
- message: typeof result === "string" ? result.substring(0, 100) : "Completed",
151
+ text: `🔐 **C-MFA AFFIRMED**: Sovereign clearance granted.`,
256
152
  elapsedMs: this.tracker.elapsedMs(),
257
153
  });
258
- run.activeToolName = undefined;
259
- run.activeFilePath = undefined; // Clear active file
260
- run.lastToolName = toolCall.name;
261
- this.tracker.emitProgressUpdate();
262
- if (result && typeof result === "object") {
263
- this.applyUpdate(result, toolCall.name);
264
- }
265
- // Phase 11: Code Impact Analysis
266
- this.recordCodeStats(toolCall.name, input);
267
- // Ascension Mastery: Record execution
268
- this.state.techniqueExecutions.push({
269
- name: toolCall.name,
270
- durationMs: toolDurationMs,
271
- success: true,
272
- timestamp: Date.now(),
273
- filePath: typeof execFile === "string" ? execFile : undefined,
274
- });
275
- this.state.toolHistory.push(toolCall.name);
276
- if (this.state.toolHistory.length > 20)
277
- this.state.toolHistory.shift();
278
- this.state.victoryStreak++;
279
- // Phase 7: Track sentimental metrics
280
- const runMetrics = this.tracker.getRun();
281
- if (!runMetrics.metrics)
282
- runMetrics.metrics = { cherishedFiles: [], releasedDebtCount: 0 };
283
- if (toolCall.name === "cherish_file" &&
284
- input &&
285
- typeof input === "object") {
286
- try {
287
- const p = getStringArg(input, "path");
288
- if (p && !runMetrics.metrics.cherishedFiles.includes(p)) {
289
- runMetrics.metrics.cherishedFiles.push(p);
290
- this.tracker.emitProgressUpdate(`File cherished: ${p.split("/").pop()}`);
291
- }
292
- }
293
- catch (e) {
294
- console.warn("Failed to extract path for cherish_file metric", e);
295
- }
296
- }
297
- else if (toolCall.name === "discard_file") {
298
- runMetrics.metrics.releasedDebtCount++;
299
- this.tracker.emitProgressUpdate("Technical debt released 🍂");
300
- }
301
- let finalResult = typeof result === "string" ? result : JSON.stringify(result);
302
- // ZENITH AUTONOMY: Autonomous Dependency Sentinel
303
- if (tool.isDestructive && execFile && typeof execFile === "string") {
304
- const [zoningAlert, buildAlert] = await Promise.all([
305
- this.runZoningSentinel(execFile, typeof result === "string" ? result : undefined, signal),
306
- this.runBuildSentinel(execFile, signal),
307
- ]);
308
- if (zoningAlert) {
309
- finalResult += `\n\n🛡️ **ZENITH: Zoning Sentinel Alert**\n${zoningAlert}`;
310
- }
311
- if (buildAlert) {
312
- finalResult += `\n\n🧱 **SINGULARITY: Build Sentinel Alert**\n${buildAlert}`;
313
- }
314
- }
315
- return finalResult;
316
154
  }
317
- catch (error) {
318
- const rawMsg = getErrorMessage(error);
319
- const isTerminal = this.isTerminalError(name, rawMsg);
320
- const run = this.tracker.getRun();
321
- run.activeToolName = undefined;
322
- run.lastToolName = name;
155
+ return null;
156
+ }
157
+ async prepareExecution(name, input, id, isDestructive, signal) {
158
+ this.tracker.recordLog(`[Marie] Tool ${name} starting. ID: ${id}`);
159
+ // UI Feedback: Active Path
160
+ const execFile = input?.path || input?.targetFile || input?.file || input?.filePath;
161
+ if (execFile && typeof execFile === "string") {
162
+ this.tracker.getRun().activeFilePath = execFile;
163
+ this.tracker.emitEvent({
164
+ type: "stage",
165
+ runId: this.tracker.getRun().runId,
166
+ stage: "editing",
167
+ label: `Editing ${path.basename(execFile)}...`,
168
+ elapsedMs: this.tracker.elapsedMs(),
169
+ });
323
170
  this.tracker.emitProgressUpdate();
324
- // TRANSACTIONAL RECOVERY: Restore state on failure
325
- let rollbackErrorMsg = "";
326
- try {
327
- console.log(`[Marie] Initiating systemic rollback for tool failure: ${name}`);
328
- if (this.fs) {
329
- await this.fs.rollbackAll(signal);
330
- }
331
- else {
332
- await rollbackAll(signal);
333
- }
334
- }
335
- catch (restoreError) {
336
- console.error(`[Marie] Transactional recovery failed: ${restoreError}`);
337
- rollbackErrorMsg = `\n\n🚨 CRITICAL: Systemic rollback failed. File system may be in an inconsistent state. Manual verification required. Error: ${restoreError}`;
338
- }
339
- // CIRCUIT BREAKER RECORD: Increment failure count for same tool/input
340
- const state = this.failureCircuitBreaker.get(name) || {
341
- count: 0,
342
- lastInput: inputStr,
343
- };
344
- if (state.lastInput === inputStr) {
345
- state.count++;
346
- }
347
- else {
348
- state.count = 1;
349
- state.lastInput = inputStr;
350
- }
351
- this.failureCircuitBreaker.set(name, state);
352
- this.recordError(name, rawMsg, isTerminal, toolCall.id);
353
- console.error(`[Marie] Tool ${name} failed: ${rawMsg}`);
354
- this.recordError(name, rawMsg, isTerminal, toolCall.id);
355
- console.error(`[Marie] Tool ${name} failed: ${rawMsg}`);
356
- // Ascension Mastery: Record failure
357
- const failFile = toolCall.input?.path ||
358
- toolCall.input?.targetFile ||
359
- toolCall.input?.file ||
360
- toolCall.input?.filePath;
361
- this.state.techniqueExecutions.push({
362
- name: name,
363
- durationMs: 0,
364
- success: false,
365
- timestamp: Date.now(),
366
- filePath: typeof failFile === "string" ? failFile : undefined,
171
+ if (isDestructive && this.fs)
172
+ await this.fs.backupFile(execFile, signal);
173
+ }
174
+ // Start Event
175
+ this.tracker.emitEvent({
176
+ type: "tool",
177
+ runId: this.tracker.getRun().runId,
178
+ id,
179
+ phase: "start",
180
+ name,
181
+ input: this.sanitizeForLogging(input),
182
+ elapsedMs: this.tracker.elapsedMs(),
183
+ });
184
+ this.tracker.recordToolUsage(name);
185
+ }
186
+ handleToolUpdate(update, name) {
187
+ if (update.bytesWritten !== undefined && update.path) {
188
+ this.tracker.emitEvent({
189
+ type: "file_stream_delta",
190
+ runId: this.tracker.getRun().runId,
191
+ path: update.path,
192
+ bytesWritten: update.bytesWritten,
193
+ totalBytes: update.totalBytes,
194
+ elapsedMs: this.tracker.elapsedMs(),
367
195
  });
368
- this.state.totalErrorCount++;
369
- this.state.victoryStreak = 0;
370
- if (typeof failFile === "string") {
371
- this.state.errorHotspots[failFile] =
372
- (this.state.errorHotspots[failFile] || 0) + 1;
373
- }
374
- // PHASE 9: Report Consecutive Failures to Metrics
375
- try {
376
- const { NoormmeEngine } = await import("../../persistence/NoormmeEngine.js");
377
- const db = await NoormmeEngine.getInstance();
378
- const originatingSessionId = this.tracker.getRun().originatingSessionId || "default";
379
- const failureCount = state.count;
380
- await db.agent.cortex.metrics.recordMetric("consecutive_failures", failureCount, {
381
- sessionId: originatingSessionId,
382
- metadata: { toolName: name, filePath: failFile }
383
- });
384
- }
385
- catch (e) {
386
- console.warn("[MarieToolProcessor] Failed to report failure metrics", e);
387
- }
388
- if (isTerminal || state.count >= 3) {
389
- const circuitBreakerSuffix = state.count >= 3 ? " [CIRCUIT BREAKER TRIPPED]" : "";
390
- return `HALT: Critical protocol or parsing failure in ${name}: ${rawMsg}${circuitBreakerSuffix}${rollbackErrorMsg}`;
391
- }
392
- // Constructive Feedback Layer
393
- const msgParts = [
394
- `Error executing ${name}: ${rawMsg}${rollbackErrorMsg}`,
395
- ];
396
- // Ascension-Aware Error Hotspot Hint
397
- if (failFile && typeof failFile === "string") {
398
- const hotspotCount = this.state.errorHotspots[failFile] || 0;
399
- if (hotspotCount >= 2) {
400
- msgParts.push(`\n\n🔥 CURSE HOTSPOT: This file (${failFile}) has failed ${hotspotCount} times. Technique adjustment required.`);
401
- }
402
- }
403
- if (this.state.spiritPressure < 30) {
404
- msgParts.push(`\n⚠️ Low spirit pressure (${this.state.spiritPressure}/100). Simplify your next action.`);
405
- }
406
- if (this.state.mood === "CAUTIOUS") {
407
- msgParts.push(`\n🛡️ Ascension Mood: CAUTIOUS. Observe before acting. Verify the pattern.`);
408
- }
409
- if (rawMsg.includes("ENOENT") || rawMsg.includes("no such file")) {
410
- msgParts.push(`\n\n💡 Reflection Hint: The file or directory does not exist. Use 'list_dir' to verify the path or 'grep_search' to locate it.`);
411
- }
412
- else if (rawMsg.includes("target content not found")) {
413
- msgParts.push(`\n\n💡 Reflection Hint: The content you tried to replace wasn't found. Use 'read_file' (without line numbers) to verify the current file content before retrying.`);
414
- }
415
- else if (rawMsg.includes("Input is required")) {
416
- msgParts.push(`\n\n💡 Reflection Hint: You missed a required argument. Check the tool schema.`);
417
- }
418
- else {
419
- msgParts.push(`\n\n💡 Reflection Hint: Please analyze why this failed and propose a diverse alternative strategy.`);
420
- }
421
- if (state.count > 1) {
422
- msgParts.push(`\n\n⚠️ REPEATED FAILURE: This exact tool call has failed ${state.count} times. If it fails again, the circuit breaker will trip and you will be forced to change strategy.`);
423
- }
424
- return msgParts.join("");
196
+ }
197
+ else {
198
+ this.applyUpdate(update, name);
425
199
  }
426
200
  }
201
+ async postExecute(name, input, result, startTime, id, isDestructive, signal) {
202
+ let finalResult = typeof result === "string" ? result : safeStringify(result);
203
+ if (finalResult.length > 512 * 1024) {
204
+ finalResult =
205
+ finalResult.substring(0, 512 * 1024) +
206
+ "\n\n🚨 STABILITY ALERT: Output truncated at 512KB.";
207
+ }
208
+ if (this.fs)
209
+ this.fs.clearBackups();
210
+ this.failureCircuitBreaker.delete(name);
211
+ const duration = Date.now() - startTime;
212
+ this.tracker.emitEvent({
213
+ type: "tool",
214
+ runId: this.tracker.getRun().runId,
215
+ id,
216
+ phase: "complete",
217
+ name,
218
+ message: finalResult.substring(0, 100),
219
+ elapsedMs: this.tracker.elapsedMs(),
220
+ });
221
+ const run = this.tracker.getRun();
222
+ run.activeToolName = undefined;
223
+ run.activeFilePath = undefined;
224
+ this.tracker.emitProgressUpdate();
225
+ // Stats & History
226
+ this.recordCodeStats(name, input);
227
+ this.state.techniqueExecutions.push({
228
+ name,
229
+ durationMs: duration,
230
+ success: true,
231
+ timestamp: Date.now(),
232
+ filePath: input?.path || input?.targetFile,
233
+ });
234
+ this.state.toolHistory.push(name);
235
+ if (this.state.toolHistory.length > 20)
236
+ this.state.toolHistory.shift();
237
+ this.state.victoryStreak++;
238
+ // Sentinels
239
+ const execFile = input?.path || input?.targetFile || input?.file || input?.filePath;
240
+ if (isDestructive && execFile && typeof execFile === "string") {
241
+ const [zoning, build] = await Promise.all([
242
+ this.runZoningSentinel(execFile, finalResult, signal),
243
+ this.runBuildSentinel(execFile, signal),
244
+ ]);
245
+ if (zoning)
246
+ finalResult += `\n\n🛡️ **ZENITH ALERT**\n${zoning}`;
247
+ if (build)
248
+ finalResult += `\n\n🧱 **SINGULARITY ALERT**\n${build}`;
249
+ }
250
+ return finalResult;
251
+ }
252
+ async handleError(name, inputStr, error, id, signal) {
253
+ const rawMsg = getErrorMessage(error);
254
+ const isTerminal = this.isTerminalError(name, rawMsg);
255
+ // Rollback
256
+ try {
257
+ if (this.fs)
258
+ await this.fs.rollbackAll(signal);
259
+ else
260
+ await rollbackAll(signal);
261
+ }
262
+ catch (e) {
263
+ console.error("Rollback failed", e);
264
+ }
265
+ // Circuit Breaker Increment
266
+ const state = this.failureCircuitBreaker.get(name) || {
267
+ count: 0,
268
+ lastInput: inputStr,
269
+ };
270
+ state.count = state.lastInput === inputStr ? state.count + 1 : 1;
271
+ state.lastInput = inputStr;
272
+ this.failureCircuitBreaker.set(name, state);
273
+ this.recordError(name, rawMsg, isTerminal, id);
274
+ this.state.totalErrorCount++;
275
+ this.state.victoryStreak = 0;
276
+ if (isTerminal || state.count >= 3)
277
+ return `HALT: Critical failure in ${name}: ${rawMsg}`;
278
+ return `Error executing ${name}: ${rawMsg}. Refine your strategy.`;
279
+ }
280
+ sanitizeForLogging(input) {
281
+ const sanitized = safeSpread(input);
282
+ if (typeof sanitized.content === "string" && sanitized.content.length > 500)
283
+ sanitized.content =
284
+ sanitized.content.substring(0, 500) + "...[TRUNCATED]";
285
+ if (typeof sanitized.replacementContent === "string" &&
286
+ sanitized.replacementContent.length > 500)
287
+ sanitized.replacementContent =
288
+ sanitized.replacementContent.substring(0, 500) + "...[TRUNCATED]";
289
+ return sanitized;
290
+ }
291
+ // --- Methods below are mostly unchanged logic, just kept for completeness ---
427
292
  isTerminalError(toolName, message) {
428
- // Critical ritual failures are terminal
429
293
  if (toolName === "checkpoint_pass" && message.includes("failed"))
430
294
  return true;
431
- // Repeated parsing failures (marked by provider) are terminal
432
295
  if (message.includes("Failed to parse tool arguments"))
433
296
  return true;
434
297
  return false;
435
298
  }
436
299
  validate(name, input) {
437
- // PHASE 21: DEFAULT-DENY POLICY
438
- // If a tool is not in TOOL_CAPABILITIES, we default to READ only for safety.
439
- const requirements = MarieToolProcessor.TOOL_CAPABILITIES[name] || ["READ"];
440
- // Capability check
441
- const allowedCapabilities = ConfigService.getCapabilities();
442
- const missing = requirements.filter(cap => !allowedCapabilities.includes(cap));
443
- if (missing.length > 0) {
444
- return `Sovereign Capability Breach: Tool "${name}" requires missing capabilities: [${missing.join(", ")}]. 🛑`;
445
- }
300
+ const requirements = this.constructor.TOOL_CAPABILITIES[name] || [
301
+ "READ",
302
+ ];
303
+ const allowed = getCapabilities();
304
+ const missing = requirements.filter((cap) => !allowed.includes(cap));
305
+ if (missing.length > 0)
306
+ return `Capability Breach: Tool "${name}" requires missing capabilities: [${missing.join(", ")}]. 🛑`;
446
307
  if (!input || typeof input !== "object")
447
308
  return "Input must be a valid object";
448
- const tool = this.toolRegistry.getTool(name);
309
+ const tool = getTool(name);
449
310
  if (!tool)
450
- return `Tool "${name}" not found in registry`;
451
- // Check required fields from schema
311
+ return `Tool "${name}" not found.`;
452
312
  const schema = tool.input_schema;
453
313
  if (schema.required && Array.isArray(schema.required)) {
454
- const missing = schema.required.filter((field) => !(field in input));
455
- if (missing.length > 0) {
456
- return `Missing required fields: ${missing.join(", ")}`;
457
- }
314
+ const missingFields = schema.required.filter((field) => !(field in input));
315
+ if (missingFields.length > 0)
316
+ return `Missing required fields: ${missingFields.join(", ")}`;
458
317
  }
459
- // Security: Workspace Boundary Enforcement
460
318
  const pathFields = [
461
319
  "path",
462
320
  "targetFile",
@@ -467,257 +325,116 @@ export class MarieToolProcessor {
467
325
  ];
468
326
  for (const field of pathFields) {
469
327
  if (input[field] && typeof input[field] === "string") {
470
- const pathError = this.validatePath(input[field]);
471
- if (pathError)
472
- return pathError;
328
+ const error = this.validatePath(input[field]);
329
+ if (error)
330
+ return error;
473
331
  }
474
332
  }
475
- // PHASE 23: Adversarial Reasoning Guard
476
- const alerts = MarieSanitizer.scanToolArguments(name, input);
477
- if (alerts.length > 0) {
478
- this.tracker.emitEvent({
479
- type: "reasoning",
480
- runId: this.tracker.getRun().runId,
481
- text: `🛡️ **ADVERSARIAL GUARD**: ${alerts.join(" ")}`,
482
- elapsedMs: this.tracker.elapsedMs(),
483
- });
484
- if (ConfigService.getAdversarialSensitivity() > 0.8) {
485
- return `Sovereign Security Breach: Dangerous patterns detected in tool arguments. Execution blocked by Adversarial Guard. 🛑`;
486
- }
333
+ return null;
334
+ }
335
+ validatePath(p) {
336
+ const root = getWorkspaceRoot();
337
+ if (!root)
338
+ return null;
339
+ if ((p.startsWith("/") || (p.length > 1 && p[1] === ":")) &&
340
+ !p.startsWith(root)) {
341
+ return `Security Error: Path ${p} is outside workspace boundary.`;
487
342
  }
488
343
  return null;
489
344
  }
490
345
  requiresSovereignAffirmation(name, input) {
491
- if (!ConfigService.isMfaRequired())
346
+ if (!isMfaRequired())
492
347
  return false;
493
- // High-risk tools or arguments
494
348
  if (name === "run_command") {
495
349
  const cmd = (input.CommandLine || input.command || "").toLowerCase();
496
- const destructiveKeywords = ["sudo ", "rm ", "kill ", "chmod ", "> /dev/", "format ", "mkfs "];
497
- if (destructiveKeywords.some(kw => cmd.includes(kw)))
498
- return true;
499
- }
500
- if (name === "delete_file" || name === "prune_sovereign_memory")
501
- return true;
502
- // Escalate if sanitizer found alerts
503
- const alerts = MarieSanitizer.scanToolArguments(name, input);
504
- return alerts.length > 0;
505
- }
506
- validatePath(p) {
507
- const vscode = getVscode();
508
- const workspaceFolders = vscode?.workspace.workspaceFolders;
509
- if (!workspaceFolders || workspaceFolders.length === 0)
510
- return null; // No workspace, no boundary to enforce
511
- const workspaceRoot = workspaceFolders[0].uri.fsPath;
512
- // Basic check for drive-letter-relative or absolute paths that bypass the root
513
- const normalized = p.startsWith("~") ? p : p.includes(":") ? p : p; // PathResolver handles ~ expansion
514
- // We'll trust resolvePath but check the result against workspace root if possible
515
- // Since ToolProcessor doesn't have easy access to resolvePath without importing,
516
- // we'll do a simple string check for now, matching FileService's logic.
517
- // If the path starts with / or \ but NOT workspaceRoot, it's a breach.
518
- if (p.startsWith("/") || (p.length > 1 && p[1] === ":")) {
519
- if (!p.startsWith(workspaceRoot)) {
520
- return `Security Error: Path ${p} is outside the workspace boundary (${workspaceRoot}). Access denied. 🛑`;
521
- }
350
+ return ["sudo ", "rm ", "kill ", "chmod "].some((kw) => cmd.includes(kw));
522
351
  }
523
- if (p.startsWith("/") || (p.length > 1 && p[1] === ":")) {
524
- if (!p.startsWith(workspaceRoot)) {
525
- return `Security Error: Path ${p} is outside the workspace boundary (${workspaceRoot}). Access denied. 🛑`;
526
- }
527
- }
528
- return null;
352
+ return ["delete_file", "prune_sovereign_memory"].includes(name);
529
353
  }
530
354
  async requestApproval(name, input) {
531
- const run = this.tracker.getRun();
532
- // Try to construct a diff for preview
533
- let diff;
534
- if (name === "replace_in_file" &&
535
- input.targetContent &&
536
- input.replacementContent) {
537
- diff = { old: input.targetContent, new: input.replacementContent };
538
- }
539
- else if (name === "write_file" && input.content) {
540
- diff = { old: "", new: input.content };
541
- }
542
- // Use the callback to request approval via the frontend
543
- const approved = await this.approvalRequester(name, input, diff);
544
- return approved;
355
+ return await this.approvalRequester(name, input);
545
356
  }
546
357
  applyUpdate(update, toolName) {
547
358
  const run = this.tracker.getRun();
548
- if (update.context)
549
- run.currentContext = update.context;
550
- if (update.activeObjectiveId)
551
- run.activeObjectiveId = update.activeObjectiveId;
552
- if (update.lifecycleStage)
553
- run.lifecycleStage = update.lifecycleStage;
554
- if (update.totalPasses !== undefined)
555
- run.totalPasses = update.totalPasses;
556
- if (update.currentPass !== undefined)
557
- run.currentPass =
558
- update.currentPass === null ? undefined : update.currentPass;
559
- if (update.passFocus !== undefined)
560
- run.passFocus = update.passFocus;
561
- if (update.passHistory) {
562
- run.passHistory = [...(run.passHistory || []), ...update.passHistory];
563
- }
564
- if (update.metrics) {
565
- run.metrics = {
566
- cherishedFiles: Array.from(new Set([
567
- ...(run.metrics?.cherishedFiles || []),
568
- ...(update.metrics.cherishedFiles || []),
569
- ])),
570
- releasedDebtCount: (run.metrics?.releasedDebtCount || 0) +
571
- (update.metrics.releasedDebtCount || 0),
572
- };
573
- }
574
- // Auto-increment currentPass on checkpoint_pass or if specifically requested
575
- if (toolName === "checkpoint_pass" && run.currentPass !== undefined) {
359
+ Object.assign(run, safeSpread(update));
360
+ if (toolName === "checkpoint_pass" && run.currentPass !== undefined)
576
361
  run.currentPass++;
577
- }
578
- if (run.currentPass !== undefined &&
579
- run.totalPasses !== undefined &&
580
- run.passFocus) {
581
- this.tracker.emitPassTransition(run.currentPass, run.totalPasses, run.passFocus);
582
- }
583
- else {
584
- this.tracker.emitProgressUpdate();
585
- }
586
- // Handle Roadmap Augmentation
587
- if (toolName === "augment_roadmap" && update.totalPasses !== undefined) {
588
- run.totalPasses = (run.totalPasses || 0) + update.totalPasses;
589
- this.tracker.emitProgressUpdate(`Roadmap calibrated: ${run.totalPasses} total passes.`);
590
- }
591
- }
592
- countLines(str) {
593
- if (!str)
594
- return 0;
595
- let count = 1; // Start at 1 for single line
596
- let pos = -1;
597
- while ((pos = str.indexOf("\n", pos + 1)) !== -1) {
598
- count++;
599
- }
600
- return count;
362
+ this.tracker.emitProgressUpdate();
601
363
  }
602
364
  recordCodeStats(toolName, input) {
603
- try {
604
- if (toolName === "write_to_file") {
605
- // Counts as strict addition
606
- const lines = this.countLines(input.content);
607
- const path = input.targetFile || input.file || input.path || input.filePath; // Handle varying schemas
608
- if (path)
609
- this.tracker.recordFileChange(path, lines, 0);
610
- }
611
- else if (toolName === "replace_file_content") {
612
- const added = this.countLines(input.replacementContent);
613
- const removed = this.countLines(input.targetContent);
614
- const path = input.targetFile || input.file || input.path || input.filePath;
615
- if (path)
616
- this.tracker.recordFileChange(path, added, removed);
617
- }
618
- else if (toolName === "multi_replace_file_content" &&
619
- Array.isArray(input.replacementChunks)) {
620
- let added = 0;
621
- let removed = 0;
622
- for (const chunk of input.replacementChunks) {
623
- added += this.countLines(chunk.replacementContent);
624
- removed += this.countLines(chunk.targetContent);
625
- }
626
- const path = input.targetFile || input.file || input.path || input.filePath;
627
- if (path)
628
- this.tracker.recordFileChange(path, added, removed);
629
- }
630
- }
631
- catch (e) {
632
- console.warn("Failed to record code stats", e);
633
- }
365
+ const path = input.targetFile || input.file || input.path;
366
+ if (!path)
367
+ return;
368
+ const roundedInput = safeSpread(input);
369
+ const added = roundedInput.content
370
+ ? roundedInput.content.split("\n").length
371
+ : roundedInput.replacementContent
372
+ ? roundedInput.replacementContent.split("\n").length
373
+ : 0;
374
+ const removed = roundedInput.targetContent
375
+ ? roundedInput.targetContent.split("\n").length
376
+ : 0;
377
+ if (added || removed)
378
+ this.tracker.recordFileChange(path, added, removed);
634
379
  }
635
- recordError(name, message, isTerminal = false, toolCallId) {
380
+ recordError(name, message, terminal = false, id) {
636
381
  this.tracker.emitEvent({
637
382
  type: "tool",
638
383
  runId: this.tracker.getRun().runId,
639
- id: toolCallId,
384
+ id,
640
385
  phase: "error",
641
386
  name,
642
- message: (isTerminal ? "[TERMINAL] " : "") + message,
387
+ message: (terminal ? "[TERMINAL] " : "") + message,
643
388
  elapsedMs: this.tracker.elapsedMs(),
644
389
  });
645
390
  }
646
- async runZoningSentinel(filePath, toolResult, signal) {
391
+ async runZoningSentinel(filePath, result, signal) {
647
392
  try {
648
- if (signal?.aborted)
649
- return null;
650
393
  const { detectMigrationNeeds } = await import("../../../plumbing/analysis/CodeHealthService.js");
651
394
  const { readFile } = await import("../../../plumbing/filesystem/FileService.js");
652
395
  const content = await readFile(filePath, undefined, undefined, signal);
653
396
  const { shouldMigrate, targetZone, reason } = detectMigrationNeeds(filePath, content);
654
- if (shouldMigrate) {
655
- this.tracker.emitEvent({
656
- type: "reasoning",
657
- runId: this.tracker.getRun().runId,
658
- text: `🛡️ ZENITH: Zoning Sentinel detected a leak in \`${filePath.split("/").pop()}\`.`,
659
- elapsedMs: this.tracker.elapsedMs(),
660
- });
661
- return `⚠️ **Dependency Leak**: ${reason}\nSuggested Zone: \`${targetZone}\`. Consider moving this file or refactoring its dependencies.`;
662
- }
663
- // Also check for cross-zone import leaks (Heuristic)
664
- if (filePath.includes("/domain/") &&
665
- (content.includes("/infrastructure/") || content.includes("/adapters/"))) {
666
- return `⚠️ **Architectural Heresy**: Domain layer should not depend on Infrastructure. Found infrastructure imports in \`${path.basename(filePath)}\`.`;
667
- }
668
- return null;
397
+ return shouldMigrate
398
+ ? `Dependency Leak: ${reason}. Target: ${targetZone}`
399
+ : null;
669
400
  }
670
- catch (e) {
671
- console.warn("[Zenith] Zoning Sentinel failed", e);
401
+ catch {
672
402
  return null;
673
403
  }
674
404
  }
675
405
  async runBuildSentinel(filePath, signal) {
676
- const vscode = getVscode();
677
- const workingDir = vscode?.workspace.workspaceFolders?.[0].uri.fsPath || process.cwd();
678
406
  try {
679
- if (signal?.aborted)
680
- return null;
681
- const { QualityGuardrailService } = await import("../../../plumbing/analysis/QualityGuardrailService.js");
682
- this.tracker.emitProgressUpdate("Initiating Sub-Atomic Integrity Audit... 🛡️");
683
- const result = await QualityGuardrailService.evaluate(workingDir, filePath);
684
- if (result.surgicalMends > 0) {
685
- this.tracker.emitEvent({
686
- type: "reasoning",
687
- runId: this.tracker.getRun().runId,
688
- text: `✨ SURGICAL MEND: Marie autonomously repaired ${result.surgicalMends} sub-atomic issue(s) in \`${path.basename(filePath)}\`.`,
689
- elapsedMs: this.tracker.elapsedMs(),
690
- });
691
- }
692
- if (!result.passed) {
693
- this.tracker.emitEvent({
694
- type: "reasoning",
695
- runId: this.tracker.getRun().runId,
696
- text: `🧱 SUB-ATOMIC REJECTION: Project integrity at risk (Score: ${result.score}/100).`,
697
- elapsedMs: this.tracker.elapsedMs(),
698
- });
699
- let summary = `🚨 **SUB-ATOMIC INTEGRITY REJECTION** 🚨\n\nMarie has audited your change and found it architecturally or stylistically toxic.\n\n`;
700
- summary += `**Quality Score**: ${result.score}/100\n`;
701
- summary += result.violations.map((v) => `- ❌ ${v}`).join("\n");
702
- summary += `\n\n**Action Required**: You must resolve these precision regressions. Use 'resolve_lint_errors' for location-specific data. Type sovereignty is absolute. 🚩`;
703
- return summary;
704
- }
705
- if (result.score < 100) {
706
- this.tracker.emitProgressUpdate(`Sub-Atomic Audit Passed (Score: ${result.score}/100) ✨`);
707
- }
407
+ const { evaluateQualityGuardrail } = await import("../../../plumbing/analysis/QualityGuardrailService.js");
408
+ const res = await evaluateQualityGuardrail(getWorkspaceRoot() || "", filePath);
409
+ return res.passed ? null : `Quality rejection (Score: ${res.score}/100)`;
708
410
  }
709
- catch (e) {
710
- console.warn("[Singularity] Sub-Atomic Guardrails failed", e);
711
- // Fallback to basic VS Code diagnostics if service fails
712
- if (vscode) {
713
- const diagnostics = vscode.languages.getDiagnostics(vscode.Uri.file(filePath));
714
- const errors = diagnostics.filter((d) => d.severity === vscode.DiagnosticSeverity.Error);
715
- if (errors.length > 0) {
716
- return `🚨 **Build Regressions Detected**: ${errors.length} error(s) found. Fix these immediately.`;
717
- }
718
- }
411
+ catch {
412
+ return null;
719
413
  }
720
- return null;
721
414
  }
415
+ static TOOL_CAPABILITIES = {
416
+ read_file: ["READ"],
417
+ view_file: ["READ"],
418
+ list_dir: ["READ"],
419
+ grep_search: ["READ"],
420
+ find_by_name: ["READ"],
421
+ get_file_diagnostics: ["READ"],
422
+ write_to_file: ["WRITE"],
423
+ replace_file_content: ["WRITE"],
424
+ multi_replace_file_content: ["WRITE"],
425
+ delete_file: ["WRITE"],
426
+ rename_file: ["WRITE"],
427
+ move_file: ["WRITE"],
428
+ run_command: ["SHELL"],
429
+ search_web: ["NETWORK"],
430
+ read_url_content: ["NETWORK"],
431
+ read_browser_page: ["NETWORK"],
432
+ open_browser_url: ["NETWORK"],
433
+ evolve_mind_structure: ["WRITE", "SHELL"],
434
+ prune_sovereign_memory: ["WRITE"],
435
+ complete_task_ritual: ["READ", "WRITE"],
436
+ execute_semantic_move: ["READ", "WRITE"],
437
+ self_heal: ["READ", "WRITE", "SHELL"],
438
+ };
722
439
  }
723
440
  //# sourceMappingURL=MarieToolProcessor.js.map