@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.
Files changed (162) hide show
  1. package/LICENSE +131 -64
  2. package/README.md +3 -1
  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/codex-sm.js +51 -11
  11. package/dist/src/cli/commands/brain.js +206 -0
  12. package/dist/src/cli/commands/company-os.js +184 -0
  13. package/dist/src/cli/commands/context.js +5 -0
  14. package/dist/src/cli/commands/operator.js +127 -0
  15. package/dist/src/cli/commands/orchestrate.js +2 -0
  16. package/dist/src/cli/commands/orchestrator.js +3 -2
  17. package/dist/src/cli/commands/patterns.js +254 -0
  18. package/dist/src/cli/commands/portal.js +161 -0
  19. package/dist/src/cli/commands/scaffold.js +92 -0
  20. package/dist/src/cli/commands/setup.js +1 -4
  21. package/dist/src/cli/commands/sync.js +253 -0
  22. package/dist/src/cli/commands/tasks.js +130 -1
  23. package/dist/src/cli/commands/vision.js +221 -0
  24. package/dist/src/cli/hermes-sm.js +224 -0
  25. package/dist/src/cli/index.js +15 -10
  26. package/dist/src/cli/utils/real-cli-bin.js +72 -0
  27. package/dist/src/core/brain/brain-store.js +187 -0
  28. package/dist/src/core/brain/brain-sync.js +193 -0
  29. package/dist/src/core/brain/index.js +78 -0
  30. package/dist/src/core/brain/types.js +10 -0
  31. package/dist/src/core/cache/token-estimator.js +24 -1
  32. package/dist/src/core/config/feature-flags.js +2 -6
  33. package/dist/src/core/context/frame-database.js +44 -0
  34. package/dist/src/core/context/recursive-context-manager.js +1 -1
  35. package/dist/src/core/context/rehydration.js +2 -1
  36. package/dist/src/core/database/sqlite-adapter.js +14 -1
  37. package/dist/src/core/models/model-router.js +33 -1
  38. package/dist/src/core/models/provider-pricing.js +58 -4
  39. package/dist/src/core/patterns/index.js +22 -0
  40. package/dist/src/core/patterns/pattern-applier.js +39 -0
  41. package/dist/src/core/patterns/pattern-observer.js +157 -0
  42. package/dist/src/core/patterns/pattern-store.js +259 -0
  43. package/dist/src/core/patterns/types.js +19 -0
  44. package/dist/src/core/retrieval/llm-context-retrieval.js +5 -4
  45. package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
  46. package/dist/src/core/skill-packs/types.js +14 -1
  47. package/dist/src/core/storage/cloud-sync-manager.js +116 -0
  48. package/dist/src/core/storage/cloud-sync.js +574 -0
  49. package/dist/src/core/storage/two-tier-storage.js +5 -1
  50. package/dist/src/core/tasks/master-tasks-template.js +43 -0
  51. package/dist/src/core/tasks/md-task-parser.js +138 -0
  52. package/dist/src/core/vision/index.js +27 -0
  53. package/dist/src/core/vision/signals.js +79 -0
  54. package/dist/src/core/vision/types.js +22 -0
  55. package/dist/src/core/vision/vision-file.js +146 -0
  56. package/dist/src/core/vision/vision-loop.js +220 -0
  57. package/dist/src/core/wiki/wiki-compiler.js +103 -1
  58. package/dist/src/daemon/daemon-config.js +45 -0
  59. package/dist/src/daemon/services/desire-path-service.js +566 -0
  60. package/dist/src/daemon/services/research-stream-service.js +320 -0
  61. package/dist/src/daemon/services/telemetry-service.js +192 -0
  62. package/dist/src/daemon/unified-daemon.js +28 -1
  63. package/dist/src/features/browser/cli-browser-agent.js +417 -0
  64. package/dist/src/features/browser/stagehand-workflows.js +578 -0
  65. package/dist/src/features/operator/adapter-factory.js +62 -0
  66. package/dist/src/features/operator/browser-adapter.js +109 -0
  67. package/dist/src/features/operator/desktop-adapter.js +125 -0
  68. package/dist/src/features/operator/index.js +39 -0
  69. package/dist/src/features/operator/llm-decision.js +137 -0
  70. package/dist/src/features/operator/operator-logger.js +92 -0
  71. package/dist/src/features/operator/overnight-runner.js +327 -0
  72. package/dist/src/features/operator/screen-adapter.js +91 -0
  73. package/dist/src/features/operator/session-manager.js +127 -0
  74. package/dist/src/features/operator/state-machine.js +227 -0
  75. package/dist/src/features/operator/task-queue.js +81 -0
  76. package/dist/src/features/portal/index.js +26 -0
  77. package/dist/src/features/portal/server.js +240 -0
  78. package/dist/src/features/portal/types.js +14 -0
  79. package/dist/src/features/portal/ui.js +195 -0
  80. package/dist/src/features/tasks/task-aware-context.js +2 -1
  81. package/dist/src/features/tui/simple-monitor.js +0 -23
  82. package/dist/src/features/tui/swarm-monitor.js +8 -66
  83. package/dist/src/{integrations/diffmem/index.js → features/web/client/hooks/use-socket.js} +6 -5
  84. package/dist/src/features/web/client/lib/utils.js +12 -0
  85. package/dist/src/features/web/client/stores/session-store.js +12 -0
  86. package/dist/src/features/web/server/gcp-billing.js +76 -0
  87. package/dist/src/features/web/server/index.js +10 -0
  88. package/dist/src/features/web/server/spend-calculator.js +228 -0
  89. package/dist/src/hooks/schemas.js +4 -1
  90. package/dist/src/integrations/anthropic/client.js +3 -2
  91. package/dist/src/integrations/claude-code/agent-bridge.js +0 -3
  92. package/dist/src/integrations/claude-code/subagent-client.js +218 -11
  93. package/dist/src/integrations/claude-code/task-coordinator.js +2 -1
  94. package/dist/src/integrations/linear/webhook-retry.js +196 -0
  95. package/dist/src/integrations/linear/webhook-server.js +18 -22
  96. package/dist/src/integrations/mcp/handlers/cloud-sync-handlers.js +101 -0
  97. package/dist/src/integrations/mcp/handlers/index.js +27 -52
  98. package/dist/src/integrations/mcp/server.js +122 -335
  99. package/dist/src/integrations/mcp/tool-alias-registry.js +0 -73
  100. package/dist/src/integrations/mcp/tool-definitions.js +111 -510
  101. package/dist/src/mcp/stackmemory-mcp-server.js +404 -379
  102. package/dist/src/orchestrators/multimodal/determinism.js +2 -1
  103. package/dist/src/orchestrators/multimodal/harness.js +2 -1
  104. package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
  105. package/dist/src/utils/process-cleanup.js +1 -7
  106. package/docs/README.md +42 -0
  107. package/docs/guides/README_INSTALL.md +208 -0
  108. package/package.json +18 -9
  109. package/scripts/claude-code-wrapper.sh +11 -0
  110. package/scripts/claude-sm-setup.sh +12 -1
  111. package/scripts/codex-wrapper.sh +11 -0
  112. package/scripts/git-hooks/branch-context-manager.sh +11 -0
  113. package/scripts/git-hooks/post-checkout-stackmemory.sh +11 -0
  114. package/scripts/git-hooks/post-commit-stackmemory.sh +11 -0
  115. package/scripts/git-hooks/pre-commit-stackmemory.sh +11 -0
  116. package/scripts/hooks/cleanup-shell.sh +12 -1
  117. package/scripts/hooks/task-complete.sh +12 -1
  118. package/scripts/install-code-execution-hooks.sh +12 -1
  119. package/scripts/install-sweep-hook.sh +12 -0
  120. package/scripts/install.sh +11 -0
  121. package/scripts/opencode-wrapper.sh +11 -0
  122. package/scripts/portal/cloud-init.yaml +69 -0
  123. package/scripts/portal/setup.sh +69 -0
  124. package/scripts/portal/stackmemory-portal.service +34 -0
  125. package/scripts/setup-claude-integration.sh +12 -1
  126. package/scripts/smoke-init-db.sh +23 -0
  127. package/scripts/stackmemory-daemon.sh +11 -0
  128. package/scripts/verify-dist.cjs +11 -4
  129. package/dist/src/cli/commands/ralph.js +0 -1053
  130. package/dist/src/hooks/diffmem-hooks.js +0 -376
  131. package/dist/src/integrations/diffmem/client.js +0 -208
  132. package/dist/src/integrations/diffmem/config.js +0 -14
  133. package/dist/src/integrations/greptile/client.js +0 -101
  134. package/dist/src/integrations/greptile/config.js +0 -14
  135. package/dist/src/integrations/greptile/index.js +0 -11
  136. package/dist/src/integrations/mcp/handlers/cross-search-handlers.js +0 -188
  137. package/dist/src/integrations/mcp/handlers/diffmem-handlers.js +0 -455
  138. package/dist/src/integrations/mcp/handlers/greptile-handlers.js +0 -456
  139. package/dist/src/integrations/mcp/handlers/provider-handlers.js +0 -227
  140. package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -863
  141. package/dist/src/integrations/ralph/context/context-budget-manager.js +0 -308
  142. package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +0 -354
  143. package/dist/src/integrations/ralph/index.js +0 -17
  144. package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -416
  145. package/dist/src/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
  146. package/dist/src/integrations/ralph/loopmax.js +0 -488
  147. package/dist/src/integrations/ralph/monitoring/swarm-dashboard.js +0 -293
  148. package/dist/src/integrations/ralph/monitoring/swarm-registry.js +0 -107
  149. package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -508
  150. package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -407
  151. package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +0 -495
  152. package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +0 -387
  153. package/dist/src/integrations/ralph/performance/performance-optimizer.js +0 -357
  154. package/dist/src/integrations/ralph/recovery/crash-recovery.js +0 -461
  155. package/dist/src/integrations/ralph/state/state-reconciler.js +0 -420
  156. package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +0 -444
  157. package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -1005
  158. package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
  159. package/scripts/ralph-loop-implementation.js +0 -404
  160. /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
  161. /package/dist/src/{integrations/greptile → features/operator}/types.js +0 -0
  162. /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
- };