@bike4mind/cli 0.2.64-worktree-refactor-extract-search-query-builders.21815 → 0.2.64
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/bin/bike4mind-cli.mjs +6 -6
- package/dist/BubblewrapRuntime-BHbtqvLx.mjs +72 -0
- package/dist/ConfigStore-CllM6jOf.mjs +8614 -0
- package/dist/ImageStore-DaKT_Ew8.mjs +202 -0
- package/dist/ProxyManager-Dl2nFk-A.mjs +259 -0
- package/dist/ProxyManager-kiOD1X8-.mjs +3 -0
- package/dist/SandboxOrchestrator-BEW3rqYi.mjs +159 -0
- package/dist/SandboxOrchestrator-CHZgSR3P.mjs +3 -0
- package/dist/SandboxRuntimeAdapter-C1B4t20N.mjs +57 -0
- package/dist/SandboxRuntimeAdapter-D7UAG13n.mjs +3 -0
- package/dist/SeatbeltRuntime-D4m0VOcD.mjs +116 -0
- package/dist/StderrViolationParser-D0afQ3-1.mjs +70 -0
- package/dist/ViolationLogStore-CZl35HcA.mjs +96 -0
- package/dist/bashExecute-BTkdqlSs-5foM20Lb.mjs +466 -0
- package/dist/commands/doctorCommand.mjs +101 -0
- package/dist/commands/headlessCommand.mjs +319 -0
- package/dist/commands/mcpCommand.mjs +218 -0
- package/dist/commands/updateCommand.mjs +40 -0
- package/dist/createFile-yQfh8uvk-I-yM5DxC.mjs +63 -0
- package/dist/deleteFile-DKHfnyny-G3b1Kj2T.mjs +66 -0
- package/dist/globFiles-D1en6joM-8jekiXdX.mjs +100 -0
- package/dist/grepSearch-aMamoBn_-DCJcY8JS.mjs +173 -0
- package/dist/index.mjs +6722 -0
- package/dist/pathValidation-Cgjh5WQO-DiCZTcq6.mjs +63 -0
- package/dist/store-Dw1nZX2Y.mjs +128 -0
- package/dist/store-nZExNOWX.mjs +3 -0
- package/dist/terminalSetup-rmr1P8KF.mjs +254 -0
- package/dist/tools-C6M5aW8W.mjs +20907 -0
- package/dist/treeSitterEngine-DCSXcm_3.mjs +309 -0
- package/dist/types-DBEjF9YS.mjs +59 -0
- package/dist/types-DK3P88Px.mjs +3 -0
- package/dist/updateChecker-Cu9dkHxV.mjs +120 -0
- package/package.json +10 -10
- package/dist/BubblewrapRuntime-PMIOLWKR.js +0 -71
- package/dist/HydrationEngine-YL2HWJ3V.js +0 -9
- package/dist/ImageStore-MMUOUPI2.js +0 -224
- package/dist/ProxyManager-HEB4TLVX.js +0 -7
- package/dist/SandboxOrchestrator-UIJ5GYBB.js +0 -8
- package/dist/SandboxRuntimeAdapter-FQ56MAB2.js +0 -13
- package/dist/SeatbeltRuntime-EE3TTLEP.js +0 -98
- package/dist/StderrViolationParser-7OYPM2DJ.js +0 -59
- package/dist/ViolationLogStore-RIIUVURH.js +0 -104
- package/dist/artifactExtractor-R7DIP2XO.js +0 -180
- package/dist/bashExecute-GLGLD3JD.js +0 -379
- package/dist/chunk-4BIBE3J7.js +0 -48
- package/dist/chunk-5LZS5CVJ.js +0 -161
- package/dist/chunk-BDQBOLYG.js +0 -120
- package/dist/chunk-BPFEGDC7.js +0 -192
- package/dist/chunk-EPIYC3LA.js +0 -13770
- package/dist/chunk-G4ZGEQFT.js +0 -250
- package/dist/chunk-GQGOWACU.js +0 -770
- package/dist/chunk-J6ZBI6TI.js +0 -1079
- package/dist/chunk-JW3JRHH7.js +0 -12433
- package/dist/chunk-KQAMBXAW.js +0 -163
- package/dist/chunk-KUVV2NAB.js +0 -19125
- package/dist/chunk-LTLJRF6I.js +0 -44
- package/dist/chunk-PFBYGCOW.js +0 -449
- package/dist/chunk-QWB6ZYY4.js +0 -48
- package/dist/chunk-SGPRXN4C.js +0 -245
- package/dist/chunk-UZUHPHZC.js +0 -95
- package/dist/chunk-WBE7SQUB.js +0 -241
- package/dist/chunk-Y4WOJJM3.js +0 -147
- package/dist/commands/doctorCommand.js +0 -87
- package/dist/commands/headlessCommand.js +0 -380
- package/dist/commands/mcpCommand.js +0 -203
- package/dist/commands/updateCommand.js +0 -42
- package/dist/create-C4VEEEYR.js +0 -12
- package/dist/createFile-6PSPLW6R.js +0 -71
- package/dist/deleteFile-AUSRLWIK.js +0 -73
- package/dist/formatConverter-5QEJDW24.js +0 -7
- package/dist/globFiles-TSRN64N2.js +0 -120
- package/dist/grepSearch-634XWZOJ.js +0 -216
- package/dist/index.js +0 -6779
- package/dist/llmMarkdownGenerator-Z6NB26TT.js +0 -371
- package/dist/markdownGenerator-SK2ZQQL4.js +0 -269
- package/dist/mementoService-N4IM6QAC.js +0 -12
- package/dist/notificationDeduplicator-HUC53NEW.js +0 -9
- package/dist/src-F4KZCAA2.js +0 -319
- package/dist/src-ISX322I7.js +0 -1101
- package/dist/store-CAB6BV3P.js +0 -11
- package/dist/subtractCredits-D4KEM6VU.js +0 -12
- package/dist/terminalSetup-C5FHMLC3.js +0 -214
- package/dist/treeSitterEngine-4SGFQDY3.js +0 -330
- package/dist/types-KB5NP6T4.js +0 -7
- package/dist/utils-JCHWDM4Z.js +0 -31
package/dist/chunk-GQGOWACU.js
DELETED
|
@@ -1,770 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// ../../b4m-core/packages/services/dist/src/latticeService/DependencyTracker.js
|
|
4
|
-
var DependencyTracker = class {
|
|
5
|
-
constructor() {
|
|
6
|
-
this.nodes = /* @__PURE__ */ new Map();
|
|
7
|
-
this.topologicalOrder = null;
|
|
8
|
-
this.hasChanges = true;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Build the dependency graph from a rules store
|
|
12
|
-
*/
|
|
13
|
-
build(rulesStore) {
|
|
14
|
-
this.nodes.clear();
|
|
15
|
-
this.topologicalOrder = null;
|
|
16
|
-
this.hasChanges = true;
|
|
17
|
-
for (const rule of rulesStore.rules) {
|
|
18
|
-
if (!rule.enabled)
|
|
19
|
-
continue;
|
|
20
|
-
this.nodes.set(rule.id, {
|
|
21
|
-
ruleId: rule.id,
|
|
22
|
-
dependencies: new Set(rule.dependencies),
|
|
23
|
-
dependents: /* @__PURE__ */ new Set()
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
for (const node of this.nodes.values()) {
|
|
27
|
-
for (const depId of node.dependencies) {
|
|
28
|
-
const depNode = this.nodes.get(depId);
|
|
29
|
-
if (depNode) {
|
|
30
|
-
depNode.dependents.add(node.ruleId);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Add a single rule to the graph
|
|
37
|
-
*/
|
|
38
|
-
addRule(rule) {
|
|
39
|
-
if (!rule.enabled)
|
|
40
|
-
return;
|
|
41
|
-
this.nodes.set(rule.id, {
|
|
42
|
-
ruleId: rule.id,
|
|
43
|
-
dependencies: new Set(rule.dependencies),
|
|
44
|
-
dependents: /* @__PURE__ */ new Set()
|
|
45
|
-
});
|
|
46
|
-
for (const depId of rule.dependencies) {
|
|
47
|
-
const depNode = this.nodes.get(depId);
|
|
48
|
-
if (depNode) {
|
|
49
|
-
depNode.dependents.add(rule.id);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
this.hasChanges = true;
|
|
53
|
-
this.topologicalOrder = null;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Remove a rule from the graph
|
|
57
|
-
*/
|
|
58
|
-
removeRule(ruleId) {
|
|
59
|
-
const node = this.nodes.get(ruleId);
|
|
60
|
-
if (!node)
|
|
61
|
-
return;
|
|
62
|
-
for (const depId of node.dependencies) {
|
|
63
|
-
const depNode = this.nodes.get(depId);
|
|
64
|
-
if (depNode) {
|
|
65
|
-
depNode.dependents.delete(ruleId);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
for (const dependentId of node.dependents) {
|
|
69
|
-
const dependentNode = this.nodes.get(dependentId);
|
|
70
|
-
if (dependentNode) {
|
|
71
|
-
dependentNode.dependencies.delete(ruleId);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
this.nodes.delete(ruleId);
|
|
75
|
-
this.hasChanges = true;
|
|
76
|
-
this.topologicalOrder = null;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Update dependencies for a rule
|
|
80
|
-
*/
|
|
81
|
-
updateDependencies(ruleId, newDependencies) {
|
|
82
|
-
const node = this.nodes.get(ruleId);
|
|
83
|
-
if (!node)
|
|
84
|
-
return;
|
|
85
|
-
for (const oldDepId of node.dependencies) {
|
|
86
|
-
const oldDepNode = this.nodes.get(oldDepId);
|
|
87
|
-
if (oldDepNode) {
|
|
88
|
-
oldDepNode.dependents.delete(ruleId);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
node.dependencies = new Set(newDependencies);
|
|
92
|
-
for (const newDepId of newDependencies) {
|
|
93
|
-
const newDepNode = this.nodes.get(newDepId);
|
|
94
|
-
if (newDepNode) {
|
|
95
|
-
newDepNode.dependents.add(ruleId);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
this.hasChanges = true;
|
|
99
|
-
this.topologicalOrder = null;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Validate the dependency graph for cycles
|
|
103
|
-
*/
|
|
104
|
-
validate() {
|
|
105
|
-
const errors = [];
|
|
106
|
-
const cycles = [];
|
|
107
|
-
const visited = /* @__PURE__ */ new Set();
|
|
108
|
-
const recursionStack = /* @__PURE__ */ new Set();
|
|
109
|
-
const path = [];
|
|
110
|
-
const dfs = (ruleId) => {
|
|
111
|
-
visited.add(ruleId);
|
|
112
|
-
recursionStack.add(ruleId);
|
|
113
|
-
path.push(ruleId);
|
|
114
|
-
try {
|
|
115
|
-
const node = this.nodes.get(ruleId);
|
|
116
|
-
if (node) {
|
|
117
|
-
for (const depId of node.dependencies) {
|
|
118
|
-
if (!visited.has(depId)) {
|
|
119
|
-
dfs(depId);
|
|
120
|
-
} else if (recursionStack.has(depId)) {
|
|
121
|
-
const cycleStart = path.indexOf(depId);
|
|
122
|
-
const cycle = [...path.slice(cycleStart), depId];
|
|
123
|
-
cycles.push(cycle);
|
|
124
|
-
errors.push({
|
|
125
|
-
type: "CIRCULAR_DEPENDENCY",
|
|
126
|
-
message: `Circular dependency detected: ${cycle.join(" \u2192 ")}`,
|
|
127
|
-
context: {
|
|
128
|
-
relatedRules: cycle
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
} finally {
|
|
135
|
-
path.pop();
|
|
136
|
-
recursionStack.delete(ruleId);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
for (const ruleId of this.nodes.keys()) {
|
|
140
|
-
if (!visited.has(ruleId)) {
|
|
141
|
-
dfs(ruleId);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return {
|
|
145
|
-
isValid: cycles.length === 0,
|
|
146
|
-
errors,
|
|
147
|
-
cycles
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Get topological order for computation (dependencies before dependents)
|
|
152
|
-
*/
|
|
153
|
-
getComputationOrder() {
|
|
154
|
-
if (this.topologicalOrder && !this.hasChanges) {
|
|
155
|
-
return this.topologicalOrder;
|
|
156
|
-
}
|
|
157
|
-
const inDegree = /* @__PURE__ */ new Map();
|
|
158
|
-
const queue = [];
|
|
159
|
-
const result = [];
|
|
160
|
-
for (const [ruleId, node] of this.nodes) {
|
|
161
|
-
inDegree.set(ruleId, node.dependencies.size);
|
|
162
|
-
if (node.dependencies.size === 0) {
|
|
163
|
-
queue.push(ruleId);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
let qi = 0;
|
|
167
|
-
while (qi < queue.length) {
|
|
168
|
-
const ruleId = queue[qi++];
|
|
169
|
-
result.push(ruleId);
|
|
170
|
-
const node = this.nodes.get(ruleId);
|
|
171
|
-
if (node) {
|
|
172
|
-
for (const dependentId of node.dependents) {
|
|
173
|
-
const degree = inDegree.get(dependentId) - 1;
|
|
174
|
-
inDegree.set(dependentId, degree);
|
|
175
|
-
if (degree === 0) {
|
|
176
|
-
queue.push(dependentId);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
if (result.length !== this.nodes.size) {
|
|
182
|
-
console.warn("Dependency graph contains cycles; returning partial order");
|
|
183
|
-
}
|
|
184
|
-
this.topologicalOrder = result;
|
|
185
|
-
this.hasChanges = false;
|
|
186
|
-
return result;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Get all rules affected by changes to a specific rule
|
|
190
|
-
*/
|
|
191
|
-
getAffectedBy(ruleId) {
|
|
192
|
-
const node = this.nodes.get(ruleId);
|
|
193
|
-
if (!node) {
|
|
194
|
-
return { directlyAffected: [], transitivelyAffected: [] };
|
|
195
|
-
}
|
|
196
|
-
const directlyAffected = Array.from(node.dependents);
|
|
197
|
-
const transitivelyAffected = /* @__PURE__ */ new Set();
|
|
198
|
-
const queue = [...directlyAffected];
|
|
199
|
-
while (queue.length > 0) {
|
|
200
|
-
const currentId = queue.shift();
|
|
201
|
-
if (transitivelyAffected.has(currentId))
|
|
202
|
-
continue;
|
|
203
|
-
transitivelyAffected.add(currentId);
|
|
204
|
-
const currentNode = this.nodes.get(currentId);
|
|
205
|
-
if (currentNode) {
|
|
206
|
-
for (const dependentId of currentNode.dependents) {
|
|
207
|
-
if (!transitivelyAffected.has(dependentId)) {
|
|
208
|
-
queue.push(dependentId);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return {
|
|
214
|
-
directlyAffected,
|
|
215
|
-
transitivelyAffected: Array.from(transitivelyAffected)
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Get direct dependencies of a rule
|
|
220
|
-
*/
|
|
221
|
-
getDependencies(ruleId) {
|
|
222
|
-
const node = this.nodes.get(ruleId);
|
|
223
|
-
return node ? Array.from(node.dependencies) : [];
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Get direct dependents of a rule
|
|
227
|
-
*/
|
|
228
|
-
getDependents(ruleId) {
|
|
229
|
-
const node = this.nodes.get(ruleId);
|
|
230
|
-
return node ? Array.from(node.dependents) : [];
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Check if adding a dependency would create a cycle
|
|
234
|
-
*/
|
|
235
|
-
wouldCreateCycle(fromRuleId, toRuleId) {
|
|
236
|
-
const visited = /* @__PURE__ */ new Set();
|
|
237
|
-
const queue = [toRuleId];
|
|
238
|
-
while (queue.length > 0) {
|
|
239
|
-
const currentId = queue.shift();
|
|
240
|
-
if (currentId === fromRuleId)
|
|
241
|
-
return true;
|
|
242
|
-
if (visited.has(currentId))
|
|
243
|
-
continue;
|
|
244
|
-
visited.add(currentId);
|
|
245
|
-
const node = this.nodes.get(currentId);
|
|
246
|
-
if (node) {
|
|
247
|
-
for (const depId of node.dependencies) {
|
|
248
|
-
if (!visited.has(depId)) {
|
|
249
|
-
queue.push(depId);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Get all rule IDs in the graph
|
|
258
|
-
*/
|
|
259
|
-
getAllRuleIds() {
|
|
260
|
-
return Array.from(this.nodes.keys());
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Get the number of rules in the graph
|
|
264
|
-
*/
|
|
265
|
-
size() {
|
|
266
|
-
return this.nodes.size;
|
|
267
|
-
}
|
|
268
|
-
/**
|
|
269
|
-
* Clear the entire graph
|
|
270
|
-
*/
|
|
271
|
-
clear() {
|
|
272
|
-
this.nodes.clear();
|
|
273
|
-
this.topologicalOrder = null;
|
|
274
|
-
this.hasChanges = true;
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Export graph for debugging/visualization
|
|
278
|
-
*/
|
|
279
|
-
toDebugString() {
|
|
280
|
-
const lines = ["Dependency Graph:"];
|
|
281
|
-
for (const [ruleId, node] of this.nodes) {
|
|
282
|
-
const deps = Array.from(node.dependencies).join(", ") || "(none)";
|
|
283
|
-
const dependents = Array.from(node.dependents).join(", ") || "(none)";
|
|
284
|
-
lines.push(` ${ruleId}:`);
|
|
285
|
-
lines.push(` depends on: ${deps}`);
|
|
286
|
-
lines.push(` depended by: ${dependents}`);
|
|
287
|
-
}
|
|
288
|
-
return lines.join("\n");
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
function createDependencyTracker(rulesStore) {
|
|
292
|
-
const tracker = new DependencyTracker();
|
|
293
|
-
if (rulesStore) {
|
|
294
|
-
tracker.build(rulesStore);
|
|
295
|
-
}
|
|
296
|
-
return tracker;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// ../../b4m-core/packages/services/dist/src/latticeService/HydrationEngine.js
|
|
300
|
-
var HydrationEngine = class {
|
|
301
|
-
constructor() {
|
|
302
|
-
this.dependencyTracker = createDependencyTracker();
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Hydrate (compute) all values from data and rules
|
|
306
|
-
*/
|
|
307
|
-
hydrate(data, rules, options = {}) {
|
|
308
|
-
const startTime = performance.now();
|
|
309
|
-
const errors = [];
|
|
310
|
-
this.dependencyTracker.build(rules);
|
|
311
|
-
const validation = this.dependencyTracker.validate();
|
|
312
|
-
if (!validation.isValid) {
|
|
313
|
-
return {
|
|
314
|
-
values: {},
|
|
315
|
-
errors: validation.errors,
|
|
316
|
-
duration: performance.now() - startTime,
|
|
317
|
-
rulesEvaluated: 0
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
const computedValues = this.initializeFromData(data, options.scenario);
|
|
321
|
-
const context = {
|
|
322
|
-
data,
|
|
323
|
-
rules,
|
|
324
|
-
computedValues,
|
|
325
|
-
scenario: options.scenario,
|
|
326
|
-
errors
|
|
327
|
-
};
|
|
328
|
-
let ruleOrder = this.dependencyTracker.getComputationOrder();
|
|
329
|
-
if (options.partialRuleIds && options.partialRuleIds.length > 0) {
|
|
330
|
-
const neededRules = this.getNeededRules(options.partialRuleIds);
|
|
331
|
-
ruleOrder = ruleOrder.filter((id) => neededRules.has(id));
|
|
332
|
-
}
|
|
333
|
-
let rulesEvaluated = 0;
|
|
334
|
-
for (const ruleId of ruleOrder) {
|
|
335
|
-
const rule = rules.rules.find((r) => r.id === ruleId);
|
|
336
|
-
if (!rule || !rule.enabled)
|
|
337
|
-
continue;
|
|
338
|
-
try {
|
|
339
|
-
this.evaluateRule(rule, context);
|
|
340
|
-
rulesEvaluated++;
|
|
341
|
-
} catch (error) {
|
|
342
|
-
errors.push({
|
|
343
|
-
type: "INVALID_OPERATION",
|
|
344
|
-
message: `Error evaluating rule "${rule.name}": ${error instanceof Error ? error.message : String(error)}`,
|
|
345
|
-
context: { relatedRules: [ruleId] }
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
return {
|
|
350
|
-
values: computedValues,
|
|
351
|
-
errors,
|
|
352
|
-
duration: performance.now() - startTime,
|
|
353
|
-
rulesEvaluated
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* Initialize computed values from base data (including scenario overrides)
|
|
358
|
-
*/
|
|
359
|
-
initializeFromData(data, scenario) {
|
|
360
|
-
const values = {};
|
|
361
|
-
for (const entity of data.entities) {
|
|
362
|
-
values[entity.id] = {};
|
|
363
|
-
for (const attr of entity.attributes) {
|
|
364
|
-
if (!attr.isComputed) {
|
|
365
|
-
values[entity.id][attr.key] = {
|
|
366
|
-
value: attr.value,
|
|
367
|
-
computedByRuleId: "base",
|
|
368
|
-
computedAt: /* @__PURE__ */ new Date()
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
if (scenario) {
|
|
374
|
-
for (const override of scenario.overrides) {
|
|
375
|
-
if (!values[override.entityId]) {
|
|
376
|
-
values[override.entityId] = {};
|
|
377
|
-
}
|
|
378
|
-
values[override.entityId][override.attributeKey] = {
|
|
379
|
-
value: override.value,
|
|
380
|
-
computedByRuleId: `scenario:${scenario.id}`,
|
|
381
|
-
computedAt: /* @__PURE__ */ new Date()
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
return values;
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Get all rules needed to compute the given rules (including dependencies)
|
|
389
|
-
*/
|
|
390
|
-
getNeededRules(ruleIds) {
|
|
391
|
-
const needed = /* @__PURE__ */ new Set();
|
|
392
|
-
const addWithDependencies = (ruleId) => {
|
|
393
|
-
if (needed.has(ruleId))
|
|
394
|
-
return;
|
|
395
|
-
needed.add(ruleId);
|
|
396
|
-
const deps = this.dependencyTracker.getDependencies(ruleId);
|
|
397
|
-
for (const depId of deps) {
|
|
398
|
-
addWithDependencies(depId);
|
|
399
|
-
}
|
|
400
|
-
};
|
|
401
|
-
for (const ruleId of ruleIds) {
|
|
402
|
-
addWithDependencies(ruleId);
|
|
403
|
-
}
|
|
404
|
-
return needed;
|
|
405
|
-
}
|
|
406
|
-
/**
|
|
407
|
-
* Evaluate a single rule and store results
|
|
408
|
-
*/
|
|
409
|
-
evaluateRule(rule, context) {
|
|
410
|
-
const { definition } = rule;
|
|
411
|
-
const inputValues = this.resolveInputs(definition.inputs, context);
|
|
412
|
-
if (definition.conditions && definition.conditions.length > 0) {
|
|
413
|
-
const conditionsMet = this.evaluateConditions(definition.conditions, context);
|
|
414
|
-
if (!conditionsMet)
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
const result = this.applyOperation(definition.operation, inputValues, context);
|
|
418
|
-
const { targetEntityId, targetAttribute } = definition.output;
|
|
419
|
-
if (!context.computedValues[targetEntityId]) {
|
|
420
|
-
context.computedValues[targetEntityId] = {};
|
|
421
|
-
}
|
|
422
|
-
context.computedValues[targetEntityId][targetAttribute] = {
|
|
423
|
-
value: result,
|
|
424
|
-
computedByRuleId: rule.id,
|
|
425
|
-
computedAt: /* @__PURE__ */ new Date()
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Resolve input references to actual values
|
|
430
|
-
*/
|
|
431
|
-
resolveInputs(inputs, context) {
|
|
432
|
-
const values = [];
|
|
433
|
-
for (const input of inputs) {
|
|
434
|
-
switch (input.type) {
|
|
435
|
-
case "literal":
|
|
436
|
-
values.push(this.parseLiteral(input.ref));
|
|
437
|
-
break;
|
|
438
|
-
case "attribute":
|
|
439
|
-
case "entity": {
|
|
440
|
-
const [entityId, attrKey] = input.selector ? [input.ref, input.selector] : input.ref.split(".");
|
|
441
|
-
const entityValues = context.computedValues[entityId];
|
|
442
|
-
if (entityValues && attrKey in entityValues) {
|
|
443
|
-
values.push(entityValues[attrKey].value);
|
|
444
|
-
} else {
|
|
445
|
-
values.push(null);
|
|
446
|
-
}
|
|
447
|
-
break;
|
|
448
|
-
}
|
|
449
|
-
case "rule": {
|
|
450
|
-
const rule = context.rules.rules.find((r) => r.id === input.ref);
|
|
451
|
-
if (rule) {
|
|
452
|
-
const { targetEntityId, targetAttribute } = rule.definition.output;
|
|
453
|
-
const entityValues = context.computedValues[targetEntityId];
|
|
454
|
-
if (entityValues && targetAttribute in entityValues) {
|
|
455
|
-
values.push(entityValues[targetAttribute].value);
|
|
456
|
-
} else {
|
|
457
|
-
values.push(null);
|
|
458
|
-
}
|
|
459
|
-
} else {
|
|
460
|
-
values.push(null);
|
|
461
|
-
}
|
|
462
|
-
break;
|
|
463
|
-
}
|
|
464
|
-
case "range": {
|
|
465
|
-
const rangeValues = this.resolveRange(input.ref, input.selector, context);
|
|
466
|
-
values.push(...rangeValues);
|
|
467
|
-
break;
|
|
468
|
-
}
|
|
469
|
-
default:
|
|
470
|
-
values.push(null);
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
return values;
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* Resolve a range reference to multiple values
|
|
477
|
-
*/
|
|
478
|
-
resolveRange(entityPattern, selector, context) {
|
|
479
|
-
const values = [];
|
|
480
|
-
if (entityPattern.includes("*")) {
|
|
481
|
-
for (const [entityId, entityValues] of Object.entries(context.computedValues)) {
|
|
482
|
-
if (this.matchesPattern(entityId, entityPattern)) {
|
|
483
|
-
if (selector === "*") {
|
|
484
|
-
values.push(...Object.values(entityValues).map((v) => v.value));
|
|
485
|
-
} else if (selector) {
|
|
486
|
-
if (selector in entityValues) {
|
|
487
|
-
values.push(entityValues[selector].value);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
} else {
|
|
493
|
-
const entityValues = context.computedValues[entityPattern];
|
|
494
|
-
if (entityValues) {
|
|
495
|
-
if (selector === "*") {
|
|
496
|
-
values.push(...Object.values(entityValues).map((v) => v.value));
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
return values;
|
|
501
|
-
}
|
|
502
|
-
/**
|
|
503
|
-
* Check if an entity ID matches a pattern
|
|
504
|
-
*/
|
|
505
|
-
matchesPattern(entityId, pattern) {
|
|
506
|
-
if (pattern === "*")
|
|
507
|
-
return true;
|
|
508
|
-
if (!pattern.includes("*"))
|
|
509
|
-
return entityId === pattern;
|
|
510
|
-
const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
|
|
511
|
-
return regex.test(entityId);
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* Parse a literal string to a value
|
|
515
|
-
*/
|
|
516
|
-
parseLiteral(value) {
|
|
517
|
-
const num = parseFloat(value);
|
|
518
|
-
if (!isNaN(num))
|
|
519
|
-
return num;
|
|
520
|
-
if (value.toLowerCase() === "true")
|
|
521
|
-
return true;
|
|
522
|
-
if (value.toLowerCase() === "false")
|
|
523
|
-
return false;
|
|
524
|
-
return value;
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* Evaluate rule conditions
|
|
528
|
-
*/
|
|
529
|
-
evaluateConditions(conditions, context) {
|
|
530
|
-
if (!conditions || conditions.length === 0)
|
|
531
|
-
return true;
|
|
532
|
-
let result = true;
|
|
533
|
-
let currentJoin;
|
|
534
|
-
for (const condition of conditions) {
|
|
535
|
-
const leftValue = this.resolveInputs([condition.left], context)[0];
|
|
536
|
-
const rightValue = this.resolveInputs([condition.right], context)[0];
|
|
537
|
-
const conditionResult = this.evaluateComparison(leftValue, condition.operator, rightValue);
|
|
538
|
-
if (currentJoin === "OR") {
|
|
539
|
-
result = result || conditionResult;
|
|
540
|
-
} else {
|
|
541
|
-
result = result && conditionResult;
|
|
542
|
-
}
|
|
543
|
-
currentJoin = condition.logicalJoin;
|
|
544
|
-
}
|
|
545
|
-
return result;
|
|
546
|
-
}
|
|
547
|
-
/**
|
|
548
|
-
* Evaluate a comparison
|
|
549
|
-
*/
|
|
550
|
-
evaluateComparison(left, operator, right) {
|
|
551
|
-
switch (operator) {
|
|
552
|
-
case "==":
|
|
553
|
-
return left === right;
|
|
554
|
-
case "!=":
|
|
555
|
-
return left !== right;
|
|
556
|
-
case ">":
|
|
557
|
-
return left > right;
|
|
558
|
-
case "<":
|
|
559
|
-
return left < right;
|
|
560
|
-
case ">=":
|
|
561
|
-
return left >= right;
|
|
562
|
-
case "<=":
|
|
563
|
-
return left <= right;
|
|
564
|
-
case "contains":
|
|
565
|
-
return String(left).includes(String(right));
|
|
566
|
-
case "in":
|
|
567
|
-
return Array.isArray(right) && right.includes(left);
|
|
568
|
-
default:
|
|
569
|
-
return false;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
/**
|
|
573
|
-
* Apply an operation to input values
|
|
574
|
-
*/
|
|
575
|
-
applyOperation(operation, inputs, context) {
|
|
576
|
-
const numericInputs = inputs.filter((v) => v !== null && typeof v === "number").map((v) => v);
|
|
577
|
-
switch (operation) {
|
|
578
|
-
// Arithmetic
|
|
579
|
-
case "ADD":
|
|
580
|
-
return numericInputs.reduce((a, b) => a + b, 0);
|
|
581
|
-
case "SUBTRACT":
|
|
582
|
-
if (numericInputs.length === 0)
|
|
583
|
-
return 0;
|
|
584
|
-
return numericInputs.slice(1).reduce((a, b) => a - b, numericInputs[0]);
|
|
585
|
-
case "MULTIPLY":
|
|
586
|
-
return numericInputs.reduce((a, b) => a * b, 1);
|
|
587
|
-
case "DIVIDE":
|
|
588
|
-
if (numericInputs.length < 2 || numericInputs[1] === 0) {
|
|
589
|
-
context.errors.push({
|
|
590
|
-
type: "DIVISION_BY_ZERO",
|
|
591
|
-
message: "Division by zero"
|
|
592
|
-
});
|
|
593
|
-
return null;
|
|
594
|
-
}
|
|
595
|
-
return numericInputs[0] / numericInputs[1];
|
|
596
|
-
case "ABS":
|
|
597
|
-
return numericInputs.length > 0 ? Math.abs(numericInputs[0]) : 0;
|
|
598
|
-
case "ROUND": {
|
|
599
|
-
if (numericInputs.length === 0)
|
|
600
|
-
return 0;
|
|
601
|
-
const decimals = numericInputs[1] ?? 0;
|
|
602
|
-
const factor = Math.pow(10, decimals);
|
|
603
|
-
return Math.round(numericInputs[0] * factor) / factor;
|
|
604
|
-
}
|
|
605
|
-
case "FLOOR":
|
|
606
|
-
return numericInputs.length > 0 ? Math.floor(numericInputs[0]) : 0;
|
|
607
|
-
case "CEIL":
|
|
608
|
-
return numericInputs.length > 0 ? Math.ceil(numericInputs[0]) : 0;
|
|
609
|
-
case "POWER":
|
|
610
|
-
if (numericInputs.length < 2)
|
|
611
|
-
return numericInputs[0] ?? 0;
|
|
612
|
-
return Math.pow(numericInputs[0], numericInputs[1]);
|
|
613
|
-
case "SQRT":
|
|
614
|
-
return numericInputs.length > 0 ? Math.sqrt(numericInputs[0]) : 0;
|
|
615
|
-
// Aggregation
|
|
616
|
-
case "SUM":
|
|
617
|
-
return numericInputs.reduce((a, b) => a + b, 0);
|
|
618
|
-
case "AVERAGE":
|
|
619
|
-
if (numericInputs.length === 0)
|
|
620
|
-
return 0;
|
|
621
|
-
return numericInputs.reduce((a, b) => a + b, 0) / numericInputs.length;
|
|
622
|
-
case "MIN":
|
|
623
|
-
return numericInputs.length > 0 ? Math.min(...numericInputs) : 0;
|
|
624
|
-
case "MAX":
|
|
625
|
-
return numericInputs.length > 0 ? Math.max(...numericInputs) : 0;
|
|
626
|
-
case "COUNT":
|
|
627
|
-
return inputs.filter((v) => v !== null).length;
|
|
628
|
-
case "MEDIAN": {
|
|
629
|
-
if (numericInputs.length === 0)
|
|
630
|
-
return 0;
|
|
631
|
-
const sorted = [...numericInputs].sort((a, b) => a - b);
|
|
632
|
-
const mid = Math.floor(sorted.length / 2);
|
|
633
|
-
return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
634
|
-
}
|
|
635
|
-
// Logical
|
|
636
|
-
case "IF":
|
|
637
|
-
return inputs[0] ? inputs[1] : inputs[2];
|
|
638
|
-
case "AND":
|
|
639
|
-
return inputs.every((v) => Boolean(v));
|
|
640
|
-
case "OR":
|
|
641
|
-
return inputs.some((v) => Boolean(v));
|
|
642
|
-
case "NOT":
|
|
643
|
-
return !inputs[0];
|
|
644
|
-
case "EQUALS":
|
|
645
|
-
return inputs.length >= 2 && inputs[0] === inputs[1];
|
|
646
|
-
case "GREATER_THAN":
|
|
647
|
-
return inputs.length >= 2 && inputs[0] > inputs[1];
|
|
648
|
-
case "LESS_THAN":
|
|
649
|
-
return inputs.length >= 2 && inputs[0] < inputs[1];
|
|
650
|
-
case "GREATER_THAN_OR_EQUAL":
|
|
651
|
-
return inputs.length >= 2 && inputs[0] >= inputs[1];
|
|
652
|
-
case "LESS_THAN_OR_EQUAL":
|
|
653
|
-
return inputs.length >= 2 && inputs[0] <= inputs[1];
|
|
654
|
-
case "BETWEEN": {
|
|
655
|
-
if (inputs.length < 3)
|
|
656
|
-
return false;
|
|
657
|
-
const val = inputs[0];
|
|
658
|
-
const min = inputs[1];
|
|
659
|
-
const max = inputs[2];
|
|
660
|
-
return val >= min && val <= max;
|
|
661
|
-
}
|
|
662
|
-
// Financial
|
|
663
|
-
case "PERCENT_OF":
|
|
664
|
-
if (numericInputs.length < 2 || numericInputs[1] === 0)
|
|
665
|
-
return 0;
|
|
666
|
-
return numericInputs[0] / numericInputs[1] * 100;
|
|
667
|
-
case "GROWTH_RATE":
|
|
668
|
-
if (numericInputs.length < 2 || numericInputs[1] === 0)
|
|
669
|
-
return 0;
|
|
670
|
-
return (numericInputs[0] - numericInputs[1]) / numericInputs[1] * 100;
|
|
671
|
-
case "NPV": {
|
|
672
|
-
if (numericInputs.length < 2)
|
|
673
|
-
return 0;
|
|
674
|
-
const rate = numericInputs[0];
|
|
675
|
-
const cashflows = numericInputs.slice(1);
|
|
676
|
-
return cashflows.reduce((npv, cf, i) => npv + cf / Math.pow(1 + rate, i + 1), 0);
|
|
677
|
-
}
|
|
678
|
-
case "IRR":
|
|
679
|
-
return this.calculateIRR(numericInputs);
|
|
680
|
-
case "PMT": {
|
|
681
|
-
if (numericInputs.length < 3)
|
|
682
|
-
return 0;
|
|
683
|
-
const [rate, nper, pv, fv = 0, type = 0] = numericInputs;
|
|
684
|
-
if (rate === 0)
|
|
685
|
-
return -(pv + fv) / nper;
|
|
686
|
-
const pvif = Math.pow(1 + rate, nper);
|
|
687
|
-
let pmt = rate * (pv * pvif + fv) / (pvif - 1);
|
|
688
|
-
if (type === 1)
|
|
689
|
-
pmt = pmt / (1 + rate);
|
|
690
|
-
return -pmt;
|
|
691
|
-
}
|
|
692
|
-
case "FV": {
|
|
693
|
-
if (numericInputs.length < 3)
|
|
694
|
-
return 0;
|
|
695
|
-
const [rate, nper, pmt, pv = 0, type = 0] = numericInputs;
|
|
696
|
-
if (rate === 0)
|
|
697
|
-
return -(pv + pmt * nper);
|
|
698
|
-
const pvif = Math.pow(1 + rate, nper);
|
|
699
|
-
let fv = -pv * pvif - pmt * (pvif - 1) / rate;
|
|
700
|
-
if (type === 1)
|
|
701
|
-
fv = fv - pmt * rate * nper;
|
|
702
|
-
return fv;
|
|
703
|
-
}
|
|
704
|
-
case "PV": {
|
|
705
|
-
if (numericInputs.length < 3)
|
|
706
|
-
return 0;
|
|
707
|
-
const [rate, nper, pmt, fv = 0, type = 0] = numericInputs;
|
|
708
|
-
if (rate === 0)
|
|
709
|
-
return -(fv + pmt * nper);
|
|
710
|
-
const pvif = Math.pow(1 + rate, nper);
|
|
711
|
-
let pv = (-fv - pmt * (pvif - 1) / rate) / pvif;
|
|
712
|
-
if (type === 1)
|
|
713
|
-
pv = pv / (1 + rate);
|
|
714
|
-
return pv;
|
|
715
|
-
}
|
|
716
|
-
// Special
|
|
717
|
-
case "REFERENCE":
|
|
718
|
-
return inputs[0];
|
|
719
|
-
// Pass through
|
|
720
|
-
case "LOOKUP": {
|
|
721
|
-
if (inputs.length < 2)
|
|
722
|
-
return null;
|
|
723
|
-
const index = inputs[0];
|
|
724
|
-
return inputs[Math.min(index + 1, inputs.length - 1)];
|
|
725
|
-
}
|
|
726
|
-
default:
|
|
727
|
-
context.errors.push({
|
|
728
|
-
type: "INVALID_OPERATION",
|
|
729
|
-
message: `Unknown operation: ${operation}`
|
|
730
|
-
});
|
|
731
|
-
return null;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* Calculate IRR using Newton's method
|
|
736
|
-
*/
|
|
737
|
-
calculateIRR(cashflows, guess = 0.1, maxIterations = 100, tolerance = 1e-4) {
|
|
738
|
-
let rate = guess;
|
|
739
|
-
for (let i = 0; i < maxIterations; i++) {
|
|
740
|
-
let npv = 0;
|
|
741
|
-
let dnpv = 0;
|
|
742
|
-
for (let j = 0; j < cashflows.length; j++) {
|
|
743
|
-
const factor = Math.pow(1 + rate, j);
|
|
744
|
-
npv += cashflows[j] / factor;
|
|
745
|
-
dnpv -= j * cashflows[j] / Math.pow(1 + rate, j + 1);
|
|
746
|
-
}
|
|
747
|
-
if (Math.abs(npv) < tolerance) {
|
|
748
|
-
return rate;
|
|
749
|
-
}
|
|
750
|
-
if (dnpv === 0)
|
|
751
|
-
break;
|
|
752
|
-
rate = rate - npv / dnpv;
|
|
753
|
-
}
|
|
754
|
-
return rate;
|
|
755
|
-
}
|
|
756
|
-
/**
|
|
757
|
-
* Get the dependency tracker (for advanced use cases)
|
|
758
|
-
*/
|
|
759
|
-
getDependencyTracker() {
|
|
760
|
-
return this.dependencyTracker;
|
|
761
|
-
}
|
|
762
|
-
};
|
|
763
|
-
function createHydrationEngine() {
|
|
764
|
-
return new HydrationEngine();
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
export {
|
|
768
|
-
HydrationEngine,
|
|
769
|
-
createHydrationEngine
|
|
770
|
-
};
|