@bakers-build/core 0.0.0-stage → 0.1.0-next.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +4 -2
- package/dist/src/cli/bakers-dir.d.ts +99 -0
- package/dist/src/cli/bakers-dir.js +228 -0
- package/dist/src/cli/commands.d.ts +42 -0
- package/dist/src/cli/commands.js +1 -0
- package/dist/src/cli/config-inventory.d.ts +30 -0
- package/dist/src/cli/config-inventory.js +502 -0
- package/dist/src/cli/config-online.d.ts +49 -0
- package/dist/src/cli/config-online.js +238 -0
- package/dist/src/cli/config-report.d.ts +100 -0
- package/dist/src/cli/config-report.js +29 -0
- package/dist/src/cli/config-source.d.ts +89 -0
- package/dist/src/cli/config-source.js +363 -0
- package/dist/src/cli/import-config.d.ts +20 -0
- package/dist/src/cli/import-config.js +141 -0
- package/dist/src/cli/layered-ui-entries.d.ts +36 -0
- package/dist/src/cli/layered-ui-entries.js +49 -0
- package/dist/src/cli/load-bakers-config.d.ts +108 -0
- package/dist/src/cli/load-bakers-config.js +422 -0
- package/dist/src/cli/machine-context.d.ts +48 -0
- package/dist/src/cli/machine-context.js +36 -0
- package/dist/src/cli/paths.d.ts +3 -0
- package/dist/src/cli/paths.js +17 -0
- package/dist/src/cli/resolve-module.d.ts +6 -0
- package/dist/src/cli/resolve-module.js +44 -0
- package/dist/src/cli/version-check.d.ts +31 -0
- package/dist/src/cli/version-check.js +151 -0
- package/dist/src/cli/workspace-recovery.d.ts +43 -0
- package/dist/src/cli/workspace-recovery.js +95 -0
- package/dist/src/core/checkout-root.d.ts +33 -0
- package/dist/src/core/checkout-root.js +49 -0
- package/dist/src/core/conductor-id.d.ts +1 -0
- package/dist/src/core/conductor-id.js +8 -0
- package/dist/src/core/exec.d.ts +41 -0
- package/dist/src/core/exec.js +81 -0
- package/dist/src/core/liveness.d.ts +53 -0
- package/dist/src/core/liveness.js +56 -0
- package/dist/src/core/logger.d.ts +56 -0
- package/dist/src/core/logger.js +78 -0
- package/dist/src/core/proc.d.ts +77 -0
- package/dist/src/core/proc.js +156 -0
- package/dist/src/core/shell.d.ts +11 -0
- package/dist/src/core/shell.js +13 -0
- package/dist/src/core/slug.d.ts +9 -0
- package/dist/src/core/slug.js +18 -0
- package/dist/src/index.d.ts +28 -0
- package/dist/src/index.js +44 -0
- package/dist/src/plugins/discover-addons.d.ts +69 -0
- package/dist/src/plugins/discover-addons.js +359 -0
- package/dist/src/plugins/preset.d.ts +149 -0
- package/dist/src/plugins/preset.js +67 -0
- package/dist/src/plugins/scoped-addons.d.ts +74 -0
- package/dist/src/plugins/scoped-addons.js +208 -0
- package/dist/src/workflow/step-contract.d.ts +233 -0
- package/dist/src/workflow/step-contract.js +677 -0
- package/package.json +38 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 keytec GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @bakers-build/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
bakers.build surface-agnostic kernel: host contract, split-config helpers, addon preset/discovery machinery, shared primitives.
|
|
4
|
+
|
|
5
|
+
Part of the bakers.build CLI. Install the meta package `@bakers-build/bakers` to get the `bakers` CLI with all addons. Source: https://git.key-tec.de/bakers-build/bakers-build (bakers-cli/).
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The conductor stem a config file name denotes, or `undefined` when the file
|
|
3
|
+
* is not a conductor config at all.
|
|
4
|
+
*
|
|
5
|
+
* The inverse of {@link fileForStem}, exported because the naming rule has to
|
|
6
|
+
* stay in one place: a conductor reporting which config it was started from
|
|
7
|
+
* would otherwise slice the filename itself and quietly disagree with the
|
|
8
|
+
* loader about the near-miss cases this rule exists to exclude
|
|
9
|
+
* (`myconductor.config.js`, `vite.config.js`, `bakers.config.js`).
|
|
10
|
+
*
|
|
11
|
+
* Takes a bare file name, not a path — callers pass `basename(config_path)`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function stemForConfigFile(fileName: string): string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* The user-global `.bakers` dir. Core owns where the split-config files live,
|
|
16
|
+
* so a consumer that must recognise the home dir (e.g. to exclude it from a
|
|
17
|
+
* project walk-up, BB-219 AC-9) asks for it rather than joining it itself.
|
|
18
|
+
*
|
|
19
|
+
* This is the ONE place that decides where `.bakers` lives. `BB_HOME` names
|
|
20
|
+
* that directory itself — not a home containing one — so an isolated test, a
|
|
21
|
+
* second identity on one machine, or a container can relocate it without
|
|
22
|
+
* redirecting HOME. A relative value is resolved against the cwd, because the
|
|
23
|
+
* value travels into generated config text where an ambiguous path is a bug.
|
|
24
|
+
* An explicit `home` argument still wins: callers that already know whose home
|
|
25
|
+
* they mean (a fixture, another user's layer) are not overridden by the
|
|
26
|
+
* environment.
|
|
27
|
+
*/
|
|
28
|
+
export declare function homeBbDir(home?: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Walk from `cwd` root-ward (git/eslint style) to the nearest ancestor whose
|
|
31
|
+
* `.bakers/` dir holds at least one conductor config; return that `.bakers/` dir, or
|
|
32
|
+
* `undefined` if none is found up to the filesystem root.
|
|
33
|
+
*/
|
|
34
|
+
export declare function findBbDir(cwd: string): string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the ENGINE (`conductor.config.js`) config path from `cwd`.
|
|
37
|
+
*
|
|
38
|
+
* 1. An explicit `--config` / `$BB_CONDUCTOR_CONFIG` wins verbatim (no walk).
|
|
39
|
+
* 2. Otherwise walk root-ward to the nearest `.bakers/` dir holding a conductor
|
|
40
|
+
* config — so any subdirectory of a project/worktree resolves the same dir.
|
|
41
|
+
* - A `--conductor <name>` / `$BB_CONDUCTOR` selector resolves the stem's
|
|
42
|
+
* file (`conductor` → `conductor.config.js`, else `<name>.conductor.config.js`).
|
|
43
|
+
* - No selector: `conductor.config.js` present → the default; else exactly
|
|
44
|
+
* one config → use it (back-compat); else → error naming the stems.
|
|
45
|
+
* 3. No `.bakers/` config anywhere up the tree → an `ENOENT` error naming
|
|
46
|
+
* `bakers config init --scope project`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveConfigPath(override?: string, cwd?: string, conductorName?: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Which leg of the connection precedence produced the resolved path. Purely
|
|
51
|
+
* diagnostic (BB-219 D4): it lets a consumer report project-vs-home without
|
|
52
|
+
* re-deriving the rule, which would be a second precedence implementation.
|
|
53
|
+
*/
|
|
54
|
+
export type BbConfigSource = 'explicit' | 'project' | 'home';
|
|
55
|
+
/** A current resolved connection with diagnostic source metadata. */
|
|
56
|
+
export interface BbConfigResolution {
|
|
57
|
+
path: string;
|
|
58
|
+
/** Current connections never use a credential fallback. */
|
|
59
|
+
fallback: boolean;
|
|
60
|
+
/** Current resolution never selects a historical engine connection. */
|
|
61
|
+
legacy: boolean;
|
|
62
|
+
/** Which leg produced `path` (BB-219 D4). */
|
|
63
|
+
source: BbConfigSource;
|
|
64
|
+
}
|
|
65
|
+
/** Walk upward for current project connection files only. Legacy engine files
|
|
66
|
+
* are migration input, never runtime connection sources. */
|
|
67
|
+
export declare function findBbConfig(cwd: string): {
|
|
68
|
+
path: string;
|
|
69
|
+
legacy: boolean;
|
|
70
|
+
} | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Walk root-ward for the nearest `.bakers/` dir that marks a **project** — one
|
|
73
|
+
* holding any bakers config at all, a `bakers.config.js` or at least one conductor
|
|
74
|
+
* config. Returns that `.bakers/` dir, or `undefined` up to the filesystem root.
|
|
75
|
+
*
|
|
76
|
+
* Deliberately a different question from `findBbConfig` (BB-219 AC-9):
|
|
77
|
+
* "which project am I standing in" is not "where does my connection come from".
|
|
78
|
+
* Since BB-230 the connection walk-up skips an engine-only
|
|
79
|
+
* `conductor.config.js`, and BB-218 makes exactly that the canonical repo
|
|
80
|
+
* shape — so keying project detection on the connection would stop recognising
|
|
81
|
+
* the most common project as a project. It is content-agnostic for the same
|
|
82
|
+
* reason `findBbDir` is: a `.bakers/` dir is the marker.
|
|
83
|
+
*
|
|
84
|
+
* It is a superset of `findBbDir`, which requires a *conductor* config
|
|
85
|
+
* because it resolves the engine config; a repo carrying only a project
|
|
86
|
+
* connection override is a project here and not there.
|
|
87
|
+
*/
|
|
88
|
+
export declare function findProjectBbDir(cwd: string): string | undefined;
|
|
89
|
+
/** Configuration management also recognizes an empty/partial .bakers directory.
|
|
90
|
+
* Keep runtime engine and connection root resolution unchanged.
|
|
91
|
+
*/
|
|
92
|
+
export declare function findConfigProjectBbDir(cwd: string, home?: string): string | undefined;
|
|
93
|
+
/** Resolve explicit → project → global connection. An absent global still
|
|
94
|
+
* names its canonical owner so callers can provide a precise init remedy. */
|
|
95
|
+
export declare function resolveBbConfigPath(opts?: {
|
|
96
|
+
cwd?: string;
|
|
97
|
+
explicit?: string | undefined;
|
|
98
|
+
home?: string;
|
|
99
|
+
}): BbConfigResolution;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
/** A repo's config files live in this dir, one conductor config per conductor. */
|
|
5
|
+
const BB_DIR = '.bakers';
|
|
6
|
+
/** The default conductor's file name; its stem is `conductor`. */
|
|
7
|
+
const DEFAULT_CONFIG = 'conductor.config.js';
|
|
8
|
+
/** Variant files are `<stem>.conductor.config.js`. */
|
|
9
|
+
const VARIANT_SUFFIX = '.conductor.config.js';
|
|
10
|
+
/** The connection config file name (project + home). */
|
|
11
|
+
const BB_CONFIG = 'bakers.config.js';
|
|
12
|
+
/**
|
|
13
|
+
* List the conductor-config stems in a `.bakers/` dir. A file is a conductor
|
|
14
|
+
* config iff it is exactly `conductor.config.js` (stem `conductor`, the
|
|
15
|
+
* default) or ends with `.conductor.config.js` (stem = the leading part).
|
|
16
|
+
* Every other file (`vite.config.js`, the near-miss `myconductor.config.js`,
|
|
17
|
+
* and `bakers.config.js` itself) is ignored.
|
|
18
|
+
*/
|
|
19
|
+
function configStems(bakersDir) {
|
|
20
|
+
return readdirSync(bakersDir)
|
|
21
|
+
.map(stemForConfigFile)
|
|
22
|
+
.filter((s) => s !== undefined)
|
|
23
|
+
.sort();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The conductor stem a config file name denotes, or `undefined` when the file
|
|
27
|
+
* is not a conductor config at all.
|
|
28
|
+
*
|
|
29
|
+
* The inverse of {@link fileForStem}, exported because the naming rule has to
|
|
30
|
+
* stay in one place: a conductor reporting which config it was started from
|
|
31
|
+
* would otherwise slice the filename itself and quietly disagree with the
|
|
32
|
+
* loader about the near-miss cases this rule exists to exclude
|
|
33
|
+
* (`myconductor.config.js`, `vite.config.js`, `bakers.config.js`).
|
|
34
|
+
*
|
|
35
|
+
* Takes a bare file name, not a path — callers pass `basename(config_path)`.
|
|
36
|
+
*/
|
|
37
|
+
export function stemForConfigFile(fileName) {
|
|
38
|
+
if (fileName === DEFAULT_CONFIG)
|
|
39
|
+
return 'conductor';
|
|
40
|
+
if (fileName.endsWith(VARIANT_SUFFIX)) {
|
|
41
|
+
const stem = fileName.slice(0, -VARIANT_SUFFIX.length);
|
|
42
|
+
return stem === '' ? undefined : stem;
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/** Map a conductor stem back to its file name. */
|
|
47
|
+
function fileForStem(stem) {
|
|
48
|
+
return stem === 'conductor' ? DEFAULT_CONFIG : `${stem}${VARIANT_SUFFIX}`;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The user-global `.bakers` dir. Core owns where the split-config files live,
|
|
52
|
+
* so a consumer that must recognise the home dir (e.g. to exclude it from a
|
|
53
|
+
* project walk-up, BB-219 AC-9) asks for it rather than joining it itself.
|
|
54
|
+
*
|
|
55
|
+
* This is the ONE place that decides where `.bakers` lives. `BB_HOME` names
|
|
56
|
+
* that directory itself — not a home containing one — so an isolated test, a
|
|
57
|
+
* second identity on one machine, or a container can relocate it without
|
|
58
|
+
* redirecting HOME. A relative value is resolved against the cwd, because the
|
|
59
|
+
* value travels into generated config text where an ambiguous path is a bug.
|
|
60
|
+
* An explicit `home` argument still wins: callers that already know whose home
|
|
61
|
+
* they mean (a fixture, another user's layer) are not overridden by the
|
|
62
|
+
* environment.
|
|
63
|
+
*/
|
|
64
|
+
export function homeBbDir(home) {
|
|
65
|
+
if (home !== undefined)
|
|
66
|
+
return join(home, BB_DIR);
|
|
67
|
+
const override = process.env.BB_HOME;
|
|
68
|
+
return override ? resolve(override) : join(homedir(), BB_DIR);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Walk from `cwd` root-ward (git/eslint style) to the nearest ancestor whose
|
|
72
|
+
* `.bakers/` dir holds at least one conductor config; return that `.bakers/` dir, or
|
|
73
|
+
* `undefined` if none is found up to the filesystem root.
|
|
74
|
+
*/
|
|
75
|
+
export function findBbDir(cwd) {
|
|
76
|
+
let dir = resolve(cwd);
|
|
77
|
+
for (;;) {
|
|
78
|
+
const bakersDir = join(dir, BB_DIR);
|
|
79
|
+
if (existsSync(bakersDir) && configStems(bakersDir).length > 0) {
|
|
80
|
+
return bakersDir;
|
|
81
|
+
}
|
|
82
|
+
const parent = dirname(dir);
|
|
83
|
+
if (parent === dir) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
dir = parent;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Resolve the ENGINE (`conductor.config.js`) config path from `cwd`.
|
|
91
|
+
*
|
|
92
|
+
* 1. An explicit `--config` / `$BB_CONDUCTOR_CONFIG` wins verbatim (no walk).
|
|
93
|
+
* 2. Otherwise walk root-ward to the nearest `.bakers/` dir holding a conductor
|
|
94
|
+
* config — so any subdirectory of a project/worktree resolves the same dir.
|
|
95
|
+
* - A `--conductor <name>` / `$BB_CONDUCTOR` selector resolves the stem's
|
|
96
|
+
* file (`conductor` → `conductor.config.js`, else `<name>.conductor.config.js`).
|
|
97
|
+
* - No selector: `conductor.config.js` present → the default; else exactly
|
|
98
|
+
* one config → use it (back-compat); else → error naming the stems.
|
|
99
|
+
* 3. No `.bakers/` config anywhere up the tree → an `ENOENT` error naming
|
|
100
|
+
* `bakers config init --scope project`.
|
|
101
|
+
*/
|
|
102
|
+
export function resolveConfigPath(override, cwd = process.cwd(), conductorName) {
|
|
103
|
+
const explicit = override ?? process.env.BB_CONDUCTOR_CONFIG;
|
|
104
|
+
if (explicit) {
|
|
105
|
+
return explicit;
|
|
106
|
+
}
|
|
107
|
+
const bakersDir = findBbDir(cwd);
|
|
108
|
+
if (bakersDir === undefined) {
|
|
109
|
+
// `ENOENT`, because that is what this is: the file the caller asked for
|
|
110
|
+
// does not exist. A caller for whom the project layer is optional then
|
|
111
|
+
// treats a failed walk and an absent file the same way, instead of
|
|
112
|
+
// discriminating one Error's message from another's.
|
|
113
|
+
//
|
|
114
|
+
// The remedy names `config init --scope project`, never `bakers init`: the
|
|
115
|
+
// latter writes machine and connection and deliberately leaves the project
|
|
116
|
+
// layer alone, so recommending it sends the reader back to the command
|
|
117
|
+
// they have already run.
|
|
118
|
+
throw Object.assign(new Error(`no .bakers/conductor.config.js found from ${cwd} upward; ` +
|
|
119
|
+
'run `bakers config init --scope project` in a project checkout'), { code: 'ENOENT' });
|
|
120
|
+
}
|
|
121
|
+
const stems = configStems(bakersDir);
|
|
122
|
+
const name = conductorName ?? process.env.BB_CONDUCTOR;
|
|
123
|
+
if (name !== undefined && name !== '') {
|
|
124
|
+
const candidate = join(bakersDir, fileForStem(name));
|
|
125
|
+
if (!existsSync(candidate)) {
|
|
126
|
+
throw new Error(`no conductor '${name}' in ${bakersDir}; available: ${stems.join(', ')}`);
|
|
127
|
+
}
|
|
128
|
+
return candidate;
|
|
129
|
+
}
|
|
130
|
+
if (stems.includes('conductor')) {
|
|
131
|
+
return join(bakersDir, DEFAULT_CONFIG);
|
|
132
|
+
}
|
|
133
|
+
if (stems.length === 1) {
|
|
134
|
+
return join(bakersDir, fileForStem(stems[0]));
|
|
135
|
+
}
|
|
136
|
+
throw new Error(`${stems.length} conductors in ${bakersDir} (${stems.join(', ')}); ` +
|
|
137
|
+
'select one with --conductor <name> or $BB_CONDUCTOR');
|
|
138
|
+
}
|
|
139
|
+
/** Walk upward for current project connection files only. Legacy engine files
|
|
140
|
+
* are migration input, never runtime connection sources. */
|
|
141
|
+
export function findBbConfig(cwd) {
|
|
142
|
+
let dir = resolve(cwd);
|
|
143
|
+
for (;;) {
|
|
144
|
+
const bakersDir = join(dir, BB_DIR);
|
|
145
|
+
if (existsSync(bakersDir)) {
|
|
146
|
+
const bakersCfg = join(bakersDir, BB_CONFIG);
|
|
147
|
+
if (existsSync(bakersCfg))
|
|
148
|
+
return { path: bakersCfg, legacy: false };
|
|
149
|
+
}
|
|
150
|
+
const parent = dirname(dir);
|
|
151
|
+
if (parent === dir)
|
|
152
|
+
return undefined;
|
|
153
|
+
dir = parent;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Walk root-ward for the nearest `.bakers/` dir that marks a **project** — one
|
|
158
|
+
* holding any bakers config at all, a `bakers.config.js` or at least one conductor
|
|
159
|
+
* config. Returns that `.bakers/` dir, or `undefined` up to the filesystem root.
|
|
160
|
+
*
|
|
161
|
+
* Deliberately a different question from `findBbConfig` (BB-219 AC-9):
|
|
162
|
+
* "which project am I standing in" is not "where does my connection come from".
|
|
163
|
+
* Since BB-230 the connection walk-up skips an engine-only
|
|
164
|
+
* `conductor.config.js`, and BB-218 makes exactly that the canonical repo
|
|
165
|
+
* shape — so keying project detection on the connection would stop recognising
|
|
166
|
+
* the most common project as a project. It is content-agnostic for the same
|
|
167
|
+
* reason `findBbDir` is: a `.bakers/` dir is the marker.
|
|
168
|
+
*
|
|
169
|
+
* It is a superset of `findBbDir`, which requires a *conductor* config
|
|
170
|
+
* because it resolves the engine config; a repo carrying only a project
|
|
171
|
+
* connection override is a project here and not there.
|
|
172
|
+
*/
|
|
173
|
+
export function findProjectBbDir(cwd) {
|
|
174
|
+
let dir = resolve(cwd);
|
|
175
|
+
for (;;) {
|
|
176
|
+
const bakersDir = join(dir, BB_DIR);
|
|
177
|
+
if (existsSync(bakersDir) &&
|
|
178
|
+
(existsSync(join(bakersDir, BB_CONFIG)) ||
|
|
179
|
+
configStems(bakersDir).length > 0)) {
|
|
180
|
+
return bakersDir;
|
|
181
|
+
}
|
|
182
|
+
const parent = dirname(dir);
|
|
183
|
+
if (parent === dir)
|
|
184
|
+
return undefined;
|
|
185
|
+
dir = parent;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/** Configuration management also recognizes an empty/partial .bakers directory.
|
|
189
|
+
* Keep runtime engine and connection root resolution unchanged.
|
|
190
|
+
*/
|
|
191
|
+
export function findConfigProjectBbDir(cwd, home) {
|
|
192
|
+
let dir = resolve(cwd);
|
|
193
|
+
const globalDir = resolve(homeBbDir(home));
|
|
194
|
+
for (;;) {
|
|
195
|
+
const bakersDir = join(dir, BB_DIR);
|
|
196
|
+
if (bakersDir !== globalDir && existsSync(bakersDir))
|
|
197
|
+
return bakersDir;
|
|
198
|
+
const parent = dirname(dir);
|
|
199
|
+
if (parent === dir)
|
|
200
|
+
return undefined;
|
|
201
|
+
dir = parent;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/** Resolve explicit → project → global connection. An absent global still
|
|
205
|
+
* names its canonical owner so callers can provide a precise init remedy. */
|
|
206
|
+
export function resolveBbConfigPath(opts = {}) {
|
|
207
|
+
const homeCfg = join(homeBbDir(opts.home), BB_CONFIG);
|
|
208
|
+
const explicit = opts.explicit;
|
|
209
|
+
if (explicit !== undefined && explicit.trim() !== '') {
|
|
210
|
+
return {
|
|
211
|
+
path: explicit,
|
|
212
|
+
fallback: false,
|
|
213
|
+
legacy: false,
|
|
214
|
+
source: 'explicit',
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
218
|
+
const project = findBbConfig(cwd);
|
|
219
|
+
if (project !== undefined) {
|
|
220
|
+
return {
|
|
221
|
+
path: project.path,
|
|
222
|
+
fallback: false,
|
|
223
|
+
legacy: project.legacy,
|
|
224
|
+
source: project.path === homeCfg ? 'home' : 'project',
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return { path: homeCfg, fallback: false, legacy: false, source: 'home' };
|
|
228
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import type { DropSHPlugin } from 'dropsh/plugin';
|
|
3
|
+
import type { BbConnectionConfig } from './load-bakers-config.js';
|
|
4
|
+
/**
|
|
5
|
+
* What the host hands each command plugin at mount time. `resolveBases` is the
|
|
6
|
+
* ESLint-style base order the plugin passes to `resolveModuleEslintStyle` for
|
|
7
|
+
* pnpm-safe sibling resolution (renderer, dropsh auth plugins) — the host owns
|
|
8
|
+
* it because only the host knows its own install location; a plugin resolving
|
|
9
|
+
* from its own `import.meta.url` breaks under pnpm's isolated store.
|
|
10
|
+
*/
|
|
11
|
+
export interface BbCommandHost {
|
|
12
|
+
/** Base dirs/URLs for ESLint-style module resolution: host install → cwd. */
|
|
13
|
+
resolveBases: string[];
|
|
14
|
+
/** Host-owned product-workspace plugin factory for scoped command surfaces. */
|
|
15
|
+
workspacePlugin?: (workspaceId: string) => DropSHPlugin | Promise<DropSHPlugin>;
|
|
16
|
+
/** Conductor-owned project context, supplied by the meta host when present. */
|
|
17
|
+
projectContext?: {
|
|
18
|
+
resolveConfigPath(cwd: string): string;
|
|
19
|
+
readWorkspace(configPath: string): string | undefined;
|
|
20
|
+
writeWorkspace(configPath: string, name: string): Promise<void>;
|
|
21
|
+
resolveContext?(configPath: string, connection: BbConnectionConfig): Promise<{
|
|
22
|
+
projectId: string;
|
|
23
|
+
workspaceId: string;
|
|
24
|
+
workspace: string;
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A command plugin the host mounts under its `name` (`bakers <name> …`).
|
|
30
|
+
* `describe` is shown in `bakers --help` even when the plugin is NOT loaded (the
|
|
31
|
+
* host renders a describe-only stub), so lazy mounting keeps `--help` complete.
|
|
32
|
+
* `register` receives the top-level `commander` program and the host; it adds
|
|
33
|
+
* the plugin's subcommand tree.
|
|
34
|
+
*/
|
|
35
|
+
export interface BbCommandPlugin {
|
|
36
|
+
/** BB-215: the total-tag discriminant — a command plugin self-identifies its
|
|
37
|
+
* surface, like every other bakers.build plugin carries a `.kind`. */
|
|
38
|
+
readonly kind: 'command';
|
|
39
|
+
name: string;
|
|
40
|
+
describe: string;
|
|
41
|
+
register(program: Command, host: BbCommandHost): void | Promise<void>;
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ConfigFileKind, type ConfigOperation, type ConfigReport } from './config-report.js';
|
|
2
|
+
import { type ConfigSourceInspection } from './config-source.js';
|
|
3
|
+
export interface ConfigInventoryOptions {
|
|
4
|
+
operation?: ConfigOperation;
|
|
5
|
+
scope?: string;
|
|
6
|
+
cwd?: string;
|
|
7
|
+
path?: string;
|
|
8
|
+
home?: string;
|
|
9
|
+
machinePath?: string;
|
|
10
|
+
connectionPath?: string;
|
|
11
|
+
project?: string;
|
|
12
|
+
/**
|
|
13
|
+
* The `bakers init` shortcut's own scope resolution: `all` without ever
|
|
14
|
+
* pulling the project layer in, even when a project root resolves. Never
|
|
15
|
+
* set by `bakers config init --scope all`, which keeps today's behaviour of
|
|
16
|
+
* including a resolved project root (BB-496 finding 1).
|
|
17
|
+
*/
|
|
18
|
+
excludeProjectLayer?: boolean;
|
|
19
|
+
/** Schema policy is supplied by the owning command/migration registry. */
|
|
20
|
+
currentVersions?: Partial<Record<ConfigFileKind, number>>;
|
|
21
|
+
/** Internal planner overlay: proposed modules are validated without filesystem writes. */
|
|
22
|
+
sourceTexts?: ReadonlyMap<string, string | null>;
|
|
23
|
+
}
|
|
24
|
+
export interface ConfigInventory {
|
|
25
|
+
report: ConfigReport;
|
|
26
|
+
/** Secret-bearing data for the planner, never part of the public report. */
|
|
27
|
+
sources: Map<string, ConfigSourceInspection>;
|
|
28
|
+
}
|
|
29
|
+
/** Collect selected files and prerequisite sources without importing any module. */
|
|
30
|
+
export declare function inventoryConfig(options?: ConfigInventoryOptions): ConfigInventory;
|