@kindgi/cli 0.1.2 → 0.1.3

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 (89) hide show
  1. package/README.md +71 -9
  2. package/dist/build/containerfile.d.ts +1 -1
  3. package/dist/build/containerfile.d.ts.map +1 -1
  4. package/dist/build/containerfile.js +16 -2
  5. package/dist/build/containerfile.js.map +1 -1
  6. package/dist/build/defaults.d.ts.map +1 -1
  7. package/dist/build/defaults.js +10 -0
  8. package/dist/build/defaults.js.map +1 -1
  9. package/dist/build/host-install.d.ts +8 -0
  10. package/dist/build/host-install.d.ts.map +1 -1
  11. package/dist/build/host-install.js.map +1 -1
  12. package/dist/build/runners.d.ts +5 -0
  13. package/dist/build/runners.d.ts.map +1 -1
  14. package/dist/commands/build.d.ts.map +1 -1
  15. package/dist/commands/build.js +34 -3
  16. package/dist/commands/build.js.map +1 -1
  17. package/dist/commands/dev.d.ts.map +1 -1
  18. package/dist/commands/dev.js +219 -40
  19. package/dist/commands/dev.js.map +1 -1
  20. package/dist/commands/env.js +1 -1
  21. package/dist/commands/env.js.map +1 -1
  22. package/dist/commands/providers.d.ts.map +1 -1
  23. package/dist/commands/providers.js +10 -1
  24. package/dist/commands/providers.js.map +1 -1
  25. package/dist/commands/runs.d.ts.map +1 -1
  26. package/dist/commands/runs.js +27 -7
  27. package/dist/commands/runs.js.map +1 -1
  28. package/dist/deploy/post.d.ts.map +1 -1
  29. package/dist/deploy/post.js +4 -0
  30. package/dist/deploy/post.js.map +1 -1
  31. package/dist/deploy/response.d.ts.map +1 -1
  32. package/dist/deploy/response.js +30 -7
  33. package/dist/deploy/response.js.map +1 -1
  34. package/dist/deploy/runners.d.ts +8 -0
  35. package/dist/deploy/runners.d.ts.map +1 -1
  36. package/dist/dev/bundler.d.ts +21 -0
  37. package/dist/dev/bundler.d.ts.map +1 -1
  38. package/dist/dev/bundler.js +46 -18
  39. package/dist/dev/bundler.js.map +1 -1
  40. package/dist/dev/defaults.d.ts +11 -0
  41. package/dist/dev/defaults.d.ts.map +1 -1
  42. package/dist/dev/defaults.js +19 -6
  43. package/dist/dev/defaults.js.map +1 -1
  44. package/dist/dev/project-database.d.ts +68 -0
  45. package/dist/dev/project-database.d.ts.map +1 -0
  46. package/dist/dev/project-database.js +142 -0
  47. package/dist/dev/project-database.js.map +1 -0
  48. package/dist/dev/project.d.ts +59 -0
  49. package/dist/dev/project.d.ts.map +1 -0
  50. package/dist/dev/project.js +182 -0
  51. package/dist/dev/project.js.map +1 -0
  52. package/dist/dev/providers.d.ts +96 -0
  53. package/dist/dev/providers.d.ts.map +1 -0
  54. package/dist/dev/providers.js +406 -0
  55. package/dist/dev/providers.js.map +1 -0
  56. package/dist/dev/runners.d.ts +17 -0
  57. package/dist/dev/runners.d.ts.map +1 -1
  58. package/dist/dev/runtime-image.d.ts +1 -1
  59. package/dist/dev/runtime-image.js +1 -1
  60. package/dist/env/pack-env-plan.d.ts +7 -1
  61. package/dist/env/pack-env-plan.d.ts.map +1 -1
  62. package/dist/env/pack-env-plan.js +9 -3
  63. package/dist/env/pack-env-plan.js.map +1 -1
  64. package/dist/providers/preset-loader.d.ts +5 -0
  65. package/dist/providers/preset-loader.d.ts.map +1 -1
  66. package/dist/providers/preset-loader.js +9 -1
  67. package/dist/providers/preset-loader.js.map +1 -1
  68. package/dist/providers/presets/gemini.json +2 -1
  69. package/dist/runs/follow.d.ts +25 -0
  70. package/dist/runs/follow.d.ts.map +1 -0
  71. package/dist/runs/follow.js +48 -0
  72. package/dist/runs/follow.js.map +1 -0
  73. package/dist/sdk-skills/kindgi-authoring-agents/SKILL.md +1 -1
  74. package/dist/sdk-skills/kindgi-authoring-flows/SKILL.md +1 -1
  75. package/dist/sdk-skills/kindgi-authoring-guardrails/SKILL.md +1 -1
  76. package/dist/sdk-skills/kindgi-authoring-mcp-servers/SKILL.md +1 -1
  77. package/dist/sdk-skills/kindgi-authoring-providers/SKILL.md +41 -6
  78. package/dist/sdk-skills/kindgi-authoring-tools/SKILL.md +3 -2
  79. package/dist/sdk-skills/kindgi-framework-feedback/SKILL.md +1 -1
  80. package/dist/sdk-skills/kindgi-getting-started/SKILL.md +38 -6
  81. package/dist/sdk-skills/kindgi-python-authoring-agents/SKILL.md +1 -1
  82. package/dist/sdk-skills/kindgi-python-authoring-flows/SKILL.md +1 -1
  83. package/dist/sdk-skills/kindgi-python-authoring-guardrails/SKILL.md +1 -1
  84. package/dist/sdk-skills/kindgi-python-authoring-tools/SKILL.md +5 -1
  85. package/dist/sdk-skills/kindgi-python-getting-started/SKILL.md +44 -6
  86. package/dist/templates/minimal/AGENTS.md +4 -3
  87. package/dist/templates/python/AGENTS.md +5 -4
  88. package/dist/templates/sample/AGENTS.md +4 -3
  89. package/package.json +10 -10
