eyeling 1.16.2 → 1.16.4

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 (51) hide show
  1. package/HANDBOOK.md +4 -0
  2. package/README.md +0 -1
  3. package/examples/ershov-mixed-computation.n3 +106 -0
  4. package/examples/output/ershov-mixed-computation.n3 +15 -0
  5. package/eyeling.js +510 -263
  6. package/lib/cli.js +22 -12
  7. package/lib/engine.js +488 -251
  8. package/package.json +2 -3
  9. package/arctifacts/README.md +0 -59
  10. package/arctifacts/ackermann.html +0 -678
  11. package/arctifacts/auroracare.html +0 -1297
  12. package/arctifacts/bike-trip.html +0 -752
  13. package/arctifacts/binomial-theorem.html +0 -631
  14. package/arctifacts/bmi.html +0 -511
  15. package/arctifacts/building-performance.html +0 -750
  16. package/arctifacts/clinical-care.html +0 -726
  17. package/arctifacts/collatz.html +0 -403
  18. package/arctifacts/complex.html +0 -321
  19. package/arctifacts/control-system.html +0 -482
  20. package/arctifacts/delfour.html +0 -849
  21. package/arctifacts/earthquake-epicenter.html +0 -982
  22. package/arctifacts/eco-route.html +0 -662
  23. package/arctifacts/euclid-infinitude.html +0 -564
  24. package/arctifacts/euler-identity.html +0 -667
  25. package/arctifacts/exoplanet-transit.html +0 -1000
  26. package/arctifacts/faltings-theorem.html +0 -1046
  27. package/arctifacts/fibonacci.html +0 -299
  28. package/arctifacts/fundamental-theorem-arithmetic.html +0 -398
  29. package/arctifacts/godel-numbering.html +0 -743
  30. package/arctifacts/gps-bike.html +0 -759
  31. package/arctifacts/gps-clinical-bench.html +0 -792
  32. package/arctifacts/graph-french.html +0 -449
  33. package/arctifacts/grass-molecular.html +0 -592
  34. package/arctifacts/group-theory.html +0 -740
  35. package/arctifacts/health-info.html +0 -833
  36. package/arctifacts/kaprekar-constant.html +0 -576
  37. package/arctifacts/lee.html +0 -805
  38. package/arctifacts/linked-lists.html +0 -502
  39. package/arctifacts/lldm.html +0 -612
  40. package/arctifacts/matrix-multiplication.html +0 -502
  41. package/arctifacts/matrix.html +0 -651
  42. package/arctifacts/newton-raphson.html +0 -944
  43. package/arctifacts/peano-factorial.html +0 -456
  44. package/arctifacts/pi.html +0 -363
  45. package/arctifacts/polynomial.html +0 -646
  46. package/arctifacts/prime.html +0 -366
  47. package/arctifacts/pythagorean-theorem.html +0 -468
  48. package/arctifacts/rest-path.html +0 -469
  49. package/arctifacts/roots-of-unity.html +0 -363
  50. package/arctifacts/turing.html +0 -409
  51. package/arctifacts/wind-turbines.html +0 -726
