@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.
- package/README.md +17 -0
- package/bin/kumiko-build.ts +3 -2
- package/bin/kumiko-dev.ts +1 -1
- package/bin/kumiko-init-deploy.ts +1 -1
- package/bin/kumiko-schema-check.ts +4 -1
- package/dist/build-server-bundle.d.ts +31 -0
- package/dist/build-server-bundle.js +282 -0
- package/dist/build.d.ts +2 -0
- package/dist/build.js +5 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +9 -0
- package/dist/codegen/index.d.ts +4 -0
- package/dist/codegen/index.js +4 -0
- package/dist/codegen/render.d.ts +55 -0
- package/dist/codegen/render.js +273 -0
- package/dist/codegen/run-codegen.d.ts +20 -0
- package/dist/codegen/run-codegen.js +219 -0
- package/dist/codegen/scan-events.d.ts +76 -0
- package/dist/codegen/scan-events.js +447 -0
- package/dist/codegen/watch.d.ts +33 -0
- package/dist/codegen/watch.js +112 -0
- package/dist/compose-stacks.d.ts +60 -0
- package/dist/compose-stacks.js +127 -0
- package/dist/crash-tracker.d.ts +17 -0
- package/dist/crash-tracker.js +37 -0
- package/dist/create-kumiko-server.d.ts +195 -0
- package/dist/create-kumiko-server.js +1040 -0
- package/dist/env-schema.d.ts +15 -0
- package/dist/env-schema.js +60 -0
- package/dist/few-shot-corpus.d.ts +72 -0
- package/dist/few-shot-corpus.js +262 -0
- package/dist/framework-version.d.ts +1 -0
- package/dist/framework-version.js +31 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +33 -0
- package/dist/init-deploy-cli.d.ts +10 -0
- package/dist/init-deploy-cli.js +111 -0
- package/dist/kebab.d.ts +1 -0
- package/{src/kebab.ts → dist/kebab.js} +2 -3
- package/dist/run-dev-app.d.ts +174 -0
- package/dist/run-dev-app.js +403 -0
- package/dist/scaffold-app-feature.d.ts +16 -0
- package/dist/scaffold-app-feature.js +240 -0
- package/dist/scaffold-app.d.ts +45 -0
- package/dist/scaffold-app.js +852 -0
- package/dist/scaffold-demo-tasks.d.ts +8 -0
- package/{src/scaffold-demo-tasks.ts → dist/scaffold-demo-tasks.js} +69 -98
- package/dist/scaffold-deploy.d.ts +92 -0
- package/dist/scaffold-deploy.js +254 -0
- package/dist/scaffold-feature.d.ts +26 -0
- package/dist/scaffold-feature.js +163 -0
- package/dist/schema-apply.d.ts +11 -0
- package/dist/schema-apply.js +95 -0
- package/dist/schema-check-core.d.ts +2 -0
- package/{src/schema-check-core.ts → dist/schema-check-core.js} +8 -10
- package/dist/schema-tables-auth-mode.d.ts +2 -0
- package/{src/schema-tables-auth-mode.ts → dist/schema-tables-auth-mode.js} +2 -10
- package/dist/schema-tables-minimal.d.ts +2 -0
- package/{src/schema-tables-minimal.ts → dist/schema-tables-minimal.js} +2 -11
- package/dist/setup-test-stack-from-features.d.ts +11 -0
- package/dist/setup-test-stack-from-features.js +42 -0
- package/dist/welcome-banner.d.ts +15 -0
- package/dist/welcome-banner.js +27 -0
- package/package.json +71 -24
- package/src/changes.json +6 -0
- package/src/__tests__/build-prod-bundle.integration.test.ts +0 -282
- package/src/__tests__/build-server-bundle.test.ts +0 -228
- package/src/__tests__/classify-change.test.ts +0 -87
- package/src/__tests__/compose-stacks.test.ts +0 -273
- package/src/__tests__/config-resolver-default.integration.test.ts +0 -165
- package/src/__tests__/crash-tracker.test.ts +0 -89
- package/src/__tests__/create-kumiko-server-errors.test.ts +0 -54
- package/src/__tests__/create-kumiko-server-options.test.ts +0 -33
- package/src/__tests__/create-kumiko-server.integration.test.ts +0 -1007
- package/src/__tests__/discover-format.test.ts +0 -32
- package/src/__tests__/env-schema.integration.test.ts +0 -248
- package/src/__tests__/env-schema.test.ts +0 -132
- package/src/__tests__/few-shot-corpus.test.ts +0 -316
- package/src/__tests__/framework-version.test.ts +0 -45
- package/src/__tests__/init-deploy-cli.test.ts +0 -113
- package/src/__tests__/kumiko-schema-check.test.ts +0 -56
- package/src/__tests__/merge-extra-context.test.ts +0 -67
- package/src/__tests__/resolve-stylesheet.test.ts +0 -132
- package/src/__tests__/run-dev-app-boot-validation.test.ts +0 -38
- package/src/__tests__/run-dev-app.integration.test.ts +0 -290
- package/src/__tests__/runtime-classification.test.ts +0 -26
- package/src/__tests__/saas-identity-wire.integration.test.ts +0 -427
- package/src/__tests__/scaffold-app-feature.test.ts +0 -216
- package/src/__tests__/scaffold-app.test.ts +0 -630
- package/src/__tests__/scaffold-demo-tasks.test.ts +0 -47
- package/src/__tests__/scaffold-deploy.test.ts +0 -464
- package/src/__tests__/scaffold-dev-cycle.integration.test.ts +0 -109
- package/src/__tests__/scaffold-feature.test.ts +0 -143
- package/src/__tests__/schema-apply.integration.test.ts +0 -191
- package/src/__tests__/setup-test-stack-from-features.integration.test.ts +0 -30
- package/src/__tests__/setup-test-stack-job-run-logger.integration.test.ts +0 -72
- package/src/__tests__/walkthrough.integration.test.ts +0 -140
- package/src/__tests__/welcome-banner.test.ts +0 -42
- package/src/build-server-bundle.ts +0 -346
- package/src/build.ts +0 -28
- package/src/codegen/__tests__/render-codegen.test.ts +0 -100
- package/src/codegen/__tests__/run-codegen.test.ts +0 -665
- package/src/codegen/__tests__/strict-mode-diagnostics.test.ts +0 -347
- package/src/codegen/__tests__/watch.test.ts +0 -222
- package/src/codegen/index.ts +0 -19
- package/src/codegen/render.ts +0 -305
- package/src/codegen/run-codegen.ts +0 -278
- package/src/codegen/scan-events.ts +0 -565
- package/src/codegen/watch.ts +0 -140
- package/src/compose-stacks.ts +0 -193
- package/src/crash-tracker.ts +0 -56
- package/src/create-kumiko-server.ts +0 -1397
- package/src/env-schema.ts +0 -72
- package/src/few-shot-corpus.ts +0 -370
- package/src/framework-version.ts +0 -39
- package/src/index.ts +0 -105
- package/src/init-deploy-cli.ts +0 -148
- package/src/run-dev-app.ts +0 -694
- package/src/scaffold-app-feature.ts +0 -283
- package/src/scaffold-app.ts +0 -1033
- package/src/scaffold-deploy.ts +0 -393
- package/src/scaffold-feature.ts +0 -226
- package/src/schema-apply.ts +0 -123
- package/src/setup-test-stack-from-features.ts +0 -80
- 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>;
|
package/src/few-shot-corpus.ts
DELETED
|
@@ -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
|
-
}
|
package/src/framework-version.ts
DELETED
|
@@ -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";
|