@polycode-projects/the-mechanical-code-talker 2.8.13 → 2.9.3
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 +50 -28
- package/bin/tmct.mjs +176 -31
- package/corpus/LICENSES.json +7 -0
- package/corpus/sprites/src/sprite-facts.jsonl +1033 -0
- package/corpus/worlds/manifest.json +9 -9
- package/corpus/worlds/shards/ashcombe-hall.jsonl.gz +0 -0
- package/corpus/worlds/shards/spider-fly.jsonl.gz +0 -0
- package/corpus/worlds/src/ashcombe-hall.jsonl +3 -0
- package/corpus/worlds/src/spider-fly.jsonl +17 -0
- package/package.json +37 -34
- package/src/adapters/corpus/wikipedia-live.mjs +145 -0
- package/src/adapters/memory/core.mjs +77 -12
- package/src/adapters/toml-config.mjs +6 -5
- package/src/domain/cli-verbs.mjs +4 -2
- package/src/domain/hanoi-lesson.mjs +10 -0
- package/src/domain/reference-pack.mjs +102 -0
- package/src/domain/spider-fly-world.mjs +54 -1
- package/src/domain/sprite-facts.mjs +0 -0
- package/src/services/adventure-viz.mjs +208 -66
- package/src/services/chat-page-viz.mjs +366 -37
- package/src/services/chat-session.mjs +38 -22
- package/src/services/chat.mjs +199 -20
- package/src/services/fold.mjs +28 -44
- package/src/services/import-file.mjs +7 -6
- package/src/services/init.mjs +10 -5
- package/src/services/ledger-viz.mjs +25 -34
- package/src/services/plan-viz.mjs +22 -26
- package/src/services/sessions.mjs +15 -3
- package/src/services/spider-fly-viz.mjs +52 -49
- package/src/services/sprite-catalog-viz.mjs +187 -3
- package/src/services/viz-theme.mjs +8 -0
- package/src/surfaces/web/adventure-browser-entry.mjs +23 -10
- package/src/surfaces/web/chat-browser-entry.mjs +17 -2
- package/src/surfaces/web/idb-persist.mjs +115 -0
- package/src/surfaces/web/memory-ask-browser.bundle.js +155 -25927
- package/src/surfaces/web/sprites-browser-entry.mjs +68 -0
- package/src/tools/memory-fallthrough.mjs +11 -4
package/README.md
CHANGED
|
@@ -119,16 +119,22 @@ tmct> /exit
|
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
**[Try it live in your browser →](https://polycode-projects.gitlab.io/the-mechanical-code-talker/)**
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
runs the actual query engine client-side. No server, no install. The landing
|
|
123
|
+
page answers codebase questions live, and six more pages each ground their
|
|
124
|
+
own domain: a full chat seeded with 19,228 facts (the same nine bands as
|
|
125
|
+
`npm run init:xl`, capped to a 22.8 MB download), the **memory ledger**
|
|
126
|
+
(every fact as a readable sentence; drill by clicking the terms inside), a
|
|
127
|
+
Towers-of-Hanoi plan replayed move by move, the spider-and-fly and
|
|
128
|
+
text-adventure games, and a sprite gallery whose chat dock answers from
|
|
129
|
+
1,033 generated sprite facts.
|
|
130
|
+
The site hosts its own copy of wink-nlp, ships its assets precompressed,
|
|
131
|
+
and a service worker precaches the big ones, so a second visit works
|
|
132
|
+
offline. `tmct chat --render spider-fly|adventure|sprites [--output <path>]`
|
|
133
|
+
writes any of the three view pages as one self-contained file.
|
|
128
134
|
|
|
129
135
|
From a clone, two build scripts regenerate that demo so you can check it
|
|
130
|
-
offline before it deploys. The example graph, the
|
|
131
|
-
engine copy land in `public/`. The in-page chat's query bundle is rebuilt
|
|
136
|
+
offline before it deploys. The example graph, the chat seed, the pages, and
|
|
137
|
+
the engine copy land in `public/`. The in-page chat's query bundle is rebuilt
|
|
132
138
|
from the same `src/` the CLI runs:
|
|
133
139
|
|
|
134
140
|
```bash e2e cwd=repo
|
|
@@ -381,8 +387,7 @@ contradict each other it names the contradicting pair and stops rather than
|
|
|
381
387
|
guessing on. Say `think of a number` to swap seats: tmct commits to a secret
|
|
382
388
|
and answers your guesses honestly, reveals on request, and corrects you from
|
|
383
389
|
its own record if you claim it already said `correct`. The behaviour is
|
|
384
|
-
pinned by `test/corpus/games/guess-number.jsonl
|
|
385
|
-
rail plays the guesser side live in your browser.
|
|
390
|
+
pinned by `test/corpus/games/guess-number.jsonl`.
|
|
386
391
|
|
|
387
392
|
**A text adventure.** Say `start the adventure` (or `play ashcombe hall`)
|
|
388
393
|
and tmct loads a small country-house mystery from a lazily-fetched worlds
|
|
@@ -426,15 +431,25 @@ Facts first, prose second; if neither pack carries the term, the turn is the
|
|
|
426
431
|
same honest miss it always was, byte for byte. An unknown word, a parse
|
|
427
432
|
failure, or an ambiguous reading never consults a pack at all. The gate and
|
|
428
433
|
both fallbacks are pinned by `test/corpus/reference.jsonl` and the
|
|
429
|
-
chat-lane tests beside it
|
|
434
|
+
chat-lane tests beside it.
|
|
435
|
+
|
|
436
|
+
Live Wikipedia is the opt-in third tier, off by default. Turn it on with
|
|
437
|
+
`/wiki on` in a session, `--live-wikipedia` on the command line,
|
|
438
|
+
`TMCT_LIVE_WIKIPEDIA=1`, or `tier = "tier3"` under `[corpus]` in `tmct.toml`.
|
|
439
|
+
The browser chat page has the same switch ("ask Wikipedia when I don't
|
|
440
|
+
know"). When it is on and both shipped packs miss, tmct makes two requests
|
|
441
|
+
to en.wikipedia.org (a title search, then the page summary) and answers as a
|
|
442
|
+
cited read-out, CC BY-SA, pinned to the revision it read (provenance
|
|
443
|
+
`reference:wikipedia-live:<Title>@<revid>`). A failed lookup (no matching
|
|
444
|
+
title, a timeout, a rate limit) leaves the honest miss byte-identical.
|
|
430
445
|
|
|
431
446
|
## How it remembers
|
|
432
447
|
|
|
433
448
|
tmct's memory has two layers, both fed by every parsed request and response and
|
|
434
449
|
by cleaned session logs:
|
|
435
450
|
|
|
436
|
-
- an **always-loaded OWL-labelled
|
|
437
|
-
artifact, never committed);
|
|
451
|
+
- an **always-loaded OWL-labelled graph** on disk under `.tmct/`, a SQLite
|
|
452
|
+
file by default (local artifact, never committed);
|
|
438
453
|
- **text blocks under a PageRank-style index**, pulled into context on
|
|
439
454
|
relevance rather than loaded wholesale.
|
|
440
455
|
|
|
@@ -456,20 +471,19 @@ reasoning).
|
|
|
456
471
|
|
|
457
472
|
### Memory backends
|
|
458
473
|
|
|
459
|
-
The default
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
thing directly: `runChat({ memoryBackend: "sqlite" })`.
|
|
474
|
+
The default backend persists taught facts to a local SQLite file
|
|
475
|
+
(`.tmct/memory/graph.sqlite`). A second backend, `memory`, keeps them in the
|
|
476
|
+
process only and writes nothing to disk. `tmct init --memory-backend <name>`
|
|
477
|
+
writes the choice into `tmct.toml` and every later `tmct chat` in that repo
|
|
478
|
+
picks it up. Precedence is `--memory-backend` flag > `TMCT_MEMORY_BACKEND`
|
|
479
|
+
env > tmct.toml's `[memory] backend` > the sqlite default. A library caller
|
|
480
|
+
sets the same thing directly: `runChat({ memoryBackend: "memory" })`.
|
|
467
481
|
|
|
468
482
|
Three init presets in `package.json` wrap the common setups. What each one
|
|
469
483
|
runs (`--force` re-initializes the same directory):
|
|
470
484
|
|
|
471
485
|
```bash
|
|
472
|
-
npx tmct init
|
|
486
|
+
npx tmct init # npm run init:sqlite — sqlite is already the default backend
|
|
473
487
|
npx tmct init --force --with-persona human # npm run init:persona:human — the default persona, made explicit
|
|
474
488
|
npx tmct init --force --with-persona empty # npm run init:persona:empty — no seeded vocabulary at all
|
|
475
489
|
```
|
|
@@ -577,16 +591,23 @@ Usage:
|
|
|
577
591
|
the final answer (teach state first, trigger last)
|
|
578
592
|
[--render blocks] with --prompt: when the final turn produced a plan,
|
|
579
593
|
write it as a self-contained animated page
|
|
580
|
-
[--
|
|
594
|
+
[--render spider-fly|adventure|sprites] write that demo view as one self-contained
|
|
595
|
+
page (no --prompt; the game pages inline their engine)
|
|
596
|
+
[--output <path>] the rendered page's path (default plan.html for
|
|
597
|
+
blocks, <archetype>.html for the views)
|
|
581
598
|
[--narrate] start with narrate mode on — a verbose, developer-facing
|
|
582
599
|
trace of decision points/matched pattern/results/goal per
|
|
583
600
|
turn, appended under a "--- narrate ---" marker (also
|
|
584
601
|
TMCT_NARRATE=1; toggle mid-session with /narrate on|off)
|
|
602
|
+
[--live-wikipedia] start with the live Wikipedia supplement on — a question
|
|
603
|
+
nothing local can answer also tries en.wikipedia.org,
|
|
604
|
+
cited (network; also TMCT_LIVE_WIKIPEDIA=1 or tmct.toml
|
|
605
|
+
corpus tier3; toggle mid-session with /wiki on|off)
|
|
585
606
|
[--plain] force the plain readline shell (the default when
|
|
586
607
|
stdin/stdout is not a terminal)
|
|
587
608
|
[--memory-backend <default|memory|sqlite>] storage backend for taught facts this
|
|
588
609
|
session (CLI flag > TMCT_MEMORY_BACKEND env > tmct.toml's
|
|
589
|
-
[memory] backend >
|
|
610
|
+
[memory] backend > sqlite, .tmct/memory/graph.sqlite)
|
|
590
611
|
```
|
|
591
612
|
|
|
592
613
|
`tmct memory` is the CLI-side view of the same data the `/memory` chat command shows:
|
|
@@ -742,14 +763,15 @@ TMCT_GRAPH_FILE env > tmct.toml graph_file/graph_files > --repo-derived
|
|
|
742
763
|
"repo_path" fills the --repo tier when the flag is absent.
|
|
743
764
|
|
|
744
765
|
Memory-backend precedence (chat; see src/services/chat.mjs createSession): --memory-backend
|
|
745
|
-
flag > TMCT_MEMORY_BACKEND env > tmct.toml [memory] backend >
|
|
746
|
-
.tmct/
|
|
747
|
-
|
|
766
|
+
flag > TMCT_MEMORY_BACKEND env > tmct.toml [memory] backend > sqlite (the built-in
|
|
767
|
+
default, .tmct/memory/graph.sqlite); "memory" keeps the store in-process only. Set it
|
|
768
|
+
once with `tmct init --memory-backend <...>` and every later `tmct chat` in that
|
|
769
|
+
repo picks it up with no flag needed.
|
|
748
770
|
```
|
|
749
771
|
|
|
750
772
|
`npm run init:large` in `package.json` chains one `init` and five `import --corpus`
|
|
751
773
|
calls to combine every shipped bundle (human persona + seon + conceptnet +
|
|
752
|
-
aws/python/java) into ~7,380 facts on the default
|
|
774
|
+
aws/python/java) into ~7,380 facts on the default sqlite backend, a working
|
|
753
775
|
example to copy from. `init:xl` starts from the large persona tier and adds
|
|
754
776
|
the wordnet-xl corpus (~72,000 facts); `init:xxl` swaps wordnet-xl for the
|
|
755
777
|
full WordNet slice plus namenet (~239,000 facts, the biggest committed
|
package/bin/tmct.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env -S node --disable-warning=ExperimentalWarning
|
|
2
2
|
// tmct — The Mechanical Code Talker. The headline entry is CHAT: a bare
|
|
3
3
|
// invocation drops you into a tolerant, offline, $0 prompt that guides you
|
|
4
4
|
// toward precision queries about a repository (ELIZA/PARRY-style, but obsessed
|
|
@@ -34,6 +34,18 @@
|
|
|
34
34
|
// static import here costs `tmct --help` nothing.
|
|
35
35
|
import { renderUsage, unknownInvocationMessage } from "../src/domain/cli-verbs.mjs";
|
|
36
36
|
|
|
37
|
+
// The default memory backend rides node:sqlite, which Node still ships behind
|
|
38
|
+
// an ExperimentalWarning. The shebang and the package.json scripts both pass
|
|
39
|
+
// --disable-warning=ExperimentalWarning, but a direct `node bin/tmct.mjs`
|
|
40
|
+
// (spawnSync, some CI shells) bypasses both — so replace the default warning
|
|
41
|
+
// printer with one that swallows exactly that warning and re-prints everything
|
|
42
|
+
// else in Node's own format.
|
|
43
|
+
process.removeAllListeners("warning");
|
|
44
|
+
process.on("warning", (warning) => {
|
|
45
|
+
if (warning?.name === "ExperimentalWarning" && /sqlite/i.test(String(warning?.message || ""))) return;
|
|
46
|
+
process.stderr.write(`(node:${process.pid}) ${warning?.name || "Warning"}: ${warning?.message || warning}\n`);
|
|
47
|
+
});
|
|
48
|
+
|
|
37
49
|
const HELP = `tmct — The Mechanical Code Talker
|
|
38
50
|
|
|
39
51
|
A tolerant, offline, $0 chat that guides you toward precision queries about a
|
|
@@ -51,9 +63,10 @@ TMCT_GRAPH_FILE env > tmct.toml graph_file/graph_files > --repo-derived
|
|
|
51
63
|
"repo_path" fills the --repo tier when the flag is absent.
|
|
52
64
|
|
|
53
65
|
Memory-backend precedence (chat; see src/services/chat.mjs createSession): --memory-backend
|
|
54
|
-
flag > TMCT_MEMORY_BACKEND env > tmct.toml [memory] backend >
|
|
55
|
-
.tmct/
|
|
56
|
-
|
|
66
|
+
flag > TMCT_MEMORY_BACKEND env > tmct.toml [memory] backend > sqlite (the built-in
|
|
67
|
+
default, .tmct/memory/graph.sqlite); "memory" keeps the store in-process only. Set it
|
|
68
|
+
once with \`tmct init --memory-backend <...>\` and every later \`tmct chat\` in that
|
|
69
|
+
repo picks it up with no flag needed.
|
|
57
70
|
`;
|
|
58
71
|
|
|
59
72
|
const argv = process.argv.slice(2);
|
|
@@ -503,6 +516,86 @@ async function appendGraphFiles(repoRoot, graphPaths) {
|
|
|
503
516
|
await writeConfig(repoRoot, cfg);
|
|
504
517
|
}
|
|
505
518
|
|
|
519
|
+
/** Build one game page's browser engine bundle into a throwaway dir and
|
|
520
|
+
* return its text for inlining. The bundle builders live in scripts/ and
|
|
521
|
+
* need esbuild — a git checkout with dev dependencies, not the npm package —
|
|
522
|
+
* so an unbuildable engine is a clear refusal here, never a written page
|
|
523
|
+
* that hangs at "loading the engine". */
|
|
524
|
+
async function buildEngineBundleJs(builderFile) {
|
|
525
|
+
const { mkdtemp, readFile, rm } = await import("node:fs/promises");
|
|
526
|
+
const { tmpdir } = await import("node:os");
|
|
527
|
+
const { join } = await import("node:path");
|
|
528
|
+
let build;
|
|
529
|
+
try {
|
|
530
|
+
({ main: build } = await import(new URL(`../scripts/${builderFile}`, import.meta.url).href));
|
|
531
|
+
} catch {
|
|
532
|
+
throw new Error(
|
|
533
|
+
`this render inlines the page's engine bundle, and its builder (scripts/${builderFile}) `
|
|
534
|
+
+ "isn't available here — run it from a git checkout with dev dependencies installed (npm install)",
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
const dir = await mkdtemp(join(tmpdir(), "tmct-render-"));
|
|
538
|
+
try {
|
|
539
|
+
const { outPath } = await build(dir);
|
|
540
|
+
return await readFile(outPath, "utf8");
|
|
541
|
+
} finally {
|
|
542
|
+
await rm(dir, { recursive: true, force: true });
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/** `--render spider-fly|adventure|sprites [--output <path>]` — write that demo
|
|
547
|
+
* view as ONE self-contained file: build-time data read here in Node (the
|
|
548
|
+
* same reads scripts/build-demo-site.mjs does for the deployed site), and,
|
|
549
|
+
* for the two game pages, the engine bundle built fresh and inlined instead
|
|
550
|
+
* of linked as a sibling — so the written file opens from file:// alone. */
|
|
551
|
+
async function writeStandaloneViewPage(archetype, rest) {
|
|
552
|
+
const { strFlag } = await import("../src/services/cli-args.mjs");
|
|
553
|
+
const { writeFile } = await import("node:fs/promises");
|
|
554
|
+
const { resolve: resolvePath } = await import("node:path");
|
|
555
|
+
const outPath = resolvePath(process.cwd(), strFlag(rest, ["--output", "--out"], `${archetype}.html`));
|
|
556
|
+
let html;
|
|
557
|
+
if (archetype === "sprites") {
|
|
558
|
+
const { readSpriteTemplateFiles } = await import("../src/adapters/corpus/sprite-template-files.mjs");
|
|
559
|
+
const { readSpriteLargeTemplateFiles } = await import("../src/adapters/corpus/sprite-large-template-files.mjs");
|
|
560
|
+
const { loadSpriteOntologyFactRows, renderSpriteCatalogHtml } = await import("../src/services/sprite-catalog-viz.mjs");
|
|
561
|
+
html = renderSpriteCatalogHtml({
|
|
562
|
+
iconTemplates: readSpriteTemplateFiles(),
|
|
563
|
+
largeTemplates: readSpriteLargeTemplateFiles(),
|
|
564
|
+
factRows: await loadSpriteOntologyFactRows(),
|
|
565
|
+
});
|
|
566
|
+
} else if (archetype === "spider-fly") {
|
|
567
|
+
const engineBundleJs = await buildEngineBundleJs("build-spider-fly-bundle.mjs");
|
|
568
|
+
// The large sprite tier, same as the site build: the only tier the
|
|
569
|
+
// emotion-carrying spider/fly templates exist in. Missing (e.g. outside
|
|
570
|
+
// this checkout) reads as [], and every agent falls back to the flat
|
|
571
|
+
// built-in registry.
|
|
572
|
+
const { readSpriteLargeTemplateFiles } = await import("../src/adapters/corpus/sprite-large-template-files.mjs");
|
|
573
|
+
const { renderSpiderFlyHtml } = await import("../src/services/spider-fly-viz.mjs");
|
|
574
|
+
html = renderSpiderFlyHtml({ spriteTemplates: readSpriteLargeTemplateFiles(), engineBundleJs });
|
|
575
|
+
} else {
|
|
576
|
+
const engineBundleJs = await buildEngineBundleJs("build-adventure-bundle.mjs");
|
|
577
|
+
const { getWorldsPackProvider } = await import("../src/adapters/corpus/worlds-pack.mjs");
|
|
578
|
+
const world = await getWorldsPackProvider().load("ashcombe-hall");
|
|
579
|
+
if (!world) {
|
|
580
|
+
throw new Error("the ashcombe-hall world isn't in the worlds pack (corpus/worlds/) — run `npm run gen:worlds-pack` first");
|
|
581
|
+
}
|
|
582
|
+
const { readSpriteTemplateFiles } = await import("../src/adapters/corpus/sprite-template-files.mjs");
|
|
583
|
+
const { renderAdventureHtml } = await import("../src/services/adventure-viz.mjs");
|
|
584
|
+
html = renderAdventureHtml({
|
|
585
|
+
worldPayload: {
|
|
586
|
+
name: world.name,
|
|
587
|
+
facts: world.facts.map((f) => ({ subject: f.subject, predicate: f.predicate, object: f.object })),
|
|
588
|
+
rules: world.rules.map((r) => ({ name: r.name, ruleKind: r.ruleKind, slots: r.slots })),
|
|
589
|
+
opening: world.meta?.opening || "",
|
|
590
|
+
},
|
|
591
|
+
spriteTemplates: readSpriteTemplateFiles(),
|
|
592
|
+
engineBundleJs,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
await writeFile(outPath, html, "utf8");
|
|
596
|
+
process.stdout.write(`wrote ${outPath} (${(Buffer.byteLength(html, "utf8") / 1024).toFixed(0)} KB, self-contained)\n`);
|
|
597
|
+
}
|
|
598
|
+
|
|
506
599
|
async function main() {
|
|
507
600
|
const mode = process.argv[2];
|
|
508
601
|
|
|
@@ -520,6 +613,11 @@ async function main() {
|
|
|
520
613
|
// session with the verbose developer/debug narrate mode already on. Default
|
|
521
614
|
// OFF; `/narrate on`/`/narrate off` also toggles it mid-session.
|
|
522
615
|
const narrate = rest.includes("--narrate");
|
|
616
|
+
// `--live-wikipedia` (or TMCT_LIVE_WIKIPEDIA=1 / tmct.toml corpus tier3,
|
|
617
|
+
// both read inside createSession): start with the live Wikipedia
|
|
618
|
+
// supplement on. Default OFF; `/wiki on`/`/wiki off` toggles it
|
|
619
|
+
// mid-session.
|
|
620
|
+
const liveReference = rest.includes("--live-wikipedia");
|
|
523
621
|
// `--graph <path>` (repeatable) / `--config <path>` (src/services/cli-args.mjs): threaded
|
|
524
622
|
// through as the new top tier of createSession's graph-resolution order (above
|
|
525
623
|
// TMCT_GRAPH_FILE — see chat.mjs's own docblock at createSession). Omitted from
|
|
@@ -549,17 +647,23 @@ async function main() {
|
|
|
549
647
|
// FINAL turn's answer prints to stdout, and the process exits. Piped stdin
|
|
550
648
|
// stays the interactive fallback.
|
|
551
649
|
const prompt = strFlag(rest, ["--prompt"]);
|
|
552
|
-
// `--render <archetype> [--output <path>]` —
|
|
553
|
-
//
|
|
554
|
-
//
|
|
555
|
-
//
|
|
650
|
+
// `--render <archetype> [--output <path>]` — write one standalone page.
|
|
651
|
+
// "blocks" is the animated plan replay (src/services/plan-viz.mjs) and
|
|
652
|
+
// requires --prompt: interactive chat has no single final turn to render.
|
|
653
|
+
// The demo views (spider-fly / adventure / sprites) take no prompt — their
|
|
654
|
+
// data is read at render time, and the two game pages inline a freshly
|
|
655
|
+
// built engine bundle so the file opens from file:// with no siblings.
|
|
556
656
|
let renderArchetype;
|
|
557
657
|
try {
|
|
558
|
-
renderArchetype = enumFlag(rest, ["--render"], ["blocks"]);
|
|
658
|
+
renderArchetype = enumFlag(rest, ["--render"], ["blocks", "spider-fly", "adventure", "sprites"]);
|
|
559
659
|
} catch (e) {
|
|
560
660
|
process.stderr.write(`tmct: ${e?.message || e}\n`);
|
|
561
661
|
process.exit(2);
|
|
562
662
|
}
|
|
663
|
+
if (renderArchetype && renderArchetype !== "blocks") {
|
|
664
|
+
await writeStandaloneViewPage(renderArchetype, rest);
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
563
667
|
if (renderArchetype && !prompt) {
|
|
564
668
|
process.stderr.write("tmct: --render needs --prompt (a one-shot turn whose plan it renders)\n");
|
|
565
669
|
process.exit(1);
|
|
@@ -567,7 +671,7 @@ async function main() {
|
|
|
567
671
|
if (prompt) {
|
|
568
672
|
const { createSession } = await import("../src/services/chat.mjs");
|
|
569
673
|
const { splitSentences } = await import("../src/services/sentences.mjs");
|
|
570
|
-
const session = await createSession({ repoPath, ephemeral, narrate, ...extra });
|
|
674
|
+
const session = await createSession({ repoPath, ephemeral, narrate, liveReference, ...extra });
|
|
571
675
|
let finalAnswer = "";
|
|
572
676
|
let finalPlan = null;
|
|
573
677
|
let parts;
|
|
@@ -609,10 +713,10 @@ async function main() {
|
|
|
609
713
|
const plain = rest.includes("--plain") || !process.stdin.isTTY || !process.stdout.isTTY;
|
|
610
714
|
if (plain) {
|
|
611
715
|
const { runChat } = await import("../src/services/chat.mjs");
|
|
612
|
-
await runChat({ repoPath, ephemeral, narrate, ...extra });
|
|
716
|
+
await runChat({ repoPath, ephemeral, narrate, liveReference, ...extra });
|
|
613
717
|
} else {
|
|
614
718
|
const { runTui } = await import("../src/surfaces/tui/app.mjs");
|
|
615
|
-
await runTui({ repoPath, ephemeral, narrate, ...extra });
|
|
719
|
+
await runTui({ repoPath, ephemeral, narrate, liveReference, ...extra });
|
|
616
720
|
}
|
|
617
721
|
return;
|
|
618
722
|
}
|
|
@@ -626,9 +730,24 @@ async function main() {
|
|
|
626
730
|
const rest = process.argv.slice(3);
|
|
627
731
|
const verbose = rest.includes("--verbose") || rest.includes("-v");
|
|
628
732
|
const { resolveRuntimeConfig } = await import("../src/services/cli-args.mjs");
|
|
629
|
-
const {
|
|
630
|
-
const {
|
|
631
|
-
|
|
733
|
+
const { renderMemory } = await import("../src/adapters/memory/inspect.mjs");
|
|
734
|
+
const { loadMemory, openMemoryBackend } = await import("../src/adapters/memory/core.mjs");
|
|
735
|
+
const { loadBlockIndex } = await import("../src/adapters/memory/blocks.mjs");
|
|
736
|
+
const { repo, toml } = await resolveRuntimeConfig({ argv: rest });
|
|
737
|
+
// Same backend resolution as chat's createSession, minus the (nonexistent
|
|
738
|
+
// here) CLI-flag tier: env > tmct.toml > the sqlite default — so this verb
|
|
739
|
+
// inspects the store a chat session in this repo actually writes.
|
|
740
|
+
const backendChoice = String(process.env.TMCT_MEMORY_BACKEND || toml?.memory?.backend || "").trim().toLowerCase();
|
|
741
|
+
const { dir: memoryDir, close: closeMemoryStore } = await openMemoryBackend(repo, backendChoice);
|
|
742
|
+
try {
|
|
743
|
+
const memory = await loadMemory(memoryDir);
|
|
744
|
+
// The folded-block index is file-backed beside the session logs, not part
|
|
745
|
+
// of the memory store — read it off the repo path directly.
|
|
746
|
+
const blocks = await loadBlockIndex(repo);
|
|
747
|
+
process.stdout.write(renderMemory({ memory, blocks }, { verbose }) + "\n");
|
|
748
|
+
} finally {
|
|
749
|
+
await closeMemoryStore();
|
|
750
|
+
}
|
|
632
751
|
return;
|
|
633
752
|
}
|
|
634
753
|
|
|
@@ -1023,14 +1142,23 @@ async function main() {
|
|
|
1023
1142
|
};
|
|
1024
1143
|
const { resolveRuntimeConfig } = await import("../src/services/cli-args.mjs");
|
|
1025
1144
|
const { syllogise, DEFAULT_MAX_ENVIRONMENTS } = await import("../src/domain/syllogise.mjs");
|
|
1026
|
-
const { loadMemory, readFactRows, appendFacts, loadSyllogiseState, saveSyllogiseState } = await import("../src/adapters/memory/core.mjs");
|
|
1027
|
-
const { repo } = await resolveRuntimeConfig({ argv: rest });
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1145
|
+
const { loadMemory, readFactRows, appendFacts, loadSyllogiseState, saveSyllogiseState, openMemoryBackend } = await import("../src/adapters/memory/core.mjs");
|
|
1146
|
+
const { repo, toml } = await resolveRuntimeConfig({ argv: rest });
|
|
1147
|
+
// Same env > tmct.toml > default backend resolution as `tmct memory` — the
|
|
1148
|
+
// entailed facts must land in the store chat reads back.
|
|
1149
|
+
const backendChoice = String(process.env.TMCT_MEMORY_BACKEND || toml?.memory?.backend || "").trim().toLowerCase();
|
|
1150
|
+
const { dir: memoryDir, close: closeMemoryStore } = await openMemoryBackend(repo, backendChoice);
|
|
1151
|
+
let res;
|
|
1152
|
+
try {
|
|
1153
|
+
res = await syllogise(memoryDir, {
|
|
1154
|
+
depth: numFlag("--depth", 32), budget: numFlag("--budget", 50),
|
|
1155
|
+
maxEnvironments: numFlag("--max-environments", DEFAULT_MAX_ENVIRONMENTS),
|
|
1156
|
+
full: rest.includes("--full"),
|
|
1157
|
+
store: { loadMemory, readFactRows, appendFacts, loadSyllogiseState, saveSyllogiseState },
|
|
1158
|
+
});
|
|
1159
|
+
} finally {
|
|
1160
|
+
await closeMemoryStore();
|
|
1161
|
+
}
|
|
1034
1162
|
process.stdout.write(
|
|
1035
1163
|
`tmct syllogise — derived ${res.count} entailed fact(s) (mode ${res.mode}${res.mode === "delta" ? `, Δ${res.deltaSize}` : ""}, depth ${res.depth}, budget ${res.budget})`
|
|
1036
1164
|
+ (res.environmentsAdded > 0 ? `, ${res.environmentsAdded} alternate environment(s) recorded` : "")
|
|
@@ -1074,12 +1202,22 @@ async function main() {
|
|
|
1074
1202
|
const focus = strFlag(rest, ["--focus"]);
|
|
1075
1203
|
const term = strFlag(rest, ["--term"]); // seeds via normFactTerm; --focus wins when both are given
|
|
1076
1204
|
const outPath = resolve(process.cwd(), strFlag(rest, ["--output", "--out"], "ledger.html"));
|
|
1077
|
-
const { repo } = await resolveRuntimeConfig({ argv: rest });
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
});
|
|
1205
|
+
const { repo, toml } = await resolveRuntimeConfig({ argv: rest });
|
|
1206
|
+
// Same env > tmct.toml > default backend resolution as `tmct memory` — the
|
|
1207
|
+
// ledger must render the store chat actually wrote.
|
|
1208
|
+
const { openMemoryBackend } = await import("../src/adapters/memory/core.mjs");
|
|
1209
|
+
const backendChoice = String(process.env.TMCT_MEMORY_BACKEND || toml?.memory?.backend || "").trim().toLowerCase();
|
|
1210
|
+
const { dir: memoryDir, close: closeMemoryStore } = await openMemoryBackend(repo, backendChoice);
|
|
1211
|
+
let data;
|
|
1212
|
+
try {
|
|
1213
|
+
data = await computeLedgerData(memoryDir, {
|
|
1214
|
+
...(focus ? { focus } : {}),
|
|
1215
|
+
...(!focus && term ? { term } : {}),
|
|
1216
|
+
...(rowLimit != null ? { rowLimit } : {}),
|
|
1217
|
+
});
|
|
1218
|
+
} finally {
|
|
1219
|
+
await closeMemoryStore();
|
|
1220
|
+
}
|
|
1083
1221
|
// readMemoryAskBundle never throws; an empty string renders the page with
|
|
1084
1222
|
// an honest "chat unavailable" note instead of the dock (e.g. a fresh
|
|
1085
1223
|
// checkout before the bundle's first build).
|
|
@@ -1198,12 +1336,18 @@ async function main() {
|
|
|
1198
1336
|
process.stderr.write("tmct plan: needs a request, e.g. `tmct plan \"of the modules impacted by X, which are untested\"`\n");
|
|
1199
1337
|
process.exit(2);
|
|
1200
1338
|
}
|
|
1201
|
-
const { repo, config } = await resolveRuntimeConfig({ argv: rest });
|
|
1339
|
+
const { repo, config, toml } = await resolveRuntimeConfig({ argv: rest });
|
|
1202
1340
|
const { buildCapabilityPlanCtx, runCapabilityPlan, declaredCapabilityNames } = await import("../src/domain/router/drive.mjs");
|
|
1203
1341
|
const { capabilityPlanDeps } = await import("../src/services/chat.mjs");
|
|
1342
|
+
// Same env > tmct.toml > default backend resolution as `tmct memory` — the
|
|
1343
|
+
// taught world/rule records the planner registers live in the store chat
|
|
1344
|
+
// wrote them to.
|
|
1345
|
+
const { openMemoryBackend } = await import("../src/adapters/memory/core.mjs");
|
|
1346
|
+
const backendChoice = String(process.env.TMCT_MEMORY_BACKEND || toml?.memory?.backend || "").trim().toLowerCase();
|
|
1347
|
+
const { dir: memoryDir, close: closeMemoryStore } = await openMemoryBackend(repo, backendChoice);
|
|
1204
1348
|
let ctx;
|
|
1205
1349
|
try {
|
|
1206
|
-
ctx = await buildCapabilityPlanCtx({ ...capabilityPlanDeps(), config, memoryDir
|
|
1350
|
+
ctx = await buildCapabilityPlanCtx({ ...capabilityPlanDeps(), config, memoryDir });
|
|
1207
1351
|
} catch (e) {
|
|
1208
1352
|
process.stderr.write(`tmct plan: could not load the graph — ${e?.message || e}\n`);
|
|
1209
1353
|
process.exit(1);
|
|
@@ -1256,6 +1400,7 @@ async function main() {
|
|
|
1256
1400
|
}
|
|
1257
1401
|
} finally {
|
|
1258
1402
|
for (const dispose of ctx.disposers || []) dispose();
|
|
1403
|
+
await closeMemoryStore();
|
|
1259
1404
|
}
|
|
1260
1405
|
return;
|
|
1261
1406
|
}
|
package/corpus/LICENSES.json
CHANGED
|
@@ -135,6 +135,13 @@
|
|
|
135
135
|
"shareAlike": false,
|
|
136
136
|
"notice": "LICENSE"
|
|
137
137
|
},
|
|
138
|
+
{
|
|
139
|
+
"path": "corpus/sprites/",
|
|
140
|
+
"upstream": "first-party (mechanically generated by scripts/gen-sprite-facts.mjs from this repository's own hand-authored sprite templates, data/sprites/ and data/sprites-large/)",
|
|
141
|
+
"license": "MPL-2.0",
|
|
142
|
+
"shareAlike": false,
|
|
143
|
+
"notice": "LICENSE"
|
|
144
|
+
},
|
|
138
145
|
{
|
|
139
146
|
"path": "corpus/generated/ace-surface-variants.jsonl",
|
|
140
147
|
"upstream": "mechanically generated from Open English WordNet / SemCor example sentences (CC-BY-4.0) and corpus/prose/, which includes CC-BY-SA-4.0 Wikipedia text",
|