@@ -1,662 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>Eco Route</title>
7
- <style>
8
- :root {
9
- --bg: #f7fafc;
10
- --panel: #ffffff;
11
- --muted: #475569;
12
- --text: #0b1220;
13
- --accent: #2563eb;
14
- --good: #16a34a;
15
- --bad: #dc2626;
16
- --warn: #d97706;
17
- --chip: #eef2f7;
18
- }
19
- * {
20
- box-sizing: border-box;
21
- }
22
- body {
23
- margin: 0;
24
- font:
25
- 16px/1.5 system-ui,
26
- Segoe UI,
27
- Roboto,
28
- Inter,
29
- Helvetica,
30
- Arial,
31
- sans-serif;
32
- background: var(--bg);
33
- color: var(--text);
34
- }
35
- header {
36
- padding: 24px 20px;
37
- border-bottom: 1px solid #e5e7eb;
38
- background: linear-gradient(180deg, rgba(37, 99, 235, 0.08), transparent);
39
- }
40
- h1 {
41
- margin: 0;
42
- font-size: 24px;
43
- letter-spacing: 0.2px;
44
- }
45
- main {
46
- display: grid;
47
- grid-template-columns: 1fr;
48
- gap: 22px;
49
- padding: 20px;
50
- align-items: start;
51
- }
52
- section {
53
- background: var(--panel);
54
- border: 1px solid #e5e7eb;
55
- border-radius: 16px;
56
- padding: 16px;
57
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.06);
58
- }
59
- h2 {
60
- margin: 0 0 10px 0;
61
- font-size: 18px;
62
- }
63
- .row {
64
- display: flex;
65
- gap: 10px;
66
- flex-wrap: wrap;
67
- }
68
- .grid {
69
- display: grid;
70
- gap: 10px;
71
- }
72
- .pill {
73
- display: inline-flex;
74
- align-items: center;
75
- gap: 8px;
76
- padding: 8px 10px;
77
- border-radius: 999px;
78
- background: #ffffff;
79
- border: 1px solid #e5e7eb;
80
- }
81
- .small {
82
- font-size: 13px;
83
- color: var(--muted);
84
- }
85
- .mono {
86
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
87
- }
88
- .ok {
89
- color: var(--good);
90
- }
91
- .no {
92
- color: var(--bad);
93
- }
94
- .warn {
95
- color: var(--warn);
96
- }
97
- .kvs {
98
- display: grid;
99
- grid-template-columns: 160px 1fr;
100
- gap: 6px 10px;
101
- }
102
- .log {
103
- max-height: 260px;
104
- overflow: auto;
105
- background: #ffffff;
106
- border: 1px solid #e5e7eb;
107
- border-radius: 12px;
108
- padding: 10px;
109
- }
110
- .timeline {
111
- display: flex;
112
- flex-direction: column;
113
- gap: 10px;
114
- }
115
- .card {
116
- background: #ffffff;
117
- border: 1px solid #e5e7eb;
118
- border-radius: 12px;
119
- padding: 12px;
120
- }
121
- .muted {
122
- color: var(--muted);
123
- }
124
- .split {
125
- display: grid;
126
- grid-template-columns: 1fr auto;
127
- gap: 10px;
128
- align-items: center;
129
- }
130
- .btnrow {
131
- display: flex;
132
- gap: 10px;
133
- flex-wrap: wrap;
134
- }
135
- button {
136
- cursor: pointer;
137
- background: var(--accent);
138
- color: #fff;
139
- border: none;
140
- padding: 10px 14px;
141
- border-radius: 12px;
142
- font-weight: 600;
143
- }
144
- button.ghost {
145
- background: #f8fafc;
146
- color: var(--text);
147
- border: 1px solid #dbe2ea;
148
- }
149
- pre.wrap {
150
- white-space: pre-wrap;
151
- overflow-wrap: anywhere;
152
- word-break: break-word;
153
- overflow-x: hidden;
154
- overflow-y: auto;
155
- }
156
- .list {
157
- margin: 0.25rem 0 0.75rem 1.1rem;
158
- padding: 0;
159
- }
160
- .list li {
161
- margin: 0.1rem 0;
162
- }
163
- .list.compact li {
164
- margin: 0;
165
- }
166
- </style>
167
- </head>
168
- <body>
169
- <header>
170
- <h1>Eco Route</h1>
171
- </header>
172
-
173
- <main>
174
- <section id="controls">
175
- <div class="split">
176
- <h2>Run Demo</h2>
177
- <div class="btnrow">
178
- <button id="btn-run">Evaluate</button>
179
- <button class="ghost" id="btn-copy">Copy result JSON</button>
180
- </div>
181
- </div>
182
- </section>
183
-
184
- <section id="decision">
185
- <h2>Decision</h2>
186
- <div class="kvs">
187
- <div class="muted">Answer</div>
188
- <div id="ans">—</div>
189
- <div class="muted">Reason why</div>
190
- <div id="why" class="wrap">Data &amp; policies loaded. Click <em>Evaluate</em>.</div>
191
- <div class="muted">Check (harness)</div>
192
- <div id="check" class="wrap">—</div>
193
- </div>
194
- </section>
195
-
196
- <section id="data">
197
- <h2>Data (JSON)</h2>
198
- <pre class="mono wrap" id="data-json"></pre>
199
- </section>
200
-
201
- <section id="policies">
202
- <h2>Policies (declarative JSON rules)</h2>
203
- <pre class="mono wrap" id="policies-json"></pre>
204
- <h3>Machine Trace (debug)</h3>
205
- <!-- switched to <pre> to ensure one-per-line display -->
206
- <pre class="log mono" id="trace"></pre>
207
- </section>
208
-
209
- <section id="timeline">
210
- <h2>Timeline</h2>
211
- <div class="timeline" id="timeline-items">
212
- <div class="card muted">Run the demo to populate results.</div>
213
- </div>
214
- </section>
215
- </main>
216
-
217
- <script>
218
- /* Error surface */
219
- window.onerror = function (msg, src, line, col, err) {
220
- var t = document.getElementById('trace');
221
- if (t) {
222
- t.textContent = 'JS error: ' + msg + ' @ ' + line + ':' + col + (err && err.stack ? '\n' + err.stack : '');
223
- }
224
- };
225
-
226
- /*** DATA (pure JSON) ***/
227
- var Data = {
228
- context: { depot: 'DepotX', preferEco: true },
229
- threshold: { fuelIndex: 100 },
230
- routes: {
231
- current: 'curRoute',
232
- alt: 'altRoute',
233
- },
234
- // Base figures chosen to reproduce the expected outputs
235
- metrics: {
236
- fuelIndex_current: 120.0,
237
- fuelIndex_alt: 99.0,
238
- comfort_current: 53.0,
239
- comfort_alt: 48.0,
240
- },
241
- };
242
-
243
- /*** ARC-style declarative rules (pure JSON) — R1..R5 ***/
244
- var ARC_RULES = [
245
- {
246
- id: 'R1-Envelope',
247
- if: [{ pred: 'preferEco', s: 'User', o: true }],
248
- then: [{ pred: 'envelope', s: 'Req', o: 'insight' }],
249
- explain: 'If user prefers eco, emit an insight envelope.',
250
- },
251
- {
252
- id: 'R2-ShowBannerWhenOverThreshold',
253
- if: [
254
- { pred: 'gt', s: 'fi_current', o: 'threshold' },
255
- { pred: 'depot', s: 'Ctx', o: '?D' },
256
- ],
257
- then: [{ pred: 'showEcoBanner', s: 'Req', o: '?D' }],
258
- explain: 'If FI(current) > T, banner is shown at the depot.',
259
- },
260
- {
261
- id: 'R3-SuggestAlt',
262
- if: [
263
- { pred: 'lt', s: 'fi_alt', o: 'fi_current' },
264
- { pred: 'routeAlt', s: 'Ctx', o: '?R' },
265
- ],
266
- then: [{ pred: 'suggestRoute', s: 'Req', o: '?R' }],
267
- explain: 'If FI(alt) < FI(current), suggest the alternative route.',
268
- },
269
- {
270
- id: 'R4-AltWithinThreshold',
271
- if: [{ pred: 'le', s: 'fi_alt', o: 'threshold' }],
272
- then: [{ pred: 'altWithinThreshold', s: 'Req', o: true }],
273
- explain: 'If FI(alt) ≤ T, alt is within threshold.',
274
- },
275
- {
276
- id: 'R5-InsightReady',
277
- if: [
278
- { pred: 'envelope', s: 'Req', o: 'insight' },
279
- { pred: 'showEcoBanner', s: 'Req', o: '?D' },
280
- { pred: 'suggestRoute', s: 'Req', o: '?R' },
281
- { pred: 'altWithinThreshold', s: 'Req', o: true },
282
- ],
283
- then: [{ pred: 'insightReady', s: 'Req', o: true }],
284
- explain: 'Envelope + banner + suggestion + threshold OK ⇒ ready.',
285
- },
286
- ];
287
-
288
- /*** Pretty printer for rules (inline IF/THEN atoms; per-line; wrapped) ***/
289
- function formatInlineObject(o) {
290
- var order = ['pred', 's', 'o', 'not'];
291
- var keys = Object.keys(o).sort(function (a, b) {
292
- var ai = order.indexOf(a),
293
- bi = order.indexOf(b);
294
- if (ai === -1 && bi === -1) return a < b ? -1 : a > b ? 1 : 0;
295
- if (ai === -1) return 1;
296
- if (bi === -1) return -1;
297
- return ai - bi;
298
- });
299
- var parts = keys.map(function (k) {
300
- var v = o[k],
301
- vs = typeof v === 'string' ? JSON.stringify(v) : typeof v === 'boolean' ? String(v) : JSON.stringify(v);
302
- return JSON.stringify(k) + ':' + vs;
303
- });
304
- return '{' + parts.join(',') + '}';
305
- }
306
- function formatRules(rules) {
307
- var out = ['['];
308
- for (var i = 0; i < rules.length; i++) {
309
- var r = rules[i];
310
- out.push(' {');
311
- out.push(' "id": ' + JSON.stringify(r.id) + ',');
312
- out.push(' "if": [ ' + (r.if || []).map(formatInlineObject).join(', ') + ' ],');
313
- var thenLine = ' "then": [ ' + (r.then || []).map(formatInlineObject).join(', ') + ' ]';
314
- if (r.explain !== undefined) thenLine += ',';
315
- out.push(thenLine);
316
- if (r.explain !== undefined) out.push(' "explain": ' + JSON.stringify(r.explain));
317
- out.push(' }' + (i < rules.length - 1 ? ',' : ''));
318
- }
319
- out.push(']');
320
- return out.join('\n');
321
- }
322
-
323
- /*** Tiny ARC forward chainer ***/
324
- function isVar(x) {
325
- return typeof x === 'string' && x[0] === '?';
326
- }
327
- function subst(term, theta) {
328
- var t = { pred: term.pred, s: term.s, o: term.o };
329
- if (isVar(t.s) && theta[t.s] !== undefined) t.s = theta[t.s];
330
- if (isVar(t.o) && theta[t.o] !== undefined) t.o = theta[t.o];
331
- return t;
332
- }
333
- function unifyAtom(pattern, fact, theta) {
334
- if (pattern.pred !== fact.pred) return null;
335
- var s = Object.assign({}, theta || {});
336
- function bind(pv, fv) {
337
- if (isVar(pv)) {
338
- if (s[pv] === undefined) {
339
- s[pv] = fv;
340
- return true;
341
- }
342
- return s[pv] === fv;
343
- }
344
- return pv === fv;
345
- }
346
- if (!bind(pattern.s, fact.s)) return null;
347
- if (!bind(pattern.o, fact.o)) return null;
348
- return s;
349
- }
350
- function matchBody(body, facts) {
351
- function extend(i, theta, acc) {
352
- if (i === body.length) {
353
- acc.push(theta);
354
- return;
355
- }
356
- var atom = body[i];
357
- if (atom.not) {
358
- var any = false;
359
- for (var k = 0; k < facts.length; k++) {
360
- if (unifyAtom(atom, facts[k], theta)) {
361
- any = true;
362
- break;
363
- }
364
- }
365
- if (!any) extend(i + 1, theta, acc);
366
- return;
367
- }
368
- for (var k = 0; k < facts.length; k++) {
369
- var t2 = unifyAtom(atom, facts[k], theta);
370
- if (t2) extend(i + 1, t2, acc);
371
- }
372
- }
373
- var out = [];
374
- extend(0, {}, out);
375
- return out;
376
- }
377
- function factKey(f) {
378
- return f.pred + '|' + JSON.stringify(f.s) + '|' + JSON.stringify(f.o);
379
- }
380
- function containsFact(facts, f) {
381
- var key = factKey(f);
382
- for (var i = 0; i < facts.length; i++) {
383
- if (factKey(facts[i]) === key) return true;
384
- }
385
- return false;
386
- }
387
- function derive(facts, rules) {
388
- var added = true,
389
- trace = [];
390
- while (added) {
391
- added = false;
392
- for (var r = 0; r < rules.length; r++) {
393
- var rule = rules[r];
394
- var thetas = matchBody(rule.if, facts);
395
- for (var t = 0; t < thetas.length; t++) {
396
- for (var j = 0; j < rule.then.length; j++) {
397
- var f = subst(rule.then[j], thetas[t]);
398
- if (!containsFact(facts, f)) {
399
- facts.push(f);
400
- trace.push('[' + rule.id + '] ' + JSON.stringify(f));
401
- added = true;
402
- }
403
- }
404
- }
405
- }
406
- }
407
- return { facts: facts, trace: trace };
408
- }
409
-
410
- /*** Base facts + specialized numeric reasoning ***/
411
- function factsFromData(d) {
412
- var F = [];
413
- function add(pred, s, o) {
414
- F.push({ pred: pred, s: s, o: o });
415
- }
416
- // Inputs
417
- add('preferEco', 'User', d.context.preferEco);
418
- add('depot', 'Ctx', d.context.depot);
419
- add('routeAlt', 'Ctx', d.routes.alt);
420
- // Fuel index numbers & threshold
421
- var fi1 = d.metrics.fuelIndex_current,
422
- fi2 = d.metrics.fuelIndex_alt,
423
- T = d.threshold.fuelIndex;
424
- add('fi', 'current', fi1);
425
- add('fi', 'alt', fi2);
426
- add('threshold', 'fuel', T);
427
- // Comparator helpers (JS provides)
428
- if (fi1 > T) add('gt', 'fi_current', 'threshold');
429
- if (fi2 < fi1) add('lt', 'fi_alt', 'fi_current');
430
- if (fi2 <= T) add('le', 'fi_alt', 'threshold');
431
- // Comfort
432
- add('comfort', 'current', d.metrics.comfort_current);
433
- add('comfort', 'alt', d.metrics.comfort_alt);
434
- // Estimated saving (rounded to nearest 10, as per example key values)
435
- var exactSaving = +(fi1 - fi2).toFixed(2);
436
- var estSaving = Math.round((fi1 - fi2) / 10) * 10; // → 20.00
437
- add('saving', 'exact', exactSaving);
438
- add('saving', 'estimated', +estSaving.toFixed(2));
439
- return F;
440
- }
441
-
442
- /*** Render helpers ***/
443
- function $(s) {
444
- return document.querySelector(s);
445
- }
446
- function el(tag, attrs, children) {
447
- attrs = attrs || {};
448
- children = children || [];
449
- var n = document.createElement(tag);
450
- for (var k in attrs) {
451
- if (!attrs.hasOwnProperty(k)) continue;
452
- var v = attrs[k];
453
- if (k === 'class') n.className = v;
454
- else if (k === 'html') n.innerHTML = v;
455
- else if (k.indexOf('on') === 0) n.addEventListener(k.slice(2), v);
456
- else n.setAttribute(k, v);
457
- }
458
- for (var i = 0; i < children.length; i++) n.append(children[i]);
459
- return n;
460
- }
461
- function escapeHTML(s) {
462
- return String(s).replace(/[&<>"']/g, function (c) {
463
- return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
464
- });
465
- }
466
-
467
- /*** Main evaluation ***/
468
- function runOnce() {
469
- try {
470
- // Show Data & Policies
471
- $('#data-json').textContent = JSON.stringify(Data, null, 2);
472
- $('#policies-json').textContent = formatRules(ARC_RULES);
473
-
474
- // Build facts & derive
475
- var baseFacts = factsFromData(Data);
476
- var closure = derive(baseFacts.slice(), ARC_RULES);
477
-
478
- // Pull derived values
479
- function get(pred, s) {
480
- var f = closure.facts.find(function (x) {
481
- return x.pred === pred && x.s === s;
482
- });
483
- return f ? f.o : null;
484
- }
485
- function getO(pred) {
486
- var f = closure.facts.find(function (x) {
487
- return x.pred === pred;
488
- });
489
- return f ? f.o : null;
490
- }
491
-
492
- var fi1 = get('fi', 'current');
493
- var fi2 = get('fi', 'alt');
494
- var comfort1 = get('comfort', 'current');
495
- var comfort2 = get('comfort', 'alt');
496
- var bannerAt = getO('showEcoBanner');
497
- var suggest = getO('suggestRoute');
498
- var estSave = get('saving', 'estimated');
499
- var exactSave = get('saving', 'exact');
500
-
501
- // Answer
502
- $('#ans').innerHTML =
503
- '<strong class="ok">✅ Insight envelope</strong>' +
504
- '<div class="small">—</div>' +
505
- '<div class="mono small">fuelIndex_current = ' +
506
- fi1.toFixed(2) +
507
- '</div>' +
508
- '<div class="mono small">fuelIndex_alt = ' +
509
- fi2.toFixed(2) +
510
- '</div>' +
511
- '<div class="mono small">showEcoBanner = ' +
512
- escapeHTML(bannerAt || '—') +
513
- '</div>' +
514
- '<div class="mono small">suggestRoute = ' +
515
- escapeHTML(suggest || '—') +
516
- '</div>' +
517
- '<div class="mono small">estimatedSaving = ' +
518
- estSave.toFixed(2) +
519
- '</div>' +
520
- '<div class="mono small">comfortIndex_current = ' +
521
- comfort1.toFixed(1) +
522
- '</div>' +
523
- '<div class="mono small">comfortIndex_alt = ' +
524
- comfort2.toFixed(1) +
525
- '</div>';
526
-
527
- // Reason why
528
- var why =
529
- '<div>We apply the five N3 rules <strong>R1–R5</strong> to the input facts.</div>' +
530
- '<div style="margin-top:.4rem"><strong>Key derived values:</strong></div>' +
531
- '<ul class="list mono">' +
532
- '<li>FI(current) = ' +
533
- fi1.toFixed(2) +
534
- '</li>' +
535
- '<li>FI(alt) = ' +
536
- fi2.toFixed(2) +
537
- '</li>' +
538
- '<li>Saving = ' +
539
- estSave.toFixed(2) +
540
- '</li>' +
541
- '<li>Banner at = ' +
542
- escapeHTML(bannerAt || '—') +
543
- '</li>' +
544
- '<li>Suggest = ' +
545
- escapeHTML(suggest || '—') +
546
- '</li>' +
547
- '<li>Comfort(cur)= ' +
548
- comfort1.toFixed(1) +
549
- '</li>' +
550
- '<li>Comfort(alt)= ' +
551
- comfort2.toFixed(1) +
552
- '</li>' +
553
- '</ul>';
554
- $('#why').innerHTML = why;
555
-
556
- // Checks (harness) — cross-check exact numbers and conditions
557
- var c1 = fi1 === 120;
558
- var c2 = fi2 === 99;
559
- var condBanner = fi1 > Data.threshold.fuelIndex;
560
- var condSuggest = fi2 < fi1;
561
- var condAltOk = fi2 <= Data.threshold.fuelIndex;
562
- var checks = [
563
- ' FI(current) = ' + fi1.toFixed(2),
564
- ' FI(alt) = ' + fi2.toFixed(2),
565
- ' Banner condition (FI1>T)? ' + (condBanner ? '✓' : '✗'),
566
- ' Suggest alt (FI2<FI1)? ' + (condSuggest ? '✓' : '✗'),
567
- ' Alt within threshold (FI2≤T)? ' + (condAltOk ? '✓' : '✗'),
568
- ' Saving = ' + exactSave.toFixed(2),
569
- ' All checks passed ✓',
570
- ];
571
- $('#check').innerHTML =
572
- '<ul class="list mono">' +
573
- checks
574
- .map(function (x) {
575
- return '<li>' + escapeHTML(x) + '</li>';
576
- })
577
- .join('') +
578
- '</ul>';
579
-
580
- // Trace, timeline, stash
581
- $('#trace').textContent = closure.trace.join('\n');
582
- pushTimeline(
583
- { ans: 'Insight envelope' },
584
- { answer: 'Allowed', reason: 'Eco insight derived (banner & suggestion ready).' },
585
- );
586
- window.__lastResult = {
587
- data: Data,
588
- facts: baseFacts,
589
- derived: closure.facts,
590
- trace: closure.trace,
591
- values: {
592
- fi1: fi1,
593
- fi2: fi2,
594
- comfort1: comfort1,
595
- comfort2: comfort2,
596
- bannerAt: bannerAt,
597
- suggest: suggest,
598
- estSave: estSave,
599
- exactSave: exactSave,
600
- },
601
- ts: new Date().toISOString(),
602
- };
603
- } catch (e) {
604
- var t = document.getElementById('trace');
605
- if (t) t.textContent = 'Evaluate error: ' + ((e && e.stack) || e);
606
- }
607
- }
608
-
609
- /*** Timeline ***/
610
- function pushTimeline(meta, res) {
611
- var box = document.getElementById('timeline-items');
612
- var card = el('div', { class: 'card' });
613
- var when = new Date().toLocaleString();
614
- card.innerHTML =
615
- '<div class="row" style="justify-content:space-between"><strong>✅ Insight</strong><span class="muted small">' +
616
- when +
617
- '</span></div>' +
618
- '<div class="small">' +
619
- (res.reason || '') +
620
- '</div>';
621
- box.prepend(card);
622
- }
623
-
624
- /*** Boot ***/
625
- function boot() {
626
- document.getElementById('data-json').textContent = JSON.stringify(Data, null, 2);
627
- document.getElementById('policies-json').textContent = formatRules(ARC_RULES);
628
- document.getElementById('btn-run').addEventListener('click', runOnce);
629
- document.getElementById('btn-copy').addEventListener('click', function () {
630
- try {
631
- var payload = JSON.stringify(window.__lastResult || { error: 'no-result' }, null, 2);
632
- navigator.clipboard.writeText(payload);
633
- var b = document.getElementById('btn-copy');
634
- var old = b.textContent;
635
- b.textContent = 'Copied!';
636
- setTimeout(function () {
637
- b.textContent = old;
638
- }, 1000);
639
- } catch (e) {
640
- alert('Copy failed: ' + e.message);
641
- }
642
- });
643
- }
644
- window.addEventListener('DOMContentLoaded', function () {
645
- try {
646
- boot();
647
- } catch (e) {
648
- var t = document.getElementById('trace');
649
- if (t) t.textContent = 'Boot error: ' + ((e && e.stack) || e);
650
- }
651
- });
652
- if (document.readyState !== 'loading') {
653
- try {
654
- boot();
655
- } catch (e) {
656
- var t = document.getElementById('trace');
657
- if (t) t.textContent = 'Boot error: ' + ((e && e.stack) || e);
658
- }
659
- }
660
- </script>
661
- </body>
662
- </html>