run-dmcp 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -10
- package/dist/bin/run-dmcp.d.ts +2 -0
- package/dist/bin/run-dmcp.js +55 -0
- package/dist/db/connection.d.ts +32 -0
- package/dist/db/connection.js +38 -16
- package/dist/db/schema.d.ts +29 -1
- package/dist/db/schema.js +439 -7
- package/dist/http/server.js +3 -3
- package/dist/index.d.ts +36 -2
- package/dist/index.js +184 -92
- package/dist/mcp-server.d.ts +49 -0
- package/dist/mcp-server.js +127 -0
- package/dist/reader/turnReader.d.ts +185 -0
- package/dist/reader/turnReader.js +288 -0
- package/dist/register/batch.js +5 -79
- package/dist/register/mcp-resources.d.ts +9 -0
- package/dist/register/mcp-resources.js +16 -62
- package/dist/register/render.d.ts +17 -0
- package/dist/register/render.js +50 -0
- package/dist/register/resolve.d.ts +14 -0
- package/dist/register/resolve.js +102 -0
- package/dist/register/resources.js +11 -4
- package/dist/register/timeline.d.ts +2 -0
- package/dist/register/timeline.js +311 -0
- package/dist/rpg/index.d.ts +29 -0
- package/dist/rpg/index.js +55 -0
- package/dist/rpg/register/abilities.d.ts +2 -0
- package/dist/rpg/register/abilities.js +165 -0
- package/dist/rpg/register/batch.d.ts +2 -0
- package/dist/rpg/register/batch.js +92 -0
- package/dist/rpg/register/combat.d.ts +2 -0
- package/dist/rpg/register/combat.js +207 -0
- package/dist/rpg/register/mcp-prompts.d.ts +2 -0
- package/dist/rpg/register/mcp-prompts.js +684 -0
- package/dist/rpg/register/mcp-resources.d.ts +2 -0
- package/dist/rpg/register/mcp-resources.js +61 -0
- package/dist/rpg/register/quests.d.ts +2 -0
- package/dist/rpg/register/quests.js +118 -0
- package/dist/rpg/register/status.d.ts +2 -0
- package/dist/rpg/register/status.js +130 -0
- package/dist/rpg/register/tables.d.ts +2 -0
- package/dist/rpg/register/tables.js +146 -0
- package/dist/rpg/tools/ability.d.ts +48 -0
- package/dist/rpg/tools/ability.js +238 -0
- package/dist/rpg/tools/combat.d.ts +13 -0
- package/dist/rpg/tools/combat.js +195 -0
- package/dist/rpg/tools/dice.d.ts +23 -0
- package/dist/rpg/tools/dice.js +111 -0
- package/dist/rpg/tools/quest.d.ts +34 -0
- package/dist/rpg/tools/quest.js +164 -0
- package/dist/rpg/tools/status.d.ts +36 -0
- package/dist/rpg/tools/status.js +218 -0
- package/dist/rpg/tools/tables.d.ts +33 -0
- package/dist/rpg/tools/tables.js +209 -0
- package/dist/schemas/index.d.ts +12 -12
- package/dist/timeline/adjudication.d.ts +150 -0
- package/dist/timeline/adjudication.js +174 -0
- package/dist/timeline/changes.d.ts +100 -0
- package/dist/timeline/changes.js +161 -0
- package/dist/timeline/checkpoint.d.ts +69 -0
- package/dist/timeline/checkpoint.js +131 -0
- package/dist/timeline/clock.d.ts +89 -0
- package/dist/timeline/clock.js +173 -0
- package/dist/timeline/constrained.d.ts +220 -0
- package/dist/timeline/constrained.js +671 -0
- package/dist/timeline/export.d.ts +171 -0
- package/dist/timeline/export.js +329 -0
- package/dist/timeline/irreversible.d.ts +85 -0
- package/dist/timeline/irreversible.js +108 -0
- package/dist/timeline/kinds.d.ts +14 -0
- package/dist/timeline/kinds.js +22 -0
- package/dist/timeline/narration.d.ts +175 -0
- package/dist/timeline/narration.js +259 -0
- package/dist/timeline/projection.d.ts +97 -0
- package/dist/timeline/projection.js +330 -0
- package/dist/timeline/provenance.d.ts +66 -0
- package/dist/timeline/provenance.js +45 -0
- package/dist/timeline/registry.d.ts +95 -0
- package/dist/timeline/registry.js +124 -0
- package/dist/timeline/render.d.ts +121 -0
- package/dist/timeline/render.js +187 -0
- package/dist/timeline/replay.d.ts +64 -0
- package/dist/timeline/replay.js +104 -0
- package/dist/timeline/resolve.d.ts +262 -0
- package/dist/timeline/resolve.js +226 -0
- package/dist/timeline/schema.d.ts +13 -0
- package/dist/timeline/schema.js +262 -0
- package/dist/timeline/t.d.ts +80 -0
- package/dist/timeline/t.js +37 -0
- package/dist/tools/constraint.d.ts +44 -80
- package/dist/tools/constraint.js +115 -124
- package/dist/tools/relationship.d.ts +83 -2
- package/dist/tools/relationship.js +139 -62
- package/dist/tools/resource.d.ts +31 -6
- package/dist/tools/resource.js +106 -153
- package/dist/types/index.d.ts +19 -1
- package/dist/utils/output-schemas.d.ts +593 -2
- package/dist/utils/output-schemas.js +3 -0
- package/dist/utils/webui.d.ts +32 -0
- package/dist/utils/webui.js +54 -1
- package/package.json +20 -4
- package/dist/__tests__/engineVocabulary.test.d.ts +0 -1
- package/dist/__tests__/engineVocabulary.test.js +0 -147
- package/dist/db/__tests__/connection.test.d.ts +0 -1
- package/dist/db/__tests__/connection.test.js +0 -72
- package/dist/db/__tests__/testDb.d.ts +0 -33
- package/dist/db/__tests__/testDb.js +0 -41
- package/dist/test-setup.d.ts +0 -1
- package/dist/test-setup.js +0 -13
- package/dist/tools/__tests__/audio.test.d.ts +0 -1
- package/dist/tools/__tests__/audio.test.js +0 -59
- package/dist/tools/__tests__/conserved.test.d.ts +0 -1
- package/dist/tools/__tests__/conserved.test.js +0 -488
- package/dist/tools/__tests__/constraint.test.d.ts +0 -1
- package/dist/tools/__tests__/constraint.test.js +0 -212
- package/dist/tools/__tests__/expiry-consequences.test.d.ts +0 -1
- package/dist/tools/__tests__/expiry-consequences.test.js +0 -110
- package/dist/tools/__tests__/images.test.d.ts +0 -1
- package/dist/tools/__tests__/images.test.js +0 -59
- package/dist/tools/__tests__/relationship.test.d.ts +0 -1
- package/dist/tools/__tests__/relationship.test.js +0 -132
- package/dist/tools/__tests__/resource-constraints.test.d.ts +0 -1
- package/dist/tools/__tests__/resource-constraints.test.js +0 -131
- package/dist/tools/__tests__/resource.test.d.ts +0 -1
- package/dist/tools/__tests__/resource.test.js +0 -190
- package/dist/tools/__tests__/time.test.d.ts +0 -1
- package/dist/tools/__tests__/time.test.js +0 -404
- package/dist/tools/__tests__/timers.test.d.ts +0 -1
- package/dist/tools/__tests__/timers.test.js +0 -426
- package/dist/tools/__tests__/world.test.d.ts +0 -1
- package/dist/tools/__tests__/world.test.js +0 -70
- package/dist/utils/__tests__/json.test.d.ts +0 -1
- package/dist/utils/__tests__/json.test.js +0 -55
- package/dist/utils/__tests__/validation.test.d.ts +0 -1
- package/dist/utils/__tests__/validation.test.js +0 -90
package/dist/db/schema.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { getDatabase } from "./connection.js";
|
|
2
|
-
|
|
1
|
+
import { getDatabase, withTransaction } from "./connection.js";
|
|
2
|
+
import { createLogger } from "../utils/logger.js";
|
|
3
|
+
import { initializeTimelineSchema } from "../timeline/schema.js";
|
|
4
|
+
import { initializeAdjudicationSchema } from "../timeline/adjudication.js";
|
|
5
|
+
const log = createLogger("schema");
|
|
6
|
+
export function initializeSchema(options) {
|
|
3
7
|
const db = getDatabase();
|
|
4
8
|
// ============================================================================
|
|
5
9
|
// MIGRATION: Rename 'sessions' to 'games' and 'session_id' to 'game_id'
|
|
@@ -215,7 +219,9 @@ export function initializeSchema() {
|
|
|
215
219
|
FOREIGN KEY (game_id) REFERENCES games(id) ON DELETE CASCADE
|
|
216
220
|
)
|
|
217
221
|
`);
|
|
218
|
-
// Resource history table (tracks all changes)
|
|
222
|
+
// Resource history table (tracks all changes) -- FROZEN, see the trigger
|
|
223
|
+
// immediately below. Kept for existing rows only; nothing writes here any
|
|
224
|
+
// more.
|
|
219
225
|
db.exec(`
|
|
220
226
|
CREATE TABLE IF NOT EXISTS resource_history (
|
|
221
227
|
id TEXT PRIMARY KEY,
|
|
@@ -227,22 +233,281 @@ export function initializeSchema() {
|
|
|
227
233
|
timestamp TEXT NOT NULL,
|
|
228
234
|
FOREIGN KEY (resource_id) REFERENCES resources(id) ON DELETE CASCADE
|
|
229
235
|
)
|
|
236
|
+
`);
|
|
237
|
+
// Design §5.4 option (C) / issue #9, Phase 3: `resource_history` stops
|
|
238
|
+
// being a mechanism. Interval-versioned `facts` (via the timeline's one
|
|
239
|
+
// choke point, writeConstrainedValue/transferConstrainedValue in
|
|
240
|
+
// src/timeline/constrained.ts) are now the ONLY record of what a
|
|
241
|
+
// resource's value used to be -- see valueHistory() there, and
|
|
242
|
+
// getResourceHistory() in src/tools/resource.ts, which reads through it.
|
|
243
|
+
// This trigger makes the second write path this project spent its whole
|
|
244
|
+
// history accumulating (see engineVocabulary.test.ts's epigraph on
|
|
245
|
+
// resource_history/relationship_history) UNCONSTRUCTABLE rather than
|
|
246
|
+
// merely undocumented: any INSERT here -- from old code nobody rewrote,
|
|
247
|
+
// from a copy-pasted query, from anything -- aborts loudly instead of
|
|
248
|
+
// silently reintroducing a second history.
|
|
249
|
+
//
|
|
250
|
+
// The table is frozen, not dropped. This project has no down-migrations
|
|
251
|
+
// (root CLAUDE.md) and no framework beyond "idempotent DDL runs on every
|
|
252
|
+
// startup" -- a migration that DROPped this table would destroy rows a
|
|
253
|
+
// user's existing database may still hold, permanently, the first time
|
|
254
|
+
// they upgraded, which is a strictly worse outcome than a table that
|
|
255
|
+
// simply stops growing. Nothing reads it (getResourceHistory() no longer
|
|
256
|
+
// does) and nothing writes it (this trigger); the rows already on disk
|
|
257
|
+
// are inert history, not a mechanism.
|
|
258
|
+
//
|
|
259
|
+
// DROP TRIGGER IF EXISTS then CREATE, not CREATE TRIGGER IF NOT EXISTS --
|
|
260
|
+
// the same reasoning src/timeline/schema.ts's append-only guards give for
|
|
261
|
+
// their own triggers: IF NOT EXISTS would freeze whatever guard first
|
|
262
|
+
// shipped for a given on-disk database forever, so a later fix to this
|
|
263
|
+
// trigger's logic or message would silently never reach a database that
|
|
264
|
+
// already had an older version installed. Dropping and recreating on
|
|
265
|
+
// every startup keeps the guard a database actually has in sync with the
|
|
266
|
+
// guard this build believes it deployed.
|
|
267
|
+
db.exec(`
|
|
268
|
+
DROP TRIGGER IF EXISTS resource_history_frozen;
|
|
269
|
+
CREATE TRIGGER resource_history_frozen BEFORE INSERT ON resource_history
|
|
270
|
+
BEGIN
|
|
271
|
+
SELECT RAISE(ABORT, 'resource_history is frozen -- interval-versioned facts are now the only record of what a resource value used to be (design section 5.4 option C); write through writeConstrainedValue in src/timeline/constrained.ts instead');
|
|
272
|
+
END;
|
|
230
273
|
`);
|
|
231
274
|
// Resource constraints table -- optional, server-enforced invariants on
|
|
232
275
|
// resource values (see src/tools/constraint.ts). Opt-in: a resource with
|
|
233
276
|
// no row here (directly or via resource_constraint_members) behaves
|
|
234
277
|
// exactly as before this feature existed.
|
|
235
|
-
|
|
278
|
+
//
|
|
279
|
+
// `RESOURCE_CONSTRAINTS_DDL` is a shared constant, not a literal inlined
|
|
280
|
+
// here, because issue #13's `resolve_only` (design §5.3's fourth
|
|
281
|
+
// row-based member) needs this exact CHECK-widened text executed in TWO
|
|
282
|
+
// places: here, for a fresh database, and again inside the CHECK-rebuild
|
|
283
|
+
// migration further below, for a database that still carries the OLD
|
|
284
|
+
// three-member CHECK (SQLite cannot ALTER a CHECK constraint -- widening
|
|
285
|
+
// one needs a full table rebuild; see that block's comment for the
|
|
286
|
+
// recipe). Sharing one JS string is what makes "a fresh database and a
|
|
287
|
+
// migrated database converge on byte-identical `sqlite_master.sql` for
|
|
288
|
+
// this table" true BY CONSTRUCTION rather than by two hand-written
|
|
289
|
+
// literals happening to agree today -- resolveOnly.test.ts asserts
|
|
290
|
+
// exactly that equality, and it would be a permanent, silent trap to
|
|
291
|
+
// maintain as two copies.
|
|
292
|
+
const RESOURCE_CONSTRAINTS_DDL = `
|
|
236
293
|
CREATE TABLE IF NOT EXISTS resource_constraints (
|
|
237
294
|
id TEXT PRIMARY KEY,
|
|
238
295
|
game_id TEXT NOT NULL,
|
|
239
|
-
kind TEXT NOT NULL CHECK (kind IN ('bounded', 'monotonic', 'conserved')),
|
|
296
|
+
kind TEXT NOT NULL CHECK (kind IN ('bounded', 'monotonic', 'conserved', 'resolve_only')),
|
|
240
297
|
direction TEXT CHECK (direction IN ('increasing', 'decreasing')),
|
|
241
298
|
total REAL,
|
|
242
299
|
created_at TEXT NOT NULL,
|
|
243
300
|
FOREIGN KEY (game_id) REFERENCES games(id) ON DELETE CASCADE
|
|
244
301
|
)
|
|
245
|
-
|
|
302
|
+
`;
|
|
303
|
+
db.exec(RESOURCE_CONSTRAINTS_DDL);
|
|
304
|
+
// Add fact_key column to resource_constraints (migration, Phase 3 / issue
|
|
305
|
+
// #9 step 1, design §5.4 option (C)). A constraint governs a numeric
|
|
306
|
+
// *fact key* on an entity, not an entire row -- once the generic
|
|
307
|
+
// (entityId, factKey) choke point this column exists to prepare for
|
|
308
|
+
// lands, an entity can carry more than one numeric fact, and a constraint
|
|
309
|
+
// must say which one it governs or it would silently apply to all of
|
|
310
|
+
// them. 'value' is the default because every constraint that exists
|
|
311
|
+
// today (declared through declareBoundedConstraint/declareMonotonicConstraint/
|
|
312
|
+
// declareConservedConstraint in src/tools/constraint.ts) governs
|
|
313
|
+
// `resources.value` -- the sole numeric fact key any of them has ever
|
|
314
|
+
// constrained -- so defaulting means an existing database needs no data
|
|
315
|
+
// migration to keep reading its own constraints correctly. This column belongs on
|
|
316
|
+
// resource_constraints (the constraint), NOT on resource_constraint_members
|
|
317
|
+
// below: a 'conserved' set's members all share one key by construction
|
|
318
|
+
// (they are summed against a single total), and putting it on the member
|
|
319
|
+
// row would permit a set whose members are constrained on different
|
|
320
|
+
// keys -- a generality nothing has asked for.
|
|
321
|
+
//
|
|
322
|
+
// Shared for the same reason RESOURCE_CONSTRAINTS_DDL is above: the
|
|
323
|
+
// CHECK-rebuild migration below re-adds this exact column to its
|
|
324
|
+
// replacement table, and reusing the identical statement text (rather
|
|
325
|
+
// than a second hand-written ALTER) is what makes the fresh and migrated
|
|
326
|
+
// paths' final stored SQL provably identical instead of coincidentally
|
|
327
|
+
// similar.
|
|
328
|
+
const RESOURCE_CONSTRAINTS_ADD_FACT_KEY_DDL = `ALTER TABLE resource_constraints ADD COLUMN fact_key TEXT NOT NULL DEFAULT 'value'`;
|
|
329
|
+
try {
|
|
330
|
+
db.exec(RESOURCE_CONSTRAINTS_ADD_FACT_KEY_DDL);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Column already exists
|
|
334
|
+
}
|
|
335
|
+
// Issue #13 / design §5.3, §5.4 option (C): widen resource_constraints'
|
|
336
|
+
// `kind` CHECK to admit 'resolve_only', the fourth row-based constraint
|
|
337
|
+
// family member. SQLite cannot ALTER a CHECK constraint -- unlike the
|
|
338
|
+
// fact_key column just above, there is no `ALTER TABLE ... ADD` for
|
|
339
|
+
// "loosen this CHECK" -- so a database that already has resource_constraints
|
|
340
|
+
// rows under the OLD three-member CHECK needs SQLite's own documented
|
|
341
|
+
// recipe for "other kinds of table schema changes": build a replacement
|
|
342
|
+
// table with the new CHECK, copy every row across, drop the old table, and
|
|
343
|
+
// put the replacement in its place. This is the riskiest part of issue #13
|
|
344
|
+
// precisely because it is a real ALTER on a table other code already
|
|
345
|
+
// depends on (resource_constraint_members' own FOREIGN KEY points at it),
|
|
346
|
+
// so every step below is deliberate -- see resolveOnly.test.ts for the
|
|
347
|
+
// "an existing database survives the rebuild with every row and every FK
|
|
348
|
+
// intact" test this comment describes.
|
|
349
|
+
//
|
|
350
|
+
// DETECTION IS IDEMPOTENT AND LITERAL, not a guess: read this codebase's
|
|
351
|
+
// OWN generated DDL back out of `sqlite_master` and check whether it
|
|
352
|
+
// already contains the token 'resolve_only'. Hard rule 4 (never
|
|
353
|
+
// pattern-match meaning) forbids deriving state by matching words or
|
|
354
|
+
// phrases against natural language -- narrative text a model wrote, or a
|
|
355
|
+
// player typed. This is neither: it is a literal substring check against
|
|
356
|
+
// SQL text THIS FUNCTION generated a few lines above, for a token THIS
|
|
357
|
+
// FUNCTION defined (the CHECK's own enum member). Rule 4 explicitly
|
|
358
|
+
// permits exactly that ("a literal check for a token we defined in output
|
|
359
|
+
// we generated is fine; understanding English is not") -- flagged here in
|
|
360
|
+
// as many words because a future reader skimming a string-literal
|
|
361
|
+
// `.includes()` check might otherwise mistake it for the thing rule 4
|
|
362
|
+
// bans. A truly fresh database never takes the branch below:
|
|
363
|
+
// RESOURCE_CONSTRAINTS_DDL's CREATE TABLE IF NOT EXISTS a few lines up
|
|
364
|
+
// already carries the widened CHECK, so by the time this runs, this
|
|
365
|
+
// database's own resource_constraints already contains 'resolve_only'.
|
|
366
|
+
const resourceConstraintsDdl = db
|
|
367
|
+
.prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'resource_constraints'`)
|
|
368
|
+
.get();
|
|
369
|
+
if (resourceConstraintsDdl && !resourceConstraintsDdl.sql.includes("resolve_only")) {
|
|
370
|
+
// DROP THE resolve_only TRIGGER FIRST, UNCONDITIONALLY, IF IT EXISTS --
|
|
371
|
+
// made ORDER-INDEPENDENT rather than relying on "this trigger has never
|
|
372
|
+
// been created yet the one time this branch runs." That reliance was
|
|
373
|
+
// real on today's code (this block runs before initializeTimelineSchema()
|
|
374
|
+
// ever installs timeline_facts_resolve_only for the very first time, so
|
|
375
|
+
// on the one startup that performs a rebuild, the trigger genuinely does
|
|
376
|
+
// not exist yet) -- but it is an ACCIDENT OF ORDERING, not a structural
|
|
377
|
+
// guarantee, and root CLAUDE.md's "test against an existing database,
|
|
378
|
+
// not just a fresh one" warning exists precisely because accidents of
|
|
379
|
+
// ordering are how this kind of bug survives review. The trigger's own
|
|
380
|
+
// `WHEN` clause names `resource_constraints`, and SQLite revalidates
|
|
381
|
+
// every trigger body during schema surgery on a table it references
|
|
382
|
+
// (measured, not assumed -- see resolveOnly.test.ts, whose migration
|
|
383
|
+
// fixture hit exactly this: `ALTER TABLE ... RENAME TO resource_constraints`
|
|
384
|
+
// failed with "no such table: resource_constraints" while this trigger
|
|
385
|
+
// still existed and the table was transiently absent mid-rebuild) --
|
|
386
|
+
// so a database where the trigger was somehow installed before a rebuild
|
|
387
|
+
// runs (a future change that reorders trigger installation, or widens
|
|
388
|
+
// this CHECK a second time some other way) would break at startup with
|
|
389
|
+
// the schema half-rebuilt. Dropping it here costs nothing: the
|
|
390
|
+
// DROP-then-CREATE discipline every trigger in this codebase already
|
|
391
|
+
// follows (see the trigger's own creation site, far below, and the
|
|
392
|
+
// reasoning timeline_facts_irreversible gives for the same pattern)
|
|
393
|
+
// means it is unconditionally reinstalled before this function returns
|
|
394
|
+
// regardless -- this is that discipline paying for itself a second time.
|
|
395
|
+
db.exec(`DROP TRIGGER IF EXISTS timeline_facts_resolve_only`);
|
|
396
|
+
// PRAGMA foreign_keys is a documented no-op when toggled inside a
|
|
397
|
+
// pending transaction, so it brackets withTransaction() below rather
|
|
398
|
+
// than living inside it -- set OFF here (before BEGIN), restored ON
|
|
399
|
+
// after COMMIT. connection.ts turns it ON for every connection at
|
|
400
|
+
// open (`getDatabase()`); this block is the one place in the codebase
|
|
401
|
+
// that deliberately, temporarily, undoes that, and it is responsible
|
|
402
|
+
// for putting it back.
|
|
403
|
+
db.pragma("foreign_keys = OFF");
|
|
404
|
+
withTransaction(() => {
|
|
405
|
+
// EMPIRICALLY MEASURED, NOT ASSUMED (see resolveOnly.test.ts, whose
|
|
406
|
+
// FK-check assertion caught a real bug in an earlier version of this
|
|
407
|
+
// block): `ALTER TABLE ... RENAME TO` does not just rename the table
|
|
408
|
+
// being renamed -- it also rewrites the stored FOREIGN KEY clause of
|
|
409
|
+
// every OTHER table that references it by name (here,
|
|
410
|
+
// resource_constraint_members' `FOREIGN KEY (constraint_id)
|
|
411
|
+
// REFERENCES resource_constraints(id)`), REGARDLESS of the
|
|
412
|
+
// `foreign_keys` pragma above. Renaming the OLD table out of the way
|
|
413
|
+
// (the obvious first move) would therefore silently rewrite
|
|
414
|
+
// resource_constraint_members to reference the OLD table's new,
|
|
415
|
+
// temporary name -- and once that old table is dropped a few steps
|
|
416
|
+
// later, that reference is permanently dangling, with no further
|
|
417
|
+
// rename ever pointed at it to fix it back. `DROP TABLE`, unlike
|
|
418
|
+
// `RENAME TO`, does NOT rewrite other tables' references (there is
|
|
419
|
+
// nothing to rewrite them TO), so this recipe routes around the
|
|
420
|
+
// problem entirely: the old table is copied out of and then DROPped
|
|
421
|
+
// (never renamed), and the FINAL name is produced by a genuine
|
|
422
|
+
// `CREATE TABLE` (also never a rename target) -- so
|
|
423
|
+
// resource_constraint_members' FK text is never touched by anything
|
|
424
|
+
// in this block, and is simply valid again the moment step 4 below
|
|
425
|
+
// recreates a table under the name it always pointed at.
|
|
426
|
+
//
|
|
427
|
+
// 1. Copy the OLD table's rows into a staging table under a temporary
|
|
428
|
+
// name -- widened CHECK, and fact_key included from the start
|
|
429
|
+
// (unlike the final table a few steps down, this one is never
|
|
430
|
+
// compared to RESOURCE_CONSTRAINTS_DDL's stored text, so there is
|
|
431
|
+
// no reason to reproduce the fresh path's "add fact_key later via
|
|
432
|
+
// ALTER" shape here).
|
|
433
|
+
db.exec(`
|
|
434
|
+
CREATE TABLE resource_constraints_staging (
|
|
435
|
+
id TEXT PRIMARY KEY,
|
|
436
|
+
game_id TEXT NOT NULL,
|
|
437
|
+
kind TEXT NOT NULL CHECK (kind IN ('bounded', 'monotonic', 'conserved', 'resolve_only')),
|
|
438
|
+
direction TEXT CHECK (direction IN ('increasing', 'decreasing')),
|
|
439
|
+
total REAL,
|
|
440
|
+
created_at TEXT NOT NULL,
|
|
441
|
+
fact_key TEXT NOT NULL DEFAULT 'value'
|
|
442
|
+
)
|
|
443
|
+
`);
|
|
444
|
+
db.exec(`
|
|
445
|
+
INSERT INTO resource_constraints_staging (id, game_id, kind, direction, total, created_at, fact_key)
|
|
446
|
+
SELECT id, game_id, kind, direction, total, created_at, fact_key FROM resource_constraints
|
|
447
|
+
`);
|
|
448
|
+
// 2. Drop the OLD table outright -- not renamed, per the note above.
|
|
449
|
+
db.exec(`DROP TABLE resource_constraints`);
|
|
450
|
+
// 3. Recreate under the FINAL name using the exact same DDL text the
|
|
451
|
+
// fresh-database path executed above -- RESOURCE_CONSTRAINTS_DDL
|
|
452
|
+
// itself, not a second hand-copied literal. This is a genuine
|
|
453
|
+
// `CREATE TABLE resource_constraints (...)`, never a rename
|
|
454
|
+
// target, so its stored SQL stays unquoted -- matching the
|
|
455
|
+
// fresh-database path byte for byte (verified empirically, see
|
|
456
|
+
// resolveOnly.test.ts's "byte-identical" assertion) rather than
|
|
457
|
+
// picking up RENAME TO's habit of re-quoting the identifier.
|
|
458
|
+
db.exec(RESOURCE_CONSTRAINTS_DDL);
|
|
459
|
+
// 4. Copy every row across from the staging table with an EXPLICIT
|
|
460
|
+
// column list -- never SELECT * -- naming every column except
|
|
461
|
+
// fact_key, which the just-recreated table does not have yet. It
|
|
462
|
+
// is added next, the same way the fresh path adds it.
|
|
463
|
+
db.exec(`
|
|
464
|
+
INSERT INTO resource_constraints (id, game_id, kind, direction, total, created_at)
|
|
465
|
+
SELECT id, game_id, kind, direction, total, created_at FROM resource_constraints_staging
|
|
466
|
+
`);
|
|
467
|
+
// 5. Add fact_key via the IDENTICAL statement text the fresh path
|
|
468
|
+
// uses (RESOURCE_CONSTRAINTS_ADD_FACT_KEY_DDL, not a hand-written
|
|
469
|
+
// equivalent). This is what makes the two paths' stored SQL
|
|
470
|
+
// provably byte-identical after this point: SQLite's ALTER TABLE
|
|
471
|
+
// ADD COLUMN rewrites a table's stored CREATE TABLE text by
|
|
472
|
+
// inserting the new column definition right after the last
|
|
473
|
+
// existing column and before any table-level constraint (verified
|
|
474
|
+
// empirically, not assumed -- see resolveOnly.test.ts) -- running
|
|
475
|
+
// the same statement against two structurally identical tables
|
|
476
|
+
// produces the same rewritten text, with no need to hand-guess
|
|
477
|
+
// that formatting.
|
|
478
|
+
db.exec(RESOURCE_CONSTRAINTS_ADD_FACT_KEY_DDL);
|
|
479
|
+
// 6. The ALTER above just backfilled every just-copied row's fact_key
|
|
480
|
+
// with its DEFAULT 'value' -- correct for every row that can exist
|
|
481
|
+
// today (every declare*Constraint() function other than
|
|
482
|
+
// declareResolveOnlyConstraint hardcodes factKey 'value', and
|
|
483
|
+
// declareResolveOnlyConstraint cannot have written a row before
|
|
484
|
+
// this migration exists to run), but this UPDATE restores each
|
|
485
|
+
// row's ACTUAL prior fact_key from the staging table by id rather
|
|
486
|
+
// than leaning on that staying true forever. An UPDATE never
|
|
487
|
+
// touches sqlite_master, so it cannot disturb the byte-identical
|
|
488
|
+
// DDL text step 5 just produced.
|
|
489
|
+
db.exec(`
|
|
490
|
+
UPDATE resource_constraints
|
|
491
|
+
SET fact_key = (
|
|
492
|
+
SELECT fact_key FROM resource_constraints_staging
|
|
493
|
+
WHERE resource_constraints_staging.id = resource_constraints.id
|
|
494
|
+
)
|
|
495
|
+
`);
|
|
496
|
+
// 7. Drop the staging table. Every id was copied verbatim in step 4,
|
|
497
|
+
// so resource_constraint_members' FOREIGN KEY (constraint_id)
|
|
498
|
+
// REFERENCES resource_constraints(id) -- never touched by any of
|
|
499
|
+
// the steps above -- is satisfied by the replacement table
|
|
500
|
+
// throughout, verified for real by the PRAGMA foreign_key_check
|
|
501
|
+
// below, not merely assumed here.
|
|
502
|
+
db.exec(`DROP TABLE resource_constraints_staging`);
|
|
503
|
+
});
|
|
504
|
+
const fkViolations = db.pragma("foreign_key_check");
|
|
505
|
+
if (fkViolations.length > 0) {
|
|
506
|
+
throw new Error(`resource_constraints CHECK migration (resolve_only, issue #13) left dangling foreign keys: ` +
|
|
507
|
+
JSON.stringify(fkViolations));
|
|
508
|
+
}
|
|
509
|
+
db.pragma("foreign_keys = ON");
|
|
510
|
+
}
|
|
246
511
|
// Members of a resource constraint. 'bounded' and 'monotonic' constraints
|
|
247
512
|
// have exactly one member (the resource they govern); 'conserved'
|
|
248
513
|
// constraints have two or more (the set that must sum to a fixed total).
|
|
@@ -255,6 +520,12 @@ export function initializeSchema() {
|
|
|
255
520
|
FOREIGN KEY (resource_id) REFERENCES resources(id) ON DELETE CASCADE
|
|
256
521
|
)
|
|
257
522
|
`);
|
|
523
|
+
// The adjudication window (design §5.3, §5.2a; issue #13): created here,
|
|
524
|
+
// BEFORE `timeline_facts_resolve_only` (the trigger that reads it, added
|
|
525
|
+
// near the end of this function once `facts` exists) -- see
|
|
526
|
+
// src/timeline/adjudication.ts for the table's own doc comment, including
|
|
527
|
+
// why its startup pass unconditionally clears every row.
|
|
528
|
+
initializeAdjudicationSchema(db);
|
|
258
529
|
// Game time table (one per game)
|
|
259
530
|
db.exec(`
|
|
260
531
|
CREATE TABLE IF NOT EXISTS game_time (
|
|
@@ -366,7 +637,8 @@ export function initializeSchema() {
|
|
|
366
637
|
FOREIGN KEY (game_id) REFERENCES games(id) ON DELETE CASCADE
|
|
367
638
|
)
|
|
368
639
|
`);
|
|
369
|
-
// Relationship history table
|
|
640
|
+
// Relationship history table -- FROZEN, see the trigger immediately below.
|
|
641
|
+
// Kept for existing rows only; nothing writes here any more.
|
|
370
642
|
db.exec(`
|
|
371
643
|
CREATE TABLE IF NOT EXISTS relationship_history (
|
|
372
644
|
id TEXT PRIMARY KEY,
|
|
@@ -377,6 +649,25 @@ export function initializeSchema() {
|
|
|
377
649
|
timestamp TEXT NOT NULL,
|
|
378
650
|
FOREIGN KEY (relationship_id) REFERENCES relationships(id) ON DELETE CASCADE
|
|
379
651
|
)
|
|
652
|
+
`);
|
|
653
|
+
// Design §5.4 option (C) / issue #9, Phase 3 step 3: `relationship_history`
|
|
654
|
+
// stops being a mechanism, same as `resource_history` immediately above --
|
|
655
|
+
// see that trigger's comment for the shared reasoning (why frozen and not
|
|
656
|
+
// dropped, why DROP-then-CREATE on every startup). The one thing specific
|
|
657
|
+
// here: `relationships` was already a `PROJECTED_TABLES` row (projection.ts)
|
|
658
|
+
// before this trigger existed, so its `value` column was already being
|
|
659
|
+
// dual-written into interval-versioned `facts` -- this freeze is what makes
|
|
660
|
+
// that the ONLY record, by routing every relationship value write through
|
|
661
|
+
// writeConstrainedValue() (src/timeline/constrained.ts) and cutting off the
|
|
662
|
+
// second path this table represented. See valueHistory() there, and
|
|
663
|
+
// getRelationshipHistory() in src/tools/relationship.ts, which reads
|
|
664
|
+
// through it.
|
|
665
|
+
db.exec(`
|
|
666
|
+
DROP TRIGGER IF EXISTS relationship_history_frozen;
|
|
667
|
+
CREATE TRIGGER relationship_history_frozen BEFORE INSERT ON relationship_history
|
|
668
|
+
BEGIN
|
|
669
|
+
SELECT RAISE(ABORT, 'relationship_history is frozen -- interval-versioned facts are now the only record of what a relationship value used to be (design section 5.4 option C); write through writeConstrainedValue in src/timeline/constrained.ts instead');
|
|
670
|
+
END;
|
|
380
671
|
`);
|
|
381
672
|
// Factions table
|
|
382
673
|
db.exec(`
|
|
@@ -722,4 +1013,145 @@ export function initializeSchema() {
|
|
|
722
1013
|
CREATE INDEX IF NOT EXISTS idx_stored_audio_primary ON stored_audio(entity_id, entity_type, is_primary);
|
|
723
1014
|
CREATE INDEX IF NOT EXISTS idx_stored_audio_voice_ref ON stored_audio(game_id, is_voice_reference);
|
|
724
1015
|
`);
|
|
1016
|
+
// Consumer-registered migrations (see `SchemaMigration` above) run after
|
|
1017
|
+
// every core table above exists.
|
|
1018
|
+
runConsumerMigrations(db, options?.migrations);
|
|
1019
|
+
// Timeline substrate (design §5.1), and it must be LAST -- after the
|
|
1020
|
+
// consumer's migrations, not merely after this function's own DDL.
|
|
1021
|
+
//
|
|
1022
|
+
// The projection triggers are generated from a live `pragma_table_info`
|
|
1023
|
+
// read of each projected table (see timeline/projection.ts), so whatever
|
|
1024
|
+
// ran most recently is what they are built against. A consumer migration
|
|
1025
|
+
// that adds a column to a projected table therefore gets that column
|
|
1026
|
+
// projected as a fact key, and reconciliation backfills it, with no code
|
|
1027
|
+
// change on either side. Run this before `runConsumerMigrations` instead
|
|
1028
|
+
// and such a column would be silently absent from the timeline until some
|
|
1029
|
+
// later startup happened to regenerate -- which is precisely the drift the
|
|
1030
|
+
// Phase 1 checkpoint exists to catch, arriving through the one door the
|
|
1031
|
+
// engine hands a consumer.
|
|
1032
|
+
initializeTimelineSchema();
|
|
1033
|
+
// Issue #13 / design §5.3, §5.2a: `resolve_only`'s enforcement backstop --
|
|
1034
|
+
// the SQL-level twin of the `resolve_only` branch in assertConstraintsAllow()
|
|
1035
|
+
// (src/timeline/constrained.ts). That JS check covers every write that
|
|
1036
|
+
// goes through writeConstrainedValue/transferConstrainedValue; THIS
|
|
1037
|
+
// trigger is what makes a write that skips those functions entirely --
|
|
1038
|
+
// a raw `UPDATE resources SET value = ...`, old code nobody rewrote, a
|
|
1039
|
+
// copy-pasted query -- unconstructable rather than merely unchecked. It
|
|
1040
|
+
// has to live HERE, not inside initializeTimelineSchema() (src/timeline/schema.ts)
|
|
1041
|
+
// alongside timeline_facts_irreversible (the trigger it is modeled on):
|
|
1042
|
+
// it reads resource_constraints/resource_constraint_members, which are
|
|
1043
|
+
// src/db/schema.ts's own tables, AND facts, which initializeTimelineSchema()
|
|
1044
|
+
// just created a line above -- and initializeTimelineSchema() is the LAST
|
|
1045
|
+
// thing this function calls (see the comment above it), so `facts` does
|
|
1046
|
+
// not exist at any point before that call returns. Creating this trigger
|
|
1047
|
+
// any earlier would `CREATE TRIGGER` against a table that isn't there
|
|
1048
|
+
// yet.
|
|
1049
|
+
//
|
|
1050
|
+
// ORDERING REQUIREMENT, STATED EXPLICITLY SO NOBODY MOVES THIS LATER: this
|
|
1051
|
+
// CREATE must run AFTER resource_constraints, resource_constraint_members
|
|
1052
|
+
// and timeline_adjudications_open all exist (true from here on, since all
|
|
1053
|
+
// three are created earlier in this same function) AND after the CHECK
|
|
1054
|
+
// -rebuild migration above has already run for this call. The rebuild
|
|
1055
|
+
// block enforces the second half of that itself -- it unconditionally
|
|
1056
|
+
// `DROP TRIGGER IF EXISTS`s this exact trigger before doing any table
|
|
1057
|
+
// surgery, precisely so that surgery can never run while this trigger
|
|
1058
|
+
// still exists to have its `WHEN` clause revalidated mid-rebuild against a
|
|
1059
|
+
// table that is transiently missing (see that block's own comment). Do
|
|
1060
|
+
// not reorder this CREATE ahead of that block on the theory that "it
|
|
1061
|
+
// always ran after anyway" -- that theory is exactly what the rebuild
|
|
1062
|
+
// block's DROP now makes irrelevant, and reordering would silently
|
|
1063
|
+
// reintroduce the dependency the DROP exists to remove.
|
|
1064
|
+
//
|
|
1065
|
+
// SCOPED PER (entity_id, key), unlike timeline_facts_irreversible's
|
|
1066
|
+
// per-(entity_id, key) VALUE comparison -- resolve_only has no value to
|
|
1067
|
+
// compare, only a declaration to look up, via the same JOIN
|
|
1068
|
+
// registry.ts's constraintsFor() runs in JS: is there a 'resolve_only'
|
|
1069
|
+
// constraint whose member list includes NEW.entity_id and whose fact_key
|
|
1070
|
+
// matches NEW.key. AND conditional on the window: the second half of the
|
|
1071
|
+
// WHEN clause, `NOT EXISTS (SELECT 1 FROM timeline_adjudications_open)`,
|
|
1072
|
+
// reads the exact same table `adjudicationOpen()` (src/timeline/adjudication.js)
|
|
1073
|
+
// reads in JS -- see that module's doc comment for why this is one source
|
|
1074
|
+
// of truth read in two places, never two independent checks that happen
|
|
1075
|
+
// to agree.
|
|
1076
|
+
//
|
|
1077
|
+
// BEFORE INSERT ON facts, not UPDATE: facts are append-only
|
|
1078
|
+
// (timeline_facts_immutable, src/timeline/schema.ts), so a new value for a
|
|
1079
|
+
// key always arrives as a fresh INSERT. This is deliberately an INSERT
|
|
1080
|
+
// guard for the same reason timeline_facts_irreversible is one: closing an
|
|
1081
|
+
// interval is `UPDATE facts SET valid_to_t = ...`, a different table
|
|
1082
|
+
// event entirely, and is NOT a write of a new value -- it never reaches
|
|
1083
|
+
// this trigger. That is what keeps destroying an entity, or otherwise
|
|
1084
|
+
// closing a resolve_only-governed fact, legal even with no adjudication
|
|
1085
|
+
// window open: the engine records decisions, it does not impose policy on
|
|
1086
|
+
// top of them (hard rule 2), and refusing to let an entity be destroyed
|
|
1087
|
+
// because it happens to carry a resolve_only fact would be exactly that.
|
|
1088
|
+
//
|
|
1089
|
+
// DROP-then-CREATE, never CREATE TRIGGER IF NOT EXISTS -- the same
|
|
1090
|
+
// reasoning timeline_facts_irreversible and every other trigger in this
|
|
1091
|
+
// codebase give for themselves: IF NOT EXISTS would freeze whatever guard
|
|
1092
|
+
// first shipped for a given on-disk database forever, so a later fix to
|
|
1093
|
+
// this trigger's logic or wording would silently never reach a database
|
|
1094
|
+
// that already had an older version installed. Dropping and recreating on
|
|
1095
|
+
// every startup keeps the guard a database actually has in sync with the
|
|
1096
|
+
// guard this build believes it deployed.
|
|
1097
|
+
//
|
|
1098
|
+
// NOTE FOR THE NEXT READER OF reconcileTimeline() (src/timeline/projection.ts):
|
|
1099
|
+
// reconciliation runs at the end of every startup and, per column, closes
|
|
1100
|
+
// a diverged fact and opens a new one -- an INSERT that would hit this
|
|
1101
|
+
// very trigger for a resolve_only-governed key with no window open
|
|
1102
|
+
// (reconciliation is not an adjudicating call). projection.ts's
|
|
1103
|
+
// reconcileTable() carries its own guard for exactly that, modeled on the
|
|
1104
|
+
// one it already had for `irreversible` -- see the comment on its
|
|
1105
|
+
// close-UPDATE and open-INSERT statements.
|
|
1106
|
+
db.exec(`
|
|
1107
|
+
DROP TRIGGER IF EXISTS timeline_facts_resolve_only;
|
|
1108
|
+
CREATE TRIGGER timeline_facts_resolve_only
|
|
1109
|
+
BEFORE INSERT ON facts
|
|
1110
|
+
WHEN EXISTS (
|
|
1111
|
+
SELECT 1 FROM resource_constraints rc
|
|
1112
|
+
JOIN resource_constraint_members rcm ON rcm.constraint_id = rc.id
|
|
1113
|
+
WHERE rc.kind = 'resolve_only'
|
|
1114
|
+
AND rcm.resource_id = NEW.entity_id
|
|
1115
|
+
AND rc.fact_key = NEW.key
|
|
1116
|
+
) AND NOT EXISTS (SELECT 1 FROM timeline_adjudications_open)
|
|
1117
|
+
BEGIN
|
|
1118
|
+
SELECT RAISE(ABORT, 'timeline: ''' || NEW.key || ''' on this entity is resolve_only-constrained; direct writes are refused -- this value can only change through the adjudicating call that opens the resolution window');
|
|
1119
|
+
END;
|
|
1120
|
+
`);
|
|
1121
|
+
}
|
|
1122
|
+
function runConsumerMigrations(db, migrations) {
|
|
1123
|
+
if (!migrations || migrations.length === 0) {
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
validateMigrations(migrations);
|
|
1127
|
+
for (const migration of migrations) {
|
|
1128
|
+
try {
|
|
1129
|
+
db.transaction(() => {
|
|
1130
|
+
migration.up(db);
|
|
1131
|
+
})();
|
|
1132
|
+
}
|
|
1133
|
+
catch (err) {
|
|
1134
|
+
log.error("Consumer schema migration failed", {
|
|
1135
|
+
migration: migration.name,
|
|
1136
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1137
|
+
});
|
|
1138
|
+
throw new Error(`Schema migration '${migration.name}' failed`, { cause: err });
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
function validateMigrations(migrations) {
|
|
1143
|
+
const seen = new Set();
|
|
1144
|
+
for (const migration of migrations) {
|
|
1145
|
+
const name = migration?.name;
|
|
1146
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
1147
|
+
throw new Error(`Invalid schema migration: 'name' must be a non-empty string, got ${JSON.stringify(name)}`);
|
|
1148
|
+
}
|
|
1149
|
+
if (seen.has(name)) {
|
|
1150
|
+
throw new Error(`Duplicate schema migration name: '${name}'`);
|
|
1151
|
+
}
|
|
1152
|
+
seen.add(name);
|
|
1153
|
+
if (typeof migration.up !== "function") {
|
|
1154
|
+
throw new Error(`Schema migration '${name}' has no 'up' function`);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
725
1157
|
}
|
package/dist/http/server.js
CHANGED
|
@@ -9,18 +9,18 @@ import { getCharacter, listCharacters, renderCharacterSheet, } from "../tools/ch
|
|
|
9
9
|
import { getLocation, listLocations, renderMap } from "../tools/world.js";
|
|
10
10
|
import { getImage, getImageData, listEntityImages, listGameImages, } from "../tools/images.js";
|
|
11
11
|
import { getInventory, getItem, listGameItems } from "../tools/inventory.js";
|
|
12
|
-
import { listQuests, getQuest } from "../tools/quest.js";
|
|
12
|
+
import { listQuests, getQuest } from "../rpg/tools/quest.js";
|
|
13
13
|
import { getHistory } from "../tools/narrative.js";
|
|
14
14
|
import { getDisplayConfig, getGameDisplayConfig, hasGameTheme, } from "../tools/display.js";
|
|
15
15
|
import { listFactions, getFaction } from "../tools/faction.js";
|
|
16
16
|
import { listResources, getResource } from "../tools/resource.js";
|
|
17
17
|
import { listNotes, getNote } from "../tools/notes.js";
|
|
18
18
|
import { listRelationships } from "../tools/relationship.js";
|
|
19
|
-
import { listAbilities, getAbility } from "../tools/ability.js";
|
|
19
|
+
import { listAbilities, getAbility } from "../rpg/tools/ability.js";
|
|
20
20
|
import { listTimers, getTimer } from "../tools/timers.js";
|
|
21
21
|
import { listSecrets } from "../tools/secrets.js";
|
|
22
22
|
import { getTime } from "../tools/time.js";
|
|
23
|
-
import { getActiveCombat } from "../tools/combat.js";
|
|
23
|
+
import { getActiveCombat } from "../rpg/tools/combat.js";
|
|
24
24
|
import { gameEvents } from "../events/emitter.js";
|
|
25
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
26
26
|
const __dirname = dirname(__filename);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
export {};
|
|
1
|
+
export { createCoreMcpServer, SERVER_NAME, SERVER_VERSION } from "./mcp-server.js";
|
|
2
|
+
export { getDatabase, closeDatabase, withTransaction, getDatabasePath, getDataDir, resolveDataPathFrom, } from "./db/connection.js";
|
|
3
|
+
export type { DataPathInputs } from "./db/connection.js";
|
|
4
|
+
export { initializeSchema } from "./db/schema.js";
|
|
5
|
+
export type { SchemaMigration } from "./db/schema.js";
|
|
6
|
+
export { replay } from "./timeline/replay.js";
|
|
7
|
+
export type { Snapshot, ReplayedEntity, ReplayedFact } from "./timeline/replay.js";
|
|
8
|
+
export { declareTimeAxis, setStoryTime, currentStoryTime } from "./timeline/clock.js";
|
|
9
|
+
export type { StoryTime } from "./timeline/clock.js";
|
|
10
|
+
export { changesWithin } from "./timeline/changes.js";
|
|
11
|
+
export type { Change, ChangeSet, EventChange, FactChange } from "./timeline/changes.js";
|
|
12
|
+
export { compareT, assertT } from "./timeline/t.js";
|
|
13
|
+
export type { T, TimeAxis } from "./timeline/t.js";
|
|
14
|
+
export { timelineDivergences } from "./timeline/checkpoint.js";
|
|
15
|
+
export type { Divergence } from "./timeline/checkpoint.js";
|
|
16
|
+
export { declareIrreversible, irreversibleFactFor, listIrreversibleFacts, } from "./timeline/irreversible.js";
|
|
17
|
+
export type { IrreversibleFact } from "./timeline/irreversible.js";
|
|
18
|
+
export { openingEventId } from "./timeline/provenance.js";
|
|
19
|
+
export type { FactProvenance } from "./timeline/provenance.js";
|
|
20
|
+
export { narrationConstraintAt, contradictions, NARRATION_CONSTRAINT_FORMAT_VERSION, } from "./timeline/narration.js";
|
|
21
|
+
export type { NarrationConstraint, ConstraintFact, Claim, Contradiction } from "./timeline/narration.js";
|
|
22
|
+
export { writeConstrainedValue, transferConstrainedValue, valueHistory, } from "./timeline/constrained.js";
|
|
23
|
+
export type { ValueTransition } from "./timeline/constrained.js";
|
|
24
|
+
export { ConstraintViolationError, constraintsFor, conservedConstraintFor } from "./timeline/registry.js";
|
|
25
|
+
export { createResolver, ResolveProtocolError } from "./timeline/resolve.js";
|
|
26
|
+
export type { Mechanic, Resolver, Proposal, Expectation, AdjudicationInput, Adjudication, IntendedChange, IntendedWrite, IntendedTransfer, Outcome, ResolveRefusalReason, } from "./timeline/resolve.js";
|
|
27
|
+
export { createStateRenderer } from "./timeline/render.js";
|
|
28
|
+
export type { RenderVocabulary, VocabularyEntry, StateRenderer, RenderedState, RenderedNoun, UnnamedFact, } from "./timeline/render.js";
|
|
29
|
+
export { createTurnReader } from "./reader/turnReader.js";
|
|
30
|
+
export type { TurnReader, ReaderQuestion, ReaderSource, ReaderTransport, ReadRequest, TransportAnswer, ReaderResult, AnsweredQuestion, RejectedOffer, RejectionReason, } from "./reader/turnReader.js";
|
|
31
|
+
export { exportTimeline, importTimeline, exportTimelineToFile, importTimelineFromFile, TIMELINE_FORMAT_VERSION, } from "./timeline/export.js";
|
|
32
|
+
export type { TimelineExport, TimelineExportEntity, TimelineExportFact, TimelineExportEvent, TimelineExportClock, TimelineImportResult, } from "./timeline/export.js";
|
|
33
|
+
export { ENTITY_KINDS } from "./timeline/kinds.js";
|
|
34
|
+
export type { EntityKind } from "./timeline/kinds.js";
|
|
35
|
+
export { DEFAULT_HTTP_PORT, httpPortFromEnv, webUiEnabled, setHttpPort, getWebUiBaseUrl, } from "./utils/webui.js";
|
|
36
|
+
export type * from "./types/index.js";
|