@polycode-projects/the-mechanical-code-talker 1.11.6 → 2.0.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 +244 -48
- package/ROADMAP.md +23 -34
- package/bin/tmct.mjs +117 -81
- package/corpus/LICENSES.json +118 -0
- package/corpus/README.md +17 -13
- package/corpus/conceptnet/README.md +5 -5
- package/corpus/conceptnet/fetch-slice.mjs +1 -1
- package/corpus/conceptnet/filter-dump.mjs +1 -1
- package/corpus/generated/README.md +9 -10
- package/corpus/namenet/README.md +39 -0
- package/corpus/seon/README.md +2 -2
- package/corpus/tier2/generate.mjs +58 -9
- package/corpus/tier2/manifest.json +44 -0
- package/corpus/wordnet/README.md +37 -0
- package/corpus/wordnet/generate.mjs +1 -1
- package/data/templates/constructions/agent-noun-relations.toml +2 -2
- package/data/templates/grammar-rules.toml +1 -1
- package/package.json +13 -22
- package/src/{ask-nlp.mjs → adapters/ask-nlp.mjs} +1 -1
- package/src/{config.mjs → adapters/config.mjs} +1 -1
- package/src/{corpus → adapters/corpus}/conceptnet-map.toml +4 -4
- package/src/{corpus → adapters/corpus}/conceptnet.mjs +3 -3
- package/src/adapters/corpus/construction-banks.mjs +43 -0
- package/src/{corpus → adapters/corpus}/templates.mjs +1 -1
- package/src/{embed.mjs → adapters/embed.mjs} +1 -11
- package/src/{graph-build.mjs → adapters/graph-build.mjs} +6 -6
- package/src/{memory → adapters/memory}/blocks.mjs +2 -2
- package/src/{memory → adapters/memory}/core.mjs +38 -94
- package/src/adapters/prose-tokens.mjs +98 -0
- package/src/{providers → adapters/providers}/bootstrap.mjs +2 -2
- package/src/{providers → adapters/providers}/fixture.mjs +3 -3
- package/src/{providers → adapters/providers}/graph-service.mjs +9 -4
- package/src/{source-slice.mjs → adapters/source-slice.mjs} +2 -2
- package/src/{source.mjs → adapters/source.mjs} +1 -1
- package/src/{toml-config.mjs → adapters/toml-config.mjs} +1 -1
- package/src/{answer-variants.json → domain/answer-variants.json} +1 -1
- package/src/domain/answer-variants.mjs +23 -0
- package/src/{ask-vocab.mjs → domain/ask-vocab.mjs} +37 -5
- package/src/{ask.mjs → domain/ask.mjs} +216 -52
- package/src/{codegraph.mjs → domain/codegraph.mjs} +31 -315
- package/src/{completions → domain/completions}/complete.mjs +16 -10
- package/src/{completions → domain/completions}/graph-adapter.mjs +10 -4
- package/src/{completions → domain/completions}/group.mjs +14 -6
- package/src/{completions → domain/completions}/infer.mjs +57 -39
- package/src/domain/completions/injected.mjs +21 -0
- package/src/{completions → domain/completions}/rank.mjs +15 -8
- package/src/{completions → domain/completions}/search.mjs +4 -2
- package/src/{grammar → domain/grammar}/ace.mjs +3 -3
- package/src/{grammar → domain/grammar}/assert.mjs +12 -8
- package/src/{grammar → domain/grammar}/lexicon-core.json +1 -1
- package/src/{grammar → domain/grammar}/lexicon.mjs +4 -6
- package/src/domain/hash.mjs +147 -0
- package/src/{interpret → domain/interpret}/fuzzy.mjs +42 -4
- package/src/domain/interpret/nlp-registry.mjs +20 -0
- package/src/{interpret → domain/interpret}/normalize.mjs +35 -5
- package/src/{interpret → domain/interpret}/pipeline.mjs +1 -5
- package/src/{interpret → domain/interpret}/strategies/ace.mjs +1 -1
- package/src/{interpret → domain/interpret}/strategies/constructions.mjs +30 -52
- package/src/{interpret → domain/interpret}/strategies/keywords.mjs +48 -26
- package/src/domain/memory/capability.mjs +235 -0
- package/src/domain/memory/fold.mjs +54 -0
- package/src/domain/memory/session-turns.mjs +7 -0
- package/src/{memory → domain/memory}/trust.mjs +48 -0
- package/src/{paraphrase.mjs → domain/paraphrase.mjs} +2 -2
- package/src/{prose.mjs → domain/prose.mjs} +1 -1
- package/src/domain/real-word-collisions.json +1 -0
- package/src/{router → domain/router}/call-validator.mjs +1 -1
- package/src/{router → domain/router}/drive.mjs +34 -25
- package/src/{router → domain/router}/goal-reasoner.mjs +1 -1
- package/src/{router → domain/router}/guardrail.mjs +1 -1
- package/src/{router → domain/router}/planner.mjs +1 -1
- package/src/{router → domain/router}/registry.mjs +5 -5
- package/src/{router → domain/router}/resolver.mjs +16 -13
- package/src/{router → domain/router}/results.mjs +1 -1
- package/src/{router → domain/router}/set-algebra.mjs +1 -1
- package/src/{router → domain/router}/taught.mjs +10 -9
- package/src/{syllogise.mjs → domain/syllogise.mjs} +21 -4
- package/src/domain/vector.mjs +12 -0
- package/src/services/chat-session.mjs +451 -0
- package/src/{chat.mjs → services/chat.mjs} +1238 -680
- package/src/{cli-args.mjs → services/cli-args.mjs} +2 -2
- package/src/services/completions.mjs +55 -0
- package/src/{extensions.mjs → services/extensions.mjs} +7 -7
- package/src/{finish.mjs → services/finish.mjs} +2 -2
- package/src/{memory → services}/fold.mjs +0 -0
- package/src/{import-file.mjs → services/import-file.mjs} +3 -3
- package/src/{index.mjs → services/index.mjs} +21 -12
- package/src/{init.mjs → services/init.mjs} +9 -9
- package/src/{ledger-viz.mjs → services/ledger-viz.mjs} +38 -7
- package/src/{plan-viz.mjs → services/plan-viz.mjs} +65 -26
- package/src/{sentences.mjs → services/sentences.mjs} +1 -1
- package/src/{sessions.mjs → services/sessions.mjs} +4 -5
- package/src/{telemetry.mjs → services/telemetry.mjs} +1 -1
- package/src/{server-http.mjs → surfaces/http/server-http.mjs} +11 -65
- package/src/{tui → surfaces/tui}/app.mjs +3 -3
- package/src/{memory-ask-browser-entry.mjs → surfaces/web/memory-ask-browser-entry.mjs} +5 -5
- package/src/{memory-ask-browser.bundle.js → surfaces/web/memory-ask-browser.bundle.js} +9465 -6366
- package/src/tools/catalog.mjs +29 -0
- package/src/{conformance.mjs → tools/conformance.mjs} +2 -2
- package/src/tools/definitions.mjs +288 -0
- package/src/tools/graph-load.mjs +20 -0
- package/src/tools/handlers/index.mjs +54 -0
- package/src/tools/handlers/kit.mjs +33 -0
- package/src/tools/handlers/tmct-architecture.mjs +7 -0
- package/src/tools/handlers/tmct-ask.mjs +14 -0
- package/src/tools/handlers/tmct-callees.mjs +6 -0
- package/src/tools/handlers/tmct-callers.mjs +6 -0
- package/src/tools/handlers/tmct-calls.mjs +6 -0
- package/src/tools/handlers/tmct-class-history.mjs +6 -0
- package/src/tools/handlers/tmct-cochanges.mjs +6 -0
- package/src/tools/handlers/tmct-context-more.mjs +9 -0
- package/src/tools/handlers/tmct-context.mjs +163 -0
- package/src/tools/handlers/tmct-describe.mjs +15 -0
- package/src/tools/handlers/tmct-exports.mjs +9 -0
- package/src/tools/handlers/tmct-file-history.mjs +6 -0
- package/src/tools/handlers/tmct-history.mjs +6 -0
- package/src/tools/handlers/tmct-impact.mjs +9 -0
- package/src/tools/handlers/tmct-members.mjs +16 -0
- package/src/tools/handlers/tmct-method-history.mjs +6 -0
- package/src/tools/handlers/tmct-search.mjs +22 -0
- package/src/tools/handlers/tmct-signature.mjs +6 -0
- package/src/tools/handlers/tmct-snippet.mjs +37 -0
- package/src/tools/handlers/tmct-subclasses.mjs +16 -0
- package/src/tools/handlers/tmct-tests-for.mjs +6 -0
- package/src/tools/handlers/tmct-untested.mjs +7 -0
- package/src/tools/memory-fallthrough.mjs +65 -0
- package/src/{schema-docs.mjs → tools/schema-docs.mjs} +1 -1
- package/src/tools/server.mjs +61 -0
- package/src/answer-variants.mjs +0 -39
- package/src/hash.mjs +0 -24
- package/src/server.mjs +0 -501
- /package/src/{corpus → adapters/corpus}/unknown-ingest.mjs +0 -0
- /package/src/{graph-merge.mjs → adapters/graph-merge.mjs} +0 -0
- /package/src/{memory → adapters/memory}/inspect.mjs +0 -0
- /package/src/{memory → adapters/memory}/shacl.mjs +0 -0
- /package/src/{prose-nlp.mjs → adapters/prose-nlp.mjs} +0 -0
- /package/src/{repository-interface.mjs → adapters/repository-interface.mjs} +0 -0
- /package/src/{uuid.mjs → adapters/uuid.mjs} +0 -0
- /package/src/{wink-model.mjs → adapters/wink-model.mjs} +0 -0
- /package/src/{completions → domain/completions}/prune.mjs +0 -0
- /package/src/{concept.mjs → domain/concept.mjs} +0 -0
- /package/src/{domain.mjs → domain/domain.mjs} +0 -0
- /package/src/{interpret → domain/interpret}/merge.mjs +0 -0
- /package/src/{interpret → domain/interpret}/strategies/grammar.mjs +0 -0
- /package/src/{interpret → domain/interpret}/strategies/noise-strip.mjs +0 -0
- /package/src/{memory → domain/memory}/bias.mjs +0 -0
- /package/src/{planning.mjs → domain/planning.mjs} +0 -0
- /package/src/{viz-theme.mjs → services/viz-theme.mjs} +0 -0
|
@@ -22,8 +22,8 @@ import { spawnSync } from "node:child_process";
|
|
|
22
22
|
import { dirname, resolve } from "node:path";
|
|
23
23
|
import { stat } from "node:fs/promises";
|
|
24
24
|
import { join } from "node:path";
|
|
25
|
-
import { loadTomlConfig, normalizeConfig, mergeEffective, CONFIG_FILE } from "
|
|
26
|
-
import { DEFAULT_GRAPH_REL } from "
|
|
25
|
+
import { loadTomlConfig, normalizeConfig, mergeEffective, CONFIG_FILE } from "../adapters/toml-config.mjs";
|
|
26
|
+
import { DEFAULT_GRAPH_REL } from "../adapters/config.mjs";
|
|
27
27
|
|
|
28
28
|
/** The git top-level for `cwd`, or null if not in a repo (or git is
|
|
29
29
|
* unavailable). A deliberate re-declaration of chat.mjs's gitToplevel (not an
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// completions.mjs — the composition root for src/domain/completions/'s pipeline. The stages
|
|
2
|
+
// there are pure: they read the memory store, the block store, the graph service and the
|
|
3
|
+
// prose finisher through an explicit `store`/`finisher` handle, and import none of them. This
|
|
4
|
+
// file builds the real handles from the adapters and re-exports both entry points with the
|
|
5
|
+
// signatures package.json's `./generateCompletion` and `./createCompletionsGraphAdapter`
|
|
6
|
+
// subpaths publish, so an external caller never passes a store of its own.
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
buildNeighbours, degreeOf, OVERLAP_MIN, rankBlocks, retrieveBlocks, tokenizeBlock,
|
|
10
|
+
} from "../adapters/memory/blocks.mjs";
|
|
11
|
+
import { loadMemory, normFactTerm, readFactRows, resolveRelationChase } from "../adapters/memory/core.mjs";
|
|
12
|
+
import { createGraphService } from "../adapters/providers/graph-service.mjs";
|
|
13
|
+
import { finish, grammarRules } from "./finish.mjs";
|
|
14
|
+
import { generateCompletion as generateCompletionOver } from "../domain/completions/complete.mjs";
|
|
15
|
+
import { createCompletionsGraphAdapter as createCompletionsGraphAdapterOver } from "../domain/completions/graph-adapter.mjs";
|
|
16
|
+
|
|
17
|
+
/** Every store handle the six stages read through, in one bag: the memory store's fact
|
|
18
|
+
* readers, the block store's retrieval/clustering/ranking helpers, and the graph service
|
|
19
|
+
* factory graph-adapter.mjs wraps. */
|
|
20
|
+
export const COMPLETIONS_STORE = {
|
|
21
|
+
loadMemory,
|
|
22
|
+
readFactRows,
|
|
23
|
+
normFactTerm,
|
|
24
|
+
resolveRelationChase,
|
|
25
|
+
retrieveBlocks,
|
|
26
|
+
buildNeighbours,
|
|
27
|
+
rankBlocks,
|
|
28
|
+
degreeOf,
|
|
29
|
+
tokenizeBlock,
|
|
30
|
+
OVERLAP_MIN,
|
|
31
|
+
createGraphService,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** finish.mjs reads its grammar rules from TOML on disk, so it stays in services and reaches
|
|
35
|
+
* the pipeline's Stage 6 through this handle. */
|
|
36
|
+
export const COMPLETIONS_FINISHER = { finish, grammarRules };
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The full mechanical-text-generation pipeline over the real store. Same signature and
|
|
40
|
+
* behaviour as src/domain/completions/complete.mjs's generateCompletion(); see its docblock
|
|
41
|
+
* for the options. A caller may still override any handle through `opts.store`/`opts.finisher`.
|
|
42
|
+
*/
|
|
43
|
+
export function generateCompletion(dir, prompt, opts = {}) {
|
|
44
|
+
return generateCompletionOver(dir, prompt, {
|
|
45
|
+
store: COMPLETIONS_STORE, finisher: COMPLETIONS_FINISHER, ...opts,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A graphService-shaped adapter for broadSearch() over the real store. Same signature and
|
|
51
|
+
* behaviour as src/domain/completions/graph-adapter.mjs's createCompletionsGraphAdapter().
|
|
52
|
+
*/
|
|
53
|
+
export function createCompletionsGraphAdapter(graph, memory = null) {
|
|
54
|
+
return createCompletionsGraphAdapterOver(graph, memory, { store: COMPLETIONS_STORE });
|
|
55
|
+
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// A `tmct.toml` `[extensions]` table-of-tables may override a recognized builtin, or
|
|
13
13
|
// declare a new host entry with its own `kind` (corpus | lexicon | templates | pack |
|
|
14
14
|
// ontology). A separate flat `[bias]` table (bundle-name → number) feeds
|
|
15
|
-
// src/memory/bias.mjs's ranking.
|
|
15
|
+
// src/domain/memory/bias.mjs's ranking.
|
|
16
16
|
//
|
|
17
17
|
// Entries are returned in a fixed order: `seon` first, then `conceptnet`, then the rest
|
|
18
18
|
// sorted by name (so seon's curated facts win idempotency races over ConceptNet noise).
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import { isAbsolute, join, resolve, dirname } from "node:path";
|
|
21
21
|
import { readFile } from "node:fs/promises";
|
|
22
22
|
import { fileURLToPath } from "node:url";
|
|
23
|
-
import { loadTomlConfig } from "
|
|
23
|
+
import { loadTomlConfig } from "../adapters/toml-config.mjs";
|
|
24
24
|
import {
|
|
25
25
|
SEON_CONCEPTS_FILE,
|
|
26
26
|
SLICE_FILE as CONCEPTNET_SLICE_FILE,
|
|
@@ -30,10 +30,10 @@ import {
|
|
|
30
30
|
loadSlice,
|
|
31
31
|
loadMap,
|
|
32
32
|
toFacts,
|
|
33
|
-
} from "
|
|
33
|
+
} from "../adapters/corpus/conceptnet.mjs";
|
|
34
34
|
|
|
35
35
|
// corpus/namenet/generate.mjs's output — a single small top-up bundle.
|
|
36
|
-
const NAMENET_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "corpus", "namenet");
|
|
36
|
+
const NAMENET_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "corpus", "namenet");
|
|
37
37
|
|
|
38
38
|
export const EXTENSION_KINDS = Object.freeze(["corpus", "lexicon", "templates", "pack", "ontology"]);
|
|
39
39
|
|
|
@@ -258,7 +258,7 @@ export async function resolveExtensions(repoRoot, { configFile } = {}) {
|
|
|
258
258
|
* recorded as `perBundle[name].error` while every other bundle still seeds normally.
|
|
259
259
|
* Returns `{ appended, skipped, total, perBundle: { name: {appended,skipped,total,error?} } }`. */
|
|
260
260
|
export async function seedActiveCorpusEntries(repo, entries) {
|
|
261
|
-
const { seedMemory } = await import("
|
|
261
|
+
const { seedMemory } = await import("../adapters/corpus/conceptnet.mjs");
|
|
262
262
|
const perBundle = {};
|
|
263
263
|
let appended = 0;
|
|
264
264
|
let skipped = 0;
|
|
@@ -347,7 +347,7 @@ export async function validateExtensionPack(dir, candidate) {
|
|
|
347
347
|
if (candidate.lexiconPath) {
|
|
348
348
|
const path = abs(candidate.lexiconPath);
|
|
349
349
|
try {
|
|
350
|
-
const { loadLexicon } = await import("
|
|
350
|
+
const { loadLexicon } = await import("../domain/grammar/lexicon.mjs");
|
|
351
351
|
const raw = JSON.parse(await readFile(path, "utf8"));
|
|
352
352
|
const lex = loadLexicon(raw);
|
|
353
353
|
results.push({
|
|
@@ -362,7 +362,7 @@ export async function validateExtensionPack(dir, candidate) {
|
|
|
362
362
|
if (candidate.templatesPath) {
|
|
363
363
|
const path = abs(candidate.templatesPath);
|
|
364
364
|
try {
|
|
365
|
-
const { loadTemplates } = await import("
|
|
365
|
+
const { loadTemplates } = await import("../adapters/corpus/templates.mjs");
|
|
366
366
|
const templates = await loadTemplates(path);
|
|
367
367
|
const unnamespaced = [...templates.keys()].filter((id) => !id.includes(":"));
|
|
368
368
|
if (unnamespaced.length) {
|
|
@@ -12,13 +12,13 @@ import { fileURLToPath } from "node:url";
|
|
|
12
12
|
import { join, dirname } from "node:path";
|
|
13
13
|
import { parse as parseToml } from "smol-toml";
|
|
14
14
|
|
|
15
|
-
import { flatten } from "
|
|
15
|
+
import { flatten } from "../adapters/corpus/templates.mjs";
|
|
16
16
|
|
|
17
17
|
export { flatten };
|
|
18
18
|
|
|
19
19
|
const GRAMMAR_DIR = dirname(fileURLToPath(import.meta.url));
|
|
20
20
|
/** The data-driven grammar-rule table. */
|
|
21
|
-
export const GRAMMAR_RULES_FILE = join(GRAMMAR_DIR, "..", "data", "templates", "grammar-rules.toml");
|
|
21
|
+
export const GRAMMAR_RULES_FILE = join(GRAMMAR_DIR, "..", "..", "data", "templates", "grammar-rules.toml");
|
|
22
22
|
|
|
23
23
|
/** The segment type vocabulary. `prose` is the only unprotected type. */
|
|
24
24
|
export const SEGMENT_TYPES = Object.freeze([
|
|
Binary file
|
|
@@ -13,8 +13,8 @@ import { readFile } from "node:fs/promises";
|
|
|
13
13
|
import { basename, resolve } from "node:path";
|
|
14
14
|
|
|
15
15
|
import { runTurn, uuidv7 } from "./chat.mjs";
|
|
16
|
-
import { loadMemory, readFactRows, appendFact, openMemoryBackend } from "
|
|
17
|
-
import { loadConfig } from "
|
|
16
|
+
import { loadMemory, readFactRows, appendFact, openMemoryBackend } from "../adapters/memory/core.mjs";
|
|
17
|
+
import { loadConfig } from "../adapters/config.mjs";
|
|
18
18
|
import { splitSentences } from "./sentences.mjs";
|
|
19
19
|
|
|
20
20
|
/**
|
|
@@ -36,7 +36,7 @@ export async function importDefinitionFile(repoRoot, filePath, { env = process.e
|
|
|
36
36
|
const body = lines.filter((l) => !l.trim().startsWith("#")).join("\n");
|
|
37
37
|
const sentences = splitSentences(body).map((s) => s.trim()).filter(Boolean);
|
|
38
38
|
|
|
39
|
-
const { loadTomlConfig } = await import("
|
|
39
|
+
const { loadTomlConfig } = await import("../adapters/toml-config.mjs");
|
|
40
40
|
const raw = await loadTomlConfig(root).catch(() => null);
|
|
41
41
|
const backend = String(raw?.memory?.backend || "default").trim().toLowerCase();
|
|
42
42
|
const { dir: memoryDir, close } = await openMemoryBackend(root, backend);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @polycode-projects/the-mechanical-code-talker (tmct) — library entry point.
|
|
2
2
|
//
|
|
3
3
|
// This entry re-exports the adapter primitives a library consumer needs. The
|
|
4
|
-
// movable conversational grammar lives in src/interpret/ (normalization
|
|
4
|
+
// movable conversational grammar lives in src/domain/interpret/ (normalization
|
|
5
5
|
// pre-pass, the registered parsing strategies, the merge rule), while
|
|
6
6
|
// ask.mjs keeps the core primitives (resolveObject, traverse, render) and
|
|
7
7
|
// the ask() orchestration.
|
|
@@ -10,31 +10,41 @@
|
|
|
10
10
|
export { runChat, COMMANDS, answerCount, renderStats } from "./chat.mjs";
|
|
11
11
|
|
|
12
12
|
// Grammar / NL-over-graph primitives.
|
|
13
|
-
export { ask, resolveObject } from "
|
|
13
|
+
export { ask, resolveObject } from "../domain/ask.mjs";
|
|
14
14
|
|
|
15
15
|
// The interpretation pipeline: normalize once, run every
|
|
16
16
|
// registered strategy (grammar, keyword-spot, …) over the text, merge same-class
|
|
17
17
|
// results, surround distinct-class results — no graph access; pair it with ask()
|
|
18
18
|
// or the primitives to answer. `interpret(text, ctx)` returns the full record
|
|
19
19
|
// ({raw, normalized, normalizationChanged, results, parsed, class, alternates}).
|
|
20
|
-
export { interpret } from "
|
|
20
|
+
export { interpret } from "../domain/interpret/pipeline.mjs";
|
|
21
|
+
|
|
22
|
+
// Composition: the library entry wires the domain parser's default lemma/POS
|
|
23
|
+
// adapter and the construction-grammar banks (lazy loader), same as the chat
|
|
24
|
+
// and tool surfaces do for themselves.
|
|
25
|
+
import { setDefaultNlpAdapter } from "../domain/interpret/nlp-registry.mjs";
|
|
26
|
+
import { setConstructionBanks } from "../domain/interpret/strategies/constructions.mjs";
|
|
27
|
+
import { nlpAdapter } from "../adapters/ask-nlp.mjs";
|
|
28
|
+
import { readConstructionFiles } from "../adapters/corpus/construction-banks.mjs";
|
|
29
|
+
setDefaultNlpAdapter(nlpAdapter);
|
|
30
|
+
setConstructionBanks(readConstructionFiles);
|
|
21
31
|
|
|
22
32
|
// Graph traversal primitives.
|
|
23
|
-
export { relationKind, impactClosure } from "
|
|
33
|
+
export { relationKind, impactClosure } from "../domain/codegraph.mjs";
|
|
24
34
|
|
|
25
35
|
// Tool dispatch (slash-commands and CLI tool calls route through here).
|
|
26
|
-
export { dispatchTool } from "
|
|
36
|
+
export { dispatchTool } from "../tools/server.mjs";
|
|
27
37
|
|
|
28
38
|
// Conversational memory — tmct's OWN OWL-labelled graph under
|
|
29
39
|
// .tmct/memory/, distinct from any provider-supplied code graph.
|
|
30
|
-
export { loadMemory, appendUtterance, appendFact } from "
|
|
31
|
-
export { retrieveBlocks, saveBlock, rankBlocks } from "
|
|
32
|
-
export { foldSessionLogs } from "./
|
|
40
|
+
export { loadMemory, appendUtterance, appendFact } from "../adapters/memory/core.mjs";
|
|
41
|
+
export { retrieveBlocks, saveBlock, rankBlocks } from "../adapters/memory/blocks.mjs";
|
|
42
|
+
export { foldSessionLogs } from "./fold.mjs";
|
|
33
43
|
|
|
34
44
|
// The single graph-load choke point — the adapter's data-provider seam
|
|
35
45
|
// (docs/adapter-contract.md): registerProvider() plugs a producer in;
|
|
36
46
|
// fetchEntities() is the one read path.
|
|
37
|
-
export { fetchEntities, registerProvider } from "
|
|
47
|
+
export { fetchEntities, registerProvider } from "../adapters/source.mjs";
|
|
38
48
|
|
|
39
49
|
// `tmct init` onboarding (also reachable as the `./init` subpath export).
|
|
40
50
|
// init.mjs and toml-config.mjs each export a same-named `CONFIG_FILE`
|
|
@@ -43,9 +53,8 @@ export { fetchEntities, registerProvider } from "./source.mjs";
|
|
|
43
53
|
export { initRepo, defaultConfig, renderTomlConfig, PERSONA_PRESETS, CONFIG_FILE as INIT_CONFIG_FILE } from "./init.mjs";
|
|
44
54
|
|
|
45
55
|
// tmct.toml loading (also reachable as the `./toml-config` subpath export).
|
|
46
|
-
export { CONFIG_FILE as TOML_CONFIG_FILE } from "
|
|
56
|
+
export { CONFIG_FILE as TOML_CONFIG_FILE } from "../adapters/toml-config.mjs";
|
|
47
57
|
|
|
48
58
|
// The "detailed answer" completions pipeline (also reachable as the
|
|
49
59
|
// `./generateCompletion` and `./createCompletionsGraphAdapter` subpath exports).
|
|
50
|
-
export { generateCompletion } from "./completions
|
|
51
|
-
export { createCompletionsGraphAdapter } from "./completions/graph-adapter.mjs";
|
|
60
|
+
export { generateCompletion, createCompletionsGraphAdapter } from "./completions.mjs";
|
|
@@ -57,7 +57,7 @@ export const PERSONA_PRESETS = Object.freeze({
|
|
|
57
57
|
/** Read this package's version (best-effort, for provenance). */
|
|
58
58
|
async function tmctVersion() {
|
|
59
59
|
try {
|
|
60
|
-
const pkgPath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
60
|
+
const pkgPath = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "package.json");
|
|
61
61
|
const pkg = JSON.parse(await readFile(pkgPath, "utf8"));
|
|
62
62
|
return pkg.version || null;
|
|
63
63
|
} catch {
|
|
@@ -92,7 +92,7 @@ export function renderTomlConfig(config = defaultConfig()) {
|
|
|
92
92
|
graph_file = ${JSON.stringify(c.graphFile)}
|
|
93
93
|
${Array.isArray(c.graphFiles) && c.graphFiles.length ? `
|
|
94
94
|
# graph_files — additional graph artifacts (multi-graph). Merged with
|
|
95
|
-
# graph_file at read time (src/graph-merge.mjs); an id that collides
|
|
95
|
+
# graph_file at read time (src/adapters/graph-merge.mjs); an id that collides
|
|
96
96
|
# across graphs is auto-prefixed with its graph's name, everything else
|
|
97
97
|
# passes through unchanged. Written by \`tmct init --graph\`/\`tmct import
|
|
98
98
|
# --graph\`.
|
|
@@ -136,12 +136,12 @@ backend = ${JSON.stringify(config.memory.backend)}
|
|
|
136
136
|
if (config.bias !== undefined) extras.bias = config.bias;
|
|
137
137
|
if (!Object.keys(extras).length) return out;
|
|
138
138
|
return `${out}
|
|
139
|
-
# Extension packs + bias (src/extensions.mjs) — written by \`tmct init --with-persona\`
|
|
139
|
+
# Extension packs + bias (src/services/extensions.mjs) — written by \`tmct init --with-persona\`
|
|
140
140
|
# or a manual edit. Recognized names (human, seon, conceptnet, tier2-aws,
|
|
141
141
|
# tier2-python, tier2-java, tier2-general) override the shipped defaults; any
|
|
142
142
|
# other name declares a new host-supplied bundle (needs its own "kind").
|
|
143
143
|
# [bias] is a flat bundle-name -> weight table consumed by
|
|
144
|
-
# src/memory/bias.mjs's ranking.
|
|
144
|
+
# src/domain/memory/bias.mjs's ranking.
|
|
145
145
|
${stringifyToml(extras)}`;
|
|
146
146
|
}
|
|
147
147
|
|
|
@@ -168,7 +168,7 @@ function seedRequested({ optSeed, configEnabled, env }) {
|
|
|
168
168
|
* merged into a FRESH config only; name resolution is the caller's job (bin/tmct.mjs).
|
|
169
169
|
* @param {string} [opts.memoryBackend] "default" | "memory" | "sqlite" — merged into a
|
|
170
170
|
* FRESH config's `[memory] backend`, and selects which backend the corpus seed writes
|
|
171
|
-
* into (via src/memory/core.mjs's openMemoryBackend).
|
|
171
|
+
* into (via src/adapters/memory/core.mjs's openMemoryBackend).
|
|
172
172
|
* @returns {Promise<{
|
|
173
173
|
* created: string[], config: object, seeded: boolean,
|
|
174
174
|
* alreadyInitialized: boolean, seedResult: (object|null), message: string
|
|
@@ -206,7 +206,7 @@ export async function initRepo(dir, { force = false, seed, env = process.env, pe
|
|
|
206
206
|
{
|
|
207
207
|
const importsDir = join(paths.tmct, "imports");
|
|
208
208
|
const gamesDir = join(importsDir, "games");
|
|
209
|
-
const shippedGames = join(dirname(fileURLToPath(import.meta.url)), "..", "data", "games");
|
|
209
|
+
const shippedGames = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "data", "games");
|
|
210
210
|
if (!(await exists(gamesDir))) {
|
|
211
211
|
await mkdir(gamesDir, { recursive: true });
|
|
212
212
|
created.push(gamesDir);
|
|
@@ -277,7 +277,7 @@ export async function initRepo(dir, { force = false, seed, env = process.env, pe
|
|
|
277
277
|
if (backendChoice === "memory") {
|
|
278
278
|
seedNote = "seed skipped (memory backend is in-process only — nothing would persist past this command)";
|
|
279
279
|
} else {
|
|
280
|
-
const { openMemoryBackend } = await import("
|
|
280
|
+
const { openMemoryBackend } = await import("../adapters/memory/core.mjs");
|
|
281
281
|
const { dir: memoryDir, close: closeMemoryStore } = await openMemoryBackend(root, backendChoice);
|
|
282
282
|
try {
|
|
283
283
|
const { resolveExtensions, seedActiveCorpusEntries } = await import("./extensions.mjs");
|
|
@@ -348,7 +348,7 @@ export async function initRepo(dir, { force = false, seed, env = process.env, pe
|
|
|
348
348
|
* (toml-config.mjs) is where a bad file surfaces its error. */
|
|
349
349
|
async function readWrittenConfig(tomlPath, base) {
|
|
350
350
|
try {
|
|
351
|
-
const { loadTomlConfig } = await import("
|
|
351
|
+
const { loadTomlConfig } = await import("../adapters/toml-config.mjs");
|
|
352
352
|
const raw = await loadTomlConfig(dirname(tomlPath));
|
|
353
353
|
if (!raw) return base;
|
|
354
354
|
const cfg = { ...base };
|
|
@@ -359,7 +359,7 @@ async function readWrittenConfig(tomlPath, base) {
|
|
|
359
359
|
if (raw.seed.enabled !== undefined) cfg.seed.enabled = Boolean(raw.seed.enabled);
|
|
360
360
|
if (raw.seed.limit !== undefined) cfg.seed.limit = Number(raw.seed.limit);
|
|
361
361
|
}
|
|
362
|
-
// Sparse pass-through — src/extensions.mjs validates; this layer just carries the
|
|
362
|
+
// Sparse pass-through — src/services/extensions.mjs validates; this layer just carries the
|
|
363
363
|
// raw tables through unmodified.
|
|
364
364
|
if (raw.extensions !== undefined) cfg.extensions = raw.extensions;
|
|
365
365
|
if (raw.bias !== undefined) cfg.bias = raw.bias;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// readMemoryAskBundle() is the one extra bit of I/O renderLedgerHtml itself
|
|
11
11
|
// doesn't do: it reads the checked-in chat-dock engine bundle.
|
|
12
12
|
|
|
13
|
-
import { loadMemory, readFactRows, findContradictions, normFactTerm } from "
|
|
13
|
+
import { loadMemory, readFactRows, findContradictions, normFactTerm } from "../adapters/memory/core.mjs";
|
|
14
14
|
import { THEME_TOKENS_CSS, SERIF_STACK, MONO_STACK, escapeHtml, embedJson } from "./viz-theme.mjs";
|
|
15
15
|
import { readFile } from "node:fs/promises";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
@@ -19,14 +19,14 @@ import { dirname, join } from "node:path";
|
|
|
19
19
|
export const LEDGER_ROW_LIMIT_DEFAULT = 20000;
|
|
20
20
|
|
|
21
21
|
/** Read the checked-in browser memory-ask-engine bundle
|
|
22
|
-
* (`src/memory-ask-browser.bundle.js`) — the real memory-graph answer engine
|
|
22
|
+
* (`src/surfaces/web/memory-ask-browser.bundle.js`) — the real memory-graph answer engine
|
|
23
23
|
* (chat.mjs's factAnswer/factReadBack) the chat dock runs on. Returns `""`,
|
|
24
24
|
* never throws, if the bundle hasn't been built — the page then renders with
|
|
25
25
|
* an honest "chat unavailable" note instead of a dock. */
|
|
26
26
|
export async function readMemoryAskBundle() {
|
|
27
27
|
try {
|
|
28
28
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
29
|
-
return await readFile(join(here, "memory-ask-browser.bundle.js"), "utf8");
|
|
29
|
+
return await readFile(join(here, "..", "surfaces", "web", "memory-ask-browser.bundle.js"), "utf8");
|
|
30
30
|
} catch {
|
|
31
31
|
return "";
|
|
32
32
|
}
|
|
@@ -225,6 +225,38 @@ export function resolveAnsweredTerm(answerText, questionText, terms, normFn) {
|
|
|
225
225
|
return (terms || []).some((t) => t && t.term === norm) ? norm : null;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
/** Per-segment facet counts for the rows touching `focus`: each group's count
|
|
229
|
+
* is computed against the OTHER groups' active filters (its own group's
|
|
230
|
+
* selection is skipped), so a selected family narrows the provenance and
|
|
231
|
+
* recency counts but never its own rail. `sel` holds the active multi-select
|
|
232
|
+
* Sets ({prov, fam, rec}); `now` anchors the recency buckets. Self-contained
|
|
233
|
+
* on purpose: its source is injected into the rendered page verbatim, so it
|
|
234
|
+
* must close over nothing. */
|
|
235
|
+
export function facetCounts(rows, focus, sel, now) {
|
|
236
|
+
const DAY = 86400000;
|
|
237
|
+
const recencyOf = (r) => {
|
|
238
|
+
const t = Date.parse(r.createdAt);
|
|
239
|
+
if (!Number.isFinite(t)) return "older";
|
|
240
|
+
const age = now - t;
|
|
241
|
+
return age < DAY ? "today" : age < 7 * DAY ? "this week" : "older";
|
|
242
|
+
};
|
|
243
|
+
const passes = (r, skip) =>
|
|
244
|
+
(skip === "prov" || !sel.prov.size || sel.prov.has(r.prov)) &&
|
|
245
|
+
(skip === "fam" || !sel.fam.size || sel.fam.has(r.family)) &&
|
|
246
|
+
(skip === "rec" || !sel.rec.size || sel.rec.has(recencyOf(r)));
|
|
247
|
+
const counts = { prov: {}, fam: {}, rec: {} };
|
|
248
|
+
for (const r of rows || []) {
|
|
249
|
+
if (!focus || (r.s !== focus && r.o !== focus)) continue;
|
|
250
|
+
if (passes(r, "prov")) counts.prov[r.prov] = (counts.prov[r.prov] || 0) + 1;
|
|
251
|
+
if (passes(r, "fam")) counts.fam[r.family] = (counts.fam[r.family] || 0) + 1;
|
|
252
|
+
if (passes(r, "rec")) {
|
|
253
|
+
const k = recencyOf(r);
|
|
254
|
+
counts.rec[k] = (counts.rec[k] || 0) + 1;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return counts;
|
|
258
|
+
}
|
|
259
|
+
|
|
228
260
|
/** One complete, self-contained document: the ledger, segment rail,
|
|
229
261
|
* worth-a-look panel, breadcrumb/search, two-hop minimap, and (when the
|
|
230
262
|
* memory-ask bundle is present) the ask-the-graph chat dock, all over the
|
|
@@ -376,6 +408,7 @@ ${hasMemChat ? `<script>\n${bundleStr}\n</script>` : ""}
|
|
|
376
408
|
(function () {
|
|
377
409
|
"use strict";
|
|
378
410
|
const DAY = 86400000;
|
|
411
|
+
const facetCounts = ${facetCounts.toString()};
|
|
379
412
|
const el = (id) => document.getElementById(id);
|
|
380
413
|
const esc = (s) => String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
|
|
381
414
|
const FAMS = ["is-a", "has", "can", "used-for", "rests-on", "role", "other"];
|
|
@@ -418,13 +451,11 @@ ${hasMemChat ? `<script>\n${bundleStr}\n</script>` : ""}
|
|
|
418
451
|
return b;
|
|
419
452
|
}
|
|
420
453
|
function renderSegs() {
|
|
421
|
-
const
|
|
454
|
+
const counts = facetCounts(LEDGER.rows, focus, sel, Date.now());
|
|
422
455
|
const put = (id, group, values, labelOf, clsOf) => {
|
|
423
456
|
const box = el(id); box.innerHTML = "";
|
|
424
457
|
for (const v of values) {
|
|
425
|
-
|
|
426
|
-
(group === "prov" ? r.prov === v : group === "fam" ? r.family === v : recOf(r) === v)).length;
|
|
427
|
-
box.appendChild(segButton(group, v, labelOf(v), count, clsOf ? clsOf(v) : null));
|
|
458
|
+
box.appendChild(segButton(group, v, labelOf(v), counts[group][v] || 0, clsOf ? clsOf(v) : null));
|
|
428
459
|
}
|
|
429
460
|
};
|
|
430
461
|
put("segProv", "prov", PROVS.map((p) => p[0]), (v) => PROVS.find((p) => p[0] === v)[1], (v) => "c-" + provKey(v));
|
|
@@ -31,7 +31,9 @@ function darken(hex, fraction) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/** Topological rank over [smaller, larger] pairs, label tiebreak; members
|
|
34
|
-
* absent from every pair are appended in label order.
|
|
34
|
+
* absent from every pair are appended in label order. `sized` names the members
|
|
35
|
+
* a pair actually ordered — the appended rest carry a rank so they can be drawn,
|
|
36
|
+
* which says nothing about their size. */
|
|
35
37
|
function rankBySize(sizeOrder, members) {
|
|
36
38
|
const pairs = Array.isArray(sizeOrder) ? sizeOrder : [];
|
|
37
39
|
const inPairs = new Set();
|
|
@@ -62,10 +64,11 @@ function rankBySize(sizeOrder, members) {
|
|
|
62
64
|
}
|
|
63
65
|
ready.sort();
|
|
64
66
|
}
|
|
67
|
+
const sized = new Set(Object.keys(ranks));
|
|
65
68
|
for (const m of [...members].sort()) {
|
|
66
69
|
if (!(m in ranks)) ranks[m] = next++;
|
|
67
70
|
}
|
|
68
|
-
return ranks;
|
|
71
|
+
return { ranks, sized };
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
/**
|
|
@@ -106,7 +109,7 @@ export function computeBlocksLayout({ plan, rendersAs = {}, sizeOrder = [] }) {
|
|
|
106
109
|
const anchorX = new Map(anchors.map((a) => [a.id, a.x]));
|
|
107
110
|
|
|
108
111
|
const blocks = [...blockSet].sort();
|
|
109
|
-
const ranks = rankBySize(sizeOrder, blocks);
|
|
112
|
+
const { ranks, sized } = rankBySize(sizeOrder, blocks);
|
|
110
113
|
const maxRank = blocks.reduce((m, b) => Math.max(m, ranks[b] ?? 0), 0);
|
|
111
114
|
const blockClassOf = (label) =>
|
|
112
115
|
classes.find((cls) => rendersAs[cls] === "block" && (classMembers[cls] || []).includes(label));
|
|
@@ -118,21 +121,27 @@ export function computeBlocksLayout({ plan, rendersAs = {}, sizeOrder = [] }) {
|
|
|
118
121
|
};
|
|
119
122
|
|
|
120
123
|
const snapshots = (plan?.states || []).map((rows) => {
|
|
121
|
-
const
|
|
124
|
+
const restingOn = new Map(); // object -> every subject resting directly on it
|
|
122
125
|
for (const r of [...rows].sort((a, b) => (a.subject < b.subject ? -1 : 1))) {
|
|
123
|
-
if (blockSet.has(r.subject)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
+
if (!blockSet.has(r.subject)) continue;
|
|
127
|
+
if (!restingOn.has(r.object)) restingOn.set(r.object, []);
|
|
128
|
+
const above = restingOn.get(r.object);
|
|
129
|
+
if (!above.includes(r.subject)) above.push(r.subject);
|
|
126
130
|
}
|
|
127
131
|
const stacks = {};
|
|
128
132
|
const items = anchors.map((a) => ({ ...a }));
|
|
129
133
|
for (const a of anchors) {
|
|
130
134
|
const stack = [];
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
const placed = new Set();
|
|
136
|
+
const pileOnto = (support) => {
|
|
137
|
+
for (const label of [...(restingOn.get(support) || [])].sort()) {
|
|
138
|
+
if (placed.has(label)) continue;
|
|
139
|
+
placed.add(label);
|
|
140
|
+
stack.push(label);
|
|
141
|
+
pileOnto(label);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
pileOnto(a.id);
|
|
136
145
|
stacks[a.id] = stack;
|
|
137
146
|
stack.forEach((label, i) => {
|
|
138
147
|
const w = widthOf(label);
|
|
@@ -152,16 +161,24 @@ export function computeBlocksLayout({ plan, rendersAs = {}, sizeOrder = [] }) {
|
|
|
152
161
|
return { items, stacks };
|
|
153
162
|
});
|
|
154
163
|
|
|
155
|
-
return { board: { w: BOARD_W, h: BOARD_H }, ranks, anchors, snapshots };
|
|
164
|
+
return { board: { w: BOARD_W, h: BOARD_H }, ranks, sized, anchors, snapshots };
|
|
156
165
|
}
|
|
157
166
|
|
|
158
167
|
/** Phase brackets from the largest block's single move: everything before it
|
|
159
168
|
* frees the piece, the move itself is the pivot, the rest rebuilds. */
|
|
160
|
-
function phasesFor(actions, ranks) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
169
|
+
function phasesFor(actions, ranks, sized) {
|
|
170
|
+
// free-it / move-it / rebuild-on-it describes ONE shape: a puzzle whose biggest
|
|
171
|
+
// piece is declared biggest and travels once, everything before clearing its way
|
|
172
|
+
// and everything after stacking back on top. Hanoi is that shape. A puzzle that
|
|
173
|
+
// declares no sizes has no biggest piece to pivot on — rankBySize ranks its
|
|
174
|
+
// pieces by label so they can be drawn, and reading a pivot out of that ordering
|
|
175
|
+
// names an arbitrary piece. Say nothing rather than something arbitrary.
|
|
176
|
+
const ordered = [...(sized || [])];
|
|
177
|
+
if (!ordered.length || !actions.length) return [];
|
|
178
|
+
const pivot = ordered.reduce((a, b) => (ranks[a] >= ranks[b] ? a : b));
|
|
179
|
+
const moves = actions.filter((a) => a.subject === pivot);
|
|
180
|
+
if (moves.length !== 1) return []; // travels more than once — not this shape
|
|
181
|
+
const k = actions.indexOf(moves[0]);
|
|
165
182
|
if (k <= 0 || k >= actions.length - 1) return [];
|
|
166
183
|
return [
|
|
167
184
|
{ label: `free ${pivot}`, from: 0, to: k },
|
|
@@ -198,7 +215,7 @@ export function renderPlanHtml({ plan, rendersAs = {}, sizeOrder = [], title } =
|
|
|
198
215
|
anchors: layout.anchors,
|
|
199
216
|
board: layout.board,
|
|
200
217
|
facts: factsPerStep,
|
|
201
|
-
phases: phasesFor(actions, layout.ranks),
|
|
218
|
+
phases: phasesFor(actions, layout.ranks, layout.sized),
|
|
202
219
|
});
|
|
203
220
|
const pageTitle = title || `tmct plan — ${actions.length} move${actions.length === 1 ? "" : "s"}`;
|
|
204
221
|
|
|
@@ -327,13 +344,35 @@ const PLAN = ${embedded};
|
|
|
327
344
|
const a = posIn(before, id), b = posIn(after, id);
|
|
328
345
|
return a && b && (a.x !== b.x || a.y !== b.y);
|
|
329
346
|
});
|
|
330
|
-
if (reduced || movers.length
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
347
|
+
if (reduced || movers.length === 0) { drawState(i + 1); return; }
|
|
348
|
+
// A step can move several pieces at once (a carrier plus its passengers).
|
|
349
|
+
// Only pieces that change column actually travel; a piece whose column is
|
|
350
|
+
// unchanged is settling into the gap a departing piece left, so it drops
|
|
351
|
+
// in place rather than miming the journey.
|
|
352
|
+
const travellers = movers.filter((id) => posIn(before, id).x !== posIn(after, id).x);
|
|
353
|
+
const settlers = movers.filter((id) => posIn(before, id).x === posIn(after, id).x);
|
|
354
|
+
animating = true;
|
|
355
|
+
// Each traveller rides its own lane so pieces crossing together stay
|
|
356
|
+
// legible instead of stacking up on one another mid-air.
|
|
357
|
+
const riders = travellers.map((id, lane) => ({
|
|
358
|
+
el: blockEls[id],
|
|
359
|
+
to: posIn(after, id),
|
|
360
|
+
liftY: ${LIFT_Y} - lane * ${BLOCK_H + BLOCK_GAP},
|
|
361
|
+
}));
|
|
362
|
+
for (const r of riders) r.el.classList.add("moving");
|
|
363
|
+
for (const r of riders) { r.el.style.transition = "top .18s ease-in"; r.el.style.top = r.liftY + "px"; }
|
|
364
|
+
await wait(190);
|
|
365
|
+
for (const id of settlers) {
|
|
366
|
+
const el = blockEls[id];
|
|
367
|
+
el.style.transition = "top .2s ease-in-out"; el.style.top = posIn(after, id).y + "px";
|
|
368
|
+
}
|
|
369
|
+
for (const r of riders) { r.el.style.transition = "left .26s ease-in-out"; r.el.style.left = r.to.x + "px"; }
|
|
370
|
+
await wait(270);
|
|
371
|
+
for (const r of riders) { r.el.style.transition = "top .18s ease-out"; r.el.style.top = r.to.y + "px"; }
|
|
372
|
+
await wait(200);
|
|
373
|
+
for (const r of riders) r.el.classList.remove("moving");
|
|
374
|
+
drawState(i + 1);
|
|
375
|
+
animating = false;
|
|
337
376
|
}
|
|
338
377
|
const phaseFor = (i) => {
|
|
339
378
|
if (i >= N) return "done";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// sentences.mjs — sentence-boundary splitting, shared by the extract-facts
|
|
2
2
|
// script, the chat one-shot CLI, and runTurn's multi-sentence pre-split.
|
|
3
3
|
|
|
4
|
-
import { winkInstance } from "
|
|
4
|
+
import { winkInstance } from "../adapters/wink-model.mjs";
|
|
5
5
|
|
|
6
6
|
/** Split text into trimmed, non-empty sentences via wink-nlp's own
|
|
7
7
|
* sentence-boundary detection — never a naive regex split, matching the
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
|
|
19
19
|
import { mkdir, readFile, readdir, rename, writeFile } from "node:fs/promises";
|
|
20
20
|
import { basename, dirname, join } from "node:path";
|
|
21
|
-
import { appendUtterances, CREATED_AT_PROP, UPDATED_AT_PROP } from "
|
|
21
|
+
import { appendUtterances, CREATED_AT_PROP, UPDATED_AT_PROP } from "../adapters/memory/core.mjs";
|
|
22
|
+
import { turnKey } from "../domain/memory/session-turns.mjs";
|
|
22
23
|
|
|
23
24
|
export const SESSIONS_DIR_REL = join(".tmct", "sessions");
|
|
24
25
|
|
|
@@ -236,7 +237,7 @@ async function recordSessionMemory(graphFile, record, repoDirOverride = null) {
|
|
|
236
237
|
ended = Boolean(parseSessionJsonl(sidecar)?.ended);
|
|
237
238
|
} catch { /* no sidecar — nothing to fold from */ }
|
|
238
239
|
if (ended) {
|
|
239
|
-
const { foldSessionLogs } = await import("./
|
|
240
|
+
const { foldSessionLogs } = await import("./fold.mjs"); // lazy: fold imports this module
|
|
240
241
|
await foldSessionLogs(repoDir, { sessionId: record.id });
|
|
241
242
|
}
|
|
242
243
|
}
|
|
@@ -277,9 +278,7 @@ export function parseSessionJsonl(text) {
|
|
|
277
278
|
// echoed "> <query>" line (chat.mjs's logLines shape).
|
|
278
279
|
const LOG_TS_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
279
280
|
|
|
280
|
-
|
|
281
|
-
* two instant turns land in the same millisecond). */
|
|
282
|
-
export const turnKey = (ts, query) => `${ts}${query}`;
|
|
281
|
+
export { turnKey };
|
|
283
282
|
|
|
284
283
|
/**
|
|
285
284
|
* Parse a human-readable session transcript (.tmct/session-<id>.log) into a
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { appendFile } from "node:fs/promises";
|
|
14
14
|
import { dirname, join } from "node:path";
|
|
15
|
-
import { uuidv7 } from "
|
|
15
|
+
import { uuidv7 } from "../adapters/uuid.mjs";
|
|
16
16
|
|
|
17
17
|
/** Field names whose VALUES are (or embed) raw source and must never be logged. `body` is
|
|
18
18
|
* the Repository Interface's own field name for real source text (snippet()/context()'s
|