@sprig-and-prose/sprig 0.8.0 → 0.9.1

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 (36) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +58 -18
  4. package/dist/cli.js.map +1 -1
  5. package/dist/scene-compiler.d.ts +9 -2
  6. package/dist/scene-compiler.d.ts.map +1 -1
  7. package/dist/scene-compiler.js +55 -39
  8. package/dist/scene-compiler.js.map +1 -1
  9. package/dist/scene-discovery.d.ts +11 -0
  10. package/dist/scene-discovery.d.ts.map +1 -0
  11. package/dist/scene-discovery.js +41 -0
  12. package/dist/scene-discovery.js.map +1 -0
  13. package/package.json +1 -1
  14. package/src/cli.ts +77 -19
  15. package/src/scene-compiler.ts +62 -39
  16. package/src/scene-discovery.ts +51 -0
  17. package/tests/compile-scene-only.test.js +109 -0
  18. package/tests/fixtures/scene-only-empty/.gitkeep +0 -0
  19. package/tests/fixtures/scene-only-invalid/.sprig-out/bad.error.txt +2 -0
  20. package/tests/fixtures/scene-only-invalid/bad.scene.prose +10 -0
  21. package/tests/fixtures/scene-only-valid/.sprig-emit/AnotherScene.scene.json +15 -0
  22. package/tests/fixtures/scene-only-valid/.sprig-emit/SimpleScene.scene.json +15 -0
  23. package/tests/fixtures/scene-only-valid/.sprig-out/AnotherScene.scene.json +15 -0
  24. package/tests/fixtures/scene-only-valid/.sprig-out/SimpleScene.scene.json +15 -0
  25. package/tests/fixtures/scene-only-valid/another.scene.prose +3 -0
  26. package/tests/fixtures/scene-only-valid/simple.scene.prose +3 -0
  27. package/tests/fixtures/universe-unchanged/.sprig/TestScene.scene.json +15 -0
  28. package/tests/fixtures/universe-unchanged/.sprig/manifest.json +62 -0
  29. package/tests/fixtures/universe-unchanged/custom-out/TestScene.scene.json +15 -0
  30. package/tests/fixtures/universe-unchanged/custom-out/manifest.json +62 -0
  31. package/tests/fixtures/universe-unchanged/scene.scene.prose +3 -0
  32. package/tests/fixtures/universe-unchanged/universe.prose +5 -0
  33. package/tests/fixtures/universe-upstream/subdir/.sprig/OneScene.scene.json +15 -0
  34. package/tests/fixtures/universe-upstream/subdir/.sprig/manifest.json +62 -0
  35. package/tests/fixtures/universe-upstream/subdir/one.scene.prose +3 -0
  36. package/tests/fixtures/universe-upstream/universe.prose +5 -0
package/src/cli.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  import { resolve, join } from "node:path";
4
4
  import { existsSync, writeFileSync } from "node:fs";
5
5
  import { discoverUniverseRoot } from "./root.js";
6
+ import { discoverSceneFiles } from "./scene-discovery.js";
6
7
  import { loadProseFiles } from "./prose.js";
7
8
  import { compileUniverse } from "./compiler.js";
8
9
  import { compileScenes } from "./scene-compiler.js";
@@ -26,13 +27,15 @@ function printHelp() {
26
27
  console.log(" --legacy Use the legacy parser/graph pipeline");
27
28
  console.log("");
28
29
  console.log("Root discovery:");
29
- console.log(" - Walks upward from provided path (or current directory)");
30
+ console.log(" - Walks upward from path (or cwd for 'sprig compile')");
30
31
  console.log(" - Finds directory containing universe.prose");
32
+ console.log(" - Scene-only mode: requires --out when no universe.prose");
31
33
  }
32
34
 
33
35
  function parseArgs(): {
34
36
  command: Command | null;
35
37
  path: string;
38
+ pathExplicit: boolean;
36
39
  port?: number;
37
40
  universeName?: string;
38
41
  legacy?: boolean;
@@ -41,7 +44,7 @@ function parseArgs(): {
41
44
  const args = process.argv.slice(2);
42
45
 
43
46
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
44
- return { command: null, path: process.cwd() };
47
+ return { command: null, path: process.cwd(), pathExplicit: false };
45
48
  }
46
49
 
47
50
  const command = args[0] as Command;
@@ -57,11 +60,12 @@ function parseArgs(): {
57
60
  console.error("Usage: sprig init <UniverseName>");
58
61
  process.exit(1);
59
62
  }
60
- return { command, path: process.cwd(), universeName: args[1] };
63
+ return { command, path: process.cwd(), pathExplicit: false, universeName: args[1] };
61
64
  }
