skynet-graph 1.2.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 (213) hide show
  1. package/CONTRIBUTING.md +22 -0
  2. package/LICENSE +661 -0
  3. package/README.md +245 -0
  4. package/bin/sg +20 -0
  5. package/concepts/README.md +23 -0
  6. package/concepts/_substrate/Claim/Confidence/Trusted.json +6 -0
  7. package/concepts/_substrate/Claim/Confidence.json +10 -0
  8. package/concepts/_substrate/Claim/Freshness/Stale.json +7 -0
  9. package/concepts/_substrate/Claim/Freshness.json +5 -0
  10. package/concepts/_substrate/Claim/Verification/Refuted.json +6 -0
  11. package/concepts/_substrate/Claim/Verification.json +6 -0
  12. package/concepts/_substrate/Claim.json +4 -0
  13. package/concepts/_substrate/Frontier/InBeam.json +6 -0
  14. package/concepts/_substrate/Frontier/Stuck.json +6 -0
  15. package/concepts/_substrate/Frontier.json +5 -0
  16. package/concepts/_substrate/Intake/ToTask.json +22 -0
  17. package/concepts/_substrate/Intake/Typed.json +10 -0
  18. package/concepts/_substrate/Intake.json +27 -0
  19. package/concepts/_substrate/Task/Answer.json +12 -0
  20. package/concepts/_substrate/Task/Complexity/Atomic.json +5 -0
  21. package/concepts/_substrate/Task/Complexity/Compound/Expansion.json +7 -0
  22. package/concepts/_substrate/Task/Complexity/Compound.json +6 -0
  23. package/concepts/_substrate/Task/Complexity.json +6 -0
  24. package/concepts/_substrate/Task/EvalComplexity.json +13 -0
  25. package/concepts/_substrate/Task/ReportUp.json +6 -0
  26. package/concepts/_substrate/Task/Rollup.json +10 -0
  27. package/concepts/_substrate/Task.json +5 -0
  28. package/concepts/clinical/Diagnosis/Medication.json +6 -0
  29. package/concepts/clinical/Diagnosis.json +15 -0
  30. package/concepts/clinical/Observation/LabValue/OutOfRange.json +6 -0
  31. package/concepts/clinical/Observation/LabValue.json +5 -0
  32. package/concepts/clinical/Observation.json +6 -0
  33. package/concepts/common/Document/pathBasket.json +6 -0
  34. package/concepts/common/Document.json +3 -0
  35. package/concepts/common/Edge/Distance.json +13 -0
  36. package/concepts/common/Edge/Stay/LongStay.json +8 -0
  37. package/concepts/common/Edge/Stay.json +8 -0
  38. package/concepts/common/Edge/Travel/LongTravel.json +16 -0
  39. package/concepts/common/Edge/Travel/ShortTravel.json +11 -0
  40. package/concepts/common/Edge/Travel/targetNode.json +7 -0
  41. package/concepts/common/Edge/Travel.json +7 -0
  42. package/concepts/common/Edge.json +3 -0
  43. package/concepts/common/Vertice.json +3 -0
  44. package/concepts/supply/Fulfillment.json +10 -0
  45. package/concepts/supply/Inventory/Reorder.json +7 -0
  46. package/concepts/supply/Inventory.json +5 -0
  47. package/concepts/supply/Procurement/SupplierConfirm.json +6 -0
  48. package/concepts/supply/Procurement.json +8 -0
  49. package/concepts/supply/Transport.json +5 -0
  50. package/doc/API.md +556 -0
  51. package/doc/CAPABILITIES.md +373 -0
  52. package/doc/MODELISATION.md +511 -0
  53. package/doc/architecture.md +267 -0
  54. package/doc/concept-as-graph.md +379 -0
  55. package/doc/concept-learning.md +168 -0
  56. package/doc/creative-loop-map.md +202 -0
  57. package/doc/original-2016-doc.md +148 -0
  58. package/doc/usage.md +501 -0
  59. package/lib/authoring/abstract.js +401 -0
  60. package/lib/authoring/abstraction.js +190 -0
  61. package/lib/authoring/adapt.js +393 -0
  62. package/lib/authoring/ancestry.js +216 -0
  63. package/lib/authoring/author.js +147 -0
  64. package/lib/authoring/bounded-merge.js +57 -0
  65. package/lib/authoring/canon.js +158 -0
  66. package/lib/authoring/clock.js +123 -0
  67. package/lib/authoring/combinator.js +92 -0
  68. package/lib/authoring/compete.js +76 -0
  69. package/lib/authoring/compose-hotspot.js +314 -0
  70. package/lib/authoring/compress.js +279 -0
  71. package/lib/authoring/concept-net.js +254 -0
  72. package/lib/authoring/concepts.js +66 -0
  73. package/lib/authoring/context-project.js +277 -0
  74. package/lib/authoring/contract.js +476 -0
  75. package/lib/authoring/corpus-pack.js +125 -0
  76. package/lib/authoring/cost-probe.js +86 -0
  77. package/lib/authoring/crystallize.js +555 -0
  78. package/lib/authoring/dag-decompose.js +256 -0
  79. package/lib/authoring/dataset-adapter.js +253 -0
  80. package/lib/authoring/debug-provider.js +92 -0
  81. package/lib/authoring/decompose.js +343 -0
  82. package/lib/authoring/emittability.js +236 -0
  83. package/lib/authoring/equilibrium.js +160 -0
  84. package/lib/authoring/extract.js +153 -0
  85. package/lib/authoring/forest.js +55 -0
  86. package/lib/authoring/forge-fallback.js +116 -0
  87. package/lib/authoring/givens.js +121 -0
  88. package/lib/authoring/glossary.js +177 -0
  89. package/lib/authoring/grammar-graph.js +191 -0
  90. package/lib/authoring/granularity.js +80 -0
  91. package/lib/authoring/graph-net.js +108 -0
  92. package/lib/authoring/ground.js +148 -0
  93. package/lib/authoring/higher-order.js +85 -0
  94. package/lib/authoring/hotspot.js +132 -0
  95. package/lib/authoring/hysteresis.js +85 -0
  96. package/lib/authoring/index.js +106 -0
  97. package/lib/authoring/lattice-morphism.js +61 -0
  98. package/lib/authoring/lattice-pack.js +148 -0
  99. package/lib/authoring/leaf-io.js +77 -0
  100. package/lib/authoring/library.js +156 -0
  101. package/lib/authoring/lifecycle.js +92 -0
  102. package/lib/authoring/loop.js +193 -0
  103. package/lib/authoring/master-loop.js +132 -0
  104. package/lib/authoring/mdl.js +209 -0
  105. package/lib/authoring/memo-stability.js +122 -0
  106. package/lib/authoring/method-explorer.js +138 -0
  107. package/lib/authoring/method-pack.js +181 -0
  108. package/lib/authoring/method.js +202 -0
  109. package/lib/authoring/mine.js +510 -0
  110. package/lib/authoring/mount.js +119 -0
  111. package/lib/authoring/negotiate.js +100 -0
  112. package/lib/authoring/parametric.js +139 -0
  113. package/lib/authoring/reaggregate.js +75 -0
  114. package/lib/authoring/rebalance.js +157 -0
  115. package/lib/authoring/recall.js +135 -0
  116. package/lib/authoring/registry.js +350 -0
  117. package/lib/authoring/relearn.js +147 -0
  118. package/lib/authoring/retention.js +89 -0
  119. package/lib/authoring/segment-proxy.js +114 -0
  120. package/lib/authoring/serve-leaf.js +64 -0
  121. package/lib/authoring/slot-aware-serve.js +77 -0
  122. package/lib/authoring/sound-invoke.js +59 -0
  123. package/lib/authoring/split-serve.js +74 -0
  124. package/lib/authoring/ste.js +239 -0
  125. package/lib/authoring/stock.js +101 -0
  126. package/lib/authoring/store.js +94 -0
  127. package/lib/authoring/supervise.js +138 -0
  128. package/lib/authoring/support.js +131 -0
  129. package/lib/authoring/task-mirror.js +51 -0
  130. package/lib/authoring/typed-loop.js +160 -0
  131. package/lib/authoring/validate.js +569 -0
  132. package/lib/authoring/widen.js +88 -0
  133. package/lib/combos/appliance.js +189 -0
  134. package/lib/combos/critique.js +377 -0
  135. package/lib/combos/defaults.js +86 -0
  136. package/lib/combos/durable-runner.js +115 -0
  137. package/lib/combos/forge.js +209 -0
  138. package/lib/combos/index.js +86 -0
  139. package/lib/combos/learning-library.js +253 -0
  140. package/lib/combos/mixture-serve.js +193 -0
  141. package/lib/combos/plan-loop.js +192 -0
  142. package/lib/combos/proxy-cache.js +272 -0
  143. package/lib/combos/self-mod.js +94 -0
  144. package/lib/durable/audit.js +102 -0
  145. package/lib/durable/checkpoint-store.js +550 -0
  146. package/lib/durable/fold.js +62 -0
  147. package/lib/durable/interpreter.js +242 -0
  148. package/lib/durable/xlate.js +185 -0
  149. package/lib/graph/Graph.js +2486 -0
  150. package/lib/graph/expr.js +307 -0
  151. package/lib/graph/index.js +26 -0
  152. package/lib/graph/log.js +134 -0
  153. package/lib/graph/objects/Concept.js +382 -0
  154. package/lib/graph/objects/Entity.js +503 -0
  155. package/lib/graph/objects/Node.js +57 -0
  156. package/lib/graph/objects/PathMap.js +557 -0
  157. package/lib/graph/objects/Segment.js +100 -0
  158. package/lib/graph/tasks/stabilize.js +59 -0
  159. package/lib/graph/tasks/taskflow.js +247 -0
  160. package/lib/index.js +122 -0
  161. package/lib/load.js +132 -0
  162. package/lib/providers/backends.js +117 -0
  163. package/lib/providers/borderline.js +129 -0
  164. package/lib/providers/cache.js +226 -0
  165. package/lib/providers/canonicalize.js +198 -0
  166. package/lib/providers/constat.js +107 -0
  167. package/lib/providers/geo.js +53 -0
  168. package/lib/providers/index.js +116 -0
  169. package/lib/providers/intake.js +263 -0
  170. package/lib/providers/llm-local.js +88 -0
  171. package/lib/providers/llm.js +236 -0
  172. package/lib/providers/local-host.js +197 -0
  173. package/lib/providers/merge-consistency.js +162 -0
  174. package/lib/providers/nogood.js +149 -0
  175. package/lib/providers/reason-loop.js +223 -0
  176. package/lib/providers/semiring.js +285 -0
  177. package/lib/providers/solver-fork.js +163 -0
  178. package/lib/providers/stats.js +228 -0
  179. package/lib/providers/verify.js +120 -0
  180. package/lib/runtime/index.js +135 -0
  181. package/lib/runtime/invoke-pool.js +92 -0
  182. package/lib/runtime/protocol.js +210 -0
  183. package/lib/runtime/transport-socket.js +77 -0
  184. package/lib/runtime/worker-entry.js +31 -0
  185. package/lib/sg/cli.js +601 -0
  186. package/lib/sg/log-sinks.js +214 -0
  187. package/lib/sg/mcp.js +395 -0
  188. package/lib/sg/proxy-run.js +66 -0
  189. package/lib/sg/serve-demo.js +185 -0
  190. package/lib/sg/serve.js +205 -0
  191. package/lib/sg/trace.js +118 -0
  192. package/lib/studio/protocol.js +45 -0
  193. package/lib/studio/public/app.js +310 -0
  194. package/lib/studio/public/components/ConceptEditor.js +43 -0
  195. package/lib/studio/public/components/ConceptTree.js +43 -0
  196. package/lib/studio/public/components/CorpusPanel.js +68 -0
  197. package/lib/studio/public/components/ForkTree.js +36 -0
  198. package/lib/studio/public/components/GrammarGraph.js +99 -0
  199. package/lib/studio/public/components/GraphCanvas.js +156 -0
  200. package/lib/studio/public/components/Inspector.js +48 -0
  201. package/lib/studio/public/components/LearningPanel.js +85 -0
  202. package/lib/studio/public/components/PromptConsole.js +46 -0
  203. package/lib/studio/public/components/ProviderTrace.js +39 -0
  204. package/lib/studio/public/components/SessionSplit.js +47 -0
  205. package/lib/studio/public/components/TilingOverlay.js +40 -0
  206. package/lib/studio/public/components/Timeline.js +57 -0
  207. package/lib/studio/public/index.html +26 -0
  208. package/lib/studio/public/styles.css +185 -0
  209. package/lib/studio/public/ws.js +58 -0
  210. package/lib/studio/server.js +130 -0
  211. package/lib/studio/session.js +397 -0
  212. package/lib/studio/studio.js +149 -0
  213. package/package.json +42 -0
