qnce-engine 1.2.3 â 1.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.
- package/README.md +12 -6
- package/dist/adapters/contracts.d.ts +23 -0
- package/dist/adapters/contracts.d.ts.map +1 -0
- package/dist/adapters/contracts.js +5 -0
- package/dist/adapters/contracts.js.map +1 -0
- package/dist/adapters/story/CustomJSONAdapter.d.ts +10 -0
- package/dist/adapters/story/CustomJSONAdapter.d.ts.map +1 -0
- package/dist/adapters/story/CustomJSONAdapter.js +94 -0
- package/dist/adapters/story/CustomJSONAdapter.js.map +1 -0
- package/dist/adapters/story/InkAdapter.d.ts +10 -0
- package/dist/adapters/story/InkAdapter.d.ts.map +1 -0
- package/dist/adapters/story/InkAdapter.js +44 -0
- package/dist/adapters/story/InkAdapter.js.map +1 -0
- package/dist/adapters/story/TwisonAdapter.d.ts +10 -0
- package/dist/adapters/story/TwisonAdapter.d.ts.map +1 -0
- package/dist/adapters/story/TwisonAdapter.js +66 -0
- package/dist/adapters/story/TwisonAdapter.js.map +1 -0
- package/dist/cli/import.d.ts +3 -0
- package/dist/cli/import.d.ts.map +1 -0
- package/dist/cli/import.js +166 -0
- package/dist/cli/import.js.map +1 -0
- package/dist/cli/play.d.ts.map +1 -1
- package/dist/cli/play.js +86 -2
- package/dist/cli/play.js.map +1 -1
- package/dist/engine/core.d.ts +25 -0
- package/dist/engine/core.d.ts.map +1 -1
- package/dist/engine/core.js +52 -0
- package/dist/engine/core.js.map +1 -1
- package/dist/persistence/StorageAdapters.d.ts +106 -0
- package/dist/persistence/StorageAdapters.d.ts.map +1 -0
- package/dist/persistence/StorageAdapters.js +383 -0
- package/dist/persistence/StorageAdapters.js.map +1 -0
- package/dist/schemas/story-data.schema.json +52 -0
- package/dist/schemas/validateStoryData.d.ts +8 -0
- package/dist/schemas/validateStoryData.d.ts.map +1 -0
- package/dist/schemas/validateStoryData.js +16 -0
- package/dist/schemas/validateStoryData.js.map +1 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Quantum Narrative Convergence Engine** - A framework-agnostic TypeScript library for creating interactive narrative experiences with quantum-inspired mechanics.
|
|
4
4
|
|
|
5
|
-
> **đ Latest v1.2.
|
|
5
|
+
> **đ Latest v1.2.3:** Documentation consistency update and version alignment; core features unchanged from v1.2.2 (state persistence, advanced branching with AI integration, autosave & undo/redo, conditional choices, React UI components).
|
|
6
6
|
|
|
7
7
|
[](https://badge.fury.io/js/qnce-engine)
|
|
8
8
|
[](https://www.typescriptlang.org/)
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
- **Collapse:** Player choices "collapse" the narrative to a specific path, updating state and flags
|
|
15
15
|
- **Entanglement:** Early decisions affect later outcomes, enabling complex, interconnected stories
|
|
16
16
|
|
|
17
|
-
## ⨠Current Features (v1.2.
|
|
17
|
+
## ⨠Current Features (v1.2.3)
|
|
18
18
|
|
|
19
19
|
### đž State Persistence & Checkpoints
|
|
20
20
|
- **Complete save/load system** with data integrity validation
|
|
@@ -128,10 +128,6 @@ const complexStory = {
|
|
|
128
128
|
{
|
|
129
129
|
id: 'time-limited-escape',
|
|
130
130
|
text: 'Escape through the secret passage',
|
|
131
|
-
nextNodeId: 'secret-escape',
|
|
132
|
-
condition: 'context.timeElapsed < 300 && flags.knowsSecretPath'
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
131
|
id: 'sacrifice-play',
|
|
136
132
|
text: 'Make the ultimate sacrifice',
|
|
137
133
|
nextNodeId: 'heroic-end',
|
|
@@ -632,6 +628,16 @@ Stories are defined using JSON with the following structure:
|
|
|
632
628
|
```
|
|
633
629
|
|
|
634
630
|
## CLI Tools
|
|
631
|
+
### Import compatibility (developer preview)
|
|
632
|
+
|
|
633
|
+
Support matrix for qnce-import adapters:
|
|
634
|
+
|
|
635
|
+
- Custom JSON: supported (strict mode available)
|
|
636
|
+
- Twison/Twine JSON: supported (passages, links, start detection). Tags are mapped to node.meta.tags.
|
|
637
|
+
- Ink JSON: minimal support (knots/text/choices). Use `--experimental-ink` for best-effort extras.
|
|
638
|
+
|
|
639
|
+
Tip: Use `--id-prefix` to namespace node IDs when merging sources.
|
|
640
|
+
|
|
635
641
|
|
|
636
642
|
### qnce-audit
|
|
637
643
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StoryData } from '../engine/core';
|
|
2
|
+
import type { ValidationResult } from '../engine/validation';
|
|
3
|
+
export interface AdapterOptions {
|
|
4
|
+
namespace?: string;
|
|
5
|
+
strict?: boolean;
|
|
6
|
+
idPrefix?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface StoryAdapter {
|
|
9
|
+
load(source: string | object, options?: AdapterOptions): Promise<StoryData>;
|
|
10
|
+
validate(storyData: StoryData): ValidationResult;
|
|
11
|
+
detect?(source: unknown): boolean;
|
|
12
|
+
mapIds?(storyData: StoryData, strategy?: 'deterministic' | 'passthrough'): StoryData;
|
|
13
|
+
}
|
|
14
|
+
export interface SaveEnvelope<TPayload = any> {
|
|
15
|
+
version: number;
|
|
16
|
+
storyId: string;
|
|
17
|
+
storyVersion: string;
|
|
18
|
+
timestamp: string;
|
|
19
|
+
engineVersion: string;
|
|
20
|
+
checksum: string;
|
|
21
|
+
payload: TPayload;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=contracts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../src/adapters/contracts.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC5E,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,gBAAgB,CAAC;IACjD,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;IAClC,MAAM,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,aAAa,GAAG,SAAS,CAAC;CACtF;AAGD,MAAM,WAAW,YAAY,CAAC,QAAQ,GAAG,GAAG;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,QAAQ,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../src/adapters/contracts.ts"],"names":[],"mappings":";AAAA,yBAAyB;AACzB,wDAAwD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StoryAdapter, AdapterOptions } from '../../adapters/contracts';
|
|
2
|
+
import type { StoryData } from '../../engine/core';
|
|
3
|
+
import type { ValidationResult } from '../../engine/validation';
|
|
4
|
+
export declare class CustomJSONAdapter implements StoryAdapter {
|
|
5
|
+
load(source: string | object, options?: AdapterOptions): Promise<StoryData>;
|
|
6
|
+
validate(_storyData: StoryData): ValidationResult;
|
|
7
|
+
detect(source: unknown): boolean;
|
|
8
|
+
}
|
|
9
|
+
export default CustomJSONAdapter;
|
|
10
|
+
//# sourceMappingURL=CustomJSONAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomJSONAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/story/CustomJSONAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,qBAAa,iBAAkB,YAAW,YAAY;IAC9C,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC;IA+DjF,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,gBAAgB;IAIjD,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;CAYjC;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Custom JSON Story Adapter
|
|
3
|
+
// Accepts already-normalized QNCE StoryData or a close variant and ensures it conforms
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.CustomJSONAdapter = void 0;
|
|
6
|
+
class CustomJSONAdapter {
|
|
7
|
+
async load(source, options) {
|
|
8
|
+
const data = typeof source === 'string' ? JSON.parse(source) : source;
|
|
9
|
+
if (!data || typeof data !== 'object')
|
|
10
|
+
throw new Error('Invalid story source');
|
|
11
|
+
const initialNodeId = data.initialNodeId || 'start';
|
|
12
|
+
const nodes = data.nodes || [];
|
|
13
|
+
if (!Array.isArray(nodes))
|
|
14
|
+
throw new Error('Invalid nodes array');
|
|
15
|
+
const normalized = {
|
|
16
|
+
initialNodeId,
|
|
17
|
+
nodes: nodes.map((n) => ({
|
|
18
|
+
id: String(n.id),
|
|
19
|
+
text: String(n.text ?? ''),
|
|
20
|
+
meta: n.meta && typeof n.meta === 'object'
|
|
21
|
+
? {
|
|
22
|
+
tags: Array.isArray(n.meta.tags) ? n.meta.tags.map((t) => String(t)) : undefined
|
|
23
|
+
}
|
|
24
|
+
: undefined,
|
|
25
|
+
choices: Array.isArray(n.choices)
|
|
26
|
+
? n.choices.map((c) => ({
|
|
27
|
+
text: String(c.text ?? ''),
|
|
28
|
+
nextNodeId: String(c.nextNodeId ?? ''),
|
|
29
|
+
flagEffects: c.flagEffects,
|
|
30
|
+
flagRequirements: c.flagRequirements,
|
|
31
|
+
timeRequirements: c.timeRequirements,
|
|
32
|
+
inventoryRequirements: c.inventoryRequirements,
|
|
33
|
+
enabled: c.enabled,
|
|
34
|
+
condition: c.condition,
|
|
35
|
+
}))
|
|
36
|
+
: [],
|
|
37
|
+
})),
|
|
38
|
+
};
|
|
39
|
+
if (options?.strict) {
|
|
40
|
+
// Fail on unknown keys at top-level nodes/choices
|
|
41
|
+
const allowedNodeKeys = new Set(['id', 'text', 'choices', 'meta']);
|
|
42
|
+
const allowedChoiceKeys = new Set([
|
|
43
|
+
'text', 'nextNodeId', 'flagEffects', 'flagRequirements', 'timeRequirements', 'inventoryRequirements', 'enabled', 'condition'
|
|
44
|
+
]);
|
|
45
|
+
for (const n of nodes) {
|
|
46
|
+
for (const k of Object.keys(n))
|
|
47
|
+
if (!allowedNodeKeys.has(k))
|
|
48
|
+
throw new Error(`Unknown node key: ${k}`);
|
|
49
|
+
for (const c of (n.choices || [])) {
|
|
50
|
+
for (const ck of Object.keys(c))
|
|
51
|
+
if (!allowedChoiceKeys.has(ck))
|
|
52
|
+
throw new Error(`Unknown choice key: ${ck}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// Lenient mode: warn on unknown keys
|
|
58
|
+
const allowedNodeKeys = new Set(['id', 'text', 'choices', 'meta']);
|
|
59
|
+
const allowedChoiceKeys = new Set([
|
|
60
|
+
'text', 'nextNodeId', 'flagEffects', 'flagRequirements', 'timeRequirements', 'inventoryRequirements', 'enabled', 'condition'
|
|
61
|
+
]);
|
|
62
|
+
for (const n of nodes) {
|
|
63
|
+
for (const k of Object.keys(n))
|
|
64
|
+
if (!allowedNodeKeys.has(k))
|
|
65
|
+
console.warn(`[QNCE] Unknown node key ignored: ${k}`);
|
|
66
|
+
for (const c of (n.choices || [])) {
|
|
67
|
+
for (const ck of Object.keys(c))
|
|
68
|
+
if (!allowedChoiceKeys.has(ck))
|
|
69
|
+
console.warn(`[QNCE] Unknown choice key ignored: ${ck}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return normalized;
|
|
74
|
+
}
|
|
75
|
+
validate(_storyData) {
|
|
76
|
+
return { isValid: true };
|
|
77
|
+
}
|
|
78
|
+
detect(source) {
|
|
79
|
+
if (typeof source === 'string') {
|
|
80
|
+
try {
|
|
81
|
+
const obj = JSON.parse(source);
|
|
82
|
+
return !!obj && typeof obj === 'object' && Array.isArray(obj.nodes);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const obj = source;
|
|
89
|
+
return !!obj && typeof obj === 'object' && Array.isArray(obj.nodes);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.CustomJSONAdapter = CustomJSONAdapter;
|
|
93
|
+
exports.default = CustomJSONAdapter;
|
|
94
|
+
//# sourceMappingURL=CustomJSONAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomJSONAdapter.js","sourceRoot":"","sources":["../../../src/adapters/story/CustomJSONAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StoryAdapter, AdapterOptions } from '../../adapters/contracts';
|
|
2
|
+
import type { StoryData } from '../../engine/core';
|
|
3
|
+
import type { ValidationResult } from '../../engine/validation';
|
|
4
|
+
export declare class InkAdapter implements StoryAdapter {
|
|
5
|
+
load(source: string | object, options?: AdapterOptions): Promise<StoryData>;
|
|
6
|
+
validate(_storyData: StoryData): ValidationResult;
|
|
7
|
+
detect(source: unknown): boolean;
|
|
8
|
+
}
|
|
9
|
+
export default InkAdapter;
|
|
10
|
+
//# sourceMappingURL=InkAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/story/InkAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,qBAAa,UAAW,YAAW,YAAY;IACvC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC;IAwBjF,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,gBAAgB;IAEjD,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;CAKjC;AAED,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Ink (Inklecate JSON) Story Adapter - minimal stub
|
|
3
|
+
// Many Ink workflows compile to a JSON state machine; here we support a simple node/choice projection
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.InkAdapter = void 0;
|
|
6
|
+
// This is intentionally a very light stub; real Ink JSON can be complex.
|
|
7
|
+
class InkAdapter {
|
|
8
|
+
async load(source, options) {
|
|
9
|
+
const obj = typeof source === 'string' ? JSON.parse(source) : source;
|
|
10
|
+
if (!obj || typeof obj !== 'object')
|
|
11
|
+
throw new Error('Invalid Ink JSON');
|
|
12
|
+
// Heuristic: accept a simplified format { knots: { [name]: { text, choices: [{ text, target }] } } , start?: string }
|
|
13
|
+
const knots = obj.knots || {};
|
|
14
|
+
const idPrefix = options?.idPrefix ?? '';
|
|
15
|
+
if (!options?.experimentalInk && (obj.inkVersion || obj.listDefs || obj.inkState)) {
|
|
16
|
+
console.warn('[QNCE] Ink JSON appears complex; using minimal adapter. Pass experimentalInk to attempt richer import.');
|
|
17
|
+
}
|
|
18
|
+
const nodes = Object.keys(knots).map((k) => ({
|
|
19
|
+
id: `${idPrefix}${k}`,
|
|
20
|
+
text: String(knots[k].text ?? ''),
|
|
21
|
+
choices: Array.isArray(knots[k].choices)
|
|
22
|
+
? knots[k].choices.map((c) => ({ text: String(c.text ?? ''), nextNodeId: `${idPrefix}${c.target}` }))
|
|
23
|
+
: [],
|
|
24
|
+
}));
|
|
25
|
+
const initialNodeId = `${idPrefix}${(obj.start ?? Object.keys(knots)[0] ?? 'start')}`;
|
|
26
|
+
return { initialNodeId, nodes };
|
|
27
|
+
}
|
|
28
|
+
validate(_storyData) { return { isValid: true }; }
|
|
29
|
+
detect(source) {
|
|
30
|
+
let obj = source;
|
|
31
|
+
if (typeof source === 'string') {
|
|
32
|
+
try {
|
|
33
|
+
obj = JSON.parse(source);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return !!obj && typeof obj === 'object' && (!!obj.knots || !!obj.inkVersion);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.InkAdapter = InkAdapter;
|
|
43
|
+
exports.default = InkAdapter;
|
|
44
|
+
//# sourceMappingURL=InkAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InkAdapter.js","sourceRoot":"","sources":["../../../src/adapters/story/InkAdapter.ts"],"names":[],"mappings":";AAAA,oDAAoD;AACpD,sGAAsG;;;AAMtG,yEAAyE;AACzE,MAAa,UAAU;IACrB,KAAK,CAAC,IAAI,CAAC,MAAuB,EAAE,OAAwB;QAC1D,MAAM,GAAG,GAAQ,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1E,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAEzE,sHAAsH;QACtH,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC;QAEzC,IAAI,CAAE,OAAe,EAAE,eAAe,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3F,OAAO,CAAC,IAAI,CAAC,wGAAwG,CAAC,CAAC;QACzH,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3C,EAAE,EAAE,GAAG,QAAQ,GAAG,CAAC,EAAE;YACrB,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YACjC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;gBACtC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,GAAG,QAAQ,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAC1G,CAAC,CAAC,EAAE;SACP,CAAC,CAAC,CAAC;QAEJ,MAAM,aAAa,GAAG,GAAG,QAAQ,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,EAAE,CAAC;QACtF,OAAO,EAAE,aAAa,EAAE,KAAK,EAAe,CAAC;IAC/C,CAAC;IAED,QAAQ,CAAC,UAAqB,IAAsB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAE/E,MAAM,CAAC,MAAe;QACpB,IAAI,GAAG,GAAQ,MAAM,CAAC;QACtB,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAAC,IAAI,CAAC;gBAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,KAAK,CAAC;YAAC,CAAC;QAAC,CAAC;QAC7F,OAAO,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC/E,CAAC;CACF;AAhCD,gCAgCC;AAED,kBAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StoryAdapter, AdapterOptions } from '../../adapters/contracts';
|
|
2
|
+
import type { StoryData } from '../../engine/core';
|
|
3
|
+
import type { ValidationResult } from '../../engine/validation';
|
|
4
|
+
export declare class TwisonAdapter implements StoryAdapter {
|
|
5
|
+
load(source: string | object, options?: AdapterOptions): Promise<StoryData>;
|
|
6
|
+
validate(_storyData: StoryData): ValidationResult;
|
|
7
|
+
detect(source: unknown): boolean;
|
|
8
|
+
}
|
|
9
|
+
export default TwisonAdapter;
|
|
10
|
+
//# sourceMappingURL=TwisonAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TwisonAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/story/TwisonAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAiBhE,qBAAa,aAAc,YAAW,YAAY;IAC1C,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC;IA4CjF,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,gBAAgB;IAIjD,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO;CAOjC;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Twison (Twine JSON) Story Adapter
|
|
3
|
+
// Parses Twison/Twine JSON export into QNCE StoryData
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.TwisonAdapter = void 0;
|
|
6
|
+
class TwisonAdapter {
|
|
7
|
+
async load(source, options) {
|
|
8
|
+
const doc = typeof source === 'string' ? JSON.parse(source) : source;
|
|
9
|
+
if (!doc || !Array.isArray(doc.passages))
|
|
10
|
+
throw new Error('Invalid Twison document');
|
|
11
|
+
const idPrefix = options?.idPrefix ?? '';
|
|
12
|
+
const makeId = (name) => `${idPrefix}${name}`;
|
|
13
|
+
const tagSet = new Set();
|
|
14
|
+
const nodes = doc.passages.map((p) => ({
|
|
15
|
+
id: makeId(p.name),
|
|
16
|
+
text: p.text ?? '',
|
|
17
|
+
choices: (p.links ?? []).map((l) => ({
|
|
18
|
+
text: l.name ?? l.link,
|
|
19
|
+
nextNodeId: makeId(l.link),
|
|
20
|
+
// tags could be surfaced as requirements/effects by a later mapping stage
|
|
21
|
+
})),
|
|
22
|
+
meta: Array.isArray(p.tags) && p.tags.length > 0 ? { tags: p.tags.filter(Boolean).map(String) } : undefined,
|
|
23
|
+
}));
|
|
24
|
+
// Collect tags for visibility (not yet mapped into StoryData schema)
|
|
25
|
+
for (const p of doc.passages) {
|
|
26
|
+
if (Array.isArray(p.tags)) {
|
|
27
|
+
p.tags.filter(Boolean).forEach((t) => tagSet.add(String(t)));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Improved start detection:
|
|
31
|
+
// 1) explicit startnode by pid
|
|
32
|
+
// 2) passage named "Start" (case-insensitive)
|
|
33
|
+
// 3) first passage fallback
|
|
34
|
+
let initialNodeId = nodes[0]?.id ?? 'start';
|
|
35
|
+
if (doc.startnode) {
|
|
36
|
+
const startPassage = doc.passages.find((p) => p.pid === doc.startnode) || doc.passages[0];
|
|
37
|
+
if (startPassage)
|
|
38
|
+
initialNodeId = makeId(startPassage.name);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const byName = doc.passages.find((p) => /^(start)$/i.test(p.name));
|
|
42
|
+
if (byName)
|
|
43
|
+
initialNodeId = makeId(byName.name);
|
|
44
|
+
}
|
|
45
|
+
// Tags are now captured in node.meta.tags; no warning needed.
|
|
46
|
+
return { initialNodeId, nodes };
|
|
47
|
+
}
|
|
48
|
+
validate(_storyData) {
|
|
49
|
+
return { isValid: true };
|
|
50
|
+
}
|
|
51
|
+
detect(source) {
|
|
52
|
+
let obj = source;
|
|
53
|
+
if (typeof source === 'string') {
|
|
54
|
+
try {
|
|
55
|
+
obj = JSON.parse(source);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return !!obj && Array.isArray(obj.passages);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.TwisonAdapter = TwisonAdapter;
|
|
65
|
+
exports.default = TwisonAdapter;
|
|
66
|
+
//# sourceMappingURL=TwisonAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TwisonAdapter.js","sourceRoot":"","sources":["../../../src/adapters/story/TwisonAdapter.ts"],"names":[],"mappings":";AAAA,oCAAoC;AACpC,sDAAsD;;;AAqBtD,MAAa,aAAa;IACxB,KAAK,CAAC,IAAI,CAAC,MAAuB,EAAE,OAAwB;QAC1D,MAAM,GAAG,GAAmB,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAE,MAAc,CAAC;QAC9F,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAErF,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC;QAEzC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,QAAQ,GAAG,IAAI,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;QACjC,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACrC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YAClB,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;YAClB,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACnC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI;gBACtB,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC1B,0EAA0E;aAC3E,CAAC,CAAC;YACH,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;SAC5G,CAAC,CAAC,CAAC;QAEJ,qEAAqE;QACrE,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC;QAED,4BAA4B;QAC5B,+BAA+B;QAC/B,8CAA8C;QAC9C,4BAA4B;QAC5B,IAAI,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,OAAO,CAAC;QAC5C,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;YAClB,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAC1F,IAAI,YAAY;gBAAE,aAAa,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAC9D,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACnE,IAAI,MAAM;gBAAE,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClD,CAAC;QAEH,8DAA8D;QAE5D,OAAO,EAAE,aAAa,EAAE,KAAK,EAAe,CAAC;IAC/C,CAAC;IAED,QAAQ,CAAC,UAAqB;QAC5B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,MAAe;QACpB,IAAI,GAAG,GAAQ,MAAM,CAAC;QACtB,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC;gBAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,KAAK,CAAC;YAAC,CAAC;QAC3D,CAAC;QACD,OAAO,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;CACF;AAxDD,sCAwDC;AAED,kBAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/cli/import.ts"],"names":[],"mappings":";AAqKA,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const core_js_1 = require("../engine/core.js");
|
|
7
|
+
const CustomJSONAdapter_js_1 = require("../adapters/story/CustomJSONAdapter.js");
|
|
8
|
+
const TwisonAdapter_js_1 = require("../adapters/story/TwisonAdapter.js");
|
|
9
|
+
const InkAdapter_js_1 = require("../adapters/story/InkAdapter.js");
|
|
10
|
+
const validateStoryData_js_1 = require("../schemas/validateStoryData.js");
|
|
11
|
+
/**
|
|
12
|
+
* QNCE Import CLI
|
|
13
|
+
* Detects story format (Custom JSON, Twison, basic Ink) and outputs normalized QNCE StoryData JSON
|
|
14
|
+
*/
|
|
15
|
+
function detectAdapter(payload) {
|
|
16
|
+
const candidates = [
|
|
17
|
+
{ key: 'json', inst: new CustomJSONAdapter_js_1.CustomJSONAdapter() },
|
|
18
|
+
{ key: 'twison', inst: new TwisonAdapter_js_1.TwisonAdapter() },
|
|
19
|
+
{ key: 'ink', inst: new InkAdapter_js_1.InkAdapter() }
|
|
20
|
+
];
|
|
21
|
+
for (const c of candidates) {
|
|
22
|
+
try {
|
|
23
|
+
if (c.inst.detect?.(payload))
|
|
24
|
+
return c;
|
|
25
|
+
}
|
|
26
|
+
catch { }
|
|
27
|
+
}
|
|
28
|
+
return candidates[0];
|
|
29
|
+
}
|
|
30
|
+
async function readStdin() {
|
|
31
|
+
const chunks = [];
|
|
32
|
+
return await new Promise((resolve) => {
|
|
33
|
+
process.stdin.on('data', (d) => chunks.push(Buffer.from(d)));
|
|
34
|
+
process.stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async function main() {
|
|
38
|
+
const args = process.argv.slice(2);
|
|
39
|
+
const showHelp = args.length === 0 && process.stdin.isTTY;
|
|
40
|
+
if (showHelp || args.includes('--help') || args.includes('-h')) {
|
|
41
|
+
console.log(`\nQNCE Import CLI\nUsage: qnce-import <input-file>|(read from stdin) [--out <file>|stdout] [--id-prefix <prefix>] [--format json|twison|ink] [--strict] [--experimental-ink]\n`);
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
const formatIdx = args.indexOf('--format');
|
|
45
|
+
const format = formatIdx >= 0 ? args[formatIdx + 1] : undefined;
|
|
46
|
+
const strict = args.includes('--strict');
|
|
47
|
+
const experimentalInk = args.includes('--experimental-ink');
|
|
48
|
+
const idPrefixIndex = args.indexOf('--id-prefix');
|
|
49
|
+
const idPrefix = idPrefixIndex >= 0 ? args[idPrefixIndex + 1] : '';
|
|
50
|
+
const outIndex = args.indexOf('--out');
|
|
51
|
+
const outArg = outIndex >= 0 ? args[outIndex + 1] : undefined;
|
|
52
|
+
let raw;
|
|
53
|
+
let inputName = 'stdin';
|
|
54
|
+
if (args[0] && !args[0].startsWith('--')) {
|
|
55
|
+
const inPath = (0, path_1.resolve)(args[0]);
|
|
56
|
+
inputName = inPath;
|
|
57
|
+
raw = (0, fs_1.readFileSync)(inPath, 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
raw = await readStdin();
|
|
61
|
+
}
|
|
62
|
+
let exitCode = 0;
|
|
63
|
+
try {
|
|
64
|
+
const json = JSON.parse(raw);
|
|
65
|
+
let selected;
|
|
66
|
+
if (format) {
|
|
67
|
+
const map = {
|
|
68
|
+
json: new CustomJSONAdapter_js_1.CustomJSONAdapter(),
|
|
69
|
+
twison: new TwisonAdapter_js_1.TwisonAdapter(),
|
|
70
|
+
ink: new InkAdapter_js_1.InkAdapter()
|
|
71
|
+
};
|
|
72
|
+
if (!map[format])
|
|
73
|
+
throw new Error(`Unknown format: ${format}`);
|
|
74
|
+
selected = { key: format, inst: map[format] };
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
selected = detectAdapter(json);
|
|
78
|
+
console.log(`âšī¸ Detected format: ${selected.key} (from ${inputName})`);
|
|
79
|
+
}
|
|
80
|
+
const normalized = await selected.inst.load(json, { idPrefix, strict, experimentalInk });
|
|
81
|
+
// Schema validation (strict enforces failure)
|
|
82
|
+
const schema = (0, validateStoryData_js_1.validateStoryData)(normalized);
|
|
83
|
+
if (!schema.valid) {
|
|
84
|
+
const msg = `Schema validation failed with ${schema.errors?.length || 0} error(s).`;
|
|
85
|
+
const fmtErrors = (schema.errors || []).map((e) => ` - ${(e.instancePath ?? e.dataPath) || ''} ${e.message || ''}`).join('\n');
|
|
86
|
+
if (strict) {
|
|
87
|
+
console.error(`â ${msg}`);
|
|
88
|
+
if (fmtErrors)
|
|
89
|
+
console.error(fmtErrors);
|
|
90
|
+
process.exit(2);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.warn(`â ī¸ ${msg}`);
|
|
94
|
+
if (fmtErrors)
|
|
95
|
+
console.warn(fmtErrors);
|
|
96
|
+
exitCode = Math.max(exitCode, 1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Additional semantic checks: initial node exists, dangling nextNodeId targets
|
|
100
|
+
const nodeIds = new Set(normalized.nodes.map(n => n.id));
|
|
101
|
+
const invalidLinks = [];
|
|
102
|
+
for (const n of normalized.nodes) {
|
|
103
|
+
for (const c of n.choices) {
|
|
104
|
+
if (c.nextNodeId && !nodeIds.has(c.nextNodeId)) {
|
|
105
|
+
invalidLinks.push({ from: n.id, to: c.nextNodeId });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const initialExists = nodeIds.has(normalized.initialNodeId);
|
|
110
|
+
if (!initialExists) {
|
|
111
|
+
const msg = `Initial node '${normalized.initialNodeId}' does not exist in nodes`;
|
|
112
|
+
if (strict) {
|
|
113
|
+
console.error(`â ${msg}`);
|
|
114
|
+
process.exit(2);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
console.warn(`â ī¸ ${msg}`);
|
|
118
|
+
exitCode = Math.max(exitCode, 1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (invalidLinks.length > 0) {
|
|
122
|
+
const msg = `Found ${invalidLinks.length} dangling link(s)`;
|
|
123
|
+
const lines = invalidLinks.slice(0, 10).map(l => ` - ${l.from} -> ${l.to} (missing)`);
|
|
124
|
+
if (strict) {
|
|
125
|
+
console.error(`â ${msg}`);
|
|
126
|
+
if (lines.length)
|
|
127
|
+
console.error(lines.join('\n'));
|
|
128
|
+
process.exit(2);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.warn(`â ī¸ ${msg}`);
|
|
132
|
+
if (lines.length)
|
|
133
|
+
console.warn(lines.join('\n'));
|
|
134
|
+
exitCode = Math.max(exitCode, 1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const story = (0, core_js_1.loadStoryData)(normalized);
|
|
138
|
+
if (outArg && outArg !== 'stdout') {
|
|
139
|
+
const outPath = (0, path_1.resolve)(outArg);
|
|
140
|
+
(0, fs_1.writeFileSync)(outPath, JSON.stringify(story, null, 2));
|
|
141
|
+
console.log(`â
Imported and normalized to ${outPath}`);
|
|
142
|
+
}
|
|
143
|
+
else if (!outArg && inputName !== 'stdin') {
|
|
144
|
+
const outPath = (0, path_1.resolve)((0, path_1.basename)(inputName).replace(/\.[^.]+$/, '') + '.qnce.json');
|
|
145
|
+
(0, fs_1.writeFileSync)(outPath, JSON.stringify(story, null, 2));
|
|
146
|
+
console.log(`â
Imported and normalized to ${outPath}`);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// stdout
|
|
150
|
+
process.stdout.write(JSON.stringify(story, null, 2));
|
|
151
|
+
}
|
|
152
|
+
process.exit(exitCode);
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
console.error('â Import failed:', err?.message || err);
|
|
156
|
+
process.exit(2);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const isMainModule = require.main === module;
|
|
160
|
+
if (isMainModule) {
|
|
161
|
+
main().catch((e) => {
|
|
162
|
+
console.error('â Import failed:', e?.message || e);
|
|
163
|
+
process.exit(2);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import.js","sourceRoot":"","sources":["../../src/cli/import.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/play.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"play.d.ts","sourceRoot":"","sources":["../../src/cli/play.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"play.d.ts","sourceRoot":"","sources":["../../src/cli/play.ts"],"names":[],"mappings":";AAiQA,iBAAS,IAAI,IAAI,IAAI,CAuHpB;AAOD,OAAO,EAAE,IAAI,IAAI,eAAe,EAAE,CAAC"}
|