kozou 0.0.2 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/LICENSE +202 -21
  2. package/README.md +97 -17
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +54 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/dev-runtime.d.ts +5 -0
  8. package/dist/commands/dev-runtime.d.ts.map +1 -0
  9. package/dist/commands/dev-runtime.js +38 -0
  10. package/dist/commands/dev-runtime.js.map +1 -0
  11. package/dist/commands/dev.d.ts +5 -0
  12. package/dist/commands/dev.d.ts.map +1 -0
  13. package/dist/commands/dev.js +96 -0
  14. package/dist/commands/dev.js.map +1 -0
  15. package/dist/commands/inspect.d.ts +10 -0
  16. package/dist/commands/inspect.d.ts.map +1 -0
  17. package/dist/commands/inspect.js +47 -0
  18. package/dist/commands/inspect.js.map +1 -0
  19. package/dist/commands/mcp.d.ts +9 -0
  20. package/dist/commands/mcp.d.ts.map +1 -0
  21. package/dist/commands/mcp.js +29 -0
  22. package/dist/commands/mcp.js.map +1 -0
  23. package/dist/config.d.ts +54 -0
  24. package/dist/config.d.ts.map +1 -0
  25. package/dist/config.js +178 -0
  26. package/dist/config.js.map +1 -0
  27. package/dist/create-kozou.d.ts +3 -0
  28. package/dist/create-kozou.d.ts.map +1 -0
  29. package/dist/create-kozou.js +27 -0
  30. package/dist/create-kozou.js.map +1 -0
  31. package/dist/index.d.ts +12 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +22 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/scaffold.d.ts +11 -0
  36. package/dist/scaffold.d.ts.map +1 -0
  37. package/dist/scaffold.js +65 -0
  38. package/dist/scaffold.js.map +1 -0
  39. package/dist/templates/docker-compose.yml +64 -0
  40. package/dist/templates/env.example +17 -0
  41. package/dist/templates/kozou.config.yaml +29 -0
  42. package/dist/templates/migrations/0001_init.sql +25 -0
  43. package/dist/templates/ui-hints.yaml +26 -0
  44. package/package.json +52 -21
