@polycode-projects/the-mechanical-code-talker 1.8.20 → 1.9.1
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 +27 -6
- package/ROADMAP.md +1 -1
- package/bin/tmct.mjs +167 -20
- package/corpus/generated/README.md +2 -2
- package/corpus/namenet/LICENSE-NOTICE +68 -0
- package/corpus/namenet/generate.mjs +309 -0
- package/corpus/namenet/manifest.json +20 -0
- package/corpus/namenet/namenet.jsonl +7260 -0
- package/corpus/wordnet/LICENSE-NOTICE +49 -0
- package/corpus/wordnet/generate.mjs +333 -0
- package/corpus/wordnet/manifest.json +34 -0
- package/corpus/wordnet/wordnet-full.jsonl +192498 -0
- package/corpus/wordnet/wordnet-xl.jsonl +23805 -0
- package/package.json +6 -2
- package/src/ask-browser-entry.mjs +13 -2
- package/src/ask-browser.bundle.js +272 -19
- package/src/chat.mjs +229 -82
- package/src/cli-args.mjs +20 -1
- package/src/codegraph.mjs +306 -1
- package/src/corpus/conceptnet-map.toml +17 -12
- package/src/corpus/conceptnet.mjs +23 -1
- package/src/extensions.mjs +44 -1
- package/src/init.mjs +99 -46
- package/src/interpret/normalize.mjs +1 -3
- package/src/memory/core.mjs +191 -14
- package/src/memory/trust.mjs +27 -6
- package/src/memory-ask-browser-entry.mjs +36 -0
- package/src/memory-ask-browser.bundle.js +5544 -0
- package/src/toml-config.mjs +11 -1
- package/src/viz.mjs +548 -73
package/README.md
CHANGED
|
@@ -334,12 +334,23 @@ reasoning). Design detail and the full fact-count tables are in `archive/PLAN_SE
|
|
|
334
334
|
### Memory backends
|
|
335
335
|
|
|
336
336
|
The default memory backend writes an OWL-labelled JSON file under `.tmct/`.
|
|
337
|
-
Two more exist
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
337
|
+
Two more exist: `memory` keeps taught facts in the process only, nothing
|
|
338
|
+
written to disk; `sqlite` persists them to a local SQLite file instead
|
|
339
|
+
(`.tmct/memory/graph.sqlite`).
|
|
340
|
+
|
|
341
|
+
Pick one at init time and it sticks — `tmct init --memory-backend sqlite`
|
|
342
|
+
writes the choice into `tmct.toml`, and every later `tmct chat` in that repo
|
|
343
|
+
uses it with no flag needed:
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
tmct init --memory-backend sqlite # writes [memory] backend = "sqlite" to tmct.toml
|
|
347
|
+
tmct chat # picks it up automatically
|
|
348
|
+
tmct chat --memory-backend memory # override for just this session
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Precedence is `--memory-backend` flag > `TMCT_MEMORY_BACKEND` env > tmct.toml's
|
|
352
|
+
`[memory] backend` > the default. A library caller sets the same thing
|
|
353
|
+
directly: `runChat({ memoryBackend: "sqlite" })`.
|
|
343
354
|
|
|
344
355
|
Teaching isn't limited to the ACE grammar's fixed shapes. Tell tmct an
|
|
345
356
|
arbitrary fact, like "margo really eats ribs", and it mints a fact you can
|
|
@@ -411,6 +422,10 @@ Inside the chat: `/help` lists commands, `/memory` inspects what tmct remembers
|
|
|
411
422
|
(grouped by OWL class, with provenance and any contradictions), `/exit` leaves.
|
|
412
423
|
`TMCT_GRAPH_FILE` overrides the graph location.
|
|
413
424
|
|
|
425
|
+
`tmct --help` (or `npm run help` from a clone of this repo) is the full,
|
|
426
|
+
up-to-date flag reference for every subcommand — a bare `npm run` only lists
|
|
427
|
+
script names, so `npm run help` is the documented way in from there.
|
|
428
|
+
|
|
414
429
|
`tmct init` is the onboarding surface for the repository interface below: it
|
|
415
430
|
creates the `.tmct/` directory, writes the externalized `tmct.toml`
|
|
416
431
|
configuration, seeds the default persona, and records provenance. A host
|
|
@@ -435,17 +450,23 @@ tmct init --lexicon <name|path> # activate a lexicon bundle (never
|
|
|
435
450
|
tmct init --graph <path> [--graph <path> …] # set tmct.toml's graph_file/graph_files
|
|
436
451
|
tmct init --config <path> # write to an alternate tmct.toml location
|
|
437
452
|
tmct init --persona-size medium|large # grow the default persona (Small is default)
|
|
453
|
+
tmct init --memory-backend default|memory|sqlite # write tmct.toml's [memory] backend —
|
|
454
|
+
# every later `tmct chat` here uses it
|
|
438
455
|
|
|
439
456
|
tmct import --corpus <id|path> # activate+seed into an ALREADY-initialized
|
|
440
457
|
tmct import --ontology <name|path> # repo — any combination of these flags in
|
|
441
458
|
tmct import --lexicon <name|path> # one call. --graph is a DIFFERENT, purely
|
|
442
459
|
tmct import --graph <path> # additive op: it appends to graph_files,
|
|
443
460
|
# never activates an extensions bundle.
|
|
461
|
+
tmct import --memory-backend default|memory|sqlite # same knob as `tmct init`, for a
|
|
462
|
+
# repo that's already initialized
|
|
444
463
|
|
|
445
464
|
tmct chat --graph <path> [--graph <path> …] # explicit graph file(s) — multiple merge
|
|
446
465
|
# (ids that collide across graphs are
|
|
447
466
|
# auto-prefixed; see src/graph-merge.mjs)
|
|
448
467
|
tmct chat --config <path> # an alternate tmct.toml (a file or a dir)
|
|
468
|
+
tmct chat --memory-backend default|memory|sqlite # override tmct.toml's backend for
|
|
469
|
+
# just this session
|
|
449
470
|
tmct serve --graph <path> --config <path> # same two flags, for the HTTP endpoint
|
|
450
471
|
```
|
|
451
472
|
|
package/ROADMAP.md
CHANGED
|
@@ -32,7 +32,7 @@ getting silently traded away by inherited caution:
|
|
|
32
32
|
|
|
33
33
|
## What's next (feature-shaped — see `HANDOVER.md` for the current task-level list)
|
|
34
34
|
|
|
35
|
-
- **`PLAN_BREADTH_FIRST_NLU.md`'s own remaining scope** — all six tracks shipped (entity-tie
|
|
35
|
+
- **`archive/PLAN_BREADTH_FIRST_NLU.md`'s own remaining scope** — all six tracks shipped (entity-tie
|
|
36
36
|
ambiguity, router candidate enrichment, `tmct viz` + its embedded chat panel, template-coverage
|
|
37
37
|
harness, alternates-on-hits, canonical representation for the ask/teach lanes — all now in "Current
|
|
38
38
|
capability surface" above). Two named items are satisfied and closed, per their own track's
|
package/bin/tmct.mjs
CHANGED
|
@@ -44,6 +44,9 @@ Usage:
|
|
|
44
44
|
TMCT_NARRATE=1; toggle mid-session with /narrate on|off)
|
|
45
45
|
[--plain] force the plain readline shell (the default when
|
|
46
46
|
stdin/stdout is not a terminal)
|
|
47
|
+
[--memory-backend <default|memory|sqlite>] storage backend for taught facts this
|
|
48
|
+
session (CLI flag > TMCT_MEMORY_BACKEND env > tmct.toml's
|
|
49
|
+
[memory] backend > "default", the flat .tmct/ JSON file)
|
|
47
50
|
tmct memory [--repo <abs>] what tmct remembers: facts, utterances, sessions,
|
|
48
51
|
[--config <path>] folded blocks (the /memory chat command, from the shell)
|
|
49
52
|
[--verbose]
|
|
@@ -66,11 +69,15 @@ Usage:
|
|
|
66
69
|
activates human-large.jsonl (~13,600 facts total,
|
|
67
70
|
with genuine multi-hop hypernym chains) — additive
|
|
68
71
|
size tiers of the SAME bundle, not separate personas
|
|
72
|
+
[--memory-backend <default|memory|sqlite>] write tmct.toml's [memory] backend
|
|
73
|
+
(same flag name as \`tmct chat\`) — a later \`tmct chat\`
|
|
74
|
+
in this repo picks it up with no flag needed
|
|
69
75
|
tmct import [--repo <abs>] activate+seed into an ALREADY-initialized repo (any
|
|
70
76
|
[--corpus <id|path>] combination of these flags in one call). --graph is a
|
|
71
77
|
[--ontology <name|path>] DIFFERENT operation from the others: it APPENDS to
|
|
72
78
|
[--lexicon <name|path>] tmct.toml's graph_files array (multi-graph growth),
|
|
73
79
|
[--graph <path>] never an extensions-bundle activation.
|
|
80
|
+
[--memory-backend <default|memory|sqlite>] same knob as \`tmct init\`
|
|
74
81
|
[--config <path>]
|
|
75
82
|
tmct extend --validate <dir> validate a third-party extension pack's declared
|
|
76
83
|
[--config <path>] resources (corpus/lexicon/templates) before activating
|
|
@@ -80,8 +87,18 @@ Usage:
|
|
|
80
87
|
[--config <path>] bounded, low-trust, retractable entailed facts (never on the chat path)
|
|
81
88
|
tmct viz [--repo <abs>] write one self-contained, navigable HTML file rendering the
|
|
82
89
|
[--focus <id>] memory graph: pan/zoom, click a node for its label/class/
|
|
83
|
-
[--
|
|
84
|
-
[--
|
|
90
|
+
[--term <word>] timestamps. Seeds from the most recently created individual
|
|
91
|
+
[--depth <n>] by default (--focus <id> or --term <word> override it);
|
|
92
|
+
[--limit <n>] --output defaults to graph.html in the cwd.
|
|
93
|
+
[--hub-degree <n>] --depth = max arcs (hops) from the focus node (default 3);
|
|
94
|
+
[--edge-kind <mode>] --limit = spiral length, total nodes walked (default 300);
|
|
95
|
+
[--output <path>] --hub-degree = stop expanding THROUGH a node above N
|
|
96
|
+
[--config <path>] connections, still shows it (default 40); --edge-kind =
|
|
97
|
+
meta|relation|both (default both) — which edge kinds the
|
|
98
|
+
walk follows (provenance-only, concept-relations-only, or
|
|
99
|
+
both — see the page's own edge-kind toggle to change this
|
|
100
|
+
live); --term <word> resolves to the Fact(s) whose subject/
|
|
101
|
+
object normalizes to that word and seeds from there.
|
|
85
102
|
tmct serve [--repo <abs>] run the Anthropic Messages API-compatible endpoint
|
|
86
103
|
[--host <h>] [--port <n>] (POST /v1/messages) over the graph — a deterministic,
|
|
87
104
|
[--graph <path>] no-LLM "model" a tool-loop client can call; $0 usage.
|
|
@@ -96,6 +113,11 @@ In chat: /help lists slash-commands; /exit leaves. Session log → <repo>/.tmct/
|
|
|
96
113
|
Shared graph-path precedence (chat/serve; see src/cli-args.mjs): --graph flag(s) >
|
|
97
114
|
TMCT_GRAPH_FILE env > tmct.toml graph_file/graph_files > --repo-derived
|
|
98
115
|
<repo>/.tmct/graph.json > git-root/cwd default.
|
|
116
|
+
|
|
117
|
+
Memory-backend precedence (chat; see src/chat.mjs createSession): --memory-backend
|
|
118
|
+
flag > TMCT_MEMORY_BACKEND env > tmct.toml [memory] backend > "default" (the flat
|
|
119
|
+
.tmct/ JSON file). Set it once with \`tmct init --memory-backend <...>\` and every
|
|
120
|
+
later \`tmct chat\` in that repo picks it up with no flag needed.
|
|
99
121
|
`;
|
|
100
122
|
|
|
101
123
|
const argv = process.argv.slice(2);
|
|
@@ -330,6 +352,7 @@ async function readConfigForRewrite(repoRoot) {
|
|
|
330
352
|
}
|
|
331
353
|
if (raw?.extensions !== undefined) cfg.extensions = raw.extensions;
|
|
332
354
|
if (raw?.bias !== undefined) cfg.bias = raw.bias;
|
|
355
|
+
if (raw?.memory?.backend !== undefined) cfg.memory = { ...cfg.memory, backend: raw.memory.backend };
|
|
333
356
|
return { raw, cfg };
|
|
334
357
|
}
|
|
335
358
|
|
|
@@ -459,7 +482,27 @@ async function activatePluggableInput(repoRoot, resolved) {
|
|
|
459
482
|
if (!seedable) {
|
|
460
483
|
return `activated "${name}" (${entry.kind}) in tmct.toml — no corpus facts to seed for this kind.\n`;
|
|
461
484
|
}
|
|
462
|
-
|
|
485
|
+
// Backend-aware seeding (same split-brain bug fix as src/init.mjs's own
|
|
486
|
+
// corpus seed, found in review): `cfg.memory.backend` already reflects
|
|
487
|
+
// tmct.toml as it stands RIGHT NOW (readConfigForRewrite, above) — which,
|
|
488
|
+
// for a `tmct init --corpus X --memory-backend sqlite` / `tmct import
|
|
489
|
+
// --corpus X --memory-backend sqlite` combined call, already carries the
|
|
490
|
+
// NEW backend (bin/tmct.mjs's init/import handlers write --memory-backend
|
|
491
|
+
// before running any activation). Resolved via the SAME openMemoryBackend
|
|
492
|
+
// createSession/initRepo use, so this bundle's facts land in the store a
|
|
493
|
+
// later `tmct chat` will actually read.
|
|
494
|
+
const { openMemoryBackend } = await import("../src/memory/core.mjs");
|
|
495
|
+
const backendChoice = String(cfg.memory?.backend || "").trim().toLowerCase();
|
|
496
|
+
if (backendChoice === "memory") {
|
|
497
|
+
return `activated "${name}" (${entry.kind}) in tmct.toml — seeding skipped (memory backend is in-process only, nothing would persist past this command).\n`;
|
|
498
|
+
}
|
|
499
|
+
const { dir: memoryDir, close: closeMemoryStore } = await openMemoryBackend(repoRoot, backendChoice);
|
|
500
|
+
let perBundle;
|
|
501
|
+
try {
|
|
502
|
+
({ perBundle } = await seedActiveCorpusEntries(memoryDir, new Map([[name, entry]])));
|
|
503
|
+
} finally {
|
|
504
|
+
await closeMemoryStore();
|
|
505
|
+
}
|
|
463
506
|
const seeded = perBundle[name];
|
|
464
507
|
if (seeded.error) {
|
|
465
508
|
throw new Error(`could not seed "${name}" — ${seeded.error}`);
|
|
@@ -526,12 +569,25 @@ async function main() {
|
|
|
526
569
|
// TMCT_GRAPH_FILE — see chat.mjs's own docblock at createSession). Omitted from
|
|
527
570
|
// the call entirely when absent, so a plain `tmct chat [--repo]` invocation is
|
|
528
571
|
// byte-identical to before these flags existed.
|
|
529
|
-
const { repeatedFlag, strFlag } = await import("../src/cli-args.mjs");
|
|
572
|
+
const { repeatedFlag, strFlag, enumFlag } = await import("../src/cli-args.mjs");
|
|
530
573
|
const graphPaths = repeatedFlag(rest, ["--graph"]);
|
|
531
574
|
const configPath = strFlag(rest, ["--config"]);
|
|
575
|
+
// `--memory-backend <default|memory|sqlite>`: the CLI's top tier of
|
|
576
|
+
// createSession's memoryBackend precedence (CLI flag > TMCT_MEMORY_BACKEND
|
|
577
|
+
// env > tmct.toml's [memory] backend > built-in default — src/cli-args.mjs's
|
|
578
|
+
// shared precedence order, resolved inside createSession itself). Omitted
|
|
579
|
+
// when absent so the lower tiers still apply unchanged.
|
|
580
|
+
let memoryBackend;
|
|
581
|
+
try {
|
|
582
|
+
memoryBackend = enumFlag(rest, ["--memory-backend"], ["default", "memory", "sqlite"]);
|
|
583
|
+
} catch (e) {
|
|
584
|
+
process.stderr.write(`tmct: ${e?.message || e}\n`);
|
|
585
|
+
process.exit(2);
|
|
586
|
+
}
|
|
532
587
|
const extra = {};
|
|
533
588
|
if (graphPaths.length) extra.graphPaths = graphPaths;
|
|
534
589
|
if (configPath) extra.configPath = configPath;
|
|
590
|
+
if (memoryBackend) extra.memoryBackend = memoryBackend;
|
|
535
591
|
// The shell gate: a real terminal gets the full-screen Ink TUI; `--plain` or a
|
|
536
592
|
// non-TTY stream (pipes, scripts, the test suite) gets the readline shell. Both
|
|
537
593
|
// drive the same createSession sink — only the drawing differs.
|
|
@@ -577,7 +633,7 @@ async function main() {
|
|
|
577
633
|
// subcommand without a --repo flag. It now takes one like every other
|
|
578
634
|
// subcommand, defaulting to cwd exactly as before when absent.
|
|
579
635
|
const rest = process.argv.slice(3);
|
|
580
|
-
const { strFlag, repeatedFlag } = await import("../src/cli-args.mjs");
|
|
636
|
+
const { strFlag, repeatedFlag, enumFlag } = await import("../src/cli-args.mjs");
|
|
581
637
|
const { resolve: resolvePath } = await import("node:path");
|
|
582
638
|
const { initRepo, PERSONA_PRESETS } = await import("../src/init.mjs");
|
|
583
639
|
|
|
@@ -589,6 +645,20 @@ async function main() {
|
|
|
589
645
|
const lexiconVal = strFlag(rest, ["--lexicon"]);
|
|
590
646
|
const graphFlags = repeatedFlag(rest, ["--graph"]);
|
|
591
647
|
|
|
648
|
+
// `--memory-backend <default|memory|sqlite>` (PLAN_SEED.md §6's storage-backend
|
|
649
|
+
// seam, now reachable from `tmct init`): validated BEFORE touching disk, same
|
|
650
|
+
// discipline as every other pluggable input below. Written into tmct.toml's
|
|
651
|
+
// `[memory] backend` (src/init.mjs's renderTomlConfig); chat.mjs's
|
|
652
|
+
// createSession reads it back at CLI-flag > TMCT_MEMORY_BACKEND env >
|
|
653
|
+
// tmct.toml > default precedence (src/cli-args.mjs's shared precedence order).
|
|
654
|
+
let memoryBackendVal;
|
|
655
|
+
try {
|
|
656
|
+
memoryBackendVal = enumFlag(rest, ["--memory-backend"], ["default", "memory", "sqlite"]);
|
|
657
|
+
} catch (e) {
|
|
658
|
+
process.stderr.write(`tmct init: ${e?.message || e}\n`);
|
|
659
|
+
process.exit(2);
|
|
660
|
+
}
|
|
661
|
+
|
|
592
662
|
// Resolve + validate EVERY pluggable input BEFORE touching disk — mirrors
|
|
593
663
|
// `--with-persona`'s own "validate before scaffolding" discipline, and the
|
|
594
664
|
// original `--corpus`'s "unknown id touches nothing" contract.
|
|
@@ -650,7 +720,32 @@ async function main() {
|
|
|
650
720
|
}
|
|
651
721
|
}
|
|
652
722
|
|
|
653
|
-
|
|
723
|
+
// `--memory-backend <default|memory|sqlite>`: written EARLY, before
|
|
724
|
+
// initRepo/any --corpus/--ontology/--lexicon activation below, so every
|
|
725
|
+
// seed step (initRepo's own corpus seed, AND activatePluggableInput's,
|
|
726
|
+
// below) sees the FINAL backend choice. A split-brain bug found in
|
|
727
|
+
// review: writing this AFTER seeding meant corpus facts always landed in
|
|
728
|
+
// the OLD backend, regardless of this flag. Two cases:
|
|
729
|
+
// - tmct.toml doesn't exist yet (the common case): threaded into
|
|
730
|
+
// initRepo() as `memoryBackend`, below — written atomically as part
|
|
731
|
+
// of the SAME fresh config write persona/corpus-limit already use.
|
|
732
|
+
// - tmct.toml already exists and `--force` isn't set (initRepo's own
|
|
733
|
+
// "preserve a user's tmct.toml" rule, same as persona): written HERE,
|
|
734
|
+
// before initRepo/activation run, so this repo's re-seed (if any) and
|
|
735
|
+
// any --corpus/--ontology/--lexicon activation below see it.
|
|
736
|
+
const forceFlag = rest.includes("--force");
|
|
737
|
+
if (memoryBackendVal) {
|
|
738
|
+
const { access } = await import("node:fs/promises");
|
|
739
|
+
const tomlPath = resolvePath(repoRoot, "tmct.toml");
|
|
740
|
+
const tomlAlreadyExists = await access(tomlPath).then(() => true, () => false);
|
|
741
|
+
if (tomlAlreadyExists && !forceFlag) {
|
|
742
|
+
const { cfg } = await readConfigForRewrite(repoRoot);
|
|
743
|
+
cfg.memory = { ...(cfg.memory || {}), backend: memoryBackendVal };
|
|
744
|
+
await writeConfig(repoRoot, cfg);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const res = await initRepo(repoRoot, { force: forceFlag, persona: personaPreset, memoryBackend: memoryBackendVal });
|
|
654
749
|
process.stdout.write(res.message + "\n");
|
|
655
750
|
|
|
656
751
|
// `--corpus`/`--ontology`/`--lexicon` now mean "activate this bundle and
|
|
@@ -689,6 +784,14 @@ async function main() {
|
|
|
689
784
|
anyActivation = true;
|
|
690
785
|
}
|
|
691
786
|
|
|
787
|
+
// `--memory-backend <default|memory|sqlite>`: already WRITTEN by now —
|
|
788
|
+
// either just above (pre-existing tmct.toml) or inside initRepo() itself
|
|
789
|
+
// (a fresh write, `memoryBackend` opt) — this just reports it.
|
|
790
|
+
if (memoryBackendVal) {
|
|
791
|
+
process.stdout.write(`memory backend set in tmct.toml: ${memoryBackendVal}\n`);
|
|
792
|
+
anyActivation = true;
|
|
793
|
+
}
|
|
794
|
+
|
|
692
795
|
if (anyActivation) return;
|
|
693
796
|
|
|
694
797
|
if (rest.includes("--detect")) {
|
|
@@ -719,7 +822,7 @@ async function main() {
|
|
|
719
822
|
// additive operation (appendGraphFiles) — it grows tmct.toml's graph_files
|
|
720
823
|
// array, never activates an extensions bundle.
|
|
721
824
|
const rest = process.argv.slice(3);
|
|
722
|
-
const { strFlag, repeatedFlag } = await import("../src/cli-args.mjs");
|
|
825
|
+
const { strFlag, repeatedFlag, enumFlag } = await import("../src/cli-args.mjs");
|
|
723
826
|
const { resolve: resolvePath } = await import("node:path");
|
|
724
827
|
|
|
725
828
|
const repoFlag = strFlag(rest, ["--repo"]);
|
|
@@ -729,9 +832,19 @@ async function main() {
|
|
|
729
832
|
const ontologyVal = strFlag(rest, ["--ontology"]);
|
|
730
833
|
const lexiconVal = strFlag(rest, ["--lexicon"]);
|
|
731
834
|
const graphFlags = repeatedFlag(rest, ["--graph"]);
|
|
835
|
+
// `--memory-backend <default|memory|sqlite>`: same knob as `tmct init`'s
|
|
836
|
+
// (consistent name, same [memory] backend tmct.toml field) — lets an
|
|
837
|
+
// already-initialized repo change its storage backend without a re-init.
|
|
838
|
+
let memoryBackendVal;
|
|
839
|
+
try {
|
|
840
|
+
memoryBackendVal = enumFlag(rest, ["--memory-backend"], ["default", "memory", "sqlite"]);
|
|
841
|
+
} catch (e) {
|
|
842
|
+
process.stderr.write(`tmct import: ${e?.message || e}\n`);
|
|
843
|
+
process.exit(2);
|
|
844
|
+
}
|
|
732
845
|
|
|
733
|
-
if (!corpusVal && !ontologyVal && !lexiconVal && !graphFlags.length) {
|
|
734
|
-
process.stderr.write("tmct import: needs at least one of --corpus/--ontology/--lexicon/--graph\n");
|
|
846
|
+
if (!corpusVal && !ontologyVal && !lexiconVal && !graphFlags.length && !memoryBackendVal) {
|
|
847
|
+
process.stderr.write("tmct import: needs at least one of --corpus/--ontology/--lexicon/--graph/--memory-backend\n");
|
|
735
848
|
process.exit(2);
|
|
736
849
|
}
|
|
737
850
|
|
|
@@ -745,6 +858,19 @@ async function main() {
|
|
|
745
858
|
process.exit(2);
|
|
746
859
|
}
|
|
747
860
|
|
|
861
|
+
// `--memory-backend` is written FIRST, before any --corpus/--ontology/
|
|
862
|
+
// --lexicon activation below — the same split-brain bug fix as `tmct
|
|
863
|
+
// init`'s ordering: activatePluggableInput seeds into whichever backend
|
|
864
|
+
// tmct.toml names AT THE TIME it runs, so `tmct import --corpus aws
|
|
865
|
+
// --memory-backend sqlite` in one call must have the new backend on disk
|
|
866
|
+
// BEFORE the aws seed step, not after.
|
|
867
|
+
if (memoryBackendVal) {
|
|
868
|
+
const { cfg } = await readConfigForRewrite(repoRoot);
|
|
869
|
+
cfg.memory = { ...(cfg.memory || {}), backend: memoryBackendVal };
|
|
870
|
+
await writeConfig(repoRoot, cfg);
|
|
871
|
+
process.stdout.write(`memory backend set in tmct.toml: ${memoryBackendVal}\n`);
|
|
872
|
+
}
|
|
873
|
+
|
|
748
874
|
for (const resolved of [corpusResolved, ontologyResolved, lexiconResolved]) {
|
|
749
875
|
if (!resolved) continue;
|
|
750
876
|
try {
|
|
@@ -863,24 +989,45 @@ async function main() {
|
|
|
863
989
|
// resolveRuntimeConfig: --repo > git root > cwd.
|
|
864
990
|
const rest = process.argv.slice(3);
|
|
865
991
|
const { strFlag, resolveRuntimeConfig } = await import("../src/cli-args.mjs");
|
|
866
|
-
const { computeVizGraph, renderVizHtml, readAskBundle } = await import("../src/viz.mjs");
|
|
992
|
+
const { computeVizGraph, renderVizHtml, readAskBundle, readMemoryAskBundle } = await import("../src/viz.mjs");
|
|
867
993
|
const { writeFile } = await import("node:fs/promises");
|
|
868
994
|
const { resolve } = await import("node:path");
|
|
995
|
+
const numFlag = (name) => {
|
|
996
|
+
const j = rest.indexOf(name);
|
|
997
|
+
const v = j !== -1 ? Number(rest[j + 1]) : NaN;
|
|
998
|
+
return Number.isFinite(v) ? v : undefined;
|
|
999
|
+
};
|
|
869
1000
|
const focus = strFlag(rest, ["--focus"]);
|
|
1001
|
+
const term = strFlag(rest, ["--term"]); // PLAN_VIZ_MEMORY.md: seed via normFactTerm-matched Fact(s), alongside --focus
|
|
1002
|
+
const depth = numFlag("--depth"); // max arcs (hops) from the focus node
|
|
1003
|
+
const nodeLimit = numFlag("--limit"); // spiral length: total nodes walked
|
|
1004
|
+
const hubDegree = numFlag("--hub-degree"); // stop expanding THROUGH a node above N connections
|
|
1005
|
+
const edgeKindModeRaw = strFlag(rest, ["--edge-kind"]);
|
|
1006
|
+
const edgeKindMode = ["meta", "relation", "both"].includes(edgeKindModeRaw) ? edgeKindModeRaw : undefined;
|
|
870
1007
|
const outPath = resolve(process.cwd(), strFlag(rest, ["--output", "--out"], "graph.html"));
|
|
871
1008
|
const { repo } = await resolveRuntimeConfig({ argv: rest });
|
|
872
|
-
const vizGraph = await computeVizGraph(repo,
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
1009
|
+
const vizGraph = await computeVizGraph(repo, {
|
|
1010
|
+
...(focus ? { focus } : {}),
|
|
1011
|
+
...(!focus && term ? { term } : {}), // --focus takes precedence when both are given
|
|
1012
|
+
...(depth != null ? { depth } : {}),
|
|
1013
|
+
...(nodeLimit != null ? { nodeLimit } : {}),
|
|
1014
|
+
...(hubDegree != null ? { hubDegree } : {}),
|
|
1015
|
+
...(edgeKindMode ? { edgeKindMode } : {}),
|
|
1016
|
+
});
|
|
1017
|
+
// The embedded "Ask the graph" chat panels — TWO real engines, bundled for
|
|
1018
|
+
// the browser (scripts/build-ask-bundle.mjs's checked-in output): the
|
|
1019
|
+
// code-graph ask.mjs engine, and (PLAN_VIZ_MEMORY.md Bug 1 fix) the
|
|
1020
|
+
// memory-graph factAnswer engine. Neither read*AskBundle() ever throws; an
|
|
1021
|
+
// empty string degrades that ONE engine gracefully rather than breaking
|
|
1022
|
+
// the page (e.g. a fresh checkout before the bundles' first build).
|
|
1023
|
+
const [askBundle, memoryAskBundle] = await Promise.all([readAskBundle(), readMemoryAskBundle()]);
|
|
1024
|
+
const html = renderVizHtml({ ...vizGraph, askBundle, memoryAskBundle });
|
|
880
1025
|
await writeFile(outPath, html, "utf8");
|
|
1026
|
+
const chatNote = askBundle || memoryAskBundle
|
|
1027
|
+
? ` (with the embedded ask-the-graph chat panel${askBundle && memoryAskBundle ? "s" : ""})`
|
|
1028
|
+
: " (no chat panel — run `npm run build:ask-bundle` first)";
|
|
881
1029
|
process.stdout.write(
|
|
882
|
-
`tmct viz — wrote ${vizGraph.nodes.length} node(s), ${vizGraph.edges.length} edge(s) to ${outPath}
|
|
883
|
-
+ `${askBundle ? " (with the embedded ask-the-graph chat panel)" : " (no chat panel — run `npm run build:ask-bundle` first)"}\n`,
|
|
1030
|
+
`tmct viz — wrote ${vizGraph.nodes.length} node(s), ${vizGraph.edges.length} edge(s) to ${outPath}${chatNote}\n`,
|
|
884
1031
|
);
|
|
885
1032
|
return;
|
|
886
1033
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# corpus/generated/ — mechanically-generated ACE surface variants
|
|
2
2
|
|
|
3
|
-
`ace-surface-variants.jsonl` — PLAN_BREADTH_FIRST_NLU.md §6a's raw material for
|
|
3
|
+
`ace-surface-variants.jsonl` — archive/PLAN_BREADTH_FIRST_NLU.md §6a's raw material for
|
|
4
4
|
tmct's "richer template/surface-realization variety" goal. Never an LLM, never
|
|
5
5
|
invented text: every row is a real seed sentence with one word swapped for a
|
|
6
6
|
real WordNet synset sibling, or a real sentence's alternate ACE-grammar-
|
|
@@ -29,7 +29,7 @@ Every row also carries `provenance` (`wordnet:<synsetId>` or
|
|
|
29
29
|
|
|
30
30
|
This corpus is not loaded by `src/chat.mjs`/`src/ask.mjs` or any other
|
|
31
31
|
product code — it is committed raw material, verified by
|
|
32
|
-
`scripts/template-coverage.mjs`, per PLAN_BREADTH_FIRST_NLU.md §6's explicit
|
|
32
|
+
`scripts/template-coverage.mjs`, per archive/PLAN_BREADTH_FIRST_NLU.md §6's explicit
|
|
33
33
|
non-goal. Wiring it into live answer rendering is a separate, future phase.
|
|
34
34
|
|
|
35
35
|
## Licence
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
LICENSE NOTICE — corpus/namenet/namenet.jsonl
|
|
2
|
+
================================================================================
|
|
3
|
+
|
|
4
|
+
The file namenet.jsonl in this directory is a mechanical, ConceptNet-shape
|
|
5
|
+
conversion of three human-reviewed linking tables (species, taxon-to-common-
|
|
6
|
+
name, occupations) from the Open English Namenet project. It is licensed
|
|
7
|
+
under the Creative Commons Attribution 4.0 International License
|
|
8
|
+
(CC-BY-4.0), NOT under this repository's MPL-2.0.
|
|
9
|
+
|
|
10
|
+
https://creativecommons.org/licenses/by/4.0/
|
|
11
|
+
|
|
12
|
+
License status of the source repository — read this before redistributing
|
|
13
|
+
--------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
The source repository, globalwordnet/english-namenet, declares NO explicit
|
|
16
|
+
license of its own: no LICENSE file in the checkout, no license statement in
|
|
17
|
+
its README.md, and GitHub's own repository metadata reports `license: null`
|
|
18
|
+
(confirmed 2026-07-12). CC-BY-4.0 above is a CONSERVATIVE CHOICE by this
|
|
19
|
+
repository, matching the license of the Open English WordNet data the source
|
|
20
|
+
CSVs link against (see Attribution below) — it is not a license the
|
|
21
|
+
globalwordnet/english-namenet maintainers have themselves stated. Anyone
|
|
22
|
+
redistributing namenet.jsonl more widely than this repository should seek
|
|
23
|
+
explicit confirmation from the GlobalWordNet team before relying on that
|
|
24
|
+
label.
|
|
25
|
+
|
|
26
|
+
Attribution
|
|
27
|
+
-----------
|
|
28
|
+
|
|
29
|
+
This work includes data derived from the Open English Namenet project (an
|
|
30
|
+
extension of Open English WordNet with names drawn from Wikidata), and
|
|
31
|
+
transitively from Open English WordNet itself (CC-BY-4.0) and Wikidata
|
|
32
|
+
(structured data, CC0).
|
|
33
|
+
|
|
34
|
+
- Project: https://github.com/globalwordnet/english-namenet
|
|
35
|
+
- Open English WordNet: https://github.com/globalwordnet/english-wordnet
|
|
36
|
+
- Wikidata: https://www.wikidata.org/
|
|
37
|
+
|
|
38
|
+
Source
|
|
39
|
+
------
|
|
40
|
+
|
|
41
|
+
- Dataset: three reviewed CSVs from a LOCAL, uncommitted checkout of
|
|
42
|
+
globalwordnet/english-namenet — never vendored into this repository:
|
|
43
|
+
- species_reviewed.csv (5,101 rows)
|
|
44
|
+
- taxon2common_reviewed.csv (2,368 rows)
|
|
45
|
+
- linked_occupations_reviewed.csv (2,193 rows)
|
|
46
|
+
Every accepted row in all three links a name/label to an Open English
|
|
47
|
+
WordNet synset or lemma set that a human reviewer confirmed denotes the
|
|
48
|
+
SAME real-world thing (a species, a folk-taxonomic category, an
|
|
49
|
+
occupation) — never a broader/narrower or capability relation. See
|
|
50
|
+
corpus/namenet/generate.mjs's own header comment for the full reasoning
|
|
51
|
+
behind mapping every row to /r/Synonym, and the exact accept/skip rules
|
|
52
|
+
per source file.
|
|
53
|
+
- species_reviewed.csv also required cross-referencing a SECOND local
|
|
54
|
+
checkout, globalwordnet/english-wordnet's `src/yaml/` synset source (the
|
|
55
|
+
same one corpus/wordnet/generate.mjs reads), to resolve each row's SSID
|
|
56
|
+
into a representative lemma — that CSV alone carries no lemma text.
|
|
57
|
+
- Conversion tool: corpus/namenet/generate.mjs (tmct code, MPL-2.0).
|
|
58
|
+
|
|
59
|
+
Share-alike
|
|
60
|
+
-----------
|
|
61
|
+
|
|
62
|
+
CC-BY-4.0 does NOT require share-alike (unlike ConceptNet's CC-BY-SA 4.0 in
|
|
63
|
+
corpus/conceptnet/) — a CC-BY-4.0 derivative may be relicensed, provided
|
|
64
|
+
attribution is preserved. This repository chooses to keep redistributing
|
|
65
|
+
namenet.jsonl itself under CC-BY-4.0 regardless, to stay unambiguous about
|
|
66
|
+
its origin, subject to the license-status caveat above. The code in this
|
|
67
|
+
directory (generate.mjs) is tmct code under the repository's MPL-2.0; only
|
|
68
|
+
the data file (namenet.jsonl) carries the CC-BY-4.0 label.
|