@askdb/config 1.0.0-beta.16 → 1.0.0-beta.18

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 (69) hide show
  1. package/README.md +15 -4
  2. package/dist/ai-env.d.ts +31 -0
  3. package/dist/ai-env.d.ts.map +1 -0
  4. package/dist/ai-env.js +88 -0
  5. package/dist/ai-env.js.map +1 -0
  6. package/dist/bootstrap.d.ts +6 -4
  7. package/dist/bootstrap.d.ts.map +1 -1
  8. package/dist/bootstrap.js +6 -17
  9. package/dist/bootstrap.js.map +1 -1
  10. package/dist/defaults.d.ts +7 -20
  11. package/dist/defaults.d.ts.map +1 -1
  12. package/dist/defaults.js +7 -58
  13. package/dist/defaults.js.map +1 -1
  14. package/dist/env.d.ts +2 -1
  15. package/dist/env.d.ts.map +1 -1
  16. package/dist/env.js +2 -1
  17. package/dist/env.js.map +1 -1
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/load-merge.js +1 -1
  23. package/dist/load-merge.js.map +1 -1
  24. package/dist/projection.d.ts +12 -2
  25. package/dist/projection.d.ts.map +1 -1
  26. package/dist/projection.js +18 -6
  27. package/dist/projection.js.map +1 -1
  28. package/dist/resolve.d.ts +36 -0
  29. package/dist/resolve.d.ts.map +1 -0
  30. package/dist/{normalize.js → resolve.js} +375 -8
  31. package/dist/resolve.js.map +1 -0
  32. package/dist/runtime-config.d.ts +5 -173
  33. package/dist/runtime-config.d.ts.map +1 -1
  34. package/dist/runtime-config.js +18 -222
  35. package/dist/runtime-config.js.map +1 -1
  36. package/dist/runtime-store.d.ts +9 -6
  37. package/dist/runtime-store.d.ts.map +1 -1
  38. package/dist/runtime-store.js +9 -11
  39. package/dist/runtime-store.js.map +1 -1
  40. package/dist/runtime-types.d.ts +176 -0
  41. package/dist/runtime-types.d.ts.map +1 -0
  42. package/dist/runtime-types.js +2 -0
  43. package/dist/runtime-types.js.map +1 -0
  44. package/dist/scaffold/ai.d.ts +3 -0
  45. package/dist/scaffold/ai.d.ts.map +1 -1
  46. package/dist/scaffold/ai.js +3 -0
  47. package/dist/scaffold/ai.js.map +1 -1
  48. package/dist/scaffold/index.d.ts +12 -3
  49. package/dist/scaffold/index.d.ts.map +1 -1
  50. package/dist/scaffold/index.js +10 -3
  51. package/dist/scaffold/index.js.map +1 -1
  52. package/dist/scaffold/package-manager.d.ts +93 -0
  53. package/dist/scaffold/package-manager.d.ts.map +1 -0
  54. package/dist/scaffold/package-manager.js +200 -0
  55. package/dist/scaffold/package-manager.js.map +1 -0
  56. package/dist/scaffold/plan.d.ts +110 -0
  57. package/dist/scaffold/plan.d.ts.map +1 -0
  58. package/dist/scaffold/plan.js +301 -0
  59. package/dist/scaffold/plan.js.map +1 -0
  60. package/dist/types.d.ts +6 -13
  61. package/dist/types.d.ts.map +1 -1
  62. package/package.json +1 -1
  63. package/dist/flatten.d.ts +0 -14
  64. package/dist/flatten.d.ts.map +0 -1
  65. package/dist/flatten.js +0 -255
  66. package/dist/flatten.js.map +0 -1
  67. package/dist/normalize.d.ts +0 -58
  68. package/dist/normalize.d.ts.map +0 -1
  69. package/dist/normalize.js.map +0 -1