@@ -0,0 +1,68 @@
1
+ import type { DevProject } from './project.js';
2
+ /** The bundled Postgres's container (compose and plain-docker starts alike). */
3
+ export declare const BUNDLED_POSTGRES_CONTAINER = "kindgi-dev_postgres";
4
+ /** One SQL statement's tuples-only output, or why it failed. */
5
+ export type SqlRunner = (sql: string) => Promise<{
6
+ readonly ok: true;
7
+ readonly out: string;
8
+ } | {
9
+ readonly ok: false;
10
+ readonly error: string;
11
+ }>;
12
+ /** Who owns a project database, as its comment records it. */
13
+ export interface DatabaseOwner {
14
+ readonly root: string;
15
+ readonly createdBy: string;
16
+ }
17
+ export type EnsureOutcome = {
18
+ readonly kind: 'created';
19
+ } | {
20
+ readonly kind: 'exists';
21
+ }
22
+ /** The owner's folder moved (the recorded one is gone): the database is this folder's now. */
23
+ | {
24
+ readonly kind: 'adopted';
25
+ readonly previousRoot: string;
26
+ } | {
27
+ readonly kind: 'refused';
28
+ readonly message: string;
29
+ } | {
30
+ readonly kind: 'error';
31
+ readonly message: string;
32
+ };
33
+ export interface ProjectDatabases {
34
+ /** The URL the runtime connects with, for a database in the bundled Postgres. */
35
+ urlFor(database: string): string;
36
+ /** Make sure the project's database exists and belongs to this folder. */
37
+ ensure(project: DevProject, cliVersion: string): Promise<EnsureOutcome>;
38
+ /** Drop the project's database, disconnecting whoever is on it (`--reset`). */
39
+ drop(database: string): Promise<{
40
+ readonly ok: true;
41
+ } | {
42
+ readonly ok: false;
43
+ readonly error: string;
44
+ }>;
45
+ /** Whether a database is there (the old shared `kindgi` one, say). */
46
+ exists(database: string): Promise<boolean>;
47
+ }
48
+ /**
49
+ * The bundled Postgres's project databases. `run` executes one statement
50
+ * in the container's `kindgi` database; `baseUrl` is the shared
51
+ * database's URL (only the database name changes per project).
52
+ */
53
+ export declare function createProjectDatabases(input: {
54
+ readonly run: SqlRunner;
55
+ readonly baseUrl: string;
56
+ /** Whether a folder exists (test seam). */
57
+ readonly folderExists?: (path: string) => boolean;
58
+ }): ProjectDatabases;
59
+ /**
60
+ * The real runner: `docker exec kindgi-dev_postgres psql -U kindgi -d kindgi
61
+ * -tA -v ON_ERROR_STOP=1 -c <sql>`, through the CLI's docker helper.
62
+ */
63
+ export declare function bundledSqlRunner(docker: (args: readonly string[]) => Promise<{
64
+ readonly code: number | null;
65
+ readonly stdout: string;
66
+ readonly stderr: string;
67
+ }>): SqlRunner;
68
+ //# sourceMappingURL=project-database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-database.d.ts","sourceRoot":"","sources":["../../src/dev/project-database.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,gFAAgF;AAChF,eAAO,MAAM,0BAA0B,wBAAwB,CAAC;AAEhE,gEAAgE;AAChE,MAAM,MAAM,SAAS,GAAG,CACtB,GAAG,EAAE,MAAM,KACR,OAAO,CACV;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAC7F,CAAC;AAEF,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE;AAC7B,8FAA8F;GAC5F;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,0EAA0E;IAC1E,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACxE,+EAA+E;IAC/E,IAAI,CACF,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnF,sEAAsE;IACtE,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC5C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,2CAA2C;IAC3C,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACnD,GAAG,gBAAgB,CA6FnB;AAYD;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,CACN,IAAI,EAAE,SAAS,MAAM,EAAE,KACpB,OAAO,CAAC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GAC/F,SAAS,CAoBX"}
@@ -0,0 +1,142 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * A project's database in the bundled Postgres (`kindgi-dev_postgres`):
5
+ * created when missing, and owned by one folder. The owner is recorded in
6
+ * the database's comment (`{"kindgi":{"root":…,"createdBy":…}}`), so two
7
+ * unrelated folders that resolve to the same project name don't share a
8
+ * database and a tenant without knowing it. Statements go through
9
+ * `docker exec … psql` in the container: the CLI carries no Postgres
10
+ * client, and only manages the bundled Postgres (never a database a
11
+ * `--database-url` names).
12
+ */
13
+ import { existsSync } from 'node:fs';
14
+ /** The bundled Postgres's container (compose and plain-docker starts alike). */
15
+ export const BUNDLED_POSTGRES_CONTAINER = 'kindgi-dev_postgres';
16
+ /**
17
+ * The bundled Postgres's project databases. `run` executes one statement
18
+ * in the container's `kindgi` database; `baseUrl` is the shared
19
+ * database's URL (only the database name changes per project).
20
+ */
21
+ export function createProjectDatabases(input) {
22
+ const { run } = input;
23
+ const folderExists = input.folderExists ?? existsSync;
24
+ const exists = async (database) => {
25
+ const found = await run(`SELECT 1 FROM pg_database WHERE datname = ${literal(database)}`);
26
+ return found.ok && found.out.trim() === '1';
27
+ };
28
+ const owner = async (database) => {
29
+ const read = await run(`SELECT shobj_description(oid, 'pg_database') FROM pg_database WHERE datname = ${literal(database)}`);
30
+ if (!read.ok)
31
+ return undefined;
32
+ try {
33
+ const parsed = JSON.parse(read.out.trim());
34
+ const root = parsed.kindgi?.root;
35
+ return typeof root === 'string'
36
+ ? { root, createdBy: String(parsed.kindgi?.createdBy ?? 'unknown') }
37
+ : undefined;
38
+ }
39
+ catch {
40
+ return undefined;
41
+ }
42
+ };
43
+ const setOwner = (database, value) => run(`COMMENT ON DATABASE ${identifier(database)} IS ${literal(JSON.stringify({ kindgi: value }))}`);
44
+ return {
45
+ urlFor(database) {
46
+ const url = new URL(input.baseUrl);
47
+ url.pathname = `/${database}`;
48
+ return url.toString();
49
+ },
50
+ exists,
51
+ async ensure(project, cliVersion) {
52
+ const recorded = { root: project.root, createdBy: cliVersion };
53
+ if (!(await exists(project.database))) {
54
+ const created = await run(`CREATE DATABASE ${identifier(project.database)}`);
55
+ // Two packs of one project starting at once: the other one made it.
56
+ if (!created.ok && !/already exists/.test(created.error)) {
57
+ return {
58
+ kind: 'error',
59
+ message: `could not create ${project.database}: ${created.error}`,
60
+ };
61
+ }
62
+ if (created.ok) {
63
+ const commented = await setOwner(project.database, recorded);
64
+ if (!commented.ok) {
65
+ return {
66
+ kind: 'error',
67
+ message: `could not record ${project.database}'s folder: ${commented.error}`,
68
+ };
69
+ }
70
+ return { kind: 'created' };
71
+ }
72
+ }
73
+ const current = await owner(project.database);
74
+ if (current === undefined) {
75
+ // A database without Kindgi's record (made by hand): this folder's now.
76
+ const commented = await setOwner(project.database, recorded);
77
+ return commented.ok
78
+ ? { kind: 'exists' }
79
+ : {
80
+ kind: 'error',
81
+ message: `could not record ${project.database}'s folder: ${commented.error}`,
82
+ };
83
+ }
84
+ if (current.root === project.root)
85
+ return { kind: 'exists' };
86
+ if (folderExists(current.root)) {
87
+ return {
88
+ kind: 'refused',
89
+ message: `the database ${project.database} belongs to ${current.root}, another folder whose project is also named "${project.name}". Give this one its own name: set \`project\` in kindgi.config.ts (or \`project\` under [tool.kindgi] in pyproject.toml), or pass --database-url.`,
90
+ };
91
+ }
92
+ const moved = await setOwner(project.database, {
93
+ root: project.root,
94
+ createdBy: current.createdBy,
95
+ });
96
+ return moved.ok
97
+ ? { kind: 'adopted', previousRoot: current.root }
98
+ : {
99
+ kind: 'error',
100
+ message: `could not record ${project.database}'s folder: ${moved.error}`,
101
+ };
102
+ },
103
+ async drop(database) {
104
+ const dropped = await run(`DROP DATABASE IF EXISTS ${identifier(database)} WITH (FORCE)`);
105
+ return dropped.ok ? { ok: true } : { ok: false, error: dropped.error };
106
+ },
107
+ };
108
+ }
109
+ /** A database name as a quoted identifier (names from `projectDatabaseName` are already plain). */
110
+ function identifier(name) {
111
+ return `"${name.replace(/"/g, '""')}"`;
112
+ }
113
+ /** A SQL string literal. */
114
+ function literal(value) {
115
+ return `'${value.replace(/'/g, "''")}'`;
116
+ }
117
+ /**
118
+ * The real runner: `docker exec kindgi-dev_postgres psql -U kindgi -d kindgi
119
+ * -tA -v ON_ERROR_STOP=1 -c <sql>`, through the CLI's docker helper.
120
+ */
121
+ export function bundledSqlRunner(docker) {
122
+ return async (sql) => {
123
+ const out = await docker([
124
+ 'exec',
125
+ BUNDLED_POSTGRES_CONTAINER,
126
+ 'psql',
127
+ '-U',
128
+ 'kindgi',
129
+ '-d',
130
+ 'kindgi',
131
+ '-tA',
132
+ '-v',
133
+ 'ON_ERROR_STOP=1',
134
+ '-c',
135
+ sql,
136
+ ]);
137
+ return out.code === 0
138
+ ? { ok: true, out: out.stdout }
139
+ : { ok: false, error: out.stderr.trim() || `psql exited ${out.code ?? 'without a code'}` };
140
+ };
141
+ }
142
+ //# sourceMappingURL=project-database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-database.js","sourceRoot":"","sources":["../../src/dev/project-database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /** Where the project's name came from. */
2
+ export type ProjectNameSource = 'config' | 'repository' | 'workspace' | 'pack folder';
3
+ export interface DevProject {
4
+ /** The project's name, as given or found. */
5
+ readonly name: string;
6
+ readonly nameFrom: ProjectNameSource;
7
+ /** This checkout's root: the worktree's, or the repository's, or the workspace's, or the pack's. */
8
+ readonly root: string;
9
+ /** In a linked git worktree: git's name for it. */
10
+ readonly worktree?: string;
11
+ /** The database in the bundled Postgres. */
12
+ readonly database: string;
13
+ /** The dev tenant every pack of this project (and worktree) shares. */
14
+ readonly tenantId: string;
15
+ /** The dev user the tenant's token resolves to. */
16
+ readonly userId: string;
17
+ }
18
+ /** What `git rev-parse` says about a folder: `undefined` outside a repository. */
19
+ export interface GitLocation {
20
+ readonly toplevel: string;
21
+ readonly gitDir: string;
22
+ readonly commonDir: string;
23
+ }
24
+ export type GitLocator = (dir: string) => Promise<GitLocation | undefined>;
25
+ export type ProjectOutcome = {
26
+ readonly kind: 'ok';
27
+ readonly project: DevProject;
28
+ } | {
29
+ readonly kind: 'invalid';
30
+ readonly message: string;
31
+ };
32
+ /**
33
+ * Resolve the project for a pack at `packDir`. `configured` is the
34
+ * config's `project` value, as loaded (validated here).
35
+ */
36
+ export declare function resolveDevProject(input: {
37
+ readonly packDir: string;
38
+ readonly configured: unknown;
39
+ readonly git?: GitLocator;
40
+ }): Promise<ProjectOutcome>;
41
+ /**
42
+ * The database's name: `kindgi_<project>`, plus `__<worktree>` in a linked
43
+ * worktree, in Postgres's plain-identifier characters. A name past 63
44
+ * bytes keeps its start and ends with a hash of the whole.
45
+ */
46
+ export declare function projectDatabaseName(project: string, worktree?: string): string;
47
+ /**
48
+ * The nearest folder at or above `dir` that roots a workspace: a
49
+ * `pnpm-workspace.yaml`, a `package.json` with `workspaces`, or a
50
+ * `pyproject.toml` with a uv workspace.
51
+ */
52
+ export declare function findWorkspaceRoot(dir: string): string | undefined;
53
+ /** `git rev-parse` for `dir`, with absolute paths; `undefined` outside a repository or without git. */
54
+ export declare const locateGit: GitLocator;
55
+ /** A name-based UUID (RFC 9562 version 5, SHA-1) in the dev namespace. */
56
+ export declare function uuidV5(name: string): string;
57
+ /** A name-based UUID (RFC 9562 version 5, SHA-1) in `namespace`. */
58
+ export declare function uuidV5In(namespace: string, name: string): string;
59
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/dev/project.ts"],"names":[],"mappings":"AA0BA,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,YAAY,GAAG,WAAW,GAAG,aAAa,CAAC;AAEtF,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,oGAAoG;IACpG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mDAAmD;IACnD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;AAQ3E,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC;CAC3B,GAAG,OAAO,CAAC,cAAc,CAAC,CA8C1B;AAOD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAK9E;AAsBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQjE;AAwBD,uGAAuG;AACvG,eAAO,MAAM,SAAS,EAAE,UAmBpB,CAAC;AAEL,0EAA0E;AAC1E,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAWhE"}
@@ -0,0 +1,182 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * The project `kindgi dev` runs in, and what it gets from it: one database
5
+ * in the bundled Postgres, and one dev tenant and user, for every pack of
6
+ * the project.
7
+ *
8
+ * - **The name:** `project` in the Kindgi config (`kindgi.config.ts`, or
9
+ * `[tool.kindgi]` in `pyproject.toml`); else the git repository's name
10
+ * (its main checkout's folder, the same in every worktree); else the
11
+ * nearest workspace root's folder; else the pack's folder.
12
+ * - **A linked git worktree** gets a database of its own,
13
+ * `kindgi_<project>__<worktree>`, named after git's own (unique) name for
14
+ * the worktree: branches on different Kindgi versions usually live in
15
+ * worktrees, and must not share a schema. The main checkout has
16
+ * `kindgi_<project>`.
17
+ * - **The tenant and user** derive from the database's name, so every pack
18
+ * of the project, and every restart, get the same ones.
19
+ */
20
+ import { execFile } from 'node:child_process';
21
+ import { createHash } from 'node:crypto';
22
+ import { existsSync, readFileSync } from 'node:fs';
23
+ import { basename, dirname, join, resolve } from 'node:path';
24
+ /** Postgres's identifier limit, in bytes. */
25
+ const MAX_IDENTIFIER = 63;
26
+ /** The namespace of the dev tenants' and users' UUIDs (v5). Never change it. */
27
+ const DEV_NAMESPACE = '7a1c5e2e-4b8f-5d6a-9c3e-1f0b2d4e6a8c';
28
+ /**
29
+ * Resolve the project for a pack at `packDir`. `configured` is the
30
+ * config's `project` value, as loaded (validated here).
31
+ */
32
+ export async function resolveDevProject(input) {
33
+ const packDir = resolve(input.packDir);
34
+ const configured = input.configured;
35
+ if (configured !== undefined && !isProjectName(configured)) {
36
+ return {
37
+ kind: 'invalid',
38
+ message: '`project` in the Kindgi config must be a name with at least one letter or digit, e.g. "acme-app".',
39
+ };
40
+ }
41
+ const git = await (input.git ?? locateGit)(packDir);
42
+ // A workspace root above the pack. The pack's own folder is no workspace
43
+ // of its own: `kindgi init` gives a pack its own pnpm-workspace.yaml.
44
+ const found = git === undefined ? findWorkspaceRoot(packDir) : undefined;
45
+ const workspace = found !== undefined && found !== packDir ? found : undefined;
46
+ const worktree = git !== undefined && linkedWorktree(git) ? basename(git.gitDir) : undefined;
47
+ let name;
48
+ let nameFrom;
49
+ if (configured !== undefined) {
50
+ name = configured;
51
+ nameFrom = 'config';
52
+ }
53
+ else if (git !== undefined) {
54
+ name = repositoryName(git);
55
+ nameFrom = 'repository';
56
+ }
57
+ else if (workspace !== undefined) {
58
+ name = basename(workspace);
59
+ nameFrom = 'workspace';
60
+ }
61
+ else {
62
+ name = basename(packDir);
63
+ nameFrom = 'pack folder';
64
+ }
65
+ const root = git?.toplevel ?? workspace ?? packDir;
66
+ const database = projectDatabaseName(name, worktree);
67
+ return {
68
+ kind: 'ok',
69
+ project: {
70
+ name,
71
+ nameFrom,
72
+ root,
73
+ ...(worktree !== undefined && { worktree }),
74
+ database,
75
+ tenantId: uuidV5(`tenant:${database}`),
76
+ userId: uuidV5(`user:${database}`),
77
+ },
78
+ };
79
+ }
80
+ /** A usable `project` value: a string with a letter or digit in it. */
81
+ function isProjectName(value) {
82
+ return typeof value === 'string' && slug(value) !== '';
83
+ }
84
+ /**
85
+ * The database's name: `kindgi_<project>`, plus `__<worktree>` in a linked
86
+ * worktree, in Postgres's plain-identifier characters. A name past 63
87
+ * bytes keeps its start and ends with a hash of the whole.
88
+ */
89
+ export function projectDatabaseName(project, worktree) {
90
+ const full = `kindgi_${slug(project) || 'project'}${worktree === undefined ? '' : `__${slug(worktree) || 'worktree'}`}`;
91
+ if (full.length <= MAX_IDENTIFIER)
92
+ return full;
93
+ const hash = createHash('sha256').update(full).digest('hex').slice(0, 8);
94
+ return `${full.slice(0, MAX_IDENTIFIER - hash.length - 1).replace(/_+$/, '')}_${hash}`;
95
+ }
96
+ /** Lowercase letters, digits and single underscores: each other run becomes one `_`. */
97
+ function slug(value) {
98
+ return value
99
+ .toLowerCase()
100
+ .replace(/[^a-z0-9]+/g, '_')
101
+ .replace(/^_+|_+$/g, '');
102
+ }
103
+ /** A linked worktree: its git dir isn't the repository's common one. */
104
+ function linkedWorktree(git) {
105
+ return resolve(git.gitDir) !== resolve(git.commonDir);
106
+ }
107
+ /** The repository's name: its main checkout's folder (`<root>/.git`), or a bare repository's. */
108
+ function repositoryName(git) {
109
+ const common = resolve(git.commonDir);
110
+ if (basename(common) === '.git')
111
+ return basename(dirname(common));
112
+ return basename(common).replace(/\.git$/, '') || basename(git.toplevel);
113
+ }
114
+ /**
115
+ * The nearest folder at or above `dir` that roots a workspace: a
116
+ * `pnpm-workspace.yaml`, a `package.json` with `workspaces`, or a
117
+ * `pyproject.toml` with a uv workspace.
118
+ */
119
+ export function findWorkspaceRoot(dir) {
120
+ let current = resolve(dir);
121
+ for (;;) {
122
+ if (isWorkspaceRoot(current))
123
+ return current;
124
+ const parent = dirname(current);
125
+ if (parent === current)
126
+ return undefined;
127
+ current = parent;
128
+ }
129
+ }
130
+ function isWorkspaceRoot(dir) {
131
+ if (existsSync(join(dir, 'pnpm-workspace.yaml')))
132
+ return true;
133
+ const pkg = readIfExists(join(dir, 'package.json'));
134
+ if (pkg !== undefined) {
135
+ try {
136
+ if (JSON.parse(pkg).workspaces !== undefined)
137
+ return true;
138
+ }
139
+ catch {
140
+ // Not JSON: not a workspace root.
141
+ }
142
+ }
143
+ const pyproject = readIfExists(join(dir, 'pyproject.toml'));
144
+ return pyproject !== undefined && /^\s*\[tool\.uv\.workspace\]/m.test(pyproject);
145
+ }
146
+ function readIfExists(path) {
147
+ try {
148
+ return readFileSync(path, 'utf8');
149
+ }
150
+ catch {
151
+ return undefined;
152
+ }
153
+ }
154
+ /** `git rev-parse` for `dir`, with absolute paths; `undefined` outside a repository or without git. */
155
+ export const locateGit = (dir) => new Promise((resolvePromise) => {
156
+ execFile('git', ['rev-parse', '--path-format=absolute', '--show-toplevel', '--git-dir', '--git-common-dir'], { cwd: dir, timeout: 5000 }, (err, stdout) => {
157
+ if (err !== null) {
158
+ resolvePromise(undefined);
159
+ return;
160
+ }
161
+ const [toplevel, gitDir, commonDir] = stdout.trim().split('\n');
162
+ resolvePromise(toplevel !== undefined && gitDir !== undefined && commonDir !== undefined
163
+ ? { toplevel, gitDir, commonDir }
164
+ : undefined);
165
+ });
166
+ });
167
+ /** A name-based UUID (RFC 9562 version 5, SHA-1) in the dev namespace. */
168
+ export function uuidV5(name) {
169
+ return uuidV5In(DEV_NAMESPACE, name);
170
+ }
171
+ /** A name-based UUID (RFC 9562 version 5, SHA-1) in `namespace`. */
172
+ export function uuidV5In(namespace, name) {
173
+ const bytes = createHash('sha1')
174
+ .update(Buffer.concat([Buffer.from(namespace.replace(/-/g, ''), 'hex'), Buffer.from(name, 'utf8')]))
175
+ .digest()
176
+ .subarray(0, 16);
177
+ bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x50;
178
+ bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;
179
+ const hex = bytes.toString('hex');
180
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
181
+ }
182
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/dev/project.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ import type { Provider, RegisterProviderInput } from '@kindgi/client';
2
+ import { type ProviderPreset } from '../providers/preset-loader.js';
3
+ /** A provider the config declares, as it will be registered. */
4
+ export interface DeclaredProvider {
5
+ readonly id: string;
6
+ readonly input: RegisterProviderInput;
7
+ }
8
+ export type DeclaredProvidersOutcome = {
9
+ readonly kind: 'ok';
10
+ readonly providers: readonly DeclaredProvider[];
11
+ } | {
12
+ readonly kind: 'invalid';
13
+ readonly message: string;
14
+ };
15
+ /**
16
+ * The config's `providers`, as registration bodies. `file` names the
17
+ * config in the messages (`kindgi.config.ts`, `pyproject.toml`).
18
+ */
19
+ export declare function declaredProviders(config: Readonly<Record<string, unknown>> | undefined, file: string, presets: Readonly<Record<string, ProviderPreset>>): DeclaredProvidersOutcome;
20
+ /** What this pack registered: hashes of the declared body and of the runtime's listing after. */
21
+ export interface OwnedProvider {
22
+ readonly declared: string;
23
+ readonly registered: string;
24
+ }
25
+ export type OwnedProviders = Readonly<Record<string, OwnedProvider>>;
26
+ /** Where `kindgi dev` records which providers this pack registered. */
27
+ export declare function devProvidersRecordPath(packDir: string): string;
28
+ /**
29
+ * The record's key: the dev database (host, port, name; never the
30
+ * credentials) and the tenant. Another database, or a new tenant, starts
31
+ * with nothing owned.
32
+ */
33
+ export declare function devProvidersKey(databaseUrl: string | undefined, tenantId: string): string;
34
+ /** This pack's providers in that database and tenant; nothing when the record is missing or unreadable. */
35
+ export declare function readOwnedProviders(path: string, key: string): Promise<OwnedProviders>;
36
+ export declare function writeOwnedProviders(path: string, key: string, owned: OwnedProviders): Promise<void>;
37
+ export interface ProvidersClient {
38
+ /** Every provider of the tenant (all pages). */
39
+ readonly list: () => Promise<readonly Provider[]>;
40
+ readonly register: (input: RegisterProviderInput) => Promise<unknown>;
41
+ readonly unregister: (id: string) => Promise<unknown>;
42
+ }
43
+ export type ProviderOutcome = {
44
+ readonly id: string;
45
+ readonly kind: 'registered' | 'updated' | 'unchanged' | 'removed';
46
+ }
47
+ /** Registered already, as declared, but not by this pack: left. */
48
+ | {
49
+ readonly id: string;
50
+ readonly kind: 'present';
51
+ }
52
+ /** Registered already, differently, not by this pack: left. */
53
+ | {
54
+ readonly id: string;
55
+ readonly kind: 'conflict';
56
+ }
57
+ /** This pack's before, changed since in the runtime: left, and no longer this pack's. */
58
+ | {
59
+ readonly id: string;
60
+ readonly kind: 'released';
61
+ }
62
+ /** Its secret isn't in the env files: not registered. */
63
+ | {
64
+ readonly id: string;
65
+ readonly kind: 'skipped';
66
+ readonly secret: string;
67
+ } | {
68
+ readonly id: string;
69
+ readonly kind: 'failed';
70
+ readonly message: string;
71
+ };
72
+ export interface ReconcileInputs {
73
+ readonly declared: readonly DeclaredProvider[];
74
+ readonly owned: OwnedProviders;
75
+ readonly client: ProvidersClient;
76
+ /** Whether a secret of `local` can be resolved (it's in the pack's env files). */
77
+ readonly hasSecret: (name: string) => boolean;
78
+ }
79
+ export interface ReconcileResult {
80
+ readonly outcomes: readonly ProviderOutcome[];
81
+ /** The record to keep. */
82
+ readonly owned: OwnedProviders;
83
+ }
84
+ /** Bring the runtime's providers in step with the config's. Throws only when they can't be listed. */
85
+ export declare function reconcileProviders(inputs: ReconcileInputs): Promise<ReconcileResult>;
86
+ export interface DescribeInputs {
87
+ /** The config's file name. */
88
+ readonly file: string;
89
+ /** A `kindgi` command line, in the pack's own runner. */
90
+ readonly kindgi: (...args: string[]) => string;
91
+ /** The env files `local` reads, for a missing secret's line. */
92
+ readonly envFiles: string;
93
+ }
94
+ /** The boot log's lines for a reconcile; none when the config declares nothing and nothing changed. */
95
+ export declare function describeReconcile(outcomes: readonly ProviderOutcome[], inputs: DescribeInputs): readonly string[];
96
+ //# sourceMappingURL=providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/dev/providers.ts"],"names":[],"mappings":"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"}