62
65
 
63
66
  // Parse path and options
64
67
  let path = process.cwd();
68
+ let pathExplicit = false;
65
69
  let port: number | undefined;
66
70
  let legacy = false;
67
71
  let out: string | undefined;
@@ -92,8 +96,9 @@ function parseArgs(): {
92
96
  } else if (arg === "--legacy") {
93
97
  legacy = true;
94
98
  } else if (!arg.startsWith("-")) {
95
- // First non-option argument is the path
99
+ // First non-option argument is the path (in-directory)
96
100
  path = resolve(arg);
101
+ pathExplicit = true;
97
102
  } else {
98
103
  console.error(`Error: Unknown option "${arg}"`);
99
104
  console.error("Run 'sprig --help' for usage information");
@@ -101,22 +106,78 @@ function parseArgs(): {
101
106
  }
102
107
  }
103
108
 
104
- return { command, path, port, legacy, out };
109
+ return { command, path, pathExplicit, port, legacy, out };
105
110
  }
106
111
 
107
- async function handleCompile(path: string, outDir: string | undefined, legacy = false): Promise<void> {
112
+ async function handleCompile(
113
+ path: string,
114
+ outDir: string | undefined,
115
+ legacy = false,
116
+ pathExplicit = false,
117
+ ): Promise<void> {
108
118
  const root = discoverUniverseRoot(path);
109
- if (!root) {
110
- console.error("Could not find universe.prose when walking upward from", path);
111
- console.error("");
112
- console.error("Make sure you're inside a universe repository.");
119
+
120
+ if (!pathExplicit) {
121
+ // sprig compile (no path): discover from cwd, require universe
122
+ if (!root) {
123
+ console.error("No universe.prose found.");
124
+ process.exit(1);
125
+ }
126
+ const outputDir = outDir || join(root, ".sprig");
127
+ await runUniverseCompile(root, outputDir, legacy);
128
+ return;
129
+ }
130
+
131
+ // sprig compile <in-directory>: path was explicitly provided
132
+ if (root) {
133
+ // Universe found: output to in-directory/.sprig or --out
134
+ const outputDir = outDir || join(path, ".sprig");
135
+ await runUniverseCompile(root, outputDir, legacy);
136
+ return;
137
+ }
138
+
139
+ // Universe not found: scene-only gated by --out
140
+ if (!outDir) {
141
+ console.error(`No universe.prose found for ${path}. Provide --out <out-directory> to compile scenes only.`);
142
+ process.exit(1);
143
+ }
144
+
145
+ const discovery = discoverSceneFiles(path);
146
+ if (!discovery) {
147
+ console.error("No universe.prose found and no *.scene.prose files found in:", path);
148
+ process.exit(1);
149
+ }
150
+
151
+ const sceneResult = await compileScenes(discovery.searchRoot, outDir, {
152
+ sceneFiles: discovery.sceneFiles,
153
+ emitManifests: true,
154
+ });
155
+
156
+ const errors = sceneResult.diagnostics.filter((d) => d.severity === "error");
157
+ const warnings = sceneResult.diagnostics.filter((d) => d.severity === "warning");
158
+
159
+ if (!sceneResult.success) {
160
+ if (errors.length > 0) {
161
+ printDiagnostics(errors, "Error");
162
+ }
113
163
  process.exit(1);
114
164
  }
115
165
 
116
- // Resolve output directory: --out flag takes precedence over default
117
- const outputDir = outDir || join(root, ".sprig");
166
+ const sceneCount = sceneResult.scenes.length;
167
+ const scenesText = sceneCount === 1 ? "scene" : "scenes";
168
+ console.log(`✓ Compiled ${sceneCount} ${scenesText}`);
169
+
170
+ if (warnings.length > 0) {
171
+ console.log("");
172
+ printDiagnostics(warnings, "Warning");
173
+ }
174
+ }
118
175
 
119
- // Compile universe
176
+ async function runUniverseCompile(
177
+ root: string,
178
+ outputDir: string,
179
+ legacy: boolean,
180
+ ): Promise<void> {
120
181
  const files = await loadProseFiles(root);
121
182
  const universeResult = await compileUniverse(root, files, true, { legacy, outputDir });
122
183
 
@@ -128,10 +189,8 @@ async function handleCompile(path: string, outDir: string | undefined, legacy =
128
189
  process.exit(1);
129
190
  }
130
191
 
131
- // Compile scenes
132
192
  const sceneResult = await compileScenes(root, outputDir);
133
-
134
- // Combine diagnostics
193
+
135
194
  const allDiagnostics = [...universeResult.diagnostics, ...sceneResult.diagnostics];
136
195
  const errors = allDiagnostics.filter((d) => d.severity === "error");
137
196
  const warnings = allDiagnostics.filter((d) => d.severity === "warning");
@@ -143,7 +202,6 @@ async function handleCompile(path: string, outDir: string | undefined, legacy =
143
202
  process.exit(1);
144
203
  }
145
204
 
146
- // Print summary
147
205
  const sceneCount = sceneResult.scenes.length;
148
206
  const scenesText = sceneCount === 1 ? "scene" : "scenes";
149
207
  console.log(`✓ Compiled 1 universe + ${sceneCount} ${scenesText}`);
@@ -341,7 +399,7 @@ async function handleUI(path: string, port?: number, legacy = false): Promise<vo
341
399
  }
342
400
 
343
401
  async function main() {
344
- const { command, path, port, universeName, legacy, out } = parseArgs();
402
+ const { command, path, pathExplicit, port, universeName, legacy, out } = parseArgs();
345
403
 
346
404
  if (!command) {
347
405
  printHelp();
@@ -351,7 +409,7 @@ async function main() {
351
409
  try {
352
410
  switch (command) {
353
411
  case "compile":
354
- await handleCompile(path, out, legacy);
412
+ await handleCompile(path, out, legacy, pathExplicit);
355
413
  break;
356
414
  case "validate":
357
415
  await handleValidate(path, legacy);
@@ -53,26 +53,41 @@ function generateManifestId(): string {
53
53
  return `time:${new Date().toISOString()}`;
54
54
  }
55
55
 
56
+ export interface CompileScenesOptions {
57
+ /** Explicit scene file paths (skips globbing) */
58
+ sceneFiles?: string[];
59
+ /** If false, parse and validate only; do not write manifests or error files */
60
+ emitManifests?: boolean;
61
+ }
62
+
56
63
  /**
57
64
  * Compile all scene files in the universe
58
- * @param universeRoot - Universe root directory
65
+ * @param universeRoot - Universe root directory (or search root for scene-only mode)
59
66
  * @param outputDir - Output directory for scene manifests
67
+ * @param options - Optional: sceneFiles (explicit list), emitManifests (default true in universe mode)
60
68
  * @returns Compile result with success status and list of compiled scenes
61
69
  */
62
70
  export async function compileScenes(
63
71
  universeRoot: string,
64
72
  outputDir: string,
73
+ options?: CompileScenesOptions,
65
74
  ): Promise<SceneCompileResult> {
66
75
  const diagnostics: Array<{ severity: string; message: string; source?: unknown; scene?: string }> = [];
67
76
  const compiledScenes: string[] = [];
77
+ const emitManifests = options?.emitManifests !== false;
68
78
 
69
79
  try {
70
- // Find all .scene.prose files
71
- const sceneFiles = await fg("**/*.scene.prose", {
72
- cwd: universeRoot,
73
- absolute: true,
74
- ignore: ["node_modules/**", ".git/**"],
75
- });
80
+ // Use explicit scene files or discover via glob
81
+ let sceneFiles: string[];
82
+ if (options?.sceneFiles && options.sceneFiles.length > 0) {
83
+ sceneFiles = options.sceneFiles;
84
+ } else {
85
+ sceneFiles = await fg("**/*.scene.prose", {
86
+ cwd: universeRoot,
87
+ absolute: true,
88
+ ignore: ["node_modules/**", ".git/**"],
89
+ });
90
+ }
76
91
 
77
92
  if (sceneFiles.length === 0) {
78
93
  // No scenes to compile is not an error
@@ -83,15 +98,17 @@ export async function compileScenes(
83
98
  };
84
99
  }
85
100
 
86
- // Ensure output directory exists
87
- try {
88
- mkdirSync(outputDir, { recursive: true });
89
- } catch (error) {
90
- // Directory might already exist, ignore
101
+ if (emitManifests) {
102
+ // Ensure output directory exists
103
+ try {
104
+ mkdirSync(outputDir, { recursive: true });
105
+ } catch (error) {
106
+ // Directory might already exist, ignore
107
+ }
91
108
  }
92
109
 
93
110
  const generatedAt = new Date().toISOString();
94
- const manifestId = generateManifestId();
111
+ const manifestId = emitManifests ? generateManifestId() : "";
95
112
 
96
113
  // Compile each scene
97
114
  for (const sceneFile of sceneFiles) {
@@ -107,35 +124,39 @@ export async function compileScenes(
107
124
  message,
108
125
  source: sceneFile,
109
126
  });
110
- writeSceneErrors(outputDir, sceneFile, [message], sourceText);
127
+ if (emitManifests) {
128
+ writeSceneErrors(outputDir, sceneFile, [message], sourceText);
129
+ }
111
130
  continue;
112
131
  }
113
132
 
114
- // Inject metadata
115
- const manifestWithMeta = {
116
- ...manifest,
117
- meta: {
118
- generatedAt,
119
- manifestId,
120
- },
121
- };
122
-
123
- // Write to output directory
124
- const outputPath = join(outputDir, `${manifest.sceneName}.scene.json`);
125
- const tempPath = `${outputPath}.tmp`;
126
- const json = JSON.stringify(manifestWithMeta, null, 2);
127
- writeFileSync(tempPath, json, "utf-8");
128
- renameSync(tempPath, outputPath);
129
-
130
- // Remove any prior .error.txt for this scene (same source file base name)
131
- const errorPath = join(outputDir, `${sceneFileBaseName(sceneFile)}.error.txt`);
132
- try {
133
- unlinkSync(errorPath);
134
- } catch {
135
- // ignore if missing
136
- }
137
-
138
133
  compiledScenes.push(manifest.sceneName);
134
+
135
+ if (emitManifests) {
136
+ // Inject metadata
137
+ const manifestWithMeta = {
138
+ ...manifest,
139
+ meta: {
140
+ generatedAt,
141
+ manifestId,
142
+ },
143
+ };
144
+
145
+ // Write to output directory
146
+ const outputPath = join(outputDir, `${manifest.sceneName}.scene.json`);
147
+ const tempPath = `${outputPath}.tmp`;
148
+ const json = JSON.stringify(manifestWithMeta, null, 2);
149
+ writeFileSync(tempPath, json, "utf-8");
150
+ renameSync(tempPath, outputPath);
151
+
152
+ // Remove any prior .error.txt for this scene (same source file base name)
153
+ const errorPath = join(outputDir, `${sceneFileBaseName(sceneFile)}.error.txt`);
154
+ try {
155
+ unlinkSync(errorPath);
156
+ } catch {
157
+ // ignore if missing
158
+ }
159
+ }
139
160
  } catch (error) {
140
161
  const message = error instanceof Error ? error.message : String(error);
141
162
  diagnostics.push({
@@ -143,7 +164,9 @@ export async function compileScenes(
143
164
  message: `Scene compile failed: ${message}`,
144
165
  source: sceneFile,
145
166
  });
146
- writeSceneErrors(outputDir, sceneFile, [message], sourceText);
167
+ if (emitManifests) {
168
+ writeSceneErrors(outputDir, sceneFile, [message], sourceText);
169
+ }
147
170
  }
148
171
  }
149
172
 
@@ -0,0 +1,51 @@
1
+ import { statSync, existsSync } from "node:fs";
2
+ import { resolve, dirname, join } from "node:path";
3
+ import fg from "fast-glob";
4
+
5
+ export interface SceneDiscovery {
6
+ sceneFiles: string[];
7
+ searchRoot: string;
8
+ }
9
+
10
+ /**
11
+ * Discover scene files when no universe.prose is found.
12
+ * @param path - Path (file or directory) from user
13
+ * @returns SceneDiscovery with sceneFiles and searchRoot, or null if no scenes found
14
+ */
15
+ export function discoverSceneFiles(path: string): SceneDiscovery | null {
16
+ const resolved = resolve(path);
17
+
18
+ if (!existsSync(resolved)) {
19
+ return null;
20
+ }
21
+
22
+ const stat = statSync(resolved);
23
+
24
+ if (stat.isFile()) {
25
+ if (/\.scene\.prose$/i.test(resolved)) {
26
+ return {
27
+ sceneFiles: [resolved],
28
+ searchRoot: dirname(resolved),
29
+ };
30
+ }
31
+ // Other file: search in same directory
32
+ const searchRoot = dirname(resolved);
33
+ const sceneFiles = fg.sync("**/*.scene.prose", {
34
+ cwd: searchRoot,
35
+ absolute: true,
36
+ ignore: ["node_modules/**", ".git/**"],
37
+ });
38
+ return sceneFiles.length > 0 ? { sceneFiles, searchRoot } : null;
39
+ }
40
+
41
+ if (stat.isDirectory()) {
42
+ const sceneFiles = fg.sync("**/*.scene.prose", {
43
+ cwd: resolved,
44
+ absolute: true,
45
+ ignore: ["node_modules/**", ".git/**"],
46
+ });
47
+ return sceneFiles.length > 0 ? { sceneFiles, searchRoot: resolved } : null;
48
+ }
49
+
50
+ return null;
51
+ }
@@ -0,0 +1,109 @@
1
+ import { test } from "node:test";
2
+ import { strict as assert } from "node:assert";
3
+ import { existsSync } from "node:fs";
4
+ import { join, dirname } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { spawnSync } from "node:child_process";
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const FIXTURES = join(__dirname, "fixtures");
10
+ const CLI_PATH = join(__dirname, "..", "dist", "cli.js");
11
+
12
+ function runCompile(args, cwd) {
13
+ const result = spawnSync("node", [CLI_PATH, "compile", ...args], {
14
+ encoding: "utf-8",
15
+ cwd: cwd ?? join(__dirname, ".."),
16
+ });
17
+ return {
18
+ status: result.status,
19
+ stdout: result.stdout ?? "",
20
+ stderr: result.stderr ?? "",
21
+ };
22
+ }
23
+
24
+ test("sprig compile with no universe in cwd: errors", () => {
25
+ const cwd = join(FIXTURES, "scene-only-empty");
26
+ const { status, stderr } = runCompile([], cwd);
27
+
28
+ assert.notStrictEqual(status, 0, "Expected non-zero exit");
29
+ assert.ok(stderr.includes("No universe.prose found."), "Should show expected error");
30
+ });
31
+
32
+ test("sprig compile <dir> universe in dir, no --out: writes to dir/.sprig", () => {
33
+ const dir = join(FIXTURES, "universe-unchanged");
34
+ const { status, stderr } = runCompile([dir]);
35
+
36
+ assert.strictEqual(status, 0, `Expected exit 0, got ${status}. stderr: ${stderr}`);
37
+
38
+ const sprigDir = join(dir, ".sprig");
39
+ assert.ok(existsSync(sprigDir), ".sprig should exist");
40
+ assert.ok(existsSync(join(sprigDir, "manifest.json")), "manifest.json should exist");
41
+ assert.ok(existsSync(join(sprigDir, "TestScene.scene.json")), "TestScene.scene.json should exist");
42
+ });
43
+
44
+ test("sprig compile <dir> --out <out> universe found: writes to out", () => {
45
+ const dir = join(FIXTURES, "universe-unchanged");
46
+ const outDir = join(dir, "custom-out");
47
+ const { status, stderr } = runCompile([dir, "--out", outDir]);
48
+
49
+ assert.strictEqual(status, 0, `Expected exit 0, got ${status}. stderr: ${stderr}`);
50
+
51
+ assert.ok(existsSync(join(outDir, "manifest.json")), "manifest.json should exist in --out");
52
+ assert.ok(existsSync(join(outDir, "TestScene.scene.json")), "TestScene.scene.json should exist in --out");
53
+ });
54
+
55
+ test("sprig compile <dir> no universe, no --out: errors with guidance", () => {
56
+ const dir = join(FIXTURES, "scene-only-valid");
57
+ const { status, stderr } = runCompile([dir]);
58
+
59
+ assert.notStrictEqual(status, 0, "Expected non-zero exit");
60
+ assert.ok(
61
+ stderr.includes("No universe.prose found for"),
62
+ "Should mention no universe for dir",
63
+ );
64
+ assert.ok(stderr.includes("Provide --out"), "Should suggest --out");
65
+ });
66
+
67
+ test("sprig compile <dir> --out <out> no universe, scenes present: emits to out", () => {
68
+ const dir = join(FIXTURES, "scene-only-valid");
69
+ const outDir = join(dir, ".sprig-out");
70
+ const { status, stderr } = runCompile([dir, "--out", outDir]);
71
+
72
+ assert.strictEqual(status, 0, `Expected exit 0, got ${status}. stderr: ${stderr}`);
73
+
74
+ assert.ok(existsSync(join(outDir, "SimpleScene.scene.json")), "SimpleScene.scene.json should exist");
75
+ assert.ok(existsSync(join(outDir, "AnotherScene.scene.json")), "AnotherScene.scene.json should exist");
76
+ });
77
+
78
+ test("sprig compile <dir> --out <out> no universe, no scenes: errors", () => {
79
+ const dir = join(FIXTURES, "scene-only-empty");
80
+ const outDir = join(dir, ".sprig-out");
81
+ const { status, stderr } = runCompile([dir, "--out", outDir]);
82
+
83
+ assert.notStrictEqual(status, 0, "Expected non-zero exit");
84
+ assert.ok(
85
+ stderr.includes("No universe.prose found and no *.scene.prose files found in:"),
86
+ "Should show no scenes error",
87
+ );
88
+ });
89
+
90
+ test("sprig compile <dir> universe in parent, no --out: writes to in-directory/.sprig", () => {
91
+ const subdir = join(FIXTURES, "universe-upstream", "subdir");
92
+ const { status, stderr } = runCompile([subdir]);
93
+
94
+ assert.strictEqual(status, 0, `Expected exit 0, got ${status}. stderr: ${stderr}`);
95
+
96
+ const sprigDir = join(subdir, ".sprig");
97
+ assert.ok(existsSync(sprigDir), "Output should be in subdir/.sprig (in-directory)");
98
+ assert.ok(existsSync(join(sprigDir, "manifest.json")), "manifest.json should exist");
99
+ assert.ok(existsSync(join(sprigDir, "OneScene.scene.json")), "OneScene.scene.json should exist");
100
+ });
101
+
102
+ test("scene-only invalid dir with --out: exits non-zero", () => {
103
+ const dir = join(FIXTURES, "scene-only-invalid");
104
+ const outDir = join(dir, ".sprig-out");
105
+ const { status, stderr } = runCompile([dir, "--out", outDir]);
106
+
107
+ assert.notStrictEqual(status, 0, "Expected non-zero exit on invalid scene");
108
+ assert.ok(stderr.includes("BadScene") || stderr.includes("bad.scene.prose"), "Error should mention scene or file");
109
+ });
File without changes
@@ -0,0 +1,2 @@
1
+ Field 'id' may only define a single type (e.g. integer, string, array, or an actor). This error appears because two or more types are defined for this field.
2
+ at BadScene
@@ -0,0 +1,10 @@
1
+ scene BadScene {
2
+ actor Actor {
3
+ shape {
4
+ id {
5
+ integer
6
+ string
7
+ }
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "sceneName": "AnotherScene",
3
+ "actors": {
4
+ "NameActor": {
5
+ "type": "string",
6
+ "identity": []
7
+ }
8
+ },
9
+ "portals": {},
10
+ "derived": {},
11
+ "meta": {
12
+ "generatedAt": "2026-02-21T20:00:48.348Z",
13
+ "manifestId": "git:e97c34ae2cb10839cafef399d1ef329411e3bd22"
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "sceneName": "SimpleScene",
3
+ "actors": {
4
+ "IntActor": {
5
+ "type": "integer",
6
+ "identity": []
7
+ }
8
+ },
9
+ "portals": {},
10
+ "derived": {},
11
+ "meta": {
12
+ "generatedAt": "2026-02-21T20:00:48.348Z",
13
+ "manifestId": "git:e97c34ae2cb10839cafef399d1ef329411e3bd22"
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "sceneName": "AnotherScene",
3
+ "actors": {
4
+ "NameActor": {
5
+ "type": "string",
6
+ "identity": []
7
+ }
8
+ },
9
+ "portals": {},
10
+ "derived": {},
11
+ "meta": {
12
+ "generatedAt": "2026-02-21T20:23:33.528Z",
13
+ "manifestId": "git:e97c34ae2cb10839cafef399d1ef329411e3bd22"
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "sceneName": "SimpleScene",
3
+ "actors": {
4
+ "IntActor": {
5
+ "type": "integer",
6
+ "identity": []
7
+ }
8
+ },
9
+ "portals": {},
10
+ "derived": {},
11
+ "meta": {
12
+ "generatedAt": "2026-02-21T20:23:33.528Z",
13
+ "manifestId": "git:e97c34ae2cb10839cafef399d1ef329411e3bd22"
14
+ }
15
+ }
@@ -0,0 +1,3 @@
1
+ scene AnotherScene {
2
+ actor NameActor { string }
3
+ }
@@ -0,0 +1,3 @@
1
+ scene SimpleScene {
2
+ actor IntActor { integer }
3
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "sceneName": "TestScene",
3
+ "actors": {
4
+ "IntActor": {
5
+ "type": "integer",
6
+ "identity": []
7
+ }
8
+ },
9
+ "portals": {},
10
+ "derived": {},
11
+ "meta": {
12
+ "generatedAt": "2026-02-21T20:23:33.122Z",
13
+ "manifestId": "git:e97c34ae2cb10839cafef399d1ef329411e3bd22"
14
+ }
15
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "version": 1,
3
+ "universes": {
4
+ "TestUniverse": {
5
+ "name": "TestUniverse",
6
+ "root": "TestUniverse:universe:TestUniverse"
7
+ }
8
+ },
9
+ "nodes": {
10
+ "TestUniverse:universe:TestUniverse": {
11
+ "id": "TestUniverse:universe:TestUniverse",
12
+ "kind": "universe",
13
+ "name": "TestUniverse",
14
+ "children": [],
15
+ "source": {
16
+ "file": "/home/grumpy/git/sprig/packages/cli/tests/fixtures/universe-unchanged/universe.prose",
17
+ "start": {
18
+ "line": 1,
19
+ "col": 1,
20
+ "offset": 0
21
+ },
22
+ "end": {
23
+ "line": 5,
24
+ "col": 2,
25
+ "offset": 63
26
+ }
27
+ },
28
+ "describe": {
29
+ "raw": "\n A test universe.\n ",
30
+ "normalized": "\n A test universe.\n ",
31
+ "source": {
32
+ "file": "/home/grumpy/git/sprig/packages/cli/tests/fixtures/universe-unchanged/universe.prose",
33
+ "start": {
34
+ "line": 2,
35
+ "col": 3,
36
+ "offset": 26
37
+ },
38
+ "end": {
39
+ "line": 4,
40
+ "col": 4,
41
+ "offset": 61
42
+ }
43
+ }
44
+ }
45
+ }
46
+ },
47
+ "edges": [],
48
+ "edgesAsserted": [],
49
+ "diagnostics": [],
50
+ "repositories": {},
51
+ "references": {},
52
+ "arcs": {},
53
+ "documentsByName": {},
54
+ "relationshipDecls": {
55
+ "TestUniverse": {}
56
+ },
57
+ "generatedAt": "2026-02-21T20:23:33.116Z",
58
+ "meta": {
59
+ "generatedAt": "2026-02-21T20:23:33.116Z",
60
+ "manifestId": "git:e97c34ae2cb10839cafef399d1ef329411e3bd22"
61
+ }
62
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "sceneName": "TestScene",
3
+ "actors": {
4
+ "IntActor": {
5
+ "type": "integer",
6
+ "identity": []
7
+ }
8
+ },
9
+ "portals": {},
10
+ "derived": {},
11
+ "meta": {
12
+ "generatedAt": "2026-02-21T20:23:33.279Z",
13
+ "manifestId": "git:e97c34ae2cb10839cafef399d1ef329411e3bd22"
14
+ }
15
+ }