@polycode-projects/the-mechanical-code-talker 4.0.0 → 4.1.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.
- package/README.md +178 -9
- package/corpus/reference/index.json.gz +0 -0
- package/corpus/reference/manifest.json +8 -8
- package/corpus/reference/shards/ref-00.jsonl.gz +0 -0
- package/corpus/sprites/src/sprite-facts.jsonl +401 -0
- package/corpus/worlds/index.json.gz +0 -0
- package/corpus/worlds/manifest.json +49 -9
- package/corpus/worlds/shards/greyvale-museum.jsonl.gz +0 -0
- package/corpus/worlds/shards/lantern-cottage.jsonl.gz +0 -0
- package/corpus/worlds/shards/mud-hollow.jsonl.gz +0 -0
- package/corpus/worlds/shards/mud-warren.jsonl.gz +0 -0
- package/corpus/worlds/shards/spider-fly.jsonl.gz +0 -0
- package/corpus/worlds/src/greyvale-museum.jsonl +136 -0
- package/corpus/worlds/src/lantern-cottage.jsonl +60 -0
- package/corpus/worlds/src/mud-hollow.jsonl +82 -0
- package/corpus/worlds/src/mud-warren.jsonl +124 -0
- package/corpus/worlds/src/spider-fly.jsonl +1 -1
- package/data/sprites/animal-icon.toml +11 -5
- package/data/sprites/book-icon.toml +9 -5
- package/data/sprites/cabinet-icon.toml +10 -5
- package/data/sprites/cellar-icon.toml +16 -6
- package/data/sprites/container-icon.toml +7 -3
- package/data/sprites/desk-icon.toml +8 -5
- package/data/sprites/dog-icon.toml +8 -5
- package/data/sprites/dog-with-colour-icon.toml +13 -12
- package/data/sprites/drawing-room-icon.toml +14 -5
- package/data/sprites/egg-icon.toml +6 -3
- package/data/sprites/fly-icon.toml +10 -5
- package/data/sprites/furniture-icon.toml +5 -3
- package/data/sprites/garden-icon.toml +10 -3
- package/data/sprites/key-icon.toml +3 -1
- package/data/sprites/kitchen-icon.toml +15 -6
- package/data/sprites/lamp-icon.toml +9 -4
- package/data/sprites/letter-icon.toml +7 -4
- package/data/sprites/library-icon.toml +14 -3
- package/data/sprites/pan-icon.toml +7 -3
- package/data/sprites/person-icon.toml +6 -2
- package/data/sprites/poodle-icon.toml +1 -1
- package/data/sprites/portable-icon.toml +6 -4
- package/data/sprites/portrait-icon.toml +7 -4
- package/data/sprites/room-icon.toml +11 -2
- package/data/sprites/spider-icon.toml +9 -3
- package/data/sprites/study-icon.toml +10 -2
- package/package.json +5 -4
- package/src/adapters/memory/core.mjs +20 -0
- package/src/domain/ask-vocab.mjs +71 -0
- package/src/domain/ask.mjs +168 -0
- package/src/domain/game-config.mjs +11 -0
- package/src/domain/grammar/ace.mjs +40 -4
- package/src/domain/grammar/lexicon-core.json +2 -1
- package/src/domain/grammar/lexicon.mjs +18 -0
- package/src/domain/mud-facts.mjs +15 -0
- package/src/domain/reference-pack.mjs +31 -7
- package/src/domain/router/drive.mjs +35 -9
- package/src/domain/router/registry.mjs +24 -4
- package/src/domain/router/resolver.mjs +102 -40
- package/src/domain/scene-compose.mjs +117 -0
- package/src/domain/spider-fly-world.mjs +37 -1
- package/src/domain/sprite-facts.mjs +0 -0
- package/src/domain/sprite-request.mjs +156 -0
- package/src/domain/sprite-templates.mjs +169 -20
- package/src/services/adventure-editor.mjs +8 -14
- package/src/services/adventure-viz.mjs +209 -157
- package/src/services/adventure.mjs +526 -391
- package/src/services/chat-page-viz.mjs +69 -25
- package/src/services/chat.mjs +200 -51
- package/src/services/code-explorer-viz.mjs +102 -62
- package/src/services/extract-facts.mjs +4 -7
- package/src/services/ingest-viz.mjs +68 -82
- package/src/services/ledger-viz.mjs +136 -67
- package/src/services/memory-panel-viz.mjs +62 -0
- package/src/services/mud-editor.mjs +10 -15
- package/src/services/mud-turn.mjs +6 -6
- package/src/services/mud-viz.mjs +1016 -208
- package/src/services/p2p-room.mjs +90 -23
- package/src/services/plan-pddl.mjs +3 -1
- package/src/services/plan-viz.mjs +123 -64
- package/src/services/research-viz.mjs +160 -108
- package/src/services/spider-fly-turn.mjs +15 -23
- package/src/services/spider-fly-viz.mjs +146 -161
- package/src/services/spider-fly.mjs +69 -11
- package/src/services/sprite-catalog-viz.mjs +414 -240
- package/src/services/viz-boot.mjs +71 -0
- package/src/services/viz-room-graph.mjs +203 -0
- package/src/services/viz-theme.mjs +90 -1
- package/src/services/viz-ticker.mjs +22 -0
- package/src/surfaces/web/adventure-browser-entry.mjs +49 -33
- package/src/surfaces/web/chat-browser-entry.mjs +30 -105
- package/src/surfaces/web/code-explorer-browser-entry.mjs +168 -24
- package/src/surfaces/web/ingest-browser-entry.mjs +3 -13
- package/src/surfaces/web/ledger-browser-entry.mjs +7 -47
- package/src/surfaces/web/memory-ask-browser.bundle.js +127 -124
- package/src/surfaces/web/memory-stats.mjs +11 -0
- package/src/surfaces/web/mud-browser-entry.mjs +71 -29
- package/src/surfaces/web/plan-browser-entry.mjs +22 -40
- package/src/surfaces/web/research-browser-entry.mjs +26 -41
- package/src/surfaces/web/spider-fly-browser-entry.mjs +45 -28
- package/src/surfaces/web/sprites-browser-entry.mjs +14 -27
- package/src/surfaces/web/turn-session.mjs +120 -0
- package/src/tools/definitions.mjs +30 -0
- package/src/tools/handlers/index.mjs +6 -3
- package/src/tools/handlers/kit.mjs +19 -2
- package/src/tools/handlers/tmct-ask.mjs +11 -6
- package/src/tools/handlers/tmct-ingest.mjs +5 -1
- package/src/tools/handlers/tmct-related.mjs +4 -4
- package/src/tools/handlers/tmct-sprite.mjs +147 -0
- package/src/tools/memory-fallthrough.mjs +9 -2
- package/src/tools/server.mjs +25 -1
|
@@ -15,14 +15,54 @@
|
|
|
15
15
|
// doesn't do: it reads the checked-in chat-dock engine bundle.
|
|
16
16
|
|
|
17
17
|
import { loadMemory, readFactRows, findContradictions, normFactTerm } from "../adapters/memory/core.mjs";
|
|
18
|
-
import { THEME_TOKENS_CSS,
|
|
18
|
+
import { THEME_TOKENS_CSS, MONO_STACK, escapeHtml, embedJson, countLabel, TOKENS } from "./viz-theme.mjs";
|
|
19
19
|
import { createTicker, prefersReducedMotion } from "./viz-ticker.mjs";
|
|
20
|
+
import { bfsLevels } from "../domain/planning.mjs";
|
|
21
|
+
import { pluralOf } from "../domain/inflect.mjs";
|
|
20
22
|
import { readFile } from "node:fs/promises";
|
|
21
23
|
import { fileURLToPath } from "node:url";
|
|
22
24
|
import { dirname, join } from "node:path";
|
|
23
25
|
|
|
24
26
|
const LEDGER_ROW_LIMIT_DEFAULT = 20000;
|
|
25
27
|
|
|
28
|
+
// The ledger reads as an observability dashboard (dense stat tiles, bar
|
|
29
|
+
// panels, a log-style fact stream) rather than an editorial page, so its
|
|
30
|
+
// chrome runs the system sans everywhere instead of THEME_TOKENS_CSS's
|
|
31
|
+
// serif body face; MONO_STACK still carries every metric, label, and log row.
|
|
32
|
+
const DASH_SANS_STACK = `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif`;
|
|
33
|
+
|
|
34
|
+
// This page pins a dark, New-Relic-style dashboard register in BOTH site
|
|
35
|
+
// themes — a deliberate departure from THEME_TOKENS_CSS's light/dark switch,
|
|
36
|
+
// which every other generated page still follows. --taught/--corpus/--entail/
|
|
37
|
+
// --alert stay the shared semantic provenance tokens; here they're pinned to
|
|
38
|
+
// their dark-theme-friendly values, read straight off viz-theme.mjs's own
|
|
39
|
+
// exported TOKENS.dark table so this page's palette can never drift from the
|
|
40
|
+
// one every other generated page's dark mode uses. The tier alphas (.35/.65/1)
|
|
41
|
+
// match TOKENS's own tier scale; the four "soft" tints use higher alphas than
|
|
42
|
+
// THEME_TOKENS_CSS's shared soft tokens on purpose — this dashboard chrome
|
|
43
|
+
// wants a more visible tint against its always-dark background than the
|
|
44
|
+
// light/dark-switching pages need, so those four alphas stay page-specific.
|
|
45
|
+
function hexRgb(hex) {
|
|
46
|
+
const n = parseInt(hex.slice(1), 16);
|
|
47
|
+
return `${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}`;
|
|
48
|
+
}
|
|
49
|
+
const DASH_DARK_CHROME_CSS = (() => {
|
|
50
|
+
const t = TOKENS.dark;
|
|
51
|
+
const [taught, corpus, entail] = [hexRgb(t.taught), hexRgb(t.corpus), hexRgb(t.entail)];
|
|
52
|
+
return `
|
|
53
|
+
:root { color-scheme: dark; }
|
|
54
|
+
body {
|
|
55
|
+
--bg: ${t.bg}; --ink: ${t.ink}; --muted: ${t.muted}; --line: ${t.line}; --card: ${t.card};
|
|
56
|
+
--taught: ${t.taught}; --corpus: ${t.corpus}; --entail: ${t.entail}; --alert: ${t.alert};
|
|
57
|
+
--taught-t1: rgba(${taught},.35); --taught-t2: rgba(${taught},.65); --taught-t3: rgba(${taught},1);
|
|
58
|
+
--corpus-t1: rgba(${corpus},.35); --corpus-t2: rgba(${corpus},.65); --corpus-t3: rgba(${corpus},1);
|
|
59
|
+
--entail-t1: rgba(${entail},.35); --entail-t2: rgba(${entail},.65); --entail-t3: rgba(${entail},1);
|
|
60
|
+
--taught-soft: rgba(${taught},.14); --corpus-soft: rgba(${corpus},.14);
|
|
61
|
+
--entail-soft: rgba(${entail},.16); --alert-soft: rgba(${hexRgb(t.alert)},.16);
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
})();
|
|
65
|
+
|
|
26
66
|
/** Read the checked-in browser memory-ask-engine bundle
|
|
27
67
|
* (`src/surfaces/web/memory-ask-browser.bundle.js`) — the real memory-graph answer engine
|
|
28
68
|
* (chat.mjs's factAnswer/factReadBack) the chat dock runs on. Returns `""`,
|
|
@@ -407,7 +447,7 @@ function dashboardHtml(stats, { fresh = false } = {}) {
|
|
|
407
447
|
const total = s.totalFacts || 0;
|
|
408
448
|
const freshCls = fresh ? " fresh" : "";
|
|
409
449
|
if (!total) {
|
|
410
|
-
return `<section class="dash${freshCls}" id="dash" aria-label="Ledger metrics"><div class="tile"><span class="tile-label">facts.total</span><span class="tile-value">0</span><span class="tile-sub">nothing taught yet</span></div></section>`;
|
|
450
|
+
return `<section class="dash${freshCls}" id="dash" aria-label="Ledger metrics"><div class="kpirow"><div class="tile"><span class="tile-label">facts.total</span><span class="tile-value">0</span><span class="tile-sub">nothing taught yet</span></div></div></section>`;
|
|
411
451
|
}
|
|
412
452
|
const terms = s.totalTerms || 0;
|
|
413
453
|
const qualityCls = s.contradictionCount > 0 ? " tile-alert" : "";
|
|
@@ -415,33 +455,42 @@ function dashboardHtml(stats, { fresh = false } = {}) {
|
|
|
415
455
|
const predicatesHtml = s.predicates?.length
|
|
416
456
|
? microbarsHtml(s.predicates.map((p) => ({ label: p.phrase || p.predicate, count: p.count })))
|
|
417
457
|
: `<span class="tile-sub">none yet</span>`;
|
|
458
|
+
// Two explicit-column grids — a 4-up KPI row, then a 2-up row of bar-chart
|
|
459
|
+
// tiles — instead of one auto-fill grid: auto-fill's column count depends
|
|
460
|
+
// on viewport width, so a wide-tile mid-row wrap used to strand empty
|
|
461
|
+
// tracks on the right of both rows. Both stay `.tile` (the dashboard-strip
|
|
462
|
+
// e2e test counts six of them under `.dash`, whatever their sub-grid).
|
|
418
463
|
return `<section class="dash${freshCls}" id="dash" aria-label="Ledger metrics">
|
|
419
|
-
<div class="
|
|
420
|
-
<
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
<
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
<
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
<
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
<span class="tile-label">corpus.bundles</span>
|
|
440
|
-
<div class="bundlebars">${bundlesHtml}</div>
|
|
464
|
+
<div class="kpirow">
|
|
465
|
+
<div class="tile">
|
|
466
|
+
<span class="tile-label">facts.total</span>
|
|
467
|
+
<span class="tile-value">${total}</span>
|
|
468
|
+
<span class="tile-sub">${countLabel(terms, "term")} tracked</span>
|
|
469
|
+
</div>
|
|
470
|
+
<div class="tile tile-tier">
|
|
471
|
+
<span class="tile-label">facts.by-tier</span>
|
|
472
|
+
${tierTileHtml(s.byProv || {}, total)}
|
|
473
|
+
</div>
|
|
474
|
+
<div class="tile">
|
|
475
|
+
<span class="tile-label">graph.avg-degree</span>
|
|
476
|
+
<span class="tile-value">${(s.density || 0).toFixed(1)}</span>
|
|
477
|
+
<span class="tile-sub">facts per term</span>
|
|
478
|
+
</div>
|
|
479
|
+
<div class="tile${qualityCls}">
|
|
480
|
+
<span class="tile-label">data.quality</span>
|
|
481
|
+
<span class="tile-value">${s.contradictionCount || 0}</span>
|
|
482
|
+
<span class="tile-sub">${s.contradictionCount === 1 ? "term" : pluralOf("term")} with more than one answer</span>
|
|
483
|
+
</div>
|
|
441
484
|
</div>
|
|
442
|
-
<div class="
|
|
443
|
-
<
|
|
444
|
-
|
|
485
|
+
<div class="barpanels">
|
|
486
|
+
<div class="tile tile-bars">
|
|
487
|
+
<span class="tile-label">corpus.bundles</span>
|
|
488
|
+
<div class="bundlebars">${bundlesHtml}</div>
|
|
489
|
+
</div>
|
|
490
|
+
<div class="tile tile-bars">
|
|
491
|
+
<span class="tile-label">predicate.top</span>
|
|
492
|
+
<div class="bundlebars">${predicatesHtml}</div>
|
|
493
|
+
</div>
|
|
445
494
|
</div>
|
|
446
495
|
</section>`;
|
|
447
496
|
}
|
|
@@ -508,7 +557,7 @@ export function renderLedgerHtml({ rows, terms, edges, focus, contradictions, wo
|
|
|
508
557
|
const ledgerJson = embedJson({ rows: rows || [], terms: terms || [], edges: edges || [], focus: focus || null, contradictions: contradictions || [], worthALook: worthALook || null, meta: meta || { shown: 0, total: 0, truncated: false }, focusDigest: focusDigest || null, digestStructures: Array.isArray(digestStructures) ? digestStructures : [] });
|
|
509
558
|
const payloadJson = embedJson(payload || { individuals: [], objectProperties: [] });
|
|
510
559
|
const shown = meta?.shown ?? (rows || []).length;
|
|
511
|
-
const title = `tmct ledger — ${shown
|
|
560
|
+
const title = `tmct ledger — ${countLabel(shown, "fact")}${focus ? ` (focus: ${escapeHtml(focus)})` : ""}`;
|
|
512
561
|
const bundleStr = typeof memoryAskBundle === "string" ? memoryAskBundle : "";
|
|
513
562
|
const hasMemChat = bundleStr.length > 0;
|
|
514
563
|
// The placeholder is honest: the canonical exchange only when its terms are
|
|
@@ -534,7 +583,7 @@ export function renderLedgerHtml({ rows, terms, edges, focus, contradictions, wo
|
|
|
534
583
|
<button type="button" id="ingestToggle" class="dockbtn">ingest text…</button>
|
|
535
584
|
<button type="button" id="exportFacts" class="dockbtn">export facts</button>
|
|
536
585
|
</div>
|
|
537
|
-
<div class="researchrow" title="Fetches the topic from Simple English Wikipedia into this graph, then queues the topics its lead section links to
|
|
586
|
+
<div class="researchrow" title="Fetches the topic from Simple English Wikipedia into this graph, then queues the topics its lead section links to. Each queued topic runs as its own dock turn, paced politely. Asking is the network consent for these fetches.">
|
|
538
587
|
<label for="researchTopic" class="mono">research:</label>
|
|
539
588
|
<input id="researchTopic" type="text" autocomplete="off" spellcheck="false"
|
|
540
589
|
placeholder="a topic, e.g. owls" aria-label="Topic to research on Simple English Wikipedia">
|
|
@@ -544,7 +593,7 @@ export function renderLedgerHtml({ rows, terms, edges, focus, contradictions, wo
|
|
|
544
593
|
</div>
|
|
545
594
|
<div class="ingestpanel" id="ingestPanel" hidden>
|
|
546
595
|
<textarea id="ingestText" spellcheck="false" aria-label="Text to ingest into the graph"
|
|
547
|
-
placeholder="Paste text or drop a .txt/.md file. Each sentence it recognizes as a fact is added to the graph
|
|
596
|
+
placeholder="Paste text or drop a .txt/.md file. Each sentence it recognizes as a fact is added to the graph. The rest are skipped."></textarea>
|
|
548
597
|
<div class="ingestrow">
|
|
549
598
|
<button type="button" class="dockbtn" id="ingestBrowse">browse…</button>
|
|
550
599
|
<input type="file" id="ingestFile" accept=".txt,.md,text/plain,text/markdown" hidden>
|
|
@@ -562,7 +611,7 @@ export function renderLedgerHtml({ rows, terms, edges, focus, contradictions, wo
|
|
|
562
611
|
</form>
|
|
563
612
|
${ingestHtml}
|
|
564
613
|
</div>`
|
|
565
|
-
: `<div class="chat chat-off"><p class="chatnote">
|
|
614
|
+
: `<div class="chat chat-off"><p class="chatnote">Chat unavailable. Run <span class="mono">npm run build:ask-bundle</span> to enable the in-page ask engine.</p></div>`;
|
|
566
615
|
|
|
567
616
|
return `<!doctype html>
|
|
568
617
|
<html lang="en">
|
|
@@ -587,46 +636,52 @@ export function renderLedgerHtml({ rows, terms, edges, focus, contradictions, wo
|
|
|
587
636
|
-->
|
|
588
637
|
<style>
|
|
589
638
|
${THEME_TOKENS_CSS}
|
|
639
|
+
${DASH_DARK_CHROME_CSS}
|
|
590
640
|
html { background: var(--bg); }
|
|
591
|
-
body { margin: 0; background: var(--bg); color: var(--ink); font-family: ${
|
|
641
|
+
body { margin: 0; background: var(--bg); color: var(--ink); font-family: ${DASH_SANS_STACK}; font-size: 15px; line-height: 1.5; }
|
|
592
642
|
.mono { font-family: ${MONO_STACK}; }
|
|
593
|
-
main { max-width:
|
|
643
|
+
main { max-width: 1200px; margin: 0 auto; padding: 1.4rem 1.2rem 3rem; }
|
|
594
644
|
.eyebrow { font-family: ${MONO_STACK}; font-size: .7rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); display: flex; flex-wrap: wrap; gap: .4em 1.2em; margin-bottom: .9rem; }
|
|
595
645
|
button { font: inherit; color: inherit; background: none; border: none; padding: 0; cursor: pointer; }
|
|
596
|
-
button:focus-visible, input:focus-visible { outline: 2px solid var(--
|
|
597
|
-
.topbar { display: flex; flex-wrap: wrap; align-items: center; gap: .8rem;
|
|
646
|
+
button:focus-visible, input:focus-visible { outline: 2px solid var(--corpus); outline-offset: 2px; border-radius: 4px; }
|
|
647
|
+
.topbar { display: flex; flex-wrap: wrap; align-items: center; gap: .8rem; background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: .5rem .7rem; margin-bottom: 1.1rem; }
|
|
598
648
|
.crumbs { display: flex; align-items: center; flex-wrap: wrap; gap: .35rem; font-size: .78rem; }
|
|
599
649
|
.crumbs .sep { color: var(--muted); }
|
|
600
|
-
.crumb { font-family: ${MONO_STACK}; font-size: .74rem; padding: .12rem .5rem; border: 1px solid var(--line); border-radius: 99px; background: var(--
|
|
650
|
+
.crumb { font-family: ${MONO_STACK}; font-size: .74rem; padding: .12rem .5rem; border: 1px solid var(--line); border-radius: 99px; background: var(--bg); }
|
|
601
651
|
.crumb[aria-current="true"] { background: var(--ink); color: var(--bg); border-color: var(--ink); }
|
|
602
652
|
.search { margin-left: auto; display: flex; align-items: center; gap: .5rem; }
|
|
603
|
-
.search input { font-family: ${MONO_STACK}; font-size: .78rem; background: var(--
|
|
653
|
+
.search input { font-family: ${MONO_STACK}; font-size: .78rem; background: var(--bg); color: var(--ink); border: 1px solid var(--line); border-radius: 6px; padding: .3rem .6rem; width: 170px; }
|
|
604
654
|
.search .miss { font-size: .72rem; color: var(--alert); font-family: ${MONO_STACK}; }
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
.
|
|
655
|
+
/* Two explicit-column grids instead of one auto-fill grid: a 4-up KPI row,
|
|
656
|
+
then a 2-up row of bar-chart tiles, so both rows fill the container's
|
|
657
|
+
full width at any viewport rather than stranding a leftover track. */
|
|
658
|
+
.dash { display: flex; flex-direction: column; gap: .6rem; margin: 0 0 1.1rem; }
|
|
659
|
+
.kpirow { display: grid; grid-template-columns: repeat(4, 1fr); gap: .6rem; }
|
|
660
|
+
.barpanels { display: grid; grid-template-columns: repeat(2, 1fr); gap: .6rem; }
|
|
661
|
+
@media (max-width: 700px) { .kpirow { grid-template-columns: repeat(2, 1fr); } .barpanels { grid-template-columns: 1fr; } }
|
|
662
|
+
.tile { background: var(--card); border: 1px solid var(--line); border-left: 3px solid var(--line); border-radius: 6px; padding: .6rem .75rem .65rem; display: flex; flex-direction: column; gap: .18rem; min-width: 0; }
|
|
663
|
+
.tile-alert { border-left-color: var(--alert); }
|
|
609
664
|
.tile-label { font-family: ${MONO_STACK}; font-size: .62rem; letter-spacing: .07em; text-transform: uppercase; color: var(--muted); }
|
|
610
|
-
.tile-value { font-family: ${MONO_STACK}; font-size: 1.
|
|
665
|
+
.tile-value { font-family: ${MONO_STACK}; font-size: 1.6rem; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.15; }
|
|
611
666
|
.tile-alert .tile-value { color: var(--alert); }
|
|
612
667
|
.tile-sub { font-family: ${MONO_STACK}; font-size: .68rem; color: var(--muted); }
|
|
613
|
-
.tierbar { display: flex; height: 8px; border-radius: 99px; overflow: hidden; background: var(--line); margin-top: .
|
|
668
|
+
.tierbar { display: flex; height: 8px; border-radius: 99px; overflow: hidden; background: var(--line); margin-top: .35rem; }
|
|
614
669
|
.tseg { height: 100%; }
|
|
615
670
|
.tseg.t-taught { background: var(--taught); } .tseg.t-corpus { background: var(--corpus); } .tseg.t-entail { background: var(--entail); }
|
|
616
671
|
.tierlegend { display: flex; flex-wrap: wrap; gap: .15rem .7rem; margin-top: .35rem; font-family: ${MONO_STACK}; font-size: .65rem; }
|
|
617
672
|
.tleg.t-taught { color: var(--taught); } .tleg.t-corpus { color: var(--corpus); } .tleg.t-entail { color: var(--entail); }
|
|
618
|
-
.bundlebars { display: flex; flex-direction: column; gap: .
|
|
619
|
-
.bbar { display: grid; grid-template-columns: minmax(0,1fr) 3.4rem 1.6rem; align-items: center; gap: .4rem; font-family: ${MONO_STACK}; font-size: .
|
|
673
|
+
.bundlebars { display: flex; flex-direction: column; gap: .26rem; margin-top: .4rem; }
|
|
674
|
+
.bbar { display: grid; grid-template-columns: minmax(0,1fr) 3.4rem 1.6rem; align-items: center; gap: .4rem; font-family: ${MONO_STACK}; font-size: .7rem; }
|
|
620
675
|
.bblabel { color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
621
676
|
.bbtrack { background: var(--line); border-radius: 99px; height: 5px; overflow: hidden; }
|
|
622
|
-
.bbfill { display: block; height: 100%; background: var(--ink); opacity: .
|
|
677
|
+
.bbfill { display: block; height: 100%; background: var(--ink); opacity: .6; border-radius: 99px; }
|
|
623
678
|
.bbn { color: var(--muted); text-align: right; font-variant-numeric: tabular-nums; }
|
|
624
679
|
.sparkwrap { margin-top: .5rem; }
|
|
625
680
|
.spark { display: block; width: 100%; height: 44px; }
|
|
626
681
|
.spark .fill { fill: var(--muted); opacity: .18; stroke: none; }
|
|
627
682
|
.spark .line { fill: none; stroke: var(--ink); stroke-width: 1.4; }
|
|
628
683
|
.spark .dot { fill: var(--ink); }
|
|
629
|
-
.app { display: grid; grid-template-columns: 190px minmax(0,1fr)
|
|
684
|
+
.app { display: grid; grid-template-columns: 190px minmax(0,1fr) 240px; gap: 1.1rem; grid-template-areas: "rail ledger aside"; align-items: start; }
|
|
630
685
|
.rail { grid-area: rail; } .ledger { grid-area: ledger; } .aside { grid-area: aside; }
|
|
631
686
|
@media (max-width: 880px) { .app { grid-template-columns: 1fr; grid-template-areas: "ledger" "aside" "rail"; } .search { margin-left: 0; } }
|
|
632
687
|
.rail h2, .aside h2 { font-family: ${MONO_STACK}; font-size: .66rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); font-weight: 400; margin: 1rem 0 .4rem; }
|
|
@@ -641,7 +696,7 @@ ${THEME_TOKENS_CSS}
|
|
|
641
696
|
.seg.on.neutral { background: var(--ink); color: var(--bg); } .seg.on.neutral .n { color: var(--bg); }
|
|
642
697
|
.seg.on.c-taught { background: var(--taught); } .seg.on.c-corpus { background: var(--corpus); } .seg.on.c-entail { background: var(--entail); }
|
|
643
698
|
.d-taught { background: var(--taught); } .d-corpus { background: var(--corpus); } .d-entail { background: var(--entail); }
|
|
644
|
-
.focuscard { background: var(--card); border: 1px solid var(--line); border-radius:
|
|
699
|
+
.focuscard { background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: .85rem 1rem; margin-bottom: 1rem; }
|
|
645
700
|
.focuscard .term { font-size: 1.35rem; font-weight: 700; }
|
|
646
701
|
.focuscard .klass, .focuscard .stats { font-family: ${MONO_STACK}; font-size: .72rem; color: var(--muted); margin-top: .3rem; font-variant-numeric: tabular-nums; }
|
|
647
702
|
.focuscard .focusdigest { margin-top: .7rem; font-size: .92rem; line-height: 1.5; }
|
|
@@ -656,8 +711,13 @@ ${THEME_TOKENS_CSS}
|
|
|
656
711
|
.group { margin: 1.1rem 0; }
|
|
657
712
|
.group h3 { font-family: ${MONO_STACK}; font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); font-weight: 400; margin: 0 0 .35rem; display: flex; align-items: baseline; gap: .5rem; }
|
|
658
713
|
.group h3::after { content: ""; flex: 1; border-top: 1px solid var(--line); transform: translateY(-.2em); }
|
|
659
|
-
|
|
660
|
-
|
|
714
|
+
/* The fact stream reads as a dense query-result log: full-width rows, a
|
|
715
|
+
hairline between each, a provenance-colored left rail, no per-row card
|
|
716
|
+
chrome. */
|
|
717
|
+
.rows { display: flex; flex-direction: column; }
|
|
718
|
+
.row { background: transparent; border: none; border-left: 3px solid var(--line); border-bottom: 1px solid var(--line); border-radius: 0; padding: .42rem .7rem; display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem .5rem; font-family: ${MONO_STACK}; font-size: .82rem; }
|
|
719
|
+
.rows .row:last-child { border-bottom: none; }
|
|
720
|
+
.row:hover { background: var(--line); }
|
|
661
721
|
.row.p-taught.t3 { border-left-color: var(--taught-t3); } .row.p-taught.t2 { border-left-color: var(--taught-t2); } .row.p-taught.t1 { border-left-color: var(--taught-t1); }
|
|
662
722
|
.row.p-corpus.t3 { border-left-color: var(--corpus-t3); } .row.p-corpus.t2 { border-left-color: var(--corpus-t2); } .row.p-corpus.t1 { border-left-color: var(--corpus-t1); }
|
|
663
723
|
.row.p-entail.t3 { border-left-color: var(--entail-t3); } .row.p-entail.t2 { border-left-color: var(--entail-t2); } .row.p-entail.t1 { border-left-color: var(--entail-t1); }
|
|
@@ -668,18 +728,18 @@ ${THEME_TOKENS_CSS}
|
|
|
668
728
|
.prov.p-taught { color: var(--taught); background: var(--taught-soft); }
|
|
669
729
|
.prov.p-corpus { color: var(--corpus); background: var(--corpus-soft); }
|
|
670
730
|
.prov.p-entail { color: var(--entail); background: var(--entail-soft); }
|
|
671
|
-
.contra { border: 1px solid var(--alert); border-radius:
|
|
731
|
+
.contra { border: 1px solid var(--alert); border-radius: 6px; padding: .5rem; margin-top: .35rem; }
|
|
672
732
|
.contra .label { font-family: ${MONO_STACK}; font-size: .66rem; color: var(--alert); margin: 0 0 .35rem .2rem; }
|
|
673
|
-
.empty { color: var(--muted); font-size: .
|
|
733
|
+
.empty { color: var(--muted); font-size: .88rem; border: 1px dashed var(--line); border-radius: 6px; padding: .8rem 1rem; }
|
|
674
734
|
.looks { display: flex; flex-direction: column; gap: .45rem; }
|
|
675
|
-
.look { display: block; text-align: left; background: var(--card); border: 1px solid var(--line); border-radius:
|
|
735
|
+
.look { display: block; text-align: left; background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: .5rem .65rem; font-size: .8rem; width: 100%; }
|
|
676
736
|
.look:hover { border-color: var(--ink); }
|
|
677
737
|
.look .tag { display: block; font-family: ${MONO_STACK}; font-size: .62rem; letter-spacing: .06em; text-transform: uppercase; margin-bottom: .18rem; }
|
|
678
738
|
.look.k-taught .tag { color: var(--taught); } .look.k-alert .tag { color: var(--alert); } .look.k-hub .tag { color: var(--corpus); }
|
|
679
|
-
.mapwrap { background: var(--card); border: 1px solid var(--line); border-radius:
|
|
739
|
+
.mapwrap { background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: .45rem; margin-top: .45rem; }
|
|
680
740
|
.mapwrap canvas { display: block; width: 100%; height: 160px; cursor: pointer; }
|
|
681
741
|
.mapnote { font-family: ${MONO_STACK}; font-size: .62rem; color: var(--muted); margin: .3rem .2rem 0; }
|
|
682
|
-
.chat { background: var(--card); border: 1px solid var(--line); border-radius:
|
|
742
|
+
.chat { background: var(--card); border: 1px solid var(--line); border-radius: 6px; padding: .65rem .85rem; margin-bottom: 1rem; }
|
|
683
743
|
.chatlog { display: flex; flex-direction: column; gap: .45rem; max-height: 220px; overflow-y: auto; }
|
|
684
744
|
.chatlog:empty { display: none; }
|
|
685
745
|
.chatlog .u { font-family: ${MONO_STACK}; font-size: .76rem; color: var(--muted); }
|
|
@@ -712,6 +772,7 @@ ${THEME_TOKENS_CSS}
|
|
|
712
772
|
.ingeststatus { font-size: .68rem; color: var(--muted); }
|
|
713
773
|
@media (prefers-reduced-motion: no-preference) {
|
|
714
774
|
.seg, .chip, .look { transition: border-color .12s ease, background-color .12s ease; }
|
|
775
|
+
.row { transition: background-color .1s ease; }
|
|
715
776
|
/* A live teach re-render swaps the dash section wholesale (dashboardHtml
|
|
716
777
|
is called again in full — see the inline script below), so the "this
|
|
717
778
|
just changed" signal has to be an animation on the fresh markup itself,
|
|
@@ -784,6 +845,11 @@ ${ledgerBundleAvailable ? `<script src="./ledger-browser.bundle.js"></script>` :
|
|
|
784
845
|
// escapeHtml/pct by their real names) resolve without a second copy.
|
|
785
846
|
const escapeHtml = esc;
|
|
786
847
|
const pct = ${pct.toString()};
|
|
848
|
+
// pluralOf underlies countLabel's own default-parameter lookup — spliced
|
|
849
|
+
// ahead of it so that lookup resolves the same way it does node-side.
|
|
850
|
+
const pluralOf = ${pluralOf.toString()};
|
|
851
|
+
const countLabel = ${countLabel.toString()};
|
|
852
|
+
const bfsLevels = ${bfsLevels.toString()};
|
|
787
853
|
const tierTileHtml = ${tierTileHtml.toString()};
|
|
788
854
|
const microbarsHtml = ${microbarsHtml.toString()};
|
|
789
855
|
const dashboardHtml = ${dashboardHtml.toString()};
|
|
@@ -916,7 +982,7 @@ ${ledgerBundleAvailable ? `<script src="./ledger-browser.bundle.js"></script>` :
|
|
|
916
982
|
: "";
|
|
917
983
|
let html = '<div class="focuscard"><div class="term">' + esc(focus) + "</div>" +
|
|
918
984
|
'<div class="klass">' + (klass ? esc(klass.phrase + " " + klass.o) : "no class recorded") + "</div>" +
|
|
919
|
-
'<div class="stats">' + all.length + "
|
|
985
|
+
'<div class="stats">' + countLabel(all.length, "fact") + " · " + countLabel(srcs.size, "source") +
|
|
920
986
|
(dates.length ? " · first " + esc(dates[0].slice(0, 10)) + " · last " + esc(dates[dates.length - 1].slice(0, 10)) : "") + "</div>" + digestHtml + "</div>";
|
|
921
987
|
const bracketed = new Set();
|
|
922
988
|
for (const fam of FAMS) {
|
|
@@ -934,7 +1000,7 @@ ${ledgerBundleAvailable ? `<script src="./ledger-browser.bundle.js"></script>` :
|
|
|
934
1000
|
for (const [, grp] of groupsHere) {
|
|
935
1001
|
if (grp.length < 2) continue;
|
|
936
1002
|
grp.forEach((r) => bracketed.add(r.id));
|
|
937
|
-
inner += '<div class="contra"><p class="label">more than one answer on record
|
|
1003
|
+
inner += '<div class="contra"><p class="label">more than one answer on record, shown, not merged</p><div class="rows">' + grp.map(rowHtml).join("") + "</div></div>";
|
|
938
1004
|
}
|
|
939
1005
|
html += '<div class="group"><h3>' + esc(FAM_LABEL[fam]) + '</h3><div class="rows">' + inner + "</div></div>";
|
|
940
1006
|
}
|
|
@@ -952,7 +1018,7 @@ ${ledgerBundleAvailable ? `<script src="./ledger-browser.bundle.js"></script>` :
|
|
|
952
1018
|
looks.push({ cls: "k-taught", tag: "newest teach", target: w.newestTaught.term, body: r ? esc(r.s + " " + r.phrase + " " + r.o) : esc(w.newestTaught.term) });
|
|
953
1019
|
}
|
|
954
1020
|
if (w.contradictions && w.contradictions.count) {
|
|
955
|
-
looks.push({ cls: "k-alert", tag: w.contradictions.count + " with more than one answer", target: w.contradictions.firstFocusTerm, body: '<span class="mono">' + esc(w.contradictions.firstFocusTerm) + "</span> has answers that differ
|
|
1021
|
+
looks.push({ cls: "k-alert", tag: w.contradictions.count + " with more than one answer", target: w.contradictions.firstFocusTerm, body: '<span class="mono">' + esc(w.contradictions.firstFocusTerm) + "</span> has answers that differ. Read both." });
|
|
956
1022
|
}
|
|
957
1023
|
if (w.biggestHub) {
|
|
958
1024
|
looks.push({ cls: "k-hub", tag: "biggest hub", target: w.biggestHub.term, body: '<span class="mono">' + esc(w.biggestHub.term) + "</span> touches " + w.biggestHub.degree + " facts" });
|
|
@@ -979,13 +1045,16 @@ ${ledgerBundleAvailable ? `<script src="./ledger-browser.bundle.js"></script>` :
|
|
|
979
1045
|
if (!focus) return;
|
|
980
1046
|
const color = { taught: cssVar("--taught"), corpus: cssVar("--corpus"), entailed: cssVar("--entail"), entail: cssVar("--entail") };
|
|
981
1047
|
const lineC = cssVar("--line"), inkC = cssVar("--ink");
|
|
982
|
-
const
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1048
|
+
const neighborsOf = (term) => {
|
|
1049
|
+
const out = [];
|
|
1050
|
+
for (const e of LEDGER.edges) {
|
|
1051
|
+
if (e.s === term) out.push(e.o);
|
|
1052
|
+
else if (e.o === term) out.push(e.s);
|
|
1053
|
+
}
|
|
1054
|
+
return out;
|
|
1055
|
+
};
|
|
1056
|
+
const [hop1Level, hop2Level] = bfsLevels(focus, neighborsOf, { maxDepth: 2 });
|
|
1057
|
+
const hop1 = new Set(hop1Level || []), hop2 = new Set(hop2Level || []);
|
|
989
1058
|
const cx = w / 2, cy = h / 2, r1 = 42, r2 = 68;
|
|
990
1059
|
const pos = { [focus]: { x: cx, y: cy } };
|
|
991
1060
|
const place = (set, r) => { const a = [...set].sort(); a.forEach((t, i) => { const ang = (2 * Math.PI * i) / a.length - Math.PI / 2; pos[t] = { x: cx + r * Math.cos(ang), y: cy + r * Math.sin(ang) }; }); };
|
|
@@ -1222,7 +1291,7 @@ ${ledgerBundleAvailable ? `<script src="./ledger-browser.bundle.js"></script>` :
|
|
|
1222
1291
|
const fresh = tmctLedger.computeLedgerDataFromPayload(s.memoryDir.payload, {});
|
|
1223
1292
|
applyLedgerData(fresh);
|
|
1224
1293
|
const skipped = sentences.length - grounded;
|
|
1225
|
-
statusEl.textContent = sentences.length
|
|
1294
|
+
statusEl.textContent = countLabel(sentences.length, "sentence")
|
|
1226
1295
|
+ ", " + grounded + " added" + (skipped ? ", " + skipped + " skipped" : "");
|
|
1227
1296
|
} catch {
|
|
1228
1297
|
statusEl.textContent = "something went wrong ingesting that";
|
|
@@ -1274,7 +1343,7 @@ ${ledgerBundleAvailable ? `<script src="./ledger-browser.bundle.js"></script>` :
|
|
|
1274
1343
|
researchPlayBtn.setAttribute("aria-pressed", String(st.playing));
|
|
1275
1344
|
researchStatusEl.textContent = !researchQueue ? ""
|
|
1276
1345
|
: researchQueue.complete
|
|
1277
|
-
? 'research "' + researchQueue.topic + '" complete \\u2014 ' + researchQueue.done.length
|
|
1346
|
+
? 'research "' + researchQueue.topic + '" complete \\u2014 ' + countLabel(researchQueue.done.length, "topic")
|
|
1278
1347
|
: researchQueue.done.length + " done \\u00b7 " + researchQueue.pending.length + " queued";
|
|
1279
1348
|
}
|
|
1280
1349
|
|
|
@@ -49,6 +49,30 @@ export function statsSummaryLine(stats, bandLabel) {
|
|
|
49
49
|
: stats.total + " starter facts loaded";
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/** Drop every asset the site's service worker has cached, and unregister the
|
|
53
|
+
* worker itself, so the next load reads the shipped files off the network.
|
|
54
|
+
* A page's own taught-facts store lives in IndexedDB, a different store
|
|
55
|
+
* entirely — clearing that alone would still re-seed from whatever copy of
|
|
56
|
+
* chat-seed.json the worker cached, which is the whole reason this exists.
|
|
57
|
+
* Best-effort throughout: a browser with no Cache Storage, no worker, or a
|
|
58
|
+
* storage call that throws just leaves the caller to reload as before.
|
|
59
|
+
* Pure of this module's scope, so it stays `.toString()`-splice safe. */
|
|
60
|
+
export async function clearSiteAssetCaches() {
|
|
61
|
+
try {
|
|
62
|
+
if (globalThis.caches) {
|
|
63
|
+
for (const key of await caches.keys()) {
|
|
64
|
+
if (key.startsWith("tmct-precache-")) await caches.delete(key);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} catch { /* the reload still re-reads whatever the worker will serve */ }
|
|
68
|
+
try {
|
|
69
|
+
if (navigator.serviceWorker && navigator.serviceWorker.getRegistrations) {
|
|
70
|
+
const registrations = await navigator.serviceWorker.getRegistrations();
|
|
71
|
+
await Promise.all(registrations.map((registration) => registration.unregister()));
|
|
72
|
+
}
|
|
73
|
+
} catch { /* an un-unregisterable worker still has an empty cache now */ }
|
|
74
|
+
}
|
|
75
|
+
|
|
52
76
|
/** Fetch `url` reading the body as a stream, reporting (loadedBytes,
|
|
53
77
|
* totalBytes) after every chunk — total is 0 when the response carries no
|
|
54
78
|
* Content-Length. Resolves to a Blob of the whole body. Falls back to a
|
|
@@ -157,3 +181,41 @@ export function renderStatsPanelInto(panelEl, stats, opts) {
|
|
|
157
181
|
}
|
|
158
182
|
}
|
|
159
183
|
}
|
|
184
|
+
|
|
185
|
+
/** The boot statusline while the big engine assets stream in — byte-identical
|
|
186
|
+
* across research-viz.mjs and ingest-viz.mjs, each commenting that it uses
|
|
187
|
+
* "the same aggregator" as the other. `parts` is an array of { loaded, total }
|
|
188
|
+
* byte counts (total 0 when a response carried no Content-Length); with no
|
|
189
|
+
* usable total the line shows loaded bytes alone rather than inventing a
|
|
190
|
+
* denominator. Self-contained, `.toString()`-splice safe. */
|
|
191
|
+
export function loadProgressLine(parts) {
|
|
192
|
+
const mb = (n) => (n / 1048576).toFixed(1);
|
|
193
|
+
let loaded = 0;
|
|
194
|
+
let total = 0;
|
|
195
|
+
let totalKnown = true;
|
|
196
|
+
for (const p of parts || []) {
|
|
197
|
+
loaded += (p && p.loaded) || 0;
|
|
198
|
+
if (p && p.total > 0) total += p.total;
|
|
199
|
+
else totalKnown = false;
|
|
200
|
+
}
|
|
201
|
+
return totalKnown && total > 0
|
|
202
|
+
? "loading the engine… " + mb(loaded) + " MB / " + mb(total) + " MB"
|
|
203
|
+
: "loading the engine… " + mb(loaded) + " MB";
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** One learned/grounded fact as its three canonical cells, plus whichever of
|
|
207
|
+
* the two per-page provenance fields the caller's fact objects carry: `source`
|
|
208
|
+
* (research.html's source key, e.g. "taught"/"seed:conceptnet" — used for the
|
|
209
|
+
* tone dot) and `provenance` (ingest.html's raw ' | '-joined tag string —
|
|
210
|
+
* shown verbatim). Both default to "" when the fact object doesn't carry
|
|
211
|
+
* that field, so either page reads back only the one it populated. Pure,
|
|
212
|
+
* `.toString()`-splice safe. */
|
|
213
|
+
export function factTripleParts(fact) {
|
|
214
|
+
return {
|
|
215
|
+
subject: String((fact && fact.subject) || ""),
|
|
216
|
+
predicate: String((fact && fact.predicate) || ""),
|
|
217
|
+
object: String((fact && fact.object) || ""),
|
|
218
|
+
source: String((fact && fact.source) || ""),
|
|
219
|
+
provenance: String((fact && fact.provenance) || ""),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
@@ -12,11 +12,14 @@
|
|
|
12
12
|
// point is "change what this world is made of" has to speak the vocabulary the
|
|
13
13
|
// world is actually written in, and neither table is a superset of the other.
|
|
14
14
|
//
|
|
15
|
-
//
|
|
16
|
-
// adventure-editor.mjs and the
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
15
|
+
// Every export here but wordBeforeCursor is written locally, and is
|
|
16
|
+
// `.toString()`-splice-safe, the same discipline adventure-editor.mjs and the
|
|
17
|
+
// *-viz render-glue functions hold — mud-viz.mjs splices these straight into
|
|
18
|
+
// mud.html's inline script, which captures a function's own source text and
|
|
19
|
+
// nothing it closes over. A splice-safe function carries its whole dependency
|
|
20
|
+
// graph inside its own body. wordBeforeCursor is a re-export of viz-theme.mjs's
|
|
21
|
+
// shared implementation, itself self-contained and splice-safe the same way —
|
|
22
|
+
// this module no longer keeps its own copy of it.
|
|
20
23
|
//
|
|
21
24
|
// Two predicate families sync differently, for the reason adventure-editor.mjs's
|
|
22
25
|
// own header sets out:
|
|
@@ -34,6 +37,8 @@
|
|
|
34
37
|
// that fails to parse this keystroke must never be read as "this fact is
|
|
35
38
|
// gone".
|
|
36
39
|
|
|
40
|
+
export { wordBeforeCursor } from "./viz-theme.mjs";
|
|
41
|
+
|
|
37
42
|
const PLACEMENT_KIND = "placement";
|
|
38
43
|
const OPENNESS_KIND = "openness";
|
|
39
44
|
const MASS_KIND = "mass";
|
|
@@ -301,13 +306,3 @@ export function planMudEditorSync(rows, state, triples) {
|
|
|
301
306
|
}
|
|
302
307
|
return { toAppend, toRemoveIds };
|
|
303
308
|
}
|
|
304
|
-
|
|
305
|
-
/** The word immediately before `cursorPos` in `text` — a run of letters, digits
|
|
306
|
-
* and hyphens, the shape this vocabulary's own terms take ("underground-space",
|
|
307
|
-
* "mole-1"). Empty when the cursor sits after whitespace or punctuation with no
|
|
308
|
-
* word directly behind it. Pure. */
|
|
309
|
-
export function wordBeforeCursor(text, cursorPos) {
|
|
310
|
-
const head = String(text || "").slice(0, cursorPos);
|
|
311
|
-
const m = head.match(/[A-Za-z][A-Za-z0-9-]*$/);
|
|
312
|
-
return m ? m[0].toLowerCase() : "";
|
|
313
|
-
}
|
|
@@ -50,10 +50,12 @@ import { fnv1a32 } from "../domain/hash.mjs";
|
|
|
50
50
|
import { bfsLevels } from "../domain/planning.mjs";
|
|
51
51
|
import { loadMemory, readFactRows } from "../adapters/memory/core.mjs";
|
|
52
52
|
import { DEFAULT_GAME_CONFIG, mudMassDrainPerTurn } from "../domain/game-config.mjs";
|
|
53
|
+
import { predatorSubjects } from "../domain/mud-facts.mjs";
|
|
53
54
|
import {
|
|
54
55
|
foldWorldState, worldActionRows, runWorldCommand, recordTold, recordExamined,
|
|
55
56
|
recordMassDrain, personKnowledgeLines, objectClassChain, diggableDirections,
|
|
56
57
|
isOutOfPlay, outOfPlayReasonOf, outOfPlayPhrase, massDrainPerTurnOf,
|
|
58
|
+
parseSnapshotSubject,
|
|
57
59
|
} from "./adventure.mjs";
|
|
58
60
|
|
|
59
61
|
const FOOD_CLASS = "food";
|
|
@@ -61,7 +63,6 @@ const LATERAL_DIRECTIONS = ["north", "south", "east", "west"];
|
|
|
61
63
|
// Deep enough to cross a whole burrow without letting one character's
|
|
62
64
|
// pathfinder walk a whole grown world every tick.
|
|
63
65
|
const WALK_SEARCH_DEPTH = 8;
|
|
64
|
-
const SNAPSHOT_RE = /^(.+)@turn(\d+)$/;
|
|
65
66
|
|
|
66
67
|
const EXIT_TOWARD_FOOD_CHANCE = 0.5;
|
|
67
68
|
const EDGE_FOLLOW_DIG_CHANCE = 0.25;
|
|
@@ -208,8 +209,8 @@ function roomsStoodIn(rows, character) {
|
|
|
208
209
|
const visited = new Set();
|
|
209
210
|
for (const row of worldActionRows(rows)) {
|
|
210
211
|
if (row.predicate !== "mgx:currently-in") continue;
|
|
211
|
-
const snapshot =
|
|
212
|
-
if ((snapshot ? snapshot
|
|
212
|
+
const snapshot = parseSnapshotSubject(row.subject);
|
|
213
|
+
if ((snapshot ? snapshot.base : row.subject) !== character) continue;
|
|
213
214
|
visited.add(row.object);
|
|
214
215
|
}
|
|
215
216
|
return visited;
|
|
@@ -220,9 +221,8 @@ function roomsStoodIn(rows, character) {
|
|
|
220
221
|
* funnel straight to the den, since the unvisited room nearest the burrow is
|
|
221
222
|
* exactly where the fox lives. The den stays reachable by the food gamble
|
|
222
223
|
* below, which is a gamble and is meant to be. */
|
|
223
|
-
const predatorRooms = (rows, state) => new Set((rows
|
|
224
|
-
.
|
|
225
|
-
.map((r) => state.placements.get(r.subject)?.object)
|
|
224
|
+
const predatorRooms = (rows, state) => new Set(predatorSubjects(rows)
|
|
225
|
+
.map((subject) => state.placements.get(subject)?.object)
|
|
226
226
|
.filter(Boolean));
|
|
227
227
|
|
|
228
228
|
/**
|