@polycode-projects/the-mechanical-code-talker 6.0.18 → 6.0.20
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 +20 -23
- package/bin/tmct.mjs +16 -33
- package/corpus/LICENSES.json +0 -21
- package/corpus/README.md +10 -13
- package/corpus/reference/manifest.json +19 -19
- package/corpus/reference/shards/ref-01.jsonl.gz +0 -0
- package/corpus/reference/shards/ref-04.jsonl.gz +0 -0
- package/corpus/reference/shards/ref-08.jsonl.gz +0 -0
- package/corpus/reference/shards/ref-10.jsonl.gz +0 -0
- package/corpus/reference/shards/ref-11.jsonl.gz +0 -0
- package/corpus/reference/shards/ref-17.jsonl.gz +0 -0
- package/corpus/reference/shards/ref-20.jsonl.gz +0 -0
- package/corpus/reference/shards/ref-25.jsonl.gz +0 -0
- package/corpus/reference/shards/ref-2c.jsonl.gz +0 -0
- package/corpus/tier2/generate.mjs +6 -142
- package/corpus/tier2/manifest.json +0 -42
- package/package.json +6 -4
- package/src/adapters/corpus/child-seed.mjs +74 -0
- package/src/adapters/corpus/conceptnet.mjs +45 -26
- package/src/adapters/corpus/research-source.mjs +6 -2
- package/src/adapters/corpus/wikidata-live.mjs +92 -51
- package/src/adapters/memory/blocks.mjs +7 -1
- package/src/adapters/memory/core.mjs +505 -107
- package/src/adapters/memory/corpus-bands.mjs +27 -10
- package/src/adapters/memory/inspect.mjs +24 -5
- package/src/adapters/memory/rows.mjs +359 -30
- package/src/adapters/memory/shacl.mjs +10 -3
- package/src/domain/ask.mjs +27 -10
- package/src/domain/cli-verbs.mjs +3 -4
- package/src/domain/completions/group.mjs +8 -3
- package/src/domain/completions/infer.mjs +7 -2
- package/src/domain/completions/prune.mjs +5 -1
- package/src/domain/completions/rank.mjs +7 -2
- package/src/domain/digest/compose.mjs +5 -1
- package/src/domain/digest/select.mjs +12 -6
- package/src/domain/domain.mjs +15 -8
- package/src/domain/el-classify.mjs +11 -2
- package/src/domain/fact-phrase.mjs +86 -4
- package/src/domain/hash.mjs +9 -0
- package/src/domain/memory/bias.mjs +8 -4
- package/src/domain/memory/capability.mjs +12 -6
- package/src/domain/memory/fact-order.mjs +29 -0
- package/src/domain/memory/resolution.mjs +3 -0
- package/src/domain/news-feed.mjs +862 -92
- package/src/domain/reference-pack.mjs +5 -0
- package/src/domain/sense-gate.mjs +220 -0
- package/src/domain/sense-scope.mjs +116 -0
- package/src/domain/sense-split.mjs +1 -1
- package/src/domain/syllogise.mjs +60 -21
- package/src/domain/tableau.mjs +23 -14
- package/src/domain/term-ledger.mjs +16 -1
- package/src/domain/worlds-pack.mjs +5 -1
- package/src/services/adventure-autoplay.mjs +6 -1
- package/src/services/adventure-editor.mjs +43 -21
- package/src/services/adventure-viz.mjs +26 -9
- package/src/services/adventure.mjs +40 -10
- package/src/services/chat.mjs +270 -125
- package/src/services/extensions.mjs +51 -58
- package/src/services/extract-facts.mjs +906 -66
- package/src/services/init.mjs +4 -4
- package/src/services/ledger-viz.mjs +9 -4
- package/src/services/memory-panel-viz.mjs +4 -5
- package/src/services/mud-editor.mjs +40 -16
- package/src/services/mud-viz.mjs +8 -2
- package/src/services/mudiii-turn.mjs +5 -3
- package/src/services/mudiii-viz.mjs +8 -2
- package/src/services/news.mjs +306 -21
- package/src/services/research-viz.mjs +1 -1
- package/src/services/sprite-catalog-viz.mjs +10 -5
- package/src/surfaces/web/adventure-browser-entry.mjs +6 -12
- package/src/surfaces/web/memory-ask-browser.bundle.js +152 -151
- package/src/surfaces/web/mud-browser-entry.mjs +7 -11
- package/src/surfaces/web/research-browser-entry.mjs +5 -2
- package/corpus/tier2/aws.jsonl +0 -39
- package/corpus/tier2/java.jsonl +0 -31
- package/corpus/tier2/python.jsonl +0 -30
package/src/services/init.mjs
CHANGED
|
@@ -199,8 +199,8 @@ source = ${JSON.stringify(config.research.source)}
|
|
|
199
199
|
if (!Object.keys(extras).length) return out;
|
|
200
200
|
return `${out}
|
|
201
201
|
# Extension packs + bias (src/services/extensions.mjs) — written by \`tmct init --with-persona\`
|
|
202
|
-
# or a manual edit. Recognized names (human, seon, code, conceptnet,
|
|
203
|
-
#
|
|
202
|
+
# or a manual edit. Recognized names (human, seon, code, conceptnet, child,
|
|
203
|
+
# namenet, tier2-general) override the shipped defaults; any
|
|
204
204
|
# other name declares a new host-supplied bundle (needs its own "kind").
|
|
205
205
|
# [bias] is a flat bundle-name -> weight table consumed by
|
|
206
206
|
# src/domain/memory/bias.mjs's ranking.
|
|
@@ -298,8 +298,8 @@ export async function initRepo(dir, { force = false, seed, env = process.env, pe
|
|
|
298
298
|
"",
|
|
299
299
|
"Corpus bundles (activate by id — no local copy needed):",
|
|
300
300
|
" tmct import --corpus human | human-medium | human-large",
|
|
301
|
-
" tmct import --corpus
|
|
302
|
-
" tmct import --corpus wordnet-xl | wordnet-full | namenet (large: tens of thousands of facts)",
|
|
301
|
+
" tmct import --corpus code | seon | conceptnet | general",
|
|
302
|
+
" tmct import --corpus wordnet-xl | wordnet-full | namenet | child (large: tens of thousands of facts)",
|
|
303
303
|
"",
|
|
304
304
|
"Ontology / lexicon resources are file paths declared as extension entries:",
|
|
305
305
|
" tmct import --ontology <path> | --lexicon <path>",
|
|
@@ -25,6 +25,11 @@ import { dirname, join } from "node:path";
|
|
|
25
25
|
|
|
26
26
|
const LEDGER_ROW_LIMIT_DEFAULT = 20000;
|
|
27
27
|
|
|
28
|
+
/** Codepoint order, never localeCompare — every string sorted below (a fact
|
|
29
|
+
* row's id or createdAt, a term label, a source bundle key, a predicate) is
|
|
30
|
+
* read off the stored fact set, so two locales have to render the same page. */
|
|
31
|
+
const byCodepoint = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
32
|
+
|
|
28
33
|
// The ledger reads as an observability dashboard (dense stat tiles, bar
|
|
29
34
|
// panels, a log-style fact stream) rather than an editorial page, so its
|
|
30
35
|
// chrome runs the system sans everywhere instead of THEME_TOKENS_CSS's
|
|
@@ -168,7 +173,7 @@ export function computeLedgerDataFromPayload(payload, { focus, term, rowLimit =
|
|
|
168
173
|
src: r.provenance || (r.sourceTypes || []).join(" ") || "unrecorded",
|
|
169
174
|
};
|
|
170
175
|
});
|
|
171
|
-
rows.sort((a, b) => (b.createdAt || ""
|
|
176
|
+
rows.sort((a, b) => byCodepoint(b.createdAt || "", a.createdAt || "") || byCodepoint(a.id, b.id));
|
|
172
177
|
|
|
173
178
|
// Term index + adjacency.
|
|
174
179
|
const termMap = new Map(); // term -> { degree, best: {trust, prov}, newest }
|
|
@@ -187,7 +192,7 @@ export function computeLedgerDataFromPayload(payload, { focus, term, rowLimit =
|
|
|
187
192
|
}
|
|
188
193
|
const terms = [...termMap.values()]
|
|
189
194
|
.map(({ term: t, degree, prov, newest }) => ({ term: t, degree, prov, newest }))
|
|
190
|
-
.sort((a, b) => b.degree - a.degree || a.term
|
|
195
|
+
.sort((a, b) => b.degree - a.degree || byCodepoint(a.term, b.term));
|
|
191
196
|
const edges = rows.map((r) => ({ s: r.s, o: r.o, id: r.id }));
|
|
192
197
|
|
|
193
198
|
// Focus: the asked term when it resolves; otherwise the newest taught
|
|
@@ -382,11 +387,11 @@ export function computeLedgerStats(rows, terms, contradictions) {
|
|
|
382
387
|
}
|
|
383
388
|
const bundles = [...bundleCounts.entries()]
|
|
384
389
|
.map(([key, count]) => ({ key, label: bundleLabelFor(key), count }))
|
|
385
|
-
.sort((a, b) => b.count - a.count || a.key
|
|
390
|
+
.sort((a, b) => b.count - a.count || byCodepoint(a.key, b.key))
|
|
386
391
|
.slice(0, BUNDLE_TOP_N);
|
|
387
392
|
const predicates = [...predicateCounts.entries()]
|
|
388
393
|
.map(([predicate, v]) => ({ predicate, phrase: v.phrase, count: v.count }))
|
|
389
|
-
.sort((a, b) => b.count - a.count || a.predicate
|
|
394
|
+
.sort((a, b) => b.count - a.count || byCodepoint(a.predicate, b.predicate))
|
|
390
395
|
.slice(0, PREDICATE_TOP_N);
|
|
391
396
|
|
|
392
397
|
const totalDegree = (terms || []).reduce((sum, t) => sum + (t.degree || 0), 0);
|
|
@@ -23,10 +23,9 @@ export function bandLabelFor(key) {
|
|
|
23
23
|
"human-large": "human persona (large)",
|
|
24
24
|
seon: "seon ontology",
|
|
25
25
|
conceptnet: "ConceptNet",
|
|
26
|
-
"tier2-aws": "AWS",
|
|
27
|
-
"tier2-python": "Python",
|
|
28
|
-
"tier2-java": "Java",
|
|
29
26
|
"wordnet-xl": "WordNet",
|
|
27
|
+
namenet: "NameNet",
|
|
28
|
+
child: "child vocabulary",
|
|
30
29
|
};
|
|
31
30
|
return BAND_LABELS[key] || key;
|
|
32
31
|
}
|
|
@@ -39,7 +38,7 @@ export function bandLabelFor(key) {
|
|
|
39
38
|
export function statsSummaryLine(stats, bandLabel) {
|
|
40
39
|
const BAND_ORDER = [
|
|
41
40
|
"human", "human-medium", "human-large", "seon", "conceptnet",
|
|
42
|
-
"
|
|
41
|
+
"wordnet-xl", "namenet", "child",
|
|
43
42
|
"taught this session", "other",
|
|
44
43
|
];
|
|
45
44
|
if (!stats || !stats.total) return "no starter memory; starting empty";
|
|
@@ -172,7 +171,7 @@ export function renderStatsPanelInto(panelEl, stats, opts) {
|
|
|
172
171
|
const { bandLabel, taughtHint, onForget = null, persistNote = null } = opts;
|
|
173
172
|
const BAND_ORDER = [
|
|
174
173
|
"human", "human-medium", "human-large", "seon", "conceptnet",
|
|
175
|
-
"
|
|
174
|
+
"wordnet-xl", "namenet", "child",
|
|
176
175
|
"taught this session", "other",
|
|
177
176
|
];
|
|
178
177
|
function bandRow(label, count) {
|
|
@@ -24,10 +24,15 @@
|
|
|
24
24
|
// Two predicate families sync differently, for the reason adventure-editor.mjs's
|
|
25
25
|
// own header sets out:
|
|
26
26
|
// - PLACEMENT (currently-in/located-in/fixed-in/hidden-in), OPENNESS and MASS
|
|
27
|
-
// are fold-versioned — foldWorldState
|
|
28
|
-
//
|
|
29
|
-
// an edit to one is a plain new write superseding the old,
|
|
30
|
-
// retraction.
|
|
27
|
+
// are fold-versioned — foldWorldState ranks these rows by the (epoch, turn)
|
|
28
|
+
// pair stamped on the subject, which is how every turn's own move and mass
|
|
29
|
+
// drain lands — so an edit to one is a plain new write superseding the old,
|
|
30
|
+
// never a retraction. The superseding write is stamped one turn past the
|
|
31
|
+
// world's own turn count, exactly the way every in-game action's commit()
|
|
32
|
+
// writes, so it OUTRANKS what it replaces instead of merely arriving after
|
|
33
|
+
// it — at equal turn the fold takes whichever row comes later in the array,
|
|
34
|
+
// and array order is nobody's to promise once a peer's facts have merged
|
|
35
|
+
// in. Mass belongs here and not below precisely because it MOVES: a
|
|
31
36
|
// playing animal's weight is a fold over turn snapshots, so an editor
|
|
32
37
|
// diffing raw mass rows would show the seed and fight the drain.
|
|
33
38
|
// - Everything else (typing, the class hierarchy, exits, the predator flag,
|
|
@@ -37,6 +42,8 @@
|
|
|
37
42
|
// that fails to parse this keystroke must never be read as "this fact is
|
|
38
43
|
// gone".
|
|
39
44
|
|
|
45
|
+
import { snapshotSubject } from "../domain/world-snapshot.mjs";
|
|
46
|
+
|
|
40
47
|
export { wordBeforeCursor } from "./viz-theme.mjs";
|
|
41
48
|
|
|
42
49
|
const PLACEMENT_KIND = "placement";
|
|
@@ -296,15 +303,26 @@ export function editableMudOtherRows(rows) {
|
|
|
296
303
|
|
|
297
304
|
/** Plan the fact-store writes one parsed edit implies, from already-parsed
|
|
298
305
|
* `triples` against the world's current `rows`/`state`. Returns
|
|
299
|
-
* `{ toAppend, toRemoveIds }` — pure, no I/O.
|
|
306
|
+
* `{ toAppend, toRemoveIds, editTurn }` — pure, no I/O. `toAppend` rows are
|
|
307
|
+
* store-ready: a fold-versioned one already carries its `subject@turnN`
|
|
308
|
+
* stamp, and `editTurn` is the turn every one of them was stamped at, for
|
|
309
|
+
* the caller's own provenance tag.
|
|
310
|
+
*
|
|
311
|
+
* Placement, openness and mass triples are never retracted: one joins
|
|
312
|
+
* `toAppend` only when it actually differs from the subject's current folded
|
|
313
|
+
* value, so re-asserting an unchanged line doesn't append a no-op duplicate
|
|
314
|
+
* per keystroke. Each one is stamped one turn past the world's own turn
|
|
315
|
+
* count, which is what makes it outrank the row it supersedes rather than
|
|
316
|
+
* tie with it and win on array position.
|
|
300
317
|
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
*
|
|
304
|
-
*
|
|
305
|
-
* `toRemoveIds` is safe to apply, and must skip it whenever the parse reported
|
|
306
|
-
* any unrecognized line. */
|
|
318
|
+
* Everything else keeps its bare subject — every reader takes those raw, and
|
|
319
|
+
* a stamped one names a subject no verb resolves. They get a real add/remove
|
|
320
|
+
* diff — but the CALLER decides whether `toRemoveIds` is safe to apply, and
|
|
321
|
+
* must skip it whenever the parse reported any unrecognized line. */
|
|
307
322
|
export function planMudEditorSync(rows, state, triples) {
|
|
323
|
+
const editTurn = (state?.turnCount ?? 0) + 1;
|
|
324
|
+
const editEpoch = state?.epoch ?? 0;
|
|
325
|
+
const stampedForFold = (t) => ({ ...t, subject: snapshotSubject(t.subject, editTurn, editEpoch) });
|
|
308
326
|
const toAppend = [];
|
|
309
327
|
// One "already said this" set per fold-versioned family, never one shared set:
|
|
310
328
|
// a subject can carry a placement, an openness and a mass at once, and a
|
|
@@ -320,13 +338,13 @@ export function planMudEditorSync(rows, state, triples) {
|
|
|
320
338
|
seen.add(t.subject);
|
|
321
339
|
if (t.kind === PLACEMENT_KIND) {
|
|
322
340
|
const current = state.placements?.get(t.subject);
|
|
323
|
-
if (!current || current.predicate !== t.predicate || current.object !== t.object) toAppend.push(t);
|
|
341
|
+
if (!current || current.predicate !== t.predicate || current.object !== t.object) toAppend.push(stampedForFold(t));
|
|
324
342
|
} else if (t.kind === OPENNESS_KIND) {
|
|
325
343
|
const current = state.openness?.get(t.subject);
|
|
326
|
-
if (!current || current.open !== (t.object === "true")) toAppend.push(t);
|
|
344
|
+
if (!current || current.open !== (t.object === "true")) toAppend.push(stampedForFold(t));
|
|
327
345
|
} else {
|
|
328
346
|
const current = state.masses?.get(t.subject);
|
|
329
|
-
if (!current || Number(current.value) !== Number(t.object)) toAppend.push(t);
|
|
347
|
+
if (!current || Number(current.value) !== Number(t.object)) toAppend.push(stampedForFold(t));
|
|
330
348
|
}
|
|
331
349
|
}
|
|
332
350
|
|
|
@@ -342,7 +360,7 @@ export function planMudEditorSync(rows, state, triples) {
|
|
|
342
360
|
for (const [key, id] of currentKeys) {
|
|
343
361
|
if (!newOtherKeys.has(key)) toRemoveIds.push(id);
|
|
344
362
|
}
|
|
345
|
-
return { toAppend, toRemoveIds };
|
|
363
|
+
return { toAppend, toRemoveIds, editTurn };
|
|
346
364
|
}
|
|
347
365
|
|
|
348
366
|
/** The additive half of planMudEditorSync, for ONE already-parsed triple: the
|
|
@@ -350,7 +368,13 @@ export function planMudEditorSync(rows, state, triples) {
|
|
|
350
368
|
* document says what the world contains, so a fact missing from it has gone;
|
|
351
369
|
* one sentence only ever says what it says, so nothing it leaves out is
|
|
352
370
|
* evidence of anything. Re-asserting a fact the world already holds appends
|
|
353
|
-
* nothing, and `reason` says which of the two happened. Pure.
|
|
371
|
+
* nothing, and `reason` says which of the two happened. Pure.
|
|
372
|
+
*
|
|
373
|
+
* The triple comes back with its bare subject, unlike planMudEditorSync's
|
|
374
|
+
* rows: a taught sentence can MINT the thing it talks about, and the caller
|
|
375
|
+
* picks the fresh id, so only the caller knows which subject the fold stamp
|
|
376
|
+
* belongs on. world-teach.mjs stamps a fold-versioned one at `turnCount + 1`
|
|
377
|
+
* there, for the same reason planMudEditorSync does. */
|
|
354
378
|
export function planTaughtMudTriple(rows, state, triple) {
|
|
355
379
|
if (!triple?.subject || !triple?.object) return { toAppend: [], reason: "nothing parsed" };
|
|
356
380
|
if (triple.kind === PLACEMENT_KIND) {
|
package/src/services/mud-viz.mjs
CHANGED
|
@@ -170,7 +170,10 @@ export function carriedItemsFor(rows, state, character) {
|
|
|
170
170
|
return [...state.placements]
|
|
171
171
|
.filter(([, p]) => p.predicate === "mgx:located-in" && p.object === character)
|
|
172
172
|
.map(([subject]) => ({ subject, spriteClass: spriteClassForObject(rows, subject) }))
|
|
173
|
-
|
|
173
|
+
// Codepoint order, never localeCompare — inlined, not a module-level
|
|
174
|
+
// helper, because this function is spliced verbatim into the page's own
|
|
175
|
+
// inline script and can carry no outer-scope reference with it.
|
|
176
|
+
.sort((a, b) => (a.subject < b.subject ? -1 : a.subject > b.subject ? 1 : 0));
|
|
174
177
|
}
|
|
175
178
|
|
|
176
179
|
/** Every room's depth level, `Map<roomId, number>`, BFS from `root` at level
|
|
@@ -1994,7 +1997,10 @@ function pageScript() {
|
|
|
1994
1997
|
svg: creature ? spriteSvgFor(speciesOfCharacter(subject), editRows, subject) : objectSvgFor(subject, editRows),
|
|
1995
1998
|
});
|
|
1996
1999
|
}
|
|
1997
|
-
|
|
2000
|
+
// Codepoint order, never localeCompare — a placed subject traces back to
|
|
2001
|
+
// a world fact, and two readers must render the same room-detail cast
|
|
2002
|
+
// order regardless of the browser's own locale.
|
|
2003
|
+
here.sort(function (a, b) { return a.subject < b.subject ? -1 : a.subject > b.subject ? 1 : 0; });
|
|
1998
2004
|
castEl.innerHTML = here.map(function (t) { return editCardHtml(t.subject, t.label, t.svg); }).join("");
|
|
1999
2005
|
const kind = roomKindForRoom(editRows, selectedRoomId);
|
|
2000
2006
|
const ways = [...(editState.exits.get(selectedRoomId) || new Map()).keys()].sort();
|
|
@@ -805,10 +805,12 @@ const PLACED_BY_PREDICATE = "mgx:placed-by";
|
|
|
805
805
|
|
|
806
806
|
// The families foldTownSquareState ranks by (epoch, turn). A row in one of
|
|
807
807
|
// them needs a snapshot subject or it ranks as turn 0 and loses to anything
|
|
808
|
-
// already played about the same thing. mgx:placed-by is
|
|
809
|
-
//
|
|
808
|
+
// already played about the same thing. mgx:placed-by is one of them: placeFood
|
|
809
|
+
// writes the item's first placer under a bare subject when it mints the item,
|
|
810
|
+
// so a taught placer that stayed bare too would tie with it at turn 0 and win
|
|
811
|
+
// only by sitting later in the array.
|
|
810
812
|
const TAUGHT_SNAPSHOT_PREDICATES = new Set([
|
|
811
|
-
PLACEMENT_PREDICATE, MASS_PREDICATE, MOOD_PREDICATE, FACING_PREDICATE,
|
|
813
|
+
PLACEMENT_PREDICATE, MASS_PREDICATE, MOOD_PREDICATE, FACING_PREDICATE, PLACED_BY_PREDICATE,
|
|
812
814
|
]);
|
|
813
815
|
|
|
814
816
|
// The closed cast vocabulary a taught sentence may name, matching the lane's
|
|
@@ -230,7 +230,10 @@ export function propPlacementsFrom(rows, assetManifest) {
|
|
|
230
230
|
asset: byKey.get(entry.model) || null,
|
|
231
231
|
});
|
|
232
232
|
}
|
|
233
|
-
|
|
233
|
+
// Codepoint order, never localeCompare — inlined, not a module-level
|
|
234
|
+
// helper, because this function is spliced verbatim into the page's own
|
|
235
|
+
// inline script and can carry no outer-scope reference with it.
|
|
236
|
+
placements.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
234
237
|
return placements;
|
|
235
238
|
}
|
|
236
239
|
|
|
@@ -286,7 +289,10 @@ export function currentPlacementsFrom(rows) {
|
|
|
286
289
|
for (const [subject, entry] of latest) {
|
|
287
290
|
if (!gone.has(subject)) placements.push({ subject, cell: entry.cell });
|
|
288
291
|
}
|
|
289
|
-
|
|
292
|
+
// Codepoint order, never localeCompare — inlined, not a module-level
|
|
293
|
+
// helper, because this function is spliced verbatim into the page's own
|
|
294
|
+
// inline script and can carry no outer-scope reference with it.
|
|
295
|
+
placements.sort((a, b) => (a.subject < b.subject ? -1 : a.subject > b.subject ? 1 : 0));
|
|
290
296
|
return placements;
|
|
291
297
|
}
|
|
292
298
|
|