@sharpee/ext-testing 0.9.62-beta → 0.9.66-beta
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/{dist/annotations → annotations}/context.d.ts +1 -1
- package/annotations/context.d.ts.map +1 -0
- package/annotations/context.js.map +1 -0
- package/annotations/index.d.ts.map +1 -0
- package/annotations/index.js.map +1 -0
- package/annotations/store.d.ts.map +1 -0
- package/annotations/store.js.map +1 -0
- package/checkpoints/index.d.ts.map +1 -0
- package/checkpoints/index.js.map +1 -0
- package/{dist/checkpoints → checkpoints}/serializer.d.ts +1 -1
- package/checkpoints/serializer.d.ts.map +1 -0
- package/checkpoints/serializer.js.map +1 -0
- package/checkpoints/store.d.ts.map +1 -0
- package/checkpoints/store.js.map +1 -0
- package/commands/index.d.ts.map +1 -0
- package/commands/index.js.map +1 -0
- package/commands/registry.d.ts.map +1 -0
- package/commands/registry.js.map +1 -0
- package/{dist-npm/context → context}/debug-context.d.ts +1 -1
- package/context/debug-context.d.ts.map +1 -0
- package/{dist-npm/context → context}/debug-context.js +1 -1
- package/context/debug-context.js.map +1 -0
- package/context/index.d.ts.map +1 -0
- package/context/index.js.map +1 -0
- package/{dist/extension.d.ts → extension.d.ts} +1 -1
- package/extension.d.ts.map +1 -0
- package/extension.js.map +1 -0
- package/{dist-npm/index.d.ts → index.d.ts} +1 -1
- package/index.d.ts.map +1 -0
- package/{dist-npm/index.js → index.js} +1 -1
- package/index.js.map +1 -0
- package/package.json +14 -25
- package/{dist/types.d.ts → types.d.ts} +1 -1
- package/types.d.ts.map +1 -0
- package/types.js.map +1 -0
- package/LICENSE +0 -21
- package/dist/annotations/context.d.ts.map +0 -1
- package/dist/annotations/context.js +0 -42
- package/dist/annotations/context.js.map +0 -1
- package/dist/annotations/index.d.ts +0 -6
- package/dist/annotations/index.d.ts.map +0 -1
- package/dist/annotations/index.js +0 -12
- package/dist/annotations/index.js.map +0 -1
- package/dist/annotations/store.d.ts +0 -11
- package/dist/annotations/store.d.ts.map +0 -1
- package/dist/annotations/store.js +0 -191
- package/dist/annotations/store.js.map +0 -1
- package/dist/checkpoints/index.d.ts +0 -3
- package/dist/checkpoints/index.d.ts.map +0 -1
- package/dist/checkpoints/index.js +0 -12
- package/dist/checkpoints/index.js.map +0 -1
- package/dist/checkpoints/serializer.d.ts.map +0 -1
- package/dist/checkpoints/serializer.js +0 -95
- package/dist/checkpoints/serializer.js.map +0 -1
- package/dist/checkpoints/store.d.ts +0 -20
- package/dist/checkpoints/store.d.ts.map +0 -1
- package/dist/checkpoints/store.js +0 -193
- package/dist/checkpoints/store.js.map +0 -1
- package/dist/commands/index.d.ts +0 -2
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js +0 -8
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/registry.d.ts +0 -28
- package/dist/commands/registry.d.ts.map +0 -1
- package/dist/commands/registry.js +0 -70
- package/dist/commands/registry.js.map +0 -1
- package/dist/context/debug-context.d.ts +0 -21
- package/dist/context/debug-context.d.ts.map +0 -1
- package/dist/context/debug-context.js +0 -172
- package/dist/context/debug-context.js.map +0 -1
- package/dist/context/index.d.ts +0 -2
- package/dist/context/index.d.ts.map +0 -1
- package/dist/context/index.js +0 -8
- package/dist/context/index.js.map +0 -1
- package/dist/extension.d.ts.map +0 -1
- package/dist/extension.js +0 -938
- package/dist/extension.js.map +0 -1
- package/dist/index.d.ts +0 -40
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -63
- package/dist/index.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -8
- package/dist/types.js.map +0 -1
- package/dist-npm/annotations/context.d.ts +0 -16
- package/dist-npm/annotations/context.d.ts.map +0 -1
- package/dist-npm/annotations/context.js.map +0 -1
- package/dist-npm/annotations/index.d.ts.map +0 -1
- package/dist-npm/annotations/index.js.map +0 -1
- package/dist-npm/annotations/store.d.ts.map +0 -1
- package/dist-npm/annotations/store.js.map +0 -1
- package/dist-npm/checkpoints/index.d.ts.map +0 -1
- package/dist-npm/checkpoints/index.js.map +0 -1
- package/dist-npm/checkpoints/serializer.d.ts +0 -21
- package/dist-npm/checkpoints/serializer.d.ts.map +0 -1
- package/dist-npm/checkpoints/serializer.js.map +0 -1
- package/dist-npm/checkpoints/store.d.ts.map +0 -1
- package/dist-npm/checkpoints/store.js.map +0 -1
- package/dist-npm/commands/index.d.ts.map +0 -1
- package/dist-npm/commands/index.js.map +0 -1
- package/dist-npm/commands/registry.d.ts.map +0 -1
- package/dist-npm/commands/registry.js.map +0 -1
- package/dist-npm/context/debug-context.d.ts.map +0 -1
- package/dist-npm/context/debug-context.js.map +0 -1
- package/dist-npm/context/index.d.ts.map +0 -1
- package/dist-npm/context/index.js.map +0 -1
- package/dist-npm/extension.d.ts +0 -78
- package/dist-npm/extension.d.ts.map +0 -1
- package/dist-npm/extension.js.map +0 -1
- package/dist-npm/index.d.ts.map +0 -1
- package/dist-npm/index.js.map +0 -1
- package/dist-npm/types.d.ts +0 -375
- package/dist-npm/types.d.ts.map +0 -1
- package/dist-npm/types.js.map +0 -1
- package/src/annotations/context.ts +0 -47
- package/src/annotations/index.ts +0 -6
- package/src/annotations/store.ts +0 -219
- package/src/checkpoints/index.ts +0 -2
- package/src/checkpoints/serializer.ts +0 -121
- package/src/checkpoints/store.ts +0 -188
- package/src/commands/index.ts +0 -1
- package/src/commands/registry.ts +0 -81
- package/src/context/debug-context.ts +0 -209
- package/src/context/index.ts +0 -1
- package/src/extension.ts +0 -1089
- package/src/index.ts +0 -69
- package/src/types.ts +0 -469
- package/tsconfig.json +0 -16
- package/tsconfig.tsbuildinfo +0 -1
- /package/{dist-npm/annotations → annotations}/context.js +0 -0
- /package/{dist-npm/annotations → annotations}/index.d.ts +0 -0
- /package/{dist-npm/annotations → annotations}/index.js +0 -0
- /package/{dist-npm/annotations → annotations}/store.d.ts +0 -0
- /package/{dist-npm/annotations → annotations}/store.js +0 -0
- /package/{dist-npm/checkpoints → checkpoints}/index.d.ts +0 -0
- /package/{dist-npm/checkpoints → checkpoints}/index.js +0 -0
- /package/{dist-npm/checkpoints → checkpoints}/serializer.js +0 -0
- /package/{dist-npm/checkpoints → checkpoints}/store.d.ts +0 -0
- /package/{dist-npm/checkpoints → checkpoints}/store.js +0 -0
- /package/{dist-npm/commands → commands}/index.d.ts +0 -0
- /package/{dist-npm/commands → commands}/index.js +0 -0
- /package/{dist-npm/commands → commands}/registry.d.ts +0 -0
- /package/{dist-npm/commands → commands}/registry.js +0 -0
- /package/{dist-npm/context → context}/index.d.ts +0 -0
- /package/{dist-npm/context → context}/index.js +0 -0
- /package/{dist-npm/extension.js → extension.js} +0 -0
- /package/{dist-npm/types.js → types.js} +0 -0
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Checkpoint Serializer
|
|
3
|
-
*
|
|
4
|
-
* Handles serialization and deserialization of game state for checkpoints.
|
|
5
|
-
* Captures world model state and scheduler state (daemons, fuses).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { WorldModel } from '@sharpee/world-model';
|
|
9
|
-
import type { CheckpointData, SerializedDaemon, SerializedFuse } from '../types.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Serialize current game state to checkpoint data
|
|
13
|
-
*/
|
|
14
|
-
export function serializeCheckpoint(
|
|
15
|
-
world: WorldModel,
|
|
16
|
-
name?: string
|
|
17
|
-
): CheckpointData {
|
|
18
|
-
const player = world.getPlayer();
|
|
19
|
-
const playerLocation = player ? world.getLocation(player.id) : undefined;
|
|
20
|
-
|
|
21
|
-
// Get world state via WorldModel.toJSON()
|
|
22
|
-
const worldState = world.toJSON();
|
|
23
|
-
|
|
24
|
-
// TODO: Get scheduler state when scheduler API is available
|
|
25
|
-
// For now, scheduler state is omitted
|
|
26
|
-
const schedulerState = undefined;
|
|
27
|
-
|
|
28
|
-
const checkpoint: CheckpointData = {
|
|
29
|
-
version: '1.0.0',
|
|
30
|
-
timestamp: Date.now(),
|
|
31
|
-
metadata: {
|
|
32
|
-
name,
|
|
33
|
-
turn: getTurnNumber(world),
|
|
34
|
-
location: playerLocation,
|
|
35
|
-
},
|
|
36
|
-
worldState,
|
|
37
|
-
schedulerState,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
return checkpoint;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Deserialize checkpoint data and restore game state
|
|
45
|
-
*/
|
|
46
|
-
export function deserializeCheckpoint(
|
|
47
|
-
checkpoint: CheckpointData,
|
|
48
|
-
world: WorldModel
|
|
49
|
-
): void {
|
|
50
|
-
// Validate version
|
|
51
|
-
if (checkpoint.version !== '1.0.0') {
|
|
52
|
-
throw new Error(`Unsupported checkpoint version: ${checkpoint.version}`);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Restore world state via WorldModel.loadJSON()
|
|
56
|
-
world.loadJSON(checkpoint.worldState);
|
|
57
|
-
|
|
58
|
-
// TODO: Restore scheduler state when scheduler API is available
|
|
59
|
-
if (checkpoint.schedulerState) {
|
|
60
|
-
restoreSchedulerState(world, checkpoint.schedulerState);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Get current turn number from world
|
|
66
|
-
*/
|
|
67
|
-
function getTurnNumber(world: WorldModel): number {
|
|
68
|
-
// Try to get turn from world metadata or state
|
|
69
|
-
// This may need adjustment based on actual WorldModel API
|
|
70
|
-
try {
|
|
71
|
-
const state = JSON.parse(world.toJSON());
|
|
72
|
-
return state.turn ?? 0;
|
|
73
|
-
} catch {
|
|
74
|
-
return 0;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Restore scheduler state (daemons and fuses)
|
|
80
|
-
*/
|
|
81
|
-
function restoreSchedulerState(
|
|
82
|
-
world: WorldModel,
|
|
83
|
-
state: {
|
|
84
|
-
turn: number;
|
|
85
|
-
daemons: SerializedDaemon[];
|
|
86
|
-
fuses: SerializedFuse[];
|
|
87
|
-
}
|
|
88
|
-
): void {
|
|
89
|
-
// TODO: Implement when scheduler serialization API is available
|
|
90
|
-
// This will need access to the engine's scheduler service
|
|
91
|
-
console.warn('Scheduler state restoration not yet implemented');
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Validate checkpoint data structure
|
|
96
|
-
*/
|
|
97
|
-
export function validateCheckpoint(data: unknown): data is CheckpointData {
|
|
98
|
-
if (!data || typeof data !== 'object') {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const checkpoint = data as Partial<CheckpointData>;
|
|
103
|
-
|
|
104
|
-
if (checkpoint.version !== '1.0.0') {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (typeof checkpoint.timestamp !== 'number') {
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (!checkpoint.metadata || typeof checkpoint.metadata !== 'object') {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (typeof checkpoint.worldState !== 'string') {
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return true;
|
|
121
|
-
}
|
package/src/checkpoints/store.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Checkpoint Store
|
|
3
|
-
*
|
|
4
|
-
* File-based storage for checkpoints.
|
|
5
|
-
* Supports both Node.js (filesystem) and browser (localStorage) environments.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { CheckpointData, CheckpointStore } from '../types.js';
|
|
9
|
-
import { validateCheckpoint } from './serializer.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Create a file-based checkpoint store (Node.js)
|
|
13
|
-
*/
|
|
14
|
-
export function createFileStore(directory: string): CheckpointStore {
|
|
15
|
-
// Dynamic import for Node.js fs module
|
|
16
|
-
let fs: typeof import('fs') | undefined;
|
|
17
|
-
let path: typeof import('path') | undefined;
|
|
18
|
-
|
|
19
|
-
const ensureFs = async () => {
|
|
20
|
-
if (!fs) {
|
|
21
|
-
fs = await import('fs');
|
|
22
|
-
path = await import('path');
|
|
23
|
-
}
|
|
24
|
-
return { fs, path: path! };
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const getFilePath = (pathModule: typeof import('path'), name: string): string => {
|
|
28
|
-
return pathModule.join(directory, `${name}.json`);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const store: CheckpointStore = {
|
|
32
|
-
async save(name: string, data: CheckpointData): Promise<void> {
|
|
33
|
-
const { fs, path } = await ensureFs();
|
|
34
|
-
|
|
35
|
-
// Ensure directory exists
|
|
36
|
-
if (!fs.existsSync(directory)) {
|
|
37
|
-
fs.mkdirSync(directory, { recursive: true });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const filePath = getFilePath(path, name);
|
|
41
|
-
const json = JSON.stringify(data, null, 2);
|
|
42
|
-
fs.writeFileSync(filePath, json, 'utf-8');
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
async load(name: string): Promise<CheckpointData | undefined> {
|
|
46
|
-
const { fs, path } = await ensureFs();
|
|
47
|
-
|
|
48
|
-
const filePath = getFilePath(path, name);
|
|
49
|
-
|
|
50
|
-
if (!fs.existsSync(filePath)) {
|
|
51
|
-
return undefined;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const json = fs.readFileSync(filePath, 'utf-8');
|
|
56
|
-
const data = JSON.parse(json);
|
|
57
|
-
|
|
58
|
-
if (!validateCheckpoint(data)) {
|
|
59
|
-
console.warn(`Invalid checkpoint data in ${filePath}`);
|
|
60
|
-
return undefined;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return data;
|
|
64
|
-
} catch (error) {
|
|
65
|
-
console.error(`Failed to load checkpoint ${name}:`, error);
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
async list(): Promise<string[]> {
|
|
71
|
-
const { fs } = await ensureFs();
|
|
72
|
-
|
|
73
|
-
if (!fs.existsSync(directory)) {
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const files = fs.readdirSync(directory);
|
|
78
|
-
return files
|
|
79
|
-
.filter((f) => f.endsWith('.json'))
|
|
80
|
-
.map((f) => f.replace(/\.json$/, ''));
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
async delete(name: string): Promise<boolean> {
|
|
84
|
-
const { fs, path } = await ensureFs();
|
|
85
|
-
|
|
86
|
-
const filePath = getFilePath(path, name);
|
|
87
|
-
|
|
88
|
-
if (!fs.existsSync(filePath)) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
fs.unlinkSync(filePath);
|
|
93
|
-
return true;
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
async exists(name: string): Promise<boolean> {
|
|
97
|
-
const { fs, path } = await ensureFs();
|
|
98
|
-
|
|
99
|
-
const filePath = getFilePath(path, name);
|
|
100
|
-
return fs.existsSync(filePath);
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
return store;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Create a memory-based checkpoint store (for testing or browser)
|
|
109
|
-
*/
|
|
110
|
-
export function createMemoryStore(): CheckpointStore {
|
|
111
|
-
const checkpoints = new Map<string, CheckpointData>();
|
|
112
|
-
|
|
113
|
-
return {
|
|
114
|
-
async save(name: string, data: CheckpointData): Promise<void> {
|
|
115
|
-
checkpoints.set(name, data);
|
|
116
|
-
},
|
|
117
|
-
|
|
118
|
-
async load(name: string): Promise<CheckpointData | undefined> {
|
|
119
|
-
return checkpoints.get(name);
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
async list(): Promise<string[]> {
|
|
123
|
-
return Array.from(checkpoints.keys());
|
|
124
|
-
},
|
|
125
|
-
|
|
126
|
-
async delete(name: string): Promise<boolean> {
|
|
127
|
-
return checkpoints.delete(name);
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
async exists(name: string): Promise<boolean> {
|
|
131
|
-
return checkpoints.has(name);
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Create a localStorage-based checkpoint store (browser)
|
|
138
|
-
*/
|
|
139
|
-
export function createLocalStorageStore(prefix: string = 'sharpee-checkpoint-'): CheckpointStore {
|
|
140
|
-
const getKey = (name: string) => `${prefix}${name}`;
|
|
141
|
-
|
|
142
|
-
return {
|
|
143
|
-
async save(name: string, data: CheckpointData): Promise<void> {
|
|
144
|
-
const json = JSON.stringify(data);
|
|
145
|
-
localStorage.setItem(getKey(name), json);
|
|
146
|
-
},
|
|
147
|
-
|
|
148
|
-
async load(name: string): Promise<CheckpointData | undefined> {
|
|
149
|
-
const json = localStorage.getItem(getKey(name));
|
|
150
|
-
if (!json) return undefined;
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
const data = JSON.parse(json);
|
|
154
|
-
if (!validateCheckpoint(data)) {
|
|
155
|
-
console.warn(`Invalid checkpoint data for ${name}`);
|
|
156
|
-
return undefined;
|
|
157
|
-
}
|
|
158
|
-
return data;
|
|
159
|
-
} catch {
|
|
160
|
-
return undefined;
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
async list(): Promise<string[]> {
|
|
165
|
-
const names: string[] = [];
|
|
166
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
167
|
-
const key = localStorage.key(i);
|
|
168
|
-
if (key?.startsWith(prefix)) {
|
|
169
|
-
names.push(key.slice(prefix.length));
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return names;
|
|
173
|
-
},
|
|
174
|
-
|
|
175
|
-
async delete(name: string): Promise<boolean> {
|
|
176
|
-
const key = getKey(name);
|
|
177
|
-
if (localStorage.getItem(key) === null) {
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
localStorage.removeItem(key);
|
|
181
|
-
return true;
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
async exists(name: string): Promise<boolean> {
|
|
185
|
-
return localStorage.getItem(getKey(name)) !== null;
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
}
|
package/src/commands/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { createCommandRegistry, parseGdtInput, parseTestInput } from './registry.js';
|
package/src/commands/registry.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Command Registry
|
|
3
|
-
*
|
|
4
|
-
* Central registry for debug and test commands.
|
|
5
|
-
* Commands can be looked up by GDT code or test syntax.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { DebugCommand, CommandCategory, CommandRegistry } from '../types.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Create a new command registry
|
|
12
|
-
*/
|
|
13
|
-
export function createCommandRegistry(): CommandRegistry {
|
|
14
|
-
const byCode = new Map<string, DebugCommand>();
|
|
15
|
-
const byTestSyntax = new Map<string, DebugCommand>();
|
|
16
|
-
const allCommands: DebugCommand[] = [];
|
|
17
|
-
|
|
18
|
-
const registry: CommandRegistry = {
|
|
19
|
-
register(command: DebugCommand): void {
|
|
20
|
-
// Register by code (uppercase for case-insensitive lookup)
|
|
21
|
-
byCode.set(command.code.toUpperCase(), command);
|
|
22
|
-
|
|
23
|
-
// Register by test syntax if provided
|
|
24
|
-
if (command.testSyntax) {
|
|
25
|
-
byTestSyntax.set(command.testSyntax.toLowerCase(), command);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
allCommands.push(command);
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
getByCode(code: string): DebugCommand | undefined {
|
|
32
|
-
return byCode.get(code.toUpperCase());
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
getByTestSyntax(syntax: string): DebugCommand | undefined {
|
|
36
|
-
return byTestSyntax.get(syntax.toLowerCase());
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
getAll(): DebugCommand[] {
|
|
40
|
-
return [...allCommands];
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
getByCategory(category: CommandCategory): DebugCommand[] {
|
|
44
|
-
return allCommands.filter((cmd) => cmd.category === category);
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
return registry;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Parse a GDT-style command input
|
|
53
|
-
* Format: "CODE arg1 arg2" or just "CODE"
|
|
54
|
-
*/
|
|
55
|
-
export function parseGdtInput(input: string): { code: string; args: string[] } {
|
|
56
|
-
const trimmed = input.trim();
|
|
57
|
-
const parts = trimmed.split(/\s+/);
|
|
58
|
-
const code = parts[0] || '';
|
|
59
|
-
const args = parts.slice(1);
|
|
60
|
-
|
|
61
|
-
return { code: code.toUpperCase(), args };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Parse a test command input
|
|
66
|
-
* Format: "$command arg1 arg2" or just "$command"
|
|
67
|
-
*/
|
|
68
|
-
export function parseTestInput(input: string): { syntax: string; args: string[] } | undefined {
|
|
69
|
-
const trimmed = input.trim();
|
|
70
|
-
|
|
71
|
-
if (!trimmed.startsWith('$')) {
|
|
72
|
-
return undefined;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const withoutPrefix = trimmed.slice(1);
|
|
76
|
-
const parts = withoutPrefix.split(/\s+/);
|
|
77
|
-
const syntax = parts[0] || '';
|
|
78
|
-
const args = parts.slice(1);
|
|
79
|
-
|
|
80
|
-
return { syntax: syntax.toLowerCase(), args };
|
|
81
|
-
}
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Debug Context Implementation
|
|
3
|
-
*
|
|
4
|
-
* Provides a unified context for debug and test commands to interact with the game world.
|
|
5
|
-
* Generalizes the pattern from Dungeo's GDTContext.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { WorldModel, IFEntity } from '@sharpee/world-model';
|
|
9
|
-
import { AuthorModel } from '@sharpee/world-model';
|
|
10
|
-
import type { DebugContext } from '../types.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Create a debug context for the given world
|
|
14
|
-
*/
|
|
15
|
-
export function createDebugContext(world: WorldModel): DebugContext {
|
|
16
|
-
// Create AuthorModel for bypassing game rules
|
|
17
|
-
const author = new AuthorModel(world.getDataStore(), world);
|
|
18
|
-
|
|
19
|
-
// Debug flags storage
|
|
20
|
-
const flags = new Map<string, boolean>();
|
|
21
|
-
|
|
22
|
-
// Find player entity
|
|
23
|
-
const player = world.getPlayer();
|
|
24
|
-
if (!player) {
|
|
25
|
-
throw new Error('Cannot create debug context: no player entity found');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const context: DebugContext = {
|
|
29
|
-
world,
|
|
30
|
-
author,
|
|
31
|
-
player,
|
|
32
|
-
flags,
|
|
33
|
-
|
|
34
|
-
// ========================================================================
|
|
35
|
-
// Entity Lookup
|
|
36
|
-
// ========================================================================
|
|
37
|
-
|
|
38
|
-
findEntity(idOrName: string): IFEntity | undefined {
|
|
39
|
-
// Try exact ID match first
|
|
40
|
-
const byId = world.getEntity(idOrName);
|
|
41
|
-
if (byId) return byId;
|
|
42
|
-
|
|
43
|
-
// Normalize search term: lowercase, convert hyphens to spaces
|
|
44
|
-
const searchLower = idOrName.toLowerCase();
|
|
45
|
-
const searchNormalized = searchLower.replace(/-/g, ' ');
|
|
46
|
-
const allEntities = world.getAllEntities();
|
|
47
|
-
|
|
48
|
-
// Exact name match (with normalized search)
|
|
49
|
-
const exactMatch = allEntities.find(
|
|
50
|
-
(e) => e.name?.toLowerCase() === searchNormalized ||
|
|
51
|
-
e.name?.toLowerCase() === searchLower
|
|
52
|
-
);
|
|
53
|
-
if (exactMatch) return exactMatch;
|
|
54
|
-
|
|
55
|
-
// Partial name match (with normalized search)
|
|
56
|
-
const partialMatch = allEntities.find(
|
|
57
|
-
(e) => e.name?.toLowerCase().includes(searchNormalized) ||
|
|
58
|
-
e.name?.toLowerCase().includes(searchLower)
|
|
59
|
-
);
|
|
60
|
-
if (partialMatch) return partialMatch;
|
|
61
|
-
|
|
62
|
-
// ID contains search term
|
|
63
|
-
const idMatch = allEntities.find(
|
|
64
|
-
(e) => e.id.toLowerCase().includes(searchLower)
|
|
65
|
-
);
|
|
66
|
-
return idMatch;
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
findRoom(idOrName: string): IFEntity | undefined {
|
|
70
|
-
const entity = context.findEntity(idOrName);
|
|
71
|
-
if (entity && entity.type === 'room') {
|
|
72
|
-
return entity;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Search only rooms
|
|
76
|
-
const searchLower = idOrName.toLowerCase();
|
|
77
|
-
const rooms = world.getAllEntities().filter((e) => e.type === 'room');
|
|
78
|
-
|
|
79
|
-
const exactMatch = rooms.find(
|
|
80
|
-
(r) => r.name?.toLowerCase() === searchLower
|
|
81
|
-
);
|
|
82
|
-
if (exactMatch) return exactMatch;
|
|
83
|
-
|
|
84
|
-
const partialMatch = rooms.find(
|
|
85
|
-
(r) => r.name?.toLowerCase().includes(searchLower) ||
|
|
86
|
-
r.id.toLowerCase().includes(searchLower)
|
|
87
|
-
);
|
|
88
|
-
return partialMatch;
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
findEntities(predicate: (entity: IFEntity) => boolean): IFEntity[] {
|
|
92
|
-
return world.getAllEntities().filter(predicate);
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
// ========================================================================
|
|
96
|
-
// Location Queries
|
|
97
|
-
// ========================================================================
|
|
98
|
-
|
|
99
|
-
getPlayerLocation(): IFEntity | undefined {
|
|
100
|
-
const locationId = world.getLocation(player.id);
|
|
101
|
-
if (!locationId) return undefined;
|
|
102
|
-
return world.getEntity(locationId);
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
getInventory(): IFEntity[] {
|
|
106
|
-
return world.getContents(player.id);
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
getContents(locationId: string): IFEntity[] {
|
|
110
|
-
return world.getContents(locationId);
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
// ========================================================================
|
|
114
|
-
// Mutations (bypass game rules via AuthorModel)
|
|
115
|
-
// ========================================================================
|
|
116
|
-
|
|
117
|
-
teleportPlayer(roomId: string): boolean {
|
|
118
|
-
const room = context.findRoom(roomId);
|
|
119
|
-
if (!room) return false;
|
|
120
|
-
|
|
121
|
-
author.moveEntity(player.id, room.id);
|
|
122
|
-
return true;
|
|
123
|
-
},
|
|
124
|
-
|
|
125
|
-
moveObject(objectId: string, locationId: string): boolean {
|
|
126
|
-
const object = context.findEntity(objectId);
|
|
127
|
-
const location = context.findEntity(locationId);
|
|
128
|
-
|
|
129
|
-
if (!object || !location) return false;
|
|
130
|
-
|
|
131
|
-
author.moveEntity(object.id, location.id);
|
|
132
|
-
return true;
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
takeObject(objectId: string): boolean {
|
|
136
|
-
const object = context.findEntity(objectId);
|
|
137
|
-
if (!object) return false;
|
|
138
|
-
|
|
139
|
-
author.moveEntity(object.id, player.id);
|
|
140
|
-
return true;
|
|
141
|
-
},
|
|
142
|
-
|
|
143
|
-
removeObject(objectId: string): boolean {
|
|
144
|
-
const object = context.findEntity(objectId);
|
|
145
|
-
if (!object) return false;
|
|
146
|
-
|
|
147
|
-
// Move to limbo (null location)
|
|
148
|
-
author.moveEntity(object.id, 'limbo');
|
|
149
|
-
return true;
|
|
150
|
-
},
|
|
151
|
-
|
|
152
|
-
spawnObject(objectId: string, locationId: string): boolean {
|
|
153
|
-
const object = context.findEntity(objectId);
|
|
154
|
-
const location = context.findEntity(locationId);
|
|
155
|
-
|
|
156
|
-
if (!object || !location) return false;
|
|
157
|
-
|
|
158
|
-
author.moveEntity(object.id, location.id);
|
|
159
|
-
return true;
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
// ========================================================================
|
|
163
|
-
// Flag Operations
|
|
164
|
-
// ========================================================================
|
|
165
|
-
|
|
166
|
-
setFlag(name: string, value: boolean): void {
|
|
167
|
-
flags.set(name, value);
|
|
168
|
-
},
|
|
169
|
-
|
|
170
|
-
getFlag(name: string): boolean {
|
|
171
|
-
return flags.get(name) ?? false;
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
return context;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Format entity for debug display
|
|
180
|
-
*/
|
|
181
|
-
export function formatEntity(entity: IFEntity): string {
|
|
182
|
-
const traitTypes = entity.traits
|
|
183
|
-
? Array.from(entity.traits.values()).map((t) => t.type.split('.').pop()).join(', ')
|
|
184
|
-
: 'none';
|
|
185
|
-
return `${entity.id} (${entity.name || 'unnamed'}) [${traitTypes}]`;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Format location chain for an entity
|
|
190
|
-
*/
|
|
191
|
-
export function formatLocationChain(entity: IFEntity, world: WorldModel): string {
|
|
192
|
-
const chain: string[] = [entity.id];
|
|
193
|
-
let current = entity;
|
|
194
|
-
let depth = 0;
|
|
195
|
-
|
|
196
|
-
while (depth < 10) {
|
|
197
|
-
const locationId = world.getLocation(current.id);
|
|
198
|
-
if (!locationId) break;
|
|
199
|
-
|
|
200
|
-
chain.push(locationId);
|
|
201
|
-
const location = world.getEntity(locationId);
|
|
202
|
-
if (!location) break;
|
|
203
|
-
|
|
204
|
-
current = location;
|
|
205
|
-
depth++;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return chain.join(' -> ');
|
|
209
|
-
}
|
package/src/context/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { createDebugContext, formatEntity, formatLocationChain } from './debug-context.js';
|