@sansavision/aurora 0.1.0-alpha.20260212.4

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 (150) hide show
  1. package/README.md +4 -0
  2. package/package.json +17 -0
  3. package/src/ai-diagnostics.ts +156 -0
  4. package/src/ai.ts +574 -0
  5. package/src/analyze.ts +669 -0
  6. package/src/bin/aurora.ts +15 -0
  7. package/src/build.ts +431 -0
  8. package/src/bun-test-shims.d.ts +17 -0
  9. package/src/create-feature.ts +419 -0
  10. package/src/create-route.ts +581 -0
  11. package/src/create.ts +425 -0
  12. package/src/dev.ts +126 -0
  13. package/src/devtools.ts +1143 -0
  14. package/src/doctor.ts +611 -0
  15. package/src/explain.ts +855 -0
  16. package/src/help.ts +39 -0
  17. package/src/index.ts +34 -0
  18. package/src/init.ts +1011 -0
  19. package/src/inspect-cache.ts +464 -0
  20. package/src/lsp-inline-hints.ts +254 -0
  21. package/src/node-shims.d.ts +26 -0
  22. package/src/process.d.ts +11 -0
  23. package/src/query-profiler.ts +520 -0
  24. package/src/realtime-monitor.ts +389 -0
  25. package/src/registry.ts +303 -0
  26. package/src/run.ts +37 -0
  27. package/src/start.ts +56 -0
  28. package/src/test.ts +289 -0
  29. package/templates/basic/README.md +16 -0
  30. package/templates/basic/package.json +10 -0
  31. package/templates/basic/src/actions/createMessage.action.server.ts +22 -0
  32. package/templates/basic/src/lib/auth.server.ts +11 -0
  33. package/templates/basic/src/queries/listMessages.server.ts +17 -0
  34. package/templates/basic/src/routes/index.tsx +12 -0
  35. package/templates/blog/README.md +17 -0
  36. package/templates/blog/package.json +12 -0
  37. package/templates/blog/public/assets/og-default.svg +17 -0
  38. package/templates/blog/src/content/loadPosts.server.ts +22 -0
  39. package/templates/blog/src/content/posts/hello-world.md +11 -0
  40. package/templates/blog/src/content/posts/release-notes.md +9 -0
  41. package/templates/blog/src/routes/index.tsx +22 -0
  42. package/templates/blog/src/routes/posts/[slug].tsx +19 -0
  43. package/templates/blog/src/seo/meta.ts +19 -0
  44. package/templates/dashboard/README.md +18 -0
  45. package/templates/dashboard/package.json +10 -0
  46. package/templates/dashboard/src/actions/acknowledgeAlert.action.server.ts +6 -0
  47. package/templates/dashboard/src/queries/getDashboardMetrics.server.ts +30 -0
  48. package/templates/dashboard/src/realtime/useDashboardRealtime.client.ts +13 -0
  49. package/templates/dashboard/src/routes/index.tsx +19 -0
  50. package/templates/dashboard/src/widgets/DataGrid.client.ts +8 -0
  51. package/templates/dashboard/src/widgets/MetricChart.client.ts +8 -0
  52. package/templates/desktop/README.md +18 -0
  53. package/templates/desktop/package.json +11 -0
  54. package/templates/desktop/src/actions/saveDesktopPreference.action.server.ts +28 -0
  55. package/templates/desktop/src/desktop/secureStorage.client.ts +20 -0
  56. package/templates/desktop/src/desktop/tauriBridge.client.ts +14 -0
  57. package/templates/desktop/src/queries/getDesktopSyncStatus.server.ts +9 -0
  58. package/templates/desktop/src/routes/index.tsx +27 -0
  59. package/templates/desktop/src/sync/offlineSyncBoundary.server.ts +27 -0
  60. package/templates/feature-skeleton/README.md +13 -0
  61. package/templates/feature-skeleton/actions/createFeature.action.server.ts +19 -0
  62. package/templates/feature-skeleton/index.ts +8 -0
  63. package/templates/feature-skeleton/queries/listFeature.server.ts +15 -0
  64. package/templates/feature-skeleton/realtime/useFeatureRealtime.client.ts +16 -0
  65. package/templates/feature-skeleton/template.manifest.json +15 -0
  66. package/templates/feature-skeleton/ui/FeatureView.client.tsx +14 -0
  67. package/templates/mobile/README.md +17 -0
  68. package/templates/mobile/package.json +11 -0
  69. package/templates/mobile/src/mobile/auth/session-handoff.client.ts +69 -0
  70. package/templates/mobile/src/mobile/generated/mobile-api-sdk.ts +62 -0
  71. package/templates/mobile/src/mobile/transport/mobile-api-transport.client.ts +122 -0
  72. package/templates/mobile/src/routes/index.tsx +134 -0
  73. package/templates/monorepo/README.md +18 -0
  74. package/templates/monorepo/apps/web/package.json +9 -0
  75. package/templates/monorepo/apps/web/src/routes/index.tsx +1 -0
  76. package/templates/monorepo/package.json +13 -0
  77. package/templates/monorepo/packages/shared/README.md +3 -0
  78. package/templates/monorepo/packages/ui/README.md +3 -0
  79. package/templates/saas/README.md +17 -0
  80. package/templates/saas/package.json +10 -0
  81. package/templates/saas/src/admin/getDashboard.server.ts +18 -0
  82. package/templates/saas/src/auth/session.server.ts +13 -0
  83. package/templates/saas/src/billing/checkout.server.ts +11 -0
  84. package/templates/saas/src/email/sendWelcome.server.ts +8 -0
  85. package/templates/saas/src/realtime/notifications.server.ts +8 -0
  86. package/templates/saas/src/routes/index.tsx +20 -0
  87. package/test/ai.test.ts +94 -0
  88. package/test/analyze.test.ts +301 -0
  89. package/test/build.test.ts +135 -0
  90. package/test/create-feature.test.ts +145 -0
  91. package/test/create-route.test.ts +117 -0
  92. package/test/create.test.ts +222 -0
  93. package/test/dev.test.ts +52 -0
  94. package/test/devtools.test.ts +130 -0
  95. package/test/doctor.test.ts +129 -0
  96. package/test/explain.test.ts +232 -0
  97. package/test/feature-skeleton.test.ts +53 -0
  98. package/test/fixtures/analyze/cache-input.invalid.json +1 -0
  99. package/test/fixtures/analyze/cache-input.missing-keyhash.v1.json +10 -0
  100. package/test/fixtures/analyze/cache-input.unsupported-version.v2.json +10 -0
  101. package/test/fixtures/analyze/cache-input.v1.json +12 -0
  102. package/test/fixtures/analyze/compiler-manifest/manifest.json +11 -0
  103. package/test/fixtures/analyze/guardrails-input.unsupported-version.v2.json +4 -0
  104. package/test/fixtures/analyze/guardrails-input.v1.json +49 -0
  105. package/test/fixtures/analyze/query-input.invalid-cache-status.v1.json +11 -0
  106. package/test/fixtures/analyze/query-input.unsupported-version.v2.json +11 -0
  107. package/test/fixtures/analyze/query-input.v1.json +18 -0
  108. package/test/fixtures/analyze/realtime-input.missing-lag-p95.v1.json +10 -0
  109. package/test/fixtures/analyze/realtime-input.unsupported-version.v2.json +8 -0
  110. package/test/fixtures/analyze/realtime-input.v1.json +12 -0
  111. package/test/fixtures/cache-inspector/cache-input.v1.json +23 -0
  112. package/test/fixtures/cache-inspector/invalid.json +1 -0
  113. package/test/fixtures/cache-inspector/snapshot.v1.json +34 -0
  114. package/test/fixtures/cache-inspector/unsupported-version.v2.json +13 -0
  115. package/test/fixtures/devtools/healthy.v1.json +130 -0
  116. package/test/fixtures/devtools/invalid.json +1 -0
  117. package/test/fixtures/devtools/unsupported-version.v2.json +8 -0
  118. package/test/fixtures/devtools/warn.v1.json +114 -0
  119. package/test/fixtures/doctor/clean/src/page.tsx +3 -0
  120. package/test/fixtures/doctor/findings/src/accessibility.client.tsx +7 -0
  121. package/test/fixtures/doctor/findings/src/migration.config.ts +3 -0
  122. package/test/fixtures/doctor/findings/src/page.client.tsx +5 -0
  123. package/test/fixtures/doctor/findings/src/perf.server.ts +15 -0
  124. package/test/fixtures/doctor/findings/src/routes.js +3 -0
  125. package/test/fixtures/doctor/findings/src/security.server.ts +7 -0
  126. package/test/fixtures/doctor/findings/src/users.server.ts +3 -0
  127. package/test/fixtures/doctor/governance/src/features/analytics/OWNERS.ts +2 -0
  128. package/test/fixtures/doctor/governance/src/features/analytics/page.tsx +3 -0
  129. package/test/fixtures/doctor/governance/src/features/billing/page.tsx +3 -0
  130. package/test/fixtures/explain/invalid.json +1 -0
  131. package/test/fixtures/explain/module-report.unsupported-version.v2.json +6 -0
  132. package/test/fixtures/explain/module-report.v1.json +72 -0
  133. package/test/fixtures/query-profiler/healthy.v1.json +11 -0
  134. package/test/fixtures/query-profiler/invalid.json +1 -0
  135. package/test/fixtures/query-profiler/unsupported-version.v2.json +6 -0
  136. package/test/fixtures/query-profiler/warning.v1.json +10 -0
  137. package/test/fixtures/realtime-monitor/healthy.v1.json +8 -0
  138. package/test/fixtures/realtime-monitor/invalid.json +1 -0
  139. package/test/fixtures/realtime-monitor/unsupported-version.v2.json +8 -0
  140. package/test/fixtures/realtime-monitor/warning.v1.json +8 -0
  141. package/test/help-parity.test.ts +104 -0
  142. package/test/init.test.ts +164 -0
  143. package/test/inspect-cache.test.ts +112 -0
  144. package/test/lsp-inline-hints.test.ts +65 -0
  145. package/test/query-profiler.test.ts +123 -0
  146. package/test/realtime-monitor.test.ts +115 -0
  147. package/test/registry.test.ts +41 -0
  148. package/test/start.test.ts +23 -0
  149. package/test/test-command.test.ts +65 -0
  150. package/tsconfig.json +19 -0
