run-dmcp 0.1.0 → 0.3.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.
Files changed (141) hide show
  1. package/README.md +101 -11
  2. package/dist/bin/run-dmcp.d.ts +2 -0
  3. package/dist/bin/run-dmcp.js +55 -0
  4. package/dist/db/connection.d.ts +32 -0
  5. package/dist/db/connection.js +38 -16
  6. package/dist/db/schema.d.ts +29 -1
  7. package/dist/db/schema.js +594 -10
  8. package/dist/http/server.js +25 -4
  9. package/dist/index.d.ts +69 -2
  10. package/dist/index.js +262 -92
  11. package/dist/mcp-server.d.ts +49 -0
  12. package/dist/mcp-server.js +127 -0
  13. package/dist/reader/turnReader.d.ts +185 -0
  14. package/dist/reader/turnReader.js +288 -0
  15. package/dist/register/batch.js +5 -79
  16. package/dist/register/mcp-resources.d.ts +9 -0
  17. package/dist/register/mcp-resources.js +16 -62
  18. package/dist/register/render.d.ts +17 -0
  19. package/dist/register/render.js +50 -0
  20. package/dist/register/resolve.d.ts +14 -0
  21. package/dist/register/resolve.js +102 -0
  22. package/dist/register/resources.js +13 -6
  23. package/dist/register/timeline.d.ts +2 -0
  24. package/dist/register/timeline.js +311 -0
  25. package/dist/rpg/index.d.ts +29 -0
  26. package/dist/rpg/index.js +55 -0
  27. package/dist/rpg/register/abilities.d.ts +2 -0
  28. package/dist/rpg/register/abilities.js +165 -0
  29. package/dist/rpg/register/batch.d.ts +2 -0
  30. package/dist/rpg/register/batch.js +92 -0
  31. package/dist/rpg/register/combat.d.ts +2 -0
  32. package/dist/rpg/register/combat.js +207 -0
  33. package/dist/rpg/register/mcp-prompts.d.ts +2 -0
  34. package/dist/rpg/register/mcp-prompts.js +684 -0
  35. package/dist/rpg/register/mcp-resources.d.ts +2 -0
  36. package/dist/rpg/register/mcp-resources.js +61 -0
  37. package/dist/rpg/register/quests.d.ts +2 -0
  38. package/dist/rpg/register/quests.js +118 -0
  39. package/dist/rpg/register/status.d.ts +2 -0
  40. package/dist/rpg/register/status.js +130 -0
  41. package/dist/rpg/register/tables.d.ts +2 -0
  42. package/dist/rpg/register/tables.js +146 -0
  43. package/dist/rpg/tools/ability.d.ts +48 -0
  44. package/dist/rpg/tools/ability.js +238 -0
  45. package/dist/rpg/tools/combat.d.ts +13 -0
  46. package/dist/rpg/tools/combat.js +195 -0
  47. package/dist/rpg/tools/dice.d.ts +23 -0
  48. package/dist/rpg/tools/dice.js +111 -0
  49. package/dist/rpg/tools/quest.d.ts +34 -0
  50. package/dist/rpg/tools/quest.js +164 -0
  51. package/dist/rpg/tools/status.d.ts +36 -0
  52. package/dist/rpg/tools/status.js +218 -0
  53. package/dist/rpg/tools/tables.d.ts +33 -0
  54. package/dist/rpg/tools/tables.js +209 -0
  55. package/dist/schemas/index.d.ts +12 -12
  56. package/dist/timeline/adjudication.d.ts +150 -0
  57. package/dist/timeline/adjudication.js +174 -0
  58. package/dist/timeline/changes.d.ts +108 -0
  59. package/dist/timeline/changes.js +169 -0
  60. package/dist/timeline/checkpoint.d.ts +69 -0
  61. package/dist/timeline/checkpoint.js +131 -0
  62. package/dist/timeline/clock.d.ts +89 -0
  63. package/dist/timeline/clock.js +173 -0
  64. package/dist/timeline/constrained.d.ts +220 -0
  65. package/dist/timeline/constrained.js +671 -0
  66. package/dist/timeline/export.d.ts +181 -0
  67. package/dist/timeline/export.js +339 -0
  68. package/dist/timeline/irreversible.d.ts +87 -0
  69. package/dist/timeline/irreversible.js +108 -0
  70. package/dist/timeline/kinds.d.ts +14 -0
  71. package/dist/timeline/kinds.js +22 -0
  72. package/dist/timeline/narration.d.ts +175 -0
  73. package/dist/timeline/narration.js +259 -0
  74. package/dist/timeline/projection.d.ts +97 -0
  75. package/dist/timeline/projection.js +330 -0
  76. package/dist/timeline/provenance.d.ts +66 -0
  77. package/dist/timeline/provenance.js +45 -0
  78. package/dist/timeline/registry.d.ts +95 -0
  79. package/dist/timeline/registry.js +124 -0
  80. package/dist/timeline/render.d.ts +121 -0
  81. package/dist/timeline/render.js +187 -0
  82. package/dist/timeline/replay.d.ts +86 -0
  83. package/dist/timeline/replay.js +126 -0
  84. package/dist/timeline/resolve.d.ts +262 -0
  85. package/dist/timeline/resolve.js +226 -0
  86. package/dist/timeline/schema.d.ts +13 -0
  87. package/dist/timeline/schema.js +264 -0
  88. package/dist/timeline/t.d.ts +80 -0
  89. package/dist/timeline/t.js +37 -0
  90. package/dist/tools/audio.js +13 -9
  91. package/dist/tools/constraint.d.ts +44 -80
  92. package/dist/tools/constraint.js +115 -124
  93. package/dist/tools/game.js +33 -1
  94. package/dist/tools/images.js +17 -10
  95. package/dist/tools/relationship.d.ts +83 -2
  96. package/dist/tools/relationship.js +139 -62
  97. package/dist/tools/resource.d.ts +33 -8
  98. package/dist/tools/resource.js +106 -153
  99. package/dist/tools/time.js +18 -3
  100. package/dist/types/index.d.ts +20 -2
  101. package/dist/utils/media-path.d.ts +52 -0
  102. package/dist/utils/media-path.js +106 -0
  103. package/dist/utils/output-schemas.d.ts +594 -3
  104. package/dist/utils/output-schemas.js +4 -1
  105. package/dist/utils/webui.d.ts +32 -0
  106. package/dist/utils/webui.js +54 -1
  107. package/package.json +25 -5
  108. package/dist/__tests__/engineVocabulary.test.d.ts +0 -1
  109. package/dist/__tests__/engineVocabulary.test.js +0 -147
  110. package/dist/db/__tests__/connection.test.d.ts +0 -1
  111. package/dist/db/__tests__/connection.test.js +0 -72
  112. package/dist/db/__tests__/testDb.d.ts +0 -33
  113. package/dist/db/__tests__/testDb.js +0 -41
  114. package/dist/test-setup.d.ts +0 -1
  115. package/dist/test-setup.js +0 -13
  116. package/dist/tools/__tests__/audio.test.d.ts +0 -1
  117. package/dist/tools/__tests__/audio.test.js +0 -59
  118. package/dist/tools/__tests__/conserved.test.d.ts +0 -1
  119. package/dist/tools/__tests__/conserved.test.js +0 -488
  120. package/dist/tools/__tests__/constraint.test.d.ts +0 -1
  121. package/dist/tools/__tests__/constraint.test.js +0 -212
  122. package/dist/tools/__tests__/expiry-consequences.test.d.ts +0 -1
  123. package/dist/tools/__tests__/expiry-consequences.test.js +0 -110
  124. package/dist/tools/__tests__/images.test.d.ts +0 -1
  125. package/dist/tools/__tests__/images.test.js +0 -59
  126. package/dist/tools/__tests__/relationship.test.d.ts +0 -1
  127. package/dist/tools/__tests__/relationship.test.js +0 -132
  128. package/dist/tools/__tests__/resource-constraints.test.d.ts +0 -1
  129. package/dist/tools/__tests__/resource-constraints.test.js +0 -131
  130. package/dist/tools/__tests__/resource.test.d.ts +0 -1
  131. package/dist/tools/__tests__/resource.test.js +0 -190
  132. package/dist/tools/__tests__/time.test.d.ts +0 -1
  133. package/dist/tools/__tests__/time.test.js +0 -404
  134. package/dist/tools/__tests__/timers.test.d.ts +0 -1
  135. package/dist/tools/__tests__/timers.test.js +0 -426
  136. package/dist/tools/__tests__/world.test.d.ts +0 -1
  137. package/dist/tools/__tests__/world.test.js +0 -70
  138. package/dist/utils/__tests__/json.test.d.ts +0 -1
  139. package/dist/utils/__tests__/json.test.js +0 -55
  140. package/dist/utils/__tests__/validation.test.d.ts +0 -1
  141. package/dist/utils/__tests__/validation.test.js +0 -90
