@stackmemoryai/stackmemory 1.12.0 → 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.
- package/LICENSE +131 -64
- package/README.md +3 -1
- package/bin/claude-sm +16 -1
- package/bin/claude-smd +16 -1
- package/bin/codex-smd +16 -1
- package/bin/gemini-sm +16 -1
- package/bin/hermes-sm +21 -0
- package/bin/hermes-smd +21 -0
- package/bin/opencode-sm +16 -1
- package/dist/src/cli/codex-sm.js +51 -11
- package/dist/src/cli/commands/brain.js +206 -0
- package/dist/src/cli/commands/company-os.js +184 -0
- package/dist/src/cli/commands/context.js +5 -0
- package/dist/src/cli/commands/operator.js +127 -0
- package/dist/src/cli/commands/orchestrate.js +2 -0
- package/dist/src/cli/commands/orchestrator.js +3 -2
- package/dist/src/cli/commands/patterns.js +254 -0
- package/dist/src/cli/commands/portal.js +161 -0
- package/dist/src/cli/commands/scaffold.js +92 -0
- package/dist/src/cli/commands/setup.js +1 -4
- package/dist/src/cli/commands/sync.js +253 -0
- package/dist/src/cli/commands/tasks.js +130 -1
- package/dist/src/cli/commands/vision.js +221 -0
- package/dist/src/cli/hermes-sm.js +224 -0
- package/dist/src/cli/index.js +15 -10
- package/dist/src/cli/utils/real-cli-bin.js +72 -0
- package/dist/src/core/brain/brain-store.js +187 -0
- package/dist/src/core/brain/brain-sync.js +193 -0
- package/dist/src/core/brain/index.js +78 -0
- package/dist/src/core/brain/types.js +10 -0
- package/dist/src/core/cache/token-estimator.js +24 -1
- package/dist/src/core/config/feature-flags.js +2 -6
- package/dist/src/core/context/frame-database.js +44 -0
- package/dist/src/core/context/recursive-context-manager.js +1 -1
- package/dist/src/core/context/rehydration.js +2 -1
- package/dist/src/core/database/sqlite-adapter.js +14 -1
- package/dist/src/core/models/model-router.js +33 -1
- package/dist/src/core/models/provider-pricing.js +58 -4
- package/dist/src/core/patterns/index.js +22 -0
- package/dist/src/core/patterns/pattern-applier.js +39 -0
- package/dist/src/core/patterns/pattern-observer.js +157 -0
- package/dist/src/core/patterns/pattern-store.js +259 -0
- package/dist/src/core/patterns/types.js +19 -0
- package/dist/src/core/retrieval/llm-context-retrieval.js +5 -4
- package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
- package/dist/src/core/skill-packs/types.js +14 -1
- package/dist/src/core/storage/cloud-sync-manager.js +116 -0
- package/dist/src/core/storage/cloud-sync.js +574 -0
- package/dist/src/core/storage/two-tier-storage.js +5 -1
- package/dist/src/core/tasks/master-tasks-template.js +43 -0
- package/dist/src/core/tasks/md-task-parser.js +138 -0
- package/dist/src/core/vision/index.js +27 -0
- package/dist/src/core/vision/signals.js +79 -0
- package/dist/src/core/vision/types.js +22 -0
- package/dist/src/core/vision/vision-file.js +146 -0
- package/dist/src/core/vision/vision-loop.js +220 -0
- package/dist/src/core/wiki/wiki-compiler.js +103 -1
- package/dist/src/daemon/daemon-config.js +45 -0
- package/dist/src/daemon/services/desire-path-service.js +566 -0
- package/dist/src/daemon/services/research-stream-service.js +320 -0
- package/dist/src/daemon/services/telemetry-service.js +192 -0
- package/dist/src/daemon/unified-daemon.js +28 -1
- package/dist/src/features/browser/cli-browser-agent.js +417 -0
- package/dist/src/features/browser/stagehand-workflows.js +578 -0
- package/dist/src/features/operator/adapter-factory.js +62 -0
- package/dist/src/features/operator/browser-adapter.js +109 -0
- package/dist/src/features/operator/desktop-adapter.js +125 -0
- package/dist/src/features/operator/index.js +39 -0
- package/dist/src/features/operator/llm-decision.js +137 -0
- package/dist/src/features/operator/operator-logger.js +92 -0
- package/dist/src/features/operator/overnight-runner.js +327 -0
- package/dist/src/features/operator/screen-adapter.js +91 -0
- package/dist/src/features/operator/session-manager.js +127 -0
- package/dist/src/features/operator/state-machine.js +227 -0
- package/dist/src/features/operator/task-queue.js +81 -0
- package/dist/src/features/portal/index.js +26 -0
- package/dist/src/features/portal/server.js +240 -0
- package/dist/src/features/portal/types.js +14 -0
- package/dist/src/features/portal/ui.js +195 -0
- package/dist/src/features/tasks/task-aware-context.js +2 -1
- package/dist/src/features/tui/simple-monitor.js +0 -23
- package/dist/src/features/tui/swarm-monitor.js +8 -66
- package/dist/src/{integrations/diffmem/index.js → features/web/client/hooks/use-socket.js} +6 -5
- package/dist/src/features/web/client/lib/utils.js +12 -0
- package/dist/src/features/web/client/stores/session-store.js +12 -0
- package/dist/src/features/web/server/gcp-billing.js +76 -0
- package/dist/src/features/web/server/index.js +10 -0
- package/dist/src/features/web/server/spend-calculator.js +228 -0
- package/dist/src/hooks/schemas.js +4 -1
- package/dist/src/integrations/anthropic/client.js +3 -2
- package/dist/src/integrations/claude-code/agent-bridge.js +0 -3
- package/dist/src/integrations/claude-code/subagent-client.js +218 -11
- package/dist/src/integrations/claude-code/task-coordinator.js +2 -1
- package/dist/src/integrations/linear/webhook-retry.js +196 -0
- package/dist/src/integrations/linear/webhook-server.js +18 -22
- package/dist/src/integrations/mcp/handlers/cloud-sync-handlers.js +101 -0
- package/dist/src/integrations/mcp/handlers/index.js +27 -52
- package/dist/src/integrations/mcp/server.js +122 -335
- package/dist/src/integrations/mcp/tool-alias-registry.js +0 -73
- package/dist/src/integrations/mcp/tool-definitions.js +111 -510
- package/dist/src/mcp/stackmemory-mcp-server.js +404 -379
- package/dist/src/orchestrators/multimodal/determinism.js +2 -1
- package/dist/src/orchestrators/multimodal/harness.js +2 -1
- package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
- package/dist/src/utils/process-cleanup.js +1 -7
- package/docs/README.md +42 -0
- package/docs/guides/README_INSTALL.md +208 -0
- package/package.json +18 -9
- package/scripts/claude-code-wrapper.sh +11 -0
- package/scripts/claude-sm-setup.sh +12 -1
- package/scripts/codex-wrapper.sh +11 -0
- package/scripts/git-hooks/branch-context-manager.sh +11 -0
- package/scripts/git-hooks/post-checkout-stackmemory.sh +11 -0
- package/scripts/git-hooks/post-commit-stackmemory.sh +11 -0
- package/scripts/git-hooks/pre-commit-stackmemory.sh +11 -0
- package/scripts/hooks/cleanup-shell.sh +12 -1
- package/scripts/hooks/task-complete.sh +12 -1
- package/scripts/install-code-execution-hooks.sh +12 -1
- package/scripts/install-sweep-hook.sh +12 -0
- package/scripts/install.sh +11 -0
- package/scripts/opencode-wrapper.sh +11 -0
- package/scripts/portal/cloud-init.yaml +69 -0
- package/scripts/portal/setup.sh +69 -0
- package/scripts/portal/stackmemory-portal.service +34 -0
- package/scripts/setup-claude-integration.sh +12 -1
- package/scripts/smoke-init-db.sh +23 -0
- package/scripts/stackmemory-daemon.sh +11 -0
- package/scripts/verify-dist.cjs +11 -4
- package/dist/src/cli/commands/ralph.js +0 -1053
- package/dist/src/hooks/diffmem-hooks.js +0 -376
- package/dist/src/integrations/diffmem/client.js +0 -208
- package/dist/src/integrations/diffmem/config.js +0 -14
- package/dist/src/integrations/greptile/client.js +0 -101
- package/dist/src/integrations/greptile/config.js +0 -14
- package/dist/src/integrations/greptile/index.js +0 -11
- package/dist/src/integrations/mcp/handlers/cross-search-handlers.js +0 -188
- package/dist/src/integrations/mcp/handlers/diffmem-handlers.js +0 -455
- package/dist/src/integrations/mcp/handlers/greptile-handlers.js +0 -456
- package/dist/src/integrations/mcp/handlers/provider-handlers.js +0 -227
- package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -863
- package/dist/src/integrations/ralph/context/context-budget-manager.js +0 -308
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +0 -354
- package/dist/src/integrations/ralph/index.js +0 -17
- package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -416
- package/dist/src/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
- package/dist/src/integrations/ralph/loopmax.js +0 -488
- package/dist/src/integrations/ralph/monitoring/swarm-dashboard.js +0 -293
- package/dist/src/integrations/ralph/monitoring/swarm-registry.js +0 -107
- package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -508
- package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -407
- package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +0 -495
- package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +0 -387
- package/dist/src/integrations/ralph/performance/performance-optimizer.js +0 -357
- package/dist/src/integrations/ralph/recovery/crash-recovery.js +0 -461
- package/dist/src/integrations/ralph/state/state-reconciler.js +0 -420
- package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +0 -444
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -1005
- package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
- package/scripts/ralph-loop-implementation.js +0 -404
- /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
- /package/dist/src/{integrations/greptile → features/operator}/types.js +0 -0
- /package/dist/src/{integrations/ralph/types.js → features/web/client/next-env.d.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
|
-
};
|