@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,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
- };