@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,448 +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 { EventEmitter } from "events";
|
|
6
|
-
import { execSync } from "child_process";
|
|
7
|
-
import { logger } from "../../../core/monitoring/logger.js";
|
|
8
|
-
class IterationLifecycle extends EventEmitter {
|
|
9
|
-
config;
|
|
10
|
-
hooks = {};
|
|
11
|
-
checkpoints = [];
|
|
12
|
-
currentIteration;
|
|
13
|
-
iterationHistory = [];
|
|
14
|
-
activeTimers = /* @__PURE__ */ new Map();
|
|
15
|
-
constructor(config, hooks) {
|
|
16
|
-
super();
|
|
17
|
-
this.config = {
|
|
18
|
-
hooks: {
|
|
19
|
-
preIteration: config?.hooks?.preIteration ?? true,
|
|
20
|
-
postIteration: config?.hooks?.postIteration ?? true,
|
|
21
|
-
onStateChange: config?.hooks?.onStateChange ?? true,
|
|
22
|
-
onError: config?.hooks?.onError ?? true,
|
|
23
|
-
onComplete: config?.hooks?.onComplete ?? true
|
|
24
|
-
},
|
|
25
|
-
checkpoints: {
|
|
26
|
-
enabled: config?.checkpoints?.enabled ?? true,
|
|
27
|
-
frequency: config?.checkpoints?.frequency || 5,
|
|
28
|
-
retentionDays: config?.checkpoints?.retentionDays || 7
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
if (hooks) {
|
|
32
|
-
this.registerHooks(hooks);
|
|
33
|
-
}
|
|
34
|
-
this.setupEventHandlers();
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Register lifecycle hooks
|
|
38
|
-
*/
|
|
39
|
-
registerHooks(hooks) {
|
|
40
|
-
this.hooks = { ...this.hooks, ...hooks };
|
|
41
|
-
logger.debug("Lifecycle hooks registered", {
|
|
42
|
-
registered: Object.keys(hooks)
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Start iteration with lifecycle management
|
|
47
|
-
*/
|
|
48
|
-
async startIteration(iterationNumber, context) {
|
|
49
|
-
logger.info("Starting iteration", { iteration: iterationNumber });
|
|
50
|
-
this.emitEvent({
|
|
51
|
-
type: "iteration.started",
|
|
52
|
-
timestamp: Date.now(),
|
|
53
|
-
iteration: iterationNumber,
|
|
54
|
-
data: { context }
|
|
55
|
-
});
|
|
56
|
-
let processedContext = context;
|
|
57
|
-
if (this.config.hooks.preIteration && this.hooks.preIteration) {
|
|
58
|
-
try {
|
|
59
|
-
processedContext = await this.hooks.preIteration(context);
|
|
60
|
-
logger.debug("Pre-iteration hook executed", {
|
|
61
|
-
original: context.tokenCount,
|
|
62
|
-
processed: processedContext.tokenCount
|
|
63
|
-
});
|
|
64
|
-
} catch (error) {
|
|
65
|
-
await this.handleError(error, { phase: "preIteration", context });
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
this.startTimer(`iteration-${iterationNumber}`);
|
|
69
|
-
return processedContext;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Complete iteration with lifecycle management
|
|
73
|
-
*/
|
|
74
|
-
async completeIteration(iteration) {
|
|
75
|
-
logger.info("Completing iteration", { iteration: iteration.number });
|
|
76
|
-
this.currentIteration = iteration;
|
|
77
|
-
const duration = this.stopTimer(`iteration-${iteration.number}`);
|
|
78
|
-
if (this.config.hooks.postIteration && this.hooks.postIteration) {
|
|
79
|
-
try {
|
|
80
|
-
await this.hooks.postIteration(iteration);
|
|
81
|
-
logger.debug("Post-iteration hook executed");
|
|
82
|
-
} catch (error) {
|
|
83
|
-
await this.handleError(error, { phase: "postIteration", iteration });
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (this.shouldCreateCheckpoint(iteration.number)) {
|
|
87
|
-
await this.createCheckpoint(iteration);
|
|
88
|
-
}
|
|
89
|
-
this.emitEvent({
|
|
90
|
-
type: "iteration.completed",
|
|
91
|
-
timestamp: Date.now(),
|
|
92
|
-
iteration: iteration.number,
|
|
93
|
-
data: {
|
|
94
|
-
iteration,
|
|
95
|
-
duration,
|
|
96
|
-
success: iteration.validation.testsPass
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
await this.cleanOldCheckpoints();
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Handle iteration failure
|
|
103
|
-
*/
|
|
104
|
-
async failIteration(iterationNumber, error, context) {
|
|
105
|
-
logger.error("Iteration failed", {
|
|
106
|
-
iteration: iterationNumber,
|
|
107
|
-
error: error.message
|
|
108
|
-
});
|
|
109
|
-
this.stopTimer(`iteration-${iterationNumber}`);
|
|
110
|
-
if (this.config.hooks.onError && this.hooks.onError) {
|
|
111
|
-
try {
|
|
112
|
-
await this.hooks.onError(error, context);
|
|
113
|
-
} catch (hookError) {
|
|
114
|
-
logger.error("Error hook failed", { error: hookError.message });
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
this.emitEvent({
|
|
118
|
-
type: "iteration.failed",
|
|
119
|
-
timestamp: Date.now(),
|
|
120
|
-
iteration: iterationNumber,
|
|
121
|
-
data: {
|
|
122
|
-
error: error.message,
|
|
123
|
-
stack: error.stack,
|
|
124
|
-
context
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Handle state change
|
|
130
|
-
*/
|
|
131
|
-
async handleStateChange(oldState, newState) {
|
|
132
|
-
logger.debug("State change detected", {
|
|
133
|
-
old: oldState.status,
|
|
134
|
-
new: newState.status,
|
|
135
|
-
iteration: newState.iteration
|
|
136
|
-
});
|
|
137
|
-
if (this.config.hooks.onStateChange && this.hooks.onStateChange) {
|
|
138
|
-
try {
|
|
139
|
-
await this.hooks.onStateChange(oldState, newState);
|
|
140
|
-
} catch (error) {
|
|
141
|
-
await this.handleError(error, {
|
|
142
|
-
phase: "stateChange",
|
|
143
|
-
oldState,
|
|
144
|
-
newState
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
this.emitEvent({
|
|
149
|
-
type: "state.changed",
|
|
150
|
-
timestamp: Date.now(),
|
|
151
|
-
iteration: newState.iteration,
|
|
152
|
-
data: {
|
|
153
|
-
oldStatus: oldState.status,
|
|
154
|
-
newStatus: newState.status,
|
|
155
|
-
changes: this.detectStateChanges(oldState, newState)
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
if (newState.status === "completed" && oldState.status !== "completed") {
|
|
159
|
-
await this.handleCompletion(newState);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Handle loop completion
|
|
164
|
-
*/
|
|
165
|
-
async handleCompletion(state) {
|
|
166
|
-
logger.info("Loop completed", {
|
|
167
|
-
iterations: state.iteration,
|
|
168
|
-
duration: state.lastUpdateTime - state.startTime
|
|
169
|
-
});
|
|
170
|
-
if (this.config.hooks.onComplete && this.hooks.onComplete) {
|
|
171
|
-
try {
|
|
172
|
-
await this.hooks.onComplete(state);
|
|
173
|
-
} catch (error) {
|
|
174
|
-
await this.handleError(error, { phase: "completion", state });
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
await this.createFinalCheckpoint(state);
|
|
178
|
-
this.cleanupTimers();
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Create checkpoint
|
|
182
|
-
*/
|
|
183
|
-
async createCheckpoint(iteration) {
|
|
184
|
-
const checkpoint = {
|
|
185
|
-
id: this.generateCheckpointId(),
|
|
186
|
-
iteration: iteration.number,
|
|
187
|
-
timestamp: Date.now(),
|
|
188
|
-
state: await this.captureCurrentState(),
|
|
189
|
-
gitCommit: await this.getCurrentGitCommit(),
|
|
190
|
-
verified: false
|
|
191
|
-
};
|
|
192
|
-
checkpoint.verified = await this.verifyCheckpoint(checkpoint);
|
|
193
|
-
this.checkpoints.push(checkpoint);
|
|
194
|
-
logger.info("Checkpoint created", {
|
|
195
|
-
id: checkpoint.id,
|
|
196
|
-
iteration: checkpoint.iteration,
|
|
197
|
-
verified: checkpoint.verified
|
|
198
|
-
});
|
|
199
|
-
if (this.hooks.onCheckpoint) {
|
|
200
|
-
try {
|
|
201
|
-
await this.hooks.onCheckpoint(checkpoint);
|
|
202
|
-
} catch (error) {
|
|
203
|
-
logger.error("Checkpoint hook failed", { error: error.message });
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
this.emitEvent({
|
|
207
|
-
type: "checkpoint.created",
|
|
208
|
-
timestamp: Date.now(),
|
|
209
|
-
iteration: iteration.number,
|
|
210
|
-
data: { checkpoint }
|
|
211
|
-
});
|
|
212
|
-
return checkpoint;
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Get checkpoints
|
|
216
|
-
*/
|
|
217
|
-
getCheckpoints() {
|
|
218
|
-
return [...this.checkpoints];
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Get last checkpoint
|
|
222
|
-
*/
|
|
223
|
-
getLastCheckpoint() {
|
|
224
|
-
return this.checkpoints[this.checkpoints.length - 1];
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Restore from checkpoint
|
|
228
|
-
*/
|
|
229
|
-
async restoreFromCheckpoint(checkpointId) {
|
|
230
|
-
const checkpoint = this.checkpoints.find((c) => c.id === checkpointId);
|
|
231
|
-
if (!checkpoint) {
|
|
232
|
-
throw new Error(`Checkpoint not found: ${checkpointId}`);
|
|
233
|
-
}
|
|
234
|
-
logger.info("Restoring from checkpoint", {
|
|
235
|
-
id: checkpoint.id,
|
|
236
|
-
iteration: checkpoint.iteration
|
|
237
|
-
});
|
|
238
|
-
if (checkpoint.gitCommit) {
|
|
239
|
-
await this.restoreGitState(checkpoint.gitCommit);
|
|
240
|
-
}
|
|
241
|
-
await this.restoreRalphState(checkpoint.state);
|
|
242
|
-
logger.info("Checkpoint restored successfully");
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Get iteration events
|
|
246
|
-
*/
|
|
247
|
-
getEvents(filter) {
|
|
248
|
-
let events = [...this.iterationHistory];
|
|
249
|
-
if (filter?.type) {
|
|
250
|
-
events = events.filter((e) => e.type === filter.type);
|
|
251
|
-
}
|
|
252
|
-
if (filter?.iteration !== void 0) {
|
|
253
|
-
events = events.filter((e) => e.iteration === filter.iteration);
|
|
254
|
-
}
|
|
255
|
-
if (filter?.since) {
|
|
256
|
-
events = events.filter((e) => e.timestamp >= filter.since);
|
|
257
|
-
}
|
|
258
|
-
return events;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Clean up resources
|
|
262
|
-
*/
|
|
263
|
-
cleanup() {
|
|
264
|
-
this.cleanupTimers();
|
|
265
|
-
this.removeAllListeners();
|
|
266
|
-
this.iterationHistory = [];
|
|
267
|
-
this.checkpoints = [];
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Setup internal event handlers
|
|
271
|
-
*/
|
|
272
|
-
setupEventHandlers() {
|
|
273
|
-
this.on("*", (event) => {
|
|
274
|
-
logger.debug("Lifecycle event", {
|
|
275
|
-
type: event.type,
|
|
276
|
-
iteration: event.iteration
|
|
277
|
-
});
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* Emit and track event
|
|
282
|
-
*/
|
|
283
|
-
emitEvent(event) {
|
|
284
|
-
this.iterationHistory.push(event);
|
|
285
|
-
this.emit(event.type, event);
|
|
286
|
-
this.emit("*", event);
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Should create checkpoint based on frequency
|
|
290
|
-
*/
|
|
291
|
-
shouldCreateCheckpoint(iteration) {
|
|
292
|
-
if (!this.config.checkpoints.enabled) {
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
|
-
return iteration % this.config.checkpoints.frequency === 0;
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Generate checkpoint ID
|
|
299
|
-
*/
|
|
300
|
-
generateCheckpointId() {
|
|
301
|
-
return `chk-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Capture current state
|
|
305
|
-
*/
|
|
306
|
-
async captureCurrentState() {
|
|
307
|
-
return {
|
|
308
|
-
loopId: "current",
|
|
309
|
-
task: "",
|
|
310
|
-
criteria: "",
|
|
311
|
-
iteration: this.currentIteration?.number || 0,
|
|
312
|
-
status: "running",
|
|
313
|
-
startTime: Date.now(),
|
|
314
|
-
lastUpdateTime: Date.now()
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Get current git commit
|
|
319
|
-
*/
|
|
320
|
-
async getCurrentGitCommit() {
|
|
321
|
-
try {
|
|
322
|
-
return execSync("git rev-parse HEAD", { encoding: "utf8" }).trim();
|
|
323
|
-
} catch {
|
|
324
|
-
return "";
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Verify checkpoint integrity
|
|
329
|
-
*/
|
|
330
|
-
async verifyCheckpoint(checkpoint) {
|
|
331
|
-
try {
|
|
332
|
-
if (!checkpoint.state.loopId || !checkpoint.state.task) {
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
if (checkpoint.gitCommit) {
|
|
336
|
-
execSync(`git rev-parse ${checkpoint.gitCommit}`, { encoding: "utf8" });
|
|
337
|
-
}
|
|
338
|
-
return true;
|
|
339
|
-
} catch {
|
|
340
|
-
return false;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Clean old checkpoints based on retention
|
|
345
|
-
*/
|
|
346
|
-
async cleanOldCheckpoints() {
|
|
347
|
-
const cutoff = Date.now() - this.config.checkpoints.retentionDays * 24 * 60 * 60 * 1e3;
|
|
348
|
-
const before = this.checkpoints.length;
|
|
349
|
-
this.checkpoints = this.checkpoints.filter((c) => c.timestamp >= cutoff);
|
|
350
|
-
const removed = before - this.checkpoints.length;
|
|
351
|
-
if (removed > 0) {
|
|
352
|
-
logger.debug("Cleaned old checkpoints", { removed });
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Create final checkpoint
|
|
357
|
-
*/
|
|
358
|
-
async createFinalCheckpoint(state) {
|
|
359
|
-
const checkpoint = {
|
|
360
|
-
id: `final-${this.generateCheckpointId()}`,
|
|
361
|
-
iteration: state.iteration,
|
|
362
|
-
timestamp: Date.now(),
|
|
363
|
-
state,
|
|
364
|
-
gitCommit: await this.getCurrentGitCommit(),
|
|
365
|
-
verified: true
|
|
366
|
-
};
|
|
367
|
-
this.checkpoints.push(checkpoint);
|
|
368
|
-
logger.info("Final checkpoint created", {
|
|
369
|
-
id: checkpoint.id,
|
|
370
|
-
iterations: state.iteration
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* Restore git state
|
|
375
|
-
*/
|
|
376
|
-
async restoreGitState(commit) {
|
|
377
|
-
execSync("git stash", { encoding: "utf8" });
|
|
378
|
-
execSync(`git checkout ${commit}`, { encoding: "utf8" });
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Restore Ralph state
|
|
382
|
-
*/
|
|
383
|
-
async restoreRalphState(state) {
|
|
384
|
-
logger.debug("Ralph state restored", { iteration: state.iteration });
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* Detect state changes
|
|
388
|
-
*/
|
|
389
|
-
detectStateChanges(oldState, newState) {
|
|
390
|
-
const changes = [];
|
|
391
|
-
for (const key of Object.keys(newState)) {
|
|
392
|
-
if (JSON.stringify(oldState[key]) !== JSON.stringify(newState[key])) {
|
|
393
|
-
changes.push(key);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
return changes;
|
|
397
|
-
}
|
|
398
|
-
/**
|
|
399
|
-
* Handle errors
|
|
400
|
-
*/
|
|
401
|
-
async handleError(error, context) {
|
|
402
|
-
logger.error("Lifecycle error", {
|
|
403
|
-
error: error.message,
|
|
404
|
-
context
|
|
405
|
-
});
|
|
406
|
-
if (this.config.hooks.onError && this.hooks.onError) {
|
|
407
|
-
try {
|
|
408
|
-
await this.hooks.onError(error, context);
|
|
409
|
-
} catch (hookError) {
|
|
410
|
-
logger.error("Error hook failed", { error: hookError.message });
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
/**
|
|
415
|
-
* Start timer for metrics
|
|
416
|
-
*/
|
|
417
|
-
startTimer(name) {
|
|
418
|
-
const start = Date.now();
|
|
419
|
-
const timeout = setTimeout(() => {
|
|
420
|
-
this.activeTimers.delete(name);
|
|
421
|
-
}, 0);
|
|
422
|
-
timeout.startTime = start;
|
|
423
|
-
this.activeTimers.set(name, timeout);
|
|
424
|
-
}
|
|
425
|
-
/**
|
|
426
|
-
* Stop timer and get duration
|
|
427
|
-
*/
|
|
428
|
-
stopTimer(name) {
|
|
429
|
-
const timer = this.activeTimers.get(name);
|
|
430
|
-
if (!timer) return 0;
|
|
431
|
-
const duration = Date.now() - (timer.startTime || Date.now());
|
|
432
|
-
clearTimeout(timer);
|
|
433
|
-
this.activeTimers.delete(name);
|
|
434
|
-
return duration;
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* Clean up all timers
|
|
438
|
-
*/
|
|
439
|
-
cleanupTimers() {
|
|
440
|
-
for (const timer of this.activeTimers.values()) {
|
|
441
|
-
clearTimeout(timer);
|
|
442
|
-
}
|
|
443
|
-
this.activeTimers.clear();
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
export {
|
|
447
|
-
IterationLifecycle
|
|
448
|
-
};
|