@@ -0,0 +1,301 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import { describe, expect, it } from "bun:test";
5
+
6
+ import { runAnalyzeCommand } from "../src";
7
+
8
+ const projectRoot = join(import.meta.dir, "..");
9
+
10
+ function fixturePath(name: string): string {
11
+ return join("test/fixtures/analyze", name);
12
+ }
13
+
14
+ function readFixture(name: string): string {
15
+ return readFileSync(join(import.meta.dir, "fixtures/analyze", name), "utf8");
16
+ }
17
+
18
+ describe("runAnalyzeCommand", () => {
19
+ it("generates a bundle-mode text report", () => {
20
+ const result = runAnalyzeCommand([], { cwd: projectRoot });
21
+
22
+ expect(result.exitCode).toBe(0);
23
+ expect(result.stdout).toContain("aurora analyze bundle report");
24
+ expect(result.stdout).toContain("out_dir: .aurora/analyze/compiler");
25
+ expect(result.stdout).toContain("manifest_found: false");
26
+ });
27
+
28
+ it("supports bundle-mode json output", () => {
29
+ const result = runAnalyzeCommand(["--format", "json"], { cwd: projectRoot });
30
+
31
+ expect(result.exitCode).toBe(0);
32
+ const parsed = JSON.parse(result.stdout ?? "{}") as {
33
+ mode?: string;
34
+ outDir?: string;
35
+ manifestFound?: boolean;
36
+ };
37
+
38
+ expect(parsed.mode).toBe("bundle");
39
+ expect(parsed.outDir).toBe(".aurora/analyze/compiler");
40
+ expect(parsed.manifestFound).toBe(false);
41
+ });
42
+
43
+ it("loads compiler manifest data when --out-dir contains manifest.json", () => {
44
+ const result = runAnalyzeCommand(
45
+ ["--out-dir", "test/fixtures/analyze/compiler-manifest", "--format", "json"],
46
+ { cwd: projectRoot },
47
+ );
48
+
49
+ expect(result.exitCode).toBe(0);
50
+ const parsed = JSON.parse(result.stdout ?? "{}") as {
51
+ mode?: string;
52
+ manifestFound?: boolean;
53
+ routeCount?: number;
54
+ chunkCount?: number;
55
+ note?: string;
56
+ };
57
+
58
+ expect(parsed.mode).toBe("bundle");
59
+ expect(parsed.manifestFound).toBe(true);
60
+ expect(parsed.routeCount).toBe(3);
61
+ expect(parsed.chunkCount).toBe(2);
62
+ expect(parsed.note).toBe("manifest loaded");
63
+ });
64
+
65
+ it("supports cache mode for schemaVersion 1 fixtures", () => {
66
+ const inputPath = fixturePath("cache-input.v1.json");
67
+ const result = runAnalyzeCommand(
68
+ ["--mode", "cache", "--input", inputPath, "--format", "json"],
69
+ { cwd: projectRoot },
70
+ );
71
+
72
+ expect(result.exitCode).toBe(0);
73
+ const parsed = JSON.parse(result.stdout ?? "{}") as {
74
+ mode?: string;
75
+ entries?: number;
76
+ };
77
+ expect(parsed.mode).toBe("cache");
78
+ expect(parsed.entries).toBe(1);
79
+ });
80
+
81
+ it("supports realtime mode for schemaVersion 1 fixtures", () => {
82
+ const inputPath = fixturePath("realtime-input.v1.json");
83
+ const result = runAnalyzeCommand(["--mode", "realtime", "--input", inputPath], {
84
+ cwd: projectRoot,
85
+ });
86
+
87
+ expect(result.exitCode).toBe(0);
88
+ expect(result.stdout).toContain("aurora analyze realtime report");
89
+ expect(result.stdout).toContain("lag_p95_ms: 260");
90
+ });
91
+
92
+ it("supports query mode for schemaVersion 1 fixtures", () => {
93
+ const inputPath = fixturePath("query-input.v1.json");
94
+ const result = runAnalyzeCommand(["--mode", "query", "--input", inputPath, "--format", "json"], {
95
+ cwd: projectRoot,
96
+ });
97
+
98
+ expect(result.exitCode).toBe(0);
99
+ const parsed = JSON.parse(result.stdout ?? "{}") as {
100
+ mode?: string;
101
+ samples?: number;
102
+ };
103
+ expect(parsed.mode).toBe("query");
104
+ expect(parsed.samples).toBe(2);
105
+ });
106
+
107
+ it("supports guardrails mode for schemaVersion 1 fixtures", () => {
108
+ const inputPath = fixturePath("guardrails-input.v1.json");
109
+ const result = runAnalyzeCommand(
110
+ ["--mode", "guardrails", "--input", inputPath, "--format", "json"],
111
+ { cwd: projectRoot },
112
+ );
113
+
114
+ expect(result.exitCode).toBe(0);
115
+ const parsed = JSON.parse(result.stdout ?? "{}") as {
116
+ mode?: string;
117
+ status?: string;
118
+ summary?: { total?: number; warnings?: number; errors?: number };
119
+ issues?: Array<{ code?: string }>;
120
+ };
121
+
122
+ expect(parsed.mode).toBe("guardrails");
123
+ expect(parsed.status).toBe("error");
124
+ expect(parsed.summary?.total).toBe(5);
125
+ expect(parsed.summary?.warnings).toBe(4);
126
+ expect(parsed.summary?.errors).toBe(1);
127
+ expect(parsed.issues?.some((issue) => issue.code === "PERF_PAYLOAD_ERROR")).toBe(true);
128
+ });
129
+
130
+ it("returns exit code 2 for invalid options", () => {
131
+ const result = runAnalyzeCommand(["--format", "xml"], { cwd: projectRoot });
132
+
133
+ expect(result.exitCode).toBe(2);
134
+ expect(result.stderr).toContain("aurora analyze: invalid format 'xml'");
135
+ });
136
+
137
+ it("requires --input for non-bundle modes", () => {
138
+ const result = runAnalyzeCommand(["--mode", "cache"], { cwd: projectRoot });
139
+
140
+ expect(result.exitCode).toBe(2);
141
+ expect(result.stderr).toContain(
142
+ "aurora analyze: --input is required when --mode is cache, realtime, query, or guardrails",
143
+ );
144
+ });
145
+
146
+ it("rejects --out-dir when non-bundle mode is selected", () => {
147
+ const result = runAnalyzeCommand(
148
+ ["--mode", "query", "--input", fixturePath("query-input.v1.json"), "--out-dir", "dist/compiler"],
149
+ { cwd: projectRoot },
150
+ );
151
+
152
+ expect(result.exitCode).toBe(2);
153
+ expect(result.stderr).toContain("aurora analyze: --out-dir is only valid when --mode is bundle");
154
+ });
155
+
156
+ it("rejects --input when bundle mode is selected", () => {
157
+ const result = runAnalyzeCommand(["--mode", "bundle", "--input", fixturePath("cache-input.v1.json")], {
158
+ cwd: projectRoot,
159
+ });
160
+
161
+ expect(result.exitCode).toBe(2);
162
+ expect(result.stderr).toContain(
163
+ "aurora analyze: --input is only valid when --mode is cache, realtime, query, or guardrails",
164
+ );
165
+ });
166
+
167
+ it("returns readable errors for invalid json input in non-bundle modes", () => {
168
+ const inputPath = fixturePath("cache-input.invalid.json");
169
+ const result = runAnalyzeCommand(["--mode", "cache", "--input", inputPath], {
170
+ cwd: projectRoot,
171
+ });
172
+
173
+ expect(result.exitCode).toBe(1);
174
+ expect(result.stderr).toContain(`aurora analyze: invalid json input at ${inputPath}`);
175
+ });
176
+
177
+ it("reports semantic cache fixture errors when key hash fields are missing", () => {
178
+ const inputPath = fixturePath("cache-input.missing-keyhash.v1.json");
179
+ const result = runAnalyzeCommand(["--mode", "cache", "--input", inputPath], {
180
+ cwd: projectRoot,
181
+ });
182
+
183
+ expect(result.exitCode).toBe(1);
184
+ expect(result.stderr).toContain("aurora analyze: cache mode failed");
185
+ expect(result.stderr).toContain("missing required string field (keyHash or hash)");
186
+ });
187
+
188
+ it("reports semantic realtime fixture errors when lag p95 fields are missing", () => {
189
+ const inputPath = fixturePath("realtime-input.missing-lag-p95.v1.json");
190
+ const result = runAnalyzeCommand(["--mode", "realtime", "--input", inputPath], {
191
+ cwd: projectRoot,
192
+ });
193
+
194
+ expect(result.exitCode).toBe(1);
195
+ expect(result.stderr).toContain("aurora analyze: realtime mode failed");
196
+ expect(result.stderr).toContain("missing required numeric field (lagP95Ms or p95)");
197
+ });
198
+
199
+ it("reports semantic query fixture errors for invalid cache status", () => {
200
+ const inputPath = fixturePath("query-input.invalid-cache-status.v1.json");
201
+ const result = runAnalyzeCommand(["--mode", "query", "--input", inputPath], {
202
+ cwd: projectRoot,
203
+ });
204
+
205
+ expect(result.exitCode).toBe(1);
206
+ expect(result.stderr).toContain("aurora analyze: query mode failed");
207
+ expect(result.stderr).toContain(
208
+ "missing required cache status field (cacheStatus/cache/status or hit)",
209
+ );
210
+ });
211
+
212
+ it("fails cache mode for unsupported schemaVersion", () => {
213
+ const inputPath = fixturePath("cache-input.unsupported-version.v2.json");
214
+ const result = runAnalyzeCommand(["--mode", "cache", "--input", inputPath], {
215
+ cwd: projectRoot,
216
+ });
217
+
218
+ expect(result.exitCode).toBe(1);
219
+ expect(result.stderr).toContain("aurora analyze: cache mode failed");
220
+ expect(result.stderr).toContain("unsupported schemaVersion 2 for cache input; expected 1");
221
+ });
222
+
223
+ it("fails realtime mode for unsupported schemaVersion", () => {
224
+ const inputPath = fixturePath("realtime-input.unsupported-version.v2.json");
225
+ const result = runAnalyzeCommand(["--mode", "realtime", "--input", inputPath], {
226
+ cwd: projectRoot,
227
+ });
228
+
229
+ expect(result.exitCode).toBe(1);
230
+ expect(result.stderr).toContain("aurora analyze: realtime mode failed");
231
+ expect(result.stderr).toContain("unsupported schemaVersion 2 for realtime input; expected 1");
232
+ });
233
+
234
+ it("fails query mode for unsupported schemaVersion", () => {
235
+ const inputPath = fixturePath("query-input.unsupported-version.v2.json");
236
+ const result = runAnalyzeCommand(["--mode", "query", "--input", inputPath], {
237
+ cwd: projectRoot,
238
+ });
239
+
240
+ expect(result.exitCode).toBe(1);
241
+ expect(result.stderr).toContain("aurora analyze: query mode failed");
242
+ expect(result.stderr).toContain("unsupported schemaVersion 2 for query input; expected 1");
243
+ });
244
+
245
+ it("fails guardrails mode for unsupported schemaVersion", () => {
246
+ const inputPath = fixturePath("guardrails-input.unsupported-version.v2.json");
247
+ const result = runAnalyzeCommand(["--mode", "guardrails", "--input", inputPath], {
248
+ cwd: projectRoot,
249
+ });
250
+
251
+ expect(result.exitCode).toBe(1);
252
+ expect(result.stderr).toContain("aurora analyze: guardrails mode failed");
253
+ expect(result.stderr).toContain("unsupported schemaVersion 2 for guardrails input; expected 1");
254
+ });
255
+
256
+ it("uses schemaVersion 1 for all analyze fixtures", () => {
257
+ const cacheFixture = JSON.parse(readFixture("cache-input.v1.json")) as { schemaVersion?: number };
258
+ const realtimeFixture = JSON.parse(readFixture("realtime-input.v1.json")) as { schemaVersion?: number };
259
+ const queryFixture = JSON.parse(readFixture("query-input.v1.json")) as { schemaVersion?: number };
260
+ const guardrailsFixture = JSON.parse(readFixture("guardrails-input.v1.json")) as { schemaVersion?: number };
261
+ const invalidCacheFixture = JSON.parse(readFixture("cache-input.missing-keyhash.v1.json")) as {
262
+ schemaVersion?: number;
263
+ };
264
+ const invalidRealtimeFixture = JSON.parse(
265
+ readFixture("realtime-input.missing-lag-p95.v1.json"),
266
+ ) as { schemaVersion?: number };
267
+ const invalidQueryFixture = JSON.parse(
268
+ readFixture("query-input.invalid-cache-status.v1.json"),
269
+ ) as { schemaVersion?: number };
270
+
271
+ expect(cacheFixture.schemaVersion).toBe(1);
272
+ expect(realtimeFixture.schemaVersion).toBe(1);
273
+ expect(queryFixture.schemaVersion).toBe(1);
274
+ expect(guardrailsFixture.schemaVersion).toBe(1);
275
+ expect(invalidCacheFixture.schemaVersion).toBe(1);
276
+ expect(invalidRealtimeFixture.schemaVersion).toBe(1);
277
+ expect(invalidQueryFixture.schemaVersion).toBe(1);
278
+ });
279
+
280
+ it("uses schemaVersion 2 for unsupported-version analyze fixtures", () => {
281
+ const cacheFixture = JSON.parse(readFixture("cache-input.unsupported-version.v2.json")) as {
282
+ schemaVersion?: number;
283
+ };
284
+ const realtimeFixture = JSON.parse(readFixture("realtime-input.unsupported-version.v2.json")) as {
285
+ schemaVersion?: number;
286
+ };
287
+ const queryFixture = JSON.parse(readFixture("query-input.unsupported-version.v2.json")) as {
288
+ schemaVersion?: number;
289
+ };
290
+ const guardrailsFixture = JSON.parse(
291
+ readFixture("guardrails-input.unsupported-version.v2.json"),
292
+ ) as {
293
+ schemaVersion?: number;
294
+ };
295
+
296
+ expect(cacheFixture.schemaVersion).toBe(2);
297
+ expect(realtimeFixture.schemaVersion).toBe(2);
298
+ expect(queryFixture.schemaVersion).toBe(2);
299
+ expect(guardrailsFixture.schemaVersion).toBe(2);
300
+ });
301
+ });
@@ -0,0 +1,135 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ import { runAuroraCli } from "../src";
6
+
7
+ describe("aurora build", () => {
8
+ it("prints bootstrap output with node target defaults", () => {
9
+ const cwd = createTempWorkspace("aurora-build-default");
10
+ const result = runAuroraCli(["build"], { cwd });
11
+
12
+ expect(result.exitCode).toBe(0);
13
+ expect(result.stdout).toContain("aurora build bootstrap");
14
+ expect(result.stdout).toContain("target: node");
15
+ expect(result.stdout).toContain(`output_path: ${cwd}/.aurora/build/node/server.mjs`);
16
+ expect(result.stdout).toContain("analyze: disabled");
17
+ expect(result.stdout).toContain("security_headers: enabled");
18
+ expect(result.stdout).toContain("raw_sql_tagged_template: enforced");
19
+ expect(result.stdout).toContain("dependency_audit_status: skipped-no-lockfile");
20
+ });
21
+
22
+ it("supports explicit edge/static target selection and analyze toggle", () => {
23
+ const cwd = createTempWorkspace("aurora-build-targets");
24
+
25
+ const edgeResult = runAuroraCli(
26
+ ["build", "--target", "edge", "--analyze", "--skip-audit"],
27
+ { cwd },
28
+ );
29
+ const staticResult = runAuroraCli(
30
+ ["build", "--target", "static", "--audit-severity", "critical"],
31
+ { cwd },
32
+ );
33
+
34
+ expect(edgeResult.exitCode).toBe(0);
35
+ expect(edgeResult.stdout).toContain("target: edge");
36
+ expect(edgeResult.stdout).toContain(`output_path: ${cwd}/.aurora/build/edge/worker.mjs`);
37
+ expect(edgeResult.stdout).toContain("analyze: enabled");
38
+ expect(edgeResult.stdout).toContain("dependency_audit_gate: disabled");
39
+ expect(edgeResult.stdout).toContain("dependency_audit_status: skipped-disabled");
40
+
41
+ expect(staticResult.exitCode).toBe(0);
42
+ expect(staticResult.stdout).toContain("target: static");
43
+ expect(staticResult.stdout).toContain(`output_path: ${cwd}/.aurora/build/static`);
44
+ expect(staticResult.stdout).toContain("dependency_audit_threshold: critical");
45
+ });
46
+
47
+ it("returns an error for invalid build/audit option values", () => {
48
+ const cwd = createTempWorkspace("aurora-build-errors");
49
+
50
+ const missingTarget = runAuroraCli(["build", "--target"], { cwd });
51
+ const invalidTarget = runAuroraCli(["build", "--target", "bun"], { cwd });
52
+ const missingSeverity = runAuroraCli(["build", "--audit-severity"], { cwd });
53
+ const invalidSeverity = runAuroraCli(
54
+ ["build", "--audit-severity", "none"],
55
+ { cwd },
56
+ );
57
+ const missingReportPath = runAuroraCli(["build", "--audit-report"], { cwd });
58
+
59
+ expect(missingTarget.exitCode).toBe(2);
60
+ expect(missingTarget.stderr).toContain(
61
+ "aurora build: --target requires one of 'node', 'edge', or 'static'",
62
+ );
63
+
64
+ expect(invalidTarget.exitCode).toBe(2);
65
+ expect(invalidTarget.stderr).toContain(
66
+ "aurora build: invalid target 'bun'. Expected 'node', 'edge', or 'static'",
67
+ );
68
+
69
+ expect(missingSeverity.exitCode).toBe(2);
70
+ expect(missingSeverity.stderr).toContain(
71
+ "aurora build: --audit-severity requires one of 'low', 'moderate', 'high', or 'critical'",
72
+ );
73
+
74
+ expect(invalidSeverity.exitCode).toBe(2);
75
+ expect(invalidSeverity.stderr).toContain(
76
+ "aurora build: invalid audit severity 'none'. Expected 'low', 'moderate', 'high', or 'critical'",
77
+ );
78
+
79
+ expect(missingReportPath.exitCode).toBe(2);
80
+ expect(missingReportPath.stderr).toContain(
81
+ "aurora build: --audit-report requires a path",
82
+ );
83
+ });
84
+
85
+ it("returns an error for unknown build options", () => {
86
+ const cwd = createTempWorkspace("aurora-build-unknown-option");
87
+ const result = runAuroraCli(["build", "--unknown"], { cwd });
88
+
89
+ expect(result.exitCode).toBe(2);
90
+ expect(result.stderr).toContain("aurora build: unknown option '--unknown'");
91
+ });
92
+
93
+ it("fails when dependency audit report includes severity at/above threshold", () => {
94
+ const cwd = createTempWorkspace("aurora-build-audit-fail");
95
+ writeFileSync(join(cwd, "package-lock.json"), "{}", "utf8");
96
+ mkdirSync(join(cwd, ".aurora", "security"), { recursive: true });
97
+ writeFileSync(
98
+ join(cwd, ".aurora", "security", "dependency-audit.json"),
99
+ JSON.stringify(
100
+ {
101
+ vulnerabilities: [
102
+ {
103
+ package: "left-pad",
104
+ severity: "high",
105
+ advisory: "CVE-TEST-0001",
106
+ },
107
+ ],
108
+ },
109
+ null,
110
+ 2,
111
+ ),
112
+ "utf8",
113
+ );
114
+
115
+ const failed = runAuroraCli(["build"], { cwd });
116
+ const passed = runAuroraCli(["build", "--audit-severity", "critical"], { cwd });
117
+
118
+ expect(failed.exitCode).toBe(1);
119
+ expect(failed.stderr).toContain(
120
+ "aurora build: dependency audit failed for severity >= 'high'",
121
+ );
122
+
123
+ expect(passed.exitCode).toBe(0);
124
+ expect(passed.stdout).toContain("dependency_audit_status: passed");
125
+ expect(passed.stdout).toContain("dependency_lockfile:");
126
+ expect(passed.stdout).toContain("dependency_audit_report:");
127
+ });
128
+ });
129
+
130
+ function createTempWorkspace(prefix: string): string {
131
+ const unique = `${prefix}-${Date.now()}-${Math.floor(Math.random() * 1_000_000)}`;
132
+ const cwd = join("/tmp", unique);
133
+ mkdirSync(cwd, { recursive: true });
134
+ return cwd;
135
+ }
@@ -0,0 +1,145 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import { describe, expect, it } from "bun:test";
5
+
6
+ import { runAuroraCli } from "../src";
7
+
8
+ let tempCounter = 1;
9
+
10
+ function uniqueTempPath(suffix: string): string {
11
+ tempCounter += 1;
12
+ return `/tmp/aurora-cli-create-feature-${suffix}-${Date.now()}-${tempCounter}`;
13
+ }
14
+
15
+ describe("aurora create-feature", () => {
16
+ it("scaffolds a feature folder from feature skeleton template", () => {
17
+ const cwd = uniqueTempPath("basic");
18
+ mkdirSync(cwd, { recursive: true });
19
+
20
+ const result = runAuroraCli(["create-feature", "audit-log"], { cwd });
21
+ const featureRoot = join(cwd, "src/features/audit-log");
22
+
23
+ expect(result.exitCode).toBe(0);
24
+ expect(result.stdout).toContain("aurora create-feature bootstrap");
25
+ expect(result.stdout).toContain("feature_slug: audit-log");
26
+ expect(result.stdout).toContain("feature_name: AuditLog");
27
+ expect(result.stdout).toContain("route_scaffold: enabled");
28
+ expect(result.stdout).toContain("route_kind: form");
29
+ expect(result.stdout).toContain("route_data_source: database");
30
+ expect(result.stdout).toContain("route_auth: public");
31
+ expect(result.stdout).toContain("route_realtime: disabled");
32
+
33
+ expect(existsSync(join(featureRoot, "ui/FeatureView.client.tsx"))).toBe(true);
34
+ expect(existsSync(join(featureRoot, "queries/listFeature.server.ts"))).toBe(true);
35
+ expect(existsSync(join(featureRoot, "actions/createFeature.action.server.ts"))).toBe(true);
36
+ expect(existsSync(join(featureRoot, "realtime/useFeatureRealtime.client.ts"))).toBe(true);
37
+ expect(existsSync(join(cwd, "src/routes/audit-log/page.tsx"))).toBe(true);
38
+ expect(existsSync(join(cwd, "src/routes/audit-log/audit-log.server.ts"))).toBe(true);
39
+ expect(existsSync(join(cwd, "src/routes/audit-log/audit-log.client.tsx"))).toBe(true);
40
+
41
+ const uiSource = readFileSync(join(featureRoot, "ui/FeatureView.client.tsx"), "utf8");
42
+ expect(uiSource).toContain("AuditLog");
43
+ expect(uiSource).toContain("audit-log");
44
+ });
45
+
46
+ it("normalizes non-kebab feature names to slug and pascal name", () => {
47
+ const cwd = uniqueTempPath("normalize");
48
+ mkdirSync(cwd, { recursive: true });
49
+
50
+ const result = runAuroraCli(["create-feature", "user_profile"], { cwd });
51
+ const featureRoot = join(cwd, "src/features/user-profile");
52
+
53
+ expect(result.exitCode).toBe(0);
54
+ expect(result.stdout).toContain("feature_slug: user-profile");
55
+ expect(result.stdout).toContain("feature_name: UserProfile");
56
+ expect(existsSync(featureRoot)).toBe(true);
57
+ expect(existsSync(join(cwd, "src/routes/user-profile/page.tsx"))).toBe(true);
58
+ });
59
+
60
+ it("supports disabling paired route scaffolding", () => {
61
+ const cwd = uniqueTempPath("no-route");
62
+ mkdirSync(cwd, { recursive: true });
63
+
64
+ const result = runAuroraCli(["create-feature", "notifications", "--no-route"], { cwd });
65
+
66
+ expect(result.exitCode).toBe(0);
67
+ expect(result.stdout).toContain("route_scaffold: disabled");
68
+ expect(existsSync(join(cwd, "src/features/notifications"))).toBe(true);
69
+ expect(existsSync(join(cwd, "src/routes/notifications"))).toBe(false);
70
+ });
71
+
72
+ it("supports route scaffold option overrides", () => {
73
+ const cwd = uniqueTempPath("route-overrides");
74
+ mkdirSync(cwd, { recursive: true });
75
+
76
+ const result = runAuroraCli(
77
+ [
78
+ "create-feature",
79
+ "alerts",
80
+ "--kind",
81
+ "dashboard",
82
+ "--data",
83
+ "api",
84
+ "--auth",
85
+ "user",
86
+ "--realtime",
87
+ ],
88
+ { cwd },
89
+ );
90
+
91
+ const routeServer = join(cwd, "src/routes/alerts/alerts.server.ts");
92
+
93
+ expect(result.exitCode).toBe(0);
94
+ expect(result.stdout).toContain("route_kind: dashboard");
95
+ expect(result.stdout).toContain("route_data_source: api");
96
+ expect(result.stdout).toContain("route_auth: user");
97
+ expect(result.stdout).toContain("route_realtime: enabled");
98
+ expect(readFileSync(routeServer, "utf8")).toContain("AlertsRealtimeChannel");
99
+ });
100
+
101
+ it("returns an error when feature name is missing", () => {
102
+ const cwd = uniqueTempPath("missing");
103
+ mkdirSync(cwd, { recursive: true });
104
+
105
+ const result = runAuroraCli(["create-feature"], { cwd });
106
+
107
+ expect(result.exitCode).toBe(2);
108
+ expect(result.stderr).toContain("aurora create-feature: feature name is required");
109
+ });
110
+
111
+ it("returns an error for unknown options", () => {
112
+ const cwd = uniqueTempPath("unknown-option");
113
+ mkdirSync(cwd, { recursive: true });
114
+
115
+ const result = runAuroraCli(["create-feature", "billing", "--dry-run"], { cwd });
116
+
117
+ expect(result.exitCode).toBe(2);
118
+ expect(result.stderr).toContain("aurora create-feature: unknown option '--dry-run'");
119
+ });
120
+
121
+ it("returns an error when feature directory already exists and is not empty", () => {
122
+ const cwd = uniqueTempPath("exists");
123
+ const featureRoot = join(cwd, "src/features/chat");
124
+ mkdirSync(featureRoot, { recursive: true });
125
+ writeFileSync(join(featureRoot, "seed.txt"), "seed\n", "utf8");
126
+
127
+ const result = runAuroraCli(["create-feature", "chat"], { cwd });
128
+
129
+ expect(result.exitCode).toBe(2);
130
+ expect(result.stderr).toContain("target directory already exists and is not empty");
131
+ });
132
+
133
+ it("returns an error when paired route directory already exists and is not empty", () => {
134
+ const cwd = uniqueTempPath("route-exists");
135
+ const routeRoot = join(cwd, "src/routes/billing");
136
+ mkdirSync(routeRoot, { recursive: true });
137
+ writeFileSync(join(routeRoot, "seed.txt"), "seed\n", "utf8");
138
+
139
+ const result = runAuroraCli(["create-feature", "billing"], { cwd });
140
+
141
+ expect(result.exitCode).toBe(2);
142
+ expect(result.stderr).toContain("target directory already exists and is not empty");
143
+ expect(result.stderr).toContain(routeRoot);
144
+ });
145
+ });