@@ -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);
@@ -583,7 +583,28 @@ export function createHttpServer(_port = 3456) {
583
583
  next();
584
584
  return;
585
585
  }
586
- res.sendFile(join(CLIENT_DIST, "index.html"));
586
+ // `dotfiles: "allow"` is load-bearing, and its absence was a real bug.
587
+ //
588
+ // res.sendFile() with no `root` option hands the WHOLE absolute path to
589
+ // `send`, whose `dotfiles` default is "ignore" -- so if ANY segment of
590
+ // the path this package is installed under begins with a dot, `send`
591
+ // refuses the file with NotFoundError and the error handler below turns
592
+ // that into a 500. Every client-side route breaks at once, while `/`
593
+ // keeps working (it is served by express.static above, which only
594
+ // dotfile-checks the REQUEST path, not its own root). That is a
595
+ // spectacularly confusing failure: the app is fine, the file is there,
596
+ // and the deep link 500s because of where the checkout happens to live.
597
+ //
598
+ // Installing under a dot directory is ordinary -- a worktree beneath
599
+ // `.claude/`, a deploy under `~/.local/share`, a CI checkout in a dotted
600
+ // cache path -- so this is not a hypothetical.
601
+ //
602
+ // Safe, because the dotfiles guard is protecting nothing here: this path
603
+ // is a server-controlled constant (CLIENT_DIST plus a literal file name)
604
+ // and no part of it comes from the request. The guard exists to stop a
605
+ // user-supplied path from reaching `.env` or `.git`; there is no
606
+ // user-supplied path in it.
607
+ res.sendFile(join(CLIENT_DIST, "index.html"), { dotfiles: "allow" });
587
608
  });
