@cosmicdrift/kumiko-dev-server 0.328.1 → 0.330.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.
Files changed (125) hide show
  1. package/README.md +17 -0
  2. package/bin/kumiko-build.ts +3 -2
  3. package/bin/kumiko-dev.ts +1 -1
  4. package/bin/kumiko-init-deploy.ts +1 -1
  5. package/bin/kumiko-schema-check.ts +4 -1
  6. package/dist/build-server-bundle.d.ts +31 -0
  7. package/dist/build-server-bundle.js +282 -0
  8. package/dist/build.d.ts +2 -0
  9. package/dist/build.js +5 -0
  10. package/dist/cli.d.ts +5 -0
  11. package/dist/cli.js +9 -0
  12. package/dist/codegen/index.d.ts +4 -0
  13. package/dist/codegen/index.js +4 -0
  14. package/dist/codegen/render.d.ts +55 -0
  15. package/dist/codegen/render.js +273 -0
  16. package/dist/codegen/run-codegen.d.ts +20 -0
  17. package/dist/codegen/run-codegen.js +219 -0
  18. package/dist/codegen/scan-events.d.ts +76 -0
  19. package/dist/codegen/scan-events.js +447 -0
  20. package/dist/codegen/watch.d.ts +33 -0
  21. package/dist/codegen/watch.js +112 -0
  22. package/dist/compose-stacks.d.ts +60 -0
  23. package/dist/compose-stacks.js +127 -0
  24. package/dist/crash-tracker.d.ts +17 -0
  25. package/dist/crash-tracker.js +37 -0
  26. package/dist/create-kumiko-server.d.ts +195 -0
  27. package/dist/create-kumiko-server.js +1040 -0
  28. package/dist/env-schema.d.ts +15 -0
  29. package/dist/env-schema.js +60 -0
  30. package/dist/few-shot-corpus.d.ts +72 -0
  31. package/dist/few-shot-corpus.js +262 -0
  32. package/dist/framework-version.d.ts +1 -0
  33. package/dist/framework-version.js +31 -0
  34. package/dist/index.d.ts +22 -0
  35. package/dist/index.js +33 -0
  36. package/dist/init-deploy-cli.d.ts +10 -0
  37. package/dist/init-deploy-cli.js +111 -0
  38. package/dist/kebab.d.ts +1 -0
  39. package/{src/kebab.ts → dist/kebab.js} +2 -3
  40. package/dist/run-dev-app.d.ts +174 -0
  41. package/dist/run-dev-app.js +403 -0
  42. package/dist/scaffold-app-feature.d.ts +16 -0
  43. package/dist/scaffold-app-feature.js +240 -0
  44. package/dist/scaffold-app.d.ts +45 -0
  45. package/dist/scaffold-app.js +852 -0
  46. package/dist/scaffold-demo-tasks.d.ts +8 -0
  47. package/{src/scaffold-demo-tasks.ts → dist/scaffold-demo-tasks.js} +69 -98
  48. package/dist/scaffold-deploy.d.ts +92 -0
  49. package/dist/scaffold-deploy.js +254 -0
  50. package/dist/scaffold-feature.d.ts +26 -0
  51. package/dist/scaffold-feature.js +163 -0
  52. package/dist/schema-apply.d.ts +11 -0
  53. package/dist/schema-apply.js +95 -0
  54. package/dist/schema-check-core.d.ts +2 -0
  55. package/{src/schema-check-core.ts → dist/schema-check-core.js} +8 -10
  56. package/dist/schema-tables-auth-mode.d.ts +2 -0
  57. package/{src/schema-tables-auth-mode.ts → dist/schema-tables-auth-mode.js} +2 -10
  58. package/dist/schema-tables-minimal.d.ts +2 -0
  59. package/{src/schema-tables-minimal.ts → dist/schema-tables-minimal.js} +2 -11
  60. package/dist/setup-test-stack-from-features.d.ts +11 -0
  61. package/dist/setup-test-stack-from-features.js +42 -0
  62. package/dist/welcome-banner.d.ts +15 -0
  63. package/dist/welcome-banner.js +27 -0
  64. package/package.json +71 -24
  65. package/src/changes.json +6 -0
  66. package/src/__tests__/build-prod-bundle.integration.test.ts +0 -282
  67. package/src/__tests__/build-server-bundle.test.ts +0 -228
  68. package/src/__tests__/classify-change.test.ts +0 -87
  69. package/src/__tests__/compose-stacks.test.ts +0 -273
  70. package/src/__tests__/config-resolver-default.integration.test.ts +0 -165
  71. package/src/__tests__/crash-tracker.test.ts +0 -89
  72. package/src/__tests__/create-kumiko-server-errors.test.ts +0 -54
  73. package/src/__tests__/create-kumiko-server-options.test.ts +0 -33
  74. package/src/__tests__/create-kumiko-server.integration.test.ts +0 -1007
  75. package/src/__tests__/discover-format.test.ts +0 -32
  76. package/src/__tests__/env-schema.integration.test.ts +0 -248
  77. package/src/__tests__/env-schema.test.ts +0 -132
  78. package/src/__tests__/few-shot-corpus.test.ts +0 -316
  79. package/src/__tests__/framework-version.test.ts +0 -45
  80. package/src/__tests__/init-deploy-cli.test.ts +0 -113
  81. package/src/__tests__/kumiko-schema-check.test.ts +0 -56
  82. package/src/__tests__/merge-extra-context.test.ts +0 -67
  83. package/src/__tests__/resolve-stylesheet.test.ts +0 -132
  84. package/src/__tests__/run-dev-app-boot-validation.test.ts +0 -38
  85. package/src/__tests__/run-dev-app.integration.test.ts +0 -290
  86. package/src/__tests__/runtime-classification.test.ts +0 -26
  87. package/src/__tests__/saas-identity-wire.integration.test.ts +0 -427
  88. package/src/__tests__/scaffold-app-feature.test.ts +0 -216
  89. package/src/__tests__/scaffold-app.test.ts +0 -630
  90. package/src/__tests__/scaffold-demo-tasks.test.ts +0 -47
  91. package/src/__tests__/scaffold-deploy.test.ts +0 -464
  92. package/src/__tests__/scaffold-dev-cycle.integration.test.ts +0 -109
  93. package/src/__tests__/scaffold-feature.test.ts +0 -143
  94. package/src/__tests__/schema-apply.integration.test.ts +0 -191
  95. package/src/__tests__/setup-test-stack-from-features.integration.test.ts +0 -30
  96. package/src/__tests__/setup-test-stack-job-run-logger.integration.test.ts +0 -72
  97. package/src/__tests__/walkthrough.integration.test.ts +0 -140
  98. package/src/__tests__/welcome-banner.test.ts +0 -42
  99. package/src/build-server-bundle.ts +0 -346
  100. package/src/build.ts +0 -28
  101. package/src/codegen/__tests__/render-codegen.test.ts +0 -100
  102. package/src/codegen/__tests__/run-codegen.test.ts +0 -665
  103. package/src/codegen/__tests__/strict-mode-diagnostics.test.ts +0 -347
  104. package/src/codegen/__tests__/watch.test.ts +0 -222
  105. package/src/codegen/index.ts +0 -19
  106. package/src/codegen/render.ts +0 -305
  107. package/src/codegen/run-codegen.ts +0 -278
  108. package/src/codegen/scan-events.ts +0 -565
  109. package/src/codegen/watch.ts +0 -140
  110. package/src/compose-stacks.ts +0 -193
  111. package/src/crash-tracker.ts +0 -56
  112. package/src/create-kumiko-server.ts +0 -1397
  113. package/src/env-schema.ts +0 -72
  114. package/src/few-shot-corpus.ts +0 -370
  115. package/src/framework-version.ts +0 -39
  116. package/src/index.ts +0 -105
  117. package/src/init-deploy-cli.ts +0 -148
  118. package/src/run-dev-app.ts +0 -694
  119. package/src/scaffold-app-feature.ts +0 -283
  120. package/src/scaffold-app.ts +0 -1033
  121. package/src/scaffold-deploy.ts +0 -393
  122. package/src/scaffold-feature.ts +0 -226
  123. package/src/schema-apply.ts +0 -123
  124. package/src/setup-test-stack-from-features.ts +0 -80
  125. package/src/welcome-banner.ts +0 -43