@@ -0,0 +1,307 @@
1
+ /*
2
+ * Copyright 2026 Nathanael Braun
3
+ * @author : Nathanael BRAUN <pp9ping@gmail.com>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+ 'use strict';
19
+ /**
20
+ * Safe expression evaluator for the concept mini-DSL — replaces the pervasive
21
+ * `new Function(...)` usage (Concept asserts/ensure, Graph.queryMaps /
22
+ * getChildMatching, Entity.doEval / test, PathMap queries).
23
+ *
24
+ * Why: `new Function` is an `eval` variant — RCE surface (LLM/host text flows
25
+ * into expressions), CSP-incompatible, and a hard blocker for WASM. This module
26
+ * parses the *full expression grammar* with `jsep` and interprets the AST with
27
+ * no code generation, so expressiveness is NOT capped: member access (./[]),
28
+ * method/function calls, ternary, array/object literals and every operator all
29
+ * work — only statement-level JS (loops/assignments) is out of reach, which
30
+ * `return (EXPR)` never meaningfully hosted anyway.
31
+ *
32
+ * Reference resolution preserves the engine's exact semantics: a `$ref` token
33
+ * (including cross-object walks like `$originNode:Position.lat` and the `$$id`
34
+ * bagRef/literal-id form) is captured *whole* by the original regex and handed
35
+ * verbatim to the injected resolver — i.e. to `getRef`, which walks the path.
36
+ * The regex rewrites `$ref` -> `__ref("ref")` (the same transformation the old
37
+ * code applied to `scope.getRef("ref")`), then jsep parses the rest.
38
+ *
39
+ * Security: because member access + calls are allowed, the classic
40
+ * `"".constructor.constructor("…")()` escape is blocked by refusing access to
41
+ * `constructor` / `__proto__` / `prototype`. No assert/query legitimately needs
42
+ * them, so this is not a cap on expressiveness — it is the whole point of
43
+ * dropping `eval`.
44
+ *
45
+ * Runtime errors yield `undefined`, faithful to the original
46
+ * `try{ … }catch{ return undefined }` wrapping.
47
+ *
48
+ * @author Skynet-Graph V1 (Neurosymbolic Reasoning Graph) — Phase 0
49
+ */
50
+
51
+ var _jsep = require('jsep');
52
+ var jsep = (_jsep && _jsep.default) ? _jsep.default : _jsep;
53
+
54
+ var _ternary = require('@jsep-plugin/ternary');
55
+ var _object = require('@jsep-plugin/object');
56
+ jsep.plugins.register(
57
+ (_ternary && _ternary.default) ? _ternary.default : _ternary,
58
+ (_object && _object.default) ? _object.default : _object
59
+ );
60
+
61
+ // $ref / $$ref -> __ref("ref") (identical capture to the original engine regex)
62
+ var REF_RE = /\$(\$?[A-Za-z_][\w.:$]*)/g;
63
+ var REF_FN = '__ref';
64
+
65
+ // Properties that open a path back to the Function constructor / prototype chain.
66
+ var BLOCKED_PROPS = { constructor: true, __proto__: true, prototype: true };
67
+
68
+ // Stratified set-aggregation over a value array (roadmap #8) — closes the aggregation gap
69
+ // (getRef walks SINGLE refs; only `.length` worked) WITHOUT lambdas, so it stays inside the
70
+ // safe evaluator. `op`/`val` form a comparison predicate; omit them for a truthiness predicate.
71
+ // count($votes,'==','yes') >= 2 all($childScores,'>=',0.5) any($flags)
72
+ // "Stratified" = run it after the collection is complete (the existing cardinality gate,
73
+ // e.g. `$votes.length==$expected && count($votes,'==','yes')>=k`), exactly like `.length`.
74
+ function aggCompare( a, op, b ) {
75
+ switch ( op ) {
76
+ case '==': return a == b; case '!=': return a != b;
77
+ case '===': return a === b; case '!==': return a !== b;
78
+ case '<': return a < b; case '>': return a > b;
79
+ case '<=': return a <= b; case '>=': return a >= b;
80
+ }
81
+ return false; // unknown op -> matches nothing
82
+ }
83
+ function aggPredicate( op, val ) {
84
+ return op === undefined ? function ( e ) { return !!e; } : function ( e ) { return aggCompare(e, op, val); };
85
+ }
86
+ function aggCount( arr, op, val ) {
87
+ if ( !Array.isArray(arr) ) return 0;
88
+ var p = aggPredicate(op, val), n = 0;
89
+ for ( var i = 0; i < arr.length; i++ ) if ( p(arr[i]) ) n++;
90
+ return n;
91
+ }
92
+ function aggAll( arr, op, val ) { // vacuously true on []; false on a non-array (not-yet-present)
93
+ if ( !Array.isArray(arr) ) return false;
94
+ var p = aggPredicate(op, val);
95
+ for ( var i = 0; i < arr.length; i++ ) if ( !p(arr[i]) ) return false;
96
+ return true;
97
+ }
98
+ function aggAny( arr, op, val ) {
99
+ if ( !Array.isArray(arr) ) return false;
100
+ var p = aggPredicate(op, val);
101
+ for ( var i = 0; i < arr.length; i++ ) if ( p(arr[i]) ) return true;
102
+ return false;
103
+ }
104
+
105
+ // Curated, side-effect-free globals reachable by bare identifiers. Deliberately
106
+ // excludes Function/eval/require/process/globalThis etc. (absent -> undefined).
107
+ var GLOBALS = {
108
+ Math: Math, JSON: JSON,
109
+ Number: Number, String: String, Boolean: Boolean, Array: Array,
110
+ parseInt: parseInt, parseFloat: parseFloat,
111
+ isNaN: isNaN, isFinite: isFinite,
112
+ count: aggCount, all: aggAll, any: aggAny, // stratified set-aggregation (#8)
113
+ undefined: undefined, NaN: NaN, Infinity: Infinity
114
+ };
115
+
116
+ function hasOwn( o, k ) { return o != null && Object.prototype.hasOwnProperty.call(o, k); }
117
+
118
+ function safeProp( name ) {
119
+ if ( BLOCKED_PROPS[name] ) throw new Error('expr: access to "' + name + '" is blocked');
120
+ return name;
121
+ }
122
+
123
+ // ----------------------------------------------------------- interpreter
124
+ function evalNode( node, ctx ) {
125
+ switch ( node.type ) {
126
+ case 'Literal':
127
+ return node.value;
128
+
129
+ case 'Identifier': {
130
+ var nm = node.name;
131
+ if ( hasOwn(ctx.names, nm) ) return ctx.names[nm];
132
+ if ( hasOwn(GLOBALS, nm) ) return GLOBALS[nm];
133
+ return undefined;
134
+ }
135
+
136
+ case 'MemberExpression': {
137
+ var obj = evalNode(node.object, ctx);
138
+ if ( obj == null ) return undefined;
139
+ var key = node.computed ? evalNode(node.property, ctx) : node.property.name;
140
+ return obj[safeProp(key)];
141
+ }
142
+
143
+ case 'CallExpression': {
144
+ var callee = node.callee;
145
+
146
+ // `$ref` marker: callee is the injected __ref(<string literal>)
147
+ if ( callee.type === 'Identifier' && callee.name === REF_FN ) {
148
+ return ctx.resolve(node.arguments[0].value);
149
+ }
150
+
151
+ var thisObj, fn;
152
+ if ( callee.type === 'MemberExpression' ) {
153
+ thisObj = evalNode(callee.object, ctx);
154
+ if ( thisObj == null ) return undefined;
155
+ var mkey = callee.computed ? evalNode(callee.property, ctx) : callee.property.name;
156
+ fn = thisObj[safeProp(mkey)];
157
+ } else {
158
+ thisObj = undefined;
159
+ fn = evalNode(callee, ctx);
160
+ }
161
+ if ( typeof fn !== 'function' ) return undefined;
162
+ return fn.apply(thisObj, node.arguments.map(function ( a ) { return evalNode(a, ctx); }));
163
+ }
164
+
165
+ case 'BinaryExpression':
166
+ case 'LogicalExpression':
167
+ return evalBinary(node, ctx);
168
+
169
+ case 'UnaryExpression': {
170
+ var v = evalNode(node.argument, ctx);
171
+ switch ( node.operator ) {
172
+ case '!': return !v;
173
+ case '-': return -v;
174
+ case '+': return +v;
175
+ case '~': return ~v;
176
+ case 'typeof': return typeof v;
177
+ }
178
+ throw new Error('expr: unsupported unary "' + node.operator + '"');
179
+ }
180
+
181
+ case 'ConditionalExpression':
182
+ return evalNode(node.test, ctx)
183
+ ? evalNode(node.consequent, ctx)
184
+ : evalNode(node.alternate, ctx);
185
+
186
+ case 'ArrayExpression':
187
+ return node.elements.map(function ( e ) { return evalNode(e, ctx); });
188
+
189
+ case 'ObjectExpression': {
190
+ var o = {};
191
+ node.properties.forEach(function ( pr ) {
192
+ var k = pr.computed ? evalNode(pr.key, ctx)
193
+ : (pr.key.name != null ? pr.key.name : pr.key.value);
194
+ o[safeProp(String(k))] = evalNode(pr.value, ctx);
195
+ });
196
+ return o;
197
+ }
198
+
199
+ case 'Compound': {
200
+ var last;
201
+ node.body.forEach(function ( n ) { last = evalNode(n, ctx); });
202
+ return last;
203
+ }
204
+
205
+ case 'ThisExpression':
206
+ return undefined;
207
+ }
208
+ throw new Error('expr: unsupported node "' + node.type + '"');
209
+ }
210
+
211
+ function evalBinary( node, ctx ) {
212
+ var op = node.operator;
213
+ // logical operators short-circuit and return the operand (like JS / the
214
+ // original `return (expr)`)
215
+ if ( op === '&&' ) return evalNode(node.left, ctx) && evalNode(node.right, ctx);
216
+ if ( op === '||' ) return evalNode(node.left, ctx) || evalNode(node.right, ctx);
217
+
218
+ var l = evalNode(node.left, ctx), r = evalNode(node.right, ctx);
219
+ switch ( op ) {
220
+ case '==': return l == r; // loose, matching original DSL semantics
221
+ case '!=': return l != r;
222
+ case '===': return l === r;
223
+ case '!==': return l !== r;
224
+ case '<': return l < r;
225
+ case '>': return l > r;
226
+ case '<=': return l <= r;
227
+ case '>=': return l >= r;
228
+ case '+': return l + r;
229
+ case '-': return l - r;
230
+ case '*': return l * r;
231
+ case '/': return l / r;
232
+ case '%': return l % r;
233
+ case '**': return Math.pow(l, r);
234
+ case '&': return l & r;
235
+ case '|': return l | r;
236
+ case '^': return l ^ r;
237
+ case '<<': return l << r;
238
+ case '>>': return l >> r;
239
+ case '>>>': return l >>> r;
240
+ }
241
+ throw new Error('expr: unsupported binary "' + op + '"');
242
+ }
243
+
244
+ // -------------------------------------------------------------- public API
245
+ function preprocessRefs( src ) {
246
+ return src.replace(REF_RE, function ( _m, ref ) {
247
+ return REF_FN + '(' + JSON.stringify(ref) + ')';
248
+ });
249
+ }
250
+
251
+ // Join an array of sub-expressions with AND, mirroring the original
252
+ // `query.join(") && (")` wrapped in `(...)`.
253
+ function normalize( source ) {
254
+ if ( Array.isArray(source) ) {
255
+ var parts = source.filter(function ( s ) { return s != null && String(s).trim() !== ''; });
256
+ if ( !parts.length ) return '';
257
+ return '(' + parts.join(') && (') + ')';
258
+ }
259
+ return source == null ? '' : String(source);
260
+ }
261
+
262
+ /**
263
+ * Compile a mini-DSL expression into a safe evaluator.
264
+ *
265
+ * @param {string|string[]} source expression, or array AND-joined together
266
+ * @param {{empty?: *}} [options] `empty` is returned for an empty source
267
+ * (default `true`, matching Concept/queryMaps;
268
+ * pass `false` for getChildMatching/test)
269
+ * @returns {function(resolve, names=): *} `resolve(refName)` resolves `$ref`s,
270
+ * `names` (optional) resolves bare identifiers
271
+ * (stands in for doEval's `with(refMap)`).
272
+ * Returns `undefined` on any runtime error.
273
+ * @throws {Error} on syntax errors (faithful: `new Function` also threw at compile)
274
+ */
275
+ function compileExpression( source, options ) {
276
+ var fallback = ( options && 'empty' in options ) ? options.empty : true;
277
+ var src = normalize(source).trim();
278
+
279
+ if ( !src ) {
280
+ return function () { return fallback; };
281
+ }
282
+
283
+ var ast = jsep(preprocessRefs(src));
284
+
285
+ return function ( resolve, names ) {
286
+ try {
287
+ return evalNode(ast, { resolve: resolve, names: names });
288
+ } catch ( e ) {
289
+ return undefined;
290
+ }
291
+ };
292
+ }
293
+
294
+ /**
295
+ * Parse a mini-DSL expression to its jsep AST (refs already rewritten to `__ref("ref")`
296
+ * CallExpression nodes — identify a ref node by `node.type==='CallExpression' &&
297
+ * node.callee.name===REF_FN`, its key is `node.arguments[0].value`). For author-time
298
+ * static analysis (validate.js); the evaluator path stays `compileExpression`.
299
+ * @returns the AST, or `null` for an empty source. Throws on a syntax error.
300
+ */
301
+ function parseExpression( source ) {
302
+ var src = normalize(source).trim();
303
+ if ( !src ) return null;
304
+ return jsep(preprocessRefs(src));
305
+ }
306
+
307
+ module.exports = { compileExpression: compileExpression, parseExpression: parseExpression, REF_FN: REF_FN };
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Copyright 2026 Nathanael Braun
3
+ * @author : Nathanael BRAUN <pp9ping@gmail.com>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+
19
+
20
+ // `__SERVER__` is a host/build flag (true = node/server, false = browser/client) read as
21
+ // a bare global by the engine. Default it to server when undefined so the lib loads
22
+ // standalone without a ReferenceError; a browser host can set globalThis.__SERVER__ =
23
+ // false before requiring the engine. (Previously injected by webpack DefinePlugin / _boot.)
24
+ if ( typeof globalThis.__SERVER__ === 'undefined' ) globalThis.__SERVER__ = true;
25
+
26
+ module.exports = require('./Graph.js');
@@ -0,0 +1,134 @@
1
+ /*
2
+ * Copyright 2026 Nathanael Braun
3
+ * @author : Nathanael BRAUN <pp9ping@gmail.com>
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+ 'use strict';
19
+ /**
20
+ * Skynet-Graph logger — fs-free core.
21
+ *
22
+ * Lives in the engine (lib/graph/) so every engine file can require it without
23
+ * pulling node:fs; all file/TTY sinks live in lib/sg/. This replaces the old
24
+ * `var debug = console` indirection: same console-compatible call shape, but now
25
+ * leveled, sinked, context-aware and per-graph.
26
+ *
27
+ * Levels (severity descending) — a record reaches sinks iff
28
+ * rank(record.level) <= rank(threshold):
29
+ * error(0) > warn(1) > log(2) > info(3) > verbose(4)
30
+ *
31
+ * A LogRecord { level, ts, label, ctx, msg, args } is JSON-serializable (Errors
32
+ * in args are reduced to {name,message,stack}), so it crosses a worker_threads
33
+ * boundary unchanged.
34
+ *
35
+ * child(ctx) returns a logger that shares the root's sinks / ring buffer / level
36
+ * but merges ctx into every record. A concept-apply tags its logs with
37
+ * { concept, target, applyId } this way, so they can be retrieved afterwards via
38
+ * tail(n,{concept|applyId}) WITHOUT ever being stored on the graph objects.
39
+ */
40
+
41
+ var LEVELS = { error: 0, warn: 1, log: 2, info: 3, verbose: 4 };
42
+ var LEVEL_NAMES = ['error', 'warn', 'log', 'info', 'verbose'];
43
+
44
+ function rankOf ( name ) { return LEVELS[name] == null ? LEVELS.info : LEVELS[name]; }
45
+
46
+ // Reduce args to something JSON-serializable (Errors -> plain object, functions
47
+ // -> tag), so a record survives structured-clone across a worker boundary.
48
+ function sanitizeArgs ( args ) {
49
+ return args.map(function ( a ) {
50
+ if ( a instanceof Error ) return { name: a.name, message: a.message, stack: a.stack };
51
+ if ( typeof a === 'function' ) return '[function ' + (a.name || 'anonymous') + ']';
52
+ return a;
53
+ });
54
+ }
55
+
56
+ function recordMatches ( rec, f ) {
57
+ if ( !f ) return true;
58
+ var c = rec.ctx || {};
59
+ if ( f.level != null && rec.level !== f.level ) return false;
60
+ if ( f.concept != null && c.concept !== f.concept ) return false;
61
+ if ( f.target != null && c.target !== f.target ) return false;
62
+ if ( f.applyId != null && c.applyId !== f.applyId ) return false;
63
+ return true;
64
+ }
65
+
66
+ // Default sink: format the record back into a console.<level>(...) call so the
67
+ // out-of-the-box behavior matches the old `debug = console` — but level-gated.
68
+ function consoleSink ( rec ) {
69
+ var fn = console[rec.level] || console.log;
70
+ var head = '[' + rec.label + (rec.ctx && rec.ctx.concept ? '·' + rec.ctx.concept : '') + ']';
71
+ fn.apply(console, [head, rec.msg].concat(rec.args || []));
72
+ }
73
+
74
+ /**
75
+ * @param {object} [opts]
76
+ * @param {string} [opts.label='graph']
77
+ * @param {string} [opts.level] threshold; default env SG_LOG_LEVEL or 'warn'
78
+ * @param {function} [opts.onRecord] convenience sink fn(record)
79
+ * @param {number} [opts.capacity=500] ring-buffer size for tail()
80
+ * @param {boolean} [opts.console=true] install the default console sink
81
+ * @returns {object} logger
82
+ */
83
+ function createLogger ( opts ) {
84
+ opts = opts || {};
85
+ // shared mutable state — a child closes over the SAME state object as its root
86
+ var state = {
87
+ label: opts.label || 'graph',
88
+ level: opts.level || (typeof process !== 'undefined' && process.env.SG_LOG_LEVEL) || 'warn',
89
+ sinks: [],
90
+ buf : [],
91
+ cap : opts.capacity || 500
92
+ };
93
+ if ( opts.console !== false ) state.sinks.push(consoleSink);
94
+ if ( opts.onRecord ) state.sinks.push(opts.onRecord);
95
+
96
+ function make ( ctx ) {
97
+ var logger = {};
98
+
99
+ function emit ( level, msg, args ) {
100
+ if ( rankOf(level) > rankOf(state.level) ) return; // below threshold -> drop
101
+ var rec = { level: level, ts: Date.now(), label: state.label, ctx: ctx, msg: msg, args: sanitizeArgs(args) };
102
+ state.buf.push(rec);
103
+ if ( state.buf.length > state.cap ) state.buf.shift();
104
+ for ( var i = 0 ; i < state.sinks.length ; i++ ) {
105
+ try { state.sinks[i](rec); } catch ( e ) { /* a broken sink must never break the engine */ }
106
+ }
107
+ }
108
+
109
+ LEVEL_NAMES.forEach(function ( lvl ) {
110
+ logger[lvl] = function ( msg ) { emit(lvl, msg, Array.prototype.slice.call(arguments, 1)); };
111
+ });
112
+
113
+ logger.child = function ( extra ) { return make(Object.assign({}, ctx, extra)); };
114
+ logger.addSink = function ( fn ) { state.sinks.push(fn); return fn; };
115
+ logger.removeSink = function ( fn ) { var i = state.sinks.indexOf(fn); if ( i >= 0 ) state.sinks.splice(i, 1); };
116
+ logger.setLevel = function ( name ) { if ( LEVELS[name] != null ) state.level = name; return state.level; };
117
+ logger.tail = function ( n, filter ) {
118
+ var out = filter ? state.buf.filter(function ( r ) { return recordMatches(r, filter); }) : state.buf.slice();
119
+ return n ? out.slice(-n) : out;
120
+ };
121
+ Object.defineProperty(logger, 'level', { get: function () { return state.level; } });
122
+ Object.defineProperty(logger, 'records', { get: function () { return state.buf.slice(); } });
123
+ Object.defineProperty(logger, 'ctx', { get: function () { return ctx; } });
124
+ Object.defineProperty(logger, 'label', { get: function () { return state.label; } });
125
+ return logger;
126
+ }
127
+
128
+ return make(null);
129
+ }
130
+
131
+ // process-wide fallback for the rare engine spots with no graph in scope.
132
+ var defaultLogger = createLogger({ label: 'sg' });
133
+
134
+ module.exports = { createLogger: createLogger, defaultLogger: defaultLogger, LEVELS: LEVELS, LEVEL_NAMES: LEVEL_NAMES };