run-dmcp 0.1.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/LICENSE +22 -0
- package/README.md +79 -0
- package/dist/__tests__/engineVocabulary.test.d.ts +1 -0
- package/dist/__tests__/engineVocabulary.test.js +147 -0
- package/dist/db/__tests__/connection.test.d.ts +1 -0
- package/dist/db/__tests__/connection.test.js +72 -0
- package/dist/db/__tests__/testDb.d.ts +33 -0
- package/dist/db/__tests__/testDb.js +41 -0
- package/dist/db/connection.d.ts +22 -0
- package/dist/db/connection.js +107 -0
- package/dist/db/schema.d.ts +1 -0
- package/dist/db/schema.js +725 -0
- package/dist/events/emitter.d.ts +22 -0
- package/dist/events/emitter.js +71 -0
- package/dist/http/server.d.ts +3 -0
- package/dist/http/server.js +649 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +92 -0
- package/dist/register/abilities.d.ts +2 -0
- package/dist/register/abilities.js +165 -0
- package/dist/register/audio.d.ts +2 -0
- package/dist/register/audio.js +326 -0
- package/dist/register/batch.d.ts +2 -0
- package/dist/register/batch.js +343 -0
- package/dist/register/character.d.ts +2 -0
- package/dist/register/character.js +324 -0
- package/dist/register/combat.d.ts +2 -0
- package/dist/register/combat.js +207 -0
- package/dist/register/core.d.ts +2 -0
- package/dist/register/core.js +1040 -0
- package/dist/register/display.d.ts +2 -0
- package/dist/register/display.js +263 -0
- package/dist/register/factions.d.ts +2 -0
- package/dist/register/factions.js +186 -0
- package/dist/register/images.d.ts +2 -0
- package/dist/register/images.js +400 -0
- package/dist/register/inventory.d.ts +2 -0
- package/dist/register/inventory.js +115 -0
- package/dist/register/mcp-prompts.d.ts +2 -0
- package/dist/register/mcp-prompts.js +684 -0
- package/dist/register/mcp-resources.d.ts +2 -0
- package/dist/register/mcp-resources.js +335 -0
- package/dist/register/narrative.d.ts +2 -0
- package/dist/register/narrative.js +242 -0
- package/dist/register/notes.d.ts +2 -0
- package/dist/register/notes.js +170 -0
- package/dist/register/pause.d.ts +2 -0
- package/dist/register/pause.js +580 -0
- package/dist/register/quests.d.ts +2 -0
- package/dist/register/quests.js +118 -0
- package/dist/register/relationships.d.ts +2 -0
- package/dist/register/relationships.js +147 -0
- package/dist/register/resources.d.ts +2 -0
- package/dist/register/resources.js +277 -0
- package/dist/register/secrets.d.ts +2 -0
- package/dist/register/secrets.js +192 -0
- package/dist/register/status.d.ts +2 -0
- package/dist/register/status.js +130 -0
- package/dist/register/tables.d.ts +2 -0
- package/dist/register/tables.js +146 -0
- package/dist/register/tags.d.ts +2 -0
- package/dist/register/tags.js +114 -0
- package/dist/register/time.d.ts +2 -0
- package/dist/register/time.js +281 -0
- package/dist/register/world.d.ts +2 -0
- package/dist/register/world.js +127 -0
- package/dist/schemas/index.d.ts +921 -0
- package/dist/schemas/index.js +121 -0
- package/dist/test-setup.d.ts +1 -0
- package/dist/test-setup.js +13 -0
- package/dist/tools/__tests__/audio.test.d.ts +1 -0
- package/dist/tools/__tests__/audio.test.js +59 -0
- package/dist/tools/__tests__/conserved.test.d.ts +1 -0
- package/dist/tools/__tests__/conserved.test.js +488 -0
- package/dist/tools/__tests__/constraint.test.d.ts +1 -0
- package/dist/tools/__tests__/constraint.test.js +212 -0
- package/dist/tools/__tests__/expiry-consequences.test.d.ts +1 -0
- package/dist/tools/__tests__/expiry-consequences.test.js +110 -0
- package/dist/tools/__tests__/images.test.d.ts +1 -0
- package/dist/tools/__tests__/images.test.js +59 -0
- package/dist/tools/__tests__/relationship.test.d.ts +1 -0
- package/dist/tools/__tests__/relationship.test.js +132 -0
- package/dist/tools/__tests__/resource-constraints.test.d.ts +1 -0
- package/dist/tools/__tests__/resource-constraints.test.js +131 -0
- package/dist/tools/__tests__/resource.test.d.ts +1 -0
- package/dist/tools/__tests__/resource.test.js +190 -0
- package/dist/tools/__tests__/time.test.d.ts +1 -0
- package/dist/tools/__tests__/time.test.js +404 -0
- package/dist/tools/__tests__/timers.test.d.ts +1 -0
- package/dist/tools/__tests__/timers.test.js +426 -0
- package/dist/tools/__tests__/world.test.d.ts +1 -0
- package/dist/tools/__tests__/world.test.js +70 -0
- package/dist/tools/ability.d.ts +48 -0
- package/dist/tools/ability.js +238 -0
- package/dist/tools/audio.d.ts +24 -0
- package/dist/tools/audio.js +365 -0
- package/dist/tools/character.d.ts +70 -0
- package/dist/tools/character.js +309 -0
- package/dist/tools/combat.d.ts +13 -0
- package/dist/tools/combat.js +195 -0
- package/dist/tools/constraint.d.ts +132 -0
- package/dist/tools/constraint.js +269 -0
- package/dist/tools/dice.d.ts +23 -0
- package/dist/tools/dice.js +111 -0
- package/dist/tools/display.d.ts +120 -0
- package/dist/tools/display.js +528 -0
- package/dist/tools/faction.d.ts +61 -0
- package/dist/tools/faction.js +269 -0
- package/dist/tools/game.d.ts +96 -0
- package/dist/tools/game.js +526 -0
- package/dist/tools/image-prompt.d.ts +49 -0
- package/dist/tools/image-prompt.js +479 -0
- package/dist/tools/images.d.ts +47 -0
- package/dist/tools/images.js +449 -0
- package/dist/tools/inventory.d.ts +20 -0
- package/dist/tools/inventory.js +145 -0
- package/dist/tools/narrative.d.ts +58 -0
- package/dist/tools/narrative.js +237 -0
- package/dist/tools/notes.d.ts +41 -0
- package/dist/tools/notes.js +220 -0
- package/dist/tools/pause.d.ts +110 -0
- package/dist/tools/pause.js +1254 -0
- package/dist/tools/quest.d.ts +34 -0
- package/dist/tools/quest.js +164 -0
- package/dist/tools/relationship.d.ts +74 -0
- package/dist/tools/relationship.js +324 -0
- package/dist/tools/resource.d.ts +93 -0
- package/dist/tools/resource.js +374 -0
- package/dist/tools/rules.d.ts +4 -0
- package/dist/tools/rules.js +30 -0
- package/dist/tools/secrets.d.ts +49 -0
- package/dist/tools/secrets.js +195 -0
- package/dist/tools/status.d.ts +36 -0
- package/dist/tools/status.js +218 -0
- package/dist/tools/tables.d.ts +33 -0
- package/dist/tools/tables.js +209 -0
- package/dist/tools/tags.d.ts +52 -0
- package/dist/tools/tags.js +176 -0
- package/dist/tools/time.d.ts +33 -0
- package/dist/tools/time.js +276 -0
- package/dist/tools/timers.d.ts +41 -0
- package/dist/tools/timers.js +215 -0
- package/dist/tools/world.d.ts +78 -0
- package/dist/tools/world.js +331 -0
- package/dist/types/index.d.ts +969 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/__tests__/json.test.d.ts +1 -0
- package/dist/utils/__tests__/json.test.js +55 -0
- package/dist/utils/__tests__/validation.test.d.ts +1 -0
- package/dist/utils/__tests__/validation.test.js +90 -0
- package/dist/utils/errors.d.ts +44 -0
- package/dist/utils/errors.js +121 -0
- package/dist/utils/json.d.ts +9 -0
- package/dist/utils/json.js +23 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.js +50 -0
- package/dist/utils/output-schemas.d.ts +594 -0
- package/dist/utils/output-schemas.js +331 -0
- package/dist/utils/tool-annotations.d.ts +147 -0
- package/dist/utils/tool-annotations.js +98 -0
- package/dist/utils/validation.d.ts +34 -0
- package/dist/utils/validation.js +52 -0
- package/dist/utils/verbosity.d.ts +57 -0
- package/dist/utils/verbosity.js +67 -0
- package/dist/utils/webui.d.ts +20 -0
- package/dist/utils/webui.js +35 -0
- package/package.json +75 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Reusable Zod schemas for image generation
|
|
3
|
+
export const subjectDescriptionSchema = z.object({
|
|
4
|
+
type: z.enum(["character", "location", "item", "scene"]),
|
|
5
|
+
primaryDescription: z.string(),
|
|
6
|
+
physicalTraits: z.object({
|
|
7
|
+
age: z.string().optional(),
|
|
8
|
+
gender: z.string().optional(),
|
|
9
|
+
bodyType: z.string().optional(),
|
|
10
|
+
height: z.string().optional(),
|
|
11
|
+
skinTone: z.string().optional(),
|
|
12
|
+
hairColor: z.string().optional(),
|
|
13
|
+
hairStyle: z.string().optional(),
|
|
14
|
+
eyeColor: z.string().optional(),
|
|
15
|
+
facialFeatures: z.string().optional(),
|
|
16
|
+
distinguishingMarks: z.array(z.string()).optional(),
|
|
17
|
+
}).optional(),
|
|
18
|
+
attire: z.object({
|
|
19
|
+
description: z.string(),
|
|
20
|
+
colors: z.array(z.string()).optional(),
|
|
21
|
+
materials: z.array(z.string()).optional(),
|
|
22
|
+
accessories: z.array(z.string()).optional(),
|
|
23
|
+
}).optional(),
|
|
24
|
+
environment: z.object({
|
|
25
|
+
setting: z.string(),
|
|
26
|
+
timeOfDay: z.string().optional(),
|
|
27
|
+
weather: z.string().optional(),
|
|
28
|
+
lighting: z.string().optional(),
|
|
29
|
+
architecture: z.string().optional(),
|
|
30
|
+
vegetation: z.string().optional(),
|
|
31
|
+
notableFeatures: z.array(z.string()).optional(),
|
|
32
|
+
}).optional(),
|
|
33
|
+
objectDetails: z.object({
|
|
34
|
+
material: z.string().optional(),
|
|
35
|
+
size: z.string().optional(),
|
|
36
|
+
condition: z.string().optional(),
|
|
37
|
+
glowOrEffects: z.string().optional(),
|
|
38
|
+
}).optional(),
|
|
39
|
+
pose: z.string().optional(),
|
|
40
|
+
expression: z.string().optional(),
|
|
41
|
+
action: z.string().optional(),
|
|
42
|
+
});
|
|
43
|
+
export const styleDescriptionSchema = z.object({
|
|
44
|
+
artisticStyle: z.string(),
|
|
45
|
+
genre: z.string(),
|
|
46
|
+
mood: z.string(),
|
|
47
|
+
colorScheme: z.string().optional(),
|
|
48
|
+
influences: z.array(z.string()).optional(),
|
|
49
|
+
qualityTags: z.array(z.string()).optional(),
|
|
50
|
+
negativeElements: z.array(z.string()).optional(),
|
|
51
|
+
});
|
|
52
|
+
export const compositionDescriptionSchema = z.object({
|
|
53
|
+
framing: z.string(),
|
|
54
|
+
cameraAngle: z.string().optional(),
|
|
55
|
+
aspectRatio: z.string().optional(),
|
|
56
|
+
focusPoint: z.string().optional(),
|
|
57
|
+
background: z.string().optional(),
|
|
58
|
+
depth: z.string().optional(),
|
|
59
|
+
});
|
|
60
|
+
export const comfyUIPromptSchema = z.object({
|
|
61
|
+
positive: z.string(),
|
|
62
|
+
negative: z.string(),
|
|
63
|
+
checkpoint: z.string().optional(),
|
|
64
|
+
loras: z.array(z.object({
|
|
65
|
+
name: z.string(),
|
|
66
|
+
weight: z.number(),
|
|
67
|
+
})).optional(),
|
|
68
|
+
samplerSettings: z.object({
|
|
69
|
+
sampler: z.string().optional(),
|
|
70
|
+
scheduler: z.string().optional(),
|
|
71
|
+
steps: z.number().optional(),
|
|
72
|
+
cfg: z.number().optional(),
|
|
73
|
+
}).optional(),
|
|
74
|
+
});
|
|
75
|
+
export const generatedImageSchema = z.object({
|
|
76
|
+
id: z.string(),
|
|
77
|
+
tool: z.string(),
|
|
78
|
+
prompt: z.string(),
|
|
79
|
+
url: z.string().optional(),
|
|
80
|
+
base64: z.string().optional(),
|
|
81
|
+
seed: z.number().optional(),
|
|
82
|
+
timestamp: z.string(),
|
|
83
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
84
|
+
});
|
|
85
|
+
export const imageGenSchema = z.object({
|
|
86
|
+
subject: subjectDescriptionSchema,
|
|
87
|
+
style: styleDescriptionSchema,
|
|
88
|
+
composition: compositionDescriptionSchema,
|
|
89
|
+
prompts: z.object({
|
|
90
|
+
generic: z.string().optional(),
|
|
91
|
+
sdxl: z.string().optional(),
|
|
92
|
+
dalle: z.string().optional(),
|
|
93
|
+
midjourney: z.string().optional(),
|
|
94
|
+
flux: z.string().optional(),
|
|
95
|
+
comfyui: comfyUIPromptSchema.optional(),
|
|
96
|
+
}).optional(),
|
|
97
|
+
generations: z.array(generatedImageSchema).optional(),
|
|
98
|
+
consistency: z.object({
|
|
99
|
+
characterRef: z.string().optional(),
|
|
100
|
+
seedImage: z.string().optional(),
|
|
101
|
+
colorPalette: z.array(z.string()).optional(),
|
|
102
|
+
styleRef: z.string().optional(),
|
|
103
|
+
}).optional(),
|
|
104
|
+
}).describe("Image generation metadata for visual representation");
|
|
105
|
+
// Voice schema for characters
|
|
106
|
+
export const voiceSchema = z.object({
|
|
107
|
+
pitch: z.enum(["very_low", "low", "medium", "high", "very_high"]).describe("Voice pitch"),
|
|
108
|
+
speed: z.enum(["very_slow", "slow", "medium", "fast", "very_fast"]).describe("Speaking speed"),
|
|
109
|
+
tone: z.string().describe("Voice tone (e.g., 'gravelly', 'melodic', 'nasal', 'breathy')"),
|
|
110
|
+
accent: z.string().optional().describe("Accent (e.g., 'Scottish', 'French', 'Brooklyn')"),
|
|
111
|
+
quirks: z.array(z.string()).optional().describe("Speech quirks (e.g., 'stutters when nervous')"),
|
|
112
|
+
description: z.string().optional().describe("Free-form voice description for more nuance"),
|
|
113
|
+
});
|
|
114
|
+
// Random table entry schema
|
|
115
|
+
export const tableEntrySchema = z.object({
|
|
116
|
+
minRoll: z.number().optional().describe("Minimum roll to get this result (for ranged tables)"),
|
|
117
|
+
maxRoll: z.number().optional().describe("Maximum roll for this result"),
|
|
118
|
+
weight: z.number().optional().describe("Weight for weighted random selection"),
|
|
119
|
+
result: z.string().describe("The result text"),
|
|
120
|
+
effects: z.record(z.unknown()).optional().describe("Optional structured effects"),
|
|
121
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Vitest setupFiles entry (see vitest.config.ts): a process-wide safety net
|
|
2
|
+
// guaranteeing no test can ever open the real on-disk database.
|
|
3
|
+
//
|
|
4
|
+
// `getDatabase()` resolves DMCP_DB_PATH lazily, so the per-test fixture in
|
|
5
|
+
// src/db/__tests__/testDb.ts is normally sufficient. This exists for the
|
|
6
|
+
// cases the fixture cannot cover -- a `getDatabase()` reached at module scope,
|
|
7
|
+
// or from code a test imports before its own `beforeEach` runs. A setupFiles
|
|
8
|
+
// module is imported before the test file itself, so this lands first.
|
|
9
|
+
//
|
|
10
|
+
// Nothing should ever `delete` this env var mid-run; doing so re-opens the
|
|
11
|
+
// hole for every subsequent test.
|
|
12
|
+
process.env.DMCP_DB_PATH = ":memory:";
|
|
13
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
3
|
+
import { createTestDb, destroyTestDb } from '../../db/__tests__/testDb.js';
|
|
4
|
+
import { getDatabase } from '../../db/connection.js';
|
|
5
|
+
import { createGame } from '../game.js';
|
|
6
|
+
import { createCharacter } from '../character.js';
|
|
7
|
+
import { getAudio, setPrimaryAudio } from '../audio.js';
|
|
8
|
+
// Inserts a stored_audio row directly via SQL so these tests can exercise
|
|
9
|
+
// setPrimaryAudio() without going through storeAudio()'s file I/O / network
|
|
10
|
+
// fetch, which is unrelated to the atomicity behavior under test here.
|
|
11
|
+
function insertStoredAudio(params) {
|
|
12
|
+
const db = getDatabase();
|
|
13
|
+
const id = uuidv4();
|
|
14
|
+
db.prepare(`
|
|
15
|
+
INSERT INTO stored_audio (id, game_id, entity_id, entity_type, file_path, file_size, mime_type, source, is_primary, created_at)
|
|
16
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
17
|
+
`).run(id, params.gameId, params.entityId, params.entityType, `${id}.mp3`, 100, 'audio/mpeg', 'uploaded', params.isPrimary ? 1 : 0, new Date().toISOString());
|
|
18
|
+
return id;
|
|
19
|
+
}
|
|
20
|
+
describe('setPrimaryAudio', () => {
|
|
21
|
+
let gameId;
|
|
22
|
+
let characterId;
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
createTestDb();
|
|
25
|
+
gameId = createGame({ name: 'Test Game', setting: 'Test Setting', style: 'Test Style' }).id;
|
|
26
|
+
characterId = createCharacter({ gameId, name: 'Narrator', isPlayer: false }).id;
|
|
27
|
+
});
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
destroyTestDb();
|
|
30
|
+
});
|
|
31
|
+
it('unsets the previous primary and sets the new one', () => {
|
|
32
|
+
const first = insertStoredAudio({ gameId, entityId: characterId, entityType: 'character', isPrimary: true });
|
|
33
|
+
const second = insertStoredAudio({ gameId, entityId: characterId, entityType: 'character', isPrimary: false });
|
|
34
|
+
setPrimaryAudio(second);
|
|
35
|
+
expect(getAudio(first)?.isPrimary).toBe(false);
|
|
36
|
+
expect(getAudio(second)?.isPrimary).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it('leaves NO partial write when the second update fails mid-operation: the old primary stays primary', () => {
|
|
39
|
+
const first = insertStoredAudio({ gameId, entityId: characterId, entityType: 'character', isPrimary: true });
|
|
40
|
+
const second = insertStoredAudio({ gameId, entityId: characterId, entityType: 'character', isPrimary: false });
|
|
41
|
+
// Fault injection: make the UPDATE that sets `second` as primary fail,
|
|
42
|
+
// simulating a mid-operation failure between the unset and the set.
|
|
43
|
+
const db = getDatabase();
|
|
44
|
+
db.exec(`
|
|
45
|
+
CREATE TRIGGER fail_set_new_primary_audio
|
|
46
|
+
BEFORE UPDATE ON stored_audio
|
|
47
|
+
WHEN NEW.id = '${second}' AND NEW.is_primary = 1
|
|
48
|
+
BEGIN
|
|
49
|
+
SELECT RAISE(ABORT, 'simulated failure');
|
|
50
|
+
END;
|
|
51
|
+
`);
|
|
52
|
+
expect(() => setPrimaryAudio(second)).toThrow();
|
|
53
|
+
// Without a real transaction, the first UPDATE (unsetting `first`)
|
|
54
|
+
// would have already committed, leaving NO primary at all. With a
|
|
55
|
+
// transaction, `first` must still be primary.
|
|
56
|
+
expect(getAudio(first)?.isPrimary).toBe(true);
|
|
57
|
+
expect(getAudio(second)?.isPrimary).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|