package/src/env-schema.ts DELETED
@@ -1,72 +0,0 @@
1
- // @runtime runtime
2
- // Consumed at prod boot via composeEnvSchema (same as compose-stacks),
3
- // not only by tooling — keep runtime-isolation-safe (kumiko-framework#2340).
4
- //
5
- // Framework-core env-schema — the vars that runProdApp + buildServer
6
- // + the connection-pool read directly from process.env today. Apps merge
7
- // this into their app-wide schema via `composeEnvSchema({ core, ... })`.
8
- //
9
- // Sprint 9.2 is purely additive: the schema is exposed, but the call-sites
10
- // in run-prod-app.ts (requireEnv("DATABASE_URL"), …) and api/server.ts
11
- // (process.env["KUMIKO_INSTANCE_ID"]) keep reading process.env directly.
12
- // Apps that opt into the schema get aggregated boot-validation errors
13
- // BEFORE those legacy reads run; apps that don't, behave as before.
14
- //
15
- // Feature-specific vars (JWT_SECRET, KUMIKO_SECRETS_MASTER_KEY_*) live
16
- // in their owning feature's envSchema — Phase 2 (bundled-features).
17
-
18
- import * as z from "zod";
19
-
20
- /** Env-vars read by framework-core (api/server, db/connection,
21
- * dev-server/run-prod-app). NOT including feature-specific vars.
22
- *
23
- * PORT-default "3000" is the same fallback as
24
- * `packages/dev-server/src/run-prod-app.ts:533` — keep in sync when the
25
- * call-site is refactored to consume parsed env (Sprint 9.5 Phase 4). */
26
- export const frameworkCoreEnvSchema = z.object({
27
- PORT: z
28
- .string()
29
- .regex(/^\d+$/, "PORT must be a positive integer string")
30
- .default("3000")
31
- .describe("HTTP listen port. runProdApp defaults to 3000 when unset."),
32
-
33
- DATABASE_URL: z
34
- // `protocol` is matched against the URL scheme without the trailing
35
- // colon — `postgres://`/`postgresql://` pass, `https://`/`ftp://` are
36
- // rejected so the error message's promise actually holds at boot.
37
- .url({ protocol: /^postgres(ql)?$/, error: "DATABASE_URL must be a valid postgres:// URL" })
38
- .describe("Primary Postgres connection string (write + read).")
39
- .meta({ kumiko: { pulumi: { secret: true } } }),
40
-
41
- REDIS_URL: z
42
- // `redis://` + the TLS variant `rediss://` pass; other schemes reject.
43
- .url({ protocol: /^rediss?$/, error: "REDIS_URL must be a valid redis:// URL" })
44
- .describe("Redis connection string for SSE-broker + job-queues.")
45
- .meta({ kumiko: { pulumi: { secret: true } } }),
46
-
47
- KUMIKO_INSTANCE_ID: z
48
- .string()
49
- .min(1)
50
- .optional()
51
- .describe(
52
- "Stable per-process identifier (pod name, hostname). " +
53
- "Multi-instance deploys SHOULD set this so per-instance consumers " +
54
- "(SSE) don't accumulate orphaned cursor-rows on restart.",
55
- ),
56
-
57
- // `z.string().optional()` (not `z.literal("1")`) — the run-prod-app
58
- // call-site (`envSource["KUMIKO_SKIP_ES_OPS"] !== "1"`) ignores any
59
- // value other than literal "1". A stricter schema would reject e.g.
60
- // "true" / "yes" that the runtime silently ignores, surfacing
61
- // boot-errors for inputs the framework doesn't actually care about.
62
- KUMIKO_SKIP_ES_OPS: z
63
- .string()
64
- .optional()
65
- .describe(
66
- "Set to '1' to skip event-store ops (seed/migrate) at boot. " +
67
- "Any other value is treated as 'not set' by run-prod-app. " +
68
- "Used by integration-test stacks that manage ES-ops out-of-band.",
69
- ),
70
- });
71
-
72
- export type FrameworkCoreEnv = z.infer<typeof frameworkCoreEnvSchema>;
@@ -1,370 +0,0 @@
1
- // buildFewShotCorpus — extracts feature-files from the repo into a
2
- // structured JSON corpus that L2 (Prompt-Pipeline) feeds into the LLM
3
- // at generation time. One entry per feature-file, four data sources
4
- // per entry: raw source text, package.json description, parsed
5
- // FeaturePattern[], plus pattern-categories from the C4 library.
6
- //
7
- // **Why a checked-in JSON file (docs/few-shot-corpus.json):**
8
- // - Offline-consumable: AI-Builder can prompt without re-parsing
9
- // 30+ feature files at request time.
10
- // - Diff-reviewable: when a feature changes, the corpus diff shows
11
- // up in the PR — humans see how the example surface shifted.
12
- // - Portable: the corpus is a flat JSON, can ship to a hosted LLM
13
- // service / fine-tuning pipeline / customer environment without
14
- // dragging the framework's parser along.
15
- //
16
- // **Authoring-Style classification:**
17
- // - `canonical` → 0 ParseErrors. The example is "do it like this"
18
- // for the LLM.
19
- // - `legacy` → has ParseErrors. The example shows what code looks
20
- // like in the wild (Factory-style, identifier-refs) and is useful
21
- // for understanding intent — but the LLM should NOT replicate
22
- // this style. L2 marks legacy entries as "do not generate".
23
- //
24
- // **Why the corpus includes legacy entries but the Designer does not:**
25
- // The two consumers want different slices of the same data. L2 needs
26
- // counter-examples (showing the LLM what *not* to emit raises the
27
- // chance of clean output), so legacy entries are kept and tagged.
28
- // The Designer can only round-trip canonical-form patterns through
29
- // the AST-Patcher — legacy entries would render as read-only with
30
- // no edit affordance, which is worse than hiding them. So the corpus
31
- // builder is permissive, and the Designer filters at read-time.
32
-
33
- import { existsSync, readdirSync, readFileSync } from "node:fs";
34
- import { dirname, join, relative, resolve } from "node:path";
35
- import {
36
- type FeaturePattern,
37
- type FeaturePatternKind,
38
- PATTERN_LIBRARY,
39
- type ParseError,
40
- parseFeatureFile,
41
- } from "@cosmicdrift/kumiko-framework/engine";
42
-
43
- // =============================================================================
44
- // Public types
45
- // =============================================================================
46
-
47
- export type AuthoringStyle = "canonical" | "legacy";
48
-
49
- export type CorpusWarning = {
50
- /** Repo-relative path to the file that triggered the warning. */
51
- readonly sourcePath: string;
52
- /** Human-readable explanation. Currently only "parser-throw" but
53
- * kept open-ended so future builders can add more (e.g.
54
- * "duplicate-id", "no-feature-name"). */
55
- readonly message: string;
56
- };
57
-
58
- export type FewShotEntry = {
59
- /** Stable id derived from the path (`samples/recipes/basic-entity`). */
60
- readonly id: string;
61
- /** Repo-relative path to the feature-file. */
62
- readonly sourcePath: string;
63
- /** Repo-relative path to the workspace package.json (for description lookup). */
64
- readonly packageJsonPath: string | undefined;
65
- /** Workspace name (`@cosmicdrift/kumiko-sample-basic-entity`). */
66
- readonly packageName: string | undefined;
67
- /** English description from package.json. */
68
- readonly description: string | undefined;
69
- /** Feature name from `defineFeature("...", ...)`. Undefined if the
70
- * parser couldn't read it (rare — implies a non-feature file got
71
- * picked up). */
72
- readonly featureName: string | undefined;
73
- /** Pattern-categories present in this feature, deduplicated. Useful
74
- * as topic-tags for retrieval ("show me cross-cutting examples"). */
75
- readonly tags: readonly string[];
76
- /** Counts per pattern-kind — quick stats without scanning the
77
- * patterns array. */
78
- readonly patternsByKind: Readonly<Record<string, number>>;
79
- /** All parsed patterns. Same shape the parser emits. */
80
- readonly patterns: readonly FeaturePattern[];
81
- /** Errors the parser raised. Empty for canonical-form features. */
82
- readonly parseErrors: readonly ParseError[];
83
- /** `canonical` (clean parse) or `legacy` (parser couldn't read it
84
- * fully — Factory-style / identifier-refs). */
85
- readonly authoringStyle: AuthoringStyle;
86
- /** Raw source text — kept verbatim so the LLM can train on the
87
- * exact byte-form, including comments + whitespace. */
88
- readonly rawSource: string;
89
- };
90
-
91
- export type FewShotCorpus = {
92
- /** ISO-instant when the corpus was generated. */
93
- readonly generatedAt: string;
94
- /** Total entry count, broken down by authoringStyle for quick stats. */
95
- readonly totals: {
96
- readonly all: number;
97
- readonly canonical: number;
98
- readonly legacy: number;
99
- };
100
- readonly entries: readonly FewShotEntry[];
101
- /** Files that were discovered but couldn't be turned into entries.
102
- * Surfaces parser crashes + duplicate-id collisions instead of
103
- * swallowing them — the regenerate-script reports these to the user
104
- * and the drift-test asserts the count stays constant. */
105
- readonly warnings: readonly CorpusWarning[];
106
- };
107
-
108
- export type BuildFewShotCorpusOptions = {
109
- /** Repo root — used for relative-path output and security guards. */
110
- readonly repoRoot: string;
111
- /** Folders to scan recursively. Defaults to samples/* + bundled-features. */
112
- readonly scanRoots?: readonly string[];
113
- };
114
-
115
- // =============================================================================
116
- // Builder
117
- // =============================================================================
118
-
119
- const FEATURE_FILE_PATTERN = /(?:^|\/)(feature|.*\.feature)\.ts$/;
120
-
121
- const DEFAULT_SCAN_ROOTS: readonly string[] = [
122
- "samples/recipes",
123
- "samples/apps",
124
- "samples/showcases",
125
- "packages/bundled-features/src",
126
- ];
127
-
128
- // Static timestamp keeps the JSON output deterministic across CI runs —
129
- // the regenerate-script could overwrite this with a real timestamp,
130
- // but drift-tests compare structural data, not timestamps. Centralized
131
- // here so the build path and any future inspector use the same value.
132
- const STATIC_GENERATED_AT = "1970-01-01T00:00:00Z";
133
-
134
- export function buildFewShotCorpus(options: BuildFewShotCorpusOptions): FewShotCorpus {
135
- const repoRoot = resolve(options.repoRoot);
136
- const scanRoots = (options.scanRoots ?? DEFAULT_SCAN_ROOTS).map((r) => resolve(repoRoot, r));
137
-
138
- const featureFiles: string[] = [];
139
- for (const root of scanRoots) {
140
- if (!existsSync(root)) continue;
141
- walkDir(root, featureFiles);
142
- }
143
- featureFiles.sort();
144
-
145
- const entries: FewShotEntry[] = [];
146
- const warnings: CorpusWarning[] = [];
147
- const seenIds = new Map<string, string>();
148
-
149
- for (const filePath of featureFiles) {
150
- const result = buildEntry(filePath, repoRoot);
151
- if (result.warning) {
152
- warnings.push(result.warning);
153
- continue;
154
- }
155
- const entry = result.entry;
156
- const previousPath = seenIds.get(entry.id);
157
- if (previousPath) {
158
- // Two feature-files mapped to the same id. The corpus uses ids
159
- // for retrieval — duplicates would silently overwrite each other
160
- // in any consumer that built a Map<id, entry>. Surface as a
161
- // warning, drop the second occurrence.
162
- warnings.push({
163
- sourcePath: entry.sourcePath,
164
- message: `duplicate-id: collides with ${previousPath}`,
165
- });
166
- continue;
167
- }
168
- seenIds.set(entry.id, entry.sourcePath);
169
- entries.push(entry);
170
- }
171
-
172
- const canonical = entries.filter((e) => e.authoringStyle === "canonical").length;
173
- return {
174
- generatedAt: STATIC_GENERATED_AT,
175
- totals: {
176
- all: entries.length,
177
- canonical,
178
- legacy: entries.length - canonical,
179
- },
180
- entries,
181
- warnings,
182
- };
183
- }
184
-
185
- type BuildEntryResult =
186
- | { readonly entry: FewShotEntry; readonly warning?: never }
187
- | { readonly entry?: never; readonly warning: CorpusWarning };
188
-
189
- function buildEntry(filePath: string, repoRoot: string): BuildEntryResult {
190
- const sourcePath = relative(repoRoot, filePath);
191
-
192
- let parsed: ReturnType<typeof parseFeatureFile>;
193
- try {
194
- parsed = parseFeatureFile(filePath);
195
- } catch (err) {
196
- // ts-morph couldn't read the file (syntax-error, IO problem, weird
197
- // encoding). Skip the entry but record *why* — silent skip used to
198
- // hide newly broken feature-files until L2 hit them.
199
- const detail = err instanceof Error ? err.message : String(err);
200
- return {
201
- warning: { sourcePath, message: `parser-throw: ${detail}` },
202
- };
203
- }
204
-
205
- const rawSource = readFileSync(filePath, "utf8");
206
- const id = pathToId(sourcePath);
207
-
208
- const pkgInfo = findPackageJson(filePath, repoRoot);
209
-
210
- const tags = collectTags(parsed.patterns);
211
- const patternsByKind = countPatternsByKind(parsed.patterns);
212
-
213
- const authoringStyle: AuthoringStyle = parsed.errors.length === 0 ? "canonical" : "legacy";
214
-
215
- // SourceLocation.file is an absolute path coming out of the parser —
216
- // strip it to repo-relative so the corpus diff stays stable across
217
- // machines / CI runners. Same for ParseError.source.file.
218
- const patterns = parsed.patterns.map((p) => relativizeSources(p, repoRoot) as FeaturePattern);
219
- const parseErrors = parsed.errors.map((e) => ({
220
- ...e,
221
- source: { ...e.source, file: relative(repoRoot, e.source.file) },
222
- }));
223
-
224
- return {
225
- entry: {
226
- id,
227
- sourcePath,
228
- packageJsonPath: pkgInfo?.relPath,
229
- packageName: pkgInfo?.name,
230
- description: pkgInfo?.description,
231
- featureName: parsed.featureName,
232
- tags,
233
- patternsByKind,
234
- patterns,
235
- parseErrors,
236
- authoringStyle,
237
- rawSource,
238
- },
239
- };
240
- }
241
-
242
- /**
243
- * Recursively walk a value and rewrite every nested SourceLocation's
244
- * `file` field to be repo-relative. Identifies SourceLocation by
245
- * structural shape (`{ file, start, end, raw }`) rather than by
246
- * type-tag — the parsed objects are plain JSON-ish at this point and
247
- * a discriminator would complicate the renderer.
248
- *
249
- * Typed `unknown → unknown` so the walker stays honest about what it
250
- * sees. The single boundary cast lives at the call site
251
- * (`as FeaturePattern`) where the input contract is known.
252
- */
253
- function relativizeSources(value: unknown, repoRoot: string): unknown {
254
- if (Array.isArray(value)) {
255
- return value.map((v) => relativizeSources(v, repoRoot));
256
- }
257
- if (value && typeof value === "object") {
258
- const obj = value as Record<string, unknown>;
259
- if (
260
- typeof obj["file"] === "string" &&
261
- typeof obj["raw"] === "string" &&
262
- typeof obj["start"] === "object" &&
263
- typeof obj["end"] === "object"
264
- ) {
265
- return { ...obj, file: relative(repoRoot, obj["file"]) };
266
- }
267
- const out: Record<string, unknown> = {};
268
- for (const [k, v] of Object.entries(obj)) {
269
- out[k] = relativizeSources(v, repoRoot);
270
- }
271
- return out;
272
- }
273
- return value;
274
- }
275
-
276
- // =============================================================================
277
- // Helpers
278
- // =============================================================================
279
-
280
- /**
281
- * Stable id from the source path. Drops the leading `samples/` or
282
- * `packages/` prefix and the trailing `/src/feature.ts` suffix so the
283
- * id reads like the canonical short name (`basic-entity`,
284
- * `bundled-features/auth-email-password`).
285
- */
286
- export function pathToId(sourcePath: string): string {
287
- return sourcePath
288
- .replace(/^(samples|packages)\//, "")
289
- .replace(/\/src\/feature\.ts$/, "")
290
- .replace(/\/feature\.ts$/, "");
291
- }
292
-
293
- function walkDir(dir: string, acc: string[]): void {
294
- let entries: { name: string; isDirectory: () => boolean; isFile: () => boolean }[];
295
- try {
296
- entries = readdirSync(dir, { withFileTypes: true });
297
- } catch {
298
- // skip: directory missing/unreadable, nothing to walk
299
- return;
300
- }
301
- for (const entry of entries) {
302
- const name = String(entry.name);
303
- const full = join(dir, name);
304
- if (entry.isDirectory()) {
305
- if (name === "node_modules" || name === "dist" || name === "dist-server") continue;
306
- if (name.startsWith(".")) continue;
307
- walkDir(full, acc);
308
- } else if (entry.isFile() && FEATURE_FILE_PATTERN.test(full)) {
309
- acc.push(full);
310
- }
311
- }
312
- }
313
-
314
- /**
315
- * Walk upward from `featureFile` to find the nearest `package.json` and
316
- * pluck name + description out of it. Stops at `repoRoot`.
317
- */
318
- function findPackageJson(
319
- featureFile: string,
320
- repoRoot: string,
321
- ): { relPath: string; name: string | undefined; description: string | undefined } | undefined {
322
- let dir = dirname(featureFile);
323
- const stopAt = resolve(repoRoot);
324
- while (true) {
325
- const candidate = join(dir, "package.json");
326
- if (existsSync(candidate)) {
327
- try {
328
- const pkg = JSON.parse(readFileSync(candidate, "utf8")) as {
329
- name?: unknown;
330
- description?: unknown;
331
- };
332
- return {
333
- relPath: relative(repoRoot, candidate),
334
- name: typeof pkg.name === "string" ? pkg.name : undefined,
335
- description: typeof pkg.description === "string" ? pkg.description : undefined,
336
- };
337
- } catch {
338
- // Malformed package.json — keep walking up.
339
- }
340
- }
341
- const parent = dirname(dir);
342
- if (parent === dir || dir === stopAt) return undefined;
343
- dir = parent;
344
- }
345
- }
346
-
347
- /**
348
- * Collect the union of pattern-categories present in the feature.
349
- * Categories come from the pattern-library — the same vocabulary the
350
- * Designer / AI-Builder uses for filtering ("show me background-jobs
351
- * examples").
352
- */
353
- function collectTags(patterns: readonly FeaturePattern[]): readonly string[] {
354
- const tags = new Set<string>();
355
- for (const p of patterns) {
356
- const schema = PATTERN_LIBRARY[p.kind as FeaturePatternKind];
357
- if (schema) tags.add(schema.category);
358
- }
359
- return [...tags].sort();
360
- }
361
-
362
- function countPatternsByKind(
363
- patterns: readonly FeaturePattern[],
364
- ): Readonly<Record<string, number>> {
365
- const counts: Record<string, number> = {};
366
- for (const p of patterns) {
367
- counts[p.kind] = (counts[p.kind] ?? 0) + 1;
368
- }
369
- return counts;
370
- }
@@ -1,39 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { dirname, join } from "node:path";
3
- import { parseJsonSafe } from "@cosmicdrift/kumiko-framework/utils";
4
-
5
- const DEV_SERVER_PACKAGE = "@cosmicdrift/kumiko-dev-server";
6
-
7
- interface DevServerManifest {
8
- readonly name: typeof DEV_SERVER_PACKAGE;
9
- readonly version: string;
10
- }
11
-
12
- function isDevServerManifest(value: unknown): value is DevServerManifest {
13
- return (
14
- typeof value === "object" &&
15
- value !== null &&
16
- "name" in value &&
17
- value.name === DEV_SERVER_PACKAGE &&
18
- "version" in value &&
19
- typeof value.version === "string" &&
20
- value.version !== ""
21
- );
22
- }
23
-
24
- // All @cosmicdrift packages release in lockstep (changesets fixed-group), so
25
- // the dev-server's own version is the framework version.
26
- export function resolveFrameworkVersion(startDir: string = import.meta.dir): string | undefined {
27
- let dir = startDir;
28
- while (true) {
29
- const candidate = join(dir, "package.json");
30
- if (existsSync(candidate)) {
31
- // A corrupt or foreign package.json on the way up must not abort the search.
32
- const manifest = parseJsonSafe<unknown>(readFileSync(candidate, "utf-8"), undefined);
33
- if (isDevServerManifest(manifest)) return `^${manifest.version}`;
34
- }
35
- const parent = dirname(dir);
36
- if (parent === dir) return undefined;
37
- dir = parent;
38
- }
39
- }
package/src/index.ts DELETED
@@ -1,105 +0,0 @@
1
- // Public API für den Kumiko-Dev-Server. Zwei Schichten:
2
- //
3
- // - createKumikoServer (low-level)
4
- // Bun.serve-Wrapper der Client-Bundle, /styles.css, AppSchema-
5
- // Injection, SSE-Reload und einen Auto-Mint-JWT-Modus liefert. Nimmt
6
- // features + clientEntry direkt an, kein Auth-Auto-Wiring. Wer
7
- // einen ungewöhnlichen Auth-Setup braucht (alternative Membership-
8
- // Query, eigener Rate-Limiter, custom Login-Routes) geht hier rein.
9
- //
10
- // - runDevApp (high-level)
11
- // Mischt die Standard-Features (config/user/tenant/auth-email-
12
- // password) automatisch dazu wenn `auth` gesetzt ist, wired die
13
- // Login-Routes + Error-Map, ruft seedAdminGuarded im onAfterSetup. Default
14
- // für Sample-Apps und Showcases — 5-10 Zeilen Bootstrap statt 50.
15
-
16
- export {
17
- type ComposeFeaturesOptions,
18
- composeFeatures,
19
- } from "@cosmicdrift/kumiko-server-runtime/compose-features";
20
- // Build-Toolchain (buildProdBundle, Bun.build, Tailwind-Pipeline, ts-morph) lebt
21
- // im Sub-Path-Export `@cosmicdrift/kumiko-dev-server/build`. Damit zieht der Main-Barrel
22
- // kein Bun-Toolchain-Bundle mehr in Production-Reads (z.B. wenn drizzle-kit
23
- // die App-Config unter Node lädt).
24
- export {
25
- type CodegenOptions,
26
- type CodegenResult,
27
- runCodegen,
28
- type ScannedEvent,
29
- type ScanWarning,
30
- scanEvents,
31
- } from "./codegen";
32
- export {
33
- composeFileStack,
34
- composeGdprStack,
35
- composeIdentityStack,
36
- composeMailStack,
37
- composeOpsStack,
38
- composePagesStack,
39
- composeRendererStack,
40
- composeUserDataRightsStack,
41
- type FileProviderKind,
42
- type FileStackOptions,
43
- type GdprStackOptions,
44
- type GdprStackOrder,
45
- type IdentityStackOptions,
46
- type MailStackOptions,
47
- type MailTransportKind,
48
- type OpsStackOptions,
49
- type PagesStackOptions,
50
- stackFeatureNames,
51
- type UserDataRightsStackOptions,
52
- } from "./compose-stacks";
53
- export {
54
- type CreateKumikoServerOptions,
55
- createKumikoServer,
56
- type KumikoServerHandle,
57
- PROD_BUNDLES_ENV,
58
- resolveStylesheet,
59
- STYLESHEET_WATCH_ENV,
60
- } from "./create-kumiko-server";
61
- export { type FrameworkCoreEnv, frameworkCoreEnvSchema } from "./env-schema";
62
- export type {
63
- AuthoringStyle,
64
- BuildFewShotCorpusOptions,
65
- CorpusWarning,
66
- FewShotCorpus,
67
- FewShotEntry,
68
- } from "./few-shot-corpus";
69
- export { buildFewShotCorpus, pathToId } from "./few-shot-corpus";
70
- export { resolveFrameworkVersion } from "./framework-version";
71
- export type { CliOutput, RunInitDeployCliOptions } from "./init-deploy-cli";
72
- export { runInitDeployCli } from "./init-deploy-cli";
73
- export type { RunDevAppAuthOptions, RunDevAppOptions, SeedFn } from "./run-dev-app";
74
- export { runDevApp } from "./run-dev-app";
75
- export type {
76
- ScaffoldAppOptions,
77
- ScaffoldAppResult,
78
- ScaffoldFeatureEntry,
79
- } from "./scaffold-app";
80
- export { scaffoldApp } from "./scaffold-app";
81
- export type {
82
- ScaffoldAppFeatureOptions,
83
- ScaffoldAppFeatureResult,
84
- } from "./scaffold-app-feature";
85
- export { runConfigPathForApp, scaffoldAppFeature } from "./scaffold-app-feature";
86
- export type {
87
- CheckDeployDriftResult,
88
- DeployDriftEntry,
89
- RenderDeployFilesOptions,
90
- RenderDeployFilesResult,
91
- RenderedDeployFile,
92
- ScaffoldDeployDetected,
93
- ScaffoldDeployOptions,
94
- ScaffoldDeployResult,
95
- ScaffoldedFile,
96
- } from "./scaffold-deploy";
97
- export { checkDeployDrift, renderDeployFiles, scaffoldDeploy } from "./scaffold-deploy";
98
- export type { ScaffoldFeatureOptions, ScaffoldFeatureResult } from "./scaffold-feature";
99
- export { scaffoldFeature } from "./scaffold-feature";
100
- export {
101
- type SetupTestStackFromFeaturesOptions,
102
- setupTestStackFromFeatures,
103
- type TestStackPreset,
104
- } from "./setup-test-stack-from-features";
105
- export { renderWelcomeBanner, type WelcomeBannerInput } from "./welcome-banner";