@stackmemoryai/stackmemory 1.10.5 → 1.14.0

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 (225) hide show
  1. package/LICENSE +131 -64
  2. package/README.md +107 -24
  3. package/bin/claude-sm +16 -1
  4. package/bin/claude-smd +16 -1
  5. package/bin/codex-smd +16 -1
  6. package/bin/gemini-sm +16 -1
  7. package/bin/hermes-sm +21 -0
  8. package/bin/hermes-smd +21 -0
  9. package/bin/opencode-sm +16 -1
  10. package/dist/src/cli/claude-sm.js +266 -84
  11. package/dist/src/cli/codex-sm.js +225 -33
  12. package/dist/src/cli/commands/bench.js +209 -2
  13. package/dist/src/cli/commands/brain.js +206 -0
  14. package/dist/src/cli/commands/cache.js +126 -0
  15. package/dist/src/cli/commands/company-os.js +184 -0
  16. package/dist/src/cli/commands/context.js +5 -0
  17. package/dist/src/cli/commands/daemon.js +41 -0
  18. package/dist/src/cli/commands/handoff.js +40 -9
  19. package/dist/src/cli/commands/onboard.js +70 -3
  20. package/dist/src/cli/commands/operator.js +127 -0
  21. package/dist/src/cli/commands/optimize.js +117 -0
  22. package/dist/src/cli/commands/orchestrate.js +232 -5
  23. package/dist/src/cli/commands/orchestrator.js +315 -26
  24. package/dist/src/cli/commands/pack.js +322 -0
  25. package/dist/src/cli/commands/patterns.js +254 -0
  26. package/dist/src/cli/commands/portal.js +161 -0
  27. package/dist/src/cli/commands/scaffold.js +92 -0
  28. package/dist/src/cli/commands/search.js +40 -1
  29. package/dist/src/cli/commands/setup.js +178 -11
  30. package/dist/src/cli/commands/skills.js +10 -1
  31. package/dist/src/cli/commands/state.js +265 -0
  32. package/dist/src/cli/commands/sync.js +253 -0
  33. package/dist/src/cli/commands/tasks.js +130 -1
  34. package/dist/src/cli/commands/vision.js +221 -0
  35. package/dist/src/cli/gemini-sm.js +19 -29
  36. package/dist/src/cli/hermes-sm.js +224 -0
  37. package/dist/src/cli/index.js +105 -39
  38. package/dist/src/cli/opencode-sm.js +38 -21
  39. package/dist/src/cli/utils/determinism-watcher.js +66 -0
  40. package/dist/src/cli/utils/real-cli-bin.js +116 -0
  41. package/dist/src/core/brain/brain-store.js +187 -0
  42. package/dist/src/core/brain/brain-sync.js +193 -0
  43. package/dist/src/core/brain/index.js +78 -0
  44. package/dist/src/core/brain/types.js +10 -0
  45. package/dist/src/core/cache/content-cache.js +238 -0
  46. package/dist/src/{integrations/diffmem → core/cache}/index.js +5 -5
  47. package/dist/src/core/cache/token-estimator.js +39 -0
  48. package/dist/src/core/config/feature-flags.js +2 -6
  49. package/dist/src/core/context/frame-database.js +79 -27
  50. package/dist/src/core/context/recursive-context-manager.js +1 -1
  51. package/dist/src/core/context/rehydration.js +2 -1
  52. package/dist/src/core/cross-search/cross-project-search.js +269 -0
  53. package/dist/src/core/cross-search/index.js +10 -0
  54. package/dist/src/core/database/sqlite-adapter.js +14 -84
  55. package/dist/src/core/extensions/provider-adapter.js +5 -0
  56. package/dist/src/core/models/model-router.js +54 -2
  57. package/dist/src/core/models/provider-pricing.js +58 -4
  58. package/dist/src/core/monitoring/logger.js +2 -1
  59. package/dist/src/core/optimization/trace-optimizer.js +413 -0
  60. package/dist/src/core/patterns/index.js +22 -0
  61. package/dist/src/core/patterns/pattern-applier.js +39 -0
  62. package/dist/src/core/patterns/pattern-observer.js +157 -0
  63. package/dist/src/core/patterns/pattern-store.js +259 -0
  64. package/dist/src/core/patterns/types.js +19 -0
  65. package/dist/src/core/provenance/confidence-scorer.js +128 -0
  66. package/dist/src/core/provenance/index.js +40 -0
  67. package/dist/src/core/provenance/provenance-store.js +194 -0
  68. package/dist/src/core/provenance/types.js +82 -0
  69. package/dist/src/core/retrieval/llm-context-retrieval.js +5 -4
  70. package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
  71. package/dist/src/core/session/project-handoff.js +64 -0
  72. package/dist/src/core/session/session-manager.js +28 -0
  73. package/dist/src/core/shared-state/canonical-store.js +564 -0
  74. package/dist/src/core/skill-packs/index.js +18 -0
  75. package/dist/src/core/skill-packs/parser.js +42 -0
  76. package/dist/src/core/skill-packs/registry.js +224 -0
  77. package/dist/src/core/skill-packs/types.js +79 -0
  78. package/dist/src/core/storage/cloud-sync-manager.js +116 -0
  79. package/dist/src/core/storage/cloud-sync.js +574 -0
  80. package/dist/src/core/storage/two-tier-storage.js +5 -1
  81. package/dist/src/core/tasks/master-tasks-template.js +43 -0
  82. package/dist/src/core/tasks/md-task-parser.js +138 -0
  83. package/dist/src/core/trace/trace-event-store.js +282 -0
  84. package/dist/src/core/vision/index.js +27 -0
  85. package/dist/src/core/vision/signals.js +79 -0
  86. package/dist/src/core/vision/types.js +22 -0
  87. package/dist/src/core/vision/vision-file.js +146 -0
  88. package/dist/src/core/vision/vision-loop.js +220 -0
  89. package/dist/src/core/wiki/wiki-compiler.js +103 -1
  90. package/dist/src/daemon/daemon-config.js +52 -0
  91. package/dist/src/daemon/services/desire-path-service.js +566 -0
  92. package/dist/src/daemon/services/github-service.js +126 -0
  93. package/dist/src/daemon/services/research-stream-service.js +320 -0
  94. package/dist/src/daemon/services/telemetry-service.js +192 -0
  95. package/dist/src/daemon/unified-daemon.js +58 -1
  96. package/dist/src/features/browser/cli-browser-agent.js +417 -0
  97. package/dist/src/features/browser/stagehand-workflows.js +578 -0
  98. package/dist/src/features/operator/adapter-factory.js +62 -0
  99. package/dist/src/features/operator/browser-adapter.js +109 -0
  100. package/dist/src/features/operator/desktop-adapter.js +125 -0
  101. package/dist/src/features/operator/index.js +39 -0
  102. package/dist/src/features/operator/llm-decision.js +137 -0
  103. package/dist/src/features/operator/operator-logger.js +92 -0
  104. package/dist/src/features/operator/overnight-runner.js +327 -0
  105. package/dist/src/features/operator/screen-adapter.js +91 -0
  106. package/dist/src/features/operator/session-manager.js +127 -0
  107. package/dist/src/features/operator/state-machine.js +227 -0
  108. package/dist/src/features/operator/task-queue.js +81 -0
  109. package/dist/src/features/portal/index.js +26 -0
  110. package/dist/src/features/portal/server.js +240 -0
  111. package/dist/src/features/portal/types.js +14 -0
  112. package/dist/src/features/portal/ui.js +195 -0
  113. package/dist/src/features/sweep/pty-wrapper.js +13 -5
  114. package/dist/src/features/tasks/task-aware-context.js +2 -1
  115. package/dist/src/features/tui/simple-monitor.js +0 -23
  116. package/dist/src/features/tui/swarm-monitor.js +8 -66
  117. package/dist/src/features/web/client/hooks/use-socket.js +12 -0
  118. package/dist/src/{core/merge/index.js → features/web/client/lib/utils.js} +8 -4
  119. package/dist/src/features/web/client/next-env.d.js +4 -0
  120. package/dist/src/features/web/client/stores/session-store.js +12 -0
  121. package/dist/src/features/web/server/gcp-billing.js +76 -0
  122. package/dist/src/features/web/server/index.js +10 -0
  123. package/dist/src/features/web/server/spend-calculator.js +228 -0
  124. package/dist/src/hooks/schemas.js +6 -1
  125. package/dist/src/integrations/anthropic/client.js +3 -2
  126. package/dist/src/integrations/claude-code/agent-bridge.js +0 -3
  127. package/dist/src/integrations/claude-code/subagent-client.js +307 -11
  128. package/dist/src/integrations/claude-code/task-coordinator.js +2 -1
  129. package/dist/src/integrations/github/pr-state.js +158 -0
  130. package/dist/src/integrations/linear/client.js +4 -1
  131. package/dist/src/integrations/linear/webhook-retry.js +196 -0
  132. package/dist/src/integrations/linear/webhook-server.js +18 -22
  133. package/dist/src/integrations/mcp/handlers/cloud-sync-handlers.js +101 -0
  134. package/dist/src/integrations/mcp/handlers/index.js +40 -84
  135. package/dist/src/integrations/mcp/server.js +542 -641
  136. package/dist/src/integrations/mcp/tool-alias-registry.js +297 -0
  137. package/dist/src/integrations/mcp/tool-definitions.js +152 -682
  138. package/dist/src/mcp/stackmemory-mcp-server.js +571 -231
  139. package/dist/src/orchestrators/multimodal/determinism.js +244 -0
  140. package/dist/src/orchestrators/multimodal/harness.js +149 -78
  141. package/dist/src/orchestrators/multimodal/providers.js +44 -3
  142. package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
  143. package/dist/src/utils/hook-installer.js +0 -8
  144. package/dist/src/utils/process-cleanup.js +1 -7
  145. package/docs/README.md +42 -0
  146. package/docs/guides/README_INSTALL.md +208 -0
  147. package/package.json +27 -9
  148. package/packs/coding/python-fastapi/instructions.md +60 -0
  149. package/packs/coding/python-fastapi/pack.yaml +28 -0
  150. package/packs/coding/typescript-react/instructions.md +47 -0
  151. package/packs/coding/typescript-react/pack.yaml +28 -0
  152. package/packs/core/commands/capture.md +32 -0
  153. package/packs/core/commands/learn.md +73 -0
  154. package/packs/core/commands/next.md +36 -0
  155. package/packs/core/commands/restart.md +58 -0
  156. package/packs/core/commands/restore.md +29 -0
  157. package/packs/core/commands/start.md +57 -0
  158. package/packs/core/commands/stop.md +65 -0
  159. package/packs/core/commands/summary.md +40 -0
  160. package/packs/core/manifest.json +24 -0
  161. package/packs/ops/decision-recovery/instructions.md +65 -0
  162. package/packs/ops/decision-recovery/pack.yaml +89 -0
  163. package/scripts/claude-code-wrapper.sh +11 -0
  164. package/scripts/claude-sm-setup.sh +12 -1
  165. package/scripts/codex-wrapper.sh +11 -0
  166. package/scripts/git-hooks/branch-context-manager.sh +11 -0
  167. package/scripts/git-hooks/post-checkout-stackmemory.sh +11 -0
  168. package/scripts/git-hooks/post-commit-stackmemory.sh +11 -0
  169. package/scripts/git-hooks/pre-commit-stackmemory.sh +11 -0
  170. package/scripts/hooks/cleanup-shell.sh +12 -1
  171. package/scripts/hooks/task-complete.sh +12 -1
  172. package/scripts/install-code-execution-hooks.sh +12 -1
  173. package/scripts/install-sweep-hook.sh +12 -0
  174. package/scripts/install.sh +11 -0
  175. package/scripts/opencode-wrapper.sh +11 -0
  176. package/scripts/portal/cloud-init.yaml +69 -0
  177. package/scripts/portal/setup.sh +69 -0
  178. package/scripts/portal/stackmemory-portal.service +34 -0
  179. package/scripts/setup-claude-integration.sh +12 -1
  180. package/scripts/smoke-init-db.sh +23 -0
  181. package/scripts/stackmemory-daemon.sh +11 -0
  182. package/scripts/verify-dist.cjs +11 -4
  183. package/dist/src/cli/commands/ralph.js +0 -1053
  184. package/dist/src/cli/commands/team.js +0 -168
  185. package/dist/src/core/context/shared-context-layer.js +0 -620
  186. package/dist/src/core/context/stack-merge-resolver.js +0 -748
  187. package/dist/src/core/merge/conflict-detector.js +0 -430
  188. package/dist/src/core/merge/resolution-engine.js +0 -557
  189. package/dist/src/core/merge/stack-diff.js +0 -531
  190. package/dist/src/core/merge/unified-merge-resolver.js +0 -302
  191. package/dist/src/hooks/diffmem-hooks.js +0 -376
  192. package/dist/src/integrations/diffmem/client.js +0 -208
  193. package/dist/src/integrations/diffmem/config.js +0 -14
  194. package/dist/src/integrations/greptile/client.js +0 -101
  195. package/dist/src/integrations/greptile/config.js +0 -14
  196. package/dist/src/integrations/greptile/index.js +0 -11
  197. package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
  198. package/dist/src/integrations/mcp/handlers/diffmem-handlers.js +0 -455
  199. package/dist/src/integrations/mcp/handlers/greptile-handlers.js +0 -456
  200. package/dist/src/integrations/mcp/handlers/provider-handlers.js +0 -227
  201. package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
  202. package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -863
  203. package/dist/src/integrations/ralph/context/context-budget-manager.js +0 -308
  204. package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +0 -391
  205. package/dist/src/integrations/ralph/index.js +0 -17
  206. package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -435
  207. package/dist/src/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
  208. package/dist/src/integrations/ralph/loopmax.js +0 -488
  209. package/dist/src/integrations/ralph/monitoring/swarm-dashboard.js +0 -293
  210. package/dist/src/integrations/ralph/monitoring/swarm-registry.js +0 -107
  211. package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -508
  212. package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -407
  213. package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +0 -495
  214. package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +0 -387
  215. package/dist/src/integrations/ralph/performance/performance-optimizer.js +0 -357
  216. package/dist/src/integrations/ralph/recovery/crash-recovery.js +0 -461
  217. package/dist/src/integrations/ralph/state/state-reconciler.js +0 -420
  218. package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +0 -444
  219. package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -1007
  220. package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
  221. package/scripts/ralph-loop-implementation.js +0 -404
  222. /package/dist/src/core/{merge → cache}/types.js +0 -0
  223. /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
  224. /package/dist/src/{integrations/greptile/types.js → core/trace/trace-event.js} +0 -0
  225. /package/dist/src/{integrations/ralph → features/operator}/types.js +0 -0