@@ -0,0 +1,47 @@
1
+ // `kozou inspect` command implementation.
2
+ //
3
+ // Pipeline:
4
+ // 1. Load the kozou.config.yaml (or fall back to defaults).
5
+ // 2. Introspect the target Postgres schema (@kozou/introspect).
6
+ // 3. Optionally load UI hints (@kozou/core.loadUIHints).
7
+ // 4. Build a SchemaContext (@kozou/core.buildSchemaContext).
8
+ // 5. Serialize to JSON or YAML and write to stdout or a file.
9
+ //
10
+ // See Kozou v0.1 design spec §9.1.
11
+ import { writeFile } from 'node:fs/promises';
12
+ import { stringify as stringifyYAML } from 'yaml';
13
+ import { buildSchemaContext, loadUIHints } from '@kozou/core';
14
+ import { introspect } from '@kozou/introspect';
15
+ import { loadConfig } from '../config.js';
16
+ export async function inspectCommand(opts = {}) {
17
+ const format = opts.format ?? 'json';
18
+ const output = opts.output ?? '-';
19
+ if (format !== 'json' && format !== 'yaml') {
20
+ throw new Error(`kozou inspect: invalid --format "${format}" (expected "json" or "yaml")`);
21
+ }
22
+ const config = await loadConfig({ path: opts.config });
23
+ const raw = await introspect({
24
+ connection: config.database.url,
25
+ schemas: config.database.schemas,
26
+ });
27
+ let uiHints;
28
+ if (config.uiHints.path !== null && config.uiHints.path !== '') {
29
+ try {
30
+ uiHints = await loadUIHints(config.uiHints.path);
31
+ }
32
+ catch (err) {
33
+ // UI hints are optional; warn but continue without them.
34
+ const message = err instanceof Error ? err.message : String(err);
35
+ process.stderr.write(`[kozou inspect] could not load UI hints: ${message}\n`);
36
+ }
37
+ }
38
+ const ctx = await buildSchemaContext({ raw, uiHints });
39
+ const serialized = format === 'yaml' ? stringifyYAML(ctx) : JSON.stringify(ctx, null, 2);
40
+ const payload = serialized.endsWith('\n') ? serialized : serialized + '\n';
41
+ if (output === '-') {
42
+ process.stdout.write(payload);
43
+ return;
44
+ }
45
+ await writeFile(output, payload, 'utf8');
46
+ }
47
+ //# sourceMappingURL=inspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../src/commands/inspect.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,EAAE;AACF,YAAY;AACZ,8DAA8D;AAC9D,kEAAkE;AAClE,2DAA2D;AAC3D,+DAA+D;AAC/D,gEAAgE;AAChE,EAAE;AACF,mCAAmC;AAEnC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAW1C,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB,EAAE;IAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC;IAClC,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,+BAA+B,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvD,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC;QAC3B,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG;QAC/B,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO;KACjC,CAAC,CAAC;IAEH,IAAI,OAA4B,CAAC;IACjC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;QAC/D,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,yDAAyD;YACzD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,OAAO,IAAI,CAAC,CAAC;QAChF,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACzF,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,GAAG,IAAI,CAAC;IAE3E,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IACD,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type McpOptions = {
2
+ stdio?: boolean;
3
+ http?: boolean;
4
+ port?: number;
5
+ host?: string;
6
+ config?: string;
7
+ };
8
+ export declare function mcpCommand(opts?: McpOptions): Promise<void>;
9
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAsB,UAAU,CAAC,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBrE"}
@@ -0,0 +1,29 @@
1
+ // `kozou mcp` command implementation.
2
+ //
3
+ // --stdio: spins up the @kozou/mcp server with a stdio transport, reading
4
+ // connection details from kozou.config.yaml / environment.
5
+ // --http: spins up the @kozou/mcp server with the Streamable HTTP
6
+ // transport (Kozou v0.1 spec §7.1), binding to localhost by default and
7
+ // exposing POST /admin/refresh for cache invalidation (§7.5).
8
+ //
9
+ // See Kozou v0.1 design spec §9.1 and §7.
10
+ import { SchemaCache, startHttpServer, startStdioServer } from '@kozou/mcp';
11
+ import { loadConfig } from '../config.js';
12
+ export async function mcpCommand(opts = {}) {
13
+ const config = await loadConfig({ path: opts.config });
14
+ const cache = new SchemaCache({
15
+ connection: config.database.url,
16
+ schemas: config.database.schemas,
17
+ ttlMs: config.cache.ttlMs,
18
+ });
19
+ if (opts.http === true) {
20
+ await startHttpServer(cache, {
21
+ port: opts.port,
22
+ host: opts.host,
23
+ logPrefix: '[kozou mcp]',
24
+ });
25
+ return;
26
+ }
27
+ await startStdioServer(cache, { logPrefix: '[kozou mcp]' });
28
+ }
29
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,0EAA0E;AAC1E,6DAA6D;AAC7D,kEAAkE;AAClE,0EAA0E;AAC1E,gEAAgE;AAChE,EAAE;AACF,0CAA0C;AAE1C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAU1C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAmB,EAAE;IACpD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvD,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC;QAC5B,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG;QAC/B,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,OAAO;QAChC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK;KAC1B,CAAC,CAAC;IAEH,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACvB,MAAM,eAAe,CAAC,KAAK,EAAE;YAC3B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,aAAa;SACzB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { z } from 'zod';
2
+ declare const configSchema: z.ZodObject<{
3
+ database: z.ZodObject<{
4
+ url: z.ZodString;
5
+ schemas: z.ZodDefault<z.ZodArray<z.ZodString>>;
6
+ }, z.core.$strip>;
7
+ server: z.ZodPrefault<z.ZodObject<{
8
+ ui: z.ZodPrefault<z.ZodObject<{
9
+ port: z.ZodDefault<z.ZodNumber>;
10
+ host: z.ZodDefault<z.ZodString>;
11
+ }, z.core.$strip>>;
12
+ mcp: z.ZodPrefault<z.ZodObject<{
13
+ http: z.ZodPrefault<z.ZodObject<{
14
+ port: z.ZodDefault<z.ZodNumber>;
15
+ host: z.ZodDefault<z.ZodString>;
16
+ }, z.core.$strip>>;
17
+ stdio: z.ZodDefault<z.ZodBoolean>;
18
+ }, z.core.$strip>>;
19
+ }, z.core.$strip>>;
20
+ adapter: z.ZodPrefault<z.ZodObject<{
21
+ type: z.ZodDefault<z.ZodLiteral<"postgrest">>;
22
+ url: z.ZodDefault<z.ZodString>;
23
+ }, z.core.$strip>>;
24
+ uiHints: z.ZodPrefault<z.ZodObject<{
25
+ path: z.ZodDefault<z.ZodNullable<z.ZodString>>;
26
+ }, z.core.$strip>>;
27
+ cache: z.ZodPrefault<z.ZodObject<{
28
+ ttlMs: z.ZodDefault<z.ZodNumber>;
29
+ }, z.core.$strip>>;
30
+ }, z.core.$strip>;
31
+ export type KozouConfig = z.infer<typeof configSchema>;
32
+ export type KozouConfigIssue = {
33
+ path: string;
34
+ message: string;
35
+ };
36
+ export declare class KozouConfigError extends Error {
37
+ readonly issues: KozouConfigIssue[];
38
+ readonly filePath: string | null;
39
+ constructor(message: string, filePath: string | null, issues: KozouConfigIssue[]);
40
+ }
41
+ export type LoadConfigOptions = {
42
+ /** Path to kozou.config.yaml. Default: ./kozou.config.yaml relative to cwd. */
43
+ path?: string;
44
+ /** Environment variables for ${VAR} expansion. Default: process.env. */
45
+ env?: NodeJS.ProcessEnv;
46
+ /**
47
+ * If true, do not read any file from disk; only honor explicit options and
48
+ * environment variables. Useful for unit tests.
49
+ */
50
+ skipFile?: boolean;
51
+ };
52
+ export declare function loadConfig(opts?: LoadConfigOptions): Promise<KozouConfig>;
53
+ export {};
54
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA+DxB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMhB,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAIvD,MAAM,MAAM,gBAAgB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;gBACrB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE;CAMjF;AAMD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA2DF,wBAAsB,UAAU,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CA2CnF"}
package/dist/config.js ADDED
@@ -0,0 +1,178 @@
1
+ // kozou.config.yaml loader.
2
+ //
3
+ // Reads the YAML config file, expands ${VAR} / ${VAR:-default} placeholders
4
+ // against the process environment, fills in defaults, and validates the
5
+ // result with zod. Every field has a default so kozou can run with only the
6
+ // DATABASE_URL environment variable set, per the Kozou v0.1 design spec §9.2.
7
+ //
8
+ // A literal `$$` escapes to a single `$`, so `$${VAR}` produces the literal
9
+ // text `${VAR}` instead of expanding it. Expansion is single-level by design:
10
+ // a value substituted from the environment is never re-scanned, so a secret
11
+ // that legitimately contains `${...}` (e.g. inside a DATABASE_URL password) is
12
+ // preserved rather than mistaken for a placeholder. See expandEnvVars below.
13
+ import { readFile } from 'node:fs/promises';
14
+ import { existsSync } from 'node:fs';
15
+ import { resolve, isAbsolute } from 'node:path';
16
+ import { parse as parseYAML } from 'yaml';
17
+ import { z } from 'zod';
18
+ // ---- Schema ---------------------------------------------------------------
19
+ // Nested sections use `.prefault({})` rather than `.default({})`: in zod 4
20
+ // `.default(v)` short-circuits to `v` as-is when the input is undefined (so
21
+ // it would need the fully-populated object), whereas `.prefault(v)` feeds
22
+ // `v` back through the schema so each field's own `.default(...)` still
23
+ // applies. `.prefault({})` therefore reproduces the zod 3 behaviour of
24
+ // "absent section -> object filled entirely from inner defaults".
25
+ const uiServerSchema = z
26
+ .object({
27
+ port: z.number().int().min(0).max(65_535).default(3333),
28
+ host: z.string().min(1).default('0.0.0.0'),
29
+ })
30
+ .prefault({});
31
+ const mcpHttpServerSchema = z
32
+ .object({
33
+ port: z.number().int().min(0).max(65_535).default(3334),
34
+ host: z.string().min(1).default('0.0.0.0'),
35
+ })
36
+ .prefault({});
37
+ const mcpServerSchema = z
38
+ .object({
39
+ http: mcpHttpServerSchema,
40
+ stdio: z.boolean().default(false),
41
+ })
42
+ .prefault({});
43
+ const serverSchema = z
44
+ .object({
45
+ ui: uiServerSchema,
46
+ mcp: mcpServerSchema,
47
+ })
48
+ .prefault({});
49
+ const adapterSchema = z
50
+ .object({
51
+ type: z.literal('postgrest').default('postgrest'),
52
+ url: z.string().min(1).default('http://postgrest:3000'),
53
+ })
54
+ .prefault({});
55
+ const uiHintsSchema = z
56
+ .object({
57
+ path: z.string().nullable().default(null),
58
+ })
59
+ .prefault({});
60
+ const cacheSchema = z
61
+ .object({
62
+ ttlMs: z.number().int().min(0).default(60_000),
63
+ })
64
+ .prefault({});
65
+ const databaseSchema = z.object({
66
+ url: z.string().min(1, 'database.url is required (set DATABASE_URL or kozou.config.yaml)'),
67
+ schemas: z.array(z.string().min(1)).default(['public']),
68
+ });
69
+ const configSchema = z.object({
70
+ database: databaseSchema,
71
+ server: serverSchema,
72
+ adapter: adapterSchema,
73
+ uiHints: uiHintsSchema,
74
+ cache: cacheSchema,
75
+ });
76
+ export class KozouConfigError extends Error {
77
+ issues;
78
+ filePath;
79
+ constructor(message, filePath, issues) {
80
+ super(message);
81
+ this.name = 'KozouConfigError';
82
+ this.filePath = filePath;
83
+ this.issues = issues;
84
+ }
85
+ }
86
+ // ---- Loader --------------------------------------------------------------
87
+ const DEFAULT_CONFIG_PATH = 'kozou.config.yaml';
88
+ // Matches either an escaped `$$` (which becomes a literal `$`) or a
89
+ // `${VAR}` / `${VAR:-default}` placeholder. `$$` is listed first so the
90
+ // alternation consumes it before the placeholder branch can see a stray `$`.
91
+ const ENV_TOKEN_RE = /\$\$|\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g;
92
+ function expandEnvVars(value, env) {
93
+ if (typeof value === 'string') {
94
+ return value.replace(ENV_TOKEN_RE, (match, name, fallback) => {
95
+ // `$$` -> literal `$`. So `$${VAR}` yields the literal `${VAR}`:
96
+ // the trailing `{VAR}` is left untouched because it no longer has
97
+ // a `$` prefix to start a placeholder.
98
+ if (match === '$$')
99
+ return '$';
100
+ // Otherwise `match` is a `${...}` placeholder and `name` is its
101
+ // (always-present) variable name. The substituted value is taken
102
+ // verbatim and never re-scanned (single-level expansion), so a
103
+ // value containing `${...}` is preserved as-is.
104
+ const v = env[name];
105
+ if (v !== undefined)
106
+ return v;
107
+ if (fallback !== undefined)
108
+ return fallback;
109
+ return '';
110
+ });
111
+ }
112
+ if (Array.isArray(value)) {
113
+ return value.map((v) => expandEnvVars(v, env));
114
+ }
115
+ if (value !== null && typeof value === 'object') {
116
+ const out = {};
117
+ for (const [k, v] of Object.entries(value)) {
118
+ out[k] = expandEnvVars(v, env);
119
+ }
120
+ return out;
121
+ }
122
+ return value;
123
+ }
124
+ function injectDatabaseUrlFromEnv(raw, env) {
125
+ if (raw === null || typeof raw !== 'object')
126
+ return raw;
127
+ const obj = raw;
128
+ const envUrl = env.DATABASE_URL;
129
+ if (envUrl === undefined || envUrl === '')
130
+ return obj;
131
+ const existing = obj.database;
132
+ if (existing === undefined) {
133
+ return { ...obj, database: { url: envUrl } };
134
+ }
135
+ if (existing !== null && typeof existing === 'object') {
136
+ const db = existing;
137
+ if (db.url === undefined || db.url === '') {
138
+ return { ...obj, database: { ...db, url: envUrl } };
139
+ }
140
+ }
141
+ return obj;
142
+ }
143
+ export async function loadConfig(opts = {}) {
144
+ const env = opts.env ?? process.env;
145
+ const requestedPath = opts.path ?? DEFAULT_CONFIG_PATH;
146
+ const absPath = isAbsolute(requestedPath)
147
+ ? requestedPath
148
+ : resolve(process.cwd(), requestedPath);
149
+ let raw = {};
150
+ let fileLoaded = null;
151
+ if (!opts.skipFile && existsSync(absPath)) {
152
+ const content = await readFile(absPath, 'utf8');
153
+ try {
154
+ raw = parseYAML(content) ?? {};
155
+ }
156
+ catch (err) {
157
+ const message = err instanceof Error ? err.message : String(err);
158
+ throw new KozouConfigError(`Failed to parse kozou config: ${message}`, absPath, [{ path: '<yaml>', message }]);
159
+ }
160
+ fileLoaded = absPath;
161
+ }
162
+ // Fall back to DATABASE_URL env if database.url is not set in the file.
163
+ const withDbDefault = injectDatabaseUrlFromEnv(raw, env);
164
+ const expanded = expandEnvVars(withDbDefault, env);
165
+ try {
166
+ return configSchema.parse(expanded);
167
+ }
168
+ catch (err) {
169
+ if (err instanceof z.ZodError) {
170
+ throw new KozouConfigError(`Invalid kozou config: ${err.issues.length} issue(s)`, fileLoaded, err.issues.map((i) => ({
171
+ path: i.path.join('.') || '<root>',
172
+ message: i.message,
173
+ })));
174
+ }
175
+ throw err;
176
+ }
177
+ }
178
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=create-kozou.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-kozou.d.ts","sourceRoot":"","sources":["../src/create-kozou.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ // `create-kozou` bin entry. Thin wrapper around createKozouScaffold().
3
+ import { createKozouScaffold, KozouScaffoldError } from './scaffold.js';
4
+ async function main() {
5
+ const target = process.argv[2];
6
+ if (!target || target === '--help' || target === '-h') {
7
+ process.stderr.write('Usage: create-kozou <directory>\n');
8
+ process.exit(target ? 0 : 1);
9
+ }
10
+ try {
11
+ await createKozouScaffold({ target });
12
+ }
13
+ catch (err) {
14
+ if (err instanceof KozouScaffoldError) {
15
+ process.stderr.write(`${err.message}\n`);
16
+ process.exit(1);
17
+ }
18
+ throw err;
19
+ }
20
+ process.stderr.write(`Scaffolded ${target}/\n`);
21
+ process.stderr.write(`Next: cd ${target} && cp .env.example .env && docker compose up\n`);
22
+ }
23
+ main().catch((err) => {
24
+ process.stderr.write(`create-kozou: fatal: ${err instanceof Error ? err.message : String(err)}\n`);
25
+ process.exit(1);
26
+ });
27
+ //# sourceMappingURL=create-kozou.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-kozou.js","sourceRoot":"","sources":["../src/create-kozou.ts"],"names":[],"mappings":";AACA,uEAAuE;AAEvE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExE,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,CAAC;QACH,MAAM,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;YACtC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,MAAM,KAAK,CAAC,CAAC;IAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,YAAY,MAAM,iDAAiD,CACpE,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ export declare const PACKAGE_VERSION: string;
2
+ export { loadConfig, KozouConfigError } from './config.js';
3
+ export type { KozouConfig, KozouConfigIssue, LoadConfigOptions } from './config.js';
4
+ export { inspectCommand } from './commands/inspect.js';
5
+ export type { InspectOptions } from './commands/inspect.js';
6
+ export { mcpCommand } from './commands/mcp.js';
7
+ export type { McpOptions } from './commands/mcp.js';
8
+ export { devCommand } from './commands/dev.js';
9
+ export type { DevOptions } from './commands/dev.js';
10
+ export { createKozouScaffold, KozouScaffoldError } from './scaffold.js';
11
+ export type { CreateScaffoldOptions } from './scaffold.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,eAAe,QAAc,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEpF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxE,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ // kozou (CLI package): public API surface for adopters embedding the
2
+ // commands programmatically. The bin entry points live in cli.ts and
3
+ // create-kozou.ts; this module re-exports the underlying primitives so
4
+ // integrators can build their own glue if they need to.
5
+ import { readFileSync } from 'node:fs';
6
+ import { createRequire } from 'node:module';
7
+ // `package.json` is the single source of truth for the version. Read it
8
+ // at module load (the same createRequire idiom commands/dev-runtime.ts
9
+ // uses to resolve a sibling package) instead of hardcoding a copy here,
10
+ // so a release bump in package.json can never drift from this constant.
11
+ // `../package.json` resolves to packages/kozou/package.json from the
12
+ // compiled dist/index.js, and npm always ships package.json in the
13
+ // published tarball.
14
+ const require = createRequire(import.meta.url);
15
+ const pkg = JSON.parse(readFileSync(require.resolve('../package.json'), 'utf8'));
16
+ export const PACKAGE_VERSION = pkg.version;
17
+ export { loadConfig, KozouConfigError } from './config.js';
18
+ export { inspectCommand } from './commands/inspect.js';
19
+ export { mcpCommand } from './commands/mcp.js';
20
+ export { devCommand } from './commands/dev.js';
21
+ export { createKozouScaffold, KozouScaffoldError } from './scaffold.js';
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,qEAAqE;AACrE,uEAAuE;AACvE,wDAAwD;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,wEAAwE;AACxE,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,qEAAqE;AACrE,mEAAmE;AACnE,qBAAqB;AACrB,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAE9E,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAC,OAAO,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,11 @@
1
+ export type CreateScaffoldOptions = {
2
+ /** Target directory. Must not already exist. */
3
+ target: string;
4
+ /** Override the templates directory (used by unit tests). */
5
+ templatesDir?: string;
6
+ };
7
+ export declare class KozouScaffoldError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ export declare function createKozouScaffold(opts: CreateScaffoldOptions): Promise<void>;
11
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,qBAAqB,GAAG;IAClC,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAyBD,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBpF"}
@@ -0,0 +1,65 @@
1
+ // `create-kozou` scaffolding logic.
2
+ //
3
+ // Copies the contents of packages/kozou/src/templates/ into the target
4
+ // directory the user picks. Renames env.example to .env.example along
5
+ // the way so the scaffolded project ships a real dotfile (the template
6
+ // stays a normal file because npm's tarball handling for dotfiles
7
+ // inside published packages can be surprising).
8
+ import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
9
+ import { dirname, join } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ const DEFAULT_TEMPLATE_DIR = fileURLToPath(new URL('./templates', import.meta.url));
12
+ export class KozouScaffoldError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = 'KozouScaffoldError';
16
+ }
17
+ }
18
+ async function copyRecursive(src, dest) {
19
+ const entries = await readdir(src, { withFileTypes: true });
20
+ for (const entry of entries) {
21
+ const sourcePath = join(src, entry.name);
22
+ let targetName = entry.name;
23
+ // env.example -> .env.example so the scaffolded project has a real
24
+ // dotfile but the template itself stays out of dotfile-tooling
25
+ // edge cases when published to npm.
26
+ if (entry.isFile() && entry.name === 'env.example') {
27
+ targetName = '.env.example';
28
+ }
29
+ const destPath = join(dest, targetName);
30
+ if (entry.isDirectory()) {
31
+ await mkdir(destPath, { recursive: true });
32
+ await copyRecursive(sourcePath, destPath);
33
+ }
34
+ else if (entry.isFile()) {
35
+ const content = await readFile(sourcePath, 'utf8');
36
+ await writeFile(destPath, content, 'utf8');
37
+ }
38
+ // Symlinks and other entry kinds are skipped intentionally.
39
+ }
40
+ }
41
+ export async function createKozouScaffold(opts) {
42
+ const target = (opts.target ?? '').trim();
43
+ if (target === '') {
44
+ throw new KozouScaffoldError('create-kozou: target directory is required');
45
+ }
46
+ const templatesDir = opts.templatesDir ?? DEFAULT_TEMPLATE_DIR;
47
+ // Create any missing parent directories, then create the target itself
48
+ // with a NON-recursive mkdir so an already-existing target fails
49
+ // atomically with EEXIST. A recursive mkdir silently succeeds on an
50
+ // existing directory, so the previous existsSync()-then-mkdir guard had
51
+ // a TOCTOU window (the target could be created between the check and the
52
+ // mkdir); letting mkdir own the "must not exist" check closes it.
53
+ await mkdir(dirname(target), { recursive: true });
54
+ try {
55
+ await mkdir(target);
56
+ }
57
+ catch (err) {
58
+ if (err.code === 'EEXIST') {
59
+ throw new KozouScaffoldError(`create-kozou: "${target}" already exists`);
60
+ }
61
+ throw err;
62
+ }
63
+ await copyRecursive(templatesDir, target);
64
+ }
65
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,uEAAuE;AACvE,kEAAkE;AAClE,gDAAgD;AAEhD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,oBAAoB,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AASpF,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,IAAY;IACpD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC;QAC5B,mEAAmE;QACnE,+DAA+D;QAC/D,oCAAoC;QACpC,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACnD,UAAU,GAAG,cAAc,CAAC;QAC9B,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACxC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3C,MAAM,aAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC5C,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YACnD,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7C,CAAC;QACD,4DAA4D;IAC9D,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAA2B;IACnE,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1C,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,kBAAkB,CAAC,4CAA4C,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,oBAAoB,CAAC;IAC/D,uEAAuE;IACvE,iEAAiE;IACjE,oEAAoE;IACpE,wEAAwE;IACxE,yEAAyE;IACzE,kEAAkE;IAClE,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,IAAI,kBAAkB,CAAC,kBAAkB,MAAM,kBAAkB,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,MAAM,aAAa,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,64 @@
1
+ # Docker Compose stack for a kozou project.
2
+ #
3
+ # Brings up:
4
+ # - postgres PostgreSQL 16 (the source of truth)
5
+ # - postgrest REST adapter consumed by the Kozou DataAdapter
6
+ # (MIT-licensed external dependency, not bundled)
7
+ # - kozou `kozou dev` - the bundled Admin UI + MCP HTTP server
8
+ # (ghcr.io/kozou-dev/kozou). Binds 0.0.0.0 inside the
9
+ # container so the port mappings below reach your host.
10
+ #
11
+ # Customize the credentials in .env before running `docker compose up`.
12
+
13
+ services:
14
+ postgres:
15
+ image: postgres:16
16
+ environment:
17
+ POSTGRES_USER: ${POSTGRES_USER:-kozou}
18
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-kozou}
19
+ POSTGRES_DB: ${POSTGRES_DB:-kozou}
20
+ ports:
21
+ - "${POSTGRES_PORT:-5432}:5432"
22
+ volumes:
23
+ - ./migrations:/docker-entrypoint-initdb.d:ro
24
+ healthcheck:
25
+ test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-kozou}"]
26
+ interval: 5s
27
+ timeout: 5s
28
+ retries: 10
29
+
30
+ postgrest:
31
+ image: postgrest/postgrest:latest
32
+ environment:
33
+ PGRST_DB_URI: postgres://${POSTGRES_USER:-kozou}:${POSTGRES_PASSWORD:-kozou}@postgres:5432/${POSTGRES_DB:-kozou}
34
+ PGRST_DB_SCHEMA: public
35
+ PGRST_DB_ANON_ROLE: ${POSTGRES_USER:-kozou}
36
+ ports:
37
+ - "3000:3000"
38
+ depends_on:
39
+ postgres:
40
+ condition: service_healthy
41
+
42
+ kozou:
43
+ # `kozou dev` spawns the bundled @kozou/svelte-ui Admin UI and the
44
+ # MCP HTTP server (Kozou v0.1 spec §9.1). Both bind 0.0.0.0 inside
45
+ # the container so the port mappings below reach your host.
46
+ image: ghcr.io/kozou-dev/kozou:v0.1.1
47
+ command: ["dev"]
48
+ environment:
49
+ DATABASE_URL: postgres://${POSTGRES_USER:-kozou}:${POSTGRES_PASSWORD:-kozou}@postgres:5432/${POSTGRES_DB:-kozou}
50
+ KOZOU_ADAPTER_URL: http://postgrest:3000
51
+ # The Admin UI is a SvelteKit (adapter-node) app. Without ORIGIN
52
+ # it assumes https and rejects every form POST (create / edit /
53
+ # delete) over plain http with a 403 "Cross-site POST forbidden".
54
+ # Set it to the exact URL you open in the browser; override if you
55
+ # publish the Admin UI on a different host or port.
56
+ ORIGIN: ${KOZOU_ORIGIN:-http://localhost:3333}
57
+ depends_on:
58
+ postgres:
59
+ condition: service_healthy
60
+ postgrest:
61
+ condition: service_started
62
+ ports:
63
+ - "3333:3333" # Admin UI
64
+ - "3334:3334" # MCP HTTP
@@ -0,0 +1,17 @@
1
+ # Copy this file to .env and fill in the real values before running
2
+ # `docker compose up`.
3
+
4
+ POSTGRES_USER=kozou
5
+ POSTGRES_PASSWORD=change-me
6
+ POSTGRES_DB=kozou
7
+ POSTGRES_PORT=5432
8
+
9
+ # Used by kozou + postgrest at runtime; defaults match the compose stack.
10
+ DATABASE_URL=postgres://kozou:change-me@postgres:5432/kozou
11
+ KOZOU_ADAPTER_URL=http://postgrest:3000
12
+
13
+ # Public URL you open the Admin UI on (v0.1.1). The bundled SvelteKit
14
+ # (adapter-node) server needs this to accept form submissions over plain
15
+ # http — without it, create / edit / delete are rejected with a 403
16
+ # "Cross-site POST forbidden". Override if you serve the UI elsewhere.
17
+ KOZOU_ORIGIN=http://localhost:3333
@@ -0,0 +1,29 @@
1
+ # kozou.config.yaml
2
+ #
3
+ # Every field has a sensible default; only set what you need to override.
4
+ # All ${VAR} and ${VAR:-fallback} placeholders are expanded against the
5
+ # process environment at startup.
6
+
7
+ database:
8
+ url: ${DATABASE_URL}
9
+ schemas: [public]
10
+
11
+ server:
12
+ ui:
13
+ port: 3333
14
+ host: 0.0.0.0
15
+ mcp:
16
+ http:
17
+ port: 3334
18
+ host: 0.0.0.0
19
+ stdio: false
20
+
21
+ adapter:
22
+ type: postgrest
23
+ url: ${KOZOU_ADAPTER_URL:-http://postgrest:3000}
24
+
25
+ uiHints:
26
+ path: ./ui-hints.yaml
27
+
28
+ cache:
29
+ ttlMs: 60000