588
609
  }
589
610
  else {
package/dist/index.d.ts CHANGED
@@ -1,2 +1,69 @@
1
- #!/usr/bin/env node
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, getGameUrl, getCharacterUrl, getLocationUrl, } from "./utils/webui.js";
36
+ export * from "./tools/game.js";
37
+ export * from "./tools/world.js";
38
+ export * from "./tools/character.js";
39
+ export * from "./tools/faction.js";
40
+ export * from "./tools/relationship.js";
41
+ export * from "./tools/resource.js";
42
+ export * from "./tools/constraint.js";
43
+ export * from "./tools/inventory.js";
44
+ export * from "./tools/secrets.js";
45
+ export * from "./tools/narrative.js";
46
+ export * from "./tools/notes.js";
47
+ export * from "./tools/tags.js";
48
+ export * from "./tools/time.js";
49
+ export * from "./tools/timers.js";
50
+ export * from "./tools/rules.js";
51
+ export * from "./tools/pause.js";
52
+ export * from "./tools/display.js";
53
+ export * from "./tools/images.js";
54
+ export * from "./tools/audio.js";
55
+ export * from "./tools/image-prompt.js";
56
+ export { gameEvents } from "./events/emitter.js";
57
+ export type { GameEvent } from "./events/emitter.js";
58
+ export { ANNOTATIONS, withAnnotations } from "./utils/tool-annotations.js";
59
+ export { LIMITS, validatedSchemas, boundedString, boundedArray } from "./utils/validation.js";
60
+ export { createError, formatErrorResponse, errors } from "./utils/errors.js";
61
+ export type { AgentError } from "./utils/errors.js";
62
+ export { createLogger } from "./utils/logger.js";
63
+ export type { Logger } from "./utils/logger.js";
64
+ export { verbositySchema, applyVerbosity, filterFields } from "./utils/verbosity.js";
65
+ export type { VerbosityLevel } from "./utils/verbosity.js";
66
+ export { safeJsonParse, safeJsonParseOrNull } from "./utils/json.js";
67
+ export { successResponseSchema, textResultSchema, deletedResponseSchema, listResponseSchema, characterOutputSchema, characterStatusSchema, conditionModifyOutputSchema, tagModifyOutputSchema, } from "./utils/output-schemas.js";
68
+ export { imageGenSchema, voiceSchema } from "./schemas/index.js";
69
+ export type * from "./types/index.js";
package/dist/index.js CHANGED
@@ -1,92 +1,262 @@
1
- #!/usr/bin/env node
2
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { initializeSchema } from "./db/schema.js";
5
- import { closeDatabase } from "./db/connection.js";
6
- import { startHttpServer } from "./http/server.js";
7
- import { setHttpPort } from "./utils/webui.js";
8
- // Import registration functions
9
- import { registerCoreTools } from "./register/core.js";
10
- import { registerWorldTools } from "./register/world.js";
11
- import { registerCharacterTools } from "./register/character.js";
12
- import { registerCombatTools } from "./register/combat.js";
13
- import { registerInventoryTools } from "./register/inventory.js";
14
- import { registerQuestTools } from "./register/quests.js";
15
- import { registerNarrativeTools } from "./register/narrative.js";
16
- import { registerResourceTools } from "./register/resources.js";
17
- import { registerTimeTools } from "./register/time.js";
18
- import { registerTableTools } from "./register/tables.js";
19
- import { registerSecretTools } from "./register/secrets.js";
20
- import { registerRelationshipTools } from "./register/relationships.js";
21
- import { registerTagTools } from "./register/tags.js";
22
- import { registerStatusTools } from "./register/status.js";
23
- import { registerFactionTools } from "./register/factions.js";
24
- import { registerAbilityTools } from "./register/abilities.js";
25
- import { registerNoteTools } from "./register/notes.js";
26
- import { registerPauseTools } from "./register/pause.js";
27
- import { registerImageTools } from "./register/images.js";
28
- import { registerAudioTools } from "./register/audio.js";
29
- import { registerDisplayTools } from "./register/display.js";
30
- import { registerBatchTools } from "./register/batch.js";
31
- import { registerMcpResources } from "./register/mcp-resources.js";
32
- import { registerMcpPrompts } from "./register/mcp-prompts.js";
33
- // Initialize database
34
- initializeSchema();
35
- // Create MCP server
36
- const server = new McpServer({
37
- name: "dmcp",
38
- version: "0.1.0",
39
- });
40
- // Register all tools by domain
41
- registerCoreTools(server); // Game, Interview, Rules
42
- registerWorldTools(server); // Locations, Connections, Map
43
- registerCharacterTools(server); // Characters (PC/NPC)
44
- registerCombatTools(server); // Combat, Dice, Checks
45
- registerInventoryTools(server); // Items
46
- registerQuestTools(server); // Quests, Objectives
47
- registerNarrativeTools(server); // Events, History, Export, Player Choices
48
- registerResourceTools(server); // Custom Resources
49
- registerTimeTools(server); // Calendar, Time, Timers
50
- registerTableTools(server); // Random Tables
51
- registerSecretTools(server); // Secrets, Knowledge
52
- registerRelationshipTools(server); // Relationships
53
- registerTagTools(server); // Tags
54
- registerStatusTools(server); // Status Effects
55
- registerFactionTools(server); // Factions
56
- registerAbilityTools(server); // Abilities/Powers
57
- registerNoteTools(server); // Game Notes
58
- registerPauseTools(server); // Pause/Resume, Context Snapshots, External Updates
59
- registerImageTools(server); // Stored Images
60
- registerAudioTools(server); // Stored Audio (TTS, Voice References)
61
- registerDisplayTools(server); // Display/Theme Configuration
62
- registerBatchTools(server); // Batch Operations (multi-entity, workflows)
63
- // Register MCP Resources and Prompts
64
- registerMcpResources(server); // Read-only data access via URI
65
- registerMcpPrompts(server); // Reusable prompt templates
66
- // ============================================================================
67
- // START SERVER
68
- // ============================================================================
69
- // HTTP server port (configurable via environment variable)
70
- const HTTP_PORT = parseInt(process.env.DMCP_HTTP_PORT || "3456", 10);
71
- async function main() {
72
- // Start HTTP server for web UI (runs alongside MCP)
73
- const actualPort = await startHttpServer(HTTP_PORT);
74
- setHttpPort(actualPort);
75
- // Start MCP server with stdio transport
76
- const transport = new StdioServerTransport();
77
- await server.connect(transport);
78
- }
79
- // Handle cleanup
80
- process.on("SIGINT", () => {
81
- closeDatabase();
82
- process.exit(0);
83
- });
84
- process.on("SIGTERM", () => {
85
- closeDatabase();
86
- process.exit(0);
87
- });
88
- main().catch((error) => {
89
- console.error("Server error:", error);
90
- closeDatabase();
91
- process.exit(1);
92
- });
1
+ // The library entry point: exports, and nothing else.
2
+ //
3
+ // Importing this module must do nothing to the machine -- no database file, no
4
+ // listener, no transport, no timer, no work of any kind. 0.1.0 shipped one
5
+ // entry that was both library and application, so importing the package opened
6
+ // a database inside node_modules and bound the web UI's port, and the listener
7
+ // outlived the import by hours.
8
+ //
9
+ // The rule is asserted from the outside in src/__tests__/entrypoints.test.ts:
10
+ // a child process imports this file and must be able to EXIT. Anything left
11
+ // open keeps it alive and fails the test, so the guarantee does not depend on
12
+ // anyone remembering to enumerate what must not start.
13
+ //
14
+ // Starting things is src/bin/run-dmcp.ts, which is what `bin` points at.
15
+ //
16
+ // THIS PACKAGE ROOT IS THE CORE (design §8, issue #17): entities, facts,
17
+ // events, the timeline, and the entity/property domains a consumer cannot
18
+ // lose without losing its own spine -- resources, relationships, factions,
19
+ // secrets, locations, items. Dice, combat, abilities, status effects, random
20
+ // tables and quests are genuinely game-shaped, and they are an OPTIONAL
21
+ // layer above this, not part of it: import "run-dmcp/rpg" for
22
+ // `createMcpServer`, the full assembly this package used to export under
23
+ // that name. That is design §8's line, not an inversion of it -- the core
24
+ // stays importable, buildable and useful with nothing above it, and the
25
+ // layer stays free to depend down into the core without the core ever
26
+ // depending up into it. `src/__tests__/layerBoundary.test.ts` walks the
27
+ // static import graph from this file and fails if anything under `src/rpg/`
28
+ // is reachable from it.
29
+ export { createCoreMcpServer, SERVER_NAME, SERVER_VERSION } from "./mcp-server.js";
30
+ // The database, and where it lives. The path resolves against the consuming
31
+ // application (DMCP_DB_PATH, else an existing XDG data directory, else the
32
+ // working directory) and never against this package's install location.
33
+ export { getDatabase, closeDatabase, withTransaction, getDatabasePath, getDataDir, resolveDataPathFrom, } from "./db/connection.js";
34
+ // The schema, and the hook a consuming application uses to bring up its own
35
+ // tables in the same startup pass, in the same database, under the same rules.
36
+ export { initializeSchema } from "./db/schema.js";
37
+ // The timeline (design §5.1) -- the reason this engine exists, and therefore
38
+ // something a consuming application reaches directly rather than only through
39
+ // a tool call. `replay` answers what the world looked like at any `t`;
40
+ // `declareTimeAxis` is where an application says what its `t` actually is,
41
+ // which it must do before its first write for that game if it wants its own
42
+ // origin (see clock.ts).
43
+ //
44
+ // `timelineDivergences` is exported for the same reason design §13 makes it a
45
+ // stop condition rather than a nicety: an application that keeps its world
46
+ // here is entitled to ask, of its own database, whether the log it is trusting
47
+ // still reproduces its live tables. It returns rows and never a verdict.
48
+ export { replay } from "./timeline/replay.js";
49
+ export { declareTimeAxis, setStoryTime, currentStoryTime } from "./timeline/clock.js";
50
+ // `changes_within(t0, t1)` (design §5.5) -- the range companion to `replay`,
51
+ // for a consumer whose units have duration rather than instants. It returns
52
+ // transitions and never a verdict: one caller reads a change inside a window
53
+ // as a defect, another reads the same rows to build a summary of what has
54
+ // happened since it last looked. Same primitive, opposite readings, which is
55
+ // how you can tell it belongs in the core rather than to whoever asked first.
56
+ export { changesWithin } from "./timeline/changes.js";
57
+ export { compareT, assertT } from "./timeline/t.js";
58
+ export { timelineDivergences } from "./timeline/checkpoint.js";
59
+ // `irreversible` (design §5.3) -- the temporal member of the constraint family.
60
+ // Exported because the enforcement is structural (triggers on `facts`), which
61
+ // means an application never calls a checker: it declares, and later
62
+ // contradictions are refused at the write that attempts them. What it does need
63
+ // from here is the declaration itself, and the ability to ask which facts carry
64
+ // it -- with the one hop of provenance (§5.2c) that makes a refusal reviewable
65
+ // rather than merely obeyed.
66
+ export { declareIrreversible, irreversibleFactFor, listIrreversibleFacts, } from "./timeline/irreversible.js";
67
+ export { openingEventId } from "./timeline/provenance.js";
68
+ // The narration constraint (design §5.2b/§5.2c, GitHub issues #11 and #12)
69
+ // -- the outbound half of authority, and the half with two consumers.
70
+ // "Here is what is true; depict it, do not argue with it." Exported as a
71
+ // library function FIRST, before any MCP tool wraps it (the one tool that
72
+ // does, `narration_constraint_at`, is a thin JSON-over-stdio wrapper around
73
+ // this same call), because the consumer that most needs it is a process
74
+ // that must never call a model at runtime: its units have duration and
75
+ // everything in them is already known in advance, so its narrator output
76
+ // is generated once, reviewed by a human, committed as a file, and
77
+ // rendered hours later by a lint over that finished artifact, with no
78
+ // engine and no model in the loop (§6's "library functions first, MCP
79
+ // tools second," restated here because this is the export where it matters
80
+ // most). `contradictions` is exported alongside it for the same reason and
81
+ // takes no database handle at all -- it is a pure function over the plain
82
+ // object `narrationConstraintAt` returns, so a caller can serialize a
83
+ // constraint once, hand the JSON to an entirely separate process, and run
84
+ // the check there hours or days later. Prohibitions in the returned shape
85
+ // are derived and structural, never authored and lexical (hard rule 5): the
86
+ // engine records that a fact holds and lets a claim disagree or not,
87
+ // exactly the way `changes_within` (§5.5) records transitions rather than a
88
+ // verdict -- there is no `mustNotSay`, no severity, nothing this project's
89
+ // four recorded negative-prompt failures would recognise.
90
+ export { narrationConstraintAt, contradictions, NARRATION_CONSTRAINT_FORMAT_VERSION, } from "./timeline/narration.js";
91
+ // The constrained-write choke point (design §5.4 option (C)) -- the one place
92
+ // a constrained numeric fact key changes, and the reason there is no longer a
93
+ // `resource_history` table beside the timeline answering the same question.
94
+ // Exported because an application that keeps invariant-bearing numbers here
95
+ // has to be able to write them, and writing them anywhere else is precisely
96
+ // the second path option (C) exists to close: a direct UPDATE still lands in
97
+ // `facts` (the projection triggers see to that), but it arrives unchecked and
98
+ // unannotated.
99
+ //
100
+ // `valueHistory` is the read half, and it is deliberately not a separate
101
+ // mechanism -- it is `facts` and `events`, assembled. It returns rows and
102
+ // never a verdict.
103
+ //
104
+ // `ConstraintViolationError` is exported because a refusal is only reviewable
105
+ // if the caller can tell it apart from a failure. For the `irreversible`
106
+ // member it carries §5.2c's one hop -- the contradicted fact, its
107
+ // `valid_from_t`, and the event that opened it -- so a reviewer can answer
108
+ // "is the fact wrong, or is the claim wrong", which is undecidable without it.
109
+ export { writeConstrainedValue, transferConstrainedValue, valueHistory, } from "./timeline/constrained.js";
110
+ export { ConstraintViolationError, constraintsFor, conservedConstraintFor } from "./timeline/registry.js";
111
+ // The resolve protocol (design §5.2a, GitHub issue #10) -- the inbound half of
112
+ // authority. The engine enforces the PROTOCOL -- resolution happens before
113
+ // narration, writes go through the audited path, declared expectations are
114
+ // checked -- without knowing what any particular mechanic MEANS. An application
115
+ // registers its mechanics by passing them to `createResolver`, and the engine
116
+ // dispatches them and never learns their names.
117
+ //
118
+ // Registration is injection at construction, exactly like `initializeSchema({
119
+ // migrations })` and for exactly the same reason: a global registry would make
120
+ // behaviour depend on module import order and on side effects at import time,
121
+ // which is the disease the entry-point split above cured. A parameter cannot be
122
+ // registered too late.
123
+ //
124
+ // NOTE WHAT IS DELIBERATELY *NOT* EXPORTED HERE: `withAdjudicationOpen` and
125
+ // `adjudicationOpen` (./timeline/adjudication.js). `resolve_only` (issue #13)
126
+ // means a value moves only through an adjudicating call, and the adjudication
127
+ // window is what "adjudicating" is measured against -- so exporting the ability
128
+ // to open one would hand every caller a one-line bypass of the constraint, and
129
+ // the fourth member of the family would be enforced against everybody except
130
+ // whoever read the export list. `resolver.resolve()` is the only public door to
131
+ // a `resolve_only` value. That is the whole point of the constraint, so the
132
+ // window stays internal to the engine that opens it.
133
+ export { createResolver, ResolveProtocolError } from "./timeline/resolve.js";
134
+ // The state-to-text projection (design §7, GitHub issue #16) -- "say what IS
135
+ // true, never what is absent."
136
+ //
137
+ // What is exported here is the MECHANISM and the TYPE of a vocabulary. There
138
+ // is deliberately no vocabulary value, no default and no example anywhere in
139
+ // this package: a vocabulary rich enough to render a real world contains a
140
+ // caller's own nouns, and either sitting in the engine would fail
141
+ // `engineVocabulary.test.ts` on day one -- correctly (§7's closing paragraph,
142
+ // §10). `RenderVocabulary` is a parameter type; a caller supplies the words.
143
+ //
144
+ // The rule is enforced at CONSTRUCTION and never by scanning output.
145
+ // `createStateRenderer` refuses a vocabulary entry carrying any field but
146
+ // `noun` and `adjectives`, by name -- which is what stops an `avoid:` or a
147
+ // `negate:` being bolted on later -- and the renderer's only source of state
148
+ // is `replay(t)`, so a fact that does not hold produces NOTHING rather than a
149
+ // phrase about its absence. There is no differential form and never will be:
150
+ // nothing here takes two `t`s, because "render the change between these two
151
+ // states" is precisely the shape that produces "no longer" (hard rules 3 and
152
+ // 4; the four recorded negative-prompt failures across two codebases).
153
+ export { createStateRenderer } from "./timeline/render.js";
154
+ // The turn reader (design §12 seam 3, GitHub issue #15) -- one model call per
155
+ // unit of progress, answering the questions a server cannot answer with code.
156
+ //
157
+ // The engine owns the call, the citation rule, coercion to keys that actually
158
+ // exist, the safe-direction default and the fallback ladder; the caller owns
159
+ // the questions and the key vocabulary they are answered in. Answers come back
160
+ // as KEYS, never prose.
161
+ //
162
+ // NOTE WHAT IS NOT HERE, BECAUSE IT IS THE POINT: no transport. A
163
+ // `ReaderTransport` is a plain async function the CALLER writes and injects,
164
+ // so this package contains no vendor SDK, no API key, no endpoint, and no
165
+ // network code of any kind -- enforced mechanically by
166
+ // `src/reader/__tests__/noVendorTransports.test.ts`, which scans this
167
+ // directory for vendor and credential tokens the way the vocabulary test
168
+ // scans for a consumer's language. The engine is provably ignorant of what is
169
+ // on the other end of a rung, which is also why the ladder's ORDER is the
170
+ // caller's: it never learns which rung is local and which is hosted.
171
+ export { createTurnReader } from "./reader/turnReader.js";
172
+ // Timeline export (design §6) -- the boundary that keeps both halves honest:
173
+ // conversational authoring upstream of a frozen artifact, deterministic
174
+ // consumers downstream of it. These are exported as library functions first
175
+ // and served as MCP tools second, because the consumer that most needs them
176
+ // is a process that must never call a model at runtime.
177
+ export { exportTimeline, importTimeline, exportTimelineToFile, importTimelineFromFile, TIMELINE_FORMAT_VERSION, } from "./timeline/export.js";
178
+ export { ENTITY_KINDS } from "./timeline/kinds.js";
179
+ // The web UI's port helpers -- no RPG dependency, so they stay here. The web
180
+ // UI server itself (`createHttpServer`/`startHttpServer`) imports quest,
181
+ // ability and combat tools and is exported from "run-dmcp/rpg" instead
182
+ // (src/rpg/index.ts), even though the file that implements it stays at
183
+ // src/http/server.ts on disk.
184
+ export { DEFAULT_HTTP_PORT, httpPortFromEnv, webUiEnabled, setHttpPort, getWebUiBaseUrl, getGameUrl, getCharacterUrl, getLocationUrl, } from "./utils/webui.js";
185
+ // ===========================================================================
186
+ // The core's own tool modules, as library functions (design §8, §11 Phase 5).
187
+ //
188
+ // §8's layer table puts factions, relationships-with-history, secrets,
189
+ // resources, locations and items in the CORE, and gives the reason: they are
190
+ // "the client's spine. If these go up into the RPG layer, the client cannot
191
+ // consume the package without dragging the RPG layer with it -- which defeats
192
+ // the split." That reason is only satisfied if a consumer can actually IMPORT
193
+ // them. Until this block, it could not: everything above is the timeline and
194
+ // the database, and the only door to the spine was `createCoreMcpServer` --
195
+ // the whole assembled server, which a consumer would then have to make tool
196
+ // calls into, over a transport, to read its own tables.
197
+ //
198
+ // The layer ABOVE this one already got it right. src/rpg/index.ts ends with
199
+ // six export-stars over its own tool modules, under a comment saying it is
200
+ // using "the same shape core's index.ts uses for the timeline... a consumer
201
+ // that wants to call combat/quest/table/status/ability/dice logic directly,
202
+ // without going through an MCP tool call, can." The core never did
203
+ //
204
+ // (Those six are named here in prose rather than quoted as import lines on
205
+ // purpose: layerBoundary.test.ts walks this file's import graph with a
206
+ // deliberately syntactic scan for `from "<specifier>"`, and it cannot tell a
207
+ // quoted example in a comment from a real edge. That is the guard being
208
+ // conservative rather than clever, which is the right trade -- it fails loud
209
+ // and names the chain. Do not teach it to strip comments; reword instead.)
210
+ // the same for its own tools, which left the OPTIONAL layer more consumable
211
+ // than the thing it is optional on top of. That is an oversight and not a
212
+ // decision: §6's rule is "library functions first, MCP tools second", and the
213
+ // narration-constraint and timeline-export blocks above both invoke it.
214
+ //
215
+ // This changes no behaviour and adds no dependency. Every module below is
216
+ // ALREADY in this file's static import graph, reached through
217
+ // ./mcp-server.js -> ./register/* -> ./tools/*, so src/__tests__/
218
+ // layerBoundary.test.ts walks exactly the same file set before and after --
219
+ // nothing under src/rpg/ becomes reachable, and none of the six tool modules
220
+ // that moved up there is named here.
221
+ export * from "./tools/game.js";
222
+ export * from "./tools/world.js";
223
+ export * from "./tools/character.js";
224
+ export * from "./tools/faction.js";
225
+ export * from "./tools/relationship.js";
226
+ export * from "./tools/resource.js";
227
+ export * from "./tools/constraint.js";
228
+ export * from "./tools/inventory.js";
229
+ export * from "./tools/secrets.js";
230
+ export * from "./tools/narrative.js";
231
+ export * from "./tools/notes.js";
232
+ export * from "./tools/tags.js";
233
+ export * from "./tools/time.js";
234
+ export * from "./tools/timers.js";
235
+ export * from "./tools/rules.js";
236
+ export * from "./tools/pause.js";
237
+ export * from "./tools/display.js";
238
+ export * from "./tools/images.js";
239
+ export * from "./tools/audio.js";
240
+ export * from "./tools/image-prompt.js";
241
+ // The event emitter the tool modules above write to. A consumer's own write
242
+ // paths emit through the same singleton, so its tables and the engine's reach
243
+ // one SSE subscriber rather than two competing ones.
244
+ export { gameEvents } from "./events/emitter.js";
245
+ // ===========================================================================
246
+ // What a consumer needs to register tools OF ITS OWN onto the core server.
247
+ //
248
+ // A client keeps its own MCP surface -- that is the whole point of the split;
249
+ // its mechanics are its own and the engine never learns their names. But a
250
+ // tool it registers should refuse, bound and annotate the way the engine's do,
251
+ // and today a client re-implements these or copies them and lets the copy
252
+ // drift. Named one by one rather than star-exported: these modules contain
253
+ // identifiers like `CREATE` and `UPDATE` that have no business in a package's
254
+ // root namespace.
255
+ export { ANNOTATIONS, withAnnotations } from "./utils/tool-annotations.js";
256
+ export { LIMITS, validatedSchemas, boundedString, boundedArray } from "./utils/validation.js";
257
+ export { createError, formatErrorResponse, errors } from "./utils/errors.js";
258
+ export { createLogger } from "./utils/logger.js";
259
+ export { verbositySchema, applyVerbosity, filterFields } from "./utils/verbosity.js";
260
+ export { safeJsonParse, safeJsonParseOrNull } from "./utils/json.js";
261
+ export { successResponseSchema, textResultSchema, deletedResponseSchema, listResponseSchema, characterOutputSchema, characterStatusSchema, conditionModifyOutputSchema, tagModifyOutputSchema, } from "./utils/output-schemas.js";
262
+ export { imageGenSchema, voiceSchema } from "./schemas/index.js";
@@ -0,0 +1,49 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type Mechanic } from "./timeline/resolve.js";
3
+ import { type RenderVocabulary } from "./timeline/render.js";
4
+ export declare const SERVER_NAME = "dmcp";
5
+ export declare const SERVER_VERSION = "0.3.0";
6
+ /**
7
+ * Build an MCP server with every CORE tool, resource and prompt this engine
8
+ * serves -- entities, facts, events, the timeline, and the entity/property
9
+ * domains (resources, relationships, factions, secrets, locations, items)
10
+ * design §8 keeps out of the RPG layer because a consumer that lost them
11
+ * would have to drag that layer back in to get them. No dice, no combat, no
12
+ * abilities, no status effects, no random tables, no quests, and no
13
+ * game-master prompt library -- those are `registerRpgTools` in
14
+ * src/rpg/index.ts, which calls this function first and adds its layer on
15
+ * top of what it returns. `createMcpServer` there is the full assembly this
16
+ * function used to be, under the same name, with the same behaviour, so
17
+ * nothing that already depends on the full server sees any difference.
18
+ *
19
+ * The returned server is not connected to anything. Connect it to a transport
20
+ * yourself, and call `initializeSchema()` before serving a request -- both are
21
+ * the caller's to decide, and neither happens on import.
22
+ *
23
+ * `mechanics` (design §5.2a, issue #10) is injection at construction, the
24
+ * same way `initializeSchema({ migrations })` (src/db/schema.ts) is -- there
25
+ * is no global resolver anywhere in this codebase, only the one a caller
26
+ * builds by passing its mechanics here. Every existing zero-argument call
27
+ * site (src/bin/run-dmcp.ts, via src/rpg/index.ts) keeps working unchanged:
28
+ * `options` and `options.mechanics` are both optional, and calling
29
+ * `createCoreMcpServer()` with nothing at all registers every core tool this
30
+ * engine serves and no resolve surface. That absence is deliberate, not an
31
+ * oversight -- an engine with no mechanics registered has nothing a
32
+ * `resolve` tool could ever dispatch, so it gets no `resolve`/`list_mechanics`
33
+ * tools rather than a pair that could only ever answer "unknown-mechanic"
34
+ * and "[]".
35
+ *
36
+ * `vocabulary` (design §7, issue #16) is injected the same way and for the
37
+ * same reason -- and here the injection is not merely a style choice, it is
38
+ * the design's own line: the state-to-text projection's MECHANISM is core,
39
+ * and the NOUNS it may emit belong to each caller. A vocabulary rich enough
40
+ * to render a real world would fail this engine's vocabulary hygiene test on
41
+ * day one, correctly, so this package ships none and there is no default to
42
+ * fall back to. An engine with no vocabulary injected has nothing it could
43
+ * name, so it registers no `render_state_at` tool at all -- the identical
44
+ * shape (and the identical silence) as `mechanics` above.
45
+ */
46
+ export declare function createCoreMcpServer(options?: {
47
+ mechanics?: readonly Mechanic[];
48
+ vocabulary?: RenderVocabulary;
49
+ }): McpServer;