@@ -1,420 +0,0 @@
1
- import { fileURLToPath as __fileURLToPath } from 'url';
2
- import { dirname as __pathDirname } from 'path';
3
- const __filename = __fileURLToPath(import.meta.url);
4
- const __dirname = __pathDirname(__filename);
5
- import * as fs from "fs/promises";
6
- import * as path from "path";
7
- import { execSync } from "child_process";
8
- import { logger } from "../../../core/monitoring/logger.js";
9
- class StateReconciler {
10
- config;
11
- ralphDir = ".ralph";
12
- reconciliationLog = [];
13
- constructor(config) {
14
- this.config = {
15
- precedence: config?.precedence || ["git", "files", "memory"],
16
- conflictResolution: config?.conflictResolution || "automatic",
17
- syncInterval: config?.syncInterval || 5e3,
18
- validateConsistency: config?.validateConsistency ?? true
19
- };
20
- }
21
- /**
22
- * Reconcile state from multiple sources
23
- */
24
- async reconcile(sources) {
25
- logger.info("Reconciling state from sources", {
26
- sources: sources.map((s) => ({ type: s.type, confidence: s.confidence }))
27
- });
28
- const sortedSources = this.sortByPrecedence(sources);
29
- const conflicts = this.detectConflicts(sortedSources);
30
- if (conflicts.length > 0) {
31
- logger.warn("State conflicts detected", {
32
- count: conflicts.length,
33
- fields: conflicts.map((c) => c.field)
34
- });
35
- const resolutions = await this.resolveConflicts(conflicts);
36
- return this.applyResolutions(
37
- sortedSources[0].state,
38
- resolutions
39
- );
40
- }
41
- return this.mergeStates(sortedSources);
42
- }
43
- /**
44
- * Detect conflicts between state sources
45
- */
46
- detectConflicts(sources) {
47
- const conflicts = [];
48
- const fields = /* @__PURE__ */ new Set();
49
- sources.forEach((source) => {
50
- Object.keys(source.state).forEach((field) => fields.add(field));
51
- });
52
- for (const field of fields) {
53
- const values = sources.filter((s) => s.state[field] !== void 0).map((s) => ({
54
- source: s,
55
- value: s.state[field]
56
- }));
57
- if (values.length > 1 && !this.valuesMatch(values.map((v) => v.value))) {
58
- conflicts.push({
59
- field,
60
- sources: values.map((v) => v.source),
61
- severity: this.assessConflictSeverity(field),
62
- suggestedResolution: this.suggestResolution(
63
- field,
64
- values.map((v) => v.source)
65
- )
66
- });
67
- }
68
- }
69
- return conflicts;
70
- }
71
- /**
72
- * Resolve a single conflict
73
- */
74
- async resolveConflict(conflict) {
75
- const resolution = await this.resolveConflictByStrategy(conflict);
76
- this.reconciliationLog.push(resolution);
77
- logger.debug("Conflict resolved", {
78
- field: conflict.field,
79
- resolution: resolution.source,
80
- rationale: resolution.rationale
81
- });
82
- return resolution;
83
- }
84
- /**
85
- * Validate state consistency
86
- */
87
- async validateConsistency(state) {
88
- const errors = [];
89
- const warnings = [];
90
- try {
91
- await this.validateFileSystemState(state, errors, warnings);
92
- this.validateGitState(state, errors, warnings);
93
- this.validateLogicalConsistency(state, errors, warnings);
94
- return {
95
- testsPass: errors.length === 0,
96
- lintClean: true,
97
- buildSuccess: true,
98
- errors,
99
- warnings
100
- };
101
- } catch (error) {
102
- errors.push(`Validation failed: ${error.message}`);
103
- return {
104
- testsPass: false,
105
- lintClean: false,
106
- buildSuccess: false,
107
- errors,
108
- warnings
109
- };
110
- }
111
- }
112
- /**
113
- * Get state from git
114
- */
115
- async getGitState() {
116
- try {
117
- const currentCommit = execSync("git rev-parse HEAD", {
118
- encoding: "utf8"
119
- }).trim();
120
- const _branch = execSync("git branch --show-current", {
121
- encoding: "utf8"
122
- }).trim();
123
- const uncommittedChanges = execSync("git status --porcelain", {
124
- encoding: "utf8"
125
- });
126
- const ralphCommits = execSync(
127
- 'git log --oneline --grep="Ralph iteration"',
128
- {
129
- encoding: "utf8"
130
- }
131
- ).split("\n").filter(Boolean);
132
- const lastRalphCommit = ralphCommits[0]?.split(" ")[0];
133
- const iteration = ralphCommits.length;
134
- return {
135
- type: "git",
136
- state: {
137
- currentCommit,
138
- startCommit: lastRalphCommit,
139
- iteration,
140
- status: uncommittedChanges ? "running" : "completed"
141
- },
142
- timestamp: Date.now(),
143
- confidence: 0.9
144
- };
145
- } catch (error) {
146
- logger.error("Failed to get git state", { error: error.message });
147
- return {
148
- type: "git",
149
- state: {},
150
- timestamp: Date.now(),
151
- confidence: 0.1
152
- };
153
- }
154
- }
155
- /**
156
- * Get state from file system
157
- */
158
- async getFileState() {
159
- try {
160
- const statePath = path.join(this.ralphDir, "state.json");
161
- const iterationPath = path.join(this.ralphDir, "iteration.txt");
162
- const feedbackPath = path.join(this.ralphDir, "feedback.txt");
163
- const taskPath = path.join(this.ralphDir, "task.md");
164
- const criteriaPath = path.join(this.ralphDir, "completion-criteria.md");
165
- const [stateData, iteration, feedback, task, criteria] = await Promise.all([
166
- fs.readFile(statePath, "utf8").catch(() => "{}"),
167
- fs.readFile(iterationPath, "utf8").catch(() => "0"),
168
- fs.readFile(feedbackPath, "utf8").catch(() => ""),
169
- fs.readFile(taskPath, "utf8").catch(() => ""),
170
- fs.readFile(criteriaPath, "utf8").catch(() => "")
171
- ]);
172
- const state = JSON.parse(stateData);
173
- return {
174
- type: "files",
175
- state: {
176
- ...state,
177
- iteration: parseInt(iteration.trim()),
178
- feedback: feedback.trim() || void 0,
179
- task: task.trim(),
180
- criteria: criteria.trim()
181
- },
182
- timestamp: Date.now(),
183
- confidence: 0.95
184
- };
185
- } catch (error) {
186
- logger.error("Failed to get file state", { error: error.message });
187
- return {
188
- type: "files",
189
- state: {},
190
- timestamp: Date.now(),
191
- confidence: 0.1
192
- };
193
- }
194
- }
195
- /**
196
- * Get state from memory (StackMemory)
197
- */
198
- async getMemoryState(loopId) {
199
- try {
200
- return {
201
- type: "memory",
202
- state: {
203
- loopId,
204
- lastUpdateTime: Date.now()
205
- },
206
- timestamp: Date.now(),
207
- confidence: 0.8
208
- };
209
- } catch (error) {
210
- logger.error("Failed to get memory state", { error: error.message });
211
- return {
212
- type: "memory",
213
- state: {},
214
- timestamp: Date.now(),
215
- confidence: 0.1
216
- };
217
- }
218
- }
219
- /**
220
- * Sort sources by configured precedence
221
- */
222
- sortByPrecedence(sources) {
223
- return sources.sort((a, b) => {
224
- const aIndex = this.config.precedence.indexOf(a.type);
225
- const bIndex = this.config.precedence.indexOf(b.type);
226
- if (aIndex === -1 && bIndex === -1) {
227
- return b.confidence - a.confidence;
228
- }
229
- if (aIndex === -1) return 1;
230
- if (bIndex === -1) return -1;
231
- return aIndex - bIndex;
232
- });
233
- }
234
- /**
235
- * Check if values match
236
- */
237
- valuesMatch(values) {
238
- if (values.length === 0) return true;
239
- const first = JSON.stringify(values[0]);
240
- return values.every((v) => JSON.stringify(v) === first);
241
- }
242
- /**
243
- * Assess conflict severity
244
- */
245
- assessConflictSeverity(field) {
246
- const highSeverityFields = ["loopId", "task", "criteria", "status"];
247
- const mediumSeverityFields = ["iteration", "currentCommit", "feedback"];
248
- if (highSeverityFields.includes(field)) return "high";
249
- if (mediumSeverityFields.includes(field)) return "medium";
250
- return "low";
251
- }
252
- /**
253
- * Suggest resolution based on field and sources
254
- */
255
- suggestResolution(field, sources) {
256
- const sorted = this.sortByPrecedence(sources);
257
- const highestConfidence = sorted.reduce(
258
- (max, s) => s.confidence > max.confidence ? s : max
259
- );
260
- return highestConfidence.state[field];
261
- }
262
- /**
263
- * Resolve conflicts based on configured strategy
264
- */
265
- async resolveConflicts(conflicts) {
266
- const resolutions = [];
267
- for (const conflict of conflicts) {
268
- const resolution = await this.resolveConflictByStrategy(conflict);
269
- resolutions.push(resolution);
270
- }
271
- return resolutions;
272
- }
273
- /**
274
- * Resolve conflict based on strategy
275
- */
276
- async resolveConflictByStrategy(conflict) {
277
- switch (this.config.conflictResolution) {
278
- case "automatic":
279
- return this.automaticResolution(conflict);
280
- case "manual":
281
- return this.manualResolution(conflict);
282
- case "interactive":
283
- return this.interactiveResolution(conflict);
284
- default:
285
- return this.automaticResolution(conflict);
286
- }
287
- }
288
- /**
289
- * Automatic resolution based on precedence and confidence
290
- */
291
- automaticResolution(conflict) {
292
- const sorted = this.sortByPrecedence(conflict.sources);
293
- const winner = sorted[0];
294
- return {
295
- field: conflict.field,
296
- value: winner.state[conflict.field],
297
- source: winner.type,
298
- rationale: `Automatic resolution: ${winner.type} has highest precedence (confidence: ${winner.confidence})`
299
- };
300
- }
301
- /**
302
- * Manual resolution (uses suggested resolution)
303
- */
304
- manualResolution(conflict) {
305
- return {
306
- field: conflict.field,
307
- value: conflict.suggestedResolution,
308
- source: "manual",
309
- rationale: "Manual resolution: using suggested value"
310
- };
311
- }
312
- /**
313
- * Interactive resolution (would prompt user in real implementation)
314
- */
315
- async interactiveResolution(conflict) {
316
- logger.info("Interactive resolution required", {
317
- field: conflict.field,
318
- options: conflict.sources.map((s) => ({
319
- type: s.type,
320
- value: s.state[conflict.field],
321
- confidence: s.confidence
322
- }))
323
- });
324
- return this.automaticResolution(conflict);
325
- }
326
- /**
327
- * Apply resolutions to base state
328
- */
329
- applyResolutions(baseState, resolutions) {
330
- const resolvedState = { ...baseState };
331
- for (const resolution of resolutions) {
332
- resolvedState[resolution.field] = resolution.value;
333
- }
334
- return resolvedState;
335
- }
336
- /**
337
- * Merge states without conflicts
338
- */
339
- mergeStates(sources) {
340
- const merged = {};
341
- for (const source of sources) {
342
- Object.assign(merged, source.state);
343
- }
344
- return merged;
345
- }
346
- /**
347
- * Validate file system state
348
- */
349
- async validateFileSystemState(state, errors, warnings) {
350
- try {
351
- const ralphDirExists = await fs.stat(this.ralphDir).then(() => true).catch(() => false);
352
- if (!ralphDirExists) {
353
- warnings.push("Ralph directory does not exist");
354
- return;
355
- }
356
- const requiredFiles = ["task.md", "state.json", "iteration.txt"];
357
- for (const file of requiredFiles) {
358
- const filePath = path.join(this.ralphDir, file);
359
- const exists = await fs.stat(filePath).then(() => true).catch(() => false);
360
- if (!exists) {
361
- warnings.push(`Missing file: ${file}`);
362
- }
363
- }
364
- } catch (error) {
365
- errors.push(`File system validation failed: ${error.message}`);
366
- }
367
- }
368
- /**
369
- * Validate git state
370
- */
371
- validateGitState(state, errors, warnings) {
372
- try {
373
- const isGitRepo = execSync("git rev-parse --is-inside-work-tree", {
374
- encoding: "utf8"
375
- }).trim() === "true";
376
- if (!isGitRepo) {
377
- warnings.push("Not in a git repository");
378
- }
379
- if (state.currentCommit && state.startCommit) {
380
- try {
381
- execSync(`git rev-parse ${state.currentCommit}`, {
382
- encoding: "utf8"
383
- });
384
- } catch {
385
- errors.push(`Invalid current commit: ${state.currentCommit}`);
386
- }
387
- try {
388
- execSync(`git rev-parse ${state.startCommit}`, { encoding: "utf8" });
389
- } catch {
390
- warnings.push(`Invalid start commit: ${state.startCommit}`);
391
- }
392
- }
393
- } catch (error) {
394
- warnings.push(`Git validation failed: ${error.message}`);
395
- }
396
- }
397
- /**
398
- * Validate logical consistency
399
- */
400
- validateLogicalConsistency(state, errors, warnings) {
401
- if (state.iteration < 0) {
402
- errors.push("Invalid iteration number: cannot be negative");
403
- }
404
- if (state.status === "completed" && !state.completionData) {
405
- warnings.push("Status is completed but no completion data");
406
- }
407
- if (state.lastUpdateTime && state.startTime && state.lastUpdateTime < state.startTime) {
408
- errors.push("Last update time is before start time");
409
- }
410
- if (!state.task) {
411
- errors.push("No task defined");
412
- }
413
- if (!state.criteria) {
414
- warnings.push("No completion criteria defined");
415
- }
416
- }
417
- }
418
- export {
419
- StateReconciler
420
- };