@@ -0,0 +1,176 @@
1
+ import type { AskDbDialectId, AskDbIntrospectionProvider, AskDbLogLevel, AskDbModeV1, AskDbRagStore, AskDbStudioExecuteProvider } from "./constants.js";
2
+ import type { AskDbConfig } from "./types.js";
3
+ /** One resolved `ai` section: its provider, the connection it uses, its model, and an env view built from that connection only. */
4
+ export type AskDbRuntimeAiSection = {
5
+ provider: string;
6
+ /** Connection name within `ai.providerConfig.<provider>`. */
7
+ connection: string;
8
+ model: string | undefined;
9
+ /** `AiEnv` for `@askdb/ai` registry calls, built from this section's connection only. */
10
+ env: Record<string, string | undefined>;
11
+ };
12
+ /**
13
+ * Typed AI runtime settings for `@askdb/core` (not `process.env`).
14
+ */
15
+ export type AskDbRuntimeAiConfig = {
16
+ /**
17
+ * Flat env-shaped map built from the runtime snapshot: the language view plus every other
18
+ * canonical key. Pass to `@askdb/ai` registry methods such as `resolveAiConfig` and
19
+ * `createLanguageModelFromEnv`.
20
+ */
21
+ aiEnv: Record<string, string | undefined>;
22
+ /** `ai.language`: the language model. `model` is undefined only for a custom provider with no model set. */
23
+ language: AskDbRuntimeAiSection & {
24
+ modelFamily: string | undefined;
25
+ };
26
+ /**
27
+ * `ai.embedding`: the embedding model. Undefined unless `rag.embedder` is `"ai"`. Pass `env`
28
+ * to `resolveEmbeddingConfig` / `createEmbeddingModelFromEnv`, and `{ dimensions }` as the
29
+ * latter's options: `env` holds the connection and model, not the width.
30
+ */
31
+ embedding: (AskDbRuntimeAiSection & {
32
+ model: string;
33
+ /**
34
+ * `ai.embedding.dimensions`: the vector size to request from the provider. Undefined
35
+ * leaves the width to the model; `detectEmbeddingDimensions` in `@askdb/rag` learns it.
36
+ */
37
+ dimensions: number | undefined;
38
+ }) | undefined;
39
+ };
40
+ /**
41
+ * OpenAI embedder settings for the `askdb-rag` CLI. Filled from `ai.embedding` when its provider
42
+ * is `openai`; otherwise only from the OpenAI language connection.
43
+ */
44
+ export type AskDbRuntimeRagEmbedderConfig = {
45
+ apiKey: string | undefined;
46
+ baseURL: string | undefined;
47
+ model: string | undefined;
48
+ };
49
+ export type AskDbRuntimeRagConfig = {
50
+ embedder: AskDbRuntimeRagEmbedderConfig;
51
+ /** `rag.store`, or `"memory"` when the config has no `rag` block. Read this rather than `structured.rag`, which is `undefined` when the block is omitted. */
52
+ store: AskDbRagStore;
53
+ /** `rag.storeConfig` as written, with no defaults filled in; `{}` when the config has no `rag` block or the block has no `storeConfig`. */
54
+ storeConfig: NonNullable<AskDbConfig["rag"]>["storeConfig"];
55
+ };
56
+ export type AskDbRuntimeLoggingConfig = {
57
+ /** `logging.level`; `undefined` leaves the level to each tool (the CLI and the HTTP API server differ). */
58
+ level: AskDbLogLevel | undefined;
59
+ correlationId: string | undefined;
60
+ logFile: string | undefined;
61
+ logStdout: boolean;
62
+ };
63
+ export type AskDbRuntimeHttpApiConfig = {
64
+ listen: {
65
+ port: number;
66
+ host: string;
67
+ };
68
+ /** Whether `POST /ask` accepts a per-request `schemaJson` override. Default `false`. */
69
+ allowSchemaOverride: boolean;
70
+ /** Model-call timeout per `POST /ask` request, in milliseconds (1 to 2147483647). Default `60000`. */
71
+ requestTimeoutMs: number;
72
+ };
73
+ export type AskDbRuntimeIntrospectionConfig = {
74
+ provider: AskDbIntrospectionProvider;
75
+ /**
76
+ * Resolved Postgres connection URL when `provider === "postgres"`:
77
+ * `providerConfig.postgres.databaseUrl`. Never read from `process.env`.
78
+ * `undefined` for non-Postgres providers.
79
+ */
80
+ postgresDatabaseUrl: string | undefined;
81
+ /** Resolved from `introspection.providerConfig.prisma.schemaPath`; `undefined` triggers auto-discovery in `@askdb/prisma`. */
82
+ prismaSchemaPath: string | undefined;
83
+ /**
84
+ * Resolved MySQL connection URL when `provider === "mysql"`:
85
+ * `providerConfig.mysql.databaseUrl`. Never read from `process.env`.
86
+ * `undefined` for non-MySQL providers.
87
+ */
88
+ mysqlDatabaseUrl: string | undefined;
89
+ /**
90
+ * Schemas (MySQL/MariaDB: databases) to introspect, for every provider: `introspection.schemas`.
91
+ * `undefined` means the engine's default. `askdb introspect --schemas` overrides it.
92
+ */
93
+ schemas: string[] | undefined;
94
+ /**
95
+ * Resolved SQLite file path when `provider === "sqlite"`:
96
+ * `providerConfig.sqlite.file`. Never read from `process.env`.
97
+ * `undefined` for non-SQLite providers.
98
+ */
99
+ sqliteFile: string | undefined;
100
+ /**
101
+ * Resolved SQL Server connection URL when `provider === "sqlserver"`:
102
+ * `providerConfig.sqlserver.databaseUrl`. Never read from `process.env`.
103
+ * `undefined` for non-SQL Server providers.
104
+ */
105
+ sqlserverDatabaseUrl: string | undefined;
106
+ /** Resolved from `introspection.outputDir`; falls back to the package default (`./askdb/`). */
107
+ outputDir: string;
108
+ };
109
+ export type AskDbRuntimeDevConfig = {
110
+ mockSql: string | undefined;
111
+ };
112
+ export type AskDbRuntimeModesConfig = {
113
+ /** `modes.askdbMode`; `undefined` means `"schema_only"`. */
114
+ askdbMode: AskDbModeV1 | undefined;
115
+ omitSensitiveFromPrompt: boolean;
116
+ };
117
+ export type AskDbRuntimeNlToSqlConfig = {
118
+ /**
119
+ * Optional NL→SQL dialect override from `askdb.config.ts`. When set, hosts
120
+ * (CLI / HTTP API / Studio) pass this to `ask({ dialect })` instead of
121
+ * inferring from the introspection provider.
122
+ */
123
+ dialect: AskDbDialectId | undefined;
124
+ };
125
+ export type AskDbRuntimeStudioConfig = {
126
+ execute: {
127
+ /**
128
+ * Resolved execute provider. Falls back to the active introspection provider when it
129
+ * is a live engine (`postgres`, `mysql`, `sqlite`, `sqlserver`), then defaults to
130
+ * `"postgres"`.
131
+ */
132
+ provider: AskDbStudioExecuteProvider;
133
+ /** Connection URL used by the Studio playground query runner for network databases. */
134
+ databaseUrl: string | undefined;
135
+ /** SQLite file path used when `provider === "sqlite"`. */
136
+ file: string | undefined;
137
+ /** Whether `POST /api/execute` is allowed. Default `false` (opt-in). */
138
+ enabled: boolean;
139
+ /**
140
+ * Whether `databaseUrl` / `file` may fall back to the active introspection
141
+ * connection. Default `false`.
142
+ */
143
+ useIntrospectionConnection: boolean;
144
+ /**
145
+ * True when the introspection config has a connection for this provider that
146
+ * Studio did not use because `useIntrospectionConnection` is off. Lets hosts
147
+ * explain why execute reports "not configured".
148
+ */
149
+ introspectionConnectionAvailable: boolean;
150
+ /** Per-query timeout in milliseconds. Default `30000`. */
151
+ timeoutMs: number;
152
+ /** Maximum rows returned per query. Default `500`. */
153
+ maxRows: number;
154
+ };
155
+ };
156
+ /**
157
+ * Typed runtime view over the bootstrapped AskDB config snapshot. Every field is resolved from
158
+ * `structured`; `flat` and `ai.aiEnv` are projections of the same resolution, never read back.
159
+ */
160
+ export type AskDbRuntimeConfig = {
161
+ readonly structured: Readonly<AskDbConfig>;
162
+ /** Canonical flattened map (subprocess env via {@link mergeAskDbFlatIntoEnvMap}), built from `structured`. */
163
+ readonly flat: Readonly<Record<string, string>>;
164
+ ai: AskDbRuntimeAiConfig;
165
+ introspection: AskDbRuntimeIntrospectionConfig;
166
+ rag: AskDbRuntimeRagConfig;
167
+ logging: AskDbRuntimeLoggingConfig;
168
+ httpApi: AskDbRuntimeHttpApiConfig;
169
+ dev: AskDbRuntimeDevConfig;
170
+ modes: AskDbRuntimeModesConfig;
171
+ nlToSql: AskDbRuntimeNlToSqlConfig;
172
+ studio: AskDbRuntimeStudioConfig;
173
+ /** One message per deprecated config key in use (it names the old and new key, never a value). */
174
+ deprecations: readonly string[];
175
+ };
176
+ //# sourceMappingURL=runtime-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-types.d.ts","sourceRoot":"","sources":["../src/runtime-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=runtime-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-types.js","sourceRoot":"","sources":["../src/runtime-types.ts"],"names":[],"mappings":""}
@@ -25,6 +25,9 @@ export type AskDbAiConfigScaffold = {
25
25
  *
26
26
  * Every value is emitted as a JSON string literal: the generated file is
27
27
  * executed when the config loads, so a raw quote in a name must not inject code.
28
+ *
29
+ * @experimental Tooling for `askdb init` and AskDB Studio: a minor release of
30
+ * `@askdb/config` may change it (ADR 0030).
28
31
  */
29
32
  export declare function renderAskDbAiConfigScaffold(input: AskDbAiConfigScaffoldInput): AskDbAiConfigScaffold;
30
33
  //# sourceMappingURL=ai.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/scaffold/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE7E,4DAA4D;AAC5D,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,oHAAoH;IACpH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAChC,CAAC;AAYF;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,0BAA0B,GAAG,qBAAqB,CAmCpG"}
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/scaffold/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE7E,4DAA4D;AAC5D,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,oHAAoH;IACpH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAChC,CAAC;AAYF;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,0BAA0B,GAAG,qBAAqB,CAmCpG"}
@@ -14,6 +14,9 @@ const AZURE_RESOURCE_NAME_ENV = "AZURE_RESOURCE_NAME";
14
14
  *
15
15
  * Every value is emitted as a JSON string literal: the generated file is
16
16
  * executed when the config loads, so a raw quote in a name must not inject code.
17
+ *
18
+ * @experimental Tooling for `askdb init` and AskDB Studio: a minor release of
19
+ * `@askdb/config` may change it (ADR 0030).
17
20
  */
18
21
  export function renderAskDbAiConfigScaffold(input) {
19
22
  const { provider, keyEnv, modelEnv } = input;
@@ -1 +1 @@
1
- {"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/scaffold/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA0B,MAAM,iBAAiB,CAAC;AAwB7E,SAAS,YAAY,CAAC,QAAgB;IACpC,OAAQ,kBAAwC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CAAC,KAAiC;IAC3E,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC7C,8EAA8E;IAC9E,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,OAAO,GAA0B,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,UAAU,EAAE,CAAC,CAAC;IAC1F,MAAM,MAAM,GAAG,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3D,oGAAoG;IACpG,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,iBAAiB,EAAE,CAAC,CAAC;QACxE,QAAQ,GAAG;;mBAEI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;OACpC,CAAC;IACN,CAAC;IACD,gFAAgF;IAChF,yEAAyE;IACzE,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,uBAAuB;YAC7B,OAAO,EAAE,kFAAkF;SAC5F,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,qBAAqB,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,MAAM,GAAG;gBACD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;;QAEhC,QAAQ;EACd,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;QAE9C,QAAQ;KACX,CAAC;IACJ,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC"}
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../../src/scaffold/ai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA0B,MAAM,iBAAiB,CAAC;AAwB7E,SAAS,YAAY,CAAC,QAAgB;IACpC,OAAQ,kBAAwC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,2BAA2B,CAAC,KAAiC;IAC3E,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC7C,8EAA8E;IAC9E,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,OAAO,GAA0B,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,UAAU,EAAE,CAAC,CAAC;IAC1F,MAAM,MAAM,GAAG,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3D,oGAAoG;IACpG,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ,iBAAiB,EAAE,CAAC,CAAC;QACxE,QAAQ,GAAG;;mBAEI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;OACpC,CAAC;IACN,CAAC;IACD,gFAAgF;IAChF,yEAAyE;IACzE,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,uBAAuB;YAC7B,OAAO,EAAE,kFAAkF;SAC5F,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,qBAAqB,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,MAAM,GAAG;gBACD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;;QAEhC,QAAQ;EACd,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;QAE9C,QAAQ;KACX,CAAC;IACJ,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC"}
@@ -1,8 +1,17 @@
1
1
  /**
2
- * `@askdb/config/scaffold`: helpers for tools that write a new `askdb.config.ts`
3
- * (`askdb init`, Studio's setup wizard). Kept off the main entry, which user
4
- * configs import, so tooling can change without touching the config API.
2
+ * `@askdb/config/scaffold`: helpers for tools that set up a project and write a new
3
+ * `askdb.config.ts` (`askdb init`, Studio's setup wizard): the planner, which turns a
4
+ * project's answers into its config, `.env.example` and installs, and the package-manager
5
+ * helpers that run the installs. Kept off the main entry, which user configs import, so
6
+ * tooling can change without touching the config API.
7
+ *
8
+ * @experimental Tooling for `askdb init` and AskDB Studio: a minor release of
9
+ * `@askdb/config` may change these exports (ADR 0030).
5
10
  */
6
11
  export { renderAskDbAiConfigScaffold } from "./ai.js";
7
12
  export type { AskDbAiConfigScaffold, AskDbAiConfigScaffoldInput, AskDbScaffoldEnvVar } from "./ai.js";
13
+ export { AskDbScaffoldInputError, isAskDbScaffoldEnvName, planAskDbScaffold } from "./plan.js";
14
+ export type { AskDbScaffoldAnswers, AskDbScaffoldPlan, ScaffoldValue } from "./plan.js";
15
+ export { detectPackageManager, findNearestPackageJsonDir, formatInstallCommand, isLikelyWorkspaceRoot, lockfilePackageManager, packageManagerAddArgs, packageManagerSpawnSpec, supportedBuildApprovals, } from "./package-manager.js";
16
+ export type { PackageManager, PackageManagerSpawnSpec } from "./package-manager.js";
8
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,2BAA2B,EAAE,MAAM,SAAS,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,2BAA2B,EAAE,MAAM,SAAS,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACtG,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC/F,YAAY,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACxF,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1,7 +1,14 @@
1
1
  /**
2
- * `@askdb/config/scaffold`: helpers for tools that write a new `askdb.config.ts`
3
- * (`askdb init`, Studio's setup wizard). Kept off the main entry, which user
4
- * configs import, so tooling can change without touching the config API.
2
+ * `@askdb/config/scaffold`: helpers for tools that set up a project and write a new
3
+ * `askdb.config.ts` (`askdb init`, Studio's setup wizard): the planner, which turns a
4
+ * project's answers into its config, `.env.example` and installs, and the package-manager
5
+ * helpers that run the installs. Kept off the main entry, which user configs import, so
6
+ * tooling can change without touching the config API.
7
+ *
8
+ * @experimental Tooling for `askdb init` and AskDB Studio: a minor release of
9
+ * `@askdb/config` may change these exports (ADR 0030).
5
10
  */
6
11
  export { renderAskDbAiConfigScaffold } from "./ai.js";
12
+ export { AskDbScaffoldInputError, isAskDbScaffoldEnvName, planAskDbScaffold } from "./plan.js";
13
+ export { detectPackageManager, findNearestPackageJsonDir, formatInstallCommand, isLikelyWorkspaceRoot, lockfilePackageManager, packageManagerAddArgs, packageManagerSpawnSpec, supportedBuildApprovals, } from "./package-manager.js";
7
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,2BAA2B,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,2BAA2B,EAAE,MAAM,SAAS,CAAC;AAEtD,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE/F,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Package-manager helpers for the tools that set up a project: `askdb init` and
3
+ * Studio's setup wizard and execute-driver install. One copy, so the two front
4
+ * ends detect, format and spawn the same way.
5
+ *
6
+ * @experimental Tooling for `askdb init` and AskDB Studio: a minor release of
7
+ * `@askdb/config` may change these exports (ADR 0030).
8
+ *
9
+ * Only allowlisted package names ever reach these helpers, never user- or
10
+ * browser-supplied strings, but {@link packageManagerSpawnSpec} re-checks every
11
+ * argument anyway because Windows needs `shell: true` (see below).
12
+ */
13
+ /** @experimental See the module note. */
14
+ export type PackageManager = "pnpm" | "npm" | "yarn" | "bun";
15
+ /**
16
+ * The nearest directory at or above `startDir` that holds a `package.json`.
17
+ *
18
+ * @experimental See the module note.
19
+ */
20
+ export declare function findNearestPackageJsonDir(startDir: string): string | undefined;
21
+ /**
22
+ * Whether `packageDir` looks like a monorepo or workspace root (a `pnpm-workspace.yaml`,
23
+ * or a `workspaces` field), whose `package.json` setup tools leave alone.
24
+ *
25
+ * @experimental See the module note.
26
+ */
27
+ export declare function isLikelyWorkspaceRoot(packageDir: string): boolean;
28
+ /**
29
+ * The package manager implied by a lockfile directly inside `dir`, if any.
30
+ *
31
+ * @experimental See the module note.
32
+ */
33
+ export declare function lockfilePackageManager(dir: string): PackageManager | null;
34
+ /**
35
+ * The package manager to install with in `packageDir`, from the first of these that
36
+ * names one:
37
+ *
38
+ * 1. a lockfile in `packageDir` or a parent (pnpm, then Bun, Yarn, npm in one directory);
39
+ * 2. the nearest `package.json`, walking up, that declares a manager: its `packageManager`
40
+ * field (Corepack's `pnpm@11.28.10`), then `devEngines.packageManager` (`{ name }` or a
41
+ * list of them; `pnpm init` writes it);
42
+ * 3. `npm_config_user_agent` in `env`, which `pnpm dlx`, `yarn dlx`, `npx` and `bunx` set;
43
+ * 4. npm.
44
+ *
45
+ * An existing lockfile wins, so a project's install never switches managers.
46
+ *
47
+ * @experimental See the module note.
48
+ */
49
+ export declare function detectPackageManager(packageDir: string, env?: Readonly<Record<string, string | undefined>>): PackageManager;
50
+ /**
51
+ * Arguments that add `packages` as dependencies with the given package manager.
52
+ * `allowBuilds` are dependencies whose install scripts pnpm must be told to run
53
+ * (`--allow-build=<name>`; pnpm 11 exits 1 on an unapproved one). npm and Yarn
54
+ * run install scripts, and Bun skips untrusted ones without failing, so only
55
+ * pnpm gets them.
56
+ *
57
+ * @experimental See the module note.
58
+ */
59
+ export declare function packageManagerAddArgs(pm: PackageManager, packages: readonly string[], allowBuilds?: readonly string[]): string[];
60
+ /**
61
+ * The build approvals to pass `pm` in `dir`: `allowBuilds`, or none for a pnpm older
62
+ * than 10.4.0, whose `add` rejects `--allow-build` (pnpm 9 runs install scripts, and
63
+ * 10.0 to 10.3 skip unapproved ones without failing). A pnpm whose version can't be
64
+ * read keeps them.
65
+ *
66
+ * @experimental See the module note.
67
+ */
68
+ export declare function supportedBuildApprovals(pm: PackageManager, dir: string, allowBuilds: readonly string[]): string[];
69
+ /**
70
+ * Human-readable install command, e.g. `pnpm add pg`.
71
+ *
72
+ * @experimental See the module note.
73
+ */
74
+ export declare function formatInstallCommand(pm: PackageManager, packages: readonly string[], allowBuilds?: readonly string[]): string;
75
+ /** @experimental See the module note. */
76
+ export type PackageManagerSpawnSpec = {
77
+ command: string;
78
+ args: string[];
79
+ shell: boolean;
80
+ };
81
+ /**
82
+ * How to spawn a package manager on this platform.
83
+ *
84
+ * On Windows, package managers are `.cmd` shims, and Node refuses to spawn
85
+ * `.cmd`/`.bat` files without a shell (EINVAL since Node 18.20.2 / 20.12.2,
86
+ * CVE-2024-27980). So Windows gets `shell: true` with the bare command name.
87
+ * Arguments are validated against a strict allowlist pattern first, so the
88
+ * shell never sees anything it could interpret.
89
+ *
90
+ * @experimental See the module note.
91
+ */
92
+ export declare function packageManagerSpawnSpec(pm: PackageManager, args: readonly string[], platform?: NodeJS.Platform): PackageManagerSpawnSpec;
93
+ //# sourceMappingURL=package-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../src/scaffold/package-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,yCAAyC;AACzC,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;AAK7D;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE9E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAUjE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAMzE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,MAAM,EAClB,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAC9D,cAAc,CAWhB;AAuCD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,GAAE,SAAS,MAAM,EAAO,GAClC,MAAM,EAAE,CAIV;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAMjH;AAQD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,cAAc,EAClB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,GAAE,SAAS,MAAM,EAAO,GAClC,MAAM,CAER;AAED,yCAAyC;AACzC,MAAM,MAAM,uBAAuB,GAAG;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAQF;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC3C,uBAAuB,CAUzB"}
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Package-manager helpers for the tools that set up a project: `askdb init` and
3
+ * Studio's setup wizard and execute-driver install. One copy, so the two front
4
+ * ends detect, format and spawn the same way.
5
+ *
6
+ * @experimental Tooling for `askdb init` and AskDB Studio: a minor release of
7
+ * `@askdb/config` may change these exports (ADR 0030).
8
+ *
9
+ * Only allowlisted package names ever reach these helpers, never user- or
10
+ * browser-supplied strings, but {@link packageManagerSpawnSpec} re-checks every
11
+ * argument anyway because Windows needs `shell: true` (see below).
12
+ */
13
+ import { spawnSync } from "node:child_process";
14
+ import { existsSync, readFileSync } from "node:fs";
15
+ import { dirname, join, resolve } from "node:path";
16
+ /** How far up the helpers walk looking for a `package.json` or lockfile. */
17
+ const MAX_WALK_UP = 40;
18
+ /**
19
+ * The nearest directory at or above `startDir` that holds a `package.json`.
20
+ *
21
+ * @experimental See the module note.
22
+ */
23
+ export function findNearestPackageJsonDir(startDir) {
24
+ return ancestors(startDir).find((dir) => existsSync(join(dir, "package.json")));
25
+ }
26
+ /**
27
+ * Whether `packageDir` looks like a monorepo or workspace root (a `pnpm-workspace.yaml`,
28
+ * or a `workspaces` field), whose `package.json` setup tools leave alone.
29
+ *
30
+ * @experimental See the module note.
31
+ */
32
+ export function isLikelyWorkspaceRoot(packageDir) {
33
+ if (existsSync(join(packageDir, "pnpm-workspace.yaml")) || existsSync(join(packageDir, "pnpm-workspace.yml"))) {
34
+ return true;
35
+ }
36
+ try {
37
+ const pkg = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8"));
38
+ return pkg.workspaces !== undefined && pkg.workspaces !== null;
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ * The package manager implied by a lockfile directly inside `dir`, if any.
46
+ *
47
+ * @experimental See the module note.
48
+ */
49
+ export function lockfilePackageManager(dir) {
50
+ if (existsSync(join(dir, "pnpm-lock.yaml")))
51
+ return "pnpm";
52
+ if (existsSync(join(dir, "bun.lockb")) || existsSync(join(dir, "bun.lock")))
53
+ return "bun";
54
+ if (existsSync(join(dir, "yarn.lock")))
55
+ return "yarn";
56
+ if (existsSync(join(dir, "package-lock.json")))
57
+ return "npm";
58
+ return null;
59
+ }
60
+ /**
61
+ * The package manager to install with in `packageDir`, from the first of these that
62
+ * names one:
63
+ *
64
+ * 1. a lockfile in `packageDir` or a parent (pnpm, then Bun, Yarn, npm in one directory);
65
+ * 2. the nearest `package.json`, walking up, that declares a manager: its `packageManager`
66
+ * field (Corepack's `pnpm@11.28.10`), then `devEngines.packageManager` (`{ name }` or a
67
+ * list of them; `pnpm init` writes it);
68
+ * 3. `npm_config_user_agent` in `env`, which `pnpm dlx`, `yarn dlx`, `npx` and `bunx` set;
69
+ * 4. npm.
70
+ *
71
+ * An existing lockfile wins, so a project's install never switches managers.
72
+ *
73
+ * @experimental See the module note.
74
+ */
75
+ export function detectPackageManager(packageDir, env = process.env) {
76
+ const dirs = ancestors(packageDir);
77
+ for (const dir of dirs) {
78
+ const pm = lockfilePackageManager(dir);
79
+ if (pm)
80
+ return pm;
81
+ }
82
+ for (const dir of dirs) {
83
+ const pm = declaredPackageManager(dir);
84
+ if (pm)
85
+ return pm;
86
+ }
87
+ return knownPackageManager(env.npm_config_user_agent?.split("/")[0]) ?? "npm";
88
+ }
89
+ /** `dir` and its parents, nearest first, at most {@link MAX_WALK_UP} of them. */
90
+ function ancestors(dir) {
91
+ const dirs = [resolve(dir)];
92
+ while (dirs.length < MAX_WALK_UP) {
93
+ const parent = dirname(dirs[dirs.length - 1]);
94
+ if (parent === dirs[dirs.length - 1])
95
+ break;
96
+ dirs.push(parent);
97
+ }
98
+ return dirs;
99
+ }
100
+ /** The manager `dir/package.json` declares in `packageManager` or `devEngines.packageManager`. */
101
+ function declaredPackageManager(dir) {
102
+ let pkg;
103
+ try {
104
+ pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
105
+ }
106
+ catch {
107
+ return null;
108
+ }
109
+ if (pkg === null || typeof pkg !== "object")
110
+ return null;
111
+ if (typeof pkg.packageManager === "string") {
112
+ const pm = knownPackageManager(pkg.packageManager.split("@")[0]);
113
+ if (pm)
114
+ return pm;
115
+ }
116
+ const devEngine = pkg.devEngines?.packageManager;
117
+ for (const entry of Array.isArray(devEngine) ? devEngine : [devEngine]) {
118
+ const name = entry !== null && typeof entry === "object" ? entry.name : undefined;
119
+ const pm = knownPackageManager(name);
120
+ if (pm)
121
+ return pm;
122
+ }
123
+ return null;
124
+ }
125
+ function knownPackageManager(name) {
126
+ return name === "pnpm" || name === "npm" || name === "yarn" || name === "bun" ? name : null;
127
+ }
128
+ /**
129
+ * Arguments that add `packages` as dependencies with the given package manager.
130
+ * `allowBuilds` are dependencies whose install scripts pnpm must be told to run
131
+ * (`--allow-build=<name>`; pnpm 11 exits 1 on an unapproved one). npm and Yarn
132
+ * run install scripts, and Bun skips untrusted ones without failing, so only
133
+ * pnpm gets them.
134
+ *
135
+ * @experimental See the module note.
136
+ */
137
+ export function packageManagerAddArgs(pm, packages, allowBuilds = []) {
138
+ if (pm === "npm")
139
+ return ["install", "--save", ...packages];
140
+ if (pm === "pnpm")
141
+ return ["add", ...allowBuilds.map((name) => `--allow-build=${name}`), ...packages];
142
+ return ["add", ...packages];
143
+ }
144
+ /**
145
+ * The build approvals to pass `pm` in `dir`: `allowBuilds`, or none for a pnpm older
146
+ * than 10.4.0, whose `add` rejects `--allow-build` (pnpm 9 runs install scripts, and
147
+ * 10.0 to 10.3 skip unapproved ones without failing). A pnpm whose version can't be
148
+ * read keeps them.
149
+ *
150
+ * @experimental See the module note.
151
+ */
152
+ export function supportedBuildApprovals(pm, dir, allowBuilds) {
153
+ if (pm !== "pnpm" || allowBuilds.length === 0)
154
+ return [...allowBuilds];
155
+ const match = /^(\d+)\.(\d+)\./.exec(pnpmVersion(dir) ?? "");
156
+ if (!match)
157
+ return [...allowBuilds];
158
+ const [major, minor] = [Number(match[1]), Number(match[2])];
159
+ return major > 10 || (major === 10 && minor >= 4) ? [...allowBuilds] : [];
160
+ }
161
+ function pnpmVersion(dir) {
162
+ const { command, args, shell } = packageManagerSpawnSpec("pnpm", ["--version"]);
163
+ const result = spawnSync(command, args, { cwd: dir, encoding: "utf8", shell, stdio: ["ignore", "pipe", "ignore"], timeout: 15_000 });
164
+ return result.status === 0 ? result.stdout.trim() : null;
165
+ }
166
+ /**
167
+ * Human-readable install command, e.g. `pnpm add pg`.
168
+ *
169
+ * @experimental See the module note.
170
+ */
171
+ export function formatInstallCommand(pm, packages, allowBuilds = []) {
172
+ return [pm, ...packageManagerAddArgs(pm, packages, allowBuilds)].join(" ");
173
+ }
174
+ // npm package names (optionally scoped, optionally with a version/range suffix),
175
+ // simple `--flag` arguments, and pnpm's `--allow-build=<package name>`. Nothing a
176
+ // shell would interpret.
177
+ const SAFE_ARG = /^(?:--[a-z][a-z-]*|--allow-build=(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*|(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*(?:@[a-z0-9.^~<>=*_-]+)?|add|install)$/i;
178
+ /**
179
+ * How to spawn a package manager on this platform.
180
+ *
181
+ * On Windows, package managers are `.cmd` shims, and Node refuses to spawn
182
+ * `.cmd`/`.bat` files without a shell (EINVAL since Node 18.20.2 / 20.12.2,
183
+ * CVE-2024-27980). So Windows gets `shell: true` with the bare command name.
184
+ * Arguments are validated against a strict allowlist pattern first, so the
185
+ * shell never sees anything it could interpret.
186
+ *
187
+ * @experimental See the module note.
188
+ */
189
+ export function packageManagerSpawnSpec(pm, args, platform = process.platform) {
190
+ for (const arg of args) {
191
+ if (!SAFE_ARG.test(arg)) {
192
+ throw new Error(`Refusing to pass unsafe argument to ${pm}: ${JSON.stringify(arg)}`);
193
+ }
194
+ }
195
+ if (platform === "win32") {
196
+ return { command: pm, args: [...args], shell: true };
197
+ }
198
+ return { command: pm, args: [...args], shell: false };
199
+ }
200
+ //# sourceMappingURL=package-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-manager.js","sourceRoot":"","sources":["../../src/scaffold/package-manager.ts"],"names":[],"